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