1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73#include "libbb.h"
74#include "bb_archive.h"
75
76#if 0
77# define dbg(...) bb_error_msg(__VA_ARGS__)
78#else
79# define dbg(...) ((void)0)
80#endif
81
82enum {
83#if BB_BIG_ENDIAN
84 ZIP_FILEHEADER_MAGIC = 0x504b0304,
85 ZIP_CDF_MAGIC = 0x504b0102,
86 ZIP_CDE_MAGIC = 0x504b0506,
87 ZIP64_CDE_MAGIC = 0x504b0606,
88 ZIP_DD_MAGIC = 0x504b0708,
89#else
90 ZIP_FILEHEADER_MAGIC = 0x04034b50,
91 ZIP_CDF_MAGIC = 0x02014b50,
92 ZIP_CDE_MAGIC = 0x06054b50,
93 ZIP64_CDE_MAGIC = 0x06064b50,
94 ZIP_DD_MAGIC = 0x08074b50,
95#endif
96};
97
98#define ZIP_HEADER_LEN 26
99
100typedef union {
101 uint8_t raw[ZIP_HEADER_LEN];
102 struct {
103 uint16_t version;
104 uint16_t zip_flags;
105 uint16_t method;
106 uint16_t modtime;
107 uint16_t moddate;
108 uint32_t crc32 PACKED;
109 uint32_t cmpsize PACKED;
110 uint32_t ucmpsize PACKED;
111 uint16_t filename_len;
112 uint16_t extra_len;
113
114
115
116 } fmt PACKED;
117} zip_header_t;
118
119#define FIX_ENDIANNESS_ZIP(zip) \
120do { if (BB_BIG_ENDIAN) { \
121 (zip).fmt.method = SWAP_LE16((zip).fmt.method ); \
122 (zip).fmt.modtime = SWAP_LE16((zip).fmt.modtime ); \
123 (zip).fmt.moddate = SWAP_LE16((zip).fmt.moddate ); \
124 (zip).fmt.crc32 = SWAP_LE32((zip).fmt.crc32 ); \
125 (zip).fmt.cmpsize = SWAP_LE32((zip).fmt.cmpsize ); \
126 (zip).fmt.ucmpsize = SWAP_LE32((zip).fmt.ucmpsize ); \
127 (zip).fmt.filename_len = SWAP_LE16((zip).fmt.filename_len); \
128 (zip).fmt.extra_len = SWAP_LE16((zip).fmt.extra_len ); \
129}} while (0)
130
131#define CDF_HEADER_LEN 42
132
133typedef union {
134 uint8_t raw[CDF_HEADER_LEN];
135 struct {
136
137 uint16_t version_made_by;
138 uint16_t version_needed;
139 uint16_t cdf_flags;
140 uint16_t method;
141 uint16_t modtime;
142 uint16_t moddate;
143 uint32_t crc32;
144 uint32_t cmpsize;
145 uint32_t ucmpsize;
146 uint16_t filename_len;
147 uint16_t extra_len;
148 uint16_t file_comment_length;
149 uint16_t disk_number_start;
150 uint16_t internal_attributes;
151 uint32_t external_attributes PACKED;
152 uint32_t relative_offset_of_local_header PACKED;
153
154
155
156 } fmt PACKED;
157} cdf_header_t;
158
159#define FIX_ENDIANNESS_CDF(cdf) \
160do { if (BB_BIG_ENDIAN) { \
161 (cdf).fmt.version_made_by = SWAP_LE16((cdf).fmt.version_made_by); \
162 (cdf).fmt.version_needed = SWAP_LE16((cdf).fmt.version_needed ); \
163 (cdf).fmt.method = SWAP_LE16((cdf).fmt.method ); \
164 (cdf).fmt.modtime = SWAP_LE16((cdf).fmt.modtime ); \
165 (cdf).fmt.moddate = SWAP_LE16((cdf).fmt.moddate ); \
166 (cdf).fmt.crc32 = SWAP_LE32((cdf).fmt.crc32 ); \
167 (cdf).fmt.cmpsize = SWAP_LE32((cdf).fmt.cmpsize ); \
168 (cdf).fmt.ucmpsize = SWAP_LE32((cdf).fmt.ucmpsize ); \
169 (cdf).fmt.filename_len = SWAP_LE16((cdf).fmt.filename_len ); \
170 (cdf).fmt.extra_len = SWAP_LE16((cdf).fmt.extra_len ); \
171 (cdf).fmt.file_comment_length = SWAP_LE16((cdf).fmt.file_comment_length); \
172 (cdf).fmt.external_attributes = SWAP_LE32((cdf).fmt.external_attributes); \
173}} while (0)
174
175#define CDE_LEN 16
176
177typedef union {
178 uint8_t raw[CDE_LEN];
179 struct {
180
181 uint16_t this_disk_no;
182 uint16_t disk_with_cdf_no;
183 uint16_t cdf_entries_on_this_disk;
184 uint16_t cdf_entries_total;
185 uint32_t cdf_size;
186 uint32_t cdf_offset;
187
188
189 } fmt PACKED;
190} cde_t;
191
192#define FIX_ENDIANNESS_CDE(cde) \
193do { if (BB_BIG_ENDIAN) { \
194 (cde).fmt.cdf_offset = SWAP_LE32((cde).fmt.cdf_offset); \
195}} while (0)
196
197struct BUG {
198
199
200
201
202 char BUG_zip_header_must_be_26_bytes[
203 offsetof(zip_header_t, fmt.extra_len) + 2
204 == ZIP_HEADER_LEN ? 1 : -1];
205 char BUG_cdf_header_must_be_42_bytes[
206 offsetof(cdf_header_t, fmt.relative_offset_of_local_header) + 4
207 == CDF_HEADER_LEN ? 1 : -1];
208 char BUG_cde_must_be_16_bytes[
209 sizeof(cde_t) == CDE_LEN ? 1 : -1];
210};
211
212
213enum { zip_fd = 3 };
214
215
216
217#define BAD_CDF_OFFSET ((uint32_t)0xffffffff)
218
219#if !ENABLE_FEATURE_UNZIP_CDF
220
221# define find_cdf_offset() BAD_CDF_OFFSET
222
223#else
224
225
226
227
228
229
230
231#define PEEK_FROM_END (64*1024)
232
233static uint32_t find_cdf_offset(void)
234{
235 cde_t cde;
236 unsigned char *buf;
237 unsigned char *p;
238 off_t end;
239 uint32_t found;
240
241 end = lseek(zip_fd, 0, SEEK_END);
242 if (end == (off_t) -1)
243 return BAD_CDF_OFFSET;
244
245 end -= PEEK_FROM_END;
246 if (end < 0)
247 end = 0;
248
249 dbg("Looking for cdf_offset starting from 0x%"OFF_FMT"x", end);
250 xlseek(zip_fd, end, SEEK_SET);
251 buf = xzalloc(PEEK_FROM_END);
252 full_read(zip_fd, buf, PEEK_FROM_END);
253
254 found = BAD_CDF_OFFSET;
255 p = buf;
256 while (p <= buf + PEEK_FROM_END - CDE_LEN - 4) {
257 if (*p != 'P') {
258 p++;
259 continue;
260 }
261 if (*++p != 'K')
262 continue;
263 if (*++p != 5)
264 continue;
265 if (*++p != 6)
266 continue;
267
268 memcpy(cde.raw, p + 1, CDE_LEN);
269 dbg("cde.this_disk_no:%d", cde.fmt.this_disk_no );
270 dbg("cde.disk_with_cdf_no:%d", cde.fmt.disk_with_cdf_no );
271 dbg("cde.cdf_entries_on_this_disk:%d", cde.fmt.cdf_entries_on_this_disk);
272 dbg("cde.cdf_entries_total:%d", cde.fmt.cdf_entries_total );
273 dbg("cde.cdf_size:%d", cde.fmt.cdf_size );
274 dbg("cde.cdf_offset:%x", cde.fmt.cdf_offset );
275 FIX_ENDIANNESS_CDE(cde);
276
277
278
279
280
281 if (cde.fmt.cdf_offset < end + (p - buf)) {
282 found = cde.fmt.cdf_offset;
283 dbg("Possible cdf_offset:0x%x at 0x%"OFF_FMT"x",
284 (unsigned)found, end + (p-3 - buf));
285 dbg(" cdf_offset+cdf_size:0x%x",
286 (unsigned)(found + SWAP_LE32(cde.fmt.cdf_size)));
287
288
289
290
291
292
293 }
294 }
295 free(buf);
296 dbg("Found cdf_offset:0x%x", (unsigned)found);
297 return found;
298};
299
300static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf)
301{
302 uint32_t magic;
303
304 if (cdf_offset == BAD_CDF_OFFSET)
305 return cdf_offset;
306
307 dbg("Reading CDF at 0x%x", (unsigned)cdf_offset);
308 xlseek(zip_fd, cdf_offset, SEEK_SET);
309 xread(zip_fd, &magic, 4);
310
311
312
313 if (magic == ZIP_CDE_MAGIC) {
314 dbg("got ZIP_CDE_MAGIC");
315 return 0;
316 }
317 if (magic == ZIP64_CDE_MAGIC) {
318 dbg("got ZIP64_CDE_MAGIC");
319 return 0;
320 }
321 xread(zip_fd, cdf->raw, CDF_HEADER_LEN);
322
323 FIX_ENDIANNESS_CDF(*cdf);
324 dbg(" magic:%08x filename_len:%u extra_len:%u file_comment_length:%u",
325 magic,
326 (unsigned)cdf->fmt.filename_len,
327 (unsigned)cdf->fmt.extra_len,
328 (unsigned)cdf->fmt.file_comment_length
329 );
330
331
332 cdf_offset += 4 + CDF_HEADER_LEN
333 + cdf->fmt.filename_len
334 + cdf->fmt.extra_len
335 + cdf->fmt.file_comment_length;
336
337 dbg("Next cdf_offset 0x%x", cdf_offset);
338 return cdf_offset;
339};
340#endif
341
342static void die_if_bad_fnamesize(unsigned sz)
343{
344 if (sz > 0xfff)
345 bb_simple_error_msg_and_die("bad archive");
346}
347
348static void unzip_skip(off_t skip)
349{
350 if (skip != 0)
351 if (lseek(zip_fd, skip, SEEK_CUR) == (off_t)-1)
352 bb_copyfd_exact_size(zip_fd, -1, skip);
353}
354
355static void unzip_create_leading_dirs(const char *fn)
356{
357
358 char *name = xstrdup(fn);
359
360
361 if (bb_make_directory(dirname(name), -1, FILEUTILS_RECUR)) {
362 xfunc_die();
363 }
364 free(name);
365}
366
367#if ENABLE_FEATURE_UNZIP_CDF
368static void unzip_extract_symlink(llist_t **symlink_placeholders,
369 zip_header_t *zip,
370 const char *dst_fn)
371{
372 char *target;
373
374 die_if_bad_fnamesize(zip->fmt.ucmpsize);
375
376 if (zip->fmt.method == 0) {
377
378 target = xzalloc(zip->fmt.ucmpsize + 1);
379 xread(zip_fd, target, zip->fmt.ucmpsize);
380 } else {
381#if 1
382 bb_simple_error_msg_and_die("compressed symlink is not supported");
383#else
384 transformer_state_t xstate;
385 init_transformer_state(&xstate);
386 xstate.mem_output_size_max = zip->fmt.ucmpsize;
387
388 if (!xstate.mem_output_buf)
389 WTF();
390 target = xstate.mem_output_buf;
391 target = xrealloc(target, xstate.mem_output_size + 1);
392 target[xstate.mem_output_size] = '\0';
393#endif
394 }
395 create_or_remember_link(symlink_placeholders,
396 target,
397 dst_fn,
398 0);
399 free(target);
400}
401#endif
402
403static void unzip_extract(zip_header_t *zip, int dst_fd)
404{
405 transformer_state_t xstate;
406
407 if (zip->fmt.method == 0) {
408
409 off_t size = zip->fmt.ucmpsize;
410 if (size)
411 bb_copyfd_exact_size(zip_fd, dst_fd, size);
412 return;
413 }
414
415 init_transformer_state(&xstate);
416 xstate.bytes_in = zip->fmt.cmpsize;
417 xstate.src_fd = zip_fd;
418 xstate.dst_fd = dst_fd;
419 if (zip->fmt.method == 8) {
420
421 if (inflate_unzip(&xstate) < 0)
422 bb_simple_error_msg_and_die("inflate error");
423
424 if (zip->fmt.crc32 != (xstate.crc32 ^ 0xffffffffL)) {
425 bb_simple_error_msg_and_die("crc error");
426 }
427 }
428#if ENABLE_FEATURE_UNZIP_BZIP2
429 else if (zip->fmt.method == 12) {
430
431
432
433 xstate.bytes_out = unpack_bz2_stream(&xstate);
434 if (xstate.bytes_out < 0)
435 bb_simple_error_msg_and_die("inflate error");
436 }
437#endif
438#if ENABLE_FEATURE_UNZIP_LZMA
439 else if (zip->fmt.method == 14) {
440
441 xstate.bytes_out = unpack_lzma_stream(&xstate);
442 if (xstate.bytes_out < 0)
443 bb_simple_error_msg_and_die("inflate error");
444 }
445#endif
446#if ENABLE_FEATURE_UNZIP_XZ
447 else if (zip->fmt.method == 95) {
448
449 xstate.bytes_out = unpack_xz_stream(&xstate);
450 if (xstate.bytes_out < 0)
451 bb_simple_error_msg_and_die("inflate error");
452 }
453#endif
454 else {
455 bb_error_msg_and_die("unsupported method %u", zip->fmt.method);
456 }
457
458
459 if (zip->fmt.ucmpsize != 0xffffffff
460 && zip->fmt.ucmpsize != xstate.bytes_out
461 ) {
462
463
464 bb_simple_error_msg("bad length");
465 }
466}
467
468static void my_fgets80(char *buf80)
469{
470 fflush_all();
471 if (!fgets(buf80, 80, stdin)) {
472 bb_simple_perror_msg_and_die("can't read standard input");
473 }
474}
475
476static int get_lstat_mode(const char *dst_fn)
477{
478 struct stat stat_buf;
479 if (lstat(dst_fn, &stat_buf) == -1) {
480 if (errno != ENOENT) {
481 bb_perror_msg_and_die("can't stat '%s'",
482 dst_fn
483 );
484 }
485
486 return -1;
487 }
488 return stat_buf.st_mode;
489}
490
491int unzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
492int unzip_main(int argc, char **argv)
493{
494 enum {
495 OPT_l = (1 << 0),
496 OPT_x = (1 << 1),
497 OPT_j = (1 << 2),
498 OPT_K = (1 << 3),
499 };
500 unsigned opts;
501 smallint quiet = 0;
502 IF_NOT_FEATURE_UNZIP_CDF(const) smallint verbose = 0;
503 enum { O_PROMPT, O_NEVER, O_ALWAYS };
504 smallint overwrite = O_PROMPT;
505 uint32_t cdf_offset;
506 unsigned long total_usize;
507 unsigned long total_size;
508 unsigned total_entries;
509 int dst_fd = -1;
510 char *src_fn = NULL;
511 char *dst_fn = NULL;
512 llist_t *zaccept = NULL;
513 llist_t *zreject = NULL;
514 char *base_dir = NULL;
515#if ENABLE_FEATURE_UNZIP_CDF
516 llist_t *symlink_placeholders = NULL;
517#endif
518 int i;
519 char key_buf[80];
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567 opts = 0;
568
569 while ((i = getopt(argc, argv, "-d:lnotpqxjvK")) != -1) {
570 switch (i) {
571 case 'd':
572 base_dir = optarg;
573 break;
574
575 case 'l':
576 opts |= OPT_l;
577 break;
578
579 case 'n':
580 overwrite = O_NEVER;
581 break;
582
583 case 'o':
584 overwrite = O_ALWAYS;
585 break;
586
587 case 't':
588 xmove_fd(xopen("/dev/null", O_WRONLY), STDOUT_FILENO);
589
590
591
592 case 'p':
593 dst_fd = STDOUT_FILENO;
594
595
596 case 'q':
597 quiet++;
598 break;
599
600 case 'v':
601 IF_FEATURE_UNZIP_CDF(verbose++;)
602 opts |= OPT_l;
603 break;
604
605 case 'x':
606 opts |= OPT_x;
607 break;
608
609 case 'j':
610 opts |= OPT_j;
611 break;
612
613 case 'K':
614 opts |= OPT_K;
615 break;
616
617 case 1:
618 if (!src_fn) {
619
620
621 src_fn = xmalloc(strlen(optarg) + 5);
622 strcpy(src_fn, optarg);
623 } else if (!(opts & OPT_x)) {
624
625 llist_add_to(&zaccept, optarg);
626 } else {
627
628 llist_add_to(&zreject, optarg);
629 }
630 break;
631
632 default:
633 bb_show_usage();
634 }
635 }
636
637#ifndef __GLIBC__
638
639
640
641
642
643
644
645 argv += optind;
646 if (argv[0]) {
647
648 src_fn = xmalloc(strlen(argv[0]) + 5);
649 strcpy(src_fn, argv[0]);
650 while (*++argv)
651 llist_add_to(&zaccept, *argv);
652 }
653#endif
654
655 if (!src_fn) {
656 bb_show_usage();
657 }
658
659
660 if (LONE_DASH(src_fn)) {
661 xdup2(STDIN_FILENO, zip_fd);
662
663 if (overwrite == O_PROMPT)
664 overwrite = O_NEVER;
665 } else {
666 static const char extn[][5] ALIGN1 = { ".zip", ".ZIP" };
667 char *ext = src_fn + strlen(src_fn);
668 int src_fd;
669
670 i = 0;
671 for (;;) {
672 src_fd = open(src_fn, O_RDONLY);
673 if (src_fd >= 0)
674 break;
675 if (++i > 2) {
676 *ext = '\0';
677 bb_error_msg_and_die("can't open %s[.zip]",
678 src_fn
679 );
680 }
681 strcpy(ext, extn[i - 1]);
682 }
683 xmove_fd(src_fd, zip_fd);
684 }
685
686
687 if (base_dir) {
688
689
690
691
692 mkdir(base_dir, 0777);
693 xchdir(base_dir);
694 }
695
696 if (quiet <= 1) {
697 if (quiet == 0) {
698 printf("Archive: %s\n",
699 printable_string(src_fn)
700 );
701 }
702 if (opts & OPT_l) {
703 puts(verbose ?
704 " Length Method Size Cmpr Date Time CRC-32 Name\n"
705 "-------- ------ ------- ---- ---------- ----- -------- ----"
706 :
707 " Length Date Time Name\n"
708 "--------- ---------- ----- ----"
709 );
710 }
711 }
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732 total_usize = 0;
733 total_size = 0;
734 total_entries = 0;
735 cdf_offset = find_cdf_offset();
736 while (1) {
737 zip_header_t zip;
738 mode_t dir_mode = 0777;
739#if ENABLE_FEATURE_UNZIP_CDF
740 mode_t file_mode = 0666;
741#endif
742
743 if (!ENABLE_FEATURE_UNZIP_CDF || cdf_offset == BAD_CDF_OFFSET) {
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759 uint32_t magic;
760
761
762 xread(zip_fd, &magic, 4);
763
764 if (magic == ZIP_CDF_MAGIC) {
765 dbg("got ZIP_CDF_MAGIC");
766 break;
767 }
768
769 if (magic == ZIP_DD_MAGIC) {
770 dbg("got ZIP_DD_MAGIC");
771
772 unzip_skip(3 * 4);
773 continue;
774 }
775 if (magic != ZIP_FILEHEADER_MAGIC)
776 bb_error_msg_and_die("invalid zip magic %08X", (int)magic);
777 dbg("got ZIP_FILEHEADER_MAGIC");
778
779 xread(zip_fd, zip.raw, ZIP_HEADER_LEN);
780 FIX_ENDIANNESS_ZIP(zip);
781 if (zip.fmt.zip_flags & SWAP_LE16(0x0008)) {
782 bb_error_msg_and_die("zip flag %s is not supported",
783 "8 (streaming)");
784 }
785 }
786#if ENABLE_FEATURE_UNZIP_CDF
787 else {
788
789 cdf_header_t cdf;
790 cdf_offset = read_next_cdf(cdf_offset, &cdf);
791 if (cdf_offset == 0)
792 break;
793# if 1
794 xlseek(zip_fd,
795 SWAP_LE32(cdf.fmt.relative_offset_of_local_header) + 4,
796 SEEK_SET);
797 xread(zip_fd, zip.raw, ZIP_HEADER_LEN);
798 FIX_ENDIANNESS_ZIP(zip);
799 if (zip.fmt.zip_flags & SWAP_LE16(0x0008)) {
800
801
802
803 zip.fmt.crc32 = cdf.fmt.crc32;
804 zip.fmt.cmpsize = cdf.fmt.cmpsize;
805 zip.fmt.ucmpsize = cdf.fmt.ucmpsize;
806 }
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821# else
822
823
824
825
826 memcpy(&zip.fmt.version,
827 &cdf.fmt.version_needed, ZIP_HEADER_LEN);
828 xlseek(zip_fd,
829 SWAP_LE32(cdf.fmt.relative_offset_of_local_header) + 4 + ZIP_HEADER_LEN,
830 SEEK_SET);
831# endif
832 if ((cdf.fmt.version_made_by >> 8) == 3) {
833
834 file_mode = (cdf.fmt.external_attributes >> 16);
835 if (!(opts & OPT_K))
836 file_mode &= ~(mode_t)(S_ISUID | S_ISGID);
837 dir_mode = file_mode;
838 }
839 }
840#endif
841
842 if (zip.fmt.zip_flags & SWAP_LE16(0x0001)) {
843
844 bb_error_msg_and_die("zip flag %s is not supported",
845 "1 (encryption)");
846 }
847 dbg("File cmpsize:0x%x extra_len:0x%x ucmpsize:0x%x",
848 (unsigned)zip.fmt.cmpsize,
849 (unsigned)zip.fmt.extra_len,
850 (unsigned)zip.fmt.ucmpsize
851 );
852
853
854 free(dst_fn);
855 die_if_bad_fnamesize(zip.fmt.filename_len);
856 dst_fn = xzalloc(zip.fmt.filename_len + 1);
857 xread(zip_fd, dst_fn, zip.fmt.filename_len);
858
859 unzip_skip(zip.fmt.extra_len);
860
861
862
863 overlapping_strcpy(dst_fn, strip_unsafe_prefix(dst_fn));
864
865
866 if (find_list_entry(zreject, dst_fn)
867 || (zaccept && !find_list_entry(zaccept, dst_fn))
868 ) {
869 goto skip_cmpsize;
870 }
871
872 if (opts & OPT_l) {
873
874 char dtbuf[sizeof("mm-dd-yyyy hh:mm")];
875 sprintf(dtbuf, "%02u-%02u-%04u %02u:%02u",
876 (zip.fmt.moddate >> 5) & 0xf,
877 (zip.fmt.moddate) & 0x1f,
878 (zip.fmt.moddate >> 9) + 1980,
879 (zip.fmt.modtime >> 11),
880 (zip.fmt.modtime >> 5) & 0x3f
881
882 );
883 if (!verbose) {
884
885
886 printf( "%9u " "%s " "%s\n",
887 (unsigned)zip.fmt.ucmpsize,
888 dtbuf,
889 printable_string(dst_fn)
890 );
891 } else {
892 char method6[7];
893 unsigned long percents;
894
895 sprintf(method6, "%6u", zip.fmt.method);
896 if (zip.fmt.method == 0) {
897 strcpy(method6, "Stored");
898 }
899 if (zip.fmt.method == 8) {
900 strcpy(method6, "Defl:N");
901
902 IF_DESKTOP(method6[5] = "NXFS"[(zip.fmt.zip_flags >> 1) & 3];)
903 }
904 percents = zip.fmt.ucmpsize - zip.fmt.cmpsize;
905 if ((int32_t)percents < 0)
906 percents = 0;
907 percents = percents * 100;
908 if (zip.fmt.ucmpsize)
909 percents /= zip.fmt.ucmpsize;
910
911
912 printf( "%8u %s" "%9u%4u%% " "%s " "%08x " "%s\n",
913 (unsigned)zip.fmt.ucmpsize,
914 method6,
915 (unsigned)zip.fmt.cmpsize,
916 (unsigned)percents,
917 dtbuf,
918 zip.fmt.crc32,
919 printable_string(dst_fn)
920 );
921 total_size += zip.fmt.cmpsize;
922 }
923 total_usize += zip.fmt.ucmpsize;
924 goto skip_cmpsize;
925 }
926
927 if (dst_fd == STDOUT_FILENO) {
928
929 goto do_extract;
930 }
931
932
933 if (opts & OPT_j)
934 overlapping_strcpy(dst_fn, bb_basename(dst_fn));
935
936 if (!dst_fn[0])
937 goto skip_cmpsize;
938
939 if (last_char_is(dst_fn, '/')) {
940 int mode;
941
942
943 mode = get_lstat_mode(dst_fn);
944 if (mode == -1) {
945 if (!quiet) {
946 printf(" creating: %s\n", printable_string(dst_fn));
947 }
948 unzip_create_leading_dirs(dst_fn);
949 if (bb_make_directory(dst_fn, dir_mode, FILEUTILS_IGNORE_CHMOD_ERR)) {
950 xfunc_die();
951 }
952 } else {
953 if (!S_ISDIR(mode)) {
954 bb_error_msg_and_die("'%s' exists but is not a %s",
955 printable_string(dst_fn),
956 "directory"
957 );
958 }
959 }
960 goto skip_cmpsize;
961 }
962 check_file:
963
964 {
965 int mode = get_lstat_mode(dst_fn);
966 if (mode == -1) {
967
968 goto do_open_and_extract;
969 }
970 if (overwrite == O_NEVER) {
971 goto skip_cmpsize;
972 }
973 if (!S_ISREG(mode)) {
974 fishy:
975 bb_error_msg_and_die("'%s' exists but is not a %s",
976 printable_string(dst_fn),
977 "regular file"
978 );
979 }
980 if (overwrite == O_ALWAYS) {
981 goto do_open_and_extract;
982 }
983 printf("replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ",
984 printable_string(dst_fn)
985 );
986 my_fgets80(key_buf);
987
988 mode = get_lstat_mode(dst_fn);
989 if (!S_ISREG(mode))
990 goto fishy;
991 }
992
993
994 switch (key_buf[0]) {
995 case 'A':
996 overwrite = O_ALWAYS;
997 case 'y':
998 do_open_and_extract:
999 unzip_create_leading_dirs(dst_fn);
1000#if ENABLE_FEATURE_UNZIP_CDF
1001 dst_fd = -1;
1002 if (!S_ISLNK(file_mode)) {
1003 dst_fd = xopen3(dst_fn,
1004 O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW,
1005 file_mode);
1006 }
1007#else
1008
1009 dst_fd = xopen(dst_fn, O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW);
1010#endif
1011 if (!quiet) {
1012 printf(
1013
1014 " inflating: %s\n",
1015 printable_string(dst_fn)
1016 );
1017 }
1018 do_extract:
1019#if ENABLE_FEATURE_UNZIP_CDF
1020 if (S_ISLNK(file_mode)) {
1021 if (dst_fd != STDOUT_FILENO)
1022 unzip_extract_symlink(&symlink_placeholders, &zip, dst_fn);
1023 } else
1024#endif
1025 {
1026 unzip_extract(&zip, dst_fd);
1027 if (dst_fd != STDOUT_FILENO) {
1028
1029 close(dst_fd);
1030 }
1031 }
1032 break;
1033
1034 case 'N':
1035 overwrite = O_NEVER;
1036 case 'n':
1037 skip_cmpsize:
1038 unzip_skip(zip.fmt.cmpsize);
1039 break;
1040
1041 case 'r':
1042
1043 printf("new name: ");
1044 my_fgets80(key_buf);
1045 free(dst_fn);
1046 dst_fn = xstrdup(key_buf);
1047 chomp(dst_fn);
1048 goto check_file;
1049
1050 default:
1051 printf("error: invalid response [%c]\n", (char)key_buf[0]);
1052 goto check_file;
1053 }
1054
1055 total_entries++;
1056 }
1057
1058#if ENABLE_FEATURE_UNZIP_CDF
1059 create_links_from_list(symlink_placeholders);
1060#endif
1061
1062 if ((opts & OPT_l) && quiet <= 1) {
1063 if (!verbose) {
1064
1065
1066 printf( " --------%21s" "-------\n"
1067 "%9lu%21s" "%u files\n",
1068 "",
1069 total_usize, "", total_entries);
1070 } else {
1071 unsigned long percents = total_usize - total_size;
1072 if ((long)percents < 0)
1073 percents = 0;
1074 percents = percents * 100;
1075 if (total_usize)
1076 percents /= total_usize;
1077
1078
1079 printf( "-------- ------- ----%28s" "----\n"
1080 "%8lu" "%17lu%4u%%%28s" "%u files\n",
1081 "",
1082 total_usize, total_size, (unsigned)percents, "",
1083 total_entries);
1084 }
1085 }
1086
1087 return 0;
1088}
1089