fix
authorMiklos Szeredi <miklos@szeredi.hu>
Thu, 7 Apr 2005 15:40:21 +0000 (15:40 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Thu, 7 Apr 2005 15:40:21 +0000 (15:40 +0000)
ChangeLog
example/.cvsignore
example/Makefile.am
example/fusexmp.c
example/fusexmp_fh.c [new file with mode: 0644]
example/hello.c
include/fuse.h
lib/fuse.c
lib/fuse_kernel_compat5.h

index 8811780312c2ac5d700f5c822ccf5626f95767e0..d32280f8977b05bcca2e07ed4bacd744b08b9857 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2005-04-07  Miklos Szeredi <miklos@szeredi.hu>
+
+       * lib: finalized new readdir() interface, which now supersedes the
+       getdir() method.
+
 2005-04-03  Miklos Szeredi <miklos@szeredi.hu>
 
        * Released 2.3-pre3
index f9c78843604f1974ff9cc4056c910e27391e440b..80eb82bdbbf99d88db596cff836105f5792e7162 100644 (file)
@@ -2,6 +2,7 @@ Makefile.in
 Makefile
 .deps
 fusexmp
+fusexmp_fh
 null
 hello
 .libs
index e8c8a6dccc8ab270ccfc9b6c5af491047d98fda4..be7a67470b58fb832c80e7942ddb556ce9ebbb9d 100644 (file)
@@ -1,8 +1,9 @@
 ## Process this file with automake to produce Makefile.in
 
-noinst_PROGRAMS = fusexmp null hello
+noinst_PROGRAMS = fusexmp fusexmp_fh null hello
 
 fusexmp_SOURCES = fusexmp.c
+fusexmp_fh_SOURCES = fusexmp_fh.c
 null_SOURCES = null.c
 hello_SOURCES = hello.c
 
index 3230c3600a8030e8f3a9ce5fd6eadd3eee13a2a3..95d26b35cd275309f77a1df11abc00f0f27326ce 100644 (file)
@@ -49,24 +49,30 @@ static int xmp_readlink(const char *path, char *buf, size_t size)
 }
 
 
-static int xmp_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler)
+static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+                       off_t offset, struct fuse_file_info *fi)
 {
     DIR *dp;
     struct dirent *de;
-    int res = 0;
+
+    (void) offset;
+    (void) fi;
 
     dp = opendir(path);
     if(dp == NULL)
         return -errno;
 
     while((de = readdir(dp)) != NULL) {
-        res = filler(h, de->d_name, de->d_type, de->d_ino);
-        if(res != 0)
+        struct stat st;
+        memset(&st, 0, sizeof(st));
+        st.st_ino = de->d_ino;
+        st.st_mode = de->d_type << 12;
+        if (filler(buf, de->d_name, &st, 0))
             break;
     }
 
     closedir(dp);
-    return res;
+    return 0;
 }
 
 static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
@@ -314,7 +320,7 @@ static int xmp_removexattr(const char *path, const char *name)
 static struct fuse_operations xmp_oper = {
     .getattr   = xmp_getattr,
     .readlink  = xmp_readlink,
-    .getdir    = xmp_getdir,
+    .readdir   = xmp_readdir,
     .mknod     = xmp_mknod,
     .mkdir     = xmp_mkdir,
     .symlink   = xmp_symlink,
diff --git a/example/fusexmp_fh.c b/example/fusexmp_fh.c
new file mode 100644 (file)
index 0000000..8a40c9e
--- /dev/null
@@ -0,0 +1,355 @@
+/*
+    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 <config.h>
+
+#ifdef linux
+/* For pread()/pwrite() */
+#define _XOPEN_SOURCE 500
+#endif
+
+#include <fuse.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <sys/statfs.h>
+#ifdef HAVE_SETXATTR
+#include <sys/xattr.h>
+#endif
+
+static int xmp_getattr(const char *path, struct stat *stbuf)
+{
+    int res;
+
+    res = lstat(path, stbuf);
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+static int xmp_readlink(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 xmp_opendir(const char *path, struct fuse_file_info *fi)
+{
+    DIR *dp = opendir(path);
+    if (dp == NULL)
+        return -errno;
+
+    fi->fh = (unsigned long) dp;
+    return 0;
+}
+
+static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+                       off_t offset, struct fuse_file_info *fi)
+{
+    DIR *dp = (DIR *) fi->fh;
+    struct dirent *de;
+
+    (void) path;
+    seekdir(dp, offset);
+    while ((de = readdir(dp)) != NULL) {
+        struct stat st;
+        memset(&st, 0, sizeof(st));
+        st.st_ino = de->d_ino;
+        st.st_mode = de->d_type << 12;
+        if (filler(buf, de->d_name, &st, de->d_off))
+            break;
+    }
+
+    return 0;
+}
+
+static int xmp_releasedir(const char *path, struct fuse_file_info *fi)
+{
+    DIR *dp = (DIR *) fi->fh;
+    (void) path;
+    closedir(dp);
+    return 0;
+}
+
+static int xmp_mknod(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 xmp_mkdir(const char *path, mode_t mode)
+{
+    int res;
+
+    res = mkdir(path, mode);
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+static int xmp_unlink(const char *path)
+{
+    int res;
+
+    res = unlink(path);
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+static int xmp_rmdir(const char *path)
+{
+    int res;
+
+    res = rmdir(path);
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+static int xmp_symlink(const char *from, const char *to)
+{
+    int res;
+
+    res = symlink(from, to);
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+static int xmp_rename(const char *from, const char *to)
+{
+    int res;
+
+    res = rename(from, to);
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+static int xmp_link(const char *from, const char *to)
+{
+    int res;
+
+    res = link(from, to);
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+static int xmp_chmod(const char *path, mode_t mode)
+{
+    int res;
+
+    res = chmod(path, mode);
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+static int xmp_chown(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 xmp_truncate(const char *path, off_t size)
+{
+    int res;
+
+    res = truncate(path, size);
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+static int xmp_utime(const char *path, struct utimbuf *buf)
+{
+    int res;
+
+    res = utime(path, buf);
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+
+static int xmp_open(const char *path, struct fuse_file_info *fi)
+{
+    int res;
+
+    res = open(path, fi->flags);
+    if(res == -1)
+        return -errno;
+
+    fi->fh = res;
+    return 0;
+}
+
+static int xmp_read(const char *path, char *buf, size_t size, off_t offset,
+                    struct fuse_file_info *fi)
+{
+    int res;
+
+    (void) path;
+    res = pread(fi->fh, buf, size, offset);
+    if(res == -1)
+        res = -errno;
+
+    return res;
+}
+
+static int xmp_write(const char *path, const char *buf, size_t size,
+                     off_t offset, struct fuse_file_info *fi)
+{
+    int res;
+
+    (void) path;
+    res = pwrite(fi->fh, buf, size, offset);
+    if(res == -1)
+        res = -errno;
+
+    return res;
+}
+
+static int xmp_statfs(const char *path, struct statfs *stbuf)
+{
+    int res;
+
+    res = statfs(path, stbuf);
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+static int xmp_release(const char *path, struct fuse_file_info *fi)
+{
+    (void) path;
+    close(fi->fh);
+
+    return 0;
+}
+
+static int xmp_fsync(const char *path, int isdatasync,
+                     struct fuse_file_info *fi)
+{
+    int res;
+    (void) path;
+
+    if (isdatasync)
+        res = fdatasync(fi->fh);
+    else
+        res = fsync(fi->fh);
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+#ifdef HAVE_SETXATTR
+/* xattr operations are optional and can safely be left unimplemented */
+static int xmp_setxattr(const char *path, const char *name, const char *value,
+                        size_t size, int flags)
+{
+    int res = lsetxattr(path, name, value, size, flags);
+    if(res == -1)
+        return -errno;
+    return 0;
+}
+
+static int xmp_getxattr(const char *path, const char *name, char *value,
+                    size_t size)
+{
+    int res = lgetxattr(path, name, value, size);
+    if(res == -1)
+        return -errno;
+    return res;
+}
+
+static int xmp_listxattr(const char *path, char *list, size_t size)
+{
+    int res = llistxattr(path, list, size);
+    if(res == -1)
+        return -errno;
+    return res;
+}
+
+static int xmp_removexattr(const char *path, const char *name)
+{
+    int res = lremovexattr(path, name);
+    if(res == -1)
+        return -errno;
+    return 0;
+}
+#endif /* HAVE_SETXATTR */
+
+static struct fuse_operations xmp_oper = {
+    .getattr   = xmp_getattr,
+    .readlink  = xmp_readlink,
+    .opendir   = xmp_opendir,
+    .readdir   = xmp_readdir,
+    .releasedir        = xmp_releasedir,
+    .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,
+    .statfs    = xmp_statfs,
+    .release   = xmp_release,
+    .fsync     = xmp_fsync,
+#ifdef HAVE_SETXATTR
+    .setxattr  = xmp_setxattr,
+    .getxattr  = xmp_getxattr,
+    .listxattr = xmp_listxattr,
+    .removexattr= xmp_removexattr,
+#endif
+};
+
+int main(int argc, char *argv[])
+{
+    return fuse_main(argc, argv, &xmp_oper);
+}
index 9e4099b33b6871957b7d7bad244e366d9748c78b..b71bcd645ecc857163cebe396d24a5a0c18d0a7e 100644 (file)
@@ -35,14 +35,18 @@ static int hello_getattr(const char *path, struct stat *stbuf)
     return res;
 }
 
-static int hello_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler)
+static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+                         off_t offset, struct fuse_file_info *fi)
 {
+    (void) offset;
+    (void) fi;
+
     if(strcmp(path, "/") != 0)
         return -ENOENT;
 
-    filler(h, ".", 0, 0);
-    filler(h, "..", 0, 0);
-    filler(h, hello_path + 1, 0, 0);
+    filler(buf, ".", NULL, 0);
+    filler(buf, "..", NULL, 0);
+    filler(buf, hello_path + 1, NULL, 0);
 
     return 0;
 }
@@ -79,7 +83,7 @@ static int hello_read(const char *path, char *buf, size_t size, off_t offset,
 
 static struct fuse_operations hello_oper = {
     .getattr   = hello_getattr,
-    .getdir    = hello_getdir,
+    .readdir   = hello_readdir,
     .open      = hello_open,
     .read      = hello_read,
 };
index 35ec49ffb7319e54425e1a42b6e8417fe2b28930..336e8f3ea9f3fce5d5f33f2d9b5188692b43ad0d 100644 (file)
@@ -47,33 +47,21 @@ extern "C" {
 /** 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
- *
- * @param h the handle passed to the getdir() operation
- * @param name the file name of the directory entry
- * @param type the file type (0 if unknown)  see <dirent.h>
- * @param ino the inode number, ignored if "use_ino" mount option is
- *            not specified
- * @return 0 on success, -errno on error
- */
-typedef int (*fuse_dirfil_t) (fuse_dirh_t h, const char *name, int type,
-                              ino_t ino);
-
 /** Function to add an entry in a readdir() operation
  *
  * @param buf the buffer passed to the readdir() operation
  * @param name the file name of the directory entry
- * @param type the file type (0 if unknown)  see <dirent.h>
- * @param ino the inode number, ignored if "use_ino" mount option is
- *            not specified
- * @param off offset of the next entry
- * @return 0 on success, 1 if buffer is full
+ * @param stat file attributes, can be NULL
+ * @param off offset of the next entry or zero
+ * @return 1 if buffer is full, zero otherwise
  */
-typedef int (*fuse_dirfil5_t) (void *buf, const char *name, int type,
-                               ino_t ino, off_t off);
+typedef int (*fuse_fill_dir_t) (void *buf, const char *name,
+                                const struct stat *stat, off_t off);
+
+/* Used by deprecated getdir() method */
+typedef struct fuse_dirhandle *fuse_dirh_t;
+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 {
@@ -99,7 +87,7 @@ struct fuse_file_info {
  *
  * All methods are optional, but some are essential for a useful
  * filesystem (e.g. getattr).  Flush, release, fsync, opendir,
- * readdir, releasedir, fsyncdir, init and destroy are special purpose
+ * releasedir, fsyncdir, init and destroy are special purpose
  * methods, without which a full featured filesystem can still be
  * implemented.
  */
@@ -122,12 +110,7 @@ struct fuse_operations {
      */
     int (*readlink) (const char *, char *, size_t);
 
-    /** Read the contents of a directory
-     *
-     * This operation is the opendir(), readdir(), ..., closedir()
-     * sequence in one call. For each directory entry the filldir
-     * function should be called.
-     */
+    /* Deprecated, use readdir() instead */
     int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t);
 
     /** Create a file node
@@ -265,10 +248,24 @@ struct fuse_operations {
 
     /** Read directory
      *
-     * This is an alternative inteface to getdir(), and if defined
-     * getdir() will not be called
+     * This supersedes the old getdir() interface.  New applications
+     * should use this.
+     *
+     * The filesystem may choose between two modes of operation:
+     * 
+     * 1) The readdir implementation ignores the offset parameter, and
+     * passes zero to the filler function's offset.  The filler
+     * function will not return '1' (unless an error happens), so the
+     * whole directory is read in a single readdir operation.  This
+     * works just like the old getdir() method.
+     *
+     * 2) The readdir implementation keeps track of the offsets of the
+     * directory entries.  It uses the offset parameter and always
+     * passes non-zero offset to the filler function.  When the buffer
+     * is full (or an error happens) the filler function will return
+     * '1'.
      */
-    int (*readdir) (const char *, void *, fuse_dirfil5_t, off_t,
+    int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t,
                     struct fuse_file_info *);
 
     /** Release directory */
index 40230af1181c7a8731ab3b9b5b83241728963b33..82adeb274d43fac9c5bbb596cd1a69ec4141a1cd 100644 (file)
@@ -21,6 +21,7 @@
 #include <assert.h>
 #include <stdint.h>
 #include <sys/param.h>
+#include <sys/uio.h>
 
 /* FUSE flags: */
 
@@ -69,17 +70,15 @@ struct node {
 };
 
 struct fuse_dirhandle {
+    pthread_mutex_t lock;
     struct fuse *fuse;
     unsigned char *contents;
+    int allocated;
     unsigned len;
+    unsigned needlen;
     int filled;
     unsigned long fh;
-};
-
-struct fuse_dirbuf {
-    struct fuse *fuse;
-    char *buf;
-    unsigned len;
+    int error;
 };
 
 struct fuse_cmd {
@@ -90,6 +89,19 @@ struct fuse_cmd {
 
 static struct fuse_context *(*fuse_getcontext)(void) = NULL;
 
+#ifndef USE_UCLIBC
+#define mutex_init(mut) pthread_mutex_init(mut, NULL)
+#else
+static void mutex_init(pthread_mutex_t mut)
+{
+    pthread_mutexattr_t attr;
+    pthread_mutexattr_init(&attr);
+    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
+    pthread_mutex_init(mut, &attr);
+    pthread_mutexattr_destroy(&attr);
+}
+#endif
+
 static const char *opname(enum fuse_opcode opcode)
 {
     switch (opcode) {
@@ -453,103 +465,22 @@ static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
 #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_compat5(struct fuse_dirhandle *dh, const char *name,
-                            int type, ino_t ino)
+static  size_t iov_length(const struct iovec *iov, size_t count)
 {
-    size_t namelen = strlen(name);
-    size_t entsize = sizeof(struct fuse_dirhandle) + namelen + 8;
-    struct fuse_dirent_compat5 *dirent;
-
-    if (namelen > FUSE_NAME_MAX)
-        namelen = FUSE_NAME_MAX;
-
-    dh->contents = realloc(dh->contents, dh->len + entsize);
-    if (dh->contents == NULL)
-        return -ENOMEM;
-
-    dirent = (struct fuse_dirent_compat5 *) (dh->contents + dh->len);
-    memset(dirent, 0, entsize);
-    if ((dh->fuse->flags & FUSE_USE_INO))
-        dirent->ino = ino;
-    else
-        dirent->ino = (unsigned long) -1;
-    dirent->namelen = namelen;
-    strncpy(dirent->name, name, namelen);
-    dirent->type = type;
-    dh->len += FUSE_DIRENT_SIZE_COMPAT5(dirent);
-    return 0;
-}
-
-static int fill_dir_new(struct fuse_dirhandle *dh, const char *name, int type,
-                        ino_t ino)
-{
-    size_t namelen = strlen(name);
-    size_t entsize = sizeof(struct fuse_dirhandle) + namelen + 8;
-    struct fuse_dirent *dirent;
-
-    if (namelen > FUSE_NAME_MAX)
-        namelen = FUSE_NAME_MAX;
-
-    dh->contents = realloc(dh->contents, dh->len + entsize);
-    if (dh->contents == NULL)
-        return -ENOMEM;
-
-    dirent = (struct fuse_dirent *) (dh->contents + dh->len);
-    memset(dirent, 0, entsize);
-    if ((dh->fuse->flags & FUSE_USE_INO))
-        dirent->ino = ino;
-    else
-        dirent->ino = (unsigned long) -1;
-    dirent->namelen = namelen;
-    strncpy(dirent->name, name, namelen);
-    dirent->type = type;
-    dh->len += FUSE_DIRENT_SIZE(dirent);
-    dirent->off = dh->len;
-    return 0;
-}
+    size_t seg;
+    size_t ret = 0;
 
-static int fill_dir(struct fuse_dirhandle *dh, const char *name, int type,
-                    ino_t ino)
-{
-    if (dh->fuse->major == 5)
-        return fill_dir_compat5(dh, name, type, ino);
-    else
-        return fill_dir_new(dh, name, type, ino);
+    for (seg = 0; seg < count; seg++)
+        ret += iov[seg].iov_len;
+    return ret;
 }
 
-static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize)
+static int send_reply_raw(struct fuse *f, const struct iovec iov[],
+                          size_t count)
 {
     int res;
-    struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
+    unsigned outsize = iov_length(iov, count);
+    struct fuse_out_header *out = (struct fuse_out_header *) iov[0].iov_base;
     out->len = outsize;
 
     if ((f->flags & FUSE_DEBUG)) {
@@ -563,7 +494,7 @@ static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize)
        increased long after the operation is done */
     fuse_inc_avail(f);
 
-    res = write(f->fd, outbuf, outsize);
+    res = writev(f->fd, iov, count);
     if (res == -1) {
         /* ENOENT means the operation was interrupted */
         if (!f->exited && errno != ENOENT)
@@ -576,37 +507,26 @@ static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize)
 static int send_reply(struct fuse *f, struct fuse_in_header *in, int error,
                       void *arg, size_t argsize)
 {
-    int res;
-    char *outbuf;
-    size_t outsize;
-    struct fuse_out_header *out;
+    struct fuse_out_header out;
+    struct iovec iov[2];
+    size_t count;
 
     if (error <= -1000 || error > 0) {
         fprintf(stderr, "fuse: bad error value: %i\n",  error);
         error = -ERANGE;
     }
 
-    if (error)
-        argsize = 0;
-
-    outsize = sizeof(struct fuse_out_header) + argsize;
-    outbuf = (char *) malloc(outsize);
-    if (outbuf == NULL) {
-        fprintf(stderr, "fuse: failed to allocate reply buffer\n");
-        res = -ENOMEM;
-    } else {
-        out = (struct fuse_out_header *) outbuf;
-        memset(out, 0, sizeof(struct fuse_out_header));
-        out->unique = in->unique;
-        out->error = error;
-        if (argsize != 0)
-            memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
-
-        res = send_reply_raw(f, outbuf, outsize);
-        free(outbuf);
+    out.unique = in->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_len = argsize;
     }
-
-    return res;
+    return send_reply_raw(f, iov, count);
 }
 
 static int is_open(struct fuse *f, nodeid_t dir, const char *name)
@@ -887,23 +807,6 @@ static void do_readlink(struct fuse *f, struct fuse_in_header *in)
     send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
 }
 
-static int common_getdir(struct fuse *f, struct fuse_in_header *in,
-                       struct fuse_dirhandle *dh)
-{
-    int res;
-    char *path;
-
-    res = -ENOENT;
-    path = get_path(f, in->nodeid);
-    if (path != NULL) {
-        res = -ENOSYS;
-        if (f->op.getdir)
-            res = f->op.getdir(path, dh, fill_dir);
-        free(path);
-    }
-    return res;
-}
-
 static void do_mknod(struct fuse *f, struct fuse_in_header *in,
                      struct fuse_mknod_in *inarg)
 {
@@ -1237,52 +1140,47 @@ static void do_read(struct fuse *f, struct fuse_in_header *in,
 {
     int res;
     char *path;
-    char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
-    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;
-        size_t outsize;
-        struct fuse_file_info fi;
+    size_t size;
+    char *buf;
+    struct fuse_file_info fi;
 
-        memset(&fi, 0, sizeof(fi));
-        fi.fh = arg->fh;
+    buf = (char *) malloc(arg->size);
+    if (buf == NULL) {
+        send_reply(f, in, -ENOMEM, NULL, 0);
+        return;
+    }
 
-        res = -ENOENT;
-        path = get_path(f, in->nodeid);
-        if (path != NULL) {
-            if (f->flags & FUSE_DEBUG) {
-                printf("READ[%lu] %u bytes from %llu\n",
-                       (unsigned long) arg->fh, arg->size, arg->offset);
-                fflush(stdout);
-            }
+    memset(&fi, 0, sizeof(fi));
+    fi.fh = arg->fh;
 
-            res = -ENOSYS;
-            if (f->op.read)
-                res = f->op.read(path, buf, arg->size, arg->offset, &fi);
-            free(path);
+    res = -ENOENT;
+    path = get_path(f, in->nodeid);
+    if (path != NULL) {
+        if (f->flags & FUSE_DEBUG) {
+            printf("READ[%lu] %u bytes from %llu\n",
+                   (unsigned long) arg->fh, arg->size, arg->offset);
+            fflush(stdout);
         }
 
-        size = 0;
-        if (res >= 0) {
-            size = res;
-            res = 0;
-            if (f->flags & FUSE_DEBUG) {
-                printf("   READ[%lu] %u bytes\n", (unsigned long) arg->fh,
-                       size);
-                fflush(stdout);
-            }
-        }
-        memset(out, 0, sizeof(struct fuse_out_header));
-        out->unique = in->unique;
-        out->error = res;
-        outsize = sizeof(struct fuse_out_header) + size;
+        res = -ENOSYS;
+        if (f->op.read)
+            res = f->op.read(path, buf, arg->size, arg->offset, &fi);
+        free(path);
+    }
 
-        send_reply_raw(f, outbuf, outsize);
-        free(outbuf);
+    size = 0;
+    if (res >= 0) {
+        size = res;
+        res = 0;
+        if (f->flags & FUSE_DEBUG) {
+            printf("   READ[%lu] %u bytes\n", (unsigned long) arg->fh,
+                   size);
+            fflush(stdout);
+        }
     }
+
+    send_reply(f, in, res, buf, size);
+    free(buf);
 }
 
 static void do_write(struct fuse *f, struct fuse_in_header *in,
@@ -1313,6 +1211,7 @@ static void do_write(struct fuse *f, struct fuse_in_header *in,
         free(path);
     }
 
+    memset(&outarg, 0, sizeof(outarg));
     if (res >= 0) {
         outarg.size = res;
         res = 0;
@@ -1443,26 +1342,19 @@ static void do_getxattr_read(struct fuse *f, struct fuse_in_header *in,
                              const char *name, size_t size)
 {
     int res;
-    char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
-    if (outbuf == NULL)
+    char *value = (char *) malloc(size);
+    if (value == NULL) {
         send_reply(f, in, -ENOMEM, NULL, 0);
-    else {
-        struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
-        char *value = outbuf + sizeof(struct fuse_out_header);
-
-        res = common_getxattr(f, in, name, value, size);
-        size = 0;
-        if (res > 0) {
-            size = res;
-            res = 0;
-        }
-        memset(out, 0, sizeof(struct fuse_out_header));
-        out->unique = in->unique;
-        out->error = res;
-
-        send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size);
-        free(outbuf);
+        return;
     }
+    res = common_getxattr(f, in, name, value, size);
+    size = 0;
+    if (res > 0) {
+        size = res;
+        res = 0;
+    }
+    send_reply(f, in, res, value, size);
+    free(value);
 }
 
 static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in,
@@ -1471,6 +1363,7 @@ static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in,
     int res;
     struct fuse_getxattr_out arg;
 
+    memset(&arg, 0, sizeof(arg));
     res = common_getxattr(f, in, name, NULL, 0);
     if (res >= 0) {
         arg.size = res;
@@ -1511,26 +1404,19 @@ static void do_listxattr_read(struct fuse *f, struct fuse_in_header *in,
                               size_t size)
 {
     int res;
-    char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
-    if (outbuf == NULL)
+    char *list = (char *) malloc(size);
+    if (list == NULL) {
         send_reply(f, in, -ENOMEM, NULL, 0);
-    else {
-        struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
-        char *list = outbuf + sizeof(struct fuse_out_header);
-
-        res = common_listxattr(f, in, list, size);
-        size = 0;
-        if (res > 0) {
-            size = res;
-            res = 0;
-        }
-        memset(out, 0, sizeof(struct fuse_out_header));
-        out->unique = in->unique;
-        out->error = res;
-
-        send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size);
-        free(outbuf);
+        return;
     }
+    res = common_listxattr(f, in, list, size);
+    size = 0;
+    if (res > 0) {
+        size = res;
+        res = 0;
+    }
+    send_reply(f, in, res, list, size);
+    free(list);
 }
 
 static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in)
@@ -1538,6 +1424,7 @@ static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in)
     int res;
     struct fuse_getxattr_out arg;
 
+    memset(&arg, 0, sizeof(arg));
     res = common_listxattr(f, in, NULL, 0);
     if (res >= 0) {
         arg.size = res;
@@ -1631,6 +1518,7 @@ static void do_opendir(struct fuse *f, struct fuse_in_header *in,
     dh->contents = NULL;
     dh->len = 0;
     dh->filled = 0;
+    mutex_init(&dh->lock);
 
     memset(&outarg, 0, sizeof(outarg));
     outarg.fh = (unsigned long) dh;
@@ -1657,6 +1545,7 @@ static void do_opendir(struct fuse *f, struct fuse_in_header *in,
                    cancelled */
                 if(f->op.releasedir)
                     f->op.releasedir(path, &fi);
+                pthread_mutex_destroy(&dh->lock);
                 free(dh);
             }
             pthread_mutex_unlock(&f->lock);
@@ -1665,76 +1554,143 @@ static void do_opendir(struct fuse *f, struct fuse_in_header *in,
             free(dh);
         }
         free(path);
-    } else 
+    } else
         send_reply(f, in, 0, &outarg, SIZEOF_COMPAT(f, fuse_open_out));
 }
 
-static void do_readdir(struct fuse *f, struct fuse_in_header *in,
-                       struct fuse_read_in *arg)
+static int fill_dir_common(struct fuse_dirhandle *dh, const char *name,
+                           int type, ino_t ino, off_t off)
 {
-    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;
+    unsigned namelen = strlen(name);
+    unsigned entlen;
+    unsigned entsize;
+    unsigned padlen;
+    unsigned newlen;
+    unsigned char *newptr;
 
-    outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
-    if (outbuf == NULL) {
-        send_reply(f, in, -ENOMEM, NULL, 0);
-        return;
+    if (!(dh->fuse->flags & FUSE_USE_INO))
+        ino = (ino_t) -1;
+
+    if (namelen > FUSE_NAME_MAX)
+        namelen = FUSE_NAME_MAX;
+    else if (!namelen) {
+        dh->error = -EIO;
+        return 1;
     }
-    buf = outbuf + sizeof(struct fuse_out_header);
 
-    if (f->op.readdir && f->major != 5) {
-        struct fuse_dirbuf db;
-        struct fuse_file_info fi;
-        char *path;
+    entlen = (dh->fuse->major == 5 ?
+              FUSE_NAME_OFFSET_COMPAT5 : FUSE_NAME_OFFSET) + namelen;
+    entsize = FUSE_DIRENT_ALIGN(entlen);
+    padlen = entsize - entlen;
+    newlen = dh->len + entsize;
+    if (off && dh->fuse->major != 5) {
+        dh->filled = 0;
+        if (newlen > dh->needlen)
+            return 1;
+    }
+    
+    newptr = realloc(dh->contents, newlen);
+    if (!newptr) {
+        dh->error = -ENOMEM;
+        return 1;
+    }
+    dh->contents = newptr;
+    if (dh->fuse->major == 5) {
+        struct fuse_dirent_compat5 *dirent;
+        dirent = (struct fuse_dirent_compat5 *) (dh->contents + dh->len);
+        dirent->ino = ino;
+        dirent->namelen = namelen;
+        dirent->type = type;
+        strncpy(dirent->name, name, namelen);
+    } else {
+        struct fuse_dirent *dirent;
+        dirent = (struct fuse_dirent *) (dh->contents + dh->len);
+        dirent->ino = ino;
+        dirent->off = off ? off : newlen;
+        dirent->namelen = namelen;
+        dirent->type = type;
+        strncpy(dirent->name, name, namelen);
+    }
+    if (padlen)
+        memset(dh->contents + dh->len + entlen, 0, padlen);
+    dh->len = newlen;
+    return 0;
+}
 
-        db.fuse = f;
-        db.buf = buf;
-        db.len = arg->size;
+static int fill_dir(void *buf, const char *name, const struct stat *stat,
+                    off_t off)
+{
+    int type = stat ? (stat->st_mode & 0170000) >> 12 : 0;
+    ino_t ino = stat ? stat->st_ino : (ino_t) -1;
+    return fill_dir_common(buf, name, type, ino, off);
+}
+
+static int fill_dir_old(struct fuse_dirhandle *dh, const char *name, int type,
+                        ino_t ino)
+{
+    fill_dir_common(dh, name, type, ino, 0);
+    return dh->error;
+}
+
+static int readdir_fill(struct fuse *f, struct fuse_in_header *in,
+                        struct fuse_read_in *arg, struct fuse_dirhandle *dh)
+{
+    int err = -ENOENT;
+    char *path = get_path(f, in->nodeid);
+    if (path != NULL) {
+        struct fuse_file_info fi;
 
         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);
+        dh->len = 0;
+        dh->error = 0;
+        dh->needlen = arg->size;
+        dh->filled = 1;
+        err = -ENOSYS;
+        if (f->op.readdir) {
+            off_t offset = f->major == 5 ? 0 : arg->offset;
+            err = f->op.readdir(path, dh, fill_dir, offset, &fi);
+        } else if (f->op.getdir)
+            err = f->op.getdir(path, dh, fill_dir_old);
+        if (!err)
+            err = dh->error;
+        if (err)
+            dh->filled = 0;
         free(path);
-        if (res)
-            goto err;
+    }
+    return err;
+}
 
-        size = arg->size - db.len;
-    } else {
-        if (!dh->filled) {
-            res = common_getdir(f, in, dh);
-            if (res)
-                goto err;
-            dh->filled = 1;
-        }
+static void do_readdir(struct fuse *f, struct fuse_in_header *in,
+                       struct fuse_read_in *arg)
+{
+    int err = 0;
+    struct fuse_dirhandle *dh = get_dirhandle(arg->fh);
+    size_t size = 0;
+    unsigned char *buf = NULL;
 
+    pthread_mutex_lock(&dh->lock);
+    if (!dh->filled) {
+        err = readdir_fill(f, in, arg, dh);
+        if (err)
+            goto out;
+    }
+    if (dh->filled) {
         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);
+            buf = dh->contents + arg->offset;
         }
+    } else {
+        size = dh->len;
+        buf = dh->contents;
     }
-    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);
out:
+    send_reply(f, in, err, buf, size);
+    pthread_mutex_unlock(&dh->lock);
 }
 
 static void do_releasedir(struct fuse *f, struct fuse_in_header *in,
@@ -1744,7 +1700,7 @@ static void do_releasedir(struct fuse *f, struct fuse_in_header *in,
     if (f->op.releasedir) {
         char *path;
         struct fuse_file_info fi;
-        
+
         memset(&fi, 0, sizeof(fi));
         fi.fh = dh->fh;
 
@@ -1752,6 +1708,9 @@ static void do_releasedir(struct fuse *f, struct fuse_in_header *in,
         f->op.releasedir(path ? path : "-", &fi);
         free(path);
     }
+    pthread_mutex_lock(&dh->lock);
+    pthread_mutex_unlock(&dh->lock);
+    pthread_mutex_destroy(&dh->lock);
     free(dh->contents);
     free(dh);
     send_reply(f, in, 0, NULL, 0);
@@ -2115,19 +2074,8 @@ struct fuse *fuse_new_common(int fd, const char *opts,
         goto out_free_name_table;
     }
 
-#ifndef USE_UCLIBC
-     pthread_mutex_init(&f->lock, NULL);
-     pthread_mutex_init(&f->worker_lock, NULL);
-#else
-     {
-         pthread_mutexattr_t attr;
-         pthread_mutexattr_init(&attr);
-         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
-         pthread_mutex_init(&f->lock, &attr);
-         pthread_mutex_init(&f->worker_lock, &attr);
-         pthread_mutexattr_destroy(&attr);
-     }
-#endif
+    mutex_init(&f->lock);
+    mutex_init(&f->worker_lock);
     f->numworker = 0;
     f->numavail = 0;
     memcpy(&f->op, op, op_size);
index 8edca59d1464185c846cc3c7ff4a8ddc3c655f00..49936dc50503a5f399e26d5fbf053cefb5ecb0dd 100644 (file)
@@ -38,5 +38,3 @@ struct fuse_dirent_compat5 {
 };
 
 #define FUSE_NAME_OFFSET_COMPAT5 ((unsigned) ((struct fuse_dirent_compat5 *) 0)->name)
-#define FUSE_DIRENT_SIZE_COMPAT5(d) \
-       FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET_COMPAT5 + (d)->namelen)