aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2023-09-15 21:43:36 +0200
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2023-09-19 11:45:53 +0200
commit273a5ef517dd6c3f8b795b1dacf40d5a83acbbcc (patch)
tree0ebe593877cbdb339aaca4659244d836aa4a38cb
parentdc28467db83432f19f004bb76f5e8515c71f8d0b (diff)
libsqfs: Add a SquashFS implementation of the dir_iterator_t
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
-rw-r--r--include/sqfs/io.h24
-rw-r--r--lib/sqfs/Makemodule.am2
-rw-r--r--lib/sqfs/src/dir_iterator.c267
-rw-r--r--lib/sqfs/src/dir_reader.c2
4 files changed, 292 insertions, 3 deletions
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 <goliath@infraroot.at>
+ */
+#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 <stdlib.h>
+#include <string.h>
+
+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"