Mercurial > hg > octave-shane > gnulib-hg
annotate lib/modechange.c @ 16201:8250f2777afc
maint: update all copyright year number ranges
Run "make update-copyright".
author | Jim Meyering <meyering@redhat.com> |
---|---|
date | Sun, 01 Jan 2012 10:04:58 +0100 |
parents | 97fc9a21a8fb |
children | 18a38c9615f0 |
rev | line source |
---|---|
5 | 1 /* modechange.c -- file mode manipulation |
4360 | 2 |
16201
8250f2777afc
maint: update all copyright year number ranges
Jim Meyering <meyering@redhat.com>
parents:
14079
diff
changeset
|
3 Copyright (C) 1989-1990, 1997-1999, 2001, 2003-2006, 2009-2012 Free Software |
12518
b5e42ef33b49
update nearly all FSF copyright year lists to include 2009
Jim Meyering <meyering@redhat.com>
parents:
12421
diff
changeset
|
4 Foundation, Inc. |
5 | 5 |
9309
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
7302
diff
changeset
|
6 This program is free software: you can redistribute it and/or modify |
5 | 7 it under the terms of the GNU General Public License as published by |
9309
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
7302
diff
changeset
|
8 the Free Software Foundation; either version 3 of the License, or |
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
7302
diff
changeset
|
9 (at your option) any later version. |
5 | 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 | |
9309
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
7302
diff
changeset
|
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
5 | 18 |
19 /* Written by David MacKenzie <djm@ai.mit.edu> */ | |
20 | |
5813 | 21 /* The ASCII mode string is compiled into an array of `struct |
5 | 22 modechange', which can then be applied to each file to be changed. |
23 We do this instead of re-parsing the ASCII string for each file | |
24 because the compiled form requires less computation to use; when | |
25 changing the mode of many files, this probably results in a | |
5813 | 26 performance gain. */ |
5 | 27 |
7302
8a1a9361108c
* _fpending.c: Include <config.h> unconditionally, since we no
Paul Eggert <eggert@cs.ucla.edu>
parents:
7056
diff
changeset
|
28 #include <config.h> |
229 | 29 |
1818
b2644b45e17f
(make_node_op_equals, mode_compile, mode_create_from_ref, mode_adjust):
Jim Meyering <jim@meyering.net>
parents:
1769
diff
changeset
|
30 #include "modechange.h" |
5 | 31 #include <sys/stat.h> |
5813 | 32 #include "stat-macros.h" |
33 #include "xalloc.h" | |
4666 | 34 #include <stdlib.h> |
5 | 35 |
3081
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
36 /* 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
|
37 #define SUID 04000 |
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
38 #define SGID 02000 |
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
39 #define SVTX 01000 |
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
40 #define RUSR 00400 |
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
41 #define WUSR 00200 |
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
42 #define XUSR 00100 |
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
43 #define RGRP 00040 |
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
44 #define WGRP 00020 |
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
45 #define XGRP 00010 |
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
46 #define ROTH 00004 |
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
47 #define WOTH 00002 |
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
48 #define XOTH 00001 |
b7402f1afb7b
Do not assume that mode_t uses the
Jim Meyering <jim@meyering.net>
parents:
2950
diff
changeset
|
49 #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
|
50 |
6969 | 51 /* Convert OCTAL, which uses one of the traditional octal values, to |
52 an internal mode_t value. */ | |
53 static mode_t | |
54 octal_to_mode (unsigned int octal) | |
55 { | |
56 /* Help the compiler optimize the usual case where mode_t uses | |
57 the traditional octal representation. */ | |
58 return ((S_ISUID == SUID && S_ISGID == SGID && S_ISVTX == SVTX | |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
59 && S_IRUSR == RUSR && S_IWUSR == WUSR && S_IXUSR == XUSR |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
60 && S_IRGRP == RGRP && S_IWGRP == WGRP && S_IXGRP == XGRP |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
61 && S_IROTH == ROTH && S_IWOTH == WOTH && S_IXOTH == XOTH) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
62 ? octal |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
63 : (mode_t) ((octal & SUID ? S_ISUID : 0) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
64 | (octal & SGID ? S_ISGID : 0) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
65 | (octal & SVTX ? S_ISVTX : 0) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
66 | (octal & RUSR ? S_IRUSR : 0) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
67 | (octal & WUSR ? S_IWUSR : 0) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
68 | (octal & XUSR ? S_IXUSR : 0) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
69 | (octal & RGRP ? S_IRGRP : 0) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
70 | (octal & WGRP ? S_IWGRP : 0) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
71 | (octal & XGRP ? S_IXGRP : 0) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
72 | (octal & ROTH ? S_IROTH : 0) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
73 | (octal & WOTH ? S_IWOTH : 0) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
74 | (octal & XOTH ? S_IXOTH : 0))); |
6969 | 75 } |
76 | |
5813 | 77 /* Special operations flags. */ |
78 enum | |
79 { | |
80 /* For the sentinel at the end of the mode changes array. */ | |
81 MODE_DONE, | |
82 | |
83 /* The typical case. */ | |
84 MODE_ORDINARY_CHANGE, | |
85 | |
86 /* In addition to the typical case, affect the execute bits if at | |
87 least one execute bit is set already, or if the file is a | |
88 directory. */ | |
89 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
|
90 |
5813 | 91 /* Instead of the typical case, copy some existing permissions for |
92 u, g, or o onto the other two. Which of u, g, or o is copied | |
93 is determined by which bits are set in the `value' field. */ | |
94 MODE_COPY_EXISTING | |
95 }; | |
1818
b2644b45e17f
(make_node_op_equals, mode_compile, mode_create_from_ref, mode_adjust):
Jim Meyering <jim@meyering.net>
parents:
1769
diff
changeset
|
96 |
5813 | 97 /* Description of a mode change. */ |
98 struct mode_change | |
99 { | |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
100 char op; /* One of "=+-". */ |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
101 char flag; /* Special operations flag. */ |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
102 mode_t affected; /* Set for u, g, o, or a. */ |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
103 mode_t value; /* Bits to add/remove. */ |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
104 mode_t mentioned; /* Bits explicitly mentioned. */ |
5813 | 105 }; |
5 | 106 |
5813 | 107 /* Return a mode_change array with the specified `=ddd'-style |
6969 | 108 mode change operation, where NEW_MODE is `ddd' and MENTIONED |
109 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
|
110 |
bc0ac225f0a8
(make_node_op_equals): New function.
Jim Meyering <jim@meyering.net>
parents:
1760
diff
changeset
|
111 static struct mode_change * |
6969 | 112 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
|
113 { |
5813 | 114 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
|
115 p->op = '='; |
5813 | 116 p->flag = MODE_ORDINARY_CHANGE; |
117 p->affected = CHMOD_MODE_BITS; | |
1769
bc0ac225f0a8
(make_node_op_equals): New function.
Jim Meyering <jim@meyering.net>
parents:
1760
diff
changeset
|
118 p->value = new_mode; |
6969 | 119 p->mentioned = mentioned; |
5813 | 120 p[1].flag = MODE_DONE; |
1769
bc0ac225f0a8
(make_node_op_equals): New function.
Jim Meyering <jim@meyering.net>
parents:
1760
diff
changeset
|
121 return p; |
bc0ac225f0a8
(make_node_op_equals): New function.
Jim Meyering <jim@meyering.net>
parents:
1760
diff
changeset
|
122 } |
bc0ac225f0a8
(make_node_op_equals): New function.
Jim Meyering <jim@meyering.net>
parents:
1760
diff
changeset
|
123 |
5813 | 124 /* Return a pointer to an array of file mode change operations created from |
5 | 125 MODE_STRING, an ASCII string that contains either an octal number |
126 specifying an absolute mode, or symbolic mode change operations with | |
127 the form: | |
128 [ugoa...][[+-=][rwxXstugo...]...][,...] | |
129 | |
5813 | 130 Return NULL if `mode_string' does not contain a valid |
131 representation of file mode change operations. */ | |
5 | 132 |
133 struct mode_change * | |
5813 | 134 mode_compile (char const *mode_string) |
5 | 135 { |
5813 | 136 /* The array of mode-change directives to be returned. */ |
137 struct mode_change *mc; | |
138 size_t used = 0; | |
1769
bc0ac225f0a8
(make_node_op_equals): New function.
Jim Meyering <jim@meyering.net>
parents:
1760
diff
changeset
|
139 |
5813 | 140 if ('0' <= *mode_string && *mode_string < '8') |
141 { | |
6969 | 142 unsigned int octal_mode = 0; |
7056
db9b9e26e735
* modechange.c (mode_compile): Numeric modes now affect setuid and
Paul Eggert <eggert@cs.ucla.edu>
parents:
6969
diff
changeset
|
143 mode_t mode; |
db9b9e26e735
* modechange.c (mode_compile): Numeric modes now affect setuid and
Paul Eggert <eggert@cs.ucla.edu>
parents:
6969
diff
changeset
|
144 mode_t mentioned; |
5 | 145 |
5813 | 146 do |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
147 { |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
148 octal_mode = 8 * octal_mode + *mode_string++ - '0'; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
149 if (ALLM < octal_mode) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
150 return NULL; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
151 } |
5813 | 152 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
|
153 |
6527 | 154 if (*mode_string) |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
155 return NULL; |
6527 | 156 |
7056
db9b9e26e735
* modechange.c (mode_compile): Numeric modes now affect setuid and
Paul Eggert <eggert@cs.ucla.edu>
parents:
6969
diff
changeset
|
157 mode = octal_to_mode (octal_mode); |
db9b9e26e735
* modechange.c (mode_compile): Numeric modes now affect setuid and
Paul Eggert <eggert@cs.ucla.edu>
parents:
6969
diff
changeset
|
158 mentioned = (mode & (S_ISUID | S_ISGID)) | S_ISVTX | S_IRWXUGO; |
db9b9e26e735
* modechange.c (mode_compile): Numeric modes now affect setuid and
Paul Eggert <eggert@cs.ucla.edu>
parents:
6969
diff
changeset
|
159 return make_node_op_equals (mode, mentioned); |
5 | 160 } |
161 | |
5813 | 162 /* Allocate enough space to hold the result. */ |
163 { | |
164 size_t needed = 1; | |
165 char const *p; | |
166 for (p = mode_string; *p; p++) | |
167 needed += (*p == '=' || *p == '+' || *p == '-'); | |
168 mc = xnmalloc (needed, sizeof *mc); | |
169 } | |
5 | 170 |
5813 | 171 /* 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
|
172 for (;; mode_string++) |
5 | 173 { |
5813 | 174 /* Which bits in the mode are operated on. */ |
175 mode_t affected = 0; | |
1769
bc0ac225f0a8
(make_node_op_equals): New function.
Jim Meyering <jim@meyering.net>
parents:
1760
diff
changeset
|
176 |
5813 | 177 /* 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
|
178 for (;; mode_string++) |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
179 switch (*mode_string) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
180 { |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
181 default: |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
182 goto invalid; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
183 case 'u': |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
184 affected |= S_ISUID | S_IRWXU; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
185 break; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
186 case 'g': |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
187 affected |= S_ISGID | S_IRWXG; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
188 break; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
189 case 'o': |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
190 affected |= S_ISVTX | S_IRWXO; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
191 break; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
192 case 'a': |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
193 affected |= CHMOD_MODE_BITS; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
194 break; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
195 case '=': case '+': case '-': |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
196 goto no_more_affected; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
197 } |
5813 | 198 no_more_affected:; |
5 | 199 |
5813 | 200 do |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
201 { |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
202 char op = *mode_string++; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
203 mode_t value; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
204 char flag = MODE_COPY_EXISTING; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
205 struct mode_change *change; |
5 | 206 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
207 switch (*mode_string++) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
208 { |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
209 case 'u': |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
210 /* Set the affected bits to the value of the `u' bits |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
211 on the same file. */ |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
212 value = S_IRWXU; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
213 break; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
214 case 'g': |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
215 /* Set the affected bits to the value of the `g' bits |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
216 on the same file. */ |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
217 value = S_IRWXG; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
218 break; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
219 case 'o': |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
220 /* Set the affected bits to the value of the `o' bits |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
221 on the same file. */ |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
222 value = S_IRWXO; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
223 break; |
5 | 224 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
225 default: |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
226 value = 0; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
227 flag = MODE_ORDINARY_CHANGE; |
1769
bc0ac225f0a8
(make_node_op_equals): New function.
Jim Meyering <jim@meyering.net>
parents:
1760
diff
changeset
|
228 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
229 for (mode_string--;; mode_string++) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
230 switch (*mode_string) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
231 { |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
232 case 'r': |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
233 value |= S_IRUSR | S_IRGRP | S_IROTH; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
234 break; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
235 case 'w': |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
236 value |= S_IWUSR | S_IWGRP | S_IWOTH; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
237 break; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
238 case 'x': |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
239 value |= S_IXUSR | S_IXGRP | S_IXOTH; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
240 break; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
241 case 'X': |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
242 flag = MODE_X_IF_ANY_X; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
243 break; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
244 case 's': |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
245 /* Set the setuid/gid bits if `u' or `g' is selected. */ |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
246 value |= S_ISUID | S_ISGID; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
247 break; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
248 case 't': |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
249 /* Set the "save text image" bit if `o' is selected. */ |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
250 value |= S_ISVTX; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
251 break; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
252 default: |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
253 goto no_more_values; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
254 } |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
255 no_more_values:; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
256 } |
1769
bc0ac225f0a8
(make_node_op_equals): New function.
Jim Meyering <jim@meyering.net>
parents:
1760
diff
changeset
|
257 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
258 change = &mc[used++]; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
259 change->op = op; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
260 change->flag = flag; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
261 change->affected = affected; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
262 change->value = value; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
263 change->mentioned = (affected ? affected & value : value); |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
264 } |
5813 | 265 while (*mode_string == '=' || *mode_string == '+' |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
266 || *mode_string == '-'); |
5304
707482f5c106
(mode_compile): Don't decrement a pointer that
Paul Eggert <eggert@cs.ucla.edu>
parents:
5159
diff
changeset
|
267 |
707482f5c106
(mode_compile): Don't decrement a pointer that
Paul Eggert <eggert@cs.ucla.edu>
parents:
5159
diff
changeset
|
268 if (*mode_string != ',') |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
269 break; |
5304
707482f5c106
(mode_compile): Don't decrement a pointer that
Paul Eggert <eggert@cs.ucla.edu>
parents:
5159
diff
changeset
|
270 } |
707482f5c106
(mode_compile): Don't decrement a pointer that
Paul Eggert <eggert@cs.ucla.edu>
parents:
5159
diff
changeset
|
271 |
5 | 272 if (*mode_string == 0) |
5813 | 273 { |
274 mc[used].flag = MODE_DONE; | |
275 return mc; | |
276 } | |
277 | |
5 | 278 invalid: |
5813 | 279 free (mc); |
280 return NULL; | |
5 | 281 } |
282 | |
989
c68ed1182a64
(mode_create_from_ref): Don't use umask.
Jim Meyering <jim@meyering.net>
parents:
972
diff
changeset
|
283 /* Return a file mode change operation that sets permissions to match those |
5813 | 284 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
|
285 |
b30f9ff1e92e
(mode_create_from_ref): New function.
Jim Meyering <jim@meyering.net>
parents:
761
diff
changeset
|
286 struct mode_change * |
1494 | 287 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
|
288 { |
b30f9ff1e92e
(mode_create_from_ref): New function.
Jim Meyering <jim@meyering.net>
parents:
761
diff
changeset
|
289 struct stat ref_stats; |
b30f9ff1e92e
(mode_create_from_ref): New function.
Jim Meyering <jim@meyering.net>
parents:
761
diff
changeset
|
290 |
5813 | 291 if (stat (ref_file, &ref_stats) != 0) |
292 return NULL; | |
6969 | 293 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
|
294 } |
b30f9ff1e92e
(mode_create_from_ref): New function.
Jim Meyering <jim@meyering.net>
parents:
761
diff
changeset
|
295 |
6969 | 296 /* Return the file mode bits of OLDMODE (which is the mode of a |
297 directory if DIR), assuming the umask is UMASK_VALUE, adjusted as | |
298 indicated by the list of change operations CHANGES. If DIR, the | |
299 type 'X' change affects the returned value even if no execute bits | |
7056
db9b9e26e735
* modechange.c (mode_compile): Numeric modes now affect setuid and
Paul Eggert <eggert@cs.ucla.edu>
parents:
6969
diff
changeset
|
300 were set in OLDMODE, and set user and group ID bits are preserved |
db9b9e26e735
* modechange.c (mode_compile): Numeric modes now affect setuid and
Paul Eggert <eggert@cs.ucla.edu>
parents:
6969
diff
changeset
|
301 unless CHANGES mentioned them. If PMODE_BITS is not null, store into |
6969 | 302 *PMODE_BITS a mask denoting file mode bits that are affected by |
303 CHANGES. | |
304 | |
305 The returned value and *PMODE_BITS contain only file mode bits. | |
306 For example, they have the S_IFMT bits cleared on a standard | |
307 Unix-like host. */ | |
5 | 308 |
1818
b2644b45e17f
(make_node_op_equals, mode_compile, mode_create_from_ref, mode_adjust):
Jim Meyering <jim@meyering.net>
parents:
1769
diff
changeset
|
309 mode_t |
6969 | 310 mode_adjust (mode_t oldmode, bool dir, mode_t umask_value, |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
311 struct mode_change const *changes, mode_t *pmode_bits) |
5 | 312 { |
5813 | 313 /* The adjusted mode. */ |
314 mode_t newmode = oldmode & CHMOD_MODE_BITS; | |
5 | 315 |
6969 | 316 /* File mode bits that CHANGES cares about. */ |
317 mode_t mode_bits = 0; | |
318 | |
5813 | 319 for (; changes->flag != MODE_DONE; changes++) |
5 | 320 { |
5813 | 321 mode_t affected = changes->affected; |
6969 | 322 mode_t omit_change = |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
323 (dir ? S_ISUID | S_ISGID : 0) & ~ changes->mentioned; |
5813 | 324 mode_t value = changes->value; |
325 | |
326 switch (changes->flag) | |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
327 { |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
328 case MODE_ORDINARY_CHANGE: |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
329 break; |
5813 | 330 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
331 case MODE_COPY_EXISTING: |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
332 /* Isolate in `value' the bits in `newmode' to copy. */ |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
333 value &= newmode; |
5 | 334 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
335 /* Copy the isolated bits to the other two parts. */ |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
336 value |= ((value & (S_IRUSR | S_IRGRP | S_IROTH) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
337 ? S_IRUSR | S_IRGRP | S_IROTH : 0) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
338 | (value & (S_IWUSR | S_IWGRP | S_IWOTH) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
339 ? S_IWUSR | S_IWGRP | S_IWOTH : 0) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
340 | (value & (S_IXUSR | S_IXGRP | S_IXOTH) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
341 ? S_IXUSR | S_IXGRP | S_IXOTH : 0)); |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
342 break; |
5 | 343 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
344 case MODE_X_IF_ANY_X: |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
345 /* Affect the execute bits if execute bits are already set |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
346 or if the file is a directory. */ |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
347 if ((newmode & (S_IXUSR | S_IXGRP | S_IXOTH)) | dir) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
348 value |= S_IXUSR | S_IXGRP | S_IXOTH; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
349 break; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
350 } |
5813 | 351 |
352 /* If WHO was specified, limit the change to the affected bits. | |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
353 Otherwise, apply the umask. Either way, omit changes as |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
354 requested. */ |
6969 | 355 value &= (affected ? affected : ~umask_value) & ~ omit_change; |
5 | 356 |
357 switch (changes->op) | |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
358 { |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
359 case '=': |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
360 /* If WHO was specified, preserve the previous values of |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
361 bits that are not affected by this change operation. |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
362 Otherwise, clear all the bits. */ |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
363 { |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
364 mode_t preserved = (affected ? ~affected : 0) | omit_change; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
365 mode_bits |= CHMOD_MODE_BITS & ~preserved; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
366 newmode = (newmode & preserved) | value; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
367 break; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
368 } |
6969 | 369 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
370 case '+': |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
371 mode_bits |= value; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
372 newmode |= value; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
373 break; |
5813 | 374 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
375 case '-': |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
376 mode_bits |= value; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
377 newmode &= ~value; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
378 break; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
379 } |
5 | 380 } |
5813 | 381 |
6969 | 382 if (pmode_bits) |
383 *pmode_bits = mode_bits; | |
5 | 384 return newmode; |
385 } |