01234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
|
// 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 <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
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; }
}
}
|