summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2018-12-21 13:24:29 +0200
committerSergey Poznyakoff <gray@gnu.org>2018-12-21 13:54:11 +0200
commit983a82a3767da04cb3ca15eefe2e4b21154c335f (patch)
treee105be1624b3a58bcfd2e6e3f575caf507d3f92a
parent916fe62ae9b91a5d71cfa752f7cad89a558d7672 (diff)
downloadtar-983a82a3767da04cb3ca15eefe2e4b21154c335f.tar.gz
Fix semantics of -K used together with explicit member names.
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.
-rw-r--r--NEWS12
-rw-r--r--src/common.h5
-rw-r--r--src/names.c45
-rw-r--r--src/tar.c3
4 files changed, 55 insertions, 10 deletions
diff --git a/NEWS b/NEWS
index ee607ed2..93f31975 100644
--- 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>
@@ -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.
+
version 1.30 - Sergey Poznyakoff, 2017-12-17
diff --git a/src/common.h b/src/common.h
index 28779751..32e6f8bd 100644
--- a/src/common.h
+++ b/src/common.h
@@ -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);
diff --git a/src/names.c b/src/names.c
index f4dc978c..d3728d84 100644
--- a/src/names.c
+++ b/src/names.c
@@ -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);
}
diff --git a/src/tar.c b/src/tar.c
index 19938875..9919e87e 100644
--- 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: