aboutsummaryrefslogtreecommitdiff
path: root/lib/sqfs/src/readdir.c
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2023-01-31 11:21:30 +0100
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2023-01-31 13:51:49 +0100
commitcdccc69c62579b0c13b35fad0728079652b8f3c9 (patch)
tree9fa54c710f73c5e08a9c8466e7a712eb63ee07ac /lib/sqfs/src/readdir.c
parent2182129c8f359c4fa1390eaba7a65b595ccd4182 (diff)
Move library source into src sub-directory
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib/sqfs/src/readdir.c')
-rw-r--r--lib/sqfs/src/readdir.c161
1 files changed, 161 insertions, 0 deletions
diff --git a/lib/sqfs/src/readdir.c b/lib/sqfs/src/readdir.c
new file mode 100644
index 0000000..e2dbcd4
--- /dev/null
+++ b/lib/sqfs/src/readdir.c
@@ -0,0 +1,161 @@
+/* SPDX-License-Identifier: LGPL-3.0-or-later */
+/*
+ * readdir.c
+ *
+ * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
+ */
+#define SQFS_BUILDING_DLL
+#include "config.h"
+
+#include "sqfs/meta_reader.h"
+#include "sqfs/error.h"
+#include "sqfs/super.h"
+#include "sqfs/inode.h"
+#include "sqfs/dir.h"
+#include "compat.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+int sqfs_meta_reader_read_dir_header(sqfs_meta_reader_t *m,
+ sqfs_dir_header_t *hdr)
+{
+ int err = sqfs_meta_reader_read(m, hdr, sizeof(*hdr));
+ if (err)
+ return err;
+
+ hdr->count = le32toh(hdr->count);
+ hdr->start_block = le32toh(hdr->start_block);
+ hdr->inode_number = le32toh(hdr->inode_number);
+
+ if (hdr->count > (SQFS_MAX_DIR_ENT - 1))
+ return SQFS_ERROR_CORRUPTED;
+
+ return 0;
+}
+
+int sqfs_meta_reader_read_dir_ent(sqfs_meta_reader_t *m,
+ sqfs_dir_entry_t **result)
+{
+ sqfs_dir_entry_t ent, *out;
+ sqfs_u16 *diff_u16;
+ int err;
+
+ err = sqfs_meta_reader_read(m, &ent, sizeof(ent));
+ if (err)
+ return err;
+
+ diff_u16 = (sqfs_u16 *)&ent.inode_diff;
+ *diff_u16 = le16toh(*diff_u16);
+
+ ent.offset = le16toh(ent.offset);
+ ent.type = le16toh(ent.type);
+ ent.size = le16toh(ent.size);
+
+ out = calloc(1, sizeof(*out) + ent.size + 2);
+ if (out == NULL)
+ return SQFS_ERROR_ALLOC;
+
+ *out = ent;
+ err = sqfs_meta_reader_read(m, out->name, ent.size + 1);
+ if (err) {
+ free(out);
+ return err;
+ }
+
+ *result = out;
+ return 0;
+}
+
+int sqfs_readdir_state_init(sqfs_readdir_state_t *s, const sqfs_super_t *super,
+ const sqfs_inode_generic_t *inode)
+{
+ memset(s, 0, sizeof(*s));
+
+ if (inode->base.type == SQFS_INODE_DIR) {
+ s->init.block = inode->data.dir.start_block;
+ s->init.offset = inode->data.dir.offset;
+ s->init.size = inode->data.dir.size;
+ } else if (inode->base.type == SQFS_INODE_EXT_DIR) {
+ s->init.block = inode->data.dir_ext.start_block;
+ s->init.offset = inode->data.dir_ext.offset;
+ s->init.size = inode->data.dir_ext.size;
+ } else {
+ return SQFS_ERROR_NOT_DIR;
+ }
+
+ s->init.block += super->directory_table_start;
+ s->current = s->init;
+ return 0;
+}
+
+int sqfs_meta_reader_readdir(sqfs_meta_reader_t *m, sqfs_readdir_state_t *it,
+ sqfs_dir_entry_t **ent,
+ sqfs_u32 *inum, sqfs_u64 *iref)
+{
+ size_t count;
+ int ret;
+
+ if (it->entries == 0) {
+ sqfs_dir_header_t hdr;
+
+ if (it->current.size <= sizeof(hdr))
+ goto out_eof;
+
+ ret = sqfs_meta_reader_seek(m, it->current.block,
+ it->current.offset);
+ if (ret != 0)
+ return ret;
+
+ ret = sqfs_meta_reader_read_dir_header(m, &hdr);
+ if (ret != 0)
+ return ret;
+
+ sqfs_meta_reader_get_position(m, &it->current.block,
+ &it->current.offset);
+
+ it->current.size -= sizeof(hdr);
+ it->entries = hdr.count + 1;
+ it->inum_base = hdr.inode_number;
+ it->inode_block = hdr.start_block;
+ }
+
+ if (it->current.size <= sizeof(**ent))
+ goto out_eof;
+
+ ret = sqfs_meta_reader_seek(m, it->current.block, it->current.offset);
+ if (ret != 0)
+ return ret;
+
+ ret = sqfs_meta_reader_read_dir_ent(m, ent);
+ if (ret)
+ return ret;
+
+ sqfs_meta_reader_get_position(m, &it->current.block,
+ &it->current.offset);
+
+ it->current.size -= sizeof(**ent);
+ it->entries -= 1;
+
+ count = (*ent)->size + 1;
+
+ if (count >= it->current.size) {
+ it->current.size = 0;
+ } else {
+ it->current.size -= count;
+ }
+
+ if (inum != NULL)
+ *inum = it->inum_base + (*ent)->inode_diff;
+
+ if (iref != NULL) {
+ *iref = (sqfs_u64)it->inode_block << 16UL;
+ *iref |= (*ent)->offset;
+ }
+
+ return 0;
+out_eof:
+ it->current.size = 0;
+ it->entries = 0;
+ return 1;
+}