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