Run alternative decompression programs if the principal one is not available.
Some compression programs are able to handle various compression formats (e.g. `gzip' can decompress files created by `compress', `xz' is able to handle lzma, etc.) Tar tries to use such programs for decompression if the principal decompressor cannot be started. * src/buffer.c (compress_type): Swap ct_none and ct_tar. (archive_compression_type): New static variable. (zip_magic): Remove program and option fields. (zip_program): New structure and static. (compress_program): Remove macro. (find_zip_program): New static function. (first_decompress_program,next_decompress_program): New functions. (open_compressed_archive): Set archive_compression_type instead of use_compress_program_option. * src/common.h (first_decompress_program) (next_decompress_program): New functions. (WARN_DECOMPRESS_PROGRAM): New flag. (WARN_VERBOSE_WARNINGS): Include WARN_DECOMPRESS_PROGRAM. * src/warning.c (warning_args): Add "decompress-program". (warning_types): Add WARN_DECOMPRESS_PROGRAM. * src/system.c (run_decompress_program): New function. (sys_child_open_for_uncompress): Use run_decompress_program instead of calling execlp directly.
This commit is contained in:
35
doc/tar.texi
35
doc/tar.texi
@@ -4166,6 +4166,23 @@ Disable all warning messages.
|
||||
@cindex @samp{Ignoring unknown extended header keyword `%s'}, warning message
|
||||
@item unknown-keyword
|
||||
@samp{Ignoring unknown extended header keyword `%s'}
|
||||
@kwindex decompress-program
|
||||
@item decompress-program
|
||||
Controls verbose messages describing execution failures when trying
|
||||
alternative decompressor programs (@pxref{alternative decompression
|
||||
programs}). This warning is disabled by default (unless
|
||||
@option{--verbose} is used). A common example of what you can get
|
||||
when using this warning is:
|
||||
|
||||
@smallexample
|
||||
$ @kbd{tar --warning=decompress-program -x -f archive.Z}
|
||||
tar (child): cannot run compress: No such file or directory
|
||||
tar (child): trying gzip
|
||||
@end smallexample
|
||||
|
||||
This means that @command{tar} first tried to decompress
|
||||
@file{archive.Z} using @command{compress}, and, when that
|
||||
failed, switched to @command{gzip}.
|
||||
@end table
|
||||
|
||||
@subheading Keywords controlling incremental extraction:
|
||||
@@ -8755,6 +8772,24 @@ certain compression formats. If this approach fails, @command{tar}
|
||||
falls back to using archive name suffix to determine its format
|
||||
(@pxref{auto-compress}, for a list of recognized suffixes).
|
||||
|
||||
@anchor{alternative decompression programs}
|
||||
@cindex alternative decompression programs
|
||||
Some compression programs are able to handle different compression
|
||||
formats. @GNUTAR{} uses this, if the principal decompressor for the
|
||||
given format is not available. For example, if @command{compress} is
|
||||
not installed, @command{tar} will try to use @command{gzip}. As of
|
||||
version @value{VERSION} the following alternatives are
|
||||
tried@footnote{To verbosely trace the decompressor selection, use the
|
||||
@option{--warning=decompress-program} option
|
||||
(@pxref{warnings,decompress-program}).}:
|
||||
|
||||
@multitable @columnfractions 0.3 0.3 0.3
|
||||
@headitem Format @tab Main decompressor @tab Alternatives
|
||||
@item compress @tab compress @tab gzip
|
||||
@item lzma @tab lzma @tab xz
|
||||
@item bzip2 @tab bzip2 @tab lbzip2
|
||||
@end multitable
|
||||
|
||||
The only case when you have to specify a decompression option while
|
||||
reading the archive is when reading from a pipe or from a tape drive
|
||||
that does not support random access. However, in this case @GNUTAR{}
|
||||
|
||||
95
src/buffer.c
95
src/buffer.c
@@ -261,8 +261,8 @@ compute_duration ()
|
||||
/* Compression detection */
|
||||
|
||||
enum compress_type {
|
||||
ct_tar, /* Plain tar file */
|
||||
ct_none, /* Unknown compression type */
|
||||
ct_tar, /* Plain tar file */
|
||||
ct_compress,
|
||||
ct_gzip,
|
||||
ct_bzip2,
|
||||
@@ -272,31 +272,102 @@ enum compress_type {
|
||||
ct_xz
|
||||
};
|
||||
|
||||
static enum compress_type archive_compression_type = ct_none;
|
||||
|
||||
struct zip_magic
|
||||
{
|
||||
enum compress_type type;
|
||||
size_t length;
|
||||
char const *magic;
|
||||
};
|
||||
|
||||
struct zip_program
|
||||
{
|
||||
enum compress_type type;
|
||||
char const *program;
|
||||
char const *option;
|
||||
};
|
||||
|
||||
static struct zip_magic const magic[] = {
|
||||
{ ct_tar },
|
||||
{ ct_none, },
|
||||
{ ct_compress, 2, "\037\235", COMPRESS_PROGRAM, "-Z" },
|
||||
{ ct_gzip, 2, "\037\213", GZIP_PROGRAM, "-z" },
|
||||
{ ct_bzip2, 3, "BZh", BZIP2_PROGRAM, "-j" },
|
||||
{ ct_lzip, 4, "LZIP", LZIP_PROGRAM, "--lzip" },
|
||||
{ ct_lzma, 6, "\xFFLZMA", LZMA_PROGRAM, "--lzma" },
|
||||
{ ct_lzop, 4, "\211LZO", LZOP_PROGRAM, "--lzop" },
|
||||
{ ct_xz, 6, "\xFD" "7zXZ", XZ_PROGRAM, "-J" },
|
||||
{ ct_tar },
|
||||
{ ct_compress, 2, "\037\235" },
|
||||
{ ct_gzip, 2, "\037\213" },
|
||||
{ ct_bzip2, 3, "BZh" },
|
||||
{ ct_lzip, 4, "LZIP" },
|
||||
{ ct_lzma, 6, "\xFFLZMA" },
|
||||
{ ct_lzop, 4, "\211LZO" },
|
||||
{ ct_xz, 6, "\xFD" "7zXZ" },
|
||||
};
|
||||
|
||||
#define NMAGIC (sizeof(magic)/sizeof(magic[0]))
|
||||
|
||||
#define compress_option(t) magic[t].option
|
||||
#define compress_program(t) magic[t].program
|
||||
static struct zip_program zip_program[] = {
|
||||
{ ct_compress, COMPRESS_PROGRAM, "-Z" },
|
||||
{ ct_compress, GZIP_PROGRAM, "-z" },
|
||||
{ ct_gzip, GZIP_PROGRAM, "-z" },
|
||||
{ ct_bzip2, BZIP2_PROGRAM, "-j" },
|
||||
{ ct_bzip2, "lbzip2", "-j" },
|
||||
{ ct_lzip, LZIP_PROGRAM, "--lzip" },
|
||||
{ ct_lzma, LZMA_PROGRAM, "--lzma" },
|
||||
{ ct_lzma, XZ_PROGRAM, "-J" },
|
||||
{ ct_lzop, LZOP_PROGRAM, "--lzop" },
|
||||
{ ct_xz, XZ_PROGRAM, "-J" },
|
||||
{ ct_none }
|
||||
};
|
||||
|
||||
static struct zip_program const *
|
||||
find_zip_program (enum compress_type type, int *pstate)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = *pstate; zip_program[i].type != ct_none; i++)
|
||||
{
|
||||
if (zip_program[i].type == type)
|
||||
{
|
||||
*pstate = i + 1;
|
||||
return zip_program + i;
|
||||
}
|
||||
}
|
||||
*pstate = i;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *
|
||||
first_decompress_program (int *pstate)
|
||||
{
|
||||
struct zip_program const *zp;
|
||||
|
||||
if (use_compress_program_option)
|
||||
return use_compress_program_option;
|
||||
|
||||
if (archive_compression_type == ct_none)
|
||||
return NULL;
|
||||
|
||||
*pstate = 0;
|
||||
zp = find_zip_program (archive_compression_type, pstate);
|
||||
return zp ? zp->program : NULL;
|
||||
}
|
||||
|
||||
const char *
|
||||
next_decompress_program (int *pstate)
|
||||
{
|
||||
struct zip_program const *zp;
|
||||
|
||||
if (use_compress_program_option)
|
||||
return NULL;
|
||||
zp = find_zip_program (archive_compression_type, pstate);
|
||||
return zp ? zp->program : NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
compress_option (enum compress_type type)
|
||||
{
|
||||
struct zip_program const *zp;
|
||||
int i = 0;
|
||||
zp = find_zip_program (type, &i);
|
||||
return zp ? zp->option : NULL;
|
||||
}
|
||||
|
||||
/* Check if the file ARCHIVE is a compressed archive. */
|
||||
static enum compress_type
|
||||
@@ -395,7 +466,7 @@ open_compressed_archive (void)
|
||||
break;
|
||||
|
||||
default:
|
||||
use_compress_program_option = compress_program (type);
|
||||
archive_compression_type = type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -440,6 +440,9 @@ void mv_size_left (off_t size);
|
||||
|
||||
void buffer_write_global_xheader (void);
|
||||
|
||||
const char *first_decompress_program (int *pstate);
|
||||
const char *next_decompress_program (int *pstate);
|
||||
|
||||
/* Module create.c. */
|
||||
|
||||
enum dump_status
|
||||
@@ -805,10 +808,12 @@ void checkpoint_run (bool do_write);
|
||||
#define WARN_UNKNOWN_CAST 0x00010000
|
||||
#define WARN_UNKNOWN_KEYWORD 0x00020000
|
||||
#define WARN_XDEV 0x00040000
|
||||
#define WARN_DECOMPRESS_PROGRAM 0x00080000
|
||||
|
||||
/* The warnings composing WARN_VERBOSE_WARNINGS are enabled by default
|
||||
in verbose mode */
|
||||
#define WARN_VERBOSE_WARNINGS (WARN_RENAME_DIRECTORY|WARN_NEW_DIRECTORY)
|
||||
#define WARN_VERBOSE_WARNINGS (WARN_RENAME_DIRECTORY|WARN_NEW_DIRECTORY|\
|
||||
WARN_DECOMPRESS_PROGRAM)
|
||||
#define WARN_ALL (~WARN_VERBOSE_WARNINGS)
|
||||
|
||||
void set_warning_option (const char *arg);
|
||||
|
||||
31
src/system.c
31
src/system.c
@@ -455,6 +455,29 @@ sys_child_open_for_compress (void)
|
||||
wait_for_grandchild (grandchild_pid);
|
||||
}
|
||||
|
||||
static void
|
||||
run_decompress_program (void)
|
||||
{
|
||||
int i;
|
||||
const char *p, *prog = NULL;
|
||||
|
||||
for (p = first_decompress_program (&i); p; p = next_decompress_program (&i))
|
||||
{
|
||||
if (prog)
|
||||
{
|
||||
WARNOPT (WARN_DECOMPRESS_PROGRAM,
|
||||
(0, errno, _("cannot run %s"), prog));
|
||||
WARNOPT (WARN_DECOMPRESS_PROGRAM,
|
||||
(0, 0, _("trying %s"), p));
|
||||
}
|
||||
prog = p;
|
||||
execlp (p, p, "-d", NULL);
|
||||
}
|
||||
if (!prog)
|
||||
FATAL_ERROR ((0, 0, _("unable to run decompression program")));
|
||||
exec_fatal (prog);
|
||||
}
|
||||
|
||||
/* Set ARCHIVE for uncompressing, then reading an archive. */
|
||||
pid_t
|
||||
sys_child_open_for_uncompress (void)
|
||||
@@ -501,9 +524,7 @@ sys_child_open_for_uncompress (void)
|
||||
open_fatal (archive_name_array[0]);
|
||||
xdup2 (archive, STDIN_FILENO);
|
||||
priv_set_restore_linkdir ();
|
||||
execlp (use_compress_program_option, use_compress_program_option,
|
||||
"-d", (char *) 0);
|
||||
exec_fatal (use_compress_program_option);
|
||||
run_decompress_program ();
|
||||
}
|
||||
|
||||
/* We do need a grandchild tar. */
|
||||
@@ -520,9 +541,7 @@ sys_child_open_for_uncompress (void)
|
||||
xdup2 (child_pipe[PREAD], STDIN_FILENO);
|
||||
xclose (child_pipe[PWRITE]);
|
||||
priv_set_restore_linkdir ();
|
||||
execlp (use_compress_program_option, use_compress_program_option,
|
||||
"-d", (char *) 0);
|
||||
exec_fatal (use_compress_program_option);
|
||||
run_decompress_program ();
|
||||
}
|
||||
|
||||
/* The child tar is still here! */
|
||||
|
||||
@@ -41,6 +41,7 @@ static char const *const warning_args[] = {
|
||||
"unknown-cast",
|
||||
"unknown-keyword",
|
||||
"xdev",
|
||||
"decompress-program",
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -64,7 +65,8 @@ static int warning_types[] = {
|
||||
WARN_TIMESTAMP,
|
||||
WARN_UNKNOWN_CAST,
|
||||
WARN_UNKNOWN_KEYWORD,
|
||||
WARN_XDEV
|
||||
WARN_XDEV,
|
||||
WARN_DECOMPRESS_PROGRAM
|
||||
};
|
||||
|
||||
ARGMATCH_VERIFY (warning_args, warning_types);
|
||||
|
||||
Reference in New Issue
Block a user