diff options
author | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2022-04-04 17:45:01 +0200 |
---|---|---|
committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2022-04-05 20:19:56 +0200 |
commit | 94c3fdc66b9aa8130b20a644f399fc021d0a823c (patch) | |
tree | 5a841462555e39f78b6ab863a7d695d257daa6a7 /lib/sqfs/dir_reader/dir_reader.c | |
parent | 916c8f6e26140cf3c03e58726b57dc4f86e18316 (diff) |
libsqfs: move dir reader code to sub directory, add internal header
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib/sqfs/dir_reader/dir_reader.c')
-rw-r--r-- | lib/sqfs/dir_reader/dir_reader.c | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/lib/sqfs/dir_reader/dir_reader.c b/lib/sqfs/dir_reader/dir_reader.c new file mode 100644 index 0000000..969b71d --- /dev/null +++ b/lib/sqfs/dir_reader/dir_reader.c @@ -0,0 +1,232 @@ +/* SPDX-License-Identifier: LGPL-3.0-or-later */ +/* + * fs_reader.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#define SQFS_BUILDING_DLL +#include "internal.h" + +static void dir_reader_destroy(sqfs_object_t *obj) +{ + sqfs_dir_reader_t *rd = (sqfs_dir_reader_t *)obj; + + sqfs_destroy(rd->meta_inode); + sqfs_destroy(rd->meta_dir); + free(rd); +} + +static sqfs_object_t *dir_reader_copy(const sqfs_object_t *obj) +{ + const sqfs_dir_reader_t *rd = (const sqfs_dir_reader_t *)obj; + sqfs_dir_reader_t *copy = malloc(sizeof(*copy)); + + if (copy == NULL) + return NULL; + + memcpy(copy, rd, sizeof(*copy)); + + copy->meta_inode = sqfs_copy(rd->meta_inode); + if (copy->meta_inode == NULL) + goto fail_mino; + + copy->meta_dir = sqfs_copy(rd->meta_dir); + if (copy->meta_dir == NULL) + goto fail_mdir; + + return (sqfs_object_t *)copy; +fail_mdir: + sqfs_destroy(copy->meta_inode); +fail_mino: + free(copy); + return NULL; +} + +sqfs_dir_reader_t *sqfs_dir_reader_create(const sqfs_super_t *super, + sqfs_compressor_t *cmp, + sqfs_file_t *file, + sqfs_u32 flags) +{ + sqfs_dir_reader_t *rd; + sqfs_u64 start, limit; + + if (flags != 0) + return NULL; + + rd = calloc(1, sizeof(*rd)); + if (rd == NULL) + return NULL; + + start = super->inode_table_start; + limit = super->directory_table_start; + + rd->meta_inode = sqfs_meta_reader_create(file, cmp, start, limit); + + if (rd->meta_inode == NULL) { + free(rd); + return NULL; + } + + start = super->directory_table_start; + limit = super->id_table_start; + + if (super->fragment_table_start < limit) + limit = super->fragment_table_start; + + if (super->export_table_start < limit) + limit = super->export_table_start; + + rd->meta_dir = sqfs_meta_reader_create(file, cmp, start, limit); + + if (rd->meta_dir == NULL) { + sqfs_destroy(rd->meta_inode); + free(rd); + return NULL; + } + + ((sqfs_object_t *)rd)->destroy = dir_reader_destroy; + ((sqfs_object_t *)rd)->copy = dir_reader_copy; + rd->super = super; + return rd; +} + +int sqfs_dir_reader_open_dir(sqfs_dir_reader_t *rd, + const sqfs_inode_generic_t *inode, + sqfs_u32 flags) +{ + sqfs_u64 block_start; + size_t size, offset; + + if (flags != 0) + return SQFS_ERROR_UNSUPPORTED; + + if (inode->base.type == SQFS_INODE_DIR) { + size = inode->data.dir.size; + offset = inode->data.dir.offset; + block_start = inode->data.dir.start_block; + } else if (inode->base.type == SQFS_INODE_EXT_DIR) { + size = inode->data.dir_ext.size; + offset = inode->data.dir_ext.offset; + block_start = inode->data.dir_ext.start_block; + } else { + return SQFS_ERROR_NOT_DIR; + } + + memset(&rd->hdr, 0, sizeof(rd->hdr)); + rd->size = size; + rd->entries = 0; + + block_start += rd->super->directory_table_start; + + rd->dir_block_start = block_start; + rd->dir_offset = offset; + rd->start_size = size; + + if (rd->size <= sizeof(rd->hdr)) + return 0; + + return sqfs_meta_reader_seek(rd->meta_dir, block_start, offset); +} + +int sqfs_dir_reader_read(sqfs_dir_reader_t *rd, sqfs_dir_entry_t **out) +{ + sqfs_dir_entry_t *ent; + size_t count; + int err; + + if (!rd->entries) { + if (rd->size <= sizeof(rd->hdr)) + return 1; + + err = sqfs_meta_reader_read_dir_header(rd->meta_dir, &rd->hdr); + if (err) + return err; + + rd->size -= sizeof(rd->hdr); + rd->entries = rd->hdr.count + 1; + } + + if (rd->size <= sizeof(*ent)) { + rd->size = 0; + rd->entries = 0; + return 1; + } + + err = sqfs_meta_reader_read_dir_ent(rd->meta_dir, &ent); + if (err) + return err; + + count = sizeof(*ent) + strlen((const char *)ent->name); + + if (count > rd->size) { + rd->size = 0; + rd->entries = 0; + } else { + rd->size -= count; + rd->entries -= 1; + } + + rd->inode_offset = ent->offset; + *out = ent; + return 0; +} + +int sqfs_dir_reader_rewind(sqfs_dir_reader_t *rd) +{ + memset(&rd->hdr, 0, sizeof(rd->hdr)); + rd->size = rd->start_size; + rd->entries = 0; + + if (rd->size <= sizeof(rd->hdr)) + return 0; + + return sqfs_meta_reader_seek(rd->meta_dir, rd->dir_block_start, + rd->dir_offset); +} + +int sqfs_dir_reader_find(sqfs_dir_reader_t *rd, const char *name) +{ + sqfs_dir_entry_t *ent; + int ret; + + if (rd->size != rd->start_size) { + ret = sqfs_dir_reader_rewind(rd); + if (ret) + return ret; + } + + do { + ret = sqfs_dir_reader_read(rd, &ent); + if (ret < 0) + return ret; + if (ret > 0) + return SQFS_ERROR_NO_ENTRY; + + ret = strcmp((const char *)ent->name, name); + free(ent); + } while (ret < 0); + + return ret == 0 ? 0 : SQFS_ERROR_NO_ENTRY; +} + +int sqfs_dir_reader_get_inode(sqfs_dir_reader_t *rd, + sqfs_inode_generic_t **inode) +{ + sqfs_u64 block_start; + + block_start = rd->hdr.start_block; + + return sqfs_meta_reader_read_inode(rd->meta_inode, rd->super, + block_start, rd->inode_offset, + inode); +} + +int sqfs_dir_reader_get_root_inode(sqfs_dir_reader_t *rd, + sqfs_inode_generic_t **inode) +{ + sqfs_u64 block_start = rd->super->root_inode_ref >> 16; + sqfs_u16 offset = rd->super->root_inode_ref & 0xFFFF; + + return sqfs_meta_reader_read_inode(rd->meta_inode, rd->super, + block_start, offset, inode); +} |