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_ */