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