packvfs
changeset 0:df5e9ee65a50
packvfs initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Fri, 02 Aug 2013 06:03:38 +0300 |
parents | |
children | a0b3b6682d92 |
files | .hgignore Makefile src/pvfs.c src/pvfs.h src/pvfs_impl.h src/vnode.c src/vnode.h |
diffstat | 7 files changed, 555 insertions(+), 0 deletions(-) [+] |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/.hgignore Fri Aug 02 06:03:38 2013 +0300 1.3 @@ -0,0 +1,4 @@ 1.4 +\.o$ 1.5 +\.d$ 1.6 +\.swp$ 1.7 +^libpackvfs\.
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/Makefile Fri Aug 02 06:03:38 2013 +0300 2.3 @@ -0,0 +1,37 @@ 2.4 +PREFIX = /usr/local 2.5 +dbg = -g 2.6 + 2.7 +src = $(wildcard src/*.c) 2.8 +obj = $(src:.c=.o) 2.9 +dep = $(obj:.o=.d) 2.10 +name = packvfs 2.11 + 2.12 +somajor = 0 2.13 +sominor = 1 2.14 + 2.15 +lib_a = lib$(name).a 2.16 + 2.17 +ifeq ($(shell uname -s), Darwin) 2.18 + lib_so = lib$(name).dylib 2.19 + shared = -dynamiclib 2.20 +else 2.21 + pic = -fPIC 2.22 + devlink = lib$(name).so 2.23 + soname = $(devlink).$(somajor) 2.24 + lib_so = $(soname).$(sominor) 2.25 + shared = -shared -Wl,-soname=$(soname) 2.26 +endif 2.27 + 2.28 +CFLAGS = -pedantic -Wall $(dbg) $(opt) $(pic) 2.29 + 2.30 +$(lib_so): $(obj) 2.31 + $(CC) -o $@ $(shared) $(obj) $(LDFLAGS) 2.32 + 2.33 +$(lib_a): $(obj) 2.34 + $(AR) rcs $@ $(obj) 2.35 + 2.36 +-include $(dep) 2.37 + 2.38 +.PHONY: clean 2.39 +clean: 2.40 + rm -f $(obj) $(lib_a)
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/src/pvfs.c Fri Aug 02 06:03:38 2013 +0300 3.3 @@ -0,0 +1,219 @@ 3.4 +#include <string.h> 3.5 +#include <alloca.h> 3.6 +#include <assert.h> 3.7 +#include "pvfs.h" 3.8 +#include "vnode.h" 3.9 + 3.10 +int pvfs_errno; 3.11 + 3.12 +int pvfs_mount(const char *mntpoint, const char *target) 3.13 +{ 3.14 + struct vnode *srcnode, *destnode; 3.15 + 3.16 + /* first locate the mount point vnode */ 3.17 + if(!(srcnode = vnode_lookup(mntpoint))) { 3.18 + pvfs_errno = ENOENT; 3.19 + return -1; 3.20 + } 3.21 + /* and make sure it's a directory */ 3.22 + if(srcnode->type != VNODE_DIR) { 3.23 + pvfs_errno = ENOTDIR; 3.24 + return -1; 3.25 + } 3.26 + 3.27 + /* then locate the target vnode (if it exists) */ 3.28 + if(!(destnode = vnode_lookup(target))) { 3.29 + /* it's some error other than that target doesn't exist, fail... */ 3.30 + if(pvfs_errno != ENOENT) { 3.31 + return -1; 3.32 + } 3.33 + /* if it doesn't exist, it might be the case we're trying 3.34 + * to mount a package file or a real directory here. let's 3.35 + * try them in turn... 3.36 + */ 3.37 + PVFS_DIR *dir; 3.38 + PVFS_FILE *fp; 3.39 + 3.40 + if((dir = pvfs_opendir(target))) { 3.41 + /* it's obviously a real dir as vnode_lookup failed before... */ 3.42 + assert(dir->real); 3.43 + if(!(destnode = vnode_create_dir(target, dir))) { 3.44 + return -1; 3.45 + } 3.46 + 3.47 + } else if((fp = pvfs_fopen(target, "rb"))) { 3.48 + /* again, obviously real... */ 3.49 + assert(fp->real); 3.50 + if(!(destnode = vnode_create_file(target, fp))) { 3.51 + return -1; 3.52 + } 3.53 + 3.54 + } else { 3.55 + /* it's neither... so let's fail */ 3.56 + pvfs_errno = ENOENT; 3.57 + return -1; 3.58 + } 3.59 + } 3.60 + 3.61 + /* ok so we've got the two nodes, connect them up */ 3.62 + srcnode->target = destnode; 3.63 + return 0; 3.64 +} 3.65 + 3.66 +int pvfs_umount(const char *mntpoint) 3.67 +{ 3.68 + struct vnode *node = vnode_lookup(mntpoint); 3.69 + if(!node) { 3.70 + return -1; 3.71 + } 3.72 + if(node->type != VNODE_DIR) { 3.73 + pvfs_errno = ENOTDIR; 3.74 + return -1; 3.75 + } 3.76 + if(!node->target) { 3.77 + pvfs_errno = EINVAL; 3.78 + return -1; 3.79 + } 3.80 + node->target = 0; 3.81 + return 0; 3.82 +} 3.83 + 3.84 +int pvfs_chdir(const char *path) 3.85 +{ 3.86 + return vnode_chdir(path); 3.87 +} 3.88 + 3.89 +int pvfs_mkdir(const char *path, unsigned int mode) 3.90 +{ 3.91 + char *ppath; 3.92 + const char *dname; 3.93 + struct vnode *parent = 0; 3.94 + 3.95 + ppath = alloca(strlen(path) + 1); 3.96 + strcpy(ppath, path); 3.97 + 3.98 + if((dname = strrchr(path, '/'))) { 3.99 + ppath[++dname - path] = 0; 3.100 + if(!*dname) { 3.101 + pvfs_errno = ENOENT; 3.102 + return -1; 3.103 + } 3.104 + if(!(parent = vnode_lookup(ppath))) { 3.105 + return -1; 3.106 + } 3.107 + } else { 3.108 + dname = ppath; 3.109 + parent = vnode_getcwd(); 3.110 + } 3.111 + 3.112 + return vnode_mkdir(parent, dname); 3.113 +} 3.114 + 3.115 +PVFS_FILE *pvfs_fopen(const char *fname, const char *mode) 3.116 +{ 3.117 + FILE *fp; 3.118 + struct vnode *node; 3.119 + 3.120 + /* if we find it in the filesystem, just use it... */ 3.121 + if((fp = fopen(fname, mode))) { 3.122 + PVFS_FILE *vfp = malloc(sizeof *vfp); 3.123 + if(!vfp) { 3.124 + pvfs_errno = ENOMEM; 3.125 + return 0; 3.126 + } 3.127 + vfp->fp = fp; 3.128 + vfp->real = 1; 3.129 + return vfp; 3.130 + } 3.131 + 3.132 + /* otherwise try and locate it in the virtual hierarchy */ 3.133 + if(!(node = vnode_lookup(fname))) { 3.134 + return 0; 3.135 + } 3.136 + if(node->type != VNODE_FILE) { 3.137 + pvfs_errno = EISDIR; 3.138 + return 0; 3.139 + } 3.140 + 3.141 + return VFILE(node); 3.142 +} 3.143 + 3.144 +int pvfs_fclose(PVFS_FILE *fp) 3.145 +{ 3.146 + if(fp->real) { 3.147 + /* it's real, just close it and free the struct */ 3.148 + fclose(fp->fp); 3.149 + free(fp); 3.150 + return 0; 3.151 + } 3.152 + 3.153 + /* TODO */ 3.154 + return -1; 3.155 +} 3.156 + 3.157 +int pvfs_fseek(PVFS_FILE *fp, long offset, int whence); 3.158 +long pvfs_ftell(PVFS_FILE *fp); 3.159 +void pvfs_rewind(PVFS_FILE *fp); 3.160 + 3.161 +size_t pvfs_fread(void *buf, size_t size, size_t nitems, PVFS_FILE *fp); 3.162 +size_t pvfs_write(void *buf, size_t size, size_t nitems, PVFS_FILE *fp); 3.163 + 3.164 +int pvfs_fgetc(PVFS_FILE *fp); 3.165 +int pvfs_fputc(int c, PVFS_FILE *fp); 3.166 + 3.167 +char *pvfs_fgets(char *buf, int size, PVFS_FILE *fp); 3.168 +int pvfs_fputs(char *buf, PVFS_FILE *fp); 3.169 + 3.170 +int pvfs_fscanf(PVFS_FILE *fp, const char *fmt, ...); 3.171 +int pvfs_vfscanf(PVFS_FILE *fp, const char *fmt, va_list ap); 3.172 +int pvfs_fprintf(PVFS_FILE *fp, const char *fmt, ...); 3.173 +int pvfs_vfprintf(PVFS_FILE *fp, const char *fmt, va_list ap); 3.174 + 3.175 +void pvfs_clearerr(PVFS_FILE *fp); 3.176 +int pvfs_feof(PVFS_FILE *fp); 3.177 +int pvfs_ferror(PVFS_FILE *fp); 3.178 + 3.179 +/* POSIX stuff */ 3.180 +PVFS_DIR *pvfs_opendir(const char *dirname) 3.181 +{ 3.182 + DIR *dir; 3.183 + struct vnode *node; 3.184 + 3.185 + if((dir = opendir(dirname))) { 3.186 + PVFS_DIR *vdir = malloc(sizeof *vdir); 3.187 + if(!vdir) { 3.188 + pvfs_errno = ENOMEM; 3.189 + return 0; 3.190 + } 3.191 + 3.192 + vdir->real = 1; 3.193 + vdir->dir = dir; 3.194 + return vdir; 3.195 + } 3.196 + 3.197 + if(!(node = vnode_lookup(dirname))) { 3.198 + return 0; 3.199 + } 3.200 + if(node->type != VNODE_DIR) { 3.201 + pvfs_errno = ENOTDIR; 3.202 + return 0; 3.203 + } 3.204 + return VDIR(node); 3.205 +} 3.206 + 3.207 +int pvfs_closedir(PVFS_DIR *dir) 3.208 +{ 3.209 + if(dir->real) { 3.210 + int res = closedir(dir->dir); 3.211 + free(dir); 3.212 + return res; 3.213 + } 3.214 + 3.215 + /* TODO */ 3.216 + return -1; 3.217 +} 3.218 +struct pvfs_dirent *pvfs_readdir(PVFS_DIR *dir); 3.219 +void pvfs_rewinddir(PVFS_DIR *dir); 3.220 + 3.221 +int pvfs_stat(const char *path, struct pvfs_stat *buf); 3.222 +
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/src/pvfs.h Fri Aug 02 06:03:38 2013 +0300 4.3 @@ -0,0 +1,69 @@ 4.4 +#ifndef PVFS_H_ 4.5 +#define PVFS_H_ 4.6 + 4.7 +#include <stdio.h> 4.8 +#include <stdlib.h> 4.9 +#include <errno.h> 4.10 + 4.11 +typedef struct PVFS_FILE PVFS_FILE; 4.12 +typedef struct PVFS_DIR PVFS_DIR; 4.13 + 4.14 +struct pvfs_dirent { 4.15 + char d_name[256]; 4.16 +}; 4.17 + 4.18 +struct pvfs_stat { 4.19 + unsigned int st_mode; 4.20 + unsigned long st_size; 4.21 +}; 4.22 + 4.23 +extern int pvfs_errno; 4.24 + 4.25 +#ifdef __cplusplus 4.26 +extern "C" { 4.27 +#endif 4.28 + 4.29 +/* mount some target (which can be a directory or a pack filename) */ 4.30 +int pvfs_mount(const char *mntpoint, const char *target); 4.31 +int pvfs_umount(const char *mntpoint); 4.32 + 4.33 +int pvfs_chdir(const char *path); 4.34 +int pvfs_mkdir(const char *path, unsigned int mode); /* XXX mode is ignored */ 4.35 + 4.36 +PVFS_FILE *pvfs_fopen(const char *fname, const char *mode); 4.37 +int pvfs_fclose(PVFS_FILE *fp); 4.38 + 4.39 +int pvfs_fseek(PVFS_FILE *fp, long offset, int whence); 4.40 +long pvfs_ftell(PVFS_FILE *fp); 4.41 +void pvfs_rewind(PVFS_FILE *fp); 4.42 + 4.43 +size_t pvfs_fread(void *buf, size_t size, size_t nitems, PVFS_FILE *fp); 4.44 +size_t pvfs_write(void *buf, size_t size, size_t nitems, PVFS_FILE *fp); 4.45 + 4.46 +int pvfs_fgetc(PVFS_FILE *fp); 4.47 +int pvfs_fputc(int c, PVFS_FILE *fp); 4.48 + 4.49 +char *pvfs_fgets(char *buf, int size, PVFS_FILE *fp); 4.50 +int pvfs_fputs(char *buf, PVFS_FILE *fp); 4.51 + 4.52 +int pvfs_fscanf(PVFS_FILE *fp, const char *fmt, ...); 4.53 +int pvfs_vfscanf(PVFS_FILE *fp, const char *fmt, va_list ap); 4.54 +int pvfs_fprintf(PVFS_FILE *fp, const char *fmt, ...); 4.55 +int pvfs_vfprintf(PVFS_FILE *fp, const char *fmt, va_list ap); 4.56 + 4.57 +void pvfs_clearerr(PVFS_FILE *fp); 4.58 +int pvfs_feof(PVFS_FILE *fp); 4.59 +int pvfs_ferror(PVFS_FILE *fp); 4.60 + 4.61 +PVFS_DIR *pvfs_opendir(const char *dirname); 4.62 +int pvfs_closedir(PVFS_DIR *dir); 4.63 +struct pvfs_dirent *pvfs_readdir(PVFS_DIR *dir); 4.64 +void pvfs_rewinddir(PVFS_DIR *dir); 4.65 + 4.66 +int pvfs_stat(const char *path, struct pvfs_stat *buf); 4.67 + 4.68 +#ifdef __cplusplus 4.69 +} 4.70 +#endif 4.71 + 4.72 +#endif /* PVFS_H_ */
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/src/pvfs_impl.h Fri Aug 02 06:03:38 2013 +0300 5.3 @@ -0,0 +1,17 @@ 5.4 +#ifndef PVFS_IMPL_H_ 5.5 +#define PVFS_IMPL_H_ 5.6 + 5.7 +#include <stdio.h> 5.8 +#include <dirent.h> 5.9 + 5.10 +struct PVFS_FILE { 5.11 + int real; 5.12 + FILE *fp; 5.13 +}; 5.14 + 5.15 +struct PVFS_DIR { 5.16 + int real; 5.17 + DIR *dir; 5.18 +}; 5.19 + 5.20 +#endif /* PVFS_IMPL_H_ */
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/src/vnode.c Fri Aug 02 06:03:38 2013 +0300 6.3 @@ -0,0 +1,163 @@ 6.4 +#include <string.h> 6.5 +#include <pthread.h> 6.6 +#include <alloca.h> 6.7 +#include "pvfs.h" 6.8 +#include "vnode.h" 6.9 + 6.10 +static void add_child(struct vnode *parent, struct vnode *child); 6.11 +static struct vnode *find_child(struct vnode *node, const char *name); 6.12 + 6.13 +static struct vnode *root; 6.14 +static struct vnode *cwd; 6.15 + 6.16 +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 6.17 + 6.18 + 6.19 +struct vnode *vnode_create(const char *name) 6.20 +{ 6.21 + struct vnode *n; 6.22 + 6.23 + if(!(n = calloc(1, sizeof *n)) || !(n->name = strdup(name))) { 6.24 + pvfs_errno = ENOMEM; 6.25 + return 0; 6.26 + } 6.27 + return n; 6.28 +} 6.29 + 6.30 +struct vnode *vnode_create_file(const char *name, PVFS_FILE *fp) 6.31 +{ 6.32 + struct vnode *n; 6.33 + 6.34 + if(!(n = vnode_create(name))) { 6.35 + return 0; 6.36 + } 6.37 + n->type = VNODE_FILE; 6.38 + n->obj = fp; 6.39 + return n; 6.40 +} 6.41 + 6.42 +struct vnode *vnode_create_dir(const char *name, PVFS_DIR *dir) 6.43 +{ 6.44 + struct vnode *n; 6.45 + 6.46 + if(!(n = vnode_create(name))) { 6.47 + return 0; 6.48 + } 6.49 + n->type = VNODE_DIR; 6.50 + n->obj = dir; 6.51 + return n; 6.52 +} 6.53 + 6.54 +void vnode_free(struct vnode *n) 6.55 +{ 6.56 + free(n->name); 6.57 + free(n); 6.58 +} 6.59 + 6.60 +static void destroy_tree_rec(struct vnode *tree) 6.61 +{ 6.62 + struct vnode *c = tree->childlist; 6.63 + while(c) { 6.64 + struct vnode *tmp = c; 6.65 + c = c->next; 6.66 + vnode_destroy_tree(tmp); 6.67 + } 6.68 + vnode_free(tree); 6.69 +} 6.70 + 6.71 +void vnode_destroy_tree(struct vnode *tree) 6.72 +{ 6.73 + pthread_mutex_lock(&mutex); 6.74 + destroy_tree_rec(tree); 6.75 + pthread_mutex_unlock(&mutex); 6.76 +} 6.77 + 6.78 +struct vnode *vnode_lookup(const char *const_path) 6.79 +{ 6.80 + struct vnode *node, *res = 0; 6.81 + char *path; 6.82 + 6.83 + path = alloca(strlen(const_path) + 1); 6.84 + strcpy(path, const_path); 6.85 + 6.86 + pthread_mutex_lock(&mutex); 6.87 + 6.88 + if(path[0] == '/') { 6.89 + node = root; 6.90 + path++; 6.91 + } else { 6.92 + node = cwd; 6.93 + } 6.94 + 6.95 + while(path && *path) { 6.96 + char *slash = strchr(path + 1, '/'); 6.97 + if(slash) { 6.98 + *slash = 0; 6.99 + } 6.100 + 6.101 + if(!(node = find_child(node, path))) { 6.102 + pvfs_errno = ENOENT; 6.103 + goto done; 6.104 + } 6.105 + path = slash ? slash + 1 : 0; 6.106 + } 6.107 + res = node; 6.108 + 6.109 +done: 6.110 + pthread_mutex_unlock(&mutex); 6.111 + return res; 6.112 +} 6.113 + 6.114 +int vnode_chdir(const char *name) 6.115 +{ 6.116 + struct vnode *node = vnode_lookup(name); 6.117 + if(node) { 6.118 + /* XXX race condition with delete tree, shouldn't really happen... */ 6.119 + pthread_mutex_lock(&mutex); 6.120 + cwd = node; 6.121 + pthread_mutex_unlock(&mutex); 6.122 + return 0; 6.123 + } 6.124 + return -1; 6.125 +} 6.126 + 6.127 +int vnode_mkdir(struct vnode *parent, const char *name) 6.128 +{ 6.129 + struct vnode *n; 6.130 + 6.131 + if(!parent) { 6.132 + if(root || strcmp(name, "/") != 0) { 6.133 + pvfs_errno = EEXIST; 6.134 + return -1; 6.135 + } 6.136 + } 6.137 + 6.138 + if(!(n = vnode_create_dir(name, 0))) { 6.139 + return -1; 6.140 + } 6.141 + add_child(parent, n); 6.142 + return 0; 6.143 +} 6.144 + 6.145 +static void add_child(struct vnode *parent, struct vnode *child) 6.146 +{ 6.147 + pthread_mutex_lock(&mutex); 6.148 + 6.149 + child->parent = parent; 6.150 + child->next = parent->childlist; 6.151 + parent->childlist = child; 6.152 + 6.153 + pthread_mutex_unlock(&mutex); 6.154 +} 6.155 + 6.156 +static struct vnode *find_child(struct vnode *node, const char *name) 6.157 +{ 6.158 + struct vnode *c = node->childlist; 6.159 + while(c) { 6.160 + if(strcmp(c->name, name) == 0) { 6.161 + return c; 6.162 + } 6.163 + c = c->next; 6.164 + } 6.165 + return 0; 6.166 +}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/src/vnode.h Fri Aug 02 06:03:38 2013 +0300 7.3 @@ -0,0 +1,46 @@ 7.4 +#ifndef VNODE_H_ 7.5 +#define VNODE_H_ 7.6 + 7.7 +#include "pvfs_impl.h" 7.8 + 7.9 +enum node_type { 7.10 + VNODE_FILE, 7.11 + VNODE_DIR 7.12 +}; 7.13 + 7.14 +struct vnode { 7.15 + char *name; 7.16 + enum node_type type; 7.17 + /* obj is PVFS_FILE* or PVFS_DIR* depending on type. 7.18 + * use VFILE/VDIR macros to access. 7.19 + */ 7.20 + void *obj; 7.21 + 7.22 + /* this is a link to some other vnode which is mounted in this place */ 7.23 + struct vnode *target; 7.24 + 7.25 + /* regular tree stuff */ 7.26 + struct vnode *parent; 7.27 + struct vnode *childlist; 7.28 + struct vnode *next; 7.29 +}; 7.30 + 7.31 +#define VFILE(n) \ 7.32 + (assert((n)->type == VNODE_FILE), (PVFS_FILE*)(n)->obj) 7.33 +#define VDIR(n) \ 7.34 + (assert((n)->type == VNODE_DIR), (PVFS_DIR*)(n)->obj) 7.35 + 7.36 +struct vnode *vnode_create(const char *name); 7.37 +struct vnode *vnode_create_file(const char *name, PVFS_FILE *fp); 7.38 +struct vnode *vnode_create_dir(const char *name, PVFS_DIR *dir); 7.39 +void vnode_free(struct vnode *n); 7.40 +void vnode_destroy_tree(struct vnode *tree); 7.41 + 7.42 +struct vnode *vnode_lookup(const char *path); 7.43 +#define vnode_getcwd() vnode_lookup("") 7.44 +#define vnode_getroot() vnode_lookup("/") 7.45 + 7.46 +int vnode_chdir(const char *name); 7.47 +int vnode_mkdir(struct vnode *parent, const char *name); 7.48 + 7.49 +#endif /* VNODE_H_ */