diff options
author | Patrick Ohly <patrick.ohly@intel.com> | 2016-10-24 12:54:48 +0200 |
---|---|---|
committer | Patrick Ohly <patrick.ohly@intel.com> | 2019-04-15 08:59:07 +0200 |
commit | 7c5e94c9ec3a70ddaeec6c554149eb13db9cfe60 (patch) | |
tree | 910a217dd29a26a1fc25ab45e5f80ae1a0c4f34e | |
parent | 19bd077987ff26a4cb108edde5eaf970837aa1f0 (diff) | |
download | libarchive-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.h | 2 | ||||
-rw-r--r-- | libarchive/archive_match.c | 31 | ||||
-rw-r--r-- | tar/bsdtar.1 | 3 | ||||
-rw-r--r-- | tar/bsdtar.c | 12 |
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; |