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 FD is a compressed archive. FD is guaranteed to
+ represent a local file */
+enum compress_type
+check_compressed_archive (int fd)
+{
+ struct zip_magic *p;
+ size_t status;
+ union block buf;
+
+ status = read (fd, &buf, sizeof buf);
+ if (status != sizeof buf)
+ {
+ archive_read_error ();
+ FATAL_ERROR ((0, 0, _("Quitting now.")));
+ }
+
+ lseek (fd, 0, SEEK_SET); /* This will fail if fd==0, but that does not
+ matter, since we do not handle compressed
+ stdin anyway */
+
+ if (tar_checksum (&buf) == HEADER_SUCCESS)
+ /* Probably a valid header */
+ return ct_none;
+
+ for (p = magic + 1; p < magic + NMAGIC; p++)
+ if (memcmp (buf.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 ()
+{
+ enum compress_type type;
+ int fd = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
+ MODE_RW, rsh_command_option);
+ if (fd == -1 || _isrmt (fd))
+ return fd;
+
+ type = check_compressed_archive (fd);
+
+ if (type == ct_none)
+ {
+ if (rmtlseek (fd, (off_t) 0, SEEK_CUR) != 0)
+ {
+ /* Archive may be not seekable. Reopen it. */
+ rmtclose (fd);
+ fd = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
+ MODE_RW, rsh_command_option);
+ }
+ return fd;
+ }
+
+ /* FD is not needed any more */
+ rmtclose (fd);
+
+ /* Open compressed archive */
+ use_compress_program_option = compress_program (type);
+ child_pid = sys_child_open_for_uncompress ();
+ read_full_records = reading_from_pipe = true;
+
+ 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;
+
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;
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:
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];
+ if (!reading_from_pipe)
+ {
+ char buf[UINTMAX_STRSIZE_BOUND];
- WARN((0, 0, _("Read %s bytes from %s"),
- STRINGIFY_BIGINT (record_size - left, buf),
- *archive_name_cursor));
+ WARN((0, 0, _("Read %s bytes from %s"),
+ 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;
}
/* 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 (strcmp (archive_name_cursor[0], "-") == 0)
{
- read_full_records_option = true;
+ read_full_records = true;
archive = STDIN_FILENO;
}
else if (verify_option)