|
@@ -67,11 +67,14 @@ static pid_t child_pid;
|
|
|
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
|
|
|
|
|
@@ -143,6 +146,104 @@ compute_duration ()
|
|
|
set_start_time ();
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+/* 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;
|
|
|
+}
|
|
|
|
|
|
|
|
|
void
|
|
@@ -178,7 +279,7 @@ reset_eof (void)
|
|
|
{
|
|
|
if (hit_eof)
|
|
|
{
|
|
|
- hit_eof = 0;
|
|
|
+ hit_eof = false;
|
|
|
current_block = record_start;
|
|
|
record_end = record_start + blocking_factor;
|
|
|
access_mode = ACCESS_WRITE;
|
|
@@ -198,7 +299,7 @@ find_next_block (void)
|
|
|
flush_archive ();
|
|
|
if (current_block == record_end)
|
|
|
{
|
|
|
- hit_eof = 1;
|
|
|
+ hit_eof = true;
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
@@ -304,12 +405,16 @@ open_archive (enum access_mode wanted_access)
|
|
|
/* 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:
|
|
@@ -327,14 +432,24 @@ open_archive (enum access_mode wanted_access)
|
|
|
}
|
|
|
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:
|
|
@@ -356,8 +471,7 @@ open_archive (enum access_mode wanted_access)
|
|
|
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:
|
|
@@ -544,9 +658,11 @@ flush_write (void)
|
|
|
|
|
|
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);
|
|
@@ -630,7 +746,7 @@ short_read (size_t status)
|
|
|
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)
|
|
@@ -638,15 +754,18 @@ short_read (size_t status)
|
|
|
|
|
|
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;
|
|
|
|
|
@@ -666,7 +785,7 @@ short_read (size_t status)
|
|
|
/* 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;
|
|
@@ -728,7 +847,7 @@ flush_read (void)
|
|
|
}
|
|
|
|
|
|
/* 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 */
|
|
@@ -1137,7 +1256,7 @@ new_volume (enum access_mode mode)
|
|
|
|
|
|
if (strcmp (archive_name_cursor[0], "-") == 0)
|
|
|
{
|
|
|
- read_full_records_option = true;
|
|
|
+ read_full_records = true;
|
|
|
archive = STDIN_FILENO;
|
|
|
}
|
|
|
else if (verify_option)
|