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