summaryrefslogtreecommitdiff
path: root/lib/modechange.c
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>1999-03-30 04:51:08 +0000
committerJim Meyering <jim@meyering.net>1999-03-30 04:51:08 +0000
commita717cdf2d6e84d9580885d4a26723d665efd9848 (patch)
treedc38229ca8b81b89bcba4fc7944734387124fd9d /lib/modechange.c
parentbb0631e82584ce48ab75dec4f3815652833b5257 (diff)
downloadcoreutils-a717cdf2d6e84d9580885d4a26723d665efd9848.tar.xz
(make_node_op_equals): New function.
(mode_append_entry): Likewise. (mode_compile): When none of [ugoa] is specified in an `=OP' change mode request, insert a `=0' entry into the linked list so that all bits are cleared first. Use the new functions.
Diffstat (limited to 'lib/modechange.c')
-rw-r--r--lib/modechange.c113
1 files changed, 79 insertions, 34 deletions
diff --git a/lib/modechange.c b/lib/modechange.c
index 057803124..cbb1bb905 100644
--- a/lib/modechange.c
+++ b/lib/modechange.c
@@ -72,6 +72,42 @@ oatoi (const char *s)
return i;
}
+/* Create a mode_change entry with the specified `=ddd'-style
+ mode change operation, where NEW_MODE is `ddd'. Return the
+ new entry, or NULL upon failure. */
+
+static struct mode_change *
+make_node_op_equals (int new_mode)
+{
+ struct mode_change *p;
+ p = talloc (struct mode_change);
+ if (p == NULL)
+ return p;
+ p->next = NULL;
+ p->op = '=';
+ p->flags = 0;
+ p->value = new_mode;
+ p->affected = 07777; /* Affect all permissions. */
+ return p;
+}
+
+/* Append entry E to the end of the link list with the specified
+ HEAD and TAIL. */
+
+static void
+mode_append_entry (struct mode_change **head,
+ struct mode_change **tail,
+ struct mode_change *e)
+{
+ if (*head == NULL)
+ *head = *tail = e;
+ else
+ {
+ (*tail)->next = e;
+ *tail = e;
+ }
+}
+
/* Return a linked list of file mode change operations created from
MODE_STRING, an ASCII string that contains either an octal number
specifying an absolute mode, or symbolic mode change operations with
@@ -89,41 +125,44 @@ struct mode_change *
mode_compile (const char *mode_string, unsigned int masked_ops)
{
struct mode_change *head; /* First element of the linked list. */
- struct mode_change *change; /* An element of the linked list. */
+ struct mode_change *tail; /* An element of the linked list. */
int i; /* General purpose temporary. */
int umask_value; /* The umask value (surprise). */
- unsigned short affected_bits; /* Which bits in the mode are operated on. */
- unsigned short affected_masked; /* `affected_bits' modified by umask. */
- unsigned ops_to_mask; /* Operators to actually use umask on. */
+
+ head = NULL;
+#ifdef lint
+ tail = NULL;
+#endif
i = oatoi (mode_string);
if (i >= 0)
{
+ struct mode_change *p;
if (i > 07777)
return MODE_INVALID;
- head = talloc (struct mode_change);
- if (head == NULL)
+ p = make_node_op_equals (i);
+ if (p == NULL)
return MODE_MEMORY_EXHAUSTED;
- head->next = NULL;
- head->op = '=';
- head->flags = 0;
- head->value = i;
- head->affected = 07777; /* Affect all permissions. */
+ mode_append_entry (&head, &tail, p);
return head;
}
umask_value = umask (0);
umask (umask_value); /* Restore the old value. */
-
- head = NULL;
-#ifdef lint
- change = NULL;
-#endif
--mode_string;
/* One loop iteration for each "ugoa...=+-rwxXstugo...[=+-rwxXstugo...]". */
do
{
+ /* Which bits in the mode are operated on. */
+ unsigned short affected_bits = 0;
+ /* `affected_bits' modified by umask. */
+ unsigned short affected_masked;
+ /* Operators to actually use umask on. */
+ unsigned ops_to_mask = 0;
+
+ int who_specified_p;
+
affected_bits = 0;
ops_to_mask = 0;
/* Turn on all the bits in `affected_bits' for each group given. */
@@ -149,37 +188,39 @@ mode_compile (const char *mode_string, unsigned int masked_ops)
no_more_affected:
/* If none specified, affect all bits, except perhaps those
set in the umask. */
- if (affected_bits == 0)
+ if (affected_bits)
+ who_specified_p = 1;
+ else
{
+ who_specified_p = 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
+ struct mode_change *change = talloc (struct mode_change);
+ if (change == NULL)
{
- change->next = talloc (struct mode_change);
- if (change->next == NULL)
- {
- mode_free (head);
- return MODE_MEMORY_EXHAUSTED;
- }
- change = change->next;
+ mode_free (head);
+ return MODE_MEMORY_EXHAUSTED;
}
change->next = NULL;
change->op = *mode_string; /* One of "=+-". */
affected_masked = affected_bits;
+
+ /* Per the Single Unix Spec, if `who' is not specified and the
+ `=' operator is used, then clear all the bits first. */
+ if (!who_specified_p &&
+ ops_to_mask & (*mode_string == '=' ? MODE_MASK_EQUALS : 0))
+ {
+ struct mode_change *p = make_node_op_equals (0);
+ if (p == NULL)
+ return MODE_MEMORY_EXHAUSTED;
+ mode_append_entry (&head, &tail, p);
+ }
+
if (ops_to_mask & (*mode_string == '=' ? MODE_MASK_EQUALS
: *mode_string == '+' ? MODE_MASK_PLUS
: MODE_MASK_MINUS))
@@ -188,6 +229,10 @@ mode_compile (const char *mode_string, unsigned int masked_ops)
change->value = 0;
change->flags = 0;
+ /* Add the element to the tail of the list, so the operations
+ are performed in the correct order. */
+ mode_append_entry (&head, &tail, change);
+
/* Set `value' according to the bits set in `affected_masked'. */
for (++mode_string;; ++mode_string)
switch (*mode_string)