Add libtar to TWRP instead of using busybox tar
Add proper mkdosfs tool
Add fuse to TWRP
Add experimental exfat-fuse to TWRP
Convert all system() functions to use new Exec_Cmd function
diff --git a/fuse/Android.mk b/fuse/Android.mk
new file mode 100644
index 0000000..0855959
--- /dev/null
+++ b/fuse/Android.mk
@@ -0,0 +1,65 @@
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	cuse_lowlevel.c \
+	fuse.c \
+	fuse_kern_chan.c \
+	fuse_loop.c \
+	fuse_loop_mt.c \
+	fuse_lowlevel.c \
+	fuse_mt.c fuse_opt.c \
+	fuse_session.c \
+	fuse_signals.c \
+	helper.c \
+	mount.c \
+	mount_util.c \
+	ulockmgr.c
+
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH)/include
+
+LOCAL_SHARED_LIBRARIES := \
+	libutils libdl
+
+LOCAL_CFLAGS := \
+	-D_FILE_OFFSET_BITS=64 \
+	-DFUSE_USE_VERSION=26
+
+LOCAL_MODULE := libfuse
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_STATIC_LIBRARY)
+#include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	fusexmp.c
+
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH)/include
+
+LOCAL_CFLAGS := -D_FILE_OFFSET_BITS=64
+
+LOCAL_MODULE := fusexmp
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_STATIC_LIBRARIES := libfuse
+
+include $(BUILD_EXECUTABLE)
diff --git a/fuse/README b/fuse/README
new file mode 100644
index 0000000..3d1f6f0
--- /dev/null
+++ b/fuse/README
@@ -0,0 +1,12 @@
+Libfuse for Android
+
+FUSE[1] is a framework to develop userspace file systems for linux. Since Android is based on linux, it won't be too difficult to port libfuse to Android.
+
+The main problem of building and running libfuse on Android is that the bionic c library lacks support for pthread_cancel(), which is necessary for libfuse multi-thread code. This stackoverflow entry[2] has suggested a solution, which uses SIGUSR1 as an alternative. It seems to work.
+
+Libfuse can be build with Android NDK[3]. If success, you will get libfuse.a and an example program fusexmp. To run the example, the android kernel should be built with FUSE kernel support.
+
+References:
+[1]. http://fuse.sourceforge.net
+[2]. http://stackoverflow.com/questions/4610086/pthread-cancel-alternatives-in-android-ndk
+[3]. http://developer.android.com/sdk/ndk/index.html
diff --git a/fuse/cuse_lowlevel.c b/fuse/cuse_lowlevel.c
new file mode 100644
index 0000000..970df7f
--- /dev/null
+++ b/fuse/cuse_lowlevel.c
@@ -0,0 +1,371 @@
+/*
+  CUSE: Character device in Userspace
+  Copyright (C) 2008       SUSE Linux Products GmbH
+  Copyright (C) 2008       Tejun Heo <teheo@suse.de>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB.
+*/
+
+#include "cuse_lowlevel.h"
+#include "fuse_kernel.h"
+#include "fuse_i.h"
+#include "fuse_opt.h"
+#include "fuse_misc.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <errno.h>
+#include <unistd.h>
+
+struct cuse_data {
+	struct cuse_lowlevel_ops	clop;
+	unsigned			max_read;
+	unsigned			dev_major;
+	unsigned			dev_minor;
+	unsigned			flags;
+	unsigned			dev_info_len;
+	char				dev_info[];
+};
+
+static struct cuse_lowlevel_ops *req_clop(fuse_req_t req)
+{
+	return &req->f->cuse_data->clop;
+}
+
+static void cuse_fll_open(fuse_req_t req, fuse_ino_t ino,
+			  struct fuse_file_info *fi)
+{
+	(void)ino;
+	req_clop(req)->open(req, fi);
+}
+
+static void cuse_fll_read(fuse_req_t req, fuse_ino_t ino, size_t size,
+			  off64_t off, struct fuse_file_info *fi)
+{
+	(void)ino;
+	req_clop(req)->read(req, size, off, fi);
+}
+
+static void cuse_fll_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
+			   size_t size, off64_t off, struct fuse_file_info *fi)
+{
+	(void)ino;
+	req_clop(req)->write(req, buf, size, off, fi);
+}
+
+static void cuse_fll_flush(fuse_req_t req, fuse_ino_t ino,
+			   struct fuse_file_info *fi)
+{
+	(void)ino;
+	req_clop(req)->flush(req, fi);
+}
+
+static void cuse_fll_release(fuse_req_t req, fuse_ino_t ino,
+			     struct fuse_file_info *fi)
+{
+	(void)ino;
+	req_clop(req)->release(req, fi);
+}
+
+static void cuse_fll_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
+			   struct fuse_file_info *fi)
+{
+	(void)ino;
+	req_clop(req)->fsync(req, datasync, fi);
+}
+
+static void cuse_fll_ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg,
+		       struct fuse_file_info *fi, unsigned int flags,
+		       const void *in_buf, size_t in_bufsz, size_t out_bufsz)
+{
+	(void)ino;
+	req_clop(req)->ioctl(req, cmd, arg, fi, flags, in_buf, in_bufsz,
+			     out_bufsz);
+}
+
+static void cuse_fll_poll(fuse_req_t req, fuse_ino_t ino,
+			  struct fuse_file_info *fi, struct fuse_pollhandle *ph)
+{
+	(void)ino;
+	req_clop(req)->poll(req, fi, ph);
+}
+
+static size_t cuse_pack_info(int argc, const char **argv, char *buf)
+{
+	size_t size = 0;
+	int i;
+
+	for (i = 0; i < argc; i++) {
+		size_t len;
+
+		len = strlen(argv[i]) + 1;
+		size += len;
+		if (buf) {
+			memcpy(buf, argv[i], len);
+			buf += len;
+		}
+	}
+
+	return size;
+}
+
+static struct cuse_data *cuse_prep_data(const struct cuse_info *ci,
+					const struct cuse_lowlevel_ops *clop)
+{
+	struct cuse_data *cd;
+	size_t dev_info_len;
+
+	dev_info_len = cuse_pack_info(ci->dev_info_argc, ci->dev_info_argv,
+				      NULL);
+
+	if (dev_info_len > CUSE_INIT_INFO_MAX) {
+		fprintf(stderr, "cuse: dev_info (%zu) too large, limit=%u\n",
+			dev_info_len, CUSE_INIT_INFO_MAX);
+		return NULL;
+	}
+
+	cd = calloc(1, sizeof(*cd) + dev_info_len);
+	if (!cd) {
+		fprintf(stderr, "cuse: failed to allocate cuse_data\n");
+		return NULL;
+	}
+
+	memcpy(&cd->clop, clop, sizeof(cd->clop));
+	cd->max_read = 131072;
+	cd->dev_major = ci->dev_major;
+	cd->dev_minor = ci->dev_minor;
+	cd->dev_info_len = dev_info_len;
+	cd->flags = ci->flags;
+	cuse_pack_info(ci->dev_info_argc, ci->dev_info_argv, cd->dev_info);
+
+	return cd;
+}
+
+struct fuse_session *cuse_lowlevel_new(struct fuse_args *args,
+				       const struct cuse_info *ci,
+				       const struct cuse_lowlevel_ops *clop,
+				       void *userdata)
+{
+	struct fuse_lowlevel_ops lop;
+	struct cuse_data *cd;
+	struct fuse_session *se;
+	struct fuse_ll *ll;
+
+	cd = cuse_prep_data(ci, clop);
+	if (!cd)
+		return NULL;
+
+	memset(&lop, 0, sizeof(lop));
+	lop.init	= clop->init;
+	lop.destroy	= clop->destroy;
+	lop.open	= clop->open		? cuse_fll_open		: NULL;
+	lop.read	= clop->read		? cuse_fll_read		: NULL;
+	lop.write	= clop->write		? cuse_fll_write	: NULL;
+	lop.flush	= clop->flush		? cuse_fll_flush	: NULL;
+	lop.release	= clop->release		? cuse_fll_release	: NULL;
+	lop.fsync	= clop->fsync		? cuse_fll_fsync	: NULL;
+	lop.ioctl	= clop->ioctl		? cuse_fll_ioctl	: NULL;
+	lop.poll	= clop->poll		? cuse_fll_poll		: NULL;
+
+	se = fuse_lowlevel_new_common(args, &lop, sizeof(lop), userdata);
+	if (!se) {
+		free(cd);
+		return NULL;
+	}
+	ll = se->data;
+	ll->cuse_data = cd;
+
+	return se;
+}
+
+static int cuse_reply_init(fuse_req_t req, struct cuse_init_out *arg,
+			   char *dev_info, unsigned dev_info_len)
+{
+	struct iovec iov[3];
+
+	iov[1].iov_base = arg;
+	iov[1].iov_len = sizeof(struct cuse_init_out);
+	iov[2].iov_base = dev_info;
+	iov[2].iov_len = dev_info_len;
+
+	return fuse_send_reply_iov_nofree(req, 0, iov, 3);
+}
+
+void cuse_lowlevel_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_init_in *arg = (struct fuse_init_in *) inarg;
+	struct cuse_init_out outarg;
+	struct fuse_ll *f = req->f;
+	struct cuse_data *cd = f->cuse_data;
+	size_t bufsize = fuse_chan_bufsize(req->ch);
+	struct cuse_lowlevel_ops *clop = req_clop(req);
+
+	(void) nodeid;
+	if (f->debug) {
+		fprintf(stderr, "CUSE_INIT: %u.%u\n", arg->major, arg->minor);
+		fprintf(stderr, "flags=0x%08x\n", arg->flags);
+	}
+	f->conn.proto_major = arg->major;
+	f->conn.proto_minor = arg->minor;
+	f->conn.capable = 0;
+	f->conn.want = 0;
+
+	if (arg->major < 7) {
+		fprintf(stderr, "fuse: unsupported protocol version: %u.%u\n",
+			arg->major, arg->minor);
+		fuse_reply_err(req, EPROTO);
+		return;
+	}
+
+	if (bufsize < FUSE_MIN_READ_BUFFER) {
+		fprintf(stderr, "fuse: warning: buffer size too small: %zu\n",
+			bufsize);
+		bufsize = FUSE_MIN_READ_BUFFER;
+	}
+
+	bufsize -= 4096;
+	if (bufsize < f->conn.max_write)
+		f->conn.max_write = bufsize;
+
+	f->got_init = 1;
+	if (f->op.init)
+		f->op.init(f->userdata, &f->conn);
+
+	memset(&outarg, 0, sizeof(outarg));
+	outarg.major = FUSE_KERNEL_VERSION;
+	outarg.minor = FUSE_KERNEL_MINOR_VERSION;
+	outarg.flags = cd->flags;
+	outarg.max_read = cd->max_read;
+	outarg.max_write = f->conn.max_write;
+	outarg.dev_major = cd->dev_major;
+	outarg.dev_minor = cd->dev_minor;
+
+	if (f->debug) {
+		fprintf(stderr, "   CUSE_INIT: %u.%u\n",
+			outarg.major, outarg.minor);
+		fprintf(stderr, "   flags=0x%08x\n", outarg.flags);
+		fprintf(stderr, "   max_read=0x%08x\n", outarg.max_read);
+		fprintf(stderr, "   max_write=0x%08x\n", outarg.max_write);
+		fprintf(stderr, "   dev_major=%u\n", outarg.dev_major);
+		fprintf(stderr, "   dev_minor=%u\n", outarg.dev_minor);
+		fprintf(stderr, "   dev_info: %.*s\n", cd->dev_info_len,
+			cd->dev_info);
+	}
+
+	cuse_reply_init(req, &outarg, cd->dev_info, cd->dev_info_len);
+
+	if (clop->init_done)
+		clop->init_done(f->userdata);
+
+	fuse_free_req(req);
+}
+
+struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[],
+					 const struct cuse_info *ci,
+					 const struct cuse_lowlevel_ops *clop,
+					 int *multithreaded, void *userdata)
+{
+	const char *devname = "/dev/cuse";
+	static const struct fuse_opt kill_subtype_opts[] = {
+		FUSE_OPT_KEY("subtype=",  FUSE_OPT_KEY_DISCARD),
+		FUSE_OPT_END
+	};
+	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
+	struct fuse_session *se;
+	struct fuse_chan *ch;
+	int fd;
+	int foreground;
+	int res;
+
+	res = fuse_parse_cmdline(&args, NULL, multithreaded, &foreground);
+	if (res == -1)
+		goto err_args;
+
+	res = fuse_opt_parse(&args, NULL, kill_subtype_opts, NULL);
+	if (res == -1)
+		goto err_args;
+
+	/*
+	 * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
+	 * would ensue.
+	 */
+	do {
+		fd = open("/dev/null", O_RDWR);
+		if (fd > 2)
+			close(fd);
+	} while (fd >= 0 && fd <= 2);
+
+	se = cuse_lowlevel_new(&args, ci, clop, userdata);
+	fuse_opt_free_args(&args);
+	if (se == NULL)
+		goto err_args;
+
+	fd = open(devname, O_RDWR);
+	if (fd == -1) {
+		if (errno == ENODEV || errno == ENOENT)
+			fprintf(stderr, "fuse: device not found, try 'modprobe cuse' first\n");
+		else
+			fprintf(stderr, "fuse: failed to open %s: %s\n",
+				devname, strerror(errno));
+		goto err_se;
+	}
+
+	ch = fuse_kern_chan_new(fd);
+	if (!ch) {
+		close(fd);
+		goto err_se;
+	}
+
+	fuse_session_add_chan(se, ch);
+
+	res = fuse_set_signal_handlers(se);
+	if (res == -1)
+		goto err_se;
+
+	res = fuse_daemonize(foreground);
+	if (res == -1)
+		goto err_sig;
+
+	return se;
+
+err_sig:
+	fuse_remove_signal_handlers(se);
+err_se:
+	fuse_session_destroy(se);
+err_args:
+	fuse_opt_free_args(&args);
+	return NULL;
+}
+
+void cuse_lowlevel_teardown(struct fuse_session *se)
+{
+	fuse_remove_signal_handlers(se);
+	fuse_session_destroy(se);
+}
+
+int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci,
+		       const struct cuse_lowlevel_ops *clop, void *userdata)
+{
+	struct fuse_session *se;
+	int multithreaded;
+	int res;
+
+	se = cuse_lowlevel_setup(argc, argv, ci, clop, &multithreaded,
+				 userdata);
+	if (se == NULL)
+		return 1;
+
+	if (multithreaded)
+		res = fuse_session_loop_mt(se);
+	else
+		res = fuse_session_loop(se);
+
+	cuse_lowlevel_teardown(se);
+	if (res == -1)
+		return 1;
+
+	return 0;
+}
diff --git a/fuse/fuse.c b/fuse/fuse.c
new file mode 100644
index 0000000..448c9cd
--- /dev/null
+++ b/fuse/fuse.c
@@ -0,0 +1,3968 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB
+*/
+
+
+/* For pthread_rwlock_t */
+#define _GNU_SOURCE
+
+#include "fuse_i.h"
+#include "fuse_lowlevel.h"
+#include "fuse_opt.h"
+#include "fuse_misc.h"
+#include "fuse_common_compat.h"
+#include "fuse_compat.h"
+#include "fuse_kernel.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <errno.h>
+#include <signal.h>
+#include <dlfcn.h>
+#include <assert.h>
+#include <sys/param.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+
+#define FUSE_DEFAULT_INTR_SIGNAL SIGUSR1
+
+#define FUSE_UNKNOWN_INO 0xffffffff
+#define OFFSET_MAX 0x7fffffffffffffffLL
+
+struct fuse_config {
+	unsigned int uid;
+	unsigned int gid;
+	unsigned int  umask;
+	double entry_timeout;
+	double negative_timeout;
+	double attr_timeout;
+	double ac_attr_timeout;
+	int ac_attr_timeout_set;
+	int noforget;
+	int debug;
+	int hard_remove;
+	int use_ino;
+	int readdir_ino;
+	int set_mode;
+	int set_uid;
+	int set_gid;
+	int direct_io;
+	int kernel_cache;
+	int auto_cache;
+	int intr;
+	int intr_signal;
+	int help;
+	char *modules;
+};
+
+struct fuse_fs {
+	struct fuse_operations op;
+	struct fuse_module *m;
+	void *user_data;
+	int compat;
+	int debug;
+};
+
+struct fusemod_so {
+	void *handle;
+	int ctr;
+};
+
+struct lock_queue_element {
+       struct lock_queue_element *next;
+       pthread_cond_t cond;
+};
+
+struct fuse {
+	struct fuse_session *se;
+	struct node **name_table;
+	size_t name_table_size;
+	struct node **id_table;
+	size_t id_table_size;
+	fuse_ino_t ctr;
+	unsigned int generation;
+	unsigned int hidectr;
+	pthread_mutex_t lock;
+	struct fuse_config conf;
+	int intr_installed;
+	struct fuse_fs *fs;
+	int nullpath_ok;
+	int curr_ticket;
+	struct lock_queue_element *lockq;
+};
+
+struct lock {
+	int type;
+	off64_t start;
+	off64_t end;
+	pid_t pid;
+	uint64_t owner;
+	struct lock *next;
+};
+
+struct node {
+	struct node *name_next;
+	struct node *id_next;
+	fuse_ino_t nodeid;
+	unsigned int generation;
+	int refctr;
+	struct node *parent;
+	char *name;
+	uint64_t nlookup;
+	int open_count;
+	struct timespec stat_updated;
+	struct timespec mtime;
+	off64_t size;
+	struct lock *locks;
+	unsigned int is_hidden : 1;
+	unsigned int cache_valid : 1;
+	int treelock;
+	int ticket;
+};
+
+struct fuse_dh {
+	pthread_mutex_t lock;
+	struct fuse *fuse;
+	fuse_req_t req;
+	char *contents;
+	int allocated;
+	unsigned len;
+	unsigned size;
+	unsigned needlen;
+	int filled;
+	uint64_t fh;
+	int error;
+	fuse_ino_t nodeid;
+};
+
+/* old dir handle */
+struct fuse_dirhandle {
+	fuse_fill_dir_t filler;
+	void *buf;
+};
+
+struct fuse_context_i {
+	struct fuse_context ctx;
+	fuse_req_t req;
+};
+
+static pthread_key_t fuse_context_key;
+static pthread_mutex_t fuse_context_lock = PTHREAD_MUTEX_INITIALIZER;
+static int fuse_context_ref;
+static struct fusemod_so *fuse_current_so;
+static struct fuse_module *fuse_modules;
+
+static int fuse_load_so_name(const char *soname)
+{
+	struct fusemod_so *so;
+
+	so = calloc(1, sizeof(struct fusemod_so));
+	if (!so) {
+		fprintf(stderr, "fuse: memory allocation failed\n");
+		return -1;
+	}
+
+	fuse_current_so = so;
+	so->handle = dlopen(soname, RTLD_NOW);
+	fuse_current_so = NULL;
+	if (!so->handle) {
+		fprintf(stderr, "fuse: %s\n", dlerror());
+		goto err;
+	}
+	if (!so->ctr) {
+		fprintf(stderr, "fuse: %s did not register any modules\n",
+			soname);
+		goto err;
+	}
+	return 0;
+
+err:
+	if (so->handle)
+		dlclose(so->handle);
+	free(so);
+	return -1;
+}
+
+static int fuse_load_so_module(const char *module)
+{
+	int res;
+	char *soname = malloc(strlen(module) + 64);
+	if (!soname) {
+		fprintf(stderr, "fuse: memory allocation failed\n");
+		return -1;
+	}
+	sprintf(soname, "libfusemod_%s.so", module);
+	res = fuse_load_so_name(soname);
+	free(soname);
+	return res;
+}
+
+static struct fuse_module *fuse_find_module(const char *module)
+{
+	struct fuse_module *m;
+	for (m = fuse_modules; m; m = m->next) {
+		if (strcmp(module, m->name) == 0) {
+			m->ctr++;
+			break;
+		}
+	}
+	return m;
+}
+
+static struct fuse_module *fuse_get_module(const char *module)
+{
+	struct fuse_module *m;
+
+	pthread_mutex_lock(&fuse_context_lock);
+	m = fuse_find_module(module);
+	if (!m) {
+		int err = fuse_load_so_module(module);
+		if (!err)
+			m = fuse_find_module(module);
+	}
+	pthread_mutex_unlock(&fuse_context_lock);
+	return m;
+}
+
+static void fuse_put_module(struct fuse_module *m)
+{
+	pthread_mutex_lock(&fuse_context_lock);
+	assert(m->ctr > 0);
+	m->ctr--;
+	if (!m->ctr && m->so) {
+		struct fusemod_so *so = m->so;
+		assert(so->ctr > 0);
+		so->ctr--;
+		if (!so->ctr) {
+			struct fuse_module **mp;
+			for (mp = &fuse_modules; *mp;) {
+				if ((*mp)->so == so)
+					*mp = (*mp)->next;
+				else
+					mp = &(*mp)->next;
+			}
+			dlclose(so->handle);
+			free(so);
+		}
+	}
+	pthread_mutex_unlock(&fuse_context_lock);
+}
+
+static struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid)
+{
+	size_t hash = nodeid % f->id_table_size;
+	struct node *node;
+
+	for (node = f->id_table[hash]; node != NULL; node = node->id_next)
+		if (node->nodeid == nodeid)
+			return node;
+
+	return NULL;
+}
+
+static struct node *get_node(struct fuse *f, fuse_ino_t nodeid)
+{
+	struct node *node = get_node_nocheck(f, nodeid);
+	if (!node) {
+		fprintf(stderr, "fuse internal error: node %llu not found\n",
+			(unsigned long long) nodeid);
+		abort();
+	}
+	return node;
+}
+
+static void free_node(struct node *node)
+{
+	free(node->name);
+	free(node);
+}
+
+static void unhash_id(struct fuse *f, struct node *node)
+{
+	size_t hash = node->nodeid % f->id_table_size;
+	struct node **nodep = &f->id_table[hash];
+
+	for (; *nodep != NULL; nodep = &(*nodep)->id_next)
+		if (*nodep == node) {
+			*nodep = node->id_next;
+			return;
+		}
+}
+
+static void hash_id(struct fuse *f, struct node *node)
+{
+	size_t hash = node->nodeid % f->id_table_size;
+	node->id_next = f->id_table[hash];
+	f->id_table[hash] = node;
+}
+
+static unsigned int name_hash(struct fuse *f, fuse_ino_t parent,
+			      const char *name)
+{
+	unsigned int hash = *name;
+
+	if (hash)
+		for (name += 1; *name != '\0'; name++)
+			hash = (hash << 5) - hash + *name;
+
+	return (hash + parent) % f->name_table_size;
+}
+
+static void unref_node(struct fuse *f, struct node *node);
+
+static void unhash_name(struct fuse *f, struct node *node)
+{
+	if (node->name) {
+		size_t hash = name_hash(f, node->parent->nodeid, node->name);
+		struct node **nodep = &f->name_table[hash];
+
+		for (; *nodep != NULL; nodep = &(*nodep)->name_next)
+			if (*nodep == node) {
+				*nodep = node->name_next;
+				node->name_next = NULL;
+				unref_node(f, node->parent);
+				free(node->name);
+				node->name = NULL;
+				node->parent = NULL;
+				return;
+			}
+		fprintf(stderr,
+			"fuse internal error: unable to unhash node: %llu\n",
+			(unsigned long long) node->nodeid);
+		abort();
+	}
+}
+
+static int hash_name(struct fuse *f, struct node *node, fuse_ino_t parentid,
+		     const char *name)
+{
+	size_t hash = name_hash(f, parentid, name);
+	struct node *parent = get_node(f, parentid);
+	node->name = strdup(name);
+	if (node->name == NULL)
+		return -1;
+
+	parent->refctr ++;
+	node->parent = parent;
+	node->name_next = f->name_table[hash];
+	f->name_table[hash] = node;
+	return 0;
+}
+
+static void delete_node(struct fuse *f, struct node *node)
+{
+	if (f->conf.debug)
+		fprintf(stderr, "DELETE: %llu\n",
+			(unsigned long long) node->nodeid);
+
+	assert(node->treelock == 0);
+	assert(!node->name);
+	unhash_id(f, node);
+	free_node(node);
+}
+
+static void unref_node(struct fuse *f, struct node *node)
+{
+	assert(node->refctr > 0);
+	node->refctr --;
+	if (!node->refctr)
+		delete_node(f, node);
+}
+
+static fuse_ino_t next_id(struct fuse *f)
+{
+	do {
+		f->ctr = (f->ctr + 1) & 0xffffffff;
+		if (!f->ctr)
+			f->generation ++;
+	} while (f->ctr == 0 || f->ctr == FUSE_UNKNOWN_INO ||
+		 get_node_nocheck(f, f->ctr) != NULL);
+	return f->ctr;
+}
+
+static struct node *lookup_node(struct fuse *f, fuse_ino_t parent,
+				const char *name)
+{
+	size_t hash = name_hash(f, parent, name);
+	struct node *node;
+
+	for (node = f->name_table[hash]; node != NULL; node = node->name_next)
+		if (node->parent->nodeid == parent &&
+		    strcmp(node->name, name) == 0)
+			return node;
+
+	return NULL;
+}
+
+static struct node *find_node(struct fuse *f, fuse_ino_t parent,
+			      const char *name)
+{
+	struct node *node;
+
+	pthread_mutex_lock(&f->lock);
+	if (!name)
+		node = get_node(f, parent);
+	else
+		node = lookup_node(f, parent, name);
+	if (node == NULL) {
+		node = (struct node *) calloc(1, sizeof(struct node));
+		if (node == NULL)
+			goto out_err;
+
+		if (f->conf.noforget)
+			node->nlookup = 1;
+		node->refctr = 1;
+		node->nodeid = next_id(f);
+		node->generation = f->generation;
+		node->open_count = 0;
+		node->is_hidden = 0;
+		node->treelock = 0;
+		node->ticket = 0;
+		if (hash_name(f, node, parent, name) == -1) {
+			free(node);
+			node = NULL;
+			goto out_err;
+		}
+		hash_id(f, node);
+	}
+	node->nlookup ++;
+out_err:
+	pthread_mutex_unlock(&f->lock);
+	return node;
+}
+
+static char *add_name(char **buf, unsigned *bufsize, char *s, const char *name)
+{
+	size_t len = strlen(name);
+
+	if (s - len <= *buf) {
+		unsigned pathlen = *bufsize - (s - *buf);
+		unsigned newbufsize = *bufsize;
+		char *newbuf;
+
+		while (newbufsize < pathlen + len + 1) {
+			if (newbufsize >= 0x80000000)
+				newbufsize = 0xffffffff;
+			else
+				newbufsize *= 2;
+		}
+
+		newbuf = realloc(*buf, newbufsize);
+		if (newbuf == NULL)
+			return NULL;
+
+		*buf = newbuf;
+		s = newbuf + newbufsize - pathlen;
+		memmove(s, newbuf + *bufsize - pathlen, pathlen);
+		*bufsize = newbufsize;
+	}
+	s -= len;
+	strncpy(s, name, len);
+	s--;
+	*s = '/';
+
+	return s;
+}
+
+static void unlock_path(struct fuse *f, fuse_ino_t nodeid, struct node *wnode,
+			struct node *end, int ticket)
+{
+	struct node *node;
+
+	if (wnode) {
+		assert(wnode->treelock == -1);
+		wnode->treelock = 0;
+		if (!wnode->ticket)
+			wnode->ticket = ticket;
+	}
+
+	for (node = get_node(f, nodeid);
+	     node != end && node->nodeid != FUSE_ROOT_ID; node = node->parent) {
+		assert(node->treelock > 0);
+		node->treelock--;
+		if (!node->ticket)
+			node->ticket = ticket;
+	}
+}
+
+static int try_get_path(struct fuse *f, fuse_ino_t nodeid, const char *name,
+			char **path, struct node **wnodep, int ticket)
+{
+	unsigned bufsize = 256;
+	char *buf;
+	char *s;
+	struct node *node;
+	struct node *wnode = NULL;
+	int err;
+
+	*path = NULL;
+
+	buf = malloc(bufsize);
+	if (buf == NULL)
+		return -ENOMEM;
+
+	s = buf + bufsize - 1;
+	*s = '\0';
+
+	if (name != NULL) {
+		s = add_name(&buf, &bufsize, s, name);
+		err = -ENOMEM;
+		if (s == NULL)
+			goto out_free;
+	}
+
+	if (wnodep) {
+		assert(ticket);
+		wnode = lookup_node(f, nodeid, name);
+		if (wnode) {
+			if (wnode->treelock != 0 ||
+			    (wnode->ticket && wnode->ticket != ticket)) {
+				if (!wnode->ticket)
+					wnode->ticket = ticket;
+				err = -EAGAIN;
+				goto out_free;
+			}
+			wnode->treelock = -1;
+			wnode->ticket = 0;
+		}
+	}
+
+	err = 0;
+	for (node = get_node(f, nodeid); node->nodeid != FUSE_ROOT_ID;
+	     node = node->parent) {
+		err = -ENOENT;
+		if (node->name == NULL || node->parent == NULL)
+			goto out_unlock;
+
+		err = -ENOMEM;
+		s = add_name(&buf, &bufsize, s, node->name);
+		if (s == NULL)
+			goto out_unlock;
+
+		if (ticket) {
+			err = -EAGAIN;
+			if (node->treelock == -1 ||
+			    (node->ticket && node->ticket != ticket))
+				goto out_unlock;
+
+			node->treelock++;
+			node->ticket = 0;
+		}
+	}
+
+	if (s[0])
+		memmove(buf, s, bufsize - (s - buf));
+	else
+		strcpy(buf, "/");
+
+	*path = buf;
+	if (wnodep)
+		*wnodep = wnode;
+
+	return 0;
+
+ out_unlock:
+	if (ticket)
+		unlock_path(f, nodeid, wnode, node, ticket);
+ out_free:
+	free(buf);
+
+	return err;
+}
+
+static void wake_up_first(struct fuse *f)
+{
+	if (f->lockq)
+		pthread_cond_signal(&f->lockq->cond);
+}
+
+static void wake_up_next(struct lock_queue_element *qe)
+{
+	if (qe->next)
+		pthread_cond_signal(&qe->next->cond);
+}
+
+static int get_ticket(struct fuse *f)
+{
+	do f->curr_ticket++;
+	while (f->curr_ticket == 0);
+
+	return f->curr_ticket;
+}
+
+static void debug_path(struct fuse *f, const char *msg, fuse_ino_t nodeid,
+		       const char *name, int wr)
+{
+	if (f->conf.debug) {
+		struct node *wnode = NULL;
+
+		if (wr)
+			wnode = lookup_node(f, nodeid, name);
+
+		if (wnode)
+			fprintf(stderr, "%s %li (w)\n",	msg, wnode->nodeid);
+		else
+			fprintf(stderr, "%s %li\n", msg, nodeid);
+	}
+}
+
+static void queue_path(struct fuse *f, struct lock_queue_element *qe,
+		       fuse_ino_t nodeid, const char *name, int wr)
+{
+	struct lock_queue_element **qp;
+
+	debug_path(f, "QUEUE PATH", nodeid, name, wr);
+	pthread_cond_init(&qe->cond, NULL);
+	qe->next = NULL;
+	for (qp = &f->lockq; *qp != NULL; qp = &(*qp)->next);
+	*qp = qe;
+}
+
+static void dequeue_path(struct fuse *f, struct lock_queue_element *qe,
+			 fuse_ino_t nodeid, const char *name, int wr)
+{
+	struct lock_queue_element **qp;
+
+	debug_path(f, "DEQUEUE PATH", nodeid, name, wr);
+	pthread_cond_destroy(&qe->cond);
+	for (qp = &f->lockq; *qp != qe; qp = &(*qp)->next);
+	*qp = qe->next;
+}
+
+static void wait_on_path(struct fuse *f, struct lock_queue_element *qe,
+			 fuse_ino_t nodeid, const char *name, int wr)
+{
+	debug_path(f, "WAIT ON PATH", nodeid, name, wr);
+	pthread_cond_wait(&qe->cond, &f->lock);
+}
+
+static int get_path_common(struct fuse *f, fuse_ino_t nodeid, const char *name,
+			   char **path, struct node **wnode)
+{
+	int err;
+	int ticket;
+
+	pthread_mutex_lock(&f->lock);
+	ticket = get_ticket(f);
+	err = try_get_path(f, nodeid, name, path, wnode, ticket);
+	if (err == -EAGAIN) {
+		struct lock_queue_element qe;
+
+		queue_path(f, &qe, nodeid, name, !!wnode);
+		do {
+			wait_on_path(f, &qe, nodeid, name, !!wnode);
+			err = try_get_path(f, nodeid, name, path, wnode,
+					   ticket);
+			wake_up_next(&qe);
+		} while (err == -EAGAIN);
+		dequeue_path(f, &qe, nodeid, name, !!wnode);
+	}
+	pthread_mutex_unlock(&f->lock);
+
+	return err;
+}
+
+static int get_path(struct fuse *f, fuse_ino_t nodeid, char **path)
+{
+	return get_path_common(f, nodeid, NULL, path, NULL);
+}
+
+static int get_path_nullok(struct fuse *f, fuse_ino_t nodeid, char **path)
+{
+	int err = get_path_common(f, nodeid, NULL, path, NULL);
+
+	if (err == -ENOENT && f->nullpath_ok)
+		err = 0;
+
+	return err;
+}
+
+static int get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name,
+			 char **path)
+{
+	return get_path_common(f, nodeid, name, path, NULL);
+}
+
+static int get_path_wrlock(struct fuse *f, fuse_ino_t nodeid, const char *name,
+			   char **path, struct node **wnode)
+{
+	return get_path_common(f, nodeid, name, path, wnode);
+}
+
+static int try_get_path2(struct fuse *f, fuse_ino_t nodeid1, const char *name1,
+			 fuse_ino_t nodeid2, const char *name2,
+			 char **path1, char **path2,
+			 struct node **wnode1, struct node **wnode2,
+			 int ticket)
+{
+	int err;
+
+	/* FIXME: locking two paths needs deadlock checking */
+	err = try_get_path(f, nodeid1, name1, path1, wnode1, ticket);
+	if (!err) {
+		err = try_get_path(f, nodeid2, name2, path2, wnode2, ticket);
+		if (err)
+			unlock_path(f, nodeid1, wnode1 ? *wnode1 : NULL, NULL,
+				    ticket);
+	}
+	return err;
+}
+
+static int get_path2(struct fuse *f, fuse_ino_t nodeid1, const char *name1,
+		     fuse_ino_t nodeid2, const char *name2,
+		     char **path1, char **path2,
+		     struct node **wnode1, struct node **wnode2)
+{
+	int err;
+	int ticket;
+
+	pthread_mutex_lock(&f->lock);
+	ticket = get_ticket(f);
+	err = try_get_path2(f, nodeid1, name1, nodeid2, name2,
+			    path1, path2, wnode1, wnode2, ticket);
+	if (err == -EAGAIN) {
+		struct lock_queue_element qe;
+
+		queue_path(f, &qe, nodeid1, name1, !!wnode1);
+		debug_path(f, "      path2", nodeid2, name2, !!wnode2);
+		do {
+			wait_on_path(f, &qe, nodeid1, name1, !!wnode1);
+			debug_path(f, "        path2", nodeid2, name2, !!wnode2);
+			err = try_get_path2(f, nodeid1, name1, nodeid2, name2,
+					    path1, path2, wnode1, wnode2,
+					    ticket);
+			wake_up_next(&qe);
+		} while (err == -EAGAIN);
+		dequeue_path(f, &qe, nodeid1, name1, !!wnode1);
+		debug_path(f, "        path2", nodeid2, name2, !!wnode2);
+	}
+	pthread_mutex_unlock(&f->lock);
+
+	return err;
+}
+
+static void free_path_wrlock(struct fuse *f, fuse_ino_t nodeid,
+			     struct node *wnode, char *path)
+{
+	pthread_mutex_lock(&f->lock);
+	unlock_path(f, nodeid, wnode, NULL, 0);
+	wake_up_first(f);
+	pthread_mutex_unlock(&f->lock);
+	free(path);
+}
+
+static void free_path(struct fuse *f, fuse_ino_t nodeid, char *path)
+{
+	if (path)
+		free_path_wrlock(f, nodeid, NULL, path);
+}
+
+static void free_path2(struct fuse *f, fuse_ino_t nodeid1, fuse_ino_t nodeid2,
+		       struct node *wnode1, struct node *wnode2,
+		       char *path1, char *path2)
+{
+	pthread_mutex_lock(&f->lock);
+	unlock_path(f, nodeid1, wnode1, NULL, 0);
+	unlock_path(f, nodeid2, wnode2, NULL, 0);
+	wake_up_first(f);
+	pthread_mutex_unlock(&f->lock);
+	free(path1);
+	free(path2);
+}
+
+static void forget_node(struct fuse *f, fuse_ino_t nodeid, uint64_t nlookup)
+{
+	struct node *node;
+	if (nodeid == FUSE_ROOT_ID)
+		return;
+	pthread_mutex_lock(&f->lock);
+	node = get_node(f, nodeid);
+
+	/*
+	 * Node may still be locked due to interrupt idiocy in open,
+	 * create and opendir
+	 */
+	while (node->nlookup == nlookup && node->treelock) {
+		struct lock_queue_element qe;
+
+		queue_path(f, &qe, node->nodeid, NULL, 0);
+		do {
+			wait_on_path(f, &qe, node->nodeid, NULL, 0);
+			wake_up_next(&qe);
+
+		} while (node->nlookup == nlookup && node->treelock);
+		dequeue_path(f, &qe, node->nodeid, NULL, 0);
+	}
+
+	assert(node->nlookup >= nlookup);
+	node->nlookup -= nlookup;
+	if (!node->nlookup) {
+		unhash_name(f, node);
+		unref_node(f, node);
+	}
+	pthread_mutex_unlock(&f->lock);
+}
+
+static void unlink_node(struct fuse *f, struct node *node)
+{
+	if (f->conf.noforget) {
+		assert(node->nlookup > 1);
+		node->nlookup--;
+	}
+	unhash_name(f, node);
+}
+
+static void remove_node(struct fuse *f, fuse_ino_t dir, const char *name)
+{
+	struct node *node;
+
+	pthread_mutex_lock(&f->lock);
+	node = lookup_node(f, dir, name);
+	if (node != NULL)
+		unlink_node(f, node);
+	pthread_mutex_unlock(&f->lock);
+}
+
+static int rename_node(struct fuse *f, fuse_ino_t olddir, const char *oldname,
+		       fuse_ino_t newdir, const char *newname, int hide)
+{
+	struct node *node;
+	struct node *newnode;
+	int err = 0;
+
+	pthread_mutex_lock(&f->lock);
+	node  = lookup_node(f, olddir, oldname);
+	newnode	 = lookup_node(f, newdir, newname);
+	if (node == NULL)
+		goto out;
+
+	if (newnode != NULL) {
+		if (hide) {
+			fprintf(stderr, "fuse: hidden file got created during hiding\n");
+			err = -EBUSY;
+			goto out;
+		}
+		unlink_node(f, newnode);
+	}
+
+	unhash_name(f, node);
+	if (hash_name(f, node, newdir, newname) == -1) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	if (hide)
+		node->is_hidden = 1;
+
+out:
+	pthread_mutex_unlock(&f->lock);
+	return err;
+}
+
+static void set_stat(struct fuse *f, fuse_ino_t nodeid, struct stat *stbuf)
+{
+	if (!f->conf.use_ino)
+		stbuf->st_ino = nodeid;
+	if (f->conf.set_mode)
+		stbuf->st_mode = (stbuf->st_mode & S_IFMT) |
+				 (0777 & ~f->conf.umask);
+	if (f->conf.set_uid)
+		stbuf->st_uid = f->conf.uid;
+	if (f->conf.set_gid)
+		stbuf->st_gid = f->conf.gid;
+}
+
+static struct fuse *req_fuse(fuse_req_t req)
+{
+	return (struct fuse *) fuse_req_userdata(req);
+}
+
+static void fuse_intr_sighandler(int sig)
+{
+	(void) sig;
+	/* Nothing to do */
+}
+
+struct fuse_intr_data {
+	pthread_t id;
+	pthread_cond_t cond;
+	int finished;
+};
+
+static void fuse_interrupt(fuse_req_t req, void *d_)
+{
+	struct fuse_intr_data *d = d_;
+	struct fuse *f = req_fuse(req);
+
+	if (d->id == pthread_self())
+		return;
+
+	pthread_mutex_lock(&f->lock);
+	while (!d->finished) {
+		struct timeval now;
+		struct timespec timeout;
+
+		pthread_kill(d->id, f->conf.intr_signal);
+		gettimeofday(&now, NULL);
+		timeout.tv_sec = now.tv_sec + 1;
+		timeout.tv_nsec = now.tv_usec * 1000;
+		pthread_cond_timedwait(&d->cond, &f->lock, &timeout);
+	}
+	pthread_mutex_unlock(&f->lock);
+}
+
+static void fuse_do_finish_interrupt(struct fuse *f, fuse_req_t req,
+				     struct fuse_intr_data *d)
+{
+	pthread_mutex_lock(&f->lock);
+	d->finished = 1;
+	pthread_cond_broadcast(&d->cond);
+	pthread_mutex_unlock(&f->lock);
+	fuse_req_interrupt_func(req, NULL, NULL);
+	pthread_cond_destroy(&d->cond);
+}
+
+static void fuse_do_prepare_interrupt(fuse_req_t req, struct fuse_intr_data *d)
+{
+	d->id = pthread_self();
+	pthread_cond_init(&d->cond, NULL);
+	d->finished = 0;
+	fuse_req_interrupt_func(req, fuse_interrupt, d);
+}
+
+static inline void fuse_finish_interrupt(struct fuse *f, fuse_req_t req,
+					 struct fuse_intr_data *d)
+{
+	if (f->conf.intr)
+		fuse_do_finish_interrupt(f, req, d);
+}
+
+static inline void fuse_prepare_interrupt(struct fuse *f, fuse_req_t req,
+					  struct fuse_intr_data *d)
+{
+	if (f->conf.intr)
+		fuse_do_prepare_interrupt(req, d);
+}
+
+#ifndef __FreeBSD__
+
+static int fuse_compat_open(struct fuse_fs *fs, const char *path,
+			    struct fuse_file_info *fi)
+{
+	int err;
+	if (!fs->compat || fs->compat >= 25)
+		err = fs->op.open(path, fi);
+	else if (fs->compat == 22) {
+		struct fuse_file_info_compat tmp;
+		memcpy(&tmp, fi, sizeof(tmp));
+		err = ((struct fuse_operations_compat22 *) &fs->op)->open(path,
+									  &tmp);
+		memcpy(fi, &tmp, sizeof(tmp));
+		fi->fh = tmp.fh;
+	} else
+		err = ((struct fuse_operations_compat2 *) &fs->op)
+			->open(path, fi->flags);
+	return err;
+}
+
+static int fuse_compat_release(struct fuse_fs *fs, const char *path,
+			       struct fuse_file_info *fi)
+{
+	if (!fs->compat || fs->compat >= 22)
+		return fs->op.release(path, fi);
+	else
+		return ((struct fuse_operations_compat2 *) &fs->op)
+			->release(path, fi->flags);
+}
+
+static int fuse_compat_opendir(struct fuse_fs *fs, const char *path,
+			       struct fuse_file_info *fi)
+{
+	if (!fs->compat || fs->compat >= 25)
+		return fs->op.opendir(path, fi);
+	else {
+		int err;
+		struct fuse_file_info_compat tmp;
+		memcpy(&tmp, fi, sizeof(tmp));
+		err = ((struct fuse_operations_compat22 *) &fs->op)
+			->opendir(path, &tmp);
+		memcpy(fi, &tmp, sizeof(tmp));
+		fi->fh = tmp.fh;
+		return err;
+	}
+}
+
+static void convert_statfs_compat(struct fuse_statfs_compat1 *compatbuf,
+				  struct statvfs *stbuf)
+{
+	stbuf->f_bsize	 = compatbuf->block_size;
+	stbuf->f_blocks	 = compatbuf->blocks;
+	stbuf->f_bfree	 = compatbuf->blocks_free;
+	stbuf->f_bavail	 = compatbuf->blocks_free;
+	stbuf->f_files	 = compatbuf->files;
+	stbuf->f_ffree	 = compatbuf->files_free;
+	stbuf->f_namemax = compatbuf->namelen;
+}
+
+static void convert_statfs_old(struct statfs *oldbuf, struct statvfs *stbuf)
+{
+	stbuf->f_bsize	 = oldbuf->f_bsize;
+	stbuf->f_blocks	 = oldbuf->f_blocks;
+	stbuf->f_bfree	 = oldbuf->f_bfree;
+	stbuf->f_bavail	 = oldbuf->f_bavail;
+	stbuf->f_files	 = oldbuf->f_files;
+	stbuf->f_ffree	 = oldbuf->f_ffree;
+	stbuf->f_namemax = oldbuf->f_namelen;
+}
+
+static int fuse_compat_statfs(struct fuse_fs *fs, const char *path,
+			      struct statvfs *buf)
+{
+	int err;
+
+	if (!fs->compat || fs->compat >= 25) {
+		err = fs->op.statfs(fs->compat == 25 ? "/" : path, buf);
+	} else if (fs->compat > 11) {
+		struct statfs oldbuf;
+		err = ((struct fuse_operations_compat22 *) &fs->op)
+			->statfs("/", &oldbuf);
+		if (!err)
+			convert_statfs_old(&oldbuf, buf);
+	} else {
+		struct fuse_statfs_compat1 compatbuf;
+		memset(&compatbuf, 0, sizeof(struct fuse_statfs_compat1));
+		err = ((struct fuse_operations_compat1 *) &fs->op)
+			->statfs(&compatbuf);
+		if (!err)
+			convert_statfs_compat(&compatbuf, buf);
+	}
+	return err;
+}
+
+#else /* __FreeBSD__ */
+
+static inline int fuse_compat_open(struct fuse_fs *fs, char *path,
+				   struct fuse_file_info *fi)
+{
+	return fs->op.open(path, fi);
+}
+
+static inline int fuse_compat_release(struct fuse_fs *fs, const char *path,
+				      struct fuse_file_info *fi)
+{
+	return fs->op.release(path, fi);
+}
+
+static inline int fuse_compat_opendir(struct fuse_fs *fs, const char *path,
+				      struct fuse_file_info *fi)
+{
+	return fs->op.opendir(path, fi);
+}
+
+static inline int fuse_compat_statfs(struct fuse_fs *fs, const char *path,
+				     struct statvfs *buf)
+{
+	return fs->op.statfs(fs->compat == 25 ? "/" : path, buf);
+}
+
+#endif /* __FreeBSD__ */
+
+int fuse_fs_getattr(struct fuse_fs *fs, const char *path, struct stat *buf)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.getattr) {
+		if (fs->debug)
+			fprintf(stderr, "getattr %s\n", path);
+
+		return fs->op.getattr(path, buf);
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_fgetattr(struct fuse_fs *fs, const char *path, struct stat *buf,
+		     struct fuse_file_info *fi)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.fgetattr) {
+		if (fs->debug)
+			fprintf(stderr, "fgetattr[%llu] %s\n",
+				(unsigned long long) fi->fh, path);
+
+		return fs->op.fgetattr(path, buf, fi);
+	} else if (path && fs->op.getattr) {
+		if (fs->debug)
+			fprintf(stderr, "getattr %s\n", path);
+
+		return fs->op.getattr(path, buf);
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath,
+		   const char *newpath)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.rename) {
+		if (fs->debug)
+			fprintf(stderr, "rename %s %s\n", oldpath, newpath);
+
+		return fs->op.rename(oldpath, newpath);
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_unlink(struct fuse_fs *fs, const char *path)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.unlink) {
+		if (fs->debug)
+			fprintf(stderr, "unlink %s\n", path);
+
+		return fs->op.unlink(path);
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_rmdir(struct fuse_fs *fs, const char *path)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.rmdir) {
+		if (fs->debug)
+			fprintf(stderr, "rmdir %s\n", path);
+
+		return fs->op.rmdir(path);
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_symlink(struct fuse_fs *fs, const char *linkname, const char *path)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.symlink) {
+		if (fs->debug)
+			fprintf(stderr, "symlink %s %s\n", linkname, path);
+
+		return fs->op.symlink(linkname, path);
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_link(struct fuse_fs *fs, const char *oldpath, const char *newpath)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.link) {
+		if (fs->debug)
+			fprintf(stderr, "link %s %s\n", oldpath, newpath);
+
+		return fs->op.link(oldpath, newpath);
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_release(struct fuse_fs *fs,	 const char *path,
+		    struct fuse_file_info *fi)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.release) {
+		if (fs->debug)
+			fprintf(stderr, "release%s[%llu] flags: 0x%x\n",
+				fi->flush ? "+flush" : "",
+				(unsigned long long) fi->fh, fi->flags);
+
+		return fuse_compat_release(fs, path, fi);
+	} else {
+		return 0;
+	}
+}
+
+int fuse_fs_opendir(struct fuse_fs *fs, const char *path,
+		    struct fuse_file_info *fi)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.opendir) {
+		int err;
+
+		if (fs->debug)
+			fprintf(stderr, "opendir flags: 0x%x %s\n", fi->flags,
+				path);
+
+		err = fuse_compat_opendir(fs, path, fi);
+
+		if (fs->debug && !err)
+			fprintf(stderr, "   opendir[%lli] flags: 0x%x %s\n",
+				(unsigned long long) fi->fh, fi->flags, path);
+
+		return err;
+	} else {
+		return 0;
+	}
+}
+
+int fuse_fs_open(struct fuse_fs *fs, const char *path,
+		 struct fuse_file_info *fi)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.open) {
+		int err;
+
+		if (fs->debug)
+			fprintf(stderr, "open flags: 0x%x %s\n", fi->flags,
+				path);
+
+		err = fuse_compat_open(fs, path, fi);
+
+		if (fs->debug && !err)
+			fprintf(stderr, "   open[%lli] flags: 0x%x %s\n",
+				(unsigned long long) fi->fh, fi->flags, path);
+
+		return err;
+	} else {
+		return 0;
+	}
+}
+
+int fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size,
+		 off64_t off, struct fuse_file_info *fi)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.read) {
+		int res;
+
+		if (fs->debug)
+			fprintf(stderr,
+				"read[%llu] %lu bytes from %llu flags: 0x%x\n",
+				(unsigned long long) fi->fh,
+				(unsigned long) size, (unsigned long long) off,
+				fi->flags);
+
+		res = fs->op.read(path, buf, size, off, fi);
+
+		if (fs->debug && res >= 0)
+			fprintf(stderr, "   read[%llu] %u bytes from %llu\n",
+				(unsigned long long) fi->fh, res,
+				(unsigned long long) off);
+		if (res > (int) size)
+			fprintf(stderr, "fuse: read too many bytes\n");
+
+		return res;
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *buf,
+		  size_t size, off64_t off, struct fuse_file_info *fi)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.write) {
+		int res;
+
+		if (fs->debug)
+			fprintf(stderr,
+				"write%s[%llu] %lu bytes to %llu flags: 0x%x\n",
+				fi->writepage ? "page" : "",
+				(unsigned long long) fi->fh,
+				(unsigned long) size, (unsigned long long) off,
+				fi->flags);
+
+		res = fs->op.write(path, buf, size, off, fi);
+
+		if (fs->debug && res >= 0)
+			fprintf(stderr, "   write%s[%llu] %u bytes to %llu\n",
+				fi->writepage ? "page" : "",
+				(unsigned long long) fi->fh, res,
+				(unsigned long long) off);
+		if (res > (int) size)
+			fprintf(stderr, "fuse: wrote too many bytes\n");
+
+		return res;
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync,
+		  struct fuse_file_info *fi)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.fsync) {
+		if (fs->debug)
+			fprintf(stderr, "fsync[%llu] datasync: %i\n",
+				(unsigned long long) fi->fh, datasync);
+
+		return fs->op.fsync(path, datasync, fi);
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync,
+		     struct fuse_file_info *fi)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.fsyncdir) {
+		if (fs->debug)
+			fprintf(stderr, "fsyncdir[%llu] datasync: %i\n",
+				(unsigned long long) fi->fh, datasync);
+
+		return fs->op.fsyncdir(path, datasync, fi);
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_flush(struct fuse_fs *fs, const char *path,
+		  struct fuse_file_info *fi)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.flush) {
+		if (fs->debug)
+			fprintf(stderr, "flush[%llu]\n",
+				(unsigned long long) fi->fh);
+
+		return fs->op.flush(path, fi);
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.statfs) {
+		if (fs->debug)
+			fprintf(stderr, "statfs %s\n", path);
+
+		return fuse_compat_statfs(fs, path, buf);
+	} else {
+		buf->f_namemax = 255;
+		buf->f_bsize = 512;
+		return 0;
+	}
+}
+
+int fuse_fs_releasedir(struct fuse_fs *fs, const char *path,
+		       struct fuse_file_info *fi)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.releasedir) {
+		if (fs->debug)
+			fprintf(stderr, "releasedir[%llu] flags: 0x%x\n",
+				(unsigned long long) fi->fh, fi->flags);
+
+		return fs->op.releasedir(path, fi);
+	} else {
+		return 0;
+	}
+}
+
+static int fill_dir_old(struct fuse_dirhandle *dh, const char *name, int type,
+			ino_t ino)
+{
+	int res;
+	struct stat stbuf;
+
+	memset(&stbuf, 0, sizeof(stbuf));
+	stbuf.st_mode = type << 12;
+	stbuf.st_ino = ino;
+
+	res = dh->filler(dh->buf, name, &stbuf, 0);
+	return res ? -ENOMEM : 0;
+}
+
+int fuse_fs_readdir(struct fuse_fs *fs, const char *path, void *buf,
+		    fuse_fill_dir_t filler, off64_t off,
+		    struct fuse_file_info *fi)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.readdir) {
+		if (fs->debug)
+			fprintf(stderr, "readdir[%llu] from %llu\n",
+				(unsigned long long) fi->fh,
+				(unsigned long long) off);
+
+		return fs->op.readdir(path, buf, filler, off, fi);
+	} else if (fs->op.getdir) {
+		struct fuse_dirhandle dh;
+
+		if (fs->debug)
+			fprintf(stderr, "getdir[%llu]\n",
+				(unsigned long long) fi->fh);
+
+		dh.filler = filler;
+		dh.buf = buf;
+		return fs->op.getdir(path, &dh, fill_dir_old);
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode,
+		   struct fuse_file_info *fi)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.create) {
+		int err;
+
+		if (fs->debug)
+			fprintf(stderr,
+				"create flags: 0x%x %s 0%o umask=0%03o\n",
+				fi->flags, path, mode,
+				fuse_get_context()->umask);
+
+		err = fs->op.create(path, mode, fi);
+
+		if (fs->debug && !err)
+			fprintf(stderr, "   create[%llu] flags: 0x%x %s\n",
+				(unsigned long long) fi->fh, fi->flags, path);
+
+		return err;
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_lock(struct fuse_fs *fs, const char *path,
+		 struct fuse_file_info *fi, int cmd, struct flock *lock)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.lock) {
+		if (fs->debug)
+			fprintf(stderr, "lock[%llu] %s %s start: %llu len: %llu pid: %llu\n",
+				(unsigned long long) fi->fh,
+				(cmd == F_GETLK ? "F_GETLK" :
+				 (cmd == F_SETLK ? "F_SETLK" :
+				  (cmd == F_SETLKW ? "F_SETLKW" : "???"))),
+				(lock->l_type == F_RDLCK ? "F_RDLCK" :
+				 (lock->l_type == F_WRLCK ? "F_WRLCK" :
+				  (lock->l_type == F_UNLCK ? "F_UNLCK" :
+				   "???"))),
+				(unsigned long long) lock->l_start,
+				(unsigned long long) lock->l_len,
+				(unsigned long long) lock->l_pid);
+
+		return fs->op.lock(path, fi, cmd, lock);
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.chown) {
+		if (fs->debug)
+			fprintf(stderr, "chown %s %lu %lu\n", path,
+				(unsigned long) uid, (unsigned long) gid);
+
+		return fs->op.chown(path, uid, gid);
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off64_t size)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.truncate) {
+		if (fs->debug)
+			fprintf(stderr, "truncate %s %llu\n", path,
+				(unsigned long long) size);
+
+		return fs->op.truncate(path, size);
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_ftruncate(struct fuse_fs *fs, const char *path, off64_t size,
+		      struct fuse_file_info *fi)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.ftruncate) {
+		if (fs->debug)
+			fprintf(stderr, "ftruncate[%llu] %s %llu\n",
+				(unsigned long long) fi->fh, path,
+				(unsigned long long) size);
+
+		return fs->op.ftruncate(path, size, fi);
+	} else if (path && fs->op.truncate) {
+		if (fs->debug)
+			fprintf(stderr, "truncate %s %llu\n", path,
+				(unsigned long long) size);
+
+		return fs->op.truncate(path, size);
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_utimens(struct fuse_fs *fs, const char *path,
+		    const struct timespec tv[2])
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.utimens) {
+		if (fs->debug)
+			fprintf(stderr, "utimens %s %li.%09lu %li.%09lu\n",
+				path, tv[0].tv_sec, tv[0].tv_nsec,
+				tv[1].tv_sec, tv[1].tv_nsec);
+
+		return fs->op.utimens(path, tv);
+	} else if(fs->op.utime) {
+		struct utimbuf buf;
+
+		if (fs->debug)
+			fprintf(stderr, "utime %s %li %li\n", path,
+				tv[0].tv_sec, tv[1].tv_sec);
+
+		buf.actime = tv[0].tv_sec;
+		buf.modtime = tv[1].tv_sec;
+		return fs->op.utime(path, &buf);
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_access(struct fuse_fs *fs, const char *path, int mask)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.access) {
+		if (fs->debug)
+			fprintf(stderr, "access %s 0%o\n", path, mask);
+
+		return fs->op.access(path, mask);
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf,
+		     size_t len)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.readlink) {
+		if (fs->debug)
+			fprintf(stderr, "readlink %s %lu\n", path,
+				(unsigned long) len);
+
+		return fs->op.readlink(path, buf, len);
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode,
+		  dev_t rdev)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.mknod) {
+		if (fs->debug)
+			fprintf(stderr, "mknod %s 0%o 0x%llx umask=0%03o\n",
+				path, mode, (unsigned long long) rdev,
+				fuse_get_context()->umask);
+
+		return fs->op.mknod(path, mode, rdev);
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.mkdir) {
+		if (fs->debug)
+			fprintf(stderr, "mkdir %s 0%o umask=0%03o\n",
+				path, mode, fuse_get_context()->umask);
+
+		return fs->op.mkdir(path, mode);
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name,
+		     const char *value, size_t size, int flags)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.setxattr) {
+		if (fs->debug)
+			fprintf(stderr, "setxattr %s %s %lu 0x%x\n",
+				path, name, (unsigned long) size, flags);
+
+		return fs->op.setxattr(path, name, value, size, flags);
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name,
+		     char *value, size_t size)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.getxattr) {
+		if (fs->debug)
+			fprintf(stderr, "getxattr %s %s %lu\n",
+				path, name, (unsigned long) size);
+
+		return fs->op.getxattr(path, name, value, size);
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list,
+		      size_t size)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.listxattr) {
+		if (fs->debug)
+			fprintf(stderr, "listxattr %s %lu\n",
+				path, (unsigned long) size);
+
+		return fs->op.listxattr(path, list, size);
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize,
+		 uint64_t *idx)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.bmap) {
+		if (fs->debug)
+			fprintf(stderr, "bmap %s blocksize: %lu index: %llu\n",
+				path, (unsigned long) blocksize,
+				(unsigned long long) *idx);
+
+		return fs->op.bmap(path, blocksize, idx);
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_removexattr(struct fuse_fs *fs, const char *path, const char *name)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.removexattr) {
+		if (fs->debug)
+			fprintf(stderr, "removexattr %s %s\n", path, name);
+
+		return fs->op.removexattr(path, name);
+	} else {
+		return -ENOSYS;
+	}
+}
+
+int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, int cmd, void *arg,
+		  struct fuse_file_info *fi, unsigned int flags, void *data)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.ioctl) {
+		if (fs->debug)
+			fprintf(stderr, "ioctl[%llu] 0x%x flags: 0x%x\n",
+				(unsigned long long) fi->fh, cmd, flags);
+
+		return fs->op.ioctl(path, cmd, arg, fi, flags, data);
+	} else
+		return -ENOSYS;
+}
+
+int fuse_fs_poll(struct fuse_fs *fs, const char *path,
+		 struct fuse_file_info *fi, struct fuse_pollhandle *ph,
+		 unsigned *reventsp)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.poll) {
+		int res;
+
+		if (fs->debug)
+			fprintf(stderr, "poll[%llu] ph: %p\n",
+				(unsigned long long) fi->fh, ph);
+
+		res = fs->op.poll(path, fi, ph, reventsp);
+
+		if (fs->debug && !res)
+			fprintf(stderr, "   poll[%llu] revents: 0x%x\n",
+				(unsigned long long) fi->fh, *reventsp);
+
+		return res;
+	} else
+		return -ENOSYS;
+}
+
+static int is_open(struct fuse *f, fuse_ino_t dir, const char *name)
+{
+	struct node *node;
+	int isopen = 0;
+	pthread_mutex_lock(&f->lock);
+	node = lookup_node(f, dir, name);
+	if (node && node->open_count > 0)
+		isopen = 1;
+	pthread_mutex_unlock(&f->lock);
+	return isopen;
+}
+
+static char *hidden_name(struct fuse *f, fuse_ino_t dir, const char *oldname,
+			 char *newname, size_t bufsize)
+{
+	struct stat buf;
+	struct node *node;
+	struct node *newnode;
+	char *newpath;
+	int res;
+	int failctr = 10;
+
+	do {
+		pthread_mutex_lock(&f->lock);
+		node = lookup_node(f, dir, oldname);
+		if (node == NULL) {
+			pthread_mutex_unlock(&f->lock);
+			return NULL;
+		}
+		do {
+			f->hidectr ++;
+			snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
+				 (unsigned int) node->nodeid, f->hidectr);
+			newnode = lookup_node(f, dir, newname);
+		} while(newnode);
+
+		try_get_path(f, dir, newname, &newpath, NULL, 0);
+		pthread_mutex_unlock(&f->lock);
+
+		if (!newpath)
+			break;
+
+		res = fuse_fs_getattr(f->fs, newpath, &buf);
+		if (res == -ENOENT)
+			break;
+		free(newpath);
+		newpath = NULL;
+	} while(res == 0 && --failctr);
+
+	return newpath;
+}
+
+static int hide_node(struct fuse *f, const char *oldpath,
+		     fuse_ino_t dir, const char *oldname)
+{
+	char newname[64];
+	char *newpath;
+	int err = -EBUSY;
+
+	newpath = hidden_name(f, dir, oldname, newname, sizeof(newname));
+	if (newpath) {
+		err = fuse_fs_rename(f->fs, oldpath, newpath);
+		if (!err)
+			err = rename_node(f, dir, oldname, dir, newname, 1);
+		free(newpath);
+	}
+	return err;
+}
+
+static int mtime_eq(const struct stat *stbuf, const struct timespec *ts)
+{
+	return stbuf->st_mtime == ts->tv_sec &&
+		ST_MTIM_NSEC(stbuf) == ts->tv_nsec;
+}
+
+#ifndef CLOCK_MONOTONIC
+#define CLOCK_MONOTONIC CLOCK_REALTIME
+#endif
+
+static void curr_time(struct timespec *now)
+{
+	static clockid_t clockid = CLOCK_MONOTONIC;
+	int res = clock_gettime(clockid, now);
+	if (res == -1 && errno == EINVAL) {
+		clockid = CLOCK_REALTIME;
+		res = clock_gettime(clockid, now);
+	}
+	if (res == -1) {
+		perror("fuse: clock_gettime");
+		abort();
+	}
+}
+
+static void update_stat(struct node *node, const struct stat *stbuf)
+{
+	if (node->cache_valid && (!mtime_eq(stbuf, &node->mtime) ||
+				  stbuf->st_size != node->size))
+		node->cache_valid = 0;
+	node->mtime.tv_sec = stbuf->st_mtime;
+	node->mtime.tv_nsec = ST_MTIM_NSEC(stbuf);
+	node->size = stbuf->st_size;
+	curr_time(&node->stat_updated);
+}
+
+static int lookup_path(struct fuse *f, fuse_ino_t nodeid,
+		       const char *name, const char *path,
+		       struct fuse_entry_param *e, struct fuse_file_info *fi)
+{
+	int res;
+
+	memset(e, 0, sizeof(struct fuse_entry_param));
+	if (fi)
+		res = fuse_fs_fgetattr(f->fs, path, &e->attr, fi);
+	else
+		res = fuse_fs_getattr(f->fs, path, &e->attr);
+	if (res == 0) {
+		struct node *node;
+
+		node = find_node(f, nodeid, name);
+		if (node == NULL)
+			res = -ENOMEM;
+		else {
+			e->ino = node->nodeid;
+			e->generation = node->generation;
+			e->entry_timeout = f->conf.entry_timeout;
+			e->attr_timeout = f->conf.attr_timeout;
+			if (f->conf.auto_cache) {
+				pthread_mutex_lock(&f->lock);
+				update_stat(node, &e->attr);
+				pthread_mutex_unlock(&f->lock);
+			}
+			set_stat(f, e->ino, &e->attr);
+			if (f->conf.debug)
+				fprintf(stderr, "   NODEID: %lu\n",
+					(unsigned long) e->ino);
+		}
+	}
+	return res;
+}
+
+static struct fuse_context_i *fuse_get_context_internal(void)
+{
+	struct fuse_context_i *c;
+
+	c = (struct fuse_context_i *) pthread_getspecific(fuse_context_key);
+	if (c == NULL) {
+		c = (struct fuse_context_i *)
+			malloc(sizeof(struct fuse_context_i));
+		if (c == NULL) {
+			/* This is hard to deal with properly, so just
+			   abort.  If memory is so low that the
+			   context cannot be allocated, there's not
+			   much hope for the filesystem anyway */
+			fprintf(stderr, "fuse: failed to allocate thread specific data\n");
+			abort();
+		}
+		pthread_setspecific(fuse_context_key, c);
+	}
+	return c;
+}
+
+static void fuse_freecontext(void *data)
+{
+	free(data);
+}
+
+static int fuse_create_context_key(void)
+{
+	int err = 0;
+	pthread_mutex_lock(&fuse_context_lock);
+	if (!fuse_context_ref) {
+		err = pthread_key_create(&fuse_context_key, fuse_freecontext);
+		if (err) {
+			fprintf(stderr, "fuse: failed to create thread specific key: %s\n",
+				strerror(err));
+			pthread_mutex_unlock(&fuse_context_lock);
+			return -1;
+		}
+	}
+	fuse_context_ref++;
+	pthread_mutex_unlock(&fuse_context_lock);
+	return 0;
+}
+
+static void fuse_delete_context_key(void)
+{
+	pthread_mutex_lock(&fuse_context_lock);
+	fuse_context_ref--;
+	if (!fuse_context_ref) {
+		free(pthread_getspecific(fuse_context_key));
+		pthread_key_delete(fuse_context_key);
+	}
+	pthread_mutex_unlock(&fuse_context_lock);
+}
+
+static struct fuse *req_fuse_prepare(fuse_req_t req)
+{
+	struct fuse_context_i *c = fuse_get_context_internal();
+	const struct fuse_ctx *ctx = fuse_req_ctx(req);
+	c->req = req;
+	c->ctx.fuse = req_fuse(req);
+	c->ctx.uid = ctx->uid;
+	c->ctx.gid = ctx->gid;
+	c->ctx.pid = ctx->pid;
+	c->ctx.umask = ctx->umask;
+	return c->ctx.fuse;
+}
+
+static inline void reply_err(fuse_req_t req, int err)
+{
+	/* fuse_reply_err() uses non-negated errno values */
+	fuse_reply_err(req, -err);
+}
+
+static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e,
+			int err)
+{
+	if (!err) {
+		struct fuse *f = req_fuse(req);
+		if (fuse_reply_entry(req, e) == -ENOENT) {
+			/* Skip forget for negative result */
+			if  (e->ino != 0)
+				forget_node(f, e->ino, 1);
+		}
+	} else
+		reply_err(req, err);
+}
+
+void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.init)
+		fs->user_data = fs->op.init(conn);
+}
+
+static void fuse_lib_init(void *data, struct fuse_conn_info *conn)
+{
+	struct fuse *f = (struct fuse *) data;
+	struct fuse_context_i *c = fuse_get_context_internal();
+
+	memset(c, 0, sizeof(*c));
+	c->ctx.fuse = f;
+	conn->want |= FUSE_CAP_EXPORT_SUPPORT;
+	fuse_fs_init(f->fs, conn);
+}
+
+void fuse_fs_destroy(struct fuse_fs *fs)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.destroy)
+		fs->op.destroy(fs->user_data);
+	if (fs->m)
+		fuse_put_module(fs->m);
+	free(fs);
+}
+
+static void fuse_lib_destroy(void *data)
+{
+	struct fuse *f = (struct fuse *) data;
+	struct fuse_context_i *c = fuse_get_context_internal();
+
+	memset(c, 0, sizeof(*c));
+	c->ctx.fuse = f;
+	fuse_fs_destroy(f->fs);
+	f->fs = NULL;
+}
+
+static void fuse_lib_lookup(fuse_req_t req, fuse_ino_t parent,
+			    const char *name)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	struct fuse_entry_param e;
+	char *path;
+	int err;
+	struct node *dot = NULL;
+
+	if (name[0] == '.') {
+		int len = strlen(name);
+
+		if (len == 1 || (name[1] == '.' && len == 2)) {
+			pthread_mutex_lock(&f->lock);
+			if (len == 1) {
+				if (f->conf.debug)
+					fprintf(stderr, "LOOKUP-DOT\n");
+				dot = get_node_nocheck(f, parent);
+				if (dot == NULL) {
+					pthread_mutex_unlock(&f->lock);
+					reply_entry(req, &e, -ESTALE);
+					return;
+				}
+				dot->refctr++;
+			} else {
+				if (f->conf.debug)
+					fprintf(stderr, "LOOKUP-DOTDOT\n");
+				parent = get_node(f, parent)->parent->nodeid;
+			}
+			pthread_mutex_unlock(&f->lock);
+			name = NULL;
+		}
+	}
+
+	err = get_path_name(f, parent, name, &path);
+	if (!err) {
+		struct fuse_intr_data d;
+		if (f->conf.debug)
+			fprintf(stderr, "LOOKUP %s\n", path);
+		fuse_prepare_interrupt(f, req, &d);
+		err = lookup_path(f, parent, name, path, &e, NULL);
+		if (err == -ENOENT && f->conf.negative_timeout != 0.0) {
+			e.ino = 0;
+			e.entry_timeout = f->conf.negative_timeout;
+			err = 0;
+		}
+		fuse_finish_interrupt(f, req, &d);
+		free_path(f, parent, path);
+	}
+	if (dot) {
+		pthread_mutex_lock(&f->lock);
+		unref_node(f, dot);
+		pthread_mutex_unlock(&f->lock);
+	}
+	reply_entry(req, &e, err);
+}
+
+static void fuse_lib_forget(fuse_req_t req, fuse_ino_t ino,
+			    unsigned long nlookup)
+{
+	struct fuse *f = req_fuse(req);
+	if (f->conf.debug)
+		fprintf(stderr, "FORGET %llu/%lu\n", (unsigned long long)ino,
+			nlookup);
+	forget_node(f, ino, nlookup);
+	fuse_reply_none(req);
+}
+
+static void fuse_lib_getattr(fuse_req_t req, fuse_ino_t ino,
+			     struct fuse_file_info *fi)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	struct stat buf;
+	char *path;
+	int err;
+
+	memset(&buf, 0, sizeof(buf));
+
+	if (fi != NULL)
+		err = get_path_nullok(f, ino, &path);
+	else
+		err = get_path(f, ino, &path);
+	if (!err) {
+		struct fuse_intr_data d;
+		fuse_prepare_interrupt(f, req, &d);
+		if (fi)
+			err = fuse_fs_fgetattr(f->fs, path, &buf, fi);
+		else
+			err = fuse_fs_getattr(f->fs, path, &buf);
+		fuse_finish_interrupt(f, req, &d);
+		free_path(f, ino, path);
+	}
+	if (!err) {
+		if (f->conf.auto_cache) {
+			pthread_mutex_lock(&f->lock);
+			update_stat(get_node(f, ino), &buf);
+			pthread_mutex_unlock(&f->lock);
+		}
+		set_stat(f, ino, &buf);
+		fuse_reply_attr(req, &buf, f->conf.attr_timeout);
+	} else
+		reply_err(req, err);
+}
+
+int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode)
+{
+	fuse_get_context()->private_data = fs->user_data;
+	if (fs->op.chmod)
+		return fs->op.chmod(path, mode);
+	else
+		return -ENOSYS;
+}
+
+static void fuse_lib_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
+			     int valid, struct fuse_file_info *fi)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	struct stat buf;
+	char *path;
+	int err;
+
+	err = get_path(f, ino, &path);
+	if (!err) {
+		struct fuse_intr_data d;
+		fuse_prepare_interrupt(f, req, &d);
+		err = 0;
+		if (!err && (valid & FUSE_SET_ATTR_MODE))
+			err = fuse_fs_chmod(f->fs, path, attr->st_mode);
+		if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID))) {
+			uid_t uid = (valid & FUSE_SET_ATTR_UID) ?
+				attr->st_uid : (uid_t) -1;
+			gid_t gid = (valid & FUSE_SET_ATTR_GID) ?
+				attr->st_gid : (gid_t) -1;
+			err = fuse_fs_chown(f->fs, path, uid, gid);
+		}
+		if (!err && (valid & FUSE_SET_ATTR_SIZE)) {
+			if (fi)
+				err = fuse_fs_ftruncate(f->fs, path,
+							attr->st_size, fi);
+			else
+				err = fuse_fs_truncate(f->fs, path,
+						       attr->st_size);
+		}
+		if (!err &&
+		    (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) ==
+		    (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) {
+			struct timespec tv[2];
+			tv[0].tv_sec = attr->st_atime;
+			tv[0].tv_nsec = ST_ATIM_NSEC(attr);
+			tv[1].tv_sec = attr->st_mtime;
+			tv[1].tv_nsec = ST_MTIM_NSEC(attr);
+			err = fuse_fs_utimens(f->fs, path, tv);
+		}
+		if (!err)
+			err = fuse_fs_getattr(f->fs,  path, &buf);
+		fuse_finish_interrupt(f, req, &d);
+		free_path(f, ino, path);
+	}
+	if (!err) {
+		if (f->conf.auto_cache) {
+			pthread_mutex_lock(&f->lock);
+			update_stat(get_node(f, ino), &buf);
+			pthread_mutex_unlock(&f->lock);
+		}
+		set_stat(f, ino, &buf);
+		fuse_reply_attr(req, &buf, f->conf.attr_timeout);
+	} else
+		reply_err(req, err);
+}
+
+static void fuse_lib_access(fuse_req_t req, fuse_ino_t ino, int mask)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	char *path;
+	int err;
+
+	err = get_path(f, ino, &path);
+	if (!err) {
+		struct fuse_intr_data d;
+
+		fuse_prepare_interrupt(f, req, &d);
+		err = fuse_fs_access(f->fs, path, mask);
+		fuse_finish_interrupt(f, req, &d);
+		free_path(f, ino, path);
+	}
+	reply_err(req, err);
+}
+
+static void fuse_lib_readlink(fuse_req_t req, fuse_ino_t ino)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	char linkname[PATH_MAX + 1];
+	char *path;
+	int err;
+
+	err = get_path(f, ino, &path);
+	if (!err) {
+		struct fuse_intr_data d;
+		fuse_prepare_interrupt(f, req, &d);
+		err = fuse_fs_readlink(f->fs, path, linkname, sizeof(linkname));
+		fuse_finish_interrupt(f, req, &d);
+		free_path(f, ino, path);
+	}
+	if (!err) {
+		linkname[PATH_MAX] = '\0';
+		fuse_reply_readlink(req, linkname);
+	} else
+		reply_err(req, err);
+}
+
+static void fuse_lib_mknod(fuse_req_t req, fuse_ino_t parent, const char *name,
+			   mode_t mode, dev_t rdev)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	struct fuse_entry_param e;
+	char *path;
+	int err;
+
+	err = get_path_name(f, parent, name, &path);
+	if (!err) {
+		struct fuse_intr_data d;
+
+		fuse_prepare_interrupt(f, req, &d);
+		err = -ENOSYS;
+		if (S_ISREG(mode)) {
+			struct fuse_file_info fi;
+
+			memset(&fi, 0, sizeof(fi));
+			fi.flags = O_CREAT | O_EXCL | O_WRONLY;
+			err = fuse_fs_create(f->fs, path, mode, &fi);
+			if (!err) {
+				err = lookup_path(f, parent, name, path, &e,
+						  &fi);
+				fuse_fs_release(f->fs, path, &fi);
+			}
+		}
+		if (err == -ENOSYS) {
+			err = fuse_fs_mknod(f->fs, path, mode, rdev);
+			if (!err)
+				err = lookup_path(f, parent, name, path, &e,
+						  NULL);
+		}
+		fuse_finish_interrupt(f, req, &d);
+		free_path(f, parent, path);
+	}
+	reply_entry(req, &e, err);
+}
+
+static void fuse_lib_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
+			   mode_t mode)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	struct fuse_entry_param e;
+	char *path;
+	int err;
+
+	err = get_path_name(f, parent, name, &path);
+	if (!err) {
+		struct fuse_intr_data d;
+
+		fuse_prepare_interrupt(f, req, &d);
+		err = fuse_fs_mkdir(f->fs, path, mode);
+		if (!err)
+			err = lookup_path(f, parent, name, path, &e, NULL);
+		fuse_finish_interrupt(f, req, &d);
+		free_path(f, parent, path);
+	}
+	reply_entry(req, &e, err);
+}
+
+static void fuse_lib_unlink(fuse_req_t req, fuse_ino_t parent,
+			    const char *name)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	struct node *wnode;
+	char *path;
+	int err;
+
+	err = get_path_wrlock(f, parent, name, &path, &wnode);
+	if (!err) {
+		struct fuse_intr_data d;
+
+		fuse_prepare_interrupt(f, req, &d);
+		if (!f->conf.hard_remove && is_open(f, parent, name)) {
+			err = hide_node(f, path, parent, name);
+		} else {
+			err = fuse_fs_unlink(f->fs, path);
+			if (!err)
+				remove_node(f, parent, name);
+		}
+		fuse_finish_interrupt(f, req, &d);
+		free_path_wrlock(f, parent, wnode, path);
+	}
+	reply_err(req, err);
+}
+
+static void fuse_lib_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	struct node *wnode;
+	char *path;
+	int err;
+
+	err = get_path_wrlock(f, parent, name, &path, &wnode);
+	if (!err) {
+		struct fuse_intr_data d;
+
+		fuse_prepare_interrupt(f, req, &d);
+		err = fuse_fs_rmdir(f->fs, path);
+		fuse_finish_interrupt(f, req, &d);
+		if (!err)
+			remove_node(f, parent, name);
+		free_path_wrlock(f, parent, wnode, path);
+	}
+	reply_err(req, err);
+}
+
+static void fuse_lib_symlink(fuse_req_t req, const char *linkname,
+			     fuse_ino_t parent, const char *name)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	struct fuse_entry_param e;
+	char *path;
+	int err;
+
+	err = get_path_name(f, parent, name, &path);
+	if (!err) {
+		struct fuse_intr_data d;
+
+		fuse_prepare_interrupt(f, req, &d);
+		err = fuse_fs_symlink(f->fs, linkname, path);
+		if (!err)
+			err = lookup_path(f, parent, name, path, &e, NULL);
+		fuse_finish_interrupt(f, req, &d);
+		free_path(f, parent, path);
+	}
+	reply_entry(req, &e, err);
+}
+
+static void fuse_lib_rename(fuse_req_t req, fuse_ino_t olddir,
+			    const char *oldname, fuse_ino_t newdir,
+			    const char *newname)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	char *oldpath;
+	char *newpath;
+	struct node *wnode1;
+	struct node *wnode2;
+	int err;
+
+	err = get_path2(f, olddir, oldname, newdir, newname,
+			&oldpath, &newpath, &wnode1, &wnode2);
+	if (!err) {
+		struct fuse_intr_data d;
+		err = 0;
+		fuse_prepare_interrupt(f, req, &d);
+		if (!f->conf.hard_remove && is_open(f, newdir, newname))
+			err = hide_node(f, newpath, newdir, newname);
+		if (!err) {
+			err = fuse_fs_rename(f->fs, oldpath, newpath);
+			if (!err)
+				err = rename_node(f, olddir, oldname, newdir,
+						  newname, 0);
+		}
+		fuse_finish_interrupt(f, req, &d);
+		free_path2(f, olddir, newdir, wnode1, wnode2, oldpath, newpath);
+	}
+	reply_err(req, err);
+}
+
+static void fuse_lib_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
+			  const char *newname)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	struct fuse_entry_param e;
+	char *oldpath;
+	char *newpath;
+	int err;
+
+	err = get_path2(f, ino, NULL, newparent, newname,
+			&oldpath, &newpath, NULL, NULL);
+	if (!err) {
+		struct fuse_intr_data d;
+
+		fuse_prepare_interrupt(f, req, &d);
+		err = fuse_fs_link(f->fs, oldpath, newpath);
+		if (!err)
+			err = lookup_path(f, newparent, newname, newpath,
+					  &e, NULL);
+		fuse_finish_interrupt(f, req, &d);
+		free_path2(f, ino, newparent, NULL, NULL, oldpath, newpath);
+	}
+	reply_entry(req, &e, err);
+}
+
+static void fuse_do_release(struct fuse *f, fuse_ino_t ino, const char *path,
+			    struct fuse_file_info *fi)
+{
+	struct node *node;
+	int unlink_hidden = 0;
+
+	fuse_fs_release(f->fs, (path || f->nullpath_ok) ? path : "-", fi);
+
+	pthread_mutex_lock(&f->lock);
+	node = get_node(f, ino);
+	assert(node->open_count > 0);
+	--node->open_count;
+	if (node->is_hidden && !node->open_count) {
+		unlink_hidden = 1;
+		node->is_hidden = 0;
+	}
+	pthread_mutex_unlock(&f->lock);
+
+	if(unlink_hidden && path)
+		fuse_fs_unlink(f->fs, path);
+}
+
+static void fuse_lib_create(fuse_req_t req, fuse_ino_t parent,
+			    const char *name, mode_t mode,
+			    struct fuse_file_info *fi)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	struct fuse_intr_data d;
+	struct fuse_entry_param e;
+	char *path;
+	int err;
+
+	err = get_path_name(f, parent, name, &path);
+	if (!err) {
+		fuse_prepare_interrupt(f, req, &d);
+		err = fuse_fs_create(f->fs, path, mode, fi);
+		if (!err) {
+			err = lookup_path(f, parent, name, path, &e, fi);
+			if (err)
+				fuse_fs_release(f->fs, path, fi);
+			else if (!S_ISREG(e.attr.st_mode)) {
+				err = -EIO;
+				fuse_fs_release(f->fs, path, fi);
+				forget_node(f, e.ino, 1);
+			} else {
+				if (f->conf.direct_io)
+					fi->direct_io = 1;
+				if (f->conf.kernel_cache)
+					fi->keep_cache = 1;
+
+			}
+		}
+		fuse_finish_interrupt(f, req, &d);
+	}
+	if (!err) {
+		pthread_mutex_lock(&f->lock);
+		get_node(f, e.ino)->open_count++;
+		pthread_mutex_unlock(&f->lock);
+		if (fuse_reply_create(req, &e, fi) == -ENOENT) {
+			/* The open syscall was interrupted, so it
+			   must be cancelled */
+			fuse_prepare_interrupt(f, req, &d);
+			fuse_do_release(f, e.ino, path, fi);
+			fuse_finish_interrupt(f, req, &d);
+			forget_node(f, e.ino, 1);
+		}
+	} else {
+		reply_err(req, err);
+	}
+
+	free_path(f, parent, path);
+}
+
+static double diff_timespec(const struct timespec *t1,
+			    const struct timespec *t2)
+{
+	return (t1->tv_sec - t2->tv_sec) +
+		((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0;
+}
+
+static void open_auto_cache(struct fuse *f, fuse_ino_t ino, const char *path,
+			    struct fuse_file_info *fi)
+{
+	struct node *node;
+
+	pthread_mutex_lock(&f->lock);
+	node = get_node(f, ino);
+	if (node->cache_valid) {
+		struct timespec now;
+
+		curr_time(&now);
+		if (diff_timespec(&now, &node->stat_updated) >
+		    f->conf.ac_attr_timeout) {
+			struct stat stbuf;
+			int err;
+			pthread_mutex_unlock(&f->lock);
+			err = fuse_fs_fgetattr(f->fs, path, &stbuf, fi);
+			pthread_mutex_lock(&f->lock);
+			if (!err)
+				update_stat(node, &stbuf);
+			else
+				node->cache_valid = 0;
+		}
+	}
+	if (node->cache_valid)
+		fi->keep_cache = 1;
+
+	node->cache_valid = 1;
+	pthread_mutex_unlock(&f->lock);
+}
+
+static void fuse_lib_open(fuse_req_t req, fuse_ino_t ino,
+			  struct fuse_file_info *fi)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	struct fuse_intr_data d;
+	char *path;
+	int err;
+
+	err = get_path(f, ino, &path);
+	if (!err) {
+		fuse_prepare_interrupt(f, req, &d);
+		err = fuse_fs_open(f->fs, path, fi);
+		if (!err) {
+			if (f->conf.direct_io)
+				fi->direct_io = 1;
+			if (f->conf.kernel_cache)
+				fi->keep_cache = 1;
+
+			if (f->conf.auto_cache)
+				open_auto_cache(f, ino, path, fi);
+		}
+		fuse_finish_interrupt(f, req, &d);
+	}
+	if (!err) {
+		pthread_mutex_lock(&f->lock);
+		get_node(f, ino)->open_count++;
+		pthread_mutex_unlock(&f->lock);
+		if (fuse_reply_open(req, fi) == -ENOENT) {
+			/* The open syscall was interrupted, so it
+			   must be cancelled */
+			fuse_prepare_interrupt(f, req, &d);
+			fuse_do_release(f, ino, path, fi);
+			fuse_finish_interrupt(f, req, &d);
+		}
+	} else
+		reply_err(req, err);
+
+	free_path(f, ino, path);
+}
+
+static void fuse_lib_read(fuse_req_t req, fuse_ino_t ino, size_t size,
+			  off64_t off, struct fuse_file_info *fi)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	char *path;
+	char *buf;
+	int res;
+
+	buf = (char *) malloc(size);
+	if (buf == NULL) {
+		reply_err(req, -ENOMEM);
+		return;
+	}
+
+	res = get_path_nullok(f, ino, &path);
+	if (res == 0) {
+		struct fuse_intr_data d;
+
+		fuse_prepare_interrupt(f, req, &d);
+		res = fuse_fs_read(f->fs, path, buf, size, off, fi);
+		fuse_finish_interrupt(f, req, &d);
+		free_path(f, ino, path);
+	}
+
+	if (res >= 0)
+		fuse_reply_buf(req, buf, res);
+	else
+		reply_err(req, res);
+
+	free(buf);
+}
+
+static void fuse_lib_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
+			   size_t size, off64_t off, struct fuse_file_info *fi)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	char *path;
+	int res;
+
+	res = get_path_nullok(f, ino, &path);
+	if (res == 0) {
+		struct fuse_intr_data d;
+
+		fuse_prepare_interrupt(f, req, &d);
+		res = fuse_fs_write(f->fs, path, buf, size, off, fi);
+                printf("died\n");
+		fuse_finish_interrupt(f, req, &d);
+		free_path(f, ino, path);
+	}
+
+	if (res >= 0)
+		fuse_reply_write(req, res);
+	else
+		reply_err(req, res);
+}
+
+static void fuse_lib_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
+			   struct fuse_file_info *fi)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	char *path;
+	int err;
+
+	err = get_path_nullok(f, ino, &path);
+	if (!err) {
+		struct fuse_intr_data d;
+
+		fuse_prepare_interrupt(f, req, &d);
+		err = fuse_fs_fsync(f->fs, path, datasync, fi);
+		fuse_finish_interrupt(f, req, &d);
+		free_path(f, ino, path);
+	}
+	reply_err(req, err);
+}
+
+static struct fuse_dh *get_dirhandle(const struct fuse_file_info *llfi,
+				     struct fuse_file_info *fi)
+{
+	struct fuse_dh *dh = (struct fuse_dh *) (uintptr_t) llfi->fh;
+	memset(fi, 0, sizeof(struct fuse_file_info));
+	fi->fh = dh->fh;
+	fi->fh_old = dh->fh;
+	return dh;
+}
+
+static void fuse_lib_opendir(fuse_req_t req, fuse_ino_t ino,
+			     struct fuse_file_info *llfi)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	struct fuse_intr_data d;
+	struct fuse_dh *dh;
+	struct fuse_file_info fi;
+	char *path;
+	int err;
+
+	dh = (struct fuse_dh *) malloc(sizeof(struct fuse_dh));
+	if (dh == NULL) {
+		reply_err(req, -ENOMEM);
+		return;
+	}
+	memset(dh, 0, sizeof(struct fuse_dh));
+	dh->fuse = f;
+	dh->contents = NULL;
+	dh->len = 0;
+	dh->filled = 0;
+	dh->nodeid = ino;
+	fuse_mutex_init(&dh->lock);
+
+	llfi->fh = (uintptr_t) dh;
+
+	memset(&fi, 0, sizeof(fi));
+	fi.flags = llfi->flags;
+
+	err = get_path(f, ino, &path);
+	if (!err) {
+		fuse_prepare_interrupt(f, req, &d);
+		err = fuse_fs_opendir(f->fs, path, &fi);
+		fuse_finish_interrupt(f, req, &d);
+		dh->fh = fi.fh;
+	}
+	if (!err) {
+		if (fuse_reply_open(req, llfi) == -ENOENT) {
+			/* The opendir syscall was interrupted, so it
+			   must be cancelled */
+			fuse_prepare_interrupt(f, req, &d);
+			fuse_fs_releasedir(f->fs, path, &fi);
+			fuse_finish_interrupt(f, req, &d);
+			pthread_mutex_destroy(&dh->lock);
+			free(dh);
+		}
+	} else {
+		reply_err(req, err);
+		pthread_mutex_destroy(&dh->lock);
+		free(dh);
+	}
+	free_path(f, ino, path);
+}
+
+static int extend_contents(struct fuse_dh *dh, unsigned minsize)
+{
+	if (minsize > dh->size) {
+		char *newptr;
+		unsigned newsize = dh->size;
+		if (!newsize)
+			newsize = 1024;
+		while (newsize < minsize) {
+			if (newsize >= 0x80000000)
+				newsize = 0xffffffff;
+			else
+				newsize *= 2;
+		}
+
+		newptr = (char *) realloc(dh->contents, newsize);
+		if (!newptr) {
+			dh->error = -ENOMEM;
+			return -1;
+		}
+		dh->contents = newptr;
+		dh->size = newsize;
+	}
+	return 0;
+}
+
+static int fill_dir(void *dh_, const char *name, const struct stat *statp,
+		    off64_t off)
+{
+	struct fuse_dh *dh = (struct fuse_dh *) dh_;
+	struct stat stbuf;
+	size_t newlen;
+
+	if (statp)
+		stbuf = *statp;
+	else {
+		memset(&stbuf, 0, sizeof(stbuf));
+		stbuf.st_ino = FUSE_UNKNOWN_INO;
+	}
+
+	if (!dh->fuse->conf.use_ino) {
+		stbuf.st_ino = FUSE_UNKNOWN_INO;
+		if (dh->fuse->conf.readdir_ino) {
+			struct node *node;
+			pthread_mutex_lock(&dh->fuse->lock);
+			node = lookup_node(dh->fuse, dh->nodeid, name);
+			if (node)
+				stbuf.st_ino  = (ino_t) node->nodeid;
+			pthread_mutex_unlock(&dh->fuse->lock);
+		}
+	}
+
+	if (off) {
+		if (extend_contents(dh, dh->needlen) == -1)
+			return 1;
+
+		dh->filled = 0;
+		newlen = dh->len +
+			fuse_add_direntry(dh->req, dh->contents + dh->len,
+					  dh->needlen - dh->len, name,
+					  &stbuf, off);
+		if (newlen > dh->needlen)
+			return 1;
+	} else {
+		newlen = dh->len +
+			fuse_add_direntry(dh->req, NULL, 0, name, NULL, 0);
+		if (extend_contents(dh, newlen) == -1)
+			return 1;
+
+		fuse_add_direntry(dh->req, dh->contents + dh->len,
+				  dh->size - dh->len, name, &stbuf, newlen);
+	}
+	dh->len = newlen;
+	return 0;
+}
+
+static int readdir_fill(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
+			size_t size, off64_t off, struct fuse_dh *dh,
+			struct fuse_file_info *fi)
+{
+	char *path;
+	int err;
+
+	err = get_path(f, ino, &path);
+	if (!err) {
+		struct fuse_intr_data d;
+
+		dh->len = 0;
+		dh->error = 0;
+		dh->needlen = size;
+		dh->filled = 1;
+		dh->req = req;
+		fuse_prepare_interrupt(f, req, &d);
+		err = fuse_fs_readdir(f->fs, path, dh, fill_dir, off, fi);
+		fuse_finish_interrupt(f, req, &d);
+		dh->req = NULL;
+		if (!err)
+			err = dh->error;
+		if (err)
+			dh->filled = 0;
+		free_path(f, ino, path);
+	}
+	return err;
+}
+
+static void fuse_lib_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
+			     off64_t off, struct fuse_file_info *llfi)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	struct fuse_file_info fi;
+	struct fuse_dh *dh = get_dirhandle(llfi, &fi);
+
+	pthread_mutex_lock(&dh->lock);
+	/* According to SUS, directory contents need to be refreshed on
+	   rewinddir() */
+	if (!off)
+		dh->filled = 0;
+
+	if (!dh->filled) {
+		int err = readdir_fill(f, req, ino, size, off, dh, &fi);
+		if (err) {
+			reply_err(req, err);
+			goto out;
+		}
+	}
+	if (dh->filled) {
+		if (off < dh->len) {
+			if (off + size > dh->len)
+				size = dh->len - off;
+		} else
+			size = 0;
+	} else {
+		size = dh->len;
+		off = 0;
+	}
+	fuse_reply_buf(req, dh->contents + off, size);
+out:
+	pthread_mutex_unlock(&dh->lock);
+}
+
+static void fuse_lib_releasedir(fuse_req_t req, fuse_ino_t ino,
+				struct fuse_file_info *llfi)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	struct fuse_intr_data d;
+	struct fuse_file_info fi;
+	struct fuse_dh *dh = get_dirhandle(llfi, &fi);
+	char *path;
+
+	get_path(f, ino, &path);
+	fuse_prepare_interrupt(f, req, &d);
+	fuse_fs_releasedir(f->fs, (path || f->nullpath_ok) ? path : "-", &fi);
+	fuse_finish_interrupt(f, req, &d);
+	free_path(f, ino, path);
+
+	pthread_mutex_lock(&dh->lock);
+	pthread_mutex_unlock(&dh->lock);
+	pthread_mutex_destroy(&dh->lock);
+	free(dh->contents);
+	free(dh);
+	reply_err(req, 0);
+}
+
+static void fuse_lib_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
+			      struct fuse_file_info *llfi)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	struct fuse_file_info fi;
+	char *path;
+	int err;
+
+	get_dirhandle(llfi, &fi);
+
+	err = get_path(f, ino, &path);
+	if (!err) {
+		struct fuse_intr_data d;
+		fuse_prepare_interrupt(f, req, &d);
+		err = fuse_fs_fsyncdir(f->fs, path, datasync, &fi);
+		fuse_finish_interrupt(f, req, &d);
+		free_path(f, ino, path);
+	}
+	reply_err(req, err);
+}
+
+static void fuse_lib_statfs(fuse_req_t req, fuse_ino_t ino)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	struct statvfs buf;
+	char *path = NULL;
+	int err = 0;
+
+	memset(&buf, 0, sizeof(buf));
+	if (ino)
+		err = get_path(f, ino, &path);
+
+	if (!err) {
+		struct fuse_intr_data d;
+		fuse_prepare_interrupt(f, req, &d);
+		err = fuse_fs_statfs(f->fs, path ? path : "/", &buf);
+		fuse_finish_interrupt(f, req, &d);
+		free_path(f, ino, path);
+	}
+
+	if (!err)
+		fuse_reply_statfs(req, &buf);
+	else
+		reply_err(req, err);
+}
+
+static void fuse_lib_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
+			      const char *value, size_t size, int flags)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	char *path;
+	int err;
+
+	err = get_path(f, ino, &path);
+	if (!err) {
+		struct fuse_intr_data d;
+		fuse_prepare_interrupt(f, req, &d);
+		err = fuse_fs_setxattr(f->fs, path, name, value, size, flags);
+		fuse_finish_interrupt(f, req, &d);
+		free_path(f, ino, path);
+	}
+	reply_err(req, err);
+}
+
+static int common_getxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
+			   const char *name, char *value, size_t size)
+{
+	int err;
+	char *path;
+
+	err = get_path(f, ino, &path);
+	if (!err) {
+		struct fuse_intr_data d;
+		fuse_prepare_interrupt(f, req, &d);
+		err = fuse_fs_getxattr(f->fs, path, name, value, size);
+		fuse_finish_interrupt(f, req, &d);
+		free_path(f, ino, path);
+	}
+	return err;
+}
+
+static void fuse_lib_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
+			      size_t size)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	int res;
+
+	if (size) {
+		char *value = (char *) malloc(size);
+		if (value == NULL) {
+			reply_err(req, -ENOMEM);
+			return;
+		}
+		res = common_getxattr(f, req, ino, name, value, size);
+		if (res > 0)
+			fuse_reply_buf(req, value, res);
+		else
+			reply_err(req, res);
+		free(value);
+	} else {
+		res = common_getxattr(f, req, ino, name, NULL, 0);
+		if (res >= 0)
+			fuse_reply_xattr(req, res);
+		else
+			reply_err(req, res);
+	}
+}
+
+static int common_listxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
+			    char *list, size_t size)
+{
+	char *path;
+	int err;
+
+	err = get_path(f, ino, &path);
+	if (!err) {
+		struct fuse_intr_data d;
+		fuse_prepare_interrupt(f, req, &d);
+		err = fuse_fs_listxattr(f->fs, path, list, size);
+		fuse_finish_interrupt(f, req, &d);
+		free_path(f, ino, path);
+	}
+	return err;
+}
+
+static void fuse_lib_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	int res;
+
+	if (size) {
+		char *list = (char *) malloc(size);
+		if (list == NULL) {
+			reply_err(req, -ENOMEM);
+			return;
+		}
+		res = common_listxattr(f, req, ino, list, size);
+		if (res > 0)
+			fuse_reply_buf(req, list, res);
+		else
+			reply_err(req, res);
+		free(list);
+	} else {
+		res = common_listxattr(f, req, ino, NULL, 0);
+		if (res >= 0)
+			fuse_reply_xattr(req, res);
+		else
+			reply_err(req, res);
+	}
+}
+
+static void fuse_lib_removexattr(fuse_req_t req, fuse_ino_t ino,
+				 const char *name)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	char *path;
+	int err;
+
+	err = get_path(f, ino, &path);
+	if (!err) {
+		struct fuse_intr_data d;
+		fuse_prepare_interrupt(f, req, &d);
+		err = fuse_fs_removexattr(f->fs, path, name);
+		fuse_finish_interrupt(f, req, &d);
+		free_path(f, ino, path);
+	}
+	reply_err(req, err);
+}
+
+static struct lock *locks_conflict(struct node *node, const struct lock *lock)
+{
+	struct lock *l;
+
+	for (l = node->locks; l; l = l->next)
+		if (l->owner != lock->owner &&
+		    lock->start <= l->end && l->start <= lock->end &&
+		    (l->type == F_WRLCK || lock->type == F_WRLCK))
+			break;
+
+	return l;
+}
+
+static void delete_lock(struct lock **lockp)
+{
+	struct lock *l = *lockp;
+	*lockp = l->next;
+	free(l);
+}
+
+static void insert_lock(struct lock **pos, struct lock *lock)
+{
+	lock->next = *pos;
+	*pos = lock;
+}
+
+static int locks_insert(struct node *node, struct lock *lock)
+{
+	struct lock **lp;
+	struct lock *newl1 = NULL;
+	struct lock *newl2 = NULL;
+
+	if (lock->type != F_UNLCK || lock->start != 0 ||
+	    lock->end != OFFSET_MAX) {
+		newl1 = malloc(sizeof(struct lock));
+		newl2 = malloc(sizeof(struct lock));
+
+		if (!newl1 || !newl2) {
+			free(newl1);
+			free(newl2);
+			return -ENOLCK;
+		}
+	}
+
+	for (lp = &node->locks; *lp;) {
+		struct lock *l = *lp;
+		if (l->owner != lock->owner)
+			goto skip;
+
+		if (lock->type == l->type) {
+			if (l->end < lock->start - 1)
+				goto skip;
+			if (lock->end < l->start - 1)
+				break;
+			if (l->start <= lock->start && lock->end <= l->end)
+				goto out;
+			if (l->start < lock->start)
+				lock->start = l->start;
+			if (lock->end < l->end)
+				lock->end = l->end;
+			goto delete;
+		} else {
+			if (l->end < lock->start)
+				goto skip;
+			if (lock->end < l->start)
+				break;
+			if (lock->start <= l->start && l->end <= lock->end)
+				goto delete;
+			if (l->end <= lock->end) {
+				l->end = lock->start - 1;
+				goto skip;
+			}
+			if (lock->start <= l->start) {
+				l->start = lock->end + 1;
+				break;
+			}
+			*newl2 = *l;
+			newl2->start = lock->end + 1;
+			l->end = lock->start - 1;
+			insert_lock(&l->next, newl2);
+			newl2 = NULL;
+		}
+	skip:
+		lp = &l->next;
+		continue;
+
+	delete:
+		delete_lock(lp);
+	}
+	if (lock->type != F_UNLCK) {
+		*newl1 = *lock;
+		insert_lock(lp, newl1);
+		newl1 = NULL;
+	}
+out:
+	free(newl1);
+	free(newl2);
+	return 0;
+}
+
+static void flock_to_lock(struct flock *flock, struct lock *lock)
+{
+	memset(lock, 0, sizeof(struct lock));
+	lock->type = flock->l_type;
+	lock->start = flock->l_start;
+	lock->end =
+		flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX;
+	lock->pid = flock->l_pid;
+}
+
+static void lock_to_flock(struct lock *lock, struct flock *flock)
+{
+	flock->l_type = lock->type;
+	flock->l_start = lock->start;
+	flock->l_len =
+		(lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1;
+	flock->l_pid = lock->pid;
+}
+
+static int fuse_flush_common(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
+			     const char *path, struct fuse_file_info *fi)
+{
+	struct fuse_intr_data d;
+	struct flock lock;
+	struct lock l;
+	int err;
+	int errlock;
+
+	fuse_prepare_interrupt(f, req, &d);
+	memset(&lock, 0, sizeof(lock));
+	lock.l_type = F_UNLCK;
+	lock.l_whence = SEEK_SET;
+	err = fuse_fs_flush(f->fs, path, fi);
+	errlock = fuse_fs_lock(f->fs, path, fi, F_SETLK, &lock);
+	fuse_finish_interrupt(f, req, &d);
+
+	if (errlock != -ENOSYS) {
+		flock_to_lock(&lock, &l);
+		l.owner = fi->lock_owner;
+		pthread_mutex_lock(&f->lock);
+		locks_insert(get_node(f, ino), &l);
+		pthread_mutex_unlock(&f->lock);
+
+		/* if op.lock() is defined FLUSH is needed regardless
+		   of op.flush() */
+		if (err == -ENOSYS)
+			err = 0;
+	}
+	return err;
+}
+
+static void fuse_lib_release(fuse_req_t req, fuse_ino_t ino,
+			     struct fuse_file_info *fi)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	struct fuse_intr_data d;
+	char *path;
+	int err = 0;
+
+	get_path(f, ino, &path);
+	if (fi->flush) {
+		err = fuse_flush_common(f, req, ino, path, fi);
+		if (err == -ENOSYS)
+			err = 0;
+	}
+
+	fuse_prepare_interrupt(f, req, &d);
+	fuse_do_release(f, ino, path, fi);
+	fuse_finish_interrupt(f, req, &d);
+	free_path(f, ino, path);
+
+	reply_err(req, err);
+}
+
+static void fuse_lib_flush(fuse_req_t req, fuse_ino_t ino,
+			   struct fuse_file_info *fi)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	char *path;
+	int err;
+
+	get_path(f, ino, &path);
+	err = fuse_flush_common(f, req, ino, path, fi);
+	free_path(f, ino, path);
+
+	reply_err(req, err);
+}
+
+static int fuse_lock_common(fuse_req_t req, fuse_ino_t ino,
+			    struct fuse_file_info *fi, struct flock *lock,
+			    int cmd)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	char *path;
+	int err;
+
+	err = get_path_nullok(f, ino, &path);
+	if (!err) {
+		struct fuse_intr_data d;
+		fuse_prepare_interrupt(f, req, &d);
+		err = fuse_fs_lock(f->fs, path, fi, cmd, lock);
+		fuse_finish_interrupt(f, req, &d);
+		free_path(f, ino, path);
+	}
+	return err;
+}
+
+static void fuse_lib_getlk(fuse_req_t req, fuse_ino_t ino,
+			   struct fuse_file_info *fi, struct flock *lock)
+{
+	int err;
+	struct lock l;
+	struct lock *conflict;
+	struct fuse *f = req_fuse(req);
+
+	flock_to_lock(lock, &l);
+	l.owner = fi->lock_owner;
+	pthread_mutex_lock(&f->lock);
+	conflict = locks_conflict(get_node(f, ino), &l);
+	if (conflict)
+		lock_to_flock(conflict, lock);
+	pthread_mutex_unlock(&f->lock);
+	if (!conflict)
+		err = fuse_lock_common(req, ino, fi, lock, F_GETLK);
+	else
+		err = 0;
+
+	if (!err)
+		fuse_reply_lock(req, lock);
+	else
+		reply_err(req, err);
+}
+
+static void fuse_lib_setlk(fuse_req_t req, fuse_ino_t ino,
+			   struct fuse_file_info *fi, struct flock *lock,
+			   int sleep)
+{
+	int err = fuse_lock_common(req, ino, fi, lock,
+				   sleep ? F_SETLKW : F_SETLK);
+	if (!err) {
+		struct fuse *f = req_fuse(req);
+		struct lock l;
+		flock_to_lock(lock, &l);
+		l.owner = fi->lock_owner;
+		pthread_mutex_lock(&f->lock);
+		locks_insert(get_node(f, ino), &l);
+		pthread_mutex_unlock(&f->lock);
+	}
+	reply_err(req, err);
+}
+
+static void fuse_lib_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize,
+			  uint64_t idx)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	struct fuse_intr_data d;
+	char *path;
+	int err;
+
+	err = get_path(f, ino, &path);
+	if (!err) {
+		fuse_prepare_interrupt(f, req, &d);
+		err = fuse_fs_bmap(f->fs, path, blocksize, &idx);
+		fuse_finish_interrupt(f, req, &d);
+		free_path(f, ino, path);
+	}
+	if (!err)
+		fuse_reply_bmap(req, idx);
+	else
+		reply_err(req, err);
+}
+
+static void fuse_lib_ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg,
+			   struct fuse_file_info *fi, unsigned int flags,
+			   const void *in_buf, size_t in_bufsz,
+			   size_t out_bufsz)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	struct fuse_intr_data d;
+	char *path, *out_buf = NULL;
+	int err;
+
+	err = -EPERM;
+	if (flags & FUSE_IOCTL_UNRESTRICTED)
+		goto err;
+
+	if (out_bufsz) {
+		err = -ENOMEM;
+		out_buf = malloc(out_bufsz);
+		if (!out_buf)
+			goto err;
+	}
+
+	assert(!in_bufsz || !out_bufsz || in_bufsz == out_bufsz);
+	if (out_buf)
+		memcpy(out_buf, in_buf, in_bufsz);
+
+	err = get_path(f, ino, &path);
+	if (err)
+		goto err;
+
+	fuse_prepare_interrupt(f, req, &d);
+
+	err = fuse_fs_ioctl(f->fs, path, cmd, arg, fi, flags,
+			    out_buf ?: (void *)in_buf);
+
+	fuse_finish_interrupt(f, req, &d);
+	free_path(f, ino, path);
+
+	fuse_reply_ioctl(req, err, out_buf, out_bufsz);
+	goto out;
+err:
+	reply_err(req, err);
+out:
+	free(out_buf);
+}
+
+static void fuse_lib_poll(fuse_req_t req, fuse_ino_t ino,
+			  struct fuse_file_info *fi, struct fuse_pollhandle *ph)
+{
+	struct fuse *f = req_fuse_prepare(req);
+	struct fuse_intr_data d;
+	char *path;
+	int ret;
+	unsigned revents = 0;
+
+	ret = get_path(f, ino, &path);
+	if (!ret) {
+		fuse_prepare_interrupt(f, req, &d);
+		ret = fuse_fs_poll(f->fs, path, fi, ph, &revents);
+		fuse_finish_interrupt(f, req, &d);
+		free_path(f, ino, path);
+	}
+	if (!ret)
+		fuse_reply_poll(req, revents);
+	else
+		reply_err(req, ret);
+}
+
+static struct fuse_lowlevel_ops fuse_path_ops = {
+	.init = fuse_lib_init,
+	.destroy = fuse_lib_destroy,
+	.lookup = fuse_lib_lookup,
+	.forget = fuse_lib_forget,
+	.getattr = fuse_lib_getattr,
+	.setattr = fuse_lib_setattr,
+	.access = fuse_lib_access,
+	.readlink = fuse_lib_readlink,
+	.mknod = fuse_lib_mknod,
+	.mkdir = fuse_lib_mkdir,
+	.unlink = fuse_lib_unlink,
+	.rmdir = fuse_lib_rmdir,
+	.symlink = fuse_lib_symlink,
+	.rename = fuse_lib_rename,
+	.link = fuse_lib_link,
+	.create = fuse_lib_create,
+	.open = fuse_lib_open,
+	.read = fuse_lib_read,
+	.write = fuse_lib_write,
+	.flush = fuse_lib_flush,
+	.release = fuse_lib_release,
+	.fsync = fuse_lib_fsync,
+	.opendir = fuse_lib_opendir,
+	.readdir = fuse_lib_readdir,
+	.releasedir = fuse_lib_releasedir,
+	.fsyncdir = fuse_lib_fsyncdir,
+	.statfs = fuse_lib_statfs,
+	.setxattr = fuse_lib_setxattr,
+	.getxattr = fuse_lib_getxattr,
+	.listxattr = fuse_lib_listxattr,
+	.removexattr = fuse_lib_removexattr,
+	.getlk = fuse_lib_getlk,
+	.setlk = fuse_lib_setlk,
+	.bmap = fuse_lib_bmap,
+	.ioctl = fuse_lib_ioctl,
+	.poll = fuse_lib_poll,
+};
+
+int fuse_notify_poll(struct fuse_pollhandle *ph)
+{
+	return fuse_lowlevel_notify_poll(ph);
+}
+
+static void free_cmd(struct fuse_cmd *cmd)
+{
+	free(cmd->buf);
+	free(cmd);
+}
+
+void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
+{
+	fuse_session_process(f->se, cmd->buf, cmd->buflen, cmd->ch);
+	free_cmd(cmd);
+}
+
+int fuse_exited(struct fuse *f)
+{
+	return fuse_session_exited(f->se);
+}
+
+struct fuse_session *fuse_get_session(struct fuse *f)
+{
+	return f->se;
+}
+
+static struct fuse_cmd *fuse_alloc_cmd(size_t bufsize)
+{
+	struct fuse_cmd *cmd = (struct fuse_cmd *) malloc(sizeof(*cmd));
+	if (cmd == NULL) {
+		fprintf(stderr, "fuse: failed to allocate cmd\n");
+		return NULL;
+	}
+	cmd->buf = (char *) malloc(bufsize);
+	if (cmd->buf == NULL) {
+		fprintf(stderr, "fuse: failed to allocate read buffer\n");
+		free(cmd);
+		return NULL;
+	}
+	return cmd;
+}
+
+struct fuse_cmd *fuse_read_cmd(struct fuse *f)
+{
+	struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL);
+	size_t bufsize = fuse_chan_bufsize(ch);
+	struct fuse_cmd *cmd = fuse_alloc_cmd(bufsize);
+	if (cmd != NULL) {
+		int res = fuse_chan_recv(&ch, cmd->buf, bufsize);
+		if (res <= 0) {
+			free_cmd(cmd);
+			if (res < 0 && res != -EINTR && res != -EAGAIN)
+				fuse_exit(f);
+			return NULL;
+		}
+		cmd->buflen = res;
+		cmd->ch = ch;
+	}
+	return cmd;
+}
+
+int fuse_loop(struct fuse *f)
+{
+	if (f)
+		return fuse_session_loop(f->se);
+	else
+		return -1;
+}
+
+int fuse_invalidate(struct fuse *f, const char *path)
+{
+	(void) f;
+	(void) path;
+	return -EINVAL;
+}
+
+void fuse_exit(struct fuse *f)
+{
+	fuse_session_exit(f->se);
+}
+
+struct fuse_context *fuse_get_context(void)
+{
+	return &fuse_get_context_internal()->ctx;
+}
+
+/*
+ * The size of fuse_context got extended, so need to be careful about
+ * incompatibility (i.e. a new binary cannot work with an old
+ * library).
+ */
+struct fuse_context *fuse_get_context_compat22(void);
+struct fuse_context *fuse_get_context_compat22(void)
+{
+	return &fuse_get_context_internal()->ctx;
+}
+FUSE_SYMVER(".symver fuse_get_context_compat22,fuse_get_context@FUSE_2.2");
+
+int fuse_getgroups(int size, gid_t list[])
+{
+	fuse_req_t req = fuse_get_context_internal()->req;
+	return fuse_req_getgroups(req, size, list);
+}
+
+int fuse_interrupted(void)
+{
+	return fuse_req_interrupted(fuse_get_context_internal()->req);
+}
+
+void fuse_set_getcontext_func(struct fuse_context *(*func)(void))
+{
+	(void) func;
+	/* no-op */
+}
+
+enum {
+	KEY_HELP,
+};
+
+#define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v }
+
+static const struct fuse_opt fuse_lib_opts[] = {
+	FUSE_OPT_KEY("-h",		      KEY_HELP),
+	FUSE_OPT_KEY("--help",		      KEY_HELP),
+	FUSE_OPT_KEY("debug",		      FUSE_OPT_KEY_KEEP),
+	FUSE_OPT_KEY("-d",		      FUSE_OPT_KEY_KEEP),
+	FUSE_LIB_OPT("debug",		      debug, 1),
+	FUSE_LIB_OPT("-d",		      debug, 1),
+	FUSE_LIB_OPT("hard_remove",	      hard_remove, 1),
+	FUSE_LIB_OPT("use_ino",		      use_ino, 1),
+	FUSE_LIB_OPT("readdir_ino",	      readdir_ino, 1),
+	FUSE_LIB_OPT("direct_io",	      direct_io, 1),
+	FUSE_LIB_OPT("kernel_cache",	      kernel_cache, 1),
+	FUSE_LIB_OPT("auto_cache",	      auto_cache, 1),
+	FUSE_LIB_OPT("noauto_cache",	      auto_cache, 0),
+	FUSE_LIB_OPT("umask=",		      set_mode, 1),
+	FUSE_LIB_OPT("umask=%o",	      umask, 0),
+	FUSE_LIB_OPT("uid=",		      set_uid, 1),
+	FUSE_LIB_OPT("uid=%d",		      uid, 0),
+	FUSE_LIB_OPT("gid=",		      set_gid, 1),
+	FUSE_LIB_OPT("gid=%d",		      gid, 0),
+	FUSE_LIB_OPT("entry_timeout=%lf",     entry_timeout, 0),
+	FUSE_LIB_OPT("attr_timeout=%lf",      attr_timeout, 0),
+	FUSE_LIB_OPT("ac_attr_timeout=%lf",   ac_attr_timeout, 0),
+	FUSE_LIB_OPT("ac_attr_timeout=",      ac_attr_timeout_set, 1),
+	FUSE_LIB_OPT("negative_timeout=%lf",  negative_timeout, 0),
+	FUSE_LIB_OPT("noforget",              noforget, 1),
+	FUSE_LIB_OPT("intr",		      intr, 1),
+	FUSE_LIB_OPT("intr_signal=%d",	      intr_signal, 0),
+	FUSE_LIB_OPT("modules=%s",	      modules, 0),
+	FUSE_OPT_END
+};
+
+static void fuse_lib_help(void)
+{
+	fprintf(stderr,
+"    -o hard_remove         immediate removal (don't hide files)\n"
+"    -o use_ino             let filesystem set inode numbers\n"
+"    -o readdir_ino         try to fill in d_ino in readdir\n"
+"    -o direct_io           use direct I/O\n"
+"    -o kernel_cache        cache files in kernel\n"
+"    -o [no]auto_cache      enable caching based on modification times (off)\n"
+"    -o umask=M             set file permissions (octal)\n"
+"    -o uid=N               set file owner\n"
+"    -o gid=N               set file group\n"
+"    -o entry_timeout=T     cache timeout for names (1.0s)\n"
+"    -o negative_timeout=T  cache timeout for deleted names (0.0s)\n"
+"    -o attr_timeout=T      cache timeout for attributes (1.0s)\n"
+"    -o ac_attr_timeout=T   auto cache timeout for attributes (attr_timeout)\n"
+"    -o intr                allow requests to be interrupted\n"
+"    -o intr_signal=NUM     signal to send on interrupt (%i)\n"
+"    -o modules=M1[:M2...]  names of modules to push onto filesystem stack\n"
+"\n", FUSE_DEFAULT_INTR_SIGNAL);
+}
+
+static void fuse_lib_help_modules(void)
+{
+	struct fuse_module *m;
+	fprintf(stderr, "\nModule options:\n");
+	pthread_mutex_lock(&fuse_context_lock);
+	for (m = fuse_modules; m; m = m->next) {
+		struct fuse_fs *fs = NULL;
+		struct fuse_fs *newfs;
+		struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
+		if (fuse_opt_add_arg(&args, "") != -1 &&
+		    fuse_opt_add_arg(&args, "-h") != -1) {
+			fprintf(stderr, "\n[%s]\n", m->name);
+			newfs = m->factory(&args, &fs);
+			assert(newfs == NULL);
+		}
+		fuse_opt_free_args(&args);
+	}
+	pthread_mutex_unlock(&fuse_context_lock);
+}
+
+static int fuse_lib_opt_proc(void *data, const char *arg, int key,
+			     struct fuse_args *outargs)
+{
+	(void) arg; (void) outargs;
+
+	if (key == KEY_HELP) {
+		struct fuse_config *conf = (struct fuse_config *) data;
+		fuse_lib_help();
+		conf->help = 1;
+	}
+
+	return 1;
+}
+
+int fuse_is_lib_option(const char *opt)
+{
+	return fuse_lowlevel_is_lib_option(opt) ||
+		fuse_opt_match(fuse_lib_opts, opt);
+}
+
+static int fuse_init_intr_signal(int signum, int *installed)
+{
+	struct sigaction old_sa;
+
+	if (sigaction(signum, NULL, &old_sa) == -1) {
+		perror("fuse: cannot get old signal handler");
+		return -1;
+	}
+
+	if (old_sa.sa_handler == SIG_DFL) {
+		struct sigaction sa;
+
+		memset(&sa, 0, sizeof(struct sigaction));
+		sa.sa_handler = fuse_intr_sighandler;
+		sigemptyset(&sa.sa_mask);
+
+		if (sigaction(signum, &sa, NULL) == -1) {
+			perror("fuse: cannot set interrupt signal handler");
+			return -1;
+		}
+		*installed = 1;
+	}
+	return 0;
+}
+
+static void fuse_restore_intr_signal(int signum)
+{
+	struct sigaction sa;
+
+	memset(&sa, 0, sizeof(struct sigaction));
+	sa.sa_handler = SIG_DFL;
+	sigaction(signum, &sa, NULL);
+}
+
+
+static int fuse_push_module(struct fuse *f, const char *module,
+			    struct fuse_args *args)
+{
+	struct fuse_fs *fs[2] = { f->fs, NULL };
+	struct fuse_fs *newfs;
+	struct fuse_module *m = fuse_get_module(module);
+
+	if (!m)
+		return -1;
+
+	newfs = m->factory(args, fs);
+	if (!newfs) {
+		fuse_put_module(m);
+		return -1;
+	}
+	newfs->m = m;
+	f->fs = newfs;
+	f->nullpath_ok = newfs->op.flag_nullpath_ok && f->nullpath_ok;
+	return 0;
+}
+
+struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
+			    void *user_data)
+{
+	struct fuse_fs *fs;
+
+	if (sizeof(struct fuse_operations) < op_size) {
+		fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
+		op_size = sizeof(struct fuse_operations);
+	}
+
+	fs = (struct fuse_fs *) calloc(1, sizeof(struct fuse_fs));
+	if (!fs) {
+		fprintf(stderr, "fuse: failed to allocate fuse_fs object\n");
+		return NULL;
+	}
+
+	fs->user_data = user_data;
+	if (op)
+		memcpy(&fs->op, op, op_size);
+	return fs;
+}
+
+struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
+			     const struct fuse_operations *op,
+			     size_t op_size, void *user_data, int compat)
+{
+	struct fuse *f;
+	struct node *root;
+	struct fuse_fs *fs;
+	struct fuse_lowlevel_ops llop = fuse_path_ops;
+
+	if (fuse_create_context_key() == -1)
+		goto out;
+
+	f = (struct fuse *) calloc(1, sizeof(struct fuse));
+	if (f == NULL) {
+		fprintf(stderr, "fuse: failed to allocate fuse object\n");
+		goto out_delete_context_key;
+	}
+
+	fs = fuse_fs_new(op, op_size, user_data);
+	if (!fs)
+		goto out_free;
+
+	fs->compat = compat;
+	f->fs = fs;
+	f->nullpath_ok = fs->op.flag_nullpath_ok;
+
+	/* Oh f**k, this is ugly! */
+	if (!fs->op.lock) {
+		llop.getlk = NULL;
+		llop.setlk = NULL;
+	}
+
+	f->conf.entry_timeout = 1.0;
+	f->conf.attr_timeout = 1.0;
+	f->conf.negative_timeout = 0.0;
+	f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL;
+
+	if (fuse_opt_parse(args, &f->conf, fuse_lib_opts,
+			   fuse_lib_opt_proc) == -1)
+		goto out_free_fs;
+
+	if (f->conf.modules) {
+		char *module;
+		char *next;
+
+		for (module = f->conf.modules; module; module = next) {
+			char *p;
+			for (p = module; *p && *p != ':'; p++);
+			next = *p ? p + 1 : NULL;
+			*p = '\0';
+			if (module[0] &&
+			    fuse_push_module(f, module, args) == -1)
+				goto out_free_fs;
+		}
+	}
+
+	if (!f->conf.ac_attr_timeout_set)
+		f->conf.ac_attr_timeout = f->conf.attr_timeout;
+
+#ifdef __FreeBSD__
+	/*
+	 * In FreeBSD, we always use these settings as inode numbers
+	 * are needed to make getcwd(3) work.
+	 */
+	f->conf.readdir_ino = 1;
+#endif
+
+	if (compat && compat <= 25) {
+		if (fuse_sync_compat_args(args) == -1)
+			goto out_free_fs;
+	}
+
+	f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f);
+	if (f->se == NULL) {
+		if (f->conf.help)
+			fuse_lib_help_modules();
+		goto out_free_fs;
+	}
+
+	fuse_session_add_chan(f->se, ch);
+
+	if (f->conf.debug)
+		fprintf(stderr, "nullpath_ok: %i\n", f->nullpath_ok);
+
+	/* Trace topmost layer by default */
+	f->fs->debug = f->conf.debug;
+	f->ctr = 0;
+	f->generation = 0;
+	/* FIXME: Dynamic hash table */
+	f->name_table_size = 14057;
+	f->name_table = (struct node **)
+		calloc(1, sizeof(struct node *) * f->name_table_size);
+	if (f->name_table == NULL) {
+		fprintf(stderr, "fuse: memory allocation failed\n");
+		goto out_free_session;
+	}
+
+	f->id_table_size = 14057;
+	f->id_table = (struct node **)
+		calloc(1, sizeof(struct node *) * f->id_table_size);
+	if (f->id_table == NULL) {
+		fprintf(stderr, "fuse: memory allocation failed\n");
+		goto out_free_name_table;
+	}
+
+	fuse_mutex_init(&f->lock);
+
+	root = (struct node *) calloc(1, sizeof(struct node));
+	if (root == NULL) {
+		fprintf(stderr, "fuse: memory allocation failed\n");
+		goto out_free_id_table;
+	}
+
+	root->name = strdup("/");
+	if (root->name == NULL) {
+		fprintf(stderr, "fuse: memory allocation failed\n");
+		goto out_free_root;
+	}
+
+	if (f->conf.intr &&
+	    fuse_init_intr_signal(f->conf.intr_signal,
+				  &f->intr_installed) == -1)
+		goto out_free_root_name;
+
+	root->parent = NULL;
+	root->nodeid = FUSE_ROOT_ID;
+	root->generation = 0;
+	root->refctr = 1;
+	root->nlookup = 1;
+	hash_id(f, root);
+
+	return f;
+
+out_free_root_name:
+	free(root->name);
+out_free_root:
+	free(root);
+out_free_id_table:
+	free(f->id_table);
+out_free_name_table:
+	free(f->name_table);
+out_free_session:
+	fuse_session_destroy(f->se);
+out_free_fs:
+	/* Horrible compatibility hack to stop the destructor from being
+	   called on the filesystem without init being called first */
+	fs->op.destroy = NULL;
+	fuse_fs_destroy(f->fs);
+	free(f->conf.modules);
+out_free:
+	free(f);
+out_delete_context_key:
+	fuse_delete_context_key();
+out:
+	return NULL;
+}
+
+struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
+		      const struct fuse_operations *op, size_t op_size,
+		      void *user_data)
+{
+	return fuse_new_common(ch, args, op, op_size, user_data, 0);
+}
+
+void fuse_destroy(struct fuse *f)
+{
+	size_t i;
+
+	if (f->conf.intr && f->intr_installed)
+		fuse_restore_intr_signal(f->conf.intr_signal);
+
+	if (f->fs) {
+		struct fuse_context_i *c = fuse_get_context_internal();
+
+		memset(c, 0, sizeof(*c));
+		c->ctx.fuse = f;
+
+		for (i = 0; i < f->id_table_size; i++) {
+			struct node *node;
+
+			for (node = f->id_table[i]; node != NULL;
+			     node = node->id_next) {
+				if (node->is_hidden) {
+					char *path;
+					if (try_get_path(f, node->nodeid, NULL, &path, NULL, 0) == 0) {
+						fuse_fs_unlink(f->fs, path);
+						free(path);
+					}
+				}
+			}
+		}
+	}
+	for (i = 0; i < f->id_table_size; i++) {
+		struct node *node;
+		struct node *next;
+
+		for (node = f->id_table[i]; node != NULL; node = next) {
+			next = node->id_next;
+			free_node(node);
+		}
+	}
+	free(f->id_table);
+	free(f->name_table);
+	pthread_mutex_destroy(&f->lock);
+	fuse_session_destroy(f->se);
+	free(f->conf.modules);
+	free(f);
+	fuse_delete_context_key();
+}
+
+static struct fuse *fuse_new_common_compat25(int fd, struct fuse_args *args,
+					     const struct fuse_operations *op,
+					     size_t op_size, int compat)
+{
+	struct fuse *f = NULL;
+	struct fuse_chan *ch = fuse_kern_chan_new(fd);
+
+	if (ch)
+		f = fuse_new_common(ch, args, op, op_size, NULL, compat);
+
+	return f;
+}
+
+/* called with fuse_context_lock held or during initialization (before
+   main() has been called) */
+void fuse_register_module(struct fuse_module *mod)
+{
+	mod->ctr = 0;
+	mod->so = fuse_current_so;
+	if (mod->so)
+		mod->so->ctr++;
+	mod->next = fuse_modules;
+	fuse_modules = mod;
+}
+
+#ifndef __FreeBSD__
+
+static struct fuse *fuse_new_common_compat(int fd, const char *opts,
+					   const struct fuse_operations *op,
+					   size_t op_size, int compat)
+{
+	struct fuse *f;
+	struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
+
+	if (fuse_opt_add_arg(&args, "") == -1)
+		return NULL;
+	if (opts &&
+	    (fuse_opt_add_arg(&args, "-o") == -1 ||
+	     fuse_opt_add_arg(&args, opts) == -1)) {
+		fuse_opt_free_args(&args);
+		return NULL;
+	}
+	f = fuse_new_common_compat25(fd, &args, op, op_size, compat);
+	fuse_opt_free_args(&args);
+
+	return f;
+}
+
+struct fuse *fuse_new_compat22(int fd, const char *opts,
+			       const struct fuse_operations_compat22 *op,
+			       size_t op_size)
+{
+	return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
+				      op_size, 22);
+}
+
+struct fuse *fuse_new_compat2(int fd, const char *opts,
+			      const struct fuse_operations_compat2 *op)
+{
+	return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
+				      sizeof(struct fuse_operations_compat2),
+				      21);
+}
+
+struct fuse *fuse_new_compat1(int fd, int flags,
+			      const struct fuse_operations_compat1 *op)
+{
+	const char *opts = NULL;
+	if (flags & FUSE_DEBUG_COMPAT1)
+		opts = "debug";
+	return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
+				      sizeof(struct fuse_operations_compat1),
+				      11);
+}
+
+FUSE_SYMVER(".symver fuse_exited,__fuse_exited@");
+FUSE_SYMVER(".symver fuse_process_cmd,__fuse_process_cmd@");
+FUSE_SYMVER(".symver fuse_read_cmd,__fuse_read_cmd@");
+FUSE_SYMVER(".symver fuse_set_getcontext_func,__fuse_set_getcontext_func@");
+FUSE_SYMVER(".symver fuse_new_compat2,fuse_new@");
+FUSE_SYMVER(".symver fuse_new_compat22,fuse_new@FUSE_2.2");
+
+#endif /* __FreeBSD__ */
+
+struct fuse *fuse_new_compat25(int fd, struct fuse_args *args,
+			       const struct fuse_operations_compat25 *op,
+			       size_t op_size)
+{
+	return fuse_new_common_compat25(fd, args, (struct fuse_operations *) op,
+					op_size, 25);
+}
+
+FUSE_SYMVER(".symver fuse_new_compat25,fuse_new@FUSE_2.5");
diff --git a/fuse/fuse_i.h b/fuse/fuse_i.h
new file mode 100644
index 0000000..6285c95
--- /dev/null
+++ b/fuse/fuse_i.h
@@ -0,0 +1,101 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB
+*/
+
+#include "fuse.h"
+#include "fuse_lowlevel.h"
+#include <pthread.h>
+
+struct fuse_chan;
+struct fuse_ll;
+
+struct fuse_session {
+	struct fuse_session_ops op;
+
+	void *data;
+
+	volatile int exited;
+
+	struct fuse_chan *ch;
+};
+
+struct fuse_req {
+	struct fuse_ll *f;
+	uint64_t unique;
+	int ctr;
+	pthread_mutex_t lock;
+	struct fuse_ctx ctx;
+	struct fuse_chan *ch;
+	int interrupted;
+	union {
+		struct {
+			uint64_t unique;
+		} i;
+		struct {
+			fuse_interrupt_func_t func;
+			void *data;
+		} ni;
+	} u;
+	struct fuse_req *next;
+	struct fuse_req *prev;
+};
+
+struct fuse_ll {
+	int debug;
+	int allow_root;
+	int atomic_o_trunc;
+	int no_remote_lock;
+	int big_writes;
+	struct fuse_lowlevel_ops op;
+	int got_init;
+	struct cuse_data *cuse_data;
+	void *userdata;
+	uid_t owner;
+	struct fuse_conn_info conn;
+	struct fuse_req list;
+	struct fuse_req interrupts;
+	pthread_mutex_t lock;
+	int got_destroy;
+};
+
+struct fuse_cmd {
+	char *buf;
+	size_t buflen;
+	struct fuse_chan *ch;
+};
+
+struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
+			     const struct fuse_operations *op,
+			     size_t op_size, void *user_data, int compat);
+
+int fuse_sync_compat_args(struct fuse_args *args);
+
+struct fuse_chan *fuse_kern_chan_new(int fd);
+
+struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args,
+					const struct fuse_lowlevel_ops *op,
+					size_t op_size, void *userdata);
+
+void fuse_kern_unmount_compat22(const char *mountpoint);
+void fuse_kern_unmount(const char *mountpoint, int fd);
+int fuse_kern_mount(const char *mountpoint, struct fuse_args *args);
+
+int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
+			       int count);
+void fuse_free_req(fuse_req_t req);
+
+
+struct fuse *fuse_setup_common(int argc, char *argv[],
+			       const struct fuse_operations *op,
+			       size_t op_size,
+			       char **mountpoint,
+			       int *multithreaded,
+			       int *fd,
+			       void *user_data,
+			       int compat);
+
+void cuse_lowlevel_init(fuse_req_t req, fuse_ino_t nodeide, const void *inarg);
diff --git a/fuse/fuse_kern_chan.c b/fuse/fuse_kern_chan.c
new file mode 100644
index 0000000..03291c3
--- /dev/null
+++ b/fuse/fuse_kern_chan.c
@@ -0,0 +1,95 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB
+*/
+
+#include "fuse_lowlevel.h"
+#include "fuse_kernel.h"
+#include "fuse_i.h"
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+
+static int fuse_kern_chan_receive(struct fuse_chan **chp, char *buf,
+				  size_t size)
+{
+	struct fuse_chan *ch = *chp;
+	int err;
+	ssize_t res;
+	struct fuse_session *se = fuse_chan_session(ch);
+	assert(se != NULL);
+
+restart:
+	res = read(fuse_chan_fd(ch), buf, size);
+	err = errno;
+
+	if (fuse_session_exited(se))
+		return 0;
+	if (res == -1) {
+		/* ENOENT means the operation was interrupted, it's safe
+		   to restart */
+		if (err == ENOENT)
+			goto restart;
+
+		if (err == ENODEV) {
+			fuse_session_exit(se);
+			return 0;
+		}
+		/* Errors occuring during normal operation: EINTR (read
+		   interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem
+		   umounted) */
+		if (err != EINTR && err != EAGAIN)
+			perror("fuse: reading device");
+		return -err;
+	}
+	if ((size_t) res < sizeof(struct fuse_in_header)) {
+		fprintf(stderr, "short read on fuse device\n");
+		return -EIO;
+	}
+	return res;
+}
+
+static int fuse_kern_chan_send(struct fuse_chan *ch, const struct iovec iov[],
+			       size_t count)
+{
+	if (iov) {
+		ssize_t res = writev(fuse_chan_fd(ch), iov, count);
+		int err = errno;
+
+		if (res == -1) {
+			struct fuse_session *se = fuse_chan_session(ch);
+
+			assert(se != NULL);
+
+			/* ENOENT means the operation was interrupted */
+			if (!fuse_session_exited(se) && err != ENOENT)
+				perror("fuse: writing device");
+			return -err;
+		}
+	}
+	return 0;
+}
+
+static void fuse_kern_chan_destroy(struct fuse_chan *ch)
+{
+	close(fuse_chan_fd(ch));
+}
+
+#define MIN_BUFSIZE 0x21000
+
+struct fuse_chan *fuse_kern_chan_new(int fd)
+{
+	struct fuse_chan_ops op = {
+		.receive = fuse_kern_chan_receive,
+		.send = fuse_kern_chan_send,
+		.destroy = fuse_kern_chan_destroy,
+	};
+	size_t bufsize = getpagesize() + 0x1000;
+	bufsize = bufsize < MIN_BUFSIZE ? MIN_BUFSIZE : bufsize;
+	return fuse_chan_new(&op, fd, bufsize, NULL);
+}
diff --git a/fuse/fuse_loop.c b/fuse/fuse_loop.c
new file mode 100644
index 0000000..104c5d4
--- /dev/null
+++ b/fuse/fuse_loop.c
@@ -0,0 +1,39 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB
+*/
+
+#include "fuse_lowlevel.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+int fuse_session_loop(struct fuse_session *se)
+{
+	int res = 0;
+	struct fuse_chan *ch = fuse_session_next_chan(se, NULL);
+	size_t bufsize = fuse_chan_bufsize(ch);
+	char *buf = (char *) malloc(bufsize);
+	if (!buf) {
+		fprintf(stderr, "fuse: failed to allocate read buffer\n");
+		return -1;
+	}
+
+	while (!fuse_session_exited(se)) {
+		struct fuse_chan *tmpch = ch;
+		res = fuse_chan_recv(&tmpch, buf, bufsize);
+		if (res == -EINTR)
+			continue;
+		if (res <= 0)
+			break;
+		fuse_session_process(se, buf, res, tmpch);
+	}
+
+	free(buf);
+	fuse_session_reset(se);
+	return res < 0 ? -1 : 0;
+}
diff --git a/fuse/fuse_loop_mt.c b/fuse/fuse_loop_mt.c
new file mode 100644
index 0000000..a73c399
--- /dev/null
+++ b/fuse/fuse_loop_mt.c
@@ -0,0 +1,246 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB.
+*/
+
+#include "fuse_lowlevel.h"
+#include "fuse_misc.h"
+#include "fuse_kernel.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <semaphore.h>
+#include <errno.h>
+#include <sys/time.h>
+
+#ifdef __MULTI_THREAD
+
+/* Environment var controlling the thread stack size */
+#define ENVNAME_THREAD_STACK "FUSE_THREAD_STACK"
+
+struct fuse_worker {
+	struct fuse_worker *prev;
+	struct fuse_worker *next;
+	pthread_t thread_id;
+	size_t bufsize;
+	char *buf;
+	struct fuse_mt *mt;
+};
+
+struct fuse_mt {
+	pthread_mutex_t lock;
+	int numworker;
+	int numavail;
+	struct fuse_session *se;
+	struct fuse_chan *prevch;
+	struct fuse_worker main;
+	sem_t finish;
+	int exit;
+	int error;
+};
+
+static void list_add_worker(struct fuse_worker *w, struct fuse_worker *next)
+{
+	struct fuse_worker *prev = next->prev;
+	w->next = next;
+	w->prev = prev;
+	prev->next = w;
+	next->prev = w;
+}
+
+static void list_del_worker(struct fuse_worker *w)
+{
+	struct fuse_worker *prev = w->prev;
+	struct fuse_worker *next = w->next;
+	prev->next = next;
+	next->prev = prev;
+}
+
+#define PTHREAD_CANCEL_ENABLE 0
+#define PTHREAD_CANCEL_DISABLE 1
+
+static int fuse_start_thread(struct fuse_mt *mt);
+
+static void *fuse_do_work(void *data)
+{
+	struct fuse_worker *w = (struct fuse_worker *) data;
+	struct fuse_mt *mt = w->mt;
+
+	while (!fuse_session_exited(mt->se)) {
+		int isforget = 0;
+		struct fuse_chan *ch = mt->prevch;
+		int res;
+
+		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+		res = fuse_chan_recv(&ch, w->buf, w->bufsize);
+		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+		if (res == -EINTR)
+			continue;
+		if (res <= 0) {
+			if (res < 0) {
+				fuse_session_exit(mt->se);
+				mt->error = -1;
+			}
+			break;
+		}
+
+		pthread_mutex_lock(&mt->lock);
+		if (mt->exit) {
+			pthread_mutex_unlock(&mt->lock);
+			return NULL;
+		}
+
+		/*
+		 * This disgusting hack is needed so that zillions of threads
+		 * are not created on a burst of FORGET messages
+		 */
+		if (((struct fuse_in_header *) w->buf)->opcode == FUSE_FORGET)
+			isforget = 1;
+
+		if (!isforget)
+			mt->numavail--;
+		if (mt->numavail == 0)
+			fuse_start_thread(mt);
+		pthread_mutex_unlock(&mt->lock);
+
+		fuse_session_process(mt->se, w->buf, res, ch);
+
+		pthread_mutex_lock(&mt->lock);
+		if (!isforget)
+			mt->numavail++;
+		if (mt->numavail > 10) {
+			if (mt->exit) {
+				pthread_mutex_unlock(&mt->lock);
+				return NULL;
+			}
+			list_del_worker(w);
+			mt->numavail--;
+			mt->numworker--;
+			pthread_mutex_unlock(&mt->lock);
+
+			pthread_detach(w->thread_id);
+			free(w->buf);
+			free(w);
+			return NULL;
+		}
+		pthread_mutex_unlock(&mt->lock);
+	}
+
+	sem_post(&mt->finish);
+	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+	pause();
+
+	return NULL;
+}
+
+static int fuse_start_thread(struct fuse_mt *mt)
+{
+	sigset_t oldset;
+	sigset_t newset;
+	int res;
+	pthread_attr_t attr;
+	char *stack_size;
+	struct fuse_worker *w = malloc(sizeof(struct fuse_worker));
+	if (!w) {
+		fprintf(stderr, "fuse: failed to allocate worker structure\n");
+		return -1;
+	}
+	memset(w, 0, sizeof(struct fuse_worker));
+	w->bufsize = fuse_chan_bufsize(mt->prevch);
+	w->buf = malloc(w->bufsize);
+	w->mt = mt;
+	if (!w->buf) {
+		fprintf(stderr, "fuse: failed to allocate read buffer\n");
+		free(w);
+		return -1;
+	}
+
+	/* Override default stack size */
+	pthread_attr_init(&attr);
+	stack_size = getenv(ENVNAME_THREAD_STACK);
+	if (stack_size && pthread_attr_setstacksize(&attr, atoi(stack_size)))
+		fprintf(stderr, "fuse: invalid stack size: %s\n", stack_size);
+
+	/* Disallow signal reception in worker threads */
+	sigemptyset(&newset);
+	sigaddset(&newset, SIGTERM);
+	sigaddset(&newset, SIGINT);
+	sigaddset(&newset, SIGHUP);
+	sigaddset(&newset, SIGQUIT);
+	pthread_sigmask(SIG_BLOCK, &newset, &oldset);
+	res = pthread_create(&w->thread_id, &attr, fuse_do_work, w);
+	pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+	pthread_attr_destroy(&attr);
+	if (res != 0) {
+		fprintf(stderr, "fuse: error creating thread: %s\n",
+			strerror(res));
+		free(w->buf);
+		free(w);
+		return -1;
+	}
+	list_add_worker(w, &mt->main);
+	mt->numavail ++;
+	mt->numworker ++;
+
+	return 0;
+}
+
+static void fuse_join_worker(struct fuse_mt *mt, struct fuse_worker *w)
+{
+	pthread_join(w->thread_id, NULL);
+	pthread_mutex_lock(&mt->lock);
+	list_del_worker(w);
+	pthread_mutex_unlock(&mt->lock);
+	free(w->buf);
+	free(w);
+}
+
+int fuse_session_loop_mt(struct fuse_session *se)
+{
+	int err;
+	struct fuse_mt mt;
+	struct fuse_worker *w;
+
+	memset(&mt, 0, sizeof(struct fuse_mt));
+	mt.se = se;
+	mt.prevch = fuse_session_next_chan(se, NULL);
+	mt.error = 0;
+	mt.numworker = 0;
+	mt.numavail = 0;
+	mt.main.thread_id = pthread_self();
+	mt.main.prev = mt.main.next = &mt.main;
+	sem_init(&mt.finish, 0, 0);
+	fuse_mutex_init(&mt.lock);
+
+	pthread_mutex_lock(&mt.lock);
+	err = fuse_start_thread(&mt);
+	pthread_mutex_unlock(&mt.lock);
+	if (!err) {
+		/* sem_wait() is interruptible */
+		while (!fuse_session_exited(se))
+			sem_wait(&mt.finish);
+
+		for (w = mt.main.next; w != &mt.main; w = w->next)
+			pthread_cancel(w->thread_id);
+		mt.exit = 1;
+		pthread_mutex_unlock(&mt.lock);
+
+		while (mt.main.next != &mt.main)
+			fuse_join_worker(&mt, mt.main.next);
+
+		err = mt.error;
+	}
+
+	pthread_mutex_destroy(&mt.lock);
+	sem_destroy(&mt.finish);
+	fuse_session_reset(se);
+	return err;
+}
+
+#endif
diff --git a/fuse/fuse_lowlevel.c b/fuse/fuse_lowlevel.c
new file mode 100644
index 0000000..90f756e
--- /dev/null
+++ b/fuse/fuse_lowlevel.c
@@ -0,0 +1,1862 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB
+*/
+
+#include "fuse_i.h"
+#include "fuse_kernel.h"
+#include "fuse_opt.h"
+#include "fuse_misc.h"
+#include "fuse_common_compat.h"
+#include "fuse_lowlevel_compat.h"
+
+#define linux
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+
+#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
+#define OFFSET_MAX 0x7fffffffffffffffLL
+
+struct fuse_pollhandle {
+	uint64_t kh;
+	struct fuse_chan *ch;
+	struct fuse_ll *f;
+};
+
+static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
+{
+	attr->ino	= stbuf->st_ino;
+	attr->mode	= stbuf->st_mode;
+	attr->nlink	= stbuf->st_nlink;
+	attr->uid	= stbuf->st_uid;
+	attr->gid	= stbuf->st_gid;
+	attr->rdev	= stbuf->st_rdev;
+	attr->size	= stbuf->st_size;
+	attr->blksize	= stbuf->st_blksize;
+	attr->blocks	= stbuf->st_blocks;
+	attr->atime	= stbuf->st_atime;
+	attr->mtime	= stbuf->st_mtime;
+	attr->ctime	= stbuf->st_ctime;
+	attr->atimensec = ST_ATIM_NSEC(stbuf);
+	attr->mtimensec = ST_MTIM_NSEC(stbuf);
+	attr->ctimensec = ST_CTIM_NSEC(stbuf);
+}
+
+static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf)
+{
+	stbuf->st_mode	       = attr->mode;
+	stbuf->st_uid	       = attr->uid;
+	stbuf->st_gid	       = attr->gid;
+	stbuf->st_size	       = attr->size;
+	stbuf->st_atime	       = attr->atime;
+	stbuf->st_mtime	       = attr->mtime;
+	ST_ATIM_NSEC_SET(stbuf, attr->atimensec);
+	ST_MTIM_NSEC_SET(stbuf, attr->mtimensec);
+}
+
+static	size_t iov_length(const struct iovec *iov, size_t count)
+{
+	size_t seg;
+	size_t ret = 0;
+
+	for (seg = 0; seg < count; seg++)
+		ret += iov[seg].iov_len;
+	return ret;
+}
+
+static void list_init_req(struct fuse_req *req)
+{
+	req->next = req;
+	req->prev = req;
+}
+
+static void list_del_req(struct fuse_req *req)
+{
+	struct fuse_req *prev = req->prev;
+	struct fuse_req *next = req->next;
+	prev->next = next;
+	next->prev = prev;
+}
+
+static void list_add_req(struct fuse_req *req, struct fuse_req *next)
+{
+	struct fuse_req *prev = next->prev;
+	req->next = next;
+	req->prev = prev;
+	prev->next = req;
+	next->prev = req;
+}
+
+static void destroy_req(fuse_req_t req)
+{
+	pthread_mutex_destroy(&req->lock);
+	free(req);
+}
+
+void fuse_free_req(fuse_req_t req)
+{
+	int ctr;
+	struct fuse_ll *f = req->f;
+
+	pthread_mutex_lock(&f->lock);
+	req->u.ni.func = NULL;
+	req->u.ni.data = NULL;
+	list_del_req(req);
+	ctr = --req->ctr;
+	pthread_mutex_unlock(&f->lock);
+	if (!ctr)
+		destroy_req(req);
+}
+
+int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
+			       int count)
+{
+	struct fuse_out_header out;
+
+	if (error <= -1000 || error > 0) {
+		fprintf(stderr, "fuse: bad error value: %i\n",	error);
+		error = -ERANGE;
+	}
+
+	out.unique = req->unique;
+	out.error = error;
+	iov[0].iov_base = &out;
+	iov[0].iov_len = sizeof(struct fuse_out_header);
+	out.len = iov_length(iov, count);
+
+	if (req->f->debug) {
+		if (out.error) {
+			fprintf(stderr,
+				"   unique: %llu, error: %i (%s), outsize: %i\n",
+				(unsigned long long) out.unique, out.error,
+				strerror(-out.error), out.len);
+		} else {
+			fprintf(stderr,
+				"   unique: %llu, success, outsize: %i\n",
+				(unsigned long long) out.unique, out.len);
+		}
+	}
+
+	return fuse_chan_send(req->ch, iov, count);
+}
+
+static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov,
+			  int count)
+{
+	int res;
+
+	res = fuse_send_reply_iov_nofree(req, error, iov, count);
+	fuse_free_req(req);
+	return res;
+}
+
+static int send_reply(fuse_req_t req, int error, const void *arg,
+		      size_t argsize)
+{
+	struct iovec iov[2];
+	int count = 1;
+	if (argsize) {
+		iov[1].iov_base = (void *) arg;
+		iov[1].iov_len = argsize;
+		count++;
+	}
+	return send_reply_iov(req, error, iov, count);
+}
+
+int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count)
+{
+	int res;
+	struct iovec *padded_iov;
+
+	padded_iov = malloc((count + 1) * sizeof(struct iovec));
+	if (padded_iov == NULL)
+		return fuse_reply_err(req, -ENOMEM);
+
+	memcpy(padded_iov + 1, iov, count * sizeof(struct iovec));
+	count++;
+
+	res = send_reply_iov(req, 0, padded_iov, count);
+	free(padded_iov);
+
+	return res;
+}
+
+size_t fuse_dirent_size(size_t namelen)
+{
+	return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen);
+}
+
+char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf,
+		      off64_t off)
+{
+	unsigned namelen = strlen(name);
+	unsigned entlen = FUSE_NAME_OFFSET + namelen;
+	unsigned entsize = fuse_dirent_size(namelen);
+	unsigned padlen = entsize - entlen;
+	struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
+
+	dirent->ino = stbuf->st_ino;
+	dirent->off = off;
+	dirent->namelen = namelen;
+	dirent->type = (stbuf->st_mode & 0170000) >> 12;
+	strncpy(dirent->name, name, namelen);
+	if (padlen)
+		memset(buf + entlen, 0, padlen);
+
+	return buf + entsize;
+}
+
+size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
+			 const char *name, const struct stat *stbuf, off64_t off)
+{
+	size_t entsize;
+
+	(void) req;
+	entsize = fuse_dirent_size(strlen(name));
+	if (entsize <= bufsize && buf)
+		fuse_add_dirent(buf, name, stbuf, off);
+	return entsize;
+}
+
+static void convert_statfs(const struct statvfs *stbuf,
+			   struct fuse_kstatfs *kstatfs)
+{
+	kstatfs->bsize	 = stbuf->f_bsize;
+	kstatfs->frsize	 = stbuf->f_frsize;
+	kstatfs->blocks	 = stbuf->f_blocks;
+	kstatfs->bfree	 = stbuf->f_bfree;
+	kstatfs->bavail	 = stbuf->f_bavail;
+	kstatfs->files	 = stbuf->f_files;
+	kstatfs->ffree	 = stbuf->f_ffree;
+	kstatfs->namelen = stbuf->f_namemax;
+}
+
+static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize)
+{
+	return send_reply(req, 0, arg, argsize);
+}
+
+int fuse_reply_err(fuse_req_t req, int err)
+{
+	return send_reply(req, -err, NULL, 0);
+}
+
+void fuse_reply_none(fuse_req_t req)
+{
+	fuse_chan_send(req->ch, NULL, 0);
+	fuse_free_req(req);
+}
+
+static unsigned long calc_timeout_sec(double t)
+{
+	if (t > (double) ULONG_MAX)
+		return ULONG_MAX;
+	else if (t < 0.0)
+		return 0;
+	else
+		return (unsigned long) t;
+}
+
+static unsigned int calc_timeout_nsec(double t)
+{
+	double f = t - (double) calc_timeout_sec(t);
+	if (f < 0.0)
+		return 0;
+	else if (f >= 0.999999999)
+		return 999999999;
+	else
+		return (unsigned int) (f * 1.0e9);
+}
+
+static void fill_entry(struct fuse_entry_out *arg,
+		       const struct fuse_entry_param *e)
+{
+	arg->nodeid = e->ino;
+	arg->generation = e->generation;
+	arg->entry_valid = calc_timeout_sec(e->entry_timeout);
+	arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
+	arg->attr_valid = calc_timeout_sec(e->attr_timeout);
+	arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
+	convert_stat(&e->attr, &arg->attr);
+}
+
+static void fill_open(struct fuse_open_out *arg,
+		      const struct fuse_file_info *f)
+{
+	arg->fh = f->fh;
+	if (f->direct_io)
+		arg->open_flags |= FOPEN_DIRECT_IO;
+	if (f->keep_cache)
+		arg->open_flags |= FOPEN_KEEP_CACHE;
+	if (f->nonseekable)
+		arg->open_flags |= FOPEN_NONSEEKABLE;
+}
+
+int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
+{
+	struct fuse_entry_out arg;
+	size_t size = req->f->conn.proto_minor < 9 ?
+		FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(arg);
+
+	/* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant
+	   negative entry */
+	if (!e->ino && req->f->conn.proto_minor < 4)
+		return fuse_reply_err(req, ENOENT);
+
+	memset(&arg, 0, sizeof(arg));
+	fill_entry(&arg, e);
+	return send_reply_ok(req, &arg, size);
+}
+
+int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
+		      const struct fuse_file_info *f)
+{
+	char buf[sizeof(struct fuse_entry_out) + sizeof(struct fuse_open_out)];
+	size_t entrysize = req->f->conn.proto_minor < 9 ?
+		FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(struct fuse_entry_out);
+	struct fuse_entry_out *earg = (struct fuse_entry_out *) buf;
+	struct fuse_open_out *oarg = (struct fuse_open_out *) (buf + entrysize);
+
+	memset(buf, 0, sizeof(buf));
+	fill_entry(earg, e);
+	fill_open(oarg, f);
+	return send_reply_ok(req, buf,
+			     entrysize + sizeof(struct fuse_open_out));
+}
+
+int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
+		    double attr_timeout)
+{
+	struct fuse_attr_out arg;
+	size_t size = req->f->conn.proto_minor < 9 ?
+		FUSE_COMPAT_ATTR_OUT_SIZE : sizeof(arg);
+
+	memset(&arg, 0, sizeof(arg));
+	arg.attr_valid = calc_timeout_sec(attr_timeout);
+	arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
+	convert_stat(attr, &arg.attr);
+
+	return send_reply_ok(req, &arg, size);
+}
+
+int fuse_reply_readlink(fuse_req_t req, const char *linkname)
+{
+	return send_reply_ok(req, linkname, strlen(linkname));
+}
+
+int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
+{
+	struct fuse_open_out arg;
+
+	memset(&arg, 0, sizeof(arg));
+	fill_open(&arg, f);
+	return send_reply_ok(req, &arg, sizeof(arg));
+}
+
+int fuse_reply_write(fuse_req_t req, size_t count)
+{
+	struct fuse_write_out arg;
+
+	memset(&arg, 0, sizeof(arg));
+	arg.size = count;
+
+	return send_reply_ok(req, &arg, sizeof(arg));
+}
+
+int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
+{
+	return send_reply_ok(req, buf, size);
+}
+
+int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
+{
+	struct fuse_statfs_out arg;
+	size_t size = req->f->conn.proto_minor < 4 ?
+		FUSE_COMPAT_STATFS_SIZE : sizeof(arg);
+
+	memset(&arg, 0, sizeof(arg));
+	convert_statfs(stbuf, &arg.st);
+
+	return send_reply_ok(req, &arg, size);
+}
+
+int fuse_reply_xattr(fuse_req_t req, size_t count)
+{
+	struct fuse_getxattr_out arg;
+
+	memset(&arg, 0, sizeof(arg));
+	arg.size = count;
+
+	return send_reply_ok(req, &arg, sizeof(arg));
+}
+
+int fuse_reply_lock(fuse_req_t req, struct flock *lock)
+{
+	struct fuse_lk_out arg;
+
+	memset(&arg, 0, sizeof(arg));
+	arg.lk.type = lock->l_type;
+	if (lock->l_type != F_UNLCK) {
+		arg.lk.start = lock->l_start;
+		if (lock->l_len == 0)
+			arg.lk.end = OFFSET_MAX;
+		else
+			arg.lk.end = lock->l_start + lock->l_len - 1;
+	}
+	arg.lk.pid = lock->l_pid;
+	return send_reply_ok(req, &arg, sizeof(arg));
+}
+
+int fuse_reply_bmap(fuse_req_t req, uint64_t idx)
+{
+	struct fuse_bmap_out arg;
+
+	memset(&arg, 0, sizeof(arg));
+	arg.block = idx;
+
+	return send_reply_ok(req, &arg, sizeof(arg));
+}
+
+int fuse_reply_ioctl_retry(fuse_req_t req,
+			   const struct iovec *in_iov, size_t in_count,
+			   const struct iovec *out_iov, size_t out_count)
+{
+	struct fuse_ioctl_out arg;
+	struct iovec iov[4];
+	size_t count = 1;
+
+	memset(&arg, 0, sizeof(arg));
+	arg.flags |= FUSE_IOCTL_RETRY;
+	arg.in_iovs = in_count;
+	arg.out_iovs = out_count;
+	iov[count].iov_base = &arg;
+	iov[count].iov_len = sizeof(arg);
+	count++;
+
+	if (in_count) {
+		iov[count].iov_base = (void *)in_iov;
+		iov[count].iov_len = sizeof(in_iov[0]) * in_count;
+		count++;
+	}
+
+	if (out_count) {
+		iov[count].iov_base = (void *)out_iov;
+		iov[count].iov_len = sizeof(out_iov[0]) * out_count;
+		count++;
+	}
+
+	return send_reply_iov(req, 0, iov, count);
+}
+
+int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
+{
+	struct fuse_ioctl_out arg;
+	struct iovec iov[3];
+	size_t count = 1;
+
+	memset(&arg, 0, sizeof(arg));
+	arg.result = result;
+	iov[count].iov_base = &arg;
+	iov[count].iov_len = sizeof(arg);
+	count++;
+
+	if (size) {
+		iov[count].iov_base = (char *) buf;
+		iov[count].iov_len = size;
+		count++;
+	}
+
+	return send_reply_iov(req, 0, iov, count);
+}
+
+int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov,
+			 int count)
+{
+	struct iovec *padded_iov;
+	struct fuse_ioctl_out arg;
+	int res;
+
+	padded_iov = malloc((count + 2) * sizeof(struct iovec));
+	if (padded_iov == NULL)
+		return fuse_reply_err(req, -ENOMEM);
+
+	memset(&arg, 0, sizeof(arg));
+	arg.result = result;
+	padded_iov[1].iov_base = &arg;
+	padded_iov[1].iov_len = sizeof(arg);
+
+	memcpy(&padded_iov[2], iov, count * sizeof(struct iovec));
+
+	res = send_reply_iov(req, 0, padded_iov, count + 2);
+	free(padded_iov);
+
+	return res;
+}
+
+int fuse_reply_poll(fuse_req_t req, unsigned revents)
+{
+	struct fuse_poll_out arg;
+
+	memset(&arg, 0, sizeof(arg));
+	arg.revents = revents;
+
+	return send_reply_ok(req, &arg, sizeof(arg));
+}
+
+static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	char *name = (char *) inarg;
+
+	if (req->f->op.lookup)
+		req->f->op.lookup(req, nodeid, name);
+	else
+		fuse_reply_err(req, ENOSYS);
+}
+
+static void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_forget_in *arg = (struct fuse_forget_in *) inarg;
+
+	if (req->f->op.forget)
+		req->f->op.forget(req, nodeid, arg->nlookup);
+	else
+		fuse_reply_none(req);
+}
+
+static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_file_info *fip = NULL;
+	struct fuse_file_info fi;
+
+	if (req->f->conn.proto_minor >= 9) {
+		struct fuse_getattr_in *arg = (struct fuse_getattr_in *) inarg;
+
+		if (arg->getattr_flags & FUSE_GETATTR_FH) {
+			memset(&fi, 0, sizeof(fi));
+			fi.fh = arg->fh;
+			fi.fh_old = fi.fh;
+			fip = &fi;
+		}
+	}
+
+	if (req->f->op.getattr)
+		req->f->op.getattr(req, nodeid, fip);
+	else
+		fuse_reply_err(req, ENOSYS);
+}
+
+static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_setattr_in *arg = (struct fuse_setattr_in *) inarg;
+
+	if (req->f->op.setattr) {
+		struct fuse_file_info *fi = NULL;
+		struct fuse_file_info fi_store;
+		struct stat stbuf;
+		memset(&stbuf, 0, sizeof(stbuf));
+		convert_attr(arg, &stbuf);
+		if (arg->valid & FATTR_FH) {
+			arg->valid &= ~FATTR_FH;
+			memset(&fi_store, 0, sizeof(fi_store));
+			fi = &fi_store;
+			fi->fh = arg->fh;
+			fi->fh_old = fi->fh;
+		}
+		arg->valid &=
+			FUSE_SET_ATTR_MODE	|
+			FUSE_SET_ATTR_UID	|
+			FUSE_SET_ATTR_GID	|
+			FUSE_SET_ATTR_SIZE	|
+			FUSE_SET_ATTR_ATIME	|
+			FUSE_SET_ATTR_MTIME	|
+			FUSE_SET_ATTR_ATIME_NOW	|
+			FUSE_SET_ATTR_MTIME_NOW;
+
+		req->f->op.setattr(req, nodeid, &stbuf, arg->valid, fi);
+	} else
+		fuse_reply_err(req, ENOSYS);
+}
+
+static void do_access(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_access_in *arg = (struct fuse_access_in *) inarg;
+
+	if (req->f->op.access)
+		req->f->op.access(req, nodeid, arg->mask);
+	else
+		fuse_reply_err(req, ENOSYS);
+}
+
+static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	(void) inarg;
+
+	if (req->f->op.readlink)
+		req->f->op.readlink(req, nodeid);
+	else
+		fuse_reply_err(req, ENOSYS);
+}
+
+static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_mknod_in *arg = (struct fuse_mknod_in *) inarg;
+	char *name = PARAM(arg);
+
+	if (req->f->conn.proto_minor >= 12)
+		req->ctx.umask = arg->umask;
+	else
+		name = (char *) inarg + FUSE_COMPAT_MKNOD_IN_SIZE;
+
+	if (req->f->op.mknod)
+		req->f->op.mknod(req, nodeid, name, arg->mode, arg->rdev);
+	else
+		fuse_reply_err(req, ENOSYS);
+}
+
+static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *) inarg;
+
+	if (req->f->conn.proto_minor >= 12)
+		req->ctx.umask = arg->umask;
+
+	if (req->f->op.mkdir)
+		req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
+	else
+		fuse_reply_err(req, ENOSYS);
+}
+
+static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	char *name = (char *) inarg;
+
+	if (req->f->op.unlink)
+		req->f->op.unlink(req, nodeid, name);
+	else
+		fuse_reply_err(req, ENOSYS);
+}
+
+static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	char *name = (char *) inarg;
+
+	if (req->f->op.rmdir)
+		req->f->op.rmdir(req, nodeid, name);
+	else
+		fuse_reply_err(req, ENOSYS);
+}
+
+static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	char *name = (char *) inarg;
+	char *linkname = ((char *) inarg) + strlen((char *) inarg) + 1;
+
+	if (req->f->op.symlink)
+		req->f->op.symlink(req, linkname, nodeid, name);
+	else
+		fuse_reply_err(req, ENOSYS);
+}
+
+static void do_rename(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_rename_in *arg = (struct fuse_rename_in *) inarg;
+	char *oldname = PARAM(arg);
+	char *newname = oldname + strlen(oldname) + 1;
+
+	if (req->f->op.rename)
+		req->f->op.rename(req, nodeid, oldname, arg->newdir, newname);
+	else
+		fuse_reply_err(req, ENOSYS);
+}
+
+static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_link_in *arg = (struct fuse_link_in *) inarg;
+
+	if (req->f->op.link)
+		req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
+	else
+		fuse_reply_err(req, ENOSYS);
+}
+
+static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_create_in *arg = (struct fuse_create_in *) inarg;
+
+	if (req->f->op.create) {
+		struct fuse_file_info fi;
+		char *name = PARAM(arg);
+
+		memset(&fi, 0, sizeof(fi));
+		fi.flags = arg->flags;
+
+		if (req->f->conn.proto_minor >= 12)
+			req->ctx.umask = arg->umask;
+		else
+			name = (char *) inarg + sizeof(struct fuse_open_in);
+
+		req->f->op.create(req, nodeid, name, arg->mode, &fi);
+	} else
+		fuse_reply_err(req, ENOSYS);
+}
+
+static void do_open(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
+	struct fuse_file_info fi;
+
+	memset(&fi, 0, sizeof(fi));
+	fi.flags = arg->flags;
+
+	if (req->f->op.open)
+		req->f->op.open(req, nodeid, &fi);
+	else
+		fuse_reply_open(req, &fi);
+}
+
+static void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
+
+	if (req->f->op.read) {
+		struct fuse_file_info fi;
+
+		memset(&fi, 0, sizeof(fi));
+		fi.fh = arg->fh;
+		fi.fh_old = fi.fh;
+		if (req->f->conn.proto_minor >= 9) {
+			fi.lock_owner = arg->lock_owner;
+			fi.flags = arg->flags;
+		}
+		req->f->op.read(req, nodeid, arg->size, arg->offset, &fi);
+	} else
+		fuse_reply_err(req, ENOSYS);
+}
+
+static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_write_in *arg = (struct fuse_write_in *) inarg;
+	struct fuse_file_info fi;
+	char *param;
+
+	memset(&fi, 0, sizeof(fi));
+	fi.fh = arg->fh;
+	fi.fh_old = fi.fh;
+	fi.writepage = arg->write_flags & 1;
+
+	if (req->f->conn.proto_minor < 9) {
+		param = ((char *) arg) + FUSE_COMPAT_WRITE_IN_SIZE;
+	} else {
+		fi.lock_owner = arg->lock_owner;
+		fi.flags = arg->flags;
+		param = PARAM(arg);
+	}
+
+	if (req->f->op.write)
+		req->f->op.write(req, nodeid, param, arg->size,
+				 arg->offset, &fi);
+	else
+		fuse_reply_err(req, ENOSYS);
+}
+
+static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_flush_in *arg = (struct fuse_flush_in *) inarg;
+	struct fuse_file_info fi;
+
+	memset(&fi, 0, sizeof(fi));
+	fi.fh = arg->fh;
+	fi.fh_old = fi.fh;
+	fi.flush = 1;
+	if (req->f->conn.proto_minor >= 7)
+		fi.lock_owner = arg->lock_owner;
+
+	if (req->f->op.flush)
+		req->f->op.flush(req, nodeid, &fi);
+	else
+		fuse_reply_err(req, ENOSYS);
+}
+
+static void do_release(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
+	struct fuse_file_info fi;
+
+	memset(&fi, 0, sizeof(fi));
+	fi.flags = arg->flags;
+	fi.fh = arg->fh;
+	fi.fh_old = fi.fh;
+	if (req->f->conn.proto_minor >= 8) {
+		fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0;
+		fi.lock_owner = arg->lock_owner;
+	}
+
+	if (req->f->op.release)
+		req->f->op.release(req, nodeid, &fi);
+	else
+		fuse_reply_err(req, 0);
+}
+
+static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg;
+	struct fuse_file_info fi;
+
+	memset(&fi, 0, sizeof(fi));
+	fi.fh = arg->fh;
+	fi.fh_old = fi.fh;
+
+	if (req->f->op.fsync)
+		req->f->op.fsync(req, nodeid, arg->fsync_flags & 1, &fi);
+	else
+		fuse_reply_err(req, ENOSYS);
+}
+
+static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
+	struct fuse_file_info fi;
+
+	memset(&fi, 0, sizeof(fi));
+	fi.flags = arg->flags;
+
+	if (req->f->op.opendir)
+		req->f->op.opendir(req, nodeid, &fi);
+	else
+		fuse_reply_open(req, &fi);
+}
+
+static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
+	struct fuse_file_info fi;
+
+	memset(&fi, 0, sizeof(fi));
+	fi.fh = arg->fh;
+	fi.fh_old = fi.fh;
+
+	if (req->f->op.readdir)
+		req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
+	else
+		fuse_reply_err(req, ENOSYS);
+}
+
+static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
+	struct fuse_file_info fi;
+
+	memset(&fi, 0, sizeof(fi));
+	fi.flags = arg->flags;
+	fi.fh = arg->fh;
+	fi.fh_old = fi.fh;
+
+	if (req->f->op.releasedir)
+		req->f->op.releasedir(req, nodeid, &fi);
+	else
+		fuse_reply_err(req, 0);
+}
+
+static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg;
+	struct fuse_file_info fi;
+
+	memset(&fi, 0, sizeof(fi));
+	fi.fh = arg->fh;
+	fi.fh_old = fi.fh;
+
+	if (req->f->op.fsyncdir)
+		req->f->op.fsyncdir(req, nodeid, arg->fsync_flags & 1, &fi);
+	else
+		fuse_reply_err(req, ENOSYS);
+}
+
+static void do_statfs(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	(void) nodeid;
+	(void) inarg;
+
+	if (req->f->op.statfs)
+		req->f->op.statfs(req, nodeid);
+	else {
+		struct statvfs buf = {
+			.f_namemax = 255,
+			.f_bsize = 512,
+		};
+		fuse_reply_statfs(req, &buf);
+	}
+}
+
+static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *) inarg;
+	char *name = PARAM(arg);
+	char *value = name + strlen(name) + 1;
+
+	if (req->f->op.setxattr)
+		req->f->op.setxattr(req, nodeid, name, value, arg->size,
+				    arg->flags);
+	else
+		fuse_reply_err(req, ENOSYS);
+}
+
+static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg;
+
+	if (req->f->op.getxattr)
+		req->f->op.getxattr(req, nodeid, PARAM(arg), arg->size);
+	else
+		fuse_reply_err(req, ENOSYS);
+}
+
+static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg;
+
+	if (req->f->op.listxattr)
+		req->f->op.listxattr(req, nodeid, arg->size);
+	else
+		fuse_reply_err(req, ENOSYS);
+}
+
+static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	char *name = (char *) inarg;
+
+	if (req->f->op.removexattr)
+		req->f->op.removexattr(req, nodeid, name);
+	else
+		fuse_reply_err(req, ENOSYS);
+}
+
+static void convert_fuse_file_lock(struct fuse_file_lock *fl,
+				   struct flock *flock)
+{
+	memset(flock, 0, sizeof(struct flock));
+	flock->l_type = fl->type;
+	flock->l_whence = SEEK_SET;
+	flock->l_start = fl->start;
+	if (fl->end == OFFSET_MAX)
+		flock->l_len = 0;
+	else
+		flock->l_len = fl->end - fl->start + 1;
+	flock->l_pid = fl->pid;
+}
+
+static void do_getlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg;
+	struct fuse_file_info fi;
+	struct flock flock;
+
+	memset(&fi, 0, sizeof(fi));
+	fi.fh = arg->fh;
+	fi.lock_owner = arg->owner;
+
+	convert_fuse_file_lock(&arg->lk, &flock);
+	if (req->f->op.getlk)
+		req->f->op.getlk(req, nodeid, &fi, &flock);
+	else
+		fuse_reply_err(req, ENOSYS);
+}
+
+static void do_setlk_common(fuse_req_t req, fuse_ino_t nodeid,
+			    const void *inarg, int sleep)
+{
+	struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg;
+	struct fuse_file_info fi;
+	struct flock flock;
+
+	memset(&fi, 0, sizeof(fi));
+	fi.fh = arg->fh;
+	fi.lock_owner = arg->owner;
+
+	convert_fuse_file_lock(&arg->lk, &flock);
+	if (req->f->op.setlk)
+		req->f->op.setlk(req, nodeid, &fi, &flock, sleep);
+	else
+		fuse_reply_err(req, ENOSYS);
+}
+
+static void do_setlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	do_setlk_common(req, nodeid, inarg, 0);
+}
+
+static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	do_setlk_common(req, nodeid, inarg, 1);
+}
+
+static int find_interrupted(struct fuse_ll *f, struct fuse_req *req)
+{
+	struct fuse_req *curr;
+
+	for (curr = f->list.next; curr != &f->list; curr = curr->next) {
+		if (curr->unique == req->u.i.unique) {
+			fuse_interrupt_func_t func;
+			void *data;
+
+			curr->ctr++;
+			pthread_mutex_unlock(&f->lock);
+
+			/* Ugh, ugly locking */
+			pthread_mutex_lock(&curr->lock);
+			pthread_mutex_lock(&f->lock);
+			curr->interrupted = 1;
+			func = curr->u.ni.func;
+			data = curr->u.ni.data;
+			pthread_mutex_unlock(&f->lock);
+			if (func)
+				func(curr, data);
+			pthread_mutex_unlock(&curr->lock);
+
+			pthread_mutex_lock(&f->lock);
+			curr->ctr--;
+			if (!curr->ctr)
+				destroy_req(curr);
+
+			return 1;
+		}
+	}
+	for (curr = f->interrupts.next; curr != &f->interrupts;
+	     curr = curr->next) {
+		if (curr->u.i.unique == req->u.i.unique)
+			return 1;
+	}
+	return 0;
+}
+
+static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_interrupt_in *arg = (struct fuse_interrupt_in *) inarg;
+	struct fuse_ll *f = req->f;
+
+	(void) nodeid;
+	if (f->debug)
+		fprintf(stderr, "INTERRUPT: %llu\n",
+			(unsigned long long) arg->unique);
+
+	req->u.i.unique = arg->unique;
+
+	pthread_mutex_lock(&f->lock);
+	if (find_interrupted(f, req))
+		destroy_req(req);
+	else
+		list_add_req(req, &f->interrupts);
+	pthread_mutex_unlock(&f->lock);
+}
+
+static struct fuse_req *check_interrupt(struct fuse_ll *f, struct fuse_req *req)
+{
+	struct fuse_req *curr;
+
+	for (curr = f->interrupts.next; curr != &f->interrupts;
+	     curr = curr->next) {
+		if (curr->u.i.unique == req->unique) {
+			req->interrupted = 1;
+			list_del_req(curr);
+			free(curr);
+			return NULL;
+		}
+	}
+	curr = f->interrupts.next;
+	if (curr != &f->interrupts) {
+		list_del_req(curr);
+		list_init_req(curr);
+		return curr;
+	} else
+		return NULL;
+}
+
+static void do_bmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_bmap_in *arg = (struct fuse_bmap_in *) inarg;
+
+	if (req->f->op.bmap)
+		req->f->op.bmap(req, nodeid, arg->blocksize, arg->block);
+	else
+		fuse_reply_err(req, ENOSYS);
+}
+
+static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_ioctl_in *arg = (struct fuse_ioctl_in *) inarg;
+	unsigned int flags = arg->flags;
+	void *in_buf = arg->in_size ? PARAM(arg) : NULL;
+	struct fuse_file_info fi;
+
+	memset(&fi, 0, sizeof(fi));
+	fi.fh = arg->fh;
+	fi.fh_old = fi.fh;
+
+	if (req->f->op.ioctl)
+		req->f->op.ioctl(req, nodeid, arg->cmd,
+				 (void *)(uintptr_t)arg->arg, &fi, flags,
+				 in_buf, arg->in_size, arg->out_size);
+	else
+		fuse_reply_err(req, ENOSYS);
+}
+
+void fuse_pollhandle_destroy(struct fuse_pollhandle *ph)
+{
+	free(ph);
+}
+
+static void do_poll(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_poll_in *arg = (struct fuse_poll_in *) inarg;
+	struct fuse_file_info fi;
+
+	memset(&fi, 0, sizeof(fi));
+	fi.fh = arg->fh;
+	fi.fh_old = fi.fh;
+
+	if (req->f->op.poll) {
+		struct fuse_pollhandle *ph = NULL;
+
+		if (arg->flags & FUSE_POLL_SCHEDULE_NOTIFY) {
+			ph = malloc(sizeof(struct fuse_pollhandle));
+			if (ph == NULL) {
+				fuse_reply_err(req, ENOMEM);
+				return;
+			}
+			ph->kh = arg->kh;
+			ph->ch = req->ch;
+			ph->f = req->f;
+		}
+
+		req->f->op.poll(req, nodeid, &fi, ph);
+	} else {
+		fuse_reply_err(req, ENOSYS);
+	}
+}
+
+static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_init_in *arg = (struct fuse_init_in *) inarg;
+	struct fuse_init_out outarg;
+	struct fuse_ll *f = req->f;
+	size_t bufsize = fuse_chan_bufsize(req->ch);
+
+	(void) nodeid;
+	if (f->debug) {
+		fprintf(stderr, "INIT: %u.%u\n", arg->major, arg->minor);
+		if (arg->major == 7 && arg->minor >= 6) {
+			fprintf(stderr, "flags=0x%08x\n", arg->flags);
+			fprintf(stderr, "max_readahead=0x%08x\n",
+				arg->max_readahead);
+		}
+	}
+	f->conn.proto_major = arg->major;
+	f->conn.proto_minor = arg->minor;
+	f->conn.capable = 0;
+	f->conn.want = 0;
+
+	memset(&outarg, 0, sizeof(outarg));
+	outarg.major = FUSE_KERNEL_VERSION;
+	outarg.minor = FUSE_KERNEL_MINOR_VERSION;
+
+	if (arg->major < 7) {
+		fprintf(stderr, "fuse: unsupported protocol version: %u.%u\n",
+			arg->major, arg->minor);
+		fuse_reply_err(req, EPROTO);
+		return;
+	}
+
+	if (arg->major > 7) {
+		/* Wait for a second INIT request with a 7.X version */
+		send_reply_ok(req, &outarg, sizeof(outarg));
+		return;
+	}
+
+	if (arg->minor >= 6) {
+		if (f->conn.async_read)
+			f->conn.async_read = arg->flags & FUSE_ASYNC_READ;
+		if (arg->max_readahead < f->conn.max_readahead)
+			f->conn.max_readahead = arg->max_readahead;
+		if (arg->flags & FUSE_ASYNC_READ)
+			f->conn.capable |= FUSE_CAP_ASYNC_READ;
+		if (arg->flags & FUSE_POSIX_LOCKS)
+			f->conn.capable |= FUSE_CAP_POSIX_LOCKS;
+		if (arg->flags & FUSE_ATOMIC_O_TRUNC)
+			f->conn.capable |= FUSE_CAP_ATOMIC_O_TRUNC;
+		if (arg->flags & FUSE_EXPORT_SUPPORT)
+			f->conn.capable |= FUSE_CAP_EXPORT_SUPPORT;
+		if (arg->flags & FUSE_BIG_WRITES)
+			f->conn.capable |= FUSE_CAP_BIG_WRITES;
+		if (arg->flags & FUSE_DONT_MASK)
+			f->conn.capable |= FUSE_CAP_DONT_MASK;
+	} else {
+		f->conn.async_read = 0;
+		f->conn.max_readahead = 0;
+	}
+
+	if (f->atomic_o_trunc)
+		f->conn.want |= FUSE_CAP_ATOMIC_O_TRUNC;
+	if (f->op.getlk && f->op.setlk && !f->no_remote_lock)
+		f->conn.want |= FUSE_CAP_POSIX_LOCKS;
+	if (f->big_writes)
+		f->conn.want |= FUSE_CAP_BIG_WRITES;
+
+	if (bufsize < FUSE_MIN_READ_BUFFER) {
+		fprintf(stderr, "fuse: warning: buffer size too small: %zu\n",
+			bufsize);
+		bufsize = FUSE_MIN_READ_BUFFER;
+	}
+
+	bufsize -= 4096;
+	if (bufsize < f->conn.max_write)
+		f->conn.max_write = bufsize;
+
+	f->got_init = 1;
+	if (f->op.init)
+		f->op.init(f->userdata, &f->conn);
+
+	if (f->conn.async_read || (f->conn.want & FUSE_CAP_ASYNC_READ))
+		outarg.flags |= FUSE_ASYNC_READ;
+	if (f->conn.want & FUSE_CAP_POSIX_LOCKS)
+		outarg.flags |= FUSE_POSIX_LOCKS;
+	if (f->conn.want & FUSE_CAP_ATOMIC_O_TRUNC)
+		outarg.flags |= FUSE_ATOMIC_O_TRUNC;
+	if (f->conn.want & FUSE_CAP_EXPORT_SUPPORT)
+		outarg.flags |= FUSE_EXPORT_SUPPORT;
+	if (f->conn.want & FUSE_CAP_BIG_WRITES)
+		outarg.flags |= FUSE_BIG_WRITES;
+	if (f->conn.want & FUSE_CAP_DONT_MASK)
+		outarg.flags |= FUSE_DONT_MASK;
+	outarg.max_readahead = f->conn.max_readahead;
+	outarg.max_write = f->conn.max_write;
+
+	if (f->debug) {
+		fprintf(stderr, "   INIT: %u.%u\n", outarg.major, outarg.minor);
+		fprintf(stderr, "   flags=0x%08x\n", outarg.flags);
+		fprintf(stderr, "   max_readahead=0x%08x\n",
+			outarg.max_readahead);
+		fprintf(stderr, "   max_write=0x%08x\n", outarg.max_write);
+	}
+
+	send_reply_ok(req, &outarg, arg->minor < 5 ? 8 : sizeof(outarg));
+}
+
+static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+	struct fuse_ll *f = req->f;
+
+	(void) nodeid;
+	(void) inarg;
+
+	f->got_destroy = 1;
+	if (f->op.destroy)
+		f->op.destroy(f->userdata);
+
+	send_reply_ok(req, NULL, 0);
+}
+
+static int send_notify_iov(struct fuse_ll *f, struct fuse_chan *ch,
+			   int notify_code, struct iovec *iov, int count)
+{
+	struct fuse_out_header out;
+
+	out.unique = 0;
+	out.error = notify_code;
+	iov[0].iov_base = &out;
+	iov[0].iov_len = sizeof(struct fuse_out_header);
+	out.len = iov_length(iov, count);
+
+	if (f->debug)
+		fprintf(stderr, "NOTIFY: code=%d count=%d length=%u\n",
+			notify_code, count, out.len);
+
+	return fuse_chan_send(ch, iov, count);
+}
+
+int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
+{
+	if (ph != NULL) {
+		struct fuse_notify_poll_wakeup_out outarg;
+		struct iovec iov[2];
+
+		outarg.kh = ph->kh;
+
+		iov[1].iov_base = &outarg;
+		iov[1].iov_len = sizeof(outarg);
+
+		return send_notify_iov(ph->f, ph->ch, FUSE_NOTIFY_POLL, iov, 2);
+	} else {
+		return 0;
+	}
+}
+
+int fuse_lowlevel_notify_inval_inode(struct fuse_chan *ch, fuse_ino_t ino,
+                                     off64_t off, off64_t len)
+{
+	struct fuse_notify_inval_inode_out outarg;
+	struct fuse_ll *f;
+	struct iovec iov[2];
+
+	if (!ch)
+		return -EINVAL;
+
+	f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch));
+	if (!f)
+		return -ENODEV;
+
+	outarg.ino = ino;
+	outarg.off = off;
+	outarg.len = len;
+
+	iov[1].iov_base = &outarg;
+	iov[1].iov_len = sizeof(outarg);
+
+	return send_notify_iov(f, ch, FUSE_NOTIFY_INVAL_INODE, iov, 2);
+}
+
+int fuse_lowlevel_notify_inval_entry(struct fuse_chan *ch, fuse_ino_t parent,
+                                     const char *name, size_t namelen)
+{
+	struct fuse_notify_inval_entry_out outarg;
+	struct fuse_ll *f;
+	struct iovec iov[3];
+
+	if (!ch)
+		return -EINVAL;
+
+	f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch));
+	if (!f)
+		return -ENODEV;
+
+	outarg.parent = parent;
+	outarg.namelen = namelen;
+	outarg.padding = 0;
+
+	iov[1].iov_base = &outarg;
+	iov[1].iov_len = sizeof(outarg);
+	iov[2].iov_base = (void *)name;
+	iov[2].iov_len = namelen + 1;
+
+	return send_notify_iov(f, ch, FUSE_NOTIFY_INVAL_ENTRY, iov, 3);
+}
+
+void *fuse_req_userdata(fuse_req_t req)
+{
+	return req->f->userdata;
+}
+
+const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
+{
+	return &req->ctx;
+}
+
+/*
+ * The size of fuse_ctx got extended, so need to be careful about
+ * incompatibility (i.e. a new binary cannot work with an old
+ * library).
+ */
+const struct fuse_ctx *fuse_req_ctx_compat24(fuse_req_t req);
+const struct fuse_ctx *fuse_req_ctx_compat24(fuse_req_t req)
+{
+	return fuse_req_ctx(req);
+}
+FUSE_SYMVER(".symver fuse_req_ctx_compat24,fuse_req_ctx@FUSE_2.4");
+
+
+void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,
+			     void *data)
+{
+	pthread_mutex_lock(&req->lock);
+	pthread_mutex_lock(&req->f->lock);
+	req->u.ni.func = func;
+	req->u.ni.data = data;
+	pthread_mutex_unlock(&req->f->lock);
+	if (req->interrupted && func)
+		func(req, data);
+	pthread_mutex_unlock(&req->lock);
+}
+
+int fuse_req_interrupted(fuse_req_t req)
+{
+	int interrupted;
+
+	pthread_mutex_lock(&req->f->lock);
+	interrupted = req->interrupted;
+	pthread_mutex_unlock(&req->f->lock);
+
+	return interrupted;
+}
+
+static struct {
+	void (*func)(fuse_req_t, fuse_ino_t, const void *);
+	const char *name;
+} fuse_ll_ops[] = {
+	[FUSE_LOOKUP]	   = { do_lookup,      "LOOKUP"	     },
+	[FUSE_FORGET]	   = { do_forget,      "FORGET"	     },
+	[FUSE_GETATTR]	   = { do_getattr,     "GETATTR"     },
+	[FUSE_SETATTR]	   = { do_setattr,     "SETATTR"     },
+	[FUSE_READLINK]	   = { do_readlink,    "READLINK"    },
+	[FUSE_SYMLINK]	   = { do_symlink,     "SYMLINK"     },
+	[FUSE_MKNOD]	   = { do_mknod,       "MKNOD"	     },
+	[FUSE_MKDIR]	   = { do_mkdir,       "MKDIR"	     },
+	[FUSE_UNLINK]	   = { do_unlink,      "UNLINK"	     },
+	[FUSE_RMDIR]	   = { do_rmdir,       "RMDIR"	     },
+	[FUSE_RENAME]	   = { do_rename,      "RENAME"	     },
+	[FUSE_LINK]	   = { do_link,	       "LINK"	     },
+	[FUSE_OPEN]	   = { do_open,	       "OPEN"	     },
+	[FUSE_READ]	   = { do_read,	       "READ"	     },
+	[FUSE_WRITE]	   = { do_write,       "WRITE"	     },
+	[FUSE_STATFS]	   = { do_statfs,      "STATFS"	     },
+	[FUSE_RELEASE]	   = { do_release,     "RELEASE"     },
+	[FUSE_FSYNC]	   = { do_fsync,       "FSYNC"	     },
+	[FUSE_SETXATTR]	   = { do_setxattr,    "SETXATTR"    },
+	[FUSE_GETXATTR]	   = { do_getxattr,    "GETXATTR"    },
+	[FUSE_LISTXATTR]   = { do_listxattr,   "LISTXATTR"   },
+	[FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" },
+	[FUSE_FLUSH]	   = { do_flush,       "FLUSH"	     },
+	[FUSE_INIT]	   = { do_init,	       "INIT"	     },
+	[FUSE_OPENDIR]	   = { do_opendir,     "OPENDIR"     },
+	[FUSE_READDIR]	   = { do_readdir,     "READDIR"     },
+	[FUSE_RELEASEDIR]  = { do_releasedir,  "RELEASEDIR"  },
+	[FUSE_FSYNCDIR]	   = { do_fsyncdir,    "FSYNCDIR"    },
+	[FUSE_GETLK]	   = { do_getlk,       "GETLK"	     },
+	[FUSE_SETLK]	   = { do_setlk,       "SETLK"	     },
+	[FUSE_SETLKW]	   = { do_setlkw,      "SETLKW"	     },
+	[FUSE_ACCESS]	   = { do_access,      "ACCESS"	     },
+	[FUSE_CREATE]	   = { do_create,      "CREATE"	     },
+	[FUSE_INTERRUPT]   = { do_interrupt,   "INTERRUPT"   },
+	[FUSE_BMAP]	   = { do_bmap,	       "BMAP"	     },
+	[FUSE_IOCTL]	   = { do_ioctl,       "IOCTL"	     },
+	[FUSE_POLL]	   = { do_poll,        "POLL"	     },
+	[FUSE_DESTROY]	   = { do_destroy,     "DESTROY"     },
+	[CUSE_INIT]	   = { cuse_lowlevel_init, "CUSE_INIT"   },
+};
+
+#define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0]))
+
+static const char *opname(enum fuse_opcode opcode)
+{
+	if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name)
+		return "???";
+	else
+		return fuse_ll_ops[opcode].name;
+}
+
+static void fuse_ll_process(void *data, const char *buf, size_t len,
+			    struct fuse_chan *ch)
+{
+	struct fuse_ll *f = (struct fuse_ll *) data;
+	struct fuse_in_header *in = (struct fuse_in_header *) buf;
+	const void *inarg = buf + sizeof(struct fuse_in_header);
+	struct fuse_req *req;
+	int err;
+
+	if (f->debug)
+		fprintf(stderr,
+			"unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %zu\n",
+			(unsigned long long) in->unique,
+			opname((enum fuse_opcode) in->opcode), in->opcode,
+			(unsigned long) in->nodeid, len);
+
+	req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req));
+	if (req == NULL) {
+		fprintf(stderr, "fuse: failed to allocate request\n");
+		return;
+	}
+
+	req->f = f;
+	req->unique = in->unique;
+	req->ctx.uid = in->uid;
+	req->ctx.gid = in->gid;
+	req->ctx.pid = in->pid;
+	req->ch = ch;
+	req->ctr = 1;
+	list_init_req(req);
+	fuse_mutex_init(&req->lock);
+
+	err = EIO;
+	if (!f->got_init) {
+		enum fuse_opcode expected;
+
+		expected = f->cuse_data ? CUSE_INIT : FUSE_INIT;
+		if (in->opcode != expected)
+			goto reply_err;
+	} else if (in->opcode == FUSE_INIT || in->opcode == CUSE_INIT)
+		goto reply_err;
+
+	err = EACCES;
+	if (f->allow_root && in->uid != f->owner && in->uid != 0 &&
+		 in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
+		 in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
+		 in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
+		 in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR)
+		goto reply_err;
+
+	err = ENOSYS;
+	if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func)
+		goto reply_err;
+	if (in->opcode != FUSE_INTERRUPT) {
+		struct fuse_req *intr;
+		pthread_mutex_lock(&f->lock);
+		intr = check_interrupt(f, req);
+		list_add_req(req, &f->list);
+		pthread_mutex_unlock(&f->lock);
+		if (intr)
+			fuse_reply_err(intr, EAGAIN);
+	}
+	fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);
+	return;
+
+ reply_err:
+	fuse_reply_err(req, err);
+}
+
+enum {
+	KEY_HELP,
+	KEY_VERSION,
+};
+
+static struct fuse_opt fuse_ll_opts[] = {
+	{ "debug", offsetof(struct fuse_ll, debug), 1 },
+	{ "-d", offsetof(struct fuse_ll, debug), 1 },
+	{ "allow_root", offsetof(struct fuse_ll, allow_root), 1 },
+	{ "max_write=%u", offsetof(struct fuse_ll, conn.max_write), 0 },
+	{ "max_readahead=%u", offsetof(struct fuse_ll, conn.max_readahead), 0 },
+	{ "async_read", offsetof(struct fuse_ll, conn.async_read), 1 },
+	{ "sync_read", offsetof(struct fuse_ll, conn.async_read), 0 },
+	{ "atomic_o_trunc", offsetof(struct fuse_ll, atomic_o_trunc), 1},
+	{ "no_remote_lock", offsetof(struct fuse_ll, no_remote_lock), 1},
+	{ "big_writes", offsetof(struct fuse_ll, big_writes), 1},
+	FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_DISCARD),
+	FUSE_OPT_KEY("-h", KEY_HELP),
+	FUSE_OPT_KEY("--help", KEY_HELP),
+	FUSE_OPT_KEY("-V", KEY_VERSION),
+	FUSE_OPT_KEY("--version", KEY_VERSION),
+	FUSE_OPT_END
+};
+
+static void fuse_ll_version(void)
+{
+	fprintf(stderr, "using FUSE kernel interface version %i.%i\n",
+		FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
+}
+
+static void fuse_ll_help(void)
+{
+	fprintf(stderr,
+"    -o max_write=N         set maximum size of write requests\n"
+"    -o max_readahead=N     set maximum readahead\n"
+"    -o async_read          perform reads asynchronously (default)\n"
+"    -o sync_read           perform reads synchronously\n"
+"    -o atomic_o_trunc      enable atomic open+truncate support\n"
+"    -o big_writes          enable larger than 4kB writes\n"
+"    -o no_remote_lock      disable remote file locking\n");
+}
+
+static int fuse_ll_opt_proc(void *data, const char *arg, int key,
+			    struct fuse_args *outargs)
+{
+	(void) data; (void) outargs;
+
+	switch (key) {
+	case KEY_HELP:
+		fuse_ll_help();
+		break;
+
+	case KEY_VERSION:
+		fuse_ll_version();
+		break;
+
+	default:
+		fprintf(stderr, "fuse: unknown option `%s'\n", arg);
+	}
+
+	return -1;
+}
+
+int fuse_lowlevel_is_lib_option(const char *opt)
+{
+	return fuse_opt_match(fuse_ll_opts, opt);
+}
+
+static void fuse_ll_destroy(void *data)
+{
+	struct fuse_ll *f = (struct fuse_ll *) data;
+
+	if (f->got_init && !f->got_destroy) {
+		if (f->op.destroy)
+			f->op.destroy(f->userdata);
+	}
+
+	pthread_mutex_destroy(&f->lock);
+	free(f->cuse_data);
+	free(f);
+}
+
+/*
+ * always call fuse_lowlevel_new_common() internally, to work around a
+ * misfeature in the FreeBSD runtime linker, which links the old
+ * version of a symbol to internal references.
+ */
+struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args,
+					      const struct fuse_lowlevel_ops *op,
+					      size_t op_size, void *userdata)
+{
+	struct fuse_ll *f;
+	struct fuse_session *se;
+	struct fuse_session_ops sop = {
+		.process = fuse_ll_process,
+		.destroy = fuse_ll_destroy,
+	};
+
+	if (sizeof(struct fuse_lowlevel_ops) < op_size) {
+		fprintf(stderr, "fuse: warning: library too old, some operations may not work\n");
+		op_size = sizeof(struct fuse_lowlevel_ops);
+	}
+
+	f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll));
+	if (f == NULL) {
+		fprintf(stderr, "fuse: failed to allocate fuse object\n");
+		goto out;
+	}
+
+	f->conn.async_read = 1;
+	f->conn.max_write = UINT_MAX;
+	f->conn.max_readahead = UINT_MAX;
+	f->atomic_o_trunc = 0;
+	list_init_req(&f->list);
+	list_init_req(&f->interrupts);
+	fuse_mutex_init(&f->lock);
+
+	if (fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1)
+		goto out_free;
+
+	if (f->debug)
+		fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION);
+
+	memcpy(&f->op, op, op_size);
+	f->owner = getuid();
+	f->userdata = userdata;
+
+	se = fuse_session_new(&sop, f);
+	if (!se)
+		goto out_free;
+
+	return se;
+
+out_free:
+	free(f);
+out:
+	return NULL;
+}
+
+
+struct fuse_session *fuse_lowlevel_new(struct fuse_args *args,
+				       const struct fuse_lowlevel_ops *op,
+				       size_t op_size, void *userdata)
+{
+	return fuse_lowlevel_new_common(args, op, op_size, userdata);
+}
+
+#ifdef linux
+int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
+{
+	char *buf;
+	size_t bufsize = 1024;
+	char path[128];
+	int ret;
+	int fd;
+	unsigned long pid = req->ctx.pid;
+	char *s;
+
+	sprintf(path, "/proc/%lu/task/%lu/status", pid, pid);
+
+retry:
+	buf = malloc(bufsize);
+	if (buf == NULL)
+		return -ENOMEM;
+
+	ret = -EIO;
+	fd = open(path, O_RDONLY);
+	if (fd == -1)
+		goto out_free;
+
+	ret = read(fd, buf, bufsize);
+	close(fd);
+	if (ret == -1) {
+		ret = -EIO;
+		goto out_free;
+	}
+
+	if (ret == bufsize) {
+		free(buf);
+		bufsize *= 4;
+		goto retry;
+	}
+
+	ret = -EIO;
+	s = strstr(buf, "\nGroups:");
+	if (s == NULL)
+		goto out_free;
+
+	s += 8;
+	ret = 0;
+	while (1) {
+		char *end;
+		unsigned long val = strtoul(s, &end, 0);
+		if (end == s)
+			break;
+
+		s = end;
+		if (ret < size)
+			list[ret] = val;
+		ret++;
+	}
+
+out_free:
+	free(buf);
+	return ret;
+}
+#else /* linux */
+/*
+ * This is currently not implemented on other than Linux...
+ */
+int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
+{
+	return -ENOSYS;
+}
+#endif
+
+#ifndef __FreeBSD__
+
+static void fill_open_compat(struct fuse_open_out *arg,
+			     const struct fuse_file_info_compat *f)
+{
+	arg->fh = f->fh;
+	if (f->direct_io)
+		arg->open_flags |= FOPEN_DIRECT_IO;
+	if (f->keep_cache)
+		arg->open_flags |= FOPEN_KEEP_CACHE;
+}
+
+static void convert_statfs_compat(const struct statfs *compatbuf,
+				  struct statvfs *buf)
+{
+	buf->f_bsize	= compatbuf->f_bsize;
+	buf->f_blocks	= compatbuf->f_blocks;
+	buf->f_bfree	= compatbuf->f_bfree;
+	buf->f_bavail	= compatbuf->f_bavail;
+	buf->f_files	= compatbuf->f_files;
+	buf->f_ffree	= compatbuf->f_ffree;
+	buf->f_namemax	= compatbuf->f_namelen;
+}
+
+int fuse_reply_open_compat(fuse_req_t req,
+			   const struct fuse_file_info_compat *f)
+{
+	struct fuse_open_out arg;
+
+	memset(&arg, 0, sizeof(arg));
+	fill_open_compat(&arg, f);
+	return send_reply_ok(req, &arg, sizeof(arg));
+}
+
+int fuse_reply_statfs_compat(fuse_req_t req, const struct statfs *stbuf)
+{
+	struct statvfs newbuf;
+
+	memset(&newbuf, 0, sizeof(newbuf));
+	convert_statfs_compat(stbuf, &newbuf);
+
+	return fuse_reply_statfs(req, &newbuf);
+}
+
+struct fuse_session *fuse_lowlevel_new_compat(const char *opts,
+				const struct fuse_lowlevel_ops_compat *op,
+				size_t op_size, void *userdata)
+{
+	struct fuse_session *se;
+	struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
+
+	if (opts &&
+	    (fuse_opt_add_arg(&args, "") == -1 ||
+	     fuse_opt_add_arg(&args, "-o") == -1 ||
+	     fuse_opt_add_arg(&args, opts) == -1)) {
+		fuse_opt_free_args(&args);
+		return NULL;
+	}
+	se = fuse_lowlevel_new(&args, (const struct fuse_lowlevel_ops *) op,
+			       op_size, userdata);
+	fuse_opt_free_args(&args);
+
+	return se;
+}
+
+struct fuse_ll_compat_conf {
+	unsigned max_read;
+	int set_max_read;
+};
+
+static const struct fuse_opt fuse_ll_opts_compat[] = {
+	{ "max_read=", offsetof(struct fuse_ll_compat_conf, set_max_read), 1 },
+	{ "max_read=%u", offsetof(struct fuse_ll_compat_conf, max_read), 0 },
+	FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP),
+	FUSE_OPT_END
+};
+
+int fuse_sync_compat_args(struct fuse_args *args)
+{
+	struct fuse_ll_compat_conf conf;
+
+	memset(&conf, 0, sizeof(conf));
+	if (fuse_opt_parse(args, &conf, fuse_ll_opts_compat, NULL) == -1)
+		return -1;
+
+	if (fuse_opt_insert_arg(args, 1, "-osync_read"))
+		return -1;
+
+	if (conf.set_max_read) {
+		char tmpbuf[64];
+
+		sprintf(tmpbuf, "-omax_readahead=%u", conf.max_read);
+		if (fuse_opt_insert_arg(args, 1, tmpbuf) == -1)
+			return -1;
+	}
+	return 0;
+}
+
+FUSE_SYMVER(".symver fuse_reply_statfs_compat,fuse_reply_statfs@FUSE_2.4");
+FUSE_SYMVER(".symver fuse_reply_open_compat,fuse_reply_open@FUSE_2.4");
+FUSE_SYMVER(".symver fuse_lowlevel_new_compat,fuse_lowlevel_new@FUSE_2.4");
+
+#else /* __FreeBSD__ */
+
+int fuse_sync_compat_args(struct fuse_args *args)
+{
+	(void) args;
+	return 0;
+}
+
+#endif /* __FreeBSD__ */
+
+struct fuse_session *fuse_lowlevel_new_compat25(struct fuse_args *args,
+				const struct fuse_lowlevel_ops_compat25 *op,
+				size_t op_size, void *userdata)
+{
+	if (fuse_sync_compat_args(args) == -1)
+		return NULL;
+
+	return fuse_lowlevel_new_common(args,
+					(const struct fuse_lowlevel_ops *) op,
+					op_size, userdata);
+}
+
+FUSE_SYMVER(".symver fuse_lowlevel_new_compat25,fuse_lowlevel_new@FUSE_2.5");
diff --git a/fuse/fuse_misc.h b/fuse/fuse_misc.h
new file mode 100644
index 0000000..c2cfee1
--- /dev/null
+++ b/fuse/fuse_misc.h
@@ -0,0 +1,53 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB
+*/
+
+#include "config.h"
+#include <pthread.h>
+
+/* Versioned symbols confuse the dynamic linker in uClibc */
+#ifndef __UCLIBC__
+#define FUSE_SYMVER(x) __asm__(x)
+#else
+#define FUSE_SYMVER(x)
+#endif
+
+#ifndef USE_UCLIBC
+#define fuse_mutex_init(mut) pthread_mutex_init(mut, NULL)
+#else
+/* Is this hack still needed? */
+static inline void fuse_mutex_init(pthread_mutex_t *mut)
+{
+	pthread_mutexattr_t attr;
+	pthread_mutexattr_init(&attr);
+	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
+	pthread_mutex_init(mut, &attr);
+	pthread_mutexattr_destroy(&attr);
+}
+#endif
+
+#ifdef HAVE_STRUCT_STAT_ST_ATIM
+/* Linux */
+#define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atim.tv_nsec)
+#define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctim.tv_nsec)
+#define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtim.tv_nsec)
+#define ST_ATIM_NSEC_SET(stbuf, val) (stbuf)->st_atim.tv_nsec = (val)
+#define ST_MTIM_NSEC_SET(stbuf, val) (stbuf)->st_mtim.tv_nsec = (val)
+#elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
+/* FreeBSD */
+#define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atimespec.tv_nsec)
+#define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctimespec.tv_nsec)
+#define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtimespec.tv_nsec)
+#define ST_ATIM_NSEC_SET(stbuf, val) (stbuf)->st_atimespec.tv_nsec = (val)
+#define ST_MTIM_NSEC_SET(stbuf, val) (stbuf)->st_mtimespec.tv_nsec = (val)
+#else
+#define ST_ATIM_NSEC(stbuf) 0
+#define ST_CTIM_NSEC(stbuf) 0
+#define ST_MTIM_NSEC(stbuf) 0
+#define ST_ATIM_NSEC_SET(stbuf, val) do { } while (0)
+#define ST_MTIM_NSEC_SET(stbuf, val) do { } while (0)
+#endif
diff --git a/fuse/fuse_mt.c b/fuse/fuse_mt.c
new file mode 100644
index 0000000..7f94000
--- /dev/null
+++ b/fuse/fuse_mt.c
@@ -0,0 +1,120 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB.
+*/
+
+#include "fuse_i.h"
+#include "fuse_misc.h"
+#include "fuse_lowlevel.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <assert.h>
+
+struct procdata {
+	struct fuse *f;
+	struct fuse_chan *prevch;
+	struct fuse_session *prevse;
+	fuse_processor_t proc;
+	void *data;
+};
+
+#ifdef __MULTI_THREAD
+
+static void mt_session_proc(void *data, const char *buf, size_t len,
+			    struct fuse_chan *ch)
+{
+	struct procdata *pd = (struct procdata *) data;
+	struct fuse_cmd *cmd = *(struct fuse_cmd **) buf;
+
+	(void) len;
+	(void) ch;
+	pd->proc(pd->f, cmd, pd->data);
+}
+
+static void mt_session_exit(void *data, int val)
+{
+	struct procdata *pd = (struct procdata *) data;
+	if (val)
+		fuse_session_exit(pd->prevse);
+	else
+		fuse_session_reset(pd->prevse);
+}
+
+static int mt_session_exited(void *data)
+{
+	struct procdata *pd = (struct procdata *) data;
+	return fuse_session_exited(pd->prevse);
+}
+
+static int mt_chan_receive(struct fuse_chan **chp, char *buf, size_t size)
+{
+	struct fuse_cmd *cmd;
+	struct procdata *pd = (struct procdata *) fuse_chan_data(*chp);
+
+	assert(size >= sizeof(cmd));
+
+	cmd = fuse_read_cmd(pd->f);
+	if (cmd == NULL)
+		return 0;
+
+	*(struct fuse_cmd **) buf = cmd;
+
+	return sizeof(cmd);
+}
+
+int fuse_loop_mt_proc(struct fuse *f, fuse_processor_t proc, void *data)
+{
+	int res;
+	struct procdata pd;
+	struct fuse_session *prevse = fuse_get_session(f);
+	struct fuse_session *se;
+	struct fuse_chan *prevch = fuse_session_next_chan(prevse, NULL);
+	struct fuse_chan *ch;
+	struct fuse_session_ops sop = {
+		.exit = mt_session_exit,
+		.exited = mt_session_exited,
+		.process = mt_session_proc,
+	};
+	struct fuse_chan_ops cop = {
+		.receive = mt_chan_receive,
+	};
+
+	pd.f = f;
+	pd.prevch = prevch;
+	pd.prevse = prevse;
+	pd.proc = proc;
+	pd.data = data;
+
+	se = fuse_session_new(&sop, &pd);
+	if (se == NULL)
+		return -1;
+
+	ch = fuse_chan_new(&cop, fuse_chan_fd(prevch),
+			   sizeof(struct fuse_cmd *), &pd);
+	if (ch == NULL) {
+		fuse_session_destroy(se);
+		return -1;
+	}
+	fuse_session_add_chan(se, ch);
+	res = fuse_session_loop_mt(se);
+	fuse_session_destroy(se);
+	return res;
+}
+
+int fuse_loop_mt(struct fuse *f)
+{
+	if (f == NULL)
+		return -1;
+
+	return fuse_session_loop_mt(fuse_get_session(f));
+}
+
+FUSE_SYMVER(".symver fuse_loop_mt_proc,__fuse_loop_mt@");
+
+#endif
diff --git a/fuse/fuse_opt.c b/fuse/fuse_opt.c
new file mode 100644
index 0000000..b15e7db
--- /dev/null
+++ b/fuse/fuse_opt.c
@@ -0,0 +1,409 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB
+*/
+
+#include "fuse_opt.h"
+#include "fuse_misc.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+struct fuse_opt_context {
+	void *data;
+	const struct fuse_opt *opt;
+	fuse_opt_proc_t proc;
+	int argctr;
+	int argc;
+	char **argv;
+	struct fuse_args outargs;
+	char *opts;
+	int nonopt;
+};
+
+void fuse_opt_free_args(struct fuse_args *args)
+{
+	if (args) {
+		if (args->argv && args->allocated) {
+			int i;
+			for (i = 0; i < args->argc; i++)
+				free(args->argv[i]);
+			free(args->argv);
+		}
+		args->argc = 0;
+		args->argv = NULL;
+		args->allocated = 0;
+	}
+}
+
+static int alloc_failed(void)
+{
+	fprintf(stderr, "fuse: memory allocation failed\n");
+	return -1;
+}
+
+int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
+{
+	char **newargv;
+	char *newarg;
+
+	assert(!args->argv || args->allocated);
+
+	newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *));
+	newarg = newargv ? strdup(arg) : NULL;
+	if (!newargv || !newarg)
+		return alloc_failed();
+
+	args->argv = newargv;
+	args->allocated = 1;
+	args->argv[args->argc++] = newarg;
+	args->argv[args->argc] = NULL;
+	return 0;
+}
+
+static int fuse_opt_insert_arg_common(struct fuse_args *args, int pos,
+				      const char *arg)
+{
+	assert(pos <= args->argc);
+	if (fuse_opt_add_arg(args, arg) == -1)
+		return -1;
+
+	if (pos != args->argc - 1) {
+		char *newarg = args->argv[args->argc - 1];
+		memmove(&args->argv[pos + 1], &args->argv[pos],
+			sizeof(char *) * (args->argc - pos - 1));
+		args->argv[pos] = newarg;
+	}
+	return 0;
+}
+
+int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg)
+{
+	return fuse_opt_insert_arg_common(args, pos, arg);
+}
+
+int fuse_opt_insert_arg_compat(struct fuse_args *args, int pos,
+			       const char *arg);
+int fuse_opt_insert_arg_compat(struct fuse_args *args, int pos, const char *arg)
+{
+	return fuse_opt_insert_arg_common(args, pos, arg);
+}
+
+static int next_arg(struct fuse_opt_context *ctx, const char *opt)
+{
+	if (ctx->argctr + 1 >= ctx->argc) {
+		fprintf(stderr, "fuse: missing argument after `%s'\n", opt);
+		return -1;
+	}
+	ctx->argctr++;
+	return 0;
+}
+
+static int add_arg(struct fuse_opt_context *ctx, const char *arg)
+{
+	return fuse_opt_add_arg(&ctx->outargs, arg);
+}
+
+static int add_opt_common(char **opts, const char *opt, int esc)
+{
+	unsigned oldlen = *opts ? strlen(*opts) : 0;
+	char *d = realloc(*opts, oldlen + 1 + strlen(opt) * 2 + 1);
+
+	if (!d)
+		return alloc_failed();
+
+	*opts = d;
+	if (oldlen) {
+		d += oldlen;
+		*d++ = ',';
+	}
+
+	for (; *opt; opt++) {
+		if (esc && (*opt == ',' || *opt == '\\'))
+			*d++ = '\\';
+		*d++ = *opt;
+	}
+	*d = '\0';
+
+	return 0;
+}
+
+int fuse_opt_add_opt(char **opts, const char *opt)
+{
+	return add_opt_common(opts, opt, 0);
+}
+
+int fuse_opt_add_opt_escaped(char **opts, const char *opt)
+{
+	return add_opt_common(opts, opt, 1);
+}
+
+static int add_opt(struct fuse_opt_context *ctx, const char *opt)
+{
+	return add_opt_common(&ctx->opts, opt, 1);
+}
+
+static int call_proc(struct fuse_opt_context *ctx, const char *arg, int key,
+		     int iso)
+{
+	if (key == FUSE_OPT_KEY_DISCARD)
+		return 0;
+
+	if (key != FUSE_OPT_KEY_KEEP && ctx->proc) {
+		int res = ctx->proc(ctx->data, arg, key, &ctx->outargs);
+		if (res == -1 || !res)
+			return res;
+	}
+	if (iso)
+		return add_opt(ctx, arg);
+	else
+		return add_arg(ctx, arg);
+}
+
+static int match_template(const char *t, const char *arg, unsigned *sepp)
+{
+	int arglen = strlen(arg);
+	const char *sep = strchr(t, '=');
+	sep = sep ? sep : strchr(t, ' ');
+	if (sep && (!sep[1] || sep[1] == '%')) {
+		int tlen = sep - t;
+		if (sep[0] == '=')
+			tlen ++;
+		if (arglen >= tlen && strncmp(arg, t, tlen) == 0) {
+			*sepp = sep - t;
+			return 1;
+		}
+	}
+	if (strcmp(t, arg) == 0) {
+		*sepp = 0;
+		return 1;
+	}
+	return 0;
+}
+
+static const struct fuse_opt *find_opt(const struct fuse_opt *opt,
+				       const char *arg, unsigned *sepp)
+{
+	for (; opt && opt->templ; opt++)
+		if (match_template(opt->templ, arg, sepp))
+			return opt;
+	return NULL;
+}
+
+int fuse_opt_match(const struct fuse_opt *opts, const char *opt)
+{
+	unsigned dummy;
+	return find_opt(opts, opt, &dummy) ? 1 : 0;
+}
+
+static int process_opt_param(void *var, const char *format, const char *param,
+			     const char *arg)
+{
+	assert(format[0] == '%');
+	if (format[1] == 's') {
+		char *copy = strdup(param);
+		if (!copy)
+			return alloc_failed();
+
+		*(char **) var = copy;
+	} else {
+		if (sscanf(param, format, var) != 1) {
+			fprintf(stderr, "fuse: invalid parameter in option `%s'\n", arg);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int process_opt(struct fuse_opt_context *ctx,
+		       const struct fuse_opt *opt, unsigned sep,
+		       const char *arg, int iso)
+{
+	if (opt->offset == -1U) {
+		if (call_proc(ctx, arg, opt->value, iso) == -1)
+			return -1;
+	} else {
+		void *var = ctx->data + opt->offset;
+		if (sep && opt->templ[sep + 1]) {
+			const char *param = arg + sep;
+			if (opt->templ[sep] == '=')
+				param ++;
+			if (process_opt_param(var, opt->templ + sep + 1,
+					      param, arg) == -1)
+				return -1;
+		} else
+			*(int *)var = opt->value;
+	}
+	return 0;
+}
+
+static int process_opt_sep_arg(struct fuse_opt_context *ctx,
+			       const struct fuse_opt *opt, unsigned sep,
+			       const char *arg, int iso)
+{
+	int res;
+	char *newarg;
+	char *param;
+
+	if (next_arg(ctx, arg) == -1)
+		return -1;
+
+	param = ctx->argv[ctx->argctr];
+	newarg = malloc(sep + strlen(param) + 1);
+	if (!newarg)
+		return alloc_failed();
+
+	memcpy(newarg, arg, sep);
+	strcpy(newarg + sep, param);
+	res = process_opt(ctx, opt, sep, newarg, iso);
+	free(newarg);
+
+	return res;
+}
+
+static int process_gopt(struct fuse_opt_context *ctx, const char *arg, int iso)
+{
+	unsigned sep;
+	const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep);
+	if (opt) {
+		for (; opt; opt = find_opt(opt + 1, arg, &sep)) {
+			int res;
+			if (sep && opt->templ[sep] == ' ' && !arg[sep])
+				res = process_opt_sep_arg(ctx, opt, sep, arg,
+							  iso);
+			else
+				res = process_opt(ctx, opt, sep, arg, iso);
+			if (res == -1)
+				return -1;
+		}
+		return 0;
+	} else
+		return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso);
+}
+
+static int process_real_option_group(struct fuse_opt_context *ctx, char *opts)
+{
+	char *s = opts;
+	char *d = s;
+	int end = 0;
+
+	while (!end) {
+		if (*s == '\0')
+			end = 1;
+		if (*s == ',' || end) {
+			int res;
+
+			*d = '\0';
+			res = process_gopt(ctx, opts, 1);
+			if (res == -1)
+				return -1;
+			d = opts;
+		} else {
+			if (s[0] == '\\' && s[1] != '\0')
+				s++;
+			*d++ = *s;
+		}
+		s++;
+	}
+
+	return 0;
+}
+
+static int process_option_group(struct fuse_opt_context *ctx, const char *opts)
+{
+	int res;
+	char *copy = strdup(opts);
+
+	if (!copy) {
+		fprintf(stderr, "fuse: memory allocation failed\n");
+		return -1;
+	}
+	res = process_real_option_group(ctx, copy);
+	free(copy);
+	return res;
+}
+
+static int process_one(struct fuse_opt_context *ctx, const char *arg)
+{
+	if (ctx->nonopt || arg[0] != '-')
+		return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0);
+	else if (arg[1] == 'o') {
+		if (arg[2])
+			return process_option_group(ctx, arg + 2);
+		else {
+			if (next_arg(ctx, arg) == -1)
+				return -1;
+
+			return process_option_group(ctx,
+						    ctx->argv[ctx->argctr]);
+		}
+	} else if (arg[1] == '-' && !arg[2]) {
+		if (add_arg(ctx, arg) == -1)
+			return -1;
+		ctx->nonopt = ctx->outargs.argc;
+		return 0;
+	} else
+		return process_gopt(ctx, arg, 0);
+}
+
+static int opt_parse(struct fuse_opt_context *ctx)
+{
+	if (ctx->argc) {
+		if (add_arg(ctx, ctx->argv[0]) == -1)
+			return -1;
+	}
+
+	for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++)
+		if (process_one(ctx, ctx->argv[ctx->argctr]) == -1)
+			return -1;
+
+	if (ctx->opts) {
+		if (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 ||
+		    fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1)
+			return -1;
+	}
+
+	/* If option separator ("--") is the last argument, remove it */
+	if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc &&
+	    strcmp(ctx->outargs.argv[ctx->outargs.argc - 1], "--") == 0) {
+		free(ctx->outargs.argv[ctx->outargs.argc - 1]);
+		ctx->outargs.argv[--ctx->outargs.argc] = NULL;
+	}
+
+	return 0;
+}
+
+int fuse_opt_parse(struct fuse_args *args, void *data,
+		   const struct fuse_opt opts[], fuse_opt_proc_t proc)
+{
+	int res;
+	struct fuse_opt_context ctx = {
+		.data = data,
+		.opt = opts,
+		.proc = proc,
+	};
+
+	if (!args || !args->argv || !args->argc)
+		return 0;
+
+	ctx.argc = args->argc;
+	ctx.argv = args->argv;
+
+	res = opt_parse(&ctx);
+	if (res != -1) {
+		struct fuse_args tmp = *args;
+		*args = ctx.outargs;
+		ctx.outargs = tmp;
+	}
+	free(ctx.opts);
+	fuse_opt_free_args(&ctx.outargs);
+	return res;
+}
+
+/* This symbol version was mistakenly added to the version script */
+FUSE_SYMVER(".symver fuse_opt_insert_arg_compat,fuse_opt_insert_arg@FUSE_2.5");
diff --git a/fuse/fuse_session.c b/fuse/fuse_session.c
new file mode 100644
index 0000000..3758627
--- /dev/null
+++ b/fuse/fuse_session.c
@@ -0,0 +1,205 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB
+*/
+
+#include "fuse_i.h"
+#include "fuse_misc.h"
+#include "fuse_common_compat.h"
+#include "fuse_lowlevel_compat.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+struct fuse_chan {
+	struct fuse_chan_ops op;
+
+	struct fuse_session *se;
+
+	int fd;
+
+	size_t bufsize;
+
+	void *data;
+
+	int compat;
+};
+
+struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data)
+{
+	struct fuse_session *se = (struct fuse_session *) malloc(sizeof(*se));
+	if (se == NULL) {
+		fprintf(stderr, "fuse: failed to allocate session\n");
+		return NULL;
+	}
+
+	memset(se, 0, sizeof(*se));
+	se->op = *op;
+	se->data = data;
+
+	return se;
+}
+
+void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch)
+{
+	assert(se->ch == NULL);
+	assert(ch->se == NULL);
+	se->ch = ch;
+	ch->se = se;
+}
+
+void fuse_session_remove_chan(struct fuse_chan *ch)
+{
+	struct fuse_session *se = ch->se;
+	if (se) {
+		assert(se->ch == ch);
+		se->ch = NULL;
+		ch->se = NULL;
+	}
+}
+
+struct fuse_chan *fuse_session_next_chan(struct fuse_session *se,
+					 struct fuse_chan *ch)
+{
+	assert(ch == NULL || ch == se->ch);
+	if (ch == NULL)
+		return se->ch;
+	else
+		return NULL;
+}
+
+void fuse_session_process(struct fuse_session *se, const char *buf, size_t len,
+			  struct fuse_chan *ch)
+{
+	se->op.process(se->data, buf, len, ch);
+}
+
+void fuse_session_destroy(struct fuse_session *se)
+{
+	if (se->op.destroy)
+		se->op.destroy(se->data);
+	if (se->ch != NULL)
+		fuse_chan_destroy(se->ch);
+	free(se);
+}
+
+void fuse_session_exit(struct fuse_session *se)
+{
+	if (se->op.exit)
+		se->op.exit(se->data, 1);
+	se->exited = 1;
+}
+
+void fuse_session_reset(struct fuse_session *se)
+{
+	if (se->op.exit)
+		se->op.exit(se->data, 0);
+	se->exited = 0;
+}
+
+int fuse_session_exited(struct fuse_session *se)
+{
+	if (se->op.exited)
+		return se->op.exited(se->data);
+	else
+		return se->exited;
+}
+
+void *fuse_session_data(struct fuse_session *se)
+{
+	return se->data;
+}
+
+static struct fuse_chan *fuse_chan_new_common(struct fuse_chan_ops *op, int fd,
+					      size_t bufsize, void *data,
+					      int compat)
+{
+	struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch));
+	if (ch == NULL) {
+		fprintf(stderr, "fuse: failed to allocate channel\n");
+		return NULL;
+	}
+
+	memset(ch, 0, sizeof(*ch));
+	ch->op = *op;
+	ch->fd = fd;
+	ch->bufsize = bufsize;
+	ch->data = data;
+	ch->compat = compat;
+
+	return ch;
+}
+
+struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd,
+				size_t bufsize, void *data)
+{
+	return fuse_chan_new_common(op, fd, bufsize, data, 0);
+}
+
+struct fuse_chan *fuse_chan_new_compat24(struct fuse_chan_ops_compat24 *op,
+					 int fd, size_t bufsize, void *data)
+{
+	return fuse_chan_new_common((struct fuse_chan_ops *) op, fd, bufsize,
+				    data, 24);
+}
+
+int fuse_chan_fd(struct fuse_chan *ch)
+{
+	return ch->fd;
+}
+
+size_t fuse_chan_bufsize(struct fuse_chan *ch)
+{
+	return ch->bufsize;
+}
+
+void *fuse_chan_data(struct fuse_chan *ch)
+{
+	return ch->data;
+}
+
+struct fuse_session *fuse_chan_session(struct fuse_chan *ch)
+{
+	return ch->se;
+}
+
+int fuse_chan_recv(struct fuse_chan **chp, char *buf, size_t size)
+{
+	struct fuse_chan *ch = *chp;
+	if (ch->compat)
+		return ((struct fuse_chan_ops_compat24 *) &ch->op)
+			->receive(ch, buf, size);
+	else
+		return ch->op.receive(chp, buf, size);
+}
+
+int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size)
+{
+	int res;
+
+	res = fuse_chan_recv(&ch, buf, size);
+	return res >= 0 ? res : (res != -EINTR && res != -EAGAIN) ? -1 : 0;
+}
+
+int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], size_t count)
+{
+	return ch->op.send(ch, iov, count);
+}
+
+void fuse_chan_destroy(struct fuse_chan *ch)
+{
+	fuse_session_remove_chan(ch);
+	if (ch->op.destroy)
+		ch->op.destroy(ch);
+	free(ch);
+}
+
+#ifndef __FreeBSD__
+FUSE_SYMVER(".symver fuse_chan_new_compat24,fuse_chan_new@FUSE_2.4");
+#endif
diff --git a/fuse/fuse_signals.c b/fuse/fuse_signals.c
new file mode 100644
index 0000000..88ac39e
--- /dev/null
+++ b/fuse/fuse_signals.c
@@ -0,0 +1,72 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB
+*/
+
+#include "fuse_lowlevel.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+static struct fuse_session *fuse_instance;
+
+static void exit_handler(int sig)
+{
+	(void) sig;
+	if (fuse_instance)
+		fuse_session_exit(fuse_instance);
+}
+
+static int set_one_signal_handler(int sig, void (*handler)(int))
+{
+	struct sigaction sa;
+	struct sigaction old_sa;
+
+	memset(&sa, 0, sizeof(struct sigaction));
+	sa.sa_handler = handler;
+	sigemptyset(&(sa.sa_mask));
+	sa.sa_flags = 0;
+
+	if (sigaction(sig, NULL, &old_sa) == -1) {
+		perror("fuse: cannot get old signal handler");
+		return -1;
+	}
+
+	if (old_sa.sa_handler == SIG_DFL &&
+	    sigaction(sig, &sa, NULL) == -1) {
+		perror("fuse: cannot set signal handler");
+		return -1;
+	}
+	return 0;
+}
+
+int fuse_set_signal_handlers(struct fuse_session *se)
+{
+	if (set_one_signal_handler(SIGHUP, exit_handler) == -1 ||
+	    set_one_signal_handler(SIGINT, exit_handler) == -1 ||
+	    set_one_signal_handler(SIGTERM, exit_handler) == -1 ||
+	    set_one_signal_handler(SIGPIPE, SIG_IGN) == -1)
+		return -1;
+
+	fuse_instance = se;
+	return 0;
+}
+
+void fuse_remove_signal_handlers(struct fuse_session *se)
+{
+	if (fuse_instance != se)
+		fprintf(stderr,
+			"fuse: fuse_remove_signal_handlers: unknown session\n");
+	else
+		fuse_instance = NULL;
+
+	set_one_signal_handler(SIGHUP, SIG_DFL);
+	set_one_signal_handler(SIGINT, SIG_DFL);
+	set_one_signal_handler(SIGTERM, SIG_DFL);
+	set_one_signal_handler(SIGPIPE, SIG_DFL);
+}
+
diff --git a/fuse/fusexmp.c b/fuse/fusexmp.c
new file mode 100644
index 0000000..d4edbc9
--- /dev/null
+++ b/fuse/fusexmp.c
@@ -0,0 +1,385 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU GPL.
+  See the file COPYING.
+
+  gcc -Wall `pkg-config fuse --cflags --libs` fusexmp.c -o fusexmp
+*/
+
+#define FUSE_USE_VERSION 26
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef linux
+/* For pread()/pwrite() */
+#define _XOPEN_SOURCE 500
+#endif
+
+#include <fuse.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <sys/time.h>
+#ifdef HAVE_SETXATTR
+#include <sys/xattr.h>
+#endif
+
+static int xmp_getattr(const char *path, struct stat *stbuf)
+{
+	int res;
+
+	res = lstat(path, stbuf);
+	if (res == -1)
+		return -errno;
+
+	return 0;
+}
+
+static int xmp_access(const char *path, int mask)
+{
+	int res;
+
+	res = access(path, mask);
+	if (res == -1)
+		return -errno;
+
+	return 0;
+}
+
+static int xmp_readlink(const char *path, char *buf, size_t size)
+{
+	int res;
+
+	res = readlink(path, buf, size - 1);
+	if (res == -1)
+		return -errno;
+
+	buf[res] = '\0';
+	return 0;
+}
+
+
+static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+		       off64_t offset, struct fuse_file_info *fi)
+{
+	DIR *dp;
+	struct dirent *de;
+
+	(void) offset;
+	(void) fi;
+
+	dp = opendir(path);
+	if (dp == NULL)
+		return -errno;
+
+	while ((de = readdir(dp)) != NULL) {
+		struct stat st;
+		memset(&st, 0, sizeof(st));
+		st.st_ino = de->d_ino;
+		st.st_mode = de->d_type << 12;
+		if (filler(buf, de->d_name, &st, 0))
+			break;
+	}
+
+	closedir(dp);
+	return 0;
+}
+
+static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
+{
+	int res;
+
+	/* On Linux this could just be 'mknod(path, mode, rdev)' but this
+	   is more portable */
+	if (S_ISREG(mode)) {
+		res = open(path, O_CREAT | O_EXCL | O_WRONLY, mode);
+		if (res >= 0)
+			res = close(res);
+	} else if (S_ISFIFO(mode))
+		res = mkfifo(path, mode);
+	else
+		res = mknod(path, mode, rdev);
+	if (res == -1)
+		return -errno;
+
+	return 0;
+}
+
+static int xmp_mkdir(const char *path, mode_t mode)
+{
+	int res;
+
+	res = mkdir(path, mode);
+	if (res == -1)
+		return -errno;
+
+	return 0;
+}
+
+static int xmp_unlink(const char *path)
+{
+	int res;
+
+	res = unlink(path);
+	if (res == -1)
+		return -errno;
+
+	return 0;
+}
+
+static int xmp_rmdir(const char *path)
+{
+	int res;
+
+	res = rmdir(path);
+	if (res == -1)
+		return -errno;
+
+	return 0;
+}
+
+static int xmp_symlink(const char *from, const char *to)
+{
+	int res;
+
+	res = symlink(from, to);
+	if (res == -1)
+		return -errno;
+
+	return 0;
+}
+
+static int xmp_rename(const char *from, const char *to)
+{
+	int res;
+
+	res = rename(from, to);
+	if (res == -1)
+		return -errno;
+
+	return 0;
+}
+
+static int xmp_link(const char *from, const char *to)
+{
+	int res;
+
+	res = link(from, to);
+	if (res == -1)
+		return -errno;
+
+	return 0;
+}
+
+static int xmp_chmod(const char *path, mode_t mode)
+{
+	int res;
+
+	res = chmod(path, mode);
+	if (res == -1)
+		return -errno;
+
+	return 0;
+}
+
+static int xmp_chown(const char *path, uid_t uid, gid_t gid)
+{
+	int res;
+
+	res = lchown(path, uid, gid);
+	if (res == -1)
+		return -errno;
+
+	return 0;
+}
+
+static int xmp_truncate(const char *path, off64_t size)
+{
+	int res;
+
+	res = truncate(path, size);
+	if (res == -1)
+		return -errno;
+
+	return 0;
+}
+
+static int xmp_utimens(const char *path, const struct timespec ts[2])
+{
+	int res;
+	struct timeval tv[2];
+
+	tv[0].tv_sec = ts[0].tv_sec;
+	tv[0].tv_usec = ts[0].tv_nsec / 1000;
+	tv[1].tv_sec = ts[1].tv_sec;
+	tv[1].tv_usec = ts[1].tv_nsec / 1000;
+
+	res = utimes(path, tv);
+	if (res == -1)
+		return -errno;
+
+	return 0;
+}
+
+static int xmp_open(const char *path, struct fuse_file_info *fi)
+{
+	int res;
+
+	res = open(path, fi->flags);
+	if (res == -1)
+		return -errno;
+
+	close(res);
+	return 0;
+}
+
+static int xmp_read(const char *path, char *buf, size_t size, off64_t offset,
+		    struct fuse_file_info *fi)
+{
+	int fd;
+	int res;
+
+	(void) fi;
+	fd = open(path, O_RDONLY);
+	if (fd == -1)
+		return -errno;
+
+	res = pread(fd, buf, size, offset);
+	if (res == -1)
+		res = -errno;
+
+	close(fd);
+	return res;
+}
+
+static int xmp_write(const char *path, const char *buf, size_t size,
+		     off64_t offset, struct fuse_file_info *fi)
+{
+	int fd;
+	int res;
+
+	(void) fi;
+	fd = open(path, O_WRONLY);
+	if (fd == -1)
+		return -errno;
+
+	res = pwrite(fd, buf, size, offset);
+	if (res == -1)
+		res = -errno;
+
+	close(fd);
+	return res;
+}
+
+static int xmp_statfs(const char *path, struct statvfs *stbuf)
+{
+	int res;
+
+	//res = statvfs(path, stbuf);
+	if (res == -1)
+		return -errno;
+
+	return 0;
+}
+
+static int xmp_release(const char *path, struct fuse_file_info *fi)
+{
+	/* Just a stub.	 This method is optional and can safely be left
+	   unimplemented */
+
+	(void) path;
+	(void) fi;
+	return 0;
+}
+
+static int xmp_fsync(const char *path, int isdatasync,
+		     struct fuse_file_info *fi)
+{
+	/* Just a stub.	 This method is optional and can safely be left
+	   unimplemented */
+
+	(void) path;
+	(void) isdatasync;
+	(void) fi;
+	return 0;
+}
+
+#ifdef HAVE_SETXATTR
+/* xattr operations are optional and can safely be left unimplemented */
+static int xmp_setxattr(const char *path, const char *name, const char *value,
+			size_t size, int flags)
+{
+	int res = lsetxattr(path, name, value, size, flags);
+	if (res == -1)
+		return -errno;
+	return 0;
+}
+
+static int xmp_getxattr(const char *path, const char *name, char *value,
+			size_t size)
+{
+	int res = lgetxattr(path, name, value, size);
+	if (res == -1)
+		return -errno;
+	return res;
+}
+
+static int xmp_listxattr(const char *path, char *list, size_t size)
+{
+	int res = llistxattr(path, list, size);
+	if (res == -1)
+		return -errno;
+	return res;
+}
+
+static int xmp_removexattr(const char *path, const char *name)
+{
+	int res = lremovexattr(path, name);
+	if (res == -1)
+		return -errno;
+	return 0;
+}
+#endif /* HAVE_SETXATTR */
+
+static struct fuse_operations xmp_oper = {
+	.getattr	= xmp_getattr,
+	.access		= xmp_access,
+	.readlink	= xmp_readlink,
+	.readdir	= xmp_readdir,
+	.mknod		= xmp_mknod,
+	.mkdir		= xmp_mkdir,
+	.symlink	= xmp_symlink,
+	.unlink		= xmp_unlink,
+	.rmdir		= xmp_rmdir,
+	.rename		= xmp_rename,
+	.link		= xmp_link,
+	.chmod		= xmp_chmod,
+	.chown		= xmp_chown,
+	.truncate	= xmp_truncate,
+	.utimens	= xmp_utimens,
+	.open		= xmp_open,
+	.read		= xmp_read,
+	.write		= xmp_write,
+	.statfs		= xmp_statfs,
+	.release	= xmp_release,
+	.fsync		= xmp_fsync,
+#ifdef HAVE_SETXATTR
+	.setxattr	= xmp_setxattr,
+	.getxattr	= xmp_getxattr,
+	.listxattr	= xmp_listxattr,
+	.removexattr	= xmp_removexattr,
+#endif
+};
+
+int main(int argc, char *argv[])
+{
+	umask(0);
+	return fuse_main(argc, argv, &xmp_oper, NULL);
+}
diff --git a/fuse/helper.c b/fuse/helper.c
new file mode 100644
index 0000000..7b994fd
--- /dev/null
+++ b/fuse/helper.c
@@ -0,0 +1,455 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB.
+*/
+
+#include "config.h"
+#include "fuse_i.h"
+#include "fuse_misc.h"
+#include "fuse_opt.h"
+#include "fuse_lowlevel.h"
+#include "fuse_common_compat.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+#include <sys/param.h>
+
+enum  {
+	KEY_HELP,
+	KEY_HELP_NOHEADER,
+	KEY_VERSION,
+};
+
+struct helper_opts {
+	int singlethread;
+	int foreground;
+	int nodefault_subtype;
+	char *mountpoint;
+};
+
+#define FUSE_HELPER_OPT(t, p) { t, offsetof(struct helper_opts, p), 1 }
+
+static const struct fuse_opt fuse_helper_opts[] = {
+	FUSE_HELPER_OPT("-d",		foreground),
+	FUSE_HELPER_OPT("debug",	foreground),
+	FUSE_HELPER_OPT("-f",		foreground),
+	FUSE_HELPER_OPT("-s",		singlethread),
+	FUSE_HELPER_OPT("fsname=",	nodefault_subtype),
+	FUSE_HELPER_OPT("subtype=",	nodefault_subtype),
+
+	FUSE_OPT_KEY("-h",		KEY_HELP),
+	FUSE_OPT_KEY("--help",		KEY_HELP),
+	FUSE_OPT_KEY("-ho",		KEY_HELP_NOHEADER),
+	FUSE_OPT_KEY("-V",		KEY_VERSION),
+	FUSE_OPT_KEY("--version",	KEY_VERSION),
+	FUSE_OPT_KEY("-d",		FUSE_OPT_KEY_KEEP),
+	FUSE_OPT_KEY("debug",		FUSE_OPT_KEY_KEEP),
+	FUSE_OPT_KEY("fsname=",		FUSE_OPT_KEY_KEEP),
+	FUSE_OPT_KEY("subtype=",	FUSE_OPT_KEY_KEEP),
+	FUSE_OPT_END
+};
+
+static void usage(const char *progname)
+{
+	fprintf(stderr,
+		"usage: %s mountpoint [options]\n\n", progname);
+	fprintf(stderr,
+		"general options:\n"
+		"    -o opt,[opt...]        mount options\n"
+		"    -h   --help            print help\n"
+		"    -V   --version         print version\n"
+		"\n");
+}
+
+static void helper_help(void)
+{
+	fprintf(stderr,
+		"FUSE options:\n"
+		"    -d   -o debug          enable debug output (implies -f)\n"
+		"    -f                     foreground operation\n"
+		"    -s                     disable multi-threaded operation\n"
+		"\n"
+		);
+}
+
+static void helper_version(void)
+{
+	fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION);
+}
+
+static int fuse_helper_opt_proc(void *data, const char *arg, int key,
+				struct fuse_args *outargs)
+{
+	struct helper_opts *hopts = data;
+
+	switch (key) {
+	case KEY_HELP:
+		usage(outargs->argv[0]);
+		/* fall through */
+
+	case KEY_HELP_NOHEADER:
+		helper_help();
+		return fuse_opt_add_arg(outargs, "-h");
+
+	case KEY_VERSION:
+		helper_version();
+		return 1;
+
+	case FUSE_OPT_KEY_NONOPT:
+		if (!hopts->mountpoint) {
+			char mountpoint[PATH_MAX];
+			if (realpath(arg, mountpoint) == NULL) {
+				fprintf(stderr,
+					"fuse: bad mount point `%s': %s\n",
+					arg, strerror(errno));
+				return -1;
+			}
+			return fuse_opt_add_opt(&hopts->mountpoint, mountpoint);
+		} else {
+			fprintf(stderr, "fuse: invalid argument `%s'\n", arg);
+			return -1;
+		}
+
+	default:
+		return 1;
+	}
+}
+
+static int add_default_subtype(const char *progname, struct fuse_args *args)
+{
+	int res;
+	char *subtype_opt;
+	const char *basename = strrchr(progname, '/');
+	if (basename == NULL)
+		basename = progname;
+	else if (basename[1] != '\0')
+		basename++;
+
+	subtype_opt = (char *) malloc(strlen(basename) + 64);
+	if (subtype_opt == NULL) {
+		fprintf(stderr, "fuse: memory allocation failed\n");
+		return -1;
+	}
+	sprintf(subtype_opt, "-osubtype=%s", basename);
+	res = fuse_opt_add_arg(args, subtype_opt);
+	free(subtype_opt);
+	return res;
+}
+
+int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint,
+		       int *multithreaded, int *foreground)
+{
+	int res;
+	struct helper_opts hopts;
+
+	memset(&hopts, 0, sizeof(hopts));
+	res = fuse_opt_parse(args, &hopts, fuse_helper_opts,
+			     fuse_helper_opt_proc);
+	if (res == -1)
+		return -1;
+
+	if (!hopts.nodefault_subtype) {
+		res = add_default_subtype(args->argv[0], args);
+		if (res == -1)
+			goto err;
+	}
+	if (mountpoint)
+		*mountpoint = hopts.mountpoint;
+	else
+		free(hopts.mountpoint);
+
+	if (multithreaded)
+		*multithreaded = !hopts.singlethread;
+	if (foreground)
+		*foreground = hopts.foreground;
+	return 0;
+
+err:
+	free(hopts.mountpoint);
+	return -1;
+}
+
+int fuse_daemonize(int foreground)
+{
+	int res;
+
+	if (!foreground) {
+		res = daemon(0, 0);
+		if (res == -1) {
+			perror("fuse: failed to daemonize program\n");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static struct fuse_chan *fuse_mount_common(const char *mountpoint,
+					   struct fuse_args *args)
+{
+	struct fuse_chan *ch;
+	int fd;
+
+	/*
+	 * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
+	 * would ensue.
+	 */
+	do {
+		fd = open("/dev/null", O_RDWR);
+		if (fd > 2)
+			close(fd);
+	} while (fd >= 0 && fd <= 2);
+
+	fd = fuse_mount_compat25(mountpoint, args);
+	if (fd == -1)
+		return NULL;
+
+	ch = fuse_kern_chan_new(fd);
+	if (!ch)
+		fuse_kern_unmount(mountpoint, fd);
+
+	return ch;
+}
+
+struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args)
+{
+	return fuse_mount_common(mountpoint, args);
+}
+
+static void fuse_unmount_common(const char *mountpoint, struct fuse_chan *ch)
+{
+	int fd = ch ? fuse_chan_fd(ch) : -1;
+	fuse_kern_unmount(mountpoint, fd);
+	fuse_chan_destroy(ch);
+}
+
+void fuse_unmount(const char *mountpoint, struct fuse_chan *ch)
+{
+	fuse_unmount_common(mountpoint, ch);
+}
+
+struct fuse *fuse_setup_common(int argc, char *argv[],
+			       const struct fuse_operations *op,
+			       size_t op_size,
+			       char **mountpoint,
+			       int *multithreaded,
+			       int *fd,
+			       void *user_data,
+			       int compat)
+{
+	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
+	struct fuse_chan *ch;
+	struct fuse *fuse;
+	int foreground;
+	int res;
+
+	res = fuse_parse_cmdline(&args, mountpoint, multithreaded, &foreground);
+	if (res == -1)
+		return NULL;
+
+	ch = fuse_mount_common(*mountpoint, &args);
+	if (!ch) {
+		fuse_opt_free_args(&args);
+		goto err_free;
+	}
+
+	fuse = fuse_new_common(ch, &args, op, op_size, user_data, compat);
+	fuse_opt_free_args(&args);
+	if (fuse == NULL)
+		goto err_unmount;
+
+	res = fuse_daemonize(foreground);
+	if (res == -1)
+		goto err_unmount;
+
+	res = fuse_set_signal_handlers(fuse_get_session(fuse));
+	if (res == -1)
+		goto err_unmount;
+
+	if (fd)
+		*fd = fuse_chan_fd(ch);
+
+	return fuse;
+
+err_unmount:
+	fuse_unmount_common(*mountpoint, ch);
+	if (fuse)
+		fuse_destroy(fuse);
+err_free:
+	free(*mountpoint);
+	return NULL;
+}
+
+struct fuse *fuse_setup(int argc, char *argv[],
+			const struct fuse_operations *op, size_t op_size,
+			char **mountpoint, int *multithreaded, void *user_data)
+{
+	return fuse_setup_common(argc, argv, op, op_size, mountpoint,
+				 multithreaded, NULL, user_data, 0);
+}
+
+static void fuse_teardown_common(struct fuse *fuse, char *mountpoint)
+{
+	struct fuse_session *se = fuse_get_session(fuse);
+	struct fuse_chan *ch = fuse_session_next_chan(se, NULL);
+	fuse_remove_signal_handlers(se);
+	fuse_unmount_common(mountpoint, ch);
+	fuse_destroy(fuse);
+	free(mountpoint);
+}
+
+void fuse_teardown(struct fuse *fuse, char *mountpoint)
+{
+	fuse_teardown_common(fuse, mountpoint);
+}
+
+static int fuse_main_common(int argc, char *argv[],
+			    const struct fuse_operations *op, size_t op_size,
+			    void *user_data, int compat)
+{
+	struct fuse *fuse;
+	char *mountpoint;
+	int multithreaded;
+	int res;
+
+	fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint,
+				 &multithreaded, NULL, user_data, compat);
+	if (fuse == NULL)
+		return 1;
+
+#ifdef __MULTI_THREAD
+	if (multithreaded)
+		res = fuse_loop_mt(fuse);
+	else
+#endif
+		res = fuse_loop(fuse);
+
+	fuse_teardown_common(fuse, mountpoint);
+	if (res == -1)
+		return 1;
+
+	return 0;
+}
+
+int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
+		   size_t op_size, void *user_data)
+{
+	return fuse_main_common(argc, argv, op, op_size, user_data, 0);
+}
+
+#undef fuse_main
+int fuse_main(void);
+int fuse_main(void)
+{
+	fprintf(stderr, "fuse_main(): This function does not exist\n");
+	return -1;
+}
+
+int fuse_version(void)
+{
+	return FUSE_VERSION;
+}
+
+#include "fuse_compat.h"
+
+#ifndef __FreeBSD__
+
+struct fuse *fuse_setup_compat22(int argc, char *argv[],
+				 const struct fuse_operations_compat22 *op,
+				 size_t op_size, char **mountpoint,
+				 int *multithreaded, int *fd)
+{
+	return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
+				 op_size, mountpoint, multithreaded, fd, NULL,
+				 22);
+}
+
+struct fuse *fuse_setup_compat2(int argc, char *argv[],
+				const struct fuse_operations_compat2 *op,
+				char **mountpoint, int *multithreaded,
+				int *fd)
+{
+	return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
+				 sizeof(struct fuse_operations_compat2),
+				 mountpoint, multithreaded, fd, NULL, 21);
+}
+
+int fuse_main_real_compat22(int argc, char *argv[],
+			    const struct fuse_operations_compat22 *op,
+			    size_t op_size)
+{
+	return fuse_main_common(argc, argv, (struct fuse_operations *) op,
+				op_size, NULL, 22);
+}
+
+void fuse_main_compat1(int argc, char *argv[],
+		       const struct fuse_operations_compat1 *op)
+{
+	fuse_main_common(argc, argv, (struct fuse_operations *) op,
+			 sizeof(struct fuse_operations_compat1), NULL, 11);
+}
+
+int fuse_main_compat2(int argc, char *argv[],
+		      const struct fuse_operations_compat2 *op)
+{
+	return fuse_main_common(argc, argv, (struct fuse_operations *) op,
+				sizeof(struct fuse_operations_compat2), NULL,
+				21);
+}
+
+int fuse_mount_compat1(const char *mountpoint, const char *args[])
+{
+	/* just ignore mount args for now */
+	(void) args;
+	return fuse_mount_compat22(mountpoint, NULL);
+}
+
+FUSE_SYMVER(".symver fuse_setup_compat2,__fuse_setup@");
+FUSE_SYMVER(".symver fuse_setup_compat22,fuse_setup@FUSE_2.2");
+FUSE_SYMVER(".symver fuse_teardown,__fuse_teardown@");
+FUSE_SYMVER(".symver fuse_main_compat2,fuse_main@");
+FUSE_SYMVER(".symver fuse_main_real_compat22,fuse_main_real@FUSE_2.2");
+
+#endif /* __FreeBSD__ */
+
+
+struct fuse *fuse_setup_compat25(int argc, char *argv[],
+				 const struct fuse_operations_compat25 *op,
+				 size_t op_size, char **mountpoint,
+				 int *multithreaded, int *fd)
+{
+	return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
+				 op_size, mountpoint, multithreaded, fd, NULL,
+				 25);
+}
+
+int fuse_main_real_compat25(int argc, char *argv[],
+			    const struct fuse_operations_compat25 *op,
+			    size_t op_size)
+{
+	return fuse_main_common(argc, argv, (struct fuse_operations *) op,
+				op_size, NULL, 25);
+}
+
+void fuse_teardown_compat22(struct fuse *fuse, int fd, char *mountpoint)
+{
+	(void) fd;
+	fuse_teardown_common(fuse, mountpoint);
+}
+
+int fuse_mount_compat25(const char *mountpoint, struct fuse_args *args)
+{
+	return fuse_kern_mount(mountpoint, args);
+}
+
+FUSE_SYMVER(".symver fuse_setup_compat25,fuse_setup@FUSE_2.5");
+FUSE_SYMVER(".symver fuse_teardown_compat22,fuse_teardown@FUSE_2.2");
+FUSE_SYMVER(".symver fuse_main_real_compat25,fuse_main_real@FUSE_2.5");
+FUSE_SYMVER(".symver fuse_mount_compat25,fuse_mount@FUSE_2.5");
diff --git a/fuse/include/Makefile b/fuse/include/Makefile
new file mode 100644
index 0000000..43fd00a
--- /dev/null
+++ b/fuse/include/Makefile
@@ -0,0 +1,515 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# include/Makefile.  Generated from Makefile.in by configure.
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+
+pkgdatadir = $(datadir)/fuse
+pkgincludedir = $(includedir)/fuse
+pkglibdir = $(libdir)/fuse
+pkglibexecdir = $(libexecdir)/fuse
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = i686-pc-linux-gnu
+host_triplet = i686-pc-linux-gnu
+target_triplet = i686-pc-linux-gnu
+subdir = include
+DIST_COMMON = $(fuseinclude_HEADERS) $(include_HEADERS) \
+	$(noinst_HEADERS) $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+	$(srcdir)/config.h.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+SOURCES =
+DIST_SOURCES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(fuseincludedir)" \
+	"$(DESTDIR)$(includedir)"
+HEADERS = $(fuseinclude_HEADERS) $(include_HEADERS) $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = ${SHELL} /root/fuse-2.8.5/missing --run aclocal-1.11
+AMTAR = ${SHELL} /root/fuse-2.8.5/missing --run tar
+AR = ar
+AUTOCONF = ${SHELL} /root/fuse-2.8.5/missing --run autoconf
+AUTOHEADER = ${SHELL} /root/fuse-2.8.5/missing --run autoheader
+AUTOMAKE = ${SHELL} /root/fuse-2.8.5/missing --run automake-1.11
+AWK = mawk
+CC = gcc
+CCDEPMODE = depmode=gcc3
+CFLAGS = -Wall -W -Wno-sign-compare -Wstrict-prototypes -Wmissing-declarations -Wwrite-strings -g -O2 -fno-strict-aliasing
+CPP = gcc -E
+CPPFLAGS = 
+CYGPATH_W = echo
+DEFS = -DHAVE_CONFIG_H
+DEPDIR = .deps
+DSYMUTIL = 
+DUMPBIN = 
+ECHO_C = 
+ECHO_N = -n
+ECHO_T = 
+EGREP = /bin/grep -E
+EXEEXT = 
+FGREP = /bin/grep -F
+GREP = /bin/grep
+INIT_D_PATH = /etc/init.d
+INSTALL = /usr/bin/install -c
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
+LD = /usr/bin/ld
+LDFLAGS = 
+LIBICONV = 
+LIBOBJS = 
+LIBS = 
+LIBTOOL = $(SHELL) $(top_builddir)/libtool
+LIPO = 
+LN_S = ln -s
+LTLIBICONV = 
+LTLIBOBJS = 
+MAKEINFO = ${SHELL} /root/fuse-2.8.5/missing --run makeinfo
+MKDIR_P = /bin/mkdir -p
+MOUNT_FUSE_PATH = /sbin
+NM = /usr/bin/nm -B
+NMEDIT = 
+OBJDUMP = objdump
+OBJEXT = o
+OTOOL = 
+OTOOL64 = 
+PACKAGE = fuse
+PACKAGE_BUGREPORT = 
+PACKAGE_NAME = fuse
+PACKAGE_STRING = fuse 2.8.5
+PACKAGE_TARNAME = fuse
+PACKAGE_VERSION = 2.8.5
+PATH_SEPARATOR = :
+RANLIB = ranlib
+SED = /bin/sed
+SET_MAKE = 
+SHELL = /bin/bash
+STRIP = strip
+UDEV_RULES_PATH = /etc/udev/rules.d
+VERSION = 2.8.5
+abs_builddir = /root/fuse-2.8.5/include
+abs_srcdir = /root/fuse-2.8.5/include
+abs_top_builddir = /root/fuse-2.8.5
+abs_top_srcdir = /root/fuse-2.8.5
+ac_ct_CC = gcc
+ac_ct_DUMPBIN = 
+am__include = include
+am__leading_dot = .
+am__quote = 
+am__tar = ${AMTAR} chof - "$$tardir"
+am__untar = ${AMTAR} xf -
+bindir = ${exec_prefix}/bin
+build = i686-pc-linux-gnu
+build_alias = 
+build_cpu = i686
+build_os = linux-gnu
+build_vendor = pc
+builddir = .
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
+dvidir = ${docdir}
+exec_prefix = ${prefix}
+host = i686-pc-linux-gnu
+host_alias = 
+host_cpu = i686
+host_os = linux-gnu
+host_vendor = pc
+htmldir = ${docdir}
+includedir = ${prefix}/include
+infodir = ${datarootdir}/info
+install_sh = ${SHELL} /root/fuse-2.8.5/install-sh
+libdir = ${exec_prefix}/lib
+libexecdir = ${exec_prefix}/libexec
+libfuse_libs = -pthread -lrt -ldl  
+localedir = ${datarootdir}/locale
+localstatedir = ${prefix}/var
+lt_ECHO = echo
+mandir = ${datarootdir}/man
+mkdir_p = /bin/mkdir -p
+oldincludedir = /usr/include
+pdfdir = ${docdir}
+pkgconfigdir = ${libdir}/pkgconfig
+prefix = /usr/local
+program_transform_name = s,x,x,
+psdir = ${docdir}
+sbindir = ${exec_prefix}/sbin
+sharedstatedir = ${prefix}/com
+srcdir = .
+subdirs2 = include lib util example
+sysconfdir = ${prefix}/etc
+target = i686-pc-linux-gnu
+target_alias = 
+target_cpu = i686
+target_os = linux-gnu
+target_vendor = pc
+top_build_prefix = ../
+top_builddir = ..
+top_srcdir = ..
+fuseincludedir = $(includedir)/fuse
+fuseinclude_HEADERS = \
+	fuse.h			\
+	fuse_compat.h		\
+	fuse_common.h		\
+	fuse_common_compat.h    \
+	fuse_lowlevel.h		\
+	fuse_lowlevel_compat.h	\
+	fuse_opt.h		\
+	cuse_lowlevel.h
+
+include_HEADERS = old/fuse.h ulockmgr.h
+noinst_HEADERS = fuse_kernel.h
+all: config.h
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu include/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+config.h: stamp-h1
+	@if test ! -f $@; then \
+	  rm -f stamp-h1; \
+	  $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \
+	else :; fi
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+	@rm -f stamp-h1
+	cd $(top_builddir) && $(SHELL) ./config.status include/config.h
+$(srcdir)/config.h.in:  $(am__configure_deps) 
+	($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+	rm -f stamp-h1
+	touch $@
+
+distclean-hdr:
+	-rm -f config.h stamp-h1
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+install-fuseincludeHEADERS: $(fuseinclude_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(fuseincludedir)" || $(MKDIR_P) "$(DESTDIR)$(fuseincludedir)"
+	@list='$(fuseinclude_HEADERS)'; test -n "$(fuseincludedir)" || list=; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(fuseincludedir)'"; \
+	  $(INSTALL_HEADER) $$files "$(DESTDIR)$(fuseincludedir)" || exit $$?; \
+	done
+
+uninstall-fuseincludeHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(fuseinclude_HEADERS)'; test -n "$(fuseincludedir)" || list=; \
+	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+	test -n "$$files" || exit 0; \
+	echo " ( cd '$(DESTDIR)$(fuseincludedir)' && rm -f" $$files ")"; \
+	cd "$(DESTDIR)$(fuseincludedir)" && rm -f $$files
+install-includeHEADERS: $(include_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)"
+	@list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \
+	  $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \
+	done
+
+uninstall-includeHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
+	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+	test -n "$$files" || exit 0; \
+	echo " ( cd '$(DESTDIR)$(includedir)' && rm -f" $$files ")"; \
+	cd "$(DESTDIR)$(includedir)" && rm -f $$files
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(HEADERS) config.h
+installdirs:
+	for dir in "$(DESTDIR)$(fuseincludedir)" "$(DESTDIR)$(includedir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-hdr distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-fuseincludeHEADERS install-includeHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-fuseincludeHEADERS uninstall-includeHEADERS
+
+.MAKE: all install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool ctags distclean distclean-generic distclean-hdr \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-fuseincludeHEADERS install-html \
+	install-html-am install-includeHEADERS install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
+	uninstall-am uninstall-fuseincludeHEADERS \
+	uninstall-includeHEADERS
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/fuse/include/Makefile.am b/fuse/include/Makefile.am
new file mode 100644
index 0000000..663e164
--- /dev/null
+++ b/fuse/include/Makefile.am
@@ -0,0 +1,17 @@
+## Process this file with automake to produce Makefile.in
+
+fuseincludedir=$(includedir)/fuse
+
+fuseinclude_HEADERS = \
+	fuse.h			\
+	fuse_compat.h		\
+	fuse_common.h		\
+	fuse_common_compat.h    \
+	fuse_lowlevel.h		\
+	fuse_lowlevel_compat.h	\
+	fuse_opt.h		\
+	cuse_lowlevel.h
+
+include_HEADERS = old/fuse.h ulockmgr.h
+
+noinst_HEADERS = fuse_kernel.h
diff --git a/fuse/include/Makefile.in b/fuse/include/Makefile.in
new file mode 100644
index 0000000..1ae6d85
--- /dev/null
+++ b/fuse/include/Makefile.in
@@ -0,0 +1,515 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = include
+DIST_COMMON = $(fuseinclude_HEADERS) $(include_HEADERS) \
+	$(noinst_HEADERS) $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+	$(srcdir)/config.h.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+SOURCES =
+DIST_SOURCES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(fuseincludedir)" \
+	"$(DESTDIR)$(includedir)"
+HEADERS = $(fuseinclude_HEADERS) $(include_HEADERS) $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INIT_D_PATH = @INIT_D_PATH@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+MOUNT_FUSE_PATH = @MOUNT_FUSE_PATH@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+UDEV_RULES_PATH = @UDEV_RULES_PATH@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libfuse_libs = @libfuse_libs@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgconfigdir = @pkgconfigdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs2 = @subdirs2@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+fuseincludedir = $(includedir)/fuse
+fuseinclude_HEADERS = \
+	fuse.h			\
+	fuse_compat.h		\
+	fuse_common.h		\
+	fuse_common_compat.h    \
+	fuse_lowlevel.h		\
+	fuse_lowlevel_compat.h	\
+	fuse_opt.h		\
+	cuse_lowlevel.h
+
+include_HEADERS = old/fuse.h ulockmgr.h
+noinst_HEADERS = fuse_kernel.h
+all: config.h
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu include/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+config.h: stamp-h1
+	@if test ! -f $@; then \
+	  rm -f stamp-h1; \
+	  $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \
+	else :; fi
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+	@rm -f stamp-h1
+	cd $(top_builddir) && $(SHELL) ./config.status include/config.h
+$(srcdir)/config.h.in:  $(am__configure_deps) 
+	($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+	rm -f stamp-h1
+	touch $@
+
+distclean-hdr:
+	-rm -f config.h stamp-h1
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+install-fuseincludeHEADERS: $(fuseinclude_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(fuseincludedir)" || $(MKDIR_P) "$(DESTDIR)$(fuseincludedir)"
+	@list='$(fuseinclude_HEADERS)'; test -n "$(fuseincludedir)" || list=; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(fuseincludedir)'"; \
+	  $(INSTALL_HEADER) $$files "$(DESTDIR)$(fuseincludedir)" || exit $$?; \
+	done
+
+uninstall-fuseincludeHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(fuseinclude_HEADERS)'; test -n "$(fuseincludedir)" || list=; \
+	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+	test -n "$$files" || exit 0; \
+	echo " ( cd '$(DESTDIR)$(fuseincludedir)' && rm -f" $$files ")"; \
+	cd "$(DESTDIR)$(fuseincludedir)" && rm -f $$files
+install-includeHEADERS: $(include_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)"
+	@list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \
+	  $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \
+	done
+
+uninstall-includeHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
+	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+	test -n "$$files" || exit 0; \
+	echo " ( cd '$(DESTDIR)$(includedir)' && rm -f" $$files ")"; \
+	cd "$(DESTDIR)$(includedir)" && rm -f $$files
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(HEADERS) config.h
+installdirs:
+	for dir in "$(DESTDIR)$(fuseincludedir)" "$(DESTDIR)$(includedir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-hdr distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-fuseincludeHEADERS install-includeHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-fuseincludeHEADERS uninstall-includeHEADERS
+
+.MAKE: all install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool ctags distclean distclean-generic distclean-hdr \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-fuseincludeHEADERS install-html \
+	install-html-am install-includeHEADERS install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
+	uninstall-am uninstall-fuseincludeHEADERS \
+	uninstall-includeHEADERS
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/fuse/include/config.h b/fuse/include/config.h
new file mode 100644
index 0000000..a0c603a
--- /dev/null
+++ b/fuse/include/config.h
@@ -0,0 +1,87 @@
+/* include/config.h.  Generated from config.h.in by configure.  */
+/* include/config.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `fdatasync' function. */
+#define HAVE_FDATASYNC 1
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Define if you have the iconv() function and it works. */
+#define HAVE_ICONV 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `setxattr' function. */
+#define HAVE_SETXATTR 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if `st_atim' is member of `struct stat'. */
+//#define HAVE_STRUCT_STAT_ST_ATIM 0
+
+/* Define to 1 if `st_atimespec' is member of `struct stat'. */
+/* #undef HAVE_STRUCT_STAT_ST_ATIMESPEC */
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define as const if the declaration of iconv() needs const. */
+#define ICONV_CONST 
+
+/* Don't update /etc/mtab */
+/* #undef IGNORE_MTAB */
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+/* #undef NO_MINUS_C_MINUS_O */
+
+/* Name of package */
+#define PACKAGE "fuse"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "fuse"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "fuse 2.8.5"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "fuse"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "2.8.5"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "2.8.5"
diff --git a/fuse/include/config.h.in b/fuse/include/config.h.in
new file mode 100644
index 0000000..3e7c14c
--- /dev/null
+++ b/fuse/include/config.h.in
@@ -0,0 +1,86 @@
+/* include/config.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the `fdatasync' function. */
+#undef HAVE_FDATASYNC
+
+/* Define to 1 if you have the `fork' function. */
+#undef HAVE_FORK
+
+/* Define if you have the iconv() function and it works. */
+#undef HAVE_ICONV
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `setxattr' function. */
+#undef HAVE_SETXATTR
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if `st_atim' is member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_ATIM
+
+/* Define to 1 if `st_atimespec' is member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_ATIMESPEC
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define as const if the declaration of iconv() needs const. */
+#undef ICONV_CONST
+
+/* Don't update /etc/mtab */
+#undef IGNORE_MTAB
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#undef LT_OBJDIR
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+#undef NO_MINUS_C_MINUS_O
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
diff --git a/fuse/include/cuse_lowlevel.h b/fuse/include/cuse_lowlevel.h
new file mode 100644
index 0000000..d628eac
--- /dev/null
+++ b/fuse/include/cuse_lowlevel.h
@@ -0,0 +1,87 @@
+/*
+  CUSE: Character device in Userspace
+  Copyright (C) 2008-2009  SUSE Linux Products GmbH
+  Copyright (C) 2008-2009  Tejun Heo <tj@kernel.org>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB.
+
+  Read example/cusexmp.c for usages.
+*/
+
+#ifndef _CUSE_LOWLEVEL_H_
+#define _CUSE_LOWLEVEL_H_
+
+#ifndef FUSE_USE_VERSION
+#define FUSE_USE_VERSION 29
+#endif
+
+#include "fuse_lowlevel.h"
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define CUSE_UNRESTRICTED_IOCTL		(1 << 0) /* use unrestricted ioctl */
+
+struct fuse_session;
+
+struct cuse_info {
+	unsigned	dev_major;
+	unsigned	dev_minor;
+	unsigned	dev_info_argc;
+	const char	**dev_info_argv;
+	unsigned	flags;
+};
+
+/*
+ * Most ops behave almost identically to the matching fuse_lowlevel
+ * ops except that they don't take @ino.
+ *
+ * init_done	: called after initialization is complete
+ * read/write	: always direct IO, simultaneous operations allowed
+ * ioctl	: might be in unrestricted mode depending on ci->flags
+ */
+struct cuse_lowlevel_ops {
+	void (*init) (void *userdata, struct fuse_conn_info *conn);
+	void (*init_done) (void *userdata);
+	void (*destroy) (void *userdata);
+	void (*open) (fuse_req_t req, struct fuse_file_info *fi);
+	void (*read) (fuse_req_t req, size_t size, off64_t off,
+		      struct fuse_file_info *fi);
+	void (*write) (fuse_req_t req, const char *buf, size_t size, off64_t off,
+		       struct fuse_file_info *fi);
+	void (*flush) (fuse_req_t req, struct fuse_file_info *fi);
+	void (*release) (fuse_req_t req, struct fuse_file_info *fi);
+	void (*fsync) (fuse_req_t req, int datasync, struct fuse_file_info *fi);
+	void (*ioctl) (fuse_req_t req, int cmd, void *arg,
+		       struct fuse_file_info *fi, unsigned int flags,
+		       const void *in_buf, size_t in_bufsz, size_t out_bufsz);
+	void (*poll) (fuse_req_t req, struct fuse_file_info *fi,
+		      struct fuse_pollhandle *ph);
+};
+
+struct fuse_session *cuse_lowlevel_new(struct fuse_args *args,
+				       const struct cuse_info *ci,
+				       const struct cuse_lowlevel_ops *clop,
+				       void *userdata);
+
+struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[],
+					 const struct cuse_info *ci,
+					 const struct cuse_lowlevel_ops *clop,
+					 int *multithreaded, void *userdata);
+
+void cuse_lowlevel_teardown(struct fuse_session *se);
+
+int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci,
+		       const struct cuse_lowlevel_ops *clop, void *userdata);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CUSE_LOWLEVEL_H_ */
diff --git a/fuse/include/fuse.h b/fuse/include/fuse.h
new file mode 100644
index 0000000..899830f
--- /dev/null
+++ b/fuse/include/fuse.h
@@ -0,0 +1,928 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB.
+*/
+
+#ifndef _FUSE_H_
+#define _FUSE_H_
+
+/** @file
+ *
+ * This file defines the library interface of FUSE
+ *
+ * IMPORTANT: you should define FUSE_USE_VERSION before including this
+ * header.  To use the newest API define it to 26 (recommended for any
+ * new application), to use the old API define it to 21 (default) 22
+ * or 25, to use the even older 1.X API define it to 11.
+ */
+
+#ifndef FUSE_USE_VERSION
+#define FUSE_USE_VERSION 28
+#endif
+
+#include "fuse_common.h"
+
+#include <fcntl.h>
+#include <time.h>
+#include <utime.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/uio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ----------------------------------------------------------- *
+ * Basic FUSE API					       *
+ * ----------------------------------------------------------- */
+
+/** Handle for a FUSE filesystem */
+struct fuse;
+
+/** Structure containing a raw command */
+struct fuse_cmd;
+
+/** Function to add an entry in a readdir() operation
+ *
+ * @param buf the buffer passed to the readdir() operation
+ * @param name the file name of the directory entry
+ * @param stat file attributes, can be NULL
+ * @param off offset of the next entry or zero
+ * @return 1 if buffer is full, zero otherwise
+ */
+typedef int (*fuse_fill_dir_t) (void *buf, const char *name,
+				const struct stat *stbuf, off64_t off);
+
+/* Used by deprecated getdir() method */
+typedef struct fuse_dirhandle *fuse_dirh_t;
+typedef int (*fuse_dirfil_t) (fuse_dirh_t h, const char *name, int type,
+			      ino_t ino);
+
+/**
+ * The file system operations:
+ *
+ * Most of these should work very similarly to the well known UNIX
+ * file system operations.  A major exception is that instead of
+ * returning an error in 'errno', the operation should return the
+ * negated error value (-errno) directly.
+ *
+ * All methods are optional, but some are essential for a useful
+ * filesystem (e.g. getattr).  Open, flush, release, fsync, opendir,
+ * releasedir, fsyncdir, access, create, ftruncate, fgetattr, lock,
+ * init and destroy are special purpose methods, without which a full
+ * featured filesystem can still be implemented.
+ *
+ * Almost all operations take a path which can be of any length.
+ *
+ * Changed in fuse 2.8.0 (regardless of API version)
+ * Previously, paths were limited to a length of PATH_MAX.
+ *
+ * See http://fuse.sourceforge.net/wiki/ for more information.  There
+ * is also a snapshot of the relevant wiki pages in the doc/ folder.
+ */
+struct fuse_operations {
+	/** Get file attributes.
+	 *
+	 * Similar to stat().  The 'st_dev' and 'st_blksize' fields are
+	 * ignored.	 The 'st_ino' field is ignored except if the 'use_ino'
+	 * mount option is given.
+	 */
+	int (*getattr) (const char *, struct stat *);
+
+	/** Read the target of a symbolic link
+	 *
+	 * The buffer should be filled with a null terminated string.  The
+	 * buffer size argument includes the space for the terminating
+	 * null character.	If the linkname is too long to fit in the
+	 * buffer, it should be truncated.	The return value should be 0
+	 * for success.
+	 */
+	int (*readlink) (const char *, char *, size_t);
+
+	/* Deprecated, use readdir() instead */
+	int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t);
+
+	/** Create a file node
+	 *
+	 * This is called for creation of all non-directory, non-symlink
+	 * nodes.  If the filesystem defines a create() method, then for
+	 * regular files that will be called instead.
+	 */
+	int (*mknod) (const char *, mode_t, dev_t);
+
+	/** Create a directory 
+	 *
+	 * Note that the mode argument may not have the type specification
+	 * bits set, i.e. S_ISDIR(mode) can be false.  To obtain the
+	 * correct directory type bits use  mode|S_IFDIR
+	 * */
+	int (*mkdir) (const char *, mode_t);
+
+	/** Remove a file */
+	int (*unlink) (const char *);
+
+	/** Remove a directory */
+	int (*rmdir) (const char *);
+
+	/** Create a symbolic link */
+	int (*symlink) (const char *, const char *);
+
+	/** Rename a file */
+	int (*rename) (const char *, const char *);
+
+	/** Create a hard link to a file */
+	int (*link) (const char *, const char *);
+
+	/** Change the permission bits of a file */
+	int (*chmod) (const char *, mode_t);
+
+	/** Change the owner and group of a file */
+	int (*chown) (const char *, uid_t, gid_t);
+
+	/** Change the size of a file */
+	int (*truncate) (const char *, off64_t);
+
+	/** Change the access and/or modification times of a file
+	 *
+	 * Deprecated, use utimens() instead.
+	 */
+	int (*utime) (const char *, struct utimbuf *);
+
+	/** File open operation
+	 *
+	 * No creation (O_CREAT, O_EXCL) and by default also no
+	 * truncation (O_TRUNC) flags will be passed to open(). If an
+	 * application specifies O_TRUNC, fuse first calls truncate()
+	 * and then open(). Only if 'atomic_o_trunc' has been
+	 * specified and kernel version is 2.6.24 or later, O_TRUNC is
+	 * passed on to open.
+	 *
+	 * Unless the 'default_permissions' mount option is given,
+	 * open should check if the operation is permitted for the
+	 * given flags. Optionally open may also return an arbitrary
+	 * filehandle in the fuse_file_info structure, which will be
+	 * passed to all file operations.
+	 *
+	 * Changed in version 2.2
+	 */
+	int (*open) (const char *, struct fuse_file_info *);
+
+	/** Read data from an open file
+	 *
+	 * Read should return exactly the number of bytes requested except
+	 * on EOF or error, otherwise the rest of the data will be
+	 * substituted with zeroes.	 An exception to this is when the
+	 * 'direct_io' mount option is specified, in which case the return
+	 * value of the read system call will reflect the return value of
+	 * this operation.
+	 *
+	 * Changed in version 2.2
+	 */
+	int (*read) (const char *, char *, size_t, off64_t,
+		     struct fuse_file_info *);
+
+	/** Write data to an open file
+	 *
+	 * Write should return exactly the number of bytes requested
+	 * except on error.	 An exception to this is when the 'direct_io'
+	 * mount option is specified (see read operation).
+	 *
+	 * Changed in version 2.2
+	 */
+	int (*write) (const char *, const char *, size_t, off64_t,
+		      struct fuse_file_info *);
+
+	/** Get file system statistics
+	 *
+	 * The 'f_frsize', 'f_favail', 'f_fsid' and 'f_flag' fields are ignored
+	 *
+	 * Replaced 'struct statfs' parameter with 'struct statvfs' in
+	 * version 2.5
+	 */
+	int (*statfs) (const char *, struct statvfs *);
+
+	/** Possibly flush cached data
+	 *
+	 * BIG NOTE: This is not equivalent to fsync().  It's not a
+	 * request to sync dirty data.
+	 *
+	 * Flush is called on each close() of a file descriptor.  So if a
+	 * filesystem wants to return write errors in close() and the file
+	 * has cached dirty data, this is a good place to write back data
+	 * and return any errors.  Since many applications ignore close()
+	 * errors this is not always useful.
+	 *
+	 * NOTE: The flush() method may be called more than once for each
+	 * open().	This happens if more than one file descriptor refers
+	 * to an opened file due to dup(), dup2() or fork() calls.	It is
+	 * not possible to determine if a flush is final, so each flush
+	 * should be treated equally.  Multiple write-flush sequences are
+	 * relatively rare, so this shouldn't be a problem.
+	 *
+	 * Filesystems shouldn't assume that flush will always be called
+	 * after some writes, or that if will be called at all.
+	 *
+	 * Changed in version 2.2
+	 */
+	int (*flush) (const char *, struct fuse_file_info *);
+
+	/** Release an open file
+	 *
+	 * Release is called when there are no more references to an open
+	 * file: all file descriptors are closed and all memory mappings
+	 * are unmapped.
+	 *
+	 * For every open() call there will be exactly one release() call
+	 * with the same flags and file descriptor.	 It is possible to
+	 * have a file opened more than once, in which case only the last
+	 * release will mean, that no more reads/writes will happen on the
+	 * file.  The return value of release is ignored.
+	 *
+	 * Changed in version 2.2
+	 */
+	int (*release) (const char *, struct fuse_file_info *);
+
+	/** Synchronize file contents
+	 *
+	 * If the datasync parameter is non-zero, then only the user data
+	 * should be flushed, not the meta data.
+	 *
+	 * Changed in version 2.2
+	 */
+	int (*fsync) (const char *, int, struct fuse_file_info *);
+
+	/** Set extended attributes */
+	int (*setxattr) (const char *, const char *, const char *, size_t, int);
+
+	/** Get extended attributes */
+	int (*getxattr) (const char *, const char *, char *, size_t);
+
+	/** List extended attributes */
+	int (*listxattr) (const char *, char *, size_t);
+
+	/** Remove extended attributes */
+	int (*removexattr) (const char *, const char *);
+
+	/** Open directory
+	 *
+	 * Unless the 'default_permissions' mount option is given,
+	 * this method should check if opendir is permitted for this
+	 * directory. Optionally opendir may also return an arbitrary
+	 * filehandle in the fuse_file_info structure, which will be
+	 * passed to readdir, closedir and fsyncdir.
+	 *
+	 * Introduced in version 2.3
+	 */
+	int (*opendir) (const char *, struct fuse_file_info *);
+
+	/** Read directory
+	 *
+	 * This supersedes the old getdir() interface.  New applications
+	 * should use this.
+	 *
+	 * The filesystem may choose between two modes of operation:
+	 *
+	 * 1) The readdir implementation ignores the offset parameter, and
+	 * passes zero to the filler function's offset.  The filler
+	 * function will not return '1' (unless an error happens), so the
+	 * whole directory is read in a single readdir operation.  This
+	 * works just like the old getdir() method.
+	 *
+	 * 2) The readdir implementation keeps track of the offsets of the
+	 * directory entries.  It uses the offset parameter and always
+	 * passes non-zero offset to the filler function.  When the buffer
+	 * is full (or an error happens) the filler function will return
+	 * '1'.
+	 *
+	 * Introduced in version 2.3
+	 */
+	int (*readdir) (const char *, void *, fuse_fill_dir_t, off64_t,
+			struct fuse_file_info *);
+
+	/** Release directory
+	 *
+	 * Introduced in version 2.3
+	 */
+	int (*releasedir) (const char *, struct fuse_file_info *);
+
+	/** Synchronize directory contents
+	 *
+	 * If the datasync parameter is non-zero, then only the user data
+	 * should be flushed, not the meta data
+	 *
+	 * Introduced in version 2.3
+	 */
+	int (*fsyncdir) (const char *, int, struct fuse_file_info *);
+
+	/**
+	 * Initialize filesystem
+	 *
+	 * The return value will passed in the private_data field of
+	 * fuse_context to all file operations and as a parameter to the
+	 * destroy() method.
+	 *
+	 * Introduced in version 2.3
+	 * Changed in version 2.6
+	 */
+	void *(*init) (struct fuse_conn_info *conn);
+
+	/**
+	 * Clean up filesystem
+	 *
+	 * Called on filesystem exit.
+	 *
+	 * Introduced in version 2.3
+	 */
+	void (*destroy) (void *);
+
+	/**
+	 * Check file access permissions
+	 *
+	 * This will be called for the access() system call.  If the
+	 * 'default_permissions' mount option is given, this method is not
+	 * called.
+	 *
+	 * This method is not called under Linux kernel versions 2.4.x
+	 *
+	 * Introduced in version 2.5
+	 */
+	int (*access) (const char *, int);
+
+	/**
+	 * Create and open a file
+	 *
+	 * If the file does not exist, first create it with the specified
+	 * mode, and then open it.
+	 *
+	 * If this method is not implemented or under Linux kernel
+	 * versions earlier than 2.6.15, the mknod() and open() methods
+	 * will be called instead.
+	 *
+	 * Introduced in version 2.5
+	 */
+	int (*create) (const char *, mode_t, struct fuse_file_info *);
+
+	/**
+	 * Change the size of an open file
+	 *
+	 * This method is called instead of the truncate() method if the
+	 * truncation was invoked from an ftruncate() system call.
+	 *
+	 * If this method is not implemented or under Linux kernel
+	 * versions earlier than 2.6.15, the truncate() method will be
+	 * called instead.
+	 *
+	 * Introduced in version 2.5
+	 */
+	int (*ftruncate) (const char *, off64_t, struct fuse_file_info *);
+
+	/**
+	 * Get attributes from an open file
+	 *
+	 * This method is called instead of the getattr() method if the
+	 * file information is available.
+	 *
+	 * Currently this is only called after the create() method if that
+	 * is implemented (see above).  Later it may be called for
+	 * invocations of fstat() too.
+	 *
+	 * Introduced in version 2.5
+	 */
+	int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *);
+
+	/**
+	 * Perform POSIX file locking operation
+	 *
+	 * The cmd argument will be either F_GETLK, F_SETLK or F_SETLKW.
+	 *
+	 * For the meaning of fields in 'struct flock' see the man page
+	 * for fcntl(2).  The l_whence field will always be set to
+	 * SEEK_SET.
+	 *
+	 * For checking lock ownership, the 'fuse_file_info->owner'
+	 * argument must be used.
+	 *
+	 * For F_GETLK operation, the library will first check currently
+	 * held locks, and if a conflicting lock is found it will return
+	 * information without calling this method.	 This ensures, that
+	 * for local locks the l_pid field is correctly filled in.	The
+	 * results may not be accurate in case of race conditions and in
+	 * the presence of hard links, but it's unlikly that an
+	 * application would rely on accurate GETLK results in these
+	 * cases.  If a conflicting lock is not found, this method will be
+	 * called, and the filesystem may fill out l_pid by a meaningful
+	 * value, or it may leave this field zero.
+	 *
+	 * For F_SETLK and F_SETLKW the l_pid field will be set to the pid
+	 * of the process performing the locking operation.
+	 *
+	 * Note: if this method is not implemented, the kernel will still
+	 * allow file locking to work locally.  Hence it is only
+	 * interesting for network filesystems and similar.
+	 *
+	 * Introduced in version 2.6
+	 */
+	int (*lock) (const char *, struct fuse_file_info *, int cmd,
+		     struct flock *);
+
+	/**
+	 * Change the access and modification times of a file with
+	 * nanosecond resolution
+	 *
+	 * Introduced in version 2.6
+	 */
+	int (*utimens) (const char *, const struct timespec tv[2]);
+
+	/**
+	 * Map block index within file to block index within device
+	 *
+	 * Note: This makes sense only for block device backed filesystems
+	 * mounted with the 'blkdev' option
+	 *
+	 * Introduced in version 2.6
+	 */
+	int (*bmap) (const char *, size_t blocksize, uint64_t *idx);
+
+	/**
+	 * Flag indicating, that the filesystem can accept a NULL path
+	 * as the first argument for the following operations:
+	 *
+	 * read, write, flush, release, fsync, readdir, releasedir,
+	 * fsyncdir, ftruncate, fgetattr and lock
+	 */
+	unsigned int flag_nullpath_ok : 1;
+
+	/**
+	 * Reserved flags, don't set
+	 */
+	unsigned int flag_reserved : 31;
+
+	/**
+	 * Ioctl
+	 *
+	 * flags will have FUSE_IOCTL_COMPAT set for 32bit ioctls in
+	 * 64bit environment.  The size and direction of data is
+	 * determined by _IOC_*() decoding of cmd.  For _IOC_NONE,
+	 * data will be NULL, for _IOC_WRITE data is out area, for
+	 * _IOC_READ in area and if both are set in/out area.  In all
+	 * non-NULL cases, the area is of _IOC_SIZE(cmd) bytes.
+	 *
+	 * Introduced in version 2.8
+	 */
+	int (*ioctl) (const char *, int cmd, void *arg,
+		      struct fuse_file_info *, unsigned int flags, void *data);
+
+	/**
+	 * Poll for IO readiness events
+	 *
+	 * Note: If ph is non-NULL, the client should notify
+	 * when IO readiness events occur by calling
+	 * fuse_notify_poll() with the specified ph.
+	 *
+	 * Regardless of the number of times poll with a non-NULL ph
+	 * is received, single notification is enough to clear all.
+	 * Notifying more times incurs overhead but doesn't harm
+	 * correctness.
+	 *
+	 * The callee is responsible for destroying ph with
+	 * fuse_pollhandle_destroy() when no longer in use.
+	 *
+	 * Introduced in version 2.8
+	 */
+	int (*poll) (const char *, struct fuse_file_info *,
+		     struct fuse_pollhandle *ph, unsigned *reventsp);
+};
+
+/** Extra context that may be needed by some filesystems
+ *
+ * The uid, gid and pid fields are not filled in case of a writepage
+ * operation.
+ */
+struct fuse_context {
+	/** Pointer to the fuse object */
+	struct fuse *fuse;
+
+	/** User ID of the calling process */
+	uid_t uid;
+
+	/** Group ID of the calling process */
+	gid_t gid;
+
+	/** Thread ID of the calling process */
+	pid_t pid;
+
+	/** Private filesystem data */
+	void *private_data;
+
+	/** Umask of the calling process (introduced in version 2.8) */
+	mode_t umask;
+};
+
+/**
+ * Main function of FUSE.
+ *
+ * This is for the lazy.  This is all that has to be called from the
+ * main() function.
+ *
+ * This function does the following:
+ *   - parses command line options (-d -s and -h)
+ *   - passes relevant mount options to the fuse_mount()
+ *   - installs signal handlers for INT, HUP, TERM and PIPE
+ *   - registers an exit handler to unmount the filesystem on program exit
+ *   - creates a fuse handle
+ *   - registers the operations
+ *   - calls either the single-threaded or the multi-threaded event loop
+ *
+ * Note: this is currently implemented as a macro.
+ *
+ * @param argc the argument counter passed to the main() function
+ * @param argv the argument vector passed to the main() function
+ * @param op the file system operation
+ * @param user_data user data supplied in the context during the init() method
+ * @return 0 on success, nonzero on failure
+ */
+/*
+  int fuse_main(int argc, char *argv[], const struct fuse_operations *op,
+  void *user_data);
+*/
+#define fuse_main(argc, argv, op, user_data)				\
+	fuse_main_real(argc, argv, op, sizeof(*(op)), user_data)
+
+/* ----------------------------------------------------------- *
+ * More detailed API					       *
+ * ----------------------------------------------------------- */
+
+/**
+ * Create a new FUSE filesystem.
+ *
+ * @param ch the communication channel
+ * @param args argument vector
+ * @param op the filesystem operations
+ * @param op_size the size of the fuse_operations structure
+ * @param user_data user data supplied in the context during the init() method
+ * @return the created FUSE handle
+ */
+struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
+		      const struct fuse_operations *op, size_t op_size,
+		      void *user_data);
+
+/**
+ * Destroy the FUSE handle.
+ *
+ * The communication channel attached to the handle is also destroyed.
+ *
+ * NOTE: This function does not unmount the filesystem.	 If this is
+ * needed, call fuse_unmount() before calling this function.
+ *
+ * @param f the FUSE handle
+ */
+void fuse_destroy(struct fuse *f);
+
+/**
+ * FUSE event loop.
+ *
+ * Requests from the kernel are processed, and the appropriate
+ * operations are called.
+ *
+ * @param f the FUSE handle
+ * @return 0 if no error occurred, -1 otherwise
+ */
+int fuse_loop(struct fuse *f);
+
+/**
+ * Exit from event loop
+ *
+ * @param f the FUSE handle
+ */
+void fuse_exit(struct fuse *f);
+
+/**
+ * FUSE event loop with multiple threads
+ *
+ * Requests from the kernel are processed, and the appropriate
+ * operations are called.  Request are processed in parallel by
+ * distributing them between multiple threads.
+ *
+ * Calling this function requires the pthreads library to be linked to
+ * the application.
+ *
+ * @param f the FUSE handle
+ * @return 0 if no error occurred, -1 otherwise
+ */
+int fuse_loop_mt(struct fuse *f);
+
+/**
+ * Get the current context
+ *
+ * The context is only valid for the duration of a filesystem
+ * operation, and thus must not be stored and used later.
+ *
+ * @return the context
+ */
+struct fuse_context *fuse_get_context(void);
+
+/**
+ * Get the current supplementary group IDs for the current request
+ *
+ * Similar to the getgroups(2) system call, except the return value is
+ * always the total number of group IDs, even if it is larger than the
+ * specified size.
+ *
+ * The current fuse kernel module in linux (as of 2.6.30) doesn't pass
+ * the group list to userspace, hence this function needs to parse
+ * "/proc/$TID/task/$TID/status" to get the group IDs.
+ *
+ * This feature may not be supported on all operating systems.  In
+ * such a case this function will return -ENOSYS.
+ *
+ * @param size size of given array
+ * @param list array of group IDs to be filled in
+ * @return the total number of supplementary group IDs or -errno on failure
+ */
+int fuse_getgroups(int size, gid_t list[]);
+
+/**
+ * Check if the current request has already been interrupted
+ *
+ * @return 1 if the request has been interrupted, 0 otherwise
+ */
+int fuse_interrupted(void);
+
+/**
+ * Obsolete, doesn't do anything
+ *
+ * @return -EINVAL
+ */
+int fuse_invalidate(struct fuse *f, const char *path);
+
+/* Deprecated, don't use */
+int fuse_is_lib_option(const char *opt);
+
+/**
+ * The real main function
+ *
+ * Do not call this directly, use fuse_main()
+ */
+int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
+		   size_t op_size, void *user_data);
+
+/*
+ * Stacking API
+ */
+
+/**
+ * Fuse filesystem object
+ *
+ * This is opaque object represents a filesystem layer
+ */
+struct fuse_fs;
+
+/*
+ * These functions call the relevant filesystem operation, and return
+ * the result.
+ *
+ * If the operation is not defined, they return -ENOSYS, with the
+ * exception of fuse_fs_open, fuse_fs_release, fuse_fs_opendir,
+ * fuse_fs_releasedir and fuse_fs_statfs, which return 0.
+ */
+
+int fuse_fs_getattr(struct fuse_fs *fs, const char *path, struct stat *buf);
+int fuse_fs_fgetattr(struct fuse_fs *fs, const char *path, struct stat *buf,
+		     struct fuse_file_info *fi);
+int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath,
+		   const char *newpath);
+int fuse_fs_unlink(struct fuse_fs *fs, const char *path);
+int fuse_fs_rmdir(struct fuse_fs *fs, const char *path);
+int fuse_fs_symlink(struct fuse_fs *fs, const char *linkname,
+		    const char *path);
+int fuse_fs_link(struct fuse_fs *fs, const char *oldpath, const char *newpath);
+int fuse_fs_release(struct fuse_fs *fs,	 const char *path,
+		    struct fuse_file_info *fi);
+int fuse_fs_open(struct fuse_fs *fs, const char *path,
+		 struct fuse_file_info *fi);
+int fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size,
+		 off64_t off, struct fuse_file_info *fi);
+int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *buf,
+		  size_t size, off64_t off, struct fuse_file_info *fi);
+int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync,
+		  struct fuse_file_info *fi);
+int fuse_fs_flush(struct fuse_fs *fs, const char *path,
+		  struct fuse_file_info *fi);
+int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf);
+int fuse_fs_opendir(struct fuse_fs *fs, const char *path,
+		    struct fuse_file_info *fi);
+int fuse_fs_readdir(struct fuse_fs *fs, const char *path, void *buf,
+		    fuse_fill_dir_t filler, off64_t off,
+		    struct fuse_file_info *fi);
+int fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync,
+		     struct fuse_file_info *fi);
+int fuse_fs_releasedir(struct fuse_fs *fs, const char *path,
+		       struct fuse_file_info *fi);
+int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode,
+		   struct fuse_file_info *fi);
+int fuse_fs_lock(struct fuse_fs *fs, const char *path,
+		 struct fuse_file_info *fi, int cmd, struct flock *lock);
+int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode);
+int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid);
+int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off64_t size);
+int fuse_fs_ftruncate(struct fuse_fs *fs, const char *path, off64_t size,
+		      struct fuse_file_info *fi);
+int fuse_fs_utimens(struct fuse_fs *fs, const char *path,
+		    const struct timespec tv[2]);
+int fuse_fs_access(struct fuse_fs *fs, const char *path, int mask);
+int fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf,
+		     size_t len);
+int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode,
+		  dev_t rdev);
+int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode);
+int fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name,
+		     const char *value, size_t size, int flags);
+int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name,
+		     char *value, size_t size);
+int fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list,
+		      size_t size);
+int fuse_fs_removexattr(struct fuse_fs *fs, const char *path,
+			const char *name);
+int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize,
+		 uint64_t *idx);
+int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, int cmd, void *arg,
+		  struct fuse_file_info *fi, unsigned int flags, void *data);
+int fuse_fs_poll(struct fuse_fs *fs, const char *path,
+		 struct fuse_file_info *fi, struct fuse_pollhandle *ph,
+		 unsigned *reventsp);
+void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn);
+void fuse_fs_destroy(struct fuse_fs *fs);
+
+int fuse_notify_poll(struct fuse_pollhandle *ph);
+
+/**
+ * Create a new fuse filesystem object
+ *
+ * This is usually called from the factory of a fuse module to create
+ * a new instance of a filesystem.
+ *
+ * @param op the filesystem operations
+ * @param op_size the size of the fuse_operations structure
+ * @param user_data user data supplied in the context during the init() method
+ * @return a new filesystem object
+ */
+struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
+			    void *user_data);
+
+/**
+ * Filesystem module
+ *
+ * Filesystem modules are registered with the FUSE_REGISTER_MODULE()
+ * macro.
+ *
+ * If the "-omodules=modname:..." option is present, filesystem
+ * objects are created and pushed onto the stack with the 'factory'
+ * function.
+ */
+struct fuse_module {
+	/**
+	 * Name of filesystem
+	 */
+	const char *name;
+
+	/**
+	 * Factory for creating filesystem objects
+	 *
+	 * The function may use and remove options from 'args' that belong
+	 * to this module.
+	 *
+	 * For now the 'fs' vector always contains exactly one filesystem.
+	 * This is the filesystem which will be below the newly created
+	 * filesystem in the stack.
+	 *
+	 * @param args the command line arguments
+	 * @param fs NULL terminated filesystem object vector
+	 * @return the new filesystem object
+	 */
+	struct fuse_fs *(*factory)(struct fuse_args *args,
+				   struct fuse_fs *fs[]);
+
+	struct fuse_module *next;
+	struct fusemod_so *so;
+	int ctr;
+};
+
+/**
+ * Register a filesystem module
+ *
+ * This function is used by FUSE_REGISTER_MODULE and there's usually
+ * no need to call it directly
+ */
+void fuse_register_module(struct fuse_module *mod);
+
+/**
+ * Register filesystem module
+ *
+ * For the parameters, see description of the fields in 'struct
+ * fuse_module'
+ */
+#define FUSE_REGISTER_MODULE(name_, factory_)				  \
+	static __attribute__((constructor)) void name_ ## _register(void) \
+	{								  \
+		static struct fuse_module mod =				  \
+			{ #name_, factory_, NULL, NULL, 0 };		  \
+		fuse_register_module(&mod);				  \
+	}
+
+
+/* ----------------------------------------------------------- *
+ * Advanced API for event handling, don't worry about this...  *
+ * ----------------------------------------------------------- */
+
+/* NOTE: the following functions are deprecated, and will be removed
+   from the 3.0 API.  Use the lowlevel session functions instead */
+
+/** Function type used to process commands */
+typedef void (*fuse_processor_t)(struct fuse *, struct fuse_cmd *, void *);
+
+/** This is the part of fuse_main() before the event loop */
+struct fuse *fuse_setup(int argc, char *argv[],
+			const struct fuse_operations *op, size_t op_size,
+			char **mountpoint, int *multithreaded,
+			void *user_data);
+
+/** This is the part of fuse_main() after the event loop */
+void fuse_teardown(struct fuse *fuse, char *mountpoint);
+
+/** Read a single command.  If none are read, return NULL */
+struct fuse_cmd *fuse_read_cmd(struct fuse *f);
+
+/** Process a single command */
+void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd);
+
+/** Multi threaded event loop, which calls the custom command
+    processor function */
+int fuse_loop_mt_proc(struct fuse *f, fuse_processor_t proc, void *data);
+
+/** Return the exited flag, which indicates if fuse_exit() has been
+    called */
+int fuse_exited(struct fuse *f);
+
+/** This function is obsolete and implemented as a no-op */
+void fuse_set_getcontext_func(struct fuse_context *(*func)(void));
+
+/** Get session from fuse object */
+struct fuse_session *fuse_get_session(struct fuse *f);
+
+/* ----------------------------------------------------------- *
+ * Compatibility stuff					       *
+ * ----------------------------------------------------------- */
+
+#if FUSE_USE_VERSION < 26
+#  include "fuse_compat.h"
+#  undef fuse_main
+#  if FUSE_USE_VERSION == 25
+#    define fuse_main(argc, argv, op)				\
+	fuse_main_real_compat25(argc, argv, op, sizeof(*(op)))
+#    define fuse_new fuse_new_compat25
+#    define fuse_setup fuse_setup_compat25
+#    define fuse_teardown fuse_teardown_compat22
+#    define fuse_operations fuse_operations_compat25
+#  elif FUSE_USE_VERSION == 22
+#    define fuse_main(argc, argv, op)				\
+	fuse_main_real_compat22(argc, argv, op, sizeof(*(op)))
+#    define fuse_new fuse_new_compat22
+#    define fuse_setup fuse_setup_compat22
+#    define fuse_teardown fuse_teardown_compat22
+#    define fuse_operations fuse_operations_compat22
+#    define fuse_file_info fuse_file_info_compat
+#  elif FUSE_USE_VERSION == 24
+#    error Compatibility with high-level API version 24 not supported
+#  else
+#    define fuse_dirfil_t fuse_dirfil_t_compat
+#    define __fuse_read_cmd fuse_read_cmd
+#    define __fuse_process_cmd fuse_process_cmd
+#    define __fuse_loop_mt fuse_loop_mt_proc
+#    if FUSE_USE_VERSION == 21
+#      define fuse_operations fuse_operations_compat2
+#      define fuse_main fuse_main_compat2
+#      define fuse_new fuse_new_compat2
+#      define __fuse_setup fuse_setup_compat2
+#      define __fuse_teardown fuse_teardown_compat22
+#      define __fuse_exited fuse_exited
+#      define __fuse_set_getcontext_func fuse_set_getcontext_func
+#    else
+#      define fuse_statfs fuse_statfs_compat1
+#      define fuse_operations fuse_operations_compat1
+#      define fuse_main fuse_main_compat1
+#      define fuse_new fuse_new_compat1
+#      define FUSE_DEBUG FUSE_DEBUG_COMPAT1
+#    endif
+#  endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FUSE_H_ */
diff --git a/fuse/include/fuse_common.h b/fuse/include/fuse_common.h
new file mode 100644
index 0000000..48c0746
--- /dev/null
+++ b/fuse/include/fuse_common.h
@@ -0,0 +1,298 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB.
+*/
+
+/** @file */
+
+#if !defined(_FUSE_H_) && !defined(_FUSE_LOWLEVEL_H_)
+#error "Never include <fuse_common.h> directly; use <fuse.h> or <fuse_lowlevel.h> instead."
+#endif
+
+#ifndef _FUSE_COMMON_H_
+#define _FUSE_COMMON_H_
+
+#include "fuse_opt.h"
+#include <stdint.h>
+
+/** Major version of FUSE library interface */
+#define FUSE_MAJOR_VERSION 2
+
+/** Minor version of FUSE library interface */
+#define FUSE_MINOR_VERSION 8
+
+#define FUSE_MAKE_VERSION(maj, min)  ((maj) * 10 + (min))
+#define FUSE_VERSION 26
+//#define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION)
+
+/* This interface uses 64 bit off64_t */
+#if _FILE_OFFSET_BITS != 64
+#error Please add -D_FILE_OFFSET_BITS=64 to your compile flags!
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Information about open files
+ *
+ * Changed in version 2.5
+ */
+struct fuse_file_info {
+	/** Open flags.	 Available in open() and release() */
+	int flags;
+
+	/** Old file handle, don't use */
+	unsigned long fh_old;
+
+	/** In case of a write operation indicates if this was caused by a
+	    writepage */
+	int writepage;
+
+	/** Can be filled in by open, to use direct I/O on this file.
+	    Introduced in version 2.4 */
+	unsigned int direct_io : 1;
+
+	/** Can be filled in by open, to indicate, that cached file data
+	    need not be invalidated.  Introduced in version 2.4 */
+	unsigned int keep_cache : 1;
+
+	/** Indicates a flush operation.  Set in flush operation, also
+	    maybe set in highlevel lock operation and lowlevel release
+	    operation.	Introduced in version 2.6 */
+	unsigned int flush : 1;
+
+	/** Can be filled in by open, to indicate that the file is not
+	    seekable.  Introduced in version 2.8 */
+	unsigned int nonseekable : 1;
+
+	/** Padding.  Do not use*/
+	unsigned int padding : 28;
+
+	/** File handle.  May be filled in by filesystem in open().
+	    Available in all other file operations */
+	uint64_t fh;
+
+	/** Lock owner id.  Available in locking operations and flush */
+	uint64_t lock_owner;
+};
+
+/**
+ * Capability bits for 'fuse_conn_info.capable' and 'fuse_conn_info.want'
+ *
+ * FUSE_CAP_ASYNC_READ: filesystem supports asynchronous read requests
+ * FUSE_CAP_POSIX_LOCKS: filesystem supports "remote" locking
+ * FUSE_CAP_ATOMIC_O_TRUNC: filesystem handles the O_TRUNC open flag
+ * FUSE_CAP_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
+ * FUSE_CAP_BIG_WRITES: filesystem can handle write size larger than 4kB
+ * FUSE_CAP_DONT_MASK: don't apply umask to file mode on create operations
+ */
+#define FUSE_CAP_ASYNC_READ	(1 << 0)
+#define FUSE_CAP_POSIX_LOCKS	(1 << 1)
+#define FUSE_CAP_ATOMIC_O_TRUNC	(1 << 3)
+#define FUSE_CAP_EXPORT_SUPPORT	(1 << 4)
+#define FUSE_CAP_BIG_WRITES	(1 << 5)
+#define FUSE_CAP_DONT_MASK	(1 << 6)
+
+/**
+ * Ioctl flags
+ *
+ * FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine
+ * FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed
+ * FUSE_IOCTL_RETRY: retry with new iovecs
+ *
+ * FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs
+ */
+#define FUSE_IOCTL_COMPAT	(1 << 0)
+#define FUSE_IOCTL_UNRESTRICTED	(1 << 1)
+#define FUSE_IOCTL_RETRY	(1 << 2)
+
+#define FUSE_IOCTL_MAX_IOV	256
+
+/**
+ * Connection information, passed to the ->init() method
+ *
+ * Some of the elements are read-write, these can be changed to
+ * indicate the value requested by the filesystem.  The requested
+ * value must usually be smaller than the indicated value.
+ */
+struct fuse_conn_info {
+	/**
+	 * Major version of the protocol (read-only)
+	 */
+	unsigned proto_major;
+
+	/**
+	 * Minor version of the protocol (read-only)
+	 */
+	unsigned proto_minor;
+
+	/**
+	 * Is asynchronous read supported (read-write)
+	 */
+	unsigned async_read;
+
+	/**
+	 * Maximum size of the write buffer
+	 */
+	unsigned max_write;
+
+	/**
+	 * Maximum readahead
+	 */
+	unsigned max_readahead;
+
+	/**
+	 * Capability flags, that the kernel supports
+	 */
+	unsigned capable;
+
+	/**
+	 * Capability flags, that the filesystem wants to enable
+	 */
+	unsigned want;
+
+	/**
+	 * For future use.
+	 */
+	unsigned reserved[25];
+};
+
+struct fuse_session;
+struct fuse_chan;
+struct fuse_pollhandle;
+
+/**
+ * Create a FUSE mountpoint
+ *
+ * Returns a control file descriptor suitable for passing to
+ * fuse_new()
+ *
+ * @param mountpoint the mount point path
+ * @param args argument vector
+ * @return the communication channel on success, NULL on failure
+ */
+struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args);
+
+/**
+ * Umount a FUSE mountpoint
+ *
+ * @param mountpoint the mount point path
+ * @param ch the communication channel
+ */
+void fuse_unmount(const char *mountpoint, struct fuse_chan *ch);
+
+/**
+ * Parse common options
+ *
+ * The following options are parsed:
+ *
+ *   '-f'	     foreground
+ *   '-d' '-odebug'  foreground, but keep the debug option
+ *   '-s'	     single threaded
+ *   '-h' '--help'   help
+ *   '-ho'	     help without header
+ *   '-ofsname=..'   file system name, if not present, then set to the program
+ *		     name
+ *
+ * All parameters may be NULL
+ *
+ * @param args argument vector
+ * @param mountpoint the returned mountpoint, should be freed after use
+ * @param multithreaded set to 1 unless the '-s' option is present
+ * @param foreground set to 1 if one of the relevant options is present
+ * @return 0 on success, -1 on failure
+ */
+int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint,
+		       int *multithreaded, int *foreground);
+
+/**
+ * Go into the background
+ *
+ * @param foreground if true, stay in the foreground
+ * @return 0 on success, -1 on failure
+ */
+int fuse_daemonize(int foreground);
+
+/**
+ * Get the version of the library
+ *
+ * @return the version
+ */
+int fuse_version(void);
+
+/**
+ * Destroy poll handle
+ *
+ * @param ph the poll handle
+ */
+void fuse_pollhandle_destroy(struct fuse_pollhandle *ph);
+
+/* ----------------------------------------------------------- *
+ * Signal handling					       *
+ * ----------------------------------------------------------- */
+
+/**
+ * Exit session on HUP, TERM and INT signals and ignore PIPE signal
+ *
+ * Stores session in a global variable.	 May only be called once per
+ * process until fuse_remove_signal_handlers() is called.
+ *
+ * @param se the session to exit
+ * @return 0 on success, -1 on failure
+ */
+int fuse_set_signal_handlers(struct fuse_session *se);
+
+/**
+ * Restore default signal handlers
+ *
+ * Resets global session.  After this fuse_set_signal_handlers() may
+ * be called again.
+ *
+ * @param se the same session as given in fuse_set_signal_handlers()
+ */
+void fuse_remove_signal_handlers(struct fuse_session *se);
+
+/* ----------------------------------------------------------- *
+ * Compatibility stuff					       *
+ * ----------------------------------------------------------- */
+
+#if FUSE_USE_VERSION < 26
+#    ifdef __FreeBSD__
+#	 if FUSE_USE_VERSION < 25
+#	     error On FreeBSD API version 25 or greater must be used
+#	 endif
+#    endif
+#    include "fuse_common_compat.h"
+#    undef FUSE_MINOR_VERSION
+#    undef fuse_main
+#    define fuse_unmount fuse_unmount_compat22
+#    if FUSE_USE_VERSION == 25
+#	 define FUSE_MINOR_VERSION 5
+#	 define fuse_mount fuse_mount_compat25
+#    elif FUSE_USE_VERSION == 24 || FUSE_USE_VERSION == 22
+#	 define FUSE_MINOR_VERSION 4
+#	 define fuse_mount fuse_mount_compat22
+#    elif FUSE_USE_VERSION == 21
+#	 define FUSE_MINOR_VERSION 1
+#	 define fuse_mount fuse_mount_compat22
+#    elif FUSE_USE_VERSION == 11
+#	 warning Compatibility with API version 11 is deprecated
+#	 undef FUSE_MAJOR_VERSION
+#	 define FUSE_MAJOR_VERSION 1
+#	 define FUSE_MINOR_VERSION 1
+#	 define fuse_mount fuse_mount_compat1
+#    else
+#	 error Compatibility with API version other than 21, 22, 24, 25 and 11 not supported
+#    endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FUSE_COMMON_H_ */
diff --git a/fuse/include/fuse_common_compat.h b/fuse/include/fuse_common_compat.h
new file mode 100644
index 0000000..34440ff
--- /dev/null
+++ b/fuse/include/fuse_common_compat.h
@@ -0,0 +1,26 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB.
+*/
+
+/* these definitions provide source compatibility to prior versions.
+   Do not include this file directly! */
+
+struct fuse_file_info_compat {
+	int flags;
+	unsigned long fh;
+	int writepage;
+	unsigned int direct_io : 1;
+	unsigned int keep_cache : 1;
+};
+
+int fuse_mount_compat25(const char *mountpoint, struct fuse_args *args);
+
+int fuse_mount_compat22(const char *mountpoint, const char *opts);
+
+int fuse_mount_compat1(const char *mountpoint, const char *args[]);
+
+void fuse_unmount_compat22(const char *mountpoint);
diff --git a/fuse/include/fuse_compat.h b/fuse/include/fuse_compat.h
new file mode 100644
index 0000000..95b7c78
--- /dev/null
+++ b/fuse/include/fuse_compat.h
@@ -0,0 +1,201 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB.
+*/
+
+/* these definitions provide source compatibility to prior versions.
+   Do not include this file directly! */
+
+struct fuse_operations_compat25 {
+	int (*getattr) (const char *, struct stat *);
+	int (*readlink) (const char *, char *, size_t);
+	int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t);
+	int (*mknod) (const char *, mode_t, dev_t);
+	int (*mkdir) (const char *, mode_t);
+	int (*unlink) (const char *);
+	int (*rmdir) (const char *);
+	int (*symlink) (const char *, const char *);
+	int (*rename) (const char *, const char *);
+	int (*link) (const char *, const char *);
+	int (*chmod) (const char *, mode_t);
+	int (*chown) (const char *, uid_t, gid_t);
+	int (*truncate) (const char *, off64_t);
+	int (*utime) (const char *, struct utimbuf *);
+	int (*open) (const char *, struct fuse_file_info *);
+	int (*read) (const char *, char *, size_t, off64_t,
+		     struct fuse_file_info *);
+	int (*write) (const char *, const char *, size_t, off64_t,
+		      struct fuse_file_info *);
+	int (*statfs) (const char *, struct statvfs *);
+	int (*flush) (const char *, struct fuse_file_info *);
+	int (*release) (const char *, struct fuse_file_info *);
+	int (*fsync) (const char *, int, struct fuse_file_info *);
+	int (*setxattr) (const char *, const char *, const char *, size_t, int);
+	int (*getxattr) (const char *, const char *, char *, size_t);
+	int (*listxattr) (const char *, char *, size_t);
+	int (*removexattr) (const char *, const char *);
+	int (*opendir) (const char *, struct fuse_file_info *);
+	int (*readdir) (const char *, void *, fuse_fill_dir_t, off64_t,
+			struct fuse_file_info *);
+	int (*releasedir) (const char *, struct fuse_file_info *);
+	int (*fsyncdir) (const char *, int, struct fuse_file_info *);
+	void *(*init) (void);
+	void (*destroy) (void *);
+	int (*access) (const char *, int);
+	int (*create) (const char *, mode_t, struct fuse_file_info *);
+	int (*ftruncate) (const char *, off64_t, struct fuse_file_info *);
+	int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *);
+};
+
+struct fuse *fuse_new_compat25(int fd, struct fuse_args *args,
+			       const struct fuse_operations_compat25 *op,
+			       size_t op_size);
+
+int fuse_main_real_compat25(int argc, char *argv[],
+			    const struct fuse_operations_compat25 *op,
+			    size_t op_size);
+
+struct fuse *fuse_setup_compat25(int argc, char *argv[],
+				 const struct fuse_operations_compat25 *op,
+				 size_t op_size, char **mountpoint,
+				 int *multithreaded, int *fd);
+
+void fuse_teardown_compat22(struct fuse *fuse, int fd, char *mountpoint);
+
+#ifndef __FreeBSD__
+#include <sys/statfs.h>
+
+struct fuse_operations_compat22 {
+	int (*getattr) (const char *, struct stat *);
+	int (*readlink) (const char *, char *, size_t);
+	int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t);
+	int (*mknod) (const char *, mode_t, dev_t);
+	int (*mkdir) (const char *, mode_t);
+	int (*unlink) (const char *);
+	int (*rmdir) (const char *);
+	int (*symlink) (const char *, const char *);
+	int (*rename) (const char *, const char *);
+	int (*link) (const char *, const char *);
+	int (*chmod) (const char *, mode_t);
+	int (*chown) (const char *, uid_t, gid_t);
+	int (*truncate) (const char *, off64_t);
+	int (*utime) (const char *, struct utimbuf *);
+	int (*open) (const char *, struct fuse_file_info_compat *);
+	int (*read) (const char *, char *, size_t, off64_t,
+		     struct fuse_file_info_compat *);
+	int (*write) (const char *, const char *, size_t, off64_t,
+		      struct fuse_file_info_compat *);
+	int (*statfs) (const char *, struct statfs *);
+	int (*flush) (const char *, struct fuse_file_info_compat *);
+	int (*release) (const char *, struct fuse_file_info_compat *);
+	int (*fsync) (const char *, int, struct fuse_file_info_compat *);
+	int (*setxattr) (const char *, const char *, const char *, size_t, int);
+	int (*getxattr) (const char *, const char *, char *, size_t);
+	int (*listxattr) (const char *, char *, size_t);
+	int (*removexattr) (const char *, const char *);
+	int (*opendir) (const char *, struct fuse_file_info_compat *);
+	int (*readdir) (const char *, void *, fuse_fill_dir_t, off64_t,
+			struct fuse_file_info_compat *);
+	int (*releasedir) (const char *, struct fuse_file_info_compat *);
+	int (*fsyncdir) (const char *, int, struct fuse_file_info_compat *);
+	void *(*init) (void);
+	void (*destroy) (void *);
+};
+
+struct fuse *fuse_new_compat22(int fd, const char *opts,
+			       const struct fuse_operations_compat22 *op,
+			       size_t op_size);
+
+struct fuse *fuse_setup_compat22(int argc, char *argv[],
+				 const struct fuse_operations_compat22 *op,
+				 size_t op_size, char **mountpoint,
+				 int *multithreaded, int *fd);
+
+int fuse_main_real_compat22(int argc, char *argv[],
+			    const struct fuse_operations_compat22 *op,
+			    size_t op_size);
+
+typedef int (*fuse_dirfil_t_compat) (fuse_dirh_t h, const char *name, int type);
+struct fuse_operations_compat2 {
+	int (*getattr)	   (const char *, struct stat *);
+	int (*readlink)	   (const char *, char *, size_t);
+	int (*getdir)	   (const char *, fuse_dirh_t, fuse_dirfil_t_compat);
+	int (*mknod)	   (const char *, mode_t, dev_t);
+	int (*mkdir)	   (const char *, mode_t);
+	int (*unlink)	   (const char *);
+	int (*rmdir)	   (const char *);
+	int (*symlink)	   (const char *, const char *);
+	int (*rename)	   (const char *, const char *);
+	int (*link)	   (const char *, const char *);
+	int (*chmod)	   (const char *, mode_t);
+	int (*chown)	   (const char *, uid_t, gid_t);
+	int (*truncate)	   (const char *, off64_t);
+	int (*utime)	   (const char *, struct utimbuf *);
+	int (*open)	   (const char *, int);
+	int (*read)	   (const char *, char *, size_t, off64_t);
+	int (*write)	   (const char *, const char *, size_t, off64_t);
+	int (*statfs)	   (const char *, struct statfs *);
+	int (*flush)	   (const char *);
+	int (*release)	   (const char *, int);
+	int (*fsync)	   (const char *, int);
+	int (*setxattr)	   (const char *, const char *, const char *,
+			    size_t, int);
+	int (*getxattr)	   (const char *, const char *, char *, size_t);
+	int (*listxattr)   (const char *, char *, size_t);
+	int (*removexattr) (const char *, const char *);
+};
+
+int fuse_main_compat2(int argc, char *argv[],
+		      const struct fuse_operations_compat2 *op);
+
+struct fuse *fuse_new_compat2(int fd, const char *opts,
+			      const struct fuse_operations_compat2 *op);
+
+struct fuse *fuse_setup_compat2(int argc, char *argv[],
+				const struct fuse_operations_compat2 *op,
+				char **mountpoint, int *multithreaded, int *fd);
+
+struct fuse_statfs_compat1 {
+	long block_size;
+	long blocks;
+	long blocks_free;
+	long files;
+	long files_free;
+	long namelen;
+};
+
+struct fuse_operations_compat1 {
+	int (*getattr)	(const char *, struct stat *);
+	int (*readlink) (const char *, char *, size_t);
+	int (*getdir)	(const char *, fuse_dirh_t, fuse_dirfil_t_compat);
+	int (*mknod)	(const char *, mode_t, dev_t);
+	int (*mkdir)	(const char *, mode_t);
+	int (*unlink)	(const char *);
+	int (*rmdir)	(const char *);
+	int (*symlink)	(const char *, const char *);
+	int (*rename)	(const char *, const char *);
+	int (*link)	(const char *, const char *);
+	int (*chmod)	(const char *, mode_t);
+	int (*chown)	(const char *, uid_t, gid_t);
+	int (*truncate) (const char *, off64_t);
+	int (*utime)	(const char *, struct utimbuf *);
+	int (*open)	(const char *, int);
+	int (*read)	(const char *, char *, size_t, off64_t);
+	int (*write)	(const char *, const char *, size_t, off64_t);
+	int (*statfs)	(struct fuse_statfs_compat1 *);
+	int (*release)	(const char *, int);
+	int (*fsync)	(const char *, int);
+};
+
+#define FUSE_DEBUG_COMPAT1	 (1 << 1)
+
+struct fuse *fuse_new_compat1(int fd, int flags,
+			      const struct fuse_operations_compat1 *op);
+
+void fuse_main_compat1(int argc, char *argv[],
+		       const struct fuse_operations_compat1 *op);
+
+#endif /* __FreeBSD__ */
diff --git a/fuse/include/fuse_kernel.h b/fuse/include/fuse_kernel.h
new file mode 100644
index 0000000..bd73630
--- /dev/null
+++ b/fuse/include/fuse_kernel.h
@@ -0,0 +1,593 @@
+/*
+    This file defines the kernel interface of FUSE
+    Copyright (C) 2001-2008  Miklos Szeredi <miklos@szeredi.hu>
+
+    This program can be distributed under the terms of the GNU GPL.
+    See the file COPYING.
+
+    This -- and only this -- header file may also be distributed under
+    the terms of the BSD Licence as follows:
+
+    Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+    1. Redistributions of source code must retain the above copyright
+       notice, this list of conditions and the following disclaimer.
+    2. Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+    ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+*/
+
+/*
+ * This file defines the kernel interface of FUSE
+ *
+ * Protocol changelog:
+ *
+ * 7.9:
+ *  - new fuse_getattr_in input argument of GETATTR
+ *  - add lk_flags in fuse_lk_in
+ *  - add lock_owner field to fuse_setattr_in, fuse_read_in and fuse_write_in
+ *  - add blksize field to fuse_attr
+ *  - add file flags field to fuse_read_in and fuse_write_in
+ *
+ * 7.10
+ *  - add nonseekable open flag
+ *
+ * 7.11
+ *  - add IOCTL message
+ *  - add unsolicited notification support
+ *  - add POLL message and NOTIFY_POLL notification
+ *
+ * 7.12
+ *  - add umask flag to input argument of open, mknod and mkdir
+ *  - add notification messages for invalidation of inodes and
+ *    directory entries
+ */
+
+#ifndef _LINUX_FUSE_H
+#define _LINUX_FUSE_H
+
+#include <sys/types.h>
+#define __u64 uint64_t
+#define __s64 int64_t
+#define __u32 uint32_t
+#define __s32 int32_t
+
+/*
+ * Version negotiation:
+ *
+ * Both the kernel and userspace send the version they support in the
+ * INIT request and reply respectively.
+ *
+ * If the major versions match then both shall use the smallest
+ * of the two minor versions for communication.
+ *
+ * If the kernel supports a larger major version, then userspace shall
+ * reply with the major version it supports, ignore the rest of the
+ * INIT message and expect a new INIT message from the kernel with a
+ * matching major version.
+ *
+ * If the library supports a larger major version, then it shall fall
+ * back to the major protocol version sent by the kernel for
+ * communication and reply with that major version (and an arbitrary
+ * supported minor version).
+ */
+
+/** Version number of this interface */
+#define FUSE_KERNEL_VERSION 7
+
+/** Minor version number of this interface */
+#define FUSE_KERNEL_MINOR_VERSION 12
+
+/** The node ID of the root inode */
+#define FUSE_ROOT_ID 1
+
+/* Make sure all structures are padded to 64bit boundary, so 32bit
+   userspace works under 64bit kernels */
+
+struct fuse_attr {
+	__u64	ino;
+	__u64	size;
+	__u64	blocks;
+	__u64	atime;
+	__u64	mtime;
+	__u64	ctime;
+	__u32	atimensec;
+	__u32	mtimensec;
+	__u32	ctimensec;
+	__u32	mode;
+	__u32	nlink;
+	__u32	uid;
+	__u32	gid;
+	__u32	rdev;
+	__u32	blksize;
+	__u32	padding;
+};
+
+struct fuse_kstatfs {
+	__u64	blocks;
+	__u64	bfree;
+	__u64	bavail;
+	__u64	files;
+	__u64	ffree;
+	__u32	bsize;
+	__u32	namelen;
+	__u32	frsize;
+	__u32	padding;
+	__u32	spare[6];
+};
+
+struct fuse_file_lock {
+	__u64	start;
+	__u64	end;
+	__u32	type;
+	__u32	pid; /* tgid */
+};
+
+/**
+ * Bitmasks for fuse_setattr_in.valid
+ */
+#define FATTR_MODE	(1 << 0)
+#define FATTR_UID	(1 << 1)
+#define FATTR_GID	(1 << 2)
+#define FATTR_SIZE	(1 << 3)
+#define FATTR_ATIME	(1 << 4)
+#define FATTR_MTIME	(1 << 5)
+#define FATTR_FH	(1 << 6)
+#define FATTR_ATIME_NOW	(1 << 7)
+#define FATTR_MTIME_NOW	(1 << 8)
+#define FATTR_LOCKOWNER	(1 << 9)
+
+/**
+ * Flags returned by the OPEN request
+ *
+ * FOPEN_DIRECT_IO: bypass page cache for this open file
+ * FOPEN_KEEP_CACHE: don't invalidate the data cache on open
+ * FOPEN_NONSEEKABLE: the file is not seekable
+ */
+#define FOPEN_DIRECT_IO		(1 << 0)
+#define FOPEN_KEEP_CACHE	(1 << 1)
+#define FOPEN_NONSEEKABLE	(1 << 2)
+
+/**
+ * INIT request/reply flags
+ *
+ * FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
+ * FUSE_DONT_MASK: don't apply umask to file mode on create operations
+ */
+#define FUSE_ASYNC_READ		(1 << 0)
+#define FUSE_POSIX_LOCKS	(1 << 1)
+#define FUSE_FILE_OPS		(1 << 2)
+#define FUSE_ATOMIC_O_TRUNC	(1 << 3)
+#define FUSE_EXPORT_SUPPORT	(1 << 4)
+#define FUSE_BIG_WRITES		(1 << 5)
+#define FUSE_DONT_MASK		(1 << 6)
+
+/**
+ * CUSE INIT request/reply flags
+ *
+ * CUSE_UNRESTRICTED_IOCTL:  use unrestricted ioctl
+ */
+#define CUSE_UNRESTRICTED_IOCTL	(1 << 0)
+
+/**
+ * Release flags
+ */
+#define FUSE_RELEASE_FLUSH	(1 << 0)
+
+/**
+ * Getattr flags
+ */
+#define FUSE_GETATTR_FH		(1 << 0)
+
+/**
+ * Lock flags
+ */
+#define FUSE_LK_FLOCK		(1 << 0)
+
+/**
+ * WRITE flags
+ *
+ * FUSE_WRITE_CACHE: delayed write from page cache, file handle is guessed
+ * FUSE_WRITE_LOCKOWNER: lock_owner field is valid
+ */
+#define FUSE_WRITE_CACHE	(1 << 0)
+#define FUSE_WRITE_LOCKOWNER	(1 << 1)
+
+/**
+ * Read flags
+ */
+#define FUSE_READ_LOCKOWNER	(1 << 1)
+
+/**
+ * Ioctl flags
+ *
+ * FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine
+ * FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed
+ * FUSE_IOCTL_RETRY: retry with new iovecs
+ *
+ * FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs
+ */
+#define FUSE_IOCTL_COMPAT	(1 << 0)
+#define FUSE_IOCTL_UNRESTRICTED	(1 << 1)
+#define FUSE_IOCTL_RETRY	(1 << 2)
+
+#define FUSE_IOCTL_MAX_IOV	256
+
+/**
+ * Poll flags
+ *
+ * FUSE_POLL_SCHEDULE_NOTIFY: request poll notify
+ */
+#define FUSE_POLL_SCHEDULE_NOTIFY (1 << 0)
+
+enum fuse_opcode {
+	FUSE_LOOKUP	   = 1,
+	FUSE_FORGET	   = 2,  /* no reply */
+	FUSE_GETATTR	   = 3,
+	FUSE_SETATTR	   = 4,
+	FUSE_READLINK	   = 5,
+	FUSE_SYMLINK	   = 6,
+	FUSE_MKNOD	   = 8,
+	FUSE_MKDIR	   = 9,
+	FUSE_UNLINK	   = 10,
+	FUSE_RMDIR	   = 11,
+	FUSE_RENAME	   = 12,
+	FUSE_LINK	   = 13,
+	FUSE_OPEN	   = 14,
+	FUSE_READ	   = 15,
+	FUSE_WRITE	   = 16,
+	FUSE_STATFS	   = 17,
+	FUSE_RELEASE       = 18,
+	FUSE_FSYNC         = 20,
+	FUSE_SETXATTR      = 21,
+	FUSE_GETXATTR      = 22,
+	FUSE_LISTXATTR     = 23,
+	FUSE_REMOVEXATTR   = 24,
+	FUSE_FLUSH         = 25,
+	FUSE_INIT          = 26,
+	FUSE_OPENDIR       = 27,
+	FUSE_READDIR       = 28,
+	FUSE_RELEASEDIR    = 29,
+	FUSE_FSYNCDIR      = 30,
+	FUSE_GETLK         = 31,
+	FUSE_SETLK         = 32,
+	FUSE_SETLKW        = 33,
+	FUSE_ACCESS        = 34,
+	FUSE_CREATE        = 35,
+	FUSE_INTERRUPT     = 36,
+	FUSE_BMAP          = 37,
+	FUSE_DESTROY       = 38,
+	FUSE_IOCTL         = 39,
+	FUSE_POLL          = 40,
+
+	/* CUSE specific operations */
+	CUSE_INIT          = 4096,
+};
+
+enum fuse_notify_code {
+	FUSE_NOTIFY_POLL   = 1,
+	FUSE_NOTIFY_INVAL_INODE = 2,
+	FUSE_NOTIFY_INVAL_ENTRY = 3,
+	FUSE_NOTIFY_CODE_MAX,
+};
+
+/* The read buffer is required to be at least 8k, but may be much larger */
+#define FUSE_MIN_READ_BUFFER 8192
+
+#define FUSE_COMPAT_ENTRY_OUT_SIZE 120
+
+struct fuse_entry_out {
+	__u64	nodeid;		/* Inode ID */
+	__u64	generation;	/* Inode generation: nodeid:gen must
+				   be unique for the fs's lifetime */
+	__u64	entry_valid;	/* Cache timeout for the name */
+	__u64	attr_valid;	/* Cache timeout for the attributes */
+	__u32	entry_valid_nsec;
+	__u32	attr_valid_nsec;
+	struct fuse_attr attr;
+};
+
+struct fuse_forget_in {
+	__u64	nlookup;
+};
+
+struct fuse_getattr_in {
+	__u32	getattr_flags;
+	__u32	dummy;
+	__u64	fh;
+};
+
+#define FUSE_COMPAT_ATTR_OUT_SIZE 96
+
+struct fuse_attr_out {
+	__u64	attr_valid;	/* Cache timeout for the attributes */
+	__u32	attr_valid_nsec;
+	__u32	dummy;
+	struct fuse_attr attr;
+};
+
+#define FUSE_COMPAT_MKNOD_IN_SIZE 8
+
+struct fuse_mknod_in {
+	__u32	mode;
+	__u32	rdev;
+	__u32	umask;
+	__u32	padding;
+};
+
+struct fuse_mkdir_in {
+	__u32	mode;
+	__u32	umask;
+};
+
+struct fuse_rename_in {
+	__u64	newdir;
+};
+
+struct fuse_link_in {
+	__u64	oldnodeid;
+};
+
+struct fuse_setattr_in {
+	__u32	valid;
+	__u32	padding;
+	__u64	fh;
+	__u64	size;
+	__u64	lock_owner;
+	__u64	atime;
+	__u64	mtime;
+	__u64	unused2;
+	__u32	atimensec;
+	__u32	mtimensec;
+	__u32	unused3;
+	__u32	mode;
+	__u32	unused4;
+	__u32	uid;
+	__u32	gid;
+	__u32	unused5;
+};
+
+struct fuse_open_in {
+	__u32	flags;
+	__u32	unused;
+};
+
+struct fuse_create_in {
+	__u32	flags;
+	__u32	mode;
+	__u32	umask;
+	__u32	padding;
+};
+
+struct fuse_open_out {
+	__u64	fh;
+	__u32	open_flags;
+	__u32	padding;
+};
+
+struct fuse_release_in {
+	__u64	fh;
+	__u32	flags;
+	__u32	release_flags;
+	__u64	lock_owner;
+};
+
+struct fuse_flush_in {
+	__u64	fh;
+	__u32	unused;
+	__u32	padding;
+	__u64	lock_owner;
+};
+
+struct fuse_read_in {
+	__u64	fh;
+	__u64	offset;
+	__u32	size;
+	__u32	read_flags;
+	__u64	lock_owner;
+	__u32	flags;
+	__u32	padding;
+};
+
+#define FUSE_COMPAT_WRITE_IN_SIZE 24
+
+struct fuse_write_in {
+	__u64	fh;
+	__u64	offset;
+	__u32	size;
+	__u32	write_flags;
+	__u64	lock_owner;
+	__u32	flags;
+	__u32	padding;
+};
+
+struct fuse_write_out {
+	__u32	size;
+	__u32	padding;
+};
+
+#define FUSE_COMPAT_STATFS_SIZE 48
+
+struct fuse_statfs_out {
+	struct fuse_kstatfs st;
+};
+
+struct fuse_fsync_in {
+	__u64	fh;
+	__u32	fsync_flags;
+	__u32	padding;
+};
+
+struct fuse_setxattr_in {
+	__u32	size;
+	__u32	flags;
+};
+
+struct fuse_getxattr_in {
+	__u32	size;
+	__u32	padding;
+};
+
+struct fuse_getxattr_out {
+	__u32	size;
+	__u32	padding;
+};
+
+struct fuse_lk_in {
+	__u64	fh;
+	__u64	owner;
+	struct fuse_file_lock lk;
+	__u32	lk_flags;
+	__u32	padding;
+};
+
+struct fuse_lk_out {
+	struct fuse_file_lock lk;
+};
+
+struct fuse_access_in {
+	__u32	mask;
+	__u32	padding;
+};
+
+struct fuse_init_in {
+	__u32	major;
+	__u32	minor;
+	__u32	max_readahead;
+	__u32	flags;
+};
+
+struct fuse_init_out {
+	__u32	major;
+	__u32	minor;
+	__u32	max_readahead;
+	__u32	flags;
+	__u32	unused;
+	__u32	max_write;
+};
+
+#define CUSE_INIT_INFO_MAX 4096
+
+struct cuse_init_in {
+	__u32	major;
+	__u32	minor;
+	__u32	unused;
+	__u32	flags;
+};
+
+struct cuse_init_out {
+	__u32	major;
+	__u32	minor;
+	__u32	unused;
+	__u32	flags;
+	__u32	max_read;
+	__u32	max_write;
+	__u32	dev_major;		/* chardev major */
+	__u32	dev_minor;		/* chardev minor */
+	__u32	spare[10];
+};
+
+struct fuse_interrupt_in {
+	__u64	unique;
+};
+
+struct fuse_bmap_in {
+	__u64	block;
+	__u32	blocksize;
+	__u32	padding;
+};
+
+struct fuse_bmap_out {
+	__u64	block;
+};
+
+struct fuse_ioctl_in {
+	__u64	fh;
+	__u32	flags;
+	__u32	cmd;
+	__u64	arg;
+	__u32	in_size;
+	__u32	out_size;
+};
+
+struct fuse_ioctl_out {
+	__s32	result;
+	__u32	flags;
+	__u32	in_iovs;
+	__u32	out_iovs;
+};
+
+struct fuse_poll_in {
+	__u64	fh;
+	__u64	kh;
+	__u32	flags;
+	__u32   padding;
+};
+
+struct fuse_poll_out {
+	__u32	revents;
+	__u32	padding;
+};
+
+struct fuse_notify_poll_wakeup_out {
+	__u64	kh;
+};
+
+struct fuse_in_header {
+	__u32	len;
+	__u32	opcode;
+	__u64	unique;
+	__u64	nodeid;
+	__u32	uid;
+	__u32	gid;
+	__u32	pid;
+	__u32	padding;
+};
+
+struct fuse_out_header {
+	__u32	len;
+	__s32	error;
+	__u64	unique;
+};
+
+struct fuse_dirent {
+	__u64	ino;
+	__u64	off;
+	__u32	namelen;
+	__u32	type;
+	char name[0];
+};
+
+#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)
+#define FUSE_DIRENT_ALIGN(x) (((x) + sizeof(__u64) - 1) & ~(sizeof(__u64) - 1))
+#define FUSE_DIRENT_SIZE(d) \
+	FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
+
+struct fuse_notify_inval_inode_out {
+	__u64	ino;
+	__s64	off;
+	__s64	len;
+};
+
+struct fuse_notify_inval_entry_out {
+	__u64	parent;
+	__u32	namelen;
+	__u32	padding;
+};
+
+#endif /* _LINUX_FUSE_H */
diff --git a/fuse/include/fuse_lowlevel.h b/fuse/include/fuse_lowlevel.h
new file mode 100644
index 0000000..f1cfeb9
--- /dev/null
+++ b/fuse/include/fuse_lowlevel.h
@@ -0,0 +1,1577 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB.
+*/
+
+#ifndef _FUSE_LOWLEVEL_H_
+#define _FUSE_LOWLEVEL_H_
+
+/** @file
+ *
+ * Low level API
+ *
+ * IMPORTANT: you should define FUSE_USE_VERSION before including this
+ * header.  To use the newest API define it to 26 (recommended for any
+ * new application), to use the old API define it to 24 (default) or
+ * 25
+ */
+
+#ifndef FUSE_USE_VERSION
+#define FUSE_USE_VERSION 24
+#endif
+
+#include "fuse_common.h"
+
+#include <utime.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/uio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ----------------------------------------------------------- *
+ * Miscellaneous definitions				       *
+ * ----------------------------------------------------------- */
+
+/** The node ID of the root inode */
+#define FUSE_ROOT_ID 1
+
+/** Inode number type */
+typedef unsigned long fuse_ino_t;
+
+/** Request pointer type */
+typedef struct fuse_req *fuse_req_t;
+
+/**
+ * Session
+ *
+ * This provides hooks for processing requests, and exiting
+ */
+struct fuse_session;
+
+/**
+ * Channel
+ *
+ * A communication channel, providing hooks for sending and receiving
+ * messages
+ */
+struct fuse_chan;
+
+/** Directory entry parameters supplied to fuse_reply_entry() */
+struct fuse_entry_param {
+	/** Unique inode number
+	 *
+	 * In lookup, zero means negative entry (from version 2.5)
+	 * Returning ENOENT also means negative entry, but by setting zero
+	 * ino the kernel may cache negative entries for entry_timeout
+	 * seconds.
+	 */
+	fuse_ino_t ino;
+
+	/** Generation number for this entry.
+	 *
+	 * The ino/generation pair should be unique for the filesystem's
+	 * lifetime. It must be non-zero, otherwise FUSE will treat it as an
+	 * error.
+	 */
+	unsigned long generation;
+
+	/** Inode attributes.
+	 *
+	 * Even if attr_timeout == 0, attr must be correct. For example,
+	 * for open(), FUSE uses attr.st_size from lookup() to determine
+	 * how many bytes to request. If this value is not correct,
+	 * incorrect data will be returned.
+	 */
+	struct stat attr;
+
+	/** Validity timeout (in seconds) for the attributes */
+	double attr_timeout;
+
+	/** Validity timeout (in seconds) for the name */
+	double entry_timeout;
+};
+
+/** Additional context associated with requests */
+struct fuse_ctx {
+	/** User ID of the calling process */
+	uid_t uid;
+
+	/** Group ID of the calling process */
+	gid_t gid;
+
+	/** Thread ID of the calling process */
+	pid_t pid;
+
+	/** Umask of the calling process (introduced in version 2.8) */
+	mode_t umask;
+};
+
+/* 'to_set' flags in setattr */
+#define FUSE_SET_ATTR_MODE	(1 << 0)
+#define FUSE_SET_ATTR_UID	(1 << 1)
+#define FUSE_SET_ATTR_GID	(1 << 2)
+#define FUSE_SET_ATTR_SIZE	(1 << 3)
+#define FUSE_SET_ATTR_ATIME	(1 << 4)
+#define FUSE_SET_ATTR_MTIME	(1 << 5)
+#define FUSE_SET_ATTR_ATIME_NOW	(1 << 7)
+#define FUSE_SET_ATTR_MTIME_NOW	(1 << 8)
+
+/* ----------------------------------------------------------- *
+ * Request methods and replies				       *
+ * ----------------------------------------------------------- */
+
+/**
+ * Low level filesystem operations
+ *
+ * Most of the methods (with the exception of init and destroy)
+ * receive a request handle (fuse_req_t) as their first argument.
+ * This handle must be passed to one of the specified reply functions.
+ *
+ * This may be done inside the method invocation, or after the call
+ * has returned.  The request handle is valid until one of the reply
+ * functions is called.
+ *
+ * Other pointer arguments (name, fuse_file_info, etc) are not valid
+ * after the call has returned, so if they are needed later, their
+ * contents have to be copied.
+ *
+ * The filesystem sometimes needs to handle a return value of -ENOENT
+ * from the reply function, which means, that the request was
+ * interrupted, and the reply discarded.  For example if
+ * fuse_reply_open() return -ENOENT means, that the release method for
+ * this file will not be called.
+ */
+struct fuse_lowlevel_ops {
+	/**
+	 * Initialize filesystem
+	 *
+	 * Called before any other filesystem method
+	 *
+	 * There's no reply to this function
+	 *
+	 * @param userdata the user data passed to fuse_lowlevel_new()
+	 */
+	void (*init) (void *userdata, struct fuse_conn_info *conn);
+
+	/**
+	 * Clean up filesystem
+	 *
+	 * Called on filesystem exit
+	 *
+	 * There's no reply to this function
+	 *
+	 * @param userdata the user data passed to fuse_lowlevel_new()
+	 */
+	void (*destroy) (void *userdata);
+
+	/**
+	 * Look up a directory entry by name and get its attributes.
+	 *
+	 * Valid replies:
+	 *   fuse_reply_entry
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param parent inode number of the parent directory
+	 * @param name the name to look up
+	 */
+	void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name);
+
+	/**
+	 * Forget about an inode
+	 *
+	 * The nlookup parameter indicates the number of lookups
+	 * previously performed on this inode.
+	 *
+	 * If the filesystem implements inode lifetimes, it is recommended
+	 * that inodes acquire a single reference on each lookup, and lose
+	 * nlookup references on each forget.
+	 *
+	 * The filesystem may ignore forget calls, if the inodes don't
+	 * need to have a limited lifetime.
+	 *
+	 * On unmount it is not guaranteed, that all referenced inodes
+	 * will receive a forget message.
+	 *
+	 * Valid replies:
+	 *   fuse_reply_none
+	 *
+	 * @param req request handle
+	 * @param ino the inode number
+	 * @param nlookup the number of lookups to forget
+	 */
+	void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup);
+
+	/**
+	 * Get file attributes
+	 *
+	 * Valid replies:
+	 *   fuse_reply_attr
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param ino the inode number
+	 * @param fi for future use, currently always NULL
+	 */
+	void (*getattr) (fuse_req_t req, fuse_ino_t ino,
+			 struct fuse_file_info *fi);
+
+	/**
+	 * Set file attributes
+	 *
+	 * In the 'attr' argument only members indicated by the 'to_set'
+	 * bitmask contain valid values.  Other members contain undefined
+	 * values.
+	 *
+	 * If the setattr was invoked from the ftruncate() system call
+	 * under Linux kernel versions 2.6.15 or later, the fi->fh will
+	 * contain the value set by the open method or will be undefined
+	 * if the open method didn't set any value.  Otherwise (not
+	 * ftruncate call, or kernel version earlier than 2.6.15) the fi
+	 * parameter will be NULL.
+	 *
+	 * Valid replies:
+	 *   fuse_reply_attr
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param ino the inode number
+	 * @param attr the attributes
+	 * @param to_set bit mask of attributes which should be set
+	 * @param fi file information, or NULL
+	 *
+	 * Changed in version 2.5:
+	 *     file information filled in for ftruncate
+	 */
+	void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr,
+			 int to_set, struct fuse_file_info *fi);
+
+	/**
+	 * Read symbolic link
+	 *
+	 * Valid replies:
+	 *   fuse_reply_readlink
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param ino the inode number
+	 */
+	void (*readlink) (fuse_req_t req, fuse_ino_t ino);
+
+	/**
+	 * Create file node
+	 *
+	 * Create a regular file, character device, block device, fifo or
+	 * socket node.
+	 *
+	 * Valid replies:
+	 *   fuse_reply_entry
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param parent inode number of the parent directory
+	 * @param name to create
+	 * @param mode file type and mode with which to create the new file
+	 * @param rdev the device number (only valid if created file is a device)
+	 */
+	void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name,
+		       mode_t mode, dev_t rdev);
+
+	/**
+	 * Create a directory
+	 *
+	 * Valid replies:
+	 *   fuse_reply_entry
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param parent inode number of the parent directory
+	 * @param name to create
+	 * @param mode with which to create the new file
+	 */
+	void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name,
+		       mode_t mode);
+
+	/**
+	 * Remove a file
+	 *
+	 * Valid replies:
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param parent inode number of the parent directory
+	 * @param name to remove
+	 */
+	void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name);
+
+	/**
+	 * Remove a directory
+	 *
+	 * Valid replies:
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param parent inode number of the parent directory
+	 * @param name to remove
+	 */
+	void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name);
+
+	/**
+	 * Create a symbolic link
+	 *
+	 * Valid replies:
+	 *   fuse_reply_entry
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param link the contents of the symbolic link
+	 * @param parent inode number of the parent directory
+	 * @param name to create
+	 */
+	void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent,
+			 const char *name);
+
+	/** Rename a file
+	 *
+	 * Valid replies:
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param parent inode number of the old parent directory
+	 * @param name old name
+	 * @param newparent inode number of the new parent directory
+	 * @param newname new name
+	 */
+	void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name,
+			fuse_ino_t newparent, const char *newname);
+
+	/**
+	 * Create a hard link
+	 *
+	 * Valid replies:
+	 *   fuse_reply_entry
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param ino the old inode number
+	 * @param newparent inode number of the new parent directory
+	 * @param newname new name to create
+	 */
+	void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
+		      const char *newname);
+
+	/**
+	 * Open a file
+	 *
+	 * Open flags (with the exception of O_CREAT, O_EXCL, O_NOCTTY and
+	 * O_TRUNC) are available in fi->flags.
+	 *
+	 * Filesystem may store an arbitrary file handle (pointer, index,
+	 * etc) in fi->fh, and use this in other all other file operations
+	 * (read, write, flush, release, fsync).
+	 *
+	 * Filesystem may also implement stateless file I/O and not store
+	 * anything in fi->fh.
+	 *
+	 * There are also some flags (direct_io, keep_cache) which the
+	 * filesystem may set in fi, to change the way the file is opened.
+	 * See fuse_file_info structure in <fuse_common.h> for more details.
+	 *
+	 * Valid replies:
+	 *   fuse_reply_open
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param ino the inode number
+	 * @param fi file information
+	 */
+	void (*open) (fuse_req_t req, fuse_ino_t ino,
+		      struct fuse_file_info *fi);
+
+	/**
+	 * Read data
+	 *
+	 * Read should send exactly the number of bytes requested except
+	 * on EOF or error, otherwise the rest of the data will be
+	 * substituted with zeroes.  An exception to this is when the file
+	 * has been opened in 'direct_io' mode, in which case the return
+	 * value of the read system call will reflect the return value of
+	 * this operation.
+	 *
+	 * fi->fh will contain the value set by the open method, or will
+	 * be undefined if the open method didn't set any value.
+	 *
+	 * Valid replies:
+	 *   fuse_reply_buf
+	 *   fuse_reply_iov
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param ino the inode number
+	 * @param size number of bytes to read
+	 * @param off offset to read from
+	 * @param fi file information
+	 */
+	void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off64_t off,
+		      struct fuse_file_info *fi);
+
+	/**
+	 * Write data
+	 *
+	 * Write should return exactly the number of bytes requested
+	 * except on error.  An exception to this is when the file has
+	 * been opened in 'direct_io' mode, in which case the return value
+	 * of the write system call will reflect the return value of this
+	 * operation.
+	 *
+	 * fi->fh will contain the value set by the open method, or will
+	 * be undefined if the open method didn't set any value.
+	 *
+	 * Valid replies:
+	 *   fuse_reply_write
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param ino the inode number
+	 * @param buf data to write
+	 * @param size number of bytes to write
+	 * @param off offset to write to
+	 * @param fi file information
+	 */
+	void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf,
+		       size_t size, off64_t off, struct fuse_file_info *fi);
+
+	/**
+	 * Flush method
+	 *
+	 * This is called on each close() of the opened file.
+	 *
+	 * Since file descriptors can be duplicated (dup, dup2, fork), for
+	 * one open call there may be many flush calls.
+	 *
+	 * Filesystems shouldn't assume that flush will always be called
+	 * after some writes, or that if will be called at all.
+	 *
+	 * fi->fh will contain the value set by the open method, or will
+	 * be undefined if the open method didn't set any value.
+	 *
+	 * NOTE: the name of the method is misleading, since (unlike
+	 * fsync) the filesystem is not forced to flush pending writes.
+	 * One reason to flush data, is if the filesystem wants to return
+	 * write errors.
+	 *
+	 * If the filesystem supports file locking operations (setlk,
+	 * getlk) it should remove all locks belonging to 'fi->owner'.
+	 *
+	 * Valid replies:
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param ino the inode number
+	 * @param fi file information
+	 */
+	void (*flush) (fuse_req_t req, fuse_ino_t ino,
+		       struct fuse_file_info *fi);
+
+	/**
+	 * Release an open file
+	 *
+	 * Release is called when there are no more references to an open
+	 * file: all file descriptors are closed and all memory mappings
+	 * are unmapped.
+	 *
+	 * For every open call there will be exactly one release call.
+	 *
+	 * The filesystem may reply with an error, but error values are
+	 * not returned to close() or munmap() which triggered the
+	 * release.
+	 *
+	 * fi->fh will contain the value set by the open method, or will
+	 * be undefined if the open method didn't set any value.
+	 * fi->flags will contain the same flags as for open.
+	 *
+	 * Valid replies:
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param ino the inode number
+	 * @param fi file information
+	 */
+	void (*release) (fuse_req_t req, fuse_ino_t ino,
+			 struct fuse_file_info *fi);
+
+	/**
+	 * Synchronize file contents
+	 *
+	 * If the datasync parameter is non-zero, then only the user data
+	 * should be flushed, not the meta data.
+	 *
+	 * Valid replies:
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param ino the inode number
+	 * @param datasync flag indicating if only data should be flushed
+	 * @param fi file information
+	 */
+	void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync,
+		       struct fuse_file_info *fi);
+
+	/**
+	 * Open a directory
+	 *
+	 * Filesystem may store an arbitrary file handle (pointer, index,
+	 * etc) in fi->fh, and use this in other all other directory
+	 * stream operations (readdir, releasedir, fsyncdir).
+	 *
+	 * Filesystem may also implement stateless directory I/O and not
+	 * store anything in fi->fh, though that makes it impossible to
+	 * implement standard conforming directory stream operations in
+	 * case the contents of the directory can change between opendir
+	 * and releasedir.
+	 *
+	 * Valid replies:
+	 *   fuse_reply_open
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param ino the inode number
+	 * @param fi file information
+	 */
+	void (*opendir) (fuse_req_t req, fuse_ino_t ino,
+			 struct fuse_file_info *fi);
+
+	/**
+	 * Read directory
+	 *
+	 * Send a buffer filled using fuse_add_direntry(), with size not
+	 * exceeding the requested size.  Send an empty buffer on end of
+	 * stream.
+	 *
+	 * fi->fh will contain the value set by the opendir method, or
+	 * will be undefined if the opendir method didn't set any value.
+	 *
+	 * Valid replies:
+	 *   fuse_reply_buf
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param ino the inode number
+	 * @param size maximum number of bytes to send
+	 * @param off offset to continue reading the directory stream
+	 * @param fi file information
+	 */
+	void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off64_t off,
+			 struct fuse_file_info *fi);
+
+	/**
+	 * Release an open directory
+	 *
+	 * For every opendir call there will be exactly one releasedir
+	 * call.
+	 *
+	 * fi->fh will contain the value set by the opendir method, or
+	 * will be undefined if the opendir method didn't set any value.
+	 *
+	 * Valid replies:
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param ino the inode number
+	 * @param fi file information
+	 */
+	void (*releasedir) (fuse_req_t req, fuse_ino_t ino,
+			    struct fuse_file_info *fi);
+
+	/**
+	 * Synchronize directory contents
+	 *
+	 * If the datasync parameter is non-zero, then only the directory
+	 * contents should be flushed, not the meta data.
+	 *
+	 * fi->fh will contain the value set by the opendir method, or
+	 * will be undefined if the opendir method didn't set any value.
+	 *
+	 * Valid replies:
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param ino the inode number
+	 * @param datasync flag indicating if only data should be flushed
+	 * @param fi file information
+	 */
+	void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync,
+			  struct fuse_file_info *fi);
+
+	/**
+	 * Get file system statistics
+	 *
+	 * Valid replies:
+	 *   fuse_reply_statfs
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param ino the inode number, zero means "undefined"
+	 */
+	void (*statfs) (fuse_req_t req, fuse_ino_t ino);
+
+	/**
+	 * Set an extended attribute
+	 *
+	 * Valid replies:
+	 *   fuse_reply_err
+	 */
+	void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
+			  const char *value, size_t size, int flags);
+
+	/**
+	 * Get an extended attribute
+	 *
+	 * If size is zero, the size of the value should be sent with
+	 * fuse_reply_xattr.
+	 *
+	 * If the size is non-zero, and the value fits in the buffer, the
+	 * value should be sent with fuse_reply_buf.
+	 *
+	 * If the size is too small for the value, the ERANGE error should
+	 * be sent.
+	 *
+	 * Valid replies:
+	 *   fuse_reply_buf
+	 *   fuse_reply_xattr
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param ino the inode number
+	 * @param name of the extended attribute
+	 * @param size maximum size of the value to send
+	 */
+	void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
+			  size_t size);
+
+	/**
+	 * List extended attribute names
+	 *
+	 * If size is zero, the total size of the attribute list should be
+	 * sent with fuse_reply_xattr.
+	 *
+	 * If the size is non-zero, and the null character separated
+	 * attribute list fits in the buffer, the list should be sent with
+	 * fuse_reply_buf.
+	 *
+	 * If the size is too small for the list, the ERANGE error should
+	 * be sent.
+	 *
+	 * Valid replies:
+	 *   fuse_reply_buf
+	 *   fuse_reply_xattr
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param ino the inode number
+	 * @param size maximum size of the list to send
+	 */
+	void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size);
+
+	/**
+	 * Remove an extended attribute
+	 *
+	 * Valid replies:
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param ino the inode number
+	 * @param name of the extended attribute
+	 */
+	void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name);
+
+	/**
+	 * Check file access permissions
+	 *
+	 * This will be called for the access() system call.  If the
+	 * 'default_permissions' mount option is given, this method is not
+	 * called.
+	 *
+	 * This method is not called under Linux kernel versions 2.4.x
+	 *
+	 * Introduced in version 2.5
+	 *
+	 * Valid replies:
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param ino the inode number
+	 * @param mask requested access mode
+	 */
+	void (*access) (fuse_req_t req, fuse_ino_t ino, int mask);
+
+	/**
+	 * Create and open a file
+	 *
+	 * If the file does not exist, first create it with the specified
+	 * mode, and then open it.
+	 *
+	 * Open flags (with the exception of O_NOCTTY) are available in
+	 * fi->flags.
+	 *
+	 * Filesystem may store an arbitrary file handle (pointer, index,
+	 * etc) in fi->fh, and use this in other all other file operations
+	 * (read, write, flush, release, fsync).
+	 *
+	 * There are also some flags (direct_io, keep_cache) which the
+	 * filesystem may set in fi, to change the way the file is opened.
+	 * See fuse_file_info structure in <fuse_common.h> for more details.
+	 *
+	 * If this method is not implemented or under Linux kernel
+	 * versions earlier than 2.6.15, the mknod() and open() methods
+	 * will be called instead.
+	 *
+	 * Introduced in version 2.5
+	 *
+	 * Valid replies:
+	 *   fuse_reply_create
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param parent inode number of the parent directory
+	 * @param name to create
+	 * @param mode file type and mode with which to create the new file
+	 * @param fi file information
+	 */
+	void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name,
+			mode_t mode, struct fuse_file_info *fi);
+
+	/**
+	 * Test for a POSIX file lock
+	 *
+	 * Introduced in version 2.6
+	 *
+	 * Valid replies:
+	 *   fuse_reply_lock
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param ino the inode number
+	 * @param fi file information
+	 * @param lock the region/type to test
+	 */
+	void (*getlk) (fuse_req_t req, fuse_ino_t ino,
+		       struct fuse_file_info *fi, struct flock *lock);
+
+	/**
+	 * Acquire, modify or release a POSIX file lock
+	 *
+	 * For POSIX threads (NPTL) there's a 1-1 relation between pid and
+	 * owner, but otherwise this is not always the case.  For checking
+	 * lock ownership, 'fi->owner' must be used.  The l_pid field in
+	 * 'struct flock' should only be used to fill in this field in
+	 * getlk().
+	 *
+	 * Note: if the locking methods are not implemented, the kernel
+	 * will still allow file locking to work locally.  Hence these are
+	 * only interesting for network filesystems and similar.
+	 *
+	 * Introduced in version 2.6
+	 *
+	 * Valid replies:
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param ino the inode number
+	 * @param fi file information
+	 * @param lock the region/type to test
+	 * @param sleep locking operation may sleep
+	 */
+	void (*setlk) (fuse_req_t req, fuse_ino_t ino,
+		       struct fuse_file_info *fi,
+		       struct flock *lock, int sleep);
+
+	/**
+	 * Map block index within file to block index within device
+	 *
+	 * Note: This makes sense only for block device backed filesystems
+	 * mounted with the 'blkdev' option
+	 *
+	 * Introduced in version 2.6
+	 *
+	 * Valid replies:
+	 *   fuse_reply_bmap
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param ino the inode number
+	 * @param blocksize unit of block index
+	 * @param idx block index within file
+	 */
+	void (*bmap) (fuse_req_t req, fuse_ino_t ino, size_t blocksize,
+		      uint64_t idx);
+
+	/**
+	 * Ioctl
+	 *
+	 * Note: For unrestricted ioctls (not allowed for FUSE
+	 * servers), data in and out areas can be discovered by giving
+	 * iovs and setting FUSE_IOCTL_RETRY in @flags.  For
+	 * restricted ioctls, kernel prepares in/out data area
+	 * according to the information encoded in cmd.
+	 *
+	 * Introduced in version 2.8
+	 *
+	 * Valid replies:
+	 *   fuse_reply_ioctl_retry
+	 *   fuse_reply_ioctl
+	 *   fuse_reply_ioctl_iov
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param ino the inode number
+	 * @param cmd ioctl command
+	 * @param arg ioctl argument
+	 * @param fi file information
+	 * @param flags for FUSE_IOCTL_* flags
+	 * @param in_buf data fetched from the caller
+	 * @param in_bufsz number of fetched bytes
+	 * @param out_bufsz maximum size of output data
+	 */
+	void (*ioctl) (fuse_req_t req, fuse_ino_t ino, int cmd, void *arg,
+		       struct fuse_file_info *fi, unsigned flags,
+		       const void *in_buf, size_t in_bufsz, size_t out_bufsz);
+
+	/**
+	 * Poll for IO readiness
+	 *
+	 * Introduced in version 2.8
+	 *
+	 * Note: If ph is non-NULL, the client should notify
+	 * when IO readiness events occur by calling
+	 * fuse_lowelevel_notify_poll() with the specified ph.
+	 *
+	 * Regardless of the number of times poll with a non-NULL ph
+	 * is received, single notification is enough to clear all.
+	 * Notifying more times incurs overhead but doesn't harm
+	 * correctness.
+	 *
+	 * The callee is responsible for destroying ph with
+	 * fuse_pollhandle_destroy() when no longer in use.
+	 *
+	 * Valid replies:
+	 *   fuse_reply_poll
+	 *   fuse_reply_err
+	 *
+	 * @param req request handle
+	 * @param ino the inode number
+	 * @param fi file information
+	 * @param ph poll handle to be used for notification
+	 */
+	void (*poll) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
+		      struct fuse_pollhandle *ph);
+};
+
+/**
+ * Reply with an error code or success
+ *
+ * Possible requests:
+ *   all except forget
+ *
+ * unlink, rmdir, rename, flush, release, fsync, fsyncdir, setxattr,
+ * removexattr and setlk may send a zero code
+ *
+ * @param req request handle
+ * @param err the positive error value, or zero for success
+ * @return zero for success, -errno for failure to send reply
+ */
+int fuse_reply_err(fuse_req_t req, int err);
+
+/**
+ * Don't send reply
+ *
+ * Possible requests:
+ *   forget
+ *
+ * @param req request handle
+ */
+void fuse_reply_none(fuse_req_t req);
+
+/**
+ * Reply with a directory entry
+ *
+ * Possible requests:
+ *   lookup, mknod, mkdir, symlink, link
+ *
+ * @param req request handle
+ * @param e the entry parameters
+ * @return zero for success, -errno for failure to send reply
+ */
+int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e);
+
+/**
+ * Reply with a directory entry and open parameters
+ *
+ * currently the following members of 'fi' are used:
+ *   fh, direct_io, keep_cache
+ *
+ * Possible requests:
+ *   create
+ *
+ * @param req request handle
+ * @param e the entry parameters
+ * @param fi file information
+ * @return zero for success, -errno for failure to send reply
+ */
+int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
+		      const struct fuse_file_info *fi);
+
+/**
+ * Reply with attributes
+ *
+ * Possible requests:
+ *   getattr, setattr
+ *
+ * @param req request handle
+ * @param attr the attributes
+ * @param attr_timeout	validity timeout (in seconds) for the attributes
+ * @return zero for success, -errno for failure to send reply
+ */
+int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
+		    double attr_timeout);
+
+/**
+ * Reply with the contents of a symbolic link
+ *
+ * Possible requests:
+ *   readlink
+ *
+ * @param req request handle
+ * @param link symbolic link contents
+ * @return zero for success, -errno for failure to send reply
+ */
+int fuse_reply_readlink(fuse_req_t req, const char *link);
+
+/**
+ * Reply with open parameters
+ *
+ * currently the following members of 'fi' are used:
+ *   fh, direct_io, keep_cache
+ *
+ * Possible requests:
+ *   open, opendir
+ *
+ * @param req request handle
+ * @param fi file information
+ * @return zero for success, -errno for failure to send reply
+ */
+int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi);
+
+/**
+ * Reply with number of bytes written
+ *
+ * Possible requests:
+ *   write
+ *
+ * @param req request handle
+ * @param count the number of bytes written
+ * @return zero for success, -errno for failure to send reply
+ */
+int fuse_reply_write(fuse_req_t req, size_t count);
+
+/**
+ * Reply with data
+ *
+ * Possible requests:
+ *   read, readdir, getxattr, listxattr
+ *
+ * @param req request handle
+ * @param buf buffer containing data
+ * @param size the size of data in bytes
+ * @return zero for success, -errno for failure to send reply
+ */
+int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size);
+
+/**
+ * Reply with data vector
+ *
+ * Possible requests:
+ *   read, readdir, getxattr, listxattr
+ *
+ * @param req request handle
+ * @param iov the vector containing the data
+ * @param count the size of vector
+ * @return zero for success, -errno for failure to send reply
+ */
+int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count);
+
+/**
+ * Reply with filesystem statistics
+ *
+ * Possible requests:
+ *   statfs
+ *
+ * @param req request handle
+ * @param stbuf filesystem statistics
+ * @return zero for success, -errno for failure to send reply
+ */
+int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf);
+
+/**
+ * Reply with needed buffer size
+ *
+ * Possible requests:
+ *   getxattr, listxattr
+ *
+ * @param req request handle
+ * @param count the buffer size needed in bytes
+ * @return zero for success, -errno for failure to send reply
+ */
+int fuse_reply_xattr(fuse_req_t req, size_t count);
+
+/**
+ * Reply with file lock information
+ *
+ * Possible requests:
+ *   getlk
+ *
+ * @param req request handle
+ * @param lock the lock information
+ * @return zero for success, -errno for failure to send reply
+ */
+int fuse_reply_lock(fuse_req_t req, struct flock *lock);
+
+/**
+ * Reply with block index
+ *
+ * Possible requests:
+ *   bmap
+ *
+ * @param req request handle
+ * @param idx block index within device
+ * @return zero for success, -errno for failure to send reply
+ */
+int fuse_reply_bmap(fuse_req_t req, uint64_t idx);
+
+/* ----------------------------------------------------------- *
+ * Filling a buffer in readdir				       *
+ * ----------------------------------------------------------- */
+
+/**
+ * Add a directory entry to the buffer
+ *
+ * Buffer needs to be large enough to hold the entry.  If it's not,
+ * then the entry is not filled in but the size of the entry is still
+ * returned.  The caller can check this by comparing the bufsize
+ * parameter with the returned entry size.  If the entry size is
+ * larger than the buffer size, the operation failed.
+ *
+ * From the 'stbuf' argument the st_ino field and bits 12-15 of the
+ * st_mode field are used.  The other fields are ignored.
+ *
+ * Note: offsets do not necessarily represent physical offsets, and
+ * could be any marker, that enables the implementation to find a
+ * specific point in the directory stream.
+ *
+ * @param req request handle
+ * @param buf the point where the new entry will be added to the buffer
+ * @param bufsize remaining size of the buffer
+ * @param name the name of the entry
+ * @param stbuf the file attributes
+ * @param off the offset of the next entry
+ * @return the space needed for the entry
+ */
+size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
+			 const char *name, const struct stat *stbuf,
+			 off64_t off);
+
+/**
+ * Reply to ask for data fetch and output buffer preparation.  ioctl
+ * will be retried with the specified input data fetched and output
+ * buffer prepared.
+ *
+ * Possible requests:
+ *   ioctl
+ *
+ * @param req request handle
+ * @param in_iov iovec specifying data to fetch from the caller
+ * @param in_count number of entries in in_iov
+ * @param out_iov iovec specifying addresses to write output to
+ * @param out_count number of entries in out_iov
+ * @return zero for success, -errno for failure to send reply
+ */
+int fuse_reply_ioctl_retry(fuse_req_t req,
+			   const struct iovec *in_iov, size_t in_count,
+			   const struct iovec *out_iov, size_t out_count);
+
+/**
+ * Reply to finish ioctl
+ *
+ * Possible requests:
+ *   ioctl
+ *
+ * @param req request handle
+ * @param result result to be passed to the caller
+ * @param buf buffer containing output data
+ * @param size length of output data
+ */
+int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size);
+
+/**
+ * Reply to finish ioctl with iov buffer
+ *
+ * Possible requests:
+ *   ioctl
+ *
+ * @param req request handle
+ * @param result result to be passed to the caller
+ * @param iov the vector containing the data
+ * @param count the size of vector
+ */
+int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov,
+			 int count);
+
+/**
+ * Reply with poll result event mask
+ *
+ * @param req request handle
+ * @param revents poll result event mask
+ */
+int fuse_reply_poll(fuse_req_t req, unsigned revents);
+
+/* ----------------------------------------------------------- *
+ * Notification						       *
+ * ----------------------------------------------------------- */
+
+/**
+ * Notify IO readiness event
+ *
+ * For more information, please read comment for poll operation.
+ *
+ * @param ph poll handle to notify IO readiness event for
+ */
+int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph);
+
+/**
+ * Notify to invalidate cache for an inode
+ *
+ * @param ch the channel through which to send the invalidation
+ * @param ino the inode number
+ * @param off the offset in the inode where to start invalidating
+ *            or negative to invalidate attributes only
+ * @param len the amount of cache to invalidate or 0 for all
+ * @return zero for success, -errno for failure
+ */
+int fuse_lowlevel_notify_inval_inode(struct fuse_chan *ch, fuse_ino_t ino,
+                                     off64_t off, off64_t len);
+
+/**
+ * Notify to invalidate parent attributes and the dentry matching
+ * parent/name
+ *
+ * @param ch the channel through which to send the invalidation
+ * @param parent inode number
+ * @param name file name
+ * @param namelen strlen() of file name
+ * @return zero for success, -errno for failure
+ */
+int fuse_lowlevel_notify_inval_entry(struct fuse_chan *ch, fuse_ino_t parent,
+                                     const char *name, size_t namelen);
+
+/* ----------------------------------------------------------- *
+ * Utility functions					       *
+ * ----------------------------------------------------------- */
+
+/**
+ * Get the userdata from the request
+ *
+ * @param req request handle
+ * @return the user data passed to fuse_lowlevel_new()
+ */
+void *fuse_req_userdata(fuse_req_t req);
+
+/**
+ * Get the context from the request
+ *
+ * The pointer returned by this function will only be valid for the
+ * request's lifetime
+ *
+ * @param req request handle
+ * @return the context structure
+ */
+const struct fuse_ctx *fuse_req_ctx(fuse_req_t req);
+
+/**
+ * Get the current supplementary group IDs for the specified request
+ *
+ * Similar to the getgroups(2) system call, except the return value is
+ * always the total number of group IDs, even if it is larger than the
+ * specified size.
+ *
+ * The current fuse kernel module in linux (as of 2.6.30) doesn't pass
+ * the group list to userspace, hence this function needs to parse
+ * "/proc/$TID/task/$TID/status" to get the group IDs.
+ *
+ * This feature may not be supported on all operating systems.  In
+ * such a case this function will return -ENOSYS.
+ *
+ * @param req request handle
+ * @param size size of given array
+ * @param list array of group IDs to be filled in
+ * @return the total number of supplementary group IDs or -errno on failure
+ */
+int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[]);
+
+/**
+ * Callback function for an interrupt
+ *
+ * @param req interrupted request
+ * @param data user data
+ */
+typedef void (*fuse_interrupt_func_t)(fuse_req_t req, void *data);
+
+/**
+ * Register/unregister callback for an interrupt
+ *
+ * If an interrupt has already happened, then the callback function is
+ * called from within this function, hence it's not possible for
+ * interrupts to be lost.
+ *
+ * @param req request handle
+ * @param func the callback function or NULL for unregister
+ * @param data user data passed to the callback function
+ */
+void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,
+			     void *data);
+
+/**
+ * Check if a request has already been interrupted
+ *
+ * @param req request handle
+ * @return 1 if the request has been interrupted, 0 otherwise
+ */
+int fuse_req_interrupted(fuse_req_t req);
+
+/* ----------------------------------------------------------- *
+ * Filesystem setup					       *
+ * ----------------------------------------------------------- */
+
+/* Deprecated, don't use */
+int fuse_lowlevel_is_lib_option(const char *opt);
+
+/**
+ * Create a low level session
+ *
+ * @param args argument vector
+ * @param op the low level filesystem operations
+ * @param op_size sizeof(struct fuse_lowlevel_ops)
+ * @param userdata user data
+ * @return the created session object, or NULL on failure
+ */
+struct fuse_session *fuse_lowlevel_new(struct fuse_args *args,
+				       const struct fuse_lowlevel_ops *op,
+				       size_t op_size, void *userdata);
+
+/* ----------------------------------------------------------- *
+ * Session interface					       *
+ * ----------------------------------------------------------- */
+
+/**
+ * Session operations
+ *
+ * This is used in session creation
+ */
+struct fuse_session_ops {
+	/**
+	 * Hook to process a request (mandatory)
+	 *
+	 * @param data user data passed to fuse_session_new()
+	 * @param buf buffer containing the raw request
+	 * @param len request length
+	 * @param ch channel on which the request was received
+	 */
+	void (*process) (void *data, const char *buf, size_t len,
+			 struct fuse_chan *ch);
+
+	/**
+	 * Hook for session exit and reset (optional)
+	 *
+	 * @param data user data passed to fuse_session_new()
+	 * @param val exited status (1 - exited, 0 - not exited)
+	 */
+	void (*exit) (void *data, int val);
+
+	/**
+	 * Hook for querying the current exited status (optional)
+	 *
+	 * @param data user data passed to fuse_session_new()
+	 * @return 1 if exited, 0 if not exited
+	 */
+	int (*exited) (void *data);
+
+	/**
+	 * Hook for cleaning up the channel on destroy (optional)
+	 *
+	 * @param data user data passed to fuse_session_new()
+	 */
+	void (*destroy) (void *data);
+};
+
+/**
+ * Create a new session
+ *
+ * @param op session operations
+ * @param data user data
+ * @return new session object, or NULL on failure
+ */
+struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data);
+
+/**
+ * Assign a channel to a session
+ *
+ * Note: currently only a single channel may be assigned.  This may
+ * change in the future
+ *
+ * If a session is destroyed, the assigned channel is also destroyed
+ *
+ * @param se the session
+ * @param ch the channel
+ */
+void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch);
+
+/**
+ * Remove a channel from a session
+ *
+ * If the channel is not assigned to a session, then this is a no-op
+ *
+ * @param ch the channel to remove
+ */
+void fuse_session_remove_chan(struct fuse_chan *ch);
+
+/**
+ * Iterate over the channels assigned to a session
+ *
+ * The iterating function needs to start with a NULL channel, and
+ * after that needs to pass the previously returned channel to the
+ * function.
+ *
+ * @param se the session
+ * @param ch the previous channel, or NULL
+ * @return the next channel, or NULL if no more channels exist
+ */
+struct fuse_chan *fuse_session_next_chan(struct fuse_session *se,
+					 struct fuse_chan *ch);
+
+/**
+ * Process a raw request
+ *
+ * @param se the session
+ * @param buf buffer containing the raw request
+ * @param len request length
+ * @param ch channel on which the request was received
+ */
+void fuse_session_process(struct fuse_session *se, const char *buf, size_t len,
+			  struct fuse_chan *ch);
+
+/**
+ * Destroy a session
+ *
+ * @param se the session
+ */
+void fuse_session_destroy(struct fuse_session *se);
+
+/**
+ * Exit a session
+ *
+ * @param se the session
+ */
+void fuse_session_exit(struct fuse_session *se);
+
+/**
+ * Reset the exited status of a session
+ *
+ * @param se the session
+ */
+void fuse_session_reset(struct fuse_session *se);
+
+/**
+ * Query the exited status of a session
+ *
+ * @param se the session
+ * @return 1 if exited, 0 if not exited
+ */
+int fuse_session_exited(struct fuse_session *se);
+
+/**
+ * Get the user data provided to the session
+ *
+ * @param se the session
+ * @return the user data
+ */
+void *fuse_session_data(struct fuse_session *se);
+
+/**
+ * Enter a single threaded event loop
+ *
+ * @param se the session
+ * @return 0 on success, -1 on error
+ */
+int fuse_session_loop(struct fuse_session *se);
+
+/**
+ * Enter a multi-threaded event loop
+ *
+ * @param se the session
+ * @return 0 on success, -1 on error
+ */
+int fuse_session_loop_mt(struct fuse_session *se);
+
+/* ----------------------------------------------------------- *
+ * Channel interface					       *
+ * ----------------------------------------------------------- */
+
+/**
+ * Channel operations
+ *
+ * This is used in channel creation
+ */
+struct fuse_chan_ops {
+	/**
+	 * Hook for receiving a raw request
+	 *
+	 * @param ch pointer to the channel
+	 * @param buf the buffer to store the request in
+	 * @param size the size of the buffer
+	 * @return the actual size of the raw request, or -1 on error
+	 */
+	int (*receive)(struct fuse_chan **chp, char *buf, size_t size);
+
+	/**
+	 * Hook for sending a raw reply
+	 *
+	 * A return value of -ENOENT means, that the request was
+	 * interrupted, and the reply was discarded
+	 *
+	 * @param ch the channel
+	 * @param iov vector of blocks
+	 * @param count the number of blocks in vector
+	 * @return zero on success, -errno on failure
+	 */
+	int (*send)(struct fuse_chan *ch, const struct iovec iov[],
+		    size_t count);
+
+	/**
+	 * Destroy the channel
+	 *
+	 * @param ch the channel
+	 */
+	void (*destroy)(struct fuse_chan *ch);
+};
+
+/**
+ * Create a new channel
+ *
+ * @param op channel operations
+ * @param fd file descriptor of the channel
+ * @param bufsize the minimal receive buffer size
+ * @param data user data
+ * @return the new channel object, or NULL on failure
+ */
+struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd,
+				size_t bufsize, void *data);
+
+/**
+ * Query the file descriptor of the channel
+ *
+ * @param ch the channel
+ * @return the file descriptor passed to fuse_chan_new()
+ */
+int fuse_chan_fd(struct fuse_chan *ch);
+
+/**
+ * Query the minimal receive buffer size
+ *
+ * @param ch the channel
+ * @return the buffer size passed to fuse_chan_new()
+ */
+size_t fuse_chan_bufsize(struct fuse_chan *ch);
+
+/**
+ * Query the user data
+ *
+ * @param ch the channel
+ * @return the user data passed to fuse_chan_new()
+ */
+void *fuse_chan_data(struct fuse_chan *ch);
+
+/**
+ * Query the session to which this channel is assigned
+ *
+ * @param ch the channel
+ * @return the session, or NULL if the channel is not assigned
+ */
+struct fuse_session *fuse_chan_session(struct fuse_chan *ch);
+
+/**
+ * Receive a raw request
+ *
+ * A return value of -ENODEV means, that the filesystem was unmounted
+ *
+ * @param ch pointer to the channel
+ * @param buf the buffer to store the request in
+ * @param size the size of the buffer
+ * @return the actual size of the raw request, or -errno on error
+ */
+int fuse_chan_recv(struct fuse_chan **ch, char *buf, size_t size);
+
+/**
+ * Send a raw reply
+ *
+ * A return value of -ENOENT means, that the request was
+ * interrupted, and the reply was discarded
+ *
+ * @param ch the channel
+ * @param iov vector of blocks
+ * @param count the number of blocks in vector
+ * @return zero on success, -errno on failure
+ */
+int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[],
+		   size_t count);
+
+/**
+ * Destroy a channel
+ *
+ * @param ch the channel
+ */
+void fuse_chan_destroy(struct fuse_chan *ch);
+
+/* ----------------------------------------------------------- *
+ * Compatibility stuff					       *
+ * ----------------------------------------------------------- */
+
+#if FUSE_USE_VERSION < 26
+#  include "fuse_lowlevel_compat.h"
+#  define fuse_chan_ops fuse_chan_ops_compat24
+#  define fuse_chan_new fuse_chan_new_compat24
+#  if FUSE_USE_VERSION == 25
+#    define fuse_lowlevel_ops fuse_lowlevel_ops_compat25
+#    define fuse_lowlevel_new fuse_lowlevel_new_compat25
+#  elif FUSE_USE_VERSION == 24
+#    define fuse_lowlevel_ops fuse_lowlevel_ops_compat
+#    define fuse_lowlevel_new fuse_lowlevel_new_compat
+#    define fuse_file_info fuse_file_info_compat
+#    define fuse_reply_statfs fuse_reply_statfs_compat
+#    define fuse_reply_open fuse_reply_open_compat
+#  else
+#    error Compatibility with low-level API version < 24 not supported
+#  endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FUSE_LOWLEVEL_H_ */
diff --git a/fuse/include/fuse_lowlevel_compat.h b/fuse/include/fuse_lowlevel_compat.h
new file mode 100644
index 0000000..3d2902d
--- /dev/null
+++ b/fuse/include/fuse_lowlevel_compat.h
@@ -0,0 +1,155 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB.
+*/
+
+/* these definitions provide source compatibility to prior versions.
+   Do not include this file directly! */
+
+struct fuse_lowlevel_ops_compat25 {
+	void (*init) (void *userdata);
+	void (*destroy) (void *userdata);
+	void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name);
+	void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup);
+	void (*getattr) (fuse_req_t req, fuse_ino_t ino,
+			 struct fuse_file_info *fi);
+	void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr,
+			 int to_set, struct fuse_file_info *fi);
+	void (*readlink) (fuse_req_t req, fuse_ino_t ino);
+	void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name,
+		       mode_t mode, dev_t rdev);
+	void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name,
+		       mode_t mode);
+	void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name);
+	void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name);
+	void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent,
+			 const char *name);
+	void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name,
+			fuse_ino_t newparent, const char *newname);
+	void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
+		      const char *newname);
+	void (*open) (fuse_req_t req, fuse_ino_t ino,
+		      struct fuse_file_info *fi);
+	void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off64_t off,
+		      struct fuse_file_info *fi);
+	void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf,
+		       size_t size, off64_t off, struct fuse_file_info *fi);
+	void (*flush) (fuse_req_t req, fuse_ino_t ino,
+		       struct fuse_file_info *fi);
+	void (*release) (fuse_req_t req, fuse_ino_t ino,
+			 struct fuse_file_info *fi);
+	void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync,
+		       struct fuse_file_info *fi);
+	void (*opendir) (fuse_req_t req, fuse_ino_t ino,
+			 struct fuse_file_info *fi);
+	void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off64_t off,
+			 struct fuse_file_info *fi);
+	void (*releasedir) (fuse_req_t req, fuse_ino_t ino,
+			    struct fuse_file_info *fi);
+	void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync,
+			  struct fuse_file_info *fi);
+	void (*statfs) (fuse_req_t req);
+	void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
+			  const char *value, size_t size, int flags);
+	void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
+			  size_t size);
+	void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size);
+	void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name);
+	void (*access) (fuse_req_t req, fuse_ino_t ino, int mask);
+	void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name,
+			mode_t mode, struct fuse_file_info *fi);
+};
+
+struct fuse_session *fuse_lowlevel_new_compat25(struct fuse_args *args,
+				const struct fuse_lowlevel_ops_compat25 *op,
+				size_t op_size, void *userdata);
+
+size_t fuse_dirent_size(size_t namelen);
+
+char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf,
+		      off64_t off);
+
+#ifndef __FreeBSD__
+
+#include <sys/statfs.h>
+
+struct fuse_lowlevel_ops_compat {
+	void (*init) (void *userdata);
+	void (*destroy) (void *userdata);
+	void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name);
+	void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup);
+	void (*getattr) (fuse_req_t req, fuse_ino_t ino,
+			 struct fuse_file_info_compat *fi);
+	void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr,
+			 int to_set, struct fuse_file_info_compat *fi);
+	void (*readlink) (fuse_req_t req, fuse_ino_t ino);
+	void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name,
+		       mode_t mode, dev_t rdev);
+	void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name,
+		       mode_t mode);
+	void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name);
+	void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name);
+	void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent,
+			 const char *name);
+	void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name,
+			fuse_ino_t newparent, const char *newname);
+	void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
+		      const char *newname);
+	void (*open) (fuse_req_t req, fuse_ino_t ino,
+		      struct fuse_file_info_compat *fi);
+	void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off64_t off,
+		      struct fuse_file_info_compat *fi);
+	void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf,
+		       size_t size, off64_t off, struct fuse_file_info_compat *fi);
+	void (*flush) (fuse_req_t req, fuse_ino_t ino,
+		       struct fuse_file_info_compat *fi);
+	void (*release) (fuse_req_t req, fuse_ino_t ino,
+			 struct fuse_file_info_compat *fi);
+	void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync,
+		       struct fuse_file_info_compat *fi);
+	void (*opendir) (fuse_req_t req, fuse_ino_t ino,
+			 struct fuse_file_info_compat *fi);
+	void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off64_t off,
+			 struct fuse_file_info_compat *fi);
+	void (*releasedir) (fuse_req_t req, fuse_ino_t ino,
+			    struct fuse_file_info_compat *fi);
+	void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync,
+			  struct fuse_file_info_compat *fi);
+	void (*statfs) (fuse_req_t req);
+	void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
+			  const char *value, size_t size, int flags);
+	void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
+			  size_t size);
+	void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size);
+	void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name);
+	void (*access) (fuse_req_t req, fuse_ino_t ino, int mask);
+	void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name,
+			mode_t mode, struct fuse_file_info_compat *fi);
+};
+
+int fuse_reply_statfs_compat(fuse_req_t req, const struct statfs *stbuf);
+
+int fuse_reply_open_compat(fuse_req_t req,
+			   const struct fuse_file_info_compat *fi);
+
+struct fuse_session *fuse_lowlevel_new_compat(const char *opts,
+				const struct fuse_lowlevel_ops_compat *op,
+				size_t op_size, void *userdata);
+
+#endif /* __FreeBSD__ */
+
+struct fuse_chan_ops_compat24 {
+	int (*receive)(struct fuse_chan *ch, char *buf, size_t size);
+	int (*send)(struct fuse_chan *ch, const struct iovec iov[],
+		    size_t count);
+	void (*destroy)(struct fuse_chan *ch);
+};
+
+struct fuse_chan *fuse_chan_new_compat24(struct fuse_chan_ops_compat24 *op,
+					 int fd, size_t bufsize, void *data);
+
+int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size);
+struct fuse_chan *fuse_kern_chan_new(int fd);
diff --git a/fuse/include/fuse_opt.h b/fuse/include/fuse_opt.h
new file mode 100644
index 0000000..8c08d77
--- /dev/null
+++ b/fuse/include/fuse_opt.h
@@ -0,0 +1,270 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB.
+*/
+
+#ifndef _FUSE_OPT_H_
+#define _FUSE_OPT_H_
+
+/** @file
+ *
+ * This file defines the option parsing interface of FUSE
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Option description
+ *
+ * This structure describes a single option, and and action associated
+ * with it, in case it matches.
+ *
+ * More than one such match may occur, in which case the action for
+ * each match is executed.
+ *
+ * There are three possible actions in case of a match:
+ *
+ * i) An integer (int or unsigned) variable determined by 'offset' is
+ *    set to 'value'
+ *
+ * ii) The processing function is called, with 'value' as the key
+ *
+ * iii) An integer (any) or string (char *) variable determined by
+ *    'offset' is set to the value of an option parameter
+ *
+ * 'offset' should normally be either set to
+ *
+ *  - 'offsetof(struct foo, member)'  actions i) and iii)
+ *
+ *  - -1			      action ii)
+ *
+ * The 'offsetof()' macro is defined in the <stddef.h> header.
+ *
+ * The template determines which options match, and also have an
+ * effect on the action.  Normally the action is either i) or ii), but
+ * if a format is present in the template, then action iii) is
+ * performed.
+ *
+ * The types of templates are:
+ *
+ * 1) "-x", "-foo", "--foo", "--foo-bar", etc.	These match only
+ *   themselves.  Invalid values are "--" and anything beginning
+ *   with "-o"
+ *
+ * 2) "foo", "foo-bar", etc.  These match "-ofoo", "-ofoo-bar" or
+ *    the relevant option in a comma separated option list
+ *
+ * 3) "bar=", "--foo=", etc.  These are variations of 1) and 2)
+ *    which have a parameter
+ *
+ * 4) "bar=%s", "--foo=%lu", etc.  Same matching as above but perform
+ *    action iii).
+ *
+ * 5) "-x ", etc.  Matches either "-xparam" or "-x param" as
+ *    two separate arguments
+ *
+ * 6) "-x %s", etc.  Combination of 4) and 5)
+ *
+ * If the format is "%s", memory is allocated for the string unlike
+ * with scanf().
+ */
+struct fuse_opt {
+	/** Matching template and optional parameter formatting */
+	const char *templ;
+
+	/**
+	 * Offset of variable within 'data' parameter of fuse_opt_parse()
+	 * or -1
+	 */
+	unsigned long offset;
+
+	/**
+	 * Value to set the variable to, or to be passed as 'key' to the
+	 * processing function.	 Ignored if template has a format
+	 */
+	int value;
+};
+
+/**
+ * Key option.	In case of a match, the processing function will be
+ * called with the specified key.
+ */
+#define FUSE_OPT_KEY(templ, key) { templ, -1U, key }
+
+/**
+ * Last option.	 An array of 'struct fuse_opt' must end with a NULL
+ * template value
+ */
+#define FUSE_OPT_END { NULL, 0, 0 }
+
+/**
+ * Argument list
+ */
+struct fuse_args {
+	/** Argument count */
+	int argc;
+
+	/** Argument vector.  NULL terminated */
+	char **argv;
+
+	/** Is 'argv' allocated? */
+	int allocated;
+};
+
+/**
+ * Initializer for 'struct fuse_args'
+ */
+#define FUSE_ARGS_INIT(argc, argv) { argc, argv, 0 }
+
+/**
+ * Key value passed to the processing function if an option did not
+ * match any template
+ */
+#define FUSE_OPT_KEY_OPT     -1
+
+/**
+ * Key value passed to the processing function for all non-options
+ *
+ * Non-options are the arguments beginning with a charater other than
+ * '-' or all arguments after the special '--' option
+ */
+#define FUSE_OPT_KEY_NONOPT  -2
+
+/**
+ * Special key value for options to keep
+ *
+ * Argument is not passed to processing function, but behave as if the
+ * processing function returned 1
+ */
+#define FUSE_OPT_KEY_KEEP -3
+
+/**
+ * Special key value for options to discard
+ *
+ * Argument is not passed to processing function, but behave as if the
+ * processing function returned zero
+ */
+#define FUSE_OPT_KEY_DISCARD -4
+
+/**
+ * Processing function
+ *
+ * This function is called if
+ *    - option did not match any 'struct fuse_opt'
+ *    - argument is a non-option
+ *    - option did match and offset was set to -1
+ *
+ * The 'arg' parameter will always contain the whole argument or
+ * option including the parameter if exists.  A two-argument option
+ * ("-x foo") is always converted to single arguemnt option of the
+ * form "-xfoo" before this function is called.
+ *
+ * Options of the form '-ofoo' are passed to this function without the
+ * '-o' prefix.
+ *
+ * The return value of this function determines whether this argument
+ * is to be inserted into the output argument vector, or discarded.
+ *
+ * @param data is the user data passed to the fuse_opt_parse() function
+ * @param arg is the whole argument or option
+ * @param key determines why the processing function was called
+ * @param outargs the current output argument list
+ * @return -1 on error, 0 if arg is to be discarded, 1 if arg should be kept
+ */
+typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key,
+			       struct fuse_args *outargs);
+
+/**
+ * Option parsing function
+ *
+ * If 'args' was returned from a previous call to fuse_opt_parse() or
+ * it was constructed from
+ *
+ * A NULL 'args' is equivalent to an empty argument vector
+ *
+ * A NULL 'opts' is equivalent to an 'opts' array containing a single
+ * end marker
+ *
+ * A NULL 'proc' is equivalent to a processing function always
+ * returning '1'
+ *
+ * @param args is the input and output argument list
+ * @param data is the user data
+ * @param opts is the option description array
+ * @param proc is the processing function
+ * @return -1 on error, 0 on success
+ */
+int fuse_opt_parse(struct fuse_args *args, void *data,
+		   const struct fuse_opt opts[], fuse_opt_proc_t proc);
+
+/**
+ * Add an option to a comma separated option list
+ *
+ * @param opts is a pointer to an option list, may point to a NULL value
+ * @param opt is the option to add
+ * @return -1 on allocation error, 0 on success
+ */
+int fuse_opt_add_opt(char **opts, const char *opt);
+
+/**
+ * Add an option, escaping commas, to a comma separated option list
+ *
+ * @param opts is a pointer to an option list, may point to a NULL value
+ * @param opt is the option to add
+ * @return -1 on allocation error, 0 on success
+ */
+int fuse_opt_add_opt_escaped(char **opts, const char *opt);
+
+/**
+ * Add an argument to a NULL terminated argument vector
+ *
+ * @param args is the structure containing the current argument list
+ * @param arg is the new argument to add
+ * @return -1 on allocation error, 0 on success
+ */
+int fuse_opt_add_arg(struct fuse_args *args, const char *arg);
+
+/**
+ * Add an argument at the specified position in a NULL terminated
+ * argument vector
+ *
+ * Adds the argument to the N-th position.  This is useful for adding
+ * options at the beggining of the array which must not come after the
+ * special '--' option.
+ *
+ * @param args is the structure containing the current argument list
+ * @param pos is the position at which to add the argument
+ * @param arg is the new argument to add
+ * @return -1 on allocation error, 0 on success
+ */
+int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg);
+
+/**
+ * Free the contents of argument list
+ *
+ * The structure itself is not freed
+ *
+ * @param args is the structure containing the argument list
+ */
+void fuse_opt_free_args(struct fuse_args *args);
+
+
+/**
+ * Check if an option matches
+ *
+ * @param opts is the option description array
+ * @param opt is the option to match
+ * @return 1 if a match is found, 0 if not
+ */
+int fuse_opt_match(const struct fuse_opt opts[], const char *opt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FUSE_OPT_H_ */
diff --git a/fuse/include/old/fuse.h b/fuse/include/old/fuse.h
new file mode 100644
index 0000000..3db0945
--- /dev/null
+++ b/fuse/include/old/fuse.h
@@ -0,0 +1,9 @@
+/*
+   This header is for compatibility with older software using FUSE.
+
+   Please use 'pkg-config --cflags fuse' to set include path.  The
+   correct usage is still '#include <fuse.h>', not '#include
+   <fuse/fuse.h>'.
+*/
+
+#include "fuse/fuse.h"
diff --git a/fuse/include/stamp-h1 b/fuse/include/stamp-h1
new file mode 100644
index 0000000..b330768
--- /dev/null
+++ b/fuse/include/stamp-h1
@@ -0,0 +1 @@
+timestamp for include/config.h
diff --git a/fuse/include/sys/statvfs.h b/fuse/include/sys/statvfs.h
new file mode 100644
index 0000000..6e3e39f
--- /dev/null
+++ b/fuse/include/sys/statvfs.h
@@ -0,0 +1,18 @@
+#ifndef __STATVFS_H
+#define __STATVFS_H
+
+struct statvfs {
+	unsigned long  f_bsize;    /* file system block size */
+	unsigned long  f_frsize;   /* fragment size */
+	fsblkcnt_t     f_blocks;   /* size of fs in f_frsize units */
+	fsblkcnt_t     f_bfree;    /* # free blocks */
+	fsblkcnt_t     f_bavail;   /* # free blocks for non-root */
+	fsfilcnt_t     f_files;    /* # inodes */
+	fsfilcnt_t     f_ffree;    /* # free inodes */
+	fsfilcnt_t     f_favail;   /* # free inodes for non-root */
+	unsigned long  f_fsid;     /* file system ID */
+	unsigned long  f_flag;     /* mount flags */
+	unsigned long  f_namemax;  /* maximum filename length */
+};
+
+#endif
diff --git a/fuse/include/ulockmgr.h b/fuse/include/ulockmgr.h
new file mode 100644
index 0000000..ad55579
--- /dev/null
+++ b/fuse/include/ulockmgr.h
@@ -0,0 +1,24 @@
+/*
+  libulockmgr: Userspace Lock Manager Library
+  Copyright (C) 2006  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB.
+*/
+
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/types.h>
+
+/**
+ * Perform POSIX locking operation
+ *
+ * @param fd the file descriptor
+ * @param cmd the locking command (F_GETFL, F_SETLK or F_SETLKW)
+ * @param lock the lock parameters
+ * @param owner the lock owner ID cookie
+ * @param owner_len length of the lock owner ID cookie
+ * @return 0 on success -errno on error
+ */
+int ulockmgr_op(int fd, int cmd, struct flock *lock, const void *owner,
+		size_t owner_len);
diff --git a/fuse/mount.c b/fuse/mount.c
new file mode 100644
index 0000000..88ab597
--- /dev/null
+++ b/fuse/mount.c
@@ -0,0 +1,596 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB.
+*/
+
+#include "config.h"
+#include "fuse_i.h"
+#include "fuse_misc.h"
+#include "fuse_opt.h"
+#include "fuse_common_compat.h"
+#include "mount_util.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <sys/mount.h>
+
+#define FUSERMOUNT_PROG		"fusermount"
+#define FUSE_COMMFD_ENV		"_FUSE_COMMFD"
+
+#ifndef HAVE_FORK
+#define fork() vfork()
+#endif
+
+#ifndef MS_DIRSYNC
+#define MS_DIRSYNC 128
+#endif
+
+enum {
+	KEY_KERN_FLAG,
+	KEY_KERN_OPT,
+	KEY_FUSERMOUNT_OPT,
+	KEY_SUBTYPE_OPT,
+	KEY_MTAB_OPT,
+	KEY_ALLOW_ROOT,
+	KEY_RO,
+	KEY_HELP,
+	KEY_VERSION,
+};
+
+struct mount_opts {
+	int allow_other;
+	int allow_root;
+	int ishelp;
+	int flags;
+	int nonempty;
+	int blkdev;
+	char *fsname;
+	char *subtype;
+	char *subtype_opt;
+	char *mtab_opts;
+	char *fusermount_opts;
+	char *kernel_opts;
+};
+
+#define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 }
+
+static const struct fuse_opt fuse_mount_opts[] = {
+	FUSE_MOUNT_OPT("allow_other",		allow_other),
+	FUSE_MOUNT_OPT("allow_root",		allow_root),
+	FUSE_MOUNT_OPT("nonempty",		nonempty),
+	FUSE_MOUNT_OPT("blkdev",		blkdev),
+	FUSE_MOUNT_OPT("fsname=%s",		fsname),
+	FUSE_MOUNT_OPT("subtype=%s",		subtype),
+	FUSE_OPT_KEY("allow_other",		KEY_KERN_OPT),
+	FUSE_OPT_KEY("allow_root",		KEY_ALLOW_ROOT),
+	FUSE_OPT_KEY("nonempty",		KEY_FUSERMOUNT_OPT),
+	FUSE_OPT_KEY("blkdev",			KEY_FUSERMOUNT_OPT),
+	FUSE_OPT_KEY("fsname=",			KEY_FUSERMOUNT_OPT),
+	FUSE_OPT_KEY("subtype=",		KEY_SUBTYPE_OPT),
+	FUSE_OPT_KEY("large_read",		KEY_KERN_OPT),
+	FUSE_OPT_KEY("blksize=",		KEY_KERN_OPT),
+	FUSE_OPT_KEY("default_permissions",	KEY_KERN_OPT),
+	FUSE_OPT_KEY("max_read=",		KEY_KERN_OPT),
+	FUSE_OPT_KEY("max_read=",		FUSE_OPT_KEY_KEEP),
+	FUSE_OPT_KEY("user=",			KEY_MTAB_OPT),
+	FUSE_OPT_KEY("-r",			KEY_RO),
+	FUSE_OPT_KEY("ro",			KEY_KERN_FLAG),
+	FUSE_OPT_KEY("rw",			KEY_KERN_FLAG),
+	FUSE_OPT_KEY("suid",			KEY_KERN_FLAG),
+	FUSE_OPT_KEY("nosuid",			KEY_KERN_FLAG),
+	FUSE_OPT_KEY("dev",			KEY_KERN_FLAG),
+	FUSE_OPT_KEY("nodev",			KEY_KERN_FLAG),
+	FUSE_OPT_KEY("exec",			KEY_KERN_FLAG),
+	FUSE_OPT_KEY("noexec",			KEY_KERN_FLAG),
+	FUSE_OPT_KEY("async",			KEY_KERN_FLAG),
+	FUSE_OPT_KEY("sync",			KEY_KERN_FLAG),
+	FUSE_OPT_KEY("dirsync",			KEY_KERN_FLAG),
+	FUSE_OPT_KEY("atime",			KEY_KERN_FLAG),
+	FUSE_OPT_KEY("noatime",			KEY_KERN_FLAG),
+	FUSE_OPT_KEY("-h",			KEY_HELP),
+	FUSE_OPT_KEY("--help",			KEY_HELP),
+	FUSE_OPT_KEY("-V",			KEY_VERSION),
+	FUSE_OPT_KEY("--version",		KEY_VERSION),
+	FUSE_OPT_END
+};
+
+static void mount_help(void)
+{
+	fprintf(stderr,
+"    -o allow_other         allow access to other users\n"
+"    -o allow_root          allow access to root\n"
+"    -o nonempty            allow mounts over non-empty file/dir\n"
+"    -o default_permissions enable permission checking by kernel\n"
+"    -o fsname=NAME         set filesystem name\n"
+"    -o subtype=NAME        set filesystem type\n"
+"    -o large_read          issue large read requests (2.4 only)\n"
+"    -o max_read=N          set maximum size of read requests\n"
+"\n");
+}
+
+#define FUSERMOUNT_DIR "/usr/bin"
+
+static void exec_fusermount(const char *argv[])
+{
+	execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG, (char **) argv);
+	execvp(FUSERMOUNT_PROG, (char **) argv);
+}
+
+static void mount_version(void)
+{
+	int pid = fork();
+	if (!pid) {
+		const char *argv[] = { FUSERMOUNT_PROG, "--version", NULL };
+		exec_fusermount(argv);
+		_exit(1);
+	} else if (pid != -1)
+		waitpid(pid, NULL, 0);
+}
+
+struct mount_flags {
+	const char *opt;
+	unsigned long flag;
+	int on;
+};
+
+static struct mount_flags mount_flags[] = {
+	{"rw",	    MS_RDONLY,	    0},
+	{"ro",	    MS_RDONLY,	    1},
+	{"suid",    MS_NOSUID,	    0},
+	{"nosuid",  MS_NOSUID,	    1},
+	{"dev",	    MS_NODEV,	    0},
+	{"nodev",   MS_NODEV,	    1},
+	{"exec",    MS_NOEXEC,	    0},
+	{"noexec",  MS_NOEXEC,	    1},
+	{"async",   MS_SYNCHRONOUS, 0},
+	{"sync",    MS_SYNCHRONOUS, 1},
+	{"atime",   MS_NOATIME,	    0},
+	{"noatime", MS_NOATIME,	    1},
+	{"dirsync", MS_DIRSYNC,	    1},
+	{NULL,	    0,		    0}
+};
+
+static void set_mount_flag(const char *s, int *flags)
+{
+	int i;
+
+	for (i = 0; mount_flags[i].opt != NULL; i++) {
+		const char *opt = mount_flags[i].opt;
+		if (strcmp(opt, s) == 0) {
+			if (mount_flags[i].on)
+				*flags |= mount_flags[i].flag;
+			else
+				*flags &= ~mount_flags[i].flag;
+			return;
+		}
+	}
+	fprintf(stderr, "fuse: internal error, can't find mount flag\n");
+	abort();
+}
+
+static int fuse_mount_opt_proc(void *data, const char *arg, int key,
+			       struct fuse_args *outargs)
+{
+	struct mount_opts *mo = data;
+
+	switch (key) {
+	case KEY_ALLOW_ROOT:
+		if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 ||
+		    fuse_opt_add_arg(outargs, "-oallow_root") == -1)
+			return -1;
+		return 0;
+
+	case KEY_RO:
+		arg = "ro";
+		/* fall through */
+	case KEY_KERN_FLAG:
+		set_mount_flag(arg, &mo->flags);
+		return 0;
+
+	case KEY_KERN_OPT:
+		return fuse_opt_add_opt(&mo->kernel_opts, arg);
+
+	case KEY_FUSERMOUNT_OPT:
+		return fuse_opt_add_opt_escaped(&mo->fusermount_opts, arg);
+
+	case KEY_SUBTYPE_OPT:
+		return fuse_opt_add_opt(&mo->subtype_opt, arg);
+
+	case KEY_MTAB_OPT:
+		return fuse_opt_add_opt(&mo->mtab_opts, arg);
+
+	case KEY_HELP:
+		mount_help();
+		mo->ishelp = 1;
+		break;
+
+	case KEY_VERSION:
+		mount_version();
+		mo->ishelp = 1;
+		break;
+	}
+	return 1;
+}
+
+/* return value:
+ * >= 0	 => fd
+ * -1	 => error
+ */
+static int receive_fd(int fd)
+{
+	struct msghdr msg;
+	struct iovec iov;
+	char buf[1];
+	int rv;
+	size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)];
+	struct cmsghdr *cmsg;
+
+	iov.iov_base = buf;
+	iov.iov_len = 1;
+
+	msg.msg_name = 0;
+	msg.msg_namelen = 0;
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+	/* old BSD implementations should use msg_accrights instead of
+	 * msg_control; the interface is different. */
+	msg.msg_control = ccmsg;
+	msg.msg_controllen = sizeof(ccmsg);
+
+	while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
+	if (rv == -1) {
+		perror("recvmsg");
+		return -1;
+	}
+	if(!rv) {
+		/* EOF */
+		return -1;
+	}
+
+	cmsg = CMSG_FIRSTHDR(&msg);
+	if (!cmsg->cmsg_type == SCM_RIGHTS) {
+		fprintf(stderr, "got control message of unknown type %d\n",
+			cmsg->cmsg_type);
+		return -1;
+	}
+	return *(int*)CMSG_DATA(cmsg);
+}
+
+void fuse_kern_unmount(const char *mountpoint, int fd)
+{
+	int res;
+	int pid;
+
+	if (!mountpoint)
+		return;
+
+	if (fd != -1) {
+		struct pollfd pfd;
+
+		pfd.fd = fd;
+		pfd.events = 0;
+		res = poll(&pfd, 1, 0);
+		/* If file poll returns POLLERR on the device file descriptor,
+		   then the filesystem is already unmounted */
+		if (res == 1 && (pfd.revents & POLLERR))
+			return;
+
+		/* Need to close file descriptor, otherwise synchronous umount
+		   would recurse into filesystem, and deadlock */
+		close(fd);
+	}
+
+	if (geteuid() == 0) {
+		fuse_mnt_umount("fuse", mountpoint, mountpoint,  1);
+		return;
+	}
+
+	res = umount2(mountpoint, 2);
+	if (res == 0)
+		return;
+
+	pid = fork();
+	if(pid == -1)
+		return;
+
+	if(pid == 0) {
+		const char *argv[] = { FUSERMOUNT_PROG, "-u", "-q", "-z",
+				       "--", mountpoint, NULL };
+
+		exec_fusermount(argv);
+		_exit(1);
+	}
+	waitpid(pid, NULL, 0);
+}
+
+void fuse_unmount_compat22(const char *mountpoint)
+{
+	fuse_kern_unmount(mountpoint, -1);
+}
+
+static int fuse_mount_fusermount(const char *mountpoint, const char *opts,
+				 int quiet)
+{
+	int fds[2], pid;
+	int res;
+	int rv;
+
+	if (!mountpoint) {
+		fprintf(stderr, "fuse: missing mountpoint parameter\n");
+		return -1;
+	}
+
+	res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
+	if(res == -1) {
+		perror("fuse: socketpair() failed");
+		return -1;
+	}
+
+	pid = fork();
+	if(pid == -1) {
+		perror("fuse: fork() failed");
+		close(fds[0]);
+		close(fds[1]);
+		return -1;
+	}
+
+	if(pid == 0) {
+		char env[10];
+		const char *argv[32];
+		int a = 0;
+
+		if (quiet) {
+			int fd = open("/dev/null", O_RDONLY);
+			dup2(fd, 1);
+			dup2(fd, 2);
+		}
+
+		argv[a++] = FUSERMOUNT_PROG;
+		if (opts) {
+			argv[a++] = "-o";
+			argv[a++] = opts;
+		}
+		argv[a++] = "--";
+		argv[a++] = mountpoint;
+		argv[a++] = NULL;
+
+		close(fds[1]);
+		fcntl(fds[0], F_SETFD, 0);
+		snprintf(env, sizeof(env), "%i", fds[0]);
+		setenv(FUSE_COMMFD_ENV, env, 1);
+		exec_fusermount(argv);
+		perror("fuse: failed to exec fusermount");
+		_exit(1);
+	}
+
+	close(fds[0]);
+	rv = receive_fd(fds[1]);
+	close(fds[1]);
+	waitpid(pid, NULL, 0); /* bury zombie */
+
+	return rv;
+}
+
+int fuse_mount_compat22(const char *mountpoint, const char *opts)
+{
+	return fuse_mount_fusermount(mountpoint, opts, 0);
+}
+
+static int fuse_mount_sys(const char *mnt, struct mount_opts *mo,
+			  const char *mnt_opts)
+{
+	char tmp[128];
+	const char *devname = "/dev/fuse";
+	char *source = NULL;
+	char *type = NULL;
+	struct stat stbuf;
+	int fd;
+	int res;
+
+	if (!mnt) {
+		fprintf(stderr, "fuse: missing mountpoint parameter\n");
+		return -1;
+	}
+
+	res = stat(mnt, &stbuf);
+	if (res == -1) {
+		fprintf(stderr ,"fuse: failed to access mountpoint %s: %s\n",
+			mnt, strerror(errno));
+		return -1;
+	}
+
+	if (!mo->nonempty) {
+		res = fuse_mnt_check_empty("fuse", mnt, stbuf.st_mode,
+					   stbuf.st_size);
+		if (res == -1)
+			return -1;
+	}
+
+	fd = open(devname, O_RDWR);
+	if (fd == -1) {
+		if (errno == ENODEV || errno == ENOENT)
+			fprintf(stderr, "fuse: device not found, try 'modprobe fuse' first\n");
+		else
+			fprintf(stderr, "fuse: failed to open %s: %s\n",
+				devname, strerror(errno));
+		return -1;
+	}
+
+	snprintf(tmp, sizeof(tmp),  "fd=%i,rootmode=%o,user_id=%i,group_id=%i",
+		 fd, stbuf.st_mode & S_IFMT, getuid(), getgid());
+
+	res = fuse_opt_add_opt(&mo->kernel_opts, tmp);
+	if (res == -1)
+		goto out_close;
+
+	source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +
+			(mo->subtype ? strlen(mo->subtype) : 0) +
+			strlen(devname) + 32);
+
+	type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);
+	if (!type || !source) {
+		fprintf(stderr, "fuse: failed to allocate memory\n");
+		goto out_close;
+	}
+
+	strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
+	if (mo->subtype) {
+		strcat(type, ".");
+		strcat(type, mo->subtype);
+	}
+	strcpy(source,
+	       mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));
+
+	res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
+	if (res == -1 && errno == ENODEV && mo->subtype) {
+		/* Probably missing subtype support */
+		strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
+		if (mo->fsname) {
+			if (!mo->blkdev)
+				sprintf(source, "%s#%s", mo->subtype,
+					mo->fsname);
+		} else {
+			strcpy(source, type);
+		}
+		res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
+	}
+	if (res == -1) {
+		/*
+		 * Maybe kernel doesn't support unprivileged mounts, in this
+		 * case try falling back to fusermount
+		 */
+		if (errno == EPERM) {
+			res = -2;
+		} else {
+			int errno_save = errno;
+			if (mo->blkdev && errno == ENODEV &&
+			    !fuse_mnt_check_fuseblk())
+				fprintf(stderr,
+					"fuse: 'fuseblk' support missing\n");
+			else
+				fprintf(stderr, "fuse: mount failed: %s\n",
+					strerror(errno_save));
+		}
+
+		goto out_close;
+	}
+
+	if (geteuid() == 0) {
+		char *newmnt = fuse_mnt_resolve_path("fuse", mnt);
+		res = -1;
+		if (!newmnt)
+			goto out_umount;
+
+		res = fuse_mnt_add_mount("fuse", source, newmnt, type,
+					 mnt_opts);
+		free(newmnt);
+		if (res == -1)
+			goto out_umount;
+	}
+	free(type);
+	free(source);
+
+	return fd;
+
+out_umount:
+	umount2(mnt, 2); /* lazy umount */
+out_close:
+	free(type);
+	free(source);
+	close(fd);
+	return res;
+}
+
+static int get_mnt_flag_opts(char **mnt_optsp, int flags)
+{
+	int i;
+
+	if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1)
+		return -1;
+
+	for (i = 0; mount_flags[i].opt != NULL; i++) {
+		if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
+		    fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1)
+			return -1;
+	}
+	return 0;
+}
+
+int fuse_kern_mount(const char *mountpoint, struct fuse_args *args)
+{
+	struct mount_opts mo;
+	int res = -1;
+	char *mnt_opts = NULL;
+
+	memset(&mo, 0, sizeof(mo));
+	mo.flags = MS_NOSUID | MS_NODEV;
+
+	if (args &&
+	    fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
+		return -1;
+
+	if (mo.allow_other && mo.allow_root) {
+		fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n");
+		goto out;
+	}
+	res = 0;
+	if (mo.ishelp)
+		goto out;
+
+	res = -1;
+	if (get_mnt_flag_opts(&mnt_opts, mo.flags) == -1)
+		goto out;
+	if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1)
+		goto out;
+	if (mo.mtab_opts &&  fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1)
+		goto out;
+
+	res = fuse_mount_sys(mountpoint, &mo, mnt_opts);
+	if (res == -2) {
+		if (mo.fusermount_opts &&
+		    fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) == -1)
+			goto out;
+
+		if (mo.subtype) {
+			char *tmp_opts = NULL;
+
+			res = -1;
+			if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 ||
+			    fuse_opt_add_opt(&tmp_opts, mo.subtype_opt) == -1) {
+				free(tmp_opts);
+				goto out;
+			}
+
+			res = fuse_mount_fusermount(mountpoint, tmp_opts, 1);
+			free(tmp_opts);
+			if (res == -1)
+				res = fuse_mount_fusermount(mountpoint,
+							    mnt_opts, 0);
+		} else {
+			res = fuse_mount_fusermount(mountpoint, mnt_opts, 0);
+		}
+	}
+out:
+	free(mnt_opts);
+	free(mo.fsname);
+	free(mo.subtype);
+	free(mo.fusermount_opts);
+	free(mo.subtype_opt);
+	free(mo.kernel_opts);
+	free(mo.mtab_opts);
+	return res;
+}
+
+FUSE_SYMVER(".symver fuse_mount_compat22,fuse_mount@FUSE_2.2");
+FUSE_SYMVER(".symver fuse_unmount_compat22,fuse_unmount@FUSE_2.2");
diff --git a/fuse/mount_bsd.c b/fuse/mount_bsd.c
new file mode 100644
index 0000000..62443ac
--- /dev/null
+++ b/fuse/mount_bsd.c
@@ -0,0 +1,388 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2005-2008 Csaba Henk <csaba.henk@creo.hu>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB.
+*/
+
+#include "fuse_i.h"
+#include "fuse_misc.h"
+#include "fuse_opt.h"
+
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <paths.h>
+#include <limits.h>
+
+#define FUSERMOUNT_PROG		"mount_fusefs"
+#define FUSE_DEV_TRUNK		"/dev/fuse"
+
+enum {
+	KEY_ALLOW_ROOT,
+	KEY_RO,
+	KEY_HELP,
+	KEY_VERSION,
+	KEY_KERN
+};
+
+struct mount_opts {
+	int allow_other;
+	int allow_root;
+	int ishelp;
+	char *kernel_opts;
+};
+
+#define FUSE_DUAL_OPT_KEY(templ, key) 				\
+	FUSE_OPT_KEY(templ, key), FUSE_OPT_KEY("no" templ, key)
+
+static const struct fuse_opt fuse_mount_opts[] = {
+	{ "allow_other", offsetof(struct mount_opts, allow_other), 1 },
+	{ "allow_root", offsetof(struct mount_opts, allow_root), 1 },
+	FUSE_OPT_KEY("allow_root",		KEY_ALLOW_ROOT),
+	FUSE_OPT_KEY("-r",			KEY_RO),
+	FUSE_OPT_KEY("-h",			KEY_HELP),
+	FUSE_OPT_KEY("--help",			KEY_HELP),
+	FUSE_OPT_KEY("-V",			KEY_VERSION),
+	FUSE_OPT_KEY("--version",		KEY_VERSION),
+	/* standard FreeBSD mount options */
+	FUSE_DUAL_OPT_KEY("dev",		KEY_KERN),
+	FUSE_DUAL_OPT_KEY("async",		KEY_KERN),
+	FUSE_DUAL_OPT_KEY("atime",		KEY_KERN),
+	FUSE_DUAL_OPT_KEY("dev",		KEY_KERN),
+	FUSE_DUAL_OPT_KEY("exec",		KEY_KERN),
+	FUSE_DUAL_OPT_KEY("suid",		KEY_KERN),
+	FUSE_DUAL_OPT_KEY("symfollow",		KEY_KERN),
+	FUSE_DUAL_OPT_KEY("rdonly",		KEY_KERN),
+	FUSE_DUAL_OPT_KEY("sync",		KEY_KERN),
+	FUSE_DUAL_OPT_KEY("union",		KEY_KERN),
+	FUSE_DUAL_OPT_KEY("userquota",		KEY_KERN),
+	FUSE_DUAL_OPT_KEY("groupquota",		KEY_KERN),
+	FUSE_DUAL_OPT_KEY("clusterr",		KEY_KERN),
+	FUSE_DUAL_OPT_KEY("clusterw",		KEY_KERN),
+	FUSE_DUAL_OPT_KEY("suiddir",		KEY_KERN),
+	FUSE_DUAL_OPT_KEY("snapshot",		KEY_KERN),
+	FUSE_DUAL_OPT_KEY("multilabel",		KEY_KERN),
+	FUSE_DUAL_OPT_KEY("acls",		KEY_KERN),
+	FUSE_DUAL_OPT_KEY("force",		KEY_KERN),
+	FUSE_DUAL_OPT_KEY("update",		KEY_KERN),
+	FUSE_DUAL_OPT_KEY("ro",			KEY_KERN),
+	FUSE_DUAL_OPT_KEY("rw",			KEY_KERN),
+	FUSE_DUAL_OPT_KEY("auto",		KEY_KERN),
+	/* options supported under both Linux and FBSD */
+	FUSE_DUAL_OPT_KEY("allow_other",	KEY_KERN),
+	FUSE_DUAL_OPT_KEY("default_permissions",KEY_KERN),
+	FUSE_OPT_KEY("max_read=",		KEY_KERN),
+	FUSE_OPT_KEY("subtype=",		KEY_KERN),
+	/* FBSD FUSE specific mount options */
+	FUSE_DUAL_OPT_KEY("private",		KEY_KERN),
+	FUSE_DUAL_OPT_KEY("neglect_shares",	KEY_KERN),
+	FUSE_DUAL_OPT_KEY("push_symlinks_in",	KEY_KERN),
+	FUSE_OPT_KEY("nosync_unmount",		KEY_KERN),
+	/* stock FBSD mountopt parsing routine lets anything be negated... */
+	/*
+	 * Linux specific mount options, but let just the mount util
+	 * handle them
+	 */
+	FUSE_OPT_KEY("fsname=",			KEY_KERN),
+	FUSE_OPT_KEY("nonempty",		KEY_KERN),
+	FUSE_OPT_KEY("large_read",		KEY_KERN),
+	FUSE_OPT_END
+};
+
+static void mount_help(void)
+{
+	fprintf(stderr,
+		"    -o allow_root          allow access to root\n"
+		);
+	system(FUSERMOUNT_PROG " --help");
+	fputc('\n', stderr);
+}
+
+static void mount_version(void)
+{
+	system(FUSERMOUNT_PROG " --version");
+}
+
+static int fuse_mount_opt_proc(void *data, const char *arg, int key,
+			       struct fuse_args *outargs)
+{
+	struct mount_opts *mo = data;
+
+	switch (key) {
+	case KEY_ALLOW_ROOT:
+		if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 ||
+		    fuse_opt_add_arg(outargs, "-oallow_root") == -1)
+			return -1;
+		return 0;
+
+	case KEY_RO:
+		arg = "ro";
+		/* fall through */
+
+	case KEY_KERN:
+		return fuse_opt_add_opt(&mo->kernel_opts, arg);
+
+	case KEY_HELP:
+		mount_help();
+		mo->ishelp = 1;
+		break;
+
+	case KEY_VERSION:
+		mount_version();
+		mo->ishelp = 1;
+		break;
+	}
+	return 1;
+}
+
+void fuse_unmount_compat22(const char *mountpoint)
+{
+	char dev[128];
+	char *ssc, *umount_cmd;
+	FILE *sf;
+	int rv;
+	char seekscript[] =
+		/* error message is annoying in help output */
+		"exec 2>/dev/null; "
+		"/usr/bin/fstat " FUSE_DEV_TRUNK "* | "
+		"/usr/bin/awk 'BEGIN{ getline; if (! ($3 == \"PID\" && $10 == \"NAME\")) exit 1; }; "
+		"              { if ($3 == %d) print $10; }' | "
+		"/usr/bin/sort | "
+		"/usr/bin/uniq | "
+		"/usr/bin/awk '{ i += 1; if (i > 1){ exit 1; }; printf; }; END{ if (i == 0) exit 1; }'";
+
+	(void) mountpoint;
+
+	/*
+	 * If we don't know the fd, we have to resort to the scripted
+	 * solution -- iterating over the fd-s is unpractical, as we
+	 * don't know how many of open files we have. (This could be
+	 * looked up in procfs -- however, that's optional on FBSD; or
+	 * read out from the kmem -- however, that's bound to
+	 * privileges (in fact, that's what happens when we call the
+	 * setgid kmem fstat(1) utility).
+	 */
+	if (asprintf(&ssc, seekscript, getpid()) == -1)
+		return;
+
+	errno = 0;
+	sf = popen(ssc, "r");
+	free(ssc);
+	if (! sf)
+		return;
+
+	fgets(dev, sizeof(dev), sf);
+	rv = pclose(sf);
+	if (rv)
+		return;
+
+	if (asprintf(&umount_cmd, "/sbin/umount %s", dev) == -1)
+		return;
+	system(umount_cmd);
+	free(umount_cmd);
+}
+
+static void do_unmount(char *dev, int fd)
+{
+	char device_path[SPECNAMELEN + 12];
+	const char *argv[4];
+	const char umount_cmd[] = "/sbin/umount";
+	pid_t pid;
+
+	snprintf(device_path, SPECNAMELEN + 12, _PATH_DEV "%s", dev);
+
+	argv[0] = umount_cmd;
+	argv[1] = "-f";
+	argv[2] = device_path;
+	argv[3] = NULL;
+
+	pid = fork();
+
+	if (pid == -1)
+		return;
+
+	if (pid == 0) {
+		close(fd);
+		execvp(umount_cmd, (char **)argv);
+		exit(1);
+	}
+
+	waitpid(pid, NULL, 0);
+}
+
+void fuse_kern_unmount(const char *mountpoint, int fd)
+{
+	char *ep, dev[128];
+	struct stat sbuf;
+
+	(void)mountpoint;
+
+	if (fstat(fd, &sbuf) == -1)
+		return;
+
+	devname_r(sbuf.st_rdev, S_IFCHR, dev, 128);
+
+	if (strncmp(dev, "fuse", 4))
+		return;
+
+	strtol(dev + 4, &ep, 10);
+	if (*ep != '\0')
+		return;
+
+	do_unmount(dev, fd);
+}
+
+/* Check if kernel is doing init in background */
+static int init_backgrounded(void)
+{
+	unsigned ibg, len;
+
+	len = sizeof(ibg);
+
+	if (sysctlbyname("vfs.fuse.init_backgrounded", &ibg, &len, NULL, 0))
+		return 0;
+
+	return ibg;
+}
+
+
+static int fuse_mount_core(const char *mountpoint, const char *opts)
+{
+	const char *mountprog = FUSERMOUNT_PROG;
+	int fd;
+	char *fdnam, *dev;
+	pid_t pid, cpid;
+	int status;
+
+	fdnam = getenv("FUSE_DEV_FD");
+
+	if (fdnam) {
+		char *ep;
+
+		fd = strtol(fdnam, &ep, 10);
+
+		if (*ep != '\0') {
+			fprintf(stderr, "invalid value given in FUSE_DEV_FD\n");
+			return -1;
+		}
+
+		if (fd < 0)
+			return -1;
+
+		goto mount;
+	}
+
+	dev = getenv("FUSE_DEV_NAME");
+
+	if (! dev)
+		dev = (char *)FUSE_DEV_TRUNK;
+
+	if ((fd = open(dev, O_RDWR)) < 0) {
+		perror("fuse: failed to open fuse device");
+		return -1;
+	}
+
+mount:
+	if (getenv("FUSE_NO_MOUNT") || ! mountpoint)
+		goto out;
+
+	pid = fork();
+	cpid = pid;
+
+	if (pid == -1) {
+		perror("fuse: fork() failed");
+		close(fd);
+		return -1;
+	}
+
+	if (pid == 0) {
+		if (! init_backgrounded()) {
+			/*
+			 * If init is not backgrounded, we have to
+			 * call the mount util backgrounded, to avoid
+			 * deadlock.
+			 */
+
+			pid = fork();
+
+			if (pid == -1) {
+				perror("fuse: fork() failed");
+				close(fd);
+				exit(1);
+			}
+		}
+
+		if (pid == 0) {
+			const char *argv[32];
+			int a = 0;
+
+			if (! fdnam && asprintf(&fdnam, "%d", fd) == -1) {
+				perror("fuse: failed to assemble mount arguments");
+				exit(1);
+			}
+
+			argv[a++] = mountprog;
+			if (opts) {
+				argv[a++] = "-o";
+				argv[a++] = opts;
+			}
+			argv[a++] = fdnam;
+			argv[a++] = mountpoint;
+			argv[a++] = NULL;
+			execvp(mountprog, (char **) argv);
+			perror("fuse: failed to exec mount program");
+			exit(1);
+		}
+
+		exit(0);
+	}
+
+	if (waitpid(cpid, &status, 0) == -1 || WEXITSTATUS(status) != 0) {
+		perror("fuse: failed to mount file system");
+		close(fd);
+		return -1;
+	}
+
+out:
+	return fd;
+}
+
+int fuse_kern_mount(const char *mountpoint, struct fuse_args *args)
+{
+	struct mount_opts mo;
+	int res = -1;
+
+	memset(&mo, 0, sizeof(mo));
+	/* mount util should not try to spawn the daemon */
+	setenv("MOUNT_FUSEFS_SAFE", "1", 1);
+	/* to notify the mount util it's called from lib */
+	setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1);
+
+	if (args &&
+	    fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
+		return -1;
+
+	if (mo.allow_other && mo.allow_root) {
+		fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n");
+		goto out;
+	}
+	if (mo.ishelp)
+		return 0;
+
+	res = fuse_mount_core(mountpoint, mo.kernel_opts);
+out:
+	free(mo.kernel_opts);
+	return res;
+}
+
+FUSE_SYMVER(".symver fuse_unmount_compat22,fuse_unmount@FUSE_2.2");
diff --git a/fuse/mount_util.c b/fuse/mount_util.c
new file mode 100644
index 0000000..de1bd67
--- /dev/null
+++ b/fuse/mount_util.c
@@ -0,0 +1,363 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB.
+*/
+
+#include "mount_util.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <mntent.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/mount.h>
+#include <sys/param.h>
+
+#include <paths.h>
+
+static int mtab_needs_update(const char *mnt)
+{
+	int res;
+	struct stat stbuf;
+
+	/* If mtab is within new mount, don't touch it */
+	if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 &&
+	    _PATH_MOUNTED[strlen(mnt)] == '/')
+		return 0;
+
+	/*
+	 * Skip mtab update if /etc/mtab:
+	 *
+	 *  - doesn't exist,
+	 *  - is a symlink,
+	 *  - is on a read-only filesystem.
+	 */
+	res = lstat(_PATH_MOUNTED, &stbuf);
+	if (res == -1) {
+		if (errno == ENOENT)
+			return 0;
+	} else {
+		if (S_ISLNK(stbuf.st_mode))
+			return 0;
+
+		res = access(_PATH_MOUNTED, W_OK);
+		if (res == -1 && errno == EROFS)
+			return 0;
+	}
+
+	return 1;
+}
+
+static int add_mount_legacy(const char *progname, const char *fsname,
+			    const char *mnt, const char *type, const char *opts)
+{
+	int res;
+	int status;
+	sigset_t blockmask;
+	sigset_t oldmask;
+
+	sigemptyset(&blockmask);
+	sigaddset(&blockmask, SIGCHLD);
+	res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
+	if (res == -1) {
+		fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
+		return -1;
+	}
+
+	res = fork();
+	if (res == -1) {
+		fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
+		goto out_restore;
+	}
+	if (res == 0) {
+		char templ[] = "/tmp/fusermountXXXXXX";
+		char *tmp;
+
+		sigprocmask(SIG_SETMASK, &oldmask, NULL);
+		setuid(geteuid());
+
+		/*
+		 * hide in a directory, where mount isn't able to resolve
+		 * fsname as a valid path
+		 */
+		tmp = mkdtemp(templ);
+		if (!tmp) {
+			fprintf(stderr,
+				"%s: failed to create temporary directory\n",
+				progname);
+			exit(1);
+		}
+		if (chdir(tmp)) {
+			fprintf(stderr, "%s: failed to chdir to %s: %s\n",
+				progname, tmp, strerror(errno));
+			exit(1);
+		}
+		rmdir(tmp);
+		execl("/bin/mount", "/bin/mount", "-i", "-f", "-t", type,
+		      "-o", opts, fsname, mnt, NULL);
+		fprintf(stderr, "%s: failed to execute /bin/mount: %s\n",
+			progname, strerror(errno));
+		exit(1);
+	}
+	res = waitpid(res, &status, 0);
+	if (res == -1)
+		fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
+
+	if (status != 0)
+		res = -1;
+
+ out_restore:
+	sigprocmask(SIG_SETMASK, &oldmask, NULL);
+
+	return res;
+}
+
+static int add_mount(const char *progname, const char *fsname,
+		       const char *mnt, const char *type, const char *opts)
+{
+	int res;
+	int status;
+	sigset_t blockmask;
+	sigset_t oldmask;
+
+	sigemptyset(&blockmask);
+	sigaddset(&blockmask, SIGCHLD);
+	res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
+	if (res == -1) {
+		fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
+		return -1;
+	}
+
+	res = fork();
+	if (res == -1) {
+		fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
+		goto out_restore;
+	}
+	if (res == 0) {
+		/*
+		 * Hide output, because old versions don't support
+		 * --no-canonicalize
+		 */
+		int fd = open("/dev/null", O_RDONLY);
+		dup2(fd, 1);
+		dup2(fd, 2);
+
+		sigprocmask(SIG_SETMASK, &oldmask, NULL);
+		setuid(geteuid());
+		execl("/bin/mount", "/bin/mount", "--no-canonicalize", "-i",
+		      "-f", "-t", type, "-o", opts, fsname, mnt, NULL);
+		fprintf(stderr, "%s: failed to execute /bin/mount: %s\n",
+			progname, strerror(errno));
+		exit(1);
+	}
+	res = waitpid(res, &status, 0);
+	if (res == -1)
+		fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
+
+	if (status != 0)
+		res = -1;
+
+ out_restore:
+	sigprocmask(SIG_SETMASK, &oldmask, NULL);
+
+	return res;
+}
+
+int fuse_mnt_add_mount(const char *progname, const char *fsname,
+		       const char *mnt, const char *type, const char *opts)
+{
+	int res;
+
+	if (!mtab_needs_update(mnt))
+		return 0;
+
+	res = add_mount(progname, fsname, mnt, type, opts);
+	if (res == -1)
+		res = add_mount_legacy(progname, fsname, mnt, type, opts);
+
+	return res;
+}
+
+static int exec_umount(const char *progname, const char *rel_mnt, int lazy)
+{
+	int res;
+	int status;
+	sigset_t blockmask;
+	sigset_t oldmask;
+
+	sigemptyset(&blockmask);
+	sigaddset(&blockmask, SIGCHLD);
+	res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
+	if (res == -1) {
+		fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
+		return -1;
+	}
+
+	res = fork();
+	if (res == -1) {
+		fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
+		goto out_restore;
+	}
+	if (res == 0) {
+		sigprocmask(SIG_SETMASK, &oldmask, NULL);
+		setuid(geteuid());
+		execl("/bin/umount", "/bin/umount", "-i", rel_mnt,
+		      lazy ? "-l" : NULL, NULL);
+		fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
+			progname, strerror(errno));
+		exit(1);
+	}
+	res = waitpid(res, &status, 0);
+	if (res == -1)
+		fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
+
+	if (status != 0) {
+		res = -1;
+	}
+
+ out_restore:
+	sigprocmask(SIG_SETMASK, &oldmask, NULL);
+	return res;
+
+}
+
+int fuse_mnt_umount(const char *progname, const char *abs_mnt,
+		    const char *rel_mnt, int lazy)
+{
+	int res;
+
+	if (!mtab_needs_update(abs_mnt)) {
+		res = umount2(rel_mnt, lazy ? 2 : 0);
+		if (res == -1)
+			fprintf(stderr, "%s: failed to unmount %s: %s\n",
+				progname, abs_mnt, strerror(errno));
+		return res;
+	}
+
+	return exec_umount(progname, rel_mnt, lazy);
+}
+
+char *fuse_mnt_resolve_path(const char *progname, const char *orig)
+{
+	char buf[PATH_MAX];
+	char *copy;
+	char *dst;
+	char *end;
+	char *lastcomp;
+	const char *toresolv;
+
+	if (!orig[0]) {
+		fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname,
+			orig);
+		return NULL;
+	}
+
+	copy = strdup(orig);
+	if (copy == NULL) {
+		fprintf(stderr, "%s: failed to allocate memory\n", progname);
+		return NULL;
+	}
+
+	toresolv = copy;
+	lastcomp = NULL;
+	for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
+	if (end[0] != '/') {
+		char *tmp;
+		end[1] = '\0';
+		tmp = strrchr(copy, '/');
+		if (tmp == NULL) {
+			lastcomp = copy;
+			toresolv = ".";
+		} else {
+			lastcomp = tmp + 1;
+			if (tmp == copy)
+				toresolv = "/";
+		}
+		if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
+			lastcomp = NULL;
+			toresolv = copy;
+		}
+		else if (tmp)
+			tmp[0] = '\0';
+	}
+	if (realpath(toresolv, buf) == NULL) {
+		fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
+			strerror(errno));
+		free(copy);
+		return NULL;
+	}
+	if (lastcomp == NULL)
+		dst = strdup(buf);
+	else {
+		dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
+		if (dst) {
+			unsigned buflen = strlen(buf);
+			if (buflen && buf[buflen-1] == '/')
+				sprintf(dst, "%s%s", buf, lastcomp);
+			else
+				sprintf(dst, "%s/%s", buf, lastcomp);
+		}
+	}
+	free(copy);
+	if (dst == NULL)
+		fprintf(stderr, "%s: failed to allocate memory\n", progname);
+	return dst;
+}
+
+int fuse_mnt_check_empty(const char *progname, const char *mnt,
+			 mode_t rootmode, off64_t rootsize)
+{
+	int isempty = 1;
+
+	if (S_ISDIR(rootmode)) {
+		struct dirent *ent;
+		DIR *dp = opendir(mnt);
+		if (dp == NULL) {
+			fprintf(stderr,
+				"%s: failed to open mountpoint for reading: %s\n",
+				progname, strerror(errno));
+			return -1;
+		}
+		while ((ent = readdir(dp)) != NULL) {
+			if (strcmp(ent->d_name, ".") != 0 &&
+			    strcmp(ent->d_name, "..") != 0) {
+				isempty = 0;
+				break;
+			}
+		}
+		closedir(dp);
+	} else if (rootsize)
+		isempty = 0;
+
+	if (!isempty) {
+		fprintf(stderr, "%s: mountpoint is not empty\n", progname);
+		fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname);
+		return -1;
+	}
+	return 0;
+}
+
+int fuse_mnt_check_fuseblk(void)
+{
+	char buf[256];
+	FILE *f = fopen("/proc/filesystems", "r");
+	if (!f)
+		return 1;
+
+	while (fgets(buf, sizeof(buf), f))
+		if (strstr(buf, "fuseblk\n")) {
+			fclose(f);
+			return 1;
+		}
+
+	fclose(f);
+	return 0;
+}
diff --git a/fuse/mount_util.h b/fuse/mount_util.h
new file mode 100644
index 0000000..5c2fb8e
--- /dev/null
+++ b/fuse/mount_util.h
@@ -0,0 +1,18 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB.
+*/
+
+#include <sys/types.h>
+
+int fuse_mnt_add_mount(const char *progname, const char *fsname,
+		       const char *mnt, const char *type, const char *opts);
+int fuse_mnt_umount(const char *progname, const char *abs_mnt,
+		    const char *rel_mnt, int lazy);
+char *fuse_mnt_resolve_path(const char *progname, const char *orig);
+int fuse_mnt_check_empty(const char *progname, const char *mnt,
+			 mode_t rootmode, off64_t rootsize);
+int fuse_mnt_check_fuseblk(void);
diff --git a/fuse/ulockmgr.c b/fuse/ulockmgr.c
new file mode 100644
index 0000000..4a049d5
--- /dev/null
+++ b/fuse/ulockmgr.c
@@ -0,0 +1,440 @@
+/*
+  libulockmgr: Userspace Lock Manager Library
+  Copyright (C) 2006  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB
+*/
+
+/* #define DEBUG 1 */
+
+#include "ulockmgr.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <errno.h>
+#include <assert.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+
+struct message {
+	unsigned intr : 1;
+	unsigned nofd : 1;
+	pthread_t thr;
+	int cmd;
+	int fd;
+	struct flock lock;
+	int error;
+};
+
+struct fd_store {
+	struct fd_store *next;
+	int fd;
+	int inuse;
+};
+
+struct owner {
+	struct owner *next;
+	struct owner *prev;
+	struct fd_store *fds;
+	void *id;
+	size_t id_len;
+	int cfd;
+};
+
+static pthread_mutex_t ulockmgr_lock;
+static int ulockmgr_cfd = -1;
+static struct owner owner_list = { .next = &owner_list, .prev = &owner_list };
+
+#define MAX_SEND_FDS 2
+
+static void list_del_owner(struct owner *owner)
+{
+	struct owner *prev = owner->prev;
+	struct owner *next = owner->next;
+	prev->next = next;
+	next->prev = prev;
+}
+
+static void list_add_owner(struct owner *owner, struct owner *next)
+{
+	struct owner *prev = next->prev;
+	owner->next = next;
+	owner->prev = prev;
+	prev->next = owner;
+	next->prev = owner;
+}
+
+/*
+ * There's a bug in the linux kernel (< 2.6.22) recv() implementation
+ * on AF_UNIX, SOCK_STREAM sockets, that could cause it to return
+ * zero, even if data was available.  Retrying the recv will return
+ * the data in this case.
+ */
+static int do_recv(int sock, void *buf, size_t len, int flags)
+{
+	int res = recv(sock, buf, len, flags);
+	if (res == 0)
+		res = recv(sock, buf, len, flags);
+
+	return res;
+}
+
+static int ulockmgr_send_message(int sock, void *buf, size_t buflen,
+				 int *fdp, int numfds)
+{
+	struct msghdr msg;
+	struct cmsghdr *p_cmsg;
+	struct iovec vec;
+	size_t cmsgbuf[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)];
+	int res;
+
+	assert(numfds <= MAX_SEND_FDS);
+	msg.msg_control = cmsgbuf;
+	msg.msg_controllen = sizeof(cmsgbuf);
+	p_cmsg = CMSG_FIRSTHDR(&msg);
+	p_cmsg->cmsg_level = SOL_SOCKET;
+	p_cmsg->cmsg_type = SCM_RIGHTS;
+	p_cmsg->cmsg_len = CMSG_LEN(sizeof(int) * numfds);
+	memcpy(CMSG_DATA(p_cmsg), fdp, sizeof(int) * numfds);
+	msg.msg_controllen = p_cmsg->cmsg_len;
+	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
+	msg.msg_iov = &vec;
+	msg.msg_iovlen = 1;
+	msg.msg_flags = 0;
+	vec.iov_base = buf;
+	vec.iov_len = buflen;
+	res = sendmsg(sock, &msg, MSG_NOSIGNAL);
+	if (res == -1) {
+		perror("libulockmgr: sendmsg");
+		return -1;
+	}
+	if ((size_t) res != buflen) {
+		fprintf(stderr, "libulockmgr: sendmsg short\n");
+		return -1;
+	}
+	return 0;
+}
+
+static int ulockmgr_start_daemon(void)
+{
+	int sv[2];
+	int res;
+	char tmp[64];
+
+	res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
+	if (res == -1) {
+		perror("libulockmgr: socketpair");
+		return -1;
+	}
+	snprintf(tmp, sizeof(tmp), "exec ulockmgr_server %i", sv[0]);
+	res = system(tmp);
+	close(sv[0]);
+	if (res == -1 || !WIFEXITED(res) || WEXITSTATUS(res) != 0) {
+		close(sv[1]);
+		return -1;
+	}
+	ulockmgr_cfd = sv[1];
+	return 0;
+}
+
+static struct owner *ulockmgr_new_owner(const void *id, size_t id_len)
+{
+	int sv[2];
+	int res;
+	char c = 'm';
+	struct owner *o;
+
+	if (ulockmgr_cfd == -1 && ulockmgr_start_daemon() == -1)
+		return NULL;
+
+	o = calloc(1, sizeof(struct owner) + id_len);
+	if (!o) {
+		fprintf(stderr, "libulockmgr: failed to allocate memory\n");
+		return NULL;
+	}
+	o->id = o + 1;
+	o->id_len = id_len;
+	res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
+	if (res == -1) {
+		perror("libulockmgr: socketpair");
+		goto out_free;
+	}
+	res = ulockmgr_send_message(ulockmgr_cfd, &c, sizeof(c), &sv[0], 1);
+	close(sv[0]);
+	if (res == -1) {
+		close(ulockmgr_cfd);
+		ulockmgr_cfd = -1;
+		goto out_close;
+	}
+
+	o->cfd = sv[1];
+	memcpy(o->id, id, id_len);
+	list_add_owner(o, &owner_list);
+
+	return o;
+
+out_close:
+	close(sv[1]);
+out_free:
+	free(o);
+	return NULL;
+}
+
+static int ulockmgr_send_request(struct message *msg, const void *id,
+				 size_t id_len)
+{
+	int sv[2];
+	int cfd;
+	struct owner *o;
+	struct fd_store *f = NULL;
+	struct fd_store *newf = NULL;
+	struct fd_store **fp;
+	int fd = msg->fd;
+	int cmd = msg->cmd;
+	int res;
+	int unlockall = (cmd == F_SETLK && msg->lock.l_type == F_UNLCK &&
+			 msg->lock.l_start == 0 && msg->lock.l_len == 0);
+
+	for (o = owner_list.next; o != &owner_list; o = o->next)
+		if (o->id_len == id_len && memcmp(o->id, id, id_len) == 0)
+			break;
+
+	if (o == &owner_list)
+		o = NULL;
+
+	if (!o && cmd != F_GETLK && msg->lock.l_type != F_UNLCK)
+		o = ulockmgr_new_owner(id, id_len);
+
+	if (!o) {
+		if (cmd == F_GETLK) {
+			res = fcntl(msg->fd, F_GETLK, &msg->lock);
+			return (res == -1) ? -errno : 0;
+		} else if (msg->lock.l_type == F_UNLCK)
+			return 0;
+		else
+			return -ENOLCK;
+	}
+
+	if (unlockall)
+		msg->nofd = 1;
+	else {
+		for (fp = &o->fds; *fp; fp = &(*fp)->next) {
+			f = *fp;
+			if (f->fd == fd) {
+				msg->nofd = 1;
+				break;
+			}
+		}
+	}
+
+	if (!msg->nofd) {
+		newf = f = calloc(1, sizeof(struct fd_store));
+		if (!f) {
+			fprintf(stderr, "libulockmgr: failed to allocate memory\n");
+			return -ENOLCK;
+		}
+	}
+
+	res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
+	if (res == -1) {
+		perror("libulockmgr: socketpair");
+		free(newf);
+		return -ENOLCK;
+	}
+
+	cfd = sv[1];
+	sv[1] = msg->fd;
+	res = ulockmgr_send_message(o->cfd, msg, sizeof(struct message), sv,
+				    msg->nofd ? 1 : 2);
+	close(sv[0]);
+	if (res == -1) {
+		free(newf);
+		close(cfd);
+		return -EIO;
+	}
+
+	if (newf) {
+		newf->fd = msg->fd;
+		newf->next = o->fds;
+		o->fds = newf;
+	}
+	if (f)
+		f->inuse++;
+
+	res = do_recv(cfd, msg, sizeof(struct message), MSG_WAITALL);
+	if (res == -1) {
+		perror("libulockmgr: recv");
+		msg->error = EIO;
+	} else if (res != sizeof(struct message)) {
+		fprintf(stderr, "libulockmgr: recv short\n");
+		msg->error = EIO;
+	} else if (cmd == F_SETLKW && msg->error == EAGAIN) {
+		pthread_mutex_unlock(&ulockmgr_lock);
+		while (1) {
+			sigset_t old;
+			sigset_t unblock;
+			int errno_save;
+
+			sigemptyset(&unblock);
+			sigaddset(&unblock, SIGUSR1);
+			pthread_sigmask(SIG_UNBLOCK, &unblock, &old);
+			res = do_recv(cfd, msg, sizeof(struct message),
+				      MSG_WAITALL);
+			errno_save = errno;
+			pthread_sigmask(SIG_SETMASK, &old, NULL);
+			if (res == sizeof(struct message))
+				break;
+			else if (res >= 0) {
+				fprintf(stderr, "libulockmgr: recv short\n");
+				msg->error = EIO;
+				break;
+			} else if (errno_save != EINTR) {
+				errno = errno_save;
+				perror("libulockmgr: recv");
+				msg->error = EIO;
+				break;
+			}
+			msg->intr = 1;
+			res = send(o->cfd, msg, sizeof(struct message),
+				   MSG_NOSIGNAL);
+			if (res == -1) {
+				perror("libulockmgr: send");
+				msg->error = EIO;
+				break;
+			}
+			if (res != sizeof(struct message)) {
+				fprintf(stderr, "libulockmgr: send short\n");
+				msg->error = EIO;
+				break;
+			}
+		}
+		pthread_mutex_lock(&ulockmgr_lock);
+
+	}
+	if (f)
+		f->inuse--;
+	close(cfd);
+	if (unlockall) {
+		for (fp = &o->fds; *fp;) {
+			f = *fp;
+			if (f->fd == fd && !f->inuse) {
+				*fp = f->next;
+				free(f);
+			} else
+				fp = &f->next;
+		}
+		if (!o->fds) {
+			list_del_owner(o);
+			close(o->cfd);
+			free(o);
+		}
+		/* Force OK on unlock-all, since it _will_ succeed once the
+		   owner is deleted */
+		msg->error = 0;
+	}
+
+	return -msg->error;
+}
+
+#ifdef DEBUG
+static uint32_t owner_hash(const unsigned char *id, size_t id_len)
+{
+	uint32_t h = 0;
+	size_t i;
+	for (i = 0; i < id_len; i++)
+		h = ((h << 8) | (h >> 24)) ^ id[i];
+
+	return h;
+}
+#endif
+
+static int ulockmgr_canonicalize(int fd, struct flock *lock)
+{
+	off64_t offset;
+	if (lock->l_whence == SEEK_CUR) {
+		offset = lseek(fd, 0, SEEK_CUR);
+		if (offset == (off64_t) -1)
+			return -errno;
+	} else if (lock->l_whence == SEEK_END) {
+		struct stat stbuf;
+		int res = fstat(fd, &stbuf);
+		if (res == -1)
+			return -errno;
+
+		offset = stbuf.st_size;
+	} else
+		offset = 0;
+
+	lock->l_whence = SEEK_SET;
+	lock->l_start += offset;
+
+	if (lock->l_start < 0)
+		return -EINVAL;
+
+	if (lock->l_len < 0) {
+		lock->l_start += lock->l_len;
+		if (lock->l_start < 0)
+			return -EINVAL;
+		lock->l_len = -lock->l_len;
+	}
+	if (lock->l_len && lock->l_start + lock->l_len - 1 < 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+int ulockmgr_op(int fd, int cmd, struct flock *lock, const void *owner,
+		size_t owner_len)
+{
+	int err;
+	struct message msg;
+	sigset_t old;
+	sigset_t block;
+
+	if (cmd != F_GETLK && cmd != F_SETLK && cmd != F_SETLKW)
+		return -EINVAL;
+
+	if (lock->l_whence != SEEK_SET && lock->l_whence != SEEK_CUR &&
+	    lock->l_whence != SEEK_END)
+		return -EINVAL;
+
+#ifdef DEBUG
+	fprintf(stderr, "libulockmgr: %i %i %i %lli %lli own: 0x%08x\n",
+		cmd, lock->l_type, lock->l_whence, lock->l_start, lock->l_len,
+		owner_hash(owner, owner_len));
+#endif
+
+	/* Unlock should never block anyway */
+	if (cmd == F_SETLKW && lock->l_type == F_UNLCK)
+		cmd = F_SETLK;
+
+	memset(&msg, 0, sizeof(struct message));
+	msg.cmd = cmd;
+	msg.fd = fd;
+	msg.lock = *lock;
+	err = ulockmgr_canonicalize(fd, &msg.lock);
+	if (err)
+		return err;
+
+	sigemptyset(&block);
+	sigaddset(&block, SIGUSR1);
+	pthread_sigmask(SIG_BLOCK, &block, &old);
+	pthread_mutex_lock(&ulockmgr_lock);
+	err = ulockmgr_send_request(&msg, owner, owner_len);
+	pthread_mutex_unlock(&ulockmgr_lock);
+	pthread_sigmask(SIG_SETMASK, &old, NULL);
+	if (!err && cmd == F_GETLK) {
+		if (msg.lock.l_type == F_UNLCK)
+			lock->l_type = F_UNLCK;
+		else
+			*lock = msg.lock;
+	}
+
+	return err;
+}