Fix handling of leading slashes for hardlinks

This commit is contained in:
Tim Kientzle committed 2014-11-02 17:11:36 -08:00
1 parent 86b9097ea1
commit cf8e67ffc8
5 files changed
+217 -73

No files matched your search

+2
View File
@@ -889,6 +889,7 @@ bsdtar_test_SOURCES= \
tar/test/test_extract_tar_xz.c \
tar/test/test_format_newc.c \
tar/test/test_help.c \
tar/test/test_leading_slash.c \
tar/test/test_option_C_upper.c \
tar/test/test_option_H_upper.c \
tar/test/test_option_L_upper.c \
@@ -958,6 +959,7 @@ bsdtar_test_EXTRA_DIST= \
tar/test/test_extract.tar.lzma.uu \
tar/test/test_extract.tar.lzo.uu \
tar/test/test_extract.tar.xz.uu \
tar/test/test_leading_slash.tar.uu \
tar/test/test_option_keep_newer_files.tar.Z.uu \
tar/test/test_option_passphrase.zip.uu \
tar/test/test_option_s.tar.Z.uu \
+1
View File
@@ -24,6 +24,7 @@ IF(ENABLE_TAR AND ENABLE_TEST)
test_extract_tar_xz.c
test_format_newc.c
test_help.c
test_leading_slash.c
test_option_C_upper.c
test_option_H_upper.c
test_option_L_upper.c
+41
View File
@@ -0,0 +1,41 @@
/*-
* Copyright (c) 2003-2014 Tim Kientzle
* 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$");
DEFINE_TEST(test_leading_slash)
{
const char *reffile = "test_leading_slash.tar";
extract_reference_file(reffile);
assertEqualInt(0, systemf("%s -xf %s >test.out 2>test.err", testprog, reffile));
assertFileExists("foo/file");
assertTextFileContents("foo\x0a", "foo/file");
assertTextFileContents("foo\x0a", "foo/hardlink");
assertIsHardlink("foo/file", "foo/hardlink");
assertEmptyFile("test.out");
assertTextFileContents("bsdtar: Removing leading '/' from member names\x0a", "test.err");
}
+60
View File
@@ -0,0 +1,60 @@
begin 644 test_leading_slash.tar
M+V9O;R]F:6QE````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M`````````````#`P,#8T-"``,#`P,#`P(``P,#`P,#`@`#`P,#`P,#`P,#`T
M(#$R-#$V,S4U-34V(#`Q,C8V-P`@,```````````````````````````````
M````````````````````````````````````````````````````````````
M``````````````````````````````````````````!U<W1A<@`P,')O;W0`
M````````````````````````````````````=VAE96P`````````````````
M```````````````````P,#`P,#`@`#`P,#`P,"``````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M``````````````````````!F;V\*````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M`````````````````````````````````````````````"]F;V\O:&%R9&QI
M;FL`````````````````````````````````````````````````````````
M```````````````````````````````````````````````````````````P
M,#`V-#0@`#`P,#`P,"``,#`P,#`P(``P,#`P,#`P,#`P,"`Q,C0Q-C,U-34U
M-B`P,34R-#,`(#$O9F]O+V9I;&4`````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````=7-T87(`,#!R;V]T````````````````
M`````````````````````'=H965L````````````````````````````````
M````,#`P,#`P(``P,#`P,#`@````````````````````````````````````
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````````````````````````````````````````````````````````````
H````````````````````````````````````````````````````````
`
end
+113 -73
View File
@@ -373,20 +373,107 @@ strip_components(const char *p, int elements)
}
}
static void
warn_strip_leading_char(struct bsdtar *bsdtar, const char *c)
{
if (!bsdtar->warned_lead_slash) {
lafe_warnc(0,
"Removing leading '%c' from member names",
c[0]);
bsdtar->warned_lead_slash = 1;
}
}
static void
warn_strip_drive_letter(struct bsdtar *bsdtar)
{
if (!bsdtar->warned_lead_slash) {
lafe_warnc(0,
"Removing leading drive letter from "
"member names");
bsdtar->warned_lead_slash = 1;
}
}
/*
* Convert absolute path to non-absolute path by skipping leading
* absolute path prefixes.
*/
static const char*
strip_absolute_path(struct bsdtar *bsdtar, const char *p)
{
const char *rp;
/* 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] == '\\'))
{
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;
warn_strip_drive_letter(bsdtar);
}
/* Remove multiple leading slashes and Windows drive letters. */
do {
rp = p;
if (((p[0] >= 'a' && p[0] <= 'z') ||
(p[0] >= 'A' && p[0] <= 'Z')) &&
p[1] == ':') {
p += 2;
warn_strip_drive_letter(bsdtar);
}
/* Remove leading "/../", "/./", "//", etc. */
while (p[0] == '/' || p[0] == '\\') {
if (p[1] == '.' &&
p[2] == '.' &&
(p[3] == '/' || p[3] == '\\')) {
p += 3; /* Remove "/..", leave "/" for next pass. */
} else if (p[1] == '.' &&
(p[2] == '/' || p[2] == '\\')) {
p += 2; /* Remove "/.", leave "/" for next pass. */
} else
p += 1; /* Remove "/". */
warn_strip_leading_char(bsdtar, rp);
}
} while (rp != p);
return (p);
}
/*
* Handle --strip-components and any future path-rewriting options.
* Returns non-zero if the pathname should not be extracted.
*
* Note: The rewrites are applied uniformly to pathnames and hardlink
* names but not to symlink bodies. This is deliberate: Symlink
* bodies are not necessarily filenames. Even when they are, they
* need to be interpreted relative to the directory containing them,
* so simple rewrites like this are rarely appropriate.
*
* TODO: Support pax-style regex path rewrites.
*/
int
edit_pathname(struct bsdtar *bsdtar, struct archive_entry *entry)
{
const char *name = archive_entry_pathname(entry);
const char *original_name = name;
const char *hardlinkname = archive_entry_hardlink(entry);
const char *original_hardlinkname = hardlinkname;
#if defined(HAVE_REGEX_H) || defined(HAVE_PCREPOSIX_H)
char *subst_name;
int r;
/* Apply user-specified substitution to pathname. */
r = apply_substitution(bsdtar, name, &subst_name, 0, 0);
if (r == -1) {
lafe_warnc(0, "Invalid substitution, skipping entry");
@@ -400,10 +487,12 @@ edit_pathname(struct bsdtar *bsdtar, struct archive_entry *entry)
} else
free(subst_name);
name = archive_entry_pathname(entry);
original_name = name;
}
if (archive_entry_hardlink(entry)) {
r = apply_substitution(bsdtar, archive_entry_hardlink(entry), &subst_name, 0, 1);
/* Apply user-specified substitution to hardlink target. */
if (hardlinkname != NULL) {
r = apply_substitution(bsdtar, hardlinkname, &subst_name, 0, 1);
if (r == -1) {
lafe_warnc(0, "Invalid substitution, skipping entry");
return 1;
@@ -412,7 +501,11 @@ edit_pathname(struct bsdtar *bsdtar, struct archive_entry *entry)
archive_entry_copy_hardlink(entry, subst_name);
free(subst_name);
}
hardlinkname = archive_entry_hardlink(entry);
original_hardlinkname = hardlinkname;
}
/* Apply user-specified substitution to symlink body. */
if (archive_entry_symlink(entry) != NULL) {
r = apply_substitution(bsdtar, archive_entry_symlink(entry), &subst_name, 1, 0);
if (r == -1) {
@@ -428,94 +521,41 @@ edit_pathname(struct bsdtar *bsdtar, struct archive_entry *entry)
/* Strip leading dir names as per --strip-components option. */
if (bsdtar->strip_components > 0) {
const char *linkname = archive_entry_hardlink(entry);
name = strip_components(name, bsdtar->strip_components);
if (name == NULL)
return (1);
if (linkname != NULL) {
linkname = strip_components(linkname,
if (hardlinkname != NULL) {
hardlinkname = strip_components(hardlinkname,
bsdtar->strip_components);
if (linkname == NULL)
if (hardlinkname == NULL)
return (1);
archive_entry_copy_hardlink(entry, linkname);
}
}
/* By default, don't write or restore absolute pathnames. */
if (!bsdtar->option_absolute_paths) {
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] == '\\'))
{
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;
}
/* 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)
lafe_warnc(0,
"Removing leading '%c' from member names",
name[0]);
else
lafe_warnc(0,
"Removing leading drive letter from "
"member names");
bsdtar->warned_lead_slash = 1;
}
/* Special case: Stripping everything yields ".". */
if (*p == '\0')
/* By default, don't write or restore absolute pathnames. */
name = strip_absolute_path(bsdtar, name);
if (*name == '\0')
name = ".";
else
name = p;
if (hardlinkname != NULL) {
hardlinkname = strip_absolute_path(bsdtar, hardlinkname);
if (*hardlinkname == '\0')
return (1);
}
} else {
/* Strip redundant leading '/' characters. */
while (name[0] == '/' && name[1] == '/')
name++;
}
/* Safely replace name in archive_entry. */
if (name != archive_entry_pathname(entry)) {
char *q = strdup(name);
archive_entry_copy_pathname(entry, q);
free(q);
/* Replace name in archive_entry. */
if (name != original_name) {
archive_entry_copy_pathname(entry, name);
}
if (hardlinkname != original_hardlinkname) {
archive_entry_copy_hardlink(entry, hardlinkname);
}
return (0);
}