From: Jingbo Xu Date: Thu, 17 Aug 2023 07:14:54 +0000 (+0800) Subject: erofs-utils: add erofs_read_metadata() helper X-Git-Tag: v1.8~205 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=43d3a69ef7118dd9c5bec8e2f8c186f684eaed13;p=platform%2Fupstream%2Ferofs-utils.git erofs-utils: add erofs_read_metadata() helper 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 Link: https://lore.kernel.org/r/20230817071455.12040-3-jefflexu@linux.alibaba.com Signed-off-by: Gao Xiang --- 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); +}