]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
non-recursive extract and list
authorPatrick Ohly <patrick.ohly@intel.com>
Mon, 24 Oct 2016 10:54:48 +0000 (12:54 +0200)
committerPatrick Ohly <patrick.ohly@intel.com>
Mon, 15 Apr 2019 06:59:07 +0000 (08:59 +0200)
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.

libarchive/archive.h
libarchive/archive_match.c
tar/bsdtar.1
tar/bsdtar.c

index 438ce4680a9e10ec604a4dadbc93b80df119b3d6..3633a5807c79490a156c90c26bf796afa6f305f8 100644 (file)
@@ -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 *,
index 027d9715d4941da28479d0cdad4eab0fb7d1f8c4..04747b1f6663fecb9e2158fe767989a7e5fc7482 100644 (file)
@@ -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);
@@ -470,6 +474,28 @@ archive_match_path_excluded(struct archive *_a,
 #endif
 }
 
+/*
+ * 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.
  */
@@ -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) {
index 4c0fe818f26215b78e50a216a3469a65b43c2ac9..82840547007a4eb90844df36703d6648988b260a 100644 (file)
@@ -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.
index 280a0a1607c55a793dcdc5490fd12a739888f806..b59963d0f822bcfbae34cc6a9af268994555f621 100644 (file)
@@ -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;