From: Michihiro NAKAJIMA Date: Thu, 11 Oct 2012 21:57:36 +0000 (+0900) Subject: Use an external gzip program when zlib is unavailable. X-Git-Tag: v3.1.0~40^2~46 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6879299837ff53709e11cb337f8b47002147f78c;p=thirdparty%2Flibarchive.git Use an external gzip program when zlib is unavailable. --- diff --git a/libarchive/archive_write_add_filter_gzip.c b/libarchive/archive_write_add_filter_gzip.c index 3d3f1f475..c7d3714fd 100644 --- a/libarchive/archive_write_add_filter_gzip.c +++ b/libarchive/archive_write_add_filter_gzip.c @@ -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 */ diff --git a/libarchive/test/test_empty_write.c b/libarchive/test/test_empty_write.c index d4b6f405a..60ba4168c 100644 --- a/libarchive/test/test_empty_write.c +++ b/libarchive/test/test_empty_write.c @@ -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. */ diff --git a/libarchive/test/test_read_truncated_filter.c b/libarchive/test/test_read_truncated_filter.c index ce2f1fd00..9128e83eb 100644 --- a/libarchive/test/test_read_truncated_filter.c +++ b/libarchive/test/test_read_truncated_filter.c @@ -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); } diff --git a/libarchive/test/test_write_filter_gzip.c b/libarchive/test/test_write_filter_gzip.c index e3f50beec..118da2e46 100644 --- a/libarchive/test/test_write_filter_gzip.c +++ b/libarchive/test/test_write_filter_gzip.c @@ -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));