Plan 9 from Bell Labs’s /usr/web/sources/contrib/de0u/root/sys/src/cmd/divergefs/rule.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#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(&currentpath, 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;
}



Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].