summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2005-05-01 14:26:50 +0000
committerPaul Eggert <eggert@cs.ucla.edu>2005-05-01 14:26:50 +0000
commitd4502755f4e738af6ff0a2e53176ab94d0c6c620 (patch)
tree6477a6cc85bdfd2fbdb9b33468490d9a8045e356 /lib
parent67a19c8e4272b60d248f29e0863211e59d7b556c (diff)
downloadcoreutils-d4502755f4e738af6ff0a2e53176ab94d0c6c620.tar.xz
(mode_free): Remove; all callers changed to invoke 'free'.
xstrtol.h, stdbool.h, stddef.h: Don't include; no longer needed. (MODE_DONE): New constant. (struct mode_change): Remove 'next' member. (make_node_op_equals): New function; like the old one of the same name, except it allocates an array. (mode_compile, mode_create_from_ref): Use it. (mode_compile): Allocate result as an array, not a linked list. Parse octal string ourself, so that we catch mistakes like "+0". (mode_adjust): Arg is an array, not a linked list.
Diffstat (limited to 'lib')
-rw-r--r--lib/modechange.c105
1 files changed, 51 insertions, 54 deletions
diff --git a/lib/modechange.c b/lib/modechange.c
index 8880ec09a..c7a2cb346 100644
--- a/lib/modechange.c
+++ b/lib/modechange.c
@@ -19,7 +19,7 @@
/* Written by David MacKenzie <djm@ai.mit.edu> */
-/* The ASCII mode string is compiled into a linked list of `struct
+/* The ASCII mode string is compiled into an array of `struct
modechange', which can then be applied to each file to be changed.
We do this instead of re-parsing the ASCII string for each file
because the compiled form requires less computation to use; when
@@ -34,9 +34,6 @@
#include <sys/stat.h>
#include "stat-macros.h"
#include "xalloc.h"
-#include "xstrtol.h"
-#include <stdbool.h>
-#include <stddef.h>
#include <stdlib.h>
/* The traditional octal values corresponding to each mode bit. */
@@ -57,6 +54,9 @@
/* Special operations flags. */
enum
{
+ /* For the sentinel at the end of the mode changes array. */
+ MODE_DONE,
+
/* The typical case. */
MODE_ORDINARY_CHANGE,
@@ -78,10 +78,24 @@ struct mode_change
char flag; /* Special operations flag. */
mode_t affected; /* Set for u, g, o, or a. */
mode_t value; /* Bits to add/remove. */
- struct mode_change *next; /* Link to next change in list. */
};
-/* Return a linked list of file mode change operations created from
+/* Return a mode_change array with the specified `=ddd'-style
+ mode change operation, where NEW_MODE is `ddd'. */
+
+static struct mode_change *
+make_node_op_equals (mode_t new_mode)
+{
+ struct mode_change *p = xmalloc (2 * sizeof *p);
+ p->op = '=';
+ p->flag = MODE_ORDINARY_CHANGE;
+ p->affected = CHMOD_MODE_BITS;
+ p->value = new_mode;
+ p[1].flag = MODE_DONE;
+ return p;
+}
+
+/* Return a pointer to an array 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
the form:
@@ -93,15 +107,22 @@ struct mode_change
struct mode_change *
mode_compile (char const *mode_string)
{
- struct mode_change *head; /* First element of the linked list. */
- struct mode_change **tail = &head; /* Pointer to list end. */
- unsigned long octal_value; /* The mode value, if octal. */
+ /* The array of mode-change directives to be returned. */
+ struct mode_change *mc;
+ size_t used = 0;
- if (xstrtoul (mode_string, NULL, 8, &octal_value, "") == LONGINT_OK)
+ if ('0' <= *mode_string && *mode_string < '8')
{
mode_t mode;
- if (octal_value != (octal_value & ALLM))
- return NULL;
+ unsigned int octal_value = 0;
+
+ do
+ {
+ octal_value = 8 * octal_value + *mode_string++ - '0';
+ if (ALLM < octal_value)
+ return NULL;
+ }
+ while ('0' <= *mode_string && *mode_string < '8');
/* Help the compiler optimize the usual case where mode_t uses
the traditional octal representation. */
@@ -123,15 +144,18 @@ mode_compile (char const *mode_string)
| (octal_value & WOTH ? S_IWOTH : 0)
| (octal_value & XOTH ? S_IXOTH : 0)));
- head = xmalloc (sizeof *head);
- head->op = '=';
- head->flag = MODE_ORDINARY_CHANGE;
- head->affected = CHMOD_MODE_BITS;
- head->value = mode;
- head->next = NULL;
- return head;
+ return make_node_op_equals (mode);
}
+ /* Allocate enough space to hold the result. */
+ {
+ size_t needed = 1;
+ char const *p;
+ for (p = mode_string; *p; p++)
+ needed += (*p == '=' || *p == '+' || *p == '-');
+ mc = xnmalloc (needed, sizeof *mc);
+ }
+
/* One loop iteration for each `[ugoa]*([-+=]([rwxXst]*|[ugo]))+'. */
for (;; mode_string++)
{
@@ -142,6 +166,8 @@ mode_compile (char const *mode_string)
for (;; mode_string++)
switch (*mode_string)
{
+ default:
+ goto invalid;
case 'u':
affected |= S_ISUID | S_IRWXU;
break;
@@ -156,8 +182,6 @@ mode_compile (char const *mode_string)
break;
case '=': case '+': case '-':
goto no_more_affected;
- default:
- goto invalid;
}
no_more_affected:;
@@ -219,14 +243,11 @@ mode_compile (char const *mode_string)
no_more_values:;
}
- change = xmalloc (sizeof *change);
+ change = &mc[used++];
change->op = op;
change->flag = flag;
change->affected = affected;
change->value = value;
-
- *tail = change;
- tail = &change->next;
}
while (*mode_string == '=' || *mode_string == '+'
|| *mode_string == '-');
@@ -237,13 +258,12 @@ mode_compile (char const *mode_string)
if (*mode_string == 0)
{
- *tail = NULL;
- return head;
+ mc[used].flag = MODE_DONE;
+ return mc;
}
invalid:
- *tail = NULL;
- mode_free (head);
+ free (mc);
return NULL;
}
@@ -253,20 +273,11 @@ invalid:
struct mode_change *
mode_create_from_ref (const char *ref_file)
{
- struct mode_change *change; /* the only change element */
struct stat ref_stats;
if (stat (ref_file, &ref_stats) != 0)
return NULL;
-
- change = xmalloc (sizeof *change);
- change->op = '=';
- change->flag = MODE_ORDINARY_CHANGE;
- change->affected = CHMOD_MODE_BITS;
- change->value = ref_stats.st_mode;
- change->next = NULL;
-
- return change;
+ return make_node_op_equals (ref_stats.st_mode);
}
/* Return file mode OLDMODE, adjusted as indicated by the list of change
@@ -282,7 +293,7 @@ mode_adjust (mode_t oldmode, struct mode_change const *changes,
/* The adjusted mode. */
mode_t newmode = oldmode & CHMOD_MODE_BITS;
- for (; changes; changes = changes->next)
+ for (; changes->flag != MODE_DONE; changes++)
{
mode_t affected = changes->affected;
mode_t value = changes->value;
@@ -337,17 +348,3 @@ mode_adjust (mode_t oldmode, struct mode_change const *changes,
return newmode;
}
-
-/* Free the memory used by the list of file mode change operations
- CHANGES. */
-
-void
-mode_free (struct mode_change *changes)
-{
- while (changes)
- {
- struct mode_change *next = changes->next;
- free (changes);
- changes = next;
- }
-}