summaryrefslogtreecommitdiff
path: root/lib/sqfs/blk_proc/process_block.c
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-09-23 15:28:25 +0200
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-09-23 15:35:36 +0200
commitb86cbb04c9cc72506783e175e871338b1f0e6750 (patch)
treedcb4f92b6962aa35cacb2db09219fd4dfbaf3d60 /lib/sqfs/blk_proc/process_block.c
parent8ee4a30a0f3545dac5b9a93b40c172f4fb4d44a1 (diff)
Move the bulk of the work from the data writer to the block processor
Instead of calling a callback, the block processor now takes care of writing the data blocks to the file in the correct order, keeping track of fragment blocks and deduplicating blocks. Some cleanup work remains to be done and the statistics have to be repaired (yet again). Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib/sqfs/blk_proc/process_block.c')
-rw-r--r--lib/sqfs/blk_proc/process_block.c151
1 files changed, 150 insertions, 1 deletions
diff --git a/lib/sqfs/blk_proc/process_block.c b/lib/sqfs/blk_proc/process_block.c
index 1b6ee29..0747bc5 100644
--- a/lib/sqfs/blk_proc/process_block.c
+++ b/lib/sqfs/blk_proc/process_block.c
@@ -37,6 +37,155 @@ int sqfs_block_process(sqfs_block_t *block, sqfs_compressor_t *cmp,
return 0;
}
+static int allign_file(sqfs_block_processor_t *proc, sqfs_block_t *blk)
+{
+ if (!(blk->flags & SQFS_BLK_ALLIGN))
+ return 0;
+
+ return padd_sqfs(proc->file, proc->file->get_size(proc->file),
+ proc->devblksz);
+}
+
+static int store_block_location(sqfs_block_processor_t *proc, uint64_t offset,
+ uint32_t size, uint32_t chksum)
+{
+ size_t new_sz;
+ void *new;
+
+ if (proc->num_blocks == proc->max_blocks) {
+ new_sz = proc->max_blocks * 2;
+ new = realloc(proc->blocks, sizeof(proc->blocks[0]) * new_sz);
+
+ if (new == NULL)
+ return SQFS_ERROR_ALLOC;
+
+ proc->blocks = new;
+ proc->max_blocks = new_sz;
+ }
+
+ proc->blocks[proc->num_blocks].offset = offset;
+ proc->blocks[proc->num_blocks].signature = MK_BLK_SIG(chksum, size);
+ proc->num_blocks += 1;
+ return 0;
+}
+
+static size_t deduplicate_blocks(sqfs_block_processor_t *proc, size_t count)
+{
+ size_t i, j;
+
+ for (i = 0; i < proc->file_start; ++i) {
+ for (j = 0; j < count; ++j) {
+ if (proc->blocks[i + j].signature !=
+ proc->blocks[proc->file_start + j].signature)
+ break;
+ }
+
+ if (j == count)
+ break;
+ }
+
+ return i;
+}
+
+static size_t grow_fragment_table(sqfs_block_processor_t *proc, size_t index)
+{
+ size_t newsz;
+ void *new;
+
+ if (index < proc->max_fragments)
+ return 0;
+
+ do {
+ newsz = proc->max_fragments ? proc->max_fragments * 2 : 16;
+ } while (index >= newsz);
+
+ new = realloc(proc->fragments, sizeof(proc->fragments[0]) * newsz);
+
+ if (new == NULL)
+ return SQFS_ERROR_ALLOC;
+
+ proc->max_fragments = newsz;
+ proc->fragments = new;
+ return 0;
+}
+
+static int handle_block(sqfs_block_processor_t *proc, sqfs_block_t *blk)
+{
+ size_t start, count;
+ uint64_t offset;
+ uint32_t out;
+ int err;
+
+ if (blk->flags & SQFS_BLK_FIRST_BLOCK) {
+ proc->start = proc->file->get_size(proc->file);
+ proc->file_start = proc->num_blocks;
+
+ err = allign_file(proc, blk);
+ if (err)
+ return err;
+ }
+
+ if (blk->size != 0) {
+ out = blk->size;
+ if (!(blk->flags & SQFS_BLK_IS_COMPRESSED))
+ out |= 1 << 24;
+
+ offset = proc->file->get_size(proc->file);
+
+ if (blk->flags & SQFS_BLK_FRAGMENT_BLOCK) {
+ if (grow_fragment_table(proc, blk->index))
+ return 0;
+
+ offset = htole64(offset);
+ proc->fragments[blk->index].start_offset = offset;
+ proc->fragments[blk->index].pad0 = 0;
+ proc->fragments[blk->index].size = htole32(out);
+
+ if (blk->index >= proc->num_fragments)
+ proc->num_fragments = blk->index + 1;
+ } else {
+ blk->inode->block_sizes[blk->index] = out;
+ }
+
+ err = store_block_location(proc, offset, out, blk->checksum);
+ if (err)
+ return err;
+
+ err = proc->file->write_at(proc->file, offset,
+ blk->data, blk->size);
+ if (err)
+ return err;
+ }
+
+ if (blk->flags & SQFS_BLK_LAST_BLOCK) {
+ err = allign_file(proc, blk);
+ if (err)
+ return err;
+
+ count = proc->num_blocks - proc->file_start;
+ start = deduplicate_blocks(proc, count);
+ offset = proc->blocks[start].offset;
+
+ sqfs_inode_set_file_block_start(blk->inode, offset);
+
+ if (start < proc->file_start) {
+ offset = start + count;
+
+ if (offset >= proc->file_start) {
+ proc->num_blocks = offset;
+ } else {
+ proc->num_blocks = proc->file_start;
+ }
+
+ err = proc->file->truncate(proc->file, proc->start);
+ if (err)
+ return err;
+ }
+ }
+
+ return 0;
+}
+
int process_completed_blocks(sqfs_block_processor_t *proc, sqfs_block_t *queue)
{
sqfs_block_t *it;
@@ -48,7 +197,7 @@ int process_completed_blocks(sqfs_block_processor_t *proc, sqfs_block_t *queue)
if (it->flags & SQFS_BLK_COMPRESS_ERROR) {
proc->status = SQFS_ERROR_COMRPESSOR;
} else if (proc->status == 0) {
- proc->status = proc->cb(proc->user, it);
+ proc->status = handle_block(proc, it);
}
free(it);