Fix handling of leading slashes for hardlinks
This commit is contained in:
1 parent
86b9097ea1
commit
cf8e67ffc8
5 files changed
+217
-73
No files matched your search
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user