diff options
Diffstat (limited to 'lib/sqfs/block_processor')
-rw-r--r-- | lib/sqfs/block_processor/common.c | 40 | ||||
-rw-r--r-- | lib/sqfs/block_processor/internal.h | 8 | ||||
-rw-r--r-- | lib/sqfs/block_processor/serial.c | 47 |
3 files changed, 71 insertions, 24 deletions
diff --git a/lib/sqfs/block_processor/common.c b/lib/sqfs/block_processor/common.c index b8f2760..c3363f9 100644 --- a/lib/sqfs/block_processor/common.c +++ b/lib/sqfs/block_processor/common.c @@ -63,6 +63,18 @@ static sqfs_block_t *get_new_block(sqfs_block_processor_t *proc) static void release_old_block(sqfs_block_processor_t *proc, sqfs_block_t *blk) { + sqfs_block_t *it; + + if (blk->flags & SQFS_BLK_FRAGMENT_BLOCK && blk->frag_list != NULL) { + it = blk->frag_list; + + while (it->next != NULL) + it = it->next; + + it->next = proc->free_list; + proc->free_list = blk->frag_list; + } + blk->next = proc->free_list; proc->free_list = blk; } @@ -120,11 +132,29 @@ static bool is_zero_block(unsigned char *ptr, size_t size) int block_processor_do_block(sqfs_block_t *block, sqfs_compressor_t *cmp, sqfs_u8 *scratch, size_t scratch_size) { + sqfs_block_t *it; + size_t offset; sqfs_s32 ret; if (block->size == 0) return 0; + if (block->flags & SQFS_BLK_FRAGMENT_BLOCK) { + offset = block->size; + + for (it = block->frag_list; it != NULL; it = it->next) { + assert(offset >= it->size); + offset -= it->size; + + memcpy(block->data + offset, it->data, it->size); + + block->flags |= (it->flags & SQFS_BLK_DONT_COMPRESS); + + sqfs_inode_set_frag_location(*(it->inode), + block->index, offset); + } + } + if (is_zero_block(block->data, block->size)) { block->flags |= SQFS_BLK_IS_SPARSE; return 0; @@ -211,17 +241,11 @@ 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, - proc->frag_block->size); + frag->next = proc->frag_block->frag_list; + proc->frag_block->frag_list = frag; - memcpy(proc->frag_block->data + proc->frag_block->size, - frag->data, frag->size); - - proc->frag_block->flags |= (frag->flags & SQFS_BLK_DONT_COMPRESS); proc->frag_block->size += frag->size; proc->stats.actual_frag_count += 1; - - release_old_block(proc, frag); return 0; fail: release_old_block(proc, frag); diff --git a/lib/sqfs/block_processor/internal.h b/lib/sqfs/block_processor/internal.h index eff5374..775671c 100644 --- a/lib/sqfs/block_processor/internal.h +++ b/lib/sqfs/block_processor/internal.h @@ -22,6 +22,7 @@ #include <string.h> #include <stdlib.h> +#include <assert.h> typedef struct sqfs_block_t { struct sqfs_block_t *next; @@ -33,9 +34,14 @@ typedef struct sqfs_block_t { sqfs_u32 size; sqfs_u32 checksum; - /* Data block index within the inode or fragment block index. */ + /* For data blocks: index within the inode. + For fragment fragment blocks: fragment table index. */ sqfs_u32 index; + /* For fragment blocks: list of fragments to + consolidate in reverse order. */ + struct sqfs_block_t *frag_list; + sqfs_u8 data[]; } sqfs_block_t; diff --git a/lib/sqfs/block_processor/serial.c b/lib/sqfs/block_processor/serial.c index a9190b1..54edda1 100644 --- a/lib/sqfs/block_processor/serial.c +++ b/lib/sqfs/block_processor/serial.c @@ -13,19 +13,29 @@ typedef struct { sqfs_u8 scratch[]; } serial_block_processor_t; -static void block_processor_destroy(sqfs_object_t *obj) +static void free_block_list(sqfs_block_t *list) { - sqfs_block_processor_t *proc = (sqfs_block_processor_t *)obj; sqfs_block_t *blk; - while (proc->free_list != NULL) { - blk = proc->free_list; - proc->free_list = blk->next; + while (list != NULL) { + blk = list; + list = blk->next; free(blk); } +} + +static void block_processor_destroy(sqfs_object_t *obj) +{ + sqfs_block_processor_t *proc = (sqfs_block_processor_t *)obj; + + free_block_list(proc->free_list); + + if (proc->frag_block != NULL) { + free_block_list(proc->frag_block->frag_list); + free(proc->frag_block); + } free(proc->blk_current); - free(proc->frag_block); free(proc); } @@ -57,16 +67,14 @@ int append_to_work_queue(sqfs_block_processor_t *proc, sqfs_block_t *block) serial_block_processor_t *sproc = (serial_block_processor_t *)proc; sqfs_block_t *fragblk = NULL; - if (sproc->status != 0) { - free(block); - return sproc->status; - } + if (sproc->status != 0) + goto fail; sproc->status = block_processor_do_block(block, proc->cmp, sproc->scratch, proc->max_block_size); if (sproc->status != 0) - return sproc->status; + goto fail; if (block->flags & SQFS_BLK_IS_FRAGMENT) { sproc->status = process_completed_fragment(proc, block, @@ -74,15 +82,20 @@ int append_to_work_queue(sqfs_block_processor_t *proc, sqfs_block_t *block) if (fragblk == NULL) return sproc->status; - sproc->status = block_processor_do_block(fragblk, proc->cmp, + block = fragblk; + sproc->status = block_processor_do_block(block, proc->cmp, sproc->scratch, proc->max_block_size); if (sproc->status != 0) - return sproc->status; + goto fail; } sproc->status = process_completed_block(proc, block); return sproc->status; +fail: + free_block_list(block->frag_list); + free(block); + return sproc->status; } int sqfs_block_processor_sync(sqfs_block_processor_t *proc) @@ -104,9 +117,13 @@ int sqfs_block_processor_finish(sqfs_block_processor_t *proc) goto fail; sproc->status = process_completed_block(proc, proc->frag_block); + proc->frag_block = NULL; return sproc->status; fail: - free(proc->frag_block); - proc->frag_block = NULL; + if (proc->frag_block != NULL) { + free_block_list(proc->frag_block->frag_list); + free(proc->frag_block); + proc->frag_block = NULL; + } return sproc->status; } |