summaryrefslogtreecommitdiffstats
path: root/usr.bin/tar/util.c
diff options
context:
space:
mode:
authorkientzle <kientzle@FreeBSD.org>2008-11-10 05:04:55 +0000
committerkientzle <kientzle@FreeBSD.org>2008-11-10 05:04:55 +0000
commit19a4817b26349c90c83c0e1bee2792d456160309 (patch)
tree0dd200618fa0faf37a0a4f3baeadc6ca681005ea /usr.bin/tar/util.c
parent48d5b1d6102bf6d4b152adb78c42dbaef67bb4de (diff)
downloadFreeBSD-src-19a4817b26349c90c83c0e1bee2792d456160309.zip
FreeBSD-src-19a4817b26349c90c83c0e1bee2792d456160309.tar.gz
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
Diffstat (limited to 'usr.bin/tar/util.c')
-rw-r--r--usr.bin/tar/util.c54
1 files changed, 38 insertions, 16 deletions
diff --git a/usr.bin/tar/util.c b/usr.bin/tar/util.c
index 33281aa..638145a 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. */
OpenPOWER on IntegriCloud