VirtualBox

source: vbox/trunk/src/VBox/Runtime/tools/RTChMod.cpp@ 69802

最後變更 在這個檔案從69802是 69802,由 vboxsync 提交於 7 年 前

Make the format build box happier.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 16.2 KB
 
1/* $Id: RTChMod.cpp 69802 2017-11-22 09:57:07Z vboxsync $ */
2/** @file
3 * IPRT - Changes the mode/attributes of a file system object.
4 */
5
6/*
7 * Copyright (C) 2013-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/path.h>
32#include <iprt/err.h>
33#include <iprt/initterm.h>
34#include <iprt/message.h>
35
36#include <iprt/vfs.h>
37#include <iprt/string.h>
38#include <iprt/stream.h>
39#include <iprt/getopt.h>
40#include <iprt/buildconfig.h>
41
42
43/*********************************************************************************************************************************
44* Defined Constants And Macros *
45*********************************************************************************************************************************/
46/** What to clear we all bits are being set. */
47#define RTCHMOD_SET_ALL_MASK (~( RTFS_TYPE_MASK \
48 | RTFS_DOS_NT_ENCRYPTED \
49 | RTFS_DOS_NT_COMPRESSED \
50 | RTFS_DOS_NT_REPARSE_POINT \
51 | RTFS_DOS_NT_SPARSE_FILE \
52 | RTFS_DOS_NT_DEVICE \
53 | RTFS_DOS_DIRECTORY))
54
55
56/*********************************************************************************************************************************
57* Structures and Typedefs *
58*********************************************************************************************************************************/
59typedef enum RTCMDCHMODNOISE
60{
61 kRTCmdChModNoise_Quiet,
62 kRTCmdChModNoise_Default,
63 kRTCmdChModNoise_Changes,
64 kRTCmdChModNoise_Verbose
65} RTCMDCHMODNOISE;
66
67typedef struct RTCMDCHMODOPTS
68{
69 /** The noise level. */
70 RTCMDCHMODNOISE enmNoiseLevel;
71 /** -R, --recursive */
72 bool fRecursive;
73 /** --preserve-root / --no-preserve-root (don't allow recursion from root). */
74 bool fPreserveRoot;
75 /** Whether to always use the VFS chain API (for testing). */
76 bool fAlwaysUseChainApi;
77 /** Which mode bits to set. */
78 RTFMODE fModeSet;
79 /** Which mode bits to clear. */
80 RTFMODE fModeClear;
81} RTCMDCHMODOPTS;
82
83
84
85/**
86 * Calculates the new file mode.
87 *
88 * @returns New mode mask.
89 * @param pOpts The chmod options.
90 * @param fMode The current file mode.
91 */
92static RTFMODE rtCmdMkModCalcNewMode(RTCMDCHMODOPTS const *pOpts, RTFMODE fMode)
93{
94 fMode &= ~pOpts->fModeClear;
95 fMode |= pOpts->fModeSet;
96 /** @todo do 'X' */
97 return fMode;
98}
99
100
101/**
102 * Changes the file mode of one file system object.
103 *
104 * @returns exit code
105 * @param pOpts The chmod options.
106 * @param pszPath The path to the file system object to change the
107 * file mode of.
108 */
109static RTEXITCODE rtCmdChModOne(RTCMDCHMODOPTS const *pOpts, const char *pszPath)
110{
111 int rc;
112 RTFSOBJINFO ObjInfo;
113 bool fChanges = false;
114 if (!pOpts->fAlwaysUseChainApi && !RTVfsChainIsSpec(pszPath) )
115 {
116 rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
117 if (RT_SUCCESS(rc))
118 {
119 RTFMODE fNewMode = rtCmdMkModCalcNewMode(pOpts, ObjInfo.Attr.fMode);
120 fChanges = fNewMode != ObjInfo.Attr.fMode;
121 if (fChanges)
122 {
123 rc = RTPathSetMode(pszPath, fNewMode);
124 if (RT_FAILURE(rc))
125 RTMsgError("RTPathSetMode failed on '%s' with fNewMode=%#x: %Rrc", pszPath, fNewMode, rc);
126 }
127 }
128 else
129 RTMsgError("RTPathQueryInfoEx failed on '%s': %Rrc", pszPath, rc);
130 }
131 else
132 {
133 /* Try via parent first as that's generally faster and more reliable. */
134 RTVFSDIR hVfsDir;
135 const char *pszChild;
136 uint32_t offError;
137 RTERRINFOSTATIC ErrInfo;
138 rc = RTVfsChainOpenParentDir(pszPath, 0 /*fOpen*/, &hVfsDir, &pszChild, &offError, RTErrInfoInitStatic(&ErrInfo));
139 if (RT_SUCCESS(rc))
140 {
141 rc = RTVfsDirQueryPathInfo(hVfsDir, pszChild, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
142 if (RT_SUCCESS(rc))
143 {
144 RTFMODE fNewMode = rtCmdMkModCalcNewMode(pOpts, ObjInfo.Attr.fMode);
145 fChanges = fNewMode != ObjInfo.Attr.fMode;
146 if (fChanges)
147 {
148 rc = VERR_NOT_IMPLEMENTED; //rc = RTVfsDirSetPathMode(hVfsDir, pszChild, fNewMode, RTPATH_F_FOLLOW_LINK);
149 if (RT_FAILURE(rc))
150 RTMsgError("RTVfsDirSetPathMode failed on '%s' with fNewMode=%#x: %Rrc", pszPath, fNewMode, rc);
151 }
152 }
153 RTVfsDirRelease(hVfsDir);
154 }
155 /* If we have no child part, work on the chain as a whole. */
156 else if ( rc == VERR_VFS_CHAIN_TOO_SHORT_FOR_PARENT
157 || rc == VERR_VFS_CHAIN_NOT_PATH_ONLY)
158 {
159 rc = RTVfsChainQueryInfo(pszPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK,
160 &offError, RTErrInfoInitStatic(&ErrInfo));
161 if (RT_SUCCESS(rc))
162 {
163 RTFMODE fNewMode = rtCmdMkModCalcNewMode(pOpts, ObjInfo.Attr.fMode);
164 fChanges = fNewMode != ObjInfo.Attr.fMode;
165 if (fChanges)
166 {
167 rc = VERR_NOT_IMPLEMENTED; //rc = RTVfsChainSetMode(pszPath, fNewMode, &offError, RTErrInfoInitStatic(&ErrInfo));
168 if (RT_FAILURE(rc))
169 RTMsgError("RTVfsChainSetMode failed on '%s' with fNewMode=%#x: %Rrc", pszPath, fNewMode, rc);
170 }
171 }
172 else
173 RTVfsChainMsgError("RTVfsChainQueryInfo", pszPath, rc, offError, &ErrInfo.Core);
174 }
175 else /** @todo we could implement a fallback here so we don't require a final path element. */
176 RTVfsChainMsgError("RTVfsChainOpenParentDir", pszPath, rc, offError, &ErrInfo.Core);
177 }
178
179 if (RT_SUCCESS(rc))
180 {
181 if (pOpts->enmNoiseLevel >= (fChanges ? kRTCmdChModNoise_Changes : kRTCmdChModNoise_Verbose))
182 RTPrintf("%s\n", pszPath);
183 return RTEXITCODE_SUCCESS;
184 }
185 return RTEXITCODE_FAILURE;
186}
187
188
189/**
190 * Recursively changes the file mode.
191 *
192 * @returns exit code
193 * @param pOpts The mkdir option.
194 * @param pszPath The path to start changing the mode of.
195 */
196static int rtCmdChModRecursive(RTCMDCHMODOPTS const *pOpts, const char *pszPath)
197{
198 /*
199 * Check if it's a directory first. If not, join the non-recursive code.
200 */
201 int rc;
202 uint32_t offError;
203 RTFSOBJINFO ObjInfo;
204 RTERRINFOSTATIC ErrInfo;
205 bool const fUseChainApi = pOpts->fAlwaysUseChainApi || RTVfsChainIsSpec(pszPath);
206 if (!fUseChainApi)
207 {
208 rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
209 if (RT_FAILURE(rc))
210 return RTMsgErrorExitFailure("RTPathQueryInfoEx failed on '%s': %Rrc", pszPath, rc);
211 }
212 else
213 {
214 rc = RTVfsChainQueryInfo(pszPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK,
215 &offError, RTErrInfoInitStatic(&ErrInfo));
216 if (RT_FAILURE(rc))
217 return RTVfsChainMsgErrorExitFailure("RTVfsChainQueryInfo", pszPath, rc, offError, &ErrInfo.Core);
218 }
219
220 if (!RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode))
221 return rtCmdChModOne(pOpts, pszPath);
222
223 /** @todo do root detection. */
224
225 /*
226 * For recursion we always use the VFS layer.
227 */
228 RTVFSDIR hVfsDir;
229 if (!fUseChainApi)
230 {
231 rc = RTVfsDirOpenNormal(pszPath, 0 /** @todo write attrib flag*/, &hVfsDir);
232 if (RT_FAILURE(rc))
233 return RTMsgErrorExitFailure("RTVfsDirOpenNormal failed on '%s': %Rrc", pszPath, rc);
234 }
235 else
236 {
237 rc = RTVfsChainOpenDir(pszPath, 0 /** @todo write attrib flag*/, &hVfsDir, &offError, RTErrInfoInitStatic(&ErrInfo));
238 if (RT_FAILURE(rc))
239 return RTVfsChainMsgErrorExitFailure("RTVfsChainQueryInfo", pszPath, rc, offError, &ErrInfo.Core);
240 }
241
242 RTMsgError("Recursion is not yet implemented\n");
243 RTVfsDirRelease(hVfsDir);
244 rc = VERR_NOT_IMPLEMENTED;
245
246 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
247}
248
249
250static RTEXITCODE RTCmdChMod(unsigned cArgs, char **papszArgs)
251{
252 /*
253 * Parse the command line.
254 */
255 static const RTGETOPTDEF s_aOptions[] =
256 {
257 /* operations */
258 { "--recursive", 'R', RTGETOPT_REQ_NOTHING },
259 { "--preserve-root", 'x', RTGETOPT_REQ_NOTHING },
260 { "--no-preserve-root", 'X', RTGETOPT_REQ_NOTHING },
261 { "--changes", 'c', RTGETOPT_REQ_NOTHING },
262 { "--quiet", 'f', RTGETOPT_REQ_NOTHING },
263 { "--silent", 'f', RTGETOPT_REQ_NOTHING },
264 { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
265 { "--reference", 'Z', RTGETOPT_REQ_NOTHING },
266 { "--always-use-vfs-chain-api", 'A', RTGETOPT_REQ_NOTHING },
267
268 };
269
270 RTGETOPTSTATE GetState;
271 int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1,
272 RTGETOPTINIT_FLAGS_OPTS_FIRST);
273 if (RT_FAILURE(rc))
274 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOpt failed: %Rrc", rc);
275
276 RTCMDCHMODOPTS Opts;
277 Opts.enmNoiseLevel = kRTCmdChModNoise_Default;
278 Opts.fPreserveRoot = false;
279 Opts.fRecursive = false;
280 Opts.fAlwaysUseChainApi = false;
281 Opts.fModeClear = 0;
282 Opts.fModeSet = 0;
283
284 RTGETOPTUNION ValueUnion;
285 while ( (rc = RTGetOpt(&GetState, &ValueUnion)) != 0
286 && rc != VINF_GETOPT_NOT_OPTION)
287 {
288 switch (rc)
289 {
290 case 'R':
291 Opts.fRecursive = true;
292 break;
293
294 case 'x':
295 Opts.fPreserveRoot = true;
296 break;
297 case 'X':
298 Opts.fPreserveRoot = false;
299 break;
300
301 case 'f':
302 Opts.enmNoiseLevel = kRTCmdChModNoise_Quiet;
303 break;
304 case 'c':
305 Opts.enmNoiseLevel = kRTCmdChModNoise_Changes;
306 break;
307 case 'v':
308 Opts.enmNoiseLevel = kRTCmdChModNoise_Verbose;
309 break;
310
311 case 'Z':
312 {
313 RTFSOBJINFO ObjInfo;
314 RTERRINFOSTATIC ErrInfo;
315 uint32_t offError;
316 rc = RTVfsChainQueryInfo(ValueUnion.psz, &ObjInfo,RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK,
317 &offError, RTErrInfoInitStatic(&ErrInfo));
318 if (RT_FAILURE(rc))
319 return RTVfsChainMsgErrorExitFailure("RTVfsChainQueryInfo", ValueUnion.psz, rc, offError, &ErrInfo.Core);
320 Opts.fModeClear = RTCHMOD_SET_ALL_MASK;
321 Opts.fModeSet = ObjInfo.Attr.fMode & RTCHMOD_SET_ALL_MASK;
322 break;
323 }
324
325 case 'A':
326 Opts.fAlwaysUseChainApi = true;
327 break;
328
329 case 'h':
330 RTPrintf("Usage: %s [options] <mode> <file> [..]\n"
331 "\n"
332 "Options:\n"
333 " -f, --silent, --quiet\n"
334 " -c, --changes\n"
335 " -v, --verbose\n"
336 " Noise level selection.\n"
337 " -R, --recursive\n"
338 " Recurse into directories.\n"
339 " --preserve-root, --no-preserve-root\n"
340 " Whether to allow recursion from the root (default: yes).\n"
341 " --reference <file>\n"
342 " Take mode mask to use from <file> instead of <mode>.\n"
343 "\n"
344 "The <mode> part isn't fully implemented, so only numerical octal notation\n"
345 "works. Prefix the number(s) with 0x to use hexadecimal. There are two forms\n"
346 "of the numerical notation: <SET> and <SET>:<CLEAR>\n"
347 , papszArgs[0]);
348 return RTEXITCODE_SUCCESS;
349
350 case 'V':
351 RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision());
352 return RTEXITCODE_SUCCESS;
353
354 default:
355
356 return RTGetOptPrintError(rc, &ValueUnion);
357 }
358 }
359
360 /*
361 * The MODE.
362 */
363 if ( Opts.fModeClear == 0
364 && Opts.fModeSet == 0)
365 {
366 if (rc != VINF_GETOPT_NOT_OPTION)
367 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No mode change specified.\n");
368
369 char *pszNext;
370 if ( ValueUnion.psz[0] == '0'
371 && (ValueUnion.psz[1] == 'x' || ValueUnion.psz[1] == 'X'))
372 rc = RTStrToUInt32Ex(ValueUnion.psz, &pszNext, 16, &Opts.fModeSet);
373 else
374 rc = RTStrToUInt32Ex(ValueUnion.psz, &pszNext, 8, &Opts.fModeSet);
375 if ( rc != VINF_SUCCESS
376 && (rc != VWRN_TRAILING_CHARS || *pszNext != ':'))
377 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unable to parse mode mask: %s\n", ValueUnion.psz);
378 Opts.fModeSet &= RTCHMOD_SET_ALL_MASK;
379
380 if (rc == VINF_SUCCESS)
381 Opts.fModeClear = RTCHMOD_SET_ALL_MASK;
382 else
383 {
384 pszNext++;
385 if ( pszNext[0] == '0'
386 && (pszNext[1] == 'x' || pszNext[1] == 'X'))
387 rc = RTStrToUInt32Ex(pszNext, &pszNext, 16, &Opts.fModeClear);
388 else
389 rc = RTStrToUInt32Ex(pszNext, &pszNext, 8, &Opts.fModeClear);
390 if (rc != VINF_SUCCESS)
391 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unable to parse mode mask: %s\n", ValueUnion.psz);
392 Opts.fModeClear &= RTCHMOD_SET_ALL_MASK;
393 }
394
395 rc = RTGetOpt(&GetState, &ValueUnion);
396 }
397
398 /*
399 * No files means error.
400 */
401 if (rc != VINF_GETOPT_NOT_OPTION)
402 return RTMsgErrorExit(RTEXITCODE_FAILURE, "No directories specified.\n");
403
404 /*
405 * Work thru the specified dirs.
406 */
407 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
408 while (rc == VINF_GETOPT_NOT_OPTION)
409 {
410 if (Opts.fRecursive)
411 rc = rtCmdChModRecursive(&Opts, ValueUnion.psz);
412 else
413 rc = rtCmdChModOne(&Opts, ValueUnion.psz);
414 if (RT_FAILURE(rc))
415 rcExit = RTEXITCODE_FAILURE;
416
417 /* next */
418 rc = RTGetOpt(&GetState, &ValueUnion);
419 }
420 if (rc != 0)
421 rcExit = RTGetOptPrintError(rc, &ValueUnion);
422
423 return rcExit;
424}
425
426
427int main(int argc, char **argv)
428{
429 int rc = RTR3InitExe(argc, &argv, 0);
430 if (RT_FAILURE(rc))
431 return RTMsgInitFailure(rc);
432 return RTCmdChMod(argc, argv);
433}
434
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette