summaryrefslogtreecommitdiffhomepage
path: root/archival/libunarchive/get_header_tar.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-02-19 11:26:28 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-02-19 11:26:28 +0000
commit431a7c9c53b69a7416091721da673bcff7c91a02 (patch)
tree03cbe0e15af01d82b05138f0db41d44179262a3f /archival/libunarchive/get_header_tar.c
parenta37e7134f76b7661b86bb9cc926f28f81b1e1109 (diff)
tar: optional autodetection of gz/bz2 compressed tarballs.
+130 bytes. Closes bug 992.
Diffstat (limited to 'archival/libunarchive/get_header_tar.c')
-rw-r--r--archival/libunarchive/get_header_tar.c52
1 files changed, 44 insertions, 8 deletions
diff --git a/archival/libunarchive/get_header_tar.c b/archival/libunarchive/get_header_tar.c
index 893cd5b79..54c8f7665 100644
--- a/archival/libunarchive/get_header_tar.c
+++ b/archival/libunarchive/get_header_tar.c
@@ -46,6 +46,9 @@ void BUG_tar_header_size(void);
char get_header_tar(archive_handle_t *archive_handle)
{
static smallint end;
+#if ENABLE_FEATURE_TAR_AUTODETECT
+ static smallint not_first;
+#endif
file_header_t *file_header = archive_handle->file_header;
struct {
@@ -115,7 +118,7 @@ char get_header_tar(archive_handle_t *archive_handle)
* Read until the end to empty the pipe from gz or bz2
*/
while (full_read(archive_handle->src_fd, &tar, 512) == 512)
- /* repeat */;
+ continue;
return EXIT_FAILURE;
}
end = 1;
@@ -123,16 +126,49 @@ char get_header_tar(archive_handle_t *archive_handle)
}
end = 0;
- /* Check header has valid magic, "ustar" is for the proper tar
- * 0's are for the old tar format
- */
- if (strncmp(tar.magic, "ustar", 5) != 0) {
-#if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
- if (memcmp(tar.magic, "\0\0\0\0", 5) != 0)
+ /* Check header has valid magic, "ustar" is for the proper tar,
+ * five NULs are for the old tar format */
+ if (strncmp(tar.magic, "ustar", 5) != 0
+ && (!ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
+ || memcmp(tar.magic, "\0\0\0\0", 5) != 0)
+ ) {
+#if ENABLE_FEATURE_TAR_AUTODETECT
+ char (*get_header_ptr)(archive_handle_t *);
+
+ /* tar gz/bz autodetect: check for gz/bz2 magic.
+ * If it is the very first block, and we see the magic,
+ * we can switch to get_header_tar_gz/bz2/lzma().
+ * Needs seekable fd. I wish recv(MSG_PEEK) would work
+ * on any fd... */
+ if (not_first)
+ goto err;
+#if ENABLE_FEATURE_TAR_GZIP
+ if (tar.name[0] == 0x1f && tar.name[1] == 0x8b) { /* gzip */
+ get_header_ptr = get_header_tar_gz;
+ } else
#endif
- bb_error_msg_and_die("invalid tar magic");
+#if ENABLE_FEATURE_TAR_BZIP2
+ if (tar.name[0] == 'B' && tar.name[1] == 'Z'
+ && tar.name[2] == 'h' && isdigit(tar.name[3])
+ ) { /* bzip2 */
+ get_header_ptr = get_header_tar_bz2;
+ } else
+#endif
+ goto err;
+ if (lseek(archive_handle->src_fd, -512, SEEK_CUR) != 0)
+ goto err;
+ while (get_header_ptr(archive_handle) == EXIT_SUCCESS)
+ continue;
+ return EXIT_FAILURE;
+ err:
+#endif /* FEATURE_TAR_AUTODETECT */
+ bb_error_msg_and_die("invalid tar magic");
}
+#if ENABLE_FEATURE_TAR_AUTODETECT
+ not_first = 1;
+#endif
+
/* Do checksum on headers.
* POSIX says that checksum is done on unsigned bytes, but
* Sun and HP-UX gets it wrong... more details in