From 03cebaef615f9098d030ba776c124fa5f27d5c74 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Wed, 31 Mar 2004 10:19:18 +0000 Subject: [PATCH] fix zero size case for getxattr and listxattr --- ChangeLog | 4 ++ configure.in | 2 + example/fusexmp.c | 50 +++++++++++++++++++- include/linux/fuse.h | 6 ++- kernel/dev.c | 2 +- kernel/dir.c | 34 ++++++++++---- lib/fuse.c | 106 +++++++++++++++++++++++++++++++++---------- 7 files changed, 167 insertions(+), 37 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6103987..2d8b995 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2004-03-31 Miklos Szeredi + + * fixed zero size case for getxattr and listxattr + 2004-03-30 Miklos Szeredi * new fusermount flag '-z': lazy unmount, default is not lazy diff --git a/configure.in b/configure.in index 035c419..8a29c0e 100644 --- a/configure.in +++ b/configure.in @@ -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]) diff --git a/example/fusexmp.c b/example/fusexmp.c index 3c1b601..5d972a8 100644 --- a/example/fusexmp.c +++ b/example/fusexmp.c @@ -6,6 +6,8 @@ See the file COPYING. */ +#include + #ifdef linux /* For pread()/pwrite() */ #define _XOPEN_SOURCE 500 @@ -19,6 +21,9 @@ #include #include #include +#ifdef HAVE_SETXATTR +#include +#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[]) diff --git a/include/linux/fuse.h b/include/linux/fuse.h index f641271..8467ed6 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h @@ -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; }; diff --git a/kernel/dev.c b/kernel/dev.c index f0733d0..d8535e7 100644 --- a/kernel/dev.c +++ b/kernel/dev.c @@ -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; } diff --git a/kernel/dir.c b/kernel/dir.c index 34ab665..d5d79b1 100644 --- a/kernel/dir.c +++ b/kernel/dir.c @@ -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; } diff --git a/lib/fuse.c b/lib/fuse.c index 77532a4..fddcc33 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -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: -- 2.30.2