fix zero size case for getxattr and listxattr
authorMiklos Szeredi <miklos@szeredi.hu>
Wed, 31 Mar 2004 10:19:18 +0000 (10:19 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Wed, 31 Mar 2004 10:19:18 +0000 (10:19 +0000)
ChangeLog
configure.in
example/fusexmp.c
include/linux/fuse.h
kernel/dev.c
kernel/dir.c
lib/fuse.c

index 61039870545e17ee1b7564adafdfe8a173531a34..2d8b9950c0f21dc67509d9052d115f64b104171f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2004-03-31  Miklos Szeredi <mszeredi@inf.bme.hu>
+
+       * fixed zero size case for getxattr and listxattr
+
 2004-03-30  Miklos Szeredi <mszeredi@inf.bme.hu>
 
        * new fusermount flag '-z': lazy unmount, default is not lazy
index 035c419125808d24fb87563d1f851eb2f6ce8142..8a29c0e3362e61421e13c081e85cd11abceff76f 100644 (file)
@@ -82,6 +82,8 @@ if test "$enable_example" != "no"; then
        subdirs="$subdirs example";
 fi
 
+AC_CHECK_FUNCS([setxattr])
+
 AC_SUBST(subdirs)
 
 AC_OUTPUT([Makefile kernel/Makefile lib/Makefile util/Makefile example/Makefile include/Makefile include/linux/Makefile patch/Makefile])
index 3c1b601cb4ecdb00a4237afab4abd8870747039a..5d972a8059fc6ba985f37b488a1fd73eb384fac8 100644 (file)
@@ -6,6 +6,8 @@
     See the file COPYING.
 */
 
+#include <config.h>
+
 #ifdef linux
 /* For pread()/pwrite() */
 #define _XOPEN_SOURCE 500
@@ -19,6 +21,9 @@
 #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)
 {
@@ -264,6 +269,43 @@ static int xmp_fsync(const char *path, int isdatasync)
     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,
@@ -284,7 +326,13 @@ static struct fuse_operations xmp_oper = {
     .write     = xmp_write,
     .statfs    = xmp_statfs,
     .release   = xmp_release,
-    .fsync     = xmp_fsync
+    .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[])
index f6412711eda6656206a484bda971e1887d60fd48..8467ed6c24f8db48f84e17bb925c6cbe0354b33a 100644 (file)
@@ -197,7 +197,11 @@ struct fuse_setxattr_in {
        unsigned int flags;
 };
 
-struct fuse_getlistxattr_in {
+struct fuse_getxattr_in {
+       unsigned int size;
+};
+
+struct fuse_getxattr_out {
        unsigned int size;
 };
 
index f0733d006c262880d9eb5b965cc98090282f53cd..d8535e7e099b6346c1139365c5d9d7b0a26c55dc 100644 (file)
@@ -482,7 +482,7 @@ static ssize_t fuse_dev_write(struct file *file, const char *buf,
                goto out;
        }     
 
-        if (oh.error <= -512 || oh.error > 0) {
+        if (oh.error <= -1000 || oh.error > 0) {
                 printk("fuse_dev_write: bad error value\n");
                 return -EINVAL;
         }
index 34ab6657065f61269936a3a964c516b2ffb9c699..d5d79b169490fb6c42abe6266778a628ad185b51 100644 (file)
@@ -751,7 +751,8 @@ static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
        struct fuse_conn *fc = INO_FC(inode);
        struct fuse_in in = FUSE_IN_INIT;
        struct fuse_out out = FUSE_OUT_INIT;
-       struct fuse_getlistxattr_in inarg;
+       struct fuse_getxattr_in inarg;
+       struct fuse_getxattr_out outarg;
 
        memset(&inarg, 0, sizeof(inarg));
        inarg.size = size;
@@ -763,13 +764,19 @@ static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
        in.args[0].value = &inarg;
        in.args[1].size = strlen(name) + 1;
        in.args[1].value = name;
-       out.argvar = 1;
+       /* This is really two different operations rolled into one */
        out.numargs = 1;
-       out.args[0].size = size;
-       out.args[0].value = value;
+       if(size) {
+               out.argvar = 1;
+               out.args[0].size = size;
+               out.args[0].value = value;
+       } else {
+               out.args[0].size = sizeof(outarg);
+               out.args[0].value = &outarg;
+       }
        request_send(fc, &in, &out);
        if(!out.h.error)
-               return out.args[0].size;
+               return size ? out.args[0].size : outarg.size;
        else
                return out.h.error;
 }
@@ -780,7 +787,8 @@ static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
        struct fuse_conn *fc = INO_FC(inode);
        struct fuse_in in = FUSE_IN_INIT;
        struct fuse_out out = FUSE_OUT_INIT;
-       struct fuse_getlistxattr_in inarg;
+       struct fuse_getxattr_in inarg;
+       struct fuse_getxattr_out outarg;
 
        memset(&inarg, 0, sizeof(inarg));
        inarg.size = size;
@@ -790,13 +798,19 @@ static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
        in.numargs = 1;
        in.args[0].size = sizeof(inarg);
        in.args[0].value = &inarg;
-       out.argvar = 1;
+       /* This is really two different operations rolled into one */
        out.numargs = 1;
-       out.args[0].size = size;
-       out.args[0].value = list;
+       if(size) {
+               out.argvar = 1;
+               out.args[0].size = size;
+               out.args[0].value = list;
+       } else {
+               out.args[0].size = sizeof(outarg);
+               out.args[0].value = &outarg;
+       }
        request_send(fc, &in, &out);
        if(!out.h.error)
-               return out.args[0].size;
+               return size ? out.args[0].size : outarg.size;
        else
                return out.h.error;
 }
index 77532a43067c165e44ea7bdd6e4e2880f8c43886..fddcc332ae5b818940b57a573eef41fcefcdc931 100644 (file)
@@ -390,7 +390,7 @@ static int send_reply(struct fuse *f, struct fuse_in_header *in, int error,
     size_t outsize;
     struct fuse_out_header *out;
 
-    if(error <= -512 || error > 0) {
+    if(error <= -1000 || error > 0) {
         fprintf(stderr, "fuse: bad error value: %i\n",  error);
         error = -ERANGE;
     }
@@ -991,26 +991,32 @@ static void do_setxattr(struct fuse *f, struct fuse_in_header *in,
     send_reply(f, in, res, NULL, 0);
 }
 
-static void do_getxattr(struct fuse *f, struct fuse_in_header *in,
-                        struct fuse_getlistxattr_in *arg)
+static int common_getxattr(struct fuse *f, struct fuse_in_header *in,
+                           const char *name, char *value, size_t size)
 {
     int res;
     char *path;
-    char *name = PARAM(arg);
-    char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
-    struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
-    char *value = outbuf + sizeof(struct fuse_out_header);
-    size_t size;
-    size_t outsize;
 
     res = -ENOENT;
     path = get_path(f, in->ino);
     if (path != NULL) {
         res = -EOPNOTSUPP; /* or is it ENOTSUPP ??? */
         if (f->op.getxattr)
-            res = f->op.getxattr(path, name, value, arg->size);
+            res = f->op.getxattr(path, name, value, size);
         free(path);
     }    
+    return res;
+}
+
+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);
+    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;
@@ -1019,31 +1025,62 @@ static void do_getxattr(struct fuse *f, struct fuse_in_header *in,
     memset(out, 0, sizeof(struct fuse_out_header));
     out->unique = in->unique;
     out->error = res;
-    outsize = sizeof(struct fuse_out_header) + size;
 
-    send_reply_raw(f, outbuf, outsize);
+    send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size);
     free(outbuf);
 }
 
-static void do_listxattr(struct fuse *f, struct fuse_in_header *in,
-                         struct fuse_getlistxattr_in *arg)
+static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in,
+                             const char *name)
+{
+    int res;
+    struct fuse_getxattr_out arg;
+
+    res = common_getxattr(f, in, name, NULL, 0);
+    if(res >= 0) {
+        arg.size = res;
+        res = 0;
+    }
+    send_reply(f, in, res, &arg, sizeof(arg));
+}
+
+static void do_getxattr(struct fuse *f, struct fuse_in_header *in,
+                        struct fuse_getxattr_in *arg)
+{
+    char *name = PARAM(arg);
+    
+    if(arg->size)
+        do_getxattr_read(f, in, name, arg->size);
+    else
+        do_getxattr_size(f, in, name);
+}
+
+static int common_listxattr(struct fuse *f, struct fuse_in_header *in,
+                            char *list, size_t size)
 {
     int res;
     char *path;
-    char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
-    struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
-    char *value = outbuf + sizeof(struct fuse_out_header);
-    size_t size;
-    size_t outsize;
 
     res = -ENOENT;
     path = get_path(f, in->ino);
     if (path != NULL) {
         res = -EOPNOTSUPP; /* or is it ENOTSUPP ??? */
         if (f->op.listxattr)
-            res = f->op.listxattr(path, value, arg->size);
+            res = f->op.listxattr(path, list, size);
         free(path);
     }    
+    return res;
+}
+
+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);
+    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;
@@ -1052,12 +1089,33 @@ static void do_listxattr(struct fuse *f, struct fuse_in_header *in,
     memset(out, 0, sizeof(struct fuse_out_header));
     out->unique = in->unique;
     out->error = res;
-    outsize = sizeof(struct fuse_out_header) + size;
 
-    send_reply_raw(f, outbuf, outsize);
+    send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size);
     free(outbuf);
 }
 
+static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in)
+{
+    int res;
+    struct fuse_getxattr_out arg;
+
+    res = common_listxattr(f, in, NULL, 0);
+    if (res >= 0) {
+        arg.size = res;
+        res = 0;
+    }
+    send_reply(f, in, res, &arg, sizeof(arg));
+}
+
+static void do_listxattr(struct fuse *f, struct fuse_in_header *in,
+                         struct fuse_getxattr_in *arg)
+{
+    if(arg->size)
+        do_listxattr_read(f, in, arg->size);
+    else
+        do_listxattr_size(f, in);
+}
+
 static void do_removexattr(struct fuse *f, struct fuse_in_header *in,
                            char *name)
 {
@@ -1182,11 +1240,11 @@ void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
         break;
 
     case FUSE_GETXATTR:
-        do_getxattr(f, in, (struct fuse_getlistxattr_in *) inarg);
+        do_getxattr(f, in, (struct fuse_getxattr_in *) inarg);
         break;
 
     case FUSE_LISTXATTR:
-        do_listxattr(f, in, (struct fuse_getlistxattr_in *) inarg);
+        do_listxattr(f, in, (struct fuse_getxattr_in *) inarg);
         break;
 
     case FUSE_REMOVEXATTR: