From: Sergey Poznyakoff Date: Fri, 21 Dec 2018 11:24:29 +0000 (+0200) Subject: Fix semantics of -K used together with explicit member names. X-Git-Tag: release_1_31~7 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=983a82a3767da04cb3ca15eefe2e4b21154c335f;p=thirdparty%2Ftar.git 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. --- 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 @@ -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: