From 66c843184115a19d505c10061f605e5ff1b14c7a Mon Sep 17 00:00:00 2001 From: Tim Kientzle Date: Sun, 8 Mar 2009 06:07:35 +0000 Subject: [PATCH] Merge r709,r710 from libarchive.googlecode.com: More work on Windows support. --- usr.bin/tar/test/test_patterns.c | 79 +++ usr.bin/tar/test/test_patterns_4.tar.uu | 642 ++++++++++++++++++++++++ usr.bin/tar/util.c | 91 ++-- 3 files changed, 780 insertions(+), 32 deletions(-) create mode 100644 usr.bin/tar/test/test_patterns_4.tar.uu diff --git a/usr.bin/tar/test/test_patterns.c b/usr.bin/tar/test/test_patterns.c index 36d4542450d4..9d9cc60ebf49 100644 --- a/usr.bin/tar/test/test_patterns.c +++ b/usr.bin/tar/test/test_patterns.c @@ -1,4 +1,5 @@ /*- + * Copyright (c) 2009 Michihiro NAKAJIMA * Copyright (c) 2003-2007 Tim Kientzle * All rights reserved. * @@ -30,6 +31,7 @@ DEFINE_TEST(test_patterns) int fd, r; const char *reffile2 = "test_patterns_2.tar"; const char *reffile3 = "test_patterns_3.tar"; + const char *reffile4 = "test_patterns_4.tar"; const char *p; /* @@ -101,4 +103,81 @@ DEFINE_TEST(test_patterns) assertEmptyFile("tar3d.out"); assertEmptyFile("tar3d.err"); assertEqualInt(0, access("tmp/foo/baz/bar", F_OK)); + + /* + * Test 4 archive has some entries starting with windows drive letters + * such as 'c:\', '//./c:/' or '//?/c:/'. + */ + extract_reference_file(reffile4); + + r = systemf("%s xf %s -C tmp > tar4.out 2> tar4.err", + testprog, reffile4); + assert(r != 0); + assertEmptyFile("tar4.out"); + assertNonEmptyFile("tar4.err"); + + for (r = 1; r <= 54; r++) { + char file_a[] = "tmp/fileXX"; + char file_b1[] = "tmp/server/share/fileXX"; + char file_b2[] = "tmp/server\\share\\fileXX"; + char file_c[] = "tmp/../fileXX"; + char *filex; + int xsize; + + switch (r) { + case 15: case 18: + /* + * Including server and share names. + * //?/UNC/server/share/file15 + * //?/unc/server/share/file18 + */ + filex = file_b1; + xsize = sizeof(file_b1); + break; + case 35: case 38: case 52: + /* + * Including server and share names. + * \\?\UNC\server\share\file35 + * \\?\unc\server\share\file38 + * \/?/uNc/server\share\file52 + */ + filex = file_b2; + xsize = sizeof(file_b2); + break; + default: + filex = file_a; + xsize = sizeof(file_a); + break; + } + filex[xsize-3] = '0' + r / 10; + filex[xsize-2] = '0' + r % 10; + switch (r) { + case 5: case 6: case 17: case 20: case 25: + case 26: case 37: case 40: case 43: case 54: + /* + * Not extracted patterns. + * D:../file05 + * c:../../file06 + * //?/UNC/../file17 + * //?/unc/../file20 + * z:..\file25 + * c:..\..\file26 + * \\?\UNC\..\file37 + * \\?\unc\..\file40 + * c:../..\file43 + * \/?\UnC\../file54 + */ + assertEqualInt(-1, access(filex, F_OK)); + filex = file_c; + xsize = sizeof(file_c); + filex[xsize-3] = '0' + r / 10; + filex[xsize-2] = '0' + r % 10; + assertEqualInt(-1, access(filex, F_OK)); + break; + default: + /* Extracted patterns. */ + assertEqualInt(0, access(filex, F_OK)); + break; + } + } } diff --git a/usr.bin/tar/test/test_patterns_4.tar.uu b/usr.bin/tar/test/test_patterns_4.tar.uu new file mode 100644 index 000000000000..eb89518df453 --- /dev/null +++ b/usr.bin/tar/test/test_patterns_4.tar.uu @@ -0,0 +1,642 @@ +$FreeBSD$ +begin 644 test_patterns_4.tar +M+V9I;&4P,0`````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M`````````````#`P,#8T-"``,#`Q-S4Q(``P,#$W-3$@`#`P,#`P,#`P,#`P +M(#$Q,34P-CCHN+EQF:6QE,C4````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M`````````````````#`P,#8T-"``,#`Q-S4Q(``P,#$W-3$@`#`P,#`P,#`P +M,#`P(#$Q,34P-Coption_absolute_paths) { - /* Strip Windows drive letters. */ - if (((name[0] >= 'A' && name[0] <= 'Z') - || (name[0] >= 'a' && name[0] <= 'z')) - && name[1] == ':' - && (name[2] == '/' || name[2] == '\\')) + const char *rp, *p = name; + int slashonly = 1; + + /* Remove leading "//./" or "//?/" or "//?/UNC/" + * (absolute path prefixes used by Windows API) */ + if ((p[0] == '/' || p[0] == '\\') && + (p[1] == '/' || p[1] == '\\') && + (p[2] == '.' || p[2] == '?') && + (p[3] == '/' || p[3] == '\\')) { - /* Generate a warning the first time this happens. */ - if (!bsdtar->warned_lead_slash) { - bsdtar_warnc(bsdtar, 0, - "Removing leading drive letter from member names"); - bsdtar->warned_lead_slash = 1; + if (p[2] == '?' && + (p[4] == 'U' || p[4] == 'u') && + (p[5] == 'N' || p[5] == 'n') && + (p[6] == 'C' || p[6] == 'c') && + (p[7] == '/' || p[7] == '\\')) + p += 8; + else + p += 4; + slashonly = 0; + } + do { + rp = p; + /* Remove leading drive letter from archives created + * on Windows. */ + if (((p[0] >= 'a' && p[0] <= 'z') || + (p[0] >= 'A' && p[0] <= 'Z')) && + p[1] == ':') { + p += 2; + slashonly = 0; } - name += 3; - while (*name == '/' || *name == '\\') - ++name; - /* Special case: Stripping everything yields ".". */ - if (*name == '\0') - name = "."; + /* Remove leading "/../", "//", etc. */ + while (p[0] == '/' || p[0] == '\\') { + if (p[1] == '.' && p[2] == '.' && + (p[3] == '/' || p[3] == '\\')) { + p += 3; /* Remove "/..", leave "/" + * for next pass. */ + slashonly = 0; + } else + p += 1; /* Remove "/". */ + } + } while (rp != p); + + if (p != name && !bsdtar->warned_lead_slash) { + /* Generate a warning the first time this happens. */ + if (slashonly) + bsdtar_warnc(bsdtar, 0, + "Removing leading '%c' from member names", + name[0]); + else + bsdtar_warnc(bsdtar, 0, + "Removing leading drive letter from " + "member names"); + bsdtar->warned_lead_slash = 1; } - /* Strip leading '/'. */ - if (name[0] == '/') { - /* Generate a warning the first time this happens. */ - if (!bsdtar->warned_lead_slash) { - bsdtar_warnc(bsdtar, 0, - "Removing leading '/' from member names"); - bsdtar->warned_lead_slash = 1; - } + /* Special case: Stripping everything yields ".". */ + if (*p == '\0') + name = "."; + else + name = p; + } else { + /* Strip redundant leading '/' characters. */ + while (name[0] == '/' && name[1] == '/') name++; - /* Special case: Stripping everything yields ".". */ - if (*name == '\0') - name = "."; - } } /* Safely replace name in archive_entry. */