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