From: John Starks Date: Thu, 16 Nov 2017 00:10:49 +0000 (-0800) Subject: zip: Allow backslash as path separator X-Git-Tag: v3.3.3~25^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F970%2Fhead;p=thirdparty%2Flibarchive.git zip: Allow backslash as path separator Some Windows zip archivers, such as PowerShell's Compress-Archive, use backslash as the path separator in violation of the zip specification. Info-Zip works around this by supporting this for archives that report "version made by" of 0 (MS-DOS). This change adds the same workaround to libarchive and adds a test of this case using a zip file created with PowerShell. --- diff --git a/Makefile.am b/Makefile.am index f54a61897..461402f11 100644 --- a/Makefile.am +++ b/Makefile.am @@ -681,6 +681,7 @@ libarchive_test_EXTRA_DIST=\ libarchive/test/test_compat_zip_5.zip.uu \ libarchive/test/test_compat_zip_6.zip.uu \ libarchive/test/test_compat_zip_7.xps.uu \ + libarchive/test/test_compat_zip_8.zip.uu \ libarchive/test/test_compat_zstd_1.tar.zst.uu \ libarchive/test/test_fuzz.cab.uu \ libarchive/test/test_fuzz.lzh.uu \ diff --git a/libarchive/archive_read_support_format_zip.c b/libarchive/archive_read_support_format_zip.c index 69e388ead..784160070 100644 --- a/libarchive/archive_read_support_format_zip.c +++ b/libarchive/archive_read_support_format_zip.c @@ -886,6 +886,24 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry, zip_entry->mode |= 0664; } + /* Windows archivers sometimes use backslash as the directory separator. + Normalize to slash. */ + if (zip_entry->system == 0 && + (wp = archive_entry_pathname_w(entry)) != NULL) { + if (wcschr(wp, L'/') == NULL && wcschr(wp, L'\\') != NULL) { + size_t i; + struct archive_wstring s; + archive_string_init(&s); + archive_wstrcpy(&s, wp); + for (i = 0; i < archive_strlen(&s); i++) { + if (s.s[i] == '\\') + s.s[i] = '/'; + } + archive_entry_copy_pathname_w(entry, s.s); + archive_wstring_free(&s); + } + } + /* 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. */ diff --git a/libarchive/test/test_compat_zip.c b/libarchive/test/test_compat_zip.c index bb6d92ef4..39152206c 100644 --- a/libarchive/test/test_compat_zip.c +++ b/libarchive/test/test_compat_zip.c @@ -422,3 +422,29 @@ DEFINE_TEST(test_compat_zip_7) } free(p); } + +/** + * A file with backslash path separators instead of slashes. + * PowerShell's Compress-Archive cmdlet produces such archives. + */ +DEFINE_TEST(test_compat_zip_8) +{ + const char *refname = "test_compat_zip_8.zip"; + struct archive *a; + struct archive_entry *ae; + void *p; + size_t s; + + extract_reference_file(refname); + p = slurpfile(&s, refname); + + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip(a)); + assertEqualIntA(a, ARCHIVE_OK, read_open_memory_minimal(a, p, s, 7)); + + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + /* This file is in the archive as arc\test */ + assertEqualString("arc/test", archive_entry_pathname(ae)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a)); + free(p); +} diff --git a/libarchive/test/test_compat_zip_8.zip.uu b/libarchive/test/test_compat_zip_8.zip.uu new file mode 100644 index 000000000..316b6f62d --- /dev/null +++ b/libarchive/test/test_compat_zip_8.zip.uu @@ -0,0 +1,6 @@ +begin 666 test_compat_zip_8.zip +M4$L#!!0````(`%A\;TOY6""D$`````X````(````87)C7'1E!BP$`4$L!`A0`%`````@`6'QO2_E8(*00````#@````@````````` +H`````````````&%R8UQT97-T4$L%!@`````!``$`-@```#8````````` +` +end