aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--extras/browse.c8
-rw-r--r--extras/mk42sqfs.c3
-rw-r--r--extras/mknastyfs.c3
-rw-r--r--include/sqfs/inode.h29
-rw-r--r--lib/common/data_reader_dump.c2
-rw-r--r--lib/sqfs/block_processor/common.c8
-rw-r--r--lib/sqfs/data_reader.c16
-rw-r--r--lib/sqfs/dir_writer.c9
-rw-r--r--lib/sqfs/inode.c35
-rw-r--r--lib/sqfs/read_inode.c11
-rw-r--r--lib/sqfs/write_inode.c22
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.
@@ -525,6 +531,19 @@ 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.
*
* The @ref sqfs_inode_generic_t structure contains inlined fields that have a
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 <string.h>
+#include <alloca.h>
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 = {