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:
12
NEWS
12
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>
|
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
|
When '-a' option is in effect, zstd compression is selected if the
|
||||||
destination archive name ends in '.zst' or '.tzst'.
|
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
|
version 1.30 - Sergey Poznyakoff, 2017-12-17
|
||||||
|
|
||||||
|
|||||||
@@ -302,6 +302,10 @@ enum hole_detection_method
|
|||||||
|
|
||||||
GLOBAL enum hole_detection_method hole_detection;
|
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;
|
GLOBAL bool starting_file_option;
|
||||||
|
|
||||||
/* Specified maximum byte length of each tape volume (multiple of 1024). */
|
/* 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);
|
void name_gather (void);
|
||||||
struct name *addname (char const *string, int change_dir,
|
struct name *addname (char const *string, int change_dir,
|
||||||
bool cmdline, struct name *parent);
|
bool cmdline, struct name *parent);
|
||||||
|
void add_starting_file (char const *file_name);
|
||||||
void remname (struct name *name);
|
void remname (struct name *name);
|
||||||
bool name_match (const char *name);
|
bool name_match (const char *name);
|
||||||
void names_notfound (void);
|
void names_notfound (void);
|
||||||
|
|||||||
45
src/names.c
45
src/names.c
@@ -1227,6 +1227,34 @@ addname (char const *string, int change_dir, bool cmdline, struct name *parent)
|
|||||||
return name;
|
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
|
/* Find a match for FILE_NAME (whose string length is LENGTH) in the name
|
||||||
list. */
|
list. */
|
||||||
static struct name *
|
static struct name *
|
||||||
@@ -1283,19 +1311,22 @@ name_match (const char *file_name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cursor = namelist_match (file_name, length);
|
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 (cursor)
|
||||||
{
|
{
|
||||||
if (!(ISSLASH (file_name[cursor->length]) && recursion_option)
|
if (!(ISSLASH (file_name[cursor->length]) && recursion_option)
|
||||||
|| cursor->found_count == 0)
|
|| cursor->found_count == 0)
|
||||||
cursor->found_count++; /* remember it matched */
|
cursor->found_count++; /* remember it matched */
|
||||||
if (starting_file_option)
|
|
||||||
{
|
|
||||||
free (namelist);
|
|
||||||
namelist = NULL;
|
|
||||||
nametail = NULL;
|
|
||||||
}
|
|
||||||
chdir_do (cursor->change_dir);
|
chdir_do (cursor->change_dir);
|
||||||
|
|
||||||
/* We got a match. */
|
/* We got a match. */
|
||||||
return ISFOUND (cursor);
|
return ISFOUND (cursor);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1443,8 +1443,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
|||||||
|
|
||||||
case 'K':
|
case 'K':
|
||||||
optloc_save (OC_STARTING_FILE, args->loc);
|
optloc_save (OC_STARTING_FILE, args->loc);
|
||||||
starting_file_option = true;
|
add_starting_file (arg);
|
||||||
addname (arg, 0, true, NULL);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ONE_FILE_SYSTEM_OPTION:
|
case ONE_FILE_SYSTEM_OPTION:
|
||||||
|
|||||||
Reference in New Issue
Block a user