Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 1 | From 47f7566f6829c2b14e21bbbba699916de4998c72 Mon Sep 17 00:00:00 2001 |
| 2 | From: Patrick Ohly <patrick.ohly@intel.com> |
| 3 | Date: Mon, 24 Oct 2016 12:54:48 +0200 |
| 4 | Subject: [PATCH 1/1] non-recursive extract and list |
| 5 | |
| 6 | Sometimes it makes sense to extract or list a directory contained in |
| 7 | an archive without also doing the same for the content of the |
| 8 | directory, i.e. allowing -n (= --no-recursion) in combination with the |
| 9 | x and t modes. |
| 10 | |
| 11 | bsdtar uses the match functionality in libarchive to track include |
| 12 | matches. A new libarchive API call |
| 13 | archive_match_include_directories_recursively() gets introduced to |
| 14 | influence the matching behavior, with the default behavior as before. |
| 15 | |
| 16 | Non-recursive matching can be achieved by anchoring the path match at |
| 17 | both start and end. Asking for a directory which itself isn't in the |
| 18 | archive when in non-recursive mode is an error and handled by the |
| 19 | existing mechanism for tracking unused inclusion entries. |
| 20 | |
| 21 | Upstream-Status: Submitted [https://github.com/libarchive/libarchive/pull/812] |
| 22 | |
| 23 | Signed-off-by: Patrick Ohly <patrick.ohly@intel.com> |
| 24 | |
| 25 | --- |
| 26 | libarchive/archive.h | 2 ++ |
| 27 | libarchive/archive_match.c | 30 +++++++++++++++++++++++++++++- |
| 28 | tar/bsdtar.1 | 3 +-- |
| 29 | tar/bsdtar.c | 12 ++++++++++-- |
| 30 | 4 files changed, 42 insertions(+), 5 deletions(-) |
| 31 | |
| 32 | diff --git a/libarchive/archive.h b/libarchive/archive.h |
| 33 | index 32710201..59fb4aa6 100644 |
| 34 | --- a/libarchive/archive.h |
| 35 | +++ b/libarchive/archive.h |
| 36 | @@ -1093,6 +1093,8 @@ __LA_DECL int archive_match_excluded(struct archive *, |
| 37 | */ |
| 38 | __LA_DECL int archive_match_path_excluded(struct archive *, |
| 39 | struct archive_entry *); |
| 40 | +/* Control recursive inclusion of directory content when directory is included. Default on. */ |
| 41 | +__LA_DECL int archive_match_include_directories_recursively(struct archive *, int _enabled); |
| 42 | /* Add exclusion pathname pattern. */ |
| 43 | __LA_DECL int archive_match_exclude_pattern(struct archive *, const char *); |
| 44 | __LA_DECL int archive_match_exclude_pattern_w(struct archive *, |
| 45 | diff --git a/libarchive/archive_match.c b/libarchive/archive_match.c |
| 46 | index be72066e..bb6a3407 100644 |
| 47 | --- a/libarchive/archive_match.c |
| 48 | +++ b/libarchive/archive_match.c |
| 49 | @@ -93,6 +93,9 @@ struct archive_match { |
| 50 | /* exclusion/inclusion set flag. */ |
| 51 | int setflag; |
| 52 | |
| 53 | + /* Recursively include directory content? */ |
| 54 | + int recursive_include; |
| 55 | + |
| 56 | /* |
| 57 | * Matching filename patterns. |
| 58 | */ |
| 59 | @@ -223,6 +226,7 @@ archive_match_new(void) |
| 60 | return (NULL); |
| 61 | a->archive.magic = ARCHIVE_MATCH_MAGIC; |
| 62 | a->archive.state = ARCHIVE_STATE_NEW; |
| 63 | + a->recursive_include = 1; |
| 64 | match_list_init(&(a->inclusions)); |
| 65 | match_list_init(&(a->exclusions)); |
| 66 | __archive_rb_tree_init(&(a->exclusion_tree), &rb_ops_mbs); |
| 67 | @@ -471,6 +475,28 @@ archive_match_path_excluded(struct archive *_a, |
| 68 | } |
| 69 | |
| 70 | /* |
| 71 | + * When recursive inclusion of directory content is enabled, |
| 72 | + * an inclusion pattern that matches a directory will also |
| 73 | + * include everything beneath that directory. Enabled by default. |
| 74 | + * |
| 75 | + * For compatibility with GNU tar, exclusion patterns always |
| 76 | + * match if a subset of the full patch matches (i.e., they are |
| 77 | + * are not rooted at the beginning of the path) and thus there |
| 78 | + * is no corresponding non-recursive exclusion mode. |
| 79 | + */ |
| 80 | +int |
| 81 | +archive_match_include_directories_recursively(struct archive *_a, int _enabled) |
| 82 | +{ |
| 83 | + struct archive_match *a; |
| 84 | + |
| 85 | + archive_check_magic(_a, ARCHIVE_MATCH_MAGIC, |
| 86 | + ARCHIVE_STATE_NEW, "archive_match_include_directories_recursively"); |
| 87 | + a = (struct archive_match *)_a; |
| 88 | + a->recursive_include = _enabled; |
| 89 | + return (ARCHIVE_OK); |
| 90 | +} |
| 91 | + |
| 92 | +/* |
| 93 | * Utility functions to get statistic information for inclusion patterns. |
| 94 | */ |
| 95 | int |
| 96 | @@ -781,7 +807,9 @@ static int |
| 97 | match_path_inclusion(struct archive_match *a, struct match *m, |
| 98 | int mbs, const void *pn) |
| 99 | { |
| 100 | - int flag = PATHMATCH_NO_ANCHOR_END; |
| 101 | + int flag = a->recursive_include ? |
| 102 | + PATHMATCH_NO_ANCHOR_END : /* Prefix match is good enough. */ |
| 103 | + 0; /* Full match required. */ |
| 104 | int r; |
| 105 | |
| 106 | if (mbs) { |
| 107 | diff --git a/tar/bsdtar.1 b/tar/bsdtar.1 |
| 108 | index 132e1145..1dd2a847 100644 |
| 109 | --- a/tar/bsdtar.1 |
| 110 | +++ b/tar/bsdtar.1 |
| 111 | @@ -386,8 +386,7 @@ and the default behavior in c, r, and u modes or if |
| 112 | .Nm |
| 113 | is run in x mode as root. |
| 114 | .It Fl n , Fl Fl norecurse , Fl Fl no-recursion |
| 115 | -(c, r, u modes only) |
| 116 | -Do not recursively archive the contents of directories. |
| 117 | +Do not recursively archive (c, r, u), extract (x) or list (t) the contents of directories. |
| 118 | .It Fl Fl newer Ar date |
| 119 | (c, r, u modes only) |
| 120 | Only include files and directories newer than the specified date. |
| 121 | diff --git a/tar/bsdtar.c b/tar/bsdtar.c |
| 122 | index 11dedbf9..d014cc3e 100644 |
| 123 | --- a/tar/bsdtar.c |
| 124 | +++ b/tar/bsdtar.c |
| 125 | @@ -794,8 +794,6 @@ main(int argc, char **argv) |
| 126 | break; |
| 127 | } |
| 128 | } |
| 129 | - if (bsdtar->flags & OPTFLAG_NO_SUBDIRS) |
| 130 | - only_mode(bsdtar, "-n", "cru"); |
| 131 | if (bsdtar->flags & OPTFLAG_STDOUT) |
| 132 | only_mode(bsdtar, "-O", "xt"); |
| 133 | if (bsdtar->flags & OPTFLAG_UNLINK_FIRST) |
| 134 | @@ -845,6 +843,16 @@ main(int argc, char **argv) |
| 135 | only_mode(bsdtar, buff, "cru"); |
| 136 | } |
| 137 | |
| 138 | + /* |
| 139 | + * When creating an archive from a directory tree, the directory |
| 140 | + * walking code will already avoid entering directories when |
| 141 | + * recursive inclusion of directory content is disabled, therefore |
| 142 | + * changing the matching behavior has no effect for creation modes. |
| 143 | + * It is relevant for extraction or listing. |
| 144 | + */ |
| 145 | + archive_match_include_directories_recursively(bsdtar->matching, |
| 146 | + !(bsdtar->flags & OPTFLAG_NO_SUBDIRS)); |
| 147 | + |
| 148 | /* Filename "-" implies stdio. */ |
| 149 | if (strcmp(bsdtar->filename, "-") == 0) |
| 150 | bsdtar->filename = NULL; |
| 151 | -- |
| 152 | 2.11.0 |
| 153 | |