cleanups
diff --git a/.cvsignore b/.cvsignore
index 5743e9b..d6dac71 100644
--- a/.cvsignore
+++ b/.cvsignore
@@ -1,2 +1,2 @@
-fusepro
+fusexmp
 avfsd
diff --git a/Makefile b/Makefile
index 97d19d4..92d91ad 100644
--- a/Makefile
+++ b/Makefile
@@ -1,14 +1,12 @@
 CC = gcc
 CFLAGS = -Wall -g `glib-config --cflags`
-LDFLAGS = `glib-config --libs` -ldl -L ../avfs/libneon/
+LDFLAGS = `glib-config --libs` -ldl -L ../avfs/libneon/ -L lib
 #LIBXML = -lxml
 LIBXML = -lxmltok -lxmlparse
-LDLIBS = -lneon $(LIBXML) -lpthread
+LDLIBS = -lneon $(LIBXML) -lfuse -lpthread
 CPPFLAGS = -Iinclude -I ../avfs/include
 
-
-
-all: kernel/fuse.o fusepro avfsd
+all: kernel/fuse.o fusexmp avfsd
 
 kernel/fuse.o: FORCE
 	make -C kernel fuse.o
@@ -16,15 +14,21 @@
 lib/libfuse.a: FORCE
 	make -C lib libfuse.a
 
-fusepro: fusepro.o lib/libfuse.a
+lib/libfuse.so: FORCE
+	make -C lib libfuse.so
 
-avfsd: usermux.o avfsd.o ../avfs/lib/avfs.o lib/libfuse.a 
+fusexmp: fusexmp.o lib/libfuse.so
+	gcc $(CFLAGS) $(LDFLAGS) -o fusexmp fusexmp.o $(LDLIBS)
+
+avfsd_objs = usermux.o avfsd.o ../avfs/lib/avfs.o
+avfsd: $(avfsd_objs) lib/libfuse.so
+	gcc $(CFLAGS) $(LDFLAGS) -o avfsd $(avfsd_objs) $(LDLIBS)
 
 clean:
 	make -C kernel clean
 	make -C lib clean
 	rm -f *.o
-	rm -f fusepro avfsd
+	rm -f fusexmp avfsd
 	rm -f *~
 
 FORCE:
diff --git a/fusepro.c b/fusepro.c
deleted file mode 100644
index ce32000..0000000
--- a/fusepro.c
+++ /dev/null
@@ -1,314 +0,0 @@
-#ifdef linux
-/* For pread()/pwrite() */
-#define _XOPEN_SOURCE 500
-#endif
-
-#include <fuse.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <errno.h>
-#include <signal.h>
-#include <utime.h>
-#include <fcntl.h>
-
-static struct fuse *pro_fuse;
-
-static int pro_getattr(struct fuse_cred *cred, const char *path,
-                       struct stat *stbuf)
-{
-    int res;
-
-    res = lstat(path, stbuf);
-    if(res == -1)
-        return -errno;
-
-    return 0;
-}
-
-static int pro_readlink(struct fuse_cred *cred, 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 pro_getdir(struct fuse_cred *cred, const char *path, fuse_dirh_t h,
-                      fuse_dirfil_t filler)
-{
-    DIR *dp;
-    struct dirent *de;
-    int res;
-
-    dp = opendir(path);
-    if(dp == NULL)
-        return -errno;
-
-    while((de = readdir(dp)) != NULL) {
-        res = filler(h, de->d_name, de->d_type);
-        if(res != 0)
-            break;
-    }
-
-    closedir(dp);
-    return res;
-}
-
-static int pro_mknod(struct fuse_cred *cred, const char *path, mode_t mode,
-                     dev_t rdev)
-{
-    int res;
-
-    res = mknod(path, mode, rdev);
-    if(res == -1)
-        return -errno;
-
-    return 0;
-}
-
-static int pro_mkdir(struct fuse_cred *cred, const char *path, mode_t mode)
-{
-    int res;
-
-    res = mkdir(path, mode);
-    if(res == -1)
-        return -errno;
-
-    return 0;
-}
-
-static int pro_unlink(struct fuse_cred *cred, const char *path)
-{
-    int res;
-
-    res = unlink(path);
-    if(res == -1)
-        return -errno;
-
-    return 0;
-}
-
-static int pro_rmdir(struct fuse_cred *cred, const char *path)
-{
-    int res;
-
-    res = rmdir(path);
-    if(res == -1)
-        return -errno;
-
-    return 0;
-}
-
-static int pro_symlink(struct fuse_cred *cred, const char *from,
-                       const char *to)
-{
-    int res;
-
-    res = symlink(from, to);
-    if(res == -1)
-        return -errno;
-
-    return 0;
-}
-
-static int pro_rename(struct fuse_cred *cred, const char *from, const char *to)
-{
-    int res;
-
-    res = rename(from, to);
-    if(res == -1)
-        return -errno;
-
-    return 0;
-}
-
-static int pro_link(struct fuse_cred *cred, const char *from, const char *to)
-{
-    int res;
-
-    res = link(from, to);
-    if(res == -1)
-        return -errno;
-
-    return 0;
-}
-
-static int pro_chmod(struct fuse_cred *cred, const char *path, mode_t mode)
-{
-    int res;
-
-    res = chmod(path, mode);
-    if(res == -1)
-        return -errno;
-    
-    return 0;
-}
-
-static int pro_chown(struct fuse_cred *cred, 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 pro_truncate(struct fuse_cred *cred, const char *path, off_t size)
-{
-    int res;
-    
-    res = truncate(path, size);
-    if(res == -1)
-        return -errno;
-
-    return 0;
-}
-
-static int pro_utime(struct fuse_cred *cred, const char *path,
-                     struct utimbuf *buf)
-{
-    int res;
-    
-    res = utime(path, buf);
-    if(res == -1)
-        return -errno;
-
-    return 0;
-}
-
-
-static int pro_open(struct fuse_cred *cred, const char *path, int flags)
-{
-    int res;
-
-    res = open(path, flags);
-    if(res == -1) 
-        return -errno;
-
-    close(res);
-    return 0;
-}
-
-static int pro_read(struct fuse_cred *cred, const char *path, char *buf,
-                    size_t size, off_t offset)
-{
-    int fd;
-    int res;
-
-    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 pro_write(struct fuse_cred *cred, const char *path, const char *buf,
-                     size_t size, off_t offset)
-{
-    int fd;
-    int res;
-
-    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 void exit_handler()
-{
-    exit(0);
-}
-
-static void set_signal_handlers()
-{
-    struct sigaction sa;
-
-    sa.sa_handler = exit_handler;
-    sigemptyset(&(sa.sa_mask));
-    sa.sa_flags = 0;
-
-    if (sigaction(SIGHUP, &sa, NULL) == -1 || 
-	sigaction(SIGINT, &sa, NULL) == -1 || 
-	sigaction(SIGTERM, &sa, NULL) == -1) {
-	
-	perror("Cannot set exit signal handlers");
-        exit(1);
-    }
-
-    sa.sa_handler = SIG_IGN;
-    
-    if(sigaction(SIGPIPE, &sa, NULL) == -1) {
-	perror("Cannot set ignored signals");
-        exit(1);
-    }
-}
-
-static void cleanup()
-{
-    fuse_unmount(pro_fuse);
-    fuse_destroy(pro_fuse);
-}
-
-static struct fuse_operations pro_oper = {
-    getattr:	pro_getattr,
-    readlink:	pro_readlink,
-    getdir:     pro_getdir,
-    mknod:	pro_mknod,
-    mkdir:	pro_mkdir,
-    symlink:	pro_symlink,
-    unlink:	pro_unlink,
-    rmdir:	pro_rmdir,
-    rename:     pro_rename,
-    link:	pro_link,
-    chmod:	pro_chmod,
-    chown:	pro_chown,
-    truncate:	pro_truncate,
-    utime:	pro_utime,
-    open:	pro_open,
-    read:	pro_read,
-    write:	pro_write,
-};
-
-int main(int argc, char *argv[])
-{
-    int res;
-    if(argc != 2) {
-        fprintf(stderr, "usage: %s mount_dir\n", argv[0]);
-        exit(1);
-    }
-
-    set_signal_handlers();
-    atexit(cleanup);
-
-    pro_fuse = fuse_new(0);
-    res = fuse_mount(pro_fuse, argv[1]);
-    if(res == -1)
-        exit(1);
-        
-    fuse_set_operations(pro_fuse, &pro_oper);
-    fuse_loop(pro_fuse);
-
-    return 0;
-}
diff --git a/fusexmp.c b/fusexmp.c
new file mode 100644
index 0000000..b00039d
--- /dev/null
+++ b/fusexmp.c
@@ -0,0 +1,410 @@
+#ifdef linux
+/* For pread()/pwrite() */
+#define _XOPEN_SOURCE 500
+#endif
+
+/* For setgroups() */
+#define _BSD_SOURCE
+
+#include <fuse.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <signal.h>
+#include <utime.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <sys/fsuid.h>
+
+static struct fuse *xmp_fuse;
+
+static int set_creds(struct fuse_cred *cred)
+{
+    int res;
+
+    res = setfsuid(cred->uid);
+    if(res == -1)
+        return -errno;
+
+    res = setfsgid(cred->gid);
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+static void restore_creds()
+{
+    setfsuid(getuid());
+    setfsgid(getgid());
+}
+
+static int xmp_getattr(struct fuse_cred *cred, const char *path,
+                       struct stat *stbuf)
+{
+    int res;
+
+    res = set_creds(cred);
+    if(res)
+        return res;
+    res = lstat(path, stbuf);
+    restore_creds();
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+static int xmp_readlink(struct fuse_cred *cred, const char *path, char *buf,
+                        size_t size)
+{
+    int res;
+
+    res = set_creds(cred);
+    if(res)
+        return res;
+    res = readlink(path, buf, size - 1);
+    restore_creds();
+    if(res == -1)
+        return -errno;
+
+    buf[res] = '\0';
+    return 0;
+}
+
+
+static int xmp_getdir(struct fuse_cred *cred, const char *path, fuse_dirh_t h,
+                      fuse_dirfil_t filler)
+{
+    DIR *dp;
+    struct dirent *de;
+    int res;
+
+    res = set_creds(cred);
+    if(res)
+        return res;
+    dp = opendir(path);
+    restore_creds();
+    if(dp == NULL)
+        return -errno;
+
+    while((de = readdir(dp)) != NULL) {
+        res = filler(h, de->d_name, de->d_type);
+        if(res != 0)
+            break;
+    }
+
+    closedir(dp);
+    return res;
+}
+
+static int xmp_mknod(struct fuse_cred *cred, const char *path, mode_t mode,
+                     dev_t rdev)
+{
+    int res;
+
+    res = set_creds(cred);
+    if(res)
+        return res;
+    res = mknod(path, mode, rdev);
+    restore_creds();
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+static int xmp_mkdir(struct fuse_cred *cred, const char *path, mode_t mode)
+{
+    int res;
+
+    res = set_creds(cred);
+    if(res)
+        return res;
+    res = mkdir(path, mode);
+    restore_creds();
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+static int xmp_unlink(struct fuse_cred *cred, const char *path)
+{
+    int res;
+
+    res = set_creds(cred);
+    if(res)
+        return res;
+    res = unlink(path);
+    restore_creds();
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+static int xmp_rmdir(struct fuse_cred *cred, const char *path)
+{
+    int res;
+
+    res = set_creds(cred);
+    if(res)
+        return res;
+    res = rmdir(path);
+    restore_creds();
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+static int xmp_symlink(struct fuse_cred *cred, const char *from,
+                       const char *to)
+{
+    int res;
+
+    res = set_creds(cred);
+    if(res)
+        return res;
+    res = symlink(from, to);
+    restore_creds();
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+static int xmp_rename(struct fuse_cred *cred, const char *from, const char *to)
+{
+    int res;
+
+    res = set_creds(cred);
+    if(res)
+        return res;
+    res = rename(from, to);
+    restore_creds();
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+static int xmp_link(struct fuse_cred *cred, const char *from, const char *to)
+{
+    int res;
+
+    res = set_creds(cred);
+    if(res)
+        return res;
+    res = link(from, to);
+    restore_creds();
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+static int xmp_chmod(struct fuse_cred *cred, const char *path, mode_t mode)
+{
+    int res;
+
+    res = set_creds(cred);
+    if(res)
+        return res;
+    res = chmod(path, mode);
+    restore_creds();
+    if(res == -1)
+        return -errno;
+    
+    return 0;
+}
+
+static int xmp_chown(struct fuse_cred *cred, const char *path, uid_t uid,
+                     gid_t gid)
+{
+    int res;
+
+    res = set_creds(cred);
+    if(res)
+        return res;
+    res = lchown(path, uid, gid);
+    restore_creds();
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+static int xmp_truncate(struct fuse_cred *cred, const char *path, off_t size)
+{
+    int res;
+    
+    res = set_creds(cred);
+    if(res)
+        return res;
+    res = truncate(path, size);
+    restore_creds();
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+static int xmp_utime(struct fuse_cred *cred, const char *path,
+                     struct utimbuf *buf)
+{
+    int res;
+    
+    res = set_creds(cred);
+    if(res)
+        return res;
+    res = utime(path, buf);
+    restore_creds();
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+
+static int xmp_open(struct fuse_cred *cred, const char *path, int flags)
+{
+    int res;
+
+    res = set_creds(cred);
+    if(res)
+        return res;
+    res = open(path, flags);
+    restore_creds();
+    if(res == -1) 
+        return -errno;
+
+    close(res);
+    return 0;
+}
+
+static int xmp_read(struct fuse_cred *cred, const char *path, char *buf,
+                    size_t size, off_t offset)
+{
+    int fd;
+    int res;
+
+    res = set_creds(cred);
+    if(res)
+        return res;
+    fd = open(path, O_RDONLY);
+    restore_creds();
+    if(fd == -1)
+        return -errno;
+
+    res = pread(fd, buf, size, offset);
+    if(res == -1)
+        res = -errno;
+    
+    close(fd);
+    return res;
+}
+
+static int xmp_write(struct fuse_cred *cred, const char *path, const char *buf,
+                     size_t size, off_t offset)
+{
+    int fd;
+    int res;
+
+    res = set_creds(cred);
+    if(res)
+        return res;
+    fd = open(path, O_WRONLY);
+    restore_creds();
+    if(fd == -1)
+        return -errno;
+
+    res = pwrite(fd, buf, size, offset);
+    if(res == -1)
+        res = -errno;
+    
+    close(fd);
+    return res;
+}
+
+static void exit_handler()
+{
+    exit(0);
+}
+
+static void set_signal_handlers()
+{
+    struct sigaction sa;
+
+    sa.sa_handler = exit_handler;
+    sigemptyset(&(sa.sa_mask));
+    sa.sa_flags = 0;
+
+    if (sigaction(SIGHUP, &sa, NULL) == -1 || 
+	sigaction(SIGINT, &sa, NULL) == -1 || 
+	sigaction(SIGTERM, &sa, NULL) == -1) {
+	
+	perror("Cannot set exit signal handlers");
+        exit(1);
+    }
+
+    sa.sa_handler = SIG_IGN;
+    
+    if(sigaction(SIGPIPE, &sa, NULL) == -1) {
+	perror("Cannot set ignored signals");
+        exit(1);
+    }
+}
+
+static void cleanup()
+{
+    fuse_unmount(xmp_fuse);
+    fuse_destroy(xmp_fuse);
+}
+
+static struct fuse_operations xmp_oper = {
+    getattr:	xmp_getattr,
+    readlink:	xmp_readlink,
+    getdir:     xmp_getdir,
+    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,
+    utime:	xmp_utime,
+    open:	xmp_open,
+    read:	xmp_read,
+    write:	xmp_write,
+};
+
+int main(int argc, char *argv[])
+{
+    int res;
+    if(argc != 2) {
+        fprintf(stderr, "usage: %s mount_dir\n", argv[0]);
+        exit(1);
+    }
+
+    set_signal_handlers();
+    atexit(cleanup);
+    setgroups(0, NULL);
+
+    xmp_fuse = fuse_new(0,0);
+    res = fuse_mount(xmp_fuse, argv[1]);
+    if(res == -1)
+        exit(1);
+        
+    fuse_set_operations(xmp_fuse, &xmp_oper);
+
+    fuse_loop(xmp_fuse);
+
+    return 0;
+}
diff --git a/include/fuse.h b/include/fuse.h
index 4edb0c7..4cddaaf 100644
--- a/include/fuse.h
+++ b/include/fuse.h
@@ -12,16 +12,56 @@
 #include <sys/stat.h>
 #include <utime.h>
 
+/** Handle for a FUSE filesystem */
 struct fuse;
+
+/** Handle for a getdir() operation */
 typedef struct fuse_dirhandle *fuse_dirh_t;
 
+/** Function to add an entry in a getdir() operation */
 typedef int (*fuse_dirfil_t) (fuse_dirh_t, const char *, int type);
 
+/** Credentials for an operation, these are determined by the fsuid
+    and fsgid of the calling process */
 struct fuse_cred {
     uid_t uid;
     gid_t gid;
+    /* FIXME: supplementary groups should also be included */
 };
 
+/**
+ * The file system operations:
+ *
+ * Most of these should work very similarly to the well known UNIX
+ * file system operations.  Exceptions are:
+ * 
+ *  - All operations get a fuse_cred structure by which the filesystem
+ *  implementation can check, whether the operation is permitted or
+ *  not.
+ * 
+ *  - All operations should return the negated error value (-errno) on
+ *  error.
+ * 
+ *  - readlink() should fill the buffer 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.
+ *
+ *  - getdir() is the opendir(), readdir(), ..., closedir() sequence
+ *  in one call. For each directory entry the filldir parameter should
+ *  be called. 
+ *
+ *  - There is no create() operation, mknod() will be called for
+ *  creation of all non directory, non symlink nodes.
+ *
+ *  - open() should not return a filehandle, but 0 on success.  No
+ *  creation, or trunctation flags (O_CREAT, O_EXCL, O_TRUNC) will be
+ *  passed to open().  Open should only check if the operation is
+ *  permitted for the given flags.
+ * 
+ *  - read(), write() are not passed a filehandle, but rather a
+ *  pathname.  The offset of the read and write is passed as the last
+ *  argument, like the pread() and pwrite() system calls.  */
 struct fuse_operations {
     int (*getattr)  (struct fuse_cred *, const char *, struct stat *);
     int (*readlink) (struct fuse_cred *, const char *, char *, size_t);
@@ -42,16 +82,64 @@
     int (*write)    (struct fuse_cred *, const char *, const char *, size_t, off_t);
 };
 
+/* FUSE flags: */
 #define FUSE_MULTITHREAD (1 << 0)
 
-struct fuse *fuse_new(int flags);
+/**
+ * Create a new FUSE filesystem. The filesystem is not yet mounted
+ *
+ * @param flags any combination of the FUSE flags defined above, or 0
+ * @param root the file type of the root node. 0 is the default (directory).
+ * @return the created FUSE handle
+ */
+struct fuse *fuse_new(int flags, mode_t root);
 
-int fuse_mount(struct fuse *f, const char *dir);
+/**
+ * Connect to the kernel and mount the filesystem.
+ * 
+ * @param f the FUSE handle
+ * @param mnt the mount point
+ * @return 0 on success -1 on failure
+ */
+int fuse_mount(struct fuse *f, const char *mnt);
 
+/**
+ * Set the filesystem operations. 
+ * 
+ * Operations which are initialised to NULL will return ENOSYS to the
+ * calling process.  This function can be called anytime after
+ * fuse_new() and before fuse_loop().
+ * 
+ * @param f the FUSE handle
+ * @param op the operations
+ */
 void fuse_set_operations(struct fuse *f, const struct fuse_operations *op);
 
+/**
+ * FUSE event loop.
+ *
+ * Requests from the kernel are processed, and the apropriate
+ * operations are called. 
+ *
+ * @param f the FUSE handle
+ */
 void fuse_loop(struct fuse *f);
 
+/**
+ * Disconnect from the kernel and unmount the filesystem
+ *
+ * @param f the FUSE handle
+ */
 int fuse_unmount(struct fuse *f);
 
+/**
+ * Destroy the filesystem. 
+ *
+ * The filesystem is not unmounted (call fuse_unmount() for that).
+ * After a fork() system call it is possible to call fuse_destroy() in
+ * one process, and leave the other process to service the filesystem
+ * requests.
+ *
+ * @param f the FUSE handle
+ */
 void fuse_destroy(struct fuse *f);
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index a6e74df..22897d4 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -9,11 +9,12 @@
 /* This file defines the kernel interface of FUSE */
 
 
-#define FUSE_MOUNT_VERSION 1
+#define FUSE_KERNEL_VERSION 1
 
 struct fuse_mount_data {
 	int version;
 	int fd;
+	unsigned int rootmode;
 };
 
 #define FUSE_ROOT_INO 1
diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h
index b738bed..b3f3a9c 100644
--- a/kernel/fuse_i.h
+++ b/kernel/fuse_i.h
@@ -12,8 +12,6 @@
 #include <linux/spinlock.h>
 #include <linux/rwsem.h>
 
-#define FUSE_VERSION "0.1"
-
 #define MAX_CLEARED 256
 
 /**
diff --git a/kernel/inode.c b/kernel/inode.c
index 77e8469..5fb4a66 100644
--- a/kernel/inode.c
+++ b/kernel/inode.c
@@ -66,8 +66,8 @@
 		return NULL;
 	}
 
-	if(d->version != FUSE_MOUNT_VERSION) {
-		printk("fuse_read_super: Bad mount version: %i\n", d->version);
+	if(d->version != FUSE_KERNEL_VERSION) {
+		printk("fuse_read_super: Bad version: %i\n", d->version);
 		return NULL;
 	}
 
@@ -89,12 +89,12 @@
 
 }
 
-static struct inode *get_root_inode(struct super_block *sb)
+static struct inode *get_root_inode(struct super_block *sb, unsigned int mode)
 {
 	struct fuse_attr attr;
 	memset(&attr, 0, sizeof(attr));
 
-	attr.mode = S_IFDIR;
+	attr.mode = mode;
 	return fuse_iget(sb, 1, &attr, 0);
 }
 
@@ -103,20 +103,21 @@
 {	
 	struct fuse_conn *fc;
 	struct inode *root;
+	struct fuse_mount_data *d = data;
 
         sb->s_blocksize = 1024;
         sb->s_blocksize_bits = 10;
         sb->s_magic = FUSE_SUPER_MAGIC;
         sb->s_op = &fuse_super_operations;
 
-	root = get_root_inode(sb);
+	root = get_root_inode(sb, d->rootmode);
 	if(root == NULL) {
 		printk("fuse_read_super: failed to get root inode\n");
 		return NULL;
 	}
 
 	spin_lock(&fuse_lock);
-	fc = get_conn(data);
+	fc = get_conn(d);
 	if(fc == NULL)
 		goto err;
 
diff --git a/kernel/util.c b/kernel/util.c
index 57b1a90..9b7bec1 100644
--- a/kernel/util.c
+++ b/kernel/util.c
@@ -12,8 +12,6 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 
-#define FUSE_VERSION "0.1"
-
 spinlock_t fuse_lock = SPIN_LOCK_UNLOCKED;
 
 /* Must be called with the fuse lock held */
@@ -28,7 +26,7 @@
 {
 	int res;
 
-	printk(KERN_DEBUG "fuse init (version %s)\n", FUSE_VERSION);
+	printk(KERN_DEBUG "fuse init (version %i)\n", FUSE_KERNEL_VERSION);
 
 	res = fuse_fs_init();
 	if(res)
diff --git a/lib/Makefile b/lib/Makefile
index e72a39d..88b087a 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,16 +1,18 @@
 CC = gcc
-CFLAGS = -Wall -W -g `glib-config --cflags`
+CFLAGS = -Wall -W -g `glib-config --cflags` -fPIC
 LDFLAGS = `glib-config --libs`
 CPPFLAGS = -I../include
 
-
-all: libfuse.a
+all: libfuse.a libfuse.so
 
 libfuse_objs = mount.o fuse.o
 
 libfuse.a: $(libfuse_objs)
 	ar cr libfuse.a $(libfuse_objs)
 
+libfuse.so: $(libfuse_objs)
+	gcc -shared -o libfuse.so $(libfuse_objs)
+
 clean:
 	rm -f *.o *.a
 	rm -f *~
diff --git a/lib/fuse.c b/lib/fuse.c
index 137b5ef..b12c58d 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -407,6 +407,7 @@
             res = f->op.readlink(&cred, path, link, sizeof(link));
         g_free(path);
     }
+    link[PATH_MAX] = '\0';
     send_reply(f, in, res, link, !res ? strlen(link) : 0);
 }
 
@@ -756,6 +757,17 @@
     return NULL;
 }
 
+/* This hack makes it possible to link FUSE with or without the
+   pthread library */
+__attribute__((weak))
+int pthread_create(pthread_t *thrid           __attribute__((unused)), 
+                   const pthread_attr_t *attr __attribute__((unused)), 
+                   void *(*func)(void *)      __attribute__((unused)),
+                   void *arg                  __attribute__((unused)))
+{
+    return ENOSYS;
+}
+
 void fuse_loop(struct fuse *f)
 {
     int res;
@@ -787,24 +799,35 @@
         
         if(f->flags & FUSE_MULTITHREAD) {
             res = pthread_create(&thrid, &attr, do_command, cmd);
-            if(res != 0) {
-                fprintf(stderr, "Error creating thread: %s\n", 
-                        strerror(errno));
-                exit(1);
-            }
+            if(res == 0)
+                continue;
+            
+            fprintf(stderr, "Error creating thread: %s\n", strerror(res));
+            fprintf(stderr, "Will run in single thread mode\n");
+            f->flags &= ~FUSE_MULTITHREAD;
         }
-        else
-            do_command(cmd);
+
+        do_command(cmd);
     }
 }
 
-struct fuse *fuse_new(int flags)
+struct fuse *fuse_new(int flags, mode_t root)
 {
     struct fuse *f = g_new0(struct fuse, 1);
 
+    if(!root)
+        root = S_IFDIR;
+
+    if(!S_ISDIR(root) && !S_ISREG(root)) {
+        fprintf(stderr, "Invalid mode for root: 0%o\n", root);
+        root = S_IFDIR;
+    }
+    root &= S_IFMT;
+
     f->flags = flags;
+    f->rootmode = root;
     f->fd = -1;
-    f->dir = NULL;
+    f->mnt = NULL;
     f->nametab = g_hash_table_new((GHashFunc) name_hash,
                                   (GCompareFunc) name_compare);
     pthread_mutex_init(&f->lock, NULL);
diff --git a/lib/fuse_i.h b/lib/fuse_i.h
index c28e2e8..6f363d8 100644
--- a/lib/fuse_i.h
+++ b/lib/fuse_i.h
@@ -25,7 +25,8 @@
 
 struct fuse {
     int flags;
-    char *dir;
+    char *mnt;
+    mode_t rootmode;
     int fd;
     struct fuse_operations op;
     GHashTable *nametab;
diff --git a/lib/mount.c b/lib/mount.c
index 48d9d45..98d9e59 100644
--- a/lib/mount.c
+++ b/lib/mount.c
@@ -16,13 +16,15 @@
 #include <sys/mount.h>
 #include <mntent.h>
 
-static int do_mount(const char *dev, const char *dir, const char *type, int fd)
+static int do_mount(const char *dev, const char *dir, const char *type,
+                    mode_t rootmode, int fd)
 {
     int res;
     struct fuse_mount_data data;
     
-    data.version = FUSE_MOUNT_VERSION;
+    data.version = FUSE_KERNEL_VERSION;
     data.fd = fd;
+    data.rootmode = rootmode;
 
     res = mount(dev, dir, type, MS_MGC_VAL | MS_NOSUID | MS_NODEV, &data);
     if(res == -1) {
@@ -100,7 +102,7 @@
     const char *dev = FUSE_DEV;
     const char *type = "fuse";
 
-    if(f->dir != NULL)
+    if(f->mnt != NULL)
         return 0;
 
     f->fd = open(dev, O_RDWR);
@@ -109,12 +111,12 @@
         return -1;
     }
     
-    res = do_mount(dev, dir, type, f->fd);
+    res = do_mount(dev, dir, type, f->rootmode, f->fd);
     if(res == -1)
         return -1;
 
     add_mntent(dev, dir, type);
-    f->dir = g_strdup(dir);
+    f->mnt = g_strdup(dir);
     
     return 0;
 }
@@ -123,20 +125,20 @@
 {
     int res;
 
-    if(f->dir == NULL)
+    if(f->mnt == NULL)
         return 0;
 
     close(f->fd);
     f->fd = -1;
 
-    res = umount(f->dir);
+    res = umount(f->mnt);
     if(res == -1)
         perror("umount failed");
     else
-        remove_mntent(f->dir);
+        remove_mntent(f->mnt);
 
-    g_free(f->dir);
-    f->dir = NULL;
+    g_free(f->mnt);
+    f->mnt = NULL;
 
     return res;
 }
diff --git a/usermux.c b/usermux.c
index 4caacb9..f2f11f3 100644
--- a/usermux.c
+++ b/usermux.c
@@ -50,7 +50,7 @@
     if(pw == NULL)
         return;
 
-    user_fuse = fuse_new(0);
+    user_fuse = fuse_new(FUSE_MULTITHREAD, 0);
     
     userdir = g_strdup_printf("%s/%010u", MOUNTDIR, uid);
     mkdir(userdir, 0755);
@@ -240,7 +240,7 @@
     set_signal_handlers();
     atexit(cleanup);
 
-    um_fuse = fuse_new(0);
+    um_fuse = fuse_new(FUSE_MULTITHREAD, 0);
     res = fuse_mount(um_fuse, um_dir);
     if(res == -1)
         exit(1);