summaryrefslogtreecommitdiff
path: root/lib/libfuse
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libfuse')
-rw-r--r--lib/libfuse/Makefile52
-rw-r--r--lib/libfuse/debug.c40
-rw-r--r--lib/libfuse/debug.h49
-rw-r--r--lib/libfuse/dict.c106
-rw-r--r--lib/libfuse/fuse.3241
-rw-r--r--lib/libfuse/fuse.c331
-rw-r--r--lib/libfuse/fuse.h152
-rw-r--r--lib/libfuse/fuse_ops.c884
-rw-r--r--lib/libfuse/fuse_private.h120
-rw-r--r--lib/libfuse/fuse_subr.c140
-rw-r--r--lib/libfuse/generate_pkgconfig.sh70
-rw-r--r--lib/libfuse/shlib_version2
-rw-r--r--lib/libfuse/tree.c100
13 files changed, 2287 insertions, 0 deletions
diff --git a/lib/libfuse/Makefile b/lib/libfuse/Makefile
new file mode 100644
index 00000000000..5be536881f0
--- /dev/null
+++ b/lib/libfuse/Makefile
@@ -0,0 +1,52 @@
+# $OpenBSD: Makefile,v 1.1 2013/06/03 16:00:50 tedu Exp $
+
+LIB= fuse
+MAN= fuse.3
+
+MLINKS= fuse.3 fuse_main.3 \
+ fuse.3 fuse_new.3 \
+ fuse.3 fuse_parse_cmdline.3 \
+ fuse.3 fuse_mount.3 \
+ fuse.3 fuse_remove_signal_handlers.3 \
+ fuse.3 fuse_set_signal_handlers.3 \
+ fuse.3 fuse_get_session.3 \
+ fuse.3 fuse_is_lib_option.3 \
+ fuse.3 fuse_loop.3 \
+ fuse.3 fuse_loop_mt.3 \
+ fuse.3 fuse_chan_fd.3 \
+ fuse.3 fuse_unmount.3 \
+ fuse.3 fuse_daemonize.3 \
+ fuse.3 fuse_destroy.3
+
+CFLAGS+= -Wall -g -Werror -Wshadow -Wmissing-prototypes
+CFLAGS+= -Wstrict-prototypes -Wsign-compare
+
+CDIAGFLAGS+= -Wno-long-long -Wall -W -Wnested-externs -Wformat=2
+CDIAGFLAGS+= -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
+CDIAGFLAGS+= -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare
+CDIAGFLAGS+= -Wundef -Wbad-function-cast -Winline -Wcast-align
+
+# XXX Shouldn't we use a common fuse.h with proper ifdef _KERNEL part?
+CFLAGS+= -I${.CURDIR} -DDEBUG
+
+SRCS= debug.c dict.c fuse.c fuse_ops.c fuse_subr.c tree.c
+HDRS= fuse.h
+
+PC_FILES=fuse.pc
+CLEANFILES+=${PC_FILES}
+
+includes:
+ @cd ${.CURDIR}; for i in ${HDRS}; do \
+ j="cmp -s $$i ${DESTDIR}/usr/include/$$i || \
+ ${INSTALL} ${INSTALL_COPY} -o ${BINOWN} -g ${BINGRP} -m 444 \
+ $$i ${DESTDIR}/usr/include"; \
+ echo $$j; \
+ eval "$$j"; \
+ done
+
+beforeinstall:
+ /bin/sh ${.CURDIR}/generate_pkgconfig.sh -c ${.CURDIR} -o ${.OBJDIR}
+ ${INSTALL} ${INSTALL_COPY} -o root -g ${SHAREGRP} \
+ -m ${SHAREMODE} ${.OBJDIR}/${PC_FILES} ${DESTDIR}/usr/lib/pkgconfig/
+
+.include <bsd.lib.mk>
diff --git a/lib/libfuse/debug.c b/lib/libfuse/debug.c
new file mode 100644
index 00000000000..e6262136451
--- /dev/null
+++ b/lib/libfuse/debug.c
@@ -0,0 +1,40 @@
+/* $OpenBSD: debug.c,v 1.1 2013/06/03 16:00:50 tedu Exp $ */
+/*
+ * Copyright (c) 2011 Alexandre Ratchov <alex@caoua.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "debug.h"
+
+#ifdef DEBUG
+/*
+ * debug level, -1 means uninitialized
+ */
+int ifuse_debug = -1;
+
+void
+ifuse_debug_init(void)
+{
+ char *dbg;
+
+ if (ifuse_debug < 0) {
+ dbg = issetugid() ? NULL : getenv("FUSE_DEBUG");
+ if (!dbg || sscanf(dbg, "%u", &ifuse_debug) != 1)
+ ifuse_debug = 0;
+ }
+}
+#endif
diff --git a/lib/libfuse/debug.h b/lib/libfuse/debug.h
new file mode 100644
index 00000000000..4a23e9af1b1
--- /dev/null
+++ b/lib/libfuse/debug.h
@@ -0,0 +1,49 @@
+/* $OpenBSD: debug.h,v 1.1 2013/06/03 16:00:50 tedu Exp $ */
+/*
+ * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef _DEBUG_H_
+#define _DEBUG_H_
+
+#ifdef DEBUG
+#include <stdio.h>
+
+#define DPRINTFN(n, ...) \
+ do { \
+ if (ifuse_debug >= (n)) \
+ fprintf(stderr, __VA_ARGS__); \
+ } while(0)
+
+#define DPRINTF(...) \
+ do { \
+ if (ifuse_debug > 0) \
+ fprintf(stderr, __VA_ARGS__); \
+ } while(0)
+
+#define DPERROR(s) \
+ do { \
+ if (ifuse_debug > 0) \
+ perror(s); \
+ } while(0)
+
+void ifuse_debug_init(void);
+extern int ifuse_debug;
+#else
+#define DPRINTF(...) do {} while(0)
+#define DPRINTFN(...) do {} while(0)
+#define DPERROR(s) do {} while(0)
+#endif
+
+#endif /* _DEBUG_H_ */
diff --git a/lib/libfuse/dict.c b/lib/libfuse/dict.c
new file mode 100644
index 00000000000..a30532b1f1a
--- /dev/null
+++ b/lib/libfuse/dict.c
@@ -0,0 +1,106 @@
+/* $OpenBSD: dict.c,v 1.1 2013/06/03 16:00:50 tedu Exp $ */
+
+/*
+ * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org>
+ * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "fuse_private.h"
+
+#define MAX_DICTKEY_SIZE NAME_MAX
+struct dictentry {
+ SPLAY_ENTRY(dictentry) entry;
+ char key[MAX_DICTKEY_SIZE];
+ void *data;
+};
+
+static int dictentry_cmp(struct dictentry *, struct dictentry *);
+
+SPLAY_PROTOTYPE(dict, dictentry, entry, dictentry_cmp);
+
+int
+dict_check(struct dict *d, const char *k)
+{
+ struct dictentry key;
+
+ if (strlcpy(key.key, k, sizeof key.key) >= sizeof key.key)
+ errx(1, "dict_check(%p, %s): key too large", d, k);
+
+ return (SPLAY_FIND(dict, d, &key) != NULL);
+}
+
+void *
+dict_set(struct dict *d, const char *k, void *data)
+{
+ struct dictentry *entry, key;
+
+ if (strlcpy(key.key, k, sizeof key.key) >= sizeof key.key)
+ errx(1, "dict_set(%p, %s): key too large", d, k);
+ if ((entry = SPLAY_FIND(dict, d, &key)) == NULL) {
+ entry = malloc(sizeof *entry);
+ if (entry == NULL)
+ return (NULL);
+
+ strlcpy(entry->key, k, sizeof entry->key);
+ SPLAY_INSERT(dict, d, entry);
+ }
+
+ entry->data = data;
+
+ return (entry);
+}
+
+void *
+dict_get(struct dict *d, const char *k)
+{
+ struct dictentry key, *entry;
+
+ if (strlcpy(key.key, k, sizeof key.key) >= sizeof key.key)
+ errx(1, "dict_get(%p, %s): key too large", d, k);
+ if ((entry = SPLAY_FIND(dict, d, &key)) == NULL)
+ return (NULL);
+
+ return (entry->data);
+}
+
+void *
+dict_pop(struct dict *d, const char *k)
+{
+ struct dictentry key, *entry;
+ void *data;
+
+ if (strlcpy(key.key, k, sizeof key.key) >= sizeof key.key)
+ errx(1, "dict_pop(%p, %s): key too large", d, k);
+ if ((entry = SPLAY_FIND(dict, d, &key)) == NULL)
+ return (NULL);
+
+ data = entry->data;
+ SPLAY_REMOVE(dict, d, entry);
+ free(entry);
+
+ return (data);
+}
+
+static int
+dictentry_cmp(struct dictentry *a, struct dictentry *b)
+{
+ return strcmp(a->key, b->key);
+}
+
+SPLAY_GENERATE(dict, dictentry, entry, dictentry_cmp);
diff --git a/lib/libfuse/fuse.3 b/lib/libfuse/fuse.3
new file mode 100644
index 00000000000..931cb0d2f55
--- /dev/null
+++ b/lib/libfuse/fuse.3
@@ -0,0 +1,241 @@
+.\"
+.\" Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: June 3 2013 $
+.Dt FUSE 3
+.Os
+.Sh NAME
+.Nm fuse ,
+.Nm fuse_main ,
+.Nm fuse_new ,
+.Nm fuse_parse_cmdline ,
+.Nm fuse_mount ,
+.Nm fuse_remove_signal_handlers ,
+.Nm fuse_set_signal_handlers ,
+.Nm fuse_get_session ,
+.Nm fuse_is_lib_option ,
+.Nm fuse_loop ,
+.Nm fuse_loop_mt ,
+.Nm fuse_chan_fd ,
+.Nm fuse_unmount ,
+.Nm fuse_daemonize,
+.Nm fuse_destroy
+.Nd FUSE implementation routines
+.Sh SYNOPSIS
+.Fd #include \*[Lt]fuse.h\*[Gt]
+.Ft int
+.Fn fuse_main "int argc" "char **argv" "const struct fuse_operations *ops" \
+ "void *data"
+.Ft struct fuse *
+.Fn fuse_new "struct fuse_chan *fc" "struct fuse_args *args" \
+ "const struct fuse_operations *ops" "size_t size" "void *userdata"
+.Ft int
+.Fn fuse_parse_cmdline "struct fuse_args *args" "char **mp" "int *mt" "int *fg"
+.Ft struct fuse_chan *
+.Fn fuse_mount "const char *dir" "struct fuse_args *args"
+.Ft void
+.Fn fuse_remove_signal_handlers "struct fuse_session *se"
+.Ft int
+.Fn fuse_set_signal_handlers "struct fuse_session *se"
+.Ft struct fuse_session *
+.Fn fuse_get_session "struct fuse *f"
+.Ft int
+.Fn fuse_is_lib_option "const char *opt"
+.Ft int
+.Fn fuse_loop "struct fuse *fuse"
+.Ft int
+.Fn fuse_loop_mt "struct fuse *fuse"
+.Ft int
+.Fn fuse_chan_fd "struct fuse_chan *ch"
+.Ft void
+.Fn fuse_unmount "const char *dir" "struct fuse_chan *ch"
+.Ft int
+.Fn fuse_daemonize "int foreground"
+.Ft void
+.Fn fuse_destroy "struct fuse *f"
+.Sh DESCRIPTION
+The
+.Nm
+library provides routine to implement a filesystem in userspace.
+.Ss INTRODUCTION
+There is two way of Implementing a Fuse filesystem. You can implement a fs only
+by calling
+.Fn fuse_main
+and giving this function the
+.Em ops
+argument containing all the callbacks of your filesystems. Or you can use all
+others functions.
+.Ss FUNCTIONS
+.Fn fuse_new
+Fuse new return a
+.Fa struct fuse
+That will be needed by
+.Fn fuse_loop
+.Pp
+.Fn fuse_parse_cmdline
+This function will parse the
+.Fa struct fuse_args
+given by the user and will set
+.Fa mp
+with a char * containing the mountpoint directory.
+.Pp
+.Fn fuse_mount
+Will look for an empty
+.Xr fuse 4
+device to create a connection. If this function find an available device it will
+open it to use it for fuse communication with the fuse VFS driver and will mount
+the filesystem. This function will return a
+.Fa struct fuse_chan
+that will be needed by
+.Fn fuse_new
+.Pp
+.Fn fuse_remove_signal_handlers
+I do not know yet what this function is supposed to do...
+.Pp
+.Fn fuse_set_signal_handlers
+I do not know yet what this function is supposed to do...
+.Pp
+.Fn fuse_get_session
+returns a pointer on the structure
+.Fa fuse_session
+contained in a
+.Fa struct fuse
+.Pp
+.Fn fuse_is_lib_option
+check if the string
+.Fa opt
+is an option handled by the libfuse or by the fuse client. It returns 1 if it is
+handled by the lib and 0 in the other case.
+.Pp
+.Fn fuse_loop_mt
+Do not use! It is not supported yet (and we will probably never need it...)
+.Pp
+.Fn fuse_loop
+This is the mainloop of a fuse program. This function will look for fuse
+request from kernel and will respond to it using the
+.Fa struct fuse_operation
+present in the structure
+.Fa fuse.
+It will return only if something goes wrong
+or if the kernel send a
+.Fa FUSE_DESTROY
+opcode to libfuse.
+.Pp
+.Fn fuse_chan_fd
+returns the filedescriptor used by the given
+.Fa fuse_chan
+structure.
+.Pp
+.Fn fuse_unmount
+unmount the
+.Fa dir
+mountpoint.
+.Pp
+.Fn fuse_daemonize
+daemonise the fuse library. It will permit to background the fuse program that
+will continue to handles kernel filesystems opcodes.
+.Pp
+.Fn fuse_destroy
+I do not know yet what this function is supposed to do...
+.Sh EXAMPLE
+Here is a simple example of a fuse implementation:
+.Bd -literal
+#include <errno.h>
+#include <fuse.h>
+#include <string.h>
+
+static int
+fs_readdir(const char *path, void *data, fuse_fill_dir_t filler,
+ off_t off, struct fuse_file_info *ffi)
+{
+ if (strcmp(path, "/") != 0)
+ return (-ENOENT);
+
+ filler(data, ".", NULL, 0);
+ filler(data, "..", NULL, 0);
+ filler(data, "file", NULL, 0);
+ return (0);
+}
+
+static int
+fs_read(const char *path, char *buf, size_t size, off_t off,
+ struct fuse_file_info *ffi)
+{
+ if (off >= 5)
+ return (0);
+
+ size = 5 - off;
+ memcpy(buf, "data." + off, size);
+ return (size);
+}
+
+static int
+fs_open(const char *path, struct fuse_file_info *ffi)
+{
+ if (strncmp(path, "/file", 10) != 0)
+ return (-ENOENT);
+
+ if ((ffi->flags & 3) != O_RDONLY)
+ return (-EACCES);
+
+ return (0);
+}
+
+static int
+fs_getattr(const char *path, struct stat *st)
+{
+ if (strcmp(path, "/") == 0) {
+ st->st_blksize = 512;
+ st->st_mode = 0755;
+ st->st_nlink = 2;
+ } else if (strcmp(path, "/file") == 0) {
+ st->st_mode = 0644;
+ st->st_blksize = 512;
+ st->st_nlink = 1;
+ st->st_size = 5;
+ } else {
+ return (-ENOENT);
+ }
+
+ return (0);
+}
+
+struct fuse_operations fsops = {
+ .readdir = fs_readdir,
+ .read = fs_read,
+ .open = fs_open,
+ .getattr = fs_getattr,
+};
+
+int
+main(int ac, char **av)
+{
+ return (fuse_main(ac, av, &fsops, NULL));
+}
+.Ed
+.Sh SEE ALSO
+The
+.Tn FUSE
+specifications and orignal implementation can be found at:
+.Lk http://fuse.sourceforge.net/
+.Pp
+.Xr fuse 4
+.Sh HISTORY
+The
+.Nm
+library first appeared in
+.Ox ??? .
+.Sh BUGS
+This man page is woefully incomplete
diff --git a/lib/libfuse/fuse.c b/lib/libfuse/fuse.c
new file mode 100644
index 00000000000..24099d60e66
--- /dev/null
+++ b/lib/libfuse/fuse.c
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/wait.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "fuse_private.h"
+#include "debug.h"
+
+static struct fuse_session *sigse;
+
+int
+fuse_loop(struct fuse *fuse)
+{
+ struct fusebuf fbuf;
+ struct kevent ev;
+ int error = 0;
+ size_t len = 0;
+ int ret;
+
+ fuse->fc->kq = kqueue();
+ if (fuse->fc->kq == -1)
+ return (-1);
+
+ EV_SET(&fuse->fc->event, fuse->fc->fd, EVFILT_READ, EV_ADD |
+ EV_ENABLE, 0, 0, 0);
+
+ while (!fuse->fc->dead) {
+ ret = kevent(fuse->fc->kq, &fuse->fc->event, 1, &ev, 1, NULL);
+ if (ret == -1)
+ DPERROR(__func__);
+ else if (ret > 0) {
+ error = read(fuse->fc->fd, &fbuf, sizeof(fbuf.fb_hdr));
+ if (error != sizeof(fbuf.fb_hdr)) {
+ DPRINTF("%s: bad hdr read\n", __func__);
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (fbuf.fb_len != 0) {
+ error = read(fuse->fc->fd, (char *)&fbuf.F_dat,
+ fbuf.fb_len);
+
+ if (error != (int)fbuf.fb_len) {
+ errno = EINVAL;
+ return (-1);
+ }
+ }
+
+ ret = ifuse_exec_opcode(fuse, &fbuf);
+ if (ret) {
+ return (ret);
+ }
+
+ len = sizeof(fbuf.fb_hdr) + fbuf.fb_len;
+ ret = write(fuse->fc->fd, &fbuf, len);
+
+ if (ret != (int)len) {
+ errno = EINVAL;
+ return (-1);
+ }
+ }
+ }
+
+ return (0);
+}
+
+#define DEVPATH "/dev/"
+#define FUSEDEV DEVPATH "fuse"
+
+struct fuse_chan *
+fuse_mount(const char *dir, unused struct fuse_args *args)
+{
+ struct fusefs_args fargs;
+ struct fuse_chan *fc;
+ struct stat st;
+ char busnode[16];
+ dev_t minor;
+ int i;
+
+ fc = calloc(1, sizeof(*fc));
+ if (fc == NULL)
+ return (NULL);
+
+ fc->dir = strdup(dir);
+ if (fc->dir == NULL)
+ goto bad;
+
+ for (i = 0; i < 8 ; i++) {
+ minor = -1;
+ snprintf(busnode, sizeof(busnode), FUSEDEV "%d", i);
+
+ DPRINTF("trying %s\n", busnode);
+ if ((fc->fd = open(busnode, O_RDWR)) < 0) {
+ if (errno == EBUSY)
+ DPRINTF("device %s already opened\n", busnode);
+ else if (errno != ENOENT && errno != ENXIO)
+ DPRINTF("could not open %s\n", busnode);
+ continue;
+ }
+
+ if (fstat(fc->fd, &st) != 0)
+ goto bad;
+
+ minor = st.st_rdev;
+ break;
+ }
+
+ if (minor == -1) {
+ fprintf(stderr, "%s: Cannot find a suitable fuse device\n",
+ __func__);
+ goto bad;
+ }
+
+ fargs.dev = minor;
+ if (mount(MOUNT_FUSEFS, dir, 0, &fargs)) {
+ if (errno == EOPNOTSUPP)
+ fprintf(stderr,
+ "%s: %s: FS not supported by kernel\n", __func__,
+ dir);
+ else
+ perror("fuse_mount failure:");
+
+ goto bad;
+ }
+
+ return (fc);
+bad:
+ if (fc->fd > 0)
+ close(fc->fd);
+ if (fc->dir != NULL)
+ free(fc->dir);
+ return (NULL);
+}
+
+void
+fuse_unmount(const char *dir, unused struct fuse_chan *ch)
+{
+ int ret;
+
+ if (ch->dead)
+ return ;
+
+ if ((ret = unmount(dir, MNT_UPDATE)) == -1)
+ DPERROR(__func__);
+
+ return ;
+}
+
+int
+fuse_is_lib_option(unused const char *opt)
+{
+ DPRINTF("option %s\n", opt);
+ return (0);
+}
+
+int
+fuse_chan_fd(struct fuse_chan *ch)
+{
+ return (ch->fd);
+}
+
+struct fuse_session *
+fuse_get_session(struct fuse *f)
+{
+ return (&f->se);
+}
+
+int
+fuse_loop_mt(unused struct fuse *fuse)
+{
+ return (0);
+}
+
+struct fuse *
+fuse_new(struct fuse_chan *fc, unused struct fuse_args *args,
+ const struct fuse_operations *ops, unused size_t size,
+ unused void *userdata)
+{
+ struct fuse *fuse;
+ struct fuse_vnode *root;
+
+ if ((fuse = calloc(1, sizeof(*fuse))) == NULL)
+ return (NULL);
+
+ /* copy fuse ops to their own structure */
+ memcpy(&fuse->op, ops, sizeof(fuse->op));
+
+ fuse->fc = fc;
+ fuse->max_ino = FUSE_ROOT_INO;
+ fuse->se.args = fuse;
+
+ if ((root = alloc_vn(fuse, "/", FUSE_ROOT_INO, 0)) == NULL) {
+ free(fuse);
+ return (NULL);
+ }
+
+ tree_init(&fuse->vnode_tree);
+ tree_init(&fuse->name_tree);
+ if (!set_vn(fuse, root)) {
+ free(fuse);
+ return (NULL);
+ }
+
+ return (fuse);
+}
+
+int
+fuse_daemonize(unused int foreground)
+{
+#ifdef DEBUG
+ return (daemon(0,1));
+#else
+ return (daemon(0,0));
+#endif
+}
+
+void
+fuse_destroy(unused struct fuse *f)
+{
+ close(f->fc->fd);
+ free(f->fc->dir);
+ free(f->fc);
+ free(f);
+}
+
+static void
+ifuse_get_signal(unused int num)
+{
+ struct fuse *f;
+ pid_t child;
+ int status;
+
+ if (sigse != NULL) {
+ child = fork();
+
+ if (child < 0)
+ return ;
+
+ f = sigse->args;
+ if (child == 0) {
+ fuse_unmount(f->fc->dir, f->fc);
+ sigse = NULL;
+ exit(0);
+ }
+
+ fuse_loop(f);
+ wait(&status);
+ }
+}
+
+void
+fuse_remove_signal_handlers(unused struct fuse_session *se)
+{
+ sigse = NULL;
+ signal(SIGHUP, SIG_DFL);
+ signal(SIGINT, SIG_DFL);
+ signal(SIGTERM, SIG_DFL);
+ signal(SIGPIPE, SIG_DFL);
+}
+
+int
+fuse_set_signal_handlers(unused struct fuse_session *se)
+{
+ sigse = se;
+ signal(SIGHUP, ifuse_get_signal);
+ signal(SIGINT, ifuse_get_signal);
+ signal(SIGTERM, ifuse_get_signal);
+ signal(SIGPIPE, SIG_IGN);
+ return (0);
+}
+
+int
+fuse_parse_cmdline(struct fuse_args *args, char **mp, int *mt, unused int *fg)
+{
+ int i;
+
+#ifdef DEBUG
+ ifuse_debug_init();
+#endif
+
+ for (i = args->argc - 1 ; i > 0 && *args->argv[i] == '-' ; --i);
+ *mp = args->argv[i];
+ *mt = 0;
+
+ return (0);
+}
+
+int
+fuse_main(int argc, char **argv, const struct fuse_operations *ops, void *data)
+{
+ struct fuse *fuse;
+ struct fuse_chan *fc;
+ struct fuse_args args;
+ char *mountpoint;
+ int mt, fg;
+
+ args.argc = argc;
+ args.argv = argv;
+ fuse_parse_cmdline(&args, &mountpoint, &mt, &fg);
+
+ fuse_daemonize(0);
+
+ if ((fc = fuse_mount(mountpoint, NULL)) == NULL)
+ return (-1);
+
+ if ((fuse = fuse_new(fc, NULL, ops, sizeof(*(ops)), data)) == NULL) {
+ free(fc);
+ return (-1);
+ }
+
+ return (fuse_loop(fuse));
+}
diff --git a/lib/libfuse/fuse.h b/lib/libfuse/fuse.h
new file mode 100644
index 00000000000..1ac2133f193
--- /dev/null
+++ b/lib/libfuse/fuse.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _FUSE_H_
+#define _FUSE_H_
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+
+#include <fcntl.h>
+#include <utime.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct fuse_chan;
+struct fuse_args;
+struct fuse_session;
+
+struct fuse_file_info {
+ int32_t flags; /* open(2) flags */
+ uint32_t fh_old; /* old file handle */
+ int32_t writepage;
+ uint32_t direct_io:1;
+ uint32_t keep_cache:1;
+ uint32_t flush:1;
+ uint32_t __padd:29;
+ uint64_t fh; /* file handle */
+ uint64_t lock_owner;
+};
+
+struct fuse_conn_info {
+ uint32_t proto_major;
+ uint32_t proto_minor;
+ uint32_t async_read;
+ uint32_t max_write;
+ uint32_t max_readahead;
+ uint32_t reserved[27];
+};
+
+typedef ino_t fuse_ino_t;
+typedef int (*fuse_fill_dir_t)(void *, const char *, const struct stat *,
+ off_t);
+
+typedef struct fuse_dirhandle {
+ fuse_fill_dir_t filler;
+ void *buf;
+ int filled;
+ int full;
+ int isgetdir;
+ uint32_t size;
+ uint32_t start;
+ uint32_t idx;
+} *fuse_dirh_t;
+
+typedef int (*fuse_dirfil_t)(fuse_dirh_t, const char *, int, ino_t);
+
+struct fuse_operations {
+ 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 *, off_t);
+ int (*utime)(const char *, struct utimbuf *);
+ int (*open)(const char *, struct fuse_file_info *);
+ int (*read)(const char *, char *, size_t, off_t,
+ struct fuse_file_info *);
+ int (*write)(const char *, const char *, size_t, off_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, off_t,
+ struct fuse_file_info *);
+ int (*releasedir)(const char *, struct fuse_file_info *);
+ int (*fsyncdir)(const char *, int, struct fuse_file_info *);
+ void *(*init)(struct fuse_conn_info *);
+ void (*destroy)(void *);
+ int (*access)(const char *, int);
+ int (*create)(const char *, mode_t, struct fuse_file_info *);
+ int (*ftruncate)(const char *, off_t, struct fuse_file_info *);
+ int (*fgetattr)(const char *, struct stat *, struct fuse_file_info *);
+ int (*lock)(const char *, struct fuse_file_info *, int, struct flock *);
+ int (*utimens)(const char *, const struct timespec *);
+ int (*bmap)(const char *, size_t , uint64_t *);
+};
+
+#ifndef FUSE_USE_VERSION
+#define FUSE_USE_VERSION 26
+#endif
+
+#if FUSE_USE_VERSION >= 26
+#define FUSE_VERSION 26
+#else
+#error "Fuse version < 26 not supported"
+#endif
+
+
+/*
+ * API prototypes
+ */
+int fuse_main(int, char **, const struct fuse_operations *, void *);
+struct fuse *fuse_new(struct fuse_chan *, struct fuse_args *,
+ const struct fuse_operations *, size_t, void *);
+int fuse_parse_cmdline(struct fuse_args *, char **, int *, int *);
+struct fuse_chan *fuse_mount(const char *, struct fuse_args *);
+void fuse_remove_signal_handlers(struct fuse_session *);
+int fuse_set_signal_handlers(struct fuse_session *);
+struct fuse_session *fuse_get_session(struct fuse *);
+int fuse_is_lib_option(const char *);
+int fuse_loop(struct fuse *);
+int fuse_loop_mt(struct fuse *);
+int fuse_chan_fd(struct fuse_chan *);
+void fuse_unmount(const char *, struct fuse_chan *);
+int fuse_daemonize(int);
+void fuse_destroy(struct fuse *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FUSE_H_ */
diff --git a/lib/libfuse/fuse_ops.c b/lib/libfuse/fuse_ops.c
new file mode 100644
index 00000000000..ec85e00c0ca
--- /dev/null
+++ b/lib/libfuse/fuse_ops.c
@@ -0,0 +1,884 @@
+/*
+ * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "fuse_private.h"
+#include "debug.h"
+
+#define CHECK_OPT(opname) DPRINTF("Opcode:\t%s\n", #opname); \
+ DPRINTF("Inode:\t%i\n", fbuf->fb_ino); \
+ if (!f->op.opname) { \
+ fbuf->fb_err = -ENOSYS; \
+ fbuf->fb_len = 0; \
+ DPRINTF("\n"); \
+ return (0); \
+ }
+
+static void
+stat2attr(struct vattr *v, struct stat *st)
+{
+ v->va_fileid = st->st_ino;
+ v->va_bytes = st->st_blocks;
+ v->va_mode = st->st_mode;
+ v->va_nlink = st->st_nlink;
+ v->va_uid = st->st_uid;
+ v->va_gid = st->st_gid;
+ v->va_rdev = st->st_rdev;
+ v->va_size = st->st_size;
+ v->va_blocksize = st->st_blksize;
+ v->va_atime.tv_sec = st->st_atime;
+ v->va_atime.tv_nsec = st->st_atimensec;
+ v->va_mtime.tv_sec = st->st_mtime;
+ v->va_mtime.tv_nsec = st->st_mtimensec;
+ v->va_ctime.tv_sec = st->st_ctime;
+ v->va_ctime.tv_nsec = st->st_ctimensec;
+}
+
+static int
+update_vattr(struct fuse *f, struct vattr *attr, const char *realname,
+ struct fuse_vnode *vn)
+{
+ struct stat st;
+ int ret;
+
+ bzero(&st, sizeof(st));
+ ret = f->op.getattr(realname, &st);
+
+ st.st_ino = vn->ino;
+
+ if (f->conf.set_mode)
+ st.st_mode = (st.st_mode & S_IFMT) | (0777 & ~f->conf.umask);
+
+ if (f->conf.set_uid)
+ st.st_uid = f->conf.uid;
+
+ if (f->conf.set_gid)
+ st.st_gid = f->conf.gid;
+
+ stat2attr(attr, &st);
+
+ return (ret);
+}
+
+static int
+ifuse_ops_init(struct fusebuf *fbuf)
+{
+ DPRINTF("Opcode:\tinit\n");
+ fbuf->fb_len = 0;
+ DPRINTF("\n");
+
+ return (0);
+}
+
+static int
+ifuse_ops_getattr(struct fuse *f, struct fusebuf *fbuf)
+{
+ struct fuse_vnode *vn;
+ struct stat st;
+ char *realname;
+
+ DPRINTF("Opcode:\tgetattr\n");
+ DPRINTF("Inode:\t%i\n", fbuf->fb_ino);
+ bzero(&st, sizeof(st));
+
+ fbuf->fb_len = FUSEFDSIZE;
+ bzero(&fbuf->fb_vattr, sizeof(fbuf->fb_vattr));
+
+ vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
+
+ realname = build_realname(f, vn->ino);
+ fbuf->fb_err = update_vattr(f, &fbuf->fb_vattr, realname, vn);
+ free(realname);
+
+ if (fbuf->fb_err)
+ fbuf->fb_len = 0;
+
+ DPRINTF("\n");
+ return (0);
+}
+
+static int
+ifuse_ops_access(struct fuse *f, struct fusebuf *fbuf)
+{
+ struct fuse_vnode *vn;
+ char *realname;
+
+ CHECK_OPT(access);
+
+ fbuf->fb_len = 0;
+
+ vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
+
+ realname = build_realname(f, vn->ino);
+ fbuf->fb_err = f->op.access(realname, fbuf->fb_io_mode);
+ free(realname);
+
+ DPRINTF("\n");
+ return (0);
+}
+
+static int
+ifuse_ops_open(struct fuse *f, struct fusebuf *fbuf)
+{
+ struct fuse_file_info ffi;
+ struct fuse_vnode *vn;
+ char *realname;
+
+ DPRINTF("Opcode:\topen\n");
+ DPRINTF("Inode:\t%i\n", fbuf->fb_ino);
+
+ CHECK_OPT(open);
+
+ bzero(&ffi, sizeof(ffi));
+ ffi.flags = fbuf->fb_io_flags;
+
+ fbuf->fb_len = FUSEFDSIZE;
+
+ vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
+
+ realname = build_realname(f, vn->ino);
+ fbuf->fb_err = f->op.open(realname, &ffi);
+ free(realname);
+
+ if (!fbuf->fb_err)
+ fbuf->fb_io_fd = ffi.fh;
+
+ DPRINTF("\n");
+ return (0);
+}
+
+static int
+ifuse_ops_opendir(struct fuse *f, struct fusebuf *fbuf)
+{
+ struct fuse_file_info ffi;
+ struct fuse_vnode *vn;
+ char *realname;
+
+ DPRINTF("Opcode:\topendir\n");
+ DPRINTF("Inode:\t%i\n", fbuf->fb_ino);
+
+ memset(&ffi, 0, sizeof(ffi));
+ ffi.flags = fbuf->fb_io_flags;
+
+ fbuf->fb_len = 0;
+
+ vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
+
+ if (f->op.opendir) {
+ realname = build_realname(f, vn->ino);
+ fbuf->fb_err = f->op.opendir(realname, &ffi);
+ free(realname);
+ }
+
+ if (!fbuf->fb_err) {
+ fbuf->fb_io_fd = ffi.fh;
+ fbuf->fb_len = FUSEFDSIZE;
+
+ vn->fd = calloc(1, sizeof(*vn->fd));
+ if (vn->fd == NULL) {
+ DPRINTF("\n");
+ return (errno);
+ }
+
+ vn->fd->filled = 0;
+ vn->fd->size = 0;
+ vn->fd->start = 0;
+ }
+
+ DPRINTF("\n");
+ return (0);
+}
+
+#define GENERIC_DIRSIZ(NLEN) \
+((sizeof (struct dirent) - (MAXNAMLEN+1)) + ((NLEN+1 + 3) &~ 3))
+
+static int
+ifuse_fill_readdir(void *dh, const char *name, const struct stat *stbuf,
+ off_t off)
+{
+ struct fuse_dirhandle *fd = dh;
+ struct fusebuf *fbuf;
+ struct dirent *dir;
+ uint32_t namelen;
+ uint32_t len;
+
+ fbuf = fd->buf;
+ namelen = strnlen(name, MAXNAMLEN);
+ len = GENERIC_DIRSIZ(namelen);
+
+ if (fd->full || fbdatsize(fbuf) + len > fd->size) {
+ fd->full = 1;
+ return (0);
+ }
+
+ if (fd->isgetdir && fd->start != 0 && fd->idx < fd->start) {
+ fd->idx += len;
+ return (0);
+ }
+
+ dir = (struct dirent *) &fbuf->fb_dat[fbdatsize(fbuf)];
+
+ if (!off)
+ fd->filled = 0;
+
+ if (stbuf) {
+ dir->d_fileno = stbuf->st_ino;
+ dir->d_type = stbuf->st_mode;
+ } else {
+ dir->d_fileno = 0xffffffff;
+ dir->d_type = 0;
+ }
+ dir->d_namlen = namelen;
+ dir->d_reclen = len;
+ memcpy(dir->d_name, name, namelen);
+
+ fbuf->fb_len += len;
+ if (fd->isgetdir) {
+ fd->start += len;
+ fd->idx += len;
+ }
+ return (0);
+}
+
+static int
+ifuse_fill_getdir(fuse_dirh_t fd, const char *name, int type, ino_t ino)
+{
+ struct stat st;
+
+ bzero(&st, sizeof(st));
+ st.st_mode = type << 12;
+ if (ino == 0)
+ st.st_ino = 0xffffffff;
+ else
+ st.st_ino = ino;
+
+ return (fd->filler(fd, name, &st, 0));
+}
+
+static int
+ifuse_ops_readdir(struct fuse *f, struct fusebuf *fbuf)
+{
+ struct fuse_file_info ffi;
+ struct fuse_vnode *vn;
+ char *realname;
+ uint64_t offset;
+ uint32_t size;
+ uint32_t startsave;
+
+ DPRINTF("Opcode:\treaddir\n");
+ DPRINTF("Inode:\t%i\n", fbuf->fb_ino);
+ DPRINTF("Offset:\t%llu\n", fbuf->fb_io_off);
+ DPRINTF("Size:\t%lu\n", fbuf->fb_io_len);
+
+ bzero(&ffi, sizeof(ffi));
+ ffi.fh = fbuf->fb_io_fd;
+ offset = fbuf->fb_io_off;
+ size = fbuf->fb_io_len;
+ startsave = 0;
+
+ fbuf->fb_len = FUSEFDSIZE;
+ bzero(fbuf->fb_dat, FUSELEN);
+
+ vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
+
+ if (!vn->fd->filled) {
+ vn->fd->filler = ifuse_fill_readdir;
+ vn->fd->buf = fbuf;
+ vn->fd->filled = 0;
+ vn->fd->full = 0;
+ vn->fd->isgetdir = 0;
+ vn->fd->size = size;
+
+ realname = build_realname(f, vn->ino);
+ if (f->op.readdir)
+ fbuf->fb_err = f->op.readdir(realname, vn->fd,
+ ifuse_fill_readdir, offset, &ffi);
+ else if (f->op.getdir) {
+ vn->fd->isgetdir = 1;
+ vn->fd->idx = 0;
+ startsave = vn->fd->start;
+ fbuf->fb_err = f->op.getdir(realname, vn->fd,
+ ifuse_fill_getdir);
+ } else
+ fbuf->fb_err = -ENOSYS;
+ free(realname);
+ }
+
+ if (!vn->fd->full && vn->fd->isgetdir && vn->fd->start == startsave)
+ vn->fd->filled = 1;
+
+ if (fbuf->fb_err) {
+ fbuf->fb_len = 0;
+ vn->fd->filled = 1;
+ }
+
+ DPRINTF("\n");
+ return (0);
+}
+
+static int
+ifuse_ops_releasedir(struct fuse *f, struct fusebuf *fbuf)
+{
+ struct fuse_file_info ffi;
+ struct fuse_vnode *vn;
+ char *realname;
+
+ DPRINTF("Opcode:\treleasedir\n");
+ DPRINTF("Inode:\t%i\n", fbuf->fb_ino);
+
+ bzero(&ffi, sizeof(ffi));
+ ffi.fh = fbuf->fb_io_fd;
+ ffi.fh_old = ffi.fh;
+ ffi.flags = fbuf->fb_io_flags;
+
+ fbuf->fb_len = 0;
+
+ vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
+
+ if (f->op.releasedir) {
+ realname = build_realname(f, vn->ino);
+ fbuf->fb_err = f->op.releasedir(realname, &ffi);
+ free(realname);
+ } else
+ fbuf->fb_err = 0;
+
+ if (!fbuf->fb_err)
+ free(vn->fd);
+
+ DPRINTF("\n");
+ return (0);
+}
+
+static int
+ifuse_ops_release(struct fuse *f, struct fusebuf *fbuf)
+{
+ struct fuse_file_info ffi;
+ struct fuse_vnode *vn;
+ char *realname;
+
+ CHECK_OPT(release);
+
+ bzero(&ffi, sizeof(ffi));
+ ffi.fh = fbuf->fb_io_fd;
+ ffi.fh_old = ffi.fh;
+ ffi.flags = fbuf->fb_io_flags;
+
+ fbuf->fb_len = 0;
+
+ vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
+
+ realname = build_realname(f, vn->ino);
+ fbuf->fb_err = f->op.release(realname, &ffi);
+ free(realname);
+
+ DPRINTF("\n");
+ return (0);
+}
+
+static int
+ifuse_ops_lookup(struct fuse *f, struct fusebuf *fbuf)
+{
+ struct fuse_vnode *vn;
+ char *realname;
+
+ DPRINTF("Opcode:\tlookup\n");
+ DPRINTF("Inode:\t%i\n", fbuf->fb_ino);
+ DPRINTF("For file %s\n", fbuf->fb_dat);
+
+ vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
+ if (vn == NULL) {
+ vn = alloc_vn(f, fbuf->fb_dat, -1, fbuf->fb_ino);
+ if (vn == NULL) {
+ fbuf->fb_err = -ENOMEM;
+ fbuf->fb_len = 0;
+ DPRINTF("\n");
+ return (0);
+ }
+ set_vn(f, vn); /*XXX*/
+ }
+
+ DPRINTF("new ino %i\n", vn->ino);
+ fbuf->fb_len = FUSEFDSIZE;
+
+ realname = build_realname(f, vn->ino);
+ fbuf->fb_err = update_vattr(f, &fbuf->fb_vattr, realname, vn);
+ free(realname);
+
+ if (fbuf->fb_err)
+ fbuf->fb_len = 0;
+
+ DPRINTF("\n");
+ return (0);
+}
+
+static int
+ifuse_ops_read(struct fuse *f, struct fusebuf *fbuf)
+{
+ struct fuse_file_info ffi;
+ struct fuse_vnode *vn;
+ char *realname;
+ uint64_t offset;
+ uint32_t size;
+ int ret;
+
+ CHECK_OPT(read);
+
+ bzero(&ffi, sizeof(ffi));
+ ffi.fh = fbuf->fb_io_fd;
+ size = fbuf->fb_io_len;
+ offset = fbuf->fb_io_off;
+
+ fbuf->fb_len = FUSEFDSIZE + size;
+
+ vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
+
+ realname = build_realname(f, vn->ino);
+ ret = f->op.read(realname, fbuf->fb_dat, size, offset, &ffi);
+ free(realname);
+ if (ret >= 0) {
+ fbuf->fb_len = FUSEFDSIZE + ret;
+ fbuf->fb_err = 0;
+ } else {
+ fbuf->fb_len = 0;
+ fbuf->fb_err = ret;
+ }
+
+ DPRINTF("\n");
+ return (0);
+}
+
+static int
+ifuse_ops_write(struct fuse *f, struct fusebuf *fbuf)
+{
+ struct fuse_file_info ffi;
+ struct fuse_vnode *vn;
+ char *realname;
+ uint64_t offset;
+ uint32_t size;
+ int ret;
+
+ CHECK_OPT(write);
+
+ bzero(&ffi, sizeof(ffi));
+ ffi.fh = fbuf->fb_io_fd;
+ ffi.fh_old = ffi.fh;
+ ffi.writepage = fbuf->fb_io_flags & 1;
+ size = fbuf->fb_io_len;
+ offset = fbuf->fb_io_off;
+
+ fbuf->fb_len = 0;
+
+ vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
+
+ realname = build_realname(f, vn->ino);
+ ret = f->op.write(realname, fbuf->fb_dat, size, offset, &ffi);
+ free(realname);
+
+ if (ret >= 0) {
+ fbuf->fb_io_len = ret;
+ fbuf->fb_err = 0;
+
+ fbuf->fb_len = FUSEFDSIZE;
+ } else
+ fbuf->fb_err = ret;
+
+ DPRINTF("\n");
+ return (0);
+}
+
+static int
+ifuse_ops_create(struct fuse *f, struct fusebuf *fbuf)
+{
+ struct fuse_file_info ffi;
+ struct fuse_vnode *vn;
+ uint32_t mode;
+
+ char *realname;
+
+ CHECK_OPT(create);
+
+ bzero(&ffi, sizeof(ffi));
+ ffi.flags = fbuf->fb_io_flags;
+ mode = fbuf->fb_io_mode;
+ vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
+
+ fbuf->fb_len = 0;
+
+ realname = build_realname(f, vn->ino);
+ fbuf->fb_err = f->op.create(realname, mode, &ffi);
+
+ if (!fbuf->fb_err) {
+ fbuf->fb_err = update_vattr(f, &fbuf->fb_vattr, realname, vn);
+ fbuf->fb_ino = fbuf->fb_vattr.va_fileid;
+ fbuf->fb_io_mode = fbuf->fb_vattr.va_mode;
+
+ if (!fbuf->fb_err)
+ fbuf->fb_len = FUSEFDSIZE;
+ }
+ free(realname);
+
+ DPRINTF("\n");
+ return (0);
+}
+
+static int
+ifuse_ops_mkdir(struct fuse *f, struct fusebuf *fbuf)
+{
+ struct fuse_vnode *vn;
+ char *realname;
+ uint32_t mode;
+
+ CHECK_OPT(mkdir);
+
+ mode = fbuf->fb_io_mode;
+ vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
+
+ fbuf->fb_len = 0;
+
+ realname = build_realname(f, vn->ino);
+ fbuf->fb_err = f->op.mkdir(realname, mode);
+
+ if (!fbuf->fb_err) {
+ fbuf->fb_err = update_vattr(f, &fbuf->fb_vattr, realname, vn);
+ fbuf->fb_io_mode = fbuf->fb_vattr.va_mode;
+ fbuf->fb_ino = vn->ino;
+
+ if (!fbuf->fb_err)
+ fbuf->fb_len = FUSEFDSIZE;
+ }
+ free(realname);
+
+ DPRINTF("\n");
+ return (0);
+}
+
+static int
+ifuse_ops_rmdir(struct fuse *f, struct fusebuf *fbuf)
+{
+ struct fuse_vnode *vn;
+ char *realname;
+
+ CHECK_OPT(rmdir);
+
+ fbuf->fb_len = 0;
+
+ vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
+
+ realname = build_realname(f, vn->ino);
+ fbuf->fb_err = f->op.rmdir(realname);
+ free(realname);
+
+ DPRINTF("\n");
+ return (0);
+}
+
+static int
+ifuse_ops_readlink(struct fuse *f, struct fusebuf *fbuf)
+{
+ struct fuse_vnode *vn;
+ char *realname;
+ char name[PATH_MAX + 1];
+ int len, ret;
+
+ DPRINTF("Opcode:\treadlink\n");
+ DPRINTF("Inode:\t%i\n", fbuf->fb_ino);
+
+ vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
+
+ realname = build_realname(f, vn->ino);
+ if (f->op.readlink)
+ ret = f->op.readlink(realname, name, sizeof(name));
+ else
+ ret = -ENOSYS;
+ free(realname);
+
+ if (!ret)
+ len = strnlen(name, PATH_MAX);
+ else
+ len = -1;
+
+ fbuf->fb_len = FUSEFDSIZE + len + 1;
+ fbuf->fb_err = ret;
+
+ if (!ret) {
+ memcpy(fbuf->fb_dat, name, len);
+ fbuf->fb_dat[len] = '\0';
+ } else
+ fbuf->fb_len = 0;
+
+ DPRINTF("\n");
+ return (0);
+}
+
+static int
+ifuse_ops_unlink(struct fuse *f, struct fusebuf *fbuf)
+{
+ struct fuse_vnode *vn;
+ char *realname;
+
+ fbuf->fb_len = 0;
+
+ CHECK_OPT(unlink);
+
+ vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
+
+ realname = build_realname(f, vn->ino);
+ fbuf->fb_err = f->op.unlink(realname);
+ free(realname);
+
+ DPRINTF("\n");
+ return (0);
+}
+
+static int
+ifuse_ops_statfs(struct fuse *f, struct fusebuf *fbuf)
+{
+ struct fuse_vnode *vn;
+ char *realname;
+
+ fbuf->fb_len = FUSEFDSIZE;
+ bzero(&fbuf->fb_stat, sizeof(fbuf->fb_stat));
+
+ CHECK_OPT(statfs);
+
+ vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
+
+ realname = build_realname(f, vn->ino);
+ fbuf->fb_err = f->op.statfs(realname, &fbuf->fb_stat);
+ free(realname);
+
+ if (fbuf->fb_err)
+ fbuf->fb_len = 0;
+
+ DPRINTF("\n");
+ return (0);
+}
+
+static int
+ifuse_ops_link(struct fuse *f, struct fusebuf *fbuf)
+{
+ struct fuse_vnode *vn;
+ char *realname;
+ char *realname_ln;
+ ino_t oldnodeid;
+
+ CHECK_OPT(link);
+ oldnodeid = fbuf->fb_io_ino;
+ vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
+
+ fbuf->fb_len = 0;
+
+ realname = build_realname(f, oldnodeid);
+ realname_ln = build_realname(f, vn->ino);
+ fbuf->fb_err = f->op.link(realname, realname_ln);
+ free(realname);
+ free(realname_ln);
+
+ DPRINTF("\n");
+ return (0);
+}
+
+static int
+ifuse_ops_setattr(struct fuse *f, struct fusebuf *fbuf)
+{
+ struct fuse_vnode *vn;
+ struct timespec ts[2];
+ struct utimbuf tbuf;
+ struct fb_io *io;
+ char *realname;
+ uid_t uid;
+ gid_t gid;
+
+ DPRINTF("Opcode:\tsetattr\n");
+ DPRINTF("Inode:\t%i\n", fbuf->fb_ino);
+
+ vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
+ realname = build_realname(f, vn->ino);
+ io = fbtod(fbuf, struct fb_io *);
+
+ if (io->fi_flags & FUSE_FATTR_MODE) {
+ if (f->op.chmod)
+ fbuf->fb_err = f->op.chmod(realname,
+ fbuf->fb_vattr.va_mode);
+ else
+ fbuf->fb_err = -ENOSYS;
+ }
+
+ if (!fbuf->fb_err && (io->fi_flags & FUSE_FATTR_UID ||
+ io->fi_flags & FUSE_FATTR_GID) ) {
+ uid = (io->fi_flags & FUSE_FATTR_UID) ?
+ fbuf->fb_vattr.va_uid : (gid_t)-1;
+ gid = (io->fi_flags & FUSE_FATTR_GID) ?
+ fbuf->fb_vattr.va_gid : (uid_t)-1;
+ if (f->op.chown)
+ fbuf->fb_err = f->op.chown(realname, uid, gid);
+ else
+ fbuf->fb_err = -ENOSYS;
+ }
+
+ if (!fbuf->fb_err && ( io->fi_flags & FUSE_FATTR_MTIME ||
+ io->fi_flags & FUSE_FATTR_ATIME)) {
+ ts[0].tv_sec = fbuf->fb_vattr.va_atime.tv_sec;
+ ts[0].tv_nsec = fbuf->fb_vattr.va_atime.tv_nsec;
+ ts[1].tv_sec = fbuf->fb_vattr.va_mtime.tv_sec;
+ ts[1].tv_nsec = fbuf->fb_vattr.va_mtime.tv_nsec;
+ tbuf.actime = ts[0].tv_sec;
+ tbuf.modtime = ts[1].tv_sec;
+
+ if (f->op.utimens)
+ fbuf->fb_err = f->op.utimens(realname, ts);
+ else if (f->op.utime)
+ fbuf->fb_err = f->op.utime(realname, &tbuf);
+ else
+ fbuf->fb_err = -ENOSYS;
+ }
+
+ fbuf->fb_len = FUSEFDSIZE;
+ bzero(&fbuf->fb_vattr, sizeof(fbuf->fb_vattr));
+
+ if (!fbuf->fb_err)
+ fbuf->fb_err = update_vattr(f, &fbuf->fb_vattr, realname, vn);
+ free(realname);
+
+ if (fbuf->fb_err)
+ fbuf->fb_len = 0;
+
+ DPRINTF("\n");
+ return (0);
+}
+
+static int
+ifuse_ops_symlink(unused struct fuse *f, struct fusebuf *fbuf)
+{
+ struct fuse_vnode *vn;
+ char *realname;
+ int len;
+
+ CHECK_OPT(symlink);
+
+ vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
+ len = strlen(fbuf->fb_dat);
+ fbuf->fb_len = 0;
+
+ realname = build_realname(f, vn->ino);
+ /* fuse invert the symlink params */
+ fbuf->fb_err = f->op.symlink(&fbuf->fb_dat[len + 1], realname);
+ fbuf->fb_ino = vn->ino;
+ free(realname);
+
+ DPRINTF("\n");
+ return (0);
+}
+
+static int
+ifuse_ops_destroy(struct fuse *f, struct fusebuf *fbuf)
+{
+ DPRINTF("Opcode:\tdestroy\n");
+
+ fbuf->fb_len = 0;
+
+ fbuf->fb_err = 0;
+ f->fc->dead = 1;
+
+ DPRINTF("\n");
+ return (0);
+}
+
+int
+ifuse_exec_opcode(struct fuse *f, struct fusebuf *fbuf)
+{
+ int ret = 0;
+
+ switch (fbuf->fb_type) {
+ case FBT_LOOKUP:
+ ret = ifuse_ops_lookup(f, fbuf);
+ break;
+ case FBT_GETATTR:
+ ret = ifuse_ops_getattr(f, fbuf);
+ break;
+ case FBT_SETATTR:
+ ret = ifuse_ops_setattr(f, fbuf);
+ break;
+ case FBT_READLINK:
+ ret = ifuse_ops_readlink(f, fbuf);
+ break;
+ case FBT_MKDIR:
+ ret = ifuse_ops_mkdir(f, fbuf);
+ break;
+ case FBT_UNLINK:
+ ret = ifuse_ops_unlink(f, fbuf);
+ break;
+ case FBT_RMDIR:
+ ret = ifuse_ops_rmdir(f, fbuf);
+ break;
+ case FBT_LINK:
+ ret = ifuse_ops_link(f, fbuf);
+ break;
+ case FBT_OPEN:
+ ret = ifuse_ops_open(f, fbuf);
+ break;
+ case FBT_READ:
+ ret = ifuse_ops_read(f, fbuf);
+ break;
+ case FBT_WRITE:
+ ret = ifuse_ops_write(f, fbuf);
+ break;
+ case FBT_STATFS:
+ ret = ifuse_ops_statfs(f, fbuf);
+ break;
+ case FBT_RELEASE:
+ ret = ifuse_ops_release(f, fbuf);
+ break;
+ case FBT_INIT:
+ ret = ifuse_ops_init(fbuf);
+ break;
+ case FBT_OPENDIR:
+ ret = ifuse_ops_opendir(f, fbuf);
+ break;
+ case FBT_READDIR:
+ ret = ifuse_ops_readdir(f, fbuf);
+ break;
+ case FBT_RELEASEDIR:
+ ret = ifuse_ops_releasedir(f, fbuf);
+ break;
+ case FBT_ACCESS:
+ ret = ifuse_ops_access(f, fbuf);
+ break;
+ case FBT_CREATE:
+ ret = ifuse_ops_create(f, fbuf);
+ break;
+ case FBT_SYMLINK:
+ ret = ifuse_ops_symlink(f, fbuf);
+ break;
+ case FBT_DESTROY:
+ ret = ifuse_ops_destroy(f, fbuf);
+ break;
+ default:
+ DPRINTF("Opcode:\t%i not supported\n", fbuf->fb_type);
+ DPRINTF("Inode:\t%i\n", fbuf->fb_ino);
+
+ fbuf->fb_err = -ENOSYS;
+ fbuf->fb_len = 0;
+ DPRINTF("\n");
+ }
+
+ /* fuse api use negative errno */
+ fbuf->fb_err = -fbuf->fb_err;
+ return (ret);
+}
diff --git a/lib/libfuse/fuse_private.h b/lib/libfuse/fuse_private.h
new file mode 100644
index 00000000000..7ce0d5426d7
--- /dev/null
+++ b/lib/libfuse/fuse_private.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _FUSE_SUBR_H_
+#define _FUSE_SUBR_H_
+
+#include <sys/param.h>
+#include <sys/dirent.h>
+#include <sys/mount.h>
+#include <sys/statvfs.h>
+#include <sys/vnode.h>
+#include <sys/fusebuf.h>
+
+#include "fuse.h"
+
+struct fuse_dirhandle;
+
+struct fuse_vnode {
+ ino_t ino;
+ ino_t parent;
+
+ char path[NAME_MAX];
+ struct fuse_dirhandle *fd;
+
+ SIMPLEQ_ENTRY(fuse_vnode) node; /* for dict */
+};
+
+SIMPLEQ_HEAD(fuse_vn_head, fuse_vnode);
+SPLAY_HEAD(dict, dictentry);
+SPLAY_HEAD(tree, treeentry);
+
+struct fuse_args {
+ int argc;
+ char **argv;
+ int allocated;
+};
+
+struct fuse_session {
+ void *args;
+};
+
+struct fuse_chan {
+ char *dir;
+ struct fuse_args *args;
+
+ int fd;
+ int dead;
+
+ /* kqueue stuff */
+ int kq;
+ struct kevent event;
+};
+
+struct fuse_config {
+ uid_t uid;
+ gid_t gid;
+ mode_t umask;
+ int set_mode;
+ int set_uid;
+ int set_gid;
+};
+
+struct fuse {
+ struct fuse_chan *fc;
+ struct fuse_operations op;
+
+ int compat;
+
+ struct tree vnode_tree;
+ struct dict name_tree;
+ uint64_t max_ino;
+
+ struct fuse_config conf;
+ struct fuse_session se;
+};
+
+#define FUSE_MAX_OPS 39
+#define FUSE_ROOT_INO ((ino_t)1)
+
+/* fuse_ops.c */
+int ifuse_exec_opcode(struct fuse *, struct fusebuf *);
+
+/* fuse_subr.c */
+struct fuse_vnode *alloc_vn(struct fuse *, const char *, ino_t, ino_t);
+struct fuse_vnode *get_vn_by_name_and_parent(struct fuse *, const char *,
+ ino_t);
+int set_vn(struct fuse *, struct fuse_vnode *);
+char *build_realname(struct fuse *, ino_t);
+
+/* tree.c */
+#define tree_init(t) SPLAY_INIT((t))
+#define tree_empty(t) SPLAY_EMPTY((t))
+int tree_check(struct tree *, uint64_t);
+void *tree_set(struct tree *, uint64_t, void *);
+void *tree_get(struct tree *, uint64_t);;
+void *tree_pop(struct tree *, uint64_t);
+
+/* dict.c */
+int dict_check(struct dict *, const char *);
+void *dict_set(struct dict *, const char *, void *);
+void *dict_get(struct dict *, const char *);;
+void *dict_pop(struct dict *, const char *);
+
+#define FUSE_VERSION_PKG_INFO "2.6.9"
+#define unused __attribute__ ((unused))
+
+#endif /* _FUSE_SUBR_ */
diff --git a/lib/libfuse/fuse_subr.c b/lib/libfuse/fuse_subr.c
new file mode 100644
index 00000000000..2124043697c
--- /dev/null
+++ b/lib/libfuse/fuse_subr.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "fuse_private.h"
+#include "debug.h"
+
+struct fuse_vnode *
+alloc_vn(struct fuse *f, const char *path, ino_t ino, ino_t parent)
+{
+ struct fuse_vnode *vn;
+
+ DPRINTF("%s %i@%i = %s\n", __func__, ino, parent, path);
+ if ((vn = malloc(sizeof(*vn))) == NULL) {
+ DPERROR("alloc_vn:");
+ return (NULL);
+ }
+
+ vn->ino = ino;
+ vn->parent = parent;
+ strncpy(vn->path, path, NAME_MAX);
+ vn->path[NAME_MAX - 1] = '\0';
+ if (ino == (ino_t)-1) {
+ f->max_ino++;
+ vn->ino = f->max_ino;
+ }
+
+ return (vn);
+}
+
+int
+set_vn(struct fuse *f, struct fuse_vnode *v)
+{
+ struct fuse_vn_head *vn_head;
+ struct fuse_vnode *vn;
+
+ DPRINTF("%s: create or update vnode %i%i = %s\n", __func__, v->ino,
+ v->parent, v->path);
+
+ if (tree_set(&f->vnode_tree, v->ino, v) == NULL)
+ return (0);
+
+ if (!dict_check(&f->name_tree, v->path)) {
+ vn_head = malloc(sizeof(*vn_head));
+ if (vn_head == NULL)
+ return (0);
+ SIMPLEQ_INIT(vn_head);
+ } else {
+ vn_head = dict_get(&f->name_tree, v->path);
+ if (vn_head == NULL)
+ return (0);
+ }
+
+ SIMPLEQ_FOREACH(vn, vn_head, node) {
+ if (v->parent == vn->parent && v->ino == vn->ino)
+ return (1);
+ }
+
+ SIMPLEQ_INSERT_TAIL(vn_head, v, node);
+ dict_set(&f->name_tree, v->path, vn_head);
+
+ return (1);
+}
+
+struct fuse_vnode *
+get_vn_by_name_and_parent(struct fuse *f, const char *path, ino_t parent)
+{
+ struct fuse_vn_head *vn_head;
+ struct fuse_vnode *v = NULL;
+
+ DPRINTF("%s %i = %s\n", __func__, parent, path);
+ vn_head = dict_get(&f->name_tree, path);
+
+ if (vn_head == NULL)
+ return (NULL);
+
+ SIMPLEQ_FOREACH(v, vn_head, node)
+ if (v->parent == parent)
+ return (v);
+
+ return (NULL);
+}
+
+char *
+build_realname(struct fuse *f, ino_t ino)
+{
+ struct fuse_vnode *vn;
+ char *name = strdup("/");
+ char *tmp = NULL;
+ int firstshot = 0;
+
+ vn = tree_get(&f->vnode_tree, ino);
+ if (!vn || !name) {
+ free(name);
+ return (NULL);
+ }
+
+ while (vn->parent != 0) {
+ if (firstshot++)
+ asprintf(&tmp, "/%s%s", vn->path, name);
+ else
+ asprintf(&tmp, "/%s", vn->path);
+
+ if (tmp == NULL) {
+ free(name);
+ return (NULL);
+ }
+
+ free(name);
+ name = tmp;
+ tmp = NULL;
+ vn = tree_get(&f->vnode_tree, vn->parent);
+
+ if (!vn)
+ return (NULL);
+ }
+
+ if (ino == (ino_t)0)
+ DPRINTF("%s: NULL ino\n", __func__);
+
+ DPRINTF("realname %s\n", name);
+ return (name);
+}
diff --git a/lib/libfuse/generate_pkgconfig.sh b/lib/libfuse/generate_pkgconfig.sh
new file mode 100644
index 00000000000..15c44b297b9
--- /dev/null
+++ b/lib/libfuse/generate_pkgconfig.sh
@@ -0,0 +1,70 @@
+#!/bin/sh
+#
+# $OpenBSD: generate_pkgconfig.sh,v 1.1 2013/06/03 16:00:50 tedu Exp $
+#
+# Copyright (c) 2010,2011 Jasper Lievisse Adriaanse <jasper@openbsd.org>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+# Generate pkg-config file for zlib.
+
+usage() {
+ echo "usage: ${0##*/} -c current_directory -o obj_directory"
+ exit 1
+}
+
+curdir=
+objdir=
+while getopts "c:o:" flag; do
+ case "$flag" in
+ c)
+ curdir=$OPTARG
+ ;;
+ o)
+ objdir=$OPTARG
+ ;;
+ *)
+ usage
+ ;;
+ esac
+done
+
+[ -n "${curdir}" ] || usage
+if [ ! -d "${curdir}" ]; then
+ echo "${0##*/}: ${curdir}: not found"
+ exit 1
+fi
+[ -n "${objdir}" ] || usage
+if [ ! -w "${objdir}" ]; then
+ echo "${0##*/}: ${objdir}: not found or not writable"
+ exit 1
+fi
+
+version_re="s/^#define[[:blank:]]+FUSE_VERSION_PKG_INFO[[:blank:]]+\"(.*)\".*/\1/p"
+version_file=${curdir}/fuse_private.h
+lib_version=$(sed -nE ${version_re} ${version_file})
+
+pc_file="${objdir}/fuse.pc"
+cat > ${pc_file} << __EOF__
+prefix=/usr
+exec_prefix=\${prefix}
+libdir=\${exec_prefix}/lib
+includedir=\${prefix}/include
+
+Name: fuse
+Description: fuse filesystem library
+Version: ${lib_version}
+Requires:
+Libs: -L\${libdir} -lfuse
+Cflags: -I\${includedir}
+__EOF__
diff --git a/lib/libfuse/shlib_version b/lib/libfuse/shlib_version
new file mode 100644
index 00000000000..97c9f92d6b8
--- /dev/null
+++ b/lib/libfuse/shlib_version
@@ -0,0 +1,2 @@
+major=0
+minor=0
diff --git a/lib/libfuse/tree.c b/lib/libfuse/tree.c
new file mode 100644
index 00000000000..8050f6da6e9
--- /dev/null
+++ b/lib/libfuse/tree.c
@@ -0,0 +1,100 @@
+/* $OpenBSD: tree.c,v 1.1 2013/06/03 16:00:50 tedu Exp $ */
+
+/*
+ * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+
+#include "fuse_private.h"
+
+struct treeentry {
+ SPLAY_ENTRY(treeentry) entry;
+ uint64_t id;
+ void *data;
+};
+
+static int treeentry_cmp(struct treeentry *, struct treeentry *);
+
+SPLAY_PROTOTYPE(tree, treeentry, entry, treeentry_cmp);
+
+int
+tree_check(struct tree *t, uint64_t id)
+{
+ struct treeentry key;
+
+ key.id = id;
+ return (SPLAY_FIND(tree, t, &key) != NULL);
+}
+
+void *
+tree_set(struct tree *t, uint64_t id, void *data)
+{
+ struct treeentry *entry, key;
+
+ key.id = id;
+ if ((entry = SPLAY_FIND(tree, t, &key)) == NULL) {
+ entry = malloc(sizeof *entry);
+ if (entry == NULL)
+ return (NULL);
+ entry->id = id;
+ SPLAY_INSERT(tree, t, entry);
+ }
+
+ entry->data = data;
+
+ return (entry);
+}
+
+void *
+tree_get(struct tree *t, uint64_t id)
+{
+ struct treeentry key, *entry;
+
+ key.id = id;
+ if ((entry = SPLAY_FIND(tree, t, &key)) == NULL)
+ return (NULL);
+
+ return (entry->data);
+}
+
+void *
+tree_pop(struct tree *t, uint64_t id)
+{
+ struct treeentry key, *entry;
+ void *data;
+
+ key.id = id;
+ if ((entry = SPLAY_FIND(tree, t, &key)) == NULL)
+ return (NULL);
+
+ data = entry->data;
+ SPLAY_REMOVE(tree, t, entry);
+ free(entry);
+
+ return (data);
+}
+
+static int
+treeentry_cmp(struct treeentry *a, struct treeentry *b)
+{
+ if (a->id < b->id)
+ return (-1);
+ if (a->id > b->id)
+ return (1);
+ return (0);
+}
+
+SPLAY_GENERATE(tree, treeentry, entry, treeentry_cmp);