inode based API first working version
diff --git a/example/.cvsignore b/example/.cvsignore
index 80eb82b..56dabc1 100644
--- a/example/.cvsignore
+++ b/example/.cvsignore
@@ -5,4 +5,5 @@
 fusexmp_fh
 null
 hello
+hello_ll
 .libs
diff --git a/example/Makefile.am b/example/Makefile.am
index be7a674..8d62e9d 100644
--- a/example/Makefile.am
+++ b/example/Makefile.am
@@ -1,6 +1,6 @@
 ## Process this file with automake to produce Makefile.in
 
-noinst_PROGRAMS = fusexmp fusexmp_fh null hello
+noinst_PROGRAMS = fusexmp fusexmp_fh null hello hello_ll
 
 fusexmp_SOURCES = fusexmp.c
 fusexmp_fh_SOURCES = fusexmp_fh.c
diff --git a/example/hello_ll.c b/example/hello_ll.c
new file mode 100644
index 0000000..2739e3a
--- /dev/null
+++ b/example/hello_ll.c
@@ -0,0 +1,170 @@
+/*
+    FUSE: Filesystem in Userspace
+    Copyright (C) 2001-2005  Miklos Szeredi <miklos@szeredi.hu>
+
+    This program can be distributed under the terms of the GNU GPL.
+    See the file COPYING.
+*/
+
+#include <fuse_lowlevel.h>
+#include <fuse.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <assert.h>
+
+static const char *hello_str = "Hello World!\n";
+static const char *hello_name = "hello";
+
+static int hello_stat(fuse_ino_t ino, struct stat *stbuf)
+{
+    stbuf->st_ino = ino;
+    switch (ino) {
+    case 1:
+        stbuf->st_mode = S_IFDIR | 0755;
+        stbuf->st_nlink = 2;
+        break;
+        
+    case 2:
+        stbuf->st_mode = S_IFREG | 0444;
+        stbuf->st_nlink = 1;
+        stbuf->st_size = strlen(hello_str);
+        break;
+        
+    default:
+        return -1;
+    }
+    return 0;
+}
+
+static void hello_ll_getattr(fuse_req_t req, fuse_ino_t ino)
+{
+    struct stat stbuf;
+
+    memset(&stbuf, 0, sizeof(stbuf));
+    if (hello_stat(ino, &stbuf) == -1)
+        fuse_reply_err(req, ENOENT);
+    else
+        fuse_reply_attr(req, &stbuf, 1.0);
+}
+
+static void hello_ll_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
+{
+    struct fuse_entry_param e;
+
+    if (parent != 1 || strcmp(name, hello_name) != 0)
+        fuse_reply_err(req, ENOENT);
+    else {
+        memset(&e, 0, sizeof(e));
+        e.ino = 2;
+        e.attr_timeout = 1.0;
+        e.entry_timeout = 1.0;
+        hello_stat(e.ino, &e.attr);
+        
+        fuse_reply_entry(req, &e);
+    }
+}
+
+struct dirbuf {
+    char *p;
+    size_t size;
+};
+
+static void dirbuf_add(struct dirbuf *b, const char *name, fuse_ino_t ino)
+{
+    struct stat stbuf;
+    size_t oldsize = b->size;
+    b->size += fuse_dirent_size(strlen(name));
+    b->p = realloc(b->p, b->size);
+    memset(&stbuf, 0, sizeof(stbuf));
+    stbuf.st_ino = ino;
+    fuse_add_dirent(b->p + oldsize, name, &stbuf, b->size);
+}
+
+#define min(x, y) ((x) < (y) ? (x) : (y))
+
+static int reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize,
+                             off_t off, size_t maxsize)
+{
+        
+    if (off < bufsize)
+        return fuse_reply_buf(req, buf + off, min(bufsize - off, maxsize));
+    else
+        return fuse_reply_buf(req, NULL, 0);
+}
+
+static void hello_ll_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
+                             off_t off, struct fuse_file_info *fi)
+{
+    (void) fi;
+
+    if (ino != 1)
+        fuse_reply_err(req, ENOTDIR);
+    else {
+        struct dirbuf b;
+    
+        memset(&b, 0, sizeof(b));
+        dirbuf_add(&b, ".", 1);
+        dirbuf_add(&b, "..", 1);
+        dirbuf_add(&b, hello_name, 2);
+        reply_buf_limited(req, b.p, b.size, off, size);
+        free(b.p);
+    }
+}
+
+static void hello_ll_open(fuse_req_t req, fuse_ino_t ino,
+                         struct fuse_file_info *fi)
+{
+    if (ino != 2)
+        fuse_reply_err(req, EISDIR);
+    else if ((fi->flags & 3) != O_RDONLY)
+        fuse_reply_err(req, EACCES);
+    else
+        fuse_reply_open(req, fi);
+}
+
+static void hello_ll_read(fuse_req_t req, fuse_ino_t ino, size_t size,
+                         off_t off, struct fuse_file_info *fi)
+{
+    (void) fi;
+
+    assert(ino == 2);
+    reply_buf_limited(req, hello_str, strlen(hello_str), off, size);
+}
+
+static struct fuse_ll_operations hello_ll_oper = {
+    .lookup     = hello_ll_lookup,
+    .getattr	= hello_ll_getattr,
+    .readdir    = hello_ll_readdir,
+    .open       = hello_ll_open,
+    .read	= hello_ll_read,
+};
+
+int main(int argc, char *argv[])
+{
+    const char *mountpoint;
+    struct fuse_ll *f;
+    int err = -1;
+    int fd;
+
+    if (argc != 2) {
+        fprintf(stderr, "usage: %s mountpoint\n", argv[0]);
+        return 1;
+    }
+    mountpoint = argv[1];
+    fd = fuse_mount(mountpoint, NULL);
+    if (fd != -1) {
+        f = fuse_ll_new(fd, "debug", &hello_ll_oper, sizeof(hello_ll_oper));
+        if (f != NULL) {
+            err = fuse_ll_loop(f);
+            fuse_ll_destroy(f);
+        }
+        close(fd);
+    }
+    fuse_unmount(mountpoint);
+
+    return err ? 1 : 0;
+}
diff --git a/include/fuse.h b/include/fuse.h
index 40c9b72..24e8871 100644
--- a/include/fuse.h
+++ b/include/fuse.h
@@ -31,6 +31,8 @@
 #error Please add -D_FILE_OFFSET_BITS=64 to your compile flags!
 #endif
 
+#include "fuse_common.h"
+
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/statfs.h>
@@ -63,20 +65,6 @@
 typedef int (*fuse_dirfil_t) (fuse_dirh_t h, const char *name, int type,
                               ino_t ino);
 
-/** Information about open files */
-struct fuse_file_info {
-    /** Open flags.  Available in open() and release() */
-    int flags;
-
-    /** File handle.  May be filled in by filesystem in open().
-        Available in all other file operations */
-    unsigned long fh;
-
-    /** In case of a write operation indicates if this was caused by a
-        writepage */
-    int writepage;
-};
-
 /**
  * The file system operations:
  *
@@ -459,12 +447,9 @@
 struct fuse_context *fuse_get_context(void);
 
 /**
- * Invalidate cached data of a file.
- *
- * Useful if the 'kernel_cache' mount option is given, since in that
- * case the cache is not invalidated on file open.
- *
- * @return 0 on success or -errno on failure
+ * Obsolete, doesn't do anything
+ * 
+ * @return 0 
  */
 int fuse_invalidate(struct fuse *f, const char *path);
 
diff --git a/include/fuse_common.h b/include/fuse_common.h
index cd19435..96359ef 100644
--- a/include/fuse_common.h
+++ b/include/fuse_common.h
@@ -10,6 +10,9 @@
 #error "Never include <fuse_common.h> directly; use <fuse.h> or <fuse_lowlevel.h instead."
 #endif
 
+#ifndef _FUSE_COMMON_H_
+#define _FUSE_COMMON_H_
+
 /** Information about open files */
 struct fuse_file_info {
     /** Open flags.  Available in open() and release() */
@@ -22,28 +25,9 @@
     /** 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 */
+    unsigned int direct_io : 1;
 };
 
-/** 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;
-};
-
-
+#endif /* _FUSE_COMMON_H_ */
diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h
index 673493e..0881ac8 100644
--- a/include/fuse_lowlevel.h
+++ b/include/fuse_lowlevel.h
@@ -13,7 +13,12 @@
  * Low level API                                               *
  * ----------------------------------------------------------- */
 
-#include <fuse_common.h>
+#include "fuse_common.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <utime.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -25,10 +30,9 @@
 struct fuse_entry_param {
     fuse_ino_t ino;
     unsigned long generation;
-    const struct stat *attr;
+    struct stat attr;
     double attr_timeout;
     double entry_timeout;
-    unsigned int direct_io : 1;
 };
 
 /* 'to_set' flags in setattr */
@@ -40,9 +44,14 @@
 #define FUSE_SET_ATTR_MTIME	(1 << 5)
 #define FUSE_SET_ATTR_CTIME	(1 << 6)
 
-struct fuse_lowlevel_operations {
+/* ------------------------------------------ */
+
+struct fuse_ll_operations {
+    void* (*init)   (void);
+    void (*destroy) (void *);
+
     void (*lookup)  (fuse_req_t req, fuse_ino_t parent, const char *name);
-    void (*forget)  (fuse_req_t req, fuse_ino_t ino);
+    void (*forget)  (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup);
     void (*getattr) (fuse_req_t req, fuse_ino_t ino);
     void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr,
                      int to_set);
@@ -59,22 +68,22 @@
                      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 *f);
+    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, off_t off,
-                     struct fuse_file_info *f);
+                     struct fuse_file_info *fi);
     void (*write)   (fuse_req_t req, fuse_ino_t ino, const char *buf,
-                     size_t size, off_t off, struct fuse_file_info *f);
-    void (*flush)   (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *f);
-    void (*release) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *f);
+                     size_t size, off_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 *f);
-    void (*opendir) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *f);
+                     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, off_t off,
-                     struct fuse_file_info *f);
+                      struct fuse_file_info *fi);
     void (*releasedir) (fuse_req_t req, fuse_ino_t ino,
-                        struct fuse_file_info *f);
+                        struct fuse_file_info *fi);
     void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync,
-                      struct fuse_file_info *f);
+                      struct fuse_file_info *fi);
     void (*statfs)  (fuse_req_t req, fuse_ino_t ino);
     void (*setxattr)(fuse_req_t req, fuse_ino_t ino, const char *name,
                      const char *value, size_t size, int flags);
@@ -84,43 +93,67 @@
     void (*removexattr)(fuse_req_t req, fuse_ino_t ino, const char *name);
 };
 
-/* all except release and forget */
+/* ------------------------------------------ */
+
+/* all except forget */
 int fuse_reply_err(fuse_req_t req, int err);
 
-/* forget, unlink, rmdir, rename, setxattr, removexattr, release, releasedir */
-int fuse_reply_ok(fuse_req_t req);
+/* forget */
+int fuse_reply_none(fuse_req_t req);
 
 /* lookup, mknod, mkdir, symlink, link */
-int fuse_reply_entry(fuse_req_t req, struct fuse_entry_param *e);
+int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e);
 
 /* getattr, setattr */
-int fuse_reply_attr(fuse_req_t req, int struct stat *attr, double attr_timeout);
+int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
+                    double attr_timeout);
+
 /* readlink */
 int fuse_reply_readlink(fuse_req_t req, const char *link);
 
-/* open, flush, fsync, opendir, fsyncdir */
-int fuse_reply_file_info(fuse_req_t req, const struct fuse_file_info *f);
+/* open, opendir */
+int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi);
 
 /* write */
-int fuse_reply_write(fuse_req_t req, size_t count,
-                         const struct fuse_file_info *f);
+int fuse_reply_write(fuse_req_t req, size_t count);
 
-/* read, readdir */
-int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size,
-                    const struct fuse_file_info *f);
+/* read, readdir, getxattr, listxattr */
+int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size);
 
 /* statfs */
 int fuse_reply_statfs(fuse_req_t req, const struct statfs *statfs);
 
 /* getxattr, listxattr */
-int fuse_reply_xattr(fuse_req_t req, const char *buf, size_t size);
+int fuse_reply_xattr(fuse_req_t req, size_t count);
+
+/* ------------------------------------------ */
 
 /* return the size of a directory entry */
 size_t fuse_dirent_size(size_t namelen);
 
 /* add a directory entry to the buffer */
-void fuse_add_dirent(char *buf, const char *name, const struct stat *stat,
-                     off_t off);
+char *fuse_add_dirent(char *buf, const char *name, const struct stat *stat,
+                      off_t off);
+
+/* ------------------------------------------ */
+
+struct fuse_ll *fuse_ll_new(int fd, const char *opts,
+                            const struct fuse_ll_operations *op,
+                            size_t op_size);
+
+void fuse_ll_destroy(struct fuse_ll *f);
+
+int fuse_ll_is_lib_option(const char *opt);
+
+int fuse_ll_loop(struct fuse_ll *f);
+
+int fuse_ll_exited(struct fuse_ll* f);
+
+struct fuse_cmd *fuse_ll_read_cmd(struct fuse_ll *f);
+
+void fuse_ll_process_cmd(struct fuse_ll *f, struct fuse_cmd *cmd);
+
+/* ------------------------------------------ */
 
 #ifdef __cplusplus
 }
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 4c68739..e5c356a 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -5,6 +5,7 @@
 libfuse_la_SOURCES = 	\
 	fuse.c		\
 	fuse_mt.c	\
+	fuse_lowlevel.c	\
 	helper.c	\
 	mount.c		\
 	fuse_i.h	\
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index f14aeeb..495eb1d 100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -6,10 +6,8 @@
     See the file COPYING.LIB
 */
 
-#include "fuse_i.h"
-#include "fuse_compat.h"
+#include "fuse_lowlevel.h"
 #include "fuse_kernel.h"
-#include "fuse_kernel_compat5.h"
 
 #include <stdio.h>
 #include <string.h>
@@ -28,7 +26,7 @@
     unsigned int debug : 1;
     unsigned int allow_root : 1;
     int fd;
-    struct fuse_lowlevel_operations op;
+    struct fuse_ll_operations op;
     volatile int exited;
     int got_init;
     void *user_data;
@@ -42,6 +40,14 @@
     size_t buflen;
 };
 
+struct fuse_req {
+    struct fuse_ll *f;
+    uint64_t unique;
+    uid_t uid;
+    gid_t gid;
+    pid_t pid;
+};
+
 static const char *opname(enum fuse_opcode opcode)
 {
     switch (opcode) {
@@ -77,7 +83,7 @@
     }
 }
 
-static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
+static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
 {
     attr->ino       = stbuf->st_ino;
     attr->mode      = stbuf->st_mode;
@@ -97,6 +103,22 @@
 #endif
 }
 
+static void convert_attr(const struct fuse_attr *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;
+    stbuf->st_ctime        = attr->ctime;
+#ifdef HAVE_STRUCT_STAT_ST_ATIM
+    stbuf->st_atim.tv_nsec = attr->atimensec;
+    stbuf->st_mtim.tv_nsec = attr->mtimensec;
+    stbuf->st_ctim.tv_nsec = attr->ctimensec;
+#endif
+}
+
 static  size_t iov_length(const struct iovec *iov, size_t count)
 {
     size_t seg;
@@ -115,17 +137,12 @@
     struct fuse_out_header *out = (struct fuse_out_header *) iov[0].iov_base;
     out->len = outsize;
 
-    if ((f->flags & FUSE_DEBUG)) {
+    if (f->debug) {
         printf("   unique: %llu, error: %i (%s), outsize: %i\n",
                out->unique, out->error, strerror(-out->error), outsize);
         fflush(stdout);
     }
 
-    /* This needs to be done before the reply, otherwise the scheduler
-       could play tricks with us, and only let the counter be
-       increased long after the operation is done */
-    fuse_inc_avail(f);
-
     res = writev(f->fd, iov, count);
     if (res == -1) {
         /* ENOENT means the operation was interrupted */
@@ -136,8 +153,8 @@
     return 0;
 }
 
-static int send_reply(struct fuse_ll *f, struct fuse_in_header *in, int error,
-                      void *arg, size_t argsize)
+static int send_reply(struct fuse_ll *f, uint64_t unique, int error,
+                      const void *arg, size_t argsize)
 {
     struct fuse_out_header out;
     struct iovec iov[2];
@@ -148,14 +165,14 @@
         error = -ERANGE;
     }
 
-    out.unique = in->unique;
+    out.unique = unique;
     out.error = error;
     count = 1;
     iov[0].iov_base = &out;
     iov[0].iov_len = sizeof(struct fuse_out_header);
     if (argsize && !error) {
         count++;
-        iov[1].iov_base = arg;
+        iov[1].iov_base = (void *) arg;
         iov[1].iov_len = argsize;
     }
     return send_reply_raw(f, iov, count);
@@ -166,8 +183,8 @@
     return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen);
 }
 
-void fuse_add_dirent(char *buf, const char *name, const struct stat *stat,
-                     off_t off)
+char *fuse_add_dirent(char *buf, const char *name, const struct stat *stat,
+                      off_t off)
 {
     unsigned namelen = strlen(name);
     unsigned entlen = FUSE_NAME_OFFSET + namelen;
@@ -183,10 +200,11 @@
     if (padlen)
         memset(buf + entlen, 0, padlen);
 
-    return 0;
+    return buf + entsize;
 }
 
-static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
+static void convert_statfs(const struct statfs *statfs,
+                           struct fuse_kstatfs *kstatfs)
 {
     kstatfs->bsize	= statfs->f_bsize;
     kstatfs->blocks	= statfs->f_blocks;
@@ -197,6 +215,131 @@
     kstatfs->namelen	= statfs->f_namelen;
 }
 
+static void free_req(fuse_req_t req)
+{
+    free(req);
+}
+
+static int send_reply_req(fuse_req_t req, const void *arg, size_t argsize)
+{
+    int res = send_reply(req->f, req->unique, 0, arg, argsize);
+    free_req(req);
+    return res;
+}
+
+int fuse_reply_err(fuse_req_t req, int err)
+{
+    int res = send_reply(req->f, req->unique, -err, NULL, 0);
+    free_req(req);
+    return res;
+}
+
+int fuse_reply_none(fuse_req_t req)
+{
+    free_req(req);
+    return 0;
+}
+
+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);
+}
+
+int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
+{
+    struct fuse_entry_out arg;
+
+    memset(&arg, 0, sizeof(arg));
+    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);
+
+    return send_reply_req(req, &arg, sizeof(arg));
+}
+
+int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
+                    double attr_timeout)
+{
+    struct fuse_attr_out 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_req(req, &arg, sizeof(arg));
+}
+
+int fuse_reply_readlink(fuse_req_t req, const char *link)
+{
+    return send_reply_req(req, link, strlen(link));
+}
+
+int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
+{
+    struct fuse_open_out arg;
+
+    memset(&arg, 0, sizeof(arg));
+    arg.fh = f->fh;
+    
+    return send_reply_req(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_req(req, &arg, sizeof(arg));
+}
+
+int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
+{
+    return send_reply_req(req, buf, size);
+}
+
+int fuse_reply_statfs(fuse_req_t req, const struct statfs *statfs)
+{
+    struct fuse_statfs_out arg;
+
+    memset(&arg, 0, sizeof(arg));
+    convert_statfs(statfs, &arg.st);
+    
+    return send_reply_req(req, &arg, sizeof(arg));
+}
+
+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_req(req, &arg, sizeof(arg));
+}
+
 static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, char *name)
 {
     if (req->f->op.lookup)
@@ -205,10 +348,11 @@
         fuse_reply_err(req, ENOSYS);
 }
 
-static void do_forget(fuse_req_t req, fuse_ino_t nodeid)
+static void do_forget(fuse_req_t req, fuse_ino_t nodeid,
+                      struct fuse_forget_in *arg)
 {
     if (req->f->op.forget)
-        req->f->op.forget(req, nodeid);
+        req->f->op.forget(req, nodeid, arg->nlookup);
 }
 
 static void do_getattr(fuse_req_t req, fuse_ino_t nodeid)
@@ -222,9 +366,11 @@
 static void do_setattr(fuse_req_t req, fuse_ino_t nodeid,
                        struct fuse_setattr_in *arg)
 {
-    if (req->f->op.setattr)
-        req->f->op.setattr(req, nodeid, &arg->attr, arg->valid);
-    else
+    if (req->f->op.setattr) {
+        struct stat stbuf;
+        convert_attr(&arg->attr, &stbuf);
+        req->f->op.setattr(req, nodeid, &stbuf, arg->valid);
+    } else
         fuse_reply_err(req, ENOSYS);
 }
 
@@ -304,27 +450,26 @@
                     struct fuse_open_in *arg)
 {
     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_err(req, ENOSYS);
+        fuse_reply_open(req, &fi);
 }
 
 static void do_read(fuse_req_t req, fuse_ino_t nodeid,
                     struct fuse_read_in *arg)
 {
-    struct fuse_file_info fi;
+    if (req->f->op.read) {
+        struct fuse_file_info fi;
 
-    memset(&fi, 0, sizeof(fi));
-    fi.fh = arg->fh;
-
-    if (req->f->op.read)
+        memset(&fi, 0, sizeof(fi));
+        fi.fh = arg->fh;
         req->f->op.read(req, nodeid, arg->size, arg->offset, &fi);
-    else
+    } else
         fuse_reply_err(req, ENOSYS);
 }
 
@@ -338,7 +483,8 @@
     fi.writepage = arg->write_flags & 1;
 
     if (req->f->op.write)
-        req->f->op.write(req, nodeid, PARAM(arg), arg->size, arg->offset, &fi);
+        req->f->op.write(req, nodeid, PARAM(arg), arg->size,
+                                arg->offset, &fi);
     else
         fuse_reply_err(req, ENOSYS);
 }
@@ -369,7 +515,7 @@
     if (req->f->op.release)
         req->f->op.release(req, nodeid, &fi);
     else
-        fuse_reply_err(req, ENOSYS);
+        fuse_reply_err(req, 0);
 }
 
 static void do_fsync(fuse_req_t req, fuse_ino_t nodeid,
@@ -397,7 +543,7 @@
     if (req->f->op.opendir)
         req->f->op.opendir(req, nodeid, &fi);
     else
-        fuse_reply_err(req, ENOSYS);
+        fuse_reply_open(req, &fi);
 }
 
 static void do_readdir(fuse_req_t req, fuse_ino_t nodeid,
@@ -426,7 +572,7 @@
     if (req->f->op.releasedir)
         req->f->op.releasedir(req, nodeid, &fi);
     else
-        fuse_reply_err(req, ENOSYS);
+        fuse_reply_err(req, 0);
 }
 
 static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid,
@@ -446,7 +592,7 @@
 static void do_statfs(fuse_req_t req, fuse_ino_t nodeid)
 {
     if (req->f->op.statfs)
-        res = req->f->op.statfs(req, nodeid);
+        req->f->op.statfs(req, nodeid);
     else
         fuse_reply_err(req, ENOSYS);
 }
@@ -458,7 +604,8 @@
     unsigned char *value = name + strlen(name) + 1;
 
     if (req->f->op.setxattr)
-            req->f->op.setxattr(req, nodeid, name, value, arg->size, arg->flags);
+            req->f->op.setxattr(req, nodeid, name, value, arg->size,
+                                       arg->flags);
     else
         fuse_reply_err(req, ENOSYS);
 }
@@ -489,17 +636,12 @@
         fuse_reply_err(req, ENOSYS);
 }
 
-static void do_init(struct fuse_ll *f, struct fuse_in_header *in,
+static void do_init(struct fuse_ll *f, uint64_t unique,
                     struct fuse_init_in_out *arg)
 {
     struct fuse_init_in_out outarg;
 
-    if (in->padding == 5) {
-        arg->minor = arg->major;
-        arg->major = in->padding;
-    }
-
-    if (f->flags & FUSE_DEBUG) {
+    if (f->debug) {
         printf("INIT: %u.%u\n", arg->major, arg->minor);
         fflush(stdout);
     }
@@ -507,26 +649,19 @@
     if (f->op.init)
         f->user_data = f->op.init();
 
-    if (arg->major == 5) {
-        f->major = 5;
-        f->minor = 1;
-    } else if (arg->major == 6) {
-        f->major = 6;
-        f->minor = 1;
-    } else {
-        f->major = FUSE_KERNEL_VERSION;
-        f->minor = FUSE_KERNEL_MINOR_VERSION;
-    }
+    f->major = FUSE_KERNEL_VERSION;
+    f->minor = FUSE_KERNEL_MINOR_VERSION;
+
     memset(&outarg, 0, sizeof(outarg));
     outarg.major = f->major;
     outarg.minor = f->minor;
 
-    if (f->flags & FUSE_DEBUG) {
+    if (f->debug) {
         printf("   INIT: %u.%u\n", outarg.major, outarg.minor);
         fflush(stdout);
     }
 
-    send_reply(f, in, 0, &outarg, sizeof(outarg));
+    send_reply(f, unique, 0, &outarg, sizeof(outarg));
 }
 
 static void free_cmd(struct fuse_cmd *cmd)
@@ -535,169 +670,172 @@
     free(cmd);
 }
 
-void fuse_process_cmd(struct fuse_ll *f, struct fuse_cmd *cmd)
+void fuse_ll_process_cmd(struct fuse_ll *f, struct fuse_cmd *cmd)
 {
     struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
-    void *inarg = cmd->buf + SIZEOF_COMPAT(f, fuse_in_header);
-    struct fuse_context *ctx = fuse_get_context();
+    void *inarg = cmd->buf + sizeof(struct fuse_in_header);
+    struct fuse_req *req;
 
-    fuse_dec_avail(f);
-
-    if ((f->flags & FUSE_DEBUG)) {
+    if (f->debug) {
         printf("unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %i\n",
                in->unique, opname(in->opcode), in->opcode,
                (unsigned long) in->nodeid, cmd->buflen);
         fflush(stdout);
     }
 
-    if (!f->got_init && in->opcode != FUSE_INIT) {
-        /* Old kernel version probably */
-        send_reply(f, in, -EPROTO, NULL, 0);
+    if (!f->got_init) {
+        if (in->opcode != FUSE_INIT)
+            send_reply(f, in->unique, -EPROTO, NULL, 0);
+        else
+            do_init(f, in->unique, (struct fuse_init_in_out *) inarg);
         goto out;
     }
 
-    if ((f->flags & FUSE_ALLOW_ROOT) && in->uid != f->owner && in->uid != 0 &&
+    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) {
-        send_reply(f, in, -EACCES, NULL, 0);
+        send_reply(f, in->unique, -EACCES, NULL, 0);
         goto out;
     }
 
-    ctx->fuse = f;
-    ctx->uid = in->uid;
-    ctx->gid = in->gid;
-    ctx->pid = in->pid;
-    ctx->private_data = f->user_data;
+    req = (struct fuse_req *) malloc(sizeof(struct fuse_req));
+    if (req == NULL) {
+        fprintf(stderr, "fuse: failed to allocate request\n");
+        goto out;
+    }
+    
+    req->f = f;
+    req->unique = in->unique;
+    req->uid = in->uid;
+    req->gid = in->gid;
+    req->pid = in->pid;
 
     switch (in->opcode) {
     case FUSE_LOOKUP:
-        do_lookup(f, req, nodeid, (char *) inarg);
+        do_lookup(req, in->nodeid, (char *) inarg);
         break;
 
-        do_forget(f, in, (struct fuse_forget_in *) inarg);
+    case FUSE_FORGET:
+        do_forget(req, in->nodeid, (struct fuse_forget_in *) inarg);
         break;
-    }
+
     case FUSE_GETATTR:
-        do_getattr(f, in);
+        do_getattr(req, in->nodeid);
         break;
 
     case FUSE_SETATTR:
-        do_setattr(f, in, (struct fuse_setattr_in *) inarg);
+        do_setattr(req, in->nodeid, (struct fuse_setattr_in *) inarg);
         break;
 
     case FUSE_READLINK:
-        do_readlink(f, in);
+        do_readlink(req, in->nodeid);
         break;
 
     case FUSE_MKNOD:
-        do_mknod(f, in, (struct fuse_mknod_in *) inarg);
+        do_mknod(req, in->nodeid, (struct fuse_mknod_in *) inarg);
         break;
 
     case FUSE_MKDIR:
-        do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
+        do_mkdir(req, in->nodeid, (struct fuse_mkdir_in *) inarg);
         break;
 
     case FUSE_UNLINK:
-        do_unlink(f, in, (char *) inarg);
+        do_unlink(req, in->nodeid, (char *) inarg);
         break;
 
     case FUSE_RMDIR:
-        do_rmdir(f, in, (char *) inarg);
+        do_rmdir(req, in->nodeid, (char *) inarg);
         break;
 
     case FUSE_SYMLINK:
-        do_symlink(f, in, (char *) inarg,
+        do_symlink(req, in->nodeid, (char *) inarg,
                    ((char *) inarg) + strlen((char *) inarg) + 1);
         break;
 
     case FUSE_RENAME:
-        do_rename(f, in, (struct fuse_rename_in *) inarg);
+        do_rename(req, in->nodeid, (struct fuse_rename_in *) inarg);
         break;
 
     case FUSE_LINK:
-        do_link(f, in, (struct fuse_link_in *) inarg);
+        do_link(req, in->nodeid, (struct fuse_link_in *) inarg);
         break;
 
     case FUSE_OPEN:
-        do_open(f, in, (struct fuse_open_in *) inarg);
+        do_open(req, in->nodeid, (struct fuse_open_in *) inarg);
         break;
 
     case FUSE_FLUSH:
-        do_flush(f, in, (struct fuse_flush_in *) inarg);
+        do_flush(req, in->nodeid, (struct fuse_flush_in *) inarg);
         break;
 
     case FUSE_RELEASE:
-        do_release(f, in, (struct fuse_release_in *) inarg);
+        do_release(req, in->nodeid, (struct fuse_release_in *) inarg);
         break;
 
     case FUSE_READ:
-        do_read(f, in, (struct fuse_read_in *) inarg);
+        do_read(req, in->nodeid, (struct fuse_read_in *) inarg);
         break;
 
     case FUSE_WRITE:
-        do_write(f, in, (struct fuse_write_in *) inarg);
+        do_write(req, in->nodeid, (struct fuse_write_in *) inarg);
         break;
 
     case FUSE_STATFS:
-        do_statfs(f, in);
+        do_statfs(req, in->nodeid);
         break;
 
     case FUSE_FSYNC:
-        do_fsync(f, in, (struct fuse_fsync_in *) inarg);
+        do_fsync(req, in->nodeid, (struct fuse_fsync_in *) inarg);
         break;
 
     case FUSE_SETXATTR:
-        do_setxattr(f, in, (struct fuse_setxattr_in *) inarg);
+        do_setxattr(req, in->nodeid, (struct fuse_setxattr_in *) inarg);
         break;
 
     case FUSE_GETXATTR:
-        do_getxattr(f, in, (struct fuse_getxattr_in *) inarg);
+        do_getxattr(req, in->nodeid, (struct fuse_getxattr_in *) inarg);
         break;
 
     case FUSE_LISTXATTR:
-        do_listxattr(f, in, (struct fuse_getxattr_in *) inarg);
+        do_listxattr(req, in->nodeid, (struct fuse_getxattr_in *) inarg);
         break;
 
     case FUSE_REMOVEXATTR:
-        do_removexattr(f, in, (char *) inarg);
-        break;
-
-    case FUSE_INIT:
-        do_init(f, in, (struct fuse_init_in_out *) inarg);
+        do_removexattr(req, in->nodeid, (char *) inarg);
         break;
 
     case FUSE_OPENDIR:
-        do_opendir(f, in, (struct fuse_open_in *) inarg);
+        do_opendir(req, in->nodeid, (struct fuse_open_in *) inarg);
         break;
 
     case FUSE_READDIR:
-        do_readdir(f, in, (struct fuse_read_in *) inarg);
+        do_readdir(req, in->nodeid, (struct fuse_read_in *) inarg);
         break;
 
     case FUSE_RELEASEDIR:
-        do_releasedir(f, in, (struct fuse_release_in *) inarg);
+        do_releasedir(req, in->nodeid, (struct fuse_release_in *) inarg);
         break;
 
     case FUSE_FSYNCDIR:
-        do_fsyncdir(f, in, (struct fuse_fsync_in *) inarg);
+        do_fsyncdir(req, in->nodeid, (struct fuse_fsync_in *) inarg);
         break;
 
     default:
-        send_reply(f, in, -ENOSYS, NULL, 0);
+        fuse_reply_err(req, ENOSYS);
     }
 
  out:
     free_cmd(cmd);
 }
 
-int fuse_exited(struct fuse_ll* f)
+int fuse_ll_exited(struct fuse_ll* f)
 {
     return f->exited;
 }
 
-struct fuse_cmd *fuse_read_cmd(struct fuse_ll *f)
+struct fuse_cmd *fuse_ll_read_cmd(struct fuse_ll *f)
 {
     ssize_t res;
     struct fuse_cmd *cmd;
@@ -716,12 +854,12 @@
         return NULL;
     }
     in = (struct fuse_in_header *) cmd->buf;
-    inarg = cmd->buf + SIZEOF_COMPAT(f, fuse_in_header);
+    inarg = cmd->buf + sizeof(struct fuse_in_header);
 
     res = read(f->fd, cmd->buf, FUSE_MAX_IN);
     if (res == -1) {
         free_cmd(cmd);
-        if (fuse_exited(f) || errno == EINTR || errno == ENOENT)
+        if (fuse_ll_exited(f) || errno == EINTR || errno == ENOENT)
             return NULL;
 
         /* ENODEV means we got unmounted, so we silenty return failure */
@@ -730,14 +868,14 @@
             perror("fuse: reading device");
         }
 
-        fuse_exit(f);
+        f->exited = 1;
         return NULL;
     }
-    if ((size_t) res < SIZEOF_COMPAT(f, fuse_in_header)) {
+    if ((size_t) res < sizeof(struct fuse_in_header)) {
         free_cmd(cmd);
         /* Cannot happen */
         fprintf(stderr, "short read on fuse device\n");
-        fuse_exit(f);
+        f->exited = 1;
         return NULL;
     }
     cmd->buflen = res;
@@ -746,7 +884,7 @@
     return cmd;
 }
 
-int fuse_loop(struct fuse_ll *f)
+int fuse_ll_loop(struct fuse_ll *f)
 {
     if (f == NULL)
         return -1;
@@ -754,69 +892,29 @@
     while (1) {
         struct fuse_cmd *cmd;
 
-        if (fuse_exited(f))
+        if (fuse_ll_exited(f))
             break;
 
-        cmd = fuse_read_cmd(f);
+        cmd = fuse_ll_read_cmd(f);
         if (cmd == NULL)
             continue;
 
-        fuse_process_cmd(f, cmd);
+        fuse_ll_process_cmd(f, cmd);
     }
     f->exited = 0;
     return 0;
 }
 
-int fuse_invalidate(struct fuse_ll *f, const char *path)
-{
-    (void) f;
-    (void) path;
-    return -EINVAL;
-}
-
-void fuse_exit(struct fuse_ll *f)
-{
-    f->exited = 1;
-}
-
-struct fuse_context *fuse_get_context()
-{
-    static struct fuse_context context;
-    if (fuse_getcontext)
-        return fuse_getcontext();
-    else
-        return &context;
-}
-
-void fuse_set_getcontext_func(struct fuse_context *(*func)(void))
-{
-    fuse_getcontext = func;
-}
-
-static int begins_with(const char *s, const char *beg)
-{
-    if (strncmp(s, beg, strlen(beg)) == 0)
-        return 1;
-    else
-        return 0;
-}
-
-int fuse_is_lib_option(const char *opt)
+int fuse_ll_is_lib_option(const char *opt)
 {
     if (strcmp(opt, "debug") == 0 ||
-        strcmp(opt, "hard_remove") == 0 ||
-        strcmp(opt, "use_ino") == 0 ||
-        strcmp(opt, "allow_root") == 0 ||
-        strcmp(opt, "readdir_ino") == 0 ||
-        begins_with(opt, "umask=") ||
-        begins_with(opt, "uid=") ||
-        begins_with(opt, "gid="))
+        strcmp(opt, "allow_root") == 0)
         return 1;
     else
         return 0;
 }
 
-static int parse_lib_opts(struct fuse_ll *f, const char *opts)
+static int parse_ll_opts(struct fuse_ll *f, const char *opts)
 {
     if (opts) {
         char *xopts = strdup(opts);
@@ -830,21 +928,9 @@
 
         while((opt = strsep(&s, ","))) {
             if (strcmp(opt, "debug") == 0)
-                f->flags |= FUSE_DEBUG;
-            else if (strcmp(opt, "hard_remove") == 0)
-                f->flags |= FUSE_HARD_REMOVE;
-            else if (strcmp(opt, "use_ino") == 0)
-                f->flags |= FUSE_USE_INO;
+                f->debug = 1;
             else if (strcmp(opt, "allow_root") == 0)
-                f->flags |= FUSE_ALLOW_ROOT;
-            else if (strcmp(opt, "readdir_ino") == 0)
-                f->flags |= FUSE_READDIR_INO;
-            else if (sscanf(opt, "umask=%o", &f->umask) == 1)
-                f->flags |= FUSE_SET_MODE;
-            else if (sscanf(opt, "uid=%u", &f->uid) == 1)
-                f->flags |= FUSE_SET_UID;
-            else if(sscanf(opt, "gid=%u", &f->gid) == 1)
-                f->flags |= FUSE_SET_GID;
+                f->allow_root = 1;
             else
                 fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
         }
@@ -853,15 +939,15 @@
     return 0;
 }
 
-struct fuse_ll *fuse_lowlevel_new(int fd, const char *opts,
-                                  const struct fuse_lowlevel_operations *op,
-                                  size_t op_size)
+struct fuse_ll *fuse_ll_new(int fd, const char *opts,
+                            const struct fuse_ll_operations *op,
+                            size_t op_size)
 {
     struct fuse_ll *f;
 
-    if (sizeof(struct fuse_lowlevel_operations) < op_size) {
+    if (sizeof(struct fuse_ll_operations) < op_size) {
         fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
-        op_size = sizeof(struct fuse_lowlevel_operations);
+        op_size = sizeof(struct fuse_ll_operations);
     }
 
     f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll));
@@ -870,7 +956,7 @@
         goto out;
     }
 
-    if (parse_lib_opts(f, opts) == -1)
+    if (parse_ll_opts(f, opts) == -1)
         goto out_free;
 
     f->fd = fd;
@@ -886,4 +972,8 @@
     return NULL;
 }
 
+void fuse_ll_destroy(struct fuse_ll *f)
+{
+    free(f);
+}
 
diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript
index edbed43..1068265 100644
--- a/lib/fuse_versionscript
+++ b/lib/fuse_versionscript
@@ -1,11 +1,20 @@
 FUSE_2.2 {
 	global:
+		fuse_add_dirent;
 		fuse_destroy;
+		fuse_dirent_size;
 		fuse_exit;
 		fuse_exited;
 		fuse_get_context;
 		fuse_invalidate;
 		fuse_is_lib_option;
+		fuse_ll_new;
+		fuse_ll_destroy;
+		fuse_ll_is_lib_option;
+		fuse_ll_loop;
+		fuse_ll_exited;
+		fuse_ll_read_cmd;
+		fuse_ll_process_cmd;
 		fuse_loop;
 		fuse_loop_mt;
 		fuse_loop_mt_proc;
@@ -20,6 +29,16 @@
 		fuse_new_compat2;
 		fuse_process_cmd;
 		fuse_read_cmd;
+		fuse_reply_err;
+		fuse_reply_none;
+		fuse_reply_entry;
+		fuse_reply_attr;
+		fuse_reply_readlink;
+		fuse_reply_open;
+		fuse_reply_write;
+		fuse_reply_buf;
+		fuse_reply_statfs;
+		fuse_reply_xattr;
 		fuse_set_getcontext_func;
 		fuse_setup;
 		fuse_setup_compat2;
diff --git a/lib/helper.c b/lib/helper.c
index 13f3ca2..d5c63f2 100644
--- a/lib/helper.c
+++ b/lib/helper.c
@@ -289,6 +289,7 @@
 }
 
 static struct fuse *fuse_setup_common(int argc, char *argv[],
+                                      
                                       const struct fuse_operations *op,
                                       size_t op_size,
                                       char **mountpoint,