]> git.ipfire.org Git - thirdparty/tar.git/commitdiff
Fix semantics of -K used together with explicit member names.
authorSergey Poznyakoff <gray@gnu.org>
Fri, 21 Dec 2018 11:24:29 +0000 (13:24 +0200)
committerSergey Poznyakoff <gray@gnu.org>
Fri, 21 Dec 2018 11:54:11 +0000 (13:54 +0200)
This also fixes the bug reported in
  http://lists.gnu.org/archive/html/bug-tar/2018-12/msg00012.html

* src/common.h (starting_file_option): Describe the variable.
* src/names.c (add_starting_file): New function.
(name_match): Ignore everything before the member indicated by the
--starting-file option
* src/tar.c: Use add_starting_file to handle the -K option.

NEWS
src/common.h
src/names.c
src/tar.c

diff --git a/NEWS b/NEWS
index ee607ed223318ea3cad30c997382ea41ec688415..93f3197588a3a41fee6fee45bbd80113079e6311 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-GNU tar NEWS - User visible changes. 2018-04-07
+GNU tar NEWS - User visible changes. 2018-12-21
 Please send GNU tar bug reports to <bug-tar@gnu.org>
 
 \f
@@ -15,6 +15,16 @@ recognized automatically.
 When '-a' option is in effect, zstd compression is selected if the
 destination archive name ends in '.zst' or '.tzst'.
 
+* The -K option interacts properly with member names given in the command line
+
+Names of members to extract can be specified along with the "-K NAME"
+option. In this case, tar will extract NAME and those of named members
+that appear in the archive after it, which is consistent with the
+semantics of the option.
+
+Previous versions of tar extracted NAME, those of named members that
+appeared before it, and everything after it.
+
 \f
 version 1.30 - Sergey Poznyakoff, 2017-12-17
 
index 28779751f4c88f8bfb707b9c65b722719e3b5e19..32e6f8bd5f9158cfa2e437cf4bb5cc231b454758 100644 (file)
@@ -302,6 +302,10 @@ enum hole_detection_method
 
 GLOBAL enum hole_detection_method hole_detection;
 
+/* The first entry in names.c:namelist specifies the member name to
+   start extracting from. Set by add_starting_file() upon seeing the
+   -K option.
+*/
 GLOBAL bool starting_file_option;
 
 /* Specified maximum byte length of each tape volume (multiple of 1024).  */
@@ -752,6 +756,7 @@ const char *name_next (int change_dirs);
 void name_gather (void);
 struct name *addname (char const *string, int change_dir,
                      bool cmdline, struct name *parent);
+void add_starting_file (char const *file_name);
 void remname (struct name *name);
 bool name_match (const char *name);
 void names_notfound (void);
index f4dc978ce4710bf2eb8e60464c38193815bb293b..d3728d84e0fb112671b78c0aa76b3e57ca624f1c 100644 (file)
@@ -1227,6 +1227,34 @@ addname (char const *string, int change_dir, bool cmdline, struct name *parent)
   return name;
 }
 
+void
+add_starting_file (char const *file_name)
+{
+  struct name *name = make_name (file_name);
+
+  if (starting_file_option)
+    {
+      struct name *head = namelist;
+      remname (head);
+      free_name (head);
+    }
+  
+  name->prev = NULL;
+  name->next = namelist;
+  namelist = name;
+  if (!nametail)
+    nametail = namelist;
+  
+  name->found_count = 0;
+  name->matching_flags = INCLUDE_OPTIONS;
+  name->change_dir = 0;
+  name->directory = NULL;
+  name->parent = NULL;
+  name->cmdline = true;
+
+  starting_file_option = true;
+}
+
 /* Find a match for FILE_NAME (whose string length is LENGTH) in the name
    list.  */
 static struct name *
@@ -1283,19 +1311,22 @@ name_match (const char *file_name)
        }
 
       cursor = namelist_match (file_name, length);
+      if (starting_file_option)
+       {
+         /* If starting_file_option is set, the head of the list is the name
+            of the member to start extraction from. Skip the match unless it
+            is head. */
+         if (cursor == namelist)
+           starting_file_option = false;
+         else
+           cursor = NULL;
+       }
       if (cursor)
        {
          if (!(ISSLASH (file_name[cursor->length]) && recursion_option)
              || cursor->found_count == 0)
            cursor->found_count++; /* remember it matched */
-         if (starting_file_option)
-           {
-             free (namelist);
-             namelist = NULL;
-             nametail = NULL;
-           }
          chdir_do (cursor->change_dir);
-
          /* We got a match.  */
          return ISFOUND (cursor);
        }
index 19938875bc78e44b0a15c8ec21bac36ed0c74927..9919e87ec517afdf45d0e0033bbddb5ffd885b50 100644 (file)
--- a/src/tar.c
+++ b/src/tar.c
@@ -1443,8 +1443,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
 
     case 'K':
       optloc_save (OC_STARTING_FILE, args->loc);
-      starting_file_option = true;
-      addname (arg, 0, true, NULL);
+      add_starting_file (arg);
       break;
 
     case ONE_FILE_SYSTEM_OPTION: