erofs-utils: support long xattr name prefixes for erofsfuse
authorJingbo Xu <jefflexu@linux.alibaba.com>
Thu, 17 Aug 2023 07:14:55 +0000 (15:14 +0800)
committerGao Xiang <hsiangkao@linux.alibaba.com>
Thu, 17 Aug 2023 11:21:08 +0000 (19:21 +0800)
Make erofs_listxattr() and erofs_getxattr() routine support long xattr
name prefixes.

Although the on-disk format allows long xattr name prefixes to be placed
in the meta inode or packed inode, currently mkfs.erofs will place them
in packed inode by default.  Thus let's also read long xattr name prefixes
from packed inode by default.

Since we need to read the content of the packed inode from disk when
loading long xattr name prefixes, add dependency on zlib_LIBS for
mkfs.erofs to resolve the compiling dependency.

Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
Link: https://lore.kernel.org/r/20230817071455.12040-4-jefflexu@linux.alibaba.com
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
include/erofs/internal.h
include/erofs/xattr.h
lib/super.c
lib/xattr.c
mkfs/Makefile.am

index 3e7319d8a10b2fd7131115a05b7bff80a360dff7..db766cad73492a0600519ae8f721e682cb6f6ef1 100644 (file)
@@ -57,6 +57,11 @@ struct erofs_device_info {
        u32 mapped_blkaddr;
 };
 
+struct erofs_xattr_prefix_item {
+       struct erofs_xattr_long_prefix *prefix;
+       u8 infix_len;
+};
+
 #define EROFS_PACKED_NID_UNALLOCATED   -1
 
 struct erofs_sb_info {
@@ -99,6 +104,7 @@ struct erofs_sb_info {
 
        u32 xattr_prefix_start;
        u8 xattr_prefix_count;
+       struct erofs_xattr_prefix_item *xattr_prefixes;
 
        int devfd;
        u64 devsz;
index dc27cf6eee1f285aba4636b7bc56ff1d1b5e03cb..748442af339269c1e2dc14e2994b17f952b5ecf3 100644 (file)
@@ -82,6 +82,8 @@ int erofs_build_shared_xattrs_from_path(struct erofs_sb_info *sbi, const char *p
 int erofs_xattr_insert_name_prefix(const char *prefix);
 void erofs_xattr_cleanup_name_prefixes(void);
 int erofs_xattr_write_name_prefixes(struct erofs_sb_info *sbi, FILE *f);
+void erofs_xattr_prefixes_cleanup(struct erofs_sb_info *sbi);
+int erofs_xattr_prefixes_init(struct erofs_sb_info *sbi);
 
 int erofs_setxattr(struct erofs_inode *inode, char *key,
                   const void *value, size_t size);
index e8e84aa707c22b86f773f4d4e20de04f0681661b..21dc51f73129f9b5a8c3178a18cc7a269bd772e6 100644 (file)
@@ -6,6 +6,7 @@
 #include <stdlib.h>
 #include "erofs/io.h"
 #include "erofs/print.h"
+#include "erofs/xattr.h"
 
 static bool check_layout_compatibility(struct erofs_sb_info *sbi,
                                       struct erofs_super_block *dsb)
@@ -101,6 +102,8 @@ int erofs_read_superblock(struct erofs_sb_info *sbi)
        sbi->primarydevice_blocks = le32_to_cpu(dsb->blocks);
        sbi->meta_blkaddr = le32_to_cpu(dsb->meta_blkaddr);
        sbi->xattr_blkaddr = le32_to_cpu(dsb->xattr_blkaddr);
+       sbi->xattr_prefix_start = le32_to_cpu(dsb->xattr_prefix_start);
+       sbi->xattr_prefix_count = dsb->xattr_prefix_count;
        sbi->islotbits = EROFS_ISLOTBITS;
        sbi->root_nid = le16_to_cpu(dsb->root_nid);
        sbi->packed_nid = le64_to_cpu(dsb->packed_nid);
@@ -117,11 +120,20 @@ int erofs_read_superblock(struct erofs_sb_info *sbi)
                sbi->available_compr_algs = le16_to_cpu(dsb->u1.available_compr_algs);
        else
                sbi->lz4_max_distance = le16_to_cpu(dsb->u1.lz4_max_distance);
-       return erofs_init_devices(sbi, dsb);
+
+       ret = erofs_init_devices(sbi, dsb);
+       if (ret)
+               return ret;
+
+       ret = erofs_xattr_prefixes_init(sbi);
+       if (ret)
+               free(sbi->devs);
+       return ret;
 }
 
 void erofs_put_super(struct erofs_sb_info *sbi)
 {
        if (sbi->devs)
                free(sbi->devs);
+       erofs_xattr_prefixes_cleanup(sbi);
 }
index 4091fe6c926f5e9046af2b48a20756526d4d6aec..46a301ad992f66cb4e10079ca6b25b30f6b9b94f 100644 (file)
@@ -1093,19 +1093,47 @@ out:
 struct getxattr_iter {
        struct xattr_iter it;
 
-       int buffer_size, index;
+       int buffer_size, index, infix_len;
        char *buffer;
        const char *name;
        size_t len;
 };
 
+static int erofs_xattr_long_entrymatch(struct getxattr_iter *it,
+                                      struct erofs_xattr_entry *entry)
+{
+       struct erofs_sb_info *sbi = it->it.sbi;
+       struct erofs_xattr_prefix_item *pf = sbi->xattr_prefixes +
+               (entry->e_name_index & EROFS_XATTR_LONG_PREFIX_MASK);
+
+       if (pf >= sbi->xattr_prefixes + sbi->xattr_prefix_count)
+               return -ENOATTR;
+
+       if (it->index != pf->prefix->base_index ||
+           it->len != entry->e_name_len + pf->infix_len)
+               return -ENOATTR;
+
+       if (memcmp(it->name, pf->prefix->infix, pf->infix_len))
+               return -ENOATTR;
+
+       it->infix_len = pf->infix_len;
+       return 0;
+}
+
 static int xattr_entrymatch(struct xattr_iter *_it,
                            struct erofs_xattr_entry *entry)
 {
        struct getxattr_iter *it = container_of(_it, struct getxattr_iter, it);
 
-       return (it->index != entry->e_name_index ||
-               it->len != entry->e_name_len) ? -ENOATTR : 0;
+       /* should also match the infix for long name prefixes */
+       if (entry->e_name_index & EROFS_XATTR_LONG_PREFIX)
+               return erofs_xattr_long_entrymatch(it, entry);
+
+       if (it->index != entry->e_name_index ||
+           it->len != entry->e_name_len)
+               return -ENOATTR;
+       it->infix_len = 0;
+       return 0;
 }
 
 static int xattr_namematch(struct xattr_iter *_it,
@@ -1113,8 +1141,9 @@ static int xattr_namematch(struct xattr_iter *_it,
 {
        struct getxattr_iter *it = container_of(_it, struct getxattr_iter, it);
 
-
-       return memcmp(buf, it->name + processed, len) ? -ENOATTR : 0;
+       if (memcmp(buf, it->name + it->infix_len + processed, len))
+               return -ENOATTR;
+       return 0;
 }
 
 static int xattr_checkbuffer(struct xattr_iter *_it,
@@ -1237,8 +1266,20 @@ static int xattr_entrylist(struct xattr_iter *_it,
        struct listxattr_iter *it =
                container_of(_it, struct listxattr_iter, it);
        unsigned int base_index = entry->e_name_index;
-       unsigned int prefix_len;
-       const char *prefix;
+       unsigned int prefix_len, infix_len = 0;
+       const char *prefix, *infix = NULL;
+
+       if (entry->e_name_index & EROFS_XATTR_LONG_PREFIX) {
+               struct erofs_sb_info *sbi = _it->sbi;
+               struct erofs_xattr_prefix_item *pf = sbi->xattr_prefixes +
+                       (entry->e_name_index & EROFS_XATTR_LONG_PREFIX_MASK);
+
+               if (pf >= sbi->xattr_prefixes + sbi->xattr_prefix_count)
+                       return 1;
+               infix = pf->prefix->infix;
+               infix_len = pf->infix_len;
+               base_index = pf->prefix->base_index;
+       }
 
        if (base_index >= ARRAY_SIZE(xattr_types))
                return 1;
@@ -1246,16 +1287,18 @@ static int xattr_entrylist(struct xattr_iter *_it,
        prefix_len = xattr_types[base_index].prefix_len;
 
        if (!it->buffer) {
-               it->buffer_ofs += prefix_len + entry->e_name_len + 1;
+               it->buffer_ofs += prefix_len + infix_len +
+                                       entry->e_name_len + 1;
                return 1;
        }
 
-       if (it->buffer_ofs + prefix_len
+       if (it->buffer_ofs + prefix_len + infix_len
                + entry->e_name_len + 1 > it->buffer_size)
                return -ERANGE;
 
        memcpy(it->buffer + it->buffer_ofs, prefix, prefix_len);
-       it->buffer_ofs += prefix_len;
+       memcpy(it->buffer + it->buffer_ofs + prefix_len, infix, infix_len);
+       it->buffer_ofs += prefix_len + infix_len;
        return 0;
 }
 
@@ -1404,3 +1447,55 @@ void erofs_xattr_cleanup_name_prefixes(void)
                free(tnode);
        }
 }
+
+void erofs_xattr_prefixes_cleanup(struct erofs_sb_info *sbi)
+{
+       int i;
+
+       if (sbi->xattr_prefixes) {
+               for (i = 0; i < sbi->xattr_prefix_count; i++)
+                       free(sbi->xattr_prefixes[i].prefix);
+               free(sbi->xattr_prefixes);
+               sbi->xattr_prefixes = NULL;
+       }
+}
+
+int erofs_xattr_prefixes_init(struct erofs_sb_info *sbi)
+{
+       erofs_off_t pos = (erofs_off_t)sbi->xattr_prefix_start << 2;
+       struct erofs_xattr_prefix_item *pfs;
+       erofs_nid_t nid = 0;
+       int ret = 0, i, len;
+       void *buf;
+
+       if (!sbi->xattr_prefix_count)
+               return 0;
+
+       if (sbi->packed_nid)
+               nid = sbi->packed_nid;
+
+       pfs = calloc(sbi->xattr_prefix_count, sizeof(*pfs));
+       if (!pfs)
+               return -ENOMEM;
+
+       for (i = 0; i < sbi->xattr_prefix_count; i++) {
+               buf = erofs_read_metadata(sbi, nid, &pos, &len);
+               if (IS_ERR(buf)) {
+                       ret = PTR_ERR(buf);
+                       goto out;
+               }
+               if (len < sizeof(*pfs->prefix) ||
+                   len > EROFS_NAME_LEN + sizeof(*pfs->prefix)) {
+                       free(buf);
+                       ret = -EFSCORRUPTED;
+                       goto out;
+               }
+               pfs[i].prefix = buf;
+               pfs[i].infix_len = len - sizeof(struct erofs_xattr_long_prefix);
+       }
+out:
+       sbi->xattr_prefixes = pfs;
+       if (ret)
+               erofs_xattr_prefixes_cleanup(sbi);
+       return ret;
+}
index 603c2f3387efacd0df044c6db7752fe3e91d0f13..dd754859ab4e7417eac4bf28906c24bed7a19c2c 100644 (file)
@@ -6,4 +6,5 @@ AM_CPPFLAGS = ${libselinux_CFLAGS}
 mkfs_erofs_SOURCES = main.c
 mkfs_erofs_CFLAGS = -Wall -I$(top_srcdir)/include
 mkfs_erofs_LDADD = $(top_builddir)/lib/liberofs.la ${libselinux_LIBS} \
-       ${libuuid_LIBS} ${liblz4_LIBS} ${liblzma_LIBS} ${libdeflate_LIBS}
+       ${libuuid_LIBS} ${liblz4_LIBS} ${liblzma_LIBS} ${zlib_LIBS} \
+       ${libdeflate_LIBS}