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:
Sergey Poznyakoff
2014-01-28 12:35:39 +02:00
parent 2af87fa277
commit 1689ed4388
12 changed files with 232 additions and 73 deletions
+2 -1
View File
@@ -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
View File
@@ -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 (&current_stat_info) ?
GNUTYPE_SPARSE : current_header->header.typeflag;
if (one_top_level_option)
maybe_prepend_name (&current_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
View File
@@ -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 (&current_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,
&current_stat_info);
(*do_something) ();
+42 -11
View File
@@ -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;
}
+2 -1
View File
@@ -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':