diff options
author | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2023-07-22 14:06:47 +0200 |
---|---|---|
committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2023-09-08 20:49:58 +0200 |
commit | f5e46e0444197deee2eca93d36a8ebeb1ffd7a17 (patch) | |
tree | c445d43cd13d5c2b365755744d1c3770b037f98e /lib/sqfs/test | |
parent | d5e2c6a3146c20354ab11f1dae48ab755996fa96 (diff) |
Add a hard link detecting/filtering directory iterator
The reason this is implemented separately, instead of roling it into
the recursive iterator, is so that we can do additional filtering
in between. For instance, we can rewrite the path and the hard link
path will match up, or if we remove nodes from the hierarchy, we
won't end up with a hard link pointing outside.
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib/sqfs/test')
-rw-r--r-- | lib/sqfs/test/hl_dir.c | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/lib/sqfs/test/hl_dir.c b/lib/sqfs/test/hl_dir.c new file mode 100644 index 0000000..4ff00e8 --- /dev/null +++ b/lib/sqfs/test/hl_dir.c @@ -0,0 +1,215 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * hl_dir.c + * + * Copyright (C) 2023 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; + size_t idx; +} dummy_it_t; + +static const struct { + const char *name; + int dev; + int inum; +} entries[] = { + { "foo", 1, 1 }, + { "bar", 1, 2 }, + { "baz", 1, 3 }, + { "blub", 1, 2 }, + { "a", 2, 2 }, + { "b", 2, 1 }, + { "c", 2, 2 }, +}; + +static int dummy_read_link(sqfs_dir_iterator_t *it, char **out) +{ + (void)it; (void)out; + *out = NULL; + 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 int dummy_open_subdir(sqfs_dir_iterator_t *base, + sqfs_dir_iterator_t **out) +{ + (void)base; (void)out; + TEST_ASSERT(0); + return 0; +} + +static int dummy_next(sqfs_dir_iterator_t *base, sqfs_dir_entry_t **out) +{ + dummy_it_t *it = (dummy_it_t *)base; + const char *name; + int inum, dev; + + if (it->idx >= (sizeof(entries) / sizeof(entries[0]))) + return 1; + + name = entries[it->idx].name; + inum = entries[it->idx].inum; + dev = entries[it->idx].dev; + it->idx += 1; + + *out = sqfs_dir_entry_create(name, SQFS_INODE_MODE_REG | 0644, 0); + TEST_NOT_NULL(*out); + (*out)->inode = inum; + (*out)->dev = dev; + return 0; +} + +static void dummy_destroy(sqfs_object_t *obj) +{ + free(obj); +} + +static sqfs_dir_iterator_t *mkdummyit(void) +{ + dummy_it_t *it = calloc(1, sizeof(*it)); + TEST_NOT_NULL(it); + + sqfs_object_init(it, dummy_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; +} + +int main(int argc, char **argv) +{ + sqfs_dir_iterator_t *base, *it; + sqfs_dir_entry_t *ent; + char *target; + int ret; + (void)argc; (void)argv; + + base = mkdummyit(); + TEST_NOT_NULL(base); + + ret = sqfs_hard_link_filter_create(&it, base); + TEST_EQUAL_I(ret, 0); + TEST_NOT_NULL(it); + TEST_EQUAL_UI(((sqfs_object_t *)base)->refcount, 2); + + ret = it->next(it, &ent); + TEST_EQUAL_I(ret, 0); + TEST_NOT_NULL(&ent); + TEST_STR_EQUAL(ent->name, "foo"); + TEST_ASSERT(S_ISREG(ent->mode)); + TEST_EQUAL_UI(ent->flags, 0); + ret = it->read_link(it, &target); + TEST_EQUAL_I(ret, 0); + TEST_NULL(target); + free(ent); + + ret = it->next(it, &ent); + TEST_EQUAL_I(ret, 0); + TEST_NOT_NULL(&ent); + TEST_STR_EQUAL(ent->name, "bar"); + TEST_ASSERT(S_ISREG(ent->mode)); + TEST_EQUAL_UI(ent->flags, 0); + ret = it->read_link(it, &target); + TEST_EQUAL_I(ret, 0); + TEST_NULL(target); + free(ent); + + ret = it->next(it, &ent); + TEST_EQUAL_I(ret, 0); + TEST_NOT_NULL(&ent); + TEST_STR_EQUAL(ent->name, "baz"); + TEST_ASSERT(S_ISREG(ent->mode)); + TEST_EQUAL_UI(ent->flags, 0); + ret = it->read_link(it, &target); + TEST_EQUAL_I(ret, 0); + TEST_NULL(target); + free(ent); + + ret = it->next(it, &ent); + TEST_EQUAL_I(ret, 0); + TEST_NOT_NULL(&ent); + TEST_STR_EQUAL(ent->name, "blub"); + TEST_EQUAL_UI(ent->flags, SQFS_DIR_ENTRY_FLAG_HARD_LINK); + TEST_ASSERT(S_ISLNK(ent->mode)); + ret = it->read_link(it, &target); + TEST_EQUAL_I(ret, 0); + TEST_NOT_NULL(target); + TEST_STR_EQUAL(target, "bar"); + free(target); + free(ent); + + ret = it->next(it, &ent); + TEST_EQUAL_I(ret, 0); + TEST_NOT_NULL(&ent); + TEST_STR_EQUAL(ent->name, "a"); + TEST_ASSERT(S_ISREG(ent->mode)); + TEST_EQUAL_UI(ent->flags, 0); + ret = it->read_link(it, &target); + TEST_EQUAL_I(ret, 0); + TEST_NULL(target); + free(ent); + + ret = it->next(it, &ent); + TEST_EQUAL_I(ret, 0); + TEST_NOT_NULL(&ent); + TEST_STR_EQUAL(ent->name, "b"); + TEST_ASSERT(S_ISREG(ent->mode)); + TEST_EQUAL_UI(ent->flags, 0); + ret = it->read_link(it, &target); + TEST_EQUAL_I(ret, 0); + TEST_NULL(target); + free(ent); + + ret = it->next(it, &ent); + TEST_EQUAL_I(ret, 0); + TEST_NOT_NULL(&ent); + TEST_STR_EQUAL(ent->name, "c"); + TEST_EQUAL_UI(ent->flags, SQFS_DIR_ENTRY_FLAG_HARD_LINK); + TEST_ASSERT(S_ISLNK(ent->mode)); + ret = it->read_link(it, &target); + TEST_EQUAL_I(ret, 0); + TEST_NOT_NULL(target); + TEST_STR_EQUAL(target, "a"); + free(target); + free(ent); + + ret = it->next(it, &ent); + TEST_EQUAL_I(ret, 1); + TEST_NULL(ent); + it = sqfs_drop(it); + + TEST_EQUAL_UI(((sqfs_object_t *)base)->refcount, 1); + base = sqfs_drop(base); + return EXIT_SUCCESS; +} |