[RFC PATCH 3/3] erofs-utils: fuse: support get/list xattr

Sheng Yong shengyong at oppo.com
Thu Aug 4 00:22:23 AEST 2022


Add new options get and list to xattr iteration operations to
support getxattr and listxattr.

Signed-off-by: Sheng Yong <shengyong at oppo.com>
---
 fsck/main.c           |   2 +
 fuse/main.c           | 135 ++++++++++++++++++++++++++++++++++++++++++
 include/erofs/xattr.h |   8 +++
 lib/xattr.c           |  26 ++++++--
 4 files changed, 167 insertions(+), 4 deletions(-)

diff --git a/fsck/main.c b/fsck/main.c
index 237ccc1..ceaab3d 100644
--- a/fsck/main.c
+++ b/fsck/main.c
@@ -291,6 +291,8 @@ static int erofs_verify_xattr_entry(const struct erofs_xattr_entry *entry)

 struct xattr_iter_ops erofs_verify_xattr_ops = {
        .verify = erofs_verify_xattr_entry,
+       .list = NULL,
+       .get = NULL,
 };

 static int erofs_verify_xattr(struct erofs_inode *inode)
diff --git a/fuse/main.c b/fuse/main.c
index 345bcb5..7997234 100644
--- a/fuse/main.c
+++ b/fuse/main.c
@@ -14,6 +14,7 @@
 #include "erofs/io.h"
 #include "erofs/dir.h"
 #include "erofs/inode.h"
+#include "erofs/xattr.h"

 struct erofsfuse_dir_context {
        struct erofs_dir_context ctx;
@@ -142,6 +143,138 @@ static int erofsfuse_readlink(const char *path, char *buffer, size_t size)
        return 0;
 }

+struct listxattr_iter {
+       char *buffer;
+       size_t size;
+       unsigned int ofs;
+};
+
+static int list_one_xattr(const struct erofs_xattr_entry *entry, void *data)
+{
+       struct listxattr_iter *it = (struct listxattr_iter *)data;
+       const char *prefix = xattr_types[entry->e_name_index].prefix;
+       unsigned int prefix_len = xattr_types[entry->e_name_index].prefix_len;
+       int i;
+
+       /* if size is 0, return the total size without copying data */
+       if (it->size == 0) {
+               it->ofs += prefix_len + entry->e_name_len + 1;
+               return it->ofs;
+       }
+
+       if (it->ofs + prefix_len + entry->e_name_len + 1 > it->size)
+               return -ERANGE;
+
+       switch (entry->e_name_index) {
+       case EROFS_XATTR_INDEX_USER:
+       case EROFS_XATTR_INDEX_TRUSTED:
+       case EROFS_XATTR_INDEX_SECURITY:
+               memcpy(it->buffer + it->ofs, prefix, prefix_len);
+               it->ofs += prefix_len;
+               for (i = 0; i < entry->e_name_len; i++, it->ofs++)
+                       it->buffer[it->ofs] = entry->e_name[i];
+               it->buffer[it->ofs++] = '\0';
+               break;
+       case EROFS_XATTR_INDEX_POSIX_ACL_ACCESS:
+       case EROFS_XATTR_INDEX_POSIX_ACL_DEFAULT:
+               memcpy(it->buffer + it->ofs, prefix, prefix_len);
+               it->ofs += prefix_len;
+               it->buffer[it->ofs++] = '\0';
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return it->ofs;
+}
+
+struct xattr_iter_ops erofs_listxattr_ops = {
+       .verify = NULL,
+       .list = list_one_xattr,
+       .get = NULL,
+};
+
+static int erofsfuse_listxattr(const char *path, char *list, size_t size)
+{
+       struct erofs_inode vi = {};
+       struct listxattr_iter it = {
+               .buffer = list,
+               .size = size,
+               .ofs = 0,
+       };
+
+       erofs_dbg("listxattr(%s) size %zu", path, size);
+       if (erofs_ilookup(path, &vi))
+               return -ENOENT;
+
+       return erofs_xattr_foreach(&vi, &erofs_listxattr_ops, &it);
+}
+
+struct getxattr_iter {
+       const char *name;
+       char *buffer;
+       size_t size;
+};
+
+static int get_one_xattr(const struct erofs_xattr_entry *entry, void *data)
+{
+       struct getxattr_iter *it = (struct getxattr_iter *)data;
+       const char *prefix = xattr_types[entry->e_name_index].prefix;
+       int prefix_len = xattr_types[entry->e_name_index].prefix_len;
+       int name_len, val_len;
+
+       name_len = entry->e_name_len;
+       if (strlen(it->name) != prefix_len + name_len  ||
+           strncmp(it->name, prefix, prefix_len) ||
+           strncmp(it->name + prefix_len, entry->e_name, name_len))
+               /* not match */
+               return -ENODATA;
+
+       val_len = le16_to_cpu(entry->e_value_size);
+       if (it->size == 0)
+               return val_len;
+       if (val_len > it->size)
+               return -ERANGE;
+
+       switch (entry->e_name_index) {
+       case EROFS_XATTR_INDEX_USER:
+       case EROFS_XATTR_INDEX_POSIX_ACL_ACCESS:
+       case EROFS_XATTR_INDEX_POSIX_ACL_DEFAULT:
+       case EROFS_XATTR_INDEX_TRUSTED:
+       case EROFS_XATTR_INDEX_SECURITY:
+               memcpy(it->buffer, entry->e_name + name_len, val_len);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* found */
+       return val_len;
+}
+
+struct xattr_iter_ops erofs_getxattr_ops = {
+       .verify = NULL,
+       .list = NULL,
+       .get = get_one_xattr,
+};
+
+static int erofsfuse_getxattr(const char *path, const char *name,
+                             char *value, size_t size)
+{
+       struct erofs_inode vi = {};
+       struct getxattr_iter it = {
+               .name = name,
+               .buffer = value,
+               .size = size,
+       };
+
+       erofs_dbg("getxattr(%s) name %s size %zu", path, name, size);
+       if (erofs_ilookup(path, &vi))
+               return -ENOENT;
+
+       return erofs_xattr_foreach(&vi, &erofs_getxattr_ops, &it);
+}
+
 static struct fuse_operations erofs_ops = {
        .readlink = erofsfuse_readlink,
        .getattr = erofsfuse_getattr,
@@ -149,6 +282,8 @@ static struct fuse_operations erofs_ops = {
        .open = erofsfuse_open,
        .read = erofsfuse_read,
        .init = erofsfuse_init,
+       .listxattr = erofsfuse_listxattr,
+       .getxattr = erofsfuse_getxattr,
 };

 static struct options {
diff --git a/include/erofs/xattr.h b/include/erofs/xattr.h
index c592d47..eea3a2a 100644
--- a/include/erofs/xattr.h
+++ b/include/erofs/xattr.h
@@ -45,8 +45,16 @@ extern "C"
 #define XATTR_NAME_POSIX_ACL_DEFAULT "system.posix_acl_default"
 #endif

+struct xattr_prefix {
+       const char *prefix;
+       u16 prefix_len;
+};
+extern struct xattr_prefix xattr_types[];
+
 struct xattr_iter_ops {
        int (*verify)(const struct erofs_xattr_entry *entry);
+       int (*list)(const struct erofs_xattr_entry *entry, void *data);
+       int (*get)(const struct erofs_xattr_entry *entry, void *data);
 };

 int erofs_prepare_xattr_ibody(struct erofs_inode *inode);
diff --git a/lib/xattr.c b/lib/xattr.c
index 92c155d..eed3c71 100644
--- a/lib/xattr.c
+++ b/lib/xattr.c
@@ -39,10 +39,7 @@ static DECLARE_HASHTABLE(ea_hashtable, EA_HASHTABLE_BITS);
 static LIST_HEAD(shared_xattrs_list);
 static unsigned int shared_xattrs_count, shared_xattrs_size;

-static struct xattr_prefix {
-       const char *prefix;
-       u16 prefix_len;
-} xattr_types[] = {
+struct xattr_prefix xattr_types[] = {
        [EROFS_XATTR_INDEX_USER] = {
                XATTR_USER_PREFIX,
                XATTR_USER_PREFIX_LEN
@@ -811,6 +808,17 @@ int erofs_xattr_foreach(struct erofs_inode *vi, struct xattr_iter_ops *ops,
                        if (ret < 0)
                                return ret;
                }
+               if (ops->list) {
+                       ret = ops->list(entry, data);
+                       if (ret < 0)
+                               return ret;
+               }
+               if (ops->get) {
+                       ret = ops->get(entry, data);
+                       if ((ret < 0 && ret != -ENODATA) || ret >= 0)
+                               /* error or found */
+                               return ret;
+               }

                ofs += xattr_entry_size;
                addr += xattr_entry_size;
@@ -830,6 +838,16 @@ int erofs_xattr_foreach(struct erofs_inode *vi, struct xattr_iter_ops *ops,
                        if (ret < 0)
                                return ret;
                }
+               if (ops->list) {
+                       ret = ops->list(entry, data);
+                       if (ret < 0)
+                               return ret;
+               }
+               if (ops->get) {
+                       ret = ops->get(entry, data);
+                       if ((ret < 0 && ret != -ENODATA) || ret >= 0)
+                               return ret;
+               }
                addr += entry_sz;
                remaining -= entry_sz;
        }
--
2.25.1

________________________________
OPPO

本电子邮件及其附件含有OPPO公司的保密信息,仅限于邮件指明的收件人使用(包含个人及群组)。禁止任何人在未经授权的情况下以任何形式使用。如果您错收了本邮件,请立即以电子邮件通知发件人并删除本邮件及其附件。

This e-mail and its attachments contain confidential information from OPPO, which is intended only for the person or entity whose address is listed above. Any use of the information contained herein in any way (including, but not limited to, total or partial disclosure, reproduction, or dissemination) by persons other than the intended recipient(s) is prohibited. If you receive this e-mail in error, please notify the sender by phone or email immediately and delete it!


More information about the Linux-erofs mailing list