Skip to content

Commit

Permalink
easy: add a function to list directory paths
Browse files Browse the repository at this point in the history
This change adds `sqsh_easy_directory_list_path()`, a function to list
the contents of a directory as a list of file paths. This enables the
user to get a list of paths that can be directly passed to other easy
functions like `sqsh_easy_file_content()`.

This change also adds a test for the new function.
  • Loading branch information
Gottox committed Nov 4, 2023
1 parent feb317f commit 6ea3711
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 2 deletions.
16 changes: 15 additions & 1 deletion include/sqsh_easy.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ sqsh_easy_file_mtime(struct SqshArchive *archive, const char *path, int *err);
*/

/**
* @brief retrieves the contents of a directory.
* @brief retrieves the contents of a directory as a list of file names
*
* The returned list needs to be released with `free()`.
*
Expand All @@ -132,6 +132,20 @@ sqsh_easy_file_mtime(struct SqshArchive *archive, const char *path, int *err);
char **sqsh_easy_directory_list(
struct SqshArchive *archive, const char *path, int *err);

/**
* @brief retrieves the contents of a directory as a list of file paths
*
* The returned list needs to be released with `free()`.
*
* @param[in] archive The sqsh archive context.
* @param[in] path The path the file or directory.
* @param[out] err Pointer to an int where the error code will be stored.
*
* @return A list of files and directories on success, NULL on error.
*/
char **sqsh_easy_directory_list_path(
struct SqshArchive *archive, const char *path, int *err);

/***************************************
* easy/xattr.c
*/
Expand Down
83 changes: 82 additions & 1 deletion libsqsh/src/easy/directory.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
* @file file.c
*/

#include <stdint.h>
#define _DEFAULT_SOURCE

#include <sqsh_easy.h>
Expand All @@ -46,6 +45,88 @@
#include <sqsh_file_private.h>
#include <sqsh_tree_private.h>

struct DirectoryIterator {
struct SqshDirectoryIterator dir;
const char *path;
size_t path_size;
struct CxBuffer value;
};

static int
directory_path_collector_next(
void *iterator, const char **value, size_t *size) {
struct DirectoryIterator *it = iterator;
int rv = 0;
if (sqsh_directory_iterator_next(&it->dir, &rv)) {
cx_buffer_drain(&it->value);
rv = cx_buffer_append(
&it->value, (const uint8_t *)it->path, it->path_size);
if (rv < 0) {
goto out;

Check warning on line 65 in libsqsh/src/easy/directory.c

View check run for this annotation

Codecov / codecov/patch

libsqsh/src/easy/directory.c#L65

Added line #L65 was not covered by tests
}
rv = cx_buffer_append(&it->value, (const uint8_t *)"/", 1);
if (rv < 0) {
goto out;

Check warning on line 69 in libsqsh/src/easy/directory.c

View check run for this annotation

Codecov / codecov/patch

libsqsh/src/easy/directory.c#L69

Added line #L69 was not covered by tests
}
rv = cx_buffer_append(
&it->value,
(const uint8_t *)sqsh_directory_iterator_name(&it->dir),
(size_t)sqsh_directory_iterator_name_size(&it->dir));
if (rv < 0) {
goto out;

Check warning on line 76 in libsqsh/src/easy/directory.c

View check run for this annotation

Codecov / codecov/patch

libsqsh/src/easy/directory.c#L76

Added line #L76 was not covered by tests
}
*value = (const char *)cx_buffer_data(&it->value);
*size = cx_buffer_size(&it->value);
}
out:
return rv;
}

char **
sqsh_easy_directory_list_path(
struct SqshArchive *archive, const char *path, int *err) {
int rv = 0;
struct SqshFile *file = NULL;
struct DirectoryIterator iterator = {0};
char **list = NULL;

file = sqsh_open(archive, path, &rv);
if (rv < 0) {
goto out;

Check warning on line 95 in libsqsh/src/easy/directory.c

View check run for this annotation

Codecov / codecov/patch

libsqsh/src/easy/directory.c#L95

Added line #L95 was not covered by tests
}

rv = sqsh__directory_iterator_init(&iterator.dir, file);
if (rv < 0) {
goto out;

Check warning on line 100 in libsqsh/src/easy/directory.c

View check run for this annotation

Codecov / codecov/patch

libsqsh/src/easy/directory.c#L100

Added line #L100 was not covered by tests
}

rv = cx_buffer_init(&iterator.value);
if (rv < 0) {
goto out;

Check warning on line 105 in libsqsh/src/easy/directory.c

View check run for this annotation

Codecov / codecov/patch

libsqsh/src/easy/directory.c#L105

Added line #L105 was not covered by tests
}

iterator.path = path;
iterator.path_size = strlen(path);
while (iterator.path_size > 0 &&
iterator.path[iterator.path_size - 1] == '/') {
iterator.path_size--;
}

rv = cx_collect(&list, directory_path_collector_next, &iterator.dir);
if (rv < 0) {
goto out;

Check warning on line 117 in libsqsh/src/easy/directory.c

View check run for this annotation

Codecov / codecov/patch

libsqsh/src/easy/directory.c#L117

Added line #L117 was not covered by tests
}

out:
cx_buffer_cleanup(&iterator.value);
sqsh__directory_iterator_cleanup(&iterator.dir);
sqsh_close(file);
if (err) {
*err = rv;
}
return list;
}

static int
directory_collector_next(void *iterator, const char **value, size_t *size) {
int rv = 0;
Expand Down
42 changes: 42 additions & 0 deletions test/libsqsh/easy/directory.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,48 @@ list_two_files(void) {
sqsh__archive_cleanup(&archive);
}

static void
list_two_paths(void) {
int rv = 0;
struct SqshArchive archive = {0};
uint8_t payload[] = {
/* clang-format off */
SQSH_HEADER,
/* inode */
[INODE_TABLE_OFFSET] = METABLOCK_HEADER(0, 1024),
INODE_HEADER(1, 0, 0, 0, 0, 1),
INODE_BASIC_DIR(0, 33, 0, 0),
[INODE_TABLE_OFFSET+2+128] =
INODE_HEADER(3, 0, 0, 0, 0, 2),
INODE_BASIC_SYMLINK(3),
't', 'g', 't',
[INODE_TABLE_OFFSET+2+256] =
INODE_HEADER(2, 0, 0, 0, 0, 3),
INODE_BASIC_FILE(0, 0xFFFFFFFF, 0, 0),
[DIRECTORY_TABLE_OFFSET] = METABLOCK_HEADER(0, 128),
DIRECTORY_HEADER(2, 0, 0),
DIRECTORY_ENTRY(128, 2, 3, 1),
'1',
DIRECTORY_ENTRY(256, 3, 2, 1),
'2',
[FRAGMENT_TABLE_OFFSET] = 0,
/* clang-format on */
};
mk_stub(&archive, payload, sizeof(payload));

char **dir_list = sqsh_easy_directory_list_path(&archive, "/", &rv);
assert(rv == 0);
assert(dir_list != NULL);

assert(strcmp(dir_list[0], "/1") == 0);
assert(strcmp(dir_list[1], "/2") == 0);
assert(dir_list[2] == NULL);

free(dir_list);
sqsh__archive_cleanup(&archive);
}

DECLARE_TESTS
TEST(list_two_files)
TEST(list_two_paths)
END_TESTS

0 comments on commit 6ea3711

Please sign in to comment.