- {
- char op = *mode_string++;
- mode_t value;
- char flag = MODE_COPY_EXISTING;
- struct mode_change *change;
-
- switch (*mode_string++)
- {
- case 'u':
- /* Set the affected bits to the value of the `u' bits
- on the same file. */
- value = S_IRWXU;
- break;
- case 'g':
- /* Set the affected bits to the value of the `g' bits
- on the same file. */
- value = S_IRWXG;
- break;
- case 'o':
- /* Set the affected bits to the value of the `o' bits
- on the same file. */
- value = S_IRWXO;
- break;
-
- default:
- value = 0;
- flag = MODE_ORDINARY_CHANGE;
-
- for (mode_string--;; mode_string++)
- switch (*mode_string)
- {
- case 'r':
- value |= S_IRUSR | S_IRGRP | S_IROTH;
- break;
- case 'w':
- value |= S_IWUSR | S_IWGRP | S_IWOTH;
- break;
- case 'x':
- value |= S_IXUSR | S_IXGRP | S_IXOTH;
- break;
- case 'X':
- flag = MODE_X_IF_ANY_X;
- break;
- case 's':
- /* Set the setuid/gid bits if `u' or `g' is selected. */
- value |= S_ISUID | S_ISGID;
- break;
- case 't':
- /* Set the "save text image" bit if `o' is selected. */
- value |= S_ISVTX;
- break;
- default:
- goto no_more_values;
- }
- no_more_values:;
- }
-
- change = &mc[used++];
- change->op = op;
- change->flag = flag;
- change->affected = affected;
- change->value = value;
- change->mentioned = (affected ? affected & value : value);
- }
- while (*mode_string == '=' || *mode_string == '+'
- || *mode_string == '-');
-
- if (*mode_string != ',')
- break;
+ {
+ char op = *p++;
+ mode_t value;
+ mode_t mentioned = 0;
+ char flag = MODE_COPY_EXISTING;
+ struct mode_change *change;
+
+ switch (*p)
+ {
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ {
+ unsigned int octal_mode = 0;
+
+ do
+ {
+ octal_mode = 8 * octal_mode + *p++ - '0';
+ if (ALLM < octal_mode)
+ return NULL;
+ }
+ while ('0' <= *p && *p < '8');
+
+ if (affected || (*p && *p != ','))
+ return NULL;
+ affected = mentioned = CHMOD_MODE_BITS;
+ value = octal_to_mode (octal_mode);
+ flag = MODE_ORDINARY_CHANGE;
+ break;
+ }
+
+ case 'u':
+ /* Set the affected bits to the value of the "u" bits
+ on the same file. */
+ value = S_IRWXU;
+ p++;
+ break;
+ case 'g':
+ /* Set the affected bits to the value of the "g" bits
+ on the same file. */
+ value = S_IRWXG;
+ p++;
+ break;
+ case 'o':
+ /* Set the affected bits to the value of the "o" bits
+ on the same file. */
+ value = S_IRWXO;
+ p++;
+ break;
+
+ default:
+ value = 0;
+ flag = MODE_ORDINARY_CHANGE;
+
+ for (;; p++)
+ switch (*p)
+ {
+ case 'r':
+ value |= S_IRUSR | S_IRGRP | S_IROTH;
+ break;
+ case 'w':
+ value |= S_IWUSR | S_IWGRP | S_IWOTH;
+ break;
+ case 'x':
+ value |= S_IXUSR | S_IXGRP | S_IXOTH;
+ break;
+ case 'X':
+ flag = MODE_X_IF_ANY_X;
+ break;
+ case 's':
+ /* Set the setuid/gid bits if 'u' or 'g' is selected. */
+ value |= S_ISUID | S_ISGID;
+ break;
+ case 't':
+ /* Set the "save text image" bit if 'o' is selected. */
+ value |= S_ISVTX;
+ break;
+ default:
+ goto no_more_values;
+ }
+ no_more_values:;
+ }
+
+ change = &mc[used++];
+ change->op = op;
+ change->flag = flag;
+ change->affected = affected;
+ change->value = value;
+ change->mentioned =
+ (mentioned ? mentioned : affected ? affected & value : value);
+ }
+ while (*p == '=' || *p == '+' || *p == '-');
+
+ if (*p != ',')
+ break;