See the file COPYING.
*/
+#include <config.h>
+
#ifdef linux
/* For pread()/pwrite() */
#define _XOPEN_SOURCE 500
#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)
{
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,
.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[])
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;
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;
}
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;
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;
}
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;
}
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;
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;
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)
{
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: