]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Issue #822: Try harder to detect directories in zip archives 850/head
authorPeter Wu <peter@lekensteyn.nl>
Fri, 23 Dec 2016 11:45:43 +0000 (12:45 +0100)
committerPeter Wu <peter@lekensteyn.nl>
Fri, 23 Dec 2016 13:39:56 +0000 (14:39 +0100)
Assume that anything with a trailing slash is a directory. This avoids
creating regular files when a directory is expected and could occur
when the External File Attributes (EFA) field in the Central Directory
contains bogus values:

 - Jar file: observed to have OS MS-DOS (0) and EFA 0.
 - dex2jar-2.0.zip: observed to have OS Unix (3), but EFA 0xffff0010.
   After this patch, bsdtar tv still shows mode drwsrwsrwt, but at least
   it successfully creates a directory instead of a regular file.

A test case has been added for the first case (based on
test_read_format_zip_nofiletype).

Makefile.am
libarchive/archive_read_support_format_zip.c
libarchive/test/CMakeLists.txt
libarchive/test/test_read_format_zip_jar.c [new file with mode: 0644]
libarchive/test/test_read_format_zip_jar.jar.uu [new file with mode: 0644]

index 614f8641732aa2fe598a8723e656d433afd0c00d..6ed04959aff481d6d13951faf1ce29dce76a87c3 100644 (file)
@@ -483,6 +483,7 @@ libarchive_test_SOURCES= \
        libarchive/test/test_read_format_zip_encryption_header.c \
        libarchive/test/test_read_format_zip_filename.c \
        libarchive/test/test_read_format_zip_high_compression.c \
+       libarchive/test/test_read_format_zip_jar.c \
        libarchive/test/test_read_format_zip_mac_metadata.c \
        libarchive/test/test_read_format_zip_malformed.c \
        libarchive/test/test_read_format_zip_msdos.c \
@@ -801,6 +802,7 @@ libarchive_test_EXTRA_DIST=\
        libarchive/test/test_read_format_zip_filename_utf8_ru2.zip.uu \
        libarchive/test/test_read_format_zip_high_compression.zip.uu \
        libarchive/test/test_read_format_zip_length_at_end.zip.uu \
+       libarchive/test/test_read_format_zip_jar.jar.uu \
        libarchive/test/test_read_format_zip_mac_metadata.zip.uu \
        libarchive/test/test_read_format_zip_malformed1.zip.uu \
        libarchive/test/test_read_format_zip_msdos.zip.uu \
index 9796fca161a6deddd82fc39397c6e6a6e55247d9..d19e7914e11c4c4e8714b54ccf8221e989ddb5d6 100644 (file)
@@ -864,29 +864,33 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
                zip_entry->mode |= AE_IFREG;
        }
 
-       if ((zip_entry->mode & AE_IFMT) == 0) {
-               /* Especially in streaming mode, we can end up
-                  here without having seen proper mode information.
-                  Guess from the filename. */
+       /* If the mode is totally empty, set some sane default. */
+       if (zip_entry->mode == 0) {
+               zip_entry->mode |= 0664;
+       }
+
+       /* Make sure that entries with a trailing '/' are marked as directories
+        * even if the External File Attributes contains bogus values.  If this
+        * is not a directory and there is no type, assume regularfile. */
+       if ((zip_entry->mode & AE_IFMT) != AE_IFDIR) {
+               int has_slash;
+
                wp = archive_entry_pathname_w(entry);
                if (wp != NULL) {
                        len = wcslen(wp);
-                       if (len > 0 && wp[len - 1] == L'/')
-                               zip_entry->mode |= AE_IFDIR;
-                       else
-                               zip_entry->mode |= AE_IFREG;
+                       has_slash = len > 0 && wp[len - 1] == L'/';
                } else {
                        cp = archive_entry_pathname(entry);
                        len = (cp != NULL)?strlen(cp):0;
-                       if (len > 0 && cp[len - 1] == '/')
-                               zip_entry->mode |= AE_IFDIR;
-                       else
-                               zip_entry->mode |= AE_IFREG;
+                       has_slash = len > 0 && cp[len - 1] == '/';
                }
-               if (zip_entry->mode == AE_IFDIR) {
-                       zip_entry->mode |= 0775;
-               } else if (zip_entry->mode == AE_IFREG) {
-                       zip_entry->mode |= 0664;
+               /* Correct file type as needed. */
+               if (has_slash) {
+                       zip_entry->mode &= ~AE_IFMT;
+                       zip_entry->mode |= AE_IFDIR;
+                       zip_entry->mode |= 0111;
+               } else if ((zip_entry->mode & AE_IFMT) == 0) {
+                       zip_entry->mode |= AE_IFREG;
                }
        }
 
index ab9a8a46d66a2cdb35737f9e813b8bdbb5119043..3c2671dd08fcd0a5f8a1d158724ecf64d4ff2086 100644 (file)
@@ -169,6 +169,7 @@ IF(ENABLE_TEST)
     test_read_format_zip_encryption_partially.c
     test_read_format_zip_filename.c
     test_read_format_zip_high_compression.c
+    test_read_format_zip_jar.c
     test_read_format_zip_mac_metadata.c
     test_read_format_zip_malformed.c
     test_read_format_zip_msdos.c
diff --git a/libarchive/test/test_read_format_zip_jar.c b/libarchive/test/test_read_format_zip_jar.c
new file mode 100644 (file)
index 0000000..ffb520e
--- /dev/null
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 2016 Peter Wu
+ * 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.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+/*
+ * Issue 822: jar files have an empty External File Attributes field which
+ * is misinterpreted as regular file type due to OS MS-DOS.
+ */
+
+DEFINE_TEST(test_read_format_zip_jar)
+{
+       const char *refname = "test_read_format_zip_jar.jar";
+       char *p;
+       size_t s;
+       struct archive *a;
+       struct archive_entry *ae;
+       char data[16];
+
+       extract_reference_file(refname);
+       p = slurpfile(&s, refname);
+
+       assert((a = archive_read_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip_seekable(a));
+       assertEqualIntA(a, ARCHIVE_OK, read_open_memory_seek(a, p, s, 1));
+
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+       assertEqualString("somedir/", archive_entry_pathname(ae));
+       assertEqualInt(AE_IFDIR | 0775, archive_entry_mode(ae));
+       assertEqualInt(0, archive_entry_size(ae));
+       assertEqualIntA(a, 0, archive_read_data(a, data, 16));
+
+       assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
+       free(p);
+}
diff --git a/libarchive/test/test_read_format_zip_jar.jar.uu b/libarchive/test/test_read_format_zip_jar.jar.uu
new file mode 100644 (file)
index 0000000..0778c93
--- /dev/null
@@ -0,0 +1,6 @@
+begin 640 test_read_format_zip_jar.jar
+M4$L#! H   @  $AQETD                (  0 <V]M961I<B_^R@  4$L!
+M @H "@  "   2'&720                @ !                    '-O
+@;65D:7(O_LH  %!+!08      0 ! #H    J        
+end