static int read_error_count;
/* Have we hit EOF yet? */
-static int hit_eof;
+static bool hit_eof;
/* Checkpointing counter */
static int checkpoint;
+static bool read_full_records = false;
+static bool reading_from_pipe = false;
+
/* We're reading, but we just read the last block and it's time to update.
Declared in update.c
set_start_time ();
}
+\f
+/* Compression detection */
+
+enum compress_type {
+ ct_none,
+ ct_compress,
+ ct_gzip,
+ ct_bzip2
+};
+
+struct zip_magic
+{
+ enum compress_type type;
+ unsigned char *magic;
+ size_t length;
+ char *program;
+ char *option;
+};
+
+static struct zip_magic magic[] = {
+ { ct_none, },
+ { ct_compress, "\037\235", 2, "compress", "-Z" },
+ { ct_gzip, "\037\213", 2, "gzip", "-z" },
+ { ct_bzip2, "BZh", 3, "bzip2", "-j" },
+};
+
+#define NMAGIC (sizeof(magic)/sizeof(magic[0]))
+
+#define compress_option(t) magic[t].option
+#define compress_program(t) magic[t].program
+
+/* Check if the file ARCHIVE is a compressed archive. */
+enum compress_type
+check_compressed_archive ()
+{
+ struct zip_magic *p;
+ bool sfr, srp;
+
+ /* Prepare global data needed for find_next_block: */
+ record_end = record_start; /* set up for 1st record = # 0 */
+ sfr = read_full_records;
+ read_full_records = true; /* Suppress fatal error on reading a partial
+ record */
+ srp = reading_from_pipe;
+ reading_from_pipe = true; /* Suppress warning message on reading a partial
+ record */
+ find_next_block ();
+
+ /* Restore global values */
+ read_full_records = sfr;
+ reading_from_pipe = srp;
+
+ if (tar_checksum (record_start, true) == HEADER_SUCCESS)
+ /* Probably a valid header */
+ return ct_none;
+
+ for (p = magic + 1; p < magic + NMAGIC; p++)
+ if (memcmp (record_start->buffer, p->magic, p->length) == 0)
+ return p->type;
+
+ return ct_none;
+}
+
+/* Open an archive named archive_name_array[0]. Detect if it is
+ a compressed archive of known type and use corresponding decompression
+ program if so */
+int
+open_compressed_archive ()
+{
+ archive = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
+ MODE_RW, rsh_command_option);
+ if (archive == -1)
+ return archive;
+
+ if (!multi_volume_option)
+ {
+ enum compress_type type = check_compressed_archive ();
+
+ if (type == ct_none)
+ return archive;
+
+ /* FD is not needed any more */
+ rmtclose (archive);
+
+ hit_eof = false; /* It might have been set by find_next_block in
+ check_compressed_archive */
+
+ /* Open compressed archive */
+ use_compress_program_option = compress_program (type);
+ child_pid = sys_child_open_for_uncompress ();
+ read_full_records = reading_from_pipe = true;
+ }
+
+ records_read = 0;
+ record_end = record_start; /* set up for 1st record = # 0 */
+
+ return archive;
+}
\f
void
{
if (hit_eof)
{
- hit_eof = 0;
+ hit_eof = false;
current_block = record_start;
record_end = record_start + blocking_factor;
access_mode = ACCESS_WRITE;
flush_archive ();
if (current_block == record_end)
{
- hit_eof = 1;
+ hit_eof = true;
return 0;
}
}
/* When updating the archive, we start with reading. */
access_mode = wanted_access == ACCESS_UPDATE ? ACCESS_READ : wanted_access;
+ read_full_records = read_full_records_option;
+ reading_from_pipe = false;
+
+ records_read = 0;
+
if (use_compress_program_option)
{
switch (wanted_access)
{
case ACCESS_READ:
child_pid = sys_child_open_for_uncompress ();
+ read_full_records = reading_from_pipe = true;
+ record_end = record_start; /* set up for 1st record = # 0 */
break;
case ACCESS_WRITE:
}
else if (strcmp (archive_name_array[0], "-") == 0)
{
- read_full_records_option = true; /* could be a pipe, be safe */
+ read_full_records = true; /* could be a pipe, be safe */
if (verify_option)
FATAL_ERROR ((0, 0, _("Cannot verify stdin/stdout archive")));
switch (wanted_access)
{
case ACCESS_READ:
- archive = STDIN_FILENO;
+ {
+ enum compress_type type;
+
+ archive = STDIN_FILENO;
+
+ type = check_compressed_archive (archive);
+ if (type != ct_none)
+ FATAL_ERROR ((0, 0,
+ _("Archive is compressed. Use %s option"),
+ compress_option (type)));
+ }
break;
case ACCESS_WRITE:
switch (wanted_access)
{
case ACCESS_READ:
- archive = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
- MODE_RW, rsh_command_option);
+ archive = open_compressed_archive ();
break;
case ACCESS_WRITE:
{
case ACCESS_UPDATE:
records_written = 0;
- case ACCESS_READ:
- records_read = 0;
record_end = record_start; /* set up for 1st record = # 0 */
+
+ case ACCESS_READ:
find_next_block (); /* read it in, check for EOF */
if (volume_label_option)
ssize_t status;
if (checkpoint_option && !(++checkpoint % 10))
+ /* TRANSLATORS: This is a ``checkpoint of write operation'',
+ *not* ``Writing a checkpoint''.
+ E.g. in Spanish ``Punto de comprobaci@'on de escritura'',
+ *not* ``Escribiendo un punto de comprobaci@'on'' */
WARN ((0, 0, _("Write checkpoint %d"), checkpoint));
if (tape_length_option && tape_length_option <= bytes_written)
strncpy (record_start->header.name, real_s_name, NAME_FIELD_SIZE);
record_start->header.typeflag = GNUTYPE_MULTIVOL;
+
OFF_TO_CHARS (real_s_sizeleft, record_start->header.size);
OFF_TO_CHARS (real_s_totsize - real_s_sizeleft,
record_start->oldgnu_header.offset);
+
tmp = verbose_option;
verbose_option = 0;
finish_header (¤t_stat_info, record_start, -1);
left = record_size - status;
while (left % BLOCKSIZE != 0
- || (left && status && read_full_records_option))
+ || (left && status && read_full_records))
{
if (status)
while ((status = rmtread (archive, more, left)) == SAFE_READ_ERROR)
if (status == 0)
{
- char buf[UINTMAX_STRSIZE_BOUND];
-
- WARN((0, 0, _("Read %s bytes from %s"),
- STRINGIFY_BIGINT (record_size - left, buf),
- *archive_name_cursor));
+ if (!reading_from_pipe)
+ {
+ char buf[UINTMAX_STRSIZE_BOUND];
+
+ WARN((0, 0,
+ ngettext ("Read %s byte from %s",
+ "Read %s bytes from %s",
+ record_size - left),
+ STRINGIFY_BIGINT (record_size - left, buf),
+ *archive_name_cursor));
+ }
break;
}
- if (! read_full_records_option)
+ if (! read_full_records)
{
unsigned long rest = record_size - left;
/* FIXME: for size=0, multi-volume support. On the first record, warn
about the problem. */
- if (!read_full_records_option && verbose_option > 1
+ if (!read_full_records && verbose_option > 1
&& record_start_block == 0 && status != 0)
{
unsigned long rsize = (record_size - left) / BLOCKSIZE;
size_t status; /* result from system call */
if (checkpoint_option && !(++checkpoint % 10))
+ /* TRANSLATORS: This is a ``checkpoint of read operation'',
+ *not* ``Reading a checkpoint''.
+ E.g. in Spanish ``Punto de comprobaci@'on de lectura'',
+ *not* ``Leyendo un punto de comprobaci@'on'' */
WARN ((0, 0, _("Read checkpoint %d"), checkpoint));
/* Clear the count of errors. This only applies to a single call to
}
/* The condition below used to include
- || (status > 0 && !read_full_records_option)
+ || (status > 0 && !read_full_records)
This is incorrect since even if new_volume() succeeds, the
subsequent call to rmtread will overwrite the chunk of data
already read in the buffer, so the processing will fail */
if (volno_file_option)
closeout_volume_number ();
if (system (info_script_option) != 0)
- FATAL_ERROR ((0, 0, _("`%s' command failed"), info_script_option));
+ FATAL_ERROR ((0, 0, _("%s command failed"),
+ quote (info_script_option)));
}
else
while (1)
if (strcmp (archive_name_cursor[0], "-") == 0)
{
- read_full_records_option = true;
+ read_full_records = true;
archive = STDIN_FILENO;
}
else if (verify_option)