EA operations added
authorMiklos Szeredi <miklos@szeredi.hu>
Tue, 30 Mar 2004 15:17:26 +0000 (15:17 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Tue, 30 Mar 2004 15:17:26 +0000 (15:17 +0000)
ChangeLog
include/fuse.h
include/linux/fuse.h
kernel/dir.c
lib/fuse.c
util/fusermount.c

index 6d0b2b76774b5c9c614ad0bae9e90c9f14bd5034..61039870545e17ee1b7564adafdfe8a173531a34 100644 (file)
--- 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 <mszeredi@inf.bme.hu>
 
        * If filesystem doesn't define a statfs operation, then an
index 7a751ae08b5933cf9490a12853aed6915ad28711..79c62a6e750ccbe48e42f40faf11262b9a0fabb0 100644 (file)
@@ -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 */
index d5fd35781e6b8fc21b08e35f294b58b0a73caa41..f6412711eda6656206a484bda971e1887d60fd48 100644 (file)
@@ -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;
index 4051d07389cd7d3913d874c1d21103fe0970a64c..34ab6657065f61269936a3a964c516b2ffb9c699 100644 (file)
@@ -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
index 2ca30bbd7cb0748ad5315c570f2cc40b6cd66b41..77532a43067c165e44ea7bdd6e4e2880f8c43886 100644 (file)
 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);
     }
index 9af24d103cd391b4cef258bdff6b078318bc4558..42e9d47d563a224086775ba19a60dfcddc4a3296 100644 (file)
@@ -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)