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