]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Restore compatibility with Perl Archive::Tar that was broken with #825
authorMartin Matuska <martin@matuska.org>
Thu, 1 Dec 2016 14:58:06 +0000 (15:58 +0100)
committerMartin Matuska <martin@matuska.org>
Thu, 1 Dec 2016 15:04:24 +0000 (16:04 +0100)
Makefile.am
libarchive/archive_read_support_format_tar.c
libarchive/test/CMakeLists.txt
libarchive/test/test_compat_perl_archive_tar.c [new file with mode: 0644]
libarchive/test/test_compat_perl_archive_tar.tar.uu [new file with mode: 0644]

index c04dc01a3f4d7eae60154c23e5a5cf0035e7d245..74485af962d6e737cd90505e156d42bb6d374349 100644 (file)
@@ -370,6 +370,7 @@ libarchive_test_SOURCES= \
        libarchive/test/test_compat_lzop.c \
        libarchive/test/test_compat_mac.c \
        libarchive/test/test_compat_pax_libarchive_2x.c \
+       libarchive/test/test_compat_perl_archive_tar.c \
        libarchive/test/test_compat_solaris_tar_acl.c \
        libarchive/test/test_compat_solaris_pax_sparse.c \
        libarchive/test/test_compat_star_acl_posix1e.c \
@@ -625,6 +626,7 @@ libarchive_test_EXTRA_DIST=\
        libarchive/test/test_compat_mac-1.tar.Z.uu \
        libarchive/test/test_compat_mac-2.tar.Z.uu \
        libarchive/test/test_compat_pax_libarchive_2x.tar.Z.uu \
+       libarchive/test/test_compat_perl_archive_tar.tar.uu \
        libarchive/test/test_compat_solaris_pax_sparse_1.pax.Z.uu \
        libarchive/test/test_compat_solaris_pax_sparse_2.pax.Z.uu \
        libarchive/test/test_compat_solaris_tar_acl.tar.uu \
index 0ee511ea1ae8d1d42fd3e564382b761c2ccf9c1e..b977cb7400fb102506c472da6c90e5200f103181 100644 (file)
@@ -294,8 +294,14 @@ archive_read_format_tar_cleanup(struct archive_read *a)
        return (ARCHIVE_OK);
 }
 
+/*
+ * Validate number field
+ *
+ * Flags:
+ * 1 - allow double \0 at field end
+ */
 static int
-validate_number_field(const char* p_field, size_t i_size)
+validate_number_field(const char* p_field, size_t i_size, int flags)
 {
        unsigned char marker = (unsigned char)p_field[0];
        /* octal? */
@@ -305,14 +311,24 @@ validate_number_field(const char* p_field, size_t i_size)
                for (i = 0; i < i_size; ++i) {
                        switch (p_field[i])
                        {
-                       case ' ': /* skip any leading spaces and trailing space*/
+                       case ' ':
+                               /* skip any leading spaces and trailing space */
                                if (octal_found == 0 || i == i_size - 1) {
                                        continue;
                                }
                                break;
-                       case '\0': /* null is allowed only at the end */
+                       case '\0':
+                               /*
+                                * null should be allowed only at the end
+                                *
+                                * Perl Archive::Tar terminates some fields
+                                * with two nulls. We must allow this to stay
+                                * compatible.
+                                */
                                if (i != i_size - 1) {
-                                       return 0;
+                                       if (((flags & 1) == 0)
+                                           || i != i_size - 2)
+                                               return 0;
                                }
                                break;
                        /* rest must be octal digits */
@@ -390,18 +406,25 @@ archive_read_format_tar_bid(struct archive_read *a, int best_bid)
         * Check format of mode/uid/gid/mtime/size/rdevmajor/rdevminor fields.
         * These are usually octal numbers but GNU tar encodes "big" values as
         * base256 and leading zeroes are sometimes replaced by spaces.
-        * Even the null terminator is sometimes omitted. Anyway, must be checked
-        * to avoid false positives.
+        * Even the null terminator is sometimes omitted. Anyway, must be
+        * checked to avoid false positives.
+        *
+        * Perl Archive::Tar does not follow the spec and terminates mode, uid,
+        * gid, rdevmajor and rdevminor with a double \0. For compatibility
+        * reasons we allow this deviation.
         */
-       if (bid > 0 &&
-               (validate_number_field(header->mode, sizeof(header->mode)) == 0 ||
-                validate_number_field(header->uid, sizeof(header->uid)) == 0 ||
-                validate_number_field(header->gid, sizeof(header->gid)) == 0 ||
-                validate_number_field(header->mtime, sizeof(header->mtime)) == 0 ||
-                validate_number_field(header->size, sizeof(header->size)) == 0 ||
-                validate_number_field(header->rdevmajor, sizeof(header->rdevmajor)) == 0 ||
-                validate_number_field(header->rdevminor, sizeof(header->rdevminor)) == 0)) {
-                       bid = 0;
+       if (bid > 0 && (
+           validate_number_field(header->mode, sizeof(header->mode), 1) == 0
+           || validate_number_field(header->uid, sizeof(header->uid), 1) == 0
+           || validate_number_field(header->gid, sizeof(header->gid), 1) == 0 
+           || validate_number_field(header->mtime, sizeof(header->mtime),
+           0) == 0
+           || validate_number_field(header->size, sizeof(header->size), 0) == 0
+           || validate_number_field(header->rdevmajor,
+           sizeof(header->rdevmajor), 1) == 0
+           || validate_number_field(header->rdevminor,
+           sizeof(header->rdevminor), 1) == 0)) {
+               bid = 0;
        }
 
        return (bid);
index 9d2622b0cda5aa0b933629d686b8336474729694..5dad2191021d25e9982ebc0c04eae340c285ecb5 100644 (file)
@@ -58,6 +58,7 @@ IF(ENABLE_TEST)
     test_compat_lzop.c
     test_compat_mac.c
     test_compat_pax_libarchive_2x.c
+    test_compat_perl_archive_tar.c
     test_compat_solaris_pax_sparse.c
     test_compat_solaris_tar_acl.c
     test_compat_star_acl_posix1e.c
diff --git a/libarchive/test/test_compat_perl_archive_tar.c b/libarchive/test/test_compat_perl_archive_tar.c
new file mode 100644 (file)
index 0000000..165a519
--- /dev/null
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 2016 Martin Matuska
+ * 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");
+
+/*
+ * Verify our ability to read sample files created by Perl module Archive::Tar
+ */
+
+DEFINE_TEST(test_compat_perl_archive_tar)
+{
+       char name[] = "test_compat_perl_archive_tar.tar";
+       struct archive_entry *ae;
+       struct archive *a;
+       int r;
+
+       assert((a = archive_read_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       extract_reference_file(name);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, name,
+           10240));
+
+       /* Read first entry. */
+       assertEqualIntA(a, ARCHIVE_OK, r = archive_read_next_header(a, &ae));
+       if (r != ARCHIVE_OK) {
+               archive_read_free(a);
+               return;
+       }
+       assertEqualString("file1", archive_entry_pathname(ae));
+       assertEqualInt(1480603099, archive_entry_mtime(ae));
+       assertEqualInt(1000, archive_entry_uid(ae));
+       assertEqualString("john", archive_entry_uname(ae));
+       assertEqualInt(1000, archive_entry_gid(ae));
+       assertEqualString("john", archive_entry_gname(ae));
+       assertEqualInt(0100644, archive_entry_mode(ae));
+
+       /* Verify that the format detection worked. */
+       assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_NONE);
+       assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR);
+
+       assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+       assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
diff --git a/libarchive/test/test_compat_perl_archive_tar.tar.uu b/libarchive/test/test_compat_perl_archive_tar.tar.uu
new file mode 100644 (file)
index 0000000..ca7bc2a
--- /dev/null
@@ -0,0 +1,49 @@
+begin 644 test_compat_perl_archive_tar.tar
+M9FEL93$`````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````#`P,#8T-```,#`Q-S4P```P,#$W-3```"`@("`@("`@("`U
+M`#$S,#(P,#,R-S,S`"`Q,3$R,P`@,```````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````!U<W1A<@`P,&IO:&X`
+M````````````````````````````````````:F]H;@``````````````````
+M```````````````````P,#`P,#```#`P,#`P,```````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````!A8F-D"@``````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+7````````````````````````````````
+`
+end