#include #include #include #include #include "common.h" #include "debug.h" #include "utils.h" #include "rule.h" #include "moderule.h" enum { DEBUG_MODERULE = false, DEBUG_MODEBASICRULE = false }; static void modebasicrule_free(Rule *rule); static bool modebasicrule_issatisfy(Rule *rule, char *path, Dir *d); static bool modebasicrule_contains( Rule *rule, char *path, int omode, ulong perm); typedef struct ModeBasicRuleOperations { bool (*isperm)(ulong perm); bool (*ismode)(ulong perm, char *path, Dir *d); } ModeBasicRuleOperations; typedef struct ModeBasicRule { Rule; ModeBasicRuleOperations mbops; } ModeBasicRule; static RuleOperations modebasicruleops = { .free = modebasicrule_free, .issatisfy = modebasicrule_issatisfy, .contains = modebasicrule_contains }; static bool isperm_true(ulong) { return true; } static bool isperm_append(ulong perm) { return perm_isappend(perm); } static bool isperm_exclusive(ulong perm) { return perm_isexclusive(perm); } static bool isperm_directory(ulong perm) { return perm_isdir(perm); } static bool isperm_regular(ulong perm) { return !isperm_directory(perm); } static bool ismode_true(ulong, char *, Dir *) { return true; } static bool ismode_read(ulong perm, char *path, Dir *) { if(path != nil) { return access(path, AREAD) == 0; } return perm_isread(perm); } static bool moderule_dirismode(Dir *d, bool (*modetest)(ulong)) { assert_valid(modetest); return d != nil && qid_isdir(&d->qid) && modetest(d->mode); } static bool ismode_write(ulong perm, char *path, Dir *d) { if(path != nil) { return moderule_dirismode(d, dirmode_iswrite) || access(path, AWRITE) == 0; } return perm_iswrite(perm); } static bool ismode_exec(ulong perm, char *path, Dir *d) { if(path != nil) { return moderule_dirismode(d, dirmode_isexec) || access(path, AEXEC) == 0; } return perm_isexec(perm); } static bool ismode_exist(ulong, char *path, Dir *) { if(path != nil) { return access(path, AEXIST) == 0; } return true; } typedef struct CharMbopsPair { char mode; ModeBasicRuleOperations; } CharMbopsPair; CharMbopsPair mbopsregistry[] = { {'A', isperm_append, ismode_true}, {'L', isperm_exclusive, ismode_true}, {'f', isperm_regular, ismode_true}, {'d', isperm_directory, ismode_true}, {'r', isperm_true, ismode_read}, {'w', isperm_true, ismode_write}, {'x', isperm_true, ismode_exec}, {'e', isperm_true, ismode_exist} }; static void modebasicrule_findmbops(char mode, ModeBasicRuleOperations *mbops) { int i; assert_valid(mbops); for(i = 0; i < static_array_length(mbopsregistry); ++i) { if(mode == mbopsregistry[i].mode) { NOISE(DEBUG_MODEBASICRULE, "modebasicrule_findmbops found mode: %c", mode); mbops->isperm = mbopsregistry[i].isperm; mbops->ismode = mbopsregistry[i].ismode; break; } } } Rule *modebasicrule_new(char *mode, char *root) { ModeBasicRule *result; char buf[RULE_MAXNAMELEN]; assert_valid(mode); assert_valid(root); if(strlen(mode) > 1) { return nil; } result = (ModeBasicRule *)emallocz_fs(sizeof(*result)); result->ops = &modebasicruleops; result->root = estrdup_fs(root); snprint(buf, sizeof(buf), "mode<%c>", *mode); result->name = estrdup_fs(buf); modebasicrule_findmbops(*mode, &(result->mbops)); if(result->mbops.isperm == nil || result->mbops.ismode == nil) { NOISE(DEBUG_MODEBASICRULE, "modebasicrule_new did not find any matching mode"); rule_free(result); result = nil; } return result; } static void modebasicrule_free(Rule *rule) { assert_valid(rule); free(rule->name); rule->name = nil; free(rule); } static bool modebasicrule_issatisfy(Rule *rule, char *path, Dir *d) { bool result; String *fullpath; ModeBasicRule *self = (ModeBasicRule *)rule; NOISE(DEBUG_MODEBASICRULE, "entering modebasicrule_issatisfy with path: %s d->mode: %ulX", path, d->mode); fullpath = rule_assemble_path(rule, path); result = self->mbops.ismode(0, s_to_c(fullpath), d) && self->mbops.isperm(d->mode); NOISE(DEBUG_MODEBASICRULE, "leaving modebasicrule_issatisfy with result: %d", result); s_free(fullpath); return result; } static bool modebasicrule_contains( Rule *rule, char *, int omode, ulong perm) { bool result; ModeBasicRule *self = (ModeBasicRule *)rule; NOISE(DEBUG_MODEBASICRULE, "entering modebasicrule_contains with omode: %b perm: %ulb", omode, perm); result = self->mbops.ismode(perm, nil, nil) && self->mbops.isperm(perm); NOISE(DEBUG_MODEBASICRULE, "leaving modebasicrule_contains with result: %d", result); return result; } Rule *moderule_parse(char *rule, char *setting, char *path) { assert_valid(rule); assert_valid(setting); assert_valid(path); if(strcmp(rule, "mode") != 0) { return nil; } INFO(DEBUG_MODERULE, "parsed mode rule with path: %s", path); return modebasicrule_new(setting, path); }