diff options
author | kientzle <kientzle@FreeBSD.org> | 2005-03-13 04:12:30 +0000 |
---|---|---|
committer | kientzle <kientzle@FreeBSD.org> | 2005-03-13 04:12:30 +0000 |
commit | 0eac7627b850b8c334a8046f449e923e3b71300f (patch) | |
tree | dfe7c2c3a1342845144bb340f0a5527b3e3fa7ce /usr.bin/tar | |
parent | 83b23d92b11796798d75702703ef2ea0aed23259 (diff) | |
download | FreeBSD-src-0eac7627b850b8c334a8046f449e923e3b71300f.zip FreeBSD-src-0eac7627b850b8c334a8046f449e923e3b71300f.tar.gz |
Add --strip-components option, per bin/77666.
Thanks to: Sangwoo Shim
Diffstat (limited to 'usr.bin/tar')
-rw-r--r-- | usr.bin/tar/Makefile | 2 | ||||
-rw-r--r-- | usr.bin/tar/bsdtar.1 | 6 | ||||
-rw-r--r-- | usr.bin/tar/bsdtar.c | 7 | ||||
-rw-r--r-- | usr.bin/tar/bsdtar.h | 1 | ||||
-rw-r--r-- | usr.bin/tar/read.c | 58 |
5 files changed, 72 insertions, 2 deletions
diff --git a/usr.bin/tar/Makefile b/usr.bin/tar/Makefile index d0a9696..3d7abe9 100644 --- a/usr.bin/tar/Makefile +++ b/usr.bin/tar/Makefile @@ -6,7 +6,7 @@ # PROG= bsdtar -VERSION= 1.01.020 +VERSION= 1.01.021 SRCS= bsdtar.c matching.c read.c util.c write.c WARNS?= 6 DPADD= ${LIBARCHIVE} ${LIBBZ2} ${LIBZ} diff --git a/usr.bin/tar/bsdtar.1 b/usr.bin/tar/bsdtar.1 index 2bcab1b..538328c 100644 --- a/usr.bin/tar/bsdtar.1 +++ b/usr.bin/tar/bsdtar.1 @@ -302,6 +302,12 @@ If is being run by root, the default is to restore the owner unless the .Fl o option is also specified. +.It Fl -strip-components Ar count ( Fl W Cm strip-components Ns = Ns Ar count ) +(x and t mode only) +Remove the specified number of leading path elements. +Pathnames with fewer elements will be silently skipped. +Note that the pathname is edited after checking inclusion/exclusion patterns +but before security checks. .It Fl T Ar filename In x or t mode, .Nm diff --git a/usr.bin/tar/bsdtar.c b/usr.bin/tar/bsdtar.c index 95a98cb..dfb911c 100644 --- a/usr.bin/tar/bsdtar.c +++ b/usr.bin/tar/bsdtar.c @@ -115,7 +115,8 @@ static const char *tar_opts = "+Bb:C:cF:f:HhI:jkLlmnOoPprtT:UuvW:wX:xyZz"; #define OPTION_NODUMP 18 #define OPTION_NO_SAME_PERMISSIONS 21 #define OPTION_NULL 24 -#define OPTION_ONE_FILE_SYSTEM 27 +#define OPTION_ONE_FILE_SYSTEM 25 +#define OPTION_STRIP_COMPONENTS 27 #define OPTION_TOTALS 28 #define OPTION_VERSION 30 @@ -161,6 +162,7 @@ static const struct option tar_longopts[] = { { "preserve-permissions", no_argument, NULL, 'p' }, { "read-full-blocks", no_argument, NULL, 'B' }, { "same-permissions", no_argument, NULL, 'p' }, + { "strip-components", required_argument, NULL, OPTION_STRIP_COMPONENTS }, { "to-stdout", no_argument, NULL, 'O' }, { "totals", no_argument, NULL, OPTION_TOTALS }, { "unlink", no_argument, NULL, 'U' }, @@ -369,6 +371,9 @@ main(int argc, char **argv) case 'r': /* SUSv2 */ set_mode(bsdtar, opt); break; + case OPTION_STRIP_COMPONENTS: + bsdtar->strip_components = atoi(optarg); + break; case 'T': /* GNU tar */ bsdtar->names_from_file = optarg; break; diff --git a/usr.bin/tar/bsdtar.h b/usr.bin/tar/bsdtar.h index 387c040..339adba 100644 --- a/usr.bin/tar/bsdtar.h +++ b/usr.bin/tar/bsdtar.h @@ -51,6 +51,7 @@ struct bsdtar { int bytes_per_block; /* -b block_size */ int verbose; /* -v */ int extract_flags; /* Flags for extract operation */ + int strip_components; /* Remove this many leading dirs */ char mode; /* Program mode: 'c', 't', 'r', 'u', 'x' */ char symlink_mode; /* H or L, per BSD conventions */ char create_compression; /* j, y, or z */ diff --git a/usr.bin/tar/read.c b/usr.bin/tar/read.c index 0e478a1..1bb657e 100644 --- a/usr.bin/tar/read.c +++ b/usr.bin/tar/read.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include "bsdtar.h" static void cleanup_security(struct bsdtar *); +static int edit_pathname(struct bsdtar *, struct archive_entry *); static void list_item_verbose(struct bsdtar *, FILE *, struct archive_entry *); static void read_archive(struct bsdtar *bsdtar, char mode); @@ -115,9 +116,29 @@ read_archive(struct bsdtar *bsdtar, char mode) continue; } + /* + * Note that exclusions are checked before pathname + * rewrites are handled. This gives more control over + * exclusions, since rewrites always lose information. + * (For example, consider a rewrite s/foo[0-9]/foo/. + * If we check exclusions after the rewrite, there + * would be no way to exclude foo1/bar while allowing + * foo2/bar.) + */ if (excluded(bsdtar, archive_entry_pathname(entry))) continue; + /* + * Modify the pathname as requested by the user. We + * do this for -t as well to give users a way to + * preview the effects of their rewrites. We also do + * this before extraction security checks (including + * leading '/' removal). Note that some rewrite + * failures prevent extraction. + */ + if (edit_pathname(bsdtar, entry)) + continue; + if (mode == 't') { /* Perversely, gtar uses -O to mean "send to stderr" * when used with -t. */ @@ -295,6 +316,43 @@ list_item_verbose(struct bsdtar *bsdtar, FILE *out, struct archive_entry *entry) safe_fprintf(out, " -> %s", archive_entry_symlink(entry)); } +/* + * Handle --strip-components and any future path-rewriting options. + * Returns non-zero if the pathname should not be extracted. + */ +static int +edit_pathname(struct bsdtar *bsdtar, struct archive_entry *entry) +{ + /* Strip leading dir names as per --strip-components option. */ + if (bsdtar->strip_components > 0) { + int r = bsdtar->strip_components; + const char *name = archive_entry_pathname(entry); + const char *p = name; + char *q; + + while (r > 0) { + switch (*p++) { + case '/': + r--; + name = p; + break; + case '\0': + /* Path is too short, skip it. */ + return (1); + } + } + /* Safely replace name in archive_entry. */ + q = strdup(name); + archive_entry_copy_pathname(entry, q); + free(q); + } + + return (0); +} + +/* + * Structure for storing path of last successful security check. + */ struct security { char *path; size_t path_size; |