fix
diff --git a/lib/fuse.c b/lib/fuse.c
index 9a31b15..6a919c9 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -63,6 +63,13 @@
     unsigned char *contents;
     unsigned len;
     int filled;
+    unsigned long fh;
+};
+
+struct fuse_dirbuf {
+    struct fuse *fuse;
+    char *buf;
+    unsigned len;
 };
 
 struct fuse_cmd {
@@ -436,6 +443,35 @@
 #endif
 }
 
+static int fill_dir5(void *buf, const char *name, int type, ino_t ino,
+                     off_t off)
+{
+    size_t namelen = strlen(name);
+    size_t size;
+    struct fuse_dirbuf *db = (struct fuse_dirbuf *) buf;
+    struct fuse_dirent *dirent;
+
+    if (db->len <= FUSE_NAME_OFFSET)
+        return 1;
+
+    dirent = (struct fuse_dirent *) db->buf;
+    if ((db->fuse->flags & FUSE_USE_INO))
+        dirent->ino = ino;
+    else
+        dirent->ino = (unsigned long) -1;
+    dirent->off = off;
+    dirent->namelen = namelen;
+    dirent->type = type;
+    size = FUSE_DIRENT_SIZE(dirent);
+    if (db->len < size)
+        return 1;
+    
+    strncpy(dirent->name, name, namelen);
+    db->len -= size;
+    db->buf += size;
+    return db->len > FUSE_NAME_OFFSET ? 0 : 1;
+}
+
 static int fill_dir(struct fuse_dirhandle *dh, const char *name, int type,
                     ino_t ino)
 {
@@ -459,8 +495,8 @@
     dirent->namelen = namelen;
     strncpy(dirent->name, name, namelen);
     dirent->type = type;
-    dirent->off = dh->len;
     dh->len += FUSE_DIRENT_SIZE(dirent);
+    dirent->off = dh->len;
     return 0;
 }
 
@@ -1502,6 +1538,12 @@
     if (f->op.init)
         f->user_data = f->op.init();
 
+    if (arg->major < 6) {
+        fprintf(stderr, "Kernel API version 5 not yet handled\n");
+        fuse_exit(f);
+        return;
+    }
+
     memset(&outarg, 0, sizeof(outarg));
     outarg.major = FUSE_KERNEL_VERSION;
     outarg.minor = FUSE_KERNEL_MINOR_VERSION;
@@ -1520,81 +1562,137 @@
     struct fuse_open_out outarg;
     struct fuse_dirhandle *dh;
 
+    dh = (struct fuse_dirhandle *) malloc(sizeof(struct fuse_dirhandle));
+    if (dh == NULL) {
+        send_reply(f, in, -ENOMEM, NULL, 0);
+        return;
+    }
+    memset(dh, 0, sizeof(struct fuse_dirhandle));
+    dh->fuse = f;
+    dh->contents = NULL;
+    dh->len = 0;
+    dh->filled = 0;
+
+    memset(&outarg, 0, sizeof(outarg));
+    outarg.fh = (unsigned long) dh;
+
     if (f->op.opendir) {
+        struct fuse_file_info fi;
         char *path;
+
+        memset(&fi, 0, sizeof(fi));
+        fi.flags = arg->flags;
+
         res = -ENOENT;
         path = get_path(f, in->nodeid);
         if (path != NULL) {
-            struct fuse_file_info fi;
-            memset(&fi, 0, sizeof(fi));
-            fi.flags = arg->flags;
             res = f->op.opendir(path, &fi);
-            free(path);
+            dh->fh = fi.fh;
         }
-        if (res != 0) {
+        if (res == 0) {
+            int res2;
+            pthread_mutex_lock(&f->lock);
+            res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
+            if(res2 == -ENOENT) {
+                /* The opendir syscall was interrupted, so it must be
+                   cancelled */
+                if(f->op.releasedir)
+                    f->op.releasedir(path, &fi);
+                free(dh);
+            }
+            pthread_mutex_unlock(&f->lock);
+        } else {
             send_reply(f, in, res, NULL, 0);
-            return;
+            free(dh);
         }
-    }
-
-    memset(&outarg, 0, sizeof(outarg));
-    res = -ENOMEM;
-    dh = (struct fuse_dirhandle *) malloc(sizeof(struct fuse_dirhandle));
-    if (dh != NULL) {
-        memset(dh, 0, sizeof(struct fuse_dirhandle));
-        dh->fuse = f;
-        dh->contents = NULL;
-        dh->len = 0;
-        dh->filled = 0;
-        outarg.fh = (unsigned long) dh;
-        res = 0;
-    }
-    send_reply(f, in, res, &outarg, sizeof(outarg));
+        free(path);
+    } else 
+        send_reply(f, in, 0, &outarg, sizeof(outarg));
 }
 
 static void do_readdir(struct fuse *f, struct fuse_in_header *in,
                        struct fuse_read_in *arg)
 {
-    char *outbuf;
+    int res;
     struct fuse_dirhandle *dh = get_dirhandle(arg->fh);
+    struct fuse_out_header *out;
+    char *outbuf;
+    char *buf;
+    size_t size = 0;
+    size_t outsize;
 
-    if (!dh->filled) {
-        int res = common_getdir(f, in, dh);
-        if (res) {
-            send_reply(f, in, res, NULL, 0);
-            return;
-        }
-        dh->filled = 1;
-    }
     outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
-    if (outbuf == NULL)
+    if (outbuf == NULL) {
         send_reply(f, in, -ENOMEM, NULL, 0);
-    else {
-        struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
-        char *buf = outbuf + sizeof(struct fuse_out_header);
-        size_t size = 0;
-        size_t outsize;
+        return;
+    }
+    buf = outbuf + sizeof(struct fuse_out_header);
+
+    if (f->op.readdir) {
+        struct fuse_dirbuf db;
+        struct fuse_file_info fi;
+        char *path;
+
+        db.fuse = f;
+        db.buf = buf;
+        db.len = arg->size;
+
+        memset(&fi, 0, sizeof(fi));
+        fi.fh = dh->fh;
+
+        path = get_path(f, in->nodeid);
+        res = f->op.readdir(path ? path : "-", &db, fill_dir5, arg->offset, &fi);
+        free(path);
+        if (res)
+            goto err;
+
+        size = arg->size - db.len;
+    } else {
+        if (!dh->filled) {
+            res = common_getdir(f, in, dh);
+            if (res)
+                goto err;
+            dh->filled = 1;
+        }
+
         if (arg->offset < dh->len) {
             size = arg->size;
             if (arg->offset + size > dh->len)
                 size = dh->len - arg->offset;
-
+            
             memcpy(buf, dh->contents + arg->offset, size);
         }
-        memset(out, 0, sizeof(struct fuse_out_header));
-        out->unique = in->unique;
-        out->error = 0;
-        outsize = sizeof(struct fuse_out_header) + size;
-
-        send_reply_raw(f, outbuf, outsize);
-        free(outbuf);
     }
+    out = (struct fuse_out_header *) outbuf;
+    memset(out, 0, sizeof(struct fuse_out_header));
+    out->unique = in->unique;
+    out->error = 0;
+    outsize = sizeof(struct fuse_out_header) + size;
+    
+    send_reply_raw(f, outbuf, outsize);
+    free(outbuf);
+    return;
+
+ err:
+    send_reply(f, in, res, NULL, 0);
+    free(outbuf);
 }
 
 static void do_releasedir(struct fuse *f, struct fuse_in_header *in,
                           struct fuse_release_in *arg)
 {
     struct fuse_dirhandle *dh = get_dirhandle(arg->fh);
+    if (f->op.releasedir) {
+        char *path;
+        struct fuse_file_info fi;
+        
+        memset(&fi, 0, sizeof(fi));
+        fi.fh = dh->fh;
+
+        path = get_path(f, in->nodeid);
+        f->op.releasedir(path ? path : "-", &fi);
+        free(path);
+    }
     free(dh->contents);
     free(dh);
     send_reply(f, in, 0, NULL, 0);
@@ -1605,9 +1703,12 @@
 {
     int res;
     char *path;
+    struct fuse_dirhandle *dh = get_dirhandle(inarg->fh);
     struct fuse_file_info fi;
 
     memset(&fi, 0, sizeof(fi));
+    fi.fh = dh->fh;
+
     res = -ENOENT;
     path = get_path(f, in->nodeid);
     if (path != NULL) {