From: Tim Kientzle Date: Sun, 14 Dec 2014 18:50:09 +0000 (-0800) Subject: Merge branch 'patch-1' of https://github.com/vlovich/libarchive into vlovich-patch-1 X-Git-Tag: v3.1.900a~164^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c98f832267565c5f50a1701dca493d192210345f;p=thirdparty%2Flibarchive.git Merge branch 'patch-1' of https://github.com/vlovich/libarchive into vlovich-patch-1 Conflicts: libarchive/archive_write_set_format_zip.c This was originally submitted as: https://github.com/libarchive/libarchive/pull/84 I've made the following corrections: * Added a new variable for the deflate compression level (the submitted patch mis-used the requested_compression variable) * Extended the Zip store format test to also verify correct results with compression-level=0 TODO: This really needs a new test to exercises non-zero compression-level options. --- c98f832267565c5f50a1701dca493d192210345f diff --cc libarchive/archive_write_set_format_zip.c index 00463fac8,c161c738e..0399b7b79 --- a/libarchive/archive_write_set_format_zip.c +++ b/libarchive/archive_write_set_format_zip.c @@@ -153,8 -111,7 +153,9 @@@ struct zip struct archive_string_conv *opt_sconv; struct archive_string_conv *sconv_default; enum compression requested_compression; ++ int deflate_compression_level; int init_default_conversion; + enum encryption encryption_type; #define ZIP_FLAG_AVOID_ZIP64 1 #define ZIP_FLAG_FORCE_ZIP64 2 @@@ -273,47 -223,23 +274,65 @@@ archive_write_zip_options(struct archiv ret = ARCHIVE_OK; } return (ret); + } else if (strcmp(key, "compression-level") == 0) { + if (val == NULL || !(val[0] >= '0' && val[0] <= '9') || val[1] != '\0') { + return ARCHIVE_WARN; + } + + if (val[0] == '0') { + zip->requested_compression = COMPRESSION_STORE; + return ARCHIVE_OK; - } - ++ } else { + #ifdef HAVE_ZLIB_H - zip->requested_compression = val[0] - '0'; - return ARCHIVE_OK; ++ zip->requested_compression = COMPRESSION_DEFLATE; ++ zip->deflate_compression_level = val[0] - '0'; ++ return ARCHIVE_OK; + #else - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "deflate compression not supported"); ++ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, ++ "deflate compression not supported"); + #endif ++ } + } else if (strcmp(key, "encryption") == 0) { + if (val == NULL) { + zip->encryption_type = ENCRYPTION_NONE; + ret = ARCHIVE_OK; + } else if (val[0] == '1' || strcmp(val, "traditional") == 0 + || strcmp(val, "zipcrypt") == 0 + || strcmp(val, "ZipCrypt") == 0) { + if (is_traditional_pkware_encryption_supported()) { + zip->encryption_type = ENCRYPTION_TRADITIONAL; + ret = ARCHIVE_OK; + } else { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_MISC, + "encryption not supported"); + } + } else if (strcmp(val, "aes128") == 0) { + if (is_winzip_aes_encryption_supported( + ENCRYPTION_WINZIP_AES128)) { + zip->encryption_type = ENCRYPTION_WINZIP_AES128; + ret = ARCHIVE_OK; + } else { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_MISC, + "encryption not supported"); + } + } else if (strcmp(val, "aes256") == 0) { + if (is_winzip_aes_encryption_supported( + ENCRYPTION_WINZIP_AES256)) { + zip->encryption_type = ENCRYPTION_WINZIP_AES256; + ret = ARCHIVE_OK; + } else { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_MISC, + "encryption not supported"); + } + } else { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "%s: unknown encryption '%s'", + a->format_name, val); + } + return (ret); } else if (strcmp(key, "experimental") == 0) { if (val == NULL || val[0] == 0) { zip->flags &= ~ ZIP_FLAG_EXPERIMENT_xl; @@@ -444,9 -370,9 +463,12 @@@ archive_write_set_format_zip(struct arc /* "Unspecified" lets us choose the appropriate compression. */ zip->requested_compression = COMPRESSION_UNSPECIFIED; ++#ifdef HAVE_ZLIB_H ++ zip->deflate_compression_level = Z_DEFAULT_COMPRESSION; ++#endif zip->crc32func = real_crc32; -#ifdef HAVE_ZLIB_H + /* A buffer used for both compression and encryption. */ zip->len_buf = 65536; zip->buf = malloc(zip->len_buf); if (zip->buf == NULL) { @@@ -948,7 -771,7 +970,7 @@@ archive_write_zip_header(struct archive zip->stream.opaque = Z_NULL; zip->stream.next_out = zip->buf; zip->stream.avail_out = (uInt)zip->len_buf; -- if (deflateInit2(&zip->stream, Z_DEFAULT_COMPRESSION, ++ if (deflateInit2(&zip->stream, zip->deflate_compression_level, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) != Z_OK) { archive_set_error(&a->archive, ENOMEM, "Can't init deflate compressor"); diff --cc libarchive/test/test_write_format_zip_compression_store.c index c6761f9df,c6761f9df..9d703a1df --- a/libarchive/test/test_write_format_zip_compression_store.c +++ b/libarchive/test/test_write_format_zip_compression_store.c @@@ -30,8 -30,8 +30,24 @@@ #include "test.h" __FBSDID("$FreeBSD: head/lib/libarchive/test/test_write_format_zip_no_compression.c 201247 2009-12-30 05:59:21Z kientzle $"); ++/* File data */ ++static const char file_name[] = "file"; ++static const char file_data1[] = {'1', '2', '3', '4', '5'}; ++static const char file_data2[] = {'6', '7', '8', '9', '0'}; ++static const int file_perm = 00644; ++static const short file_uid = 10; ++static const short file_gid = 20; ++ ++/* Folder data */ ++static const char folder_name[] = "folder/"; ++static const int folder_perm = 00755; ++static const short folder_uid = 30; ++static const short folder_gid = 40; ++ ++static time_t now; ++ static unsigned long --bitcrc32(unsigned long c, void *_p, size_t s) ++bitcrc32(unsigned long c, const void *_p, size_t s) { /* This is a drop-in replacement for crc32() from zlib. * Libarchive should be able to correctly generate @@@ -58,54 -58,54 +74,9 @@@ return (c); } --/* Quick and dirty: Read 2-byte and 4-byte integers from Zip file. */ --static int i2(const char *p) { return ((p[0] & 0xff) | ((p[1] & 0xff) << 8)); } --static int i4(const char *p) { return (i2(p) | (i2(p + 2) << 16)); } -- --DEFINE_TEST(test_write_format_zip_compression_store) ++static void verify_write_uncompressed(struct archive *a) { -- /* Buffer data */ -- struct archive *a; struct archive_entry *entry; -- char buff[100000]; -- const char *buffend; -- /* p is the pointer to walk over the central directory, -- * q walks over the local headers, the data and the data descriptors. */ -- const char *p, *q, *local_header, *extra_start; -- size_t used; -- -- /* File data */ -- char file_name[] = "file"; -- char file_data1[] = {'1', '2', '3', '4', '5'}; -- char file_data2[] = {'6', '7', '8', '9', '0'}; -- int file_perm = 00644; -- short file_uid = 10; -- short file_gid = 20; -- -- /* Folder data */ -- char folder_name[] = "folder/"; -- int folder_perm = 00755; -- short folder_uid = 30; -- short folder_gid = 40; -- -- /* Time data */ -- time_t t = time(NULL); -- struct tm *tm = localtime(&t); -- -- /* Misc variables */ -- unsigned long crc; -- -- /* Create new ZIP archive in memory without padding. */ -- assert((a = archive_write_new()) != NULL); -- assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_zip(a)); -- assertEqualIntA(a, ARCHIVE_OK, -- archive_write_set_options(a, "zip:compression=store")); -- assertEqualIntA(a, ARCHIVE_OK, -- archive_write_set_options(a, "zip:experimental")); -- assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_none(a)); -- assertEqualIntA(a, ARCHIVE_OK, archive_write_set_bytes_per_block(a, 1)); -- assertEqualIntA(a, ARCHIVE_OK, archive_write_set_bytes_in_last_block(a, 1)); -- assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff), &used)); /* Write entries. */ @@@ -116,8 -116,8 +87,8 @@@ archive_entry_set_size(entry, sizeof(file_data1) + sizeof(file_data2)); archive_entry_set_uid(entry, file_uid); archive_entry_set_gid(entry, file_gid); -- archive_entry_set_mtime(entry, t, 0); -- archive_entry_set_atime(entry, t + 3, 0); ++ archive_entry_set_mtime(entry, now, 0); ++ archive_entry_set_atime(entry, now + 3, 0); assertEqualIntA(a, 0, archive_write_header(a, entry)); assertEqualIntA(a, sizeof(file_data1), archive_write_data(a, file_data1, sizeof(file_data1))); assertEqualIntA(a, sizeof(file_data2), archive_write_data(a, file_data2, sizeof(file_data2))); @@@ -130,16 -130,16 +101,27 @@@ archive_entry_set_size(entry, 0); archive_entry_set_uid(entry, folder_uid); archive_entry_set_gid(entry, folder_gid); -- archive_entry_set_mtime(entry, t, 0); -- archive_entry_set_ctime(entry, t + 5, 0); ++ archive_entry_set_mtime(entry, now, 0); ++ archive_entry_set_ctime(entry, now + 5, 0); assertEqualIntA(a, 0, archive_write_header(a, entry)); archive_entry_free(entry); ++} -- /* Close the archive . */ -- assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); -- assertEqualInt(ARCHIVE_OK, archive_write_free(a)); ++/* Quick and dirty: Read 2-byte and 4-byte integers from Zip file. */ ++static int i2(const char *p) { return ((p[0] & 0xff) | ((p[1] & 0xff) << 8)); } ++static int i4(const char *p) { return (i2(p) | (i2(p + 2) << 16)); } -- dumpfile("constructed.zip", buff, used); ++static void verify_uncompressed_contents(const char *buff, size_t used) ++{ ++ const char *buffend; ++ ++ /* Misc variables */ ++ unsigned long crc; ++ struct tm *tm = localtime(&now); ++ ++ /* p is the pointer to walk over the central directory, ++ * q walks over the local headers, the data and the data descriptors. */ ++ const char *p, *q, *local_header, *extra_start; /* Remember the end of the archive in memory. */ buffend = buff + used; @@@ -192,8 -192,8 +174,8 @@@ assertEqualInt(i2(p), 0x5455); /* 'UT' extension header */ assertEqualInt(i2(p + 2), 9); /* 'UT' size */ assertEqualInt(p[4], 3); /* 'UT' flags */ -- assertEqualInt(i4(p + 5), t); /* 'UT' mtime */ -- assertEqualInt(i4(p + 9), t + 3); /* 'UT' atime */ ++ assertEqualInt(i4(p + 5), now); /* 'UT' mtime */ ++ assertEqualInt(i4(p + 9), now + 3); /* 'UT' atime */ p = p + 4 + i2(p + 2); assertEqualInt(i2(p), 0x7875); /* 'ux' extension header */ assertEqualInt(i2(p + 2), 11); /* 'ux' size */ @@@ -218,8 -218,8 +200,8 @@@ assertEqualInt(i2(q), 0x5455); /* 'UT' extension header */ assertEqualInt(i2(q + 2), 9); /* 'UT' size */ assertEqualInt(q[4], 3); /* 'UT' flags */ -- assertEqualInt(i4(q + 5), t); /* 'UT' mtime */ -- assertEqualInt(i4(q + 9), t + 3); /* 'UT' atime */ ++ assertEqualInt(i4(q + 5), now); /* 'UT' mtime */ ++ assertEqualInt(i4(q + 9), now + 3); /* 'UT' atime */ q = q + 4 + i2(q + 2); assertEqualInt(i2(q), 0x7875); /* 'ux' extension header */ @@@ -278,8 -278,8 +260,8 @@@ assertEqualInt(i2(p), 0x5455); /* 'UT' extension header */ assertEqualInt(i2(p + 2), 9); /* 'UT' size */ assertEqualInt(p[4], 5); /* 'UT' flags */ -- assertEqualInt(i4(p + 5), t); /* 'UT' mtime */ -- assertEqualInt(i4(p + 9), t + 5); /* 'UT' atime */ ++ assertEqualInt(i4(p + 5), now); /* 'UT' mtime */ ++ assertEqualInt(i4(p + 9), now + 5); /* 'UT' atime */ p = p + 4 + i2(p + 2); assertEqualInt(i2(p), 0x7875); /* 'ux' extension header */ assertEqualInt(i2(p + 2), 11); /* 'ux' size */ @@@ -308,8 -308,8 +290,8 @@@ assertEqualInt(i2(q), 0x5455); /* 'UT' extension header */ assertEqualInt(i2(q + 2), 9); /* 'UT' size */ assertEqualInt(q[4], 5); /* 'UT' flags */ -- assertEqualInt(i4(q + 5), t); /* 'UT' mtime */ -- assertEqualInt(i4(q + 9), t + 5); /* 'UT' atime */ ++ assertEqualInt(i4(q + 5), now); /* 'UT' mtime */ ++ assertEqualInt(i4(q + 9), now + 5); /* 'UT' atime */ q = q + 4 + i2(q + 2); assertEqualInt(i2(q), 0x7875); /* 'ux' extension header */ assertEqualInt(i2(q + 2), 11); /* 'ux' size */ @@@ -335,3 -335,3 +317,59 @@@ * so the first central directory entry should be next: */ assertEqualMem(q, "PK\001\002", 4); /* Signature */ } ++ ++DEFINE_TEST(test_write_format_zip_compression_store) ++{ ++ /* Buffer data */ ++ struct archive *a; ++ char buff[100000]; ++ size_t used; ++ ++ /* Time data */ ++ now = time(NULL); ++ ++ /* Create new ZIP archive in memory without padding. */ ++ /* Use compression=store to disable compression. */ ++ assert((a = archive_write_new()) != NULL); ++ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_zip(a)); ++ assertEqualIntA(a, ARCHIVE_OK, ++ archive_write_set_options(a, "zip:compression=store")); ++ assertEqualIntA(a, ARCHIVE_OK, ++ archive_write_set_options(a, "zip:experimental")); ++ assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_none(a)); ++ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_bytes_per_block(a, 1)); ++ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_bytes_in_last_block(a, 1)); ++ assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff), &used)); ++ ++ verify_write_uncompressed(a); ++ ++ /* Close the archive . */ ++ assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); ++ assertEqualInt(ARCHIVE_OK, archive_write_free(a)); ++ dumpfile("constructed.zip", buff, used); ++ ++ verify_uncompressed_contents(buff, used); ++ ++ /* Create new ZIP archive in memory without padding. */ ++ /* Use compression-level=0 to disable compression. */ ++ assert((a = archive_write_new()) != NULL); ++ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_zip(a)); ++ assertEqualIntA(a, ARCHIVE_OK, ++ archive_write_set_options(a, "zip:compression-level=0")); ++ assertEqualIntA(a, ARCHIVE_OK, ++ archive_write_set_options(a, "zip:experimental")); ++ assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_none(a)); ++ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_bytes_per_block(a, 1)); ++ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_bytes_in_last_block(a, 1)); ++ assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff), &used)); ++ ++ verify_write_uncompressed(a); ++ ++ /* Close the archive . */ ++ assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); ++ assertEqualInt(ARCHIVE_OK, archive_write_free(a)); ++ dumpfile("constructed.zip", buff, used); ++ ++ verify_uncompressed_contents(buff, used); ++ ++}