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