From ba99ef34e7b073c03519ef74f017091de6c9bee8 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Mon, 12 Jun 2023 21:21:40 +0200 Subject: Move sqfs_istream_t & sqfs_ostream_t into libsquashfs For now, only the interfaces and helper functions are moved, the concrete implementations remain in libio. Signed-off-by: David Oberhollenzer --- lib/sqfs/Makemodule.am | 15 ++++-- lib/sqfs/src/istream.c | 100 ++++++++++++++++++++++++++++++++++++++++ lib/sqfs/test/istream_read.c | 105 ++++++++++++++++++++++++++++++++++++++++++ lib/sqfs/test/istream_skip.c | 94 +++++++++++++++++++++++++++++++++++++ lib/sqfs/test/stream_splice.c | 96 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 407 insertions(+), 3 deletions(-) create mode 100644 lib/sqfs/src/istream.c create mode 100644 lib/sqfs/test/istream_read.c create mode 100644 lib/sqfs/test/istream_skip.c create mode 100644 lib/sqfs/test/stream_splice.c (limited to 'lib/sqfs') diff --git a/lib/sqfs/Makemodule.am b/lib/sqfs/Makemodule.am index d54134c..2727b11 100644 --- a/lib/sqfs/Makemodule.am +++ b/lib/sqfs/Makemodule.am @@ -30,7 +30,7 @@ libsquashfs_la_SOURCES = $(LIBSQFS_HEARDS) lib/sqfs/src/id_table.c \ lib/sqfs/src/block_processor/block_processor.c \ lib/sqfs/src/block_processor/backend.c \ lib/sqfs/src/frag_table.c lib/sqfs/src/block_writer.c \ - lib/sqfs/src/misc.c + lib/sqfs/src/misc.c lib/sqfs/src/istream.c libsquashfs_la_CPPFLAGS = $(AM_CPPFLAGS) libsquashfs_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(LIBSQUASHFS_SO_VERSION) libsquashfs_la_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS) $(ZLIB_CFLAGS) @@ -122,9 +122,18 @@ xattr_benchmark_LDADD = libcommon.a libsquashfs.la libcompat.a test_get_node_path_SOURCES = lib/sqfs/test/get_node_path.c test_get_node_path_LDADD = libcommon.a libsquashfs.la libcompat.a -LIBSQFS_TESTS = \ - test_abi test_xattr test_table test_xattr_writer test_get_node_path +test_istream_read_SOURCES = lib/sqfs/test/istream_read.c +test_istream_read_LDADD = libio.a libsquashfs.la libutil.a libcompat.a + +test_istream_skip_SOURCES = lib/sqfs/test/istream_skip.c +test_istream_skip_LDADD = libsquashfs.la libio.a libutil.a libcompat.a +test_stream_splice_SOURCES = lib/sqfs/test/stream_splice.c +test_stream_splice_LDADD = libsquashfs.la libio.a libutil.a libcompat.a + +LIBSQFS_TESTS = \ + test_abi test_xattr test_table test_xattr_writer test_get_node_path \ + test_istream_read test_istream_skip test_stream_splice noinst_PROGRAMS += xattr_benchmark check_PROGRAMS += $(LIBSQFS_TESTS) diff --git a/lib/sqfs/src/istream.c b/lib/sqfs/src/istream.c new file mode 100644 index 0000000..3d89461 --- /dev/null +++ b/lib/sqfs/src/istream.c @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: LGPL-3.0-or-later */ +/* + * istream.c + * + * Copyright (C) 2019 David Oberhollenzer + */ +#define SQFS_BUILDING_DLL +#include "config.h" + +#include "sqfs/io.h" + +#include + +sqfs_s32 sqfs_istream_read(sqfs_istream_t *strm, void *data, size_t size) +{ + sqfs_s32 total = 0; + + if (size > 0x7FFFFFFF) + size = 0x7FFFFFFF; + + while (size > 0) { + const sqfs_u8 *ptr; + size_t diff; + int ret; + + ret = strm->get_buffered_data(strm, &ptr, &diff, size); + if (ret > 0) + break; + if (ret < 0) + return ret; + + if (diff > size) + diff = size; + + memcpy(data, ptr, diff); + strm->advance_buffer(strm, diff); + data = (char *)data + diff; + size -= diff; + total += diff; + } + + return total; +} + +int sqfs_istream_skip(sqfs_istream_t *strm, sqfs_u64 size) +{ + while (size > 0) { + const sqfs_u8 *ptr; + size_t diff; + int ret; + + ret = strm->get_buffered_data(strm, &ptr, &diff, size); + if (ret < 0) + return ret; + if (ret > 0) + break; + + if ((sqfs_u64)diff > size) + diff = size; + + size -= diff; + strm->advance_buffer(strm, diff); + } + + return 0; +} + +sqfs_s32 sqfs_istream_splice(sqfs_istream_t *in, sqfs_ostream_t *out, + sqfs_u32 size) +{ + sqfs_s32 total = 0; + + if (size > 0x7FFFFFFF) + size = 0x7FFFFFFF; + + while (size > 0) { + const sqfs_u8 *ptr; + size_t diff; + int ret; + + ret = in->get_buffered_data(in, &ptr, &diff, size); + if (ret < 0) + return ret; + if (ret > 0) + break; + + if (diff > size) + diff = size; + + ret = out->append(out, ptr, diff); + if (ret) + return ret; + + total += diff; + size -= diff; + in->advance_buffer(in, diff); + } + + return total; +} diff --git a/lib/sqfs/test/istream_read.c b/lib/sqfs/test/istream_read.c new file mode 100644 index 0000000..f8facea --- /dev/null +++ b/lib/sqfs/test/istream_read.c @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * istream_read.c + * + * Copyright (C) 2023 David Oberhollenzer + */ +#include "config.h" + +#include "util/test.h" +#include "sqfs/io.h" +#include "io/mem.h" + +static const sqfs_u64 end0 = 449; /* region 1: filled with 'A' */ +static const sqfs_u64 end1 = 521; /* region 2: filled with 'B' */ +static const sqfs_u64 end2 = 941; /* region 3: filled with 'C' */ + +static sqfs_u8 rd_buffer[941]; + +static sqfs_u8 byte_at_offset(sqfs_u64 off) +{ + if (off < end0) + return 'A'; + if (off < end1) + return 'B'; + return 'C'; +} + +static void init_rd_buffer(void) +{ + for (size_t i = 0; i < end2; ++i) + rd_buffer[i] = byte_at_offset(i); +} + +int main(int argc, char **argv) +{ + sqfs_u8 read_buffer[61]; + sqfs_u64 read_off = 0; + sqfs_istream_t *dummy; + (void)argc; (void)argv; + + init_rd_buffer(); + dummy = istream_memory_create("dummy file", 103, + rd_buffer, sizeof(rd_buffer)); + TEST_NOT_NULL(dummy); + + /* region 1 */ + while (read_off < end0) { + size_t read_diff = end0 - read_off; + + if (read_diff > sizeof(read_buffer)) + read_diff = sizeof(read_buffer); + + int ret = sqfs_istream_read(dummy, read_buffer, read_diff); + TEST_ASSERT(ret > 0); + TEST_ASSERT((size_t)ret <= read_diff); + + for (int i = 0; i < ret; ++i) { + TEST_EQUAL_UI(read_buffer[i], 'A'); + } + + read_off += ret; + } + + /* region 2 */ + while (read_off < end1) { + size_t read_diff = end1 - read_off; + + if (read_diff > sizeof(read_buffer)) + read_diff = sizeof(read_buffer); + + int ret = sqfs_istream_read(dummy, read_buffer, read_diff); + TEST_ASSERT(ret > 0); + TEST_ASSERT((size_t)ret <= read_diff); + + for (int i = 0; i < ret; ++i) { + TEST_EQUAL_UI(read_buffer[i], 'B'); + } + + read_off += ret; + } + + /* region 3 */ + for (;;) { + size_t read_diff = sizeof(read_buffer); + + int ret = sqfs_istream_read(dummy, read_buffer, read_diff); + TEST_ASSERT(ret >= 0); + TEST_ASSERT((size_t)ret <= read_diff); + + if (ret == 0) { + TEST_EQUAL_UI(read_off, end2); + break; + } + + for (int i = 0; i < ret; ++i) { + TEST_EQUAL_UI(read_buffer[i], 'C'); + } + + read_off += ret; + TEST_ASSERT(read_off <= end2); + } + + sqfs_drop(dummy); + return EXIT_SUCCESS; +} diff --git a/lib/sqfs/test/istream_skip.c b/lib/sqfs/test/istream_skip.c new file mode 100644 index 0000000..d8a81f2 --- /dev/null +++ b/lib/sqfs/test/istream_skip.c @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * istream_skip.c + * + * Copyright (C) 2023 David Oberhollenzer + */ +#include "config.h" + +#include "sqfs/io.h" +#include "util/test.h" +#include "io/mem.h" + +static const sqfs_u64 end0 = 449; /* region 1: filled with 'A' */ +static const sqfs_u64 end1 = 521; /* region 2: filled with 'B' */ +static const sqfs_u64 end2 = 941; /* region 3: filled with 'C' */ + +static sqfs_u8 rd_buffer[941]; + +static sqfs_u8 byte_at_offset(sqfs_u64 off) +{ + if (off < end0) + return 'A'; + if (off < end1) + return 'B'; + return 'C'; +} + +static void init_rd_buffer(void) +{ + for (size_t i = 0; i < end2; ++i) + rd_buffer[i] = byte_at_offset(i); +} + +int main(int argc, char **argv) +{ + sqfs_u8 read_buffer[61]; + sqfs_u64 read_off = 0; + sqfs_istream_t *dummy; + (void)argc; (void)argv; + + init_rd_buffer(); + dummy = istream_memory_create("dummy file", 103, + rd_buffer, sizeof(rd_buffer)); + TEST_NOT_NULL(dummy); + + /* region 1 */ + while (read_off < end0) { + size_t read_diff = end0 - read_off; + + if (read_diff > sizeof(read_buffer)) + read_diff = sizeof(read_buffer); + + int ret = sqfs_istream_read(dummy, read_buffer, read_diff); + TEST_ASSERT(ret > 0); + TEST_ASSERT((size_t)ret <= read_diff); + + for (int i = 0; i < ret; ++i) { + TEST_EQUAL_UI(read_buffer[i], 'A'); + } + + read_off += ret; + } + + /* region 2 */ + { + int ret = sqfs_istream_skip(dummy, end2 - end1); + TEST_EQUAL_I(ret, 0); + read_off += (end2 - end1); + } + + /* region 3 */ + for (;;) { + size_t read_diff = sizeof(read_buffer); + + int ret = sqfs_istream_read(dummy, read_buffer, read_diff); + TEST_ASSERT(ret >= 0); + TEST_ASSERT((size_t)ret <= read_diff); + + if (ret == 0) { + TEST_EQUAL_UI(read_off, end2); + break; + } + + for (int i = 0; i < ret; ++i) { + TEST_EQUAL_UI(read_buffer[i], 'C'); + } + + read_off += ret; + TEST_ASSERT(read_off <= end2); + } + + sqfs_drop(dummy); + return EXIT_SUCCESS; +} diff --git a/lib/sqfs/test/stream_splice.c b/lib/sqfs/test/stream_splice.c new file mode 100644 index 0000000..6f40d1f --- /dev/null +++ b/lib/sqfs/test/stream_splice.c @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * stream_splice.c + * + * Copyright (C) 2023 David Oberhollenzer + */ +#include "config.h" + +#include "io/mem.h" +#include "util/test.h" +#include "sqfs/io.h" + +static const sqfs_u64 end0 = 449; /* region 1: filled with 'A' */ +static const sqfs_u64 end1 = 521; /* region 2: filled with 'B' */ +static const sqfs_u64 end2 = 941; /* region 3: filled with 'C' */ + +static sqfs_u8 rd_buffer[941]; + +static sqfs_u8 byte_at_offset(sqfs_u64 off) +{ + if (off < end0) + return 'A'; + if (off < end1) + return 'B'; + return 'C'; +} + +static void init_rd_buffer(void) +{ + for (size_t i = 0; i < end2; ++i) + rd_buffer[i] = byte_at_offset(i); +} + +/*****************************************************************************/ + +static int out_append(sqfs_ostream_t *strm, const void *data, size_t size); + +static sqfs_u64 out_offset = 0; + +static sqfs_ostream_t out = { + { 1, NULL, NULL }, + out_append, + NULL, + NULL, +}; + +static int out_append(sqfs_ostream_t *strm, const void *data, size_t size) +{ + const sqfs_u8 *ptr = data; + + TEST_ASSERT(strm == &out); + TEST_ASSERT(size > 0); + + while (size--) { + sqfs_u8 x = *(ptr++); + sqfs_u8 y = byte_at_offset(out_offset++); + + TEST_EQUAL_UI(x, y); + TEST_ASSERT(out_offset <= end2); + } + + return 0; +} + +/*****************************************************************************/ + +int main(int argc, char **argv) +{ + sqfs_u64 total = 0; + sqfs_istream_t *in; + sqfs_s32 ret; + (void)argc; (void)argv; + + init_rd_buffer(); + in = istream_memory_create("memory_in", 109, + rd_buffer, sizeof(rd_buffer)); + TEST_NOT_NULL(in); + + for (;;) { + ret = sqfs_istream_splice(in, &out, 211); + TEST_ASSERT(ret >= 0); + + if (ret == 0) + break; + + total += ret; + TEST_ASSERT(total <= end2); + TEST_ASSERT(out_offset <= end2); + TEST_EQUAL_UI(total, out_offset); + } + + TEST_EQUAL_UI(total, end2); + TEST_EQUAL_UI(out_offset, end2); + sqfs_drop(in); + return EXIT_SUCCESS; +} -- cgit v1.2.3