mirror of
https://git.savannah.gnu.org/git/tar.git
synced 2026-09-20 07:04:14 +00:00
Improve one-top-level functionality
Make sure the changes become visible with --show-transformed-names. * src/common.h (strip_compression_suffix): New function. (one_top_level): Rename to one_top_level_dir. All uses changed. * src/extract.c (extr_init): Use strip_compression_suffix. Bail out if unable to determine top-level directory. (maybe_prepend_name): Remove. All uses removed. * src/tar.c (options): --one-top-level takes optional argument. (parse_opt): Handle it. * src/list.c (enforce_one_top_level): New function. (transform_stat_info): Call enforce_one_top_level if required. * src/suffix.c (compression_suffixes): List "tar" (no compression); terminate with NULL entry. (find_compression_suffix): New static. (strip_compression_suffix): New function. * doc/tar.1: Update. * doc/tar.texi: Update. * tests/onetop01.at: New testcase. * tests/onetop02.at: New testcase. * tests/onetop03.at: New testcase. * tests/Makefile.am: Add new testcases. * tests/testsuite.at: Likewise.
This commit is contained in:
+2
-1
@@ -237,7 +237,7 @@ GLOBAL bool one_file_system_option;
|
||||
|
||||
/* Create a top-level directory for extracting based on the archive name. */
|
||||
GLOBAL bool one_top_level_option;
|
||||
GLOBAL char *one_top_level;
|
||||
GLOBAL char *one_top_level_dir;
|
||||
|
||||
/* Specified value to be put into tar file in place of stat () results, or
|
||||
just null and -1 if such an override should not take place. */
|
||||
@@ -860,6 +860,7 @@ bool transform_program_p (void);
|
||||
|
||||
/* Module suffix.c */
|
||||
void set_compression_program_by_suffix (const char *name, const char *defprog);
|
||||
char *strip_compression_suffix (const char *name);
|
||||
|
||||
/* Module checkpoint.c */
|
||||
void checkpoint_compile_action (const char *str);
|
||||
|
||||
+5
-51
@@ -194,31 +194,15 @@ extr_init (void)
|
||||
|
||||
/* If the user wants to guarantee that everything is under one directory,
|
||||
determine its name now and let it be created later. */
|
||||
if (one_top_level_option)
|
||||
if (one_top_level_option && !one_top_level_dir)
|
||||
{
|
||||
int i;
|
||||
char *base = base_name (archive_name_array[0]);
|
||||
|
||||
for (i = strlen (base) - 1; i > 2; i--)
|
||||
if (!strncmp (base + i - 3, ".tar", 4) ||
|
||||
!strncmp (base + i - 3, ".taz", 4) ||
|
||||
!strncmp (base + i - 3, ".tbz", 4) ||
|
||||
!strncmp (base + i - 3, ".tb2", 4) ||
|
||||
!strncmp (base + i - 3, ".tgz", 4) ||
|
||||
!strncmp (base + i - 3, ".tlz", 4) ||
|
||||
!strncmp (base + i - 3, ".txz", 4)) break;
|
||||
|
||||
if (i <= 3)
|
||||
{
|
||||
one_top_level_option = false;
|
||||
free (base);
|
||||
return;
|
||||
}
|
||||
|
||||
one_top_level = xmalloc (i - 2);
|
||||
strncpy (one_top_level, base, i - 3);
|
||||
one_top_level[i - 3] = '\0';
|
||||
one_top_level_dir = strip_compression_suffix (base);
|
||||
free (base);
|
||||
|
||||
if (!one_top_level_dir)
|
||||
USAGE_ERROR ((0, 0, _("Cannot deduce top-level directory name; please set it explicitly with --one-top-level=DIR")));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1607,33 +1591,6 @@ prepare_to_extract (char const *file_name, int typeflag, tar_extractor_t *fun)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
maybe_prepend_name (char **file_name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < strlen (*file_name); i++)
|
||||
if (!ISSLASH ((*file_name)[i]) && (*file_name)[i] != '.') break;
|
||||
|
||||
if (i == strlen (*file_name))
|
||||
return;
|
||||
|
||||
if (!strncmp (*file_name + i, one_top_level, strlen (one_top_level)))
|
||||
{
|
||||
int pos = i + strlen (one_top_level);
|
||||
if (ISSLASH ((*file_name)[pos]) || (*file_name)[pos] == '\0') return;
|
||||
}
|
||||
|
||||
char *new_name = xmalloc (strlen (one_top_level) + strlen (*file_name) + 2);
|
||||
|
||||
strcpy (new_name, one_top_level);
|
||||
strcat (new_name, "/");
|
||||
strcat (new_name, *file_name);
|
||||
|
||||
free (*file_name);
|
||||
*file_name = new_name;
|
||||
}
|
||||
|
||||
/* Extract a file from the archive. */
|
||||
void
|
||||
extract_archive (void)
|
||||
@@ -1684,9 +1641,6 @@ extract_archive (void)
|
||||
typeflag = sparse_member_p (¤t_stat_info) ?
|
||||
GNUTYPE_SPARSE : current_header->header.typeflag;
|
||||
|
||||
if (one_top_level_option)
|
||||
maybe_prepend_name (¤t_stat_info.file_name);
|
||||
|
||||
if (prepare_to_extract (current_stat_info.file_name, typeflag, &fun))
|
||||
{
|
||||
if (fun && (*fun) (current_stat_info.file_name, typeflag)
|
||||
|
||||
+28
@@ -115,6 +115,30 @@ transform_member_name (char **pinput, int type)
|
||||
return transform_name_fp (pinput, type, decode_xform, &type);
|
||||
}
|
||||
|
||||
static void
|
||||
enforce_one_top_level (char **pfile_name)
|
||||
{
|
||||
char *file_name = *pfile_name;
|
||||
char *p;
|
||||
|
||||
for (p = file_name; *p && (ISSLASH (*p) || *p == '.'); p++)
|
||||
;
|
||||
|
||||
if (!*p)
|
||||
return;
|
||||
|
||||
if (strncmp (p, one_top_level_dir, strlen (one_top_level_dir)) == 0)
|
||||
{
|
||||
int pos = strlen (one_top_level_dir);
|
||||
if (ISSLASH (p[pos]) || p[pos] == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
*pfile_name = new_name (one_top_level_dir, file_name);
|
||||
normalize_filename_x (*pfile_name);
|
||||
free (file_name);
|
||||
}
|
||||
|
||||
void
|
||||
transform_stat_info (int typeflag, struct tar_stat_info *stat_info)
|
||||
{
|
||||
@@ -132,6 +156,9 @@ transform_stat_info (int typeflag, struct tar_stat_info *stat_info)
|
||||
case LNKTYPE:
|
||||
transform_member_name (&stat_info->link_name, XFORM_LINK);
|
||||
}
|
||||
|
||||
if (one_top_level_option)
|
||||
enforce_one_top_level (¤t_stat_info.file_name);
|
||||
}
|
||||
|
||||
/* Main loop for reading an archive. */
|
||||
@@ -194,6 +221,7 @@ read_and (void (*do_something) (void))
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
transform_stat_info (current_header->header.typeflag,
|
||||
¤t_stat_info);
|
||||
(*do_something) ();
|
||||
|
||||
+42
-11
@@ -29,6 +29,7 @@ struct compression_suffix
|
||||
static struct compression_suffix compression_suffixes[] = {
|
||||
#define __CAT2__(a,b) a ## b
|
||||
#define S(s,p) #s, sizeof (#s) - 1, __CAT2__(p,_PROGRAM)
|
||||
{ "tar", 3, NULL },
|
||||
{ S(gz, GZIP) },
|
||||
{ S(tgz, GZIP) },
|
||||
{ S(taz, GZIP) },
|
||||
@@ -44,33 +45,43 @@ static struct compression_suffix compression_suffixes[] = {
|
||||
{ S(lzo, LZOP) },
|
||||
{ S(xz, XZ) },
|
||||
{ S(txz, XZ) }, /* Slackware */
|
||||
{ NULL }
|
||||
#undef S
|
||||
#undef __CAT2__
|
||||
};
|
||||
|
||||
static int nsuffixes = sizeof (compression_suffixes) /
|
||||
sizeof (compression_suffixes[0]);
|
||||
|
||||
static const char *
|
||||
find_compression_program (const char *name, const char *defprog)
|
||||
static struct compression_suffix const *
|
||||
find_compression_suffix (const char *name, size_t *base_len)
|
||||
{
|
||||
char *suf = strrchr (name, '.');
|
||||
|
||||
if (suf)
|
||||
{
|
||||
int i;
|
||||
size_t len;
|
||||
|
||||
struct compression_suffix *p;
|
||||
|
||||
suf++;
|
||||
len = strlen (suf);
|
||||
|
||||
for (i = 0; i < nsuffixes; i++)
|
||||
for (p = compression_suffixes; p->suffix; p++)
|
||||
{
|
||||
if (compression_suffixes[i].length == len
|
||||
&& memcmp (compression_suffixes[i].suffix, suf, len) == 0)
|
||||
return compression_suffixes[i].program;
|
||||
if (p->length == len && memcmp (p->suffix, suf, len) == 0)
|
||||
{
|
||||
if (*base_len)
|
||||
*base_len = strlen (name) - len - 1;
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
find_compression_program (const char *name, const char *defprog)
|
||||
{
|
||||
struct compression_suffix const *p = find_compression_suffix (name, NULL);
|
||||
if (p)
|
||||
return p->program;
|
||||
return defprog;
|
||||
}
|
||||
|
||||
@@ -81,3 +92,23 @@ set_compression_program_by_suffix (const char *name, const char *defprog)
|
||||
if (program)
|
||||
use_compress_program_option = program;
|
||||
}
|
||||
|
||||
char *
|
||||
strip_compression_suffix (const char *name)
|
||||
{
|
||||
char *s = NULL;
|
||||
size_t len;
|
||||
|
||||
if (find_compression_suffix (name, &len))
|
||||
{
|
||||
if (strncmp (name + len - 4, ".tar", 4) == 0)
|
||||
len -= 4;
|
||||
if (len == 0)
|
||||
return NULL;
|
||||
s = xmalloc (len + 1);
|
||||
memcpy (s, name, len);
|
||||
s[len] = 0;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
@@ -490,7 +490,7 @@ static struct argp_option options[] = {
|
||||
{"keep-directory-symlink", KEEP_DIRECTORY_SYMLINK_OPTION, 0, 0,
|
||||
N_("preserve existing symlinks to directories when extracting"),
|
||||
GRID+1 },
|
||||
{"one-top-level", ONE_TOP_LEVEL_OPTION, 0, 0,
|
||||
{"one-top-level", ONE_TOP_LEVEL_OPTION, N_("DIR"), OPTION_ARG_OPTIONAL,
|
||||
N_("create a subdirectory to avoid having loose files extracted"),
|
||||
GRID+1 },
|
||||
#undef GRID
|
||||
@@ -1447,6 +1447,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
|
||||
case ONE_TOP_LEVEL_OPTION:
|
||||
one_top_level_option = true;
|
||||
one_top_level_dir = arg;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
|
||||
Reference in New Issue
Block a user