unzip.c revision 228991
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 228991 2011-12-30 10:59:15Z uqs $ 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_mode(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 414static int 415handle_existing_file(char **path) 416{ 417 size_t alen; 418 ssize_t len; 419 char buf[4]; 420 421 for (;;) { 422 fprintf(stderr, 423 "replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", 424 *path); 425 if (fgets(buf, sizeof(buf), stdin) == 0) { 426 clearerr(stdin); 427 printf("NULL\n(EOF or read error, " 428 "treating as \"[N]one\"...)\n"); 429 n_opt = 1; 430 return -1; 431 } 432 switch (*buf) { 433 case 'A': 434 o_opt = 1; 435 /* FALLTHROUGH */ 436 case 'y': 437 case 'Y': 438 (void)unlink(*path); 439 return 1; 440 case 'N': 441 n_opt = 1; 442 /* FALLTHROUGH */ 443 case 'n': 444 return -1; 445 case 'r': 446 case 'R': 447 printf("New name: "); 448 fflush(stdout); 449 free(*path); 450 *path = NULL; 451 alen = 0; 452 len = getdelim(path, &alen, '\n', stdin); 453 if ((*path)[len - 1] == '\n') 454 (*path)[len - 1] = '\0'; 455 return 0; 456 default: 457 break; 458 } 459 } 460} 461 462/* 463 * Extract a regular file. 464 */ 465static void 466extract_file(struct archive *a, struct archive_entry *e, char **path) 467{ 468 int mode; 469 time_t mtime; 470 struct stat sb; 471 struct timeval tv[2]; 472 int cr, fd, text, warn, check; 473 ssize_t len; 474 unsigned char *p, *q, *end; 475 476 mode = archive_entry_mode(e) & 0777; 477 if (mode == 0) 478 mode = 0644; 479 mtime = archive_entry_mtime(e); 480 481 /* look for existing file of same name */ 482recheck: 483 if (lstat(*path, &sb) == 0) { 484 if (u_opt || f_opt) { 485 /* check if up-to-date */ 486 if (S_ISREG(sb.st_mode) && sb.st_mtime >= mtime) 487 return; 488 (void)unlink(*path); 489 } else if (o_opt) { 490 /* overwrite */ 491 (void)unlink(*path); 492 } else if (n_opt) { 493 /* do not overwrite */ 494 return; 495 } else { 496 check = handle_existing_file(path); 497 if (check == 0) 498 goto recheck; 499 if (check == -1) 500 return; /* do not overwrite */ 501 } 502 } else { 503 if (f_opt) 504 return; 505 } 506 507 if ((fd = open(*path, O_RDWR|O_CREAT|O_TRUNC, mode)) < 0) 508 error("open('%s')", *path); 509 510 /* loop over file contents and write to disk */ 511 info(" extracting: %s", *path); 512 text = a_opt; 513 warn = 0; 514 cr = 0; 515 for (int n = 0; ; n++) { 516 if (tty && (n % 4) == 0) 517 info(" %c\b\b", spinner[(n / 4) % sizeof spinner]); 518 519 len = archive_read_data(a, buffer, sizeof buffer); 520 521 if (len < 0) 522 ac(len); 523 524 /* left over CR from previous buffer */ 525 if (a_opt && cr) { 526 if (len == 0 || buffer[0] != '\n') 527 if (write(fd, "\r", 1) != 1) 528 error("write('%s')", *path); 529 cr = 0; 530 } 531 532 /* EOF */ 533 if (len == 0) 534 break; 535 end = buffer + len; 536 537 /* 538 * Detect whether this is a text file. The correct way to 539 * do this is to check the least significant bit of the 540 * "internal file attributes" field of the corresponding 541 * file header in the central directory, but libarchive 542 * does not read the central directory, so we have to 543 * guess by looking for non-ASCII characters in the 544 * buffer. Hopefully we won't guess wrong. If we do 545 * guess wrong, we print a warning message later. 546 */ 547 if (a_opt && n == 0) { 548 for (p = buffer; p < end; ++p) { 549 if (!isascii((unsigned char)*p)) { 550 text = 0; 551 break; 552 } 553 } 554 } 555 556 /* simple case */ 557 if (!a_opt || !text) { 558 if (write(fd, buffer, len) != len) 559 error("write('%s')", *path); 560 continue; 561 } 562 563 /* hard case: convert \r\n to \n (sigh...) */ 564 for (p = buffer; p < end; p = q + 1) { 565 for (q = p; q < end; q++) { 566 if (!warn && !isascii(*q)) { 567 warningx("%s may be corrupted due" 568 " to weak text file detection" 569 " heuristic", *path); 570 warn = 1; 571 } 572 if (q[0] != '\r') 573 continue; 574 if (&q[1] == end) { 575 cr = 1; 576 break; 577 } 578 if (q[1] == '\n') 579 break; 580 } 581 if (write(fd, p, q - p) != q - p) 582 error("write('%s')", *path); 583 } 584 } 585 if (tty) 586 info(" \b\b"); 587 if (text) 588 info(" (text)"); 589 info("\n"); 590 591 /* set access and modification time */ 592 tv[0].tv_sec = now; 593 tv[0].tv_usec = 0; 594 tv[1].tv_sec = mtime; 595 tv[1].tv_usec = 0; 596 if (futimes(fd, tv) != 0) 597 error("utimes('%s')", *path); 598 if (close(fd) != 0) 599 error("close('%s')", *path); 600} 601 602/* 603 * Extract a zipfile entry: first perform some sanity checks to ensure 604 * that it is either a directory or a regular file and that the path is 605 * not absolute and does not try to break out of the current directory; 606 * then call either extract_dir() or extract_file() as appropriate. 607 * 608 * This is complicated a bit by the various ways in which we need to 609 * manipulate the path name. Case conversion (if requested by the -L 610 * option) happens first, but the include / exclude patterns are applied 611 * to the full converted path name, before the directory part of the path 612 * is removed in accordance with the -j option. Sanity checks are 613 * intentionally done earlier than they need to be, so the user will get a 614 * warning about insecure paths even for files or directories which 615 * wouldn't be extracted anyway. 616 */ 617static void 618extract(struct archive *a, struct archive_entry *e) 619{ 620 char *pathname, *realpathname; 621 mode_t filetype; 622 char *p, *q; 623 624 pathname = pathdup(archive_entry_pathname(e)); 625 filetype = archive_entry_filetype(e); 626 627 /* sanity checks */ 628 if (pathname[0] == '/' || 629 strncmp(pathname, "../", 3) == 0 || 630 strstr(pathname, "/../") != NULL) { 631 warningx("skipping insecure entry '%s'", pathname); 632 ac(archive_read_data_skip(a)); 633 free(pathname); 634 return; 635 } 636 637 /* I don't think this can happen in a zipfile.. */ 638 if (!S_ISDIR(filetype) && !S_ISREG(filetype)) { 639 warningx("skipping non-regular entry '%s'", pathname); 640 ac(archive_read_data_skip(a)); 641 free(pathname); 642 return; 643 } 644 645 /* skip directories in -j case */ 646 if (S_ISDIR(filetype) && j_opt) { 647 ac(archive_read_data_skip(a)); 648 free(pathname); 649 return; 650 } 651 652 /* apply include / exclude patterns */ 653 if (!accept_pathname(pathname)) { 654 ac(archive_read_data_skip(a)); 655 free(pathname); 656 return; 657 } 658 659 /* apply -j and -d */ 660 if (j_opt) { 661 for (p = q = pathname; *p; ++p) 662 if (*p == '/') 663 q = p + 1; 664 realpathname = pathcat(d_arg, q); 665 } else { 666 realpathname = pathcat(d_arg, pathname); 667 } 668 669 /* ensure that parent directory exists */ 670 make_parent(realpathname); 671 672 if (S_ISDIR(filetype)) 673 extract_dir(a, e, realpathname); 674 else 675 extract_file(a, e, &realpathname); 676 677 free(realpathname); 678 free(pathname); 679} 680 681static void 682extract_stdout(struct archive *a, struct archive_entry *e) 683{ 684 char *pathname; 685 mode_t filetype; 686 int cr, text, warn; 687 ssize_t len; 688 unsigned char *p, *q, *end; 689 690 pathname = pathdup(archive_entry_pathname(e)); 691 filetype = archive_entry_filetype(e); 692 693 /* I don't think this can happen in a zipfile.. */ 694 if (!S_ISDIR(filetype) && !S_ISREG(filetype)) { 695 warningx("skipping non-regular entry '%s'", pathname); 696 ac(archive_read_data_skip(a)); 697 free(pathname); 698 return; 699 } 700 701 /* skip directories in -j case */ 702 if (S_ISDIR(filetype)) { 703 ac(archive_read_data_skip(a)); 704 free(pathname); 705 return; 706 } 707 708 /* apply include / exclude patterns */ 709 if (!accept_pathname(pathname)) { 710 ac(archive_read_data_skip(a)); 711 free(pathname); 712 return; 713 } 714 715 if (c_opt) 716 info("x %s\n", pathname); 717 718 text = a_opt; 719 warn = 0; 720 cr = 0; 721 for (int n = 0; ; n++) { 722 len = archive_read_data(a, buffer, sizeof buffer); 723 724 if (len < 0) 725 ac(len); 726 727 /* left over CR from previous buffer */ 728 if (a_opt && cr) { 729 if (len == 0 || buffer[0] != '\n') { 730 if (fwrite("\r", 1, 1, stderr) != 1) 731 error("write('%s')", pathname); 732 } 733 cr = 0; 734 } 735 736 /* EOF */ 737 if (len == 0) 738 break; 739 end = buffer + len; 740 741 /* 742 * Detect whether this is a text file. The correct way to 743 * do this is to check the least significant bit of the 744 * "internal file attributes" field of the corresponding 745 * file header in the central directory, but libarchive 746 * does not read the central directory, so we have to 747 * guess by looking for non-ASCII characters in the 748 * buffer. Hopefully we won't guess wrong. If we do 749 * guess wrong, we print a warning message later. 750 */ 751 if (a_opt && n == 0) { 752 for (p = buffer; p < end; ++p) { 753 if (!isascii((unsigned char)*p)) { 754 text = 0; 755 break; 756 } 757 } 758 } 759 760 /* simple case */ 761 if (!a_opt || !text) { 762 if (fwrite(buffer, 1, len, stdout) != (size_t)len) 763 error("write('%s')", pathname); 764 continue; 765 } 766 767 /* hard case: convert \r\n to \n (sigh...) */ 768 for (p = buffer; p < end; p = q + 1) { 769 for (q = p; q < end; q++) { 770 if (!warn && !isascii(*q)) { 771 warningx("%s may be corrupted due" 772 " to weak text file detection" 773 " heuristic", pathname); 774 warn = 1; 775 } 776 if (q[0] != '\r') 777 continue; 778 if (&q[1] == end) { 779 cr = 1; 780 break; 781 } 782 if (q[1] == '\n') 783 break; 784 } 785 if (fwrite(p, 1, q - p, stdout) != (size_t)(q - p)) 786 error("write('%s')", pathname); 787 } 788 } 789 790 free(pathname); 791} 792 793/* 794 * Print the name of an entry to stdout. 795 */ 796static void 797list(struct archive *a, struct archive_entry *e) 798{ 799 char buf[20]; 800 time_t mtime; 801 802 mtime = archive_entry_mtime(e); 803 strftime(buf, sizeof(buf), "%m-%d-%g %R", localtime(&mtime)); 804 805 if (v_opt == 1) { 806 printf(" %8ju %s %s\n", 807 (uintmax_t)archive_entry_size(e), 808 buf, archive_entry_pathname(e)); 809 } else if (v_opt == 2) { 810 printf("%8ju Stored %7ju 0%% %s %08x %s\n", 811 (uintmax_t)archive_entry_size(e), 812 (uintmax_t)archive_entry_size(e), 813 buf, 814 0U, 815 archive_entry_pathname(e)); 816 } 817 ac(archive_read_data_skip(a)); 818} 819 820/* 821 * Extract to memory to check CRC 822 */ 823static int 824test(struct archive *a, struct archive_entry *e) 825{ 826 ssize_t len; 827 int error_count; 828 829 error_count = 0; 830 if (S_ISDIR(archive_entry_filetype(e))) 831 return 0; 832 833 info(" testing: %s\t", archive_entry_pathname(e)); 834 while ((len = archive_read_data(a, buffer, sizeof buffer)) > 0) 835 /* nothing */; 836 if (len < 0) { 837 info(" %s\n", archive_error_string(a)); 838 ++error_count; 839 } else { 840 info(" OK\n"); 841 } 842 843 /* shouldn't be necessary, but it doesn't hurt */ 844 ac(archive_read_data_skip(a)); 845 846 return error_count; 847} 848 849 850/* 851 * Main loop: open the zipfile, iterate over its contents and decide what 852 * to do with each entry. 853 */ 854static void 855unzip(const char *fn) 856{ 857 struct archive *a; 858 struct archive_entry *e; 859 int fd, ret; 860 uintmax_t total_size, file_count, error_count; 861 862 if (strcmp(fn, "-") == 0) 863 fd = STDIN_FILENO; 864 else if ((fd = open(fn, O_RDONLY)) < 0) 865 error("%s", fn); 866 867 if ((a = archive_read_new()) == NULL) 868 error("archive_read_new failed"); 869 870 ac(archive_read_support_format_zip(a)); 871 ac(archive_read_open_fd(a, fd, 8192)); 872 873 if (!p_opt && !q_opt) 874 printf("Archive: %s\n", fn); 875 if (v_opt == 1) { 876 printf(" Length Date Time Name\n"); 877 printf(" -------- ---- ---- ----\n"); 878 } else if (v_opt == 2) { 879 printf(" Length Method Size Ratio Date Time CRC-32 Name\n"); 880 printf("-------- ------ ------- ----- ---- ---- ------ ----\n"); 881 } 882 883 total_size = 0; 884 file_count = 0; 885 error_count = 0; 886 for (;;) { 887 ret = archive_read_next_header(a, &e); 888 if (ret == ARCHIVE_EOF) 889 break; 890 ac(ret); 891 if (t_opt) 892 error_count += test(a, e); 893 else if (v_opt) 894 list(a, e); 895 else if (p_opt || c_opt) 896 extract_stdout(a, e); 897 else 898 extract(a, e); 899 900 total_size += archive_entry_size(e); 901 ++file_count; 902 } 903 904 if (v_opt == 1) { 905 printf(" -------- -------\n"); 906 printf(" %8ju %ju file%s\n", 907 total_size, file_count, file_count != 1 ? "s" : ""); 908 } else if (v_opt == 2) { 909 printf("-------- ------- --- -------\n"); 910 printf("%8ju %7ju 0%% %ju file%s\n", 911 total_size, total_size, file_count, 912 file_count != 1 ? "s" : ""); 913 } 914 915 ac(archive_read_close(a)); 916 (void)archive_read_finish(a); 917 918 if (fd != STDIN_FILENO && close(fd) != 0) 919 error("%s", fn); 920 921 if (t_opt) { 922 if (error_count > 0) { 923 errorx("%d checksum error(s) found.", error_count); 924 } 925 else { 926 printf("No errors detected in compressed data of %s.\n", 927 fn); 928 } 929 } 930} 931 932static void 933usage(void) 934{ 935 936 fprintf(stderr, "usage: unzip [-aCcfjLlnopqtuv] [-d dir] [-x pattern] zipfile\n"); 937 exit(1); 938} 939 940static int 941getopts(int argc, char *argv[]) 942{ 943 int opt; 944 945 optreset = optind = 1; 946 while ((opt = getopt(argc, argv, "aCcd:fjLlnopqtuvx:")) != -1) 947 switch (opt) { 948 case 'a': 949 a_opt = 1; 950 break; 951 case 'C': 952 C_opt = 1; 953 break; 954 case 'c': 955 c_opt = 1; 956 break; 957 case 'd': 958 d_arg = optarg; 959 break; 960 case 'f': 961 f_opt = 1; 962 break; 963 case 'j': 964 j_opt = 1; 965 break; 966 case 'L': 967 L_opt = 1; 968 break; 969 case 'l': 970 if (v_opt == 0) 971 v_opt = 1; 972 break; 973 case 'n': 974 n_opt = 1; 975 break; 976 case 'o': 977 o_opt = 1; 978 q_opt = 1; 979 break; 980 case 'p': 981 p_opt = 1; 982 break; 983 case 'q': 984 q_opt = 1; 985 break; 986 case 't': 987 t_opt = 1; 988 break; 989 case 'u': 990 u_opt = 1; 991 break; 992 case 'v': 993 v_opt = 2; 994 break; 995 case 'x': 996 add_pattern(&exclude, optarg); 997 break; 998 default: 999 usage(); 1000 } 1001 1002 return (optind); 1003} 1004 1005int 1006main(int argc, char *argv[]) 1007{ 1008 const char *zipfile; 1009 int nopts; 1010 1011 if (isatty(STDOUT_FILENO)) 1012 tty = 1; 1013 1014 if (getenv("UNZIP_DEBUG") != NULL) 1015 unzip_debug = 1; 1016 for (int i = 0; i < argc; ++i) 1017 debug("%s%c", argv[i], (i < argc - 1) ? ' ' : '\n'); 1018 1019 /* 1020 * Info-ZIP's unzip(1) expects certain options to come before the 1021 * zipfile name, and others to come after - though it does not 1022 * enforce this. For simplicity, we accept *all* options both 1023 * before and after the zipfile name. 1024 */ 1025 nopts = getopts(argc, argv); 1026 1027 if (argc <= nopts) 1028 usage(); 1029 zipfile = argv[nopts++]; 1030 1031 while (nopts < argc && *argv[nopts] != '-') 1032 add_pattern(&include, argv[nopts++]); 1033 1034 nopts--; /* fake argv[0] */ 1035 nopts += getopts(argc - nopts, argv + nopts); 1036 1037 if (n_opt + o_opt + u_opt > 1) 1038 errorx("-n, -o and -u are contradictory"); 1039 1040 time(&now); 1041 1042 unzip(zipfile); 1043 1044 exit(0); 1045} 1046