# HG changeset patch # User John Tsiombikas # Date 1375412618 -10800 # Node ID df5e9ee65a50c1a198d91502b9ff7ecafa96f62e packvfs initial commit diff -r 000000000000 -r df5e9ee65a50 .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Fri Aug 02 06:03:38 2013 +0300 @@ -0,0 +1,4 @@ +\.o$ +\.d$ +\.swp$ +^libpackvfs\. diff -r 000000000000 -r df5e9ee65a50 Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Fri Aug 02 06:03:38 2013 +0300 @@ -0,0 +1,37 @@ +PREFIX = /usr/local +dbg = -g + +src = $(wildcard src/*.c) +obj = $(src:.c=.o) +dep = $(obj:.o=.d) +name = packvfs + +somajor = 0 +sominor = 1 + +lib_a = lib$(name).a + +ifeq ($(shell uname -s), Darwin) + lib_so = lib$(name).dylib + shared = -dynamiclib +else + pic = -fPIC + devlink = lib$(name).so + soname = $(devlink).$(somajor) + lib_so = $(soname).$(sominor) + shared = -shared -Wl,-soname=$(soname) +endif + +CFLAGS = -pedantic -Wall $(dbg) $(opt) $(pic) + +$(lib_so): $(obj) + $(CC) -o $@ $(shared) $(obj) $(LDFLAGS) + +$(lib_a): $(obj) + $(AR) rcs $@ $(obj) + +-include $(dep) + +.PHONY: clean +clean: + rm -f $(obj) $(lib_a) diff -r 000000000000 -r df5e9ee65a50 src/pvfs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pvfs.c Fri Aug 02 06:03:38 2013 +0300 @@ -0,0 +1,219 @@ +#include +#include +#include +#include "pvfs.h" +#include "vnode.h" + +int pvfs_errno; + +int pvfs_mount(const char *mntpoint, const char *target) +{ + struct vnode *srcnode, *destnode; + + /* first locate the mount point vnode */ + if(!(srcnode = vnode_lookup(mntpoint))) { + pvfs_errno = ENOENT; + return -1; + } + /* and make sure it's a directory */ + if(srcnode->type != VNODE_DIR) { + pvfs_errno = ENOTDIR; + return -1; + } + + /* then locate the target vnode (if it exists) */ + if(!(destnode = vnode_lookup(target))) { + /* it's some error other than that target doesn't exist, fail... */ + if(pvfs_errno != ENOENT) { + return -1; + } + /* if it doesn't exist, it might be the case we're trying + * to mount a package file or a real directory here. let's + * try them in turn... + */ + PVFS_DIR *dir; + PVFS_FILE *fp; + + if((dir = pvfs_opendir(target))) { + /* it's obviously a real dir as vnode_lookup failed before... */ + assert(dir->real); + if(!(destnode = vnode_create_dir(target, dir))) { + return -1; + } + + } else if((fp = pvfs_fopen(target, "rb"))) { + /* again, obviously real... */ + assert(fp->real); + if(!(destnode = vnode_create_file(target, fp))) { + return -1; + } + + } else { + /* it's neither... so let's fail */ + pvfs_errno = ENOENT; + return -1; + } + } + + /* ok so we've got the two nodes, connect them up */ + srcnode->target = destnode; + return 0; +} + +int pvfs_umount(const char *mntpoint) +{ + struct vnode *node = vnode_lookup(mntpoint); + if(!node) { + return -1; + } + if(node->type != VNODE_DIR) { + pvfs_errno = ENOTDIR; + return -1; + } + if(!node->target) { + pvfs_errno = EINVAL; + return -1; + } + node->target = 0; + return 0; +} + +int pvfs_chdir(const char *path) +{ + return vnode_chdir(path); +} + +int pvfs_mkdir(const char *path, unsigned int mode) +{ + char *ppath; + const char *dname; + struct vnode *parent = 0; + + ppath = alloca(strlen(path) + 1); + strcpy(ppath, path); + + if((dname = strrchr(path, '/'))) { + ppath[++dname - path] = 0; + if(!*dname) { + pvfs_errno = ENOENT; + return -1; + } + if(!(parent = vnode_lookup(ppath))) { + return -1; + } + } else { + dname = ppath; + parent = vnode_getcwd(); + } + + return vnode_mkdir(parent, dname); +} + +PVFS_FILE *pvfs_fopen(const char *fname, const char *mode) +{ + FILE *fp; + struct vnode *node; + + /* if we find it in the filesystem, just use it... */ + if((fp = fopen(fname, mode))) { + PVFS_FILE *vfp = malloc(sizeof *vfp); + if(!vfp) { + pvfs_errno = ENOMEM; + return 0; + } + vfp->fp = fp; + vfp->real = 1; + return vfp; + } + + /* otherwise try and locate it in the virtual hierarchy */ + if(!(node = vnode_lookup(fname))) { + return 0; + } + if(node->type != VNODE_FILE) { + pvfs_errno = EISDIR; + return 0; + } + + return VFILE(node); +} + +int pvfs_fclose(PVFS_FILE *fp) +{ + if(fp->real) { + /* it's real, just close it and free the struct */ + fclose(fp->fp); + free(fp); + return 0; + } + + /* TODO */ + return -1; +} + +int pvfs_fseek(PVFS_FILE *fp, long offset, int whence); +long pvfs_ftell(PVFS_FILE *fp); +void pvfs_rewind(PVFS_FILE *fp); + +size_t pvfs_fread(void *buf, size_t size, size_t nitems, PVFS_FILE *fp); +size_t pvfs_write(void *buf, size_t size, size_t nitems, PVFS_FILE *fp); + +int pvfs_fgetc(PVFS_FILE *fp); +int pvfs_fputc(int c, PVFS_FILE *fp); + +char *pvfs_fgets(char *buf, int size, PVFS_FILE *fp); +int pvfs_fputs(char *buf, PVFS_FILE *fp); + +int pvfs_fscanf(PVFS_FILE *fp, const char *fmt, ...); +int pvfs_vfscanf(PVFS_FILE *fp, const char *fmt, va_list ap); +int pvfs_fprintf(PVFS_FILE *fp, const char *fmt, ...); +int pvfs_vfprintf(PVFS_FILE *fp, const char *fmt, va_list ap); + +void pvfs_clearerr(PVFS_FILE *fp); +int pvfs_feof(PVFS_FILE *fp); +int pvfs_ferror(PVFS_FILE *fp); + +/* POSIX stuff */ +PVFS_DIR *pvfs_opendir(const char *dirname) +{ + DIR *dir; + struct vnode *node; + + if((dir = opendir(dirname))) { + PVFS_DIR *vdir = malloc(sizeof *vdir); + if(!vdir) { + pvfs_errno = ENOMEM; + return 0; + } + + vdir->real = 1; + vdir->dir = dir; + return vdir; + } + + if(!(node = vnode_lookup(dirname))) { + return 0; + } + if(node->type != VNODE_DIR) { + pvfs_errno = ENOTDIR; + return 0; + } + return VDIR(node); +} + +int pvfs_closedir(PVFS_DIR *dir) +{ + if(dir->real) { + int res = closedir(dir->dir); + free(dir); + return res; + } + + /* TODO */ + return -1; +} +struct pvfs_dirent *pvfs_readdir(PVFS_DIR *dir); +void pvfs_rewinddir(PVFS_DIR *dir); + +int pvfs_stat(const char *path, struct pvfs_stat *buf); + diff -r 000000000000 -r df5e9ee65a50 src/pvfs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pvfs.h Fri Aug 02 06:03:38 2013 +0300 @@ -0,0 +1,69 @@ +#ifndef PVFS_H_ +#define PVFS_H_ + +#include +#include +#include + +typedef struct PVFS_FILE PVFS_FILE; +typedef struct PVFS_DIR PVFS_DIR; + +struct pvfs_dirent { + char d_name[256]; +}; + +struct pvfs_stat { + unsigned int st_mode; + unsigned long st_size; +}; + +extern int pvfs_errno; + +#ifdef __cplusplus +extern "C" { +#endif + +/* mount some target (which can be a directory or a pack filename) */ +int pvfs_mount(const char *mntpoint, const char *target); +int pvfs_umount(const char *mntpoint); + +int pvfs_chdir(const char *path); +int pvfs_mkdir(const char *path, unsigned int mode); /* XXX mode is ignored */ + +PVFS_FILE *pvfs_fopen(const char *fname, const char *mode); +int pvfs_fclose(PVFS_FILE *fp); + +int pvfs_fseek(PVFS_FILE *fp, long offset, int whence); +long pvfs_ftell(PVFS_FILE *fp); +void pvfs_rewind(PVFS_FILE *fp); + +size_t pvfs_fread(void *buf, size_t size, size_t nitems, PVFS_FILE *fp); +size_t pvfs_write(void *buf, size_t size, size_t nitems, PVFS_FILE *fp); + +int pvfs_fgetc(PVFS_FILE *fp); +int pvfs_fputc(int c, PVFS_FILE *fp); + +char *pvfs_fgets(char *buf, int size, PVFS_FILE *fp); +int pvfs_fputs(char *buf, PVFS_FILE *fp); + +int pvfs_fscanf(PVFS_FILE *fp, const char *fmt, ...); +int pvfs_vfscanf(PVFS_FILE *fp, const char *fmt, va_list ap); +int pvfs_fprintf(PVFS_FILE *fp, const char *fmt, ...); +int pvfs_vfprintf(PVFS_FILE *fp, const char *fmt, va_list ap); + +void pvfs_clearerr(PVFS_FILE *fp); +int pvfs_feof(PVFS_FILE *fp); +int pvfs_ferror(PVFS_FILE *fp); + +PVFS_DIR *pvfs_opendir(const char *dirname); +int pvfs_closedir(PVFS_DIR *dir); +struct pvfs_dirent *pvfs_readdir(PVFS_DIR *dir); +void pvfs_rewinddir(PVFS_DIR *dir); + +int pvfs_stat(const char *path, struct pvfs_stat *buf); + +#ifdef __cplusplus +} +#endif + +#endif /* PVFS_H_ */ diff -r 000000000000 -r df5e9ee65a50 src/pvfs_impl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pvfs_impl.h Fri Aug 02 06:03:38 2013 +0300 @@ -0,0 +1,17 @@ +#ifndef PVFS_IMPL_H_ +#define PVFS_IMPL_H_ + +#include +#include + +struct PVFS_FILE { + int real; + FILE *fp; +}; + +struct PVFS_DIR { + int real; + DIR *dir; +}; + +#endif /* PVFS_IMPL_H_ */ diff -r 000000000000 -r df5e9ee65a50 src/vnode.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vnode.c Fri Aug 02 06:03:38 2013 +0300 @@ -0,0 +1,163 @@ +#include +#include +#include +#include "pvfs.h" +#include "vnode.h" + +static void add_child(struct vnode *parent, struct vnode *child); +static struct vnode *find_child(struct vnode *node, const char *name); + +static struct vnode *root; +static struct vnode *cwd; + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + + +struct vnode *vnode_create(const char *name) +{ + struct vnode *n; + + if(!(n = calloc(1, sizeof *n)) || !(n->name = strdup(name))) { + pvfs_errno = ENOMEM; + return 0; + } + return n; +} + +struct vnode *vnode_create_file(const char *name, PVFS_FILE *fp) +{ + struct vnode *n; + + if(!(n = vnode_create(name))) { + return 0; + } + n->type = VNODE_FILE; + n->obj = fp; + return n; +} + +struct vnode *vnode_create_dir(const char *name, PVFS_DIR *dir) +{ + struct vnode *n; + + if(!(n = vnode_create(name))) { + return 0; + } + n->type = VNODE_DIR; + n->obj = dir; + return n; +} + +void vnode_free(struct vnode *n) +{ + free(n->name); + free(n); +} + +static void destroy_tree_rec(struct vnode *tree) +{ + struct vnode *c = tree->childlist; + while(c) { + struct vnode *tmp = c; + c = c->next; + vnode_destroy_tree(tmp); + } + vnode_free(tree); +} + +void vnode_destroy_tree(struct vnode *tree) +{ + pthread_mutex_lock(&mutex); + destroy_tree_rec(tree); + pthread_mutex_unlock(&mutex); +} + +struct vnode *vnode_lookup(const char *const_path) +{ + struct vnode *node, *res = 0; + char *path; + + path = alloca(strlen(const_path) + 1); + strcpy(path, const_path); + + pthread_mutex_lock(&mutex); + + if(path[0] == '/') { + node = root; + path++; + } else { + node = cwd; + } + + while(path && *path) { + char *slash = strchr(path + 1, '/'); + if(slash) { + *slash = 0; + } + + if(!(node = find_child(node, path))) { + pvfs_errno = ENOENT; + goto done; + } + path = slash ? slash + 1 : 0; + } + res = node; + +done: + pthread_mutex_unlock(&mutex); + return res; +} + +int vnode_chdir(const char *name) +{ + struct vnode *node = vnode_lookup(name); + if(node) { + /* XXX race condition with delete tree, shouldn't really happen... */ + pthread_mutex_lock(&mutex); + cwd = node; + pthread_mutex_unlock(&mutex); + return 0; + } + return -1; +} + +int vnode_mkdir(struct vnode *parent, const char *name) +{ + struct vnode *n; + + if(!parent) { + if(root || strcmp(name, "/") != 0) { + pvfs_errno = EEXIST; + return -1; + } + } + + if(!(n = vnode_create_dir(name, 0))) { + return -1; + } + add_child(parent, n); + return 0; +} + +static void add_child(struct vnode *parent, struct vnode *child) +{ + pthread_mutex_lock(&mutex); + + child->parent = parent; + child->next = parent->childlist; + parent->childlist = child; + + pthread_mutex_unlock(&mutex); +} + +static struct vnode *find_child(struct vnode *node, const char *name) +{ + struct vnode *c = node->childlist; + while(c) { + if(strcmp(c->name, name) == 0) { + return c; + } + c = c->next; + } + return 0; +} diff -r 000000000000 -r df5e9ee65a50 src/vnode.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vnode.h Fri Aug 02 06:03:38 2013 +0300 @@ -0,0 +1,46 @@ +#ifndef VNODE_H_ +#define VNODE_H_ + +#include "pvfs_impl.h" + +enum node_type { + VNODE_FILE, + VNODE_DIR +}; + +struct vnode { + char *name; + enum node_type type; + /* obj is PVFS_FILE* or PVFS_DIR* depending on type. + * use VFILE/VDIR macros to access. + */ + void *obj; + + /* this is a link to some other vnode which is mounted in this place */ + struct vnode *target; + + /* regular tree stuff */ + struct vnode *parent; + struct vnode *childlist; + struct vnode *next; +}; + +#define VFILE(n) \ + (assert((n)->type == VNODE_FILE), (PVFS_FILE*)(n)->obj) +#define VDIR(n) \ + (assert((n)->type == VNODE_DIR), (PVFS_DIR*)(n)->obj) + +struct vnode *vnode_create(const char *name); +struct vnode *vnode_create_file(const char *name, PVFS_FILE *fp); +struct vnode *vnode_create_dir(const char *name, PVFS_DIR *dir); +void vnode_free(struct vnode *n); +void vnode_destroy_tree(struct vnode *tree); + +struct vnode *vnode_lookup(const char *path); +#define vnode_getcwd() vnode_lookup("") +#define vnode_getroot() vnode_lookup("/") + +int vnode_chdir(const char *name); +int vnode_mkdir(struct vnode *parent, const char *name); + +#endif /* VNODE_H_ */