// util/mode.c, version 1.0.3 // Mode source file from libutil // Copyright (C) 2020, Jakob Wakeling // MIT Licence /* TODO Handle copying permissions */ #include "mode.h" #include #include #include static inline int getop(char **s); static inline mode_t getref(char **s); /* Parse an octal or symbolic mode string */ chmod_t *strmode(char *str) { char *s = str; chmod_t *m; mode_t mode = 0; size_t i; // Try and parse an octal mode for (register mode_t d; *s >= '0' && *s <= '7'; ++s) { d = *s - '0'; if (mode > (07777 - d) / 8) { break; } mode = mode * 8 + d; } if (!*s) { m = (chmod_t *)malloc(2 * sizeof (*m)); // Construct a chmod_t from the octal mode and return it m[0].flag = MF_NORM; m[1].flag = MF_NULL; m[0].op = '='; m[0].ref = M_ALL; m[0].mod = mode; return m; } // If the octal mode is invalid return NULL else if (s != str) { return NULL; } // Allocate necesary memory for chmod_t array for (i = 1; *s; ++s) { i += (*s == '+' || *s == '-' || *s == '='); } m = (chmod_t *)malloc((i + 1) * sizeof (*m)); s = str; m[i].flag = MF_NULL; i = 0; do { // Parse each part of the symbolic mode string for (mode_t ref = getref(&s); ((m[i].op = getop(&s))); ++i) { m[i].flag = MF_NORM; m[i].ref = ref; // Process the next mode for (m[i].mod = 0;;) switch (*s) { case 'r': { m[i].mod |= M_RD; ++s; continue; } case 'w': { m[i].mod |= M_WR; ++s; continue; } case 'x': { m[i].mod |= M_EX; ++s; continue; } case 'X': { m[i].flag = MF_XIFX; ++s; continue; } case 's': { m[i].mod |= M_ID; ++s; continue; } case 't': { m[i].mod |= M_ST; ++s; continue; } default: { goto end; } } end:; } } while (*s++ == ',' && *s); // If the symbolic mode is invalid return NULL if (*--s) { free(m); return NULL; } return m; } /* Process and return next operator */ static inline int getop(char **s) { switch (**s) { case '+': case '-': case '=': { return *(*s)++; }} return 0; } /* Process and return next reference */ static inline mode_t getref(char **s) { for (mode_t ref = 0;;) switch (**s) { case 'u': { ref |= M_USR; ++*s; continue; } case 'g': { ref |= M_GRP; ++*s; continue; } case 'o': { ref |= M_OTH; ++*s; continue; } case 'a': { ref |= M_ALL; ++*s; continue; } default: { return ref; } } }