From c86d4388c1b427f892670c290c8f28751313640a Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Sat, 6 Mar 2021 21:59:46 +0100 Subject: Add a simple test case for the xattr_writer_t The test case basically adds a few key/value pairs and make sure they are deduplicated correctly, including a case where they are added in a different order and a case where the value is stored OOL. Signed-off-by: David Oberhollenzer --- tests/libsqfs/Makemodule.am | 5 +- tests/libsqfs/xattr_writer.c | 321 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 325 insertions(+), 1 deletion(-) create mode 100644 tests/libsqfs/xattr_writer.c diff --git a/tests/libsqfs/Makemodule.am b/tests/libsqfs/Makemodule.am index cad473c..0ad19d9 100644 --- a/tests/libsqfs/Makemodule.am +++ b/tests/libsqfs/Makemodule.am @@ -4,8 +4,11 @@ test_abi_LDADD = libsquashfs.la test_table_SOURCES = tests/libsqfs/table.c tests/test.h test_table_LDADD = libsquashfs.la +test_xattr_writer_SOURCES = tests/libsqfs/xattr_writer.c tests/test.h +test_xattr_writer_LDADD = libsquashfs.la + LIBSQFS_TESTS = \ - test_abi test_table + test_abi test_table test_xattr_writer check_PROGRAMS += $(LIBSQFS_TESTS) TESTS += $(LIBSQFS_TESTS) diff --git a/tests/libsqfs/xattr_writer.c b/tests/libsqfs/xattr_writer.c new file mode 100644 index 0000000..d5252e3 --- /dev/null +++ b/tests/libsqfs/xattr_writer.c @@ -0,0 +1,321 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * xattr_writer.c + * + * Copyright (C) 2021 David Oberhollenzer + */ +#include "config.h" +#include "../test.h" + +#include "sqfs/xattr_writer.h" +#include "sqfs/compressor.h" +#include "sqfs/xattr.h" +#include "sqfs/error.h" +#include "sqfs/super.h" +#include "sqfs/io.h" + +static sqfs_u8 file_data[1024]; +static size_t file_used = 0; + +static int dummy_write_at(sqfs_file_t *file, sqfs_u64 offset, + const void *buffer, size_t size) +{ + (void)file; + + if (offset >= sizeof(file_data)) + return SQFS_ERROR_OUT_OF_BOUNDS; + + if (size > (sizeof(file_data) - offset)) + return SQFS_ERROR_OUT_OF_BOUNDS; + + if (offset > file_used) + memset(file_data + file_used, 0, offset - file_used); + + if ((offset + size) > file_used) + file_used = offset + size; + + memcpy(file_data + offset, buffer, size); + return 0; +} + +static sqfs_u64 dummy_get_size(const sqfs_file_t *file) +{ + (void)file; + return file_used; +} + +static sqfs_s32 dummy_compress(sqfs_compressor_t *cmp, const sqfs_u8 *in, + sqfs_u32 size, sqfs_u8 *out, sqfs_u32 outsize) +{ + (void)cmp; + memcpy(out, in, outsize < size ? outsize : size); + return 0; +} + +static sqfs_file_t dummy_file = { + { NULL, NULL }, + NULL, + dummy_write_at, + dummy_get_size, + NULL, +}; + +static sqfs_compressor_t dummy_compressor = { + { NULL, NULL }, + NULL, + NULL, + NULL, + dummy_compress, +}; + +/*****************************************************************************/ + +int main(void) +{ + size_t offset, ool_value_offset, id_offset; + sqfs_xattr_id_table_t idtbl; + sqfs_xattr_writer_t *xwr; + sqfs_xattr_value_t value; + sqfs_xattr_entry_t key; + sqfs_xattr_id_t desc; + sqfs_super_t super; + char strbuf[32]; + sqfs_u16 hdr; + sqfs_u64 ref; + sqfs_u32 id; + int ret; + + /* setup */ + xwr = sqfs_xattr_writer_create(0); + TEST_NOT_NULL(xwr); + + /* record a block of key/value pairs */ + ret = sqfs_xattr_writer_begin(xwr, 0); + TEST_EQUAL_I(ret, 0); + + ret = sqfs_xattr_writer_add(xwr, "user.foobar", "test", 4); + TEST_EQUAL_I(ret, 0); + + ret = sqfs_xattr_writer_add(xwr, "security.selinux", "Xwhatever", 9); + TEST_EQUAL_I(ret, 0); + + ret = sqfs_xattr_writer_end(xwr, &id); + TEST_EQUAL_I(ret, 0); + TEST_EQUAL_UI(id, 0); + + /* record a second, different block */ + ret = sqfs_xattr_writer_begin(xwr, 0); + TEST_EQUAL_I(ret, 0); + + ret = sqfs_xattr_writer_add(xwr, "user.foobar", "bla", 3); + TEST_EQUAL_I(ret, 0); + + ret = sqfs_xattr_writer_add(xwr, "security.selinux", "blub", 4); + TEST_EQUAL_I(ret, 0); + + ret = sqfs_xattr_writer_end(xwr, &id); + TEST_EQUAL_I(ret, 0); + TEST_EQUAL_UI(id, 1); + + /* same as first block after sorting and gets the same ID */ + ret = sqfs_xattr_writer_begin(xwr, 0); + TEST_EQUAL_I(ret, 0); + + ret = sqfs_xattr_writer_add(xwr, "security.selinux", "Xwhatever", 9); + TEST_EQUAL_I(ret, 0); + + ret = sqfs_xattr_writer_add(xwr, "user.foobar", "test", 4); + TEST_EQUAL_I(ret, 0); + + ret = sqfs_xattr_writer_end(xwr, &id); + TEST_EQUAL_I(ret, 0); + TEST_EQUAL_UI(id, 0); + + /* the third assignment overwrites the first, making + the block identical to the second one */ + ret = sqfs_xattr_writer_begin(xwr, 0); + TEST_EQUAL_I(ret, 0); + + ret = sqfs_xattr_writer_add(xwr, "user.foobar", "mimimi", 6); + TEST_EQUAL_I(ret, 0); + + ret = sqfs_xattr_writer_add(xwr, "security.selinux", "blub", 4); + TEST_EQUAL_I(ret, 0); + + ret = sqfs_xattr_writer_add(xwr, "user.foobar", "bla", 3); + TEST_EQUAL_I(ret, 0); + + ret = sqfs_xattr_writer_end(xwr, &id); + TEST_EQUAL_I(ret, 0); + TEST_EQUAL_UI(id, 1); + + /* add another block with the same value, so it gets stored OOL */ + ret = sqfs_xattr_writer_begin(xwr, 0); + TEST_EQUAL_I(ret, 0); + + ret = sqfs_xattr_writer_add(xwr, "security.selinux", "Xwhatever", 9); + TEST_EQUAL_I(ret, 0); + + ret = sqfs_xattr_writer_end(xwr, &id); + TEST_EQUAL_I(ret, 0); + TEST_EQUAL_UI(id, 2); + + /* serialize */ + sqfs_super_init(&super, 131072, 0, SQFS_COMP_GZIP); + ret = sqfs_xattr_writer_flush(xwr, &dummy_file, &super, + &dummy_compressor); + TEST_EQUAL_I(ret, 0); + + TEST_EQUAL_UI(file_used, 177); + + /* meta data block holding the key-value-pairs */ + memcpy(&hdr, file_data, sizeof(hdr)); + hdr = le16toh(hdr); + TEST_EQUAL_UI(hdr, (0x8000 | 101)); + offset = 2; + + memcpy(&key, file_data + offset, sizeof(key)); + key.type = le16toh(key.type); + key.size = le16toh(key.size); + offset += sizeof(key); + TEST_EQUAL_UI(key.type, SQFS_XATTR_USER); + TEST_EQUAL_UI(key.size, 6); + memset(strbuf, '\0', sizeof(strbuf)); + memcpy(strbuf, file_data + offset, key.size); + TEST_STR_EQUAL(strbuf, "foobar"); + offset += key.size; + + memcpy(&value, file_data + offset, sizeof(value)); + value.size = le32toh(value.size); + offset += sizeof(value); + TEST_EQUAL_UI(value.size, 4); + memset(strbuf, '\0', sizeof(strbuf)); + memcpy(strbuf, file_data + offset, value.size); + TEST_STR_EQUAL(strbuf, "test"); + offset += value.size; + + memcpy(&key, file_data + offset, sizeof(key)); + key.type = le16toh(key.type); + key.size = le16toh(key.size); + offset += sizeof(key); + TEST_EQUAL_UI(key.type, SQFS_XATTR_SECURITY); + TEST_EQUAL_UI(key.size, 7); + memset(strbuf, '\0', sizeof(strbuf)); + memcpy(strbuf, file_data + offset, key.size); + TEST_STR_EQUAL(strbuf, "selinux"); + offset += key.size; + + ool_value_offset = offset; + + memcpy(&value, file_data + offset, sizeof(value)); + value.size = le32toh(value.size); + offset += sizeof(value); + TEST_EQUAL_UI(value.size, 9); + memset(strbuf, '\0', sizeof(strbuf)); + memcpy(strbuf, file_data + offset, value.size); + TEST_STR_EQUAL(strbuf, "Xwhatever"); + offset += value.size; + + memcpy(&key, file_data + offset, sizeof(key)); + key.type = le16toh(key.type); + key.size = le16toh(key.size); + offset += sizeof(key); + TEST_EQUAL_UI(key.type, SQFS_XATTR_USER); + TEST_EQUAL_UI(key.size, 6); + memset(strbuf, '\0', sizeof(strbuf)); + memcpy(strbuf, file_data + offset, key.size); + TEST_STR_EQUAL(strbuf, "foobar"); + offset += key.size; + + memcpy(&value, file_data + offset, sizeof(value)); + value.size = le32toh(value.size); + offset += sizeof(value); + TEST_EQUAL_UI(value.size, 3); + memset(strbuf, '\0', sizeof(strbuf)); + memcpy(strbuf, file_data + offset, value.size); + TEST_STR_EQUAL(strbuf, "bla"); + offset += value.size; + + memcpy(&key, file_data + offset, sizeof(key)); + key.type = le16toh(key.type); + key.size = le16toh(key.size); + offset += sizeof(key); + TEST_EQUAL_UI(key.type, SQFS_XATTR_SECURITY); + TEST_EQUAL_UI(key.size, 7); + memset(strbuf, '\0', sizeof(strbuf)); + memcpy(strbuf, file_data + offset, key.size); + TEST_STR_EQUAL(strbuf, "selinux"); + offset += key.size; + + memcpy(&value, file_data + offset, sizeof(value)); + value.size = le32toh(value.size); + offset += sizeof(value); + TEST_EQUAL_UI(value.size, 4); + memset(strbuf, '\0', sizeof(strbuf)); + memcpy(strbuf, file_data + offset, value.size); + TEST_STR_EQUAL(strbuf, "blub"); + offset += value.size; + + memcpy(&key, file_data + offset, sizeof(key)); + key.type = le16toh(key.type); + key.size = le16toh(key.size); + offset += sizeof(key); + TEST_EQUAL_UI(key.type, (SQFS_XATTR_SECURITY | SQFS_XATTR_FLAG_OOL)); + TEST_EQUAL_UI(key.size, 7); + memset(strbuf, '\0', sizeof(strbuf)); + memcpy(strbuf, file_data + offset, key.size); + TEST_STR_EQUAL(strbuf, "selinux"); + offset += key.size; + + memcpy(&value, file_data + offset, sizeof(value)); + value.size = le32toh(value.size); + offset += sizeof(value); + TEST_EQUAL_UI(value.size, 8); + memcpy(&ref, file_data + offset, sizeof(ref)); + ref = le64toh(ref); + TEST_EQUAL_UI(ref, (ool_value_offset - 2)); + offset += value.size; + + /* meta data block holding the ID descriptions */ + id_offset = offset; + + memcpy(&hdr, file_data + offset, sizeof(hdr)); + TEST_EQUAL_UI(le16toh(hdr), (0x8000 | (16 * 3))); + offset += sizeof(hdr); + + memcpy(&desc, file_data + offset, sizeof(desc)); + TEST_EQUAL_UI(le64toh(desc.xattr), 0); + TEST_EQUAL_UI(le32toh(desc.count), 2); + TEST_EQUAL_UI(le32toh(desc.size), 42); + offset += sizeof(desc); + + memcpy(&desc, file_data + offset, sizeof(desc)); + TEST_EQUAL_UI(le64toh(desc.xattr), 42); + TEST_EQUAL_UI(le32toh(desc.count), 2); + TEST_EQUAL_UI(le32toh(desc.size), 36); + offset += sizeof(desc); + + memcpy(&desc, file_data + offset, sizeof(desc)); + TEST_EQUAL_UI(le64toh(desc.xattr), 78); + TEST_EQUAL_UI(le32toh(desc.count), 1); + TEST_EQUAL_UI(le32toh(desc.size), 23); + offset += sizeof(desc); + + /* the xattr table itself */ + TEST_EQUAL_UI(super.xattr_id_table_start, offset); + + memcpy(&idtbl, file_data + offset, sizeof(idtbl)); + TEST_EQUAL_UI(le64toh(idtbl.xattr_table_start), 0); + TEST_EQUAL_UI(le32toh(idtbl.xattr_ids), 3); + offset += sizeof(idtbl); + + memcpy(&ref, file_data + offset, sizeof(ref)); + TEST_EQUAL_UI(le64toh(ref), id_offset); + offset += sizeof(ref); + + TEST_EQUAL_UI(offset, file_used); + + /* cleanup */ + sqfs_destroy(xwr); + return EXIT_SUCCESS; +} -- cgit v1.2.3