From: Martin Matuska Date: Thu, 1 Dec 2016 14:58:06 +0000 (+0100) Subject: Restore compatibility with Perl Archive::Tar that was broken with #825 X-Git-Tag: v3.3.0~106 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2d2b3e928605f795515b03f060fd638c265b0778;p=thirdparty%2Flibarchive.git Restore compatibility with Perl Archive::Tar that was broken with #825 --- diff --git a/Makefile.am b/Makefile.am index c04dc01a3..74485af96 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 \ diff --git a/libarchive/archive_read_support_format_tar.c b/libarchive/archive_read_support_format_tar.c index 0ee511ea1..b977cb740 100644 --- a/libarchive/archive_read_support_format_tar.c +++ b/libarchive/archive_read_support_format_tar.c @@ -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); diff --git a/libarchive/test/CMakeLists.txt b/libarchive/test/CMakeLists.txt index 9d2622b0c..5dad21910 100644 --- a/libarchive/test/CMakeLists.txt +++ b/libarchive/test/CMakeLists.txt @@ -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 index 000000000..165a519a3 --- /dev/null +++ b/libarchive/test/test_compat_perl_archive_tar.c @@ -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 index 000000000..ca7bc2a97 --- /dev/null +++ b/libarchive/test/test_compat_perl_archive_tar.tar.uu @@ -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