summaryrefslogtreecommitdiffstats
path: root/usr.bin
diff options
context:
space:
mode:
authorkientzle <kientzle@FreeBSD.org>2005-04-17 17:20:54 +0000
committerkientzle <kientzle@FreeBSD.org>2005-04-17 17:20:54 +0000
commitec0a4e2bdb95f66a113cf857064d8465ec7fa7d5 (patch)
treeabfe917117053c5691d90b971216fcf322b5513f /usr.bin
parent9d042448bad3d62c8bced30cb64b1a9867e9d1c3 (diff)
downloadFreeBSD-src-ec0a4e2bdb95f66a113cf857064d8465ec7fa7d5.zip
FreeBSD-src-ec0a4e2bdb95f66a113cf857064d8465ec7fa7d5.tar.gz
Support path-rewriting options (including --strip-components) for both
extraction and creation. While I'm here, fix a bug reported by Garrett Wollman: when stripping the leading '/' from the path "/", don't produce an entry with an empty name; produce "." instead.
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/tar/Makefile2
-rw-r--r--usr.bin/tar/bsdtar.c4
-rw-r--r--usr.bin/tar/bsdtar.h1
-rw-r--r--usr.bin/tar/read.c101
-rw-r--r--usr.bin/tar/util.c53
-rw-r--r--usr.bin/tar/write.c44
6 files changed, 115 insertions, 90 deletions
diff --git a/usr.bin/tar/Makefile b/usr.bin/tar/Makefile
index 320fe7d..1e5c25e 100644
--- a/usr.bin/tar/Makefile
+++ b/usr.bin/tar/Makefile
@@ -6,7 +6,7 @@
#
PROG= bsdtar
-VERSION= 1.01.022
+VERSION= 1.01.023
DIST_SRCS= bsdtar.c getdate.y matching.c read.c util.c write.c
SRCS= ${DIST_SRCS}
WARNS?= 5
diff --git a/usr.bin/tar/bsdtar.c b/usr.bin/tar/bsdtar.c
index f2ecf03..c2ea3c5 100644
--- a/usr.bin/tar/bsdtar.c
+++ b/usr.bin/tar/bsdtar.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2003-2004 Tim Kientzle
+ * Copyright (c) 2003-2005 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -690,7 +690,7 @@ version(void)
{
printf("bsdtar %s, ", PACKAGE_VERSION);
printf("%s\n", archive_version());
- printf("Copyright (C) 2003-2004 Tim Kientzle\n");
+ printf("Copyright (C) 2003-2005 Tim Kientzle\n");
exit(1);
}
diff --git a/usr.bin/tar/bsdtar.h b/usr.bin/tar/bsdtar.h
index 12e210d..5c37a71 100644
--- a/usr.bin/tar/bsdtar.h
+++ b/usr.bin/tar/bsdtar.h
@@ -106,6 +106,7 @@ void bsdtar_strmode(struct archive_entry *entry, char *bp);
void bsdtar_warnc(struct bsdtar *, int _code, const char *fmt, ...);
void cleanup_exclusions(struct bsdtar *);
void do_chdir(struct bsdtar *);
+int edit_pathname(struct bsdtar *, struct archive_entry *);
int exclude(struct bsdtar *, const char *pattern);
int exclude_from_file(struct bsdtar *, const char *pathname);
int excluded(struct bsdtar *, const char *pathname);
diff --git a/usr.bin/tar/read.c b/usr.bin/tar/read.c
index 1bb657e..dc95409 100644
--- a/usr.bin/tar/read.c
+++ b/usr.bin/tar/read.c
@@ -46,7 +46,6 @@ __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);
@@ -73,6 +72,7 @@ read_archive(struct bsdtar *bsdtar, char mode)
FILE *out;
struct archive *a;
struct archive_entry *entry;
+ const struct stat *st;
int r;
while (*bsdtar->argv) {
@@ -117,16 +117,37 @@ read_archive(struct bsdtar *bsdtar, char mode)
}
/*
- * 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.)
+ * Exclude entries that are too old.
+ */
+ st = archive_entry_stat(entry);
+ if (bsdtar->newer_ctime_sec > 0) {
+ if (st->st_ctime < bsdtar->newer_ctime_sec)
+ continue; /* Too old, skip it. */
+ if (st->st_ctime == bsdtar->newer_ctime_sec
+ && ARCHIVE_STAT_CTIME_NANOS(st)
+ <= bsdtar->newer_ctime_nsec)
+ continue; /* Too old, skip it. */
+ }
+ if (bsdtar->newer_mtime_sec > 0) {
+ if (st->st_mtime < bsdtar->newer_mtime_sec)
+ continue; /* Too old, skip it. */
+ if (st->st_mtime == bsdtar->newer_mtime_sec
+ && ARCHIVE_STAT_MTIME_NANOS(st)
+ <= bsdtar->newer_mtime_nsec)
+ continue; /* Too old, skip it. */
+ }
+
+ /*
+ * Note that pattern 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;
+ continue; /* Excluded by a pattern test. */
/*
* Modify the pathname as requested by the user. We
@@ -137,7 +158,7 @@ read_archive(struct bsdtar *bsdtar, char mode)
* failures prevent extraction.
*/
if (edit_pathname(bsdtar, entry))
- continue;
+ continue; /* Excluded by a rewrite failure. */
if (mode == 't') {
/* Perversely, gtar uses -O to mean "send to stderr"
@@ -169,11 +190,17 @@ read_archive(struct bsdtar *bsdtar, char mode)
}
fprintf(out, "\n");
} else {
- if (bsdtar->option_interactive &&
- !yes("extract '%s'", archive_entry_pathname(entry)))
+ /*
+ * Skip security problems before prompting.
+ * Otherwise, the user may be confused that a
+ * file they wanted to extract was
+ * subsequently skipped.
+ */
+ if (security_problem(bsdtar, entry))
continue;
- if (security_problem(bsdtar, entry))
+ if (bsdtar->option_interactive &&
+ !yes("extract '%s'", archive_entry_pathname(entry)))
continue;
/*
@@ -317,40 +344,6 @@ list_item_verbose(struct bsdtar *bsdtar, FILE *out, struct archive_entry *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 {
@@ -371,23 +364,11 @@ security_problem(struct bsdtar *bsdtar, struct archive_entry *entry)
char *p;
int r;
- /* -P option forces us to just accept all pathnames. */
+ /* -P option forces us to just accept all pathnames as-is. */
if (bsdtar->option_absolute_paths)
return (0);
- /* Strip leading '/'. */
name = archive_entry_pathname(entry);
- if (name[0] == '/') {
- /* Generate a warning the first time this happens. */
- if (!bsdtar->warned_lead_slash) {
- bsdtar_warnc(bsdtar, 0,
- "Removing leading '/' from member names");
- bsdtar->warned_lead_slash = 1;
- }
- while (name[0] == '/')
- name++;
- archive_entry_set_pathname(entry, name);
- }
/* Reject any archive entry with '..' as a path element. */
pn = name;
diff --git a/usr.bin/tar/util.c b/usr.bin/tar/util.c
index 5071fe9..7f1a944 100644
--- a/usr.bin/tar/util.c
+++ b/usr.bin/tar/util.c
@@ -380,3 +380,56 @@ do_chdir(struct bsdtar *bsdtar)
free(bsdtar->pending_chdir);
bsdtar->pending_chdir = NULL;
}
+
+/*
+ * Handle --strip-components and any future path-rewriting options.
+ * Returns non-zero if the pathname should not be extracted.
+ */
+int
+edit_pathname(struct bsdtar *bsdtar, struct archive_entry *entry)
+{
+ const char *name = archive_entry_pathname(entry);
+
+ /* Strip leading dir names as per --strip-components option. */
+ if (bsdtar->strip_components > 0) {
+ int r = bsdtar->strip_components;
+ const char *p = name;
+
+ while (r > 0) {
+ switch (*p++) {
+ case '/':
+ r--;
+ name = p;
+ break;
+ case '\0':
+ /* Path is too short, skip it. */
+ return (1);
+ }
+ }
+ }
+
+ /* Strip redundant "./" from start of filename. */
+ if (name[0] == '.' && name[1] == '/' && name[2] != '\0')
+ name += 2;
+
+ /* Strip leading '/' unless user has asked us not to. */
+ if (name[0] == '/' && !bsdtar->option_absolute_paths) {
+ /* Generate a warning the first time this happens. */
+ if (!bsdtar->warned_lead_slash) {
+ bsdtar_warnc(bsdtar, 0,
+ "Removing leading '/' from member names");
+ bsdtar->warned_lead_slash = 1;
+ }
+ name++;
+ if (*name == '\0') /* Strip '/' from "/" yields "." */
+ name = ".";
+ }
+
+ /* Safely replace name in archive_entry. */
+ if (name != archive_entry_pathname(entry)) {
+ char *q = strdup(name);
+ archive_entry_copy_pathname(entry, q);
+ free(q);
+ }
+ return (0);
+}
diff --git a/usr.bin/tar/write.c b/usr.bin/tar/write.c
index aace228..9d430aa 100644
--- a/usr.bin/tar/write.c
+++ b/usr.bin/tar/write.c
@@ -126,7 +126,7 @@ static void write_entry(struct bsdtar *, struct archive *,
unsigned pathlen, const char *accpath);
static int write_file_data(struct bsdtar *, struct archive *,
int fd);
-static void write_heirarchy(struct bsdtar *, struct archive *,
+static void write_hierarchy(struct bsdtar *, struct archive *,
const char *);
void
@@ -393,7 +393,7 @@ write_archive(struct archive *a, struct bsdtar *bsdtar)
if (append_archive(bsdtar, a, arg + 1) != 0)
break;
} else
- write_heirarchy(bsdtar, a, arg);
+ write_hierarchy(bsdtar, a, arg);
}
bsdtar->argv++;
}
@@ -434,7 +434,7 @@ archive_names_from_file_helper(struct bsdtar *bsdtar, const char *line)
else {
if (*line != '/')
do_chdir(bsdtar); /* Handle a deferred -C */
- write_heirarchy(bsdtar, bsdtar->archive, line);
+ write_hierarchy(bsdtar, bsdtar->archive, line);
}
return (0);
}
@@ -509,10 +509,10 @@ append_archive(struct bsdtar *bsdtar, struct archive *a, const char *filename)
}
/*
- * Add the file or dir heirarchy named by 'path' to the archive
+ * Add the file or dir hierarchy named by 'path' to the archive
*/
static void
-write_heirarchy(struct bsdtar *bsdtar, struct archive *a, const char *path)
+write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path)
{
FTS *fts;
FTSENT *ftsent;
@@ -701,7 +701,7 @@ write_heirarchy(struct bsdtar *bsdtar, struct archive *a, const char *path)
break;
default:
bsdtar_warnc(bsdtar, 0,
- "%s: Heirarchy traversal error %d\n",
+ "%s: Hierarchy traversal error %d\n",
ftsent->fts_path,
ftsent->fts_info);
break;
@@ -736,26 +736,15 @@ write_entry(struct bsdtar *bsdtar, struct archive *a, const struct stat *st,
fd = -1;
entry = archive_entry_new();
- /* Strip redundant "./" from start of filename. */
- if (pathname != NULL && pathname[0] == '.' && pathname[1] == '/') {
- pathname += 2;
- if (*pathname == '\0') /* This is the "./" directory. */
- goto cleanup; /* Don't archive it ever. */
- }
-
- /* Strip leading '/' unless user has asked us not to. */
- if (pathname && pathname[0] == '/' && !bsdtar->option_absolute_paths) {
- /* Generate a warning the first time this happens. */
- if (!bsdtar->warned_lead_slash) {
- bsdtar_warnc(bsdtar, 0,
- "Removing leading '/' from member names");
- bsdtar->warned_lead_slash = 1;
- }
- pathname++;
- }
-
archive_entry_set_pathname(entry, pathname);
+ /*
+ * Rewrite the pathname to be archived. If rewrite
+ * fails, skip the entry.
+ */
+ if (edit_pathname(bsdtar, entry))
+ goto abort;
+
if (!S_ISDIR(st->st_mode) && (st->st_nlink > 1))
lookup_hardlink(bsdtar, entry, st);
@@ -847,14 +836,15 @@ write_entry(struct bsdtar *bsdtar, struct archive *a, const struct stat *st,
write_file_data(bsdtar, a, fd);
cleanup:
+ if (bsdtar->verbose)
+ fprintf(stderr, "\n");
+
+abort:
if (fd >= 0)
close(fd);
if (entry != NULL)
archive_entry_free(entry);
-
- if (bsdtar->verbose)
- fprintf(stderr, "\n");
}
OpenPOWER on IntegriCloud