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