diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2005-05-01 14:26:50 +0000 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2005-05-01 14:26:50 +0000 |
commit | d4502755f4e738af6ff0a2e53176ab94d0c6c620 (patch) | |
tree | 6477a6cc85bdfd2fbdb9b33468490d9a8045e356 /lib | |
parent | 67a19c8e4272b60d248f29e0863211e59d7b556c (diff) | |
download | coreutils-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.c | 105 |
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; - } -} |