From 273a5ef517dd6c3f8b795b1dacf40d5a83acbbcc Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Fri, 15 Sep 2023 21:43:36 +0200 Subject: libsqfs: Add a SquashFS implementation of the dir_iterator_t Signed-off-by: David Oberhollenzer --- include/sqfs/io.h | 24 ++++ lib/sqfs/Makemodule.am | 2 +- lib/sqfs/src/dir_iterator.c | 267 ++++++++++++++++++++++++++++++++++++++++++++ lib/sqfs/src/dir_reader.c | 2 - 4 files changed, 292 insertions(+), 3 deletions(-) create mode 100644 lib/sqfs/src/dir_iterator.c diff --git a/include/sqfs/io.h b/include/sqfs/io.h index 91343d6..ce20da2 100644 --- a/include/sqfs/io.h +++ b/include/sqfs/io.h @@ -673,6 +673,30 @@ SQFS_API int sqfs_dir_iterator_create_recursive(sqfs_dir_iterator_t **out, SQFS_API int sqfs_hard_link_filter_create(sqfs_dir_iterator_t **out, sqfs_dir_iterator_t *base); +/** + * @brief Create a directory iterator + * + * @memberof sqfs_dir_iterator_t + * + * @param rd A pointer to a directory reader + * @param id A pointer to an ID table + * @param data An optional pointer to a data reader. If this is NULL, the + * iterator cannot open files. + * @param xattr An optional pointer to an xattr reader. If this is NULL, the + * iterator will pretend that entries do not have extended + * attibutes. + * @param inode A pointer to a directory inode to open. + * @param out Returns a pointer to a iterator implementation on success. + * + * @return Zero on success, an @ref SQFS_ERROR code on failure. + */ +SQFS_API int sqfs_dir_iterator_create(sqfs_dir_reader_t *rd, + sqfs_id_table_t *id, + sqfs_data_reader_t *data, + sqfs_xattr_reader_t *xattr, + const sqfs_inode_generic_t *inode, + sqfs_dir_iterator_t **out); + #ifdef __cplusplus } #endif diff --git a/lib/sqfs/Makemodule.am b/lib/sqfs/Makemodule.am index 14fa215..b40473e 100644 --- a/lib/sqfs/Makemodule.am +++ b/lib/sqfs/Makemodule.am @@ -19,7 +19,7 @@ libsquashfs_la_SOURCES = $(LIBSQFS_HEARDS) lib/sqfs/src/id_table.c \ lib/sqfs/src/dir_writer.c lib/sqfs/src/xattr/xattr_reader.c \ lib/sqfs/src/read_table.c lib/sqfs/src/comp/compressor.c \ lib/sqfs/src/comp/internal.h lib/sqfs/src/dir_reader.c \ - lib/sqfs/src/inode.c \ + lib/sqfs/src/inode.c lib/sqfs/src/dir_iterator.c \ lib/sqfs/src/xattr/xattr_writer.c \ lib/sqfs/src/xattr/xattr_writer_flush.c \ lib/sqfs/src/xattr/xattr_writer_record.c \ diff --git a/lib/sqfs/src/dir_iterator.c b/lib/sqfs/src/dir_iterator.c new file mode 100644 index 0000000..3e1f63a --- /dev/null +++ b/lib/sqfs/src/dir_iterator.c @@ -0,0 +1,267 @@ +/* SPDX-License-Identifier: LGPL-3.0-or-later */ +/* + * dir_iterator.c + * + * Copyright (C) 2023 David Oberhollenzer + */ +#define SQFS_BUILDING_DLL +#include "sqfs/dir_reader.h" +#include "sqfs/xattr_reader.h" +#include "sqfs/dir_entry.h" +#include "sqfs/error.h" +#include "sqfs/inode.h" +#include "sqfs/id_table.h" +#include "sqfs/data_reader.h" +#include "sqfs/dir.h" +#include "sqfs/io.h" + +#include "util/util.h" + +#include +#include + +typedef struct { + sqfs_dir_iterator_t base; + + sqfs_dir_reader_state_t state; + + sqfs_u32 xattr_idx; + sqfs_inode_generic_t *inode; + sqfs_dir_node_t *dent; + + sqfs_xattr_reader_t *xattr; + sqfs_data_reader_t *data; + sqfs_dir_reader_t *rd; + sqfs_id_table_t *id; +} iterator_t; + +static int it_next(sqfs_dir_iterator_t *base, sqfs_dir_entry_t **out) +{ + iterator_t *it = (iterator_t *)base; + sqfs_dir_entry_t *ent = NULL; + sqfs_u32 uid, gid; + int ret; + + sqfs_free(it->inode); + sqfs_free(it->dent); + it->inode = NULL; + it->dent = NULL; + + ret = sqfs_dir_reader_read(it->rd, &it->state, &it->dent); + if (ret != 0) + return ret; + + ret = sqfs_dir_reader_get_inode(it->rd, it->state.ent_ref, &it->inode); + if (ret != 0) + goto fail; + + ret = SQFS_ERROR_ALLOC; + ent = alloc_flex(sizeof(*ent), 1, it->dent->size + 2); + if (ent == NULL) + goto fail; + + ret = SQFS_ERROR_CORRUPTED; + if (sqfs_id_table_index_to_id(it->id, it->inode->base.uid_idx, &uid)) + goto fail; + + if (sqfs_id_table_index_to_id(it->id, it->inode->base.gid_idx, &gid)) + goto fail; + + memcpy(ent->name, it->dent->name, it->dent->size + 1); + + ent->mode = it->inode->base.mode; + ent->mtime = it->inode->base.mod_time; + ent->uid = uid; + ent->gid = gid; + ent->inode = it->state.ent_ref; + it->xattr_idx = 0xFFFFFFFF; + + switch (it->inode->base.type) { + case SQFS_INODE_BDEV: + case SQFS_INODE_CDEV: + ent->rdev = it->inode->data.dev.devno; + break; + case SQFS_INODE_EXT_BDEV: + case SQFS_INODE_EXT_CDEV: + ent->rdev = it->inode->data.dev_ext.devno; + it->xattr_idx = it->inode->data.dev_ext.xattr_idx; + break; + case SQFS_INODE_FILE: + ent->size = it->inode->data.file.file_size; + break; + case SQFS_INODE_EXT_FILE: + ent->size = it->inode->data.file_ext.file_size; + it->xattr_idx = it->inode->data.file_ext.xattr_idx; + break; + case SQFS_INODE_DIR: + ent->size = it->inode->data.dir.size; + break; + case SQFS_INODE_EXT_DIR: + ent->size = it->inode->data.dir_ext.size; + it->xattr_idx = it->inode->data.dir_ext.xattr_idx; + break; + case SQFS_INODE_SLINK: + ent->size = it->inode->data.slink.target_size; + break; + case SQFS_INODE_EXT_SLINK: + ent->size = it->inode->data.slink_ext.target_size; + it->xattr_idx = it->inode->data.slink_ext.xattr_idx; + break; + case SQFS_INODE_EXT_FIFO: + case SQFS_INODE_EXT_SOCKET: + it->xattr_idx = it->inode->data.ipc_ext.xattr_idx; + break; + default: + break; + } + + *out = ent; + return 0; +fail: + sqfs_free(it->inode); + sqfs_free(it->dent); + sqfs_free(ent); + it->inode = NULL; + it->dent = NULL; + return ret; +} + +static int it_read_link(sqfs_dir_iterator_t *base, char **out) +{ + iterator_t *it = (iterator_t *)base; + size_t size; + + *out = NULL; + + if (it->inode == NULL) + return SQFS_ERROR_NO_ENTRY; + + if (it->inode->base.type == SQFS_INODE_SLINK) { + size = it->inode->data.slink.target_size; + } else if (it->inode->base.type == SQFS_INODE_EXT_SLINK) { + size = it->inode->data.slink.target_size; + } else { + return SQFS_ERROR_NO_ENTRY; + } + + *out = calloc(1, size + 1); + if (*out == NULL) + return SQFS_ERROR_ALLOC; + + memcpy(*out, it->inode->extra, size); + return 0; +} + +static int it_open_subdir(sqfs_dir_iterator_t *base, sqfs_dir_iterator_t **out) +{ + iterator_t *it = (iterator_t *)base; + + *out = NULL; + + if (it->inode == NULL) + return SQFS_ERROR_NO_ENTRY; + + if (it->inode->base.type != SQFS_INODE_DIR && + it->inode->base.type != SQFS_INODE_EXT_DIR) { + return SQFS_ERROR_NOT_DIR; + } + + return sqfs_dir_iterator_create(it->rd, it->id, it->data, it->xattr, + it->inode, out); +} + +static void it_ignore_subdir(sqfs_dir_iterator_t *it) +{ + (void)it; +} + +static int it_open_file_ro(sqfs_dir_iterator_t *base, sqfs_istream_t **out) +{ + iterator_t *it = (iterator_t *)base; + + if (it->inode == NULL) + return SQFS_ERROR_NO_ENTRY; + + if (it->inode->base.type != SQFS_INODE_FILE && + it->inode->base.type != SQFS_INODE_EXT_FILE) { + return SQFS_ERROR_NOT_FILE; + } + + if (it->data == NULL) + return SQFS_ERROR_UNSUPPORTED; + + return sqfs_data_reader_create_stream(it->data, it->inode, + (const char *)it->dent->name, + out); +} + +static int it_read_xattr(sqfs_dir_iterator_t *base, sqfs_xattr_t **out) +{ + iterator_t *it = (iterator_t *)base; + + if (it->inode == NULL) + return SQFS_ERROR_NO_ENTRY; + + if (it->xattr == NULL || it->xattr_idx == 0xFFFFFFFF) + return 0; + + return sqfs_xattr_reader_read_all(it->xattr, it->xattr_idx, out); +} + +static void it_destroy(sqfs_object_t *obj) +{ + iterator_t *it = (iterator_t *)obj; + + sqfs_free(it->inode); + sqfs_free(it->dent); + sqfs_drop(it->id); + sqfs_drop(it->rd); + sqfs_drop(it->data); + sqfs_drop(it->xattr); + sqfs_free(it); +} + +int sqfs_dir_iterator_create(sqfs_dir_reader_t *rd, + sqfs_id_table_t *id, + sqfs_data_reader_t *data, + sqfs_xattr_reader_t *xattr, + const sqfs_inode_generic_t *inode, + sqfs_dir_iterator_t **out) +{ + sqfs_dir_iterator_t *base; + iterator_t *it; + int ret; + + it = calloc(1, sizeof(*it)); + base = (sqfs_dir_iterator_t *)it; + + if (it == NULL) + return SQFS_ERROR_ALLOC; + + sqfs_object_init(it, it_destroy, NULL); + + ret = sqfs_dir_reader_open_dir(rd, inode, &it->state, 0); + if (ret) { + sqfs_free(it); + return ret; + } + + base->next = it_next; + base->read_link = it_read_link; + base->open_subdir = it_open_subdir; + base->ignore_subdir = it_ignore_subdir; + base->open_file_ro = it_open_file_ro; + base->read_xattr = it_read_xattr; + + it->id = sqfs_grab(id); + it->rd = sqfs_grab(rd); + + if (data != NULL) + it->data = sqfs_grab(data); + + if (xattr != NULL) + it->xattr = sqfs_grab(xattr); + + *out = base; + return 0; +} diff --git a/lib/sqfs/src/dir_reader.c b/lib/sqfs/src/dir_reader.c index fdb5976..042b93a 100644 --- a/lib/sqfs/src/dir_reader.c +++ b/lib/sqfs/src/dir_reader.c @@ -7,8 +7,6 @@ #define SQFS_BUILDING_DLL #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" -- cgit v1.2.3