source: trunk/src/gmake/kmkbuiltin/setmode.c@ 362

Last change on this file since 362 was 361, checked in by bird, 20 years ago

Ported to MSC

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