diff options
author | Tim Kientzle <kientzle@FreeBSD.org> | 2008-11-10 05:04:55 +0000 |
---|---|---|
committer | Tim Kientzle <kientzle@FreeBSD.org> | 2008-11-10 05:04:55 +0000 |
commit | c4a52c7226538f84701919adffa3f84e27ac064e (patch) | |
tree | 0dd200618fa0faf37a0a4f3baeadc6ca681005ea /usr.bin/tar/util.c | |
parent | 333b8b2fa03f9132a16422dd0a1178e7041adb71 (diff) |
Test --strip-components and fix it to actually work. Jaakko did a
good job writing this test; it exercises a lot of subtle cases. The
trickiest one is that a hardlink to something that didn't get
extracted should not itself be extracted. In some sense, this is not
the desired behavior (we'd rather restore the file), but it's the best
you can do in a single-pass restore of a tar archive.
The test here should be extended to exercise cpio and newc formats as
well, since their hardlink models are different, which will lead to
different handling of some of these edge cases.
Submitted by: Jaakko Heinonen
MFC after: 30 days
Notes
Notes:
svn path=/head/; revision=184807
Diffstat (limited to 'usr.bin/tar/util.c')
-rw-r--r-- | usr.bin/tar/util.c | 54 |
1 files changed, 38 insertions, 16 deletions
diff --git a/usr.bin/tar/util.c b/usr.bin/tar/util.c index 33281aae035e..638145aec5fe 100644 --- a/usr.bin/tar/util.c +++ b/usr.bin/tar/util.c @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); static void bsdtar_vwarnc(struct bsdtar *, int code, const char *fmt, va_list ap); +static const char *strip_components(const char *path, int elements); /* * Print a string, taking care with any non-printable characters. @@ -346,6 +347,31 @@ do_chdir(struct bsdtar *bsdtar) bsdtar->pending_chdir = NULL; } +const char * +strip_components(const char *path, int elements) +{ + const char *p = path; + + while (elements > 0) { + switch (*p++) { + case '/': + elements--; + path = p; + break; + case '\0': + /* Path is too short, skip it. */ + return (NULL); + } + } + + while (*path == '/') + ++path; + if (*path == '\0') + return (NULL); + + return (path); +} + /* * Handle --strip-components and any future path-rewriting options. * Returns non-zero if the pathname should not be extracted. @@ -402,24 +428,20 @@ edit_pathname(struct bsdtar *bsdtar, struct archive_entry *entry) #endif /* Strip leading dir names as per --strip-components option. */ - if ((r = bsdtar->strip_components) > 0) { - const char *p = name; - - while (r > 0) { - switch (*p++) { - case '/': - r--; - name = p; - break; - case '\0': - /* Path is too short, skip it. */ + 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, + bsdtar->strip_components); + if (linkname == NULL) return (1); - } + archive_entry_copy_hardlink(entry, linkname); } - while (*name == '/') - ++name; - if (*name == '\0') - return (1); } /* Strip redundant leading '/' characters. */ |