diff --git a/README.md b/README.md index 1350713d..66b84ef3 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ containing a set of command line tools and a C library. * [**fuse2**](https://libfuse.github.io/) *optional*: For mounting squashfs archives on systems that don't support fuse3. e.g. OpenBSD. * [**libcurl**](https://curl.se/) *optional*: For transparently reading squashfs - archives from the internet without downloading them first. + archives from an URL. Note that to do anything useful with *libsqsh*, you need to have at least one of the compression libraries enabled. diff --git a/libmksqsh/include/mksqsh_table.h b/libmksqsh/include/mksqsh_table.h index 0b200126..f0c4d3b9 100644 --- a/libmksqsh/include/mksqsh_table.h +++ b/libmksqsh/include/mksqsh_table.h @@ -97,8 +97,7 @@ struct MksqshIdTable { int mksqsh__id_table_init( struct MksqshIdTable *table, FILE *content_output, FILE *lookup_output); -int mksqsh__id_table_add( - struct MksqshIdTable *table, uint64_t start, uint32_t size); +int mksqsh__id_table_add(struct MksqshIdTable *table, uint32_t id); int mksqsh__id_table_flush(struct MksqshIdTable *table); diff --git a/libmksqsh/src/metablock/metablock_builder.c b/libmksqsh/src/metablock/metablock_builder.c index 91f255ee..ca810cfd 100644 --- a/libmksqsh/src/metablock/metablock_builder.c +++ b/libmksqsh/src/metablock/metablock_builder.c @@ -31,12 +31,12 @@ * @file inode_builder.c */ -#include "sqsh_error.h" #define _DEFAULT_SOURCE #include #include #include +#include #include int @@ -110,6 +110,11 @@ mksqsh__metablock_flush(struct MksqshMetablock *metablock) { return rv; } +bool +mksqsh__metablock_was_flushed(const struct MksqshMetablock *metablock) { + return metablock->flushed; +} + int mksqsh__metablock_cleanup(struct MksqshMetablock *metablock) { (void)metablock; diff --git a/libmksqsh/src/table/id_table_builder.c b/libmksqsh/src/table/id_table_builder.c index e88da12b..1345c0cc 100644 --- a/libmksqsh/src/table/id_table_builder.c +++ b/libmksqsh/src/table/id_table_builder.c @@ -2,20 +2,21 @@ #include #include +#define ENTRY_SIZE sizeof(uint32_t) + int mksqsh__id_table_init( struct MksqshIdTable *table, FILE *content_output, FILE *lookup_output) { - const size_t entry_size = sizeof(uint32_t); return mksqsh__table_init( - &table->table, entry_size, content_output, lookup_output); + &table->table, ENTRY_SIZE, content_output, lookup_output); } int -mksqsh__id_table_write(struct MksqshIdTable *table, uint32_t id) { +mksqsh__id_table_add(struct MksqshIdTable *table, uint32_t id) { uint32_t id_le = CX_CPU_2_LE32(id); - return mksqsh__table_add(&table->table, &id_le, sizeof(id_le)); + return mksqsh__table_add(&table->table, &id_le, ENTRY_SIZE); } int diff --git a/libmksqsh/src/table/table_builder.c b/libmksqsh/src/table/table_builder.c index a356e52d..031974b3 100644 --- a/libmksqsh/src/table/table_builder.c +++ b/libmksqsh/src/table/table_builder.c @@ -39,47 +39,65 @@ #include #include +static int +table_add_lookup(struct MksqshTable *table) { + int rv = 0; + const uint64_t ref = mksqsh__metablock_ref(&table->metablock_writer); + const uint64_t outer_ref = sqsh_address_ref_outer_offset(ref); + const uint64_t outer_ref_le = CX_CPU_2_LE64(outer_ref); + const unsigned long write = + fwrite(&outer_ref_le, sizeof(outer_ref_le), 1, table->output); + if (write != 1) { + rv = -1; // TODO: proper error code + goto out; + } +out: + return rv; +} + int mksqsh__table_init( struct MksqshTable *table, size_t entry_size, FILE *metablock_output, FILE *output) { - assert(0 == entry_size % SQSH_METABLOCK_BLOCK_SIZE); + int rv = 0; + assert(0 == SQSH_METABLOCK_BLOCK_SIZE % entry_size); table->entry_size = entry_size; table->output = output; table->metablock_output = metablock_output; - return mksqsh__metablock_init(&table->metablock_writer, metablock_output); + + rv = mksqsh__metablock_init(&table->metablock_writer, metablock_output); + if (rv < 0) { + goto out; + } + + rv = table_add_lookup(table); + if (rv < 0) { + goto out; + } + +out: + return rv; } int mksqsh__table_add( struct MksqshTable *table, const void *entry, size_t entry_size) { int rv = 0; - (void)table; - (void)entry; - (void)entry_size; assert(entry_size == table->entry_size); - const uint64_t ref = mksqsh__metablock_ref(&table->metablock_writer); - const uint64_t outer_ref = sqsh_address_ref_outer_offset(ref); - const uint64_t inner_ref = - sqsh_address_ref_inner_offset(ref) / table->entry_size; - - const uint64_t current_ref = sqsh_address_ref_create(outer_ref, inner_ref); - table->entry_count += 1; - - const uint64_t current_ref_le = CX_CPU_2_LE64(current_ref); - const unsigned long write = - fwrite(¤t_ref_le, sizeof(current_ref_le), 1, table->output); - if (write != 1) { - rv = -1; // TODO: proper error code - goto out; - } - rv = mksqsh__metablock_write(&table->metablock_writer, entry, entry_size); if (rv < 0) { goto out; } + + if (mksqsh__metablock_was_flushed(&table->metablock_writer)) { + rv = table_add_lookup(table); + if (rv < 0) { + goto out; + } + } + out: return rv; } diff --git a/test/libsqsh/common.h b/test/libsqsh/common.h index b8c57099..fc34256c 100644 --- a/test/libsqsh/common.h +++ b/test/libsqsh/common.h @@ -155,7 +155,7 @@ /* We're using a ridiculously small block size to * test the mappers ability to handle small blocks. */ -#define DEFAULT_BLOCK_SIZE 1 +#define DEFAULT_BLOCK_SIZE ~0 #define DEFAULT_CONFIG(s) \ (struct SqshConfig) { \ diff --git a/test/libsqsh/directory/directory_iterator.c b/test/libsqsh/directory/directory_iterator.c index 28db7627..606378c9 100644 --- a/test/libsqsh/directory/directory_iterator.c +++ b/test/libsqsh/directory/directory_iterator.c @@ -44,7 +44,7 @@ UTEST(directory_iterator, iter_invalid_file_name_with_0) { int rv; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ @@ -80,7 +80,7 @@ UTEST(directory_iterator, iter_invalid_file_name_with_0) { UTEST(directory_iterator, iter_invalid_file_name_with_slash) { int rv; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ @@ -116,7 +116,7 @@ UTEST(directory_iterator, iter_invalid_file_name_with_slash) { UTEST(directory_iterator, iter_two_files) { int rv; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ @@ -179,7 +179,7 @@ UTEST(directory_iterator, iter_two_files) { UTEST(directory_iterator, iter_invalid_file_type) { int rv; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ @@ -210,7 +210,7 @@ UTEST(directory_iterator, iter_invalid_file_type) { UTEST(directory_iterator, iter_inconsistent_file_type) { int rv; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ @@ -254,7 +254,7 @@ UTEST(directory_iterator, iter_inconsistent_file_type) { UTEST(directory_iterator, iter_over_corrupt_header_too_small) { int rv; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ @@ -292,7 +292,7 @@ UTEST(directory_iterator, iter_over_corrupt_header_too_small) { UTEST(directory_iterator, iter_inode_overflow) { int rv; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ @@ -328,7 +328,7 @@ UTEST(directory_iterator, iter_inode_overflow) { UTEST(directory_iterator, iter_inode_underflow) { int rv; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ @@ -364,7 +364,7 @@ UTEST(directory_iterator, iter_inode_underflow) { UTEST(directory_iterator, iter_inode_to_zero) { int rv; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ diff --git a/test/libsqsh/easy/directory.c b/test/libsqsh/easy/directory.c index 7c412a13..76d8e2e5 100644 --- a/test/libsqsh/easy/directory.c +++ b/test/libsqsh/easy/directory.c @@ -42,7 +42,7 @@ UTEST(ease_directory, list_two_files) { int rv = 0; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ @@ -82,7 +82,7 @@ UTEST(ease_directory, list_two_files) { UTEST(ease_directory, list_two_paths) { int rv = 0; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ diff --git a/test/libsqsh/easy/file.c b/test/libsqsh/easy/file.c index 7d3ed1a1..a5bf98fb 100644 --- a/test/libsqsh/easy/file.c +++ b/test/libsqsh/easy/file.c @@ -42,7 +42,7 @@ UTEST(ease_file, test_file_get_content_through_symlink) { struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, [1024] = '1', '2', '3', '4', '5', '6', '7', '8', @@ -80,7 +80,7 @@ UTEST(ease_file, test_file_get_content_through_symlink) { UTEST(ease_file, test_file_exists_through_dead_symlink) { int rv = 0; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, [1024] = '1', '2', '3', '4', '5', '6', '7', '8', @@ -111,7 +111,7 @@ UTEST(ease_file, test_file_exists_through_dead_symlink) { UTEST(ease_file, test_file_exists_through_symlink) { struct SqshArchive archive = {0}; int rv = 0; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, [1024] = '1', '2', '3', '4', '5', '6', '7', '8', @@ -152,7 +152,7 @@ UTEST(ease_file, test_file_exists_through_symlink) { UTEST(ease_file, test_file_size) { struct SqshArchive archive = {0}; int rv = 0; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ @@ -186,7 +186,7 @@ UTEST(ease_file, test_file_size) { UTEST(ease_file, test_file_permission) { struct SqshArchive archive = {0}; int rv = 0; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ @@ -220,7 +220,7 @@ UTEST(ease_file, test_file_permission) { UTEST(ease_file, test_file_mtime) { struct SqshArchive archive = {0}; int rv = 0; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ diff --git a/test/libsqsh/file/file.c b/test/libsqsh/file/file.c index e2d6f7b4..a3663fef 100644 --- a/test/libsqsh/file/file.c +++ b/test/libsqsh/file/file.c @@ -33,6 +33,7 @@ */ #include "../common.h" +#include #include #include @@ -158,7 +159,34 @@ UTEST(file, resolve_unkown_dir_inode) { ASSERT_EQ(-SQSH_ERROR_INODE_PARENT_UNSET, rv); sqsh_close(symlink); + sqsh__archive_cleanup(&archive); +} + +UTEST(file, get_ids) { + int rv; + struct SqshArchive archive = {0}; + struct SqshFile file = {0}; + uint8_t payload[8192] = { + SQSH_HEADER, + /* inode */ + [INODE_TABLE_OFFSET + 15] = METABLOCK_HEADER(0, 128), + INODE_HEADER(2, 0666, 0, 0, 4242, 1), + INODE_BASIC_FILE(1024, 0xFFFFFFFF, 0, 1), + UINT32_BYTES(42), + [ID_TABLE_OFFSET] = UINT64_BYTES(0), + METABLOCK_HEADER(0, 128), + UINT32_BYTES(0), + UINT32_BYTES(0), + }; + mk_stub(&archive, payload, sizeof(payload)); + uint64_t inode_ref = sqsh_address_ref_create(15, 0); + rv = sqsh__file_init(&file, &archive, inode_ref); + ASSERT_EQ(0, rv); + + ASSERT_EQ((uint32_t)123, sqsh_file_gid(&file)); + + sqsh__file_cleanup(&file); sqsh__archive_cleanup(&archive); } diff --git a/test/libsqsh/tree/path_resolver.c b/test/libsqsh/tree/path_resolver.c index 24c2bbff..e853c97c 100644 --- a/test/libsqsh/tree/path_resolver.c +++ b/test/libsqsh/tree/path_resolver.c @@ -42,7 +42,7 @@ UTEST(path_resolver, resolver_symlink_recursion) { int rv; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ @@ -78,7 +78,7 @@ UTEST(path_resolver, resolver_symlink_recursion) { UTEST(path_resolver, resolver_symlink_alternating_recursion) { int rv; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ @@ -117,7 +117,7 @@ UTEST(path_resolver, resolver_symlink_alternating_recursion) { UTEST(path_resolver, resolver_symlink_open) { int rv; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ @@ -250,7 +250,7 @@ UTEST(path_resolver, resolver_file_enter) { UTEST(path_resolver, resolver_directory_enter) { int rv; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ @@ -296,7 +296,7 @@ UTEST(path_resolver, resolver_directory_enter) { UTEST(path_resolver, resolver_uninitialized_up) { int rv; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ @@ -328,7 +328,7 @@ UTEST(path_resolver, resolver_uninitialized_up) { UTEST(path_resolver, resolver_uninitialized_down) { int rv; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ @@ -360,7 +360,7 @@ UTEST(path_resolver, resolver_uninitialized_down) { UTEST(path_resolver, resolver_next) { int rv; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ diff --git a/test/libsqsh/tree/traversal.c b/test/libsqsh/tree/traversal.c index e3ce85c4..dcca66dc 100644 --- a/test/libsqsh/tree/traversal.c +++ b/test/libsqsh/tree/traversal.c @@ -44,7 +44,7 @@ UTEST(traversal, test_recursive_directory) { int rv; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ diff --git a/test/libsqsh/tree/walker.c b/test/libsqsh/tree/walker.c index 43054c68..22ff7732 100644 --- a/test/libsqsh/tree/walker.c +++ b/test/libsqsh/tree/walker.c @@ -42,7 +42,7 @@ UTEST(tree_walker, walker_symlink_recursion) { int rv; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ @@ -75,7 +75,7 @@ UTEST(tree_walker, walker_symlink_recursion) { UTEST(tree_walker, walker_symlink_alternating_recursion) { int rv; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ @@ -113,7 +113,7 @@ UTEST(tree_walker, walker_symlink_alternating_recursion) { UTEST(tree_walker, walker_symlink_open) { int rv; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ @@ -167,7 +167,7 @@ expect_inode(struct SqshTreeWalker *walker, uint32_t inode_number) { UTEST(tree_walker, walker_directory_enter) { int rv; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ @@ -210,7 +210,7 @@ UTEST(tree_walker, walker_directory_enter) { UTEST(tree_walker, walker_uninitialized_up) { int rv; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ @@ -240,7 +240,7 @@ UTEST(tree_walker, walker_uninitialized_up) { UTEST(tree_walker, walker_uninitialized_down) { int rv; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ @@ -270,7 +270,7 @@ UTEST(tree_walker, walker_uninitialized_down) { UTEST(tree_walker, walker_next) { int rv; struct SqshArchive archive = {0}; - uint8_t payload[] = { + uint8_t payload[8192] = { /* clang-format off */ SQSH_HEADER, /* inode */ diff --git a/test/libsqsh/util.c b/test/libsqsh/util.c index 495feea4..43c1f8e2 100644 --- a/test/libsqsh/util.c +++ b/test/libsqsh/util.c @@ -38,6 +38,7 @@ #include "common.h" #include +#include #include #include #include @@ -48,6 +49,7 @@ test_sqsh_prepare_archive(uint8_t *payload, size_t payload_size) { const int compression_id = payload[20] ? payload[20] : SQSH_COMPRESSION_GZIP; struct MksqshSuperblock builder = {0}; + struct MksqshIdTable id_builder = {0}; FILE *fsuperblock = fmemopen(payload, payload_size, "r+"); assert(fsuperblock); rv = mksqsh__superblock_init(&builder); @@ -68,7 +70,7 @@ test_sqsh_prepare_archive(uint8_t *payload, size_t payload_size) { assert(rv == 0); rv = mksqsh__superblock_compression_options(&builder, true); assert(rv == 0); - rv = mksqsh__superblock_id_count(&builder, 0); + rv = mksqsh__superblock_id_count(&builder, 2); assert(rv == 0); rv = mksqsh__superblock_inode_count(&builder, 100); assert(rv == 0); @@ -101,6 +103,29 @@ test_sqsh_prepare_archive(uint8_t *payload, size_t payload_size) { rv = mksqsh__superblock_cleanup(&builder); assert(rv == 0); + FILE *fid_block = fmemopen( + &payload[ID_TABLE_OFFSET], payload_size - ID_TABLE_OFFSET, "r+"); + char *id_block_tmp; + size_t id_block_tmp_size; + FILE *fid_block_tmp = open_memstream(&id_block_tmp, &id_block_tmp_size); + assert(fid_block); + assert(fid_block_tmp); + + rv = mksqsh__id_table_init(&id_builder, fid_block, fid_block_tmp); + assert(rv == 0); + rv = mksqsh__id_table_add(&id_builder, 123); + assert(rv == 0); + rv = mksqsh__id_table_add(&id_builder, 456); + assert(rv == 0); + rv = mksqsh__id_table_flush(&id_builder); + assert(rv == 0); + rv = mksqsh__id_table_cleanup(&id_builder); + assert(rv == 0); + + fclose(fid_block); + fclose(fid_block_tmp); + free(id_block_tmp); + return fsuperblock; }