From cad5364599eb5062d59e0c397ed638ddd61a8d5d Mon Sep 17 00:00:00 2001 From: Manuel Novoa III Date: Wed, 19 Mar 2003 09:13:01 +0000 Subject: Major coreutils update. --- libbb/parse_mode.c | 215 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 129 insertions(+), 86 deletions(-) (limited to 'libbb/parse_mode.c') diff --git a/libbb/parse_mode.c b/libbb/parse_mode.c index ba34ea929..49573dfbb 100644 --- a/libbb/parse_mode.c +++ b/libbb/parse_mode.c @@ -1,134 +1,177 @@ /* vi: set sw=4 ts=4: */ /* - * Utility routines. + * parse_mode implementation for busybox * - * Copyright (C) many different people. If you wrote this, please - * acknowledge your work. + * Copyright (C) 2003 Manuel Novoa III * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * */ -#include +/* http://www.opengroup.org/onlinepubs/007904975/utilities/chmod.html */ + #include +#include +#include #include "libbb.h" +#define FILEMODEBITS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO) -/* This function parses the sort of string you might pass - * to chmod (i.e., [ugoa]{+|-|=}[rwxst] ) and returns the - * correct mode described by the string. */ -extern int parse_mode(const char *s, mode_t * theMode) +extern int bb_parse_mode(const char *s, mode_t *current_mode) { - static const mode_t group_set[] = { + 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_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO /* a */ + S_IRWXO /* o */ }; - static const mode_t mode_set[] = { + 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 */ }; - static const char group_chars[] = "ugoa"; - static const char mode_chars[] = "rwxst"; + static const char who_chars[] = "augo"; + static const char perm_chars[] = "rwxXst"; const char *p; - mode_t andMode = - S_ISVTX | S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO; - mode_t orMode = 0; - mode_t mode; - mode_t groups; - char type; - char c; + mode_t wholist; + mode_t permlist; + mode_t mask; + mode_t new_mode; + char op; + + assert(s); + + if (((unsigned int)(*s - '0')) < 8) { + unsigned long tmp; + char *e; - if (s==NULL) { - return (FALSE); + tmp = strtol(s, &e, 8); + if (*e || (tmp > 0xffffU)) { /* Check range and trailing chars. */ + return 0; + } + *current_mode = tmp; + return 1; } - do { - mode = 0; - groups = 0; - NEXT_GROUP: - if ((c = *s++) == '\0') { - return -1; + mask = umask(0); + umask(mask); + + new_mode = *current_mode; + + /* 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. */ + ++s; + continue; } - for (p=group_chars ; *p ; p++) { - if (*p == c) { - groups |= group_set[(int)(p-group_chars)]; - goto NEXT_GROUP; + + /* Get a wholist. */ + wholist = 0; + + WHO_LIST: + p = who_chars; + do { + if (*p == *s) { + wholist |= who_mask[(int)(p-who_chars)]; + if (!*++s) { + return 0; + } + goto WHO_LIST; } - } - switch (c) { - case '=': - case '+': - case '-': - type = c; - if (groups == 0) { /* The default is "all" */ - groups |= S_ISUID | S_ISGID | S_ISVTX - | S_IRWXU | S_IRWXG | S_IRWXO; + } while (*++p); + + do { /* Process action list. */ + if ((*s != '+') && (*s != '-')) { + if (*s != '=') { + return 0; } - break; - default: - if ((c < '0') || (c > '7') || (mode | groups)) { - return (FALSE); - } else { - *theMode = strtol(--s, NULL, 8); - return (TRUE); + /* Since op is '=', clear all bits corresponding to the + * wholist, of all file bits if wholist is empty. */ + permlist = ~FILEMODEBITS; + if (wholist) { + permlist = ~wholist; } - } + new_mode &= permlist; + } + op = *s++; + + /* Check for permcopy. */ + p = who_chars + 1; /* Skip 'a' entry. */ + do { + if (*p == *s) { + int i = 0; + permlist = who_mask[(int)(p-who_chars)] + & (S_IRWXU | S_IRWXG | S_IRWXO) + & new_mode; + do { + if (permlist & perm_mask[i]) { + permlist |= perm_mask[i]; + } + } while (++i < 3); + ++s; + goto GOT_ACTION; + } + } while (*++p); - NEXT_MODE: - if (((c = *s++) != '\0') && (c != ',')) { - for (p=mode_chars ; *p ; p++) { - if (*p == c) { - mode |= mode_set[(int)(p-mode_chars)]; - goto NEXT_MODE; + /* It was not a permcopy, so get a permlist. */ + permlist = 0; + + PERM_LIST: + p = perm_chars; + do { + if (*p == *s) { + if ((*p != 'X') + || (new_mode & (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH)) + ) { + permlist |= perm_mask[(int)(p-perm_chars)]; + } + if (!*++s) { + break; + } + goto PERM_LIST; + } + } while (*++p); + + GOT_ACTION: + if (permlist) { /* The permlist was nonempty. */ + mode_t tmp = ~mask; + if (wholist) { + tmp = wholist; + } + permlist &= tmp; + + if (op == '-') { + new_mode &= ~permlist; + } else { + new_mode |= permlist; } } - break; /* We're done so break out of loop.*/ - } - switch (type) { - case '=': - andMode &= ~(groups); /* Now fall through. */ - case '+': - orMode |= mode & groups; - break; - case '-': - andMode &= ~(mode & groups); - orMode &= ~(mode & groups); - break; - } - } while (c == ','); + } while (*s && (*s != ',')); + } - *theMode &= andMode; - *theMode |= orMode; + *current_mode = new_mode; - return TRUE; + return 1; } - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ -- cgit v1.2.3