erofs-utils: add erofs_read_metadata() helper
authorJingbo Xu <jefflexu@linux.alibaba.com>
Thu, 17 Aug 2023 07:14:54 +0000 (15:14 +0800)
committerGao Xiang <hsiangkao@linux.alibaba.com>
Thu, 17 Aug 2023 11:21:08 +0000 (19:21 +0800)
Add erofs_read_metadata() helper reading variable-sized metadata from
inode specified by @nid.  Read from meta inode if @nid is 0.

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

index a04e6a6e5dfd15b4c4de10877d6998f947b14d0d..3e7319d8a10b2fd7131115a05b7bff80a360dff7 100644 (file)
@@ -364,6 +364,8 @@ int erofs_read_one_data(struct erofs_inode *inode, struct erofs_map_blocks *map,
 int z_erofs_read_one_data(struct erofs_inode *inode,
                        struct erofs_map_blocks *map, char *raw, char *buffer,
                        erofs_off_t skip, erofs_off_t length, bool trimmed);
+void *erofs_read_metadata(struct erofs_sb_info *sbi, erofs_nid_t nid,
+                         erofs_off_t *offset, int *lengthp);
 
 static inline int erofs_get_occupied_size(const struct erofs_inode *inode,
                                          erofs_off_t *size)
index a172bb5735aeefb5c478751752dba664a887ea95..662e922e758a8baab6adb83b6469b9c0f81dfeb4 100644 (file)
@@ -372,3 +372,87 @@ int erofs_pread(struct erofs_inode *inode, char *buf,
        }
        return -EINVAL;
 }
+
+static void *erofs_read_metadata_nid(struct erofs_sb_info *sbi, erofs_nid_t nid,
+                                    erofs_off_t *offset, int *lengthp)
+{
+       struct erofs_inode vi = { .sbi = sbi, .nid = nid };
+       __le16 __len;
+       int ret, len;
+       char *buffer;
+
+       ret = erofs_read_inode_from_disk(&vi);
+       if (ret)
+               return ERR_PTR(ret);
+
+       *offset = round_up(*offset, 4);
+       ret = erofs_pread(&vi, (void *)&__len, sizeof(__le16), *offset);
+       if (ret)
+               return ERR_PTR(ret);
+
+       len = le16_to_cpu(__len);
+       if (!len)
+               return ERR_PTR(-EFSCORRUPTED);
+
+       buffer = malloc(len);
+       if (!buffer)
+               return ERR_PTR(-ENOMEM);
+       *offset += sizeof(__le16);
+       *lengthp = len;
+
+       ret = erofs_pread(&vi, buffer, len, *offset);
+       if (ret) {
+               free(buffer);
+               return ERR_PTR(ret);
+       }
+       *offset += len;
+       return buffer;
+}
+
+static void *erofs_read_metadata_bdi(struct erofs_sb_info *sbi,
+                                    erofs_off_t *offset, int *lengthp)
+{
+       int ret, len, i, cnt;
+       void *buffer;
+       u8 data[EROFS_MAX_BLOCK_SIZE];
+
+       *offset = round_up(*offset, 4);
+       ret = blk_read(sbi, 0, data, erofs_blknr(sbi, *offset), 1);
+       if (ret)
+               return ERR_PTR(ret);
+       len = le16_to_cpu(*(__le16 *)&data[erofs_blkoff(sbi, *offset)]);
+       if (!len)
+               return ERR_PTR(-EFSCORRUPTED);
+
+       buffer = malloc(len);
+       if (!buffer)
+               return ERR_PTR(-ENOMEM);
+       *offset += sizeof(__le16);
+       *lengthp = len;
+
+       for (i = 0; i < len; i += cnt) {
+               cnt = min_t(int, erofs_blksiz(sbi) - erofs_blkoff(sbi, *offset),
+                           len - i);
+               ret = blk_read(sbi, 0, data, erofs_blknr(sbi, *offset), 1);
+               if (ret) {
+                       free(buffer);
+                       return ERR_PTR(ret);
+               }
+               memcpy(buffer + i, data + erofs_blkoff(sbi, *offset), cnt);
+               *offset += cnt;
+       }
+       return buffer;
+}
+
+/*
+ * read variable-sized metadata, offset will be aligned by 4-byte
+ *
+ * @nid is 0 if metadata is in meta inode
+ */
+void *erofs_read_metadata(struct erofs_sb_info *sbi, erofs_nid_t nid,
+                         erofs_off_t *offset, int *lengthp)
+{
+       if (nid)
+               return erofs_read_metadata_nid(sbi, nid, offset, lengthp);
+       return erofs_read_metadata_bdi(sbi, offset, lengthp);
+}