diff options
-rw-r--r-- | include/sqfs/block.h | 26 | ||||
-rw-r--r-- | include/sqfs/data_writer.h | 6 | ||||
-rw-r--r-- | lib/sqfs/Makemodule.am | 1 | ||||
-rw-r--r-- | lib/sqfs/data_writer/fileapi.c | 101 | ||||
-rw-r--r-- | lib/sqfs/data_writer/internal.h | 12 | ||||
-rw-r--r-- | lib/sqfs/data_writer/pthread.c | 31 | ||||
-rw-r--r-- | lib/sqfs/data_writer/serial.c | 16 | ||||
-rw-r--r-- | lib/sqfshelper/data_writer.c | 87 |
8 files changed, 164 insertions, 116 deletions
diff --git a/include/sqfs/block.h b/include/sqfs/block.h index 5216fd7..0dee934 100644 --- a/include/sqfs/block.h +++ b/include/sqfs/block.h @@ -41,16 +41,6 @@ typedef enum { SQFS_BLK_DONT_COMPRESS = 0x0001, /** - * @brief Indicates that an equeued block is the first block of a file. - */ - SQFS_BLK_FIRST_BLOCK = 0x0002, - - /** - * @brief Indicates that an equeued block is the last block of a file. - */ - SQFS_BLK_LAST_BLOCK = 0x0004, - - /** * @brief Allign the block on disk to device block size. * * If set in combination with @ref SQFS_BLK_FIRST_BLOCK, the output @@ -60,13 +50,23 @@ typedef enum { * If used with @ref SQFS_BLK_LAST_BLOCK, the output file is padded * after writing the block. */ - SQFS_BLK_ALLIGN = 0x0008, + SQFS_BLK_ALLIGN = 0x0002, + + /** + * @brief Indicates that an equeued block is the first block of a file. + */ + SQFS_BLK_FIRST_BLOCK = 0x0800, + + /** + * @brief Indicates that an equeued block is the last block of a file. + */ + SQFS_BLK_LAST_BLOCK = 0x1000, /** * @brief Indicates that a block is a tail end of a file and the block * processor should take care of fragment packing and accounting. */ - SQFS_BLK_IS_FRAGMENT = 0x0010, + SQFS_BLK_IS_FRAGMENT = 0x2000, /** * @brief Set by the block processor on fragment blocks that @@ -82,7 +82,7 @@ typedef enum { /** * @brief The combination of all flags that are user settable. */ - SQFS_BLK_USER_SETTABLE_FLAGS = 0x001F, + SQFS_BLK_USER_SETTABLE_FLAGS = 0x0003, } E_SQFS_BLK_FLAGS; /** diff --git a/include/sqfs/data_writer.h b/include/sqfs/data_writer.h index cc99700..ffa3334 100644 --- a/include/sqfs/data_writer.h +++ b/include/sqfs/data_writer.h @@ -169,6 +169,10 @@ sqfs_data_writer_t *sqfs_data_writer_create(size_t max_block_size, */ SQFS_API void sqfs_data_writer_destroy(sqfs_data_writer_t *proc); +SQFS_API int sqfs_data_writer_begin_file(sqfs_data_writer_t *proc, + sqfs_inode_generic_t *inode, + uint32_t flags); + /** * @brief Add a block to be processed. * @@ -187,6 +191,8 @@ SQFS_API void sqfs_data_writer_destroy(sqfs_data_writer_t *proc); SQFS_API int sqfs_data_writer_enqueue(sqfs_data_writer_t *proc, sqfs_block_t *block); +SQFS_API int sqfs_data_writer_end_file(sqfs_data_writer_t *proc); + /** * @brief Wait for the works to finish and finally flush the current * fragment block. diff --git a/lib/sqfs/Makemodule.am b/lib/sqfs/Makemodule.am index 36a8cc8..a474423 100644 --- a/lib/sqfs/Makemodule.am +++ b/lib/sqfs/Makemodule.am @@ -21,6 +21,7 @@ libsquashfs_la_SOURCES += lib/sqfs/inode.c lib/sqfs/data_writer/fragment.c libsquashfs_la_SOURCES += lib/sqfs/data_writer/block.c lib/sqfs/io.c libsquashfs_la_SOURCES += lib/sqfs/data_writer/internal.h lib/sqfs/data_reader.c libsquashfs_la_SOURCES += lib/sqfs/data_writer/common.c +libsquashfs_la_SOURCES += lib/sqfs/data_writer/fileapi.c libsquashfs_la_CPPFLAGS = $(AM_CPPFLAGS) libsquashfs_la_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS) $(ZLIB_CFLAGS) libsquashfs_la_CFLAGS += $(XZ_CFLAGS) $(LZO_CFLAGS) $(LZ4_CFLAGS) diff --git a/lib/sqfs/data_writer/fileapi.c b/lib/sqfs/data_writer/fileapi.c new file mode 100644 index 0000000..b78d012 --- /dev/null +++ b/lib/sqfs/data_writer/fileapi.c @@ -0,0 +1,101 @@ +/* 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 add_sentinel_block(sqfs_data_writer_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 data_writer_enqueue(proc, blk); +} + +int sqfs_data_writer_begin_file(sqfs_data_writer_t *proc, + sqfs_inode_generic_t *inode, uint32_t 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; + proc->blk_index = 0; + proc->had_fragment = false; + return 0; +} + +int sqfs_data_writer_enqueue(sqfs_data_writer_t *proc, sqfs_block_t *block) +{ + int err; + + 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->block_sizes[block->index] = 0; + free(block); + return 0; + } + + if (block->size < proc->max_block_size) { + if (block->index > 0) { + err = add_sentinel_block(proc); + + if (err) { + free(block); + return err; + } + } + + proc->had_fragment = true; + block->flags |= SQFS_BLK_IS_FRAGMENT; + } else { + if (block->index == 0) + block->flags |= SQFS_BLK_FIRST_BLOCK; + + proc->inode->num_file_blocks += 1; + } + + return data_writer_enqueue(proc, block); +} + +int sqfs_data_writer_end_file(sqfs_data_writer_t *proc) +{ + int err; + + if (proc->inode == NULL) + return test_and_set_status(proc, SQFS_ERROR_INTERNAL); + + if (!proc->had_fragment && proc->inode->num_file_blocks > 0) { + err = add_sentinel_block(proc); + if (err) + return err; + } + + proc->inode = NULL; + proc->blk_flags = 0; + proc->blk_index = 0; + proc->had_fragment = false; + return 0; +} diff --git a/lib/sqfs/data_writer/internal.h b/lib/sqfs/data_writer/internal.h index 53ddc5f..9072c19 100644 --- a/lib/sqfs/data_writer/internal.h +++ b/lib/sqfs/data_writer/internal.h @@ -101,6 +101,12 @@ struct sqfs_data_writer_t { const sqfs_block_hooks_t *hooks; void *user_ptr; + /* file API */ + sqfs_inode_generic_t *inode; + uint32_t blk_flags; + size_t blk_index; + bool had_fragment; + /* used only by workers */ size_t max_block_size; @@ -138,4 +144,10 @@ SQFS_INTERNAL int data_writer_do_block(sqfs_block_t *block, sqfs_compressor_t *cmp, uint8_t *scratch, size_t scratch_size); +SQFS_INTERNAL +int test_and_set_status(sqfs_data_writer_t *proc, int status); + +SQFS_INTERNAL +int data_writer_enqueue(sqfs_data_writer_t *proc, sqfs_block_t *block); + #endif /* INTERNAL_H */ diff --git a/lib/sqfs/data_writer/pthread.c b/lib/sqfs/data_writer/pthread.c index 3170c11..9c9b0a2 100644 --- a/lib/sqfs/data_writer/pthread.c +++ b/lib/sqfs/data_writer/pthread.c @@ -156,18 +156,6 @@ static void append_to_work_queue(sqfs_data_writer_t *proc, pthread_cond_broadcast(&proc->queue_cond); } -static int test_and_set_status(sqfs_data_writer_t *proc, int status) -{ - pthread_mutex_lock(&proc->mtx); - if (proc->status == 0) { - proc->status = status; - } else { - status = proc->status; - } - pthread_cond_broadcast(&proc->queue_cond); - return status; -} - static sqfs_block_t *try_dequeue(sqfs_data_writer_t *proc) { sqfs_block_t *queue, *it, *prev; @@ -260,16 +248,23 @@ static int process_done_queue(sqfs_data_writer_t *proc, sqfs_block_t *queue) return status; } -int sqfs_data_writer_enqueue(sqfs_data_writer_t *proc, sqfs_block_t *block) +int test_and_set_status(sqfs_data_writer_t *proc, int status) +{ + pthread_mutex_lock(&proc->mtx); + if (proc->status == 0) { + proc->status = status; + } else { + status = proc->status; + } + pthread_cond_broadcast(&proc->queue_cond); + return status; +} + +int data_writer_enqueue(sqfs_data_writer_t *proc, sqfs_block_t *block) { sqfs_block_t *queue; int status; - if (block->flags & ~SQFS_BLK_USER_SETTABLE_FLAGS) { - free(block); - return test_and_set_status(proc, SQFS_ERROR_UNSUPPORTED); - } - pthread_mutex_lock(&proc->mtx); while (proc->backlog > proc->max_backlog && proc->status == 0) pthread_cond_wait(&proc->done_cond, &proc->mtx); diff --git a/lib/sqfs/data_writer/serial.c b/lib/sqfs/data_writer/serial.c index 38dcc58..916f497 100644 --- a/lib/sqfs/data_writer/serial.c +++ b/lib/sqfs/data_writer/serial.c @@ -35,7 +35,15 @@ void sqfs_data_writer_destroy(sqfs_data_writer_t *proc) data_writer_cleanup(proc); } -int sqfs_data_writer_enqueue(sqfs_data_writer_t *proc, sqfs_block_t *block) +int test_and_set_status(sqfs_data_writer_t *proc, int status) +{ + if (proc->status == 0) + proc->status = status; + + return proc->status; +} + +int data_writer_enqueue(sqfs_data_writer_t *proc, sqfs_block_t *block) { sqfs_block_t *fragblk = NULL; @@ -44,12 +52,6 @@ int sqfs_data_writer_enqueue(sqfs_data_writer_t *proc, sqfs_block_t *block) return proc->status; } - if (block->flags & ~SQFS_BLK_USER_SETTABLE_FLAGS) { - proc->status = SQFS_ERROR_UNSUPPORTED; - free(block); - return proc->status; - } - if (block->flags & SQFS_BLK_IS_FRAGMENT) { block->checksum = crc32(0, block->data, block->size); diff --git a/lib/sqfshelper/data_writer.c b/lib/sqfshelper/data_writer.c index 5c01cb8..ca47447 100644 --- a/lib/sqfshelper/data_writer.c +++ b/lib/sqfshelper/data_writer.c @@ -9,47 +9,17 @@ #include "highlevel.h" #include "util.h" -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <stdio.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 add_sentinel_block(sqfs_data_writer_t *data, - sqfs_inode_generic_t *inode, - uint32_t flags) -{ - sqfs_block_t *blk = calloc(1, sizeof(*blk)); - - if (blk == NULL) { - perror("creating sentinel block"); - return -1; - } - - blk->inode = inode; - blk->flags = flags; - - return sqfs_data_writer_enqueue(data, blk); -} - int write_data_from_file(sqfs_data_writer_t *data, sqfs_inode_generic_t *inode, sqfs_file_t *file, size_t block_size, int flags) { - uint32_t blk_flags = SQFS_BLK_FIRST_BLOCK; uint64_t filesz, offset; - size_t diff, i = 0; sqfs_block_t *blk; + size_t diff; int ret; + (void)flags; - if (flags & DW_DONT_COMPRESS) - blk_flags |= SQFS_BLK_DONT_COMPRESS; - - if (flags & DW_ALLIGN_DEVBLK) - blk_flags |= SQFS_BLK_ALLIGN; + if (sqfs_data_writer_begin_file(data, inode, 0)) + return -1; sqfs_inode_get_file_size(inode, &filesz); @@ -60,54 +30,15 @@ int write_data_from_file(sqfs_data_writer_t *data, sqfs_inode_generic_t *inode, diff = filesz - offset; } - ret = sqfs_file_create_block(file, offset, diff, inode, - blk_flags, &blk); + ret = sqfs_file_create_block(file, offset, diff, + NULL, 0, &blk); if (ret) return -1; - blk->index = i++; - - if (is_zero_block(blk->data, blk->size)) { - sqfs_inode_make_extended(inode); - inode->data.file_ext.sparse += blk->size; - inode->num_file_blocks += 1; - - inode->block_sizes[blk->index] = 0; - free(blk); - continue; - } - - if (diff < block_size && !(flags & DW_DONT_FRAGMENT)) { - if (!(blk_flags & (SQFS_BLK_FIRST_BLOCK | - SQFS_BLK_LAST_BLOCK))) { - blk_flags |= SQFS_BLK_LAST_BLOCK; - - if (add_sentinel_block(data, inode, - blk_flags)) { - free(blk); - return -1; - } - } - - blk->flags |= SQFS_BLK_IS_FRAGMENT; - - if (sqfs_data_writer_enqueue(data, blk)) - return -1; - } else { - if (sqfs_data_writer_enqueue(data, blk)) - return -1; - - blk_flags &= ~SQFS_BLK_FIRST_BLOCK; - inode->num_file_blocks += 1; - } - } - - if (!(blk_flags & (SQFS_BLK_FIRST_BLOCK | SQFS_BLK_LAST_BLOCK))) { - blk_flags |= SQFS_BLK_LAST_BLOCK; - - if (add_sentinel_block(data, inode, blk_flags)) + if (sqfs_data_writer_enqueue(data, blk)) return -1; } - return 0; + + return sqfs_data_writer_end_file(data); } |