1 /* $NetBSD: unzip.c,v 1.13 2010/04/29 06:32:19 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.13 2010/04/29 06:32:19 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 break; 578 } 579 } 580 581 /* simple case */ 582 if (!a_opt || !text) { 583 if (write(fd, buffer, len) != len) 584 error("write('%s')", path); 585 continue; 586 } 587 588 /* hard case: convert \r\n to \n (sigh...) */ 589 for (p = buffer; p < end; p = q + 1) { 590 for (q = p; q < end; q++) { 591 if (!warn && BYTE_IS_BINARY(*q)) { 592 warningx("%s may be corrupted due" 593 " to weak text file detection" 594 " heuristic", *path); 595 warn = 1; 596 } 597 if (q[0] != '\r') 598 continue; 599 if (&q[1] == end) { 600 cr = 1; 601 break; 602 } 603 if (q[1] == '\n') 604 break; 605 } 606 if (write(fd, p, q - p) != q - p) 607 error("write('%s')", *path); 608 } 609 } 610 if (tty) 611 info(" \b\b"); 612 if (text) 613 info(" (text)"); 614 info("\n"); 615 616 /* set access and modification time */ 617 tv[0].tv_sec = now; 618 tv[0].tv_usec = 0; 619 tv[1].tv_sec = mtime; 620 tv[1].tv_usec = 0; 621 if (futimes(fd, tv) != 0) 622 error("utimes('%s')", *path); 623 if (close(fd) != 0) 624 error("close('%s')", *path); 625 } 626 627 /* 628 * Extract a zipfile entry: first perform some sanity checks to ensure 629 * that it is either a directory or a regular file and that the path is 630 * not absolute and does not try to break out of the current directory; 631 * then call either extract_dir() or extract_file() as appropriate. 632 * 633 * This is complicated a bit by the various ways in which we need to 634 * manipulate the path name. Case conversion (if requested by the -L 635 * option) happens first, but the include / exclude patterns are applied 636 * to the full converted path name, before the directory part of the path 637 * is removed in accordance with the -j option. Sanity checks are 638 * intentionally done earlier than they need to be, so the user will get a 639 * warning about insecure paths even for files or directories which 640 * wouldn't be extracted anyway. 641 */ 642 static void 643 extract(struct archive *a, struct archive_entry *e) 644 { 645 char *pathname, *realpathname; 646 mode_t filetype; 647 char *p, *q; 648 649 pathname = pathdup(archive_entry_pathname(e)); 650 filetype = archive_entry_filetype(e); 651 652 /* sanity checks */ 653 if (pathname[0] == '/' || 654 strncmp(pathname, "../", 3) == 0 || 655 strstr(pathname, "/../") != NULL) { 656 warningx("skipping insecure entry '%s'", pathname); 657 ac(archive_read_data_skip(a)); 658 free(pathname); 659 return; 660 } 661 662 /* I don't think this can happen in a zipfile.. */ 663 if (!S_ISDIR(filetype) && !S_ISREG(filetype)) { 664 warningx("skipping non-regular entry '%s'", pathname); 665 ac(archive_read_data_skip(a)); 666 free(pathname); 667 return; 668 } 669 670 /* skip directories in -j case */ 671 if (S_ISDIR(filetype) && j_opt) { 672 ac(archive_read_data_skip(a)); 673 free(pathname); 674 return; 675 } 676 677 /* apply include / exclude patterns */ 678 if (!accept_pathname(pathname)) { 679 ac(archive_read_data_skip(a)); 680 free(pathname); 681 return; 682 } 683 684 /* apply -j and -d */ 685 if (j_opt) { 686 for (p = q = pathname; *p; ++p) 687 if (*p == '/') 688 q = p + 1; 689 realpathname = pathcat(d_arg, q); 690 } else { 691 realpathname = pathcat(d_arg, pathname); 692 } 693 694 /* ensure that parent directory exists */ 695 make_parent(realpathname); 696 697 if (S_ISDIR(filetype)) 698 extract_dir(a, e, realpathname); 699 else 700 extract_file(a, e, &realpathname); 701 702 free(realpathname); 703 free(pathname); 704 } 705 706 static void 707 extract_stdout(struct archive *a, struct archive_entry *e) 708 { 709 char *pathname; 710 mode_t filetype; 711 int cr, text, warn; 712 ssize_t len; 713 unsigned char *p, *q, *end; 714 715 pathname = pathdup(archive_entry_pathname(e)); 716 filetype = archive_entry_filetype(e); 717 718 /* I don't think this can happen in a zipfile.. */ 719 if (!S_ISDIR(filetype) && !S_ISREG(filetype)) { 720 warningx("skipping non-regular entry '%s'", pathname); 721 ac(archive_read_data_skip(a)); 722 free(pathname); 723 return; 724 } 725 726 /* skip directories in -j case */ 727 if (S_ISDIR(filetype)) { 728 ac(archive_read_data_skip(a)); 729 free(pathname); 730 return; 731 } 732 733 /* apply include / exclude patterns */ 734 if (!accept_pathname(pathname)) { 735 ac(archive_read_data_skip(a)); 736 free(pathname); 737 return; 738 } 739 740 if (c_opt) 741 info("x %s\n", pathname); 742 743 text = a_opt; 744 warn = 0; 745 cr = 0; 746 for (int n = 0; ; n++) { 747 len = archive_read_data(a, buffer, sizeof buffer); 748 749 if (len < 0) 750 ac(len); 751 752 /* left over CR from previous buffer */ 753 if (a_opt && cr) { 754 if (len == 0 || buffer[0] != '\n') { 755 if (fwrite("\r", 1, 1, stderr) != 1) 756 error("write('%s')", pathname); 757 } 758 cr = 0; 759 } 760 761 /* EOF */ 762 if (len == 0) 763 break; 764 end = buffer + len; 765 766 /* 767 * Detect whether this is a text file. The correct way to 768 * do this is to check the least significant bit of the 769 * "internal file attributes" field of the corresponding 770 * file header in the central directory, but libarchive 771 * does not read the central directory, so we have to 772 * guess by looking for non-ASCII characters in the 773 * buffer. Hopefully we won't guess wrong. If we do 774 * guess wrong, we print a warning message later. 775 */ 776 if (a_opt && n == 0) { 777 for (p = buffer; p < end; ++p) { 778 if (!isascii((unsigned char)*p)) { 779 text = 0; 780 break; 781 } 782 } 783 } 784 785 /* simple case */ 786 if (!a_opt || !text) { 787 if (fwrite(buffer, 1, len, stdout) != (size_t)len) 788 error("write('%s')", pathname); 789 continue; 790 } 791 792 /* hard case: convert \r\n to \n (sigh...) */ 793 for (p = buffer; p < end; p = q + 1) { 794 for (q = p; q < end; q++) { 795 if (!warn && !isascii(*q)) { 796 warningx("%s may be corrupted due" 797 " to weak text file detection" 798 " heuristic", pathname); 799 warn = 1; 800 } 801 if (q[0] != '\r') 802 continue; 803 if (&q[1] == end) { 804 cr = 1; 805 break; 806 } 807 if (q[1] == '\n') 808 break; 809 } 810 if (fwrite(p, 1, q - p, stdout) != (size_t)(q - p)) 811 error("write('%s')", pathname); 812 } 813 } 814 815 free(pathname); 816 } 817 818 /* 819 * Print the name of an entry to stdout. 820 */ 821 static void 822 list(struct archive *a, struct archive_entry *e) 823 { 824 char buf[20]; 825 time_t mtime; 826 827 mtime = archive_entry_mtime(e); 828 strftime(buf, sizeof(buf), "%m-%d-%g %R", localtime(&mtime)); 829 830 if (v_opt == 1) { 831 printf(" %8ju %s %s\n", 832 (uintmax_t)archive_entry_size(e), 833 buf, archive_entry_pathname(e)); 834 } else if (v_opt == 2) { 835 printf("%8ju Stored %7ju 0%% %s %08x %s\n", 836 (uintmax_t)archive_entry_size(e), 837 (uintmax_t)archive_entry_size(e), 838 buf, 839 0U, 840 archive_entry_pathname(e)); 841 } 842 ac(archive_read_data_skip(a)); 843 } 844 845 /* 846 * Extract to memory to check CRC 847 */ 848 static int 849 test(struct archive *a, struct archive_entry *e) 850 { 851 ssize_t len; 852 int error_count; 853 854 error_count = 0; 855 if (S_ISDIR(archive_entry_filetype(e))) 856 return 0; 857 858 info(" testing: %s\t", archive_entry_pathname(e)); 859 while ((len = archive_read_data(a, buffer, sizeof buffer)) > 0) 860 /* nothing */; 861 if (len < 0) { 862 info(" %s\n", archive_error_string(a)); 863 ++error_count; 864 } else { 865 info(" OK\n"); 866 } 867 868 /* shouldn't be necessary, but it doesn't hurt */ 869 ac(archive_read_data_skip(a)); 870 871 return error_count; 872 } 873 874 875 /* 876 * Main loop: open the zipfile, iterate over its contents and decide what 877 * to do with each entry. 878 */ 879 static void 880 unzip(const char *fn) 881 { 882 struct archive *a; 883 struct archive_entry *e; 884 int fd, ret; 885 uintmax_t total_size, file_count, error_count; 886 887 if ((fd = open(fn, O_RDONLY)) < 0) 888 error("%s", fn); 889 890 a = archive_read_new(); 891 ac(archive_read_support_format_zip(a)); 892 ac(archive_read_open_fd(a, fd, 8192)); 893 894 if (!q_opt && !p_opt) 895 printf("Archive: %s\n", fn); 896 897 if (v_opt == 1) { 898 printf(" Length Date Time Name\n"); 899 printf(" -------- ---- ---- ----\n"); 900 } else if (v_opt == 2) { 901 printf(" Length Method Size Ratio Date Time CRC-32 Name\n"); 902 printf("-------- ------ ------- ----- ---- ---- ------ ----\n"); 903 } 904 905 total_size = 0; 906 file_count = 0; 907 error_count = 0; 908 for (;;) { 909 ret = archive_read_next_header(a, &e); 910 if (ret == ARCHIVE_EOF) 911 break; 912 ac(ret); 913 if (t_opt) 914 error_count += test(a, e); 915 else if (v_opt) 916 list(a, e); 917 else if (p_opt || c_opt) 918 extract_stdout(a, e); 919 else 920 extract(a, e); 921 922 total_size += archive_entry_size(e); 923 ++file_count; 924 } 925 926 if (v_opt == 1) { 927 printf(" -------- -------\n"); 928 printf(" %8ju %ju file%s\n", 929 total_size, file_count, file_count != 1 ? "s" : ""); 930 } else if (v_opt == 2) { 931 printf("-------- ------- --- -------\n"); 932 printf("%8ju %7ju 0%% %ju file%s\n", 933 total_size, total_size, file_count, 934 file_count != 1 ? "s" : ""); 935 } 936 937 ac(archive_read_close(a)); 938 (void)archive_read_finish(a); 939 940 if (close(fd) != 0) 941 error("%s", fn); 942 943 if (t_opt) { 944 if (error_count > 0) { 945 errorx("%d checksum error(s) found.", error_count); 946 } 947 else { 948 printf("No errors detected in compressed data of %s.\n", 949 fn); 950 } 951 } 952 } 953 954 static void 955 usage(void) 956 { 957 958 fprintf(stderr, "usage: unzip [-aCcfjLlnopqtuv] [-d dir] [-x pattern] zipfile\n"); 959 exit(1); 960 } 961 962 static int 963 getopts(int argc, char *argv[]) 964 { 965 int opt; 966 967 optreset = optind = 1; 968 while ((opt = getopt(argc, argv, "aCcd:fjLlnopqtuvx:")) != -1) 969 switch (opt) { 970 case 'a': 971 a_opt = 1; 972 break; 973 case 'C': 974 C_opt = 1; 975 break; 976 case 'c': 977 c_opt = 1; 978 break; 979 case 'd': 980 d_arg = optarg; 981 break; 982 case 'f': 983 f_opt = 1; 984 break; 985 case 'j': 986 j_opt = 1; 987 break; 988 case 'L': 989 L_opt = 1; 990 break; 991 case 'l': 992 if (v_opt == 0) 993 v_opt = 1; 994 break; 995 case 'n': 996 n_opt = 1; 997 break; 998 case 'o': 999 o_opt = 1; 1000 q_opt = 1; 1001 break; 1002 case 'p': 1003 p_opt = 1; 1004 break; 1005 case 'q': 1006 q_opt = 1; 1007 break; 1008 case 't': 1009 t_opt = 1; 1010 break; 1011 case 'u': 1012 u_opt = 1; 1013 break; 1014 case 'v': 1015 v_opt = 2; 1016 break; 1017 case 'x': 1018 add_pattern(&exclude, optarg); 1019 break; 1020 default: 1021 usage(); 1022 } 1023 1024 return (optind); 1025 } 1026 1027 int 1028 main(int argc, char *argv[]) 1029 { 1030 const char *zipfile; 1031 int nopts; 1032 1033 if (isatty(STDOUT_FILENO)) 1034 tty = 1; 1035 1036 if (getenv("UNZIP_DEBUG") != NULL) 1037 unzip_debug = 1; 1038 for (int i = 0; i < argc; ++i) 1039 debug("%s%c", argv[i], (i < argc - 1) ? ' ' : '\n'); 1040 1041 /* 1042 * Info-ZIP's unzip(1) expects certain options to come before the 1043 * zipfile name, and others to come after - though it does not 1044 * enforce this. For simplicity, we accept *all* options both 1045 * before and after the zipfile name. 1046 */ 1047 nopts = getopts(argc, argv); 1048 1049 if (argc <= nopts) 1050 usage(); 1051 zipfile = argv[nopts++]; 1052 1053 while (nopts < argc && *argv[nopts] != '-') 1054 add_pattern(&include, argv[nopts++]); 1055 1056 nopts--; /* fake argv[0] */ 1057 nopts += getopts(argc - nopts, argv + nopts); 1058 1059 if (n_opt + o_opt + u_opt > 1) 1060 errorx("-n, -o and -u are contradictory"); 1061 1062 time(&now); 1063 1064 unzip(zipfile); 1065 1066 exit(0); 1067 } 1068