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