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