summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Ohly <patrick.ohly@intel.com>2016-10-24 12:54:48 +0200
committerPatrick Ohly <patrick.ohly@intel.com>2019-04-15 08:59:07 +0200
commit7c5e94c9ec3a70ddaeec6c554149eb13db9cfe60 (patch)
tree910a217dd29a26a1fc25ab45e5f80ae1a0c4f34e
parent19bd077987ff26a4cb108edde5eaf970837aa1f0 (diff)
downloadlibarchive-7c5e94c9ec3a70ddaeec6c554149eb13db9cfe60.tar.gz
non-recursive extract and list
Sometimes it makes sense to extract or list a directory contained in an archive without also doing the same for the content of the directory, i.e. allowing -n (= --no-recursion) in combination with the x and t modes. bsdtar uses the match functionality in libarchive to track include matches. A new libarchive API call archive_match_set_inclusion_recursion() gets introduced to influence the matching behavior, with the default behavior as before. Non-recursive matching can be achieved by anchoring the path match at both start and end. Asking for a directory which itself isn't in the archive when in non-recursive mode is an error and handled by the existing mechanism for tracking unused inclusion entries.
-rw-r--r--libarchive/archive.h2
-rw-r--r--libarchive/archive_match.c31
-rw-r--r--tar/bsdtar.13
-rw-r--r--tar/bsdtar.c12
4 files changed, 43 insertions, 5 deletions
diff --git a/libarchive/archive.h b/libarchive/archive.h
index 438ce468..3633a580 100644
--- a/libarchive/archive.h
+++ b/libarchive/archive.h
@@ -1095,6 +1095,8 @@ __LA_DECL int archive_match_excluded(struct archive *,
*/
__LA_DECL int archive_match_path_excluded(struct archive *,
struct archive_entry *);
+/* Control recursive inclusion of directory content when directory is included. Default on. */
+__LA_DECL int archive_match_set_inclusion_recursion(struct archive *, int);
/* Add exclusion pathname pattern. */
__LA_DECL int archive_match_exclude_pattern(struct archive *, const char *);
__LA_DECL int archive_match_exclude_pattern_w(struct archive *,
diff --git a/libarchive/archive_match.c b/libarchive/archive_match.c
index 027d9715..04747b1f 100644
--- a/libarchive/archive_match.c
+++ b/libarchive/archive_match.c
@@ -93,6 +93,9 @@ struct archive_match {
/* exclusion/inclusion set flag. */
int setflag;
+ /* Recursively include directory content? */
+ int recursive_include;
+
/*
* Matching filename patterns.
*/
@@ -223,6 +226,7 @@ archive_match_new(void)
return (NULL);
a->archive.magic = ARCHIVE_MATCH_MAGIC;
a->archive.state = ARCHIVE_STATE_NEW;
+ a->recursive_include = 1;
match_list_init(&(a->inclusions));
match_list_init(&(a->exclusions));
__archive_rb_tree_init(&(a->exclusion_tree), &rb_ops_mbs);
@@ -471,6 +475,28 @@ archive_match_path_excluded(struct archive *_a,
}
/*
+ * When recursive inclusion of directory content is enabled,
+ * an inclusion pattern that matches a directory will also
+ * include everything beneath that directory. Enabled by default.
+ *
+ * For compatibility with GNU tar, exclusion patterns always
+ * match if a subset of the full patch matches (i.e., they are
+ * are not rooted at the beginning of the path) and thus there
+ * is no corresponding non-recursive exclusion mode.
+ */
+int
+archive_match_set_inclusion_recursion(struct archive *_a, int enabled)
+{
+ struct archive_match *a;
+
+ archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_match_set_inclusion_recursion");
+ a = (struct archive_match *)_a;
+ a->recursive_include = enabled;
+ return (ARCHIVE_OK);
+}
+
+/*
* Utility functions to get statistic information for inclusion patterns.
*/
int
@@ -781,7 +807,10 @@ static int
match_path_inclusion(struct archive_match *a, struct match *m,
int mbs, const void *pn)
{
- int flag = PATHMATCH_NO_ANCHOR_END;
+ /* Recursive operation requires only a prefix match. */
+ int flag = a->recursive_include ?
+ PATHMATCH_NO_ANCHOR_END :
+ 0;
int r;
if (mbs) {
diff --git a/tar/bsdtar.1 b/tar/bsdtar.1
index 4c0fe818..82840547 100644
--- a/tar/bsdtar.1
+++ b/tar/bsdtar.1
@@ -398,8 +398,7 @@ and the default behavior in c, r, and u modes or if
.Nm
is run in x mode as root.
.It Fl n , Fl Fl norecurse , Fl Fl no-recursion
-(c, r, u modes only)
-Do not recursively archive the contents of directories.
+Do not operate recursively on the content of directories.
.It Fl Fl newer Ar date
(c, r, u modes only)
Only include files and directories newer than the specified date.
diff --git a/tar/bsdtar.c b/tar/bsdtar.c
index 280a0a16..b59963d0 100644
--- a/tar/bsdtar.c
+++ b/tar/bsdtar.c
@@ -839,8 +839,6 @@ main(int argc, char **argv)
break;
}
}
- if (bsdtar->flags & OPTFLAG_NO_SUBDIRS)
- only_mode(bsdtar, "-n", "cru");
if (bsdtar->flags & OPTFLAG_STDOUT)
only_mode(bsdtar, "-O", "xt");
if (bsdtar->flags & OPTFLAG_UNLINK_FIRST)
@@ -890,6 +888,16 @@ main(int argc, char **argv)
only_mode(bsdtar, buff, "cru");
}
+ /*
+ * When creating an archive from a directory tree, the directory
+ * walking code will already avoid entering directories when
+ * recursive inclusion of directory content is disabled, therefore
+ * changing the matching behavior has no effect for creation modes.
+ * It is relevant for extraction or listing.
+ */
+ archive_match_set_inclusion_recursion(bsdtar->matching,
+ !(bsdtar->flags & OPTFLAG_NO_SUBDIRS));
+
/* Filename "-" implies stdio. */
if (strcmp(bsdtar->filename, "-") == 0)
bsdtar->filename = NULL;