From c924d87a4cbbeb93825f34f997add1ca4573a368 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Sun, 23 Feb 2020 03:44:33 +0100 Subject: Unify the payload counters in the sqfs_inode_generic_t Instead of having seperate counters for blocks, dir index bytes and having to fiddle out the link target size, simply use a single value that stores the number of payload bytes used. A seperate "payload bytes available" is used for dynamically growing inodes during processing. Signed-off-by: David Oberhollenzer --- extras/browse.c | 8 ++++---- extras/mk42sqfs.c | 3 ++- extras/mknastyfs.c | 3 ++- include/sqfs/inode.h | 29 ++++++++++++++++++++++++----- lib/common/data_reader_dump.c | 2 +- lib/sqfs/block_processor/common.c | 8 ++++++-- lib/sqfs/data_reader.c | 16 ++++++++++------ lib/sqfs/dir_writer.c | 9 +++++---- lib/sqfs/inode.c | 35 +++-------------------------------- lib/sqfs/read_inode.c | 11 ++++++++--- lib/sqfs/write_inode.c | 22 +++++++++++++++------- 11 files changed, 80 insertions(+), 66 deletions(-) diff --git a/extras/browse.c b/extras/browse.c index 0bca183..1b32135 100644 --- a/extras/browse.c +++ b/extras/browse.c @@ -321,14 +321,14 @@ static void stat_cmd(const char *filename) case SQFS_INODE_FILE: printf("Blocks start: %u\n", inode->data.file.blocks_start); printf("Block count: %lu\n", - (unsigned long)inode->num_file_blocks); + (unsigned long)sqfs_inode_get_file_block_count(inode)); printf("Fragment index: 0x%X\n", inode->data.file.fragment_index); printf("Fragment offset: %u\n", inode->data.file.fragment_offset); printf("File size: %u\n", inode->data.file.file_size); - for (i = 0; i < inode->num_file_blocks; ++i) { + for (i = 0; i < sqfs_inode_get_file_block_count(inode); ++i) { printf("\tBlock #%lu size: %u (%s)\n", (unsigned long)i, SQFS_ON_DISK_BLOCK_SIZE(inode->extra[i]), SQFS_IS_BLOCK_COMPRESSED(inode->extra[i]) ? @@ -339,7 +339,7 @@ static void stat_cmd(const char *filename) printf("Blocks start: %lu\n", inode->data.file_ext.blocks_start); printf("Block count: %lu\n", - (unsigned long)inode->num_file_blocks); + (unsigned long)sqfs_inode_get_file_block_count(inode)); printf("Fragment index: 0x%X\n", inode->data.file_ext.fragment_idx); printf("Fragment offset: %u\n", @@ -349,7 +349,7 @@ static void stat_cmd(const char *filename) printf("Hard link count: %u\n", inode->data.file_ext.nlink); printf("Xattr index: 0x%X\n", inode->data.file_ext.xattr_idx); - for (i = 0; i < inode->num_file_blocks; ++i) { + for (i = 0; i < sqfs_inode_get_file_block_count(inode); ++i) { printf("\tBlock #%lu size: %u (%s)\n", (unsigned long)i, SQFS_ON_DISK_BLOCK_SIZE(inode->extra[i]), SQFS_IS_BLOCK_COMPRESSED(inode->extra[i]) ? diff --git a/extras/mk42sqfs.c b/extras/mk42sqfs.c index 53cf2f0..e7c5357 100644 --- a/extras/mk42sqfs.c +++ b/extras/mk42sqfs.c @@ -41,7 +41,8 @@ static sqfs_inode_generic_t *create_file_inode(sqfs_id_table_t *idtbl, inode->data.file.file_size = 4096; inode->data.file.fragment_index = 0xFFFFFFFF; - inode->num_file_blocks = 1; + inode->payload_bytes_used = sizeof(sqfs_u32); + inode->payload_bytes_available = sizeof(sqfs_u32); inode->extra[0] = (1 << 24) | inode->data.file.file_size; return inode; } diff --git a/extras/mknastyfs.c b/extras/mknastyfs.c index b11f8f9..7ec3ee0 100644 --- a/extras/mknastyfs.c +++ b/extras/mknastyfs.c @@ -37,7 +37,8 @@ static sqfs_inode_generic_t *create_file_inode(sqfs_id_table_t *idtbl, inode->data.file.file_size = 1337; inode->data.file.fragment_index = 0xFFFFFFFF; - inode->num_file_blocks = 1; + inode->payload_bytes_used = sizeof(sqfs_u32); + inode->payload_bytes_available = sizeof(sqfs_u32); inode->extra[0] = (1 << 24) | inode->data.file.file_size; return inode; } diff --git a/include/sqfs/inode.h b/include/sqfs/inode.h index 17df022..0323bef 100644 --- a/include/sqfs/inode.h +++ b/include/sqfs/inode.h @@ -483,15 +483,21 @@ struct sqfs_inode_generic_t { sqfs_inode_t base; /** - * @brief For file inodes, stores the number of blocks used. + * @brief Maximum number of available data bytes in the payload. + * + * This is used for dynamically growing an inode. The actual number + * of used payload bytes is stored in @ref payload_bytes_used. */ - size_t num_file_blocks; + sqfs_u32 payload_bytes_available; /** - * @brief For extended directory inodes, stores the number of payload - * bytes following for the directory index. + * @brief Number of used data bytes in the payload. + * + * For file inodes, stores the number of blocks used. For extended + * directory inodes, stores the number of payload bytes following + * for the directory index. */ - size_t num_dir_idx_bytes; + sqfs_u32 payload_bytes_used; /** * @brief Type specific inode data. @@ -524,6 +530,19 @@ struct sqfs_inode_generic_t { extern "C" { #endif +/** + * @brief Get the number of file blocks in a regular file inode. + * + * @param inode A pointer to an inode. + * + * @return The number of blocks. + */ +static SQFS_INLINE +size_t sqfs_inode_get_file_block_count(const sqfs_inode_generic_t *inode) +{ + return inode->payload_bytes_used / sizeof(sqfs_u32); +} + /** * @brief Create a deep copy of a generic inode. * diff --git a/lib/common/data_reader_dump.c b/lib/common/data_reader_dump.c index 33bfc4f..d832388 100644 --- a/lib/common/data_reader_dump.c +++ b/lib/common/data_reader_dump.c @@ -57,7 +57,7 @@ int sqfs_data_reader_dump(const char *name, sqfs_data_reader_t *data, allow_sparse = false; #endif - for (i = 0; i < inode->num_file_blocks; ++i) { + for (i = 0; i < sqfs_inode_get_file_block_count(inode); ++i) { diff = (filesz < block_size) ? filesz : block_size; if (SQFS_IS_SPARSE_BLOCK(inode->extra[i]) && allow_sparse) { diff --git a/lib/sqfs/block_processor/common.c b/lib/sqfs/block_processor/common.c index d855b51..51851ae 100644 --- a/lib/sqfs/block_processor/common.c +++ b/lib/sqfs/block_processor/common.c @@ -10,10 +10,14 @@ static void set_block_size(sqfs_inode_generic_t *inode, sqfs_u32 index, sqfs_u32 size) { + size_t min_size = (index + 1) * sizeof(sqfs_u32); + inode->extra[index] = size; - if (index >= inode->num_file_blocks) - inode->num_file_blocks = index + 1; + if (min_size >= inode->payload_bytes_used) { + inode->payload_bytes_used = min_size; + inode->payload_bytes_available = min_size; + } } int process_completed_block(sqfs_block_processor_t *proc, sqfs_block_t *blk) diff --git a/lib/sqfs/data_reader.c b/lib/sqfs/data_reader.c index 8c9bb2e..5e985e0 100644 --- a/lib/sqfs/data_reader.c +++ b/lib/sqfs/data_reader.c @@ -187,7 +187,7 @@ int sqfs_data_reader_get_block(sqfs_data_reader_t *data, sqfs_inode_get_file_block_start(inode, &off); sqfs_inode_get_file_size(inode, &filesz); - if (index >= inode->num_file_blocks) + if (index >= sqfs_inode_get_file_block_count(inode)) return SQFS_ERROR_OUT_OF_BOUNDS; for (i = 0; i < index; ++i) { @@ -206,6 +206,7 @@ int sqfs_data_reader_get_fragment(sqfs_data_reader_t *data, size_t *size, sqfs_u8 **out) { sqfs_u32 frag_idx, frag_off, frag_sz; + size_t block_count; sqfs_u64 filesz; int err; @@ -214,7 +215,9 @@ int sqfs_data_reader_get_fragment(sqfs_data_reader_t *data, *size = 0; *out = NULL; - if (inode->num_file_blocks * data->block_size >= filesz) + block_count = sqfs_inode_get_file_block_count(inode); + + if (block_count * data->block_size >= filesz) return 0; frag_sz = filesz % data->block_size; @@ -240,9 +243,9 @@ sqfs_s32 sqfs_data_reader_read(sqfs_data_reader_t *data, sqfs_u64 offset, void *buffer, sqfs_u32 size) { sqfs_u32 frag_idx, frag_off, diff, total = 0; + size_t i, block_count; sqfs_u64 off, filesz; char *ptr; - size_t i; int err; if (size >= 0x7FFFFFFF) @@ -252,11 +255,12 @@ sqfs_s32 sqfs_data_reader_read(sqfs_data_reader_t *data, sqfs_inode_get_file_size(inode, &filesz); sqfs_inode_get_frag_location(inode, &frag_idx, &frag_off); sqfs_inode_get_file_block_start(inode, &off); + block_count = sqfs_inode_get_file_block_count(inode); /* find location of the first block */ i = 0; - while (offset > data->block_size && i < inode->num_file_blocks) { + while (offset > data->block_size && i < block_count) { off += SQFS_ON_DISK_BLOCK_SIZE(inode->extra[i++]); offset -= data->block_size; @@ -268,7 +272,7 @@ sqfs_s32 sqfs_data_reader_read(sqfs_data_reader_t *data, } /* copy data from blocks */ - while (i < inode->num_file_blocks && size > 0 && filesz > 0) { + while (i < block_count && size > 0 && filesz > 0) { diff = data->block_size - offset; if (size < diff) diff = size; @@ -298,7 +302,7 @@ sqfs_s32 sqfs_data_reader_read(sqfs_data_reader_t *data, } /* copy from fragment */ - if (i == inode->num_file_blocks && size > 0 && filesz > 0) { + if (i == block_count && size > 0 && filesz > 0) { err = precache_fragment_block(data, frag_idx); if (err) return err; diff --git a/lib/sqfs/dir_writer.c b/lib/sqfs/dir_writer.c index 9dd7ad2..bb3e867 100644 --- a/lib/sqfs/dir_writer.c +++ b/lib/sqfs/dir_writer.c @@ -392,6 +392,7 @@ sqfs_inode_generic_t if (inode == NULL) return NULL; + inode->payload_bytes_available = index_size; start_block = writer->dir_ref >> 16; block_offset = writer->dir_ref & 0xFFFF; @@ -416,7 +417,7 @@ sqfs_inode_generic_t inode->data.dir_ext.offset = block_offset; inode->data.dir_ext.xattr_idx = xattr; inode->data.dir_ext.inodex_count = 0; - inode->num_dir_idx_bytes = 0; + inode->payload_bytes_used = 0; for (idx = writer->idx; idx != NULL; idx = idx->next) { memset(&ent, 0, sizeof(ent)); @@ -425,14 +426,14 @@ sqfs_inode_generic_t ent.size = idx->ent->name_len - 1; ptr = (sqfs_u8 *)inode->extra + - inode->num_dir_idx_bytes; + inode->payload_bytes_used; memcpy(ptr, &ent, sizeof(ent)); memcpy(ptr + sizeof(ent), idx->ent->name, idx->ent->name_len); inode->data.dir_ext.inodex_count += 1; - inode->num_dir_idx_bytes += sizeof(ent); - inode->num_dir_idx_bytes += idx->ent->name_len; + inode->payload_bytes_used += sizeof(ent); + inode->payload_bytes_used += idx->ent->name_len; } } diff --git a/lib/sqfs/inode.c b/lib/sqfs/inode.c index 815cc0f..bda244b 100644 --- a/lib/sqfs/inode.c +++ b/lib/sqfs/inode.c @@ -36,38 +36,9 @@ static int inverse_type[] = { int sqfs_inode_copy(const sqfs_inode_generic_t *src, sqfs_inode_generic_t **out) { - sqfs_inode_generic_t *copy; - size_t size = sizeof(*src); + size_t size = sizeof(*src) + src->payload_bytes_used; + sqfs_inode_generic_t *copy = calloc(1, size); - switch (src->base.type) { - case SQFS_INODE_FILE: - case SQFS_INODE_EXT_FILE: - size += src->num_file_blocks; - break; - case SQFS_INODE_DIR: - case SQFS_INODE_EXT_DIR: - size += src->num_dir_idx_bytes; - break; - case SQFS_INODE_SLINK: - size += src->data.slink.target_size; - break; - case SQFS_INODE_EXT_SLINK: - size += src->data.slink_ext.target_size; - break; - case SQFS_INODE_BDEV: - case SQFS_INODE_CDEV: - case SQFS_INODE_FIFO: - case SQFS_INODE_SOCKET: - case SQFS_INODE_EXT_BDEV: - case SQFS_INODE_EXT_CDEV: - case SQFS_INODE_EXT_FIFO: - case SQFS_INODE_EXT_SOCKET: - break; - default: - return SQFS_ERROR_CORRUPTED; - } - - copy = calloc(1, size); if (copy == NULL) return SQFS_ERROR_ALLOC; @@ -406,7 +377,7 @@ int sqfs_inode_unpack_dir_index_entry(const sqfs_inode_generic_t *inode, ptr = (char *)inode->extra; for (;;) { - if (offset >= inode->num_dir_idx_bytes) + if (offset >= inode->payload_bytes_used) return SQFS_ERROR_OUT_OF_BOUNDS; if (index == 0) diff --git a/lib/sqfs/read_inode.c b/lib/sqfs/read_inode.c index 8653928..6ca61d5 100644 --- a/lib/sqfs/read_inode.c +++ b/lib/sqfs/read_inode.c @@ -101,7 +101,8 @@ static int read_inode_file(sqfs_meta_reader_t *ir, sqfs_inode_t *base, out->base = *base; out->data.file = file; - out->num_file_blocks = count; + out->payload_bytes_available = count * sizeof(sqfs_u32); + out->payload_bytes_used = count * sizeof(sqfs_u32); err = sqfs_meta_reader_read(ir, out->extra, count * sizeof(sqfs_u32)); if (err) { @@ -147,7 +148,8 @@ static int read_inode_file_ext(sqfs_meta_reader_t *ir, sqfs_inode_t *base, out->base = *base; out->data.file_ext = file; - out->num_file_blocks = count; + out->payload_bytes_available = count * sizeof(sqfs_u32); + out->payload_bytes_used = count * sizeof(sqfs_u32); err = sqfs_meta_reader_read(ir, out->extra, count * sizeof(sqfs_u32)); if (err) { @@ -186,6 +188,8 @@ static int read_inode_slink(sqfs_meta_reader_t *ir, sqfs_inode_t *base, if (out == NULL) return SQFS_ERROR_ALLOC; + out->payload_bytes_available = size - sizeof(*out); + out->payload_bytes_used = size - sizeof(*out) - 1; out->base = *base; out->data.slink = slink; @@ -298,7 +302,8 @@ static int read_inode_dir_ext(sqfs_meta_reader_t *ir, sqfs_inode_t *base, index_used += ent.size + 1; } - out->num_dir_idx_bytes = index_used; + out->payload_bytes_used = index_used; + out->payload_bytes_available = index_used; *result = out; return 0; } diff --git a/lib/sqfs/write_inode.c b/lib/sqfs/write_inode.c index b5ba905..86ed146 100644 --- a/lib/sqfs/write_inode.c +++ b/lib/sqfs/write_inode.c @@ -14,18 +14,26 @@ #include "compat.h" #include +#include static int write_block_sizes(sqfs_meta_writer_t *ir, const sqfs_inode_generic_t *n) { - sqfs_u32 sizes[n->num_file_blocks]; + sqfs_u32 *sizes; size_t i; - for (i = 0; i < n->num_file_blocks; ++i) + if (n->payload_bytes_used < sizeof(sizes[0])) + return 0; + + if ((n->payload_bytes_used % sizeof(sizes[0])) != 0) + return SQFS_ERROR_CORRUPTED; + + sizes = alloca(n->payload_bytes_used); + + for (i = 0; i < (n->payload_bytes_used / sizeof(sizes[0])); ++i) sizes[i] = htole32(n->extra[i]); - return sqfs_meta_writer_append(ir, sizes, - sizeof(sqfs_u32) * n->num_file_blocks); + return sqfs_meta_writer_append(ir, sizes, n->payload_bytes_used); } static int write_dir_index(sqfs_meta_writer_t *ir, const sqfs_u8 *data, @@ -102,7 +110,7 @@ int sqfs_meta_writer_write_inode(sqfs_meta_writer_t *ir, ret = sqfs_meta_writer_append(ir, &file, sizeof(file)); if (ret) return ret; - return n->num_file_blocks ? write_block_sizes(ir, n) : 0; + return write_block_sizes(ir, n); } case SQFS_INODE_SLINK: { sqfs_inode_slink_t slink = { @@ -144,7 +152,7 @@ int sqfs_meta_writer_write_inode(sqfs_meta_writer_t *ir, if (ret) return ret; return write_dir_index(ir, (const sqfs_u8 *)n->extra, - n->num_dir_idx_bytes); + n->payload_bytes_used); } case SQFS_INODE_EXT_FILE: { sqfs_inode_file_ext_t file = { @@ -160,7 +168,7 @@ int sqfs_meta_writer_write_inode(sqfs_meta_writer_t *ir, ret = sqfs_meta_writer_append(ir, &file, sizeof(file)); if (ret) return ret; - return n->num_file_blocks ? write_block_sizes(ir, n) : 0; + return write_block_sizes(ir, n); } case SQFS_INODE_EXT_SLINK: { sqfs_inode_slink_t slink = { -- cgit v1.2.3