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