aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2012-03-06 16:27:48 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2012-03-06 16:27:48 +0100
commit8a6a2f9c9c214b94bd945acd97ac8b28c25e194e (patch)
tree08b9a2af482bb50a7e369c01f9e9083680543fd4
parent774bce8e8ba1e424c953e8f13aee8f0778c8a911 (diff)
downloadbusybox-w32-8a6a2f9c9c214b94bd945acd97ac8b28c25e194e.tar.gz
busybox-w32-8a6a2f9c9c214b94bd945acd97ac8b28c25e194e.tar.bz2
busybox-w32-8a6a2f9c9c214b94bd945acd97ac8b28c25e194e.zip
update seamless uncompression code
This change makes "tar tf hello_world.txz" work without adding special-casing for ".txz" extension. It also removes ever-growing magic checking code in rpm2cpio and get_header_tar - we reuse one which lives in setup_unzip_on_fd. function old new delta unpack_gz_stream 7 566 +559 check_signature16 - 70 +70 setup_unzip_on_fd 99 142 +43 handle_SIGCHLD - 41 +41 unpack_bz2_stream 342 376 +34 unzip_main 2352 2385 +33 bbunpack 503 533 +30 open_transformer 74 102 +28 unpack_Z_stream 1278 1304 +26 unpack_gunzip 101 123 +22 init_transformer_aux_data - 18 +18 unpack_xz_stream 2388 2402 +14 open_zipped 131 141 +10 rpm_main 1358 1363 +5 get_header_tar_lzma 52 57 +5 get_header_tar_bz2 52 57 +5 unpack_lzma_stream 2698 2702 +4 hash_find 234 233 -1 get_header_tar 1759 1733 -26 get_header_tar_gz 92 57 -35 unpack_uncompress 51 12 -39 rpm2cpio_main 201 147 -54 unpack_unxz 67 12 -55 unpack_bz2_stream_prime 55 - -55 get_header_tar_Z 86 - -86 unpack_gz_stream_with_info 539 - -539 ------------------------------------------------------------------------------ (add/remove: 3/3 grow/shrink: 14/6 up/down: 947/-890) Total: 57 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--archival/bbunzip.c78
-rw-r--r--archival/bzip2.c2
-rw-r--r--archival/gzip.c2
-rw-r--r--archival/libarchive/decompress_bunzip2.c18
-rw-r--r--archival/libarchive/decompress_gunzip.c27
-rw-r--r--archival/libarchive/decompress_uncompress.c5
-rw-r--r--archival/libarchive/decompress_unlzma.c2
-rw-r--r--archival/libarchive/decompress_unxz.c12
-rw-r--r--archival/libarchive/get_header_tar.c35
-rw-r--r--archival/libarchive/get_header_tar_bz2.c2
-rw-r--r--archival/libarchive/get_header_tar_gz.c17
-rw-r--r--archival/libarchive/get_header_tar_lzma.c2
-rw-r--r--archival/libarchive/open_transformer.c113
-rw-r--r--archival/lzop.c2
-rw-r--r--archival/rpm.c2
-rw-r--r--archival/rpm2cpio.c73
-rw-r--r--archival/tar.c71
-rw-r--r--archival/unzip.c10
-rw-r--r--docs/keep_data_small.txt2
-rw-r--r--include/bb_archive.h56
-rw-r--r--include/libbb.h14
21 files changed, 233 insertions, 312 deletions
diff --git a/archival/bbunzip.c b/archival/bbunzip.c
index 853c653c0..1bc04ed33 100644
--- a/archival/bbunzip.c
+++ b/archival/bbunzip.c
@@ -33,7 +33,7 @@ char* FAST_FUNC append_ext(char *filename, const char *expected_ext)
33} 33}
34 34
35int FAST_FUNC bbunpack(char **argv, 35int FAST_FUNC bbunpack(char **argv,
36 IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(unpack_info_t *info), 36 IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(transformer_aux_data_t *aux),
37 char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext), 37 char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext),
38 const char *expected_ext 38 const char *expected_ext
39) 39)
@@ -42,7 +42,7 @@ int FAST_FUNC bbunpack(char **argv,
42 IF_DESKTOP(long long) int status; 42 IF_DESKTOP(long long) int status;
43 char *filename, *new_name; 43 char *filename, *new_name;
44 smallint exitcode = 0; 44 smallint exitcode = 0;
45 unpack_info_t info; 45 transformer_aux_data_t aux;
46 46
47 do { 47 do {
48 /* NB: new_name is *maybe* malloc'ed! */ 48 /* NB: new_name is *maybe* malloc'ed! */
@@ -98,9 +98,9 @@ int FAST_FUNC bbunpack(char **argv,
98 "use -f to force it"); 98 "use -f to force it");
99 } 99 }
100 100
101 /* memset(&info, 0, sizeof(info)); */ 101 init_transformer_aux_data(&aux);
102 info.mtime = 0; /* so far it has one member only */ 102 aux.check_signature = 1;
103 status = unpacker(&info); 103 status = unpacker(&aux);
104 if (status < 0) 104 if (status < 0)
105 exitcode = 1; 105 exitcode = 1;
106 106
@@ -111,10 +111,10 @@ int FAST_FUNC bbunpack(char **argv,
111 char *del = new_name; 111 char *del = new_name;
112 if (status >= 0) { 112 if (status >= 0) {
113 /* TODO: restore other things? */ 113 /* TODO: restore other things? */
114 if (info.mtime) { 114 if (aux.mtime != 0) {
115 struct timeval times[2]; 115 struct timeval times[2];
116 116
117 times[1].tv_sec = times[0].tv_sec = info.mtime; 117 times[1].tv_sec = times[0].tv_sec = aux.mtime;
118 times[1].tv_usec = times[0].tv_usec = 0; 118 times[1].tv_usec = times[0].tv_usec = 0;
119 /* Note: we closed it first. 119 /* Note: we closed it first.
120 * On some systems calling utimes 120 * On some systems calling utimes
@@ -182,16 +182,9 @@ char* FAST_FUNC make_new_name_generic(char *filename, const char *expected_ext)
182 182
183#if ENABLE_UNCOMPRESS 183#if ENABLE_UNCOMPRESS
184static 184static
185IF_DESKTOP(long long) int FAST_FUNC unpack_uncompress(unpack_info_t *info UNUSED_PARAM) 185IF_DESKTOP(long long) int FAST_FUNC unpack_uncompress(transformer_aux_data_t *aux)
186{ 186{
187 IF_DESKTOP(long long) int status = -1; 187 return unpack_Z_stream(aux, STDIN_FILENO, STDOUT_FILENO);
188
189 if ((xread_char(STDIN_FILENO) != 0x1f) || (xread_char(STDIN_FILENO) != 0x9d)) {
190 bb_error_msg("invalid magic");
191 } else {
192 status = unpack_Z_stream(STDIN_FILENO, STDOUT_FILENO);
193 }
194 return status;
195} 188}
196int uncompress_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 189int uncompress_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
197int uncompress_main(int argc UNUSED_PARAM, char **argv) 190int uncompress_main(int argc UNUSED_PARAM, char **argv)
@@ -279,30 +272,30 @@ char* FAST_FUNC make_new_name_gunzip(char *filename, const char *expected_ext UN
279 return filename; 272 return filename;
280} 273}
281static 274static
282IF_DESKTOP(long long) int FAST_FUNC unpack_gunzip(unpack_info_t *info) 275IF_DESKTOP(long long) int FAST_FUNC unpack_gunzip(transformer_aux_data_t *aux)
283{ 276{
284 IF_DESKTOP(long long) int status = -1; 277 IF_DESKTOP(long long) int status = -1;
278 uint16_t magic2;
285 279
286 /* do the decompression, and cleanup */ 280//TODO: fold below into unpack_gz_stream? Then the whole level of indirection
287 if (xread_char(STDIN_FILENO) == 0x1f) { 281// unpack_FOO() -> unpack_FOO_stream can be collapsed in this module!
288 unsigned char magic2; 282
289 283 aux->check_signature = 0; /* we will check it here, not in unpack_*_stream */
290 magic2 = xread_char(STDIN_FILENO); 284
291 if (ENABLE_FEATURE_SEAMLESS_Z && magic2 == 0x9d) { 285 if (full_read(STDIN_FILENO, &magic2, 2) != 2)
292 status = unpack_Z_stream(STDIN_FILENO, STDOUT_FILENO); 286 goto bad_magic;
293 } else if (magic2 == 0x8b) { 287 if (ENABLE_FEATURE_SEAMLESS_Z && magic2 == COMPRESS_MAGIC) {
294 status = unpack_gz_stream_with_info(STDIN_FILENO, STDOUT_FILENO, info); 288 status = unpack_Z_stream(aux, STDIN_FILENO, STDOUT_FILENO);
295 } else { 289 } else if (magic2 == GZIP_MAGIC) {
296 goto bad_magic; 290 status = unpack_gz_stream(aux, STDIN_FILENO, STDOUT_FILENO);
297 }
298 if (status < 0) {
299 bb_error_msg("error inflating");
300 }
301 } else { 291 } else {
302 bad_magic: 292 bad_magic:
303 bb_error_msg("invalid magic"); 293 bb_error_msg("invalid magic");
304 /* status is still == -1 */ 294 /* status is still == -1 */
305 } 295 }
296 if (status < 0) {
297 bb_error_msg("error inflating");
298 }
306 return status; 299 return status;
307} 300}
308/* 301/*
@@ -352,9 +345,9 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv)
352//applet:IF_BUNZIP2(APPLET_ODDNAME(bzcat, bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP, bzcat)) 345//applet:IF_BUNZIP2(APPLET_ODDNAME(bzcat, bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP, bzcat))
353#if ENABLE_BUNZIP2 346#if ENABLE_BUNZIP2
354static 347static
355IF_DESKTOP(long long) int FAST_FUNC unpack_bunzip2(unpack_info_t *info UNUSED_PARAM) 348IF_DESKTOP(long long) int FAST_FUNC unpack_bunzip2(transformer_aux_data_t *aux)
356{ 349{
357 return unpack_bz2_stream_prime(STDIN_FILENO, STDOUT_FILENO); 350 return unpack_bz2_stream(aux, STDIN_FILENO, STDOUT_FILENO);
358} 351}
359int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 352int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
360int bunzip2_main(int argc UNUSED_PARAM, char **argv) 353int bunzip2_main(int argc UNUSED_PARAM, char **argv)
@@ -420,9 +413,9 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv)
420 413
421#if ENABLE_UNLZMA 414#if ENABLE_UNLZMA
422static 415static
423IF_DESKTOP(long long) int FAST_FUNC unpack_unlzma(unpack_info_t *info UNUSED_PARAM) 416IF_DESKTOP(long long) int FAST_FUNC unpack_unlzma(transformer_aux_data_t *aux)
424{ 417{
425 return unpack_lzma_stream(STDIN_FILENO, STDOUT_FILENO); 418 return unpack_lzma_stream(aux, STDIN_FILENO, STDOUT_FILENO);
426} 419}
427int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 420int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
428int unlzma_main(int argc UNUSED_PARAM, char **argv) 421int unlzma_main(int argc UNUSED_PARAM, char **argv)
@@ -445,18 +438,9 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv)
445 438
446#if ENABLE_UNXZ 439#if ENABLE_UNXZ
447static 440static
448IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(unpack_info_t *info UNUSED_PARAM) 441IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(transformer_aux_data_t *aux)
449{ 442{
450 struct { 443 return unpack_xz_stream(aux, STDIN_FILENO, STDOUT_FILENO);
451 uint32_t v1;
452 uint16_t v2;
453 } magic;
454 xread(STDIN_FILENO, &magic, 6);
455 if (magic.v1 != XZ_MAGIC1a || magic.v2 != XZ_MAGIC2a) {
456 bb_error_msg("invalid magic");
457 return -1;
458 }
459 return unpack_xz_stream(STDIN_FILENO, STDOUT_FILENO);
460} 444}
461int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 445int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
462int unxz_main(int argc UNUSED_PARAM, char **argv) 446int unxz_main(int argc UNUSED_PARAM, char **argv)
diff --git a/archival/bzip2.c b/archival/bzip2.c
index 0716fa89b..dd77c8efc 100644
--- a/archival/bzip2.c
+++ b/archival/bzip2.c
@@ -111,7 +111,7 @@ IF_DESKTOP(long long) int bz_write(bz_stream *strm, void* rbuf, ssize_t rlen, vo
111} 111}
112 112
113static 113static
114IF_DESKTOP(long long) int FAST_FUNC compressStream(unpack_info_t *info UNUSED_PARAM) 114IF_DESKTOP(long long) int FAST_FUNC compressStream(transformer_aux_data_t *aux UNUSED_PARAM)
115{ 115{
116 IF_DESKTOP(long long) int total; 116 IF_DESKTOP(long long) int total;
117 ssize_t count; 117 ssize_t count;
diff --git a/archival/gzip.c b/archival/gzip.c
index 929107389..80db4f969 100644
--- a/archival/gzip.c
+++ b/archival/gzip.c
@@ -2015,7 +2015,7 @@ static void zip(ulg time_stamp)
2015 2015
2016/* ======================================================================== */ 2016/* ======================================================================== */
2017static 2017static
2018IF_DESKTOP(long long) int FAST_FUNC pack_gzip(unpack_info_t *info UNUSED_PARAM) 2018IF_DESKTOP(long long) int FAST_FUNC pack_gzip(transformer_aux_data_t *aux UNUSED_PARAM)
2019{ 2019{
2020 struct stat s; 2020 struct stat s;
2021 2021
diff --git a/archival/libarchive/decompress_bunzip2.c b/archival/libarchive/decompress_bunzip2.c
index c4640d489..dc252bb82 100644
--- a/archival/libarchive/decompress_bunzip2.c
+++ b/archival/libarchive/decompress_bunzip2.c
@@ -721,7 +721,7 @@ void FAST_FUNC dealloc_bunzip(bunzip_data *bd)
721 721
722/* Decompress src_fd to dst_fd. Stops at end of bzip data, not end of file. */ 722/* Decompress src_fd to dst_fd. Stops at end of bzip data, not end of file. */
723IF_DESKTOP(long long) int FAST_FUNC 723IF_DESKTOP(long long) int FAST_FUNC
724unpack_bz2_stream(int src_fd, int dst_fd) 724unpack_bz2_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
725{ 725{
726 IF_DESKTOP(long long total_written = 0;) 726 IF_DESKTOP(long long total_written = 0;)
727 bunzip_data *bd; 727 bunzip_data *bd;
@@ -729,6 +729,9 @@ unpack_bz2_stream(int src_fd, int dst_fd)
729 int i; 729 int i;
730 unsigned len; 730 unsigned len;
731 731
732 if (check_signature16(aux, src_fd, BZIP2_MAGIC))
733 return -1;
734
732 outbuf = xmalloc(IOBUF_SIZE); 735 outbuf = xmalloc(IOBUF_SIZE);
733 len = 0; 736 len = 0;
734 while (1) { /* "Process one BZ... stream" loop */ 737 while (1) { /* "Process one BZ... stream" loop */
@@ -794,17 +797,6 @@ unpack_bz2_stream(int src_fd, int dst_fd)
794 return i ? i : IF_DESKTOP(total_written) + 0; 797 return i ? i : IF_DESKTOP(total_written) + 0;
795} 798}
796 799
797IF_DESKTOP(long long) int FAST_FUNC
798unpack_bz2_stream_prime(int src_fd, int dst_fd)
799{
800 uint16_t magic2;
801 xread(src_fd, &magic2, 2);
802 if (magic2 != BZIP2_MAGIC) {
803 bb_error_msg_and_die("invalid magic");
804 }
805 return unpack_bz2_stream(src_fd, dst_fd);
806}
807
808#ifdef TESTING 800#ifdef TESTING
809 801
810static char *const bunzip_errors[] = { 802static char *const bunzip_errors[] = {
@@ -819,7 +811,7 @@ int main(int argc, char **argv)
819 int i; 811 int i;
820 char c; 812 char c;
821 813
822 int i = unpack_bz2_stream_prime(0, 1); 814 int i = unpack_bz2_stream(0, 1);
823 if (i < 0) 815 if (i < 0)
824 fprintf(stderr, "%s\n", bunzip_errors[-i]); 816 fprintf(stderr, "%s\n", bunzip_errors[-i]);
825 else if (read(STDIN_FILENO, &c, 1)) 817 else if (read(STDIN_FILENO, &c, 1))
diff --git a/archival/libarchive/decompress_gunzip.c b/archival/libarchive/decompress_gunzip.c
index 50873e3f6..f1c9a79e5 100644
--- a/archival/libarchive/decompress_gunzip.c
+++ b/archival/libarchive/decompress_gunzip.c
@@ -1034,22 +1034,22 @@ inflate_unzip_internal(STATE_PARAM int in, int out)
1034/* For unzip */ 1034/* For unzip */
1035 1035
1036IF_DESKTOP(long long) int FAST_FUNC 1036IF_DESKTOP(long long) int FAST_FUNC
1037inflate_unzip(inflate_unzip_result *res, off_t compr_size, int in, int out) 1037inflate_unzip(transformer_aux_data_t *aux, int in, int out)
1038{ 1038{
1039 IF_DESKTOP(long long) int n; 1039 IF_DESKTOP(long long) int n;
1040 DECLARE_STATE; 1040 DECLARE_STATE;
1041 1041
1042 ALLOC_STATE; 1042 ALLOC_STATE;
1043 1043
1044 to_read = compr_size; 1044 to_read = aux->bytes_in;
1045// bytebuffer_max = 0x8000; 1045// bytebuffer_max = 0x8000;
1046 bytebuffer_offset = 4; 1046 bytebuffer_offset = 4;
1047 bytebuffer = xmalloc(bytebuffer_max); 1047 bytebuffer = xmalloc(bytebuffer_max);
1048 n = inflate_unzip_internal(PASS_STATE in, out); 1048 n = inflate_unzip_internal(PASS_STATE in, out);
1049 free(bytebuffer); 1049 free(bytebuffer);
1050 1050
1051 res->crc = gunzip_crc; 1051 aux->crc32 = gunzip_crc;
1052 res->bytes_out = gunzip_bytes_out; 1052 aux->bytes_out = gunzip_bytes_out;
1053 DEALLOC_STATE; 1053 DEALLOC_STATE;
1054 return n; 1054 return n;
1055} 1055}
@@ -1107,7 +1107,7 @@ static uint32_t buffer_read_le_u32(STATE_PARAM_ONLY)
1107 return res; 1107 return res;
1108} 1108}
1109 1109
1110static int check_header_gzip(STATE_PARAM unpack_info_t *info) 1110static int check_header_gzip(STATE_PARAM transformer_aux_data_t *aux)
1111{ 1111{
1112 union { 1112 union {
1113 unsigned char raw[8]; 1113 unsigned char raw[8];
@@ -1169,8 +1169,8 @@ static int check_header_gzip(STATE_PARAM unpack_info_t *info)
1169 } 1169 }
1170 } 1170 }
1171 1171
1172 if (info) 1172 if (aux)
1173 info->mtime = SWAP_LE32(header.formatted.mtime); 1173 aux->mtime = SWAP_LE32(header.formatted.mtime);
1174 1174
1175 /* Read the header checksum */ 1175 /* Read the header checksum */
1176 if (header.formatted.flags & 0x02) { 1176 if (header.formatted.flags & 0x02) {
@@ -1182,12 +1182,15 @@ static int check_header_gzip(STATE_PARAM unpack_info_t *info)
1182} 1182}
1183 1183
1184IF_DESKTOP(long long) int FAST_FUNC 1184IF_DESKTOP(long long) int FAST_FUNC
1185unpack_gz_stream_with_info(int src_fd, int dst_fd, unpack_info_t *info) 1185unpack_gz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
1186{ 1186{
1187 uint32_t v32; 1187 uint32_t v32;
1188 IF_DESKTOP(long long) int total, n; 1188 IF_DESKTOP(long long) int total, n;
1189 DECLARE_STATE; 1189 DECLARE_STATE;
1190 1190
1191 if (check_signature16(aux, src_fd, GZIP_MAGIC))
1192 return -1;
1193
1191 total = 0; 1194 total = 0;
1192 1195
1193 ALLOC_STATE; 1196 ALLOC_STATE;
@@ -1197,7 +1200,7 @@ unpack_gz_stream_with_info(int src_fd, int dst_fd, unpack_info_t *info)
1197 gunzip_src_fd = src_fd; 1200 gunzip_src_fd = src_fd;
1198 1201
1199 again: 1202 again:
1200 if (!check_header_gzip(PASS_STATE info)) { 1203 if (!check_header_gzip(PASS_STATE aux)) {
1201 bb_error_msg("corrupted data"); 1204 bb_error_msg("corrupted data");
1202 total = -1; 1205 total = -1;
1203 goto ret; 1206 goto ret;
@@ -1248,9 +1251,3 @@ unpack_gz_stream_with_info(int src_fd, int dst_fd, unpack_info_t *info)
1248 DEALLOC_STATE; 1251 DEALLOC_STATE;
1249 return total; 1252 return total;
1250} 1253}
1251
1252IF_DESKTOP(long long) int FAST_FUNC
1253unpack_gz_stream(int in, int out)
1254{
1255 return unpack_gz_stream_with_info(in, out, NULL);
1256}
diff --git a/archival/libarchive/decompress_uncompress.c b/archival/libarchive/decompress_uncompress.c
index 289f9e233..e9bbfb9bd 100644
--- a/archival/libarchive/decompress_uncompress.c
+++ b/archival/libarchive/decompress_uncompress.c
@@ -73,7 +73,7 @@
73 */ 73 */
74 74
75IF_DESKTOP(long long) int FAST_FUNC 75IF_DESKTOP(long long) int FAST_FUNC
76unpack_Z_stream(int src_fd, int dst_fd) 76unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
77{ 77{
78 IF_DESKTOP(long long total_written = 0;) 78 IF_DESKTOP(long long total_written = 0;)
79 IF_DESKTOP(long long) int retval = -1; 79 IF_DESKTOP(long long) int retval = -1;
@@ -103,6 +103,9 @@ unpack_Z_stream(int src_fd, int dst_fd)
103 /* block compress mode -C compatible with 2.0 */ 103 /* block compress mode -C compatible with 2.0 */
104 int block_mode; /* = BLOCK_MODE; */ 104 int block_mode; /* = BLOCK_MODE; */
105 105
106 if (check_signature16(aux, src_fd, COMPRESS_MAGIC))
107 return -1;
108
106 inbuf = xzalloc(IBUFSIZ + 64); 109 inbuf = xzalloc(IBUFSIZ + 64);
107 outbuf = xzalloc(OBUFSIZ + 2048); 110 outbuf = xzalloc(OBUFSIZ + 2048);
108 htab = xzalloc(HSIZE); /* wasn't zeroed out before, maybe can xmalloc? */ 111 htab = xzalloc(HSIZE); /* wasn't zeroed out before, maybe can xmalloc? */
diff --git a/archival/libarchive/decompress_unlzma.c b/archival/libarchive/decompress_unlzma.c
index 3631b50cc..cfde8ea56 100644
--- a/archival/libarchive/decompress_unlzma.c
+++ b/archival/libarchive/decompress_unlzma.c
@@ -213,7 +213,7 @@ enum {
213 213
214 214
215IF_DESKTOP(long long) int FAST_FUNC 215IF_DESKTOP(long long) int FAST_FUNC
216unpack_lzma_stream(int src_fd, int dst_fd) 216unpack_lzma_stream(transformer_aux_data_t *aux UNUSED_PARAM, int src_fd, int dst_fd)
217{ 217{
218 IF_DESKTOP(long long total_written = 0;) 218 IF_DESKTOP(long long total_written = 0;)
219 lzma_header_t header; 219 lzma_header_t header;
diff --git a/archival/libarchive/decompress_unxz.c b/archival/libarchive/decompress_unxz.c
index 3e5d4edca..79b48a152 100644
--- a/archival/libarchive/decompress_unxz.c
+++ b/archival/libarchive/decompress_unxz.c
@@ -38,7 +38,7 @@ static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc)
38#include "unxz/xz_dec_stream.c" 38#include "unxz/xz_dec_stream.c"
39 39
40IF_DESKTOP(long long) int FAST_FUNC 40IF_DESKTOP(long long) int FAST_FUNC
41unpack_xz_stream(int src_fd, int dst_fd) 41unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
42{ 42{
43 struct xz_buf iobuf; 43 struct xz_buf iobuf;
44 struct xz_dec *state; 44 struct xz_dec *state;
@@ -49,13 +49,17 @@ unpack_xz_stream(int src_fd, int dst_fd)
49 global_crc32_table = crc32_filltable(NULL, /*endian:*/ 0); 49 global_crc32_table = crc32_filltable(NULL, /*endian:*/ 0);
50 50
51 memset(&iobuf, 0, sizeof(iobuf)); 51 memset(&iobuf, 0, sizeof(iobuf));
52 /* Preload XZ file signature */ 52 membuf = xmalloc(2 * BUFSIZ);
53 membuf = (void*) strcpy(xmalloc(2 * BUFSIZ), HEADER_MAGIC);
54 iobuf.in = membuf; 53 iobuf.in = membuf;
55 iobuf.in_size = HEADER_MAGIC_SIZE;
56 iobuf.out = membuf + BUFSIZ; 54 iobuf.out = membuf + BUFSIZ;
57 iobuf.out_size = BUFSIZ; 55 iobuf.out_size = BUFSIZ;
58 56
57 if (!aux || aux->check_signature == 0) {
58 /* Preload XZ file signature */
59 strcpy((char*)membuf, HEADER_MAGIC);
60 iobuf.in_size = HEADER_MAGIC_SIZE;
61 } /* else: let xz code read & check it */
62
59 /* Limit memory usage to about 64 MiB. */ 63 /* Limit memory usage to about 64 MiB. */
60 state = xz_dec_init(XZ_DYNALLOC, 64*1024*1024); 64 state = xz_dec_init(XZ_DYNALLOC, 64*1024*1024);
61 65
diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c
index 8c699754b..80a709144 100644
--- a/archival/libarchive/get_header_tar.c
+++ b/archival/libarchive/get_header_tar.c
@@ -235,43 +235,18 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
235 || memcmp(tar.magic, "\0\0\0\0", 5) != 0) 235 || memcmp(tar.magic, "\0\0\0\0", 5) != 0)
236 ) { 236 ) {
237#if ENABLE_FEATURE_TAR_AUTODETECT 237#if ENABLE_FEATURE_TAR_AUTODETECT
238 char FAST_FUNC (*get_header_ptr)(archive_handle_t *);
239 uint16_t magic2;
240
241 autodetect: 238 autodetect:
242 magic2 = *(bb__aliased_uint16_t*)tar.name;
243 /* tar gz/bz autodetect: check for gz/bz2 magic.
244 * If we see the magic, and it is the very first block,
245 * we can switch to get_header_tar_gz/bz2/lzma().
246 * Needs seekable fd. I wish recv(MSG_PEEK) works
247 * on any fd... */
248# if ENABLE_FEATURE_SEAMLESS_GZ
249 if (magic2 == GZIP_MAGIC) {
250 get_header_ptr = get_header_tar_gz;
251 } else
252# endif
253# if ENABLE_FEATURE_SEAMLESS_BZ2
254 if (magic2 == BZIP2_MAGIC
255 && tar.name[2] == 'h' && isdigit(tar.name[3])
256 ) { /* bzip2 */
257 get_header_ptr = get_header_tar_bz2;
258 } else
259# endif
260# if ENABLE_FEATURE_SEAMLESS_XZ
261 //TODO: if (magic2 == XZ_MAGIC1)...
262 //else
263# endif
264 goto err;
265 /* Two different causes for lseek() != 0: 239 /* Two different causes for lseek() != 0:
266 * unseekable fd (would like to support that too, but...), 240 * unseekable fd (would like to support that too, but...),
267 * or not first block (false positive, it's not .gz/.bz2!) */ 241 * or not first block (false positive, it's not .gz/.bz2!) */
268 if (lseek(archive_handle->src_fd, -i, SEEK_CUR) != 0) 242 if (lseek(archive_handle->src_fd, -i, SEEK_CUR) != 0)
269 goto err; 243 goto err;
270 while (get_header_ptr(archive_handle) == EXIT_SUCCESS) 244 if (setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_detected:*/ 0) != 0)
271 continue;
272 return EXIT_FAILURE;
273 err: 245 err:
274#endif /* FEATURE_TAR_AUTODETECT */ 246 bb_error_msg_and_die("invalid tar magic");
247 archive_handle->offset = 0;
248 goto again_after_align;
249#endif
275 bb_error_msg_and_die("invalid tar magic"); 250 bb_error_msg_and_die("invalid tar magic");
276 } 251 }
277 252
diff --git a/archival/libarchive/get_header_tar_bz2.c b/archival/libarchive/get_header_tar_bz2.c
index e012dec3b..0ee00df53 100644
--- a/archival/libarchive/get_header_tar_bz2.c
+++ b/archival/libarchive/get_header_tar_bz2.c
@@ -11,7 +11,7 @@ char FAST_FUNC get_header_tar_bz2(archive_handle_t *archive_handle)
11 /* Can't lseek over pipes */ 11 /* Can't lseek over pipes */
12 archive_handle->seek = seek_by_read; 12 archive_handle->seek = seek_by_read;
13 13
14 open_transformer(archive_handle->src_fd, unpack_bz2_stream_prime, "bunzip2"); 14 open_transformer_with_sig(archive_handle->src_fd, unpack_bz2_stream, "bunzip2");
15 archive_handle->offset = 0; 15 archive_handle->offset = 0;
16 while (get_header_tar(archive_handle) == EXIT_SUCCESS) 16 while (get_header_tar(archive_handle) == EXIT_SUCCESS)
17 continue; 17 continue;
diff --git a/archival/libarchive/get_header_tar_gz.c b/archival/libarchive/get_header_tar_gz.c
index b9679b0bd..03284342b 100644
--- a/archival/libarchive/get_header_tar_gz.c
+++ b/archival/libarchive/get_header_tar_gz.c
@@ -8,25 +8,10 @@
8 8
9char FAST_FUNC get_header_tar_gz(archive_handle_t *archive_handle) 9char FAST_FUNC get_header_tar_gz(archive_handle_t *archive_handle)
10{ 10{
11#if BB_MMU
12 uint16_t magic;
13#endif
14
15 /* Can't lseek over pipes */ 11 /* Can't lseek over pipes */
16 archive_handle->seek = seek_by_read; 12 archive_handle->seek = seek_by_read;
17 13
18 /* Check gzip magic only if open_transformer will invoke unpack_gz_stream (MMU case). 14 open_transformer_with_sig(archive_handle->src_fd, unpack_gz_stream, "gunzip");
19 * Otherwise, it will invoke an external helper "gunzip -cf" (NOMMU case) which will
20 * need the header. */
21#if BB_MMU
22 xread(archive_handle->src_fd, &magic, 2);
23 /* Can skip this check, but error message will be less clear */
24 if (magic != GZIP_MAGIC) {
25 bb_error_msg_and_die("invalid gzip magic");
26 }
27#endif
28
29 open_transformer(archive_handle->src_fd, unpack_gz_stream, "gunzip");
30 archive_handle->offset = 0; 15 archive_handle->offset = 0;
31 while (get_header_tar(archive_handle) == EXIT_SUCCESS) 16 while (get_header_tar(archive_handle) == EXIT_SUCCESS)
32 continue; 17 continue;
diff --git a/archival/libarchive/get_header_tar_lzma.c b/archival/libarchive/get_header_tar_lzma.c
index 666700729..d565a217d 100644
--- a/archival/libarchive/get_header_tar_lzma.c
+++ b/archival/libarchive/get_header_tar_lzma.c
@@ -14,7 +14,7 @@ char FAST_FUNC get_header_tar_lzma(archive_handle_t *archive_handle)
14 /* Can't lseek over pipes */ 14 /* Can't lseek over pipes */
15 archive_handle->seek = seek_by_read; 15 archive_handle->seek = seek_by_read;
16 16
17 open_transformer(archive_handle->src_fd, unpack_lzma_stream, "unlzma"); 17 open_transformer_with_sig(archive_handle->src_fd, unpack_lzma_stream, "unlzma");
18 archive_handle->offset = 0; 18 archive_handle->offset = 0;
19 while (get_header_tar(archive_handle) == EXIT_SUCCESS) 19 while (get_header_tar(archive_handle) == EXIT_SUCCESS)
20 continue; 20 continue;
diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c
index 743ffee02..693ae9995 100644
--- a/archival/libarchive/open_transformer.c
+++ b/archival/libarchive/open_transformer.c
@@ -6,24 +6,36 @@
6#include "libbb.h" 6#include "libbb.h"
7#include "bb_archive.h" 7#include "bb_archive.h"
8 8
9#define ZIPPED (ENABLE_FEATURE_SEAMLESS_LZMA \ 9void FAST_FUNC init_transformer_aux_data(transformer_aux_data_t *aux)
10 || ENABLE_FEATURE_SEAMLESS_BZ2 \ 10{
11 || ENABLE_FEATURE_SEAMLESS_GZ \ 11 memset(aux, 0, sizeof(*aux));
12 /* || ENABLE_FEATURE_SEAMLESS_Z */ \ 12}
13)
14 13
15#if ZIPPED 14int FAST_FUNC check_signature16(transformer_aux_data_t *aux, int src_fd, unsigned magic16)
16# include "bb_archive.h" 15{
16 if (aux && aux->check_signature) {
17 uint16_t magic2;
18 if (full_read(src_fd, &magic2, 2) != 2 || magic2 != magic16) {
19 bb_error_msg("invalid magic");
20#if 0 /* possible future extension */
21 if (aux->check_signature > 1)
22 xfunc_die();
17#endif 23#endif
24 return -1;
25 }
26 }
27 return 0;
28}
18 29
19/* transformer(), more than meets the eye */ 30/* transformer(), more than meets the eye */
20/* 31#if BB_MMU
21 * On MMU machine, the transform_prog is removed by macro magic
22 * in include/archive.h. On NOMMU, transformer is removed.
23 */
24void FAST_FUNC open_transformer(int fd, 32void FAST_FUNC open_transformer(int fd,
25 IF_DESKTOP(long long) int FAST_FUNC (*transformer)(int src_fd, int dst_fd), 33 int check_signature,
26 const char *transform_prog) 34 IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd)
35)
36#else
37void FAST_FUNC open_transformer(int fd, const char *transform_prog)
38#endif
27{ 39{
28 struct fd_pair fd_pipe; 40 struct fd_pair fd_pipe;
29 int pid; 41 int pid;
@@ -35,13 +47,18 @@ void FAST_FUNC open_transformer(int fd,
35 close(fd_pipe.rd); /* we don't want to read from the parent */ 47 close(fd_pipe.rd); /* we don't want to read from the parent */
36 // FIXME: error check? 48 // FIXME: error check?
37#if BB_MMU 49#if BB_MMU
38 transformer(fd, fd_pipe.wr); 50 {
39 if (ENABLE_FEATURE_CLEAN_UP) { 51 transformer_aux_data_t aux;
40 close(fd_pipe.wr); /* send EOF */ 52 init_transformer_aux_data(&aux);
41 close(fd); 53 aux.check_signature = check_signature;
54 transformer(&aux, fd, fd_pipe.wr);
55 if (ENABLE_FEATURE_CLEAN_UP) {
56 close(fd_pipe.wr); /* send EOF */
57 close(fd);
58 }
59 /* must be _exit! bug was actually seen here */
60 _exit(EXIT_SUCCESS);
42 } 61 }
43 /* must be _exit! bug was actually seen here */
44 _exit(EXIT_SUCCESS);
45#else 62#else
46 { 63 {
47 char *argv[4]; 64 char *argv[4];
@@ -64,26 +81,21 @@ void FAST_FUNC open_transformer(int fd,
64} 81}
65 82
66 83
84#if SEAMLESS_COMPRESSION
85
67/* Used by e.g. rpm which gives us a fd without filename, 86/* Used by e.g. rpm which gives us a fd without filename,
68 * thus we can't guess the format from filename's extension. 87 * thus we can't guess the format from filename's extension.
69 */ 88 */
70#if ZIPPED 89int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_detected)
71void FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/)
72{ 90{
73 const int fail_if_not_detected = 1;
74 union { 91 union {
75 uint8_t b[4]; 92 uint8_t b[4];
76 uint16_t b16[2]; 93 uint16_t b16[2];
77 uint32_t b32[1]; 94 uint32_t b32[1];
78 } magic; 95 } magic;
79 int offset = -2; 96 int offset = -2;
80# if BB_MMU 97 USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd);)
81 IF_DESKTOP(long long) int FAST_FUNC (*xformer)(int src_fd, int dst_fd); 98 USE_FOR_NOMMU(const char *xformer_prog;)
82 enum { xformer_prog = 0 };
83# else
84 enum { xformer = 0 };
85 const char *xformer_prog;
86# endif
87 99
88 /* .gz and .bz2 both have 2-byte signature, and their 100 /* .gz and .bz2 both have 2-byte signature, and their
89 * unpack_XXX_stream wants this header skipped. */ 101 * unpack_XXX_stream wants this header skipped. */
@@ -91,21 +103,15 @@ void FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/)
91 if (ENABLE_FEATURE_SEAMLESS_GZ 103 if (ENABLE_FEATURE_SEAMLESS_GZ
92 && magic.b16[0] == GZIP_MAGIC 104 && magic.b16[0] == GZIP_MAGIC
93 ) { 105 ) {
94# if BB_MMU 106 USE_FOR_MMU(xformer = unpack_gz_stream;)
95 xformer = unpack_gz_stream; 107 USE_FOR_NOMMU(xformer_prog = "gunzip";)
96# else
97 xformer_prog = "gunzip";
98# endif
99 goto found_magic; 108 goto found_magic;
100 } 109 }
101 if (ENABLE_FEATURE_SEAMLESS_BZ2 110 if (ENABLE_FEATURE_SEAMLESS_BZ2
102 && magic.b16[0] == BZIP2_MAGIC 111 && magic.b16[0] == BZIP2_MAGIC
103 ) { 112 ) {
104# if BB_MMU 113 USE_FOR_MMU(xformer = unpack_bz2_stream;)
105 xformer = unpack_bz2_stream; 114 USE_FOR_NOMMU(xformer_prog = "bunzip2";)
106# else
107 xformer_prog = "bunzip2";
108# endif
109 goto found_magic; 115 goto found_magic;
110 } 116 }
111 if (ENABLE_FEATURE_SEAMLESS_XZ 117 if (ENABLE_FEATURE_SEAMLESS_XZ
@@ -114,13 +120,8 @@ void FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/)
114 offset = -6; 120 offset = -6;
115 xread(fd, magic.b32, sizeof(magic.b32[0])); 121 xread(fd, magic.b32, sizeof(magic.b32[0]));
116 if (magic.b32[0] == XZ_MAGIC2) { 122 if (magic.b32[0] == XZ_MAGIC2) {
117# if BB_MMU 123 USE_FOR_MMU(xformer = unpack_xz_stream;)
118 xformer = unpack_xz_stream; 124 USE_FOR_NOMMU(xformer_prog = "unxz";)
119 /* unpack_xz_stream wants fd at position 6, no need to seek */
120 //xlseek(fd, offset, SEEK_CUR);
121# else
122 xformer_prog = "unxz";
123# endif
124 goto found_magic; 125 goto found_magic;
125 } 126 }
126 } 127 }
@@ -132,24 +133,23 @@ void FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/)
132 IF_FEATURE_SEAMLESS_XZ("/xz") 133 IF_FEATURE_SEAMLESS_XZ("/xz")
133 " magic"); 134 " magic");
134 xlseek(fd, offset, SEEK_CUR); 135 xlseek(fd, offset, SEEK_CUR);
135 return; 136 return 1;
136 137
137 found_magic: 138 found_magic:
138# if !BB_MMU 139# if BB_MMU
140 open_transformer_with_no_sig(fd, xformer);
141# else
139 /* NOMMU version of open_transformer execs 142 /* NOMMU version of open_transformer execs
140 * an external unzipper that wants 143 * an external unzipper that wants
141 * file position at the start of the file */ 144 * file position at the start of the file */
142 xlseek(fd, offset, SEEK_CUR); 145 xlseek(fd, offset, SEEK_CUR);
146 open_transformer_with_sig(fd, xformer, xformer_prog);
143# endif 147# endif
144 open_transformer(fd, xformer, xformer_prog); 148 return 0;
145} 149}
146#endif /* ZIPPED */
147 150
148int FAST_FUNC open_zipped(const char *fname) 151int FAST_FUNC open_zipped(const char *fname)
149{ 152{
150#if !ZIPPED
151 return open(fname, O_RDONLY);
152#else
153 char *sfx; 153 char *sfx;
154 int fd; 154 int fd;
155 155
@@ -162,20 +162,21 @@ int FAST_FUNC open_zipped(const char *fname)
162 sfx++; 162 sfx++;
163 if (ENABLE_FEATURE_SEAMLESS_LZMA && strcmp(sfx, "lzma") == 0) 163 if (ENABLE_FEATURE_SEAMLESS_LZMA && strcmp(sfx, "lzma") == 0)
164 /* .lzma has no header/signature, just trust it */ 164 /* .lzma has no header/signature, just trust it */
165 open_transformer(fd, unpack_lzma_stream, "unlzma"); 165 open_transformer_with_sig(fd, unpack_lzma_stream, "unlzma");
166 else 166 else
167 if ((ENABLE_FEATURE_SEAMLESS_GZ && strcmp(sfx, "gz") == 0) 167 if ((ENABLE_FEATURE_SEAMLESS_GZ && strcmp(sfx, "gz") == 0)
168 || (ENABLE_FEATURE_SEAMLESS_BZ2 && strcmp(sfx, "bz2") == 0) 168 || (ENABLE_FEATURE_SEAMLESS_BZ2 && strcmp(sfx, "bz2") == 0)
169 || (ENABLE_FEATURE_SEAMLESS_XZ && strcmp(sfx, "xz") == 0) 169 || (ENABLE_FEATURE_SEAMLESS_XZ && strcmp(sfx, "xz") == 0)
170 ) { 170 ) {
171 setup_unzip_on_fd(fd /*, fail_if_not_detected: 1*/); 171 setup_unzip_on_fd(fd, /*fail_if_not_detected:*/ 1);
172 } 172 }
173 } 173 }
174 174
175 return fd; 175 return fd;
176#endif
177} 176}
178 177
178#endif /* SEAMLESS_COMPRESSION */
179
179void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) 180void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p)
180{ 181{
181 int fd; 182 int fd;
diff --git a/archival/lzop.c b/archival/lzop.c
index 67baeff7e..fbe08417d 100644
--- a/archival/lzop.c
+++ b/archival/lzop.c
@@ -1077,7 +1077,7 @@ static char* FAST_FUNC make_new_name_lzop(char *filename, const char *expected_e
1077 return xasprintf("%s.lzo", filename); 1077 return xasprintf("%s.lzo", filename);
1078} 1078}
1079 1079
1080static IF_DESKTOP(long long) int FAST_FUNC pack_lzop(unpack_info_t *info UNUSED_PARAM) 1080static IF_DESKTOP(long long) int FAST_FUNC pack_lzop(transformer_aux_data_t *aux UNUSED_PARAM)
1081{ 1081{
1082 if (option_mask32 & OPT_DECOMPRESS) 1082 if (option_mask32 & OPT_DECOMPRESS)
1083 return do_lzo_decompress(); 1083 return do_lzo_decompress();
diff --git a/archival/rpm.c b/archival/rpm.c
index 089b68983..6757a6ceb 100644
--- a/archival/rpm.c
+++ b/archival/rpm.c
@@ -236,7 +236,7 @@ static void extract_cpio(int fd, const char *source_rpm)
236 archive_handle->src_fd = fd; 236 archive_handle->src_fd = fd;
237 /*archive_handle->offset = 0; - init_handle() did it */ 237 /*archive_handle->offset = 0; - init_handle() did it */
238 238
239 setup_unzip_on_fd(archive_handle->src_fd /*, fail_if_not_detected: 1*/); 239 setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_detected:*/ 1);
240 while (get_header_cpio(archive_handle) == EXIT_SUCCESS) 240 while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
241 continue; 241 continue;
242} 242}
diff --git a/archival/rpm2cpio.c b/archival/rpm2cpio.c
index 28b43a181..7256aae6b 100644
--- a/archival/rpm2cpio.c
+++ b/archival/rpm2cpio.c
@@ -42,6 +42,26 @@ static unsigned skip_header(void)
42 return sizeof(header) + len; 42 return sizeof(header) + len;
43} 43}
44 44
45#if SEAMLESS_COMPRESSION
46static void handle_SIGCHLD(int signo UNUSED_PARAM)
47{
48 int status;
49
50 /* Wait for any child without blocking */
51 for (;;) {
52 if (wait_any_nohang(&status) < 0)
53 /* wait failed?! I'm confused... */
54 return;
55 if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
56 /* this child exited with 0 */
57 continue;
58 /* Cannot happen?
59 if (!WIFSIGNALED(status) && !WIFEXITED(status)) ???; */
60 bb_got_signal = 1;
61 }
62}
63#endif
64
45/* No getopt required */ 65/* No getopt required */
46int rpm2cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 66int rpm2cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
47int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) 67int rpm2cpio_main(int argc UNUSED_PARAM, char **argv)
@@ -66,54 +86,23 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv)
66 /* Skip the main header */ 86 /* Skip the main header */
67 skip_header(); 87 skip_header();
68 88
69#if 0 89#if SEAMLESS_COMPRESSION
90 /* We need to know whether child (gzip/bzip/etc) exits abnormally */
91 signal(SIGCHLD, handle_SIGCHLD);
92#endif
93
70 /* This works, but doesn't report uncompress errors (they happen in child) */ 94 /* This works, but doesn't report uncompress errors (they happen in child) */
71 setup_unzip_on_fd(rpm_fd /*fail_if_not_detected: 1*/); 95 setup_unzip_on_fd(rpm_fd, /*fail_if_not_detected:*/ 1);
72 if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0) 96 if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0)
73 bb_error_msg_and_die("error unpacking"); 97 bb_error_msg_and_die("error unpacking");
74#else
75 /* BLOAT */
76 {
77 union {
78 uint8_t b[4];
79 uint16_t b16[2];
80 uint32_t b32[1];
81 } magic;
82 IF_DESKTOP(long long) int FAST_FUNC (*unpack)(int src_fd, int dst_fd);
83
84 xread(rpm_fd, magic.b16, sizeof(magic.b16[0]));
85 if (magic.b16[0] == GZIP_MAGIC) {
86 unpack = unpack_gz_stream;
87 } else
88 if (ENABLE_FEATURE_SEAMLESS_BZ2
89 && magic.b16[0] == BZIP2_MAGIC
90 ) {
91 unpack = unpack_bz2_stream;
92 } else
93 if (ENABLE_FEATURE_SEAMLESS_XZ
94 && magic.b16[0] == XZ_MAGIC1
95 ) {
96 xread(rpm_fd, magic.b32, sizeof(magic.b32[0]));
97 if (magic.b32[0] != XZ_MAGIC2)
98 goto no_magic;
99 /* unpack_xz_stream wants fd at position 6, no need to seek */
100 //xlseek(rpm_fd, -6, SEEK_CUR);
101 unpack = unpack_xz_stream;
102 } else {
103 no_magic:
104 bb_error_msg_and_die("no gzip"
105 IF_FEATURE_SEAMLESS_BZ2("/bzip2")
106 IF_FEATURE_SEAMLESS_XZ("/xz")
107 " magic");
108 }
109 if (unpack(rpm_fd, STDOUT_FILENO) < 0)
110 bb_error_msg_and_die("error unpacking");
111 }
112#endif
113 98
114 if (ENABLE_FEATURE_CLEAN_UP) { 99 if (ENABLE_FEATURE_CLEAN_UP) {
115 close(rpm_fd); 100 close(rpm_fd);
116 } 101 }
117 102
118 return 0; 103#if SEAMLESS_COMPRESSION
104 return bb_got_signal;
105#else
106 return EXIT_SUCCESS;
107#endif
119} 108}
diff --git a/archival/tar.c b/archival/tar.c
index 766b79b2b..af38ac59f 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -690,31 +690,6 @@ static llist_t *append_file_list_to_list(llist_t *list)
690# define append_file_list_to_list(x) 0 690# define append_file_list_to_list(x) 0
691#endif 691#endif
692 692
693#if ENABLE_FEATURE_SEAMLESS_Z
694static char FAST_FUNC get_header_tar_Z(archive_handle_t *archive_handle)
695{
696 /* Can't lseek over pipes */
697 archive_handle->seek = seek_by_read;
698
699 /* do the decompression, and cleanup */
700 if (xread_char(archive_handle->src_fd) != 0x1f
701 || xread_char(archive_handle->src_fd) != 0x9d
702 ) {
703 bb_error_msg_and_die("invalid magic");
704 }
705
706 open_transformer(archive_handle->src_fd, unpack_Z_stream, "uncompress");
707 archive_handle->offset = 0;
708 while (get_header_tar(archive_handle) == EXIT_SUCCESS)
709 continue;
710
711 /* Can only do one file at a time */
712 return EXIT_FAILURE;
713}
714#else
715# define get_header_tar_Z NULL
716#endif
717
718#ifdef CHECK_FOR_CHILD_EXITCODE 693#ifdef CHECK_FOR_CHILD_EXITCODE
719/* Looks like it isn't needed - tar detects malformed (truncated) 694/* Looks like it isn't needed - tar detects malformed (truncated)
720 * archive if e.g. bunzip2 fails */ 695 * archive if e.g. bunzip2 fails */
@@ -843,6 +818,8 @@ enum {
843 OPT_NUMERIC_OWNER = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER )) + 0, // numeric-owner 818 OPT_NUMERIC_OWNER = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER )) + 0, // numeric-owner
844 OPT_NOPRESERVE_PERM = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0, // no-same-permissions 819 OPT_NOPRESERVE_PERM = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0, // no-same-permissions
845 OPT_OVERWRITE = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE )) + 0, // overwrite 820 OPT_OVERWRITE = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE )) + 0, // overwrite
821
822 OPT_ANY_COMPRESS = (OPT_BZIP2 | OPT_LZMA | OPT_GZIP | OPT_COMPRESS),
846}; 823};
847#if ENABLE_FEATURE_TAR_LONG_OPTIONS 824#if ENABLE_FEATURE_TAR_LONG_OPTIONS
848static const char tar_longopts[] ALIGN1 = 825static const char tar_longopts[] ALIGN1 =
@@ -901,7 +878,6 @@ static const char tar_longopts[] ALIGN1 =
901int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 878int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
902int tar_main(int argc UNUSED_PARAM, char **argv) 879int tar_main(int argc UNUSED_PARAM, char **argv)
903{ 880{
904 char FAST_FUNC (*get_header_ptr)(archive_handle_t *) = get_header_tar;
905 archive_handle_t *tar_handle; 881 archive_handle_t *tar_handle;
906 char *base_dir = NULL; 882 char *base_dir = NULL;
907 const char *tar_filename = "-"; 883 const char *tar_filename = "-";
@@ -1017,18 +993,6 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
1017 tar_handle->ah_flags |= ARCHIVE_O_TRUNC; 993 tar_handle->ah_flags |= ARCHIVE_O_TRUNC;
1018 } 994 }
1019 995
1020 if (opt & OPT_GZIP)
1021 get_header_ptr = get_header_tar_gz;
1022
1023 if (opt & OPT_BZIP2)
1024 get_header_ptr = get_header_tar_bz2;
1025
1026 if (opt & OPT_LZMA)
1027 get_header_ptr = get_header_tar_lzma;
1028
1029 if (opt & OPT_COMPRESS)
1030 get_header_ptr = get_header_tar_Z;
1031
1032 if (opt & OPT_NOPRESERVE_TIME) 996 if (opt & OPT_NOPRESERVE_TIME)
1033 tar_handle->ah_flags &= ~ARCHIVE_RESTORE_DATE; 997 tar_handle->ah_flags &= ~ARCHIVE_RESTORE_DATE;
1034 998
@@ -1081,7 +1045,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
1081 } else { 1045 } else {
1082 if (ENABLE_FEATURE_TAR_AUTODETECT 1046 if (ENABLE_FEATURE_TAR_AUTODETECT
1083 && flags == O_RDONLY 1047 && flags == O_RDONLY
1084 && get_header_ptr == get_header_tar 1048 && !(opt & OPT_ANY_COMPRESS)
1085 ) { 1049 ) {
1086 tar_handle->src_fd = open_zipped(tar_filename); 1050 tar_handle->src_fd = open_zipped(tar_filename);
1087 if (tar_handle->src_fd < 0) 1051 if (tar_handle->src_fd < 0)
@@ -1115,7 +1079,30 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
1115 tar_handle->reject, zipMode); 1079 tar_handle->reject, zipMode);
1116 } 1080 }
1117 1081
1118 while (get_header_ptr(tar_handle) == EXIT_SUCCESS) 1082 if (opt & OPT_ANY_COMPRESS) {
1083 USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd);)
1084 USE_FOR_NOMMU(const char *xformer_prog;)
1085
1086 if (opt & OPT_COMPRESS)
1087 USE_FOR_MMU(xformer = unpack_Z_stream;)
1088 USE_FOR_NOMMU(xformer_prog = "uncompress";)
1089 if (opt & OPT_GZIP)
1090 USE_FOR_MMU(xformer = unpack_gz_stream;)
1091 USE_FOR_NOMMU(xformer_prog = "gunzip";)
1092 if (opt & OPT_BZIP2)
1093 USE_FOR_MMU(xformer = unpack_bz2_stream;)
1094 USE_FOR_NOMMU(xformer_prog = "bunzip2";)
1095 if (opt & OPT_LZMA)
1096 USE_FOR_MMU(xformer = unpack_lzma_stream;)
1097 USE_FOR_NOMMU(xformer_prog = "unlzma";)
1098
1099 open_transformer_with_sig(tar_handle->src_fd, xformer, xformer_prog);
1100 /* Can't lseek over pipes */
1101 tar_handle->seek = seek_by_read;
1102 /*tar_handle->offset = 0; - already is */
1103 }
1104
1105 while (get_header_tar(tar_handle) == EXIT_SUCCESS)
1119 continue; 1106 continue;
1120 1107
1121 /* Check that every file that should have been extracted was */ 1108 /* Check that every file that should have been extracted was */
@@ -1131,5 +1118,9 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
1131 if (ENABLE_FEATURE_CLEAN_UP /* && tar_handle->src_fd != STDIN_FILENO */) 1118 if (ENABLE_FEATURE_CLEAN_UP /* && tar_handle->src_fd != STDIN_FILENO */)
1132 close(tar_handle->src_fd); 1119 close(tar_handle->src_fd);
1133 1120
1121#ifdef CHECK_FOR_CHILD_EXITCODE
1122 return bb_got_signal;
1123#else
1134 return EXIT_SUCCESS; 1124 return EXIT_SUCCESS;
1125#endif
1135} 1126}
diff --git a/archival/unzip.c b/archival/unzip.c
index 3a11f78a5..3c76cdafc 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -249,15 +249,17 @@ static void unzip_extract(zip_header_t *zip_header, int dst_fd)
249 bb_copyfd_exact_size(zip_fd, dst_fd, size); 249 bb_copyfd_exact_size(zip_fd, dst_fd, size);
250 } else { 250 } else {
251 /* Method 8 - inflate */ 251 /* Method 8 - inflate */
252 inflate_unzip_result res; 252 transformer_aux_data_t aux;
253 if (inflate_unzip(&res, zip_header->formatted.cmpsize, zip_fd, dst_fd) < 0) 253 init_transformer_aux_data(&aux);
254 aux.bytes_in = zip_header->formatted.cmpsize;
255 if (inflate_unzip(&aux, zip_fd, dst_fd) < 0)
254 bb_error_msg_and_die("inflate error"); 256 bb_error_msg_and_die("inflate error");
255 /* Validate decompression - crc */ 257 /* Validate decompression - crc */
256 if (zip_header->formatted.crc32 != (res.crc ^ 0xffffffffL)) { 258 if (zip_header->formatted.crc32 != (aux.crc32 ^ 0xffffffffL)) {
257 bb_error_msg_and_die("crc error"); 259 bb_error_msg_and_die("crc error");
258 } 260 }
259 /* Validate decompression - size */ 261 /* Validate decompression - size */
260 if (zip_header->formatted.ucmpsize != res.bytes_out) { 262 if (zip_header->formatted.ucmpsize != aux.bytes_out) {
261 /* Don't die. Who knows, maybe len calculation 263 /* Don't die. Who knows, maybe len calculation
262 * was botched somewhere. After all, crc matched! */ 264 * was botched somewhere. After all, crc matched! */
263 bb_error_msg("bad length"); 265 bb_error_msg("bad length");
diff --git a/docs/keep_data_small.txt b/docs/keep_data_small.txt
index 9e77a9097..21d732674 100644
--- a/docs/keep_data_small.txt
+++ b/docs/keep_data_small.txt
@@ -59,7 +59,7 @@ wait
59 Example 1 59 Example 1
60 60
61One example how to reduce global data usage is in 61One example how to reduce global data usage is in
62archival/libarchive/decompress_gunzip.c: 62archival/libarchive/decompress_unzip.c:
63 63
64/* This is somewhat complex-looking arrangement, but it allows 64/* This is somewhat complex-looking arrangement, but it allows
65 * to place decompressor state either in bss or in 65 * to place decompressor state either in bss or in
diff --git a/include/bb_archive.h b/include/bb_archive.h
index 4987de6cf..bd08115da 100644
--- a/include/bb_archive.h
+++ b/include/bb_archive.h
@@ -156,12 +156,6 @@ struct BUG_tar_header {
156 156
157 157
158 158
159/* Info struct unpackers can fill out to inform users of thing like
160 * timestamps of unpacked files */
161typedef struct unpack_info_t {
162 time_t mtime;
163} unpack_info_t;
164
165archive_handle_t *init_handle(void) FAST_FUNC; 159archive_handle_t *init_handle(void) FAST_FUNC;
166 160
167char filter_accept_all(archive_handle_t *archive_handle) FAST_FUNC; 161char filter_accept_all(archive_handle_t *archive_handle) FAST_FUNC;
@@ -204,40 +198,46 @@ int start_bunzip(bunzip_data **bdp, int in_fd, const void *inbuf, int len) FAST_
204int read_bunzip(bunzip_data *bd, char *outbuf, int len) FAST_FUNC; 198int read_bunzip(bunzip_data *bd, char *outbuf, int len) FAST_FUNC;
205void dealloc_bunzip(bunzip_data *bd) FAST_FUNC; 199void dealloc_bunzip(bunzip_data *bd) FAST_FUNC;
206 200
207typedef struct inflate_unzip_result { 201/* Meaning and direction (input/output) of the fields are transformer-specific */
208 off_t bytes_out; 202typedef struct transformer_aux_data_t {
209 uint32_t crc; 203 smallint check_signature; /* most often referenced member */
210} inflate_unzip_result; 204 off_t bytes_out;
211 205 off_t bytes_in; /* used in unzip code only: needs to know packed size */
212IF_DESKTOP(long long) int inflate_unzip(inflate_unzip_result *res, off_t compr_size, int src_fd, int dst_fd) FAST_FUNC; 206 uint32_t crc32;
213/* xz unpacker takes .xz stream from offset 6 */ 207 time_t mtime; /* gunzip code may set this on exit */
214IF_DESKTOP(long long) int unpack_xz_stream(int src_fd, int dst_fd) FAST_FUNC; 208} transformer_aux_data_t;
215/* lzma unpacker takes .lzma stream from offset 0 */ 209
216IF_DESKTOP(long long) int unpack_lzma_stream(int src_fd, int dst_fd) FAST_FUNC; 210void init_transformer_aux_data(transformer_aux_data_t *aux) FAST_FUNC;
217/* the rest wants 2 first bytes already skipped by the caller */ 211int FAST_FUNC check_signature16(transformer_aux_data_t *aux, int src_fd, unsigned magic16) FAST_FUNC;
218IF_DESKTOP(long long) int unpack_bz2_stream(int src_fd, int dst_fd) FAST_FUNC; 212
219IF_DESKTOP(long long) int unpack_gz_stream(int src_fd, int dst_fd) FAST_FUNC; 213IF_DESKTOP(long long) int inflate_unzip(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC;
220IF_DESKTOP(long long) int unpack_gz_stream_with_info(int src_fd, int dst_fd, unpack_info_t *info) FAST_FUNC; 214IF_DESKTOP(long long) int unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC;
221IF_DESKTOP(long long) int unpack_Z_stream(int src_fd, int dst_fd) FAST_FUNC; 215IF_DESKTOP(long long) int unpack_gz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC;
222/* wrapper which checks first two bytes to be "BZ" */ 216IF_DESKTOP(long long) int unpack_bz2_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC;
223IF_DESKTOP(long long) int unpack_bz2_stream_prime(int src_fd, int dst_fd) FAST_FUNC; 217IF_DESKTOP(long long) int unpack_lzma_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC;
218IF_DESKTOP(long long) int unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC;
224 219
225char* append_ext(char *filename, const char *expected_ext) FAST_FUNC; 220char* append_ext(char *filename, const char *expected_ext) FAST_FUNC;
226int bbunpack(char **argv, 221int bbunpack(char **argv,
227 IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(unpack_info_t *info), 222 IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(transformer_aux_data_t *aux),
228 char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext), 223 char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext),
229 const char *expected_ext 224 const char *expected_ext
230) FAST_FUNC; 225) FAST_FUNC;
231 226
232#if BB_MMU 227#if BB_MMU
233void open_transformer(int fd, 228void open_transformer(int fd,
234 IF_DESKTOP(long long) int FAST_FUNC (*transformer)(int src_fd, int dst_fd)) FAST_FUNC; 229 int check_signature,
235#define open_transformer(fd, transformer, transform_prog) open_transformer(fd, transformer) 230 IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd)
231) FAST_FUNC;
232#define open_transformer_with_sig(fd, transformer, transform_prog) open_transformer((fd), 1, (transformer))
233#define open_transformer_with_no_sig(fd, transformer) open_transformer((fd), 0, (transformer))
236#else 234#else
237void open_transformer(int src_fd, const char *transform_prog) FAST_FUNC; 235void open_transformer(int fd, const char *transform_prog) FAST_FUNC;
238#define open_transformer(fd, transformer, transform_prog) open_transformer(fd, transform_prog) 236#define open_transformer_with_sig(fd, transformer, transform_prog) open_transformer((fd), (transform_prog))
237/* open_transformer_with_no_sig() does not exist on NOMMU */
239#endif 238#endif
240 239
240
241POP_SAVED_FUNCTION_VISIBILITY 241POP_SAVED_FUNCTION_VISIBILITY
242 242
243#endif 243#endif
diff --git a/include/libbb.h b/include/libbb.h
index c896e5484..2cc146631 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -721,17 +721,15 @@ extern void *xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p) FAS
721 || ENABLE_FEATURE_SEAMLESS_GZ \ 721 || ENABLE_FEATURE_SEAMLESS_GZ \
722 || ENABLE_FEATURE_SEAMLESS_Z) 722 || ENABLE_FEATURE_SEAMLESS_Z)
723 723
724#if SEAMLESS_COMPRESSION
724/* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */ 725/* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */
725#if ENABLE_FEATURE_SEAMLESS_LZMA \ 726extern int setup_unzip_on_fd(int fd, int fail_if_not_detected) FAST_FUNC;
726 || ENABLE_FEATURE_SEAMLESS_BZ2 \
727 || ENABLE_FEATURE_SEAMLESS_GZ \
728 /* || ENABLE_FEATURE_SEAMLESS_Z */
729extern void setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) FAST_FUNC;
730#else
731# define setup_unzip_on_fd(...) ((void)0)
732#endif
733/* Autodetects .gz etc */ 727/* Autodetects .gz etc */
734extern int open_zipped(const char *fname) FAST_FUNC; 728extern int open_zipped(const char *fname) FAST_FUNC;
729#else
730# define setup_unzip_on_fd(...) (0)
731# define open_zipped(fname) open((fname), O_RDONLY);
732#endif
735extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; 733extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC;
736 734
737extern ssize_t safe_write(int fd, const void *buf, size_t count) FAST_FUNC; 735extern ssize_t safe_write(int fd, const void *buf, size_t count) FAST_FUNC;