]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Use liblzo2 for the lzop write filter.
authorMichihiro NAKAJIMA <ggcueroad@gmail.com>
Sun, 21 Oct 2012 02:11:46 +0000 (11:11 +0900)
committerMichihiro NAKAJIMA <ggcueroad@gmail.com>
Sun, 21 Oct 2012 02:12:35 +0000 (11:12 +0900)
cpio/test/test_option_lzop.c
libarchive/archive_write_add_filter_lzop.c
libarchive/test/test_read_truncated_filter.c
libarchive/test/test_write_filter_lzop.c
tar/test/test_option_lzop.c

index a1812d3c7467259552ff4c858a8412922fc29100..9f1666e9c5b941f7fba24b1dcd5c9e27dedd65a5 100644 (file)
@@ -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);
index 5e7a711593686f336474550e412ce8901daacc92..088ecea5167a79b189ff252d27f2f21f49eb6000 100644 (file)
@@ -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 <errno.h>
@@ -36,14 +38,40 @@ __FBSDID("$FreeBSD$");
 #ifdef HAVE_STRING_H
 #include <string.h>
 #endif
+#include <time.h>
+#ifdef HAVE_LZO_LZOCONF_H
+#include <lzo/lzoconf.h>
+#endif
+#ifdef HAVE_LZO_LZO1X_H
+#include <lzo/lzo1x.h>
+#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
index 73254d398ceea164e45196cf2fdc987f938cbb05..2fe7f6553267cdefd92fdfd4e0340df898e2b9a5 100644 (file)
@@ -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);
 }
index 52f73274a7eae33bb4885fcc701a5116d66a948a..9e840bd5cae6558f6535b9388e69359e6cd91be1 100644 (file)
@@ -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 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));
 
index cf4f8a079a2c3a88bd18f9c5ada9cdae4b84831d..1145499a460541701a41a66297bbf3d4708e55cb 100644 (file)
@@ -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);