Support receiving file handle from kernel in GETATTR request; Allow operations with...
authorMiklos Szeredi <miklos@szeredi.hu>
Fri, 8 Feb 2008 17:22:15 +0000 (17:22 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Fri, 8 Feb 2008 17:22:15 +0000 (17:22 +0000)
ChangeLog
example/fusexmp_fh.c
include/fuse.h
include/fuse_common.h
lib/fuse.c
lib/fuse_lowlevel.c
lib/modules/iconv.c
lib/modules/subdir.c

index 5b45dcfe627da868a028f01ec69cd57c05219bab..7149a0788b36d92efaa2023815647e4d1003164d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -6,6 +6,11 @@
 
        * Update kernel interface to 7.9
 
+       * Support receiving file handle from kernel in GETATTR request
+
+       * Allow operations with a NULL path argument, if the filesystem
+       supports it
+
 2008-02-03  Csaba Henk <csaba.henk@creo.hu>
 
        * lib/mount_bsd.c:
index 494967578b7c111204ff737c2716de25e3086762..b86d3f6f8a9d9a21d3bb8571ab68917e1be30abb 100644 (file)
@@ -484,6 +484,8 @@ static struct fuse_operations xmp_oper = {
        .removexattr    = xmp_removexattr,
 #endif
        .lock           = xmp_lock,
+
+       .flag_nullpath_ok = 1,
 };
 
 int main(int argc, char *argv[])
index b7708c761e148cb671c72213340bd31a206ecb45..384a7b4a4915abcf41fa51b7374137a85bd510d5 100644 (file)
@@ -423,6 +423,20 @@ struct fuse_operations {
         * Introduced in version 2.6
         */
        int (*bmap) (const char *, size_t blocksize, uint64_t *idx);
+
+       /**
+        * Flag indicating, that the filesystem can accept a NULL path
+        * as the first argument for the following operations:
+        *
+        * read, write, flush, release, fsync, readdir, releasedir,
+        * fsyncdir, ftruncate, fgetattr and lock
+        */
+       unsigned int flag_nullpath_ok : 1;
+
+       /**
+        * Reserved flags, don't set
+        */
+       unsigned int flag_reserved : 31;
 };
 
 /** Extra context that may be needed by some filesystems
index 8d4ba2b211550bbb17b7d2cdd2b02d37c842768b..5f50d60ee6a921674aef83c28cdcc8c60e31f9d5 100644 (file)
@@ -22,7 +22,7 @@
 #define FUSE_MAJOR_VERSION 2
 
 /** Minor version of FUSE library interface */
-#define FUSE_MINOR_VERSION 7
+#define FUSE_MINOR_VERSION 8
 
 #define FUSE_MAKE_VERSION(maj, min)  ((maj) * 10 + (min))
 #define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION)
index 7bcbe76572c567ed3f166a04ea65c5e312cc8eea..a15b5c26dceb1cd9c6cac9c413d8bc005e060ed5 100644 (file)
@@ -90,6 +90,7 @@ struct fuse {
        struct fuse_config conf;
        int intr_installed;
        struct fuse_fs *fs;
+       int nullpath_ok;
 };
 
 struct lock {
@@ -764,7 +765,7 @@ int fuse_fs_fgetattr(struct fuse_fs *fs, const char *path, struct stat *buf,
        fuse_get_context()->private_data = fs->user_data;
        if (fs->op.fgetattr)
                return fs->op.fgetattr(path, buf, fi);
-       else if (fs->op.getattr)
+       else if (path && fs->op.getattr)
                return fs->op.getattr(path, buf);
        else
                return -ENOSYS;
@@ -992,7 +993,7 @@ int fuse_fs_ftruncate(struct fuse_fs *fs, const char *path, off_t size,
        fuse_get_context()->private_data = fs->user_data;
        if (fs->op.ftruncate)
                return fs->op.ftruncate(path, size, fi);
-       else if (fs->op.truncate)
+       else if (path && fs->op.truncate)
                return fs->op.truncate(path, size);
        else
                return -ENOSYS;
@@ -1409,16 +1410,18 @@ static void fuse_lib_getattr(fuse_req_t req, fuse_ino_t ino,
        char *path;
        int err;
 
-       (void) fi;
        memset(&buf, 0, sizeof(buf));
 
        err = -ENOENT;
        pthread_rwlock_rdlock(&f->tree_lock);
        path = get_path(f, ino);
-       if (path != NULL) {
+       if (path != NULL || (fi && f->nullpath_ok)) {
                struct fuse_intr_data d;
                fuse_prepare_interrupt(f, req, &d);
-               err = fuse_fs_getattr(f->fs, path, &buf);
+               if (fi)
+                       err = fuse_fs_fgetattr(f->fs, path, &buf, fi);
+               else
+                       err = fuse_fs_getattr(f->fs, path, &buf);
                fuse_finish_interrupt(f, req, &d);
                free(path);
        }
@@ -1774,7 +1777,7 @@ static void fuse_do_release(struct fuse *f, fuse_ino_t ino, const char *path,
        struct node *node;
        int unlink_hidden = 0;
 
-       fuse_fs_release(f->fs, path ? path : "-", fi);
+       fuse_fs_release(f->fs, (path || f->nullpath_ok) ? path : "-", fi);
 
        pthread_mutex_lock(&f->lock);
        node = get_node(f, ino);
@@ -1950,7 +1953,7 @@ static void fuse_lib_read(fuse_req_t req, fuse_ino_t ino, size_t size,
        res = -ENOENT;
        pthread_rwlock_rdlock(&f->tree_lock);
        path = get_path(f, ino);
-       if (path != NULL) {
+       if (path != NULL || f->nullpath_ok) {
                struct fuse_intr_data d;
                if (f->conf.debug)
                        fprintf(stderr, "READ[%llu] %lu bytes from %llu\n",
@@ -1987,7 +1990,7 @@ static void fuse_lib_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
        res = -ENOENT;
        pthread_rwlock_rdlock(&f->tree_lock);
        path = get_path(f, ino);
-       if (path != NULL) {
+       if (path != NULL || f->nullpath_ok) {
                struct fuse_intr_data d;
                if (f->conf.debug)
                        fprintf(stderr, "WRITE%s[%llu] %lu bytes to %llu\n",
@@ -2024,7 +2027,7 @@ static void fuse_lib_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
        err = -ENOENT;
        pthread_rwlock_rdlock(&f->tree_lock);
        path = get_path(f, ino);
-       if (path != NULL) {
+       if (path != NULL || f->nullpath_ok) {
                struct fuse_intr_data d;
                if (f->conf.debug)
                        fprintf(stderr, "FSYNC[%llu]\n",
@@ -2251,7 +2254,7 @@ static void fuse_lib_releasedir(fuse_req_t req, fuse_ino_t ino,
        pthread_rwlock_rdlock(&f->tree_lock);
        path = get_path(f, ino);
        fuse_prepare_interrupt(f, req, &d);
-       fuse_fs_releasedir(f->fs, path ? path : "-", &fi);
+       fuse_fs_releasedir(f->fs, (path || f->nullpath_ok) ? path : "-", &fi);
        fuse_finish_interrupt(f, req, &d);
        if (path)
                free(path);
@@ -2644,7 +2647,7 @@ static void fuse_lib_flush(fuse_req_t req, fuse_ino_t ino,
 
        pthread_rwlock_rdlock(&f->tree_lock);
        path = get_path(f, ino);
-       if (path && f->conf.debug)
+       if (f->conf.debug)
                fprintf(stderr, "FLUSH[%llu]\n", (unsigned long long) fi->fh);
        err = fuse_flush_common(f, req, ino, path, fi);
        free(path);
@@ -2663,7 +2666,7 @@ static int fuse_lock_common(fuse_req_t req, fuse_ino_t ino,
        err = -ENOENT;
        pthread_rwlock_rdlock(&f->tree_lock);
        path = get_path(f, ino);
-       if (path != NULL) {
+       if (path != NULL || f->nullpath_ok) {
                struct fuse_intr_data d;
                fuse_prepare_interrupt(f, req, &d);
                err = fuse_fs_lock(f->fs, path, fi, cmd, lock);
@@ -3023,6 +3026,7 @@ static int fuse_push_module(struct fuse *f, const char *module,
        }
        newfs->m = m;
        f->fs = newfs;
+       f->nullpath_ok = newfs->op.flag_nullpath_ok && f->nullpath_ok;
        return 0;
 }
 
@@ -3072,6 +3076,7 @@ struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
 
        fs->compat = compat;
        f->fs = fs;
+       f->nullpath_ok = fs->op.flag_nullpath_ok;
 
        /* Oh f**k, this is ugly! */
        if (!fs->op.lock) {
@@ -3103,6 +3108,9 @@ struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
                }
        }
 
+       if (f->conf.debug)
+               fprintf(stderr, "nullpath_ok: %i\n", f->nullpath_ok);
+
        if (!f->conf.ac_attr_timeout_set)
                f->conf.ac_attr_timeout = f->conf.attr_timeout;
 
index ed885fd8015650360c93c1e084e19ac35c08c086..d1ef7b247e87472f95999be718b3993d4f7135c6 100644 (file)
@@ -458,10 +458,22 @@ static void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
 
 static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
 {
-       (void) inarg;
+       struct fuse_file_info *fip = NULL;
+       struct fuse_file_info fi;
+
+       if (req->f->conn.proto_minor >= 9) {
+               struct fuse_getattr_in *arg = (struct fuse_getattr_in *) inarg;
+
+               if (arg->getattr_flags & FUSE_GETATTR_FH) {
+                       memset(&fi, 0, sizeof(fi));
+                       fi.fh = arg->fh;
+                       fi.fh_old = fi.fh;
+                       fip = &fi;
+               }
+       }
 
        if (req->f->op.getattr)
-               req->f->op.getattr(req, nodeid, NULL);
+               req->f->op.getattr(req, nodeid, fip);
        else
                fuse_reply_err(req, ENOSYS);
 }
index c0e2b800c0623f567e56e7c9944397be54f27b27..409cb663efa5757b30e3754f6be67bb8a14b408e 100644 (file)
@@ -42,17 +42,27 @@ static struct iconv *iconv_get(void)
 static int iconv_convpath(struct iconv *ic, const char *path, char **newpathp,
                          int fromfs)
 {
-       size_t pathlen = strlen(path);
-       size_t newpathlen = pathlen * 4;
-       char *newpath = malloc(newpathlen + 1);
-       size_t plen = newpathlen;
-       char *p = newpath;
+       size_t pathlen;
+       size_t newpathlen;
+       char *newpath;
+       size_t plen;
+       char *p;
        size_t res;
        int err;
 
+       if (path == NULL) {
+               *newpathp = NULL;
+               return 0;
+       }
+
+       pathlen = strlen(path);
+       newpathlen = pathlen * 4;
+       newpath = malloc(newpathlen + 1);
        if (!newpath)
                return -ENOMEM;
 
+       plen = newpathlen;
+       p = newpath;
        pthread_mutex_lock(&ic->lock);
        do {
                res = iconv(fromfs ? ic->fromfs : ic->tofs, (char **) &path,
@@ -607,6 +617,8 @@ static struct fuse_operations iconv_oper = {
        .removexattr    = iconv_removexattr,
        .lock           = iconv_lock,
        .bmap           = iconv_bmap,
+
+       .flag_nullpath_ok = 1,
 };
 
 static struct fuse_opt iconv_opts[] = {
index 6f7b18759c8bbb694048cbe0631086845d33adcd..3188d1fed190bf40acb270681c85c89be23641f9 100644 (file)
@@ -27,11 +27,17 @@ static struct subdir *subdir_get(void)
        return fuse_get_context()->private_data;
 }
 
-static char *subdir_addpath(struct subdir *d, const char *path)
+static int subdir_addpath(struct subdir *d, const char *path, char **newpathp)
 {
-       unsigned newlen = d->baselen + strlen(path);
-       char *newpath = malloc(newlen + 2);
-       if (newpath) {
+       char *newpath = NULL;
+
+       if (path != NULL) {
+               unsigned newlen = d->baselen + strlen(path);
+
+               newpath = malloc(newlen + 2);
+               if (!newpath)
+                       return -ENOMEM;
+
                if (path[0] == '/')
                        path++;
                strcpy(newpath, d->base);
@@ -39,15 +45,17 @@ static char *subdir_addpath(struct subdir *d, const char *path)
                if (!newpath[0])
                        strcpy(newpath, ".");
        }
-       return newpath;
+       *newpathp = newpath;
+
+       return 0;
 }
 
 static int subdir_getattr(const char *path, struct stat *stbuf)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_getattr(d->next, newpath, stbuf);
                free(newpath);
        }
@@ -58,9 +66,9 @@ static int subdir_fgetattr(const char *path, struct stat *stbuf,
                           struct fuse_file_info *fi)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_fgetattr(d->next, newpath, stbuf, fi);
                free(newpath);
        }
@@ -70,9 +78,9 @@ static int subdir_fgetattr(const char *path, struct stat *stbuf,
 static int subdir_access(const char *path, int mask)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_access(d->next, newpath, mask);
                free(newpath);
        }
@@ -146,9 +154,9 @@ static void transform_symlink(struct subdir *d, const char *path,
 static int subdir_readlink(const char *path, char *buf, size_t size)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_readlink(d->next, newpath, buf, size);
                if (!err && d->rellinks)
                        transform_symlink(d, newpath, buf, size);
@@ -160,9 +168,9 @@ static int subdir_readlink(const char *path, char *buf, size_t size)
 static int subdir_opendir(const char *path, struct fuse_file_info *fi)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_opendir(d->next, newpath, fi);
                free(newpath);
        }
@@ -174,9 +182,9 @@ static int subdir_readdir(const char *path, void *buf,
                          struct fuse_file_info *fi)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_readdir(d->next, newpath, buf, filler, offset,
                                      fi);
                free(newpath);
@@ -187,9 +195,9 @@ static int subdir_readdir(const char *path, void *buf,
 static int subdir_releasedir(const char *path, struct fuse_file_info *fi)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_releasedir(d->next, newpath, fi);
                free(newpath);
        }
@@ -199,9 +207,9 @@ static int subdir_releasedir(const char *path, struct fuse_file_info *fi)
 static int subdir_mknod(const char *path, mode_t mode, dev_t rdev)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_mknod(d->next, newpath, mode, rdev);
                free(newpath);
        }
@@ -211,9 +219,9 @@ static int subdir_mknod(const char *path, mode_t mode, dev_t rdev)
 static int subdir_mkdir(const char *path, mode_t mode)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_mkdir(d->next, newpath, mode);
                free(newpath);
        }
@@ -223,9 +231,9 @@ static int subdir_mkdir(const char *path, mode_t mode)
 static int subdir_unlink(const char *path)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_unlink(d->next, newpath);
                free(newpath);
        }
@@ -235,9 +243,9 @@ static int subdir_unlink(const char *path)
 static int subdir_rmdir(const char *path)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_rmdir(d->next, newpath);
                free(newpath);
        }
@@ -247,9 +255,9 @@ static int subdir_rmdir(const char *path)
 static int subdir_symlink(const char *from, const char *path)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_symlink(d->next, from, newpath);
                free(newpath);
        }
@@ -259,35 +267,43 @@ static int subdir_symlink(const char *from, const char *path)
 static int subdir_rename(const char *from, const char *to)
 {
        struct subdir *d = subdir_get();
-       char *newfrom = subdir_addpath(d, from);
-       char *newto = subdir_addpath(d, to);
-       int err = -ENOMEM;
-       if (newfrom && newto)
-               err = fuse_fs_rename(d->next, newfrom, newto);
-       free(newfrom);
-       free(newto);
+       char *newfrom;
+       char *newto;
+       int err = subdir_addpath(d, from, &newfrom);
+       if (!err) {
+               err = subdir_addpath(d, to, &newto);
+               if (!err) {
+                       err = fuse_fs_rename(d->next, newfrom, newto);
+                       free(newto);
+               }
+               free(newfrom);
+       }
        return err;
 }
 
 static int subdir_link(const char *from, const char *to)
 {
        struct subdir *d = subdir_get();
-       char *newfrom = subdir_addpath(d, from);
-       char *newto = subdir_addpath(d, to);
-       int err = -ENOMEM;
-       if (newfrom && newto)
-               err = fuse_fs_link(d->next, newfrom, newto);
-       free(newfrom);
-       free(newto);
+       char *newfrom;
+       char *newto;
+       int err = subdir_addpath(d, from, &newfrom);
+       if (!err) {
+               err = subdir_addpath(d, to, &newto);
+               if (!err) {
+                       err = fuse_fs_link(d->next, newfrom, newto);
+                       free(newto);
+               }
+               free(newfrom);
+       }
        return err;
 }
 
 static int subdir_chmod(const char *path, mode_t mode)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_chmod(d->next, newpath, mode);
                free(newpath);
        }
@@ -297,9 +313,9 @@ static int subdir_chmod(const char *path, mode_t mode)
 static int subdir_chown(const char *path, uid_t uid, gid_t gid)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_chown(d->next, newpath, uid, gid);
                free(newpath);
        }
@@ -309,9 +325,9 @@ static int subdir_chown(const char *path, uid_t uid, gid_t gid)
 static int subdir_truncate(const char *path, off_t size)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_truncate(d->next, newpath, size);
                free(newpath);
        }
@@ -322,9 +338,9 @@ static int subdir_ftruncate(const char *path, off_t size,
                            struct fuse_file_info *fi)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_ftruncate(d->next, newpath, size, fi);
                free(newpath);
        }
@@ -334,9 +350,9 @@ static int subdir_ftruncate(const char *path, off_t size,
 static int subdir_utimens(const char *path, const struct timespec ts[2])
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_utimens(d->next, newpath, ts);
                free(newpath);
        }
@@ -347,9 +363,9 @@ static int subdir_create(const char *path, mode_t mode,
                         struct fuse_file_info *fi)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_create(d->next, newpath, mode, fi);
                free(newpath);
        }
@@ -359,9 +375,9 @@ static int subdir_create(const char *path, mode_t mode,
 static int subdir_open(const char *path, struct fuse_file_info *fi)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_open(d->next, newpath, fi);
                free(newpath);
        }
@@ -372,9 +388,9 @@ static int subdir_read(const char *path, char *buf, size_t size, off_t offset,
                       struct fuse_file_info *fi)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_read(d->next, newpath, buf, size, offset, fi);
                free(newpath);
        }
@@ -385,9 +401,9 @@ static int subdir_write(const char *path, const char *buf, size_t size,
                        off_t offset, struct fuse_file_info *fi)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_write(d->next, newpath, buf, size, offset, fi);
                free(newpath);
        }
@@ -397,9 +413,9 @@ static int subdir_write(const char *path, const char *buf, size_t size,
 static int subdir_statfs(const char *path, struct statvfs *stbuf)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_statfs(d->next, newpath, stbuf);
                free(newpath);
        }
@@ -409,9 +425,9 @@ static int subdir_statfs(const char *path, struct statvfs *stbuf)
 static int subdir_flush(const char *path, struct fuse_file_info *fi)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_flush(d->next, newpath, fi);
                free(newpath);
        }
@@ -421,9 +437,9 @@ static int subdir_flush(const char *path, struct fuse_file_info *fi)
 static int subdir_release(const char *path, struct fuse_file_info *fi)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_release(d->next, newpath, fi);
                free(newpath);
        }
@@ -434,9 +450,9 @@ static int subdir_fsync(const char *path, int isdatasync,
                        struct fuse_file_info *fi)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_fsync(d->next, newpath, isdatasync, fi);
                free(newpath);
        }
@@ -447,9 +463,9 @@ static int subdir_fsyncdir(const char *path, int isdatasync,
                           struct fuse_file_info *fi)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_fsyncdir(d->next, newpath, isdatasync, fi);
                free(newpath);
        }
@@ -460,9 +476,9 @@ static int subdir_setxattr(const char *path, const char *name,
                           const char *value, size_t size, int flags)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_setxattr(d->next, newpath, name, value, size,
                                       flags);
                free(newpath);
@@ -474,9 +490,9 @@ static int subdir_getxattr(const char *path, const char *name, char *value,
                           size_t size)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_getxattr(d->next, newpath, name, value, size);
                free(newpath);
        }
@@ -486,9 +502,9 @@ static int subdir_getxattr(const char *path, const char *name, char *value,
 static int subdir_listxattr(const char *path, char *list, size_t size)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_listxattr(d->next, newpath, list, size);
                free(newpath);
        }
@@ -498,9 +514,9 @@ static int subdir_listxattr(const char *path, char *list, size_t size)
 static int subdir_removexattr(const char *path, const char *name)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_removexattr(d->next, newpath, name);
                free(newpath);
        }
@@ -511,9 +527,9 @@ static int subdir_lock(const char *path, struct fuse_file_info *fi, int cmd,
                       struct flock *lock)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_lock(d->next, newpath, fi, cmd, lock);
                free(newpath);
        }
@@ -523,9 +539,9 @@ static int subdir_lock(const char *path, struct fuse_file_info *fi, int cmd,
 static int subdir_bmap(const char *path, size_t blocksize, uint64_t *idx)
 {
        struct subdir *d = subdir_get();
-       char *newpath = subdir_addpath(d, path);
-       int err = -ENOMEM;
-       if (newpath) {
+       char *newpath;
+       int err = subdir_addpath(d, path, &newpath);
+       if (!err) {
                err = fuse_fs_bmap(d->next, newpath, blocksize, idx);
                free(newpath);
        }
@@ -584,6 +600,8 @@ static struct fuse_operations subdir_oper = {
        .removexattr    = subdir_removexattr,
        .lock           = subdir_lock,
        .bmap           = subdir_bmap,
+
+       .flag_nullpath_ok = 1,
 };
 
 static struct fuse_opt subdir_opts[] = {