Mercurial > hg > octave-shane > gnulib-hg
annotate lib/modechange.c @ 6969:bbdf9204a185
Import from coreutils.
* MODULES.html.sh: Add mkancestors.
* modules/mkancesdirs: New module.
* modules/mkdir-p (Files): Remove lib/chdir-safer.c, lib/chdir-safer.h,
lib/same-inode.h, m4/afs.m4, m4/chdir-safer.m4.
The chdir-safer and afs files are now orphans; I'll remove them
unless someone speaks up.
Add lib/dirchownmod.c, lib/dirchownmod.h.
(Depends-on): Remove alloca, chown, save-cwd, dirname.
Add lchown, mkancesdirs.
(Maintainer): Add self.
* lib/dirchownmod.c, lib/dirchownmod.h:
* lib/mkancesdirs.c, lib/mkancesdirs.h: New files.
* lib/mkdir-p.c: Don't include alloca.h, stdio.h, sys/types.h,
unistd.h, string.h, chdir-safer.h, dirname.h, lchmod.h, lchown.h,
save-cwd.h. Instead, include dirchownmod.h and mkancesdirs.h.
(make_dir_parents): New args MAKE_ANCESTOR, OPTIONS, ANNOUNCE,
MODE_BITS. Remove options VERBOSE_FMT_STRING, CWD_ERRNO. All
callers changed. Revamp internals significantly, by not
attempting to create directories that are temporarily more
permissive than the final results. Do not attempt to use
save_cwd/restore_cwd; it isn't worth it for mkdir and install.
This removes some race conditions, fixes some bugs, and simplifies
things. Use new dirchownmod function to do owner and mode changes.
* lib/mkdir-p.h: Likewise.
* lib/modechange.c (octal_to_mode): New function.
(struct mode_change): New member mentioned.
(make_node_op_equals): New arg mentioned. All callers changed.
(mode_compile): Keep track of which mode bits the user has explicitly
mentioned.
(mode_adjust): New arg DIR, so that we implement the X op correctly.
New arg PMODE_BITS, to keep track of which mode bits the user
mentioned; it treats S_ISUID and S_ISGID speciall.
All callers changed.
* lib/modechange.h: Likewise.
* mkancesdirs.m4: New file.
* mkdir-p.m4 (gl_MKDIR_PARENTS): Mention dirchownmod.c, dirchownmod.h.
Don't require AC_FUNC_ALLOCA, gl_AFS, gl_CHDIR_SAFER; no longer needed.
Require gl_FUNC_LCHOWN, since dirchownmod.c needs it.
author | Paul Eggert <eggert@cs.ucla.edu> |
---|---|
date | Mon, 17 Jul 2006 06:06:48 +0000 |
parents | 6b31c8787689 |
children | db9b9e26e735 |
rev | line source |
---|---|
5 | 1 /* modechange.c -- file mode manipulation |
4360 | 2 |
6969 | 3 Copyright (C) 1989, 1990, 1997, 1998, 1999, 2001, 2003, 2004, 2005, |
4 2006 Free Software Foundation, Inc. | |
5 | 5 |
6 This program is free software; you can redistribute it and/or modify | |
7 it under the terms of the GNU General Public License as published by | |
8 the Free Software Foundation; either version 2, or (at your option) | |
9 any later version. | |
10 | |
11 This program is distributed in the hope that it will be useful, | |
12 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 GNU General Public License for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
650
b4ef1c1a0171
update FSF address in copyright
Jim Meyering <jim@meyering.net>
parents:
609
diff
changeset
|
17 along with this program; if not, write to the Free Software Foundation, |
5848
a48fb0e98c8c
*** empty log message ***
Paul Eggert <eggert@cs.ucla.edu>
parents:
5813
diff
changeset
|
18 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ |
5 | 19 |
20 /* Written by David MacKenzie <djm@ai.mit.edu> */ | |
21 | |
5813 | 22 /* The ASCII mode string is compiled into an array of `struct |
5 | 23 modechange', which can then be applied to each file to be changed. |
24 We do this instead of re-parsing the ASCII string for each file | |
25 because the compiled form requires less computation to use; when | |
26 changing the mode of many files, this probably results in a | |
5813 | 27 performance gain. */ |
5 | 28 |
6259
96c32553b4c6
Use a consistent style for including <config.h>.
Paul Eggert <eggert@cs.ucla.edu>
parents:
5848
diff
changeset
|
29 #ifdef HAVE_CONFIG_H |
702 | 30 # include <config.h> |
229 | 31 #endif |
32 | |
1818
b2644b45e17f
(make_node_op_equals, mode_compile, mode_create_from_ref, mode_adjust):
Jim Meyering <jim@meyering.net>
parents:
1769
diff
changeset
|
33 #include "modechange.h" |
5 | 34 #include <sys/stat.h> |
5813 | 35 #include "stat-macros.h" |
36 #include "xalloc.h" | |
4666 | 37 #include <stdlib.h> |
5 | 38 |
3081
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
39 /* The traditional octal values corresponding to each mode bit. */ |
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
40 #define SUID 04000 |
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
41 #define SGID 02000 |
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
42 #define SVTX 01000 |
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
43 #define RUSR 00400 |
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
44 #define WUSR 00200 |
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
45 #define XUSR 00100 |
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
46 #define RGRP 00040 |
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
47 #define WGRP 00020 |
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
48 #define XGRP 00010 |
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
49 #define ROTH 00004 |
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
50 #define WOTH 00002 |
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
51 #define XOTH 00001 |
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
52 #define ALLM 07777 /* all octal mode bits */ |
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
53 |
6969 | 54 /* Convert OCTAL, which uses one of the traditional octal values, to |
55 an internal mode_t value. */ | |
56 static mode_t | |
57 octal_to_mode (unsigned int octal) | |
58 { | |
59 /* Help the compiler optimize the usual case where mode_t uses | |
60 the traditional octal representation. */ | |
61 return ((S_ISUID == SUID && S_ISGID == SGID && S_ISVTX == SVTX | |
62 && S_IRUSR == RUSR && S_IWUSR == WUSR && S_IXUSR == XUSR | |
63 && S_IRGRP == RGRP && S_IWGRP == WGRP && S_IXGRP == XGRP | |
64 && S_IROTH == ROTH && S_IWOTH == WOTH && S_IXOTH == XOTH) | |
65 ? octal | |
66 : (mode_t) ((octal & SUID ? S_ISUID : 0) | |
67 | (octal & SGID ? S_ISGID : 0) | |
68 | (octal & SVTX ? S_ISVTX : 0) | |
69 | (octal & RUSR ? S_IRUSR : 0) | |
70 | (octal & WUSR ? S_IWUSR : 0) | |
71 | (octal & XUSR ? S_IXUSR : 0) | |
72 | (octal & RGRP ? S_IRGRP : 0) | |
73 | (octal & WGRP ? S_IWGRP : 0) | |
74 | (octal & XGRP ? S_IXGRP : 0) | |
75 | (octal & ROTH ? S_IROTH : 0) | |
76 | (octal & WOTH ? S_IWOTH : 0) | |
77 | (octal & XOTH ? S_IXOTH : 0))); | |
78 } | |
79 | |
5813 | 80 /* Special operations flags. */ |
81 enum | |
82 { | |
83 /* For the sentinel at the end of the mode changes array. */ | |
84 MODE_DONE, | |
85 | |
86 /* The typical case. */ | |
87 MODE_ORDINARY_CHANGE, | |
88 | |
89 /* In addition to the typical case, affect the execute bits if at | |
90 least one execute bit is set already, or if the file is a | |
91 directory. */ | |
92 MODE_X_IF_ANY_X, | |
1818
b2644b45e17f
(make_node_op_equals, mode_compile, mode_create_from_ref, mode_adjust):
Jim Meyering <jim@meyering.net>
parents:
1769
diff
changeset
|
93 |
5813 | 94 /* Instead of the typical case, copy some existing permissions for |
95 u, g, or o onto the other two. Which of u, g, or o is copied | |
96 is determined by which bits are set in the `value' field. */ | |
97 MODE_COPY_EXISTING | |
98 }; | |
1818
b2644b45e17f
(make_node_op_equals, mode_compile, mode_create_from_ref, mode_adjust):
Jim Meyering <jim@meyering.net>
parents:
1769
diff
changeset
|
99 |
5813 | 100 /* Description of a mode change. */ |
101 struct mode_change | |
102 { | |
103 char op; /* One of "=+-". */ | |
104 char flag; /* Special operations flag. */ | |
105 mode_t affected; /* Set for u, g, o, or a. */ | |
106 mode_t value; /* Bits to add/remove. */ | |
6969 | 107 mode_t mentioned; /* Bits explicitly mentioned. */ |
5813 | 108 }; |
5 | 109 |
5813 | 110 /* Return a mode_change array with the specified `=ddd'-style |
6969 | 111 mode change operation, where NEW_MODE is `ddd' and MENTIONED |
112 contains the bits explicitly mentioned in the mode are MENTIONED. */ | |
1769
bc0ac225f0a8
(make_node_op_equals): New function.
Jim Meyering <jim@meyering.net>
parents:
1760
diff
changeset
|
113 |
bc0ac225f0a8
(make_node_op_equals): New function.
Jim Meyering <jim@meyering.net>
parents:
1760
diff
changeset
|
114 static struct mode_change * |
6969 | 115 make_node_op_equals (mode_t new_mode, mode_t mentioned) |
1769
bc0ac225f0a8
(make_node_op_equals): New function.
Jim Meyering <jim@meyering.net>
parents:
1760
diff
changeset
|
116 { |
5813 | 117 struct mode_change *p = xmalloc (2 * sizeof *p); |
1769
bc0ac225f0a8
(make_node_op_equals): New function.
Jim Meyering <jim@meyering.net>
parents:
1760
diff
changeset
|
118 p->op = '='; |
5813 | 119 p->flag = MODE_ORDINARY_CHANGE; |
120 p->affected = CHMOD_MODE_BITS; | |
1769
bc0ac225f0a8
(make_node_op_equals): New function.
Jim Meyering <jim@meyering.net>
parents:
1760
diff
changeset
|
121 p->value = new_mode; |
6969 | 122 p->mentioned = mentioned; |
5813 | 123 p[1].flag = MODE_DONE; |
1769
bc0ac225f0a8
(make_node_op_equals): New function.
Jim Meyering <jim@meyering.net>
parents:
1760
diff
changeset
|
124 return p; |
bc0ac225f0a8
(make_node_op_equals): New function.
Jim Meyering <jim@meyering.net>
parents:
1760
diff
changeset
|
125 } |
bc0ac225f0a8
(make_node_op_equals): New function.
Jim Meyering <jim@meyering.net>
parents:
1760
diff
changeset
|
126 |
5813 | 127 /* Return a pointer to an array of file mode change operations created from |
5 | 128 MODE_STRING, an ASCII string that contains either an octal number |
129 specifying an absolute mode, or symbolic mode change operations with | |
130 the form: | |
131 [ugoa...][[+-=][rwxXstugo...]...][,...] | |
132 | |
5813 | 133 Return NULL if `mode_string' does not contain a valid |
134 representation of file mode change operations. */ | |
5 | 135 |
136 struct mode_change * | |
5813 | 137 mode_compile (char const *mode_string) |
5 | 138 { |
5813 | 139 /* The array of mode-change directives to be returned. */ |
140 struct mode_change *mc; | |
141 size_t used = 0; | |
1769
bc0ac225f0a8
(make_node_op_equals): New function.
Jim Meyering <jim@meyering.net>
parents:
1760
diff
changeset
|
142 |
5813 | 143 if ('0' <= *mode_string && *mode_string < '8') |
144 { | |
6969 | 145 unsigned int octal_mode = 0; |
146 unsigned int octal_mentioned = 0; | |
5 | 147 |
5813 | 148 do |
149 { | |
6969 | 150 octal_mode = 8 * octal_mode + *mode_string++ - '0'; |
151 octal_mentioned = 8 * octal_mentioned + 7; | |
152 if (ALLM < octal_mode) | |
5813 | 153 return NULL; |
154 } | |
155 while ('0' <= *mode_string && *mode_string < '8'); | |
3081
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
156 |
6527 | 157 if (*mode_string) |
158 return NULL; | |
159 | |
6969 | 160 return make_node_op_equals (octal_to_mode (octal_mode), |
161 octal_to_mode (octal_mentioned & ALLM)); | |
5 | 162 } |
163 | |
5813 | 164 /* Allocate enough space to hold the result. */ |
165 { | |
166 size_t needed = 1; | |
167 char const *p; | |
168 for (p = mode_string; *p; p++) | |
169 needed += (*p == '=' || *p == '+' || *p == '-'); | |
170 mc = xnmalloc (needed, sizeof *mc); | |
171 } | |
5 | 172 |
5813 | 173 /* One loop iteration for each `[ugoa]*([-+=]([rwxXst]*|[ugo]))+'. */ |
5304
707482f5c106
(mode_compile): Don't decrement a pointer that
Paul Eggert <eggert@cs.ucla.edu>
parents:
5159
diff
changeset
|
174 for (;; mode_string++) |
5 | 175 { |
5813 | 176 /* Which bits in the mode are operated on. */ |
177 mode_t affected = 0; | |
1769
bc0ac225f0a8
(make_node_op_equals): New function.
Jim Meyering <jim@meyering.net>
parents:
1760
diff
changeset
|
178 |
5813 | 179 /* Turn on all the bits in `affected' for each group given. */ |
5304
707482f5c106
(mode_compile): Don't decrement a pointer that
Paul Eggert <eggert@cs.ucla.edu>
parents:
5159
diff
changeset
|
180 for (;; mode_string++) |
5 | 181 switch (*mode_string) |
182 { | |
5813 | 183 default: |
184 goto invalid; | |
5 | 185 case 'u': |
5813 | 186 affected |= S_ISUID | S_IRWXU; |
5 | 187 break; |
188 case 'g': | |
5813 | 189 affected |= S_ISGID | S_IRWXG; |
5 | 190 break; |
191 case 'o': | |
5813 | 192 affected |= S_ISVTX | S_IRWXO; |
5 | 193 break; |
194 case 'a': | |
5813 | 195 affected |= CHMOD_MODE_BITS; |
5 | 196 break; |
5813 | 197 case '=': case '+': case '-': |
5 | 198 goto no_more_affected; |
199 } | |
5813 | 200 no_more_affected:; |
5 | 201 |
5813 | 202 do |
5 | 203 { |
5813 | 204 char op = *mode_string++; |
205 mode_t value; | |
206 char flag = MODE_COPY_EXISTING; | |
207 struct mode_change *change; | |
5 | 208 |
5813 | 209 switch (*mode_string++) |
5 | 210 { |
5813 | 211 case 'u': |
212 /* Set the affected bits to the value of the `u' bits | |
213 on the same file. */ | |
214 value = S_IRWXU; | |
215 break; | |
216 case 'g': | |
217 /* Set the affected bits to the value of the `g' bits | |
218 on the same file. */ | |
219 value = S_IRWXG; | |
220 break; | |
221 case 'o': | |
222 /* Set the affected bits to the value of the `o' bits | |
223 on the same file. */ | |
224 value = S_IRWXO; | |
225 break; | |
5 | 226 |
5813 | 227 default: |
228 value = 0; | |
229 flag = MODE_ORDINARY_CHANGE; | |
1769
bc0ac225f0a8
(make_node_op_equals): New function.
Jim Meyering <jim@meyering.net>
parents:
1760
diff
changeset
|
230 |
5813 | 231 for (mode_string--;; mode_string++) |
232 switch (*mode_string) | |
233 { | |
234 case 'r': | |
235 value |= S_IRUSR | S_IRGRP | S_IROTH; | |
236 break; | |
237 case 'w': | |
238 value |= S_IWUSR | S_IWGRP | S_IWOTH; | |
239 break; | |
240 case 'x': | |
241 value |= S_IXUSR | S_IXGRP | S_IXOTH; | |
242 break; | |
243 case 'X': | |
244 flag = MODE_X_IF_ANY_X; | |
245 break; | |
246 case 's': | |
247 /* Set the setuid/gid bits if `u' or `g' is selected. */ | |
248 value |= S_ISUID | S_ISGID; | |
249 break; | |
250 case 't': | |
251 /* Set the "save text image" bit if `o' is selected. */ | |
252 value |= S_ISVTX; | |
253 break; | |
254 default: | |
255 goto no_more_values; | |
256 } | |
257 no_more_values:; | |
1769
bc0ac225f0a8
(make_node_op_equals): New function.
Jim Meyering <jim@meyering.net>
parents:
1760
diff
changeset
|
258 } |
bc0ac225f0a8
(make_node_op_equals): New function.
Jim Meyering <jim@meyering.net>
parents:
1760
diff
changeset
|
259 |
5813 | 260 change = &mc[used++]; |
261 change->op = op; | |
262 change->flag = flag; | |
263 change->affected = affected; | |
264 change->value = value; | |
6969 | 265 change->mentioned = (affected ? affected & value : value); |
5 | 266 } |
5813 | 267 while (*mode_string == '=' || *mode_string == '+' |
268 || *mode_string == '-'); | |
5304
707482f5c106
(mode_compile): Don't decrement a pointer that
Paul Eggert <eggert@cs.ucla.edu>
parents:
5159
diff
changeset
|
269 |
707482f5c106
(mode_compile): Don't decrement a pointer that
Paul Eggert <eggert@cs.ucla.edu>
parents:
5159
diff
changeset
|
270 if (*mode_string != ',') |
707482f5c106
(mode_compile): Don't decrement a pointer that
Paul Eggert <eggert@cs.ucla.edu>
parents:
5159
diff
changeset
|
271 break; |
707482f5c106
(mode_compile): Don't decrement a pointer that
Paul Eggert <eggert@cs.ucla.edu>
parents:
5159
diff
changeset
|
272 } |
707482f5c106
(mode_compile): Don't decrement a pointer that
Paul Eggert <eggert@cs.ucla.edu>
parents:
5159
diff
changeset
|
273 |
5 | 274 if (*mode_string == 0) |
5813 | 275 { |
276 mc[used].flag = MODE_DONE; | |
277 return mc; | |
278 } | |
279 | |
5 | 280 invalid: |
5813 | 281 free (mc); |
282 return NULL; | |
5 | 283 } |
284 | |
989
c68ed1182a64
(mode_create_from_ref): Don't use umask.
Jim Meyering <jim@meyering.net>
parents:
972
diff
changeset
|
285 /* Return a file mode change operation that sets permissions to match those |
5813 | 286 of REF_FILE. Return NULL (setting errno) if REF_FILE can't be accessed. */ |
972
b30f9ff1e92e
(mode_create_from_ref): New function.
Jim Meyering <jim@meyering.net>
parents:
761
diff
changeset
|
287 |
b30f9ff1e92e
(mode_create_from_ref): New function.
Jim Meyering <jim@meyering.net>
parents:
761
diff
changeset
|
288 struct mode_change * |
1494 | 289 mode_create_from_ref (const char *ref_file) |
972
b30f9ff1e92e
(mode_create_from_ref): New function.
Jim Meyering <jim@meyering.net>
parents:
761
diff
changeset
|
290 { |
b30f9ff1e92e
(mode_create_from_ref): New function.
Jim Meyering <jim@meyering.net>
parents:
761
diff
changeset
|
291 struct stat ref_stats; |
b30f9ff1e92e
(mode_create_from_ref): New function.
Jim Meyering <jim@meyering.net>
parents:
761
diff
changeset
|
292 |
5813 | 293 if (stat (ref_file, &ref_stats) != 0) |
294 return NULL; | |
6969 | 295 return make_node_op_equals (ref_stats.st_mode, CHMOD_MODE_BITS); |
972
b30f9ff1e92e
(mode_create_from_ref): New function.
Jim Meyering <jim@meyering.net>
parents:
761
diff
changeset
|
296 } |
b30f9ff1e92e
(mode_create_from_ref): New function.
Jim Meyering <jim@meyering.net>
parents:
761
diff
changeset
|
297 |
6969 | 298 /* Return the file mode bits of OLDMODE (which is the mode of a |
299 directory if DIR), assuming the umask is UMASK_VALUE, adjusted as | |
300 indicated by the list of change operations CHANGES. If DIR, the | |
301 type 'X' change affects the returned value even if no execute bits | |
302 were set in OLDMODE. If PMODE_BITS is not null, store into | |
303 *PMODE_BITS a mask denoting file mode bits that are affected by | |
304 CHANGES. | |
305 | |
306 The returned value and *PMODE_BITS contain only file mode bits. | |
307 For example, they have the S_IFMT bits cleared on a standard | |
308 Unix-like host. */ | |
5 | 309 |
1818
b2644b45e17f
(make_node_op_equals, mode_compile, mode_create_from_ref, mode_adjust):
Jim Meyering <jim@meyering.net>
parents:
1769
diff
changeset
|
310 mode_t |
6969 | 311 mode_adjust (mode_t oldmode, bool dir, mode_t umask_value, |
312 struct mode_change const *changes, mode_t *pmode_bits) | |
5 | 313 { |
5813 | 314 /* The adjusted mode. */ |
315 mode_t newmode = oldmode & CHMOD_MODE_BITS; | |
5 | 316 |
6969 | 317 /* File mode bits that CHANGES cares about. */ |
318 mode_t mode_bits = 0; | |
319 | |
5813 | 320 for (; changes->flag != MODE_DONE; changes++) |
5 | 321 { |
5813 | 322 mode_t affected = changes->affected; |
6969 | 323 mode_t omit_change = |
324 (dir ? S_ISUID | S_ISGID : 0) & ~ changes->mentioned; | |
5813 | 325 mode_t value = changes->value; |
326 | |
327 switch (changes->flag) | |
5 | 328 { |
5813 | 329 case MODE_ORDINARY_CHANGE: |
330 break; | |
331 | |
332 case MODE_COPY_EXISTING: | |
333 /* Isolate in `value' the bits in `newmode' to copy. */ | |
334 value &= newmode; | |
5 | 335 |
5813 | 336 /* Copy the isolated bits to the other two parts. */ |
337 value |= ((value & (S_IRUSR | S_IRGRP | S_IROTH) | |
338 ? S_IRUSR | S_IRGRP | S_IROTH : 0) | |
339 | (value & (S_IWUSR | S_IWGRP | S_IWOTH) | |
340 ? S_IWUSR | S_IWGRP | S_IWOTH : 0) | |
341 | (value & (S_IXUSR | S_IXGRP | S_IXOTH) | |
342 ? S_IXUSR | S_IXGRP | S_IXOTH : 0)); | |
343 break; | |
5 | 344 |
5813 | 345 case MODE_X_IF_ANY_X: |
346 /* Affect the execute bits if execute bits are already set | |
347 or if the file is a directory. */ | |
6969 | 348 if ((newmode & (S_IXUSR | S_IXGRP | S_IXOTH)) | dir) |
5813 | 349 value |= S_IXUSR | S_IXGRP | S_IXOTH; |
350 break; | |
5 | 351 } |
5813 | 352 |
353 /* If WHO was specified, limit the change to the affected bits. | |
6969 | 354 Otherwise, apply the umask. Either way, omit changes as |
355 requested. */ | |
356 value &= (affected ? affected : ~umask_value) & ~ omit_change; | |
5 | 357 |
358 switch (changes->op) | |
359 { | |
360 case '=': | |
5813 | 361 /* If WHO was specified, preserve the previous values of |
362 bits that are not affected by this change operation. | |
363 Otherwise, clear all the bits. */ | |
6969 | 364 { |
365 mode_t preserved = (affected ? ~affected : 0) | omit_change; | |
366 mode_bits |= CHMOD_MODE_BITS & ~preserved; | |
367 newmode = (newmode & preserved) | value; | |
368 break; | |
369 } | |
370 | |
5 | 371 case '+': |
6969 | 372 mode_bits |= value; |
5 | 373 newmode |= value; |
374 break; | |
5813 | 375 |
5 | 376 case '-': |
6969 | 377 mode_bits |= value; |
5 | 378 newmode &= ~value; |
379 break; | |
380 } | |
381 } | |
5813 | 382 |
6969 | 383 if (pmode_bits) |
384 *pmode_bits = mode_bits; | |
5 | 385 return newmode; |
386 } |