diff options
Diffstat (limited to 'lib/lib.c')
-rw-r--r-- | lib/lib.c | 163 |
1 files changed, 62 insertions, 101 deletions
@@ -916,113 +916,74 @@ char *num_to_sig(int sig) } -/* mode parsing */ - -mode_t apply_mode(int who, int how, int what, mode_t base) +mode_t string_to_mode(char *modestr, mode_t mode) { - mode_t new_mode = 0, tmp_mode = 0, tmp_mask = 0; - - if (!who) tmp_mask = 07777; - if (who & 0x01) { // u - if (what & 0x01) tmp_mode |= S_IXUSR; - if (what & 0x02) tmp_mode |= S_IWUSR; - if (what & 0x04) tmp_mode |= S_IRUSR; - if (what & 0x08) tmp_mode |= S_ISUID; - tmp_mask |= S_IRWXU; - } - if (who & 0x02) { // g - if (what & 0x01) tmp_mode |= S_IXGRP; - if (what & 0x02) tmp_mode |= S_IWUSR; - if (what & 0x04) tmp_mode |= S_IRUSR; - if (what & 0x08) tmp_mode |= S_ISGID; - tmp_mask |= S_IRWXG; - } - if (who & 0x04) { // o - if (what & 0x01) tmp_mode |= S_IXOTH; - if (what & 0x02) tmp_mode |= S_IWOTH; - if (what & 0x04) tmp_mode |= S_IROTH; - tmp_mask |= S_IRWXO; + char *whos = "ugoa", *hows = "=+-", *whats = "xwrstX", *whys = "ogu"; + char *s, *str = modestr; + + // Handle octal mode + if (isdigit(*str)) { + mode = strtol(str, &s, 8); + if (*s || (mode & ~(07777))) goto barf; + + return mode; } - /* check sticky */ - if (what & 0x10) tmp_mode |= S_ISVTX; - if (how == 1) new_mode = tmp_mode | (base & tmp_mask); - else if (how == 2) new_mode = base | tmp_mode; - else if (how == 3) new_mode = base & ~(tmp_mode); + // Gaze into the bin of permission... + for (;;) { + int i, j, dowho, dohow, dowhat; - return new_mode; -} + dowho = dohow = dowhat = 0; + // Find the who, how, and what stanzas, in that order + while ((s = strchr(whos, *str))) { + dowho |= 1<<(whos-s); + str++; + } + if (!dowho) dowho = 8; + if (!(s = strchr(hows, *str))) goto barf; + dohow = *(str++); + if (!dohow) goto barf; + while ((s = strchr(whats, *str))) { + dowhat |= 1<<(whats-s); + str++; + } -mode_t string_to_mode(char *mode_str, mode_t base) -{ - mode_t new_mode; - int what = 0; - int who = 0; - int how = 0; - char *p; - long tmp; - if (!mode_str) - return base; - if (isdigit(mode_str[0])) { - tmp = strtol(mode_str, &p, 8); - if (*p || tmp < 0 || (tmp & ~(07777))) return base; - new_mode = (mode_t) tmp; - return new_mode; - } - new_mode = base; - while (*mode_str) { - /* TODO: add support for permission copying */ - switch(*mode_str) { - case ',': - /* next command */ - new_mode = apply_mode(who, how, what, new_mode); - who = 0; - how = 0; - what = 0; - break; - case 'a': - who = 0x01 | 0x02 | 0x04; - break; - case 'u': - who |= 0x01; - break; - case 'g': - who |= 0x02; - break; - case 'o': - who |= 0x04; - break; - case 'r': - what |= 0x04; - break; - case 'w': - what |= 0x02; - break; - case 'x': - what |= 0x01; - break; - case 't': - what |= 0x10; - break; - case 's': - what |= 0x08; - break; - case '=': - how = 1; - break; - case '+': - how = 2; - break; - case '-': - how = 3; - break; - default: - /* error case */ - return base; + // Convert X to x for directory or if already executable somewhere + if ((dowhat&32) && (S_ISDIR(mode) || (mode&0111))) dowhat |= 1; + + // Copy mode from another category? + if (!dowhat && (s = strchr(whys, *str))) { + dowhat = (mode>>(3*(s-str)))&7; + str++; + } + + // Are we ready to do a thing yet? + if (*str && *(str++) != ',') goto barf; + + // Ok, apply the bits to the mode. + for (i=0; i<4; i++) { + for (j=0; j<3; j++) { + mode_t bit = 0; + + // Figure out new value at this location + if (i == 3) { + } else if (dowhat&(1<<j)) bit++; + + // When selection active, modify bit + if (dowho&(8|(1<<i))) { + int where = 1<<((3*i)+j); + + if (dohow == '=' || (bit && dohow == '-')) + mode &= ~where; + if (bit && dohow != '-') mode |= where; + } + } } - mode_str++; + + if (!*str) break; } - new_mode = apply_mode(who, how, what, new_mode); - return new_mode; + return mode; +barf: + error_exit("bad mode '%s'", modestr); } |