Whamcloud - gitweb
fuse2fs: support XATTR_CREATE/REPLACE in setxattr
authorDarrick J. Wong <djwong@kernel.org>
Wed, 21 May 2025 22:36:28 +0000 (15:36 -0700)
committerTheodore Ts'o <tytso@mit.edu>
Fri, 23 May 2025 13:36:15 +0000 (09:36 -0400)
Fix the setxattr implementation to support the create and replace flags
instead of performing an upsert regardless of inputs.

Cc: linux-ext4@vger.kernel.org # v1.43
Fixes: 81cbf1ef4f5dab ("misc: add fuse2fs, a FUSE server for e2fsprogs")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Link: https://lore.kernel.org/r/174786677657.1383760.12232239908991346763.stgit@frogsfrogsfrogs
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
misc/fuse2fs.c

index 4148928..e33a0a8 100644 (file)
@@ -18,6 +18,9 @@
 # include <linux/falloc.h>
 # include <linux/xattr.h>
 #endif
+#ifdef HAVE_SYS_XATTR_H
+#include <sys/xattr.h>
+#endif
 #include <sys/ioctl.h>
 #include <unistd.h>
 #include <ctype.h>
@@ -2517,7 +2520,7 @@ out:
 
 static int op_setxattr(const char *path EXT2FS_ATTR((unused)),
                       const char *key, const char *value,
-                      size_t len, int flags EXT2FS_ATTR((unused)))
+                      size_t len, int flags)
 {
        struct fuse_context *ctxt = fuse_get_context();
        struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
@@ -2527,6 +2530,9 @@ static int op_setxattr(const char *path EXT2FS_ATTR((unused)),
        errcode_t err;
        int ret = 0;
 
+       if (flags & ~(XATTR_CREATE | XATTR_REPLACE))
+               return -EOPNOTSUPP;
+
        FUSE2FS_CHECK_CONTEXT(ff);
        fs = ff->fs;
        pthread_mutex_lock(&ff->bfl);
@@ -2561,6 +2567,31 @@ static int op_setxattr(const char *path EXT2FS_ATTR((unused)),
                goto out2;
        }
 
+       if (flags & (XATTR_CREATE | XATTR_REPLACE)) {
+               void *buf;
+               size_t buflen;
+
+               err = ext2fs_xattr_get(h, key, &buf, &buflen);
+               switch (err) {
+               case EXT2_ET_EA_KEY_NOT_FOUND:
+                       if (flags & XATTR_REPLACE) {
+                               ret = -ENODATA;
+                               goto out2;
+                       }
+                       break;
+               case 0:
+                       ext2fs_free_mem(&buf);
+                       if (flags & XATTR_CREATE) {
+                               ret = -EEXIST;
+                               goto out2;
+                       }
+                       break;
+               default:
+                       ret = translate_error(fs, ino, err);
+                       goto out2;
+               }
+       }
+
        err = ext2fs_xattr_set(h, key, value, len);
        if (err) {
                ret = translate_error(fs, ino, err);