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