From 94c3fdc66b9aa8130b20a644f399fc021d0a823c Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Mon, 4 Apr 2022 17:45:01 +0200 Subject: libsqfs: move dir reader code to sub directory, add internal header Signed-off-by: David Oberhollenzer --- lib/sqfs/Makemodule.am | 5 +- lib/sqfs/dir_reader.c | 335 ------------------------------------- lib/sqfs/dir_reader/dir_reader.c | 232 +++++++++++++++++++++++++ lib/sqfs/dir_reader/find_by_path.c | 82 +++++++++ lib/sqfs/dir_reader/internal.h | 42 +++++ lib/sqfs/dir_reader/read_tree.c | 292 ++++++++++++++++++++++++++++++++ lib/sqfs/read_tree.c | 305 --------------------------------- 7 files changed, 652 insertions(+), 641 deletions(-) delete mode 100644 lib/sqfs/dir_reader.c create mode 100644 lib/sqfs/dir_reader/dir_reader.c create mode 100644 lib/sqfs/dir_reader/find_by_path.c create mode 100644 lib/sqfs/dir_reader/internal.h create mode 100644 lib/sqfs/dir_reader/read_tree.c delete mode 100644 lib/sqfs/read_tree.c (limited to 'lib') diff --git a/lib/sqfs/Makemodule.am b/lib/sqfs/Makemodule.am index df6e3ce..c37301b 100644 --- a/lib/sqfs/Makemodule.am +++ b/lib/sqfs/Makemodule.am @@ -18,7 +18,10 @@ libsquashfs_la_SOURCES += lib/sqfs/read_inode.c lib/sqfs/write_inode.c libsquashfs_la_SOURCES += lib/sqfs/dir_writer.c lib/sqfs/xattr/xattr_reader.c libsquashfs_la_SOURCES += lib/sqfs/read_table.c lib/sqfs/comp/compressor.c libsquashfs_la_SOURCES += lib/sqfs/comp/internal.h -libsquashfs_la_SOURCES += lib/sqfs/dir_reader.c lib/sqfs/read_tree.c +libsquashfs_la_SOURCES += lib/sqfs/dir_reader/dir_reader.c +libsquashfs_la_SOURCES += lib/sqfs/dir_reader/find_by_path.c +libsquashfs_la_SOURCES += lib/sqfs/dir_reader/read_tree.c +libsquashfs_la_SOURCES += lib/sqfs/dir_reader/internal.h libsquashfs_la_SOURCES += lib/sqfs/inode.c lib/sqfs/xattr/xattr_writer.c libsquashfs_la_SOURCES += lib/sqfs/xattr/xattr_writer_flush.c libsquashfs_la_SOURCES += lib/sqfs/xattr/xattr_writer_record.c diff --git a/lib/sqfs/dir_reader.c b/lib/sqfs/dir_reader.c deleted file mode 100644 index f560069..0000000 --- a/lib/sqfs/dir_reader.c +++ /dev/null @@ -1,335 +0,0 @@ -/* SPDX-License-Identifier: LGPL-3.0-or-later */ -/* - * fs_reader.c - * - * Copyright (C) 2019 David Oberhollenzer - */ -#define SQFS_BUILDING_DLL -#include "config.h" - -#include "sqfs/meta_reader.h" -#include "sqfs/dir_reader.h" -#include "sqfs/compressor.h" -#include "sqfs/super.h" -#include "sqfs/inode.h" -#include "sqfs/error.h" -#include "sqfs/dir.h" -#include "util.h" - -#include -#include - -struct sqfs_dir_reader_t { - sqfs_object_t base; - - sqfs_meta_reader_t *meta_dir; - sqfs_meta_reader_t *meta_inode; - const sqfs_super_t *super; - - sqfs_dir_header_t hdr; - sqfs_u64 dir_block_start; - size_t entries; - size_t size; - - size_t start_size; - sqfs_u16 dir_offset; - sqfs_u16 inode_offset; -}; - -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); -} - -int sqfs_dir_reader_find_by_path(sqfs_dir_reader_t *rd, - const sqfs_inode_generic_t *start, - const char *path, sqfs_inode_generic_t **out) -{ - sqfs_inode_generic_t *inode; - sqfs_dir_entry_t *ent; - const char *ptr; - int ret = 0; - - if (start == NULL) { - ret = sqfs_dir_reader_get_root_inode(rd, &inode); - } else { - inode = alloc_flex(sizeof(*inode), 1, - start->payload_bytes_used); - if (inode == NULL) { - ret = SQFS_ERROR_ALLOC; - } else { - memcpy(inode, start, - sizeof(*start) + start->payload_bytes_used); - } - } - - if (ret) - return ret; - - while (*path != '\0') { - if (*path == '/') { - while (*path == '/') - ++path; - continue; - } - - ret = sqfs_dir_reader_open_dir(rd, inode, 0); - free(inode); - if (ret) - return ret; - - ptr = strchr(path, '/'); - if (ptr == NULL) { - - if (ptr == NULL) { - for (ptr = path; *ptr != '\0'; ++ptr) - ; - } - } - - do { - ret = sqfs_dir_reader_read(rd, &ent); - if (ret < 0) - return ret; - - if (ret == 0) { - ret = strncmp((const char *)ent->name, - path, ptr - path); - if (ret == 0) - ret = ent->name[ptr - path]; - free(ent); - } - } while (ret < 0); - - if (ret > 0) - return SQFS_ERROR_NO_ENTRY; - - ret = sqfs_dir_reader_get_inode(rd, &inode); - if (ret) - return ret; - - path = ptr; - } - - *out = inode; - return 0; -} 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 + */ +#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); +} diff --git a/lib/sqfs/dir_reader/find_by_path.c b/lib/sqfs/dir_reader/find_by_path.c new file mode 100644 index 0000000..0cd800f --- /dev/null +++ b/lib/sqfs/dir_reader/find_by_path.c @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: LGPL-3.0-or-later */ +/* + * find_by_path.c + * + * Copyright (C) 2019 David Oberhollenzer + */ +#define SQFS_BUILDING_DLL +#include "internal.h" + +int sqfs_dir_reader_find_by_path(sqfs_dir_reader_t *rd, + const sqfs_inode_generic_t *start, + const char *path, sqfs_inode_generic_t **out) +{ + sqfs_inode_generic_t *inode; + sqfs_dir_entry_t *ent; + const char *ptr; + int ret = 0; + + if (start == NULL) { + ret = sqfs_dir_reader_get_root_inode(rd, &inode); + } else { + inode = alloc_flex(sizeof(*inode), 1, + start->payload_bytes_used); + if (inode == NULL) { + ret = SQFS_ERROR_ALLOC; + } else { + memcpy(inode, start, + sizeof(*start) + start->payload_bytes_used); + } + } + + if (ret) + return ret; + + while (*path != '\0') { + if (*path == '/') { + while (*path == '/') + ++path; + continue; + } + + ret = sqfs_dir_reader_open_dir(rd, inode, 0); + free(inode); + if (ret) + return ret; + + ptr = strchr(path, '/'); + if (ptr == NULL) { + + if (ptr == NULL) { + for (ptr = path; *ptr != '\0'; ++ptr) + ; + } + } + + do { + ret = sqfs_dir_reader_read(rd, &ent); + if (ret < 0) + return ret; + + if (ret == 0) { + ret = strncmp((const char *)ent->name, + path, ptr - path); + if (ret == 0) + ret = ent->name[ptr - path]; + free(ent); + } + } while (ret < 0); + + if (ret > 0) + return SQFS_ERROR_NO_ENTRY; + + ret = sqfs_dir_reader_get_inode(rd, &inode); + if (ret) + return ret; + + path = ptr; + } + + *out = inode; + return 0; +} diff --git a/lib/sqfs/dir_reader/internal.h b/lib/sqfs/dir_reader/internal.h new file mode 100644 index 0000000..ff162ff --- /dev/null +++ b/lib/sqfs/dir_reader/internal.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: LGPL-3.0-or-later */ +/* + * internal.h + * + * Copyright (C) 2019 David Oberhollenzer + */ +#ifndef DIR_READER_INTERNAL_H +#define DIR_READER_INTERNAL_H + +#include "config.h" + +#include "sqfs/meta_reader.h" +#include "sqfs/dir_reader.h" +#include "sqfs/compressor.h" +#include "sqfs/id_table.h" +#include "sqfs/super.h" +#include "sqfs/inode.h" +#include "sqfs/error.h" +#include "sqfs/dir.h" +#include "util.h" + +#include +#include + +struct sqfs_dir_reader_t { + sqfs_object_t base; + + sqfs_meta_reader_t *meta_dir; + sqfs_meta_reader_t *meta_inode; + const sqfs_super_t *super; + + sqfs_dir_header_t hdr; + sqfs_u64 dir_block_start; + size_t entries; + size_t size; + + size_t start_size; + sqfs_u16 dir_offset; + sqfs_u16 inode_offset; +}; + +#endif /* DIR_READER_INTERNAL_H */ diff --git a/lib/sqfs/dir_reader/read_tree.c b/lib/sqfs/dir_reader/read_tree.c new file mode 100644 index 0000000..d173ef7 --- /dev/null +++ b/lib/sqfs/dir_reader/read_tree.c @@ -0,0 +1,292 @@ +/* SPDX-License-Identifier: LGPL-3.0-or-later */ +/* + * read_tree.c + * + * Copyright (C) 2019 David Oberhollenzer + */ +#define SQFS_BUILDING_DLL +#include "internal.h" + +static int should_skip(int type, unsigned int flags) +{ + switch (type) { + case SQFS_INODE_BDEV: + case SQFS_INODE_CDEV: + case SQFS_INODE_EXT_CDEV: + case SQFS_INODE_EXT_BDEV: + return (flags & SQFS_TREE_NO_DEVICES); + case SQFS_INODE_SLINK: + case SQFS_INODE_EXT_SLINK: + return (flags & SQFS_TREE_NO_SLINKS); + case SQFS_INODE_SOCKET: + case SQFS_INODE_EXT_SOCKET: + return(flags & SQFS_TREE_NO_SOCKETS); + case SQFS_INODE_FIFO: + case SQFS_INODE_EXT_FIFO: + return (flags & SQFS_TREE_NO_FIFO); + default: + break; + } + + return 0; +} + +static bool would_be_own_parent(sqfs_tree_node_t *parent, sqfs_tree_node_t *n) +{ + sqfs_u32 inum = n->inode->base.inode_number; + + while (parent != NULL) { + if (parent->inode->base.inode_number == inum) + return true; + + parent = parent->parent; + } + + return false; +} + +static sqfs_tree_node_t *create_node(sqfs_inode_generic_t *inode, + const char *name) +{ + sqfs_tree_node_t *n; + + n = alloc_flex(sizeof(*n), 1, strlen(name) + 1); + if (n == NULL) + return NULL; + + n->inode = inode; + strcpy((char *)n->name, name); + return n; +} + +static int fill_dir(sqfs_dir_reader_t *dr, sqfs_tree_node_t *root, + unsigned int flags) +{ + sqfs_tree_node_t *n, *prev, **tail; + sqfs_inode_generic_t *inode; + sqfs_dir_entry_t *ent; + int err; + + tail = &root->children; + + for (;;) { + err = sqfs_dir_reader_read(dr, &ent); + if (err > 0) + break; + if (err < 0) + return err; + + if (should_skip(ent->type, flags)) { + free(ent); + continue; + } + + err = sqfs_dir_reader_get_inode(dr, &inode); + if (err) { + free(ent); + return err; + } + + n = create_node(inode, (const char *)ent->name); + free(ent); + + if (n == NULL) { + free(inode); + return SQFS_ERROR_ALLOC; + } + + if (would_be_own_parent(root, n)) { + free(n); + free(inode); + return SQFS_ERROR_LINK_LOOP; + } + + *tail = n; + tail = &n->next; + n->parent = root; + } + + n = root->children; + prev = NULL; + + while (n != NULL) { + if (n->inode->base.type == SQFS_INODE_DIR || + n->inode->base.type == SQFS_INODE_EXT_DIR) { + if (!(flags & SQFS_TREE_NO_RECURSE)) { + err = sqfs_dir_reader_open_dir(dr, n->inode, 0); + if (err) + return err; + + err = fill_dir(dr, n, flags); + if (err) + return err; + } + + if (n->children == NULL && + (flags & SQFS_TREE_NO_EMPTY)) { + free(n->inode); + if (prev == NULL) { + root->children = root->children->next; + free(n); + n = root->children; + } else { + prev->next = n->next; + free(n); + n = prev->next; + } + continue; + } + } + + prev = n; + n = n->next; + } + + return 0; +} + +static int resolve_ids(sqfs_tree_node_t *root, const sqfs_id_table_t *idtbl) +{ + sqfs_tree_node_t *it; + int err; + + for (it = root->children; it != NULL; it = it->next) + resolve_ids(it, idtbl); + + err = sqfs_id_table_index_to_id(idtbl, root->inode->base.uid_idx, + &root->uid); + if (err) + return err; + + return sqfs_id_table_index_to_id(idtbl, root->inode->base.gid_idx, + &root->gid); +} + +void sqfs_dir_tree_destroy(sqfs_tree_node_t *root) +{ + sqfs_tree_node_t *it; + + if (!root) + return; + + while (root->children != NULL) { + it = root->children; + root->children = it->next; + + sqfs_dir_tree_destroy(it); + } + + free(root->inode); + free(root); +} + +int sqfs_dir_reader_get_full_hierarchy(sqfs_dir_reader_t *rd, + const sqfs_id_table_t *idtbl, + const char *path, unsigned int flags, + sqfs_tree_node_t **out) +{ + sqfs_tree_node_t *root, *tail, *new; + sqfs_inode_generic_t *inode; + sqfs_dir_entry_t *ent; + const char *ptr; + int ret; + + if (flags & ~SQFS_TREE_ALL_FLAGS) + return SQFS_ERROR_UNSUPPORTED; + + ret = sqfs_dir_reader_get_root_inode(rd, &inode); + if (ret) + return ret; + + root = tail = create_node(inode, ""); + if (root == NULL) { + free(inode); + return SQFS_ERROR_ALLOC; + } + inode = NULL; + + while (path != NULL && *path != '\0') { + if (*path == '/') { + while (*path == '/') + ++path; + continue; + } + + ret = sqfs_dir_reader_open_dir(rd, tail->inode, 0); + if (ret) + goto fail; + + ptr = strchr(path, '/'); + if (ptr == NULL) { + + if (ptr == NULL) { + for (ptr = path; *ptr != '\0'; ++ptr) + ; + } + } + + for (;;) { + ret = sqfs_dir_reader_read(rd, &ent); + if (ret < 0) + goto fail; + if (ret > 0) { + ret = SQFS_ERROR_NO_ENTRY; + goto fail; + } + + ret = strncmp((const char *)ent->name, + path, ptr - path); + if (ret == 0 && ent->name[ptr - path] == '\0') + break; + free(ent); + } + + ret = sqfs_dir_reader_get_inode(rd, &inode); + if (ret) { + free(ent); + goto fail; + } + + new = create_node(inode, (const char *)ent->name); + free(ent); + + if (new == NULL) { + free(inode); + ret = SQFS_ERROR_ALLOC; + goto fail; + } + + inode = NULL; + path = ptr; + + if (flags & SQFS_TREE_STORE_PARENTS) { + tail->children = new; + new->parent = tail; + tail = new; + } else { + sqfs_dir_tree_destroy(root); + root = tail = new; + } + } + + if (tail->inode->base.type == SQFS_INODE_DIR || + tail->inode->base.type == SQFS_INODE_EXT_DIR) { + ret = sqfs_dir_reader_open_dir(rd, tail->inode, 0); + if (ret) + goto fail; + + ret = fill_dir(rd, tail, flags); + if (ret) + goto fail; + } + + ret = resolve_ids(root, idtbl); + if (ret) + goto fail; + + *out = root; + return 0; +fail: + sqfs_dir_tree_destroy(root); + return ret; +} diff --git a/lib/sqfs/read_tree.c b/lib/sqfs/read_tree.c deleted file mode 100644 index feda691..0000000 --- a/lib/sqfs/read_tree.c +++ /dev/null @@ -1,305 +0,0 @@ -/* SPDX-License-Identifier: LGPL-3.0-or-later */ -/* - * read_tree.c - * - * Copyright (C) 2019 David Oberhollenzer - */ -#define SQFS_BUILDING_DLL -#include "config.h" - -#include "sqfs/meta_reader.h" -#include "sqfs/dir_reader.h" -#include "sqfs/compressor.h" -#include "sqfs/id_table.h" -#include "sqfs/super.h" -#include "sqfs/inode.h" -#include "sqfs/error.h" -#include "sqfs/dir.h" -#include "util.h" - -#include -#include - -static int should_skip(int type, unsigned int flags) -{ - switch (type) { - case SQFS_INODE_BDEV: - case SQFS_INODE_CDEV: - case SQFS_INODE_EXT_CDEV: - case SQFS_INODE_EXT_BDEV: - return (flags & SQFS_TREE_NO_DEVICES); - case SQFS_INODE_SLINK: - case SQFS_INODE_EXT_SLINK: - return (flags & SQFS_TREE_NO_SLINKS); - case SQFS_INODE_SOCKET: - case SQFS_INODE_EXT_SOCKET: - return(flags & SQFS_TREE_NO_SOCKETS); - case SQFS_INODE_FIFO: - case SQFS_INODE_EXT_FIFO: - return (flags & SQFS_TREE_NO_FIFO); - default: - break; - } - - return 0; -} - -static bool would_be_own_parent(sqfs_tree_node_t *parent, sqfs_tree_node_t *n) -{ - sqfs_u32 inum = n->inode->base.inode_number; - - while (parent != NULL) { - if (parent->inode->base.inode_number == inum) - return true; - - parent = parent->parent; - } - - return false; -} - -static sqfs_tree_node_t *create_node(sqfs_inode_generic_t *inode, - const char *name) -{ - sqfs_tree_node_t *n; - - n = alloc_flex(sizeof(*n), 1, strlen(name) + 1); - if (n == NULL) - return NULL; - - n->inode = inode; - strcpy((char *)n->name, name); - return n; -} - -static int fill_dir(sqfs_dir_reader_t *dr, sqfs_tree_node_t *root, - unsigned int flags) -{ - sqfs_tree_node_t *n, *prev, **tail; - sqfs_inode_generic_t *inode; - sqfs_dir_entry_t *ent; - int err; - - tail = &root->children; - - for (;;) { - err = sqfs_dir_reader_read(dr, &ent); - if (err > 0) - break; - if (err < 0) - return err; - - if (should_skip(ent->type, flags)) { - free(ent); - continue; - } - - err = sqfs_dir_reader_get_inode(dr, &inode); - if (err) { - free(ent); - return err; - } - - n = create_node(inode, (const char *)ent->name); - free(ent); - - if (n == NULL) { - free(inode); - return SQFS_ERROR_ALLOC; - } - - if (would_be_own_parent(root, n)) { - free(n); - free(inode); - return SQFS_ERROR_LINK_LOOP; - } - - *tail = n; - tail = &n->next; - n->parent = root; - } - - n = root->children; - prev = NULL; - - while (n != NULL) { - if (n->inode->base.type == SQFS_INODE_DIR || - n->inode->base.type == SQFS_INODE_EXT_DIR) { - if (!(flags & SQFS_TREE_NO_RECURSE)) { - err = sqfs_dir_reader_open_dir(dr, n->inode, 0); - if (err) - return err; - - err = fill_dir(dr, n, flags); - if (err) - return err; - } - - if (n->children == NULL && - (flags & SQFS_TREE_NO_EMPTY)) { - free(n->inode); - if (prev == NULL) { - root->children = root->children->next; - free(n); - n = root->children; - } else { - prev->next = n->next; - free(n); - n = prev->next; - } - continue; - } - } - - prev = n; - n = n->next; - } - - return 0; -} - -static int resolve_ids(sqfs_tree_node_t *root, const sqfs_id_table_t *idtbl) -{ - sqfs_tree_node_t *it; - int err; - - for (it = root->children; it != NULL; it = it->next) - resolve_ids(it, idtbl); - - err = sqfs_id_table_index_to_id(idtbl, root->inode->base.uid_idx, - &root->uid); - if (err) - return err; - - return sqfs_id_table_index_to_id(idtbl, root->inode->base.gid_idx, - &root->gid); -} - -void sqfs_dir_tree_destroy(sqfs_tree_node_t *root) -{ - sqfs_tree_node_t *it; - - if (!root) - return; - - while (root->children != NULL) { - it = root->children; - root->children = it->next; - - sqfs_dir_tree_destroy(it); - } - - free(root->inode); - free(root); -} - -int sqfs_dir_reader_get_full_hierarchy(sqfs_dir_reader_t *rd, - const sqfs_id_table_t *idtbl, - const char *path, unsigned int flags, - sqfs_tree_node_t **out) -{ - sqfs_tree_node_t *root, *tail, *new; - sqfs_inode_generic_t *inode; - sqfs_dir_entry_t *ent; - const char *ptr; - int ret; - - if (flags & ~SQFS_TREE_ALL_FLAGS) - return SQFS_ERROR_UNSUPPORTED; - - ret = sqfs_dir_reader_get_root_inode(rd, &inode); - if (ret) - return ret; - - root = tail = create_node(inode, ""); - if (root == NULL) { - free(inode); - return SQFS_ERROR_ALLOC; - } - inode = NULL; - - while (path != NULL && *path != '\0') { - if (*path == '/') { - while (*path == '/') - ++path; - continue; - } - - ret = sqfs_dir_reader_open_dir(rd, tail->inode, 0); - if (ret) - goto fail; - - ptr = strchr(path, '/'); - if (ptr == NULL) { - - if (ptr == NULL) { - for (ptr = path; *ptr != '\0'; ++ptr) - ; - } - } - - for (;;) { - ret = sqfs_dir_reader_read(rd, &ent); - if (ret < 0) - goto fail; - if (ret > 0) { - ret = SQFS_ERROR_NO_ENTRY; - goto fail; - } - - ret = strncmp((const char *)ent->name, - path, ptr - path); - if (ret == 0 && ent->name[ptr - path] == '\0') - break; - free(ent); - } - - ret = sqfs_dir_reader_get_inode(rd, &inode); - if (ret) { - free(ent); - goto fail; - } - - new = create_node(inode, (const char *)ent->name); - free(ent); - - if (new == NULL) { - free(inode); - ret = SQFS_ERROR_ALLOC; - goto fail; - } - - inode = NULL; - path = ptr; - - if (flags & SQFS_TREE_STORE_PARENTS) { - tail->children = new; - new->parent = tail; - tail = new; - } else { - sqfs_dir_tree_destroy(root); - root = tail = new; - } - } - - if (tail->inode->base.type == SQFS_INODE_DIR || - tail->inode->base.type == SQFS_INODE_EXT_DIR) { - ret = sqfs_dir_reader_open_dir(rd, tail->inode, 0); - if (ret) - goto fail; - - ret = fill_dir(rd, tail, flags); - if (ret) - goto fail; - } - - ret = resolve_ids(root, idtbl); - if (ret) - goto fail; - - *out = root; - return 0; -fail: - sqfs_dir_tree_destroy(root); - return ret; -} -- cgit v1.2.3