+\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 ()
+{
+ struct zip_magic *p;
+ size_t status;
+ 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) == 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)
+ {
+ hit_eof = false; /* It might have been set by find_next_block */
+ 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;
+
+ archive = fd;
+ type = check_compressed_archive ();
+
+ if (type == ct_none)
+ 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;
+
+ records_read = 0;
+ record_end = record_start; /* set up for 1st record = # 0 */
+
+ return archive;
+}