From 3ed84231ec6d4a66a5b20db355eb6e9585e9edc5 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 30 Mar 2004 15:17:26 +0000 Subject: [PATCH] EA operations added --- ChangeLog | 3 + include/fuse.h | 44 ++++++------ include/linux/fuse.h | 53 ++++++++------ kernel/dir.c | 113 ++++++++++++++++++++++++++++++ lib/fuse.c | 162 ++++++++++++++++++++++++++++++++++++++----- util/fusermount.c | 10 +-- 6 files changed, 322 insertions(+), 63 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6d0b2b7..6103987 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,9 @@ * new fusermount flag '-z': lazy unmount, default is not lazy + * Extended attributes operations added (getxattr, setxattr, + listxattr, removexattr) + 2004-03-25 Miklos Szeredi * If filesystem doesn't define a statfs operation, then an diff --git a/include/fuse.h b/include/fuse.h index 7a751ae..79c62a6 100644 --- a/include/fuse.h +++ b/include/fuse.h @@ -91,26 +91,30 @@ typedef int (*fuse_dirfil_t) (fuse_dirh_t h, const char *name, int type); * an fdatasync() operation. */ struct fuse_operations { - int (*getattr) (const char *, struct stat *); - int (*readlink) (const char *, char *, size_t); - int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t); - int (*mknod) (const char *, mode_t, dev_t); - int (*mkdir) (const char *, mode_t); - int (*unlink) (const char *); - int (*rmdir) (const char *); - int (*symlink) (const char *, const char *); - int (*rename) (const char *, const char *); - int (*link) (const char *, const char *); - int (*chmod) (const char *, mode_t); - int (*chown) (const char *, uid_t, gid_t); - int (*truncate) (const char *, off_t); - int (*utime) (const char *, struct utimbuf *); - int (*open) (const char *, int); - int (*read) (const char *, char *, size_t, off_t); - int (*write) (const char *, const char *, size_t, off_t); - int (*statfs) (const char *, struct statfs *); - int (*release) (const char *, int); - int (*fsync) (const char *, int); + int (*getattr) (const char *, struct stat *); + int (*readlink) (const char *, char *, size_t); + int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t); + int (*mknod) (const char *, mode_t, dev_t); + int (*mkdir) (const char *, mode_t); + int (*unlink) (const char *); + int (*rmdir) (const char *); + int (*symlink) (const char *, const char *); + int (*rename) (const char *, const char *); + int (*link) (const char *, const char *); + int (*chmod) (const char *, mode_t); + int (*chown) (const char *, uid_t, gid_t); + int (*truncate) (const char *, off_t); + int (*utime) (const char *, struct utimbuf *); + int (*open) (const char *, int); + int (*read) (const char *, char *, size_t, off_t); + int (*write) (const char *, const char *, size_t, off_t); + int (*statfs) (const char *, struct statfs *); + int (*release) (const char *, int); + int (*fsync) (const char *, int); + int (*setxattr) (const char *, const char *, const char *, size_t, int); + int (*getxattr) (const char *, const char *, char *, size_t); + int (*listxattr) (const char *, char *, size_t); + int (*removexattr) (const char *, const char *); }; /** Extra context that may be needed by some filesystems */ diff --git a/include/linux/fuse.h b/include/linux/fuse.h index d5fd357..f641271 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h @@ -94,26 +94,30 @@ struct fuse_kstatfs { #define FATTR_CTIME (1 << 6) enum fuse_opcode { - FUSE_LOOKUP = 1, - FUSE_FORGET = 2, /* no reply */ - FUSE_GETATTR = 3, - FUSE_SETATTR = 4, - FUSE_READLINK = 5, - FUSE_SYMLINK = 6, - FUSE_GETDIR = 7, - FUSE_MKNOD = 8, - FUSE_MKDIR = 9, - FUSE_UNLINK = 10, - FUSE_RMDIR = 11, - FUSE_RENAME = 12, - FUSE_LINK = 13, - FUSE_OPEN = 14, - FUSE_READ = 15, - FUSE_WRITE = 16, - FUSE_STATFS = 17, - FUSE_RELEASE = 18, /* no reply */ - FUSE_INVALIDATE = 19, /* user initiated */ - FUSE_FSYNC = 20 + FUSE_LOOKUP = 1, + FUSE_FORGET = 2, /* no reply */ + FUSE_GETATTR = 3, + FUSE_SETATTR = 4, + FUSE_READLINK = 5, + FUSE_SYMLINK = 6, + FUSE_GETDIR = 7, + FUSE_MKNOD = 8, + FUSE_MKDIR = 9, + FUSE_UNLINK = 10, + FUSE_RMDIR = 11, + FUSE_RENAME = 12, + FUSE_LINK = 13, + FUSE_OPEN = 14, + FUSE_READ = 15, + FUSE_WRITE = 16, + FUSE_STATFS = 17, + FUSE_RELEASE = 18, /* no reply */ + FUSE_INVALIDATE = 19, /* user initiated */ + FUSE_FSYNC = 20, + FUSE_SETXATTR = 21, + FUSE_GETXATTR = 22, + FUSE_LISTXATTR = 23, + FUSE_REMOVEXATTR = 24, }; /* Conservative buffer size for the client */ @@ -188,6 +192,15 @@ struct fuse_fsync_in { int datasync; }; +struct fuse_setxattr_in { + unsigned int size; + unsigned int flags; +}; + +struct fuse_getlistxattr_in { + unsigned int size; +}; + struct fuse_in_header { int unique; enum fuse_opcode opcode; diff --git a/kernel/dir.c b/kernel/dir.c index 4051d07..34ab665 100644 --- a/kernel/dir.c +++ b/kernel/dir.c @@ -717,6 +717,107 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) { return _fuse_dentry_revalidate(entry); } + +static int fuse_setxattr(struct dentry *entry, const char *name, + const void *value, size_t size, int flags) +{ + struct inode *inode = entry->d_inode; + struct fuse_conn *fc = INO_FC(inode); + struct fuse_in in = FUSE_IN_INIT; + struct fuse_out out = FUSE_OUT_INIT; + struct fuse_setxattr_in inarg; + + memset(&inarg, 0, sizeof(inarg)); + inarg.size = size; + inarg.flags = flags; + + in.h.opcode = FUSE_SETXATTR; + in.h.ino = inode->i_ino; + in.numargs = 3; + in.args[0].size = sizeof(inarg); + in.args[0].value = &inarg; + in.args[1].size = strlen(name) + 1; + in.args[1].value = name; + in.args[2].size = size; + in.args[2].value = value; + request_send(fc, &in, &out); + return out.h.error; +} + +static ssize_t fuse_getxattr(struct dentry *entry, const char *name, + void *value, size_t size) +{ + struct inode *inode = entry->d_inode; + 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; + + memset(&inarg, 0, sizeof(inarg)); + inarg.size = size; + + in.h.opcode = FUSE_GETXATTR; + in.h.ino = inode->i_ino; + in.numargs = 2; + in.args[0].size = sizeof(inarg); + in.args[0].value = &inarg; + in.args[1].size = strlen(name) + 1; + in.args[1].value = name; + out.argvar = 1; + out.numargs = 1; + out.args[0].size = size; + out.args[0].value = value; + request_send(fc, &in, &out); + if(!out.h.error) + return out.args[0].size; + else + return out.h.error; +} + +static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) +{ + struct inode *inode = entry->d_inode; + 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; + + memset(&inarg, 0, sizeof(inarg)); + inarg.size = size; + + in.h.opcode = FUSE_LISTXATTR; + in.h.ino = inode->i_ino; + in.numargs = 1; + in.args[0].size = sizeof(inarg); + in.args[0].value = &inarg; + out.argvar = 1; + out.numargs = 1; + out.args[0].size = size; + out.args[0].value = list; + request_send(fc, &in, &out); + if(!out.h.error) + return out.args[0].size; + else + return out.h.error; +} + +static int fuse_removexattr(struct dentry *entry, const char *name) +{ + struct inode *inode = entry->d_inode; + struct fuse_conn *fc = INO_FC(inode); + struct fuse_in in = FUSE_IN_INIT; + struct fuse_out out = FUSE_OUT_INIT; + + in.h.opcode = FUSE_REMOVEXATTR; + in.h.ino = inode->i_ino; + in.numargs = 1; + in.args[0].size = strlen(name) + 1; + in.args[0].value = name; + request_send(fc, &in, &out); + return out.h.error; + +} + #else /* KERNEL_2_6 */ #define fuse_create _fuse_create @@ -771,6 +872,10 @@ static struct inode_operations fuse_dir_inode_operations = .permission = fuse_permission, #ifdef KERNEL_2_6 .getattr = fuse_getattr, + .setxattr = fuse_setxattr, + .getxattr = fuse_getxattr, + .listxattr = fuse_listxattr, + .removexattr = fuse_removexattr, #else .revalidate = fuse_revalidate, #endif @@ -788,6 +893,10 @@ static struct inode_operations fuse_file_inode_operations = { .permission = fuse_permission, #ifdef KERNEL_2_6 .getattr = fuse_getattr, + .setxattr = fuse_setxattr, + .getxattr = fuse_getxattr, + .listxattr = fuse_listxattr, + .removexattr = fuse_removexattr, #else .revalidate = fuse_revalidate, #endif @@ -800,6 +909,10 @@ static struct inode_operations fuse_symlink_inode_operations = .follow_link = fuse_follow_link, #ifdef KERNEL_2_6 .getattr = fuse_getattr, + .setxattr = fuse_setxattr, + .getxattr = fuse_getxattr, + .listxattr = fuse_listxattr, + .removexattr = fuse_removexattr, #else .revalidate = fuse_revalidate, #endif diff --git a/lib/fuse.c b/lib/fuse.c index 2ca30bb..77532a4 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -25,25 +25,29 @@ static const char *opname(enum fuse_opcode opcode) { switch(opcode) { - case FUSE_LOOKUP: return "LOOKUP"; - case FUSE_FORGET: return "FORGET"; - case FUSE_GETATTR: return "GETATTR"; - case FUSE_SETATTR: return "SETATTR"; - case FUSE_READLINK: return "READLINK"; - case FUSE_SYMLINK: return "SYMLINK"; - case FUSE_GETDIR: return "GETDIR"; - case FUSE_MKNOD: return "MKNOD"; - case FUSE_MKDIR: return "MKDIR"; - case FUSE_UNLINK: return "UNLINK"; - case FUSE_RMDIR: return "RMDIR"; - case FUSE_RENAME: return "RENAME"; - case FUSE_LINK: return "LINK"; - case FUSE_OPEN: return "OPEN"; - case FUSE_READ: return "READ"; - case FUSE_WRITE: return "WRITE"; - case FUSE_STATFS: return "STATFS"; - case FUSE_RELEASE: return "RELEASE"; - case FUSE_FSYNC: return "FSYNC"; + case FUSE_LOOKUP: return "LOOKUP"; + case FUSE_FORGET: return "FORGET"; + case FUSE_GETATTR: return "GETATTR"; + case FUSE_SETATTR: return "SETATTR"; + case FUSE_READLINK: return "READLINK"; + case FUSE_SYMLINK: return "SYMLINK"; + case FUSE_GETDIR: return "GETDIR"; + case FUSE_MKNOD: return "MKNOD"; + case FUSE_MKDIR: return "MKDIR"; + case FUSE_UNLINK: return "UNLINK"; + case FUSE_RMDIR: return "RMDIR"; + case FUSE_RENAME: return "RENAME"; + case FUSE_LINK: return "LINK"; + case FUSE_OPEN: return "OPEN"; + case FUSE_READ: return "READ"; + case FUSE_WRITE: return "WRITE"; + case FUSE_STATFS: return "STATFS"; + case FUSE_RELEASE: return "RELEASE"; + case FUSE_FSYNC: return "FSYNC"; + case FUSE_SETXATTR: return "SETXATTR"; + case FUSE_GETXATTR: return "GETXATTR"; + case FUSE_LISTXATTR: return "LISTXATTR"; + case FUSE_REMOVEXATTR: return "REMOVEXATTR"; default: return "???"; } } @@ -968,6 +972,110 @@ static void do_fsync(struct fuse *f, struct fuse_in_header *in, send_reply(f, in, res, NULL, 0); } +static void do_setxattr(struct fuse *f, struct fuse_in_header *in, + struct fuse_setxattr_in *arg) +{ + int res; + char *path; + char *name = PARAM(arg); + unsigned char *value = name + strlen(name) + 1; + + res = -ENOENT; + path = get_path(f, in->ino); + if (path != NULL) { + res = -EOPNOTSUPP; /* or is it ENOTSUPP ??? */ + if (f->op.setxattr) + res = f->op.setxattr(path, name, value, arg->size, arg->flags); + free(path); + } + send_reply(f, in, res, NULL, 0); +} + +static void do_getxattr(struct fuse *f, struct fuse_in_header *in, + struct fuse_getlistxattr_in *arg) +{ + 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); + free(path); + } + size = 0; + if(res > 0) { + size = res; + res = 0; + } + 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); + free(outbuf); +} + +static void do_listxattr(struct fuse *f, struct fuse_in_header *in, + struct fuse_getlistxattr_in *arg) +{ + 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); + free(path); + } + size = 0; + if(res > 0) { + size = res; + res = 0; + } + 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); + free(outbuf); +} + +static void do_removexattr(struct fuse *f, struct fuse_in_header *in, + char *name) +{ + int res; + char *path; + + res = -ENOENT; + path = get_path(f, in->ino); + if (path != NULL) { + res = -EOPNOTSUPP; /* or is it ENOTSUPP ??? */ + if (f->op.removexattr) + res = f->op.removexattr(path, name); + free(path); + } + send_reply(f, in, res, NULL, 0); +} + + static void free_cmd(struct fuse_cmd *cmd) { free(cmd->buf); @@ -1069,6 +1177,22 @@ void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd) do_fsync(f, in, (struct fuse_fsync_in *) inarg); break; + case FUSE_SETXATTR: + do_setxattr(f, in, (struct fuse_setxattr_in *) inarg); + break; + + case FUSE_GETXATTR: + do_getxattr(f, in, (struct fuse_getlistxattr_in *) inarg); + break; + + case FUSE_LISTXATTR: + do_listxattr(f, in, (struct fuse_getlistxattr_in *) inarg); + break; + + case FUSE_REMOVEXATTR: + do_removexattr(f, in, (char *) inarg); + break; + default: send_reply(f, in, -ENOSYS, NULL, 0); } diff --git a/util/fusermount.c b/util/fusermount.c index 9af24d1..42e9d47 100644 --- a/util/fusermount.c +++ b/util/fusermount.c @@ -188,8 +188,9 @@ static int remove_mount(const char *mnt, int quiet, int lazy) if(found) { res = umount2(mnt, lazy ? 2 : 0); if(res == -1) { - fprintf(stderr, "%s: failed to unmount %s: %s\n", progname, mnt, - strerror(errno)); + if(!quiet) + fprintf(stderr, "%s: failed to unmount %s: %s\n", + progname, mnt,strerror(errno)); found = -1; } } @@ -587,8 +588,9 @@ int main(int argc, char *argv[]) } else { res = umount2(mnt, lazy ? 2 : 0); if(res == -1) { - fprintf(stderr, "%s: failed to unmount %s: %s\n", progname, mnt, - strerror(errno)); + if (!quiet) + fprintf(stderr, "%s: failed to unmount %s: %s\n", + progname, mnt, strerror(errno)); } } if(res == -1) -- 2.30.2