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