1/* $NetBSD: gzip.c,v 1.116 2018/10/27 11:39:12 skrll Exp $ */ 2 3/*- 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Copyright (c) 1997, 1998, 2003, 2004, 2006, 2008, 2009, 2010, 2011, 2015, 2017 7 * Matthew R. Green 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 */ 32 33/* 34 * gzip.c -- GPL free gzip using zlib. 35 * 36 * RFC 1950 covers the zlib format 37 * RFC 1951 covers the deflate format 38 * RFC 1952 covers the gzip format 39 * 40 * TODO: 41 * - use mmap where possible 42 * - make bzip2/compress -v/-t/-l support work as well as possible 43 */ 44 45#include <sys/endian.h> 46#include <sys/param.h> 47#include <sys/stat.h> 48#include <sys/time.h> 49 50#include <inttypes.h> 51#include <unistd.h> 52#include <stdio.h> 53#include <string.h> 54#include <stdlib.h> 55#include <err.h> 56#include <errno.h> 57#include <fcntl.h> 58#include <zlib.h> 59#include <fts.h> 60#include <libgen.h> 61#include <stdarg.h> 62#include <getopt.h> 63#include <time.h> 64 65/* what type of file are we dealing with */ 66enum filetype { 67 FT_GZIP, 68#ifndef NO_BZIP2_SUPPORT 69 FT_BZIP2, 70#endif 71#ifndef NO_COMPRESS_SUPPORT 72 FT_Z, 73#endif 74#ifndef NO_PACK_SUPPORT 75 FT_PACK, 76#endif 77#ifndef NO_XZ_SUPPORT 78 FT_XZ, 79#endif 80#ifndef NO_LZ_SUPPORT 81 FT_LZ, 82#endif 83#ifndef NO_ZSTD_SUPPORT 84 FT_ZSTD, 85#endif 86 FT_LAST, 87 FT_UNKNOWN 88}; 89 90#ifndef NO_BZIP2_SUPPORT 91#include <bzlib.h> 92 93#define BZ2_SUFFIX ".bz2" 94#define BZIP2_MAGIC "BZh" 95#endif 96 97#ifndef NO_COMPRESS_SUPPORT 98#define Z_SUFFIX ".Z" 99#define Z_MAGIC "\037\235" 100#endif 101 102#ifndef NO_PACK_SUPPORT 103#define PACK_MAGIC "\037\036" 104#endif 105 106#ifndef NO_XZ_SUPPORT 107#include <lzma.h> 108#define XZ_SUFFIX ".xz" 109#define XZ_MAGIC "\3757zXZ" 110#endif 111 112#ifndef NO_LZ_SUPPORT 113#define LZ_SUFFIX ".lz" 114#define LZ_MAGIC "LZIP" 115#endif 116 117#ifndef NO_ZSTD_SUPPORT 118#include <zstd.h> 119#define ZSTD_SUFFIX ".zst" 120#define ZSTD_MAGIC "\050\265\057\375" 121#endif 122 123#define GZ_SUFFIX ".gz" 124 125#define BUFLEN (64 * 1024) 126 127#define GZIP_MAGIC0 0x1F 128#define GZIP_MAGIC1 0x8B 129#define GZIP_OMAGIC1 0x9E 130 131#define GZIP_TIMESTAMP (off_t)4 132#define GZIP_ORIGNAME (off_t)10 133 134#define HEAD_CRC 0x02 135#define EXTRA_FIELD 0x04 136#define ORIG_NAME 0x08 137#define COMMENT 0x10 138 139#define OS_CODE 3 /* Unix */ 140 141typedef struct { 142 const char *zipped; 143 int ziplen; 144 const char *normal; /* for unzip - must not be longer than zipped */ 145} suffixes_t; 146static suffixes_t suffixes[] = { 147#define SUFFIX(Z, N) {Z, sizeof Z - 1, N} 148 SUFFIX(GZ_SUFFIX, ""), /* Overwritten by -S .xxx */ 149 SUFFIX(GZ_SUFFIX, ""), 150 SUFFIX(".z", ""), 151 SUFFIX("-gz", ""), 152 SUFFIX("-z", ""), 153 SUFFIX("_z", ""), 154 SUFFIX(".taz", ".tar"), 155 SUFFIX(".tgz", ".tar"), 156#ifndef NO_BZIP2_SUPPORT 157 SUFFIX(BZ2_SUFFIX, ""), 158 SUFFIX(".tbz", ".tar"), 159 SUFFIX(".tbz2", ".tar"), 160#endif 161#ifndef NO_COMPRESS_SUPPORT 162 SUFFIX(Z_SUFFIX, ""), 163#endif 164#ifndef NO_XZ_SUPPORT 165 SUFFIX(XZ_SUFFIX, ""), 166#endif 167#ifndef NO_LZ_SUPPORT 168 SUFFIX(LZ_SUFFIX, ""), 169#endif 170#ifndef NO_ZSTD_SUPPORT 171 SUFFIX(ZSTD_SUFFIX, ""), 172#endif 173 SUFFIX(GZ_SUFFIX, ""), /* Overwritten by -S "" */ 174#undef SUFFIX 175}; 176#define NUM_SUFFIXES (nitems(suffixes)) 177#define SUFFIX_MAXLEN 30 178 179static const char gzip_version[] = "FreeBSD gzip 20190107"; 180 181static const char gzip_copyright[] = \ 182" Copyright (c) 1997, 1998, 2003, 2004, 2006 Matthew R. Green\n" 183" All rights reserved.\n" 184"\n" 185" Redistribution and use in source and binary forms, with or without\n" 186" modification, are permitted provided that the following conditions\n" 187" are met:\n" 188" 1. Redistributions of source code must retain the above copyright\n" 189" notice, this list of conditions and the following disclaimer.\n" 190" 2. Redistributions in binary form must reproduce the above copyright\n" 191" notice, this list of conditions and the following disclaimer in the\n" 192" documentation and/or other materials provided with the distribution.\n" 193"\n" 194" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n" 195" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n" 196" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n" 197" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n" 198" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n" 199" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n" 200" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\n" 201" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n" 202" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n" 203" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n" 204" SUCH DAMAGE."; 205 206static int cflag; /* stdout mode */ 207static int dflag; /* decompress mode */ 208static int lflag; /* list mode */ 209static int numflag = 6; /* gzip -1..-9 value */ 210 211static const char *remove_file = NULL; /* file to be removed upon SIGINT */ 212 213static int fflag; /* force mode */ 214static int kflag; /* don't delete input files */ 215static int nflag; /* don't save name/timestamp */ 216static int Nflag; /* don't restore name/timestamp */ 217static int qflag; /* quiet mode */ 218static int rflag; /* recursive mode */ 219static int tflag; /* test */ 220static int vflag; /* verbose mode */ 221static sig_atomic_t print_info = 0; 222 223static int exit_value = 0; /* exit value */ 224 225static const char *infile; /* name of file coming in */ 226 227static void maybe_err(const char *fmt, ...) __printflike(1, 2) __dead2; 228#if !defined(NO_BZIP2_SUPPORT) || !defined(NO_PACK_SUPPORT) || \ 229 !defined(NO_XZ_SUPPORT) || !defined(NO_ZSTD_SUPPORT) 230static void maybe_errx(const char *fmt, ...) __printflike(1, 2) __dead2; 231#endif 232static void maybe_warn(const char *fmt, ...) __printflike(1, 2); 233static void maybe_warnx(const char *fmt, ...) __printflike(1, 2); 234static enum filetype file_gettype(u_char *); 235static off_t gz_compress(int, int, off_t *, const char *, uint32_t); 236static off_t gz_uncompress(int, int, char *, size_t, off_t *, const char *); 237static off_t file_compress(char *, char *, size_t); 238static off_t file_uncompress(char *, char *, size_t); 239static void handle_pathname(char *); 240static void handle_file(char *, struct stat *); 241static void handle_stdin(void); 242static void handle_stdout(void); 243static void print_ratio(off_t, off_t, FILE *); 244static void print_list(int fd, off_t, const char *, time_t); 245static void usage(void) __dead2; 246static void display_version(void) __dead2; 247static void display_license(void); 248static const suffixes_t *check_suffix(char *, int); 249static ssize_t read_retry(int, void *, size_t); 250static ssize_t write_retry(int, const void *, size_t); 251static void print_list_out(off_t, off_t, const char*); 252 253static void infile_set(const char *newinfile, off_t total); 254 255static off_t infile_total; /* total expected to read/write */ 256static off_t infile_current; /* current read/write */ 257 258static void check_siginfo(void); 259static off_t cat_fd(unsigned char *, size_t, off_t *, int fd); 260static void prepend_gzip(char *, int *, char ***); 261static void handle_dir(char *); 262static void print_verbage(const char *, const char *, off_t, off_t); 263static void print_test(const char *, int); 264static void copymodes(int fd, const struct stat *, const char *file); 265static int check_outfile(const char *outfile); 266static void setup_signals(void); 267static void infile_newdata(size_t newdata); 268static void infile_clear(void); 269 270#ifndef NO_BZIP2_SUPPORT 271static off_t unbzip2(int, int, char *, size_t, off_t *); 272#endif 273 274#ifndef NO_COMPRESS_SUPPORT 275static FILE *zdopen(int); 276static off_t zuncompress(FILE *, FILE *, char *, size_t, off_t *); 277#endif 278 279#ifndef NO_PACK_SUPPORT 280static off_t unpack(int, int, char *, size_t, off_t *); 281#endif 282 283#ifndef NO_XZ_SUPPORT 284static off_t unxz(int, int, char *, size_t, off_t *); 285static off_t unxz_len(int); 286#endif 287 288#ifndef NO_LZ_SUPPORT 289static off_t unlz(int, int, char *, size_t, off_t *); 290#endif 291 292#ifndef NO_ZSTD_SUPPORT 293static off_t unzstd(int, int, char *, size_t, off_t *); 294#endif 295 296static const struct option longopts[] = { 297 { "stdout", no_argument, 0, 'c' }, 298 { "to-stdout", no_argument, 0, 'c' }, 299 { "decompress", no_argument, 0, 'd' }, 300 { "uncompress", no_argument, 0, 'd' }, 301 { "force", no_argument, 0, 'f' }, 302 { "help", no_argument, 0, 'h' }, 303 { "keep", no_argument, 0, 'k' }, 304 { "list", no_argument, 0, 'l' }, 305 { "no-name", no_argument, 0, 'n' }, 306 { "name", no_argument, 0, 'N' }, 307 { "quiet", no_argument, 0, 'q' }, 308 { "recursive", no_argument, 0, 'r' }, 309 { "suffix", required_argument, 0, 'S' }, 310 { "test", no_argument, 0, 't' }, 311 { "verbose", no_argument, 0, 'v' }, 312 { "version", no_argument, 0, 'V' }, 313 { "fast", no_argument, 0, '1' }, 314 { "best", no_argument, 0, '9' }, 315 { "ascii", no_argument, 0, 'a' }, 316 { "license", no_argument, 0, 'L' }, 317 { NULL, no_argument, 0, 0 }, 318}; 319 320int 321main(int argc, char **argv) 322{ 323 const char *progname = getprogname(); 324 char *gzip; 325 int len; 326 int ch; 327 328 setup_signals(); 329 330 if ((gzip = getenv("GZIP")) != NULL) 331 prepend_gzip(gzip, &argc, &argv); 332 333 /* 334 * XXX 335 * handle being called `gunzip', `zcat' and `gzcat' 336 */ 337 if (strcmp(progname, "gunzip") == 0) 338 dflag = 1; 339 else if (strcmp(progname, "zcat") == 0 || 340 strcmp(progname, "gzcat") == 0) 341 dflag = cflag = 1; 342 343#define OPT_LIST "123456789acdfhklLNnqrS:tVv" 344 345 while ((ch = getopt_long(argc, argv, OPT_LIST, longopts, NULL)) != -1) { 346 switch (ch) { 347 case '1': case '2': case '3': 348 case '4': case '5': case '6': 349 case '7': case '8': case '9': 350 numflag = ch - '0'; 351 break; 352 case 'c': 353 cflag = 1; 354 break; 355 case 'd': 356 dflag = 1; 357 break; 358 case 'l': 359 lflag = 1; 360 dflag = 1; 361 break; 362 case 'V': 363 display_version(); 364 /* NOTREACHED */ 365 case 'a': 366 fprintf(stderr, "%s: option --ascii ignored on this system\n", progname); 367 break; 368 case 'f': 369 fflag = 1; 370 break; 371 case 'k': 372 kflag = 1; 373 break; 374 case 'L': 375 display_license(); 376 /* NOT REACHED */ 377 case 'N': 378 nflag = 0; 379 Nflag = 1; 380 break; 381 case 'n': 382 nflag = 1; 383 Nflag = 0; 384 break; 385 case 'q': 386 qflag = 1; 387 break; 388 case 'r': 389 rflag = 1; 390 break; 391 case 'S': 392 len = strlen(optarg); 393 if (len != 0) { 394 if (len > SUFFIX_MAXLEN) 395 errx(1, "incorrect suffix: '%s': too long", optarg); 396 suffixes[0].zipped = optarg; 397 suffixes[0].ziplen = len; 398 } else { 399 suffixes[NUM_SUFFIXES - 1].zipped = ""; 400 suffixes[NUM_SUFFIXES - 1].ziplen = 0; 401 } 402 break; 403 case 't': 404 cflag = 1; 405 tflag = 1; 406 dflag = 1; 407 break; 408 case 'v': 409 vflag = 1; 410 break; 411 default: 412 usage(); 413 /* NOTREACHED */ 414 } 415 } 416 argv += optind; 417 argc -= optind; 418 419 if (argc == 0) { 420 if (dflag) /* stdin mode */ 421 handle_stdin(); 422 else /* stdout mode */ 423 handle_stdout(); 424 } else { 425 do { 426 handle_pathname(argv[0]); 427 } while (*++argv); 428 } 429 if (qflag == 0 && lflag && argc > 1) 430 print_list(-1, 0, "(totals)", 0); 431 exit(exit_value); 432} 433 434/* maybe print a warning */ 435void 436maybe_warn(const char *fmt, ...) 437{ 438 va_list ap; 439 440 if (qflag == 0) { 441 va_start(ap, fmt); 442 vwarn(fmt, ap); 443 va_end(ap); 444 } 445 if (exit_value == 0) 446 exit_value = 1; 447} 448 449/* ... without an errno. */ 450void 451maybe_warnx(const char *fmt, ...) 452{ 453 va_list ap; 454 455 if (qflag == 0) { 456 va_start(ap, fmt); 457 vwarnx(fmt, ap); 458 va_end(ap); 459 } 460 if (exit_value == 0) 461 exit_value = 1; 462} 463 464/* maybe print an error */ 465void 466maybe_err(const char *fmt, ...) 467{ 468 va_list ap; 469 470 if (qflag == 0) { 471 va_start(ap, fmt); 472 vwarn(fmt, ap); 473 va_end(ap); 474 } 475 exit(2); 476} 477 478#if !defined(NO_BZIP2_SUPPORT) || !defined(NO_PACK_SUPPORT) || \ 479 !defined(NO_XZ_SUPPORT) || !defined(NO_ZSTD_SUPPORT) 480/* ... without an errno. */ 481void 482maybe_errx(const char *fmt, ...) 483{ 484 va_list ap; 485 486 if (qflag == 0) { 487 va_start(ap, fmt); 488 vwarnx(fmt, ap); 489 va_end(ap); 490 } 491 exit(2); 492} 493#endif 494 495/* split up $GZIP and prepend it to the argument list */ 496static void 497prepend_gzip(char *gzip, int *argc, char ***argv) 498{ 499 char *s, **nargv, **ac; 500 int nenvarg = 0, i; 501 502 /* scan how many arguments there are */ 503 for (s = gzip;;) { 504 while (*s == ' ' || *s == '\t') 505 s++; 506 if (*s == 0) 507 goto count_done; 508 nenvarg++; 509 while (*s != ' ' && *s != '\t') 510 if (*s++ == 0) 511 goto count_done; 512 } 513count_done: 514 /* punt early */ 515 if (nenvarg == 0) 516 return; 517 518 *argc += nenvarg; 519 ac = *argv; 520 521 nargv = (char **)malloc((*argc + 1) * sizeof(char *)); 522 if (nargv == NULL) 523 maybe_err("malloc"); 524 525 /* stash this away */ 526 *argv = nargv; 527 528 /* copy the program name first */ 529 i = 0; 530 nargv[i++] = *(ac++); 531 532 /* take a copy of $GZIP and add it to the array */ 533 s = strdup(gzip); 534 if (s == NULL) 535 maybe_err("strdup"); 536 for (;;) { 537 /* Skip whitespaces. */ 538 while (*s == ' ' || *s == '\t') 539 s++; 540 if (*s == 0) 541 goto copy_done; 542 nargv[i++] = s; 543 /* Find the end of this argument. */ 544 while (*s != ' ' && *s != '\t') 545 if (*s++ == 0) 546 /* Argument followed by NUL. */ 547 goto copy_done; 548 /* Terminate by overwriting ' ' or '\t' with NUL. */ 549 *s++ = 0; 550 } 551copy_done: 552 553 /* copy the original arguments and a NULL */ 554 while (*ac) 555 nargv[i++] = *(ac++); 556 nargv[i] = NULL; 557} 558 559/* compress input to output. Return bytes read, -1 on error */ 560static off_t 561gz_compress(int in, int out, off_t *gsizep, const char *origname, uint32_t mtime) 562{ 563 z_stream z; 564 char *outbufp, *inbufp; 565 off_t in_tot = 0, out_tot = 0; 566 ssize_t in_size; 567 int i, error; 568 uLong crc; 569 570 outbufp = malloc(BUFLEN); 571 inbufp = malloc(BUFLEN); 572 if (outbufp == NULL || inbufp == NULL) { 573 maybe_err("malloc failed"); 574 goto out; 575 } 576 577 memset(&z, 0, sizeof z); 578 z.zalloc = Z_NULL; 579 z.zfree = Z_NULL; 580 z.opaque = 0; 581 582 if (nflag != 0) { 583 mtime = 0; 584 origname = ""; 585 } 586 587 i = snprintf(outbufp, BUFLEN, "%c%c%c%c%c%c%c%c%c%c%s", 588 GZIP_MAGIC0, GZIP_MAGIC1, Z_DEFLATED, 589 *origname ? ORIG_NAME : 0, 590 mtime & 0xff, 591 (mtime >> 8) & 0xff, 592 (mtime >> 16) & 0xff, 593 (mtime >> 24) & 0xff, 594 numflag == 1 ? 4 : numflag == 9 ? 2 : 0, 595 OS_CODE, origname); 596 if (i >= BUFLEN) 597 /* this need PATH_MAX > BUFLEN ... */ 598 maybe_err("snprintf"); 599 if (*origname) 600 i++; 601 602 z.next_out = (unsigned char *)outbufp + i; 603 z.avail_out = BUFLEN - i; 604 605 error = deflateInit2(&z, numflag, Z_DEFLATED, 606 (-MAX_WBITS), 8, Z_DEFAULT_STRATEGY); 607 if (error != Z_OK) { 608 maybe_warnx("deflateInit2 failed"); 609 in_tot = -1; 610 goto out; 611 } 612 613 crc = crc32(0L, Z_NULL, 0); 614 for (;;) { 615 if (z.avail_out == 0) { 616 if (write_retry(out, outbufp, BUFLEN) != BUFLEN) { 617 maybe_warn("write"); 618 out_tot = -1; 619 goto out; 620 } 621 622 out_tot += BUFLEN; 623 z.next_out = (unsigned char *)outbufp; 624 z.avail_out = BUFLEN; 625 } 626 627 if (z.avail_in == 0) { 628 in_size = read(in, inbufp, BUFLEN); 629 if (in_size < 0) { 630 maybe_warn("read"); 631 in_tot = -1; 632 goto out; 633 } 634 if (in_size == 0) 635 break; 636 infile_newdata(in_size); 637 638 crc = crc32(crc, (const Bytef *)inbufp, (unsigned)in_size); 639 in_tot += in_size; 640 z.next_in = (unsigned char *)inbufp; 641 z.avail_in = in_size; 642 } 643 644 error = deflate(&z, Z_NO_FLUSH); 645 if (error != Z_OK && error != Z_STREAM_END) { 646 maybe_warnx("deflate failed"); 647 in_tot = -1; 648 goto out; 649 } 650 } 651 652 /* clean up */ 653 for (;;) { 654 size_t len; 655 ssize_t w; 656 657 error = deflate(&z, Z_FINISH); 658 if (error != Z_OK && error != Z_STREAM_END) { 659 maybe_warnx("deflate failed"); 660 in_tot = -1; 661 goto out; 662 } 663 664 len = (char *)z.next_out - outbufp; 665 666 w = write_retry(out, outbufp, len); 667 if (w == -1 || (size_t)w != len) { 668 maybe_warn("write"); 669 out_tot = -1; 670 goto out; 671 } 672 out_tot += len; 673 z.next_out = (unsigned char *)outbufp; 674 z.avail_out = BUFLEN; 675 676 if (error == Z_STREAM_END) 677 break; 678 } 679 680 if (deflateEnd(&z) != Z_OK) { 681 maybe_warnx("deflateEnd failed"); 682 in_tot = -1; 683 goto out; 684 } 685 686 i = snprintf(outbufp, BUFLEN, "%c%c%c%c%c%c%c%c", 687 (int)crc & 0xff, 688 (int)(crc >> 8) & 0xff, 689 (int)(crc >> 16) & 0xff, 690 (int)(crc >> 24) & 0xff, 691 (int)in_tot & 0xff, 692 (int)(in_tot >> 8) & 0xff, 693 (int)(in_tot >> 16) & 0xff, 694 (int)(in_tot >> 24) & 0xff); 695 if (i != 8) 696 maybe_err("snprintf"); 697 if (write_retry(out, outbufp, i) != i) { 698 maybe_warn("write"); 699 in_tot = -1; 700 } else 701 out_tot += i; 702 703out: 704 if (inbufp != NULL) 705 free(inbufp); 706 if (outbufp != NULL) 707 free(outbufp); 708 if (gsizep) 709 *gsizep = out_tot; 710 return in_tot; 711} 712 713/* 714 * uncompress input to output then close the input. return the 715 * uncompressed size written, and put the compressed sized read 716 * into `*gsizep'. 717 */ 718static off_t 719gz_uncompress(int in, int out, char *pre, size_t prelen, off_t *gsizep, 720 const char *filename) 721{ 722 z_stream z; 723 char *outbufp, *inbufp; 724 off_t out_tot = -1, in_tot = 0; 725 uint32_t out_sub_tot = 0; 726 enum { 727 GZSTATE_MAGIC0, 728 GZSTATE_MAGIC1, 729 GZSTATE_METHOD, 730 GZSTATE_FLAGS, 731 GZSTATE_SKIPPING, 732 GZSTATE_EXTRA, 733 GZSTATE_EXTRA2, 734 GZSTATE_EXTRA3, 735 GZSTATE_ORIGNAME, 736 GZSTATE_COMMENT, 737 GZSTATE_HEAD_CRC1, 738 GZSTATE_HEAD_CRC2, 739 GZSTATE_INIT, 740 GZSTATE_READ, 741 GZSTATE_CRC, 742 GZSTATE_LEN, 743 } state = GZSTATE_MAGIC0; 744 int flags = 0, skip_count = 0; 745 int error = Z_STREAM_ERROR, done_reading = 0; 746 uLong crc = 0; 747 ssize_t wr; 748 int needmore = 0; 749 750#define ADVANCE() { z.next_in++; z.avail_in--; } 751 752 if ((outbufp = malloc(BUFLEN)) == NULL) { 753 maybe_err("malloc failed"); 754 goto out2; 755 } 756 if ((inbufp = malloc(BUFLEN)) == NULL) { 757 maybe_err("malloc failed"); 758 goto out1; 759 } 760 761 memset(&z, 0, sizeof z); 762 z.avail_in = prelen; 763 z.next_in = (unsigned char *)pre; 764 z.avail_out = BUFLEN; 765 z.next_out = (unsigned char *)outbufp; 766 z.zalloc = NULL; 767 z.zfree = NULL; 768 z.opaque = 0; 769 770 in_tot = prelen; 771 out_tot = 0; 772 773 for (;;) { 774 check_siginfo(); 775 if ((z.avail_in == 0 || needmore) && done_reading == 0) { 776 ssize_t in_size; 777 778 if (z.avail_in > 0) { 779 memmove(inbufp, z.next_in, z.avail_in); 780 } 781 z.next_in = (unsigned char *)inbufp; 782 in_size = read(in, z.next_in + z.avail_in, 783 BUFLEN - z.avail_in); 784 785 if (in_size == -1) { 786 maybe_warn("failed to read stdin"); 787 goto stop_and_fail; 788 } else if (in_size == 0) { 789 done_reading = 1; 790 } 791 infile_newdata(in_size); 792 793 z.avail_in += in_size; 794 needmore = 0; 795 796 in_tot += in_size; 797 } 798 if (z.avail_in == 0) { 799 if (done_reading && state != GZSTATE_MAGIC0) { 800 maybe_warnx("%s: unexpected end of file", 801 filename); 802 goto stop_and_fail; 803 } 804 goto stop; 805 } 806 switch (state) { 807 case GZSTATE_MAGIC0: 808 if (*z.next_in != GZIP_MAGIC0) { 809 if (in_tot > 0) { 810 maybe_warnx("%s: trailing garbage " 811 "ignored", filename); 812 exit_value = 2; 813 goto stop; 814 } 815 maybe_warnx("input not gziped (MAGIC0)"); 816 goto stop_and_fail; 817 } 818 ADVANCE(); 819 state++; 820 out_sub_tot = 0; 821 crc = crc32(0L, Z_NULL, 0); 822 break; 823 824 case GZSTATE_MAGIC1: 825 if (*z.next_in != GZIP_MAGIC1 && 826 *z.next_in != GZIP_OMAGIC1) { 827 maybe_warnx("input not gziped (MAGIC1)"); 828 goto stop_and_fail; 829 } 830 ADVANCE(); 831 state++; 832 break; 833 834 case GZSTATE_METHOD: 835 if (*z.next_in != Z_DEFLATED) { 836 maybe_warnx("unknown compression method"); 837 goto stop_and_fail; 838 } 839 ADVANCE(); 840 state++; 841 break; 842 843 case GZSTATE_FLAGS: 844 flags = *z.next_in; 845 ADVANCE(); 846 skip_count = 6; 847 state++; 848 break; 849 850 case GZSTATE_SKIPPING: 851 if (skip_count > 0) { 852 skip_count--; 853 ADVANCE(); 854 } else 855 state++; 856 break; 857 858 case GZSTATE_EXTRA: 859 if ((flags & EXTRA_FIELD) == 0) { 860 state = GZSTATE_ORIGNAME; 861 break; 862 } 863 skip_count = *z.next_in; 864 ADVANCE(); 865 state++; 866 break; 867 868 case GZSTATE_EXTRA2: 869 skip_count |= ((*z.next_in) << 8); 870 ADVANCE(); 871 state++; 872 break; 873 874 case GZSTATE_EXTRA3: 875 if (skip_count > 0) { 876 skip_count--; 877 ADVANCE(); 878 } else 879 state++; 880 break; 881 882 case GZSTATE_ORIGNAME: 883 if ((flags & ORIG_NAME) == 0) { 884 state++; 885 break; 886 } 887 if (*z.next_in == 0) 888 state++; 889 ADVANCE(); 890 break; 891 892 case GZSTATE_COMMENT: 893 if ((flags & COMMENT) == 0) { 894 state++; 895 break; 896 } 897 if (*z.next_in == 0) 898 state++; 899 ADVANCE(); 900 break; 901 902 case GZSTATE_HEAD_CRC1: 903 if (flags & HEAD_CRC) 904 skip_count = 2; 905 else 906 skip_count = 0; 907 state++; 908 break; 909 910 case GZSTATE_HEAD_CRC2: 911 if (skip_count > 0) { 912 skip_count--; 913 ADVANCE(); 914 } else 915 state++; 916 break; 917 918 case GZSTATE_INIT: 919 if (inflateInit2(&z, -MAX_WBITS) != Z_OK) { 920 maybe_warnx("failed to inflateInit"); 921 goto stop_and_fail; 922 } 923 state++; 924 break; 925 926 case GZSTATE_READ: 927 error = inflate(&z, Z_FINISH); 928 switch (error) { 929 /* Z_BUF_ERROR goes with Z_FINISH... */ 930 case Z_BUF_ERROR: 931 if (z.avail_out > 0 && !done_reading) 932 continue; 933 934 case Z_STREAM_END: 935 case Z_OK: 936 break; 937 938 case Z_NEED_DICT: 939 maybe_warnx("Z_NEED_DICT error"); 940 goto stop_and_fail; 941 case Z_DATA_ERROR: 942 maybe_warnx("data stream error"); 943 goto stop_and_fail; 944 case Z_STREAM_ERROR: 945 maybe_warnx("internal stream error"); 946 goto stop_and_fail; 947 case Z_MEM_ERROR: 948 maybe_warnx("memory allocation error"); 949 goto stop_and_fail; 950 951 default: 952 maybe_warn("unknown error from inflate(): %d", 953 error); 954 } 955 wr = BUFLEN - z.avail_out; 956 957 if (wr != 0) { 958 crc = crc32(crc, (const Bytef *)outbufp, (unsigned)wr); 959 if ( 960 /* don't write anything with -t */ 961 tflag == 0 && 962 write_retry(out, outbufp, wr) != wr) { 963 maybe_warn("error writing to output"); 964 goto stop_and_fail; 965 } 966 967 out_tot += wr; 968 out_sub_tot += wr; 969 } 970 971 if (error == Z_STREAM_END) { 972 inflateEnd(&z); 973 state++; 974 } 975 976 z.next_out = (unsigned char *)outbufp; 977 z.avail_out = BUFLEN; 978 979 break; 980 case GZSTATE_CRC: 981 { 982 uLong origcrc; 983 984 if (z.avail_in < 4) { 985 if (!done_reading) { 986 needmore = 1; 987 continue; 988 } 989 maybe_warnx("truncated input"); 990 goto stop_and_fail; 991 } 992 origcrc = le32dec(&z.next_in[0]); 993 if (origcrc != crc) { 994 maybe_warnx("invalid compressed" 995 " data--crc error"); 996 goto stop_and_fail; 997 } 998 } 999 1000 z.avail_in -= 4; 1001 z.next_in += 4; 1002 1003 if (!z.avail_in && done_reading) { 1004 goto stop; 1005 } 1006 state++; 1007 break; 1008 case GZSTATE_LEN: 1009 { 1010 uLong origlen; 1011 1012 if (z.avail_in < 4) { 1013 if (!done_reading) { 1014 needmore = 1; 1015 continue; 1016 } 1017 maybe_warnx("truncated input"); 1018 goto stop_and_fail; 1019 } 1020 origlen = le32dec(&z.next_in[0]); 1021 1022 if (origlen != out_sub_tot) { 1023 maybe_warnx("invalid compressed" 1024 " data--length error"); 1025 goto stop_and_fail; 1026 } 1027 } 1028 1029 z.avail_in -= 4; 1030 z.next_in += 4; 1031 1032 if (error < 0) { 1033 maybe_warnx("decompression error"); 1034 goto stop_and_fail; 1035 } 1036 state = GZSTATE_MAGIC0; 1037 break; 1038 } 1039 continue; 1040stop_and_fail: 1041 out_tot = -1; 1042stop: 1043 break; 1044 } 1045 if (state > GZSTATE_INIT) 1046 inflateEnd(&z); 1047 1048 free(inbufp); 1049out1: 1050 free(outbufp); 1051out2: 1052 if (gsizep) 1053 *gsizep = in_tot; 1054 return (out_tot); 1055} 1056 1057/* 1058 * set the owner, mode, flags & utimes using the given file descriptor. 1059 * file is only used in possible warning messages. 1060 */ 1061static void 1062copymodes(int fd, const struct stat *sbp, const char *file) 1063{ 1064 struct timespec times[2]; 1065 struct stat sb; 1066 1067 /* 1068 * If we have no info on the input, give this file some 1069 * default values and return.. 1070 */ 1071 if (sbp == NULL) { 1072 mode_t mask = umask(022); 1073 1074 (void)fchmod(fd, DEFFILEMODE & ~mask); 1075 (void)umask(mask); 1076 return; 1077 } 1078 sb = *sbp; 1079 1080 /* if the chown fails, remove set-id bits as-per compress(1) */ 1081 if (fchown(fd, sb.st_uid, sb.st_gid) < 0) { 1082 if (errno != EPERM) 1083 maybe_warn("couldn't fchown: %s", file); 1084 sb.st_mode &= ~(S_ISUID|S_ISGID); 1085 } 1086 1087 /* we only allow set-id and the 9 normal permission bits */ 1088 sb.st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO; 1089 if (fchmod(fd, sb.st_mode) < 0) 1090 maybe_warn("couldn't fchmod: %s", file); 1091 1092 times[0] = sb.st_atim; 1093 times[1] = sb.st_mtim; 1094 if (futimens(fd, times) < 0) 1095 maybe_warn("couldn't futimens: %s", file); 1096 1097 /* only try flags if they exist already */ 1098 if (sb.st_flags != 0 && fchflags(fd, sb.st_flags) < 0) 1099 maybe_warn("couldn't fchflags: %s", file); 1100} 1101 1102/* what sort of file is this? */ 1103static enum filetype 1104file_gettype(u_char *buf) 1105{ 1106 1107 if (buf[0] == GZIP_MAGIC0 && 1108 (buf[1] == GZIP_MAGIC1 || buf[1] == GZIP_OMAGIC1)) 1109 return FT_GZIP; 1110#ifndef NO_BZIP2_SUPPORT 1111 else if (memcmp(buf, BZIP2_MAGIC, 3) == 0 && 1112 buf[3] >= '0' && buf[3] <= '9') 1113 return FT_BZIP2; 1114#endif 1115#ifndef NO_COMPRESS_SUPPORT 1116 else if (memcmp(buf, Z_MAGIC, 2) == 0) 1117 return FT_Z; 1118#endif 1119#ifndef NO_PACK_SUPPORT 1120 else if (memcmp(buf, PACK_MAGIC, 2) == 0) 1121 return FT_PACK; 1122#endif 1123#ifndef NO_XZ_SUPPORT 1124 else if (memcmp(buf, XZ_MAGIC, 4) == 0) /* XXX: We only have 4 bytes */ 1125 return FT_XZ; 1126#endif 1127#ifndef NO_LZ_SUPPORT 1128 else if (memcmp(buf, LZ_MAGIC, 4) == 0) 1129 return FT_LZ; 1130#endif 1131#ifndef NO_ZSTD_SUPPORT 1132 else if (memcmp(buf, ZSTD_MAGIC, 4) == 0) 1133 return FT_ZSTD; 1134#endif 1135 else 1136 return FT_UNKNOWN; 1137} 1138 1139/* check the outfile is OK. */ 1140static int 1141check_outfile(const char *outfile) 1142{ 1143 struct stat sb; 1144 int ok = 1; 1145 1146 if (lflag == 0 && stat(outfile, &sb) == 0) { 1147 if (fflag) 1148 unlink(outfile); 1149 else if (isatty(STDIN_FILENO)) { 1150 char ans[10] = { 'n', '\0' }; /* default */ 1151 1152 fprintf(stderr, "%s already exists -- do you wish to " 1153 "overwrite (y or n)? " , outfile); 1154 (void)fgets(ans, sizeof(ans) - 1, stdin); 1155 if (ans[0] != 'y' && ans[0] != 'Y') { 1156 fprintf(stderr, "\tnot overwriting\n"); 1157 ok = 0; 1158 } else 1159 unlink(outfile); 1160 } else { 1161 maybe_warnx("%s already exists -- skipping", outfile); 1162 ok = 0; 1163 } 1164 } 1165 return ok; 1166} 1167 1168static void 1169unlink_input(const char *file, const struct stat *sb) 1170{ 1171 struct stat nsb; 1172 1173 if (kflag) 1174 return; 1175 if (stat(file, &nsb) != 0) 1176 /* Must be gone already */ 1177 return; 1178 if (nsb.st_dev != sb->st_dev || nsb.st_ino != sb->st_ino) 1179 /* Definitely a different file */ 1180 return; 1181 unlink(file); 1182} 1183 1184static void 1185got_sigint(int signo __unused) 1186{ 1187 1188 if (remove_file != NULL) 1189 unlink(remove_file); 1190 _exit(2); 1191} 1192 1193static void 1194got_siginfo(int signo __unused) 1195{ 1196 1197 print_info = 1; 1198} 1199 1200static void 1201setup_signals(void) 1202{ 1203 1204 signal(SIGINFO, got_siginfo); 1205 signal(SIGINT, got_sigint); 1206} 1207 1208static void 1209infile_newdata(size_t newdata) 1210{ 1211 1212 infile_current += newdata; 1213} 1214 1215static void 1216infile_set(const char *newinfile, off_t total) 1217{ 1218 1219 if (newinfile) 1220 infile = newinfile; 1221 infile_total = total; 1222} 1223 1224static void 1225infile_clear(void) 1226{ 1227 1228 infile = NULL; 1229 infile_total = infile_current = 0; 1230} 1231 1232static const suffixes_t * 1233check_suffix(char *file, int xlate) 1234{ 1235 const suffixes_t *s; 1236 int len = strlen(file); 1237 char *sp; 1238 1239 for (s = suffixes; s != suffixes + NUM_SUFFIXES; s++) { 1240 /* if it doesn't fit in "a.suf", don't bother */ 1241 if (s->ziplen >= len) 1242 continue; 1243 sp = file + len - s->ziplen; 1244 if (strcmp(s->zipped, sp) != 0) 1245 continue; 1246 if (xlate) 1247 strcpy(sp, s->normal); 1248 return s; 1249 } 1250 return NULL; 1251} 1252 1253/* 1254 * compress the given file: create a corresponding .gz file and remove the 1255 * original. 1256 */ 1257static off_t 1258file_compress(char *file, char *outfile, size_t outsize) 1259{ 1260 int in; 1261 int out; 1262 off_t size, in_size; 1263 struct stat isb, osb; 1264 const suffixes_t *suff; 1265 1266 in = open(file, O_RDONLY); 1267 if (in == -1) { 1268 maybe_warn("can't open %s", file); 1269 return (-1); 1270 } 1271 1272 if (fstat(in, &isb) != 0) { 1273 maybe_warn("couldn't stat: %s", file); 1274 close(in); 1275 return (-1); 1276 } 1277 1278 if (fstat(in, &isb) != 0) { 1279 close(in); 1280 maybe_warn("can't stat %s", file); 1281 return -1; 1282 } 1283 infile_set(file, isb.st_size); 1284 1285 if (cflag == 0) { 1286 if (isb.st_nlink > 1 && fflag == 0) { 1287 maybe_warnx("%s has %ju other link%s -- " 1288 "skipping", file, 1289 (uintmax_t)isb.st_nlink - 1, 1290 isb.st_nlink == 1 ? "" : "s"); 1291 close(in); 1292 return -1; 1293 } 1294 1295 if (fflag == 0 && (suff = check_suffix(file, 0)) && 1296 suff->zipped[0] != 0) { 1297 maybe_warnx("%s already has %s suffix -- unchanged", 1298 file, suff->zipped); 1299 close(in); 1300 return (-1); 1301 } 1302 1303 /* Add (usually) .gz to filename */ 1304 if ((size_t)snprintf(outfile, outsize, "%s%s", 1305 file, suffixes[0].zipped) >= outsize) 1306 memcpy(outfile + outsize - suffixes[0].ziplen - 1, 1307 suffixes[0].zipped, suffixes[0].ziplen + 1); 1308 1309 if (check_outfile(outfile) == 0) { 1310 close(in); 1311 return (-1); 1312 } 1313 } 1314 1315 if (cflag == 0) { 1316 out = open(outfile, O_WRONLY | O_CREAT | O_EXCL, 0600); 1317 if (out == -1) { 1318 maybe_warn("could not create output: %s", outfile); 1319 fclose(stdin); 1320 return (-1); 1321 } 1322 remove_file = outfile; 1323 } else 1324 out = STDOUT_FILENO; 1325 1326 in_size = gz_compress(in, out, &size, basename(file), (uint32_t)isb.st_mtime); 1327 1328 (void)close(in); 1329 1330 /* 1331 * If there was an error, in_size will be -1. 1332 * If we compressed to stdout, just return the size. 1333 * Otherwise stat the file and check it is the correct size. 1334 * We only blow away the file if we can stat the output and it 1335 * has the expected size. 1336 */ 1337 if (cflag != 0) 1338 return in_size == -1 ? -1 : size; 1339 1340 if (fstat(out, &osb) != 0) { 1341 maybe_warn("couldn't stat: %s", outfile); 1342 goto bad_outfile; 1343 } 1344 1345 if (osb.st_size != size) { 1346 maybe_warnx("output file: %s wrong size (%ju != %ju), deleting", 1347 outfile, (uintmax_t)osb.st_size, (uintmax_t)size); 1348 goto bad_outfile; 1349 } 1350 1351 copymodes(out, &isb, outfile); 1352 remove_file = NULL; 1353 if (close(out) == -1) 1354 maybe_warn("couldn't close output"); 1355 1356 /* output is good, ok to delete input */ 1357 unlink_input(file, &isb); 1358 return (size); 1359 1360 bad_outfile: 1361 if (close(out) == -1) 1362 maybe_warn("couldn't close output"); 1363 1364 maybe_warnx("leaving original %s", file); 1365 unlink(outfile); 1366 return (size); 1367} 1368 1369/* uncompress the given file and remove the original */ 1370static off_t 1371file_uncompress(char *file, char *outfile, size_t outsize) 1372{ 1373 struct stat isb, osb; 1374 off_t size; 1375 ssize_t rbytes; 1376 unsigned char fourbytes[4]; 1377 enum filetype method; 1378 int fd, ofd, zfd = -1; 1379 int error; 1380 size_t in_size; 1381 ssize_t rv; 1382 time_t timestamp = 0; 1383 char name[PATH_MAX + 1]; 1384 1385 /* gather the old name info */ 1386 1387 fd = open(file, O_RDONLY); 1388 if (fd < 0) { 1389 maybe_warn("can't open %s", file); 1390 goto lose; 1391 } 1392 if (fstat(fd, &isb) != 0) { 1393 maybe_warn("can't stat %s", file); 1394 goto lose; 1395 } 1396 if (S_ISREG(isb.st_mode)) 1397 in_size = isb.st_size; 1398 else 1399 in_size = 0; 1400 infile_set(file, in_size); 1401 1402 strlcpy(outfile, file, outsize); 1403 if (check_suffix(outfile, 1) == NULL && !(cflag || lflag)) { 1404 maybe_warnx("%s: unknown suffix -- ignored", file); 1405 goto lose; 1406 } 1407 1408 rbytes = read(fd, fourbytes, sizeof fourbytes); 1409 if (rbytes != sizeof fourbytes) { 1410 /* we don't want to fail here. */ 1411 if (fflag) 1412 goto lose; 1413 if (rbytes == -1) 1414 maybe_warn("can't read %s", file); 1415 else 1416 goto unexpected_EOF; 1417 goto lose; 1418 } 1419 infile_newdata(rbytes); 1420 1421 method = file_gettype(fourbytes); 1422 if (fflag == 0 && method == FT_UNKNOWN) { 1423 maybe_warnx("%s: not in gzip format", file); 1424 goto lose; 1425 } 1426 1427 1428 if (method == FT_GZIP && Nflag) { 1429 unsigned char ts[4]; /* timestamp */ 1430 1431 rv = pread(fd, ts, sizeof ts, GZIP_TIMESTAMP); 1432 if (rv >= 0 && rv < (ssize_t)(sizeof ts)) 1433 goto unexpected_EOF; 1434 if (rv == -1) { 1435 if (!fflag) 1436 maybe_warn("can't read %s", file); 1437 goto lose; 1438 } 1439 infile_newdata(rv); 1440 timestamp = le32dec(&ts[0]); 1441 1442 if (fourbytes[3] & ORIG_NAME) { 1443 rbytes = pread(fd, name, sizeof(name) - 1, GZIP_ORIGNAME); 1444 if (rbytes < 0) { 1445 maybe_warn("can't read %s", file); 1446 goto lose; 1447 } 1448 if (name[0] != '\0') { 1449 char *dp, *nf; 1450 1451 /* Make sure that name is NUL-terminated */ 1452 name[rbytes] = '\0'; 1453 1454 /* strip saved directory name */ 1455 nf = strrchr(name, '/'); 1456 if (nf == NULL) 1457 nf = name; 1458 else 1459 nf++; 1460 1461 /* preserve original directory name */ 1462 dp = strrchr(file, '/'); 1463 if (dp == NULL) 1464 dp = file; 1465 else 1466 dp++; 1467 snprintf(outfile, outsize, "%.*s%.*s", 1468 (int) (dp - file), 1469 file, (int) rbytes, nf); 1470 } 1471 } 1472 } 1473 lseek(fd, 0, SEEK_SET); 1474 1475 if (cflag == 0 || lflag) { 1476 if (isb.st_nlink > 1 && lflag == 0 && fflag == 0) { 1477 maybe_warnx("%s has %ju other links -- skipping", 1478 file, (uintmax_t)isb.st_nlink - 1); 1479 goto lose; 1480 } 1481 if (nflag == 0 && timestamp) 1482 isb.st_mtime = timestamp; 1483 if (check_outfile(outfile) == 0) 1484 goto lose; 1485 } 1486 1487 if (cflag) 1488 zfd = STDOUT_FILENO; 1489 else if (lflag) 1490 zfd = -1; 1491 else { 1492 zfd = open(outfile, O_WRONLY|O_CREAT|O_EXCL, 0600); 1493 if (zfd == STDOUT_FILENO) { 1494 /* We won't close STDOUT_FILENO later... */ 1495 zfd = dup(zfd); 1496 close(STDOUT_FILENO); 1497 } 1498 if (zfd == -1) { 1499 maybe_warn("can't open %s", outfile); 1500 goto lose; 1501 } 1502 remove_file = outfile; 1503 } 1504 1505 switch (method) { 1506#ifndef NO_BZIP2_SUPPORT 1507 case FT_BZIP2: 1508 /* XXX */ 1509 if (lflag) { 1510 maybe_warnx("no -l with bzip2 files"); 1511 goto lose; 1512 } 1513 1514 size = unbzip2(fd, zfd, NULL, 0, NULL); 1515 break; 1516#endif 1517 1518#ifndef NO_COMPRESS_SUPPORT 1519 case FT_Z: { 1520 FILE *in, *out; 1521 1522 /* XXX */ 1523 if (lflag) { 1524 maybe_warnx("no -l with Lempel-Ziv files"); 1525 goto lose; 1526 } 1527 1528 if ((in = zdopen(fd)) == NULL) { 1529 maybe_warn("zdopen for read: %s", file); 1530 goto lose; 1531 } 1532 1533 out = fdopen(dup(zfd), "w"); 1534 if (out == NULL) { 1535 maybe_warn("fdopen for write: %s", outfile); 1536 fclose(in); 1537 goto lose; 1538 } 1539 1540 size = zuncompress(in, out, NULL, 0, NULL); 1541 /* need to fclose() if ferror() is true... */ 1542 error = ferror(in); 1543 if (error | fclose(in)) { 1544 if (error) 1545 maybe_warn("failed infile"); 1546 else 1547 maybe_warn("failed infile fclose"); 1548 if (cflag == 0) 1549 unlink(outfile); 1550 (void)fclose(out); 1551 goto lose; 1552 } 1553 if (fclose(out) != 0) { 1554 maybe_warn("failed outfile fclose"); 1555 if (cflag == 0) 1556 unlink(outfile); 1557 goto lose; 1558 } 1559 break; 1560 } 1561#endif 1562 1563#ifndef NO_PACK_SUPPORT 1564 case FT_PACK: 1565 if (lflag) { 1566 maybe_warnx("no -l with packed files"); 1567 goto lose; 1568 } 1569 1570 size = unpack(fd, zfd, NULL, 0, NULL); 1571 break; 1572#endif 1573 1574#ifndef NO_XZ_SUPPORT 1575 case FT_XZ: 1576 if (lflag) { 1577 size = unxz_len(fd); 1578 if (!tflag) { 1579 print_list_out(in_size, size, file); 1580 close(fd); 1581 return -1; 1582 } 1583 } else 1584 size = unxz(fd, zfd, NULL, 0, NULL); 1585 break; 1586#endif 1587 1588#ifndef NO_LZ_SUPPORT 1589 case FT_LZ: 1590 if (lflag) { 1591 maybe_warnx("no -l with lzip files"); 1592 goto lose; 1593 } 1594 size = unlz(fd, zfd, NULL, 0, NULL); 1595 break; 1596#endif 1597 1598#ifndef NO_ZSTD_SUPPORT 1599 case FT_ZSTD: 1600 if (lflag) { 1601 maybe_warnx("no -l with zstd files"); 1602 goto lose; 1603 } 1604 size = unzstd(fd, zfd, NULL, 0, NULL); 1605 break; 1606#endif 1607 case FT_UNKNOWN: 1608 if (lflag) { 1609 maybe_warnx("no -l for unknown filetypes"); 1610 goto lose; 1611 } 1612 size = cat_fd(NULL, 0, NULL, fd); 1613 break; 1614 default: 1615 if (lflag) { 1616 print_list(fd, in_size, outfile, isb.st_mtime); 1617 if (!tflag) { 1618 close(fd); 1619 return -1; /* XXX */ 1620 } 1621 } 1622 1623 size = gz_uncompress(fd, zfd, NULL, 0, NULL, file); 1624 break; 1625 } 1626 1627 if (close(fd) != 0) 1628 maybe_warn("couldn't close input"); 1629 if (zfd != STDOUT_FILENO && close(zfd) != 0) 1630 maybe_warn("couldn't close output"); 1631 1632 if (size == -1) { 1633 if (cflag == 0) 1634 unlink(outfile); 1635 maybe_warnx("%s: uncompress failed", file); 1636 return -1; 1637 } 1638 1639 /* if testing, or we uncompressed to stdout, this is all we need */ 1640 if (tflag) 1641 return size; 1642 /* if we are uncompressing to stdin, don't remove the file. */ 1643 if (cflag) 1644 return size; 1645 1646 /* 1647 * if we create a file... 1648 */ 1649 /* 1650 * if we can't stat the file don't remove the file. 1651 */ 1652 1653 ofd = open(outfile, O_RDWR, 0); 1654 if (ofd == -1) { 1655 maybe_warn("couldn't open (leaving original): %s", 1656 outfile); 1657 return -1; 1658 } 1659 if (fstat(ofd, &osb) != 0) { 1660 maybe_warn("couldn't stat (leaving original): %s", 1661 outfile); 1662 close(ofd); 1663 return -1; 1664 } 1665 if (osb.st_size != size) { 1666 maybe_warnx("stat gave different size: %ju != %ju (leaving original)", 1667 (uintmax_t)size, (uintmax_t)osb.st_size); 1668 close(ofd); 1669 unlink(outfile); 1670 return -1; 1671 } 1672 copymodes(ofd, &isb, outfile); 1673 remove_file = NULL; 1674 close(ofd); 1675 unlink_input(file, &isb); 1676 return size; 1677 1678 unexpected_EOF: 1679 maybe_warnx("%s: unexpected end of file", file); 1680 lose: 1681 if (fd != -1) 1682 close(fd); 1683 if (zfd != -1 && zfd != STDOUT_FILENO) 1684 close(zfd); 1685 return -1; 1686} 1687 1688static void 1689check_siginfo(void) 1690{ 1691 if (print_info == 0) 1692 return; 1693 if (infile) { 1694 if (infile_total) { 1695 int pcent = (int)((100.0 * infile_current) / infile_total); 1696 1697 fprintf(stderr, "%s: done %llu/%llu bytes %d%%\n", 1698 infile, (unsigned long long)infile_current, 1699 (unsigned long long)infile_total, pcent); 1700 } else 1701 fprintf(stderr, "%s: done %llu bytes\n", 1702 infile, (unsigned long long)infile_current); 1703 } 1704 print_info = 0; 1705} 1706 1707static off_t 1708cat_fd(unsigned char * prepend, size_t count, off_t *gsizep, int fd) 1709{ 1710 char buf[BUFLEN]; 1711 off_t in_tot; 1712 ssize_t w; 1713 1714 in_tot = count; 1715 w = write_retry(STDOUT_FILENO, prepend, count); 1716 if (w == -1 || (size_t)w != count) { 1717 maybe_warn("write to stdout"); 1718 return -1; 1719 } 1720 for (;;) { 1721 ssize_t rv; 1722 1723 rv = read(fd, buf, sizeof buf); 1724 if (rv == 0) 1725 break; 1726 if (rv < 0) { 1727 maybe_warn("read from fd %d", fd); 1728 break; 1729 } 1730 infile_newdata(rv); 1731 1732 if (write_retry(STDOUT_FILENO, buf, rv) != rv) { 1733 maybe_warn("write to stdout"); 1734 break; 1735 } 1736 in_tot += rv; 1737 } 1738 1739 if (gsizep) 1740 *gsizep = in_tot; 1741 return (in_tot); 1742} 1743 1744static void 1745handle_stdin(void) 1746{ 1747 struct stat isb; 1748 unsigned char fourbytes[4]; 1749 size_t in_size; 1750 off_t usize, gsize; 1751 enum filetype method; 1752 ssize_t bytes_read; 1753#ifndef NO_COMPRESS_SUPPORT 1754 FILE *in; 1755#endif 1756 1757 if (fflag == 0 && lflag == 0 && isatty(STDIN_FILENO)) { 1758 maybe_warnx("standard input is a terminal -- ignoring"); 1759 goto out; 1760 } 1761 1762 if (fstat(STDIN_FILENO, &isb) < 0) { 1763 maybe_warn("fstat"); 1764 goto out; 1765 } 1766 if (S_ISREG(isb.st_mode)) 1767 in_size = isb.st_size; 1768 else 1769 in_size = 0; 1770 infile_set("(stdin)", in_size); 1771 1772 if (lflag) { 1773 print_list(STDIN_FILENO, in_size, infile, isb.st_mtime); 1774 goto out; 1775 } 1776 1777 bytes_read = read_retry(STDIN_FILENO, fourbytes, sizeof fourbytes); 1778 if (bytes_read == -1) { 1779 maybe_warn("can't read stdin"); 1780 goto out; 1781 } else if (bytes_read != sizeof(fourbytes)) { 1782 maybe_warnx("(stdin): unexpected end of file"); 1783 goto out; 1784 } 1785 1786 method = file_gettype(fourbytes); 1787 switch (method) { 1788 default: 1789 if (fflag == 0) { 1790 maybe_warnx("unknown compression format"); 1791 goto out; 1792 } 1793 usize = cat_fd(fourbytes, sizeof fourbytes, &gsize, STDIN_FILENO); 1794 break; 1795 case FT_GZIP: 1796 usize = gz_uncompress(STDIN_FILENO, STDOUT_FILENO, 1797 (char *)fourbytes, sizeof fourbytes, &gsize, "(stdin)"); 1798 break; 1799#ifndef NO_BZIP2_SUPPORT 1800 case FT_BZIP2: 1801 usize = unbzip2(STDIN_FILENO, STDOUT_FILENO, 1802 (char *)fourbytes, sizeof fourbytes, &gsize); 1803 break; 1804#endif 1805#ifndef NO_COMPRESS_SUPPORT 1806 case FT_Z: 1807 if ((in = zdopen(STDIN_FILENO)) == NULL) { 1808 maybe_warnx("zopen of stdin"); 1809 goto out; 1810 } 1811 1812 usize = zuncompress(in, stdout, (char *)fourbytes, 1813 sizeof fourbytes, &gsize); 1814 fclose(in); 1815 break; 1816#endif 1817#ifndef NO_PACK_SUPPORT 1818 case FT_PACK: 1819 usize = unpack(STDIN_FILENO, STDOUT_FILENO, 1820 (char *)fourbytes, sizeof fourbytes, &gsize); 1821 break; 1822#endif 1823#ifndef NO_XZ_SUPPORT 1824 case FT_XZ: 1825 usize = unxz(STDIN_FILENO, STDOUT_FILENO, 1826 (char *)fourbytes, sizeof fourbytes, &gsize); 1827 break; 1828#endif 1829#ifndef NO_LZ_SUPPORT 1830 case FT_LZ: 1831 usize = unlz(STDIN_FILENO, STDOUT_FILENO, 1832 (char *)fourbytes, sizeof fourbytes, &gsize); 1833 break; 1834#endif 1835#ifndef NO_ZSTD_SUPPORT 1836 case FT_ZSTD: 1837 usize = unzstd(STDIN_FILENO, STDOUT_FILENO, 1838 (char *)fourbytes, sizeof fourbytes, &gsize); 1839 break; 1840#endif 1841 } 1842 1843 if (vflag && !tflag && usize != -1 && gsize != -1) 1844 print_verbage(NULL, NULL, usize, gsize); 1845 if (vflag && tflag) 1846 print_test("(stdin)", usize != -1); 1847 1848out: 1849 infile_clear(); 1850} 1851 1852static void 1853handle_stdout(void) 1854{ 1855 off_t gsize; 1856 off_t usize; 1857 struct stat sb; 1858 time_t systime; 1859 uint32_t mtime; 1860 int ret; 1861 1862 infile_set("(stdout)", 0); 1863 1864 if (fflag == 0 && isatty(STDOUT_FILENO)) { 1865 maybe_warnx("standard output is a terminal -- ignoring"); 1866 return; 1867 } 1868 1869 /* If stdin is a file use its mtime, otherwise use current time */ 1870 ret = fstat(STDIN_FILENO, &sb); 1871 if (ret < 0) { 1872 maybe_warn("Can't stat stdin"); 1873 return; 1874 } 1875 1876 if (S_ISREG(sb.st_mode)) { 1877 infile_set("(stdout)", sb.st_size); 1878 mtime = (uint32_t)sb.st_mtime; 1879 } else { 1880 systime = time(NULL); 1881 if (systime == -1) { 1882 maybe_warn("time"); 1883 return; 1884 } 1885 mtime = (uint32_t)systime; 1886 } 1887 1888 usize = 1889 gz_compress(STDIN_FILENO, STDOUT_FILENO, &gsize, "", mtime); 1890 if (vflag && !tflag && usize != -1 && gsize != -1) 1891 print_verbage(NULL, NULL, usize, gsize); 1892} 1893 1894/* do what is asked for, for the path name */ 1895static void 1896handle_pathname(char *path) 1897{ 1898 char *opath = path, *s = NULL; 1899 ssize_t len; 1900 int slen; 1901 struct stat sb; 1902 1903 /* check for stdout/stdin */ 1904 if (path[0] == '-' && path[1] == '\0') { 1905 if (dflag) 1906 handle_stdin(); 1907 else 1908 handle_stdout(); 1909 return; 1910 } 1911 1912retry: 1913 if (stat(path, &sb) != 0 || (fflag == 0 && cflag == 0 && 1914 lstat(path, &sb) != 0)) { 1915 /* lets try <path>.gz if we're decompressing */ 1916 if (dflag && s == NULL && errno == ENOENT) { 1917 len = strlen(path); 1918 slen = suffixes[0].ziplen; 1919 s = malloc(len + slen + 1); 1920 if (s == NULL) 1921 maybe_err("malloc"); 1922 memcpy(s, path, len); 1923 memcpy(s + len, suffixes[0].zipped, slen + 1); 1924 path = s; 1925 goto retry; 1926 } 1927 maybe_warn("can't stat: %s", opath); 1928 goto out; 1929 } 1930 1931 if (S_ISDIR(sb.st_mode)) { 1932 if (rflag) 1933 handle_dir(path); 1934 else 1935 maybe_warnx("%s is a directory", path); 1936 goto out; 1937 } 1938 1939 if (S_ISREG(sb.st_mode)) 1940 handle_file(path, &sb); 1941 else 1942 maybe_warnx("%s is not a regular file", path); 1943 1944out: 1945 if (s) 1946 free(s); 1947} 1948 1949/* compress/decompress a file */ 1950static void 1951handle_file(char *file, struct stat *sbp) 1952{ 1953 off_t usize, gsize; 1954 char outfile[PATH_MAX]; 1955 1956 infile_set(file, sbp->st_size); 1957 if (dflag) { 1958 usize = file_uncompress(file, outfile, sizeof(outfile)); 1959 if (vflag && tflag) 1960 print_test(file, usize != -1); 1961 if (usize == -1) 1962 return; 1963 gsize = sbp->st_size; 1964 } else { 1965 gsize = file_compress(file, outfile, sizeof(outfile)); 1966 if (gsize == -1) 1967 return; 1968 usize = sbp->st_size; 1969 } 1970 infile_clear(); 1971 1972 if (vflag && !tflag) 1973 print_verbage(file, (cflag) ? NULL : outfile, usize, gsize); 1974} 1975 1976/* this is used with -r to recursively descend directories */ 1977static void 1978handle_dir(char *dir) 1979{ 1980 char *path_argv[2]; 1981 FTS *fts; 1982 FTSENT *entry; 1983 1984 path_argv[0] = dir; 1985 path_argv[1] = 0; 1986 fts = fts_open(path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL); 1987 if (fts == NULL) { 1988 warn("couldn't fts_open %s", dir); 1989 return; 1990 } 1991 1992 while (errno = 0, (entry = fts_read(fts))) { 1993 switch(entry->fts_info) { 1994 case FTS_D: 1995 case FTS_DP: 1996 continue; 1997 1998 case FTS_DNR: 1999 case FTS_ERR: 2000 case FTS_NS: 2001 maybe_warn("%s", entry->fts_path); 2002 continue; 2003 case FTS_F: 2004 handle_file(entry->fts_path, entry->fts_statp); 2005 } 2006 } 2007 if (errno != 0) 2008 warn("error with fts_read %s", dir); 2009 (void)fts_close(fts); 2010} 2011 2012/* print a ratio - size reduction as a fraction of uncompressed size */ 2013static void 2014print_ratio(off_t in, off_t out, FILE *where) 2015{ 2016 int percent10; /* 10 * percent */ 2017 off_t diff; 2018 char buff[8]; 2019 int len; 2020 2021 diff = in - out/2; 2022 if (in == 0 && out == 0) 2023 percent10 = 0; 2024 else if (diff < 0) 2025 /* 2026 * Output is more than double size of input! print -99.9% 2027 * Quite possibly we've failed to get the original size. 2028 */ 2029 percent10 = -999; 2030 else { 2031 /* 2032 * We only need 12 bits of result from the final division, 2033 * so reduce the values until a 32bit division will suffice. 2034 */ 2035 while (in > 0x100000) { 2036 diff >>= 1; 2037 in >>= 1; 2038 } 2039 if (in != 0) 2040 percent10 = ((u_int)diff * 2000) / (u_int)in - 1000; 2041 else 2042 percent10 = 0; 2043 } 2044 2045 len = snprintf(buff, sizeof buff, "%2.2d.", percent10); 2046 /* Move the '.' to before the last digit */ 2047 buff[len - 1] = buff[len - 2]; 2048 buff[len - 2] = '.'; 2049 fprintf(where, "%5s%%", buff); 2050} 2051 2052/* print compression statistics, and the new name (if there is one!) */ 2053static void 2054print_verbage(const char *file, const char *nfile, off_t usize, off_t gsize) 2055{ 2056 if (file) 2057 fprintf(stderr, "%s:%s ", file, 2058 strlen(file) < 7 ? "\t\t" : "\t"); 2059 print_ratio(usize, gsize, stderr); 2060 if (nfile) 2061 fprintf(stderr, " -- replaced with %s", nfile); 2062 fprintf(stderr, "\n"); 2063 fflush(stderr); 2064} 2065 2066/* print test results */ 2067static void 2068print_test(const char *file, int ok) 2069{ 2070 2071 if (exit_value == 0 && ok == 0) 2072 exit_value = 1; 2073 fprintf(stderr, "%s:%s %s\n", file, 2074 strlen(file) < 7 ? "\t\t" : "\t", ok ? "OK" : "NOT OK"); 2075 fflush(stderr); 2076} 2077 2078/* print a file's info ala --list */ 2079/* eg: 2080 compressed uncompressed ratio uncompressed_name 2081 354841 1679360 78.8% /usr/pkgsrc/distfiles/libglade-2.0.1.tar 2082*/ 2083static void 2084print_list(int fd, off_t out, const char *outfile, time_t ts) 2085{ 2086 static int first = 1; 2087 static off_t in_tot, out_tot; 2088 uint32_t crc = 0; 2089 off_t in = 0, rv; 2090 2091 if (first) { 2092 if (vflag) 2093 printf("method crc date time "); 2094 if (qflag == 0) 2095 printf(" compressed uncompressed " 2096 "ratio uncompressed_name\n"); 2097 } 2098 first = 0; 2099 2100 /* print totals? */ 2101 if (fd == -1) { 2102 in = in_tot; 2103 out = out_tot; 2104 } else 2105 { 2106 /* read the last 4 bytes - this is the uncompressed size */ 2107 rv = lseek(fd, (off_t)(-8), SEEK_END); 2108 if (rv != -1) { 2109 unsigned char buf[8]; 2110 uint32_t usize; 2111 2112 rv = read(fd, (char *)buf, sizeof(buf)); 2113 if (rv == -1) 2114 maybe_warn("read of uncompressed size"); 2115 else if (rv != sizeof(buf)) 2116 maybe_warnx("read of uncompressed size"); 2117 2118 else { 2119 usize = le32dec(&buf[4]); 2120 in = (off_t)usize; 2121 crc = le32dec(&buf[0]); 2122 } 2123 } 2124 } 2125 2126 if (vflag && fd == -1) 2127 printf(" "); 2128 else if (vflag) { 2129 char *date = ctime(&ts); 2130 2131 /* skip the day, 1/100th second, and year */ 2132 date += 4; 2133 date[12] = 0; 2134 printf("%5s %08x %11s ", "defla"/*XXX*/, crc, date); 2135 } 2136 in_tot += in; 2137 out_tot += out; 2138 print_list_out(out, in, outfile); 2139} 2140 2141static void 2142print_list_out(off_t out, off_t in, const char *outfile) 2143{ 2144 printf("%12llu %12llu ", (unsigned long long)out, (unsigned long long)in); 2145 print_ratio(in, out, stdout); 2146 printf(" %s\n", outfile); 2147} 2148 2149/* display the usage of NetBSD gzip */ 2150static void 2151usage(void) 2152{ 2153 2154 fprintf(stderr, "%s\n", gzip_version); 2155 fprintf(stderr, 2156 "usage: %s [-123456789acdfhklLNnqrtVv] [-S .suffix] [<file> [<file> ...]]\n" 2157 " -1 --fast fastest (worst) compression\n" 2158 " -2 .. -8 set compression level\n" 2159 " -9 --best best (slowest) compression\n" 2160 " -c --stdout write to stdout, keep original files\n" 2161 " --to-stdout\n" 2162 " -d --decompress uncompress files\n" 2163 " --uncompress\n" 2164 " -f --force force overwriting & compress links\n" 2165 " -h --help display this help\n" 2166 " -k --keep don't delete input files during operation\n" 2167 " -l --list list compressed file contents\n" 2168 " -N --name save or restore original file name and time stamp\n" 2169 " -n --no-name don't save original file name or time stamp\n" 2170 " -q --quiet output no warnings\n" 2171 " -r --recursive recursively compress files in directories\n" 2172 " -S .suf use suffix .suf instead of .gz\n" 2173 " --suffix .suf\n" 2174 " -t --test test compressed file\n" 2175 " -V --version display program version\n" 2176 " -v --verbose print extra statistics\n", 2177 getprogname()); 2178 exit(0); 2179} 2180 2181/* display the license information of FreeBSD gzip */ 2182static void 2183display_license(void) 2184{ 2185 2186 fprintf(stderr, "%s (based on NetBSD gzip 20150113)\n", gzip_version); 2187 fprintf(stderr, "%s\n", gzip_copyright); 2188 exit(0); 2189} 2190 2191/* display the version of NetBSD gzip */ 2192static void 2193display_version(void) 2194{ 2195 2196 fprintf(stderr, "%s\n", gzip_version); 2197 exit(0); 2198} 2199 2200#ifndef NO_BZIP2_SUPPORT 2201#include "unbzip2.c" 2202#endif 2203#ifndef NO_COMPRESS_SUPPORT 2204#include "zuncompress.c" 2205#endif 2206#ifndef NO_PACK_SUPPORT 2207#include "unpack.c" 2208#endif 2209#ifndef NO_XZ_SUPPORT 2210#include "unxz.c" 2211#endif 2212#ifndef NO_LZ_SUPPORT 2213#include "unlz.c" 2214#endif 2215#ifndef NO_ZSTD_SUPPORT 2216#include "unzstd.c" 2217#endif 2218 2219static ssize_t 2220read_retry(int fd, void *buf, size_t sz) 2221{ 2222 char *cp = buf; 2223 size_t left = MIN(sz, (size_t) SSIZE_MAX); 2224 2225 while (left > 0) { 2226 ssize_t ret; 2227 2228 ret = read(fd, cp, left); 2229 if (ret == -1) { 2230 return ret; 2231 } else if (ret == 0) { 2232 break; /* EOF */ 2233 } 2234 cp += ret; 2235 left -= ret; 2236 } 2237 2238 return sz - left; 2239} 2240 2241static ssize_t 2242write_retry(int fd, const void *buf, size_t sz) 2243{ 2244 const char *cp = buf; 2245 size_t left = MIN(sz, (size_t) SSIZE_MAX); 2246 2247 while (left > 0) { 2248 ssize_t ret; 2249 2250 ret = write(fd, cp, left); 2251 if (ret == -1) { 2252 return ret; 2253 } else if (ret == 0) { 2254 abort(); /* Can't happen */ 2255 } 2256 cp += ret; 2257 left -= ret; 2258 } 2259 2260 return sz - left; 2261} 2262