]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Be more careful about enabling zip64 (fixes zip_compression_store test)
authorTim Kientzle <kientzle@acm.org>
Thu, 26 Dec 2013 23:29:52 +0000 (15:29 -0800)
committerTim Kientzle <kientzle@acm.org>
Thu, 26 Dec 2013 23:29:52 +0000 (15:29 -0800)
Add test for empty zip64 file
Fix reader to read empty zip64 files

Makefile.am
libarchive/archive_read_support_format_zip.c
libarchive/archive_write_set_format_zip.c
libarchive/test/CMakeLists.txt
libarchive/test/test_write_format_zip_empty_zip64.c [new file with mode: 0644]

index 85d7d032f36daff751fed088e3487c2e04a93e65..8cb5815f761ef28d94dbff8f7e3c19fb074032ab 100644 (file)
@@ -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
index 69af21a721c0d7e16c73b585d0319d4a9f48c931..83e1d97997b4808854904c1595eb5c2431ee3c46 100644 (file)
@@ -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);
index b74629b4b896c937f5d475d3bcda9b7b28a1ea8b..a1dc33ac93adfcb9010c5c05f4c851b8c8103554 100644 (file)
@@ -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,
index c21d9fedf05c9e7f7db95c9ed045647994f66732..656618e9d324851e40dbffe7583e8f7443b10086 100644 (file)
@@ -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 (file)
index 0000000..a180245
--- /dev/null
@@ -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));
+}