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