aboutsummaryrefslogtreecommitdiff
path: root/archival
diff options
context:
space:
mode:
Diffstat (limited to 'archival')
-rw-r--r--archival/Config.src10
-rw-r--r--archival/ar.c2
-rw-r--r--archival/bbunzip.c76
-rw-r--r--archival/bzip2.c16
-rw-r--r--archival/cpio.c4
-rw-r--r--archival/gzip.c28
-rw-r--r--archival/libarchive/Kbuild.src3
-rw-r--r--archival/libarchive/data_extract_all.c6
-rw-r--r--archival/libarchive/decompress_bunzip2.c6
-rw-r--r--archival/libarchive/decompress_unlzma.c31
-rw-r--r--archival/lzop.c3
-rw-r--r--archival/tar.c35
-rw-r--r--archival/unzip.c489
13 files changed, 394 insertions, 315 deletions
diff --git a/archival/Config.src b/archival/Config.src
index 5e7cfc0a4..0c97f3d7c 100644
--- a/archival/Config.src
+++ b/archival/Config.src
@@ -8,32 +8,22 @@ menu "Archival Utilities"
8config FEATURE_SEAMLESS_XZ 8config FEATURE_SEAMLESS_XZ
9 bool "Make tar, rpm, modprobe etc understand .xz data" 9 bool "Make tar, rpm, modprobe etc understand .xz data"
10 default y 10 default y
11 help
12 Make tar, rpm, modprobe etc understand .xz data.
13 11
14config FEATURE_SEAMLESS_LZMA 12config FEATURE_SEAMLESS_LZMA
15 bool "Make tar, rpm, modprobe etc understand .lzma data" 13 bool "Make tar, rpm, modprobe etc understand .lzma data"
16 default y 14 default y
17 help
18 Make tar, rpm, modprobe etc understand .lzma data.
19 15
20config FEATURE_SEAMLESS_BZ2 16config FEATURE_SEAMLESS_BZ2
21 bool "Make tar, rpm, modprobe etc understand .bz2 data" 17 bool "Make tar, rpm, modprobe etc understand .bz2 data"
22 default y 18 default y
23 help
24 Make tar, rpm, modprobe etc understand .bz2 data.
25 19
26config FEATURE_SEAMLESS_GZ 20config FEATURE_SEAMLESS_GZ
27 bool "Make tar, rpm, modprobe etc understand .gz data" 21 bool "Make tar, rpm, modprobe etc understand .gz data"
28 default y 22 default y
29 help
30 Make tar, rpm, modprobe etc understand .gz data.
31 23
32config FEATURE_SEAMLESS_Z 24config FEATURE_SEAMLESS_Z
33 bool "Make tar, rpm, modprobe etc understand .Z data" 25 bool "Make tar, rpm, modprobe etc understand .Z data"
34 default n # it is ancient 26 default n # it is ancient
35 help
36 Make tar, rpm, modprobe etc understand .Z data.
37 27
38INSERT 28INSERT
39 29
diff --git a/archival/ar.c b/archival/ar.c
index a850868f6..f9f712fde 100644
--- a/archival/ar.c
+++ b/archival/ar.c
@@ -31,7 +31,7 @@
31//config: probably say N here: most compilers come with their own ar utility. 31//config: probably say N here: most compilers come with their own ar utility.
32//config: 32//config:
33//config:config FEATURE_AR_LONG_FILENAMES 33//config:config FEATURE_AR_LONG_FILENAMES
34//config: bool "Support for long filenames (not needed for debs)" 34//config: bool "Support long filenames (not needed for debs)"
35//config: default y 35//config: default y
36//config: depends on AR 36//config: depends on AR
37//config: help 37//config: help
diff --git a/archival/bbunzip.c b/archival/bbunzip.c
index 343aec9bd..311c7333e 100644
--- a/archival/bbunzip.c
+++ b/archival/bbunzip.c
@@ -12,9 +12,9 @@
12//kbuild:lib-$(CONFIG_LZOPCAT) += bbunzip.o 12//kbuild:lib-$(CONFIG_LZOPCAT) += bbunzip.o
13//kbuild:lib-$(CONFIG_UNLZOP) += bbunzip.o 13//kbuild:lib-$(CONFIG_UNLZOP) += bbunzip.o
14/* bzip2_main() too: */ 14/* bzip2_main() too: */
15//kbuild:lib-$(CONFIG_BZIP2) += bbunzip.o 15//kbuild:lib-$(CONFIG_FEATURE_BZIP2_DECOMPRESS) += bbunzip.o
16/* gzip_main() too: */ 16/* gzip_main() too: */
17//kbuild:lib-$(CONFIG_GZIP) += bbunzip.o 17//kbuild:lib-$(CONFIG_FEATURE_GZIP_DECOMPRESS) += bbunzip.o
18 18
19/* Note: must be kept in sync with archival/lzop.c */ 19/* Note: must be kept in sync with archival/lzop.c */
20enum { 20enum {
@@ -25,7 +25,7 @@ enum {
25 OPT_QUIET = 1 << 3, 25 OPT_QUIET = 1 << 3,
26 OPT_DECOMPRESS = 1 << 4, 26 OPT_DECOMPRESS = 1 << 4,
27 OPT_TEST = 1 << 5, 27 OPT_TEST = 1 << 5,
28 SEAMLESS_MAGIC = (1 << 31) * SEAMLESS_COMPRESSION, 28 SEAMLESS_MAGIC = (1 << 31) * ENABLE_ZCAT * SEAMLESS_COMPRESSION,
29}; 29};
30 30
31static 31static
@@ -127,7 +127,7 @@ int FAST_FUNC bbunpack(char **argv,
127 127
128 if (!(option_mask32 & SEAMLESS_MAGIC)) { 128 if (!(option_mask32 & SEAMLESS_MAGIC)) {
129 init_transformer_state(&xstate); 129 init_transformer_state(&xstate);
130 xstate.signature_skipped = 0; 130 /*xstate.signature_skipped = 0; - already is */
131 /*xstate.src_fd = STDIN_FILENO; - already is */ 131 /*xstate.src_fd = STDIN_FILENO; - already is */
132 xstate.dst_fd = STDOUT_FILENO; 132 xstate.dst_fd = STDOUT_FILENO;
133 status = unpacker(&xstate); 133 status = unpacker(&xstate);
@@ -199,7 +199,7 @@ int FAST_FUNC bbunpack(char **argv,
199} 199}
200 200
201#if ENABLE_UNCOMPRESS \ 201#if ENABLE_UNCOMPRESS \
202 || ENABLE_BUNZIP2 || ENABLE_BZCAT \ 202 || ENABLE_FEATURE_BZIP2_DECOMPRESS \
203 || ENABLE_UNLZMA || ENABLE_LZCAT || ENABLE_LZMA \ 203 || ENABLE_UNLZMA || ENABLE_LZCAT || ENABLE_LZMA \
204 || ENABLE_UNXZ || ENABLE_XZCAT || ENABLE_XZ 204 || ENABLE_UNXZ || ENABLE_XZCAT || ENABLE_XZ
205static 205static
@@ -297,6 +297,7 @@ int uncompress_main(int argc UNUSED_PARAM, char **argv)
297//config:config GUNZIP 297//config:config GUNZIP
298//config: bool "gunzip" 298//config: bool "gunzip"
299//config: default y 299//config: default y
300//config: select FEATURE_GZIP_DECOMPRESS
300//config: help 301//config: help
301//config: gunzip is used to decompress archives created by gzip. 302//config: gunzip is used to decompress archives created by gzip.
302//config: You can use the `-t' option to test the integrity of 303//config: You can use the `-t' option to test the integrity of
@@ -305,6 +306,7 @@ int uncompress_main(int argc UNUSED_PARAM, char **argv)
305//config:config ZCAT 306//config:config ZCAT
306//config: bool "zcat" 307//config: bool "zcat"
307//config: default y 308//config: default y
309//config: select FEATURE_GZIP_DECOMPRESS
308//config: help 310//config: help
309//config: Alias to "gunzip -c". 311//config: Alias to "gunzip -c".
310//config: 312//config:
@@ -312,14 +314,11 @@ int uncompress_main(int argc UNUSED_PARAM, char **argv)
312//config: bool "Enable long options" 314//config: bool "Enable long options"
313//config: default y 315//config: default y
314//config: depends on (GUNZIP || ZCAT) && LONG_OPTS 316//config: depends on (GUNZIP || ZCAT) && LONG_OPTS
315//config: help
316//config: Enable use of long options.
317 317
318//applet:IF_GUNZIP(APPLET(gunzip, BB_DIR_BIN, BB_SUID_DROP)) 318//applet:IF_GUNZIP(APPLET(gunzip, BB_DIR_BIN, BB_SUID_DROP))
319// APPLET_ODDNAME:name main location suid_type help
319//applet:IF_ZCAT(APPLET_ODDNAME(zcat, gunzip, BB_DIR_BIN, BB_SUID_DROP, zcat)) 320//applet:IF_ZCAT(APPLET_ODDNAME(zcat, gunzip, BB_DIR_BIN, BB_SUID_DROP, zcat))
320//kbuild:lib-$(CONFIG_GUNZIP) += bbunzip.o 321#if ENABLE_FEATURE_GZIP_DECOMPRESS
321//kbuild:lib-$(CONFIG_ZCAT) += bbunzip.o
322#if ENABLE_GUNZIP || ENABLE_ZCAT
323static 322static
324char* FAST_FUNC make_new_name_gunzip(char *filename, const char *expected_ext UNUSED_PARAM) 323char* FAST_FUNC make_new_name_gunzip(char *filename, const char *expected_ext UNUSED_PARAM)
325{ 324{
@@ -387,7 +386,7 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv)
387 386
388 return bbunpack(argv, unpack_gz_stream, make_new_name_gunzip, /*unused:*/ NULL); 387 return bbunpack(argv, unpack_gz_stream, make_new_name_gunzip, /*unused:*/ NULL);
389} 388}
390#endif 389#endif /* FEATURE_GZIP_DECOMPRESS */
391 390
392 391
393/* 392/*
@@ -410,6 +409,7 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv)
410//config:config BUNZIP2 409//config:config BUNZIP2
411//config: bool "bunzip2" 410//config: bool "bunzip2"
412//config: default y 411//config: default y
412//config: select FEATURE_BZIP2_DECOMPRESS
413//config: help 413//config: help
414//config: bunzip2 is a compression utility using the Burrows-Wheeler block 414//config: bunzip2 is a compression utility using the Burrows-Wheeler block
415//config: sorting text compression algorithm, and Huffman coding. Compression 415//config: sorting text compression algorithm, and Huffman coding. Compression
@@ -423,14 +423,14 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv)
423//config:config BZCAT 423//config:config BZCAT
424//config: bool "bzcat" 424//config: bool "bzcat"
425//config: default y 425//config: default y
426//config: select FEATURE_BZIP2_DECOMPRESS
426//config: help 427//config: help
427//config: Alias to "bunzip2 -c". 428//config: Alias to "bunzip2 -c".
428 429
429//applet:IF_BUNZIP2(APPLET(bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP)) 430//applet:IF_BUNZIP2(APPLET(bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP))
431// APPLET_ODDNAME:name main location suid_type help
430//applet:IF_BZCAT(APPLET_ODDNAME(bzcat, bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP, bzcat)) 432//applet:IF_BZCAT(APPLET_ODDNAME(bzcat, bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP, bzcat))
431//kbuild:lib-$(CONFIG_BUNZIP2) += bbunzip.o 433#if ENABLE_FEATURE_BZIP2_DECOMPRESS
432//kbuild:lib-$(CONFIG_BZCAT) += bbunzip.o
433#if ENABLE_BUNZIP2 || ENABLE_BZCAT
434int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 434int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
435int bunzip2_main(int argc UNUSED_PARAM, char **argv) 435int bunzip2_main(int argc UNUSED_PARAM, char **argv)
436{ 436{
@@ -471,26 +471,6 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv)
471//usage: "[FILE]..." 471//usage: "[FILE]..."
472//usage:#define lzcat_full_usage "\n\n" 472//usage:#define lzcat_full_usage "\n\n"
473//usage: "Decompress to stdout" 473//usage: "Decompress to stdout"
474//usage:
475//usage:#define unxz_trivial_usage
476//usage: "[-cf] [FILE]..."
477//usage:#define unxz_full_usage "\n\n"
478//usage: "Decompress FILE (or stdin)\n"
479//usage: "\n -c Write to stdout"
480//usage: "\n -f Force"
481//usage:
482//usage:#define xz_trivial_usage
483//usage: "-d [-cf] [FILE]..."
484//usage:#define xz_full_usage "\n\n"
485//usage: "Decompress FILE (or stdin)\n"
486//usage: "\n -d Decompress"
487//usage: "\n -c Write to stdout"
488//usage: "\n -f Force"
489//usage:
490//usage:#define xzcat_trivial_usage
491//usage: "[FILE]..."
492//usage:#define xzcat_full_usage "\n\n"
493//usage: "Decompress to stdout"
494 474
495//config:config UNLZMA 475//config:config UNLZMA
496//config: bool "unlzma" 476//config: bool "unlzma"
@@ -524,7 +504,7 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv)
524//config: IOW: you'll get lzma applet, but it will always require -d option. 504//config: IOW: you'll get lzma applet, but it will always require -d option.
525//config: 505//config:
526//config:config FEATURE_LZMA_FAST 506//config:config FEATURE_LZMA_FAST
527//config: bool "Optimize unlzma for speed" 507//config: bool "Optimize for speed"
528//config: default n 508//config: default n
529//config: depends on UNLZMA || LZCAT || LZMA 509//config: depends on UNLZMA || LZCAT || LZMA
530//config: help 510//config: help
@@ -532,8 +512,9 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv)
532//config: a 1K bigger binary. 512//config: a 1K bigger binary.
533 513
534//applet:IF_UNLZMA(APPLET(unlzma, BB_DIR_USR_BIN, BB_SUID_DROP)) 514//applet:IF_UNLZMA(APPLET(unlzma, BB_DIR_USR_BIN, BB_SUID_DROP))
515// APPLET_ODDNAME:name main location suid_type help
535//applet:IF_LZCAT(APPLET_ODDNAME(lzcat, unlzma, BB_DIR_USR_BIN, BB_SUID_DROP, lzcat)) 516//applet:IF_LZCAT(APPLET_ODDNAME(lzcat, unlzma, BB_DIR_USR_BIN, BB_SUID_DROP, lzcat))
536//applet:IF_LZMA(APPLET_ODDNAME(lzma, unlzma, BB_DIR_USR_BIN, BB_SUID_DROP, lzma)) 517//applet:IF_LZMA( APPLET_ODDNAME(lzma, unlzma, BB_DIR_USR_BIN, BB_SUID_DROP, lzma))
537//kbuild:lib-$(CONFIG_UNLZMA) += bbunzip.o 518//kbuild:lib-$(CONFIG_UNLZMA) += bbunzip.o
538//kbuild:lib-$(CONFIG_LZCAT) += bbunzip.o 519//kbuild:lib-$(CONFIG_LZCAT) += bbunzip.o
539//kbuild:lib-$(CONFIG_LZMA) += bbunzip.o 520//kbuild:lib-$(CONFIG_LZMA) += bbunzip.o
@@ -557,6 +538,26 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv)
557#endif 538#endif
558 539
559 540
541//usage:#define unxz_trivial_usage
542//usage: "[-cf] [FILE]..."
543//usage:#define unxz_full_usage "\n\n"
544//usage: "Decompress FILE (or stdin)\n"
545//usage: "\n -c Write to stdout"
546//usage: "\n -f Force"
547//usage:
548//usage:#define xz_trivial_usage
549//usage: "-d [-cf] [FILE]..."
550//usage:#define xz_full_usage "\n\n"
551//usage: "Decompress FILE (or stdin)\n"
552//usage: "\n -d Decompress"
553//usage: "\n -c Write to stdout"
554//usage: "\n -f Force"
555//usage:
556//usage:#define xzcat_trivial_usage
557//usage: "[FILE]..."
558//usage:#define xzcat_full_usage "\n\n"
559//usage: "Decompress to stdout"
560
560//config:config UNXZ 561//config:config UNXZ
561//config: bool "unxz" 562//config: bool "unxz"
562//config: default y 563//config: default y
@@ -577,8 +578,9 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv)
577//config: IOW: you'll get xz applet, but it will always require -d option. 578//config: IOW: you'll get xz applet, but it will always require -d option.
578 579
579//applet:IF_UNXZ(APPLET(unxz, BB_DIR_USR_BIN, BB_SUID_DROP)) 580//applet:IF_UNXZ(APPLET(unxz, BB_DIR_USR_BIN, BB_SUID_DROP))
581// APPLET_ODDNAME:name main location suid_type help
580//applet:IF_XZCAT(APPLET_ODDNAME(xzcat, unxz, BB_DIR_USR_BIN, BB_SUID_DROP, xzcat)) 582//applet:IF_XZCAT(APPLET_ODDNAME(xzcat, unxz, BB_DIR_USR_BIN, BB_SUID_DROP, xzcat))
581//applet:IF_XZ(APPLET_ODDNAME(xz, unxz, BB_DIR_USR_BIN, BB_SUID_DROP, xz)) 583//applet:IF_XZ( APPLET_ODDNAME(xz, unxz, BB_DIR_USR_BIN, BB_SUID_DROP, xz))
582//kbuild:lib-$(CONFIG_UNXZ) += bbunzip.o 584//kbuild:lib-$(CONFIG_UNXZ) += bbunzip.o
583//kbuild:lib-$(CONFIG_XZCAT) += bbunzip.o 585//kbuild:lib-$(CONFIG_XZCAT) += bbunzip.o
584//kbuild:lib-$(CONFIG_XZ) += bbunzip.o 586//kbuild:lib-$(CONFIG_XZ) += bbunzip.o
diff --git a/archival/bzip2.c b/archival/bzip2.c
index 47fa29af3..7e38e78b3 100644
--- a/archival/bzip2.c
+++ b/archival/bzip2.c
@@ -19,6 +19,15 @@
19//config: 19//config:
20//config: Unless you have a specific application which requires bzip2, you 20//config: Unless you have a specific application which requires bzip2, you
21//config: should probably say N here. 21//config: should probably say N here.
22//config:
23//config:config FEATURE_BZIP2_DECOMPRESS
24//config: bool "Enable decompression"
25//config: default y
26//config: depends on BZIP2 || BUNZIP2 || BZCAT
27//config: help
28//config: Enable -d (--decompress) and -t (--test) options for bzip2.
29//config: This will be automatically selected if bunzip2 or bzcat is
30//config: enabled.
22 31
23//applet:IF_BZIP2(APPLET(bzip2, BB_DIR_USR_BIN, BB_SUID_DROP)) 32//applet:IF_BZIP2(APPLET(bzip2, BB_DIR_USR_BIN, BB_SUID_DROP))
24//kbuild:lib-$(CONFIG_BZIP2) += bzip2.o 33//kbuild:lib-$(CONFIG_BZIP2) += bzip2.o
@@ -28,7 +37,10 @@
28//usage:#define bzip2_full_usage "\n\n" 37//usage:#define bzip2_full_usage "\n\n"
29//usage: "Compress FILEs (or stdin) with bzip2 algorithm\n" 38//usage: "Compress FILEs (or stdin) with bzip2 algorithm\n"
30//usage: "\n -1..9 Compression level" 39//usage: "\n -1..9 Compression level"
40//usage: IF_FEATURE_BZIP2_DECOMPRESS(
31//usage: "\n -d Decompress" 41//usage: "\n -d Decompress"
42//usage: "\n -t Test file integrity"
43//usage: )
32//usage: "\n -c Write to stdout" 44//usage: "\n -c Write to stdout"
33//usage: "\n -f Force" 45//usage: "\n -f Force"
34 46
@@ -184,8 +196,8 @@ int bzip2_main(int argc UNUSED_PARAM, char **argv)
184 196
185 opt_complementary = "s2"; /* -s means -2 (compatibility) */ 197 opt_complementary = "s2"; /* -s means -2 (compatibility) */
186 /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */ 198 /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */
187 opt = getopt32(argv, "cfv" IF_BUNZIP2("dt") "123456789qzs"); 199 opt = getopt32(argv, "cfv" IF_FEATURE_BZIP2_DECOMPRESS("dt") "123456789qzs");
188#if ENABLE_BUNZIP2 /* bunzip2_main may not be visible... */ 200#if ENABLE_FEATURE_BZIP2_DECOMPRESS /* bunzip2_main may not be visible... */
189 if (opt & 0x18) // -d and/or -t 201 if (opt & 0x18) // -d and/or -t
190 return bunzip2_main(argc, argv); 202 return bunzip2_main(argc, argv);
191 opt >>= 5; 203 opt >>= 5;
diff --git a/archival/cpio.c b/archival/cpio.c
index 540218cb2..683f0bb1f 100644
--- a/archival/cpio.c
+++ b/archival/cpio.c
@@ -29,7 +29,7 @@
29//config: should probably say N here. 29//config: should probably say N here.
30//config: 30//config:
31//config:config FEATURE_CPIO_O 31//config:config FEATURE_CPIO_O
32//config: bool "Support for archive creation" 32//config: bool "Support archive creation"
33//config: default y 33//config: default y
34//config: depends on CPIO 34//config: depends on CPIO
35//config: help 35//config: help
@@ -37,7 +37,7 @@
37//config: format only. 37//config: format only.
38//config: 38//config:
39//config:config FEATURE_CPIO_P 39//config:config FEATURE_CPIO_P
40//config: bool "Support for passthrough mode" 40//config: bool "Support passthrough mode"
41//config: default y 41//config: default y
42//config: depends on FEATURE_CPIO_O 42//config: depends on FEATURE_CPIO_O
43//config: help 43//config: help
diff --git a/archival/gzip.c b/archival/gzip.c
index 9e0bee815..e698c26cd 100644
--- a/archival/gzip.c
+++ b/archival/gzip.c
@@ -48,11 +48,9 @@ aa: 85.1% -- replaced with aa.gz
48//config: bool "Enable long options" 48//config: bool "Enable long options"
49//config: default y 49//config: default y
50//config: depends on GZIP && LONG_OPTS 50//config: depends on GZIP && LONG_OPTS
51//config: help
52//config: Enable use of long options, increases size by about 106 Bytes
53//config: 51//config:
54//config:config GZIP_FAST 52//config:config GZIP_FAST
55//config: int "Trade memory for gzip speed (0:small,slow - 2:fast,big)" 53//config: int "Trade memory for speed (0:small,slow - 2:fast,big)"
56//config: default 0 54//config: default 0
57//config: range 0 2 55//config: range 0 2
58//config: depends on GZIP 56//config: depends on GZIP
@@ -72,19 +70,29 @@ aa: 85.1% -- replaced with aa.gz
72//config: is 6. If levels 1-3 are specified, 4 is used. 70//config: is 6. If levels 1-3 are specified, 4 is used.
73//config: If this option is not selected, -N options are ignored and -9 71//config: If this option is not selected, -N options are ignored and -9
74//config: is used. 72//config: is used.
73//config:
74//config:config FEATURE_GZIP_DECOMPRESS
75//config: bool "Enable decompression"
76//config: default y
77//config: depends on GZIP || GUNZIP || ZCAT
78//config: help
79//config: Enable -d (--decompress) and -t (--test) options for gzip.
80//config: This will be automatically selected if gunzip or zcat is
81//config: enabled.
75 82
76//applet:IF_GZIP(APPLET(gzip, BB_DIR_BIN, BB_SUID_DROP)) 83//applet:IF_GZIP(APPLET(gzip, BB_DIR_BIN, BB_SUID_DROP))
77//kbuild:lib-$(CONFIG_GZIP) += gzip.o 84//kbuild:lib-$(CONFIG_GZIP) += gzip.o
78 85
79//usage:#define gzip_trivial_usage 86//usage:#define gzip_trivial_usage
80//usage: "[-cf" IF_GUNZIP("d") IF_FEATURE_GZIP_LEVELS("123456789") "] [FILE]..." 87//usage: "[-cf" IF_FEATURE_GZIP_DECOMPRESS("dt") IF_FEATURE_GZIP_LEVELS("123456789") "] [FILE]..."
81//usage:#define gzip_full_usage "\n\n" 88//usage:#define gzip_full_usage "\n\n"
82//usage: "Compress FILEs (or stdin)\n" 89//usage: "Compress FILEs (or stdin)\n"
83//usage: IF_FEATURE_GZIP_LEVELS( 90//usage: IF_FEATURE_GZIP_LEVELS(
84//usage: "\n -1..9 Compression level" 91//usage: "\n -1..9 Compression level"
85//usage: ) 92//usage: )
86//usage: IF_GUNZIP( 93//usage: IF_FEATURE_GZIP_DECOMPRESS(
87//usage: "\n -d Decompress" 94//usage: "\n -d Decompress"
95//usage: "\n -t Test file integrity"
88//usage: ) 96//usage: )
89//usage: "\n -c Write to stdout" 97//usage: "\n -c Write to stdout"
90//usage: "\n -f Force" 98//usage: "\n -f Force"
@@ -2154,7 +2162,7 @@ static const char gzip_longopts[] ALIGN1 =
2154 "to-stdout\0" No_argument "c" 2162 "to-stdout\0" No_argument "c"
2155 "force\0" No_argument "f" 2163 "force\0" No_argument "f"
2156 "verbose\0" No_argument "v" 2164 "verbose\0" No_argument "v"
2157#if ENABLE_GUNZIP 2165#if ENABLE_FEATURE_GZIP_DECOMPRESS
2158 "decompress\0" No_argument "d" 2166 "decompress\0" No_argument "d"
2159 "uncompress\0" No_argument "d" 2167 "uncompress\0" No_argument "d"
2160 "test\0" No_argument "t" 2168 "test\0" No_argument "t"
@@ -2181,7 +2189,7 @@ static const char gzip_longopts[] ALIGN1 =
2181 */ 2189 */
2182 2190
2183int gzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 2191int gzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
2184#if ENABLE_GUNZIP 2192#if ENABLE_FEATURE_GZIP_DECOMPRESS
2185int gzip_main(int argc, char **argv) 2193int gzip_main(int argc, char **argv)
2186#else 2194#else
2187int gzip_main(int argc UNUSED_PARAM, char **argv) 2195int gzip_main(int argc UNUSED_PARAM, char **argv)
@@ -2211,13 +2219,13 @@ int gzip_main(int argc UNUSED_PARAM, char **argv)
2211 applet_long_options = gzip_longopts; 2219 applet_long_options = gzip_longopts;
2212#endif 2220#endif
2213 /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */ 2221 /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */
2214 opt = getopt32(argv, "cfv" IF_GUNZIP("dt") "qn123456789"); 2222 opt = getopt32(argv, "cfv" IF_FEATURE_GZIP_DECOMPRESS("dt") "qn123456789");
2215#if ENABLE_GUNZIP /* gunzip_main may not be visible... */ 2223#if ENABLE_FEATURE_GZIP_DECOMPRESS /* gunzip_main may not be visible... */
2216 if (opt & 0x18) // -d and/or -t 2224 if (opt & 0x18) // -d and/or -t
2217 return gunzip_main(argc, argv); 2225 return gunzip_main(argc, argv);
2218#endif 2226#endif
2219#ifdef ENABLE_FEATURE_GZIP_LEVELS 2227#ifdef ENABLE_FEATURE_GZIP_LEVELS
2220 opt >>= ENABLE_GUNZIP ? 7 : 5; /* drop cfv[dt]qn bits */ 2228 opt >>= ENABLE_FEATURE_GZIP_DECOMPRESS ? 7 : 5; /* drop cfv[dt]qn bits */
2221 if (opt == 0) 2229 if (opt == 0)
2222 opt = 1 << 6; /* default: 6 */ 2230 opt = 1 << 6; /* default: 6 */
2223 opt = ffs(opt >> 4); /* Maps -1..-4 to [0], -5 to [1] ... -9 to [5] */ 2231 opt = ffs(opt >> 4); /* Maps -1..-4 to [0], -5 to [1] ... -9 to [5] */
diff --git a/archival/libarchive/Kbuild.src b/archival/libarchive/Kbuild.src
index ad5c5c42d..eaf67451f 100644
--- a/archival/libarchive/Kbuild.src
+++ b/archival/libarchive/Kbuild.src
@@ -53,12 +53,15 @@ lib-$(CONFIG_LZOPCAT) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o
53lib-$(CONFIG_LZOP_COMPR_HIGH) += lzo1x_9x.o 53lib-$(CONFIG_LZOP_COMPR_HIGH) += lzo1x_9x.o
54lib-$(CONFIG_BUNZIP2) += open_transformer.o decompress_bunzip2.o 54lib-$(CONFIG_BUNZIP2) += open_transformer.o decompress_bunzip2.o
55lib-$(CONFIG_BZCAT) += open_transformer.o decompress_bunzip2.o 55lib-$(CONFIG_BZCAT) += open_transformer.o decompress_bunzip2.o
56lib-$(CONFIG_FEATURE_UNZIP_BZIP2) += open_transformer.o decompress_bunzip2.o
56lib-$(CONFIG_UNLZMA) += open_transformer.o decompress_unlzma.o 57lib-$(CONFIG_UNLZMA) += open_transformer.o decompress_unlzma.o
57lib-$(CONFIG_LZCAT) += open_transformer.o decompress_unlzma.o 58lib-$(CONFIG_LZCAT) += open_transformer.o decompress_unlzma.o
58lib-$(CONFIG_LZMA) += open_transformer.o decompress_unlzma.o 59lib-$(CONFIG_LZMA) += open_transformer.o decompress_unlzma.o
60lib-$(CONFIG_FEATURE_UNZIP_LZMA) += open_transformer.o decompress_unlzma.o
59lib-$(CONFIG_UNXZ) += open_transformer.o decompress_unxz.o 61lib-$(CONFIG_UNXZ) += open_transformer.o decompress_unxz.o
60lib-$(CONFIG_XZCAT) += open_transformer.o decompress_unxz.o 62lib-$(CONFIG_XZCAT) += open_transformer.o decompress_unxz.o
61lib-$(CONFIG_XZ) += open_transformer.o decompress_unxz.o 63lib-$(CONFIG_XZ) += open_transformer.o decompress_unxz.o
64lib-$(CONFIG_FEATURE_UNZIP_XZ) += open_transformer.o decompress_unxz.o
62lib-$(CONFIG_GUNZIP) += open_transformer.o decompress_gunzip.o 65lib-$(CONFIG_GUNZIP) += open_transformer.o decompress_gunzip.o
63lib-$(CONFIG_ZCAT) += open_transformer.o decompress_gunzip.o 66lib-$(CONFIG_ZCAT) += open_transformer.o decompress_gunzip.o
64lib-$(CONFIG_UNCOMPRESS) += open_transformer.o decompress_uncompress.o 67lib-$(CONFIG_UNCOMPRESS) += open_transformer.o decompress_uncompress.o
diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c
index bd034afdc..1830ffb8d 100644
--- a/archival/libarchive/data_extract_all.c
+++ b/archival/libarchive/data_extract_all.c
@@ -127,8 +127,9 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
127 if (hard_link) { 127 if (hard_link) {
128 res = link(hard_link, dst_name); 128 res = link(hard_link, dst_name);
129 if (res != 0 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { 129 if (res != 0 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) {
130 /* shared message */
130 bb_perror_msg("can't create %slink " 131 bb_perror_msg("can't create %slink "
131 "from %s to %s", "hard", 132 "%s to %s", "hard",
132 dst_name, 133 dst_name,
133 hard_link); 134 hard_link);
134 } 135 }
@@ -181,8 +182,9 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
181 if (res != 0 182 if (res != 0
182 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) 183 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
183 ) { 184 ) {
185 /* shared message */
184 bb_perror_msg("can't create %slink " 186 bb_perror_msg("can't create %slink "
185 "from %s to %s", "sym", 187 "%s to %s", "sym",
186 dst_name, 188 dst_name,
187 file_header->link_target); 189 file_header->link_target);
188 } 190 }
diff --git a/archival/libarchive/decompress_bunzip2.c b/archival/libarchive/decompress_bunzip2.c
index fe5953da2..4fb989c29 100644
--- a/archival/libarchive/decompress_bunzip2.c
+++ b/archival/libarchive/decompress_bunzip2.c
@@ -134,7 +134,7 @@ static unsigned get_bits(bunzip_data *bd, int bits_wanted)
134 134
135 /* Avoid 32-bit overflow (dump bit buffer to top of output) */ 135 /* Avoid 32-bit overflow (dump bit buffer to top of output) */
136 if (bit_count >= 24) { 136 if (bit_count >= 24) {
137 bits = bd->inbufBits & ((1 << bit_count) - 1); 137 bits = bd->inbufBits & ((1U << bit_count) - 1);
138 bits_wanted -= bit_count; 138 bits_wanted -= bit_count;
139 bits <<= bits_wanted; 139 bits <<= bits_wanted;
140 bit_count = 0; 140 bit_count = 0;
@@ -158,11 +158,11 @@ static int get_next_block(bunzip_data *bd)
158{ 158{
159 struct group_data *hufGroup; 159 struct group_data *hufGroup;
160 int dbufCount, dbufSize, groupCount, *base, *limit, selector, 160 int dbufCount, dbufSize, groupCount, *base, *limit, selector,
161 i, j, t, runPos, symCount, symTotal, nSelectors, byteCount[256]; 161 i, j, runPos, symCount, symTotal, nSelectors, byteCount[256];
162 int runCnt = runCnt; /* for compiler */ 162 int runCnt = runCnt; /* for compiler */
163 uint8_t uc, symToByte[256], mtfSymbol[256], *selectors; 163 uint8_t uc, symToByte[256], mtfSymbol[256], *selectors;
164 uint32_t *dbuf; 164 uint32_t *dbuf;
165 unsigned origPtr; 165 unsigned origPtr, t;
166 166
167 dbuf = bd->dbuf; 167 dbuf = bd->dbuf;
168 dbufSize = bd->dbufSize; 168 dbufSize = bd->dbufSize;
diff --git a/archival/libarchive/decompress_unlzma.c b/archival/libarchive/decompress_unlzma.c
index c8622f97b..a9040877e 100644
--- a/archival/libarchive/decompress_unlzma.c
+++ b/archival/libarchive/decompress_unlzma.c
@@ -278,9 +278,10 @@ unpack_lzma_stream(transformer_state_t *xstate)
278 278
279 if (state >= LZMA_NUM_LIT_STATES) { 279 if (state >= LZMA_NUM_LIT_STATES) {
280 int match_byte; 280 int match_byte;
281 uint32_t pos = buffer_pos - rep0; 281 uint32_t pos;
282 282
283 while (pos >= header.dict_size) 283 pos = buffer_pos - rep0;
284 if ((int32_t)pos < 0)
284 pos += header.dict_size; 285 pos += header.dict_size;
285 match_byte = buffer[pos]; 286 match_byte = buffer[pos];
286 do { 287 do {
@@ -336,9 +337,11 @@ unpack_lzma_stream(transformer_state_t *xstate)
336 ); 337 );
337 if (!rc_is_bit_1(rc, prob2)) { 338 if (!rc_is_bit_1(rc, prob2)) {
338#if ENABLE_FEATURE_LZMA_FAST 339#if ENABLE_FEATURE_LZMA_FAST
339 uint32_t pos = buffer_pos - rep0; 340 uint32_t pos;
340 state = state < LZMA_NUM_LIT_STATES ? 9 : 11; 341 state = state < LZMA_NUM_LIT_STATES ? 9 : 11;
341 while (pos >= header.dict_size) 342
343 pos = buffer_pos - rep0;
344 if ((int32_t)pos < 0)
342 pos += header.dict_size; 345 pos += header.dict_size;
343 previous_byte = buffer[pos]; 346 previous_byte = buffer[pos];
344 goto one_byte1; 347 goto one_byte1;
@@ -429,10 +432,25 @@ unpack_lzma_stream(transformer_state_t *xstate)
429 } 432 }
430 433
431 len += LZMA_MATCH_MIN_LEN; 434 len += LZMA_MATCH_MIN_LEN;
435 /*
436 * LZMA SDK has this optimized:
437 * it precalculates size and copies many bytes
438 * in a loop with simpler checks, a-la:
439 * do
440 * *(dest) = *(dest + ofs);
441 * while (++dest != lim);
442 * and
443 * do {
444 * buffer[buffer_pos++] = buffer[pos];
445 * if (++pos == header.dict_size)
446 * pos = 0;
447 * } while (--cur_len != 0);
448 * Our code is slower (more checks per byte copy):
449 */
432 IF_NOT_FEATURE_LZMA_FAST(string:) 450 IF_NOT_FEATURE_LZMA_FAST(string:)
433 do { 451 do {
434 uint32_t pos = buffer_pos - rep0; 452 uint32_t pos = buffer_pos - rep0;
435 while (pos >= header.dict_size) 453 if ((int32_t)pos < 0)
436 pos += header.dict_size; 454 pos += header.dict_size;
437 previous_byte = buffer[pos]; 455 previous_byte = buffer[pos];
438 IF_NOT_FEATURE_LZMA_FAST(one_byte2:) 456 IF_NOT_FEATURE_LZMA_FAST(one_byte2:)
@@ -448,6 +466,9 @@ unpack_lzma_stream(transformer_state_t *xstate)
448 } while (len != 0 && buffer_pos < header.dst_size); 466 } while (len != 0 && buffer_pos < header.dst_size);
449 /* FIXME: ...........^^^^^ 467 /* FIXME: ...........^^^^^
450 * shouldn't it be "global_pos + buffer_pos < header.dst_size"? 468 * shouldn't it be "global_pos + buffer_pos < header.dst_size"?
469 * It probably should, but it is a "do we accidentally
470 * unpack more bytes than expected?" check - which
471 * never happens for well-formed compression data...
451 */ 472 */
452 } 473 }
453 } 474 }
diff --git a/archival/lzop.c b/archival/lzop.c
index e0e90ac6c..ca61add3c 100644
--- a/archival/lzop.c
+++ b/archival/lzop.c
@@ -53,7 +53,8 @@
53//config: and take up 3.2K of code. 53//config: and take up 3.2K of code.
54 54
55//applet:IF_LZOP(APPLET(lzop, BB_DIR_BIN, BB_SUID_DROP)) 55//applet:IF_LZOP(APPLET(lzop, BB_DIR_BIN, BB_SUID_DROP))
56//applet:IF_UNLZOP(APPLET_ODDNAME(unlzop, lzop, BB_DIR_USR_BIN, BB_SUID_DROP, unlzop)) 56// APPLET_ODDNAME:name main location suid_type help
57//applet:IF_UNLZOP( APPLET_ODDNAME(unlzop, lzop, BB_DIR_USR_BIN, BB_SUID_DROP, unlzop))
57//applet:IF_LZOPCAT(APPLET_ODDNAME(lzopcat, lzop, BB_DIR_USR_BIN, BB_SUID_DROP, lzopcat)) 58//applet:IF_LZOPCAT(APPLET_ODDNAME(lzopcat, lzop, BB_DIR_USR_BIN, BB_SUID_DROP, lzopcat))
58//kbuild:lib-$(CONFIG_LZOP) += lzop.o 59//kbuild:lib-$(CONFIG_LZOP) += lzop.o
59//kbuild:lib-$(CONFIG_UNLZOP) += lzop.o 60//kbuild:lib-$(CONFIG_UNLZOP) += lzop.o
diff --git a/archival/tar.c b/archival/tar.c
index c87d23597..34e3052ce 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -49,13 +49,15 @@
49//config: create compressed archives. It's probably the most widely used 49//config: create compressed archives. It's probably the most widely used
50//config: UNIX archive program. 50//config: UNIX archive program.
51//config: 51//config:
52//config:config FEATURE_TAR_LONG_OPTIONS
53//config: bool "Enable long options"
54//config: default y
55//config: depends on TAR && LONG_OPTS
56//config:
52//config:config FEATURE_TAR_CREATE 57//config:config FEATURE_TAR_CREATE
53//config: bool "Enable archive creation" 58//config: bool "Enable -c (archive creation)"
54//config: default y 59//config: default y
55//config: depends on TAR 60//config: depends on TAR
56//config: help
57//config: If you enable this option you'll be able to create
58//config: tar archives using the `-c' option.
59//config: 61//config:
60//config:config FEATURE_TAR_AUTODETECT 62//config:config FEATURE_TAR_AUTODETECT
61//config: bool "Autodetect compressed tarballs" 63//config: bool "Autodetect compressed tarballs"
@@ -74,7 +76,7 @@
74//config: a list of files to include or exclude from an archive. 76//config: a list of files to include or exclude from an archive.
75//config: 77//config:
76//config:config FEATURE_TAR_OLDGNU_COMPATIBILITY 78//config:config FEATURE_TAR_OLDGNU_COMPATIBILITY
77//config: bool "Support for old tar header format" 79//config: bool "Support old tar header format"
78//config: default y 80//config: default y
79//config: depends on TAR || DPKG 81//config: depends on TAR || DPKG
80//config: help 82//config: help
@@ -93,22 +95,12 @@
93//config: tarballs still exist. 95//config: tarballs still exist.
94//config: 96//config:
95//config:config FEATURE_TAR_GNU_EXTENSIONS 97//config:config FEATURE_TAR_GNU_EXTENSIONS
96//config: bool "Support for GNU tar extensions (long filenames)" 98//config: bool "Support GNU tar extensions (long filenames)"
97//config: default y 99//config: default y
98//config: depends on TAR || DPKG 100//config: depends on TAR || DPKG
99//config: help
100//config: With this option busybox supports GNU long filenames and
101//config: linknames.
102//config:
103//config:config FEATURE_TAR_LONG_OPTIONS
104//config: bool "Enable long options"
105//config: default y
106//config: depends on TAR && LONG_OPTS
107//config: help
108//config: Enable use of long options, increases size by about 400 Bytes
109//config: 101//config:
110//config:config FEATURE_TAR_TO_COMMAND 102//config:config FEATURE_TAR_TO_COMMAND
111//config: bool "Support for writing to an external program" 103//config: bool "Support writing to an external program (--to-command)"
112//config: default y 104//config: default y
113//config: depends on TAR && FEATURE_TAR_LONG_OPTIONS 105//config: depends on TAR && FEATURE_TAR_LONG_OPTIONS
114//config: help 106//config: help
@@ -121,20 +113,17 @@
121//config: default y 113//config: default y
122//config: depends on TAR 114//config: depends on TAR
123//config: help 115//config: help
124//config: Enables use of user and group names in tar. This affects contents 116//config: Enable use of user and group names in tar. This affects contents
125//config: listings (-t) and preserving permissions when unpacking (-p). 117//config: listings (-t) and preserving permissions when unpacking (-p).
126//config: +200 bytes. 118//config: +200 bytes.
127//config: 119//config:
128//config:config FEATURE_TAR_NOPRESERVE_TIME 120//config:config FEATURE_TAR_NOPRESERVE_TIME
129//config: bool "Enable -m (do not preserve time) option" 121//config: bool "Enable -m (do not preserve time) GNU option"
130//config: default y 122//config: default y
131//config: depends on TAR 123//config: depends on TAR
132//config: help
133//config: With this option busybox supports GNU tar -m
134//config: (do not preserve time) option.
135//config: 124//config:
136//config:config FEATURE_TAR_SELINUX 125//config:config FEATURE_TAR_SELINUX
137//config: bool "Support for extracting SELinux labels" 126//config: bool "Support extracting SELinux labels"
138//config: default n 127//config: default n
139//config: depends on TAR && SELINUX 128//config: depends on TAR && SELINUX
140//config: help 129//config: help
diff --git a/archival/unzip.c b/archival/unzip.c
index 9ad03d0e2..56989fa0b 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -34,6 +34,23 @@
34//config: ZIP files without deleted/updated files, SFX archives etc, 34//config: ZIP files without deleted/updated files, SFX archives etc,
35//config: you can reduce code size by unselecting this option. 35//config: you can reduce code size by unselecting this option.
36//config: To support less trivial ZIPs, say Y. 36//config: To support less trivial ZIPs, say Y.
37//config:
38//config:config FEATURE_UNZIP_BZIP2
39//config: bool "Support compression method 12 (bzip2)"
40//config: default y
41//config: depends on FEATURE_UNZIP_CDF && DESKTOP
42// FEATURE_UNZIP_CDF is needed, otherwise we can't find start of next file
43// DESKTOP is needed to get back uncompressed length
44//config:
45//config:config FEATURE_UNZIP_LZMA
46//config: bool "Support compression method 14 (lzma)"
47//config: default y
48//config: depends on FEATURE_UNZIP_CDF && DESKTOP
49//config:
50//config:config FEATURE_UNZIP_XZ
51//config: bool "Support compression method 95 (xz)"
52//config: default y
53//config: depends on FEATURE_UNZIP_CDF && DESKTOP
37 54
38//applet:IF_UNZIP(APPLET(unzip, BB_DIR_USR_BIN, BB_SUID_DROP)) 55//applet:IF_UNZIP(APPLET(unzip, BB_DIR_USR_BIN, BB_SUID_DROP))
39//kbuild:lib-$(CONFIG_UNZIP) += unzip.o 56//kbuild:lib-$(CONFIG_UNZIP) += unzip.o
@@ -65,8 +82,8 @@
65enum { 82enum {
66#if BB_BIG_ENDIAN 83#if BB_BIG_ENDIAN
67 ZIP_FILEHEADER_MAGIC = 0x504b0304, 84 ZIP_FILEHEADER_MAGIC = 0x504b0304,
68 ZIP_CDF_MAGIC = 0x504b0102, /* central directory's file header */ 85 ZIP_CDF_MAGIC = 0x504b0102, /* CDF item */
69 ZIP_CDE_MAGIC = 0x504b0506, /* "end of central directory" record */ 86 ZIP_CDE_MAGIC = 0x504b0506, /* End of CDF */
70 ZIP_DD_MAGIC = 0x504b0708, 87 ZIP_DD_MAGIC = 0x504b0708,
71#else 88#else
72 ZIP_FILEHEADER_MAGIC = 0x04034b50, 89 ZIP_FILEHEADER_MAGIC = 0x04034b50,
@@ -94,16 +111,16 @@ typedef union {
94 /* filename follows (not NUL terminated) */ 111 /* filename follows (not NUL terminated) */
95 /* extra field follows */ 112 /* extra field follows */
96 /* data follows */ 113 /* data follows */
97 } formatted PACKED; 114 } fmt PACKED;
98} zip_header_t; /* PACKED - gcc 4.2.1 doesn't like it (spews warning) */ 115} zip_header_t; /* PACKED - gcc 4.2.1 doesn't like it (spews warning) */
99 116
100#define FIX_ENDIANNESS_ZIP(zip_header) \ 117#define FIX_ENDIANNESS_ZIP(zip) \
101do { if (BB_BIG_ENDIAN) { \ 118do { if (BB_BIG_ENDIAN) { \
102 (zip_header).formatted.crc32 = SWAP_LE32((zip_header).formatted.crc32 ); \ 119 (zip).fmt.crc32 = SWAP_LE32((zip).fmt.crc32 ); \
103 (zip_header).formatted.cmpsize = SWAP_LE32((zip_header).formatted.cmpsize ); \ 120 (zip).fmt.cmpsize = SWAP_LE32((zip).fmt.cmpsize ); \
104 (zip_header).formatted.ucmpsize = SWAP_LE32((zip_header).formatted.ucmpsize ); \ 121 (zip).fmt.ucmpsize = SWAP_LE32((zip).fmt.ucmpsize ); \
105 (zip_header).formatted.filename_len = SWAP_LE16((zip_header).formatted.filename_len); \ 122 (zip).fmt.filename_len = SWAP_LE16((zip).fmt.filename_len); \
106 (zip_header).formatted.extra_len = SWAP_LE16((zip_header).formatted.extra_len ); \ 123 (zip).fmt.extra_len = SWAP_LE16((zip).fmt.extra_len ); \
107}} while (0) 124}} while (0)
108 125
109#define CDF_HEADER_LEN 42 126#define CDF_HEADER_LEN 42
@@ -121,39 +138,39 @@ typedef union {
121 uint32_t crc32; /* 12-15 */ 138 uint32_t crc32; /* 12-15 */
122 uint32_t cmpsize; /* 16-19 */ 139 uint32_t cmpsize; /* 16-19 */
123 uint32_t ucmpsize; /* 20-23 */ 140 uint32_t ucmpsize; /* 20-23 */
124 uint16_t file_name_length; /* 24-25 */ 141 uint16_t filename_len; /* 24-25 */
125 uint16_t extra_field_length; /* 26-27 */ 142 uint16_t extra_len; /* 26-27 */
126 uint16_t file_comment_length; /* 28-29 */ 143 uint16_t file_comment_length; /* 28-29 */
127 uint16_t disk_number_start; /* 30-31 */ 144 uint16_t disk_number_start; /* 30-31 */
128 uint16_t internal_file_attributes; /* 32-33 */ 145 uint16_t internal_attributes; /* 32-33 */
129 uint32_t external_file_attributes PACKED; /* 34-37 */ 146 uint32_t external_attributes PACKED; /* 34-37 */
130 uint32_t relative_offset_of_local_header PACKED; /* 38-41 */ 147 uint32_t relative_offset_of_local_header PACKED; /* 38-41 */
131 /* filename follows (not NUL terminated) */ 148 /* filename follows (not NUL terminated) */
132 /* extra field follows */ 149 /* extra field follows */
133 /* comment follows */ 150 /* file comment follows */
134 } formatted PACKED; 151 } fmt PACKED;
135} cdf_header_t; 152} cdf_header_t;
136 153
137#define FIX_ENDIANNESS_CDF(cdf_header) \ 154#define FIX_ENDIANNESS_CDF(cdf) \
138do { if (BB_BIG_ENDIAN) { \ 155do { if (BB_BIG_ENDIAN) { \
139 (cdf_header).formatted.version_made_by = SWAP_LE16((cdf_header).formatted.version_made_by); \ 156 (cdf).fmt.version_made_by = SWAP_LE16((cdf).fmt.version_made_by); \
140 (cdf_header).formatted.version_needed = SWAP_LE16((cdf_header).formatted.version_needed); \ 157 (cdf).fmt.version_needed = SWAP_LE16((cdf).fmt.version_needed); \
141 (cdf_header).formatted.method = SWAP_LE16((cdf_header).formatted.method ); \ 158 (cdf).fmt.method = SWAP_LE16((cdf).fmt.method ); \
142 (cdf_header).formatted.modtime = SWAP_LE16((cdf_header).formatted.modtime ); \ 159 (cdf).fmt.modtime = SWAP_LE16((cdf).fmt.modtime ); \
143 (cdf_header).formatted.moddate = SWAP_LE16((cdf_header).formatted.moddate ); \ 160 (cdf).fmt.moddate = SWAP_LE16((cdf).fmt.moddate ); \
144 (cdf_header).formatted.crc32 = SWAP_LE32((cdf_header).formatted.crc32 ); \ 161 (cdf).fmt.crc32 = SWAP_LE32((cdf).fmt.crc32 ); \
145 (cdf_header).formatted.cmpsize = SWAP_LE32((cdf_header).formatted.cmpsize ); \ 162 (cdf).fmt.cmpsize = SWAP_LE32((cdf).fmt.cmpsize ); \
146 (cdf_header).formatted.ucmpsize = SWAP_LE32((cdf_header).formatted.ucmpsize ); \ 163 (cdf).fmt.ucmpsize = SWAP_LE32((cdf).fmt.ucmpsize ); \
147 (cdf_header).formatted.file_name_length = SWAP_LE16((cdf_header).formatted.file_name_length); \ 164 (cdf).fmt.filename_len = SWAP_LE16((cdf).fmt.filename_len); \
148 (cdf_header).formatted.extra_field_length = SWAP_LE16((cdf_header).formatted.extra_field_length); \ 165 (cdf).fmt.extra_len = SWAP_LE16((cdf).fmt.extra_len ); \
149 (cdf_header).formatted.file_comment_length = SWAP_LE16((cdf_header).formatted.file_comment_length); \ 166 (cdf).fmt.file_comment_length = SWAP_LE16((cdf).fmt.file_comment_length); \
150 (cdf_header).formatted.external_file_attributes = SWAP_LE32((cdf_header).formatted.external_file_attributes); \ 167 (cdf).fmt.external_attributes = SWAP_LE32((cdf).fmt.external_attributes); \
151}} while (0) 168}} while (0)
152 169
153#define CDE_HEADER_LEN 16 170#define CDE_LEN 16
154 171
155typedef union { 172typedef union {
156 uint8_t raw[CDE_HEADER_LEN]; 173 uint8_t raw[CDE_LEN];
157 struct { 174 struct {
158 /* uint32_t signature; 50 4b 05 06 */ 175 /* uint32_t signature; 50 4b 05 06 */
159 uint16_t this_disk_no; 176 uint16_t this_disk_no;
@@ -162,14 +179,14 @@ typedef union {
162 uint16_t cdf_entries_total; 179 uint16_t cdf_entries_total;
163 uint32_t cdf_size; 180 uint32_t cdf_size;
164 uint32_t cdf_offset; 181 uint32_t cdf_offset;
165 /* uint16_t file_comment_length; */ 182 /* uint16_t archive_comment_length; */
166 /* .ZIP file comment (variable size) */ 183 /* archive comment follows */
167 } formatted PACKED; 184 } fmt PACKED;
168} cde_header_t; 185} cde_t;
169 186
170#define FIX_ENDIANNESS_CDE(cde_header) \ 187#define FIX_ENDIANNESS_CDE(cde) \
171do { if (BB_BIG_ENDIAN) { \ 188do { if (BB_BIG_ENDIAN) { \
172 (cde_header).formatted.cdf_offset = SWAP_LE32((cde_header).formatted.cdf_offset); \ 189 (cde).fmt.cdf_offset = SWAP_LE32((cde).fmt.cdf_offset); \
173}} while (0) 190}} while (0)
174 191
175struct BUG { 192struct BUG {
@@ -178,13 +195,13 @@ struct BUG {
178 * even though the elements are all in the right place. 195 * even though the elements are all in the right place.
179 */ 196 */
180 char BUG_zip_header_must_be_26_bytes[ 197 char BUG_zip_header_must_be_26_bytes[
181 offsetof(zip_header_t, formatted.extra_len) + 2 198 offsetof(zip_header_t, fmt.extra_len) + 2
182 == ZIP_HEADER_LEN ? 1 : -1]; 199 == ZIP_HEADER_LEN ? 1 : -1];
183 char BUG_cdf_header_must_be_42_bytes[ 200 char BUG_cdf_header_must_be_42_bytes[
184 offsetof(cdf_header_t, formatted.relative_offset_of_local_header) + 4 201 offsetof(cdf_header_t, fmt.relative_offset_of_local_header) + 4
185 == CDF_HEADER_LEN ? 1 : -1]; 202 == CDF_HEADER_LEN ? 1 : -1];
186 char BUG_cde_header_must_be_16_bytes[ 203 char BUG_cde_must_be_16_bytes[
187 sizeof(cde_header_t) == CDE_HEADER_LEN ? 1 : -1]; 204 sizeof(cde_t) == CDE_LEN ? 1 : -1];
188}; 205};
189 206
190 207
@@ -210,7 +227,7 @@ enum { zip_fd = 3 };
210/* NB: does not preserve file position! */ 227/* NB: does not preserve file position! */
211static uint32_t find_cdf_offset(void) 228static uint32_t find_cdf_offset(void)
212{ 229{
213 cde_header_t cde_header; 230 cde_t cde;
214 unsigned char *buf; 231 unsigned char *buf;
215 unsigned char *p; 232 unsigned char *p;
216 off_t end; 233 off_t end;
@@ -231,7 +248,7 @@ static uint32_t find_cdf_offset(void)
231 248
232 found = BAD_CDF_OFFSET; 249 found = BAD_CDF_OFFSET;
233 p = buf; 250 p = buf;
234 while (p <= buf + PEEK_FROM_END - CDE_HEADER_LEN - 4) { 251 while (p <= buf + PEEK_FROM_END - CDE_LEN - 4) {
235 if (*p != 'P') { 252 if (*p != 'P') {
236 p++; 253 p++;
237 continue; 254 continue;
@@ -243,19 +260,19 @@ static uint32_t find_cdf_offset(void)
243 if (*++p != 6) 260 if (*++p != 6)
244 continue; 261 continue;
245 /* we found CDE! */ 262 /* we found CDE! */
246 memcpy(cde_header.raw, p + 1, CDE_HEADER_LEN); 263 memcpy(cde.raw, p + 1, CDE_LEN);
247 FIX_ENDIANNESS_CDE(cde_header); 264 FIX_ENDIANNESS_CDE(cde);
248 /* 265 /*
249 * I've seen .ZIP files with seemingly valid CDEs 266 * I've seen .ZIP files with seemingly valid CDEs
250 * where cdf_offset points past EOF - ?? 267 * where cdf_offset points past EOF - ??
251 * This check ignores such CDEs: 268 * This check ignores such CDEs:
252 */ 269 */
253 if (cde_header.formatted.cdf_offset < end + (p - buf)) { 270 if (cde.fmt.cdf_offset < end + (p - buf)) {
254 found = cde_header.formatted.cdf_offset; 271 found = cde.fmt.cdf_offset;
255 dbg("Possible cdf_offset:0x%x at 0x%"OFF_FMT"x", 272 dbg("Possible cdf_offset:0x%x at 0x%"OFF_FMT"x",
256 (unsigned)found, end + (p-3 - buf)); 273 (unsigned)found, end + (p-3 - buf));
257 dbg(" cdf_offset+cdf_size:0x%x", 274 dbg(" cdf_offset+cdf_size:0x%x",
258 (unsigned)(found + SWAP_LE32(cde_header.formatted.cdf_size))); 275 (unsigned)(found + SWAP_LE32(cde.fmt.cdf_size)));
259 /* 276 /*
260 * We do not "break" here because only the last CDE is valid. 277 * We do not "break" here because only the last CDE is valid.
261 * I've seen a .zip archive which contained a .zip file, 278 * I've seen a .zip archive which contained a .zip file,
@@ -269,7 +286,7 @@ static uint32_t find_cdf_offset(void)
269 return found; 286 return found;
270}; 287};
271 288
272static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr) 289static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf)
273{ 290{
274 uint32_t magic; 291 uint32_t magic;
275 292
@@ -279,23 +296,25 @@ static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr)
279 dbg("Reading CDF at 0x%x", (unsigned)cdf_offset); 296 dbg("Reading CDF at 0x%x", (unsigned)cdf_offset);
280 xlseek(zip_fd, cdf_offset, SEEK_SET); 297 xlseek(zip_fd, cdf_offset, SEEK_SET);
281 xread(zip_fd, &magic, 4); 298 xread(zip_fd, &magic, 4);
282 /* Central Directory End? */ 299 /* Central Directory End? Assume CDF has ended.
300 * (more correct method is to use cde.cdf_entries_total counter)
301 */
283 if (magic == ZIP_CDE_MAGIC) { 302 if (magic == ZIP_CDE_MAGIC) {
284 dbg("got ZIP_CDE_MAGIC"); 303 dbg("got ZIP_CDE_MAGIC");
285 return 0; /* EOF */ 304 return 0; /* EOF */
286 } 305 }
287 xread(zip_fd, cdf_ptr->raw, CDF_HEADER_LEN); 306 xread(zip_fd, cdf->raw, CDF_HEADER_LEN);
288 307
289 FIX_ENDIANNESS_CDF(*cdf_ptr); 308 FIX_ENDIANNESS_CDF(*cdf);
290 dbg(" file_name_length:%u extra_field_length:%u file_comment_length:%u", 309 dbg(" filename_len:%u extra_len:%u file_comment_length:%u",
291 (unsigned)cdf_ptr->formatted.file_name_length, 310 (unsigned)cdf->fmt.filename_len,
292 (unsigned)cdf_ptr->formatted.extra_field_length, 311 (unsigned)cdf->fmt.extra_len,
293 (unsigned)cdf_ptr->formatted.file_comment_length 312 (unsigned)cdf->fmt.file_comment_length
294 ); 313 );
295 cdf_offset += 4 + CDF_HEADER_LEN 314 cdf_offset += 4 + CDF_HEADER_LEN
296 + cdf_ptr->formatted.file_name_length 315 + cdf->fmt.filename_len
297 + cdf_ptr->formatted.extra_field_length 316 + cdf->fmt.extra_len
298 + cdf_ptr->formatted.file_comment_length; 317 + cdf->fmt.file_comment_length;
299 318
300 return cdf_offset; 319 return cdf_offset;
301}; 320};
@@ -318,34 +337,67 @@ static void unzip_create_leading_dirs(const char *fn)
318 free(name); 337 free(name);
319} 338}
320 339
321static void unzip_extract(zip_header_t *zip_header, int dst_fd) 340static void unzip_extract(zip_header_t *zip, int dst_fd)
322{ 341{
323 if (zip_header->formatted.method == 0) { 342 transformer_state_t xstate;
343
344 if (zip->fmt.method == 0) {
324 /* Method 0 - stored (not compressed) */ 345 /* Method 0 - stored (not compressed) */
325 off_t size = zip_header->formatted.ucmpsize; 346 off_t size = zip->fmt.ucmpsize;
326 if (size) 347 if (size)
327 bb_copyfd_exact_size(zip_fd, dst_fd, size); 348 bb_copyfd_exact_size(zip_fd, dst_fd, size);
328 } else { 349 return;
350 }
351
352 init_transformer_state(&xstate);
353 xstate.bytes_in = zip->fmt.cmpsize;
354 xstate.src_fd = zip_fd;
355 xstate.dst_fd = dst_fd;
356 if (zip->fmt.method == 8) {
329 /* Method 8 - inflate */ 357 /* Method 8 - inflate */
330 transformer_state_t xstate;
331 init_transformer_state(&xstate);
332 xstate.bytes_in = zip_header->formatted.cmpsize;
333 xstate.src_fd = zip_fd;
334 xstate.dst_fd = dst_fd;
335 if (inflate_unzip(&xstate) < 0) 358 if (inflate_unzip(&xstate) < 0)
336 bb_error_msg_and_die("inflate error"); 359 bb_error_msg_and_die("inflate error");
337 /* Validate decompression - crc */ 360 /* Validate decompression - crc */
338 if (zip_header->formatted.crc32 != (xstate.crc32 ^ 0xffffffffL)) { 361 if (zip->fmt.crc32 != (xstate.crc32 ^ 0xffffffffL)) {
339 bb_error_msg_and_die("crc error"); 362 bb_error_msg_and_die("crc error");
340 } 363 }
341 /* Validate decompression - size */
342 if (zip_header->formatted.ucmpsize != xstate.bytes_out) {
343 /* Don't die. Who knows, maybe len calculation
344 * was botched somewhere. After all, crc matched! */
345 bb_error_msg("bad length");
346 }
347 } 364 }
348 /* TODO? method 12: bzip2, method 14: LZMA */ 365#if ENABLE_FEATURE_UNZIP_BZIP2
366 else if (zip->fmt.method == 12) {
367 /* Tested. Unpacker reads too much, but we use CDF
368 * and will seek to the correct beginning of next file.
369 */
370 xstate.bytes_out = unpack_bz2_stream(&xstate);
371 if (xstate.bytes_out < 0)
372 bb_error_msg_and_die("inflate error");
373 }
374#endif
375#if ENABLE_FEATURE_UNZIP_LZMA
376 else if (zip->fmt.method == 14) {
377 /* Not tested yet */
378 xstate.bytes_out = unpack_lzma_stream(&xstate);
379 if (xstate.bytes_out < 0)
380 bb_error_msg_and_die("inflate error");
381 }
382#endif
383#if ENABLE_FEATURE_UNZIP_XZ
384 else if (zip->fmt.method == 95) {
385 /* Not tested yet */
386 xstate.bytes_out = unpack_xz_stream(&xstate);
387 if (xstate.bytes_out < 0)
388 bb_error_msg_and_die("inflate error");
389 }
390#endif
391 else {
392 bb_error_msg_and_die("unsupported method %u", zip->fmt.method);
393 }
394
395 /* Validate decompression - size */
396 if (zip->fmt.ucmpsize != xstate.bytes_out) {
397 /* Don't die. Who knows, maybe len calculation
398 * was botched somewhere. After all, crc matched! */
399 bb_error_msg("bad length");
400 }
349} 401}
350 402
351static void my_fgets80(char *buf80) 403static void my_fgets80(char *buf80)
@@ -566,7 +618,7 @@ int unzip_main(int argc, char **argv)
566 total_entries = 0; 618 total_entries = 0;
567 cdf_offset = find_cdf_offset(); /* try to seek to the end, find CDE and CDF start */ 619 cdf_offset = find_cdf_offset(); /* try to seek to the end, find CDE and CDF start */
568 while (1) { 620 while (1) {
569 zip_header_t zip_header; 621 zip_header_t zip;
570 mode_t dir_mode = 0777; 622 mode_t dir_mode = 0777;
571#if ENABLE_FEATURE_UNZIP_CDF 623#if ENABLE_FEATURE_UNZIP_CDF
572 mode_t file_mode = 0666; 624 mode_t file_mode = 0666;
@@ -592,7 +644,7 @@ int unzip_main(int argc, char **argv)
592 644
593 /* Check magic number */ 645 /* Check magic number */
594 xread(zip_fd, &magic, 4); 646 xread(zip_fd, &magic, 4);
595 /* Central directory? It's at the end, so exit */ 647 /* CDF item? Assume there are no more files, exit */
596 if (magic == ZIP_CDF_MAGIC) { 648 if (magic == ZIP_CDF_MAGIC) {
597 dbg("got ZIP_CDF_MAGIC"); 649 dbg("got ZIP_CDF_MAGIC");
598 break; 650 break;
@@ -608,71 +660,70 @@ int unzip_main(int argc, char **argv)
608 bb_error_msg_and_die("invalid zip magic %08X", (int)magic); 660 bb_error_msg_and_die("invalid zip magic %08X", (int)magic);
609 dbg("got ZIP_FILEHEADER_MAGIC"); 661 dbg("got ZIP_FILEHEADER_MAGIC");
610 662
611 xread(zip_fd, zip_header.raw, ZIP_HEADER_LEN); 663 xread(zip_fd, zip.raw, ZIP_HEADER_LEN);
612 FIX_ENDIANNESS_ZIP(zip_header); 664 FIX_ENDIANNESS_ZIP(zip);
613 if ((zip_header.formatted.method != 0) 665 if (zip.fmt.zip_flags & SWAP_LE16(0x0008)) {
614 && (zip_header.formatted.method != 8) 666 bb_error_msg_and_die("zip flag %s is not supported",
615 ) { 667 "8 (streaming)");
616 /* TODO? method 12: bzip2, method 14: LZMA */
617 bb_error_msg_and_die("unsupported method %d", zip_header.formatted.method);
618 }
619 if (zip_header.formatted.zip_flags & SWAP_LE16(0x0009)) {
620 bb_error_msg_and_die("zip flags 1 and 8 are not supported");
621 } 668 }
622 } 669 }
623#if ENABLE_FEATURE_UNZIP_CDF 670#if ENABLE_FEATURE_UNZIP_CDF
624 else { 671 else {
625 /* cdf_offset is valid (and we know the file is seekable) */ 672 /* cdf_offset is valid (and we know the file is seekable) */
626 cdf_header_t cdf_header; 673 cdf_header_t cdf;
627 cdf_offset = read_next_cdf(cdf_offset, &cdf_header); 674 cdf_offset = read_next_cdf(cdf_offset, &cdf);
628 if (cdf_offset == 0) /* EOF? */ 675 if (cdf_offset == 0) /* EOF? */
629 break; 676 break;
630# if 1 677# if 1
631 xlseek(zip_fd, 678 xlseek(zip_fd,
632 SWAP_LE32(cdf_header.formatted.relative_offset_of_local_header) + 4, 679 SWAP_LE32(cdf.fmt.relative_offset_of_local_header) + 4,
633 SEEK_SET); 680 SEEK_SET);
634 xread(zip_fd, zip_header.raw, ZIP_HEADER_LEN); 681 xread(zip_fd, zip.raw, ZIP_HEADER_LEN);
635 FIX_ENDIANNESS_ZIP(zip_header); 682 FIX_ENDIANNESS_ZIP(zip);
636 if (zip_header.formatted.zip_flags & SWAP_LE16(0x0008)) { 683 if (zip.fmt.zip_flags & SWAP_LE16(0x0008)) {
637 /* 0x0008 - streaming. [u]cmpsize can be reliably gotten 684 /* 0x0008 - streaming. [u]cmpsize can be reliably gotten
638 * only from Central Directory. 685 * only from Central Directory.
639 */ 686 */
640 zip_header.formatted.crc32 = cdf_header.formatted.crc32; 687 zip.fmt.crc32 = cdf.fmt.crc32;
641 zip_header.formatted.cmpsize = cdf_header.formatted.cmpsize; 688 zip.fmt.cmpsize = cdf.fmt.cmpsize;
642 zip_header.formatted.ucmpsize = cdf_header.formatted.ucmpsize; 689 zip.fmt.ucmpsize = cdf.fmt.ucmpsize;
643 } 690 }
644# else 691# else
645 /* CDF has the same data as local header, no need to read the latter */ 692 /* CDF has the same data as local header, no need to read the latter...
646 memcpy(&zip_header.formatted.version, 693 * ...not really. An archive was seen with cdf.extra_len == 6 but
647 &cdf_header.formatted.version_needed, ZIP_HEADER_LEN); 694 * zip.extra_len == 0.
695 */
696 memcpy(&zip.fmt.version,
697 &cdf.fmt.version_needed, ZIP_HEADER_LEN);
648 xlseek(zip_fd, 698 xlseek(zip_fd,
649 SWAP_LE32(cdf_header.formatted.relative_offset_of_local_header) + 4 + ZIP_HEADER_LEN, 699 SWAP_LE32(cdf.fmt.relative_offset_of_local_header) + 4 + ZIP_HEADER_LEN,
650 SEEK_SET); 700 SEEK_SET);
651# endif 701# endif
652 if ((cdf_header.formatted.version_made_by >> 8) == 3) { 702 if ((cdf.fmt.version_made_by >> 8) == 3) {
653 /* This archive is created on Unix */ 703 /* This archive is created on Unix */
654 dir_mode = file_mode = (cdf_header.formatted.external_file_attributes >> 16); 704 dir_mode = file_mode = (cdf.fmt.external_attributes >> 16);
655 } 705 }
656 } 706 }
657#endif 707#endif
658 708
659 if (zip_header.formatted.zip_flags & SWAP_LE16(0x0001)) { 709 if (zip.fmt.zip_flags & SWAP_LE16(0x0001)) {
660 /* 0x0001 - encrypted */ 710 /* 0x0001 - encrypted */
661 bb_error_msg_and_die("zip flag 1 (encryption) is not supported"); 711 bb_error_msg_and_die("zip flag %s is not supported",
712 "1 (encryption)");
662 } 713 }
663 dbg("File cmpsize:0x%x extra_len:0x%x ucmpsize:0x%x", 714 dbg("File cmpsize:0x%x extra_len:0x%x ucmpsize:0x%x",
664 (unsigned)zip_header.formatted.cmpsize, 715 (unsigned)zip.fmt.cmpsize,
665 (unsigned)zip_header.formatted.extra_len, 716 (unsigned)zip.fmt.extra_len,
666 (unsigned)zip_header.formatted.ucmpsize 717 (unsigned)zip.fmt.ucmpsize
667 ); 718 );
668 719
669 /* Read filename */ 720 /* Read filename */
670 free(dst_fn); 721 free(dst_fn);
671 dst_fn = xzalloc(zip_header.formatted.filename_len + 1); 722 dst_fn = xzalloc(zip.fmt.filename_len + 1);
672 xread(zip_fd, dst_fn, zip_header.formatted.filename_len); 723 xread(zip_fd, dst_fn, zip.fmt.filename_len);
673 724
674 /* Skip extra header bytes */ 725 /* Skip extra header bytes */
675 unzip_skip(zip_header.formatted.extra_len); 726 unzip_skip(zip.fmt.extra_len);
676 727
677 /* Guard against "/abspath", "/../" and similar attacks */ 728 /* Guard against "/abspath", "/../" and similar attacks */
678 overlapping_strcpy(dst_fn, strip_unsafe_prefix(dst_fn)); 729 overlapping_strcpy(dst_fn, strip_unsafe_prefix(dst_fn));
@@ -681,129 +732,129 @@ int unzip_main(int argc, char **argv)
681 if (find_list_entry(zreject, dst_fn) 732 if (find_list_entry(zreject, dst_fn)
682 || (zaccept && !find_list_entry(zaccept, dst_fn)) 733 || (zaccept && !find_list_entry(zaccept, dst_fn))
683 ) { /* Skip entry */ 734 ) { /* Skip entry */
684 i = 'n'; 735 goto skip_cmpsize;
685 } else { 736 }
686 if (listing) { 737
687 /* List entry */ 738 if (listing) {
688 char dtbuf[sizeof("mm-dd-yyyy hh:mm")]; 739 /* List entry */
689 sprintf(dtbuf, "%02u-%02u-%04u %02u:%02u", 740 char dtbuf[sizeof("mm-dd-yyyy hh:mm")];
690 (zip_header.formatted.moddate >> 5) & 0xf, // mm: 0x01e0 741 sprintf(dtbuf, "%02u-%02u-%04u %02u:%02u",
691 (zip_header.formatted.moddate) & 0x1f, // dd: 0x001f 742 (zip.fmt.moddate >> 5) & 0xf, // mm: 0x01e0
692 (zip_header.formatted.moddate >> 9) + 1980, // yy: 0xfe00 743 (zip.fmt.moddate) & 0x1f, // dd: 0x001f
693 (zip_header.formatted.modtime >> 11), // hh: 0xf800 744 (zip.fmt.moddate >> 9) + 1980, // yy: 0xfe00
694 (zip_header.formatted.modtime >> 5) & 0x3f // mm: 0x07e0 745 (zip.fmt.modtime >> 11), // hh: 0xf800
695 // seconds/2 are not shown, encoded in ----------- 0x001f 746 (zip.fmt.modtime >> 5) & 0x3f // mm: 0x07e0
696 ); 747 // seconds/2 not shown, encoded in -- 0x001f
697 if (!verbose) { 748 );
698 // " Length Date Time Name\n" 749 if (!verbose) {
699 // "--------- ---------- ----- ----" 750 // " Length Date Time Name\n"
700 printf( "%9u " "%s " "%s\n", 751 // "--------- ---------- ----- ----"
701 (unsigned)zip_header.formatted.ucmpsize, 752 printf( "%9u " "%s " "%s\n",
702 dtbuf, 753 (unsigned)zip.fmt.ucmpsize,
703 dst_fn); 754 dtbuf,
704 } else { 755 dst_fn);
705 unsigned long percents = zip_header.formatted.ucmpsize - zip_header.formatted.cmpsize; 756 } else {
706 if ((int32_t)percents < 0) 757 char method6[7];
707 percents = 0; /* happens if ucmpsize < cmpsize */ 758 unsigned long percents;
708 percents = percents * 100; 759
709 if (zip_header.formatted.ucmpsize) 760 sprintf(method6, "%6u", zip.fmt.method);
710 percents /= zip_header.formatted.ucmpsize; 761 if (zip.fmt.method == 0) {
711 // " Length Method Size Cmpr Date Time CRC-32 Name\n" 762 strcpy(method6, "Stored");
712 // "-------- ------ ------- ---- ---------- ----- -------- ----" 763 }
713 printf( "%8u %s" "%9u%4u%% " "%s " "%08x " "%s\n", 764 if (zip.fmt.method == 8) {
714 (unsigned)zip_header.formatted.ucmpsize, 765 strcpy(method6, "Defl:N");
715 zip_header.formatted.method == 0 ? "Stored" : "Defl:N", /* Defl is method 8 */ 766 /* normal, maximum, fast, superfast */
716/* TODO: show other methods? 767 IF_DESKTOP(method6[5] = "NXFS"[(zip.fmt.zip_flags >> 1) & 3];)
717 * 1 - Shrunk
718 * 2 - Reduced with compression factor 1
719 * 3 - Reduced with compression factor 2
720 * 4 - Reduced with compression factor 3
721 * 5 - Reduced with compression factor 4
722 * 6 - Imploded
723 * 7 - Reserved for Tokenizing compression algorithm
724 * 9 - Deflate64
725 * 10 - PKWARE Data Compression Library Imploding
726 * 11 - Reserved by PKWARE
727 * 12 - BZIP2
728 */
729 (unsigned)zip_header.formatted.cmpsize,
730 (unsigned)percents,
731 dtbuf,
732 zip_header.formatted.crc32,
733 dst_fn);
734 total_size += zip_header.formatted.cmpsize;
735 } 768 }
736 total_usize += zip_header.formatted.ucmpsize; 769 percents = zip.fmt.ucmpsize - zip.fmt.cmpsize;
737 i = 'n'; 770 if ((int32_t)percents < 0)
738 } else if (dst_fd == STDOUT_FILENO) { 771 percents = 0; /* happens if ucmpsize < cmpsize */
739 /* Extracting to STDOUT */ 772 percents = percents * 100;
740 i = -1; 773 if (zip.fmt.ucmpsize)
741 } else if (last_char_is(dst_fn, '/')) { 774 percents /= zip.fmt.ucmpsize;
742 /* Extract directory */ 775 // " Length Method Size Cmpr Date Time CRC-32 Name\n"
743 if (stat(dst_fn, &stat_buf) == -1) { 776 // "-------- ------ ------- ---- ---------- ----- -------- ----"
744 if (errno != ENOENT) { 777 printf( "%8u %s" "%9u%4u%% " "%s " "%08x " "%s\n",
745 bb_perror_msg_and_die("can't stat '%s'", dst_fn); 778 (unsigned)zip.fmt.ucmpsize,
746 } 779 method6,
747 if (!quiet) { 780 (unsigned)zip.fmt.cmpsize,
748 printf(" creating: %s\n", dst_fn); 781 (unsigned)percents,
749 } 782 dtbuf,
750 unzip_create_leading_dirs(dst_fn); 783 zip.fmt.crc32,
751 if (bb_make_directory(dst_fn, dir_mode, FILEUTILS_IGNORE_CHMOD_ERR)) { 784 dst_fn);
752 xfunc_die(); 785 total_size += zip.fmt.cmpsize;
753 } 786 }
754 } else { 787 total_usize += zip.fmt.ucmpsize;
755 if (!S_ISDIR(stat_buf.st_mode)) { 788 goto skip_cmpsize;
756 bb_error_msg_and_die("'%s' exists but is not a %s", 789 }
757 dst_fn, "directory"); 790
758 } 791 if (dst_fd == STDOUT_FILENO) {
792 /* Extracting to STDOUT */
793 goto do_extract;
794 }
795 if (last_char_is(dst_fn, '/')) {
796 /* Extract directory */
797 if (stat(dst_fn, &stat_buf) == -1) {
798 if (errno != ENOENT) {
799 bb_perror_msg_and_die("can't stat '%s'", dst_fn);
800 }
801 if (!quiet) {
802 printf(" creating: %s\n", dst_fn);
803 }
804 unzip_create_leading_dirs(dst_fn);
805 if (bb_make_directory(dst_fn, dir_mode, FILEUTILS_IGNORE_CHMOD_ERR)) {
806 xfunc_die();
759 } 807 }
760 i = 'n';
761 } else { 808 } else {
762 /* Extract file */ 809 if (!S_ISDIR(stat_buf.st_mode)) {
763 check_file: 810 bb_error_msg_and_die("'%s' exists but is not a %s",
764 if (stat(dst_fn, &stat_buf) == -1) { 811 dst_fn, "directory");
765 /* File does not exist */
766 if (errno != ENOENT) {
767 bb_perror_msg_and_die("can't stat '%s'", dst_fn);
768 }
769 i = 'y';
770 } else {
771 /* File already exists */
772 if (overwrite == O_NEVER) {
773 i = 'n';
774 } else if (S_ISREG(stat_buf.st_mode)) {
775 /* File is regular file */
776 if (overwrite == O_ALWAYS) {
777 i = 'y';
778 } else {
779 printf("replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", dst_fn);
780 my_fgets80(key_buf);
781 i = key_buf[0];
782 }
783 } else {
784 /* File is not regular file */
785 bb_error_msg_and_die("'%s' exists but is not a %s",
786 dst_fn, "regular file");
787 }
788 } 812 }
789 } 813 }
814 goto skip_cmpsize;
815 }
816 check_file:
817 /* Extract file */
818 if (stat(dst_fn, &stat_buf) == -1) {
819 /* File does not exist */
820 if (errno != ENOENT) {
821 bb_perror_msg_and_die("can't stat '%s'", dst_fn);
822 }
823 goto do_open_and_extract;
824 }
825 /* File already exists */
826 if (overwrite == O_NEVER) {
827 goto skip_cmpsize;
828 }
829 if (!S_ISREG(stat_buf.st_mode)) {
830 /* File is not regular file */
831 bb_error_msg_and_die("'%s' exists but is not a %s",
832 dst_fn, "regular file");
790 } 833 }
834 /* File is regular file */
835 if (overwrite == O_ALWAYS)
836 goto do_open_and_extract;
837 printf("replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", dst_fn);
838 my_fgets80(key_buf);
791 839
792 switch (i) { 840 switch (key_buf[0]) {
793 case 'A': 841 case 'A':
794 overwrite = O_ALWAYS; 842 overwrite = O_ALWAYS;
795 case 'y': /* Open file and fall into unzip */ 843 case 'y': /* Open file and fall into unzip */
844 do_open_and_extract:
796 unzip_create_leading_dirs(dst_fn); 845 unzip_create_leading_dirs(dst_fn);
797#if ENABLE_FEATURE_UNZIP_CDF 846#if ENABLE_FEATURE_UNZIP_CDF
798 dst_fd = xopen3(dst_fn, O_WRONLY | O_CREAT | O_TRUNC, file_mode); 847 dst_fd = xopen3(dst_fn, O_WRONLY | O_CREAT | O_TRUNC, file_mode);
799#else 848#else
800 dst_fd = xopen(dst_fn, O_WRONLY | O_CREAT | O_TRUNC); 849 dst_fd = xopen(dst_fn, O_WRONLY | O_CREAT | O_TRUNC);
801#endif 850#endif
802 case -1: /* Unzip */ 851 do_extract:
803 if (!quiet) { 852 if (!quiet) {
804 printf(" inflating: %s\n", dst_fn); 853 printf(/* zip.fmt.method == 0
854 ? " extracting: %s\n"
855 : */ " inflating: %s\n", dst_fn);
805 } 856 }
806 unzip_extract(&zip_header, dst_fd); 857 unzip_extract(&zip, dst_fd);
807 if (dst_fd != STDOUT_FILENO) { 858 if (dst_fd != STDOUT_FILENO) {
808 /* closing STDOUT is potentially bad for future business */ 859 /* closing STDOUT is potentially bad for future business */
809 close(dst_fd); 860 close(dst_fd);
@@ -812,9 +863,9 @@ int unzip_main(int argc, char **argv)
812 863
813 case 'N': 864 case 'N':
814 overwrite = O_NEVER; 865 overwrite = O_NEVER;
815 case 'n': 866 case 'n': /* Skip entry data */
816 /* Skip entry data */ 867 skip_cmpsize:
817 unzip_skip(zip_header.formatted.cmpsize); 868 unzip_skip(zip.fmt.cmpsize);
818 break; 869 break;
819 870
820 case 'r': 871 case 'r':
@@ -827,7 +878,7 @@ int unzip_main(int argc, char **argv)
827 goto check_file; 878 goto check_file;
828 879
829 default: 880 default:
830 printf("error: invalid response [%c]\n", (char)i); 881 printf("error: invalid response [%c]\n", (char)key_buf[0]);
831 goto check_file; 882 goto check_file;
832 } 883 }
833 884