This source file includes following definitions.
- octal_to_mode
- make_node_op_equals
- mode_compile
- mode_create_from_ref
- mode_adjust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 #include <config.h>
29
30 #include "modechange.h"
31 #include <sys/stat.h>
32 #include "stat-macros.h"
33 #include "xalloc.h"
34 #include <stdlib.h>
35
36
37 #define SUID 04000
38 #define SGID 02000
39 #define SVTX 01000
40 #define RUSR 00400
41 #define WUSR 00200
42 #define XUSR 00100
43 #define RGRP 00040
44 #define WGRP 00020
45 #define XGRP 00010
46 #define ROTH 00004
47 #define WOTH 00002
48 #define XOTH 00001
49 #define ALLM 07777
50
51
52
53 static mode_t
54 octal_to_mode (unsigned int octal)
55 {
56
57
58 return ((S_ISUID == SUID && S_ISGID == SGID && S_ISVTX == SVTX
59 && S_IRUSR == RUSR && S_IWUSR == WUSR && S_IXUSR == XUSR
60 && S_IRGRP == RGRP && S_IWGRP == WGRP && S_IXGRP == XGRP
61 && S_IROTH == ROTH && S_IWOTH == WOTH && S_IXOTH == XOTH)
62 ? octal
63 : (mode_t) ((octal & SUID ? S_ISUID : 0)
64 | (octal & SGID ? S_ISGID : 0)
65 | (octal & SVTX ? S_ISVTX : 0)
66 | (octal & RUSR ? S_IRUSR : 0)
67 | (octal & WUSR ? S_IWUSR : 0)
68 | (octal & XUSR ? S_IXUSR : 0)
69 | (octal & RGRP ? S_IRGRP : 0)
70 | (octal & WGRP ? S_IWGRP : 0)
71 | (octal & XGRP ? S_IXGRP : 0)
72 | (octal & ROTH ? S_IROTH : 0)
73 | (octal & WOTH ? S_IWOTH : 0)
74 | (octal & XOTH ? S_IXOTH : 0)));
75 }
76
77
78 enum
79 {
80
81 MODE_DONE,
82
83
84 MODE_ORDINARY_CHANGE,
85
86
87
88
89 MODE_X_IF_ANY_X,
90
91
92
93
94 MODE_COPY_EXISTING
95 };
96
97
98 struct mode_change
99 {
100 char op;
101 char flag;
102 mode_t affected;
103 mode_t value;
104 mode_t mentioned;
105 };
106
107
108
109
110
111 static struct mode_change *
112 make_node_op_equals (mode_t new_mode, mode_t mentioned)
113 {
114 struct mode_change *p = xmalloc (2 * sizeof *p);
115 p->op = '=';
116 p->flag = MODE_ORDINARY_CHANGE;
117 p->affected = CHMOD_MODE_BITS;
118 p->value = new_mode;
119 p->mentioned = mentioned;
120 p[1].flag = MODE_DONE;
121 return p;
122 }
123
124
125
126
127
128
129
130
131
132
133 struct mode_change *
134 mode_compile (char const *mode_string)
135 {
136
137 struct mode_change *mc;
138 size_t used = 0;
139 char const *p;
140
141 if ('0' <= *mode_string && *mode_string < '8')
142 {
143 unsigned int octal_mode = 0;
144 mode_t mode;
145 mode_t mentioned;
146
147 p = mode_string;
148 do
149 {
150 octal_mode = 8 * octal_mode + *p++ - '0';
151 if (ALLM < octal_mode)
152 return NULL;
153 }
154 while ('0' <= *p && *p < '8');
155
156 if (*p)
157 return NULL;
158
159 mode = octal_to_mode (octal_mode);
160 mentioned = (p - mode_string < 5
161 ? (mode & (S_ISUID | S_ISGID)) | S_ISVTX | S_IRWXUGO
162 : CHMOD_MODE_BITS);
163 return make_node_op_equals (mode, mentioned);
164 }
165
166
167 {
168 size_t needed = 1;
169 for (p = mode_string; *p; p++)
170 needed += (*p == '=' || *p == '+' || *p == '-');
171 mc = xnmalloc (needed, sizeof *mc);
172 }
173
174
175
176 for (p = mode_string; ; p++)
177 {
178
179 mode_t affected = 0;
180
181
182 for (;; p++)
183 switch (*p)
184 {
185 default:
186 goto invalid;
187 case 'u':
188 affected |= S_ISUID | S_IRWXU;
189 break;
190 case 'g':
191 affected |= S_ISGID | S_IRWXG;
192 break;
193 case 'o':
194 affected |= S_ISVTX | S_IRWXO;
195 break;
196 case 'a':
197 affected |= CHMOD_MODE_BITS;
198 break;
199 case '=': case '+': case '-':
200 goto no_more_affected;
201 }
202 no_more_affected:;
203
204 do
205 {
206 char op = *p++;
207 mode_t value;
208 mode_t mentioned = 0;
209 char flag = MODE_COPY_EXISTING;
210 struct mode_change *change;
211
212 switch (*p)
213 {
214 case '0': case '1': case '2': case '3':
215 case '4': case '5': case '6': case '7':
216 {
217 unsigned int octal_mode = 0;
218
219 do
220 {
221 octal_mode = 8 * octal_mode + *p++ - '0';
222 if (ALLM < octal_mode)
223 goto invalid;
224 }
225 while ('0' <= *p && *p < '8');
226
227 if (affected || (*p && *p != ','))
228 goto invalid;
229 affected = mentioned = CHMOD_MODE_BITS;
230 value = octal_to_mode (octal_mode);
231 flag = MODE_ORDINARY_CHANGE;
232 break;
233 }
234
235 case 'u':
236
237
238 value = S_IRWXU;
239 p++;
240 break;
241 case 'g':
242
243
244 value = S_IRWXG;
245 p++;
246 break;
247 case 'o':
248
249
250 value = S_IRWXO;
251 p++;
252 break;
253
254 default:
255 value = 0;
256 flag = MODE_ORDINARY_CHANGE;
257
258 for (;; p++)
259 switch (*p)
260 {
261 case 'r':
262 value |= S_IRUSR | S_IRGRP | S_IROTH;
263 break;
264 case 'w':
265 value |= S_IWUSR | S_IWGRP | S_IWOTH;
266 break;
267 case 'x':
268 value |= S_IXUSR | S_IXGRP | S_IXOTH;
269 break;
270 case 'X':
271 flag = MODE_X_IF_ANY_X;
272 break;
273 case 's':
274
275 value |= S_ISUID | S_ISGID;
276 break;
277 case 't':
278
279 value |= S_ISVTX;
280 break;
281 default:
282 goto no_more_values;
283 }
284 no_more_values:;
285 }
286
287 change = &mc[used++];
288 change->op = op;
289 change->flag = flag;
290 change->affected = affected;
291 change->value = value;
292 change->mentioned =
293 (mentioned ? mentioned : affected ? affected & value : value);
294 }
295 while (*p == '=' || *p == '+' || *p == '-');
296
297 if (*p != ',')
298 break;
299 }
300
301 if (*p == 0)
302 {
303 mc[used].flag = MODE_DONE;
304 return mc;
305 }
306
307 invalid:
308 free (mc);
309 return NULL;
310 }
311
312
313
314
315 struct mode_change *
316 mode_create_from_ref (const char *ref_file)
317 {
318 struct stat ref_stats;
319
320 if (stat (ref_file, &ref_stats) != 0)
321 return NULL;
322 return make_node_op_equals (ref_stats.st_mode, CHMOD_MODE_BITS);
323 }
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338 mode_t
339 mode_adjust (mode_t oldmode, bool dir, mode_t umask_value,
340 struct mode_change const *changes, mode_t *pmode_bits)
341 {
342
343 mode_t newmode = oldmode & CHMOD_MODE_BITS;
344
345
346 mode_t mode_bits = 0;
347
348 for (; changes->flag != MODE_DONE; changes++)
349 {
350 mode_t affected = changes->affected;
351 mode_t omit_change =
352 (dir ? S_ISUID | S_ISGID : 0) & ~ changes->mentioned;
353 mode_t value = changes->value;
354
355 switch (changes->flag)
356 {
357 case MODE_ORDINARY_CHANGE:
358 break;
359
360 case MODE_COPY_EXISTING:
361
362 value &= newmode;
363
364
365 value |= ((value & (S_IRUSR | S_IRGRP | S_IROTH)
366 ? S_IRUSR | S_IRGRP | S_IROTH : 0)
367 | (value & (S_IWUSR | S_IWGRP | S_IWOTH)
368 ? S_IWUSR | S_IWGRP | S_IWOTH : 0)
369 | (value & (S_IXUSR | S_IXGRP | S_IXOTH)
370 ? S_IXUSR | S_IXGRP | S_IXOTH : 0));
371 break;
372
373 case MODE_X_IF_ANY_X:
374
375
376 if ((newmode & (S_IXUSR | S_IXGRP | S_IXOTH)) | dir)
377 value |= S_IXUSR | S_IXGRP | S_IXOTH;
378 break;
379 }
380
381
382
383
384 value &= (affected ? affected : ~umask_value) & ~ omit_change;
385
386 switch (changes->op)
387 {
388 case '=':
389
390
391
392 {
393 mode_t preserved = (affected ? ~affected : 0) | omit_change;
394 mode_bits |= CHMOD_MODE_BITS & ~preserved;
395 newmode = (newmode & preserved) | value;
396 break;
397 }
398
399 case '+':
400 mode_bits |= value;
401 newmode |= value;
402 break;
403
404 case '-':
405 mode_bits |= value;
406 newmode &= ~value;
407 break;
408 }
409 }
410
411 if (pmode_bits)
412 *pmode_bits = mode_bits;
413 return newmode;
414 }