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'",
460 dst_fn
461 );
462 }
463
464 return -1;
465 }
466 return stat_buf.st_mode;
467}
468
469int unzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
470int unzip_main(int argc, char **argv)
471{
472 enum {
473 OPT_l = (1 << 0),
474 OPT_x = (1 << 1),
475 OPT_j = (1 << 2),
476 };
477 unsigned opts;
478 smallint quiet = 0;
479 IF_NOT_FEATURE_UNZIP_CDF(const) smallint verbose = 0;
480 enum { O_PROMPT, O_NEVER, O_ALWAYS };
481 smallint overwrite = O_PROMPT;
482 uint32_t cdf_offset;
483 unsigned long total_usize;
484 unsigned long total_size;
485 unsigned total_entries;
486 int dst_fd = -1;
487 char *src_fn = NULL;
488 char *dst_fn = NULL;
489 llist_t *zaccept = NULL;
490 llist_t *zreject = NULL;
491 char *base_dir = NULL;
492#if ENABLE_FEATURE_UNZIP_CDF
493 llist_t *symlink_placeholders = NULL;
494#endif
495 int i;
496 char key_buf[80];
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
538
539 opts = 0;
540
541 while ((i = getopt(argc, argv, "-d:lnopqxjv")) != -1) {
542 switch (i) {
543 case 'd':
544 base_dir = optarg;
545 break;
546
547 case 'l':
548 opts |= OPT_l;
549 break;
550
551 case 'n':
552 overwrite = O_NEVER;
553 break;
554
555 case 'o':
556 overwrite = O_ALWAYS;
557 break;
558
559 case 'p':
560 dst_fd = STDOUT_FILENO;
561
562 case 'q':
563 quiet++;
564 break;
565
566 case 'v':
567 IF_FEATURE_UNZIP_CDF(verbose++;)
568 opts |= OPT_l;
569 break;
570
571 case 'x':
572 opts |= OPT_x;
573 break;
574
575 case 'j':
576 opts |= OPT_j;
577 break;
578
579 case 1:
580 if (!src_fn) {
581
582
583 src_fn = xmalloc(strlen(optarg) + 5);
584 strcpy(src_fn, optarg);
585 } else if (!(opts & OPT_x)) {
586
587 llist_add_to(&zaccept, optarg);
588 } else {
589
590 llist_add_to(&zreject, optarg);
591 }
592 break;
593
594 default:
595 bb_show_usage();
596 }
597 }
598
599#ifndef __GLIBC__
600
601
602
603
604
605
606
607 argv += optind;
608 if (argv[0]) {
609
610 src_fn = xmalloc(strlen(argv[0]) + 5);
611 strcpy(src_fn, argv[0]);
612 while (*++argv)
613 llist_add_to(&zaccept, *argv);
614 }
615#endif
616
617 if (!src_fn) {
618 bb_show_usage();
619 }
620
621
622 if (LONE_DASH(src_fn)) {
623 xdup2(STDIN_FILENO, zip_fd);
624
625 if (overwrite == O_PROMPT)
626 overwrite = O_NEVER;
627 } else {
628 static const char extn[][5] ALIGN1 = { ".zip", ".ZIP" };
629 char *ext = src_fn + strlen(src_fn);
630 int src_fd;
631
632 i = 0;
633 for (;;) {
634 src_fd = open(src_fn, O_RDONLY);
635 if (src_fd >= 0)
636 break;
637 if (++i > 2) {
638 *ext = '\0';
639 bb_error_msg_and_die("can't open %s[.zip]",
640 src_fn
641 );
642 }
643 strcpy(ext, extn[i - 1]);
644 }
645 xmove_fd(src_fd, zip_fd);
646 }
647
648
649 if (base_dir)
650 xchdir(base_dir);
651
652 if (quiet <= 1) {
653 if (quiet == 0) {
654 printf("Archive: %s\n",
655 printable_string(src_fn)
656 );
657 }
658 if (opts & OPT_l) {
659 puts(verbose ?
660 " Length Method Size Cmpr Date Time CRC-32 Name\n"
661 "-------- ------ ------- ---- ---------- ----- -------- ----"
662 :
663 " Length Date Time Name\n"
664 "--------- ---------- ----- ----"
665 );
666 }
667 }
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688 total_usize = 0;
689 total_size = 0;
690 total_entries = 0;
691 cdf_offset = find_cdf_offset();
692 while (1) {
693 zip_header_t zip;
694 mode_t dir_mode = 0777;
695#if ENABLE_FEATURE_UNZIP_CDF
696 mode_t file_mode = 0666;
697#endif
698
699 if (!ENABLE_FEATURE_UNZIP_CDF || cdf_offset == BAD_CDF_OFFSET) {
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715 uint32_t magic;
716
717
718 xread(zip_fd, &magic, 4);
719
720 if (magic == ZIP_CDF_MAGIC) {
721 dbg("got ZIP_CDF_MAGIC");
722 break;
723 }
724
725 if (magic == ZIP_DD_MAGIC) {
726 dbg("got ZIP_DD_MAGIC");
727
728 unzip_skip(3 * 4);
729 continue;
730 }
731 if (magic != ZIP_FILEHEADER_MAGIC)
732 bb_error_msg_and_die("invalid zip magic %08X", (int)magic);
733 dbg("got ZIP_FILEHEADER_MAGIC");
734
735 xread(zip_fd, zip.raw, ZIP_HEADER_LEN);
736 FIX_ENDIANNESS_ZIP(zip);
737 if (zip.fmt.zip_flags & SWAP_LE16(0x0008)) {
738 bb_error_msg_and_die("zip flag %s is not supported",
739 "8 (streaming)");
740 }
741 }
742#if ENABLE_FEATURE_UNZIP_CDF
743 else {
744
745 cdf_header_t cdf;
746 cdf_offset = read_next_cdf(cdf_offset, &cdf);
747 if (cdf_offset == 0)
748 break;
749# if 1
750 xlseek(zip_fd,
751 SWAP_LE32(cdf.fmt.relative_offset_of_local_header) + 4,
752 SEEK_SET);
753 xread(zip_fd, zip.raw, ZIP_HEADER_LEN);
754 FIX_ENDIANNESS_ZIP(zip);
755 if (zip.fmt.zip_flags & SWAP_LE16(0x0008)) {
756
757
758
759 zip.fmt.crc32 = cdf.fmt.crc32;
760 zip.fmt.cmpsize = cdf.fmt.cmpsize;
761 zip.fmt.ucmpsize = cdf.fmt.ucmpsize;
762 }
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777# else
778
779
780
781
782 memcpy(&zip.fmt.version,
783 &cdf.fmt.version_needed, ZIP_HEADER_LEN);
784 xlseek(zip_fd,
785 SWAP_LE32(cdf.fmt.relative_offset_of_local_header) + 4 + ZIP_HEADER_LEN,
786 SEEK_SET);
787# endif
788 if ((cdf.fmt.version_made_by >> 8) == 3) {
789
790 dir_mode = file_mode = (cdf.fmt.external_attributes >> 16);
791 }
792 }
793#endif
794
795 if (zip.fmt.zip_flags & SWAP_LE16(0x0001)) {
796
797 bb_error_msg_and_die("zip flag %s is not supported",
798 "1 (encryption)");
799 }
800 dbg("File cmpsize:0x%x extra_len:0x%x ucmpsize:0x%x",
801 (unsigned)zip.fmt.cmpsize,
802 (unsigned)zip.fmt.extra_len,
803 (unsigned)zip.fmt.ucmpsize
804 );
805
806
807 free(dst_fn);
808 die_if_bad_fnamesize(zip.fmt.filename_len);
809 dst_fn = xzalloc(zip.fmt.filename_len + 1);
810 xread(zip_fd, dst_fn, zip.fmt.filename_len);
811
812 unzip_skip(zip.fmt.extra_len);
813
814
815 overlapping_strcpy(dst_fn, strip_unsafe_prefix(dst_fn));
816
817
818 if (find_list_entry(zreject, dst_fn)
819 || (zaccept && !find_list_entry(zaccept, dst_fn))
820 ) {
821 goto skip_cmpsize;
822 }
823
824 if (opts & OPT_l) {
825
826 char dtbuf[sizeof("mm-dd-yyyy hh:mm")];
827 sprintf(dtbuf, "%02u-%02u-%04u %02u:%02u",
828 (zip.fmt.moddate >> 5) & 0xf,
829 (zip.fmt.moddate) & 0x1f,
830 (zip.fmt.moddate >> 9) + 1980,
831 (zip.fmt.modtime >> 11),
832 (zip.fmt.modtime >> 5) & 0x3f
833
834 );
835 if (!verbose) {
836
837
838 printf( "%9u " "%s " "%s\n",
839 (unsigned)zip.fmt.ucmpsize,
840 dtbuf,
841 printable_string(dst_fn)
842 );
843 } else {
844 char method6[7];
845 unsigned long percents;
846
847 sprintf(method6, "%6u", zip.fmt.method);
848 if (zip.fmt.method == 0) {
849 strcpy(method6, "Stored");
850 }
851 if (zip.fmt.method == 8) {
852 strcpy(method6, "Defl:N");
853
854 IF_DESKTOP(method6[5] = "NXFS"[(zip.fmt.zip_flags >> 1) & 3];)
855 }
856 percents = zip.fmt.ucmpsize - zip.fmt.cmpsize;
857 if ((int32_t)percents < 0)
858 percents = 0;
859 percents = percents * 100;
860 if (zip.fmt.ucmpsize)
861 percents /= zip.fmt.ucmpsize;
862
863
864 printf( "%8u %s" "%9u%4u%% " "%s " "%08x " "%s\n",
865 (unsigned)zip.fmt.ucmpsize,
866 method6,
867 (unsigned)zip.fmt.cmpsize,
868 (unsigned)percents,
869 dtbuf,
870 zip.fmt.crc32,
871 printable_string(dst_fn)
872 );
873 total_size += zip.fmt.cmpsize;
874 }
875 total_usize += zip.fmt.ucmpsize;
876 goto skip_cmpsize;
877 }
878
879 if (dst_fd == STDOUT_FILENO) {
880
881 goto do_extract;
882 }
883
884
885 if (opts & OPT_j)
886 overlapping_strcpy(dst_fn, bb_basename(dst_fn));
887
888 if (!dst_fn[0])
889 goto skip_cmpsize;
890
891 if (last_char_is(dst_fn, '/')) {
892 int mode;
893
894
895 mode = get_lstat_mode(dst_fn);
896 if (mode == -1) {
897 if (!quiet) {
898 printf(" creating: %s\n", printable_string(dst_fn));
899 }
900 unzip_create_leading_dirs(dst_fn);
901 if (bb_make_directory(dst_fn, dir_mode, FILEUTILS_IGNORE_CHMOD_ERR)) {
902 xfunc_die();
903 }
904 } else {
905 if (!S_ISDIR(mode)) {
906 bb_error_msg_and_die("'%s' exists but is not a %s",
907 printable_string(dst_fn),
908 "directory"
909 );
910 }
911 }
912 goto skip_cmpsize;
913 }
914 check_file:
915
916 {
917 int mode = get_lstat_mode(dst_fn);
918 if (mode == -1) {
919
920 goto do_open_and_extract;
921 }
922 if (overwrite == O_NEVER) {
923 goto skip_cmpsize;
924 }
925 if (!S_ISREG(mode)) {
926 fishy:
927 bb_error_msg_and_die("'%s' exists but is not a %s",
928 printable_string(dst_fn),
929 "regular file"
930 );
931 }
932 if (overwrite == O_ALWAYS) {
933 goto do_open_and_extract;
934 }
935 printf("replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ",
936 printable_string(dst_fn)
937 );
938 my_fgets80(key_buf);
939
940 mode = get_lstat_mode(dst_fn);
941 if (!S_ISREG(mode))
942 goto fishy;
943 }
944
945
946 switch (key_buf[0]) {
947 case 'A':
948 overwrite = O_ALWAYS;
949 case 'y':
950 do_open_and_extract:
951 unzip_create_leading_dirs(dst_fn);
952#if ENABLE_FEATURE_UNZIP_CDF
953 dst_fd = -1;
954 if (!S_ISLNK(file_mode)) {
955 dst_fd = xopen3(dst_fn,
956 O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW,
957 file_mode);
958 }
959#else
960
961 dst_fd = xopen(dst_fn, O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW);
962#endif
963 do_extract:
964 if (!quiet) {
965 printf(
966
967 " inflating: %s\n",
968 printable_string(dst_fn)
969 );
970 }
971#if ENABLE_FEATURE_UNZIP_CDF
972 if (S_ISLNK(file_mode)) {
973 if (dst_fd != STDOUT_FILENO)
974 unzip_extract_symlink(&symlink_placeholders, &zip, dst_fn);
975 } else
976#endif
977 {
978 unzip_extract(&zip, dst_fd);
979 if (dst_fd != STDOUT_FILENO) {
980
981 close(dst_fd);
982 }
983 }
984 break;
985
986 case 'N':
987 overwrite = O_NEVER;
988 case 'n':
989 skip_cmpsize:
990 unzip_skip(zip.fmt.cmpsize);
991 break;
992
993 case 'r':
994
995 printf("new name: ");
996 my_fgets80(key_buf);
997 free(dst_fn);
998 dst_fn = xstrdup(key_buf);
999 chomp(dst_fn);
1000 goto check_file;
1001
1002 default:
1003 printf("error: invalid response [%c]\n", (char)key_buf[0]);
1004 goto check_file;
1005 }
1006
1007 total_entries++;
1008 }
1009
1010#if ENABLE_FEATURE_UNZIP_CDF
1011 create_links_from_list(symlink_placeholders);
1012#endif
1013
1014 if ((opts & OPT_l) && quiet <= 1) {
1015 if (!verbose) {
1016
1017
1018 printf( " --------%21s" "-------\n"
1019 "%9lu%21s" "%u files\n",
1020 "",
1021 total_usize, "", total_entries);
1022 } else {
1023 unsigned long percents = total_usize - total_size;
1024 if ((long)percents < 0)
1025 percents = 0;
1026 percents = percents * 100;
1027 if (total_usize)
1028 percents /= total_usize;
1029
1030
1031 printf( "-------- ------- ----%28s" "----\n"
1032 "%8lu" "%17lu%4u%%%28s" "%u files\n",
1033 "",
1034 total_usize, total_size, (unsigned)percents, "",
1035 total_entries);
1036 }
1037 }
1038
1039 return 0;
1040}
1041