Add --strip-components option, per bin/77666.

Thanks to: Sangwoo Shim
This commit is contained in:
kientzle 2005-03-13 04:12:30 +00:00
parent 83b23d92b1
commit 0eac7627b8
5 changed files with 72 additions and 2 deletions

View File

@ -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}

View File

@ -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

View File

@ -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;

View File

@ -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 */

View File

@ -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;