- affected_bits = 0;
- ops_to_mask = 0;
- /* Turn on all the bits in `affected_bits' for each group given. */
- for (++mode_string;; ++mode_string)
- switch (*mode_string)
- {
- case 'u':
- affected_bits |= 04700;
- break;
- case 'g':
- affected_bits |= 02070;
- break;
- case 'o':
- affected_bits |= 01007;
- break;
- case 'a':
- affected_bits |= 07777;
- break;
- default:
- goto no_more_affected;
- }
-
- no_more_affected:
- /* If none specified, affect all bits, except perhaps those
- set in the umask. */
- if (affected_bits == 0)
- {
- affected_bits = 07777;
- ops_to_mask = masked_ops;
- }
-
- while (*mode_string == '=' || *mode_string == '+' || *mode_string == '-')
- {
- /* Add the element to the tail of the list, so the operations
- are performed in the correct order. */
- if (head == NULL)
- {
- head = talloc (struct mode_change);
- if (head == NULL)
- return MODE_MEMORY_EXHAUSTED;
- change = head;
- }
- else
- {
- change->next = talloc (struct mode_change);
- if (change->next == NULL)
- {
- mode_free (change);
- return MODE_MEMORY_EXHAUSTED;
- }
- change = change->next;
- }
-
- change->next = NULL;
- change->op = *mode_string; /* One of "=+-". */
- affected_masked = affected_bits;
- if (ops_to_mask & (*mode_string == '=' ? MODE_MASK_EQUALS
- : *mode_string == '+' ? MODE_MASK_PLUS
- : MODE_MASK_MINUS))
- affected_masked &= ~umask_value;
- change->affected = affected_masked;
- change->value = 0;
- change->flags = 0;
-
- /* Set `value' according to the bits set in `affected_masked'. */
- for (++mode_string;; ++mode_string)
- switch (*mode_string)
- {
- case 'r':
- change->value |= 00444 & affected_masked;
- break;
- case 'w':
- change->value |= 00222 & affected_masked;
- break;
- case 'X':
- change->flags |= MODE_X_IF_ANY_X;
- /* Fall through. */
- case 'x':
- change->value |= 00111 & affected_masked;
- break;
- case 's':
- /* Set the setuid/gid bits if `u' or `g' is selected. */
- change->value |= 06000 & affected_masked;
- break;
- case 't':
- /* Set the "save text image" bit if `o' is selected. */
- change->value |= 01000 & affected_masked;
- break;
- case 'u':
- /* Set the affected bits to the value of the `u' bits
- on the same file. */
- if (change->value)
- goto invalid;
- change->value = 00700;
- change->flags |= MODE_COPY_EXISTING;
- break;
- case 'g':
- /* Set the affected bits to the value of the `g' bits
- on the same file. */
- if (change->value)
- goto invalid;
- change->value = 00070;
- change->flags |= MODE_COPY_EXISTING;
- break;
- case 'o':
- /* Set the affected bits to the value of the `o' bits
- on the same file. */
- if (change->value)
- goto invalid;
- change->value = 00007;
- change->flags |= MODE_COPY_EXISTING;
- break;
- default:
- goto no_more_values;
- }
- no_more_values:;
- }
- } while (*mode_string == ',');
- if (*mode_string == 0)
- return head;