#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <String.h>
#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);
}
|