summaryrefslogtreecommitdiffstats
path: root/usr.bin/tar
diff options
context:
space:
mode:
authorkientzle <kientzle@FreeBSD.org>2005-03-13 04:12:30 +0000
committerkientzle <kientzle@FreeBSD.org>2005-03-13 04:12:30 +0000
commit0eac7627b850b8c334a8046f449e923e3b71300f (patch)
treedfe7c2c3a1342845144bb340f0a5527b3e3fa7ce /usr.bin/tar
parent83b23d92b11796798d75702703ef2ea0aed23259 (diff)
downloadFreeBSD-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/Makefile2
-rw-r--r--usr.bin/tar/bsdtar.16
-rw-r--r--usr.bin/tar/bsdtar.c7
-rw-r--r--usr.bin/tar/bsdtar.h1
-rw-r--r--usr.bin/tar/read.c58
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;
OpenPOWER on IntegriCloud