From: Michihiro NAKAJIMA Date: Sun, 21 Oct 2012 02:11:46 +0000 (+0900) Subject: Use liblzo2 for the lzop write filter. X-Git-Tag: v3.1.0~40^2~23 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7e8357b376f8343b742de6aeac622eddaaf0df64;p=thirdparty%2Flibarchive.git Use liblzo2 for the lzop write filter. --- diff --git a/cpio/test/test_option_lzop.c b/cpio/test/test_option_lzop.c index a1812d3c7..9f1666e9c 100644 --- a/cpio/test/test_option_lzop.c +++ b/cpio/test/test_option_lzop.c @@ -29,22 +29,26 @@ __FBSDID("$FreeBSD$"); DEFINE_TEST(test_option_lzop) { char *p; + int r; size_t s; - if (!canLzop()) { - skipping("lzop is not supported on this platform"); - return; - } - /* Create a file. */ assertMakeFile("f", 0644, "a"); /* Archive it with lzop compression. */ - assertEqualInt(0, - systemf("echo f | %s -o --lzop >archive.out 2>archive.err", - testprog)); + r = systemf("echo f | %s -o --lzop >archive.out 2>archive.err", + testprog); p = slurpfile(&s, "archive.err"); p[s] = '\0'; + if (r != 0) { + if (!canLzop()) { + skipping("lzop is not supported on this platform"); + return; + } + failure("--lzop option is broken"); + assertEqualInt(r, 0); + return; + } /* Check that the archive file has an lzma signature. */ p = slurpfile(&s, "archive.out"); assert(s > 2); diff --git a/libarchive/archive_write_add_filter_lzop.c b/libarchive/archive_write_add_filter_lzop.c index 5e7a71159..088ecea51 100644 --- a/libarchive/archive_write_add_filter_lzop.c +++ b/libarchive/archive_write_add_filter_lzop.c @@ -26,6 +26,8 @@ #include "archive_platform.h" __FBSDID("$FreeBSD$"); +//#undef HAVE_LZO_LZOCONF_H +//#undef HAVE_LZO_LZO1X_H #ifdef HAVE_ERRNO_H #include @@ -36,14 +38,40 @@ __FBSDID("$FreeBSD$"); #ifdef HAVE_STRING_H #include #endif +#include +#ifdef HAVE_LZO_LZOCONF_H +#include +#endif +#ifdef HAVE_LZO_LZO1X_H +#include +#endif #include "archive.h" #include "archive_string.h" +#include "archive_endian.h" #include "archive_write_private.h" +enum lzo_method { + METHOD_LZO1X_1 = 1, + METHOD_LZO1X_1_15 = 2, + METHOD_LZO1X_999 = 3 +}; struct write_lzop { - struct archive_write_program_data *pdata; int compression_level; +#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H) + unsigned char *uncompressed; + size_t uncompressed_buffer_size; + size_t uncompressed_avail_bytes; + unsigned char *compressed; + size_t compressed_buffer_size; + enum lzo_method method; + unsigned char level; + lzo_voidp work_buffer; + lzo_uint32 work_buffer_size; + char header_written; +#else + struct archive_write_program_data *pdata; +#endif }; static int archive_write_lzop_open(struct archive_write_filter *); @@ -54,6 +82,57 @@ static int archive_write_lzop_write(struct archive_write_filter *, static int archive_write_lzop_close(struct archive_write_filter *); static int archive_write_lzop_free(struct archive_write_filter *); +#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H) +/* Maximum block size. */ +#define BLOCK_SIZE (256 * 1024) +/* Block infomation is composed of uncompressed size(4 bytes), + * compressed size(4 bytes) and the checksum of uncompressed data(4 bytes) + * in this lzop writer. */ +#define BLOCK_INfO_SIZE 12 + +#define HEADER_VERSION 9 +#define HEADER_LIBVERSION 11 +#define HEADER_METHOD 15 +#define HEADER_LEVEL 16 +#define HEADER_MTIME_LOW 25 +#define HEADER_MTIME_HIGH 29 +#define HEADER_H_CHECKSUM 34 + +/* + * Header template. + */ +static const unsigned char header[] = { + /* LZOP Magic code 9 bytes */ + 0x89, 0x4c, 0x5a, 0x4f, 0x00, 0x0d, 0x0a, 0x1a, 0x0a, + /* LZOP utility version(fake data) 2 bytes */ + 0x10, 0x30, + /* LZO library version 2 bytes */ + 0x09, 0x40, + /* Minimum required LZO library version 2 bytes */ + 0x09, 0x40, + /* Method */ + 1, + /* Level */ + 5, + /* Flags 4 bytes + * -OS Unix + * -Stdout + * -Stdin + * -Adler32 used for uncompressed data 4 bytes */ + 0x03, 0x00, 0x00, 0x0d, + /* Mode (AE_IFREG | 0644) 4 bytes */ + 0x00, 0x00, 0x81, 0xa4, + /* Mtime low 4 bytes */ + 0x00, 0x00, 0x00, 0x00, + /* Mtime high 4 bytes */ + 0x00, 0x00, 0x00, 0x00, + /* Filename length */ + 0x00, + /* Header checksum 4 bytes */ + 0x00, 0x00, 0x00, 0x00, +}; +#endif + int archive_write_add_filter_lzop(struct archive *_a) { @@ -68,12 +147,6 @@ archive_write_add_filter_lzop(struct archive *_a) archive_set_error(_a, ENOMEM, "Can't allocate memory"); return (ARCHIVE_FATAL); } - data->pdata = __archive_write_program_allocate(); - if (data->pdata == NULL) { - free(data); - archive_set_error(_a, ENOMEM, "Can't allocate memory"); - return (ARCHIVE_FATAL); - } f->name = "lzop"; f->code = ARCHIVE_FILTER_LZOP; @@ -83,12 +156,52 @@ archive_write_add_filter_lzop(struct archive *_a) f->write = archive_write_lzop_write; f->close = archive_write_lzop_close; f->free = archive_write_lzop_free; - - /* Note: This filter always uses an external program, so we - * return "warn" to inform of the fact. */ +#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H) + if (lzo_init() != LZO_E_OK) { + free(data); + archive_set_error(_a, ARCHIVE_ERRNO_MISC, + "lzo_init(type check) failed"); + return (ARCHIVE_FATAL); + } + if (lzo_version() < 0x940) { + free(data); + archive_set_error(_a, ARCHIVE_ERRNO_MISC, + "liblzo library is too old(%s < 0.940)", + lzo_version_string()); + return (ARCHIVE_FATAL); + } + data->compression_level = 5; + return (ARCHIVE_OK); +#else + data->pdata = __archive_write_program_allocate(); + if (data->pdata == NULL) { + free(data); + archive_set_error(_a, ENOMEM, "Can't allocate memory"); + return (ARCHIVE_FATAL); + } + data->compression_level = 0; + /* Note: We return "warn" to inform of using an external lzop + * program. */ archive_set_error(_a, ARCHIVE_ERRNO_MISC, "Using external lzop program for lzop compression"); return (ARCHIVE_WARN); +#endif +} + +static int +archive_write_lzop_free(struct archive_write_filter *f) +{ + struct write_lzop *data = (struct write_lzop *)f->data; + +#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H) + free(data->uncompressed); + free(data->compressed); + free(data->work_buffer); +#else + __archive_write_program_free(data->pdata); +#endif + free(data); + return (ARCHIVE_OK); } static int @@ -110,6 +223,229 @@ archive_write_lzop_options(struct archive_write_filter *f, const char *key, return (ARCHIVE_WARN); } +#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H) +static int +archive_write_lzop_open(struct archive_write_filter *f) +{ + struct write_lzop *data = (struct write_lzop *)f->data; + int ret; + + ret = __archive_write_open_filter(f->next_filter); + if (ret != ARCHIVE_OK) + return (ret); + + switch (data->compression_level) { + case 1: + data->method = METHOD_LZO1X_1_15; data->level = 1; break; + default: + case 2: case 3: case 4: case 5: case 6: + data->method = METHOD_LZO1X_1; data->level = 5; break; + case 7: + data->method = METHOD_LZO1X_999; data->level = 7; break; + case 8: + data->method = METHOD_LZO1X_999; data->level = 8; break; + case 9: + data->method = METHOD_LZO1X_999; data->level = 9; break; + } + switch (data->method) { + case METHOD_LZO1X_1: + data->work_buffer_size = LZO1X_1_MEM_COMPRESS; break; + case METHOD_LZO1X_1_15: + data->work_buffer_size = LZO1X_1_15_MEM_COMPRESS; break; + case METHOD_LZO1X_999: + data->work_buffer_size = LZO1X_999_MEM_COMPRESS; break; + } + if (data->work_buffer == NULL) { + data->work_buffer = (lzo_voidp)malloc(data->work_buffer_size); + if (data->work_buffer == NULL) { + archive_set_error(f->archive, ENOMEM, + "Can't allocate data for compression buffer"); + return (ARCHIVE_FATAL); + } + } + if (data->compressed == NULL) { + data->compressed_buffer_size = sizeof(header) + + BLOCK_SIZE + (BLOCK_SIZE >> 4) + 64 + 3; + data->compressed = (unsigned char *) + malloc(data->compressed_buffer_size); + if (data->compressed == NULL) { + archive_set_error(f->archive, ENOMEM, + "Can't allocate data for compression buffer"); + return (ARCHIVE_FATAL); + } + } + if (data->uncompressed == NULL) { + data->uncompressed_buffer_size = BLOCK_SIZE; + data->uncompressed = (unsigned char *) + malloc(data->uncompressed_buffer_size); + if (data->uncompressed == NULL) { + archive_set_error(f->archive, ENOMEM, + "Can't allocate data for compression buffer"); + return (ARCHIVE_FATAL); + } + data->uncompressed_avail_bytes = BLOCK_SIZE; + } + return (ARCHIVE_OK); +} + +static int +make_header(struct archive_write_filter *f) +{ + struct write_lzop *data = (struct write_lzop *)f->data; + int64_t t; + uint32_t checksum; + + memcpy(data->compressed, header, sizeof(header)); + /* Overwrite library version. */ + data->compressed[HEADER_LIBVERSION] = (unsigned char ) + (lzo_version() >> 8) & 0xff; + data->compressed[HEADER_LIBVERSION + 1] = (unsigned char ) + lzo_version() & 0xff; + /* Overwrite method and level. */ + data->compressed[HEADER_METHOD] = (unsigned char)data->method; + data->compressed[HEADER_LEVEL] = data->level; + /* Overwrite mtime with current time. */ + t = (int64_t)time(NULL); + archive_be32enc(&data->compressed[HEADER_MTIME_LOW], + (uint32_t)(t & 0xffffffff)); + archive_be32enc(&data->compressed[HEADER_MTIME_HIGH], + (uint32_t)((t >> 32) & 0xffffffff)); + /* Overwrite header checksum with calculated value. */ + checksum = lzo_adler32(1, data->compressed + HEADER_VERSION, + (lzo_uint)(HEADER_H_CHECKSUM - HEADER_VERSION)); + archive_be32enc(&data->compressed[HEADER_H_CHECKSUM], checksum); + return (sizeof(header)); +} + +static int +drive_compressor(struct archive_write_filter *f) +{ + struct write_lzop *data = (struct write_lzop *)f->data; + unsigned char *p; + const int block_info_bytes = 12; + int header_bytes, r; + lzo_uint usize, csize; + uint32_t checksum; + + if (!data->header_written) { + header_bytes = make_header(f); + data->header_written = 1; + } else + header_bytes = 0; + p = data->compressed; + + usize = (lzo_uint) + (data->uncompressed_buffer_size - data->uncompressed_avail_bytes); + csize = 0; + switch (data->method) { + default: + case METHOD_LZO1X_1: + r = lzo1x_1_compress(data->uncompressed, usize, + p + header_bytes + block_info_bytes, &csize, + data->work_buffer); + break; + case METHOD_LZO1X_1_15: + r = lzo1x_1_15_compress(data->uncompressed, usize, + p + header_bytes + block_info_bytes, &csize, + data->work_buffer); + break; + case METHOD_LZO1X_999: + r = lzo1x_999_compress_level(data->uncompressed, usize, + p + header_bytes + block_info_bytes, &csize, + data->work_buffer, NULL, 0, 0, data->level); + break; + } + if (r != LZO_E_OK) { + archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, + "Lzop compression failed: returned status %d", r); + return (ARCHIVE_FATAL); + } + + /* Store uncompressed size. */ + archive_be32enc(p + header_bytes, (uint32_t)usize); + /* Store the checksum of the uncompressed data. */ + checksum = lzo_adler32(1, data->uncompressed, usize); + archive_be32enc(p + header_bytes + 8, checksum); + + if (csize < usize) { + /* Store compressed size. */ + archive_be32enc(p + header_bytes + 4, (uint32_t)csize); + r = __archive_write_filter(f->next_filter, data->compressed, + header_bytes + block_info_bytes + csize); + } else { + /* + * This case, we output uncompressed data instead. + */ + /* Store uncompressed size as compressed size. */ + archive_be32enc(p + header_bytes + 4, (uint32_t)usize); + r = __archive_write_filter(f->next_filter, data->compressed, + header_bytes + block_info_bytes); + if (r != ARCHIVE_OK) + return (ARCHIVE_FATAL); + r = __archive_write_filter(f->next_filter, data->uncompressed, + usize); + } + + if (r != ARCHIVE_OK) + return (ARCHIVE_FATAL); + return (ARCHIVE_OK); +} + +static int +archive_write_lzop_write(struct archive_write_filter *f, + const void *buff, size_t length) +{ + struct write_lzop *data = (struct write_lzop *)f->data; + const char *p = buff; + int r; + + do { + if (data->uncompressed_avail_bytes > length) { + memcpy(data->uncompressed + + data->uncompressed_buffer_size + - data->uncompressed_avail_bytes, + p, length); + data->uncompressed_avail_bytes -= length; + return (ARCHIVE_OK); + } + + memcpy(data->uncompressed + data->uncompressed_buffer_size + - data->uncompressed_avail_bytes, + p, data->uncompressed_avail_bytes); + length -= data->uncompressed_avail_bytes; + p += data->uncompressed_avail_bytes; + data->uncompressed_avail_bytes = 0; + + r = drive_compressor(f); + if (r != ARCHIVE_OK) return (r); + data->uncompressed_avail_bytes = BLOCK_SIZE; + } while (length); + + return (ARCHIVE_OK); +} + +static int +archive_write_lzop_close(struct archive_write_filter *f) +{ + struct write_lzop *data = (struct write_lzop *)f->data; + const uint32_t endmark = 0; + int r; + + if (data->uncompressed_avail_bytes < BLOCK_SIZE) { + /* Compress and output remaining data. */ + r = drive_compressor(f); + if (r != ARCHIVE_OK) + return (r); + } + /* Write a zero uncompressed size as the end mark of the series of + * compressed block. */ + r = __archive_write_filter(f->next_filter, &endmark, sizeof(endmark)); + if (r != ARCHIVE_OK) + return (r); + return (__archive_write_close_filter(f->next_filter)); +} + +#else static int archive_write_lzop_open(struct archive_write_filter *f) { @@ -121,6 +457,7 @@ archive_write_lzop_open(struct archive_write_filter *f) archive_strcpy(&as, "lzop"); /* Specify compression level. */ if (data->compression_level > 0) { + archive_strappend_char(&as, ' '); archive_strappend_char(&as, '-'); archive_strappend_char(&as, '0' + data->compression_level); } @@ -146,13 +483,4 @@ archive_write_lzop_close(struct archive_write_filter *f) return __archive_write_program_close(f, data->pdata); } - -static int -archive_write_lzop_free(struct archive_write_filter *f) -{ - struct write_lzop *data = (struct write_lzop *)f->data; - - __archive_write_program_free(data->pdata); - free(data); - return (ARCHIVE_OK); -} +#endif diff --git a/libarchive/test/test_read_truncated_filter.c b/libarchive/test/test_read_truncated_filter.c index 73254d398..2fe7f6553 100644 --- a/libarchive/test/test_read_truncated_filter.c +++ b/libarchive/test/test_read_truncated_filter.c @@ -135,6 +135,7 @@ DEFINE_TEST(test_read_truncated_filter) test_truncation("compress", archive_write_add_filter_compress, 0); test_truncation("gzip", archive_write_add_filter_gzip, canGzip()); test_truncation("lzip", archive_write_add_filter_lzip, 0); + test_truncation("lzop", archive_write_add_filter_lzop, canLzop()); test_truncation("lzma", archive_write_add_filter_lzma, 0); test_truncation("xz", archive_write_add_filter_xz, 0); } diff --git a/libarchive/test/test_write_filter_lzop.c b/libarchive/test/test_write_filter_lzop.c index 52f73274a..9e840bd5c 100644 --- a/libarchive/test/test_write_filter_lzop.c +++ b/libarchive/test/test_write_filter_lzop.c @@ -25,6 +25,7 @@ */ #include "test.h" +__FBSDID("$FreeBSD$"); /* * A basic exercise of lzop reading and writing. @@ -38,78 +39,193 @@ DEFINE_TEST(test_write_filter_lzop) size_t buffsize, datasize; char path[16]; size_t used1, used2; - int blocksize = 1024; - int r, i, use_prog; + int i, r, use_prog = 0; - assert((a = archive_read_new()) != NULL); - r = archive_read_support_filter_lzop(a); - assertEqualInt(ARCHIVE_OK, archive_read_free(a)); - if (r != ARCHIVE_OK && !canLzop()) { - skipping("lzop is not supported on this platform"); - return; + assert((a = archive_write_new()) != NULL); + r = archive_write_add_filter_lzop(a); + if (r != ARCHIVE_OK) { + if (canLzop() && r == ARCHIVE_WARN) + use_prog = 1; + else { + skipping("lzop writing not supported on this platform"); + assertEqualInt(ARCHIVE_OK, archive_write_free(a)); + return; + } } - if (r == ARCHIVE_OK) - use_prog = 0; - else - use_prog = 1; buffsize = 2000000; assert(NULL != (buff = (char *)malloc(buffsize))); datasize = 10000; - assert(NULL != (data = (char *)malloc(datasize))); - memset(data, 0, datasize); + assert(NULL != (data = (char *)calloc(1, datasize))); /* - * Write 100 files and read them all back. + * Write a 100 files and read them all back. */ assert((a = archive_write_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a)); - assertEqualIntA(a, ARCHIVE_WARN, archive_write_add_filter_lzop(a)); + assertEqualIntA(a, (use_prog)?ARCHIVE_WARN:ARCHIVE_OK, + archive_write_add_filter_lzop(a)); assertEqualIntA(a, ARCHIVE_OK, - archive_write_set_bytes_per_block(a, blocksize)); + archive_write_set_bytes_per_block(a, 1024)); assertEqualIntA(a, ARCHIVE_OK, - archive_write_set_bytes_in_last_block(a, blocksize)); - assertEqualInt(blocksize, archive_write_get_bytes_in_last_block(a)); + archive_write_set_bytes_in_last_block(a, 1024)); assertEqualInt(ARCHIVE_FILTER_LZOP, archive_filter_code(a, 0)); assertEqualString("lzop", archive_filter_name(a, 0)); assertEqualIntA(a, ARCHIVE_OK, - archive_write_open_memory(a, buff, buffsize, &used1)); - assertEqualInt(blocksize, archive_write_get_bytes_in_last_block(a)); + archive_write_open_memory(a, buff, buffsize, &used1)); + assert((ae = archive_entry_new()) != NULL); + archive_entry_set_filetype(ae, AE_IFREG); + archive_entry_set_size(ae, datasize); + for (i = 0; i < 100; i++) { + sprintf(path, "file%03d", i); + archive_entry_copy_pathname(ae, path); + assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae)); + assertA(datasize + == (size_t)archive_write_data(a, data, datasize)); + } + archive_entry_free(ae); + assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); + assertEqualInt(ARCHIVE_OK, archive_write_free(a)); + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); + r = archive_read_support_filter_lzop(a); + if (r == ARCHIVE_WARN) { + skipping("Can't verify lzop writing by reading back;" + " lzop reading not fully supported on this platform"); + } else { + assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_memory(a, buff, used1)); + for (i = 0; i < 100; i++) { + sprintf(path, "file%03d", i); + if (!assertEqualInt(ARCHIVE_OK, + archive_read_next_header(a, &ae))) + break; + assertEqualString(path, archive_entry_pathname(ae)); + assertEqualInt((int)datasize, archive_entry_size(ae)); + } + assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); + } + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); + + /* + * Repeat the cycle again, this time setting some compression + * options. + */ + assert((a = archive_write_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a)); + assertEqualIntA(a, ARCHIVE_OK, + archive_write_set_bytes_per_block(a, 10)); + assertEqualIntA(a, (use_prog)?ARCHIVE_WARN:ARCHIVE_OK, + archive_write_add_filter_lzop(a)); + assertEqualIntA(a, ARCHIVE_FAILED, + archive_write_set_options(a, "lzop:nonexistent-option=0")); + assertEqualIntA(a, ARCHIVE_OK, + archive_write_set_options(a, "lzop:compression-level=1")); + assertEqualIntA(a, ARCHIVE_OK, + archive_write_set_filter_option(a, NULL, "compression-level", "9")); + assertEqualIntA(a, ARCHIVE_FAILED, + archive_write_set_filter_option(a, NULL, "compression-level", "abc")); + assertEqualIntA(a, ARCHIVE_FAILED, + archive_write_set_filter_option(a, NULL, "compression-level", "99")); + assertEqualIntA(a, ARCHIVE_OK, + archive_write_set_options(a, "lzop:compression-level=9")); + assertEqualIntA(a, ARCHIVE_OK, + archive_write_open_memory(a, buff, buffsize, &used2)); for (i = 0; i < 100; i++) { sprintf(path, "file%03d", i); assert((ae = archive_entry_new()) != NULL); - archive_entry_set_filetype(ae, AE_IFREG); - archive_entry_set_size(ae, datasize); archive_entry_copy_pathname(ae, path); + archive_entry_set_size(ae, datasize); + archive_entry_set_filetype(ae, AE_IFREG); assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae)); + assertA(datasize == (size_t)archive_write_data( + a, data, datasize)); archive_entry_free(ae); - assertA(datasize - == (size_t)archive_write_data(a, data, datasize)); } assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); assertEqualInt(ARCHIVE_OK, archive_write_free(a)); + failure("compression-level=9 wrote %d bytes, default wrote %d bytes", + (int)used2, (int)used1); + assert(used2 < used1); + assert((a = archive_read_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); - if (use_prog) - assertEqualIntA(a, ARCHIVE_WARN, - archive_read_support_filter_lzop(a)); - else + r = archive_read_support_filter_lzop(a); + if (r != ARCHIVE_OK && !use_prog) { + skipping("lzop reading not fully supported on this platform"); + } else { assertEqualIntA(a, ARCHIVE_OK, - archive_read_support_filter_lzop(a)); + archive_read_support_filter_all(a)); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_memory(a, buff, used2)); + for (i = 0; i < 100; i++) { + sprintf(path, "file%03d", i); + if (!assertEqualInt(ARCHIVE_OK, + archive_read_next_header(a, &ae))) + break; + assertEqualString(path, archive_entry_pathname(ae)); + assertEqualInt((int)datasize, archive_entry_size(ae)); + } + assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); + } + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); + + /* + * Repeat again, with much lower compression. + */ + assert((a = archive_write_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a)); + assertEqualIntA(a, ARCHIVE_OK, + archive_write_set_bytes_per_block(a, 10)); + assertEqualIntA(a, (use_prog)?ARCHIVE_WARN:ARCHIVE_OK, + archive_write_add_filter_lzop(a)); + assertEqualIntA(a, ARCHIVE_OK, + archive_write_set_filter_option(a, NULL, "compression-level", "1")); assertEqualIntA(a, ARCHIVE_OK, - archive_read_open_memory(a, buff, used1)); + archive_write_open_memory(a, buff, buffsize, &used2)); for (i = 0; i < 100; i++) { sprintf(path, "file%03d", i); - if (!assertEqualInt(ARCHIVE_OK, - archive_read_next_header(a, &ae))) - break; - assertEqualString(path, archive_entry_pathname(ae)); - assertEqualInt((int)datasize, archive_entry_size(ae)); + assert((ae = archive_entry_new()) != NULL); + archive_entry_copy_pathname(ae, path); + archive_entry_set_size(ae, datasize); + archive_entry_set_filetype(ae, AE_IFREG); + assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae)); + failure("Writing file %s", path); + assertEqualIntA(a, datasize, + (size_t)archive_write_data(a, data, datasize)); + archive_entry_free(ae); + } + assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); + assertEqualInt(ARCHIVE_OK, archive_write_free(a)); + +#if 0 + failure("Compression-level=1 wrote %d bytes; default wrote %d bytes", + (int)used2, (int)used1); + assert(used2 > used1); +#endif + + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); + r = archive_read_support_filter_lzop(a); + if (r == ARCHIVE_WARN) { + skipping("lzop reading not fully supported on this platform"); + } else { + assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_memory(a, buff, used2)); + for (i = 0; i < 100; i++) { + sprintf(path, "file%03d", i); + if (!assertEqualInt(ARCHIVE_OK, + archive_read_next_header(a, &ae))) + break; + assertEqualString(path, archive_entry_pathname(ae)); + assertEqualInt((int)datasize, archive_entry_size(ae)); + } + assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); } - assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); /* @@ -117,25 +233,29 @@ DEFINE_TEST(test_write_filter_lzop) * don't crash or leak memory. */ assert((a = archive_write_new()) != NULL); - assertEqualIntA(a, ARCHIVE_WARN, archive_write_add_filter_lzop(a)); + assertEqualIntA(a, (use_prog)?ARCHIVE_WARN:ARCHIVE_OK, + archive_write_add_filter_lzop(a)); assertEqualInt(ARCHIVE_OK, archive_write_free(a)); assert((a = archive_write_new()) != NULL); - assertEqualIntA(a, ARCHIVE_WARN, archive_write_add_filter_lzop(a)); + assertEqualIntA(a, (use_prog)?ARCHIVE_WARN:ARCHIVE_OK, + archive_write_add_filter_lzop(a)); assertEqualInt(ARCHIVE_OK, archive_write_close(a)); assertEqualInt(ARCHIVE_OK, archive_write_free(a)); assert((a = archive_write_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a)); - assertEqualIntA(a, ARCHIVE_WARN, archive_write_add_filter_lzop(a)); + assertEqualIntA(a, (use_prog)?ARCHIVE_WARN:ARCHIVE_OK, + archive_write_add_filter_lzop(a)); assertEqualInt(ARCHIVE_OK, archive_write_close(a)); assertEqualInt(ARCHIVE_OK, archive_write_free(a)); assert((a = archive_write_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a)); - assertEqualIntA(a, ARCHIVE_WARN, archive_write_add_filter_lzop(a)); + assertEqualIntA(a, (use_prog)?ARCHIVE_WARN:ARCHIVE_OK, + archive_write_add_filter_lzop(a)); assertEqualIntA(a, ARCHIVE_OK, - archive_write_open_memory(a, buff, buffsize, &used2)); + archive_write_open_memory(a, buff, buffsize, &used2)); assertEqualInt(ARCHIVE_OK, archive_write_close(a)); assertEqualInt(ARCHIVE_OK, archive_write_free(a)); diff --git a/tar/test/test_option_lzop.c b/tar/test/test_option_lzop.c index cf4f8a079..1145499a4 100644 --- a/tar/test/test_option_lzop.c +++ b/tar/test/test_option_lzop.c @@ -29,22 +29,25 @@ __FBSDID("$FreeBSD$"); DEFINE_TEST(test_option_lzop) { char *p; + int r; size_t s; - if (!canLzop()) { - skipping("lzop is not supported on this platform"); - return; - } - /* Create a file. */ assertMakeFile("f", 0644, "a"); /* Archive it with lzop compression. */ - assertEqualInt(0, - systemf("%s -cf - --lzop f >archive.out 2>archive.err", - testprog)); + r = systemf("%s -cf - --lzop f >archive.out 2>archive.err", testprog); p = slurpfile(&s, "archive.err"); p[s] = '\0'; + if (r != 0) { + if (!canLzop()) { + skipping("lzop is not supported on this platform"); + return; + } + failure("--lzop option is broken"); + assertEqualInt(r, 0); + return; + } /* Check that the archive file has an lzma signature. */ p = slurpfile(&s, "archive.out"); assert(s > 2);