diff options
author | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2020-01-28 21:23:21 +0100 |
---|---|---|
committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2020-01-29 17:22:50 +0100 |
commit | 9d5b0c381a7961a14d2a94a6b31a4e25a2543eae (patch) | |
tree | 089a3cc96f54cd7b09762840d03e4dc2420c5ea9 /lib/sqfs/block_processor/fileapi.c | |
parent | 60ff56b68ea0593782d7a2ef0ac4e667437418d2 (diff) |
Rename sqfs_data_writer_t back to sqfs_block_processor_t
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib/sqfs/block_processor/fileapi.c')
-rw-r--r-- | lib/sqfs/block_processor/fileapi.c | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/lib/sqfs/block_processor/fileapi.c b/lib/sqfs/block_processor/fileapi.c new file mode 100644 index 0000000..9e59c1d --- /dev/null +++ b/lib/sqfs/block_processor/fileapi.c @@ -0,0 +1,188 @@ +/* SPDX-License-Identifier: LGPL-3.0-or-later */ +/* + * fileapi.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#define SQFS_BUILDING_DLL +#include "internal.h" + +static bool is_zero_block(unsigned char *ptr, size_t size) +{ + return ptr[0] == 0 && memcmp(ptr, ptr + 1, size - 1) == 0; +} + +static int enqueue_block(sqfs_block_processor_t *proc, sqfs_block_t *block) +{ + int status; + + while (proc->backlog > proc->max_backlog) { + status = wait_completed(proc); + if (status) + return status; + } + + if (proc->backlog == proc->max_backlog) + proc->notify_threads = true; + + return append_to_work_queue(proc, block, proc->notify_threads); +} + +static int add_sentinel_block(sqfs_block_processor_t *proc) +{ + sqfs_block_t *blk = calloc(1, sizeof(*blk)); + + if (blk == NULL) + return test_and_set_status(proc, SQFS_ERROR_ALLOC); + + blk->inode = proc->inode; + blk->flags = proc->blk_flags | SQFS_BLK_LAST_BLOCK; + + return enqueue_block(proc, blk); +} + +int sqfs_block_processor_begin_file(sqfs_block_processor_t *proc, + sqfs_inode_generic_t *inode, sqfs_u32 flags) +{ + if (proc->inode != NULL) + return test_and_set_status(proc, SQFS_ERROR_INTERNAL); + + if (flags & ~SQFS_BLK_USER_SETTABLE_FLAGS) + return test_and_set_status(proc, SQFS_ERROR_UNSUPPORTED); + + proc->inode = inode; + proc->blk_flags = flags | SQFS_BLK_FIRST_BLOCK; + proc->blk_index = 0; + proc->blk_current = NULL; + return 0; +} + +static int flush_block(sqfs_block_processor_t *proc, sqfs_block_t *block) +{ + block->index = proc->blk_index++; + block->flags = proc->blk_flags; + block->inode = proc->inode; + + if (is_zero_block(block->data, block->size)) { + sqfs_inode_make_extended(proc->inode); + proc->inode->data.file_ext.sparse += block->size; + proc->inode->num_file_blocks += 1; + proc->inode->extra[block->index] = 0; + free(block); + return 0; + } + + if (block->size < proc->max_block_size && + !(block->flags & SQFS_BLK_DONT_FRAGMENT)) { + block->flags |= SQFS_BLK_IS_FRAGMENT; + } else { + proc->inode->num_file_blocks += 1; + proc->blk_flags &= ~SQFS_BLK_FIRST_BLOCK; + } + + return enqueue_block(proc, block); +} + +int sqfs_block_processor_append(sqfs_block_processor_t *proc, const void *data, + size_t size) +{ + size_t diff; + void *new; + int err; + + while (size > 0) { + if (proc->blk_current == NULL) { + new = alloc_flex(sizeof(*proc->blk_current), 1, + proc->max_block_size); + + if (new == NULL) + return test_and_set_status(proc, + SQFS_ERROR_ALLOC); + + proc->blk_current = new; + } + + diff = proc->max_block_size - proc->blk_current->size; + + if (diff == 0) { + err = flush_block(proc, proc->blk_current); + proc->blk_current = NULL; + if (err) + return err; + continue; + } + + if (diff > size) + diff = size; + + memcpy(proc->blk_current->data + proc->blk_current->size, + data, diff); + + size -= diff; + proc->blk_current->size += diff; + data = (const char *)data + diff; + } + + if (proc->blk_current != NULL && + proc->blk_current->size == proc->max_block_size) { + err = flush_block(proc, proc->blk_current); + proc->blk_current = NULL; + return err; + } + + return 0; +} + +int sqfs_block_processor_end_file(sqfs_block_processor_t *proc) +{ + int err; + + if (proc->inode == NULL) + return test_and_set_status(proc, SQFS_ERROR_INTERNAL); + + if (!(proc->blk_flags & SQFS_BLK_FIRST_BLOCK)) { + if (proc->blk_current != NULL && + (proc->blk_flags & SQFS_BLK_DONT_FRAGMENT)) { + proc->blk_flags |= SQFS_BLK_LAST_BLOCK; + } else { + err = add_sentinel_block(proc); + if (err) + return err; + } + } + + if (proc->blk_current != NULL) { + err = flush_block(proc, proc->blk_current); + proc->blk_current = NULL; + } + + proc->inode = NULL; + proc->blk_flags = 0; + proc->blk_index = 0; + return 0; +} + +int sqfs_block_processor_finish(sqfs_block_processor_t *proc) +{ + int status = 0; + + append_to_work_queue(proc, NULL, true); + + while (proc->backlog > 0) { + status = wait_completed(proc); + if (status) + return status; + } + + if (proc->frag_block != NULL) { + status = append_to_work_queue(proc, proc->frag_block, true); + proc->frag_block = NULL; + + if (status) + return status; + + status = wait_completed(proc); + } + + return status; +} |