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.
This commit is contained in:
Sergey Poznyakoff
2018-12-21 13:24:29 +02:00
parent 916fe62ae9
commit 983a82a376
4 changed files with 55 additions and 10 deletions

12
NEWS
View File

@@ -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

View 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);

View 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);
}

View File

@@ -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: