From 153d85864ebe738ca25e228e03111fd7c78ef208 Mon Sep 17 00:00:00 2001 From: Enno Boland Date: Tue, 28 May 2024 13:45:32 +0200 Subject: [PATCH 1/4] traversal: remove leading slash from paths --- libsqsh/src/tree/traversal.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libsqsh/src/tree/traversal.c b/libsqsh/src/tree/traversal.c index 16a5d52e..ec6bbd2f 100644 --- a/libsqsh/src/tree/traversal.c +++ b/libsqsh/src/tree/traversal.c @@ -312,7 +312,9 @@ sqsh_tree_traversal_path_dup(const struct SqshTreeTraversal *traversal) { const size_t count = sqsh_tree_traversal_depth(traversal); for (sqsh_index_t i = 0; i < count; i++) { - rv = cx_buffer_append(&buffer, (const uint8_t *)"/", 1); + if (i > 0) { + rv = cx_buffer_append(&buffer, (const uint8_t *)"/", 1); + } if (rv < 0) { goto out; } From 1b89f3c393bed32346b50655e3d7e52812401620 Mon Sep 17 00:00:00 2001 From: Enno Boland Date: Thu, 16 May 2024 15:02:21 +0200 Subject: [PATCH 2/4] easy: add method for file tree traversal --- include/sqsh_easy.h | 7 ++ libsqsh/src/easy/traversal.c | 122 +++++++++++++++++++++++++++++++++++ libsqsh/src/meson.build | 1 + 3 files changed, 130 insertions(+) create mode 100644 libsqsh/src/easy/traversal.c diff --git a/include/sqsh_easy.h b/include/sqsh_easy.h index 352f545c..29a87e40 100644 --- a/include/sqsh_easy.h +++ b/include/sqsh_easy.h @@ -146,6 +146,13 @@ char **sqsh_easy_directory_list( char **sqsh_easy_directory_list_path( struct SqshArchive *archive, const char *path, int *err); +/*************************************** + * easy/traversal.c + */ + +char **sqsh_easy_tree_traversal( + struct SqshArchive *archive, const char *path, int *err); + /*************************************** * easy/xattr.c */ diff --git a/libsqsh/src/easy/traversal.c b/libsqsh/src/easy/traversal.c new file mode 100644 index 00000000..706a4ff6 --- /dev/null +++ b/libsqsh/src/easy/traversal.c @@ -0,0 +1,122 @@ +/****************************************************************************** + * * + * Copyright (c) 2023-2024, Enno Boland * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are * + * met: * + * * + * * Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + ******************************************************************************/ + +/** + * @author Enno Boland (mail@eboland.de) + * @file directory.c + */ + +#include "sqsh_tree.h" +#define _DEFAULT_SOURCE + +#include + +#include +#include +#include + +#include +#include + +struct TreeTraversalIterator { + struct SqshTreeTraversal traversal; + char *value; +}; + +static int +tree_traversal_collector_next( + void *iterator, const char **value, size_t *size) { + struct TreeTraversalIterator *it = iterator; + int rv = 0; + free(it->value); + + while (sqsh_tree_traversal_next(&it->traversal, &rv)) { + enum SqshTreeTraversalState state = + sqsh_tree_traversal_state(&it->traversal); + if (state != SQSH_TREE_TRAVERSAL_STATE_FILE && + state != SQSH_TREE_TRAVERSAL_STATE_DIRECTORY_BEGIN) { + continue; + } + + it->value = sqsh_tree_traversal_path_dup(&it->traversal); + if (it->value == NULL) { + rv = -SQSH_ERROR_MALLOC_FAILED; + goto out; + } + *value = it->value; + *size = strlen(*value); + break; + } + +out: + return rv; +} + +char ** +sqsh_easy_tree_traversal( + struct SqshArchive *archive, const char *path, int *err) { + int rv = 0; + struct SqshFile *file = NULL; + struct TreeTraversalIterator iterator = {0}; + char **list = NULL; + + file = sqsh_open(archive, path, &rv); + if (rv < 0) { + goto out; + } + + if (sqsh_file_type(file) != SQSH_FILE_TYPE_DIRECTORY) { + rv = -SQSH_ERROR_NOT_A_DIRECTORY; + goto out; + } + + rv = sqsh__tree_traversal_init(&iterator.traversal, 0, file); + if (rv < 0) { + goto out; + } + + // Drop the root path + bool has_next = sqsh_tree_traversal_next(&iterator.traversal, &rv); + if (has_next == false) { + rv = -SQSH_ERROR_INTERNAL; + goto out; + } + + rv = cx_collect(&list, tree_traversal_collector_next, &iterator); + if (rv < 0) { + goto out; + } + +out: + sqsh__tree_traversal_cleanup(&iterator.traversal); + sqsh_close(file); + if (err) { + *err = rv; + } + return list; +} diff --git a/libsqsh/src/meson.build b/libsqsh/src/meson.build index 9c4ff465..284208fa 100644 --- a/libsqsh/src/meson.build +++ b/libsqsh/src/meson.build @@ -8,6 +8,7 @@ libsqsh_sources = files( 'directory/directory_iterator.c', 'easy/directory.c', 'easy/file.c', + 'easy/traversal.c', 'easy/xattr.c', 'extract/extract_manager.c', 'extract/extract_view.c', From f4cb9c108cad62fab64f8a6c2984411e0c4bdf15 Mon Sep 17 00:00:00 2001 From: Enno Boland Date: Thu, 16 May 2024 15:03:31 +0200 Subject: [PATCH 3/4] examples: add example for new easy tree traverse API. --- examples/meson.build | 6 ++++++ examples/traverse_dir.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 examples/traverse_dir.c diff --git a/examples/meson.build b/examples/meson.build index cf3bbcbd..77cd5530 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -10,6 +10,12 @@ executable( install: false, dependencies: libsqsh_dep, ) +executable( + 'traverse_dir', + 'traverse_dir.c', + install: false, + dependencies: libsqsh_dep, +) executable( 'traverse_dir_ll', 'traverse_dir_ll.c', diff --git a/examples/traverse_dir.c b/examples/traverse_dir.c new file mode 100644 index 00000000..410e9839 --- /dev/null +++ b/examples/traverse_dir.c @@ -0,0 +1,33 @@ +/** + * @author Enno Boland (mail@eboland.de) + * @file list_dir.c + * + * This is an example program that lists the top level files in a squashfs + * archive. + */ + +#include +#include +#include +#include + +int +main(int argc, char *argv[]) { + if (argc != 2) { + printf("Usage: %s \n", argv[0]); + return 1; + } + struct SqshArchive *archive = sqsh_archive_open(argv[1], NULL, NULL); + assert(archive != NULL); + + char **dir_list = sqsh_easy_tree_traversal(archive, "/xfce-extra", NULL); + assert(dir_list != NULL); + + for (int i = 0; dir_list[i] != NULL; i++) { + puts(dir_list[i]); + } + + free(dir_list); + sqsh_archive_close(archive); + return 0; +} From f4130791fbde4f438441ae099edc8da863effa80 Mon Sep 17 00:00:00 2001 From: Enno Boland Date: Tue, 28 May 2024 13:11:38 +0200 Subject: [PATCH 4/4] test: add check for easy tree traversal --- test/libsqsh/integration.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/test/libsqsh/integration.c b/test/libsqsh/integration.c index 9546eadd..6f08f8af 100644 --- a/test/libsqsh/integration.c +++ b/test/libsqsh/integration.c @@ -638,4 +638,31 @@ UTEST(integration, test_tree_traversal) { ASSERT_EQ(0, rv); } +UTEST(integration, test_easy_traversal) { + int rv; + struct SqshArchive sqsh = {0}; + struct SqshFile *file = NULL; + char **traversal = NULL; + + struct SqshConfig config = DEFAULT_CONFIG(TEST_SQUASHFS_IMAGE_LEN); + config.archive_offset = 1010; + rv = sqsh__archive_init(&sqsh, (char *)TEST_SQUASHFS_IMAGE, &config); + ASSERT_EQ(0, rv); + + traversal = sqsh_easy_tree_traversal(&sqsh, "/", &rv); + ASSERT_EQ(0, rv); + + ASSERT_STREQ("a", traversal[0]); + ASSERT_STREQ("b", traversal[1]); + ASSERT_STREQ("large_dir", traversal[2]); + ASSERT_STREQ("large_dir/1", traversal[3]); + ASSERT_STREQ("large_dir/10", traversal[4]); + + free(traversal); + rv = sqsh_close(file); + + rv = sqsh__archive_cleanup(&sqsh); + ASSERT_EQ(0, rv); +} + UTEST_MAIN()