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 use a state machine to walk through the
26 struct chmod_mode_struct *parse_chmod(char *modestr)
28 int state = STATE_1ST_HALF;
29 int where = 0, what = 0, op = 0, topbits = 0, topoct = 0, flags = 0;
30 struct chmod_mode_struct *first_mode = NULL, *curr_mode = NULL,
33 while (state != STATE_ERROR) {
34 if (!*modestr || *modestr == ',') {
41 prev_mode = curr_mode;
42 curr_mode = new_array(struct chmod_mode_struct, 1);
44 prev_mode->next = curr_mode;
46 first_mode = curr_mode;
47 curr_mode->next = NULL;
53 bits = (where * what) & ~orig_umask;
58 curr_mode->ModeAND = 07777;
59 curr_mode->ModeOR = bits + topoct;
62 curr_mode->ModeAND = 07777 - bits - topoct;
63 curr_mode->ModeOR = 0;
66 curr_mode->ModeAND = 07777 - (where * 7) - (topoct ? topbits : 0);
67 curr_mode->ModeOR = bits + topoct;
71 curr_mode->flags = flags;
77 state = STATE_1ST_HALF;
78 where = what = op = topoct = topbits = flags = 0;
81 if (state != STATE_2ND_HALF) {
84 if (flags & FLAG_FILES_ONLY)
86 flags |= FLAG_DIRS_ONLY;
89 if (flags & FLAG_DIRS_ONLY)
91 flags |= FLAG_FILES_ONLY;
109 state = STATE_2ND_HALF;
113 state = STATE_2ND_HALF;
117 state = STATE_2ND_HALF;
132 flags |= FLAG_X_KEEP;
154 if (state == STATE_ERROR) {
155 free_chmod_mode(first_mode);
162 /* Takes an existing file permission and a list of AND/OR changes, and
163 * create a new permissions. */
164 int tweak_mode(int mode, struct chmod_mode_struct *chmod_modes)
166 int IsX = mode & 0111;
167 int NonPerm = mode & ~07777;
169 for ( ; chmod_modes; chmod_modes = chmod_modes->next) {
170 if ((chmod_modes->flags & FLAG_DIRS_ONLY) && !S_ISDIR(NonPerm))
172 if ((chmod_modes->flags & FLAG_FILES_ONLY) && S_ISDIR(NonPerm))
174 mode &= chmod_modes->ModeAND;
175 if ((chmod_modes->flags & FLAG_X_KEEP) && !IsX && !S_ISDIR(NonPerm))
176 mode |= chmod_modes->ModeOR & ~0111;
178 mode |= chmod_modes->ModeOR;
181 return mode | NonPerm;
184 /* Free the linked list created by parse_chmod. */
185 int free_chmod_mode(struct chmod_mode_struct *chmod_modes)
187 struct chmod_mode_struct *next;
189 while (chmod_modes) {
190 next = chmod_modes->next;