From: Tim Kientzle Date: Thu, 26 Dec 2013 23:29:52 +0000 (-0800) Subject: Be more careful about enabling zip64 (fixes zip_compression_store test) X-Git-Tag: v3.1.900a~327^2~33 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c8b155681993b461b92951ccd117b4ce9db92e19;p=thirdparty%2Flibarchive.git Be more careful about enabling zip64 (fixes zip_compression_store test) Add test for empty zip64 file Fix reader to read empty zip64 files --- diff --git a/Makefile.am b/Makefile.am index 85d7d032f..8cb5815f7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -513,6 +513,7 @@ libarchive_test_SOURCES= \ libarchive/test/test_write_format_xar_empty.c \ libarchive/test/test_write_format_zip.c \ libarchive/test/test_write_format_zip_empty.c \ + libarchive/test/test_write_format_zip_empty_zip64.c \ libarchive/test/test_write_format_zip_compression_store.c \ libarchive/test/test_write_open_memory.c \ libarchive/test/test_zip_filename_encoding.c diff --git a/libarchive/archive_read_support_format_zip.c b/libarchive/archive_read_support_format_zip.c index 69af21a72..83e1d9799 100644 --- a/libarchive/archive_read_support_format_zip.c +++ b/libarchive/archive_read_support_format_zip.c @@ -941,6 +941,7 @@ archive_read_format_zip_streamable_bid(struct archive_read *a, int best_bid) if ((p[2] == '\001' && p[3] == '\002') || (p[2] == '\003' && p[3] == '\004') || (p[2] == '\005' && p[3] == '\006') + || (p[2] == '\006' && p[3] == '\006') || (p[2] == '\007' && p[3] == '\010') || (p[2] == '0' && p[3] == '0')) return (30); diff --git a/libarchive/archive_write_set_format_zip.c b/libarchive/archive_write_set_format_zip.c index b74629b4b..a1dc33ac9 100644 --- a/libarchive/archive_write_set_format_zip.c +++ b/libarchive/archive_write_set_format_zip.c @@ -110,7 +110,7 @@ struct zip { struct archive_string_conv *sconv_default; enum compression requested_compression; int init_default_conversion; - char force_zip64; + char avoid_zip64, force_zip64; #ifdef HAVE_ZLIB_H z_stream stream; @@ -213,7 +213,8 @@ archive_write_zip_options(struct archive_write *a, const char *key, } return (ret); } else if (strcmp(key, "zip64") == 0) { - zip->force_zip64 = (val != NULL); + zip->force_zip64 = (val != NULL && *val != '\0'); + zip->avoid_zip64 = !zip->force_zip64; return (ARCHIVE_OK); } @@ -472,6 +473,9 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) if (zip->entry_compression == COMPRESSION_UNSPECIFIED) { zip->entry_compression = COMPRESSION_DEFAULT; } + if (zip->force_zip64 /* User has forced it. */ + || zip->entry_uncompressed_size > 0xffffffffLL) /* Large entry. */ + zip->entry_uses_zip64 = 1; if (zip->entry_compression == COMPRESSION_STORE) { zip->entry_compressed_size = size; zip->entry_uncompressed_size = size; @@ -485,14 +489,15 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) /* Prefer deflate if it's available. */ zip->entry_compression = COMPRESSION_DEFAULT; zip->entry_flags |= ZIP_FLAGS_LENGTH_AT_END; - if (zip->entry_compression == COMPRESSION_STORE) { + if (!zip->avoid_zip64) { + zip->entry_uses_zip64 = 1; + } else if (zip->entry_compression == COMPRESSION_STORE) { version_needed = 10; } else { version_needed = 20; } } - /* Decide whether to use Zip64 extension for this entry. */ if (zip->entry_uses_zip64) { version_needed = 45; } @@ -506,6 +511,11 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) archive_le32enc(local_header + 10, dos_time(archive_entry_mtime(zip->entry))); archive_le32enc(local_header + 14, zip->entry_crc32); if (zip->entry_uses_zip64) { + /* Zip64 data in the local header "must" include both + * compressed and uncompressed sizes AND those fields + * are included only if these are 0xffffffff; + * THEREFORE these must be set this way, even if we + * know one of them is smaller. */ archive_le32enc(local_header + 18, 0xffffffffLL); archive_le32enc(local_header + 22, 0xffffffffLL); } else { @@ -591,7 +601,7 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) e += 8; archive_le64enc(e, zip->entry_compressed_size); e += 8; - archive_le16enc(zip64_start + 2, e - zip64_start + 4); + archive_le16enc(zip64_start + 2, e - (zip64_start + 4)); } /* Update local header with size of extra data and write it all out: */ @@ -762,7 +772,7 @@ archive_write_zip_finish_entry(struct archive_write *a) archive_le64enc(z, zip->entry_offset); z += 8; } - archive_le16enc(zip64 + 2, z - zip64 + 4); + archive_le16enc(zip64 + 2, z - (zip64 + 4)); zd = cd_alloc(zip, z - zip64); if (zd == NULL) { archive_set_error(&a->archive, ENOMEM, diff --git a/libarchive/test/CMakeLists.txt b/libarchive/test/CMakeLists.txt index c21d9fedf..656618e9d 100644 --- a/libarchive/test/CMakeLists.txt +++ b/libarchive/test/CMakeLists.txt @@ -226,6 +226,7 @@ IF(ENABLE_TEST) test_write_format_xar_empty.c test_write_format_zip.c test_write_format_zip_empty.c + test_write_format_zip_empty_zip64.c test_write_format_zip_compression_store.c test_write_open_memory.c test_zip_filename_encoding.c diff --git a/libarchive/test/test_write_format_zip_empty_zip64.c b/libarchive/test/test_write_format_zip_empty_zip64.c new file mode 100644 index 000000000..a1802453e --- /dev/null +++ b/libarchive/test/test_write_format_zip_empty_zip64.c @@ -0,0 +1,96 @@ +/*- + * Copyright (c) 2008 Anselm Strauss + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Development supported by Google Summer of Code 2008. + */ + +#include "test.h" +__FBSDID("$FreeBSD: head/lib/libarchive/test/test_write_format_zip_empty.c 201247 2009-12-30 05:59:21Z kientzle $"); + +DEFINE_TEST(test_write_format_zip_empty_zip64) +{ + struct archive *a; + struct archive_entry *ae; + char buff[256]; + size_t used; + + /* Zip format: Create a new archive in memory. */ + assert((a = archive_write_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_zip(a)); + 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)); + /* Force zip writer to use Zip64 extensions. */ + assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_option(a, "zip", "zip64", "1")); + assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff), &used)); + + /* Close out the archive without writing anything. */ + assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); + assertEqualInt(ARCHIVE_OK, archive_write_free(a)); + + /* Verify the correct format for an empy Zip archive with Zip64 extensions forced. */ + assertEqualInt(used, 98); + assertEqualMem(buff, + "PK\006\006" /* Zip64 end-of-central-directory record */ + "\x2c\0\0\0\0\0\0\0" /* 44 bytes long */ + "\x2d\0" /* Created by Zip 4.5 */ + "\x2d\0" /* Extract with Zip 4.5 or later */ + "\0\0\0\0" /* This is disk #0 */ + "\0\0\0\0" /* Central dir starts on disk #0 */ + "\0\0\0\0\0\0\0\0" /* There are 0 entries in directory on this disk*/ + "\0\0\0\0\0\0\0\0" /* There are 0 entries in directory */ + "\0\0\0\0\0\0\0\0" /* There are 0 bytes in directory */ + "\0\0\0\0\0\0\0\0" /* Directory starts at offset 0 */ + + "PK\006\007" /* Zip64 end-of-central-directory locator */ + "\0\0\0\0" /* Zip64 EOCD is on disk #0 .. */ + "\0\0\0\0\0\0\0\0" /* .. at offset 0 .. */ + "\1\0\0\0" /* .. of 1 total disks. */ + + "PK\005\006\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", + 98); + + /* Verify that we read this kind of empty archive correctly. */ + /* Try with the standard memory reader, and with the test + memory reader with and without seek support. */ + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip(a)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, 98)); + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); + assertEqualInt(ARCHIVE_OK, archive_write_free(a)); + + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip(a)); + assertEqualIntA(a, ARCHIVE_OK, read_open_memory(a, buff, 98, 1)); + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); + assertEqualInt(ARCHIVE_OK, archive_write_free(a)); + + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip(a)); + assertEqualIntA(a, ARCHIVE_OK, read_open_memory_seek(a, buff, 98, 98)); + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); + assertEqualInt(ARCHIVE_OK, archive_write_free(a)); +}