aboutsummaryrefslogtreecommitdiff
path: root/archival/unzip.c
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2017-01-08 08:56:43 +0000
committerRon Yorston <rmy@pobox.com>2017-01-08 08:56:43 +0000
commit3ef86d069577b8a44ebe3aa890c6e97ea31d0d56 (patch)
tree064587c9b2080dba963bf8d93861b8019cb306ed /archival/unzip.c
parentc66975af0b5335b9cdd156206767756237bd814b (diff)
parent86584e134eec1a81298149f8c04c77727f6dccb9 (diff)
downloadbusybox-w32-3ef86d069577b8a44ebe3aa890c6e97ea31d0d56.tar.gz
busybox-w32-3ef86d069577b8a44ebe3aa890c6e97ea31d0d56.tar.bz2
busybox-w32-3ef86d069577b8a44ebe3aa890c6e97ea31d0d56.zip
Merge branch 'busybox' into merge
Diffstat (limited to 'archival/unzip.c')
-rw-r--r--archival/unzip.c286
1 files changed, 163 insertions, 123 deletions
diff --git a/archival/unzip.c b/archival/unzip.c
index 27adb3420..7029f66c3 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -16,7 +16,6 @@
16 * TODO 16 * TODO
17 * Zip64 + other methods 17 * Zip64 + other methods
18 */ 18 */
19
20//config:config UNZIP 19//config:config UNZIP
21//config: bool "unzip" 20//config: bool "unzip"
22//config: default y 21//config: default y
@@ -24,8 +23,17 @@
24//config: unzip will list or extract files from a ZIP archive, 23//config: unzip will list or extract files from a ZIP archive,
25//config: commonly found on DOS/WIN systems. The default behavior 24//config: commonly found on DOS/WIN systems. The default behavior
26//config: (with no options) is to extract the archive into the 25//config: (with no options) is to extract the archive into the
27//config: current directory. Use the `-d' option to extract to a 26//config: current directory.
28//config: directory of your choice. 27//config:
28//config:config FEATURE_UNZIP_CDF
29//config: bool "Read and use Central Directory data"
30//config: default y
31//config: depends on UNZIP
32//config: help
33//config: If you know that you only need to deal with simple
34//config: ZIP files without deleted/updated files, SFX archives etc,
35//config: you can reduce code size by unselecting this option.
36//config: To support less trivial ZIPs, say Y.
29 37
30//applet:IF_UNZIP(APPLET(unzip, BB_DIR_USR_BIN, BB_SUID_DROP)) 38//applet:IF_UNZIP(APPLET(unzip, BB_DIR_USR_BIN, BB_SUID_DROP))
31//kbuild:lib-$(CONFIG_UNZIP) += unzip.o 39//kbuild:lib-$(CONFIG_UNZIP) += unzip.o
@@ -83,30 +91,20 @@ typedef union {
83 uint32_t ucmpsize PACKED; /* 18-21 */ 91 uint32_t ucmpsize PACKED; /* 18-21 */
84 uint16_t filename_len; /* 22-23 */ 92 uint16_t filename_len; /* 22-23 */
85 uint16_t extra_len; /* 24-25 */ 93 uint16_t extra_len; /* 24-25 */
94 /* filename follows (not NUL terminated) */
95 /* extra field follows */
96 /* data follows */
86 } formatted PACKED; 97 } formatted PACKED;
87} zip_header_t; /* PACKED - gcc 4.2.1 doesn't like it (spews warning) */ 98} zip_header_t; /* PACKED - gcc 4.2.1 doesn't like it (spews warning) */
88 99
89/* Check the offset of the last element, not the length. This leniency 100#define FIX_ENDIANNESS_ZIP(zip_header) \
90 * allows for poor packing, whereby the overall struct may be too long, 101do { if (BB_BIG_ENDIAN) { \
91 * even though the elements are all in the right place.
92 */
93struct BUG_zip_header_must_be_26_bytes {
94 char BUG_zip_header_must_be_26_bytes[
95 offsetof(zip_header_t, formatted.extra_len) + 2
96 == ZIP_HEADER_LEN ? 1 : -1];
97};
98
99#define FIX_ENDIANNESS_ZIP(zip_header) do { \
100 (zip_header).formatted.version = SWAP_LE16((zip_header).formatted.version ); \
101 (zip_header).formatted.method = SWAP_LE16((zip_header).formatted.method ); \
102 (zip_header).formatted.modtime = SWAP_LE16((zip_header).formatted.modtime ); \
103 (zip_header).formatted.moddate = SWAP_LE16((zip_header).formatted.moddate ); \
104 (zip_header).formatted.crc32 = SWAP_LE32((zip_header).formatted.crc32 ); \ 102 (zip_header).formatted.crc32 = SWAP_LE32((zip_header).formatted.crc32 ); \
105 (zip_header).formatted.cmpsize = SWAP_LE32((zip_header).formatted.cmpsize ); \ 103 (zip_header).formatted.cmpsize = SWAP_LE32((zip_header).formatted.cmpsize ); \
106 (zip_header).formatted.ucmpsize = SWAP_LE32((zip_header).formatted.ucmpsize ); \ 104 (zip_header).formatted.ucmpsize = SWAP_LE32((zip_header).formatted.ucmpsize ); \
107 (zip_header).formatted.filename_len = SWAP_LE16((zip_header).formatted.filename_len); \ 105 (zip_header).formatted.filename_len = SWAP_LE16((zip_header).formatted.filename_len); \
108 (zip_header).formatted.extra_len = SWAP_LE16((zip_header).formatted.extra_len ); \ 106 (zip_header).formatted.extra_len = SWAP_LE16((zip_header).formatted.extra_len ); \
109} while (0) 107}} while (0)
110 108
111#define CDF_HEADER_LEN 42 109#define CDF_HEADER_LEN 42
112 110
@@ -118,8 +116,8 @@ typedef union {
118 uint16_t version_needed; /* 2-3 */ 116 uint16_t version_needed; /* 2-3 */
119 uint16_t cdf_flags; /* 4-5 */ 117 uint16_t cdf_flags; /* 4-5 */
120 uint16_t method; /* 6-7 */ 118 uint16_t method; /* 6-7 */
121 uint16_t mtime; /* 8-9 */ 119 uint16_t modtime; /* 8-9 */
122 uint16_t mdate; /* 10-11 */ 120 uint16_t moddate; /* 10-11 */
123 uint32_t crc32; /* 12-15 */ 121 uint32_t crc32; /* 12-15 */
124 uint32_t cmpsize; /* 16-19 */ 122 uint32_t cmpsize; /* 16-19 */
125 uint32_t ucmpsize; /* 20-23 */ 123 uint32_t ucmpsize; /* 20-23 */
@@ -130,27 +128,27 @@ typedef union {
130 uint16_t internal_file_attributes; /* 32-33 */ 128 uint16_t internal_file_attributes; /* 32-33 */
131 uint32_t external_file_attributes PACKED; /* 34-37 */ 129 uint32_t external_file_attributes PACKED; /* 34-37 */
132 uint32_t relative_offset_of_local_header PACKED; /* 38-41 */ 130 uint32_t relative_offset_of_local_header PACKED; /* 38-41 */
131 /* filename follows (not NUL terminated) */
132 /* extra field follows */
133 /* comment follows */
133 } formatted PACKED; 134 } formatted PACKED;
134} cdf_header_t; 135} cdf_header_t;
135 136
136struct BUG_cdf_header_must_be_42_bytes { 137#define FIX_ENDIANNESS_CDF(cdf_header) \
137 char BUG_cdf_header_must_be_42_bytes[ 138do { if (BB_BIG_ENDIAN) { \
138 offsetof(cdf_header_t, formatted.relative_offset_of_local_header) + 4 139 (cdf_header).formatted.version_made_by = SWAP_LE16((cdf_header).formatted.version_made_by); \
139 == CDF_HEADER_LEN ? 1 : -1]; 140 (cdf_header).formatted.version_needed = SWAP_LE16((cdf_header).formatted.version_needed); \
140}; 141 (cdf_header).formatted.method = SWAP_LE16((cdf_header).formatted.method ); \
141 142 (cdf_header).formatted.modtime = SWAP_LE16((cdf_header).formatted.modtime ); \
142#define FIX_ENDIANNESS_CDF(cdf_header) do { \ 143 (cdf_header).formatted.moddate = SWAP_LE16((cdf_header).formatted.moddate ); \
143 (cdf_header).formatted.crc32 = SWAP_LE32((cdf_header).formatted.crc32 ); \ 144 (cdf_header).formatted.crc32 = SWAP_LE32((cdf_header).formatted.crc32 ); \
144 (cdf_header).formatted.cmpsize = SWAP_LE32((cdf_header).formatted.cmpsize ); \ 145 (cdf_header).formatted.cmpsize = SWAP_LE32((cdf_header).formatted.cmpsize ); \
145 (cdf_header).formatted.ucmpsize = SWAP_LE32((cdf_header).formatted.ucmpsize ); \ 146 (cdf_header).formatted.ucmpsize = SWAP_LE32((cdf_header).formatted.ucmpsize ); \
146 (cdf_header).formatted.file_name_length = SWAP_LE16((cdf_header).formatted.file_name_length); \ 147 (cdf_header).formatted.file_name_length = SWAP_LE16((cdf_header).formatted.file_name_length); \
147 (cdf_header).formatted.extra_field_length = SWAP_LE16((cdf_header).formatted.extra_field_length); \ 148 (cdf_header).formatted.extra_field_length = SWAP_LE16((cdf_header).formatted.extra_field_length); \
148 (cdf_header).formatted.file_comment_length = SWAP_LE16((cdf_header).formatted.file_comment_length); \ 149 (cdf_header).formatted.file_comment_length = SWAP_LE16((cdf_header).formatted.file_comment_length); \
149 IF_DESKTOP( \
150 (cdf_header).formatted.version_made_by = SWAP_LE16((cdf_header).formatted.version_made_by); \
151 (cdf_header).formatted.external_file_attributes = SWAP_LE32((cdf_header).formatted.external_file_attributes); \ 150 (cdf_header).formatted.external_file_attributes = SWAP_LE32((cdf_header).formatted.external_file_attributes); \
152 ) \ 151}} while (0)
153} while (0)
154 152
155#define CDE_HEADER_LEN 16 153#define CDE_HEADER_LEN 16
156 154
@@ -169,20 +167,38 @@ typedef union {
169 } formatted PACKED; 167 } formatted PACKED;
170} cde_header_t; 168} cde_header_t;
171 169
172struct BUG_cde_header_must_be_16_bytes { 170#define FIX_ENDIANNESS_CDE(cde_header) \
171do { if (BB_BIG_ENDIAN) { \
172 (cde_header).formatted.cdf_offset = SWAP_LE32((cde_header).formatted.cdf_offset); \
173}} while (0)
174
175struct BUG {
176 /* Check the offset of the last element, not the length. This leniency
177 * allows for poor packing, whereby the overall struct may be too long,
178 * even though the elements are all in the right place.
179 */
180 char BUG_zip_header_must_be_26_bytes[
181 offsetof(zip_header_t, formatted.extra_len) + 2
182 == ZIP_HEADER_LEN ? 1 : -1];
183 char BUG_cdf_header_must_be_42_bytes[
184 offsetof(cdf_header_t, formatted.relative_offset_of_local_header) + 4
185 == CDF_HEADER_LEN ? 1 : -1];
173 char BUG_cde_header_must_be_16_bytes[ 186 char BUG_cde_header_must_be_16_bytes[
174 sizeof(cde_header_t) == CDE_HEADER_LEN ? 1 : -1]; 187 sizeof(cde_header_t) == CDE_HEADER_LEN ? 1 : -1];
175}; 188};
176 189
177#define FIX_ENDIANNESS_CDE(cde_header) do { \
178 (cde_header).formatted.cdf_offset = SWAP_LE32((cde_header).formatted.cdf_offset); \
179} while (0)
180 190
181enum { zip_fd = 3 }; 191enum { zip_fd = 3 };
182 192
183 193
184#if ENABLE_DESKTOP 194/* This value means that we failed to find CDF */
195#define BAD_CDF_OFFSET ((uint32_t)0xffffffff)
196
197#if !ENABLE_FEATURE_UNZIP_CDF
198
199# define find_cdf_offset() BAD_CDF_OFFSET
185 200
201#else
186/* Seen in the wild: 202/* Seen in the wild:
187 * Self-extracting PRO2K3XP_32.exe contains 19078464 byte zip archive, 203 * Self-extracting PRO2K3XP_32.exe contains 19078464 byte zip archive,
188 * where CDE was nearly 48 kbytes before EOF. 204 * where CDE was nearly 48 kbytes before EOF.
@@ -191,25 +207,26 @@ enum { zip_fd = 3 };
191 * To make extraction work, bumped PEEK_FROM_END from 16k to 64k. 207 * To make extraction work, bumped PEEK_FROM_END from 16k to 64k.
192 */ 208 */
193#define PEEK_FROM_END (64*1024) 209#define PEEK_FROM_END (64*1024)
194
195/* This value means that we failed to find CDF */
196#define BAD_CDF_OFFSET ((uint32_t)0xffffffff)
197
198/* NB: does not preserve file position! */ 210/* NB: does not preserve file position! */
199static uint32_t find_cdf_offset(void) 211static uint32_t find_cdf_offset(void)
200{ 212{
201 cde_header_t cde_header; 213 cde_header_t cde_header;
214 unsigned char *buf;
202 unsigned char *p; 215 unsigned char *p;
203 off_t end; 216 off_t end;
204 unsigned char *buf = xzalloc(PEEK_FROM_END);
205 uint32_t found; 217 uint32_t found;
206 218
207 end = xlseek(zip_fd, 0, SEEK_END); 219 end = lseek(zip_fd, 0, SEEK_END);
220 if (end == (off_t) -1)
221 return BAD_CDF_OFFSET;
222
208 end -= PEEK_FROM_END; 223 end -= PEEK_FROM_END;
209 if (end < 0) 224 if (end < 0)
210 end = 0; 225 end = 0;
226
211 dbg("Looking for cdf_offset starting from 0x%"OFF_FMT"x", end); 227 dbg("Looking for cdf_offset starting from 0x%"OFF_FMT"x", end);
212 xlseek(zip_fd, end, SEEK_SET); 228 xlseek(zip_fd, end, SEEK_SET);
229 buf = xzalloc(PEEK_FROM_END);
213 full_read(zip_fd, buf, PEEK_FROM_END); 230 full_read(zip_fd, buf, PEEK_FROM_END);
214 231
215 found = BAD_CDF_OFFSET; 232 found = BAD_CDF_OFFSET;
@@ -254,31 +271,32 @@ static uint32_t find_cdf_offset(void)
254 271
255static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr) 272static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr)
256{ 273{
257 off_t org; 274 uint32_t magic;
258 275
259 org = xlseek(zip_fd, 0, SEEK_CUR); 276 if (cdf_offset == BAD_CDF_OFFSET)
260 277 return cdf_offset;
261 if (!cdf_offset) 278
262 cdf_offset = find_cdf_offset(); 279 dbg("Reading CDF at 0x%x", (unsigned)cdf_offset);
263 280 xlseek(zip_fd, cdf_offset, SEEK_SET);
264 if (cdf_offset != BAD_CDF_OFFSET) { 281 xread(zip_fd, &magic, 4);
265 dbg("Reading CDF at 0x%x", (unsigned)cdf_offset); 282 /* Central Directory End? */
266 xlseek(zip_fd, cdf_offset + 4, SEEK_SET); 283 if (magic == ZIP_CDE_MAGIC) {
267 xread(zip_fd, cdf_ptr->raw, CDF_HEADER_LEN); 284 dbg("got ZIP_CDE_MAGIC");
268 FIX_ENDIANNESS_CDF(*cdf_ptr); 285 return 0; /* EOF */
269 dbg(" file_name_length:%u extra_field_length:%u file_comment_length:%u",
270 (unsigned)cdf_ptr->formatted.file_name_length,
271 (unsigned)cdf_ptr->formatted.extra_field_length,
272 (unsigned)cdf_ptr->formatted.file_comment_length
273 );
274 cdf_offset += 4 + CDF_HEADER_LEN
275 + cdf_ptr->formatted.file_name_length
276 + cdf_ptr->formatted.extra_field_length
277 + cdf_ptr->formatted.file_comment_length;
278 } 286 }
287 xread(zip_fd, cdf_ptr->raw, CDF_HEADER_LEN);
288
289 FIX_ENDIANNESS_CDF(*cdf_ptr);
290 dbg(" file_name_length:%u extra_field_length:%u file_comment_length:%u",
291 (unsigned)cdf_ptr->formatted.file_name_length,
292 (unsigned)cdf_ptr->formatted.extra_field_length,
293 (unsigned)cdf_ptr->formatted.file_comment_length
294 );
295 cdf_offset += 4 + CDF_HEADER_LEN
296 + cdf_ptr->formatted.file_name_length
297 + cdf_ptr->formatted.extra_field_length
298 + cdf_ptr->formatted.file_comment_length;
279 299
280 dbg("Returning file position to 0x%"OFF_FMT"x", org);
281 xlseek(zip_fd, org, SEEK_SET);
282 return cdf_offset; 300 return cdf_offset;
283}; 301};
284#endif 302#endif
@@ -327,6 +345,7 @@ static void unzip_extract(zip_header_t *zip_header, int dst_fd)
327 bb_error_msg("bad length"); 345 bb_error_msg("bad length");
328 } 346 }
329 } 347 }
348 /* TODO? method 12: bzip2, method 14: LZMA */
330} 349}
331 350
332static void my_fgets80(char *buf80) 351static void my_fgets80(char *buf80)
@@ -342,15 +361,12 @@ int unzip_main(int argc, char **argv)
342{ 361{
343 enum { O_PROMPT, O_NEVER, O_ALWAYS }; 362 enum { O_PROMPT, O_NEVER, O_ALWAYS };
344 363
345 zip_header_t zip_header;
346 smallint quiet = 0; 364 smallint quiet = 0;
347 IF_NOT_DESKTOP(const) smallint verbose = 0; 365 IF_NOT_FEATURE_UNZIP_CDF(const) smallint verbose = 0;
348 smallint listing = 0; 366 smallint listing = 0;
349 smallint overwrite = O_PROMPT; 367 smallint overwrite = O_PROMPT;
350 smallint x_opt_seen; 368 smallint x_opt_seen;
351#if ENABLE_DESKTOP
352 uint32_t cdf_offset; 369 uint32_t cdf_offset;
353#endif
354 unsigned long total_usize; 370 unsigned long total_usize;
355 unsigned long total_size; 371 unsigned long total_size;
356 unsigned total_entries; 372 unsigned total_entries;
@@ -433,7 +449,7 @@ int unzip_main(int argc, char **argv)
433 break; 449 break;
434 450
435 case 'v': /* Verbose list */ 451 case 'v': /* Verbose list */
436 IF_DESKTOP(verbose++;) 452 IF_FEATURE_UNZIP_CDF(verbose++;)
437 listing = 1; 453 listing = 1;
438 break; 454 break;
439 455
@@ -548,78 +564,102 @@ int unzip_main(int argc, char **argv)
548 total_usize = 0; 564 total_usize = 0;
549 total_size = 0; 565 total_size = 0;
550 total_entries = 0; 566 total_entries = 0;
551#if ENABLE_DESKTOP 567 cdf_offset = find_cdf_offset(); /* try to seek to the end, find CDE and CDF start */
552 cdf_offset = 0;
553#endif
554 while (1) { 568 while (1) {
555 uint32_t magic; 569 zip_header_t zip_header;
556 mode_t dir_mode = 0777; 570 mode_t dir_mode = 0777;
557#if ENABLE_DESKTOP 571#if ENABLE_FEATURE_UNZIP_CDF
558 mode_t file_mode = 0666; 572 mode_t file_mode = 0666;
559#endif 573#endif
560 574
561 /* Check magic number */ 575 if (!ENABLE_FEATURE_UNZIP_CDF || cdf_offset == BAD_CDF_OFFSET) {
562 xread(zip_fd, &magic, 4); 576 /* Normally happens when input is unseekable.
563 /* Central directory? It's at the end, so exit */ 577 *
564 if (magic == ZIP_CDF_MAGIC) { 578 * Valid ZIP file has Central Directory at the end
565 dbg("got ZIP_CDF_MAGIC"); 579 * with central directory file headers (CDFs).
566 break; 580 * After it, there is a Central Directory End structure.
567 } 581 * CDFs identify what files are in the ZIP and where
568#if ENABLE_DESKTOP 582 * they are located. This allows ZIP readers to load
569 /* Data descriptor? It was a streaming file, go on */ 583 * the list of files without reading the entire ZIP archive.
570 if (magic == ZIP_DD_MAGIC) { 584 * ZIP files may be appended to, only files specified in
571 dbg("got ZIP_DD_MAGIC"); 585 * the CD are valid. Scanning for local file headers is
572 /* skip over duplicate crc32, cmpsize and ucmpsize */ 586 * not a correct algorithm.
573 unzip_skip(3 * 4); 587 *
574 continue; 588 * We try to do the above, and resort to "linear" reading
575 } 589 * of ZIP file only if seek failed or CDE wasn't found.
576#endif 590 */
577 if (magic != ZIP_FILEHEADER_MAGIC) 591 uint32_t magic;
578 bb_error_msg_and_die("invalid zip magic %08X", (int)magic);
579 dbg("got ZIP_FILEHEADER_MAGIC");
580
581 /* Read the file header */
582 xread(zip_fd, zip_header.raw, ZIP_HEADER_LEN);
583 FIX_ENDIANNESS_ZIP(zip_header);
584 if ((zip_header.formatted.method != 0) && (zip_header.formatted.method != 8)) {
585 bb_error_msg_and_die("unsupported method %d", zip_header.formatted.method);
586 }
587#if !ENABLE_DESKTOP
588 if (zip_header.formatted.zip_flags & SWAP_LE16(0x0009)) {
589 bb_error_msg_and_die("zip flags 1 and 8 are not supported");
590 }
591#else
592 if (zip_header.formatted.zip_flags & SWAP_LE16(0x0001)) {
593 /* 0x0001 - encrypted */
594 bb_error_msg_and_die("zip flag 1 (encryption) is not supported");
595 }
596 592
597 if (cdf_offset != BAD_CDF_OFFSET) { 593 /* Check magic number */
594 xread(zip_fd, &magic, 4);
595 /* Central directory? It's at the end, so exit */
596 if (magic == ZIP_CDF_MAGIC) {
597 dbg("got ZIP_CDF_MAGIC");
598 break;
599 }
600 /* Data descriptor? It was a streaming file, go on */
601 if (magic == ZIP_DD_MAGIC) {
602 dbg("got ZIP_DD_MAGIC");
603 /* skip over duplicate crc32, cmpsize and ucmpsize */
604 unzip_skip(3 * 4);
605 continue;
606 }
607 if (magic != ZIP_FILEHEADER_MAGIC)
608 bb_error_msg_and_die("invalid zip magic %08X", (int)magic);
609 dbg("got ZIP_FILEHEADER_MAGIC");
610
611 xread(zip_fd, zip_header.raw, ZIP_HEADER_LEN);
612 FIX_ENDIANNESS_ZIP(zip_header);
613 if ((zip_header.formatted.method != 0)
614 && (zip_header.formatted.method != 8)
615 ) {
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 }
622 }
623#if ENABLE_FEATURE_UNZIP_CDF
624 else {
625 /* cdf_offset is valid (and we know the file is seekable) */
598 cdf_header_t cdf_header; 626 cdf_header_t cdf_header;
599 cdf_offset = read_next_cdf(cdf_offset, &cdf_header); 627 cdf_offset = read_next_cdf(cdf_offset, &cdf_header);
600 /* 628 if (cdf_offset == 0) /* EOF? */
601 * Note: cdf_offset can become BAD_CDF_OFFSET after the above call. 629 break;
602 */ 630# if 0
631 xlseek(zip_fd,
632 SWAP_LE32(cdf_header.formatted.relative_offset_of_local_header) + 4,
633 SEEK_SET);
634 xread(zip_fd, zip_header.raw, ZIP_HEADER_LEN);
635 FIX_ENDIANNESS_ZIP(zip_header);
603 if (zip_header.formatted.zip_flags & SWAP_LE16(0x0008)) { 636 if (zip_header.formatted.zip_flags & SWAP_LE16(0x0008)) {
604 /* 0x0008 - streaming. [u]cmpsize can be reliably gotten 637 /* 0x0008 - streaming. [u]cmpsize can be reliably gotten
605 * only from Central Directory. See unzip_doc.txt 638 * only from Central Directory.
606 */ 639 */
607 zip_header.formatted.crc32 = cdf_header.formatted.crc32; 640 zip_header.formatted.crc32 = cdf_header.formatted.crc32;
608 zip_header.formatted.cmpsize = cdf_header.formatted.cmpsize; 641 zip_header.formatted.cmpsize = cdf_header.formatted.cmpsize;
609 zip_header.formatted.ucmpsize = cdf_header.formatted.ucmpsize; 642 zip_header.formatted.ucmpsize = cdf_header.formatted.ucmpsize;
610 } 643 }
644# else
645 /* CDF has the same data as local header, no need to read the latter */
646 memcpy(&zip_header.formatted.version,
647 &cdf_header.formatted.version_needed, ZIP_HEADER_LEN);
648 xlseek(zip_fd,
649 SWAP_LE32(cdf_header.formatted.relative_offset_of_local_header) + 4 + ZIP_HEADER_LEN,
650 SEEK_SET);
651# endif
611 if ((cdf_header.formatted.version_made_by >> 8) == 3) { 652 if ((cdf_header.formatted.version_made_by >> 8) == 3) {
612 /* This archive is created on Unix */ 653 /* This archive is created on Unix */
613 dir_mode = file_mode = (cdf_header.formatted.external_file_attributes >> 16); 654 dir_mode = file_mode = (cdf_header.formatted.external_file_attributes >> 16);
614 } 655 }
615 } 656 }
616 if (cdf_offset == BAD_CDF_OFFSET
617 && (zip_header.formatted.zip_flags & SWAP_LE16(0x0008))
618 ) {
619 /* If it's a streaming zip, we _require_ CDF */
620 bb_error_msg_and_die("can't find file table");
621 }
622#endif 657#endif
658
659 if (zip_header.formatted.zip_flags & SWAP_LE16(0x0001)) {
660 /* 0x0001 - encrypted */
661 bb_error_msg_and_die("zip flag 1 (encryption) is not supported");
662 }
623 dbg("File cmpsize:0x%x extra_len:0x%x ucmpsize:0x%x", 663 dbg("File cmpsize:0x%x extra_len:0x%x ucmpsize:0x%x",
624 (unsigned)zip_header.formatted.cmpsize, 664 (unsigned)zip_header.formatted.cmpsize,
625 (unsigned)zip_header.formatted.extra_len, 665 (unsigned)zip_header.formatted.extra_len,
@@ -754,7 +794,7 @@ int unzip_main(int argc, char **argv)
754 overwrite = O_ALWAYS; 794 overwrite = O_ALWAYS;
755 case 'y': /* Open file and fall into unzip */ 795 case 'y': /* Open file and fall into unzip */
756 unzip_create_leading_dirs(dst_fn); 796 unzip_create_leading_dirs(dst_fn);
757#if ENABLE_DESKTOP 797#if ENABLE_FEATURE_UNZIP_CDF
758 dst_fd = xopen3(dst_fn, O_WRONLY | O_CREAT | O_TRUNC, file_mode); 798 dst_fd = xopen3(dst_fn, O_WRONLY | O_CREAT | O_TRUNC, file_mode);
759#else 799#else
760 dst_fd = xopen(dst_fn, O_WRONLY | O_CREAT | O_TRUNC); 800 dst_fd = xopen(dst_fn, O_WRONLY | O_CREAT | O_TRUNC);