diff options
Diffstat (limited to 'lib/sqfs/block_processor')
-rw-r--r-- | lib/sqfs/block_processor/common.c | 62 | ||||
-rw-r--r-- | lib/sqfs/block_processor/internal.h | 11 |
2 files changed, 62 insertions, 11 deletions
diff --git a/lib/sqfs/block_processor/common.c b/lib/sqfs/block_processor/common.c index 11cbd51..25a15c2 100644 --- a/lib/sqfs/block_processor/common.c +++ b/lib/sqfs/block_processor/common.c @@ -180,6 +180,8 @@ static int process_completed_fragment(sqfs_block_processor_t *proc, sqfs_block_t *frag, sqfs_block_t **blk_out) { + chunk_info_t *chunk, search; + struct hash_entry *entry; sqfs_u32 index, offset; size_t size; int err; @@ -197,15 +199,18 @@ static int process_completed_fragment(sqfs_block_processor_t *proc, proc->stats.total_frag_count += 1; - if (!(frag->flags & SQFS_BLK_DONT_DEDUPLICATE) && - proc->frag_tbl != NULL) { - err = sqfs_frag_table_find_tail_end(proc->frag_tbl, - frag->checksum, frag->size, - &index, &offset); - if (err == 0) { + if (!(frag->flags & SQFS_BLK_DONT_DEDUPLICATE)) { + search.hash = frag->checksum; + search.size = frag->size; + + entry = hash_table_search_pre_hashed(proc->frag_ht, + search.hash, &search); + if (entry != NULL) { if (frag->inode != NULL) { + chunk = entry->data; sqfs_inode_set_frag_location(*(frag->inode), - index, offset); + chunk->index, + chunk->offset); } release_old_block(proc, frag); return 0; @@ -248,11 +253,21 @@ static int process_completed_fragment(sqfs_block_processor_t *proc, } if (proc->frag_tbl != NULL) { - err = sqfs_frag_table_add_tail_end(proc->frag_tbl, - index, offset, - frag->size, frag->checksum); - if (err) + chunk = calloc(1, sizeof(*chunk)); + if (chunk == NULL) goto fail_outblk; + + chunk->index = index; + chunk->offset = offset; + chunk->size = frag->size; + chunk->hash = frag->checksum; + + entry = hash_table_insert_pre_hashed(proc->frag_ht, chunk->hash, + chunk, chunk); + if (entry == NULL) { + free(chunk); + goto fail_outblk; + } } if (frag->inode != NULL) @@ -270,6 +285,24 @@ fail_outblk: return err; } +static uint32_t chunk_info_hash(const void *key) +{ + const chunk_info_t *chunk = key; + return chunk->hash; +} + +static bool chunk_info_equals(const void *a, const void *b) +{ + const chunk_info_t *a_ = a, *b_ = b; + return a_->size == b_->size && + a_->hash == b_->hash; +} + +static void ht_delete_function(struct hash_entry *entry) +{ + free(entry->data); +} + void block_processor_cleanup(sqfs_block_processor_t *base) { sqfs_block_t *it; @@ -284,6 +317,8 @@ void block_processor_cleanup(sqfs_block_processor_t *base) base->free_list = it->next; free(it); } + + hash_table_destroy(base->frag_ht, ht_delete_function); } int block_processor_init(sqfs_block_processor_t *base, size_t max_block_size, @@ -298,5 +333,10 @@ int block_processor_init(sqfs_block_processor_t *base, size_t max_block_size, base->frag_tbl = tbl; base->wr = wr; base->stats.size = sizeof(base->stats); + + base->frag_ht = hash_table_create(chunk_info_hash, chunk_info_equals); + if (base->frag_ht == NULL) + return -1; + return 0; } diff --git a/lib/sqfs/block_processor/internal.h b/lib/sqfs/block_processor/internal.h index d50a452..0c4f2b3 100644 --- a/lib/sqfs/block_processor/internal.h +++ b/lib/sqfs/block_processor/internal.h @@ -18,12 +18,22 @@ #include "sqfs/error.h" #include "sqfs/block.h" #include "sqfs/io.h" + +#include "hash_table.h" #include "util.h" #include <string.h> #include <stdlib.h> #include <assert.h> +typedef struct chunk_info_t { + struct chunk_info_t *next; + sqfs_u32 index; + sqfs_u32 offset; + sqfs_u32 size; + sqfs_u32 hash; +} chunk_info_t; + enum { BLK_FLAG_MANUAL_SUBMISSION = 0x10000000, BLK_FLAG_INTERNAL = 0x10000000, @@ -69,6 +79,7 @@ struct sqfs_block_processor_t { sqfs_u32 blk_index; void *user; + struct hash_table *frag_ht; sqfs_block_t *free_list; size_t max_block_size; |