diff options
author | Ron Yorston <rmy@pobox.com> | 2016-05-16 09:33:03 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2016-05-16 09:33:03 +0100 |
commit | 35d2f5bccb0f3dde600702ebcdb5424d4d50be4a (patch) | |
tree | 6e0ff0341c69839e268459a199682628bae734ed /archival/unzip.c | |
parent | 248a2600a2f4b442101ad568d1994b908bb28d4b (diff) | |
parent | f2559e5c2b7bd2c5fa0dd8e88d0a931da92a23af (diff) | |
download | busybox-w32-35d2f5bccb0f3dde600702ebcdb5424d4d50be4a.tar.gz busybox-w32-35d2f5bccb0f3dde600702ebcdb5424d4d50be4a.tar.bz2 busybox-w32-35d2f5bccb0f3dde600702ebcdb5424d4d50be4a.zip |
Merge branch 'busybox' into merge
Diffstat (limited to 'archival/unzip.c')
-rw-r--r-- | archival/unzip.c | 138 |
1 files changed, 96 insertions, 42 deletions
diff --git a/archival/unzip.c b/archival/unzip.c index 203073434..27adb3420 100644 --- a/archival/unzip.c +++ b/archival/unzip.c | |||
@@ -48,6 +48,12 @@ | |||
48 | #pragma pack(2) | 48 | #pragma pack(2) |
49 | #endif | 49 | #endif |
50 | 50 | ||
51 | #if 0 | ||
52 | # define dbg(...) bb_error_msg(__VA_ARGS__) | ||
53 | #else | ||
54 | # define dbg(...) ((void)0) | ||
55 | #endif | ||
56 | |||
51 | enum { | 57 | enum { |
52 | #if BB_BIG_ENDIAN | 58 | #if BB_BIG_ENDIAN |
53 | ZIP_FILEHEADER_MAGIC = 0x504b0304, | 59 | ZIP_FILEHEADER_MAGIC = 0x504b0304, |
@@ -196,15 +202,17 @@ static uint32_t find_cdf_offset(void) | |||
196 | unsigned char *p; | 202 | unsigned char *p; |
197 | off_t end; | 203 | off_t end; |
198 | unsigned char *buf = xzalloc(PEEK_FROM_END); | 204 | unsigned char *buf = xzalloc(PEEK_FROM_END); |
205 | uint32_t found; | ||
199 | 206 | ||
200 | end = xlseek(zip_fd, 0, SEEK_END); | 207 | end = xlseek(zip_fd, 0, SEEK_END); |
201 | end -= PEEK_FROM_END; | 208 | end -= PEEK_FROM_END; |
202 | if (end < 0) | 209 | if (end < 0) |
203 | end = 0; | 210 | end = 0; |
204 | xlseek(zip_fd, end, SEEK_SET); | 211 | dbg("Looking for cdf_offset starting from 0x%"OFF_FMT"x", end); |
212 | xlseek(zip_fd, end, SEEK_SET); | ||
205 | full_read(zip_fd, buf, PEEK_FROM_END); | 213 | full_read(zip_fd, buf, PEEK_FROM_END); |
206 | 214 | ||
207 | cde_header.formatted.cdf_offset = BAD_CDF_OFFSET; | 215 | found = BAD_CDF_OFFSET; |
208 | p = buf; | 216 | p = buf; |
209 | while (p <= buf + PEEK_FROM_END - CDE_HEADER_LEN - 4) { | 217 | while (p <= buf + PEEK_FROM_END - CDE_HEADER_LEN - 4) { |
210 | if (*p != 'P') { | 218 | if (*p != 'P') { |
@@ -223,14 +231,25 @@ static uint32_t find_cdf_offset(void) | |||
223 | /* | 231 | /* |
224 | * I've seen .ZIP files with seemingly valid CDEs | 232 | * I've seen .ZIP files with seemingly valid CDEs |
225 | * where cdf_offset points past EOF - ?? | 233 | * where cdf_offset points past EOF - ?? |
226 | * Ignore such CDEs: | 234 | * This check ignores such CDEs: |
227 | */ | 235 | */ |
228 | if (cde_header.formatted.cdf_offset < end + (p - buf)) | 236 | if (cde_header.formatted.cdf_offset < end + (p - buf)) { |
229 | break; | 237 | found = cde_header.formatted.cdf_offset; |
230 | cde_header.formatted.cdf_offset = BAD_CDF_OFFSET; | 238 | dbg("Possible cdf_offset:0x%x at 0x%"OFF_FMT"x", |
239 | (unsigned)found, end + (p-3 - buf)); | ||
240 | dbg(" cdf_offset+cdf_size:0x%x", | ||
241 | (unsigned)(found + SWAP_LE32(cde_header.formatted.cdf_size))); | ||
242 | /* | ||
243 | * We do not "break" here because only the last CDE is valid. | ||
244 | * I've seen a .zip archive which contained a .zip file, | ||
245 | * uncompressed, and taking the first CDE was using | ||
246 | * the CDE inside that file! | ||
247 | */ | ||
248 | } | ||
231 | } | 249 | } |
232 | free(buf); | 250 | free(buf); |
233 | return cde_header.formatted.cdf_offset; | 251 | dbg("Found cdf_offset:0x%x", (unsigned)found); |
252 | return found; | ||
234 | }; | 253 | }; |
235 | 254 | ||
236 | static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr) | 255 | static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr) |
@@ -243,15 +262,22 @@ static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr) | |||
243 | cdf_offset = find_cdf_offset(); | 262 | cdf_offset = find_cdf_offset(); |
244 | 263 | ||
245 | if (cdf_offset != BAD_CDF_OFFSET) { | 264 | if (cdf_offset != BAD_CDF_OFFSET) { |
265 | dbg("Reading CDF at 0x%x", (unsigned)cdf_offset); | ||
246 | xlseek(zip_fd, cdf_offset + 4, SEEK_SET); | 266 | xlseek(zip_fd, cdf_offset + 4, SEEK_SET); |
247 | xread(zip_fd, cdf_ptr->raw, CDF_HEADER_LEN); | 267 | xread(zip_fd, cdf_ptr->raw, CDF_HEADER_LEN); |
248 | FIX_ENDIANNESS_CDF(*cdf_ptr); | 268 | FIX_ENDIANNESS_CDF(*cdf_ptr); |
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 | ); | ||
249 | cdf_offset += 4 + CDF_HEADER_LEN | 274 | cdf_offset += 4 + CDF_HEADER_LEN |
250 | + cdf_ptr->formatted.file_name_length | 275 | + cdf_ptr->formatted.file_name_length |
251 | + cdf_ptr->formatted.extra_field_length | 276 | + cdf_ptr->formatted.extra_field_length |
252 | + cdf_ptr->formatted.file_comment_length; | 277 | + cdf_ptr->formatted.file_comment_length; |
253 | } | 278 | } |
254 | 279 | ||
280 | dbg("Returning file position to 0x%"OFF_FMT"x", org); | ||
255 | xlseek(zip_fd, org, SEEK_SET); | 281 | xlseek(zip_fd, org, SEEK_SET); |
256 | return cdf_offset; | 282 | return cdf_offset; |
257 | }; | 283 | }; |
@@ -464,7 +490,7 @@ int unzip_main(int argc, char **argv) | |||
464 | if (overwrite == O_PROMPT) | 490 | if (overwrite == O_PROMPT) |
465 | overwrite = O_NEVER; | 491 | overwrite = O_NEVER; |
466 | } else { | 492 | } else { |
467 | static const char extn[][5] = { ".zip", ".ZIP" }; | 493 | static const char extn[][5] ALIGN1 = { ".zip", ".ZIP" }; |
468 | char *ext = src_fn + strlen(src_fn); | 494 | char *ext = src_fn + strlen(src_fn); |
469 | int src_fd; | 495 | int src_fd; |
470 | 496 | ||
@@ -491,11 +517,11 @@ int unzip_main(int argc, char **argv) | |||
491 | printf("Archive: %s\n", src_fn); | 517 | printf("Archive: %s\n", src_fn); |
492 | if (listing) { | 518 | if (listing) { |
493 | puts(verbose ? | 519 | puts(verbose ? |
494 | " Length Method Size Ratio Date Time CRC-32 Name\n" | 520 | " Length Method Size Cmpr Date Time CRC-32 Name\n" |
495 | "-------- ------ ------- ----- ---- ---- ------ ----" | 521 | "-------- ------ ------- ---- ---------- ----- -------- ----" |
496 | : | 522 | : |
497 | " Length Date Time Name\n" | 523 | " Length Date Time Name\n" |
498 | " -------- ---- ---- ----" | 524 | "--------- ---------- ----- ----" |
499 | ); | 525 | ); |
500 | } | 526 | } |
501 | } | 527 | } |
@@ -535,11 +561,14 @@ int unzip_main(int argc, char **argv) | |||
535 | /* Check magic number */ | 561 | /* Check magic number */ |
536 | xread(zip_fd, &magic, 4); | 562 | xread(zip_fd, &magic, 4); |
537 | /* Central directory? It's at the end, so exit */ | 563 | /* Central directory? It's at the end, so exit */ |
538 | if (magic == ZIP_CDF_MAGIC) | 564 | if (magic == ZIP_CDF_MAGIC) { |
565 | dbg("got ZIP_CDF_MAGIC"); | ||
539 | break; | 566 | break; |
567 | } | ||
540 | #if ENABLE_DESKTOP | 568 | #if ENABLE_DESKTOP |
541 | /* Data descriptor? It was a streaming file, go on */ | 569 | /* Data descriptor? It was a streaming file, go on */ |
542 | if (magic == ZIP_DD_MAGIC) { | 570 | if (magic == ZIP_DD_MAGIC) { |
571 | dbg("got ZIP_DD_MAGIC"); | ||
543 | /* skip over duplicate crc32, cmpsize and ucmpsize */ | 572 | /* skip over duplicate crc32, cmpsize and ucmpsize */ |
544 | unzip_skip(3 * 4); | 573 | unzip_skip(3 * 4); |
545 | continue; | 574 | continue; |
@@ -547,6 +576,7 @@ int unzip_main(int argc, char **argv) | |||
547 | #endif | 576 | #endif |
548 | if (magic != ZIP_FILEHEADER_MAGIC) | 577 | if (magic != ZIP_FILEHEADER_MAGIC) |
549 | bb_error_msg_and_die("invalid zip magic %08X", (int)magic); | 578 | bb_error_msg_and_die("invalid zip magic %08X", (int)magic); |
579 | dbg("got ZIP_FILEHEADER_MAGIC"); | ||
550 | 580 | ||
551 | /* Read the file header */ | 581 | /* Read the file header */ |
552 | xread(zip_fd, zip_header.raw, ZIP_HEADER_LEN); | 582 | xread(zip_fd, zip_header.raw, ZIP_HEADER_LEN); |
@@ -590,6 +620,11 @@ int unzip_main(int argc, char **argv) | |||
590 | bb_error_msg_and_die("can't find file table"); | 620 | bb_error_msg_and_die("can't find file table"); |
591 | } | 621 | } |
592 | #endif | 622 | #endif |
623 | dbg("File cmpsize:0x%x extra_len:0x%x ucmpsize:0x%x", | ||
624 | (unsigned)zip_header.formatted.cmpsize, | ||
625 | (unsigned)zip_header.formatted.extra_len, | ||
626 | (unsigned)zip_header.formatted.ucmpsize | ||
627 | ); | ||
593 | 628 | ||
594 | /* Read filename */ | 629 | /* Read filename */ |
595 | free(dst_fn); | 630 | free(dst_fn); |
@@ -610,40 +645,55 @@ int unzip_main(int argc, char **argv) | |||
610 | } else { | 645 | } else { |
611 | if (listing) { | 646 | if (listing) { |
612 | /* List entry */ | 647 | /* List entry */ |
613 | unsigned dostime = zip_header.formatted.modtime | (zip_header.formatted.moddate << 16); | 648 | char dtbuf[sizeof("mm-dd-yyyy hh:mm")]; |
649 | sprintf(dtbuf, "%02u-%02u-%04u %02u:%02u", | ||
650 | (zip_header.formatted.moddate >> 5) & 0xf, // mm: 0x01e0 | ||
651 | (zip_header.formatted.moddate) & 0x1f, // dd: 0x001f | ||
652 | (zip_header.formatted.moddate >> 9) + 1980, // yy: 0xfe00 | ||
653 | (zip_header.formatted.modtime >> 11), // hh: 0xf800 | ||
654 | (zip_header.formatted.modtime >> 5) & 0x3f // mm: 0x07e0 | ||
655 | // seconds/2 are not shown, encoded in ----------- 0x001f | ||
656 | ); | ||
614 | if (!verbose) { | 657 | if (!verbose) { |
615 | // " Length Date Time Name\n" | 658 | // " Length Date Time Name\n" |
616 | // " -------- ---- ---- ----" | 659 | // "--------- ---------- ----- ----" |
617 | printf( "%9u %02u-%02u-%02u %02u:%02u %s\n", | 660 | printf( "%9u " "%s " "%s\n", |
618 | (unsigned)zip_header.formatted.ucmpsize, | 661 | (unsigned)zip_header.formatted.ucmpsize, |
619 | (dostime & 0x01e00000) >> 21, | 662 | dtbuf, |
620 | (dostime & 0x001f0000) >> 16, | ||
621 | (((dostime & 0xfe000000) >> 25) + 1980) % 100, | ||
622 | (dostime & 0x0000f800) >> 11, | ||
623 | (dostime & 0x000007e0) >> 5, | ||
624 | dst_fn); | 663 | dst_fn); |
625 | total_usize += zip_header.formatted.ucmpsize; | ||
626 | } else { | 664 | } else { |
627 | unsigned long percents = zip_header.formatted.ucmpsize - zip_header.formatted.cmpsize; | 665 | unsigned long percents = zip_header.formatted.ucmpsize - zip_header.formatted.cmpsize; |
666 | if ((int32_t)percents < 0) | ||
667 | percents = 0; /* happens if ucmpsize < cmpsize */ | ||
628 | percents = percents * 100; | 668 | percents = percents * 100; |
629 | if (zip_header.formatted.ucmpsize) | 669 | if (zip_header.formatted.ucmpsize) |
630 | percents /= zip_header.formatted.ucmpsize; | 670 | percents /= zip_header.formatted.ucmpsize; |
631 | // " Length Method Size Ratio Date Time CRC-32 Name\n" | 671 | // " Length Method Size Cmpr Date Time CRC-32 Name\n" |
632 | // "-------- ------ ------- ----- ---- ---- ------ ----" | 672 | // "-------- ------ ------- ---- ---------- ----- -------- ----" |
633 | printf( "%8u Defl:N" "%9u%4u%% %02u-%02u-%02u %02u:%02u %08x %s\n", | 673 | printf( "%8u %s" "%9u%4u%% " "%s " "%08x " "%s\n", |
634 | (unsigned)zip_header.formatted.ucmpsize, | 674 | (unsigned)zip_header.formatted.ucmpsize, |
675 | zip_header.formatted.method == 0 ? "Stored" : "Defl:N", /* Defl is method 8 */ | ||
676 | /* TODO: show other methods? | ||
677 | * 1 - Shrunk | ||
678 | * 2 - Reduced with compression factor 1 | ||
679 | * 3 - Reduced with compression factor 2 | ||
680 | * 4 - Reduced with compression factor 3 | ||
681 | * 5 - Reduced with compression factor 4 | ||
682 | * 6 - Imploded | ||
683 | * 7 - Reserved for Tokenizing compression algorithm | ||
684 | * 9 - Deflate64 | ||
685 | * 10 - PKWARE Data Compression Library Imploding | ||
686 | * 11 - Reserved by PKWARE | ||
687 | * 12 - BZIP2 | ||
688 | */ | ||
635 | (unsigned)zip_header.formatted.cmpsize, | 689 | (unsigned)zip_header.formatted.cmpsize, |
636 | (unsigned)percents, | 690 | (unsigned)percents, |
637 | (dostime & 0x01e00000) >> 21, | 691 | dtbuf, |
638 | (dostime & 0x001f0000) >> 16, | ||
639 | (((dostime & 0xfe000000) >> 25) + 1980) % 100, | ||
640 | (dostime & 0x0000f800) >> 11, | ||
641 | (dostime & 0x000007e0) >> 5, | ||
642 | zip_header.formatted.crc32, | 692 | zip_header.formatted.crc32, |
643 | dst_fn); | 693 | dst_fn); |
644 | total_usize += zip_header.formatted.ucmpsize; | ||
645 | total_size += zip_header.formatted.cmpsize; | 694 | total_size += zip_header.formatted.cmpsize; |
646 | } | 695 | } |
696 | total_usize += zip_header.formatted.ucmpsize; | ||
647 | i = 'n'; | 697 | i = 'n'; |
648 | } else if (dst_fd == STDOUT_FILENO) { | 698 | } else if (dst_fd == STDOUT_FILENO) { |
649 | /* Extracting to STDOUT */ | 699 | /* Extracting to STDOUT */ |
@@ -746,21 +796,25 @@ int unzip_main(int argc, char **argv) | |||
746 | 796 | ||
747 | if (listing && quiet <= 1) { | 797 | if (listing && quiet <= 1) { |
748 | if (!verbose) { | 798 | if (!verbose) { |
749 | // " Length Date Time Name\n" | 799 | // " Length Date Time Name\n" |
750 | // " -------- ---- ---- ----" | 800 | // "--------- ---------- ----- ----" |
751 | printf( " -------- -------\n" | 801 | printf( " --------%21s" "-------\n" |
752 | "%9lu" " %u files\n", | 802 | "%9lu%21s" "%u files\n", |
753 | total_usize, total_entries); | 803 | "", |
804 | total_usize, "", total_entries); | ||
754 | } else { | 805 | } else { |
755 | unsigned long percents = total_usize - total_size; | 806 | unsigned long percents = total_usize - total_size; |
807 | if ((long)percents < 0) | ||
808 | percents = 0; /* happens if usize < size */ | ||
756 | percents = percents * 100; | 809 | percents = percents * 100; |
757 | if (total_usize) | 810 | if (total_usize) |
758 | percents /= total_usize; | 811 | percents /= total_usize; |
759 | // " Length Method Size Ratio Date Time CRC-32 Name\n" | 812 | // " Length Method Size Cmpr Date Time CRC-32 Name\n" |
760 | // "-------- ------ ------- ----- ---- ---- ------ ----" | 813 | // "-------- ------ ------- ---- ---------- ----- -------- ----" |
761 | printf( "-------- ------- --- -------\n" | 814 | printf( "-------- ------- ----%28s" "----\n" |
762 | "%8lu" "%17lu%4u%% %u files\n", | 815 | "%8lu" "%17lu%4u%%%28s" "%u files\n", |
763 | total_usize, total_size, (unsigned)percents, | 816 | "", |
817 | total_usize, total_size, (unsigned)percents, "", | ||
764 | total_entries); | 818 | total_entries); |
765 | } | 819 | } |
766 | } | 820 | } |