summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2020-02-23 15:26:02 +0100
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2020-02-23 15:38:48 +0100
commitc2a093c9e9fb4889a11982797d75b8608c26da8f (patch)
tree613afb06c5eda3dba01c898ce073fcc81731eba2
parentc924d87a4cbbeb93825f34f997add1ca4573a368 (diff)
Turn file inode management completely over to the block processor
If the block processor allocates and dynamically resizes inodes on the fly, we can add data indefinitely without knowing the size of the file ahead of time. Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
-rw-r--r--include/common.h2
-rw-r--r--include/sqfs/block_processor.h23
-rw-r--r--lib/common/data_writer.c2
-rw-r--r--lib/sqfs/block_processor/common.c72
-rw-r--r--lib/sqfs/block_processor/internal.h4
-rw-r--r--mkfs/mkfs.c35
-rw-r--r--tar/tar2sqfs.c26
7 files changed, 77 insertions, 87 deletions
diff --git a/include/common.h b/include/common.h
index 0fd349a..cf2d1b5 100644
--- a/include/common.h
+++ b/include/common.h
@@ -116,7 +116,7 @@ sqfs_file_t *sqfs_get_stdin_file(FILE *fp, const sparse_map_t *map,
sqfs_u64 size);
int write_data_from_file(const char *filename, sqfs_block_processor_t *data,
- sqfs_inode_generic_t *inode,
+ sqfs_inode_generic_t **inode,
sqfs_file_t *file, int flags);
void sqfs_writer_cfg_init(sqfs_writer_cfg_t *cfg);
diff --git a/include/sqfs/block_processor.h b/include/sqfs/block_processor.h
index 6945633..2ad12c0 100644
--- a/include/sqfs/block_processor.h
+++ b/include/sqfs/block_processor.h
@@ -142,24 +142,27 @@ sqfs_block_processor_t *sqfs_block_processor_create(size_t max_block_size,
* are done. After writing all files, use @ref sqfs_block_processor_finish to
* wait until all blocks that are still in flight are done and written to disk.
*
- * The specified inode pointer is kept internally and updated with the
- * compressed block sizes and final destinations of the file and possible
- * fragment. You need to make sure it has enough backing-store for all blocks
- * to come. Furthermore, since there can still be blocks in-flight even after
- * calling @ref sqfs_block_processor_end_file, the data in the inode may still
- * change. The only point at which the data writer is guarnteed to not touch
- * them anymore is after @ref sqfs_block_processor_finish has returned.
+ * The specified pointer to an inode pointer is kept internally and updated with
+ * the compressed block sizes and final destinations of the file and possible
+ * fragment. Since the inode may have to be grown to larger size, the actual
+ * inode pointer can change over time. Furthermore, since there can still be
+ * blocks in-flight even after calling @ref sqfs_block_processor_end_file, the
+ * data in the inode and the value of the pointer may still change. The only
+ * point at which the data writer is guaranteed to not touch them anymore is
+ * after @ref sqfs_block_processor_sync or @ref sqfs_block_processor_finish has
+ * returned.
*
* @param proc A pointer to a data writer object.
- * @param inode The regular file inode representing the file. The data writer
- * internally updates it while writing blocks to disk.
+ * @param inode A pointer to a pointer to an inode. The block processor creates
+ * a file inode and stores a pointer to it here and keeps updating
+ * the inode as the file grows.
* @param flags A combination of @ref E_SQFS_BLK_FLAGS that can be used to
* micro manage how the data is processed.
*
* @return Zero on success, an @ref E_SQFS_ERROR value on failure.
*/
SQFS_API int sqfs_block_processor_begin_file(sqfs_block_processor_t *proc,
- sqfs_inode_generic_t *inode,
+ sqfs_inode_generic_t **inode,
sqfs_u32 flags);
/**
diff --git a/lib/common/data_writer.c b/lib/common/data_writer.c
index 0b4dc07..bc5a43b 100644
--- a/lib/common/data_writer.c
+++ b/lib/common/data_writer.c
@@ -9,7 +9,7 @@
static sqfs_u8 buffer[4096];
int write_data_from_file(const char *filename, sqfs_block_processor_t *data,
- sqfs_inode_generic_t *inode, sqfs_file_t *file,
+ sqfs_inode_generic_t **inode, sqfs_file_t *file,
int flags)
{
sqfs_u64 filesz, offset;
diff --git a/lib/sqfs/block_processor/common.c b/lib/sqfs/block_processor/common.c
index 51851ae..ab83b5d 100644
--- a/lib/sqfs/block_processor/common.c
+++ b/lib/sqfs/block_processor/common.c
@@ -7,17 +7,41 @@
#define SQFS_BUILDING_DLL
#include "internal.h"
-static void set_block_size(sqfs_inode_generic_t *inode,
- sqfs_u32 index, sqfs_u32 size)
+static int set_block_size(sqfs_inode_generic_t **inode,
+ sqfs_u32 index, sqfs_u32 size)
{
size_t min_size = (index + 1) * sizeof(sqfs_u32);
+ size_t avail = (*inode)->payload_bytes_available;
+ size_t newsz;
+ void *new;
- inode->extra[index] = size;
+ if (avail < min_size) {
+ newsz = avail ? avail : (sizeof(sqfs_u32) * 4);
+ while (newsz < min_size)
+ newsz *= 2;
- if (min_size >= inode->payload_bytes_used) {
- inode->payload_bytes_used = min_size;
- inode->payload_bytes_available = min_size;
+ if (SZ_ADD_OV(newsz, sizeof(**inode), &newsz))
+ return SQFS_ERROR_OVERFLOW;
+
+ if (sizeof(size_t) > sizeof(sqfs_u32)) {
+ if ((newsz - sizeof(**inode)) > 0x0FFFFFFFFUL)
+ return SQFS_ERROR_OVERFLOW;
+ }
+
+ new = realloc((*inode), newsz);
+ if (new == NULL)
+ return SQFS_ERROR_ALLOC;
+
+ (*inode) = new;
+ (*inode)->payload_bytes_available = newsz - sizeof(**inode);
}
+
+ (*inode)->extra[index] = size;
+
+ if (min_size >= (*inode)->payload_bytes_used)
+ (*inode)->payload_bytes_used = min_size;
+
+ return 0;
}
int process_completed_block(sqfs_block_processor_t *proc, sqfs_block_t *blk)
@@ -32,10 +56,12 @@ int process_completed_block(sqfs_block_processor_t *proc, sqfs_block_t *blk)
return err;
if (blk->flags & SQFS_BLK_IS_SPARSE) {
- sqfs_inode_make_extended(blk->inode);
- blk->inode->data.file_ext.sparse += blk->size;
+ sqfs_inode_make_extended(*(blk->inode));
+ (*(blk->inode))->data.file_ext.sparse += blk->size;
- set_block_size(blk->inode, blk->index, 0);
+ err = set_block_size(blk->inode, blk->index, 0);
+ if (err)
+ return err;
proc->stats.sparse_block_count += 1;
} else if (blk->size != 0) {
@@ -49,13 +75,15 @@ int process_completed_block(sqfs_block_processor_t *proc, sqfs_block_t *blk)
if (err)
return err;
} else {
- set_block_size(blk->inode, blk->index, size);
+ err = set_block_size(blk->inode, blk->index, size);
+ if (err)
+ return err;
proc->stats.data_block_count += 1;
}
}
if (blk->flags & SQFS_BLK_LAST_BLOCK)
- sqfs_inode_set_file_block_start(blk->inode, location);
+ sqfs_inode_set_file_block_start(*(blk->inode), location);
return 0;
}
@@ -104,9 +132,9 @@ int process_completed_fragment(sqfs_block_processor_t *proc, sqfs_block_t *frag,
int err;
if (frag->flags & SQFS_BLK_IS_SPARSE) {
- sqfs_inode_make_extended(frag->inode);
+ sqfs_inode_make_extended(*(frag->inode));
set_block_size(frag->inode, frag->index, 0);
- frag->inode->data.file_ext.sparse += frag->size;
+ (*(frag->inode))->data.file_ext.sparse += frag->size;
proc->stats.sparse_block_count += 1;
return 0;
@@ -117,7 +145,7 @@ int process_completed_fragment(sqfs_block_processor_t *proc, sqfs_block_t *frag,
err = sqfs_frag_table_find_tail_end(proc->frag_tbl, frag->checksum,
frag->size, &index, &offset);
if (err == 0) {
- sqfs_inode_set_frag_location(frag->inode, index, offset);
+ sqfs_inode_set_frag_location(*(frag->inode), index, offset);
return 0;
}
@@ -155,7 +183,7 @@ int process_completed_fragment(sqfs_block_processor_t *proc, sqfs_block_t *frag,
if (err)
goto fail;
- sqfs_inode_set_frag_location(frag->inode, proc->frag_block->index,
+ sqfs_inode_set_frag_location(*(frag->inode), proc->frag_block->index,
proc->frag_block->size);
memcpy(proc->frag_block->data + proc->frag_block->size,
@@ -202,7 +230,7 @@ static int flush_block(sqfs_block_processor_t *proc)
}
int sqfs_block_processor_begin_file(sqfs_block_processor_t *proc,
- sqfs_inode_generic_t *inode, sqfs_u32 flags)
+ sqfs_inode_generic_t **inode, sqfs_u32 flags)
{
if (proc->inode != NULL)
return SQFS_ERROR_SEQUENCE;
@@ -210,8 +238,12 @@ int sqfs_block_processor_begin_file(sqfs_block_processor_t *proc,
if (flags & ~SQFS_BLK_USER_SETTABLE_FLAGS)
return SQFS_ERROR_UNSUPPORTED;
- sqfs_inode_set_file_size(inode, 0);
- sqfs_inode_set_frag_location(inode, 0xFFFFFFFF, 0xFFFFFFFF);
+ (*inode) = calloc(1, sizeof(sqfs_inode_generic_t));
+ if ((*inode) == NULL)
+ return SQFS_ERROR_ALLOC;
+
+ (*inode)->base.type = SQFS_INODE_FILE;
+ sqfs_inode_set_frag_location(*inode, 0xFFFFFFFF, 0xFFFFFFFF);
proc->inode = inode;
proc->blk_flags = flags | SQFS_BLK_FIRST_BLOCK;
@@ -227,8 +259,8 @@ int sqfs_block_processor_append(sqfs_block_processor_t *proc, const void *data,
size_t diff;
int err;
- sqfs_inode_get_file_size(proc->inode, &filesize);
- sqfs_inode_set_file_size(proc->inode, filesize + size);
+ sqfs_inode_get_file_size(*(proc->inode), &filesize);
+ sqfs_inode_set_file_size(*(proc->inode), filesize + size);
while (size > 0) {
if (proc->blk_current == NULL) {
diff --git a/lib/sqfs/block_processor/internal.h b/lib/sqfs/block_processor/internal.h
index 03a8296..0e95551 100644
--- a/lib/sqfs/block_processor/internal.h
+++ b/lib/sqfs/block_processor/internal.h
@@ -25,7 +25,7 @@
typedef struct sqfs_block_t {
struct sqfs_block_t *next;
- sqfs_inode_generic_t *inode;
+ sqfs_inode_generic_t **inode;
sqfs_u32 proc_seq_num;
sqfs_u32 io_seq_num;
@@ -49,7 +49,7 @@ struct sqfs_block_processor_t {
sqfs_block_processor_stats_t stats;
- sqfs_inode_generic_t *inode;
+ sqfs_inode_generic_t **inode;
sqfs_block_t *blk_current;
sqfs_u32 blk_flags;
sqfs_u32 blk_index;
diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c
index 691c754..0ef65ca 100644
--- a/mkfs/mkfs.c
+++ b/mkfs/mkfs.c
@@ -42,15 +42,13 @@ static int set_working_dir(options_t *opt)
static int pack_files(sqfs_block_processor_t *data, fstree_t *fs,
options_t *opt)
{
- sqfs_inode_generic_t *inode;
- size_t max_blk_count;
+ sqfs_inode_generic_t **inode_ptr;
sqfs_u64 filesize;
sqfs_file_t *file;
tree_node_t *node;
const char *path;
char *node_path;
file_info_t *fi;
- size_t size;
int flags;
int ret;
@@ -86,38 +84,15 @@ static int pack_files(sqfs_block_processor_t *data, fstree_t *fs,
return -1;
}
- filesize = file->get_size(file);
-
- max_blk_count = filesize / opt->cfg.block_size;
- if (filesize % opt->cfg.block_size)
- ++max_blk_count;
-
- if (SZ_MUL_OV(sizeof(sqfs_u32), max_blk_count, &size) ||
- SZ_ADD_OV(sizeof(*inode), size, &size)) {
- fputs("creating file inode: too many blocks\n",
- stderr);
- sqfs_destroy(file);
- free(node_path);
- return -1;
- }
-
- inode = calloc(1, size);
- if (inode == NULL) {
- perror("creating file inode");
- sqfs_destroy(file);
- free(node_path);
- return -1;
- }
-
- inode->base.type = SQFS_INODE_FILE;
- fi->user_ptr = inode;
-
flags = 0;
+ filesize = file->get_size(file);
if (opt->no_tail_packing && filesize > opt->cfg.block_size)
flags |= SQFS_BLK_DONT_FRAGMENT;
- ret = write_data_from_file(path, data, inode, file, flags);
+ inode_ptr = (sqfs_inode_generic_t **)&fi->user_ptr;
+
+ ret = write_data_from_file(path, data, inode_ptr, file, flags);
sqfs_destroy(file);
free(node_path);
diff --git a/tar/tar2sqfs.c b/tar/tar2sqfs.c
index 69d445e..5c18312 100644
--- a/tar/tar2sqfs.c
+++ b/tar/tar2sqfs.c
@@ -250,32 +250,10 @@ fail_arg:
static int write_file(tar_header_decoded_t *hdr, file_info_t *fi,
sqfs_u64 filesize)
{
- sqfs_inode_generic_t *inode;
- size_t size, max_blk_count;
sqfs_file_t *file;
int flags;
int ret;
- max_blk_count = filesize / cfg.block_size;
- if (filesize % cfg.block_size)
- ++max_blk_count;
-
- if (SZ_MUL_OV(sizeof(sqfs_u32), max_blk_count, &size) ||
- SZ_ADD_OV(sizeof(*inode), size, &size)) {
- fputs("creating file inode: too many blocks\n",
- stderr);
- return -1;
- }
-
- inode = calloc(1, size);
- if (inode == NULL) {
- perror("creating file inode");
- return -1;
- }
-
- inode->base.type = SQFS_INODE_FILE;
- fi->user_ptr = inode;
-
file = sqfs_get_stdin_file(input_file, hdr->sparse, filesize);
if (file == NULL) {
perror("packing files");
@@ -286,7 +264,9 @@ static int write_file(tar_header_decoded_t *hdr, file_info_t *fi,
if (no_tail_pack && filesize > cfg.block_size)
flags |= SQFS_BLK_DONT_FRAGMENT;
- ret = write_data_from_file(hdr->name, sqfs.data, inode, file, 0);
+ ret = write_data_from_file(hdr->name, sqfs.data,
+ (sqfs_inode_generic_t **)&fi->user_ptr,
+ file, 0);
sqfs_destroy(file);
if (ret)