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