Start 1.33.0 development cycle
[oweals/busybox.git] / libbb / parse_mode.c
index 356d95db6f5505afc3d5de2f995883e5d98c4a70..dc65860f6924cfe3d7e80b050f40c6f1be02cfaa 100644 (file)
@@ -4,98 +4,84 @@
  *
  * Copyright (C) 2003  Manuel Novoa III  <mjn3@codepoet.org>
  *
- * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  */
+#include "libbb.h"
 
 /* http://www.opengroup.org/onlinepubs/007904975/utilities/chmod.html */
 
-#include <stdlib.h>
-#include <assert.h>
-#include <sys/stat.h>
-#include "libbb.h"
+/* This function is used from NOFORK applets. It must not allocate anything */
 
-#define FILEMODEBITS    (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
+#define FILEMODEBITS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
 
-int bb_parse_mode(const char *s, mode_t *current_mode)
+int FAST_FUNC bb_parse_mode(const char *s, unsigned current_mode)
 {
        static const mode_t who_mask[] = {
                S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO, /* a */
-               S_ISUID | S_IRWXU,              /* u */
-               S_ISGID | S_IRWXG,              /* g */
-               S_IRWXO                                 /* o */
+               S_ISUID | S_IRWXU,           /* u */
+               S_ISGID | S_IRWXG,           /* g */
+               S_IRWXO                      /* o */
        };
-
        static const mode_t perm_mask[] = {
                S_IRUSR | S_IRGRP | S_IROTH, /* r */
                S_IWUSR | S_IWGRP | S_IWOTH, /* w */
                S_IXUSR | S_IXGRP | S_IXOTH, /* x */
                S_IXUSR | S_IXGRP | S_IXOTH, /* X -- special -- see below */
-               S_ISUID | S_ISGID,              /* s */
-               S_ISVTX                                 /* t */
+               S_ISUID | S_ISGID,           /* s */
+               S_ISVTX                      /* t */
        };
-
-       static const char who_chars[] = "augo";
-       static const char perm_chars[] = "rwxXst";
+       static const char who_chars[] ALIGN1 = "augo";
+       static const char perm_chars[] ALIGN1 = "rwxXst";
 
        const char *p;
-
        mode_t wholist;
        mode_t permlist;
-       mode_t mask;
        mode_t new_mode;
        char op;
 
-       assert(s);
-
-       if (((unsigned int)(*s - '0')) < 8) {
+       if ((unsigned char)(*s - '0') < 8) {
                unsigned long tmp;
                char *e;
 
-               tmp = strtol(s, &e, 8);
+               tmp = strtoul(s, &e, 8);
                if (*e || (tmp > 07777U)) { /* Check range and trailing chars. */
-                       return 0;
+                       return -1;
                }
-               *current_mode = tmp;
-               return 1;
+               return tmp;
        }
 
-       mask = umask(0);
-       umask(mask);
-
-       new_mode = *current_mode;
+       new_mode = current_mode;
 
-       /* Note: We allow empty clauses, and hence empty modes.
+       /* Note: we allow empty clauses, and hence empty modes.
         * We treat an empty mode as no change to perms. */
 
-       while (*s) {    /* Process clauses. */
-
-               if (*s == ',') {        /* We allow empty clauses. */
+       while (*s) {  /* Process clauses. */
+               if (*s == ',') {  /* We allow empty clauses. */
                        ++s;
                        continue;
                }
 
                /* Get a wholist. */
                wholist = 0;
-
-       WHO_LIST:
+ WHO_LIST:
                p = who_chars;
                do {
                        if (*p == *s) {
                                wholist |= who_mask[(int)(p-who_chars)];
                                if (!*++s) {
-                                       return 0;
+                                       return -1;
                                }
                                goto WHO_LIST;
                        }
                } while (*++p);
 
-               do {    /* Process action list. */
+               do {    /* Process action list. */
                        if ((*s != '+') && (*s != '-')) {
                                if (*s != '=') {
-                                       return 0;
+                                       return -1;
                                }
                                /* Since op is '=', clear all bits corresponding to the
-                                * wholist, of all file bits if wholist is empty. */
+                                * wholist, or all file bits if wholist is empty. */
                                permlist = ~FILEMODEBITS;
                                if (wholist) {
                                        permlist = ~wholist;
@@ -105,7 +91,7 @@ int bb_parse_mode(const char *s, mode_t *current_mode)
                        op = *s++;
 
                        /* Check for permcopy. */
-                       p = who_chars + 1;      /* Skip 'a' entry. */
+                       p = who_chars + 1;  /* Skip 'a' entry. */
                        do {
                                if (*p == *s) {
                                        int i = 0;
@@ -124,13 +110,12 @@ int bb_parse_mode(const char *s, mode_t *current_mode)
 
                        /* It was not a permcopy, so get a permlist. */
                        permlist = 0;
-
-               PERM_LIST:
+ PERM_LIST:
                        p = perm_chars;
                        do {
                                if (*p == *s) {
                                        if ((*p != 'X')
-                                               || (new_mode & (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH))
+                                        || (new_mode & (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH))
                                        ) {
                                                permlist |= perm_mask[(int)(p-perm_chars)];
                                        }
@@ -140,15 +125,15 @@ int bb_parse_mode(const char *s, mode_t *current_mode)
                                        goto PERM_LIST;
                                }
                        } while (*++p);
-
-               GOT_ACTION:
-                       if (permlist) { /* The permlist was nonempty. */
-                               mode_t tmp = ~mask;
-                               if (wholist) {
-                                       tmp = wholist;
+ GOT_ACTION:
+                       if (permlist) { /* The permlist was nonempty. */
+                               mode_t tmp = wholist;
+                               if (!wholist) {
+                                       mode_t u_mask = umask(0);
+                                       umask(u_mask);
+                                       tmp = ~u_mask;
                                }
                                permlist &= tmp;
-
                                if (op == '-') {
                                        new_mode &= ~permlist;
                                } else {
@@ -158,7 +143,5 @@ int bb_parse_mode(const char *s, mode_t *current_mode)
                } while (*s && (*s != ','));
        }
 
-       *current_mode = new_mode;
-
-       return 1;
+       return new_mode;
 }