VirtualBox

source: kBuild/trunk/src/kmk/kmkbuiltin/setmode.c

最後變更 在這個檔案是 3389,由 bird 提交於 5 年 前

kmk: Avoid setting umask just to get it, store the current value in a global variable (g_fUMask). The umask(0777) call in cp.c raced other code (kmk_append) that created files and directories, leaving us with read-only files sometimes.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 11.5 KB
 
1/* $NetBSD: setmode.c,v 1.30 2003/08/07 16:42:56 agc Exp $ */
2
3/*
4 * Copyright (c) 1989, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Dave Borman at Cray Research, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35/*#include <sys/cdefs.h>*/
36#if defined(LIBC_SCCS) && !defined(lint)
37#if 0
38static char sccsid[] = "@(#)setmode.c 8.2 (Berkeley) 3/25/94";
39#else
40__RCSID("$NetBSD: setmode.c,v 1.30 2003/08/07 16:42:56 agc Exp $");
41#endif
42#endif /* LIBC_SCCS and not lint */
43
44/*#include "namespace.h"*/
45#include "config.h"
46#include <sys/types.h>
47#include <sys/stat.h>
48
49#include <assert.h>
50#include <ctype.h>
51#include <errno.h>
52#include <signal.h>
53#include <stdlib.h>
54#ifndef _MSC_VER
55#include <unistd.h>
56#else
57#include "mscfakes.h"
58#endif
59
60#ifdef SETMODE_DEBUG
61#include <stdio.h>
62#endif
63
64/*#ifdef __weak_alias
65__weak_alias(getmode,_getmode)
66__weak_alias(setmode,_setmode)
67#endif*/
68
69#define SET_LEN 6 /* initial # of bitcmd struct to malloc */
70#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */
71
72typedef struct bitcmd {
73 char cmd;
74 char cmd2;
75 mode_t bits;
76} BITCMD;
77
78#define CMD2_CLR 0x01
79#define CMD2_SET 0x02
80#define CMD2_GBITS 0x04
81#define CMD2_OBITS 0x08
82#define CMD2_UBITS 0x10
83
84static BITCMD *addcmd(BITCMD *, int, int, int, u_int);
85static void compress_mode(BITCMD *);
86#ifdef SETMODE_DEBUG
87static void dumpmode(BITCMD *);
88#endif
89
90#ifndef _DIAGASSERT
91# define _DIAGASSERT assert
92#endif
93
94#ifndef S_ISTXT
95# ifdef S_ISVTX
96# define S_ISTXT S_ISVTX
97# else
98# define S_ISTXT 0
99# endif
100#endif /* !S_ISTXT */
101
102extern mode_t g_fUMask; /* Initialize in main() and keep up to date. */
103
104
105/*
106 * Given the old mode and an array of bitcmd structures, apply the operations
107 * described in the bitcmd structures to the old mode, and return the new mode.
108 * Note that there is no '=' command; a strict assignment is just a '-' (clear
109 * bits) followed by a '+' (set bits).
110 */
111mode_t
112bsd_getmode(bbox, omode)
113 const void *bbox;
114 mode_t omode;
115{
116 const BITCMD *set;
117 mode_t clrval, newmode, value;
118
119 _DIAGASSERT(bbox != NULL);
120
121 set = (const BITCMD *)bbox;
122 newmode = omode;
123 for (value = 0;; set++)
124 switch(set->cmd) {
125 /*
126 * When copying the user, group or other bits around, we "know"
127 * where the bits are in the mode so that we can do shifts to
128 * copy them around. If we don't use shifts, it gets real
129 * grundgy with lots of single bit checks and bit sets.
130 */
131 case 'u':
132 value = (newmode & S_IRWXU) >> 6;
133 goto common;
134
135 case 'g':
136 value = (newmode & S_IRWXG) >> 3;
137 goto common;
138
139 case 'o':
140 value = newmode & S_IRWXO;
141common: if (set->cmd2 & CMD2_CLR) {
142 clrval =
143 (set->cmd2 & CMD2_SET) ? S_IRWXO : value;
144 if (set->cmd2 & CMD2_UBITS)
145 newmode &= ~((clrval<<6) & set->bits);
146 if (set->cmd2 & CMD2_GBITS)
147 newmode &= ~((clrval<<3) & set->bits);
148 if (set->cmd2 & CMD2_OBITS)
149 newmode &= ~(clrval & set->bits);
150 }
151 if (set->cmd2 & CMD2_SET) {
152 if (set->cmd2 & CMD2_UBITS)
153 newmode |= (value<<6) & set->bits;
154 if (set->cmd2 & CMD2_GBITS)
155 newmode |= (value<<3) & set->bits;
156 if (set->cmd2 & CMD2_OBITS)
157 newmode |= value & set->bits;
158 }
159 break;
160
161 case '+':
162 newmode |= set->bits;
163 break;
164
165 case '-':
166 newmode &= ~set->bits;
167 break;
168
169 case 'X':
170 if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
171 newmode |= set->bits;
172 break;
173
174 case '\0':
175 default:
176#ifdef SETMODE_DEBUG
177 (void)printf("getmode:%04o -> %04o\n", omode, newmode);
178#endif
179 return (newmode);
180 }
181}
182
183#define ADDCMD(a, b, c, d) do { \
184 if (set >= endset) { \
185 BITCMD *newset; \
186 setlen += SET_LEN_INCR; \
187 newset = realloc(saveset, sizeof(BITCMD) * setlen); \
188 if (newset == NULL) { \
189 free(saveset); \
190 return (NULL); \
191 } \
192 set = newset + (set - saveset); \
193 saveset = newset; \
194 endset = newset + (setlen - 2); \
195 } \
196 set = addcmd(set, (a), (b), (c), (d)); \
197} while (/*CONSTCOND*/0)
198
199#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
200
201void *
202bsd_setmode(p)
203 const char *p;
204{
205 int perm, who;
206 char op, *ep;
207 BITCMD *set, *saveset, *endset;
208#ifndef _MSC_VER
209 sigset_t signset, sigoset;
210#endif
211 mode_t mask;
212 int equalopdone = 0; /* pacify gcc */
213 int permXbits, setlen;
214
215 if (!*p)
216 return (NULL);
217
218 /*
219 * Get a copy of the mask for the permissions that are mask relative.
220 * Flip the bits, we want what's not set. Since it's possible that
221 * the caller is opening files inside a signal handler, protect them
222 * as best we can.
223 */
224#ifndef _MSC_VER
225 sigfillset(&signset);
226 (void)sigprocmask(SIG_BLOCK, &signset, &sigoset);
227#endif
228 mask = g_fUMask;
229 assert(mask == umask(g_fUMask));
230 mask = ~mask;
231#ifndef _MSC_VER
232 (void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
233#endif
234
235 setlen = SET_LEN + 2;
236
237 if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
238 return (NULL);
239 saveset = set;
240 endset = set + (setlen - 2);
241
242 /*
243 * If an absolute number, get it and return; disallow non-octal digits
244 * or illegal bits.
245 */
246 if (isdigit((unsigned char)*p)) {
247 perm = (mode_t)strtol(p, &ep, 8);
248 if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) {
249 free(saveset);
250 return (NULL);
251 }
252 ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
253 set->cmd = 0;
254 return (saveset);
255 }
256
257 /*
258 * Build list of structures to set/clear/copy bits as described by
259 * each clause of the symbolic mode.
260 */
261 for (;;) {
262 /* First, find out which bits might be modified. */
263 for (who = 0;; ++p) {
264 switch (*p) {
265 case 'a':
266 who |= STANDARD_BITS;
267 break;
268 case 'u':
269 who |= S_ISUID|S_IRWXU;
270 break;
271 case 'g':
272 who |= S_ISGID|S_IRWXG;
273 break;
274 case 'o':
275 who |= S_IRWXO;
276 break;
277 default:
278 goto getop;
279 }
280 }
281
282getop: if ((op = *p++) != '+' && op != '-' && op != '=') {
283 free(saveset);
284 return (NULL);
285 }
286 if (op == '=')
287 equalopdone = 0;
288
289 who &= ~S_ISTXT;
290 for (perm = 0, permXbits = 0;; ++p) {
291 switch (*p) {
292 case 'r':
293 perm |= S_IRUSR|S_IRGRP|S_IROTH;
294 break;
295 case 's':
296 /*
297 * If specific bits where requested and
298 * only "other" bits ignore set-id.
299 */
300 if (who == 0 || (who & ~S_IRWXO))
301 perm |= S_ISUID|S_ISGID;
302 break;
303 case 't':
304 /*
305 * If specific bits where requested and
306 * only "other" bits ignore set-id.
307 */
308 if (who == 0 || (who & ~S_IRWXO)) {
309 who |= S_ISTXT;
310 perm |= S_ISTXT;
311 }
312 break;
313 case 'w':
314 perm |= S_IWUSR|S_IWGRP|S_IWOTH;
315 break;
316 case 'X':
317 permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
318 break;
319 case 'x':
320 perm |= S_IXUSR|S_IXGRP|S_IXOTH;
321 break;
322 case 'u':
323 case 'g':
324 case 'o':
325 /*
326 * When ever we hit 'u', 'g', or 'o', we have
327 * to flush out any partial mode that we have,
328 * and then do the copying of the mode bits.
329 */
330 if (perm) {
331 ADDCMD(op, who, perm, mask);
332 perm = 0;
333 }
334 if (op == '=')
335 equalopdone = 1;
336 if (op == '+' && permXbits) {
337 ADDCMD('X', who, permXbits, mask);
338 permXbits = 0;
339 }
340 ADDCMD(*p, who, op, mask);
341 break;
342
343 default:
344 /*
345 * Add any permissions that we haven't already
346 * done.
347 */
348 if (perm || (op == '=' && !equalopdone)) {
349 if (op == '=')
350 equalopdone = 1;
351 ADDCMD(op, who, perm, mask);
352 perm = 0;
353 }
354 if (permXbits) {
355 ADDCMD('X', who, permXbits, mask);
356 permXbits = 0;
357 }
358 goto apply;
359 }
360 }
361
362apply: if (!*p)
363 break;
364 if (*p != ',')
365 goto getop;
366 ++p;
367 }
368 set->cmd = 0;
369#ifdef SETMODE_DEBUG
370 (void)printf("Before compress_mode()\n");
371 dumpmode(saveset);
372#endif
373 compress_mode(saveset);
374#ifdef SETMODE_DEBUG
375 (void)printf("After compress_mode()\n");
376 dumpmode(saveset);
377#endif
378 return (saveset);
379}
380
381static BITCMD *
382addcmd(set, op, who, oparg, mask)
383 BITCMD *set;
384 int oparg, who;
385 int op;
386 u_int mask;
387{
388
389 _DIAGASSERT(set != NULL);
390
391 switch (op) {
392 case '=':
393 set->cmd = '-';
394 set->bits = who ? who : STANDARD_BITS;
395 set++;
396
397 op = '+';
398 /* FALLTHROUGH */
399 case '+':
400 case '-':
401 case 'X':
402 set->cmd = op;
403 set->bits = (who ? (mode_t)who : mask) & oparg;
404 break;
405
406 case 'u':
407 case 'g':
408 case 'o':
409 set->cmd = op;
410 if (who) {
411 set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
412 ((who & S_IRGRP) ? CMD2_GBITS : 0) |
413 ((who & S_IROTH) ? CMD2_OBITS : 0);
414 set->bits = (mode_t)~0;
415 } else {
416 set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
417 set->bits = mask;
418 }
419
420 if (oparg == '+')
421 set->cmd2 |= CMD2_SET;
422 else if (oparg == '-')
423 set->cmd2 |= CMD2_CLR;
424 else if (oparg == '=')
425 set->cmd2 |= CMD2_SET|CMD2_CLR;
426 break;
427 }
428 return (set + 1);
429}
430
431#ifdef SETMODE_DEBUG
432static void
433dumpmode(set)
434 BITCMD *set;
435{
436
437 _DIAGASSERT(set != NULL);
438
439 for (; set->cmd; ++set)
440 (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
441 set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
442 set->cmd2 & CMD2_CLR ? " CLR" : "",
443 set->cmd2 & CMD2_SET ? " SET" : "",
444 set->cmd2 & CMD2_UBITS ? " UBITS" : "",
445 set->cmd2 & CMD2_GBITS ? " GBITS" : "",
446 set->cmd2 & CMD2_OBITS ? " OBITS" : "");
447}
448#endif
449
450/*
451 * Given an array of bitcmd structures, compress by compacting consecutive
452 * '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u',
453 * 'g' and 'o' commands continue to be separate. They could probably be
454 * compacted, but it's not worth the effort.
455 */
456static void
457compress_mode(set)
458 BITCMD *set;
459{
460 BITCMD *nset;
461 int setbits, clrbits, Xbits, op;
462
463 _DIAGASSERT(set != NULL);
464
465 for (nset = set;;) {
466 /* Copy over any 'u', 'g' and 'o' commands. */
467 while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
468 *set++ = *nset++;
469 if (!op)
470 return;
471 }
472
473 for (setbits = clrbits = Xbits = 0;; nset++) {
474 if ((op = nset->cmd) == '-') {
475 clrbits |= nset->bits;
476 setbits &= ~nset->bits;
477 Xbits &= ~nset->bits;
478 } else if (op == '+') {
479 setbits |= nset->bits;
480 clrbits &= ~nset->bits;
481 Xbits &= ~nset->bits;
482 } else if (op == 'X')
483 Xbits |= nset->bits & ~setbits;
484 else
485 break;
486 }
487 if (clrbits) {
488 set->cmd = '-';
489 set->cmd2 = 0;
490 set->bits = clrbits;
491 set++;
492 }
493 if (setbits) {
494 set->cmd = '+';
495 set->cmd2 = 0;
496 set->bits = setbits;
497 set++;
498 }
499 if (Xbits) {
500 set->cmd = 'X';
501 set->cmd2 = 0;
502 set->bits = Xbits;
503 set++;
504 }
505 }
506}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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