]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Use an external gzip program when zlib is unavailable.
authorMichihiro NAKAJIMA <ggcueroad@gmail.com>
Thu, 11 Oct 2012 21:57:36 +0000 (06:57 +0900)
committerMichihiro NAKAJIMA <ggcueroad@gmail.com>
Thu, 11 Oct 2012 21:57:36 +0000 (06:57 +0900)
libarchive/archive_write_add_filter_gzip.c
libarchive/test/test_empty_write.c
libarchive/test/test_read_truncated_filter.c
libarchive/test/test_write_filter_gzip.c

index 3d3f1f47504315ce48e1caf65d3b442ebd970afa..c7d3714fd9b3ed74dbdf2c7001bf238a40473cc1 100644 (file)
@@ -43,6 +43,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_compression_gzip.c 201
 
 #include "archive.h"
 #include "archive_private.h"
+#include "archive_string.h"
 #include "archive_write_private.h"
 
 #if ARCHIVE_VERSION_NUMBER < 4000000
@@ -54,24 +55,19 @@ archive_write_set_compression_gzip(struct archive *a)
 }
 #endif
 
-#ifndef HAVE_ZLIB_H
-int
-archive_write_add_filter_gzip(struct archive *a)
-{
-       archive_set_error(a, ARCHIVE_ERRNO_MISC,
-           "gzip compression not supported on this platform");
-       return (ARCHIVE_FATAL);
-}
-#else
 /* Don't compile this if we don't have zlib. */
 
 struct private_data {
        int              compression_level;
+#ifdef HAVE_ZLIB_H
        z_stream         stream;
        int64_t          total_in;
        unsigned char   *compressed;
        size_t           compressed_buffer_size;
        unsigned long    crc;
+#else
+       struct archive_write_program_data *pdata;
+#endif
 };
 
 /*
@@ -88,8 +84,10 @@ static int archive_compressor_gzip_write(struct archive_write_filter *,
                    const void *, size_t);
 static int archive_compressor_gzip_close(struct archive_write_filter *);
 static int archive_compressor_gzip_free(struct archive_write_filter *);
+#ifdef HAVE_ZLIB_H
 static int drive_compressor(struct archive_write_filter *,
                    struct private_data *, int finishing);
+#endif
 
 
 /*
@@ -110,21 +108,39 @@ archive_write_add_filter_gzip(struct archive *_a)
                return (ARCHIVE_FATAL);
        }
        f->data = data;
-       data->compression_level = Z_DEFAULT_COMPRESSION;
        f->open = &archive_compressor_gzip_open;
        f->options = &archive_compressor_gzip_options;
        f->close = &archive_compressor_gzip_close;
        f->free = &archive_compressor_gzip_free;
        f->code = ARCHIVE_FILTER_GZIP;
        f->name = "gzip";
+#ifdef HAVE_ZLIB_H
+       data->compression_level = Z_DEFAULT_COMPRESSION;
        return (ARCHIVE_OK);
+#else
+       data->pdata = __archive_write_program_allocate();
+       if (data->pdata == NULL) {
+               free(data);
+               archive_set_error(&a->archive, ENOMEM, "Out of memory");
+               return (ARCHIVE_FATAL);
+       }
+       data->compression_level = 0;
+       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+           "Using external gzip program");
+       return (ARCHIVE_WARN);
+#endif
 }
 
 static int
 archive_compressor_gzip_free(struct archive_write_filter *f)
 {
        struct private_data *data = (struct private_data *)f->data;
+
+#ifdef HAVE_ZLIB_H
        free(data->compressed);
+#else
+       __archive_write_program_free(data->pdata);
+#endif
        free(data);
        f->data = NULL;
        return (ARCHIVE_OK);
@@ -153,6 +169,7 @@ archive_compressor_gzip_options(struct archive_write_filter *f, const char *key,
        return (ARCHIVE_WARN);
 }
 
+#ifdef HAVE_ZLIB_H
 /*
  * Setup callback.
  */
@@ -367,4 +384,49 @@ drive_compressor(struct archive_write_filter *f,
        }
 }
 
+#else /* HAVE_ZLIB_H */
+
+static int
+archive_compressor_gzip_open(struct archive_write_filter *f)
+{
+       struct private_data *data = (struct private_data *)f->data;
+       struct archive_string as;
+       int r;
+
+       archive_string_init(&as);
+       archive_strcpy(&as, "gzip");
+
+       /* Specify compression level. */
+       if (data->compression_level > 0) {
+               archive_strcat(&as, " -");
+               archive_strappend_char(&as, '0' + data->compression_level);
+       }
+       r = __archive_write_program_set_cmd(data->pdata, as.s);
+       archive_string_free(&as);
+       if (r != ARCHIVE_OK) {
+               archive_set_error(f->archive, ENOMEM, "Can't allocate memory");
+               return (ARCHIVE_FATAL);
+       }
+       f->write = archive_compressor_gzip_write;
+
+       return __archive_write_program_open(f, data->pdata);
+}
+
+static int
+archive_compressor_gzip_write(struct archive_write_filter *f, const void *buff,
+    size_t length)
+{
+       struct private_data *data = (struct private_data *)f->data;
+
+       return __archive_write_program_write(f, data->pdata, buff, length);
+}
+
+static int
+archive_compressor_gzip_close(struct archive_write_filter *f)
+{
+       struct private_data *data = (struct private_data *)f->data;
+
+       return __archive_write_program_close(f, data->pdata);
+}
+
 #endif /* HAVE_ZLIB_H */
index d4b6f405a644732d947186ed4daaf95d9f2d5b6d..60ba4168cded480add29f5927837d5421683d6be 100644 (file)
@@ -41,10 +41,13 @@ DEFINE_TEST(test_empty_write)
        assert((a = archive_write_new()) != NULL);
        assertA(0 == archive_write_set_format_ustar(a));
        r = archive_write_add_filter_gzip(a);
-       if (r == ARCHIVE_FATAL) {
+       if (r != ARCHIVE_OK && !canGzip()) {
                skipping("Empty write to gzip-compressed archive");
        } else {
-               assertEqualIntA(a, ARCHIVE_OK, r);
+               if (r != ARCHIVE_OK && canGzip())
+                       assertEqualIntA(a, ARCHIVE_WARN, r);
+               else
+                       assertEqualIntA(a, ARCHIVE_OK, r);
                assertEqualIntA(a, ARCHIVE_OK,
                    archive_write_open_memory(a, buff, sizeof(buff), &used));
                /* Write a file to it. */
index ce2f1fd007f4ee8f23df9eefffae43aabeb5758d..9128e83eb69fd57c93f4d3729eb21da748df855d 100644 (file)
@@ -33,14 +33,15 @@ __FBSDID("$FreeBSD$");
  */
 
 static void
-test_truncation(const char *compression, int (*set_compression)(struct archive *))
+test_truncation(const char *compression,
+    int (*set_compression)(struct archive *), int can_prog)
 {
        struct archive_entry *ae;
        struct archive* a;
        char path[16];
        char *buff, *data;
        size_t buffsize, datasize, used1;
-       int i, j, r;
+       int i, j, r, use_prog;
 
        buffsize = 2000000;
        assert(NULL != (buff = (char *)malloc(buffsize)));
@@ -57,14 +58,17 @@ test_truncation(const char *compression, int (*set_compression)(struct archive *
        assertEqualIntA(a, ARCHIVE_OK,
            archive_write_add_filter_compress(a));
        r = (*set_compression)(a);
-       if (r == ARCHIVE_FATAL) {
-               skipping("%s writing not supported on this platform", compression);
+       if (r != ARCHIVE_OK && !can_prog) {
+               skipping("%s writing not supported on this platform",
+                   compression);
                assertEqualInt(ARCHIVE_OK, archive_write_free(a));
                return;
        }
+       use_prog = (r == ARCHIVE_WARN && can_prog);
        assertEqualIntA(a, ARCHIVE_OK,
            archive_write_set_bytes_per_block(a, 10));
-       assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, buffsize, &used1));
+       assertEqualIntA(a, ARCHIVE_OK,
+           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);
@@ -72,7 +76,8 @@ test_truncation(const char *compression, int (*set_compression)(struct archive *
                sprintf(path, "%s%d", compression, i);
                archive_entry_copy_pathname(ae, path);
                failure(path);
-               if (!assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae))) {
+               if (!assertEqualIntA(a, ARCHIVE_OK,
+                   archive_write_header(a, ae))) {
                        archive_write_free(a);
                        free(data);
                        free(buff);
@@ -82,7 +87,8 @@ test_truncation(const char *compression, int (*set_compression)(struct archive *
                        data[j] = (char)(rand() % 256);
                }
                failure(path);
-               if (!assertEqualIntA(a, datasize, archive_write_data(a, data, datasize))) {
+               if (!assertEqualIntA(a, datasize,
+                   archive_write_data(a, data, datasize))) {
                        archive_write_free(a);
                        free(data);
                        free(buff);
@@ -97,7 +103,8 @@ test_truncation(const char *compression, int (*set_compression)(struct archive *
        assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
        assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
 
-       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used1 - used1/64));
+       assertEqualIntA(a, ARCHIVE_OK,
+           archive_read_open_memory(a, buff, used1 - used1/64));
        for (i = 0; i < 100; i++) {
                if (ARCHIVE_OK != archive_read_next_header(a, &ae)) {
                        failure("Should have non-NULL error message for %s",
@@ -114,7 +121,8 @@ test_truncation(const char *compression, int (*set_compression)(struct archive *
                        break;
                }
        }
-       assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+       assertEqualIntA(a, (use_prog)?ARCHIVE_WARN:ARCHIVE_OK,
+           archive_read_close(a));
        assertEqualInt(ARCHIVE_OK, archive_read_free(a));
 
        free(data);
@@ -123,10 +131,10 @@ test_truncation(const char *compression, int (*set_compression)(struct archive *
 
 DEFINE_TEST(test_read_truncated_filter)
 {
-       test_truncation("bzip2", archive_write_add_filter_bzip2);
-       test_truncation("compress", archive_write_add_filter_compress);
-       test_truncation("gzip", archive_write_add_filter_gzip);
-       test_truncation("lzip", archive_write_add_filter_lzip);
-       test_truncation("lzma", archive_write_add_filter_lzma);
-       test_truncation("xz", archive_write_add_filter_xz);
+       test_truncation("bzip2", archive_write_add_filter_bzip2, 0);
+       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("lzma", archive_write_add_filter_lzma, 0);
+       test_truncation("xz", archive_write_add_filter_xz, 0);
 }
index e3f50beecdc0d1c11234e74d233dbf143717628b..118da2e466b096e27458852e57f98b0043611cb2 100644 (file)
@@ -41,7 +41,7 @@ DEFINE_TEST(test_write_filter_gzip)
        size_t buffsize, datasize;
        char path[16];
        size_t used1, used2;
-       int i, r;
+       int i, r, use_prog = 0;
 
        buffsize = 2000000;
        assert(NULL != (buff = (char *)malloc(buffsize)));
@@ -56,16 +56,21 @@ DEFINE_TEST(test_write_filter_gzip)
        assert((a = archive_write_new()) != NULL);
        assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
        r = archive_write_add_filter_gzip(a);
-       if (r == ARCHIVE_FATAL) {
-               skipping("gzip writing not supported on this platform");
-               assertEqualInt(ARCHIVE_OK, archive_write_free(a));
-               return;
+       if (r != ARCHIVE_OK) {
+               if (canGzip() && r == ARCHIVE_WARN)
+                       use_prog = 1;
+               else {
+                       skipping("gzip writing not supported on this platform");
+                       assertEqualInt(ARCHIVE_OK, archive_write_free(a));
+                       return;
+               }
        }
        assertEqualIntA(a, ARCHIVE_OK,
            archive_write_set_bytes_per_block(a, 10));
        assertEqualInt(ARCHIVE_FILTER_GZIP, archive_filter_code(a, 0));
        assertEqualString("gzip", archive_filter_name(a, 0));
-       assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, buffsize, &used1));
+       assertEqualIntA(a, ARCHIVE_OK,
+           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);
@@ -109,11 +114,12 @@ DEFINE_TEST(test_write_filter_gzip)
        assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
        assertEqualIntA(a, ARCHIVE_OK,
            archive_write_set_bytes_per_block(a, 10));
-       assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_gzip(a));
+       assertEqualIntA(a, (use_prog)?ARCHIVE_WARN:ARCHIVE_OK,
+           archive_write_add_filter_gzip(a));
        assertEqualIntA(a, ARCHIVE_FAILED,
            archive_write_set_options(a, "gzip:nonexistent-option=0"));
        assertEqualIntA(a, ARCHIVE_OK,
-           archive_write_set_options(a, "gzip:compression-level=0"));
+           archive_write_set_options(a, "gzip:compression-level=1"));
        assertEqualIntA(a, ARCHIVE_OK,
            archive_write_set_filter_option(a, NULL, "compression-level", "9"));
        assertEqualIntA(a, ARCHIVE_FAILED,
@@ -147,7 +153,7 @@ DEFINE_TEST(test_write_filter_gzip)
        assert((a = archive_read_new()) != NULL);
        assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
        r = archive_read_support_filter_gzip(a);
-       if (r == ARCHIVE_WARN) {
+       if (r != ARCHIVE_OK && !use_prog) {
                skipping("gzip reading not fully supported on this platform");
        } else {
                assertEqualIntA(a, ARCHIVE_OK,
@@ -173,10 +179,12 @@ DEFINE_TEST(test_write_filter_gzip)
        assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
        assertEqualIntA(a, ARCHIVE_OK,
            archive_write_set_bytes_per_block(a, 10));
-       assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_gzip(a));
+       assertEqualIntA(a, (use_prog)?ARCHIVE_WARN:ARCHIVE_OK,
+           archive_write_add_filter_gzip(a));
        assertEqualIntA(a, ARCHIVE_OK,
-           archive_write_set_filter_option(a, NULL, "compression-level", "0"));
-       assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, buffsize, &used2));
+           archive_write_set_filter_option(a, NULL, "compression-level", "1"));
+       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);
@@ -192,8 +200,8 @@ DEFINE_TEST(test_write_filter_gzip)
        assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
        assertEqualInt(ARCHIVE_OK, archive_write_free(a));
 
-       /* Level 0 really does result in larger data. */
-       failure("Compression-level=0 wrote %d bytes; default wrote %d bytes",
+       /* Level 1 really does result in larger data. */
+       failure("Compression-level=1 wrote %d bytes; default wrote %d bytes",
            (int)used2, (int)used1);
        assert(used2 > used1);
 
@@ -223,23 +231,27 @@ DEFINE_TEST(test_write_filter_gzip)
         * don't crash or leak memory.
         */
        assert((a = archive_write_new()) != NULL);
-       assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_gzip(a));
+       assertEqualIntA(a, (use_prog)?ARCHIVE_WARN:ARCHIVE_OK,
+           archive_write_add_filter_gzip(a));
        assertEqualInt(ARCHIVE_OK, archive_write_free(a));
 
        assert((a = archive_write_new()) != NULL);
-       assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_gzip(a));
+       assertEqualIntA(a, (use_prog)?ARCHIVE_WARN:ARCHIVE_OK,
+           archive_write_add_filter_gzip(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_OK, archive_write_add_filter_gzip(a));
+       assertEqualIntA(a, (use_prog)?ARCHIVE_WARN:ARCHIVE_OK,
+           archive_write_add_filter_gzip(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_OK, archive_write_add_filter_gzip(a));
+       assertEqualIntA(a, (use_prog)?ARCHIVE_WARN:ARCHIVE_OK,
+           archive_write_add_filter_gzip(a));
        assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, buffsize, &used2));
        assertEqualInt(ARCHIVE_OK, archive_write_close(a));
        assertEqualInt(ARCHIVE_OK, archive_write_free(a));