summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/sqfs/block_processor/common.c40
-rw-r--r--lib/sqfs/block_processor/internal.h8
-rw-r--r--lib/sqfs/block_processor/serial.c47
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;
}