1 /* $NetBSD: unzip.c,v 1.24 2018/07/19 18:04:25 joerg Exp $ */ 2 3 /*- 4 * Copyright (c) 2009, 2010 Joerg Sonnenberger <joerg@NetBSD.org> 5 * Copyright (c) 2007-2008 Dag-Erling Co�dan Sm�rgrav 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer 13 * in this position and unchanged. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * $FreeBSD: revision 180124$ 31 * 32 * This file would be much shorter if we didn't care about command-line 33 * compatibility with Info-ZIP's UnZip, which requires us to duplicate 34 * parts of libarchive in order to gain more detailed control of its 35 * behaviour for the purpose of implementing the -n, -o, -L and -a 36 * options. 37 */ 38 39 #include <sys/cdefs.h> 40 __RCSID("$NetBSD: unzip.c,v 1.24 2018/07/19 18:04:25 joerg Exp $"); 41 42 #include <sys/queue.h> 43 #include <sys/stat.h> 44 45 #include <ctype.h> 46 #include <errno.h> 47 #include <fcntl.h> 48 #include <fnmatch.h> 49 #include <stdarg.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <unistd.h> 54 55 #include <archive.h> 56 #include <archive_entry.h> 57 58 /* command-line options */ 59 static int a_opt; /* convert EOL */ 60 static int C_opt; /* match case-insensitively */ 61 static int c_opt; /* extract to stdout */ 62 static const char *d_arg; /* directory */ 63 static int f_opt; /* update existing files only */ 64 static int j_opt; /* junk directories */ 65 static int L_opt; /* lowercase names */ 66 static int n_opt; /* never overwrite */ 67 static int o_opt; /* always overwrite */ 68 static int p_opt; /* extract to stdout, quiet */ 69 static int q_opt; /* quiet */ 70 static int t_opt; /* test */ 71 static int u_opt; /* update */ 72 static int v_opt; /* verbose/list */ 73 static const char * y_str = ""; /* 4 digit year */ 74 75 /* time when unzip started */ 76 static time_t now; 77 78 /* debug flag */ 79 static int unzip_debug; 80 81 /* running on tty? */ 82 static int tty; 83 84 /* convenience macro */ 85 /* XXX should differentiate between ARCHIVE_{WARN,FAIL,RETRY} */ 86 #define ac(call) \ 87 do { \ 88 int acret = (call); \ 89 if (acret != ARCHIVE_OK) \ 90 errorx("%s", archive_error_string(a)); \ 91 } while (0) 92 93 /* 94 * Indicates that last info() did not end with EOL. This helps error() et 95 * al. avoid printing an error message on the same line as an incomplete 96 * informational message. 97 */ 98 static int noeol; 99 100 /* fatal error message + errno */ 101 __dead __printflike(1, 2) static void 102 error(const char *fmt, ...) 103 { 104 va_list ap; 105 106 if (noeol) 107 fprintf(stdout, "\n"); 108 fflush(stdout); 109 fprintf(stderr, "unzip: "); 110 va_start(ap, fmt); 111 vfprintf(stderr, fmt, ap); 112 va_end(ap); 113 fprintf(stderr, ": %s\n", strerror(errno)); 114 exit(1); 115 } 116 117 /* fatal error message, no errno */ 118 __dead __printflike(1, 2) static void 119 errorx(const char *fmt, ...) 120 { 121 va_list ap; 122 123 if (noeol) 124 fprintf(stdout, "\n"); 125 fflush(stdout); 126 fprintf(stderr, "unzip: "); 127 va_start(ap, fmt); 128 vfprintf(stderr, fmt, ap); 129 va_end(ap); 130 fprintf(stderr, "\n"); 131 exit(1); 132 } 133 134 /* non-fatal error message + errno */ 135 __printflike(1, 2) static void 136 warning(const char *fmt, ...) 137 { 138 va_list ap; 139 140 if (noeol) 141 fprintf(stdout, "\n"); 142 fflush(stdout); 143 fprintf(stderr, "unzip: "); 144 va_start(ap, fmt); 145 vfprintf(stderr, fmt, ap); 146 va_end(ap); 147 fprintf(stderr, ": %s\n", strerror(errno)); 148 } 149 150 /* non-fatal error message, no errno */ 151 __printflike(1, 2) static void 152 warningx(const char *fmt, ...) 153 { 154 va_list ap; 155 156 if (noeol) 157 fprintf(stdout, "\n"); 158 fflush(stdout); 159 fprintf(stderr, "unzip: "); 160 va_start(ap, fmt); 161 vfprintf(stderr, fmt, ap); 162 va_end(ap); 163 fprintf(stderr, "\n"); 164 } 165 166 /* informational message (if not -q) */ 167 __printflike(1, 2) static void 168 info(const char *fmt, ...) 169 { 170 va_list ap; 171 172 if (q_opt && !unzip_debug) 173 return; 174 va_start(ap, fmt); 175 vfprintf(stdout, fmt, ap); 176 va_end(ap); 177 fflush(stdout); 178 179 if (*fmt == '\0') 180 noeol = 1; 181 else 182 noeol = fmt[strlen(fmt) - 1] != '\n'; 183 } 184 185 /* debug message (if unzip_debug) */ 186 __printflike(1, 2) static void 187 debug(const char *fmt, ...) 188 { 189 va_list ap; 190 191 if (!unzip_debug) 192 return; 193 va_start(ap, fmt); 194 vfprintf(stderr, fmt, ap); 195 va_end(ap); 196 fflush(stderr); 197 198 if (*fmt == '\0') 199 noeol = 1; 200 else 201 noeol = fmt[strlen(fmt) - 1] != '\n'; 202 } 203 204 /* duplicate a path name, possibly converting to lower case */ 205 static char * 206 pathdup(const char *path) 207 { 208 char *str; 209 size_t i, len; 210 211 len = strlen(path); 212 while (len && path[len - 1] == '/') 213 len--; 214 if ((str = malloc(len + 1)) == NULL) { 215 errno = ENOMEM; 216 error("malloc()"); 217 } 218 if (L_opt) { 219 for (i = 0; i < len; ++i) 220 str[i] = tolower((unsigned char)path[i]); 221 } else { 222 memcpy(str, path, len); 223 } 224 str[len] = '\0'; 225 226 return (str); 227 } 228 229 /* concatenate two path names */ 230 static char * 231 pathcat(const char *prefix, const char *path) 232 { 233 char *str; 234 size_t prelen, len; 235 236 prelen = prefix ? strlen(prefix) + 1 : 0; 237 len = strlen(path) + 1; 238 if ((str = malloc(prelen + len)) == NULL) { 239 errno = ENOMEM; 240 error("malloc()"); 241 } 242 if (prefix) { 243 memcpy(str, prefix, prelen); /* includes zero */ 244 str[prelen - 1] = '/'; /* splat zero */ 245 } 246 memcpy(str + prelen, path, len); /* includes zero */ 247 248 return (str); 249 } 250 251 /* 252 * Pattern lists for include / exclude processing 253 */ 254 struct pattern { 255 STAILQ_ENTRY(pattern) link; 256 char pattern[]; 257 }; 258 259 STAILQ_HEAD(pattern_list, pattern); 260 static struct pattern_list include = STAILQ_HEAD_INITIALIZER(include); 261 static struct pattern_list exclude = STAILQ_HEAD_INITIALIZER(exclude); 262 263 /* 264 * Add an entry to a pattern list 265 */ 266 static void 267 add_pattern(struct pattern_list *list, const char *pattern) 268 { 269 struct pattern *entry; 270 size_t len; 271 272 debug("adding pattern '%s'\n", pattern); 273 len = strlen(pattern); 274 if ((entry = malloc(sizeof *entry + len + 1)) == NULL) { 275 errno = ENOMEM; 276 error("malloc()"); 277 } 278 memcpy(entry->pattern, pattern, len + 1); 279 STAILQ_INSERT_TAIL(list, entry, link); 280 } 281 282 /* 283 * Match a string against a list of patterns 284 */ 285 static int 286 match_pattern(struct pattern_list *list, const char *str) 287 { 288 struct pattern *entry; 289 290 STAILQ_FOREACH(entry, list, link) { 291 if (fnmatch(entry->pattern, str, C_opt ? FNM_CASEFOLD : 0) == 0) 292 return (1); 293 } 294 return (0); 295 } 296 297 /* 298 * Verify that a given pathname is in the include list and not in the 299 * exclude list. 300 */ 301 static int 302 accept_pathname(const char *pathname) 303 { 304 305 if (!STAILQ_EMPTY(&include) && !match_pattern(&include, pathname)) 306 return (0); 307 if (!STAILQ_EMPTY(&exclude) && match_pattern(&exclude, pathname)) 308 return (0); 309 return (1); 310 } 311 312 /* 313 * Create the specified directory with the specified mode, taking certain 314 * precautions on they way. 315 */ 316 static void 317 make_dir(const char *path, int mode) 318 { 319 struct stat sb; 320 321 if (lstat(path, &sb) == 0) { 322 if (S_ISDIR(sb.st_mode)) 323 return; 324 /* 325 * Normally, we should either ask the user about removing 326 * the non-directory of the same name as a directory we 327 * wish to create, or respect the -n or -o command-line 328 * options. However, this may lead to a later failure or 329 * even compromise (if this non-directory happens to be a 330 * symlink to somewhere unsafe), so we don't. 331 */ 332 333 /* 334 * Don't check unlink() result; failure will cause mkdir() 335 * to fail later, which we will catch. 336 */ 337 (void)unlink(path); 338 } 339 if (mkdir(path, mode) != 0 && errno != EEXIST) 340 error("mkdir('%s')", path); 341 } 342 343 /* 344 * Ensure that all directories leading up to (but not including) the 345 * specified path exist. 346 * 347 * XXX inefficient + modifies the file in-place 348 */ 349 static void 350 make_parent(char *path) 351 { 352 struct stat sb; 353 char *sep; 354 355 sep = strrchr(path, '/'); 356 if (sep == NULL || sep == path) 357 return; 358 *sep = '\0'; 359 if (lstat(path, &sb) == 0) { 360 if (S_ISDIR(sb.st_mode)) { 361 *sep = '/'; 362 return; 363 } 364 unlink(path); 365 } 366 make_parent(path); 367 mkdir(path, 0755); 368 *sep = '/'; 369 370 #if 0 371 for (sep = path; (sep = strchr(sep, '/')) != NULL; sep++) { 372 /* root in case of absolute d_arg */ 373 if (sep == path) 374 continue; 375 *sep = '\0'; 376 make_dir(path, 0755); 377 *sep = '/'; 378 } 379 #endif 380 } 381 382 /* 383 * Extract a directory. 384 */ 385 static void 386 extract_dir(struct archive *a, struct archive_entry *e, const char *path) 387 { 388 int mode; 389 390 /* 391 * Dropbox likes to create '/' directory entries, just ignore 392 * such junk. 393 */ 394 if (*path == '\0') 395 return; 396 397 mode = archive_entry_mode(e) & 0777; 398 if (mode == 0) 399 mode = 0755; 400 401 /* 402 * Some zipfiles contain directories with weird permissions such 403 * as 0644 or 0444. This can cause strange issues such as being 404 * unable to extract files into the directory we just created, or 405 * the user being unable to remove the directory later without 406 * first manually changing its permissions. Therefore, we whack 407 * the permissions into shape, assuming that the user wants full 408 * access and that anyone who gets read access also gets execute 409 * access. 410 */ 411 mode |= 0700; 412 if (mode & 0040) 413 mode |= 0010; 414 if (mode & 0004) 415 mode |= 0001; 416 417 info(" creating: %s/\n", path); 418 make_dir(path, mode); 419 ac(archive_read_data_skip(a)); 420 } 421 422 static unsigned char buffer[8192]; 423 static char spinner[] = { '|', '/', '-', '\\' }; 424 425 static int 426 handle_existing_file(char **path) 427 { 428 size_t alen; 429 ssize_t len; 430 char buf[4]; 431 432 for (;;) { 433 fprintf(stderr, 434 "replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", 435 *path); 436 fgets(buf, 4, stdin); 437 switch (*buf) { 438 case 'A': 439 o_opt = 1; 440 /* FALL THROUGH */ 441 case 'y': 442 case 'Y': 443 (void)unlink(*path); 444 return 1; 445 case 'N': 446 n_opt = 1; 447 /* FALL THROUGH */ 448 case 'n': 449 return -1; 450 case 'r': 451 case 'R': 452 printf("New name: "); 453 fflush(stdout); 454 free(*path); 455 *path = NULL; 456 alen = 0; 457 len = getline(path, &alen, stdin); 458 if ((*path)[len - 1] == '\n') 459 (*path)[len - 1] = '\0'; 460 return 0; 461 default: 462 break; 463 } 464 } 465 } 466 467 /* 468 * Detect binary files by a combination of character white list and 469 * black list. NUL bytes and other control codes without use in text files 470 * result directly in switching the file to binary mode. Otherwise, at least 471 * one white-listed byte has to be found. 472 * 473 * Black-listed: 0..6, 14..25, 28..31 474 * White-listed: 9..10, 13, >= 32 475 * 476 * See the proginfo/txtvsbin.txt in the zip sources for a detailed discussion. 477 */ 478 #define BYTE_IS_BINARY(x) ((x) < 32 && (0xf3ffc07fU & (1U << (x)))) 479 #define BYTE_IS_TEXT(x) ((x) >= 32 || (0x00002600U & (1U << (x)))) 480 481 static int 482 check_binary(const unsigned char *buf, size_t len) 483 { 484 int rv; 485 for (rv = 1; len--; ++buf) { 486 if (BYTE_IS_BINARY(*buf)) 487 return 1; 488 if (BYTE_IS_TEXT(*buf)) 489 rv = 0; 490 } 491 492 return rv; 493 } 494 495 /* 496 * Extract to a file descriptor 497 */ 498 static int 499 extract2fd(struct archive *a, char *pathname, int fd) 500 { 501 int cr, text, warn; 502 ssize_t len; 503 unsigned char *p, *q, *end; 504 505 text = a_opt; 506 warn = 0; 507 cr = 0; 508 509 /* loop over file contents and write to fd */ 510 for (int n = 0; ; n++) { 511 if (fd != STDOUT_FILENO) 512 if (tty && (n % 4) == 0) 513 info(" %c\b\b", spinner[(n / 4) % sizeof spinner]); 514 515 len = archive_read_data(a, buffer, sizeof buffer); 516 517 if (len < 0) 518 ac(len); 519 520 /* left over CR from previous buffer */ 521 if (a_opt && cr) { 522 if (len == 0 || buffer[0] != '\n') 523 if (write(fd, "\r", 1) != 1) 524 error("write('%s')", pathname); 525 cr = 0; 526 } 527 528 /* EOF */ 529 if (len == 0) 530 break; 531 end = buffer + len; 532 533 /* 534 * Detect whether this is a text file. The correct way to 535 * do this is to check the least significant bit of the 536 * "internal file attributes" field of the corresponding 537 * file header in the central directory, but libarchive 538 * does not provide access to this field, so we have to 539 * guess by looking for non-ASCII characters in the 540 * buffer. Hopefully we won't guess wrong. If we do 541 * guess wrong, we print a warning message later. 542 */ 543 if (a_opt && n == 0) { 544 if (check_binary(buffer, len)) 545 text = 0; 546 } 547 548 /* simple case */ 549 if (!a_opt || !text) { 550 if (write(fd, buffer, len) != len) 551 error("write('%s')", pathname); 552 continue; 553 } 554 555 /* hard case: convert \r\n to \n (sigh...) */ 556 for (p = buffer; p < end; p = q + 1) { 557 for (q = p; q < end; q++) { 558 if (!warn && BYTE_IS_BINARY(*q)) { 559 warningx("%s may be corrupted due" 560 " to weak text file detection" 561 " heuristic", pathname); 562 warn = 1; 563 } 564 if (q[0] != '\r') 565 continue; 566 if (&q[1] == end) { 567 cr = 1; 568 break; 569 } 570 if (q[1] == '\n') 571 break; 572 } 573 if (write(fd, p, q - p) != q - p) 574 error("write('%s')", pathname); 575 } 576 } 577 578 return text; 579 } 580 581 /* 582 * Extract a regular file. 583 */ 584 static void 585 extract_file(struct archive *a, struct archive_entry *e, char **path) 586 { 587 int mode; 588 time_t mtime; 589 struct stat sb; 590 struct timeval tv[2]; 591 int fd, check, text; 592 const char *linkname; 593 594 mode = archive_entry_mode(e) & 0777; 595 if (mode == 0) 596 mode = 0644; 597 mtime = archive_entry_mtime(e); 598 599 /* look for existing file of same name */ 600 recheck: 601 if (lstat(*path, &sb) == 0) { 602 if (u_opt || f_opt) { 603 /* check if up-to-date */ 604 if (S_ISREG(sb.st_mode) && sb.st_mtime >= mtime) 605 return; 606 (void)unlink(*path); 607 } else if (o_opt) { 608 /* overwrite */ 609 (void)unlink(*path); 610 } else if (n_opt) { 611 /* do not overwrite */ 612 return; 613 } else { 614 check = handle_existing_file(path); 615 if (check == 0) 616 goto recheck; 617 if (check == -1) 618 return; /* do not overwrite */ 619 } 620 } else { 621 if (f_opt) 622 return; 623 } 624 625 tv[0].tv_sec = now; 626 tv[0].tv_usec = 0; 627 tv[1].tv_sec = mtime; 628 tv[1].tv_usec = 0; 629 630 /* process symlinks */ 631 linkname = archive_entry_symlink(e); 632 if (linkname != NULL) { 633 if (symlink(linkname, *path) == -1) 634 error("symlink('%s', '%s')", linkname, *path); 635 info(" extracting: %s -> %s\n", *path, linkname); 636 if (lchmod(*path, mode) == -1) 637 warning("Cannot set mode for '%s'", *path); 638 if (lutimes(*path, tv) == -1) 639 warning("utimes('%s')", *path); 640 return; 641 } 642 643 /* process hardlinks */ 644 linkname = archive_entry_hardlink(e); 645 if (linkname != NULL) { 646 if (link(linkname, *path) == -1) 647 error("link('%s', '%s')", linkname, *path); 648 info(" extracting: %s link to %s\n", *path, linkname); 649 return; 650 } 651 652 if ((fd = open(*path, O_RDWR|O_CREAT|O_TRUNC, mode)) < 0) 653 error("open('%s')", *path); 654 655 info(" extracting: %s", *path); 656 657 text = extract2fd(a, *path, fd); 658 659 if (tty) 660 info(" \b\b"); 661 if (text) 662 info(" (text)"); 663 info("\n"); 664 665 /* set access and modification time */ 666 if (futimes(fd, tv) != 0) 667 error("utimes('%s')", *path); 668 if (close(fd) != 0) 669 error("close('%s')", *path); 670 } 671 672 /* 673 * Extract a zipfile entry: first perform some sanity checks to ensure 674 * that it is either a directory or a regular file and that the path is 675 * not absolute and does not try to break out of the current directory; 676 * then call either extract_dir() or extract_file() as appropriate. 677 * 678 * This is complicated a bit by the various ways in which we need to 679 * manipulate the path name. Case conversion (if requested by the -L 680 * option) happens first, but the include / exclude patterns are applied 681 * to the full converted path name, before the directory part of the path 682 * is removed in accordance with the -j option. Sanity checks are 683 * intentionally done earlier than they need to be, so the user will get a 684 * warning about insecure paths even for files or directories which 685 * wouldn't be extracted anyway. 686 */ 687 static void 688 extract(struct archive *a, struct archive_entry *e) 689 { 690 char *pathname, *realpathname; 691 mode_t filetype; 692 char *p, *q; 693 694 pathname = pathdup(archive_entry_pathname(e)); 695 filetype = archive_entry_filetype(e); 696 697 /* sanity checks */ 698 if (pathname[0] == '/' || 699 strncmp(pathname, "../", 3) == 0 || 700 strstr(pathname, "/../") != NULL) { 701 warningx("skipping insecure entry '%s'", pathname); 702 ac(archive_read_data_skip(a)); 703 free(pathname); 704 return; 705 } 706 707 /* I don't think this can happen in a zipfile.. */ 708 if (!S_ISDIR(filetype) && !S_ISREG(filetype) && !S_ISLNK(filetype)) { 709 warningx("skipping non-regular entry '%s'", pathname); 710 ac(archive_read_data_skip(a)); 711 free(pathname); 712 return; 713 } 714 715 /* skip directories in -j case */ 716 if (S_ISDIR(filetype) && j_opt) { 717 ac(archive_read_data_skip(a)); 718 free(pathname); 719 return; 720 } 721 722 /* apply include / exclude patterns */ 723 if (!accept_pathname(pathname)) { 724 ac(archive_read_data_skip(a)); 725 free(pathname); 726 return; 727 } 728 729 /* apply -j and -d */ 730 if (j_opt) { 731 for (p = q = pathname; *p; ++p) 732 if (*p == '/') 733 q = p + 1; 734 realpathname = pathcat(d_arg, q); 735 } else { 736 realpathname = pathcat(d_arg, pathname); 737 } 738 739 /* ensure that parent directory exists */ 740 make_parent(realpathname); 741 742 if (S_ISDIR(filetype)) 743 extract_dir(a, e, realpathname); 744 else 745 extract_file(a, e, &realpathname); 746 747 free(realpathname); 748 free(pathname); 749 } 750 751 static void 752 extract_stdout(struct archive *a, struct archive_entry *e) 753 { 754 char *pathname; 755 mode_t filetype; 756 757 pathname = pathdup(archive_entry_pathname(e)); 758 filetype = archive_entry_filetype(e); 759 760 /* I don't think this can happen in a zipfile.. */ 761 if (!S_ISDIR(filetype) && !S_ISREG(filetype) && !S_ISLNK(filetype)) { 762 warningx("skipping non-regular entry '%s'", pathname); 763 ac(archive_read_data_skip(a)); 764 free(pathname); 765 return; 766 } 767 768 /* skip directories in -j case */ 769 if (S_ISDIR(filetype)) { 770 ac(archive_read_data_skip(a)); 771 free(pathname); 772 return; 773 } 774 775 /* apply include / exclude patterns */ 776 if (!accept_pathname(pathname)) { 777 ac(archive_read_data_skip(a)); 778 free(pathname); 779 return; 780 } 781 782 if (c_opt) 783 info("x %s\n", pathname); 784 785 (void)extract2fd(a, pathname, STDOUT_FILENO); 786 787 free(pathname); 788 } 789 790 /* 791 * Print the name of an entry to stdout. 792 */ 793 static void 794 list(struct archive *a, struct archive_entry *e) 795 { 796 char buf[20]; 797 time_t mtime; 798 struct tm *tm; 799 800 mtime = archive_entry_mtime(e); 801 tm = localtime(&mtime); 802 if (*y_str) 803 strftime(buf, sizeof(buf), "%m-%d-%G %R", tm); 804 else 805 strftime(buf, sizeof(buf), "%m-%d-%g %R", tm); 806 807 if (v_opt == 1) { 808 printf(" %8ju %s %s\n", 809 (uintmax_t)archive_entry_size(e), 810 buf, archive_entry_pathname(e)); 811 } else if (v_opt == 2) { 812 printf("%8ju Stored %7ju 0%% %s %08x %s\n", 813 (uintmax_t)archive_entry_size(e), 814 (uintmax_t)archive_entry_size(e), 815 buf, 816 0U, 817 archive_entry_pathname(e)); 818 } 819 ac(archive_read_data_skip(a)); 820 } 821 822 /* 823 * Extract to memory to check CRC 824 */ 825 static int 826 test(struct archive *a, struct archive_entry *e) 827 { 828 ssize_t len; 829 int error_count; 830 831 error_count = 0; 832 if (S_ISDIR(archive_entry_filetype(e))) 833 return 0; 834 835 info(" testing: %s\t", archive_entry_pathname(e)); 836 while ((len = archive_read_data(a, buffer, sizeof buffer)) > 0) 837 /* nothing */; 838 if (len < 0) { 839 info(" %s\n", archive_error_string(a)); 840 ++error_count; 841 } else { 842 info(" OK\n"); 843 } 844 845 /* shouldn't be necessary, but it doesn't hurt */ 846 ac(archive_read_data_skip(a)); 847 848 return error_count; 849 } 850 851 /* 852 * Main loop: open the zipfile, iterate over its contents and decide what 853 * to do with each entry. 854 */ 855 static void 856 unzip(const char *fn) 857 { 858 struct archive *a; 859 struct archive_entry *e; 860 int ret; 861 uintmax_t total_size, file_count, error_count; 862 863 if ((a = archive_read_new()) == NULL) 864 error("archive_read_new failed"); 865 866 ac(archive_read_support_format_zip(a)); 867 ac(archive_read_open_filename(a, fn, 8192)); 868 869 if (!q_opt && !p_opt) 870 printf("Archive: %s\n", fn); 871 872 if (v_opt == 1) { 873 printf(" Length %sDate Time Name\n", y_str); 874 printf(" -------- %s---- ---- ----\n", y_str); 875 } else if (v_opt == 2) { 876 printf(" Length Method Size Ratio %sDate Time CRC-32 Name\n", y_str); 877 printf("-------- ------ ------- ----- %s---- ---- ------ ----\n", y_str); 878 } 879 880 total_size = 0; 881 file_count = 0; 882 error_count = 0; 883 for (;;) { 884 ret = archive_read_next_header(a, &e); 885 if (ret == ARCHIVE_EOF) 886 break; 887 ac(ret); 888 if (t_opt) 889 error_count += test(a, e); 890 else if (v_opt) 891 list(a, e); 892 else if (p_opt || c_opt) 893 extract_stdout(a, e); 894 else 895 extract(a, e); 896 897 total_size += archive_entry_size(e); 898 ++file_count; 899 } 900 901 if (v_opt == 1) { 902 printf(" -------- %s-------\n", y_str); 903 printf(" %8ju %s%ju file%s\n", 904 total_size, y_str, file_count, file_count != 1 ? "s" : ""); 905 } else if (v_opt == 2) { 906 printf("-------- ------- --- %s-------\n", y_str); 907 printf("%8ju %7ju 0%% %s%ju file%s\n", 908 total_size, total_size, y_str, file_count, 909 file_count != 1 ? "s" : ""); 910 } 911 912 ac(archive_read_free(a)); 913 914 if (t_opt) { 915 if (error_count > 0) { 916 errorx("%ju checksum error(s) found.", error_count); 917 } 918 else { 919 printf("No errors detected in compressed data of %s.\n", 920 fn); 921 } 922 } 923 } 924 925 static void __dead 926 usage(void) 927 { 928 929 fprintf(stderr, "Usage: %s [-aCcfjLlnopqtuvy] [-d dir] [-x pattern] " 930 "zipfile\n", getprogname()); 931 exit(1); 932 } 933 934 static int 935 getopts(int argc, char *argv[]) 936 { 937 int opt; 938 939 optreset = optind = 1; 940 while ((opt = getopt(argc, argv, "aCcd:fjLlnopqtuvyx:")) != -1) 941 switch (opt) { 942 case 'a': 943 a_opt = 1; 944 break; 945 case 'C': 946 C_opt = 1; 947 break; 948 case 'c': 949 c_opt = 1; 950 break; 951 case 'd': 952 d_arg = optarg; 953 break; 954 case 'f': 955 f_opt = 1; 956 break; 957 case 'j': 958 j_opt = 1; 959 break; 960 case 'L': 961 L_opt = 1; 962 break; 963 case 'l': 964 if (v_opt == 0) 965 v_opt = 1; 966 break; 967 case 'n': 968 n_opt = 1; 969 break; 970 case 'o': 971 o_opt = 1; 972 q_opt = 1; 973 break; 974 case 'p': 975 p_opt = 1; 976 break; 977 case 'q': 978 q_opt = 1; 979 break; 980 case 't': 981 t_opt = 1; 982 break; 983 case 'u': 984 u_opt = 1; 985 break; 986 case 'v': 987 v_opt = 2; 988 break; 989 case 'x': 990 add_pattern(&exclude, optarg); 991 break; 992 case 'y': 993 y_str = " "; 994 break; 995 default: 996 usage(); 997 } 998 999 return (optind); 1000 } 1001 1002 int 1003 main(int argc, char *argv[]) 1004 { 1005 const char *zipfile; 1006 int nopts; 1007 1008 if (isatty(STDOUT_FILENO)) 1009 tty = 1; 1010 1011 if (getenv("UNZIP_DEBUG") != NULL) 1012 unzip_debug = 1; 1013 for (int i = 0; i < argc; ++i) 1014 debug("%s%c", argv[i], (i < argc - 1) ? ' ' : '\n'); 1015 1016 /* 1017 * Info-ZIP's unzip(1) expects certain options to come before the 1018 * zipfile name, and others to come after - though it does not 1019 * enforce this. For simplicity, we accept *all* options both 1020 * before and after the zipfile name. 1021 */ 1022 nopts = getopts(argc, argv); 1023 1024 if (argc <= nopts) 1025 usage(); 1026 zipfile = argv[nopts++]; 1027 1028 if (strcmp(zipfile, "-") == 0) 1029 zipfile = NULL; /* STDIN */ 1030 1031 while (nopts < argc && *argv[nopts] != '-') 1032 add_pattern(&include, argv[nopts++]); 1033 1034 nopts--; /* fake argv[0] */ 1035 nopts += getopts(argc - nopts, argv + nopts); 1036 1037 if (n_opt + o_opt + u_opt > 1) 1038 errorx("-n, -o and -u are contradictory"); 1039 1040 time(&now); 1041 1042 unzip(zipfile); 1043 1044 exit(0); 1045 } 1046