[PATCH v3 2/3] erofs-utils: add erofs_read_metadata() helper
Jingbo Xu
jefflexu at linux.alibaba.com
Thu Aug 17 17:14:54 AEST 2023
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 at linux.alibaba.com>
---
include/erofs/internal.h | 2 +
lib/data.c | 84 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 86 insertions(+)
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index a04e6a6..3e7319d 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -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)
diff --git a/lib/data.c b/lib/data.c
index a172bb5..662e922 100644
--- a/lib/data.c
+++ b/lib/data.c
@@ -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);
+}
--
2.19.1.6.gb485710b
More information about the Linux-erofs
mailing list