Add --strip-components option, per bin/77666.
Thanks to: Sangwoo Shim
This commit is contained in:
parent
83b23d92b1
commit
0eac7627b8
@ -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}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user