3 extern mode_t orig_umask;
5 #define FLAG_X_KEEP (1<<0)
6 #define FLAG_DIRS_ONLY (1<<1)
7 #define FLAG_FILES_ONLY (1<<2)
9 struct chmod_mode_struct {
10 struct chmod_mode_struct *next;
20 #define STATE_1ST_HALF 1
21 #define STATE_2ND_HALF 2
23 /* Parse a chmod-style argument, and break it down into one or more AND/OR
24 * pairs in a linked list. We return a pointer to new items on succcess
25 * (appending the items to the specified list), or NULL on error. */
26 struct chmod_mode_struct *parse_chmod(const char *modestr,
27 struct chmod_mode_struct **root_mode_ptr)
29 int state = STATE_1ST_HALF;
30 int where = 0, what = 0, op = 0, topbits = 0, topoct = 0, flags = 0;
31 struct chmod_mode_struct *first_mode = NULL, *curr_mode = NULL,
34 while (state != STATE_ERROR) {
35 if (!*modestr || *modestr == ',') {
42 prev_mode = curr_mode;
43 curr_mode = new_array(struct chmod_mode_struct, 1);
45 prev_mode->next = curr_mode;
47 first_mode = curr_mode;
48 curr_mode->next = NULL;
54 bits = (where * what) & ~orig_umask;
59 curr_mode->ModeAND = CHMOD_BITS;
60 curr_mode->ModeOR = bits + topoct;
63 curr_mode->ModeAND = CHMOD_BITS - bits - topoct;
64 curr_mode->ModeOR = 0;
67 curr_mode->ModeAND = CHMOD_BITS - (where * 7) - (topoct ? topbits : 0);
68 curr_mode->ModeOR = bits + topoct;
72 curr_mode->flags = flags;
78 state = STATE_1ST_HALF;
79 where = what = op = topoct = topbits = flags = 0;
82 if (state != STATE_2ND_HALF) {
85 if (flags & FLAG_FILES_ONLY)
87 flags |= FLAG_DIRS_ONLY;
90 if (flags & FLAG_DIRS_ONLY)
92 flags |= FLAG_FILES_ONLY;
110 state = STATE_2ND_HALF;
114 state = STATE_2ND_HALF;
118 state = STATE_2ND_HALF;
133 flags |= FLAG_X_KEEP;
155 if (state == STATE_ERROR) {
156 free_chmod_mode(first_mode);
160 if (!(curr_mode = *root_mode_ptr))
161 *root_mode_ptr = first_mode;
163 while (curr_mode->next)
164 curr_mode = curr_mode->next;
165 curr_mode->next = first_mode;
172 /* Takes an existing file permission and a list of AND/OR changes, and
173 * create a new permissions. */
174 int tweak_mode(int mode, struct chmod_mode_struct *chmod_modes)
176 int IsX = mode & 0111;
177 int NonPerm = mode & ~CHMOD_BITS;
179 for ( ; chmod_modes; chmod_modes = chmod_modes->next) {
180 if ((chmod_modes->flags & FLAG_DIRS_ONLY) && !S_ISDIR(NonPerm))
182 if ((chmod_modes->flags & FLAG_FILES_ONLY) && S_ISDIR(NonPerm))
184 mode &= chmod_modes->ModeAND;
185 if ((chmod_modes->flags & FLAG_X_KEEP) && !IsX && !S_ISDIR(NonPerm))
186 mode |= chmod_modes->ModeOR & ~0111;
188 mode |= chmod_modes->ModeOR;
191 return mode | NonPerm;
194 /* Free the linked list created by parse_chmod. */
195 int free_chmod_mode(struct chmod_mode_struct *chmod_modes)
197 struct chmod_mode_struct *next;
199 while (chmod_modes) {
200 next = chmod_modes->next;