aboutsummaryrefslogtreecommitdiff
path: root/lib/sqfs/test/rec_dir.c
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2023-07-18 20:44:01 +0200
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2023-08-10 09:28:27 +0200
commit9d431639effb4e33169110031a689fd1e9d435cf (patch)
tree21786f15f3336fa0a4d73272b6ea142996741279 /lib/sqfs/test/rec_dir.c
parent0a1d93062463133e6f40e3398c0fe53371c47ab0 (diff)
Split recursive directory iterator
The recursive part and the filter part are split up, the recursive iterator wrapper is moved into libsquashfs and the libio iterator is modified to use that internally instead of implementig the recursion step. Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib/sqfs/test/rec_dir.c')
-rw-r--r--lib/sqfs/test/rec_dir.c237
1 files changed, 237 insertions, 0 deletions
diff --git a/lib/sqfs/test/rec_dir.c b/lib/sqfs/test/rec_dir.c
new file mode 100644
index 0000000..00e38aa
--- /dev/null
+++ b/lib/sqfs/test/rec_dir.c
@@ -0,0 +1,237 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+/*
+ * rec_dir.c
+ *
+ * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
+ */
+#include "config.h"
+
+#include "util/test.h"
+#include "sqfs/dir_entry.h"
+#include "sqfs/inode.h"
+#include "sqfs/io.h"
+#include "compat.h"
+
+typedef struct {
+ sqfs_dir_iterator_t obj;
+
+ bool current_is_dir;
+ size_t level;
+ size_t idx;
+} dummy_it_t;
+
+static int dummy_read_link(sqfs_dir_iterator_t *it, char **out)
+{
+ (void)it; (void)out;
+ TEST_ASSERT(0);
+ return 0;
+}
+
+static void dummy_ignore_subdir(sqfs_dir_iterator_t *it)
+{
+ (void)it;
+ TEST_ASSERT(0);
+}
+
+static int dummy_open_file_ro(sqfs_dir_iterator_t *it, sqfs_istream_t **out)
+{
+ (void)it; (void)out;
+ TEST_ASSERT(0);
+ return 0;
+}
+
+static int dummy_read_xattr(sqfs_dir_iterator_t *it, sqfs_xattr_t **out)
+{
+ (void)it; (void)out;
+ TEST_ASSERT(0);
+ return 0;
+}
+
+static void destroy(sqfs_object_t *obj)
+{
+ free(obj);
+}
+
+static int dummy_next(sqfs_dir_iterator_t *base, sqfs_dir_entry_t **out)
+{
+ dummy_it_t *it = (dummy_it_t *)base;
+ char buffer[3];
+
+ *out = NULL;
+ if (it->idx >= 4)
+ return 1;
+
+ buffer[0] = 'a' + it->idx;
+ buffer[1] = 'A' + it->idx;
+ buffer[2] = '\0';
+
+ if ((it->idx % 2) != 0 && it->level < 2) {
+ *out = sqfs_dir_entry_create(buffer,
+ SQFS_INODE_MODE_DIR | 0755, 0);
+ it->current_is_dir = true;
+ } else {
+ *out = sqfs_dir_entry_create(buffer,
+ SQFS_INODE_MODE_REG | 0644, 0);
+ it->current_is_dir = false;
+ }
+
+ it->idx += 1;
+ TEST_NOT_NULL((*out));
+ return 0;
+}
+
+static int dummy_open_subdir(sqfs_dir_iterator_t *base,
+ sqfs_dir_iterator_t **out)
+{
+ dummy_it_t *it = (dummy_it_t *)base, *sub;
+
+ TEST_ASSERT(it->current_is_dir);
+
+ sub = calloc(1, sizeof(*sub));
+ TEST_NOT_NULL(sub);
+ sub->level = it->level + 1;
+
+ sqfs_object_init(sub, destroy, NULL);
+ ((sqfs_dir_iterator_t *)sub)->read_link = dummy_read_link;
+ ((sqfs_dir_iterator_t *)sub)->ignore_subdir = dummy_ignore_subdir;
+ ((sqfs_dir_iterator_t *)sub)->open_file_ro = dummy_open_file_ro;
+ ((sqfs_dir_iterator_t *)sub)->read_xattr = dummy_read_xattr;
+ ((sqfs_dir_iterator_t *)sub)->next = dummy_next;
+ ((sqfs_dir_iterator_t *)sub)->open_subdir = dummy_open_subdir;
+
+ *out = (sqfs_dir_iterator_t *)sub;
+ return 0;
+}
+
+static sqfs_dir_iterator_t *mkdummyit(void)
+{
+ dummy_it_t *it = calloc(1, sizeof(*it));
+ TEST_NOT_NULL(it);
+
+ sqfs_object_init(it, destroy, NULL);
+ ((sqfs_dir_iterator_t *)it)->read_link = dummy_read_link;
+ ((sqfs_dir_iterator_t *)it)->ignore_subdir = dummy_ignore_subdir;
+ ((sqfs_dir_iterator_t *)it)->open_file_ro = dummy_open_file_ro;
+ ((sqfs_dir_iterator_t *)it)->read_xattr = dummy_read_xattr;
+ ((sqfs_dir_iterator_t *)it)->next = dummy_next;
+ ((sqfs_dir_iterator_t *)it)->open_subdir = dummy_open_subdir;
+ return (sqfs_dir_iterator_t *)it;
+}
+
+static const struct {
+ const char *name;
+ bool isdir;
+} expect[] = {
+ { "aA", false },
+ { "bB", true },
+ { "bB/aA", false },
+ { "bB/bB", true },
+ { "bB/bB/aA", false },
+ { "bB/bB/bB", false },
+ { "bB/bB/cC", false },
+ { "bB/bB/dD", false },
+ { "bB/cC", false },
+ { "bB/dD", true },
+ { "bB/dD/aA", false },
+ { "bB/dD/bB", false },
+ { "bB/dD/cC", false },
+ { "bB/dD/dD", false },
+ { "cC", false },
+ { "dD", true },
+ { "dD/aA", false },
+ { "dD/bB", true },
+ { "dD/bB/aA", false },
+ { "dD/bB/bB", false },
+ { "dD/bB/cC", false },
+ { "dD/bB/dD", false },
+ { "dD/cC", false },
+ { "dD/dD", true },
+ { "dD/dD/aA", false },
+ { "dD/dD/bB", false },
+ { "dD/dD/cC", false },
+ { "dD/dD/dD", false },
+};
+
+int main(int argc, char **argv)
+{
+ sqfs_dir_iterator_t *it, *rec;
+ sqfs_dir_entry_t *ent;
+ int ret;
+ (void)argc; (void)argv;
+
+ /* simple test of the dummy iterator */
+ it = mkdummyit();
+
+ ret = it->next(it, &ent);
+ TEST_EQUAL_I(ret, 0);
+ TEST_STR_EQUAL(ent->name, "aA");
+ TEST_ASSERT(S_ISREG(ent->mode));
+ free(ent);
+
+ ret = it->next(it, &ent);
+ TEST_EQUAL_I(ret, 0);
+ TEST_STR_EQUAL(ent->name, "bB");
+ TEST_ASSERT(S_ISDIR(ent->mode));
+ free(ent);
+
+ ret = it->next(it, &ent);
+ TEST_EQUAL_I(ret, 0);
+ TEST_STR_EQUAL(ent->name, "cC");
+ TEST_ASSERT(S_ISREG(ent->mode));
+ free(ent);
+
+ ret = it->next(it, &ent);
+ TEST_EQUAL_I(ret, 0);
+ TEST_STR_EQUAL(ent->name, "dD");
+ TEST_ASSERT(S_ISDIR(ent->mode));
+ free(ent);
+
+ ret = it->next(it, &ent);
+ TEST_EQUAL_I(ret, 1);
+ TEST_NULL(ent);
+
+ sqfs_drop(it);
+
+ /* construct recursive iterator */
+ it = mkdummyit();
+
+ ret = sqfs_dir_iterator_create_recursive(&rec, it);
+ sqfs_drop(it);
+ TEST_EQUAL_I(ret, 0);
+ TEST_NOT_NULL(rec);
+ it = rec;
+
+ for (size_t i = 0; i < sizeof(expect) / sizeof(expect[0]); ++i) {
+ ret = it->next(it, &ent);
+ TEST_EQUAL_I(ret, 0);
+
+ if (strcmp(ent->name, expect[i].name) != 0) {
+ fprintf(stderr,
+ "Entry %u should be `%s`, but is `%s`\n",
+ (unsigned int)i, expect[i].name, ent->name);
+ return EXIT_FAILURE;
+ }
+
+ if (expect[i].isdir && !S_ISDIR(ent->mode)) {
+ fprintf(stderr,
+ "Entry %u (`%s`) should be dir: "
+ "mode is `%u`\n",
+ (unsigned int)i, ent->name, ent->mode);
+ return EXIT_FAILURE;
+ } else if (!expect[i].isdir && !S_ISREG(ent->mode)) {
+ fprintf(stderr,
+ "Entry %u (`%s`) should be file: "
+ "mode is `%u`\n",
+ (unsigned int)i, ent->name, ent->mode);
+ return EXIT_FAILURE;
+ }
+
+ free(ent);
+ }
+
+ ret = it->next(it, &ent);
+ TEST_EQUAL_I(ret, 1);
+
+ sqfs_drop(it);
+ return EXIT_SUCCESS;
+}