aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/sqfs/block.h26
-rw-r--r--include/sqfs/data_writer.h6
-rw-r--r--lib/sqfs/Makemodule.am1
-rw-r--r--lib/sqfs/data_writer/fileapi.c101
-rw-r--r--lib/sqfs/data_writer/internal.h12
-rw-r--r--lib/sqfs/data_writer/pthread.c31
-rw-r--r--lib/sqfs/data_writer/serial.c16
-rw-r--r--lib/sqfshelper/data_writer.c87
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);
}