#include #include #include #include #include "common.h" #include "debug.h" #include "string.h" #include "utils.h" #include "file.h" #include "filepath.h" #include "rule.h" enum { DEBUG_RULE = false }; String *rule_assemble_path(Rule *self, char *path) { String *result; assert_valid(self); assert_valid(path); assert_valid(self->root); result = s_copy(self->root); result = s_append(result, path); return result; } bool rule_issatisfy(Rule *self, char *path, Dir *d) { assert_valid(self); assert_valid(path); assert_valid(d); assert_valid(self->ops); assert_valid(self->ops->issatisfy); return self->ops->issatisfy(self, path, d); } static Dir *rule_satisfies(Rule *self, char *path, String **fullpath) { Dir *result; String *pathstring; assert_valid(self); assert_valid(path); pathstring = rule_assemble_path(self, path); result = dirstat(s_to_c(pathstring)); INFO(DEBUG_RULE, "rule_satisfies dirstat(\"%s\") = 0x%uX", s_to_c(pathstring), result); if(result != nil) { if(!rule_issatisfy(self, path, result)) { free(result); result = nil; } else if(fullpath != nil) { *fullpath = s_incref(pathstring); } } NOISE(DEBUG_RULE, "rule_satisfies about to free pathstring"); s_free(pathstring); NOISE(DEBUG_RULE, "leaving rule_satisfies with result: %d", result); return result; } void rule_free(Rule *self) { if(self == nil) { return; } free(self->root); self->root = nil; self->ops->free(self); } char *rule_name(Rule *self) { return self->name; } Dir *rule_find(Rule *self, char *path) { assert_valid(self); NOISE(DEBUG_RULE, "entering rule_find with path: %s", path); return rule_satisfies(self, path, nil); } /** * attemps to open the file or dir and store the result Dir* in satisfies * @return fd that was opened or INVALID_FD */ static int rule_satisfied_open(Rule *self, char *path, int omode, bool isdirectory, Dir **satisfies) { int fd = INVALID_FD; String *fullpath = nil; assert_valid(self); assert_valid(path); assert_valid(satisfies); NOISE(DEBUG_RULE, "rule_satisfied_open about to call satisfies on its ops"); *satisfies = rule_satisfies(self, path, &fullpath); if(*satisfies != nil) { if(qid_isdir(&(*satisfies)->qid) == isdirectory) { fd = file_open(s_to_c(fullpath), omode); } } s_free(fullpath); return fd; } int rule_satisfied_open_file(Rule *self, char *path, int omode, Dir **satisfies) { return rule_satisfied_open(self, path, omode, false, satisfies); } int rule_satisfied_open_dir(Rule *self, char *path, int omode, Dir **satisfies) { return rule_satisfied_open(self, path, omode, true, satisfies); } static int rule_open( Rule *self, char *path, int omode, bool isdirectory) { int fd; Dir *satisfies; assert_valid(self); assert_valid(path); fd = rule_satisfied_open(self, path, omode, isdirectory, &satisfies); free(satisfies); return fd; } int rule_open_file(Rule *self, char *path, int omode) { return rule_open(self, path, omode, false); } int rule_open_dir(Rule *self, char *path, int omode) { return rule_open(self, path, omode, true); } bool rule_exists(Rule *self, char *path) { bool result; Dir *d = rule_find(self, path); result = (d != nil); free(d); return result; } bool rule_contains(Rule *self, char *path, int omode, ulong perm) { assert_valid(self); assert_valid(path); assert_valid(self->ops); assert_valid(self->ops->contains); return self->ops->contains(self, path, omode, perm); } static bool rule_mkdir(char *path) { assert_valid(path); if(file_exists(path)) { return true; } return file_mkdir(path); } static bool rule_recursive_create_dir(Rule *self, String *currentpath, char *restpath) { char *slash; assert_valid(self); assert_valid(restpath); NOISE(DEBUG_RULE, "entering rule_recursive_create_dir with current: %s rest: %s", s_to_c(currentpath), restpath); if(*restpath == '\0') { NOISE(DEBUG_RULE, "rule_recursive_create_dir done"); return true; } slash = string_nullify_if_found(restpath, '/'); filepath_append(¤tpath, restpath); if(!rule_mkdir(s_to_c(currentpath))) { ERROR(DEBUG_RULE, "rule_recursive_create_dir failed"); return false; } restpath += strlen(restpath); restpath += (slash != nil) ? 1 : 0; return rule_recursive_create_dir(self, currentpath, restpath); } static char *remove_leading_slash(char *path) { assert_valid(path); return string_skip_leading(path, '/'); } static void rule_create_dir_ondemand(Rule *self, char *path) { String *currentpath; String *dirpath; assert_valid(self); assert_valid(path); currentpath = s_copy(self->root); dirpath = s_copy(remove_leading_slash(path)); filepath_remove_last(dirpath); file_recursive_mkdir(currentpath, s_to_c(dirpath)); s_free(currentpath); s_free(dirpath); } enum { DEBUG_RULE_CREATE = false }; /** * @todo find a way to save one create call when create dir on demand fails */ int rule_create(Rule *self, char *path, int omode, ulong perm) { int result; String *fullpath; assert_valid(self); assert_valid(path); NOISE(DEBUG_RULE || DEBUG_RULE_CREATE, "rule_create self: %s(0x%uX) path: %s mode: %d perm: %uo", self->name, self, path, omode, perm); assert(rule_contains(self, path, omode, perm)); rule_create_dir_ondemand(self, path); fullpath = rule_assemble_path(self, path); result = file_create(s_to_c(fullpath), omode, perm); s_free(fullpath); return result; } bool rule_remove(Rule *self, char *path) { bool result; String *fullpath; assert_valid(self); assert_valid(path); assert(rule_exists(self, path)); fullpath = rule_assemble_path(self, path); result = file_remove(s_to_c(fullpath)); if(!result && file_isdir_empty(s_to_c(fullpath))) { result = true; } NOISE(DEBUG_RULE, "rule_remove removing %s with result: %d", s_to_c(fullpath), result); s_free(fullpath); return result; } bool rule_set_stat(Rule *self, char *path, Dir *d) { bool result; String *fullpath; assert_valid(self); assert_valid(path); assert_valid(d); assert(rule_exists(self, path)); fullpath = rule_assemble_path(self, path); result = file_dirwstat(s_to_c(fullpath), d); NOISE(DEBUG_RULE, "rule_wstat on %s mode: 0x%uX with result: %d", s_to_c(fullpath), d->mode, result); s_free(fullpath); return result; } bool rule_same_path(Rule *self, Rule *other) { assert_valid(self); assert_valid(other); return strcmp(self->root, other->root) == 0; } bool rule_same_file(Rule *self, char *path, Rule *other, char *otherpath) { assert_valid(self); assert_valid(path); assert_valid(other); assert_valid(otherpath); return rule_same_path(self, other) && strcmp(path, otherpath) == 0; } enum { DEBUG_RULE_COPY_FILE = false }; /** @TODO call appropriate rule_open_(file|dir) depend on the file type */ bool rule_copy_file(Rule *self, char *path, Rule *target, char *newpath, Dir *d) { bool result; int sourcefd; int targetfd; assert(!rule_same_file(self, path, target, newpath)); NOISE(DEBUG_RULE || DEBUG_RULE_COPY_FILE, "rule_copy_file self: %s(0x%uX) path: %s target: %s(0x%uX) path: %s", self->name, self, path, target->name, target, newpath); sourcefd = rule_open_file(self, path, OREAD); targetfd = rule_create(target, newpath, OWRITE, d->mode & 0777); if(!fd_isopen(sourcefd)) { WARNING(DEBUG_RULE || DEBUG_RULE_COPY_FILE, "rule_copy_file unable to open source file"); } if(!fd_isopen(targetfd)) { WARNING(DEBUG_RULE || DEBUG_RULE_COPY_FILE, "rule_copy_file unable to open target file"); } result = fd_isopen(sourcefd) && fd_isopen(targetfd) && file_copy(sourcefd, targetfd); if(!result) { WARNING(DEBUG_RULE || DEBUG_RULE_COPY_FILE, "rule_copy_file copying failed"); } file_close(sourcefd); file_close(targetfd); return result; } void rule_free_self(Rule *self) { if(self == nil) { return; } free(self); } bool rule_contains_true(Rule *self, char *, int, ulong) { NOISE(DEBUG_RULE, "rule_contains_true name: %s", self->name); return true; } bool rule_issatisfy_true(Rule *self, char *, Dir *) { NOISE(DEBUG_RULE, "rule_issatisfy_true name: %s", self->name); return true; }