From owner-svn-src-all@FreeBSD.ORG Sun Nov 7 03:40:37 2010 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 8A3051065672; Sun, 7 Nov 2010 03:40:37 +0000 (UTC) (envelope-from kientzle@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 77FA38FC12; Sun, 7 Nov 2010 03:40:37 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id oA73ebMx013350; Sun, 7 Nov 2010 03:40:37 GMT (envelope-from kientzle@svn.freebsd.org) Received: (from kientzle@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id oA73ebRw013346; Sun, 7 Nov 2010 03:40:37 GMT (envelope-from kientzle@svn.freebsd.org) Message-Id: <201011070340.oA73ebRw013346@svn.freebsd.org> From: Tim Kientzle Date: Sun, 7 Nov 2010 03:40:37 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r214905 - in head/lib/libarchive: . test X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 07 Nov 2010 03:40:37 -0000 Author: kientzle Date: Sun Nov 7 03:40:37 2010 New Revision: 214905 URL: http://svn.freebsd.org/changeset/base/214905 Log: If the Zip reader doesn't see a PK signature block because there's inter-entry garbage, just scan forward to find the next one. This allows us to handle a lot of Zip archives that have been modified in-place. Thanks to: Gleb Kurtsou for sending me a sample archive Added: head/lib/libarchive/test/test_compat_zip_2.zip.uu (contents, props changed) Modified: head/lib/libarchive/archive_read_support_format_zip.c head/lib/libarchive/test/test_compat_zip.c Modified: head/lib/libarchive/archive_read_support_format_zip.c ============================================================================== --- head/lib/libarchive/archive_read_support_format_zip.c Sun Nov 7 03:26:22 2010 (r214904) +++ head/lib/libarchive/archive_read_support_format_zip.c Sun Nov 7 03:40:37 2010 (r214905) @@ -128,6 +128,7 @@ static int archive_read_format_zip_read_ static int archive_read_format_zip_read_data_skip(struct archive_read *a); static int archive_read_format_zip_read_header(struct archive_read *, struct archive_entry *); +static int search_next_signature(struct archive_read *); static int zip_read_data_deflate(struct archive_read *a, const void **buff, size_t *size, off_t *offset); static int zip_read_data_none(struct archive_read *a, const void **buff, @@ -317,10 +318,17 @@ archive_read_format_zip_read_header(stru signature = (const char *)h; } + /* If we don't see a PK signature here, scan forward. */ if (signature[0] != 'P' || signature[1] != 'K') { - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "Bad ZIP file"); - return (ARCHIVE_FATAL); + r = search_next_signature(a); + if (r != ARCHIVE_OK) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Bad ZIP file"); + return (ARCHIVE_FATAL); + } + if ((h = __archive_read_ahead(a, 4, NULL)) == NULL) + return (ARCHIVE_FATAL); + signature = (const char *)h; } /* @@ -375,6 +383,42 @@ archive_read_format_zip_read_header(stru } static int +search_next_signature(struct archive_read *a) +{ + const void *h; + const char *p, *q; + size_t skip; + ssize_t bytes; + int64_t skipped = 0; + + for (;;) { + h = __archive_read_ahead(a, 4, &bytes); + if (h == NULL) + return (ARCHIVE_FATAL); + p = h; + q = p + bytes; + + while (p + 4 <= q) { + if (p[0] == 'P' && p[1] == 'K') { + if ((p[2] == '\001' && p[3] == '\002') + || (p[2] == '\003' && p[3] == '\004') + || (p[2] == '\005' && p[3] == '\006') + || (p[2] == '\007' && p[3] == '\010') + || (p[2] == '0' && p[3] == '0')) { + skip = p - (const char *)h; + __archive_read_consume(a, skip); + return (ARCHIVE_OK); + } + } + ++p; + } + skip = p - (const char *)h; + __archive_read_consume(a, skip); + skipped += skip; + } +} + +static int zip_read_file_header(struct archive_read *a, struct archive_entry *entry, struct zip *zip) { @@ -888,6 +932,9 @@ process_extra(const void* extra, struct if (datasize >= 4) zip->gid = archive_le16dec(p + offset + 2); break; + case 0x7875: + /* Info-Zip Unix Extra Field (type 3) "ux". */ + break; default: break; } Modified: head/lib/libarchive/test/test_compat_zip.c ============================================================================== --- head/lib/libarchive/test/test_compat_zip.c Sun Nov 7 03:26:22 2010 (r214904) +++ head/lib/libarchive/test/test_compat_zip.c Sun Nov 7 03:40:37 2010 (r214905) @@ -71,10 +71,43 @@ finish: #endif } +/* + * Verify that we skip junk between entries. The compat_zip_2.zip file + * has several bytes of junk between 'file1' and 'file2'. Such + * junk is routinely introduced by some Zip writers when they manipulate + * existing zip archives. + */ +static void +test_compat_zip_2(void) +{ + char name[] = "test_compat_zip_2.zip"; + struct archive_entry *ae; + struct archive *a; + + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_compression_all(a)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip(a)); + extract_reference_file(name); + assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, name, 10240)); + + /* Read first entry. */ + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualString("file1", archive_entry_pathname(ae)); + + /* Read first entry. */ + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualString("file2", archive_entry_pathname(ae)); + + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} + DEFINE_TEST(test_compat_zip) { test_compat_zip_1(); + test_compat_zip_2(); } Added: head/lib/libarchive/test/test_compat_zip_2.zip.uu ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/lib/libarchive/test/test_compat_zip_2.zip.uu Sun Nov 7 03:40:37 2010 (r214905) @@ -0,0 +1,10 @@ +$FreeBSD$ + +begin 644 test_compat_zip_2.zip +M4$L#!`H``````'V59CT````````````````%````9FEL93$M2E5.2RU02P,$ +M"@``````@95F/<>D!,D&````!@````4```!F:6QE,F9I;&4R"E!+`0(>`PH` +M`````'V59CT````````````````%``````````````"D@0````!F:6QE,5!+ +M`0(>`PH``````(&59CW'I`3)!@````8````%``````````````"D@2D```!F +::6QE,E!+!08``````@`"`&8```!2```````` +` +end