From 983a82a3767da04cb3ca15eefe2e4b21154c335f Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Fri, 21 Dec 2018 13:24:29 +0200 Subject: [PATCH 36/58] 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. --- NEWS | 12 +++++++++++- src/common.h | 5 +++++ src/names.c | 45 ++++++++++++++++++++++++++++++++++++++------- src/tar.c | 3 +-- 4 files changed, 55 insertions(+), 10 deletions(-) diff --git a/src/common.h b/src/common.h index 2877975..32e6f8b 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 f4dc978..d3728d8 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 1993887..9919e87 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: -- 2.19.1