From b635c78530d5d7f27f9805790c1f7ca227959177 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Sun, 12 Feb 2023 12:28:40 +0100 Subject: libtar: Add a test for the tar writing code Generate a simple tarball and compare it with a reference. Signed-off-by: David Oberhollenzer --- bin/gensquashfs/test/fstree_glob1.c | 7 ++ bin/tar2sqfs/test/sqfs.sha512 | 1 + lib/tar/Makemodule.am | 8 +- lib/tar/test/data/CREDITS | 4 + lib/tar/test/data/write/simple.tar | Bin 0 -> 10240 bytes lib/tar/test/tar_write_simple.c | 221 ++++++++++++++++++++++++++++++++++++ 6 files changed, 240 insertions(+), 1 deletion(-) create mode 100644 lib/tar/test/data/write/simple.tar create mode 100644 lib/tar/test/tar_write_simple.c diff --git a/bin/gensquashfs/test/fstree_glob1.c b/bin/gensquashfs/test/fstree_glob1.c index 5f4fdfe..2d3cb80 100644 --- a/bin/gensquashfs/test/fstree_glob1.c +++ b/bin/gensquashfs/test/fstree_glob1.c @@ -200,6 +200,13 @@ static void check_hierarchy(tree_node_t *root, bool subdir, bool recursive) TEST_NULL(n->data.dir.children); } + n = n->next; + TEST_NOT_NULL(n); + TEST_STR_EQUAL(n->name, "write"); + TEST_ASSERT(S_ISDIR(n->mode)); + TEST_ASSERT(n->parent == parentdir); + TEST_NULL(n->data.dir.children); + n = n->next; TEST_NOT_NULL(n); TEST_STR_EQUAL(n->name, "xattr"); diff --git a/bin/tar2sqfs/test/sqfs.sha512 b/bin/tar2sqfs/test/sqfs.sha512 index 609e154..a915b02 100644 --- a/bin/tar2sqfs/test/sqfs.sha512 +++ b/bin/tar2sqfs/test/sqfs.sha512 @@ -25,4 +25,5 @@ a5e95c464f41249da9a4156db3a23d30e01652881e839912f632f2614f1775e62a3fed184efbec1a 627a69ed25f9b5380d269fbe12603818d73b29d6a1155fcf7bebca2ba30ec1cce7b8405394498333f9847f10f0768b80b94b723551dbff10c633d2887e62b804 test_tar/data/xattr/xattr-schily.sqfs 627a69ed25f9b5380d269fbe12603818d73b29d6a1155fcf7bebca2ba30ec1cce7b8405394498333f9847f10f0768b80b94b723551dbff10c633d2887e62b804 test_tar/data/xattr/xattr-libarchive.sqfs b8e0e1cb41663c3d6278bf214234ac00ae8b86b9bc16d086bd0a7bfa9b0d28d626f70c6a1bd6f05dbbfa46431ce3f4518a4be38caf87b1f071d57edae24c5b10 test_tar/data/xattr/acl.sqfs +6b201a275180d93459f6e9d94900a9bbb14da1c4f68cc7ca5850eb8cab982617ec6ae5695ca3c23c6cbbfa93cc3957367d4f3ae636706ef176059090b3d92c3f test_tar/data/write/simple.sqfs bae693082a771c500c2d6b52a8eeb91decd98e90eaae379951bcc80589533ff43b58375f8a7f3de77c35456ee7fb269a6b17e4c29b291475578ba8453f152d0e test_tar/root-becomes.sqfs diff --git a/lib/tar/Makemodule.am b/lib/tar/Makemodule.am index 9faeecf..07eb497 100644 --- a/lib/tar/Makemodule.am +++ b/lib/tar/Makemodule.am @@ -179,6 +179,11 @@ test_tar_istream3_CPPFLAGS += -DTESTFILE=istream/sparse.tar tar_fuzz_SOURCES = lib/tar/test/tar_fuzz.c tar_fuzz_LDADD = libtar.a libio.a libutil.a libcompat.a +test_tar_write_simple_SOURCES = lib/tar/test/tar_write_simple.c +test_tar_write_simple_LDADD = libtar.a libio.a libutil.a libcompat.a +test_tar_write_simple_CPPFLAGS = $(AM_CPPFLAGS) -DTESTPATH=$(TARDATADIR) +test_tar_write_simple_CPPFLAGS += -DTESTFILE=write/simple.tar + LIBTAR_TESTS = \ test_tar_ustar0 test_tar_ustar1 test_tar_ustar2 test_tar_ustar3 \ test_tar_ustar4 test_tar_ustar5 test_tar_ustar6 \ @@ -190,7 +195,8 @@ LIBTAR_TESTS = \ test_tar_sparse_gnu2 test_tar_sparse_gnu3 \ test_tar_xattr_bsd test_tar_xattr_schily test_tar_xattr_schily_bin \ test_tar_target_filled \ - test_tar_istream test_tar_istream2 test_tar_istream3 + test_tar_istream test_tar_istream2 test_tar_istream3 \ + test_tar_write_simple check_PROGRAMS += $(LIBTAR_TESTS) TESTS += $(LIBTAR_TESTS) diff --git a/lib/tar/test/data/CREDITS b/lib/tar/test/data/CREDITS index dab8951..1e7fb32 100644 --- a/lib/tar/test/data/CREDITS +++ b/lib/tar/test/data/CREDITS @@ -36,3 +36,7 @@ The following addtional files have been added: - istream/sparse.tar Derived from sparse/gnu.tar and contains some test data for testing the tar istream implementation. + - write/simple.tar + Created using the tar writer to verify that it works as intended. Used + for testing the tar writer to check if it still produces identical + output. diff --git a/lib/tar/test/data/write/simple.tar b/lib/tar/test/data/write/simple.tar new file mode 100644 index 0000000..a910daa Binary files /dev/null and b/lib/tar/test/data/write/simple.tar differ diff --git a/lib/tar/test/tar_write_simple.c b/lib/tar/test/tar_write_simple.c new file mode 100644 index 0000000..c78565b --- /dev/null +++ b/lib/tar/test/tar_write_simple.c @@ -0,0 +1,221 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * tar_write_simple.c + * + * Copyright (C) 2023 David Oberhollenzer + */ +#include "config.h" +#include "tar/tar.h" +#include "io/ostream.h" +#include "io/file.h" +#include "util/test.h" +#include "compat.h" + +/*****************************************************************************/ + +static int buffer_append(ostream_t *strm, const void *data, size_t size); +static const char *buffer_get_filename(ostream_t *strm); + +static ostream_t mem_stream = { + { 1, NULL, NULL }, + buffer_append, + NULL, + NULL, + buffer_get_filename, +}; + +static sqfs_u8 wr_buffer[1024 * 10]; +static size_t wr_offset = 0; + +static sqfs_u8 rd_buffer[1024 * 10]; + +static int buffer_append(ostream_t *strm, const void *data, size_t size) +{ + TEST_ASSERT(strm == &mem_stream); + TEST_NOT_NULL(data); + TEST_ASSERT(wr_offset < sizeof(wr_buffer)); + TEST_ASSERT(size > 0); + TEST_ASSERT((sizeof(wr_buffer) - wr_offset) >= size); + + memcpy(wr_buffer + wr_offset, data, size); + wr_offset += size; + return 0; +} + +static const char *buffer_get_filename(ostream_t *strm) +{ + TEST_ASSERT(strm == &mem_stream); + return "dummy"; +} + +/*****************************************************************************/ + +#define TIME_STAMP (1057296600) + +static tar_xattr_t *mkxattr(const char *key, const sqfs_u8 *value, + size_t value_len) +{ + size_t key_len = strlen(key); + tar_xattr_t *out = malloc(sizeof(*out) + key_len + 1 + value_len + 1); + + TEST_NOT_NULL(out); + + out->next = NULL; + out->key = out->data; + out->value = (sqfs_u8 *)(out->data + key_len + 1); + out->value_len = value_len; + + memcpy(out->data, key, key_len); + out->data[key_len] = '\0'; + + memcpy(out->data + key_len + 1, value, value_len); + out->data[key_len + 1 + value_len] = '\0'; + + return out; +} + +static tar_xattr_t *mkxattr_chain(void) +{ + static const uint8_t value[] = { + 0x00, 0x00, 0x00, 0x02, + 0x00, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + }; + tar_xattr_t *list; + + list = mkxattr("user.mime_type", (const sqfs_u8 *)"blob/magic", 10); + list->next = mkxattr("security.capability", value, sizeof(value)); + + return list; +} + +int main(int argc, char **argv) +{ + tar_xattr_t *xattr; + struct stat sb; + istream_t *fp; + int ret; + (void)argc; (void)argv; + + /* genereate some archive contents */ + memset(&sb, 0, sizeof(sb)); + sb.st_mode = S_IFDIR | 0755; + sb.st_mtime = TIME_STAMP; + ret = write_tar_header(&mem_stream, &sb, "dev/", NULL, NULL, 0); + TEST_EQUAL_I(ret, 0); + + /* device files */ + sb.st_mode = S_IFCHR | 0620; + sb.st_gid = 5; + sb.st_rdev = makedev(4, 0); + ret = write_tar_header(&mem_stream, &sb, "dev/tty0", NULL, NULL, 1); + TEST_EQUAL_I(ret, 0); + + sb.st_rdev = makedev(4, 1); + ret = write_tar_header(&mem_stream, &sb, "dev/tty1", NULL, NULL, 2); + TEST_EQUAL_I(ret, 0); + + sb.st_rdev = makedev(4, 2); + ret = write_tar_header(&mem_stream, &sb, "dev/tty2", NULL, NULL, 3); + TEST_EQUAL_I(ret, 0); + + memset(&sb, 0, sizeof(sb)); + sb.st_mode = S_IFDIR | 0755; + sb.st_mtime = TIME_STAMP; + ret = write_tar_header(&mem_stream, &sb, "usr/", NULL, NULL, 4); + TEST_EQUAL_I(ret, 0); + + ret = write_tar_header(&mem_stream, &sb, "usr/bin/", NULL, NULL, 5); + TEST_EQUAL_I(ret, 0); + + /* sym link */ + sb.st_mode = S_IFLNK | 0777; + sb.st_size = 7; + ret = write_tar_header(&mem_stream, &sb, "bin", "usr/bin", NULL, 6); + TEST_EQUAL_I(ret, 0); + + memset(&sb, 0, sizeof(sb)); + sb.st_mode = S_IFDIR | 0755; + sb.st_mtime = TIME_STAMP; + ret = write_tar_header(&mem_stream, &sb, "home/", NULL, NULL, 7); + TEST_EQUAL_I(ret, 0); + + sb.st_mode = S_IFDIR | 0750; + sb.st_uid = 1000; + sb.st_gid = 1000; + ret = write_tar_header(&mem_stream, &sb, "home/goliath/", + NULL, NULL, 8); + TEST_EQUAL_I(ret, 0); + + /* regular file with actual content */ + sb.st_mode = S_IFREG | 0644; + sb.st_size = 14; + ret = write_tar_header(&mem_stream, &sb, "home/goliath/hello.txt", + NULL, NULL, 9); + TEST_EQUAL_I(ret, 0); + + ret = ostream_append(&mem_stream, "Hello, World!\n", 14); + TEST_EQUAL_I(ret, 0); + ret = padd_file(&mem_stream, 14); + TEST_EQUAL_I(ret, 0); + + /* hard link */ + ret = write_hard_link(&mem_stream, &sb, "home/goliath/world.txt", + "home/goliath/hello.txt", 10); + TEST_EQUAL_I(ret, 0); + + /* something with xattrs */ + xattr = mkxattr_chain(); + sb.st_mode = S_IFREG | 0750; + sb.st_size = 4; + ret = write_tar_header(&mem_stream, &sb, "home/goliath/test.exe", + NULL, xattr, 11); + TEST_EQUAL_I(ret, 0); + free_xattr_list(xattr); + + ret = ostream_append(&mem_stream, ":-)\n", 4); + TEST_EQUAL_I(ret, 0); + ret = padd_file(&mem_stream, 4); + TEST_EQUAL_I(ret, 0); + + /* now try something with a long name */ + memset(&sb, 0, sizeof(sb)); + sb.st_mode = S_IFREG | 0755; + sb.st_mtime = TIME_STAMP; + sb.st_size = 42; + ret = write_tar_header(&mem_stream, &sb, + "mnt/windows_drive/C/Documents and Settings/" + "Joe Random User/My Documents/My Evil Plans/" + "file format nonsense/really long name.doc", + NULL, NULL, 12); + TEST_EQUAL_I(ret, 0); + + ret = ostream_append(&mem_stream, + "Annoy people with really long file paths!\n", + 42); + TEST_EQUAL_I(ret, 0); + ret = padd_file(&mem_stream, 42); + TEST_EQUAL_I(ret, 0); + + /* compare with reference */ + TEST_EQUAL_UI(wr_offset, sizeof(wr_buffer)); + TEST_EQUAL_UI(sizeof(rd_buffer), sizeof(wr_buffer)); + + fp = istream_open_file(STRVALUE(TESTPATH) "/" STRVALUE(TESTFILE)); + TEST_NOT_NULL(fp); + + ret = istream_read(fp, rd_buffer, sizeof(rd_buffer)); + TEST_ASSERT(ret > 0); + TEST_EQUAL_UI(ret, sizeof(rd_buffer)); + + ret = istream_read(fp, rd_buffer, sizeof(rd_buffer)); + TEST_EQUAL_I(ret, 0); + + sqfs_drop(fp); + + ret = memcmp(wr_buffer, rd_buffer, sizeof(rd_buffer)); + TEST_EQUAL_I(ret, 0); + return EXIT_SUCCESS; +} -- cgit v1.2.3