gzip.c revision 166363
1166255Sdelphij/* $NetBSD: gzip.c,v 1.89 2006/11/13 21:57:59 mrg Exp $ */ 2166255Sdelphij 3166255Sdelphij/*- 4166255Sdelphij * Copyright (c) 1997, 1998, 2003, 2004, 2006 Matthew R. Green 5166255Sdelphij * All rights reserved. 6166255Sdelphij * 7166255Sdelphij * Redistribution and use in source and binary forms, with or without 8166255Sdelphij * modification, are permitted provided that the following conditions 9166255Sdelphij * are met: 10166255Sdelphij * 1. Redistributions of source code must retain the above copyright 11166255Sdelphij * notice, this list of conditions and the following disclaimer. 12166255Sdelphij * 2. Redistributions in binary form must reproduce the above copyright 13166255Sdelphij * notice, this list of conditions and the following disclaimer in the 14166255Sdelphij * documentation and/or other materials provided with the distribution. 15166255Sdelphij * 3. The name of the author may not be used to endorse or promote products 16166255Sdelphij * derived from this software without specific prior written permission. 17166255Sdelphij * 18166255Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19166255Sdelphij * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20166255Sdelphij * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21166255Sdelphij * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22166255Sdelphij * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 23166255Sdelphij * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24166255Sdelphij * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25166255Sdelphij * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26166255Sdelphij * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27166255Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28166255Sdelphij * SUCH DAMAGE. 29166255Sdelphij * 30166255Sdelphij */ 31166255Sdelphij 32166255Sdelphij#include <sys/cdefs.h> 33166255Sdelphij#ifndef lint 34166255Sdelphij__COPYRIGHT("@(#) Copyright (c) 1997, 1998, 2003, 2004, 2006 Matthew R. Green\n\ 35166255Sdelphij All rights reserved.\n"); 36166255Sdelphij__RCSID("$FreeBSD: head/usr.bin/gzip/gzip.c 166363 2007-01-31 07:13:25Z delphij $"); 37166255Sdelphij#endif /* not lint */ 38166255Sdelphij 39166255Sdelphij/* 40166255Sdelphij * gzip.c -- GPL free gzip using zlib. 41166255Sdelphij * 42166255Sdelphij * RFC 1950 covers the zlib format 43166255Sdelphij * RFC 1951 covers the deflate format 44166255Sdelphij * RFC 1952 covers the gzip format 45166255Sdelphij * 46166255Sdelphij * TODO: 47166255Sdelphij * - use mmap where possible 48166255Sdelphij * - handle some signals better (remove outfile?) 49166255Sdelphij * - make bzip2/compress -v/-t/-l support work as well as possible 50166255Sdelphij */ 51166255Sdelphij 52166255Sdelphij#include <sys/param.h> 53166255Sdelphij#include <sys/stat.h> 54166255Sdelphij#include <sys/time.h> 55166255Sdelphij 56166255Sdelphij#include <inttypes.h> 57166255Sdelphij#include <unistd.h> 58166255Sdelphij#include <stdio.h> 59166255Sdelphij#include <string.h> 60166255Sdelphij#include <stdlib.h> 61166255Sdelphij#include <err.h> 62166255Sdelphij#include <errno.h> 63166255Sdelphij#include <fcntl.h> 64166255Sdelphij#include <zlib.h> 65166255Sdelphij#include <fts.h> 66166255Sdelphij#include <libgen.h> 67166255Sdelphij#include <stdarg.h> 68166255Sdelphij#include <getopt.h> 69166255Sdelphij#include <time.h> 70166255Sdelphij 71166255Sdelphij#ifndef PRIdOFF 72166255Sdelphij#define PRIdOFF PRId64 73166255Sdelphij#endif 74166255Sdelphij 75166255Sdelphij/* what type of file are we dealing with */ 76166255Sdelphijenum filetype { 77166255Sdelphij FT_GZIP, 78166255Sdelphij#ifndef NO_BZIP2_SUPPORT 79166255Sdelphij FT_BZIP2, 80166255Sdelphij#endif 81166255Sdelphij#ifndef NO_COMPRESS_SUPPORT 82166255Sdelphij FT_Z, 83166255Sdelphij#endif 84166255Sdelphij FT_LAST, 85166255Sdelphij FT_UNKNOWN 86166255Sdelphij}; 87166255Sdelphij 88166255Sdelphij#ifndef NO_BZIP2_SUPPORT 89166255Sdelphij#include <bzlib.h> 90166255Sdelphij 91166255Sdelphij#define BZ2_SUFFIX ".bz2" 92166255Sdelphij#define BZIP2_MAGIC "\102\132\150" 93166255Sdelphij#endif 94166255Sdelphij 95166255Sdelphij#ifndef NO_COMPRESS_SUPPORT 96166255Sdelphij#define Z_SUFFIX ".Z" 97166255Sdelphij#define Z_MAGIC "\037\235" 98166255Sdelphij#endif 99166255Sdelphij 100166255Sdelphij#define GZ_SUFFIX ".gz" 101166255Sdelphij 102166255Sdelphij#define BUFLEN (64 * 1024) 103166255Sdelphij 104166255Sdelphij#define GZIP_MAGIC0 0x1F 105166255Sdelphij#define GZIP_MAGIC1 0x8B 106166255Sdelphij#define GZIP_OMAGIC1 0x9E 107166255Sdelphij 108166255Sdelphij#define GZIP_TIMESTAMP (off_t)4 109166255Sdelphij#define GZIP_ORIGNAME (off_t)10 110166255Sdelphij 111166255Sdelphij#define HEAD_CRC 0x02 112166255Sdelphij#define EXTRA_FIELD 0x04 113166255Sdelphij#define ORIG_NAME 0x08 114166255Sdelphij#define COMMENT 0x10 115166255Sdelphij 116166255Sdelphij#define OS_CODE 3 /* Unix */ 117166255Sdelphij 118166255Sdelphijtypedef struct { 119166255Sdelphij const char *zipped; 120166255Sdelphij int ziplen; 121166255Sdelphij const char *normal; /* for unzip - must not be longer than zipped */ 122166255Sdelphij} suffixes_t; 123166255Sdelphijstatic suffixes_t suffixes[] = { 124166255Sdelphij#define SUFFIX(Z, N) {Z, sizeof Z - 1, N} 125166255Sdelphij SUFFIX(GZ_SUFFIX, ""), /* Overwritten by -S .xxx */ 126166255Sdelphij#ifndef SMALL 127166255Sdelphij SUFFIX(GZ_SUFFIX, ""), 128166255Sdelphij SUFFIX(".z", ""), 129166255Sdelphij SUFFIX("-gz", ""), 130166255Sdelphij SUFFIX("-z", ""), 131166255Sdelphij SUFFIX("_z", ""), 132166255Sdelphij SUFFIX(".taz", ".tar"), 133166255Sdelphij SUFFIX(".tgz", ".tar"), 134166255Sdelphij#ifndef NO_BZIP2_SUPPORT 135166255Sdelphij SUFFIX(BZ2_SUFFIX, ""), 136166255Sdelphij#endif 137166255Sdelphij#ifndef NO_COMPRESS_SUPPORT 138166255Sdelphij SUFFIX(Z_SUFFIX, ""), 139166255Sdelphij#endif 140166255Sdelphij SUFFIX(GZ_SUFFIX, ""), /* Overwritten by -S "" */ 141166255Sdelphij#endif /* SMALL */ 142166255Sdelphij#undef SUFFIX 143166255Sdelphij}; 144166255Sdelphij#define NUM_SUFFIXES (sizeof suffixes / sizeof suffixes[0]) 145166255Sdelphij 146166255Sdelphijstatic const char gzip_version[] = "FreeBSD gzip 20070126"; 147166255Sdelphij 148166255Sdelphij#ifndef SMALL 149166255Sdelphijstatic const char gzip_copyright[] = \ 150166255Sdelphij" Copyright (c) 1997, 1998, 2003, 2004, 2006 Matthew R. Green\n" 151166255Sdelphij" All rights reserved.\n" 152166255Sdelphij"\n" 153166255Sdelphij" Redistribution and use in source and binary forms, with or without\n" 154166255Sdelphij" modification, are permitted provided that the following conditions\n" 155166255Sdelphij" are met:\n" 156166255Sdelphij" 1. Redistributions of source code must retain the above copyright\n" 157166255Sdelphij" notice, this list of conditions and the following disclaimer.\n" 158166255Sdelphij" 2. Redistributions in binary form must reproduce the above copyright\n" 159166255Sdelphij" notice, this list of conditions and the following disclaimer in the\n" 160166255Sdelphij" documentation and/or other materials provided with the distribution.\n" 161166255Sdelphij" 3. The name of the author may not be used to endorse or promote products\n" 162166255Sdelphij" derived from this software without specific prior written permission.\n" 163166255Sdelphij"\n" 164166255Sdelphij" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n" 165166255Sdelphij" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n" 166166255Sdelphij" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n" 167166255Sdelphij" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n" 168166255Sdelphij" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n" 169166255Sdelphij" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n" 170166255Sdelphij" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\n" 171166255Sdelphij" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n" 172166255Sdelphij" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n" 173166255Sdelphij" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n" 174166255Sdelphij" SUCH DAMAGE."; 175166255Sdelphij#endif 176166255Sdelphij 177166255Sdelphijstatic int cflag; /* stdout mode */ 178166255Sdelphijstatic int dflag; /* decompress mode */ 179166255Sdelphijstatic int lflag; /* list mode */ 180166255Sdelphijstatic int numflag = 6; /* gzip -1..-9 value */ 181166255Sdelphij 182166255Sdelphij#ifndef SMALL 183166255Sdelphijstatic int fflag; /* force mode */ 184166255Sdelphijstatic int nflag; /* don't save name/timestamp */ 185166255Sdelphijstatic int Nflag; /* don't restore name/timestamp */ 186166255Sdelphijstatic int qflag; /* quiet mode */ 187166255Sdelphijstatic int rflag; /* recursive mode */ 188166255Sdelphijstatic int tflag; /* test */ 189166255Sdelphijstatic int vflag; /* verbose mode */ 190166255Sdelphij#else 191166255Sdelphij#define qflag 0 192166255Sdelphij#define tflag 0 193166255Sdelphij#endif 194166255Sdelphij 195166255Sdelphijstatic int exit_value = 0; /* exit value */ 196166255Sdelphij 197166255Sdelphijstatic char *infile; /* name of file coming in */ 198166255Sdelphij 199166255Sdelphijstatic void maybe_err(const char *fmt, ...) 200166255Sdelphij __attribute__((__format__(__printf__, 1, 2))); 201166255Sdelphij#ifndef NO_BZIP2_SUPPORT 202166255Sdelphijstatic void maybe_errx(const char *fmt, ...) 203166255Sdelphij __attribute__((__format__(__printf__, 1, 2))); 204166255Sdelphij#endif 205166255Sdelphijstatic void maybe_warn(const char *fmt, ...) 206166255Sdelphij __attribute__((__format__(__printf__, 1, 2))); 207166255Sdelphijstatic void maybe_warnx(const char *fmt, ...) 208166255Sdelphij __attribute__((__format__(__printf__, 1, 2))); 209166255Sdelphijstatic enum filetype file_gettype(u_char *); 210166255Sdelphij#ifdef SMALL 211166255Sdelphij#define gz_compress(if, of, sz, fn, tm) gz_compress(if, of, sz) 212166255Sdelphij#endif 213166255Sdelphijstatic off_t gz_compress(int, int, off_t *, const char *, uint32_t); 214166255Sdelphijstatic off_t gz_uncompress(int, int, char *, size_t, off_t *, const char *); 215166255Sdelphijstatic off_t file_compress(char *, char *, size_t); 216166255Sdelphijstatic off_t file_uncompress(char *, char *, size_t); 217166255Sdelphijstatic void handle_pathname(char *); 218166255Sdelphijstatic void handle_file(char *, struct stat *); 219166255Sdelphijstatic void handle_stdin(void); 220166255Sdelphijstatic void handle_stdout(void); 221166255Sdelphijstatic void print_ratio(off_t, off_t, FILE *); 222166255Sdelphijstatic void print_list(int fd, off_t, const char *, time_t); 223166255Sdelphijstatic void usage(void); 224166255Sdelphijstatic void display_version(void); 225166255Sdelphij#ifndef SMALL 226166255Sdelphijstatic void display_license(void); 227166255Sdelphij#endif 228166255Sdelphijstatic const suffixes_t *check_suffix(char *, int); 229166255Sdelphijstatic ssize_t read_retry(int, void *, size_t); 230166255Sdelphij 231166255Sdelphij#ifdef SMALL 232166255Sdelphij#define unlink_input(f, sb) unlink(f) 233166255Sdelphij#else 234166255Sdelphijstatic off_t cat_fd(unsigned char *, size_t, off_t *, int fd); 235166255Sdelphijstatic void prepend_gzip(char *, int *, char ***); 236166255Sdelphijstatic void handle_dir(char *); 237166255Sdelphijstatic void print_verbage(const char *, const char *, off_t, off_t); 238166255Sdelphijstatic void print_test(const char *, int); 239166255Sdelphijstatic void copymodes(int fd, const struct stat *, const char *file); 240166255Sdelphijstatic int check_outfile(const char *outfile); 241166255Sdelphij#endif 242166255Sdelphij 243166255Sdelphij#ifndef NO_BZIP2_SUPPORT 244166255Sdelphijstatic off_t unbzip2(int, int, char *, size_t, off_t *); 245166255Sdelphij#endif 246166255Sdelphij 247166255Sdelphij#ifndef NO_COMPRESS_SUPPORT 248166255Sdelphijstatic FILE *zdopen(int); 249166255Sdelphijstatic off_t zuncompress(FILE *, FILE *, char *, size_t, off_t *); 250166255Sdelphij#endif 251166255Sdelphij 252166255Sdelphijint main(int, char **p); 253166255Sdelphij 254166255Sdelphij#ifdef SMALL 255166255Sdelphij#define getopt_long(a,b,c,d,e) getopt(a,b,c) 256166255Sdelphij#else 257166255Sdelphijstatic const struct option longopts[] = { 258166255Sdelphij { "stdout", no_argument, 0, 'c' }, 259166255Sdelphij { "to-stdout", no_argument, 0, 'c' }, 260166255Sdelphij { "decompress", no_argument, 0, 'd' }, 261166255Sdelphij { "uncompress", no_argument, 0, 'd' }, 262166255Sdelphij { "force", no_argument, 0, 'f' }, 263166255Sdelphij { "help", no_argument, 0, 'h' }, 264166255Sdelphij { "list", no_argument, 0, 'l' }, 265166255Sdelphij { "no-name", no_argument, 0, 'n' }, 266166255Sdelphij { "name", no_argument, 0, 'N' }, 267166255Sdelphij { "quiet", no_argument, 0, 'q' }, 268166255Sdelphij { "recursive", no_argument, 0, 'r' }, 269166255Sdelphij { "suffix", required_argument, 0, 'S' }, 270166255Sdelphij { "test", no_argument, 0, 't' }, 271166255Sdelphij { "verbose", no_argument, 0, 'v' }, 272166255Sdelphij { "version", no_argument, 0, 'V' }, 273166255Sdelphij { "fast", no_argument, 0, '1' }, 274166255Sdelphij { "best", no_argument, 0, '9' }, 275166255Sdelphij { "ascii", no_argument, 0, 'a' }, 276166255Sdelphij { "license", no_argument, 0, 'L' }, 277166255Sdelphij { NULL, no_argument, 0, 0 }, 278166255Sdelphij}; 279166255Sdelphij#endif 280166255Sdelphij 281166255Sdelphijint 282166255Sdelphijmain(int argc, char **argv) 283166255Sdelphij{ 284166255Sdelphij const char *progname = getprogname(); 285166255Sdelphij#ifndef SMALL 286166255Sdelphij char *gzip; 287166255Sdelphij int len; 288166255Sdelphij#endif 289166255Sdelphij int ch; 290166255Sdelphij 291166255Sdelphij /* XXX set up signals */ 292166255Sdelphij 293166255Sdelphij#ifndef SMALL 294166255Sdelphij if ((gzip = getenv("GZIP")) != NULL) 295166255Sdelphij prepend_gzip(gzip, &argc, &argv); 296166255Sdelphij#endif 297166255Sdelphij 298166255Sdelphij /* 299166255Sdelphij * XXX 300166255Sdelphij * handle being called `gunzip', `zcat' and `gzcat' 301166255Sdelphij */ 302166255Sdelphij if (strcmp(progname, "gunzip") == 0) 303166255Sdelphij dflag = 1; 304166255Sdelphij else if (strcmp(progname, "zcat") == 0 || 305166255Sdelphij strcmp(progname, "gzcat") == 0) 306166255Sdelphij dflag = cflag = 1; 307166255Sdelphij 308166255Sdelphij#ifdef SMALL 309166255Sdelphij#define OPT_LIST "123456789cdhltV" 310166255Sdelphij#else 311166255Sdelphij#define OPT_LIST "123456789acdfhlLNnqrS:tVv" 312166255Sdelphij#endif 313166255Sdelphij 314166255Sdelphij while ((ch = getopt_long(argc, argv, OPT_LIST, longopts, NULL)) != -1) { 315166255Sdelphij switch (ch) { 316166255Sdelphij case '1': case '2': case '3': 317166255Sdelphij case '4': case '5': case '6': 318166255Sdelphij case '7': case '8': case '9': 319166255Sdelphij numflag = ch - '0'; 320166255Sdelphij break; 321166255Sdelphij case 'c': 322166255Sdelphij cflag = 1; 323166255Sdelphij break; 324166255Sdelphij case 'd': 325166255Sdelphij dflag = 1; 326166255Sdelphij break; 327166255Sdelphij case 'l': 328166255Sdelphij lflag = 1; 329166255Sdelphij dflag = 1; 330166255Sdelphij break; 331166255Sdelphij case 'V': 332166255Sdelphij display_version(); 333166255Sdelphij /* NOTREACHED */ 334166255Sdelphij#ifndef SMALL 335166255Sdelphij case 'a': 336166255Sdelphij fprintf(stderr, "%s: option --ascii ignored on this system\n", progname); 337166255Sdelphij break; 338166255Sdelphij case 'f': 339166255Sdelphij fflag = 1; 340166255Sdelphij break; 341166255Sdelphij case 'L': 342166255Sdelphij display_license(); 343166255Sdelphij /* NOT REACHED */ 344166255Sdelphij case 'N': 345166255Sdelphij nflag = 0; 346166255Sdelphij Nflag = 1; 347166255Sdelphij break; 348166255Sdelphij case 'n': 349166255Sdelphij nflag = 1; 350166255Sdelphij Nflag = 0; 351166255Sdelphij break; 352166255Sdelphij case 'q': 353166255Sdelphij qflag = 1; 354166255Sdelphij break; 355166255Sdelphij case 'r': 356166255Sdelphij rflag = 1; 357166255Sdelphij break; 358166255Sdelphij case 'S': 359166255Sdelphij len = strlen(optarg); 360166255Sdelphij if (len != 0) { 361166255Sdelphij suffixes[0].zipped = optarg; 362166255Sdelphij suffixes[0].ziplen = len; 363166255Sdelphij } else { 364166255Sdelphij suffixes[NUM_SUFFIXES - 1].zipped = ""; 365166255Sdelphij suffixes[NUM_SUFFIXES - 1].ziplen = 0; 366166255Sdelphij } 367166255Sdelphij break; 368166255Sdelphij case 't': 369166255Sdelphij cflag = 1; 370166255Sdelphij tflag = 1; 371166255Sdelphij dflag = 1; 372166255Sdelphij break; 373166255Sdelphij case 'v': 374166255Sdelphij vflag = 1; 375166255Sdelphij break; 376166255Sdelphij#endif 377166255Sdelphij default: 378166255Sdelphij usage(); 379166255Sdelphij /* NOTREACHED */ 380166255Sdelphij } 381166255Sdelphij } 382166255Sdelphij argv += optind; 383166255Sdelphij argc -= optind; 384166255Sdelphij 385166255Sdelphij if (argc == 0) { 386166255Sdelphij if (dflag) /* stdin mode */ 387166255Sdelphij handle_stdin(); 388166255Sdelphij else /* stdout mode */ 389166255Sdelphij handle_stdout(); 390166255Sdelphij } else { 391166255Sdelphij do { 392166255Sdelphij handle_pathname(argv[0]); 393166255Sdelphij } while (*++argv); 394166255Sdelphij } 395166255Sdelphij#ifndef SMALL 396166255Sdelphij if (qflag == 0 && lflag && argc > 1) 397166255Sdelphij print_list(-1, 0, "(totals)", 0); 398166255Sdelphij#endif 399166255Sdelphij exit(exit_value); 400166255Sdelphij} 401166255Sdelphij 402166255Sdelphij/* maybe print a warning */ 403166255Sdelphijvoid 404166255Sdelphijmaybe_warn(const char *fmt, ...) 405166255Sdelphij{ 406166255Sdelphij va_list ap; 407166255Sdelphij 408166255Sdelphij if (qflag == 0) { 409166255Sdelphij va_start(ap, fmt); 410166255Sdelphij vwarn(fmt, ap); 411166255Sdelphij va_end(ap); 412166255Sdelphij } 413166255Sdelphij if (exit_value == 0) 414166255Sdelphij exit_value = 1; 415166255Sdelphij} 416166255Sdelphij 417166255Sdelphij/* ... without an errno. */ 418166255Sdelphijvoid 419166255Sdelphijmaybe_warnx(const char *fmt, ...) 420166255Sdelphij{ 421166255Sdelphij va_list ap; 422166255Sdelphij 423166255Sdelphij if (qflag == 0) { 424166255Sdelphij va_start(ap, fmt); 425166255Sdelphij vwarnx(fmt, ap); 426166255Sdelphij va_end(ap); 427166255Sdelphij } 428166255Sdelphij if (exit_value == 0) 429166255Sdelphij exit_value = 1; 430166255Sdelphij} 431166255Sdelphij 432166255Sdelphij/* maybe print an error */ 433166255Sdelphijvoid 434166255Sdelphijmaybe_err(const char *fmt, ...) 435166255Sdelphij{ 436166255Sdelphij va_list ap; 437166255Sdelphij 438166255Sdelphij if (qflag == 0) { 439166255Sdelphij va_start(ap, fmt); 440166255Sdelphij vwarn(fmt, ap); 441166255Sdelphij va_end(ap); 442166255Sdelphij } 443166255Sdelphij exit(2); 444166255Sdelphij} 445166255Sdelphij 446166255Sdelphij#ifndef NO_BZIP2_SUPPORT 447166255Sdelphij/* ... without an errno. */ 448166255Sdelphijvoid 449166255Sdelphijmaybe_errx(const char *fmt, ...) 450166255Sdelphij{ 451166255Sdelphij va_list ap; 452166255Sdelphij 453166255Sdelphij if (qflag == 0) { 454166255Sdelphij va_start(ap, fmt); 455166255Sdelphij vwarnx(fmt, ap); 456166255Sdelphij va_end(ap); 457166255Sdelphij } 458166255Sdelphij exit(2); 459166255Sdelphij} 460166255Sdelphij#endif 461166255Sdelphij 462166255Sdelphij#ifndef SMALL 463166255Sdelphij/* split up $GZIP and prepend it to the argument list */ 464166255Sdelphijstatic void 465166255Sdelphijprepend_gzip(char *gzip, int *argc, char ***argv) 466166255Sdelphij{ 467166255Sdelphij char *s, **nargv, **ac; 468166255Sdelphij int nenvarg = 0, i; 469166255Sdelphij 470166255Sdelphij /* scan how many arguments there are */ 471166255Sdelphij for (s = gzip;;) { 472166255Sdelphij while (*s == ' ' || *s == '\t') 473166255Sdelphij s++; 474166255Sdelphij if (*s == 0) 475166255Sdelphij goto count_done; 476166255Sdelphij nenvarg++; 477166255Sdelphij while (*s != ' ' && *s != '\t') 478166255Sdelphij if (*s++ == 0) 479166255Sdelphij goto count_done; 480166255Sdelphij } 481166255Sdelphijcount_done: 482166255Sdelphij /* punt early */ 483166255Sdelphij if (nenvarg == 0) 484166255Sdelphij return; 485166255Sdelphij 486166255Sdelphij *argc += nenvarg; 487166255Sdelphij ac = *argv; 488166255Sdelphij 489166255Sdelphij nargv = (char **)malloc((*argc + 1) * sizeof(char *)); 490166255Sdelphij if (nargv == NULL) 491166255Sdelphij maybe_err("malloc"); 492166255Sdelphij 493166255Sdelphij /* stash this away */ 494166255Sdelphij *argv = nargv; 495166255Sdelphij 496166255Sdelphij /* copy the program name first */ 497166255Sdelphij i = 0; 498166255Sdelphij nargv[i++] = *(ac++); 499166255Sdelphij 500166255Sdelphij /* take a copy of $GZIP and add it to the array */ 501166255Sdelphij s = strdup(gzip); 502166255Sdelphij if (s == NULL) 503166255Sdelphij maybe_err("strdup"); 504166255Sdelphij for (;;) { 505166255Sdelphij /* Skip whitespaces. */ 506166255Sdelphij while (*s == ' ' || *s == '\t') 507166255Sdelphij s++; 508166255Sdelphij if (*s == 0) 509166255Sdelphij goto copy_done; 510166255Sdelphij nargv[i++] = s; 511166255Sdelphij /* Find the end of this argument. */ 512166255Sdelphij while (*s != ' ' && *s != '\t') 513166255Sdelphij if (*s++ == 0) 514166255Sdelphij /* Argument followed by NUL. */ 515166255Sdelphij goto copy_done; 516166255Sdelphij /* Terminate by overwriting ' ' or '\t' with NUL. */ 517166255Sdelphij *s++ = 0; 518166255Sdelphij } 519166255Sdelphijcopy_done: 520166255Sdelphij 521166255Sdelphij /* copy the original arguments and a NULL */ 522166255Sdelphij while (*ac) 523166255Sdelphij nargv[i++] = *(ac++); 524166255Sdelphij nargv[i] = NULL; 525166255Sdelphij} 526166255Sdelphij#endif 527166255Sdelphij 528166255Sdelphij/* compress input to output. Return bytes read, -1 on error */ 529166255Sdelphijstatic off_t 530166255Sdelphijgz_compress(int in, int out, off_t *gsizep, const char *origname, uint32_t mtime) 531166255Sdelphij{ 532166255Sdelphij z_stream z; 533166255Sdelphij char *outbufp, *inbufp; 534166255Sdelphij off_t in_tot = 0, out_tot = 0; 535166255Sdelphij ssize_t in_size; 536166255Sdelphij int i, error; 537166255Sdelphij uLong crc; 538166255Sdelphij#ifdef SMALL 539166255Sdelphij static char header[] = { GZIP_MAGIC0, GZIP_MAGIC1, Z_DEFLATED, 0, 540166255Sdelphij 0, 0, 0, 0, 541166255Sdelphij 0, OS_CODE }; 542166255Sdelphij#endif 543166255Sdelphij 544166255Sdelphij outbufp = malloc(BUFLEN); 545166255Sdelphij inbufp = malloc(BUFLEN); 546166255Sdelphij if (outbufp == NULL || inbufp == NULL) { 547166255Sdelphij maybe_err("malloc failed"); 548166255Sdelphij goto out; 549166255Sdelphij } 550166255Sdelphij 551166255Sdelphij memset(&z, 0, sizeof z); 552166255Sdelphij z.zalloc = Z_NULL; 553166255Sdelphij z.zfree = Z_NULL; 554166255Sdelphij z.opaque = 0; 555166255Sdelphij 556166255Sdelphij#ifdef SMALL 557166255Sdelphij memcpy(outbufp, header, sizeof header); 558166255Sdelphij i = sizeof header; 559166255Sdelphij#else 560166255Sdelphij if (nflag != 0) { 561166255Sdelphij mtime = 0; 562166255Sdelphij origname = ""; 563166255Sdelphij } 564166255Sdelphij 565166255Sdelphij i = snprintf(outbufp, BUFLEN, "%c%c%c%c%c%c%c%c%c%c%s", 566166255Sdelphij GZIP_MAGIC0, GZIP_MAGIC1, Z_DEFLATED, 567166255Sdelphij *origname ? ORIG_NAME : 0, 568166255Sdelphij mtime & 0xff, 569166255Sdelphij (mtime >> 8) & 0xff, 570166255Sdelphij (mtime >> 16) & 0xff, 571166255Sdelphij (mtime >> 24) & 0xff, 572166255Sdelphij numflag == 1 ? 4 : numflag == 9 ? 2 : 0, 573166255Sdelphij OS_CODE, origname); 574166255Sdelphij if (i >= BUFLEN) 575166255Sdelphij /* this need PATH_MAX > BUFLEN ... */ 576166255Sdelphij maybe_err("snprintf"); 577166255Sdelphij if (*origname) 578166255Sdelphij i++; 579166255Sdelphij#endif 580166255Sdelphij 581166255Sdelphij z.next_out = (unsigned char *)outbufp + i; 582166255Sdelphij z.avail_out = BUFLEN - i; 583166255Sdelphij 584166255Sdelphij error = deflateInit2(&z, numflag, Z_DEFLATED, 585166255Sdelphij (-MAX_WBITS), 8, Z_DEFAULT_STRATEGY); 586166255Sdelphij if (error != Z_OK) { 587166255Sdelphij maybe_warnx("deflateInit2 failed"); 588166255Sdelphij in_tot = -1; 589166255Sdelphij goto out; 590166255Sdelphij } 591166255Sdelphij 592166255Sdelphij crc = crc32(0L, Z_NULL, 0); 593166255Sdelphij for (;;) { 594166255Sdelphij if (z.avail_out == 0) { 595166255Sdelphij if (write(out, outbufp, BUFLEN) != BUFLEN) { 596166255Sdelphij maybe_warn("write"); 597166255Sdelphij out_tot = -1; 598166255Sdelphij goto out; 599166255Sdelphij } 600166255Sdelphij 601166255Sdelphij out_tot += BUFLEN; 602166255Sdelphij z.next_out = (unsigned char *)outbufp; 603166255Sdelphij z.avail_out = BUFLEN; 604166255Sdelphij } 605166255Sdelphij 606166255Sdelphij if (z.avail_in == 0) { 607166255Sdelphij in_size = read(in, inbufp, BUFLEN); 608166255Sdelphij if (in_size < 0) { 609166255Sdelphij maybe_warn("read"); 610166255Sdelphij in_tot = -1; 611166255Sdelphij goto out; 612166255Sdelphij } 613166255Sdelphij if (in_size == 0) 614166255Sdelphij break; 615166255Sdelphij 616166255Sdelphij crc = crc32(crc, (const Bytef *)inbufp, (unsigned)in_size); 617166255Sdelphij in_tot += in_size; 618166255Sdelphij z.next_in = (unsigned char *)inbufp; 619166255Sdelphij z.avail_in = in_size; 620166255Sdelphij } 621166255Sdelphij 622166255Sdelphij error = deflate(&z, Z_NO_FLUSH); 623166255Sdelphij if (error != Z_OK && error != Z_STREAM_END) { 624166255Sdelphij maybe_warnx("deflate failed"); 625166255Sdelphij in_tot = -1; 626166255Sdelphij goto out; 627166255Sdelphij } 628166255Sdelphij } 629166255Sdelphij 630166255Sdelphij /* clean up */ 631166255Sdelphij for (;;) { 632166255Sdelphij size_t len; 633166255Sdelphij ssize_t w; 634166255Sdelphij 635166255Sdelphij error = deflate(&z, Z_FINISH); 636166255Sdelphij if (error != Z_OK && error != Z_STREAM_END) { 637166255Sdelphij maybe_warnx("deflate failed"); 638166255Sdelphij in_tot = -1; 639166255Sdelphij goto out; 640166255Sdelphij } 641166255Sdelphij 642166255Sdelphij len = (char *)z.next_out - outbufp; 643166255Sdelphij 644166255Sdelphij w = write(out, outbufp, len); 645166255Sdelphij if (w == -1 || (size_t)w != len) { 646166255Sdelphij maybe_warn("write"); 647166255Sdelphij out_tot = -1; 648166255Sdelphij goto out; 649166255Sdelphij } 650166255Sdelphij out_tot += len; 651166255Sdelphij z.next_out = (unsigned char *)outbufp; 652166255Sdelphij z.avail_out = BUFLEN; 653166255Sdelphij 654166255Sdelphij if (error == Z_STREAM_END) 655166255Sdelphij break; 656166255Sdelphij } 657166255Sdelphij 658166255Sdelphij if (deflateEnd(&z) != Z_OK) { 659166255Sdelphij maybe_warnx("deflateEnd failed"); 660166255Sdelphij in_tot = -1; 661166255Sdelphij goto out; 662166255Sdelphij } 663166255Sdelphij 664166255Sdelphij i = snprintf(outbufp, BUFLEN, "%c%c%c%c%c%c%c%c", 665166255Sdelphij (int)crc & 0xff, 666166255Sdelphij (int)(crc >> 8) & 0xff, 667166255Sdelphij (int)(crc >> 16) & 0xff, 668166255Sdelphij (int)(crc >> 24) & 0xff, 669166255Sdelphij (int)in_tot & 0xff, 670166255Sdelphij (int)(in_tot >> 8) & 0xff, 671166255Sdelphij (int)(in_tot >> 16) & 0xff, 672166255Sdelphij (int)(in_tot >> 24) & 0xff); 673166255Sdelphij if (i != 8) 674166255Sdelphij maybe_err("snprintf"); 675166255Sdelphij if (write(out, outbufp, i) != i) { 676166255Sdelphij maybe_warn("write"); 677166255Sdelphij in_tot = -1; 678166255Sdelphij } else 679166255Sdelphij out_tot += i; 680166255Sdelphij 681166255Sdelphijout: 682166255Sdelphij if (inbufp != NULL) 683166255Sdelphij free(inbufp); 684166255Sdelphij if (outbufp != NULL) 685166255Sdelphij free(outbufp); 686166255Sdelphij if (gsizep) 687166255Sdelphij *gsizep = out_tot; 688166255Sdelphij return in_tot; 689166255Sdelphij} 690166255Sdelphij 691166255Sdelphij/* 692166255Sdelphij * uncompress input to output then close the input. return the 693166255Sdelphij * uncompressed size written, and put the compressed sized read 694166255Sdelphij * into `*gsizep'. 695166255Sdelphij */ 696166255Sdelphijstatic off_t 697166255Sdelphijgz_uncompress(int in, int out, char *pre, size_t prelen, off_t *gsizep, 698166255Sdelphij const char *filename) 699166255Sdelphij{ 700166255Sdelphij z_stream z; 701166255Sdelphij char *outbufp, *inbufp; 702166255Sdelphij off_t out_tot = -1, in_tot = 0; 703166255Sdelphij uint32_t out_sub_tot = 0; 704166255Sdelphij enum { 705166255Sdelphij GZSTATE_MAGIC0, 706166255Sdelphij GZSTATE_MAGIC1, 707166255Sdelphij GZSTATE_METHOD, 708166255Sdelphij GZSTATE_FLAGS, 709166255Sdelphij GZSTATE_SKIPPING, 710166255Sdelphij GZSTATE_EXTRA, 711166255Sdelphij GZSTATE_EXTRA2, 712166255Sdelphij GZSTATE_EXTRA3, 713166255Sdelphij GZSTATE_ORIGNAME, 714166255Sdelphij GZSTATE_COMMENT, 715166255Sdelphij GZSTATE_HEAD_CRC1, 716166255Sdelphij GZSTATE_HEAD_CRC2, 717166255Sdelphij GZSTATE_INIT, 718166255Sdelphij GZSTATE_READ, 719166255Sdelphij GZSTATE_CRC, 720166255Sdelphij GZSTATE_LEN, 721166255Sdelphij } state = GZSTATE_MAGIC0; 722166255Sdelphij int flags = 0, skip_count = 0; 723166255Sdelphij int error = Z_STREAM_ERROR, done_reading = 0; 724166255Sdelphij uLong crc = 0; 725166255Sdelphij ssize_t wr; 726166255Sdelphij int needmore = 0; 727166255Sdelphij 728166255Sdelphij#define ADVANCE() { z.next_in++; z.avail_in--; } 729166255Sdelphij 730166255Sdelphij if ((outbufp = malloc(BUFLEN)) == NULL) { 731166255Sdelphij maybe_err("malloc failed"); 732166255Sdelphij goto out2; 733166255Sdelphij } 734166255Sdelphij if ((inbufp = malloc(BUFLEN)) == NULL) { 735166255Sdelphij maybe_err("malloc failed"); 736166255Sdelphij goto out1; 737166255Sdelphij } 738166255Sdelphij 739166255Sdelphij memset(&z, 0, sizeof z); 740166255Sdelphij z.avail_in = prelen; 741166255Sdelphij z.next_in = (unsigned char *)pre; 742166255Sdelphij z.avail_out = BUFLEN; 743166255Sdelphij z.next_out = (unsigned char *)outbufp; 744166255Sdelphij z.zalloc = NULL; 745166255Sdelphij z.zfree = NULL; 746166255Sdelphij z.opaque = 0; 747166255Sdelphij 748166255Sdelphij in_tot = prelen; 749166255Sdelphij out_tot = 0; 750166255Sdelphij 751166255Sdelphij for (;;) { 752166255Sdelphij if ((z.avail_in == 0 || needmore) && done_reading == 0) { 753166255Sdelphij ssize_t in_size; 754166255Sdelphij 755166255Sdelphij if (z.avail_in > 0) { 756166255Sdelphij memmove(inbufp, z.next_in, z.avail_in); 757166255Sdelphij } 758166255Sdelphij z.next_in = (unsigned char *)inbufp; 759166255Sdelphij in_size = read(in, z.next_in + z.avail_in, 760166255Sdelphij BUFLEN - z.avail_in); 761166255Sdelphij 762166255Sdelphij if (in_size == -1) { 763166255Sdelphij maybe_warn("failed to read stdin"); 764166255Sdelphij goto stop_and_fail; 765166255Sdelphij } else if (in_size == 0) { 766166255Sdelphij done_reading = 1; 767166255Sdelphij } 768166255Sdelphij 769166255Sdelphij z.avail_in += in_size; 770166255Sdelphij needmore = 0; 771166255Sdelphij 772166255Sdelphij in_tot += in_size; 773166255Sdelphij } 774166255Sdelphij if (z.avail_in == 0) { 775166255Sdelphij if (done_reading && state != GZSTATE_MAGIC0) { 776166255Sdelphij maybe_warnx("%s: unexpected end of file", 777166255Sdelphij filename); 778166255Sdelphij goto stop_and_fail; 779166255Sdelphij } 780166255Sdelphij goto stop; 781166255Sdelphij } 782166255Sdelphij switch (state) { 783166255Sdelphij case GZSTATE_MAGIC0: 784166255Sdelphij if (*z.next_in != GZIP_MAGIC0) { 785166255Sdelphij if (in_tot > 0) { 786166255Sdelphij maybe_warnx("%s: trailing garbage " 787166255Sdelphij "ignored", filename); 788166255Sdelphij goto stop; 789166255Sdelphij } 790166255Sdelphij maybe_warnx("input not gziped (MAGIC0)"); 791166255Sdelphij goto stop_and_fail; 792166255Sdelphij } 793166255Sdelphij ADVANCE(); 794166255Sdelphij state++; 795166255Sdelphij out_sub_tot = 0; 796166255Sdelphij crc = crc32(0L, Z_NULL, 0); 797166255Sdelphij break; 798166255Sdelphij 799166255Sdelphij case GZSTATE_MAGIC1: 800166255Sdelphij if (*z.next_in != GZIP_MAGIC1 && 801166255Sdelphij *z.next_in != GZIP_OMAGIC1) { 802166255Sdelphij maybe_warnx("input not gziped (MAGIC1)"); 803166255Sdelphij goto stop_and_fail; 804166255Sdelphij } 805166255Sdelphij ADVANCE(); 806166255Sdelphij state++; 807166255Sdelphij break; 808166255Sdelphij 809166255Sdelphij case GZSTATE_METHOD: 810166255Sdelphij if (*z.next_in != Z_DEFLATED) { 811166255Sdelphij maybe_warnx("unknown compression method"); 812166255Sdelphij goto stop_and_fail; 813166255Sdelphij } 814166255Sdelphij ADVANCE(); 815166255Sdelphij state++; 816166255Sdelphij break; 817166255Sdelphij 818166255Sdelphij case GZSTATE_FLAGS: 819166255Sdelphij flags = *z.next_in; 820166255Sdelphij ADVANCE(); 821166255Sdelphij skip_count = 6; 822166255Sdelphij state++; 823166255Sdelphij break; 824166255Sdelphij 825166255Sdelphij case GZSTATE_SKIPPING: 826166255Sdelphij if (skip_count > 0) { 827166255Sdelphij skip_count--; 828166255Sdelphij ADVANCE(); 829166255Sdelphij } else 830166255Sdelphij state++; 831166255Sdelphij break; 832166255Sdelphij 833166255Sdelphij case GZSTATE_EXTRA: 834166255Sdelphij if ((flags & EXTRA_FIELD) == 0) { 835166255Sdelphij state = GZSTATE_ORIGNAME; 836166255Sdelphij break; 837166255Sdelphij } 838166255Sdelphij skip_count = *z.next_in; 839166255Sdelphij ADVANCE(); 840166255Sdelphij state++; 841166255Sdelphij break; 842166255Sdelphij 843166255Sdelphij case GZSTATE_EXTRA2: 844166255Sdelphij skip_count |= ((*z.next_in) << 8); 845166255Sdelphij ADVANCE(); 846166255Sdelphij state++; 847166255Sdelphij break; 848166255Sdelphij 849166255Sdelphij case GZSTATE_EXTRA3: 850166255Sdelphij if (skip_count > 0) { 851166255Sdelphij skip_count--; 852166255Sdelphij ADVANCE(); 853166255Sdelphij } else 854166255Sdelphij state++; 855166255Sdelphij break; 856166255Sdelphij 857166255Sdelphij case GZSTATE_ORIGNAME: 858166255Sdelphij if ((flags & ORIG_NAME) == 0) { 859166255Sdelphij state++; 860166255Sdelphij break; 861166255Sdelphij } 862166255Sdelphij if (*z.next_in == 0) 863166255Sdelphij state++; 864166255Sdelphij ADVANCE(); 865166255Sdelphij break; 866166255Sdelphij 867166255Sdelphij case GZSTATE_COMMENT: 868166255Sdelphij if ((flags & COMMENT) == 0) { 869166255Sdelphij state++; 870166255Sdelphij break; 871166255Sdelphij } 872166255Sdelphij if (*z.next_in == 0) 873166255Sdelphij state++; 874166255Sdelphij ADVANCE(); 875166255Sdelphij break; 876166255Sdelphij 877166255Sdelphij case GZSTATE_HEAD_CRC1: 878166255Sdelphij if (flags & HEAD_CRC) 879166255Sdelphij skip_count = 2; 880166255Sdelphij else 881166255Sdelphij skip_count = 0; 882166255Sdelphij state++; 883166255Sdelphij break; 884166255Sdelphij 885166255Sdelphij case GZSTATE_HEAD_CRC2: 886166255Sdelphij if (skip_count > 0) { 887166255Sdelphij skip_count--; 888166255Sdelphij ADVANCE(); 889166255Sdelphij } else 890166255Sdelphij state++; 891166255Sdelphij break; 892166255Sdelphij 893166255Sdelphij case GZSTATE_INIT: 894166255Sdelphij if (inflateInit2(&z, -MAX_WBITS) != Z_OK) { 895166255Sdelphij maybe_warnx("failed to inflateInit"); 896166255Sdelphij goto stop_and_fail; 897166255Sdelphij } 898166255Sdelphij state++; 899166255Sdelphij break; 900166255Sdelphij 901166255Sdelphij case GZSTATE_READ: 902166255Sdelphij error = inflate(&z, Z_FINISH); 903166255Sdelphij switch (error) { 904166255Sdelphij /* Z_BUF_ERROR goes with Z_FINISH... */ 905166255Sdelphij case Z_BUF_ERROR: 906166255Sdelphij case Z_STREAM_END: 907166255Sdelphij case Z_OK: 908166255Sdelphij break; 909166255Sdelphij 910166255Sdelphij case Z_NEED_DICT: 911166255Sdelphij maybe_warnx("Z_NEED_DICT error"); 912166255Sdelphij goto stop_and_fail; 913166255Sdelphij case Z_DATA_ERROR: 914166255Sdelphij maybe_warnx("data stream error"); 915166255Sdelphij goto stop_and_fail; 916166255Sdelphij case Z_STREAM_ERROR: 917166255Sdelphij maybe_warnx("internal stream error"); 918166255Sdelphij goto stop_and_fail; 919166255Sdelphij case Z_MEM_ERROR: 920166255Sdelphij maybe_warnx("memory allocation error"); 921166255Sdelphij goto stop_and_fail; 922166255Sdelphij 923166255Sdelphij default: 924166255Sdelphij maybe_warn("unknown error from inflate(): %d", 925166255Sdelphij error); 926166255Sdelphij } 927166255Sdelphij wr = BUFLEN - z.avail_out; 928166255Sdelphij 929166255Sdelphij if (wr != 0) { 930166255Sdelphij crc = crc32(crc, (const Bytef *)outbufp, (unsigned)wr); 931166255Sdelphij if ( 932166255Sdelphij#ifndef SMALL 933166255Sdelphij /* don't write anything with -t */ 934166255Sdelphij tflag == 0 && 935166255Sdelphij#endif 936166255Sdelphij write(out, outbufp, wr) != wr) { 937166255Sdelphij maybe_warn("error writing to output"); 938166255Sdelphij goto stop_and_fail; 939166255Sdelphij } 940166255Sdelphij 941166255Sdelphij out_tot += wr; 942166255Sdelphij out_sub_tot += wr; 943166255Sdelphij } 944166255Sdelphij 945166255Sdelphij if (error == Z_STREAM_END) { 946166255Sdelphij inflateEnd(&z); 947166255Sdelphij state++; 948166255Sdelphij } 949166255Sdelphij 950166255Sdelphij z.next_out = (unsigned char *)outbufp; 951166255Sdelphij z.avail_out = BUFLEN; 952166255Sdelphij 953166255Sdelphij break; 954166255Sdelphij case GZSTATE_CRC: 955166255Sdelphij { 956166255Sdelphij uLong origcrc; 957166255Sdelphij 958166255Sdelphij if (z.avail_in < 4) { 959166255Sdelphij if (!done_reading) { 960166255Sdelphij needmore = 1; 961166255Sdelphij continue; 962166255Sdelphij } 963166255Sdelphij maybe_warnx("truncated input"); 964166255Sdelphij goto stop_and_fail; 965166255Sdelphij } 966166255Sdelphij origcrc = ((unsigned)z.next_in[0] & 0xff) | 967166255Sdelphij ((unsigned)z.next_in[1] & 0xff) << 8 | 968166255Sdelphij ((unsigned)z.next_in[2] & 0xff) << 16 | 969166255Sdelphij ((unsigned)z.next_in[3] & 0xff) << 24; 970166255Sdelphij if (origcrc != crc) { 971166255Sdelphij maybe_warnx("invalid compressed" 972166255Sdelphij " data--crc error"); 973166255Sdelphij goto stop_and_fail; 974166255Sdelphij } 975166255Sdelphij } 976166255Sdelphij 977166255Sdelphij z.avail_in -= 4; 978166255Sdelphij z.next_in += 4; 979166255Sdelphij 980166255Sdelphij if (!z.avail_in && done_reading) { 981166255Sdelphij goto stop; 982166255Sdelphij } 983166255Sdelphij state++; 984166255Sdelphij break; 985166255Sdelphij case GZSTATE_LEN: 986166255Sdelphij { 987166255Sdelphij uLong origlen; 988166255Sdelphij 989166255Sdelphij if (z.avail_in < 4) { 990166255Sdelphij if (!done_reading) { 991166255Sdelphij needmore = 1; 992166255Sdelphij continue; 993166255Sdelphij } 994166255Sdelphij maybe_warnx("truncated input"); 995166255Sdelphij goto stop_and_fail; 996166255Sdelphij } 997166255Sdelphij origlen = ((unsigned)z.next_in[0] & 0xff) | 998166255Sdelphij ((unsigned)z.next_in[1] & 0xff) << 8 | 999166255Sdelphij ((unsigned)z.next_in[2] & 0xff) << 16 | 1000166255Sdelphij ((unsigned)z.next_in[3] & 0xff) << 24; 1001166255Sdelphij 1002166255Sdelphij if (origlen != out_sub_tot) { 1003166255Sdelphij maybe_warnx("invalid compressed" 1004166255Sdelphij " data--length error"); 1005166255Sdelphij goto stop_and_fail; 1006166255Sdelphij } 1007166255Sdelphij } 1008166255Sdelphij 1009166255Sdelphij z.avail_in -= 4; 1010166255Sdelphij z.next_in += 4; 1011166255Sdelphij 1012166255Sdelphij if (error < 0) { 1013166255Sdelphij maybe_warnx("decompression error"); 1014166255Sdelphij goto stop_and_fail; 1015166255Sdelphij } 1016166255Sdelphij state = GZSTATE_MAGIC0; 1017166255Sdelphij break; 1018166255Sdelphij } 1019166255Sdelphij continue; 1020166255Sdelphijstop_and_fail: 1021166255Sdelphij out_tot = -1; 1022166255Sdelphijstop: 1023166255Sdelphij break; 1024166255Sdelphij } 1025166255Sdelphij if (state > GZSTATE_INIT) 1026166255Sdelphij inflateEnd(&z); 1027166255Sdelphij 1028166255Sdelphij free(inbufp); 1029166255Sdelphijout1: 1030166255Sdelphij free(outbufp); 1031166255Sdelphijout2: 1032166255Sdelphij if (gsizep) 1033166255Sdelphij *gsizep = in_tot; 1034166255Sdelphij return (out_tot); 1035166255Sdelphij} 1036166255Sdelphij 1037166255Sdelphij#ifndef SMALL 1038166255Sdelphij/* 1039166255Sdelphij * set the owner, mode, flags & utimes using the given file descriptor. 1040166255Sdelphij * file is only used in possible warning messages. 1041166255Sdelphij */ 1042166255Sdelphijstatic void 1043166255Sdelphijcopymodes(int fd, const struct stat *sbp, const char *file) 1044166255Sdelphij{ 1045166255Sdelphij struct timeval times[2]; 1046166255Sdelphij struct stat sb; 1047166255Sdelphij 1048166255Sdelphij /* 1049166255Sdelphij * If we have no info on the input, give this file some 1050166255Sdelphij * default values and return.. 1051166255Sdelphij */ 1052166255Sdelphij if (sbp == NULL) { 1053166255Sdelphij mode_t mask = umask(022); 1054166255Sdelphij 1055166255Sdelphij (void)fchmod(fd, DEFFILEMODE & ~mask); 1056166255Sdelphij (void)umask(mask); 1057166255Sdelphij return; 1058166255Sdelphij } 1059166255Sdelphij sb = *sbp; 1060166255Sdelphij 1061166255Sdelphij /* if the chown fails, remove set-id bits as-per compress(1) */ 1062166255Sdelphij if (fchown(fd, sb.st_uid, sb.st_gid) < 0) { 1063166255Sdelphij if (errno != EPERM) 1064166255Sdelphij maybe_warn("couldn't fchown: %s", file); 1065166255Sdelphij sb.st_mode &= ~(S_ISUID|S_ISGID); 1066166255Sdelphij } 1067166255Sdelphij 1068166255Sdelphij /* we only allow set-id and the 9 normal permission bits */ 1069166255Sdelphij sb.st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO; 1070166255Sdelphij if (fchmod(fd, sb.st_mode) < 0) 1071166255Sdelphij maybe_warn("couldn't fchmod: %s", file); 1072166255Sdelphij 1073166255Sdelphij /* only try flags if they exist already */ 1074166255Sdelphij if (sb.st_flags != 0 && fchflags(fd, sb.st_flags) < 0) 1075166255Sdelphij maybe_warn("couldn't fchflags: %s", file); 1076166255Sdelphij 1077166255Sdelphij TIMESPEC_TO_TIMEVAL(×[0], &sb.st_atimespec); 1078166255Sdelphij TIMESPEC_TO_TIMEVAL(×[1], &sb.st_mtimespec); 1079166255Sdelphij if (futimes(fd, times) < 0) 1080166255Sdelphij maybe_warn("couldn't utimes: %s", file); 1081166255Sdelphij} 1082166255Sdelphij#endif 1083166255Sdelphij 1084166255Sdelphij/* what sort of file is this? */ 1085166255Sdelphijstatic enum filetype 1086166255Sdelphijfile_gettype(u_char *buf) 1087166255Sdelphij{ 1088166255Sdelphij 1089166255Sdelphij if (buf[0] == GZIP_MAGIC0 && 1090166255Sdelphij (buf[1] == GZIP_MAGIC1 || buf[1] == GZIP_OMAGIC1)) 1091166255Sdelphij return FT_GZIP; 1092166255Sdelphij else 1093166255Sdelphij#ifndef NO_BZIP2_SUPPORT 1094166255Sdelphij if (memcmp(buf, BZIP2_MAGIC, 3) == 0 && 1095166255Sdelphij buf[3] >= '0' && buf[3] <= '9') 1096166255Sdelphij return FT_BZIP2; 1097166255Sdelphij else 1098166255Sdelphij#endif 1099166255Sdelphij#ifndef NO_COMPRESS_SUPPORT 1100166255Sdelphij if (memcmp(buf, Z_MAGIC, 2) == 0) 1101166255Sdelphij return FT_Z; 1102166255Sdelphij else 1103166255Sdelphij#endif 1104166255Sdelphij return FT_UNKNOWN; 1105166255Sdelphij} 1106166255Sdelphij 1107166255Sdelphij#ifndef SMALL 1108166255Sdelphij/* check the outfile is OK. */ 1109166255Sdelphijstatic int 1110166255Sdelphijcheck_outfile(const char *outfile) 1111166255Sdelphij{ 1112166255Sdelphij struct stat sb; 1113166255Sdelphij int ok = 1; 1114166255Sdelphij 1115166255Sdelphij if (lflag == 0 && stat(outfile, &sb) == 0) { 1116166255Sdelphij if (fflag) 1117166255Sdelphij unlink(outfile); 1118166255Sdelphij else if (isatty(STDIN_FILENO)) { 1119166255Sdelphij char ans[10] = { 'n', '\0' }; /* default */ 1120166255Sdelphij 1121166255Sdelphij fprintf(stderr, "%s already exists -- do you wish to " 1122166255Sdelphij "overwrite (y or n)? " , outfile); 1123166255Sdelphij (void)fgets(ans, sizeof(ans) - 1, stdin); 1124166255Sdelphij if (ans[0] != 'y' && ans[0] != 'Y') { 1125166363Sdelphij fprintf(stderr, "\tnot overwriting\n"); 1126166255Sdelphij ok = 0; 1127166255Sdelphij } else 1128166255Sdelphij unlink(outfile); 1129166255Sdelphij } else { 1130166255Sdelphij maybe_warnx("%s already exists -- skipping", outfile); 1131166255Sdelphij ok = 0; 1132166255Sdelphij } 1133166255Sdelphij } 1134166255Sdelphij return ok; 1135166255Sdelphij} 1136166255Sdelphij 1137166255Sdelphijstatic void 1138166255Sdelphijunlink_input(const char *file, const struct stat *sb) 1139166255Sdelphij{ 1140166255Sdelphij struct stat nsb; 1141166255Sdelphij 1142166255Sdelphij if (stat(file, &nsb) != 0) 1143166255Sdelphij /* Must be gone alrady */ 1144166255Sdelphij return; 1145166255Sdelphij if (nsb.st_dev != sb->st_dev || nsb.st_ino != sb->st_ino) 1146166255Sdelphij /* Definitely a different file */ 1147166255Sdelphij return; 1148166255Sdelphij unlink(file); 1149166255Sdelphij} 1150166255Sdelphij#endif 1151166255Sdelphij 1152166255Sdelphijstatic const suffixes_t * 1153166255Sdelphijcheck_suffix(char *file, int xlate) 1154166255Sdelphij{ 1155166255Sdelphij const suffixes_t *s; 1156166255Sdelphij int len = strlen(file); 1157166255Sdelphij char *sp; 1158166255Sdelphij 1159166255Sdelphij for (s = suffixes; s != suffixes + NUM_SUFFIXES; s++) { 1160166255Sdelphij /* if it doesn't fit in "a.suf", don't bother */ 1161166255Sdelphij if (s->ziplen >= len) 1162166255Sdelphij continue; 1163166255Sdelphij sp = file + len - s->ziplen; 1164166255Sdelphij if (strcmp(s->zipped, sp) != 0) 1165166255Sdelphij continue; 1166166255Sdelphij if (xlate) 1167166255Sdelphij strcpy(sp, s->normal); 1168166255Sdelphij return s; 1169166255Sdelphij } 1170166255Sdelphij return NULL; 1171166255Sdelphij} 1172166255Sdelphij 1173166255Sdelphij/* 1174166255Sdelphij * compress the given file: create a corresponding .gz file and remove the 1175166255Sdelphij * original. 1176166255Sdelphij */ 1177166255Sdelphijstatic off_t 1178166255Sdelphijfile_compress(char *file, char *outfile, size_t outsize) 1179166255Sdelphij{ 1180166255Sdelphij int in; 1181166255Sdelphij int out; 1182166255Sdelphij off_t size, insize; 1183166255Sdelphij#ifndef SMALL 1184166255Sdelphij struct stat isb, osb; 1185166255Sdelphij const suffixes_t *suff; 1186166255Sdelphij#endif 1187166255Sdelphij 1188166255Sdelphij in = open(file, O_RDONLY); 1189166255Sdelphij if (in == -1) { 1190166255Sdelphij maybe_warn("can't open %s", file); 1191166255Sdelphij return -1; 1192166255Sdelphij } 1193166255Sdelphij 1194166255Sdelphij if (cflag == 0) { 1195166255Sdelphij#ifndef SMALL 1196166255Sdelphij if (fstat(in, &isb) == 0) { 1197166255Sdelphij if (isb.st_nlink > 1 && fflag == 0) { 1198166255Sdelphij maybe_warnx("%s has %d other link%s -- " 1199166255Sdelphij "skipping", file, isb.st_nlink - 1, 1200166255Sdelphij isb.st_nlink == 1 ? "" : "s"); 1201166255Sdelphij close(in); 1202166255Sdelphij return -1; 1203166255Sdelphij } 1204166255Sdelphij } 1205166255Sdelphij 1206166255Sdelphij if (fflag == 0 && (suff = check_suffix(file, 0)) 1207166255Sdelphij && suff->zipped[0] != 0) { 1208166255Sdelphij maybe_warnx("%s already has %s suffix -- unchanged", 1209166255Sdelphij file, suff->zipped); 1210166255Sdelphij close(in); 1211166255Sdelphij return -1; 1212166255Sdelphij } 1213166255Sdelphij#endif 1214166255Sdelphij 1215166255Sdelphij /* Add (usually) .gz to filename */ 1216166255Sdelphij if ((size_t)snprintf(outfile, outsize, "%s%s", 1217166255Sdelphij file, suffixes[0].zipped) >= outsize) 1218166255Sdelphij memcpy(outfile - suffixes[0].ziplen - 1, 1219166255Sdelphij suffixes[0].zipped, suffixes[0].ziplen + 1); 1220166255Sdelphij 1221166255Sdelphij#ifndef SMALL 1222166255Sdelphij if (check_outfile(outfile) == 0) { 1223166255Sdelphij close(in); 1224166255Sdelphij return -1; 1225166255Sdelphij } 1226166255Sdelphij#endif 1227166255Sdelphij } 1228166255Sdelphij 1229166255Sdelphij if (cflag == 0) { 1230166255Sdelphij out = open(outfile, O_WRONLY | O_CREAT | O_EXCL, 0600); 1231166255Sdelphij if (out == -1) { 1232166255Sdelphij maybe_warn("could not create output: %s", outfile); 1233166255Sdelphij fclose(stdin); 1234166255Sdelphij return -1; 1235166255Sdelphij } 1236166255Sdelphij } else 1237166255Sdelphij out = STDOUT_FILENO; 1238166255Sdelphij 1239166255Sdelphij insize = gz_compress(in, out, &size, basename(file), (uint32_t)isb.st_mtime); 1240166255Sdelphij 1241166255Sdelphij (void)close(in); 1242166255Sdelphij 1243166255Sdelphij /* 1244166255Sdelphij * If there was an error, insize will be -1. 1245166255Sdelphij * If we compressed to stdout, just return the size. 1246166255Sdelphij * Otherwise stat the file and check it is the correct size. 1247166255Sdelphij * We only blow away the file if we can stat the output and it 1248166255Sdelphij * has the expected size. 1249166255Sdelphij */ 1250166255Sdelphij if (cflag != 0) 1251166255Sdelphij return insize == -1 ? -1 : size; 1252166255Sdelphij 1253166255Sdelphij#ifndef SMALL 1254166255Sdelphij if (fstat(out, &osb) != 0) { 1255166255Sdelphij maybe_warn("couldn't stat: %s", outfile); 1256166255Sdelphij goto bad_outfile; 1257166255Sdelphij } 1258166255Sdelphij 1259166255Sdelphij if (osb.st_size != size) { 1260166255Sdelphij maybe_warnx("output file: %s wrong size (%" PRIdOFF 1261166255Sdelphij " != %" PRIdOFF "), deleting", 1262166255Sdelphij outfile, osb.st_size, size); 1263166255Sdelphij goto bad_outfile; 1264166255Sdelphij } 1265166255Sdelphij 1266166255Sdelphij copymodes(out, &isb, outfile); 1267166255Sdelphij#endif 1268166255Sdelphij if (close(out) == -1) 1269166255Sdelphij maybe_warn("couldn't close output"); 1270166255Sdelphij 1271166255Sdelphij /* output is good, ok to delete input */ 1272166255Sdelphij unlink_input(file, &isb); 1273166255Sdelphij return size; 1274166255Sdelphij 1275166255Sdelphij#ifndef SMALL 1276166255Sdelphij bad_outfile: 1277166255Sdelphij if (close(out) == -1) 1278166255Sdelphij maybe_warn("couldn't close output"); 1279166255Sdelphij 1280166255Sdelphij maybe_warnx("leaving original %s", file); 1281166255Sdelphij unlink(outfile); 1282166255Sdelphij return size; 1283166255Sdelphij#endif 1284166255Sdelphij} 1285166255Sdelphij 1286166255Sdelphij/* uncompress the given file and remove the original */ 1287166255Sdelphijstatic off_t 1288166255Sdelphijfile_uncompress(char *file, char *outfile, size_t outsize) 1289166255Sdelphij{ 1290166255Sdelphij struct stat isb, osb; 1291166255Sdelphij off_t size; 1292166255Sdelphij ssize_t rbytes; 1293166255Sdelphij unsigned char header1[4]; 1294166255Sdelphij enum filetype method; 1295166255Sdelphij int rv, fd, ofd, zfd = -1; 1296166255Sdelphij#ifndef SMALL 1297166255Sdelphij time_t timestamp = 0; 1298166255Sdelphij unsigned char name[PATH_MAX + 1]; 1299166255Sdelphij#endif 1300166255Sdelphij 1301166255Sdelphij /* gather the old name info */ 1302166255Sdelphij 1303166255Sdelphij fd = open(file, O_RDONLY); 1304166255Sdelphij if (fd < 0) { 1305166255Sdelphij maybe_warn("can't open %s", file); 1306166255Sdelphij goto lose; 1307166255Sdelphij } 1308166255Sdelphij 1309166255Sdelphij strlcpy(outfile, file, outsize); 1310166255Sdelphij if (check_suffix(outfile, 1) == NULL && !(cflag || lflag)) { 1311166255Sdelphij maybe_warnx("%s: unknown suffix -- ignored", file); 1312166255Sdelphij goto lose; 1313166255Sdelphij } 1314166255Sdelphij 1315166255Sdelphij rbytes = read(fd, header1, sizeof header1); 1316166255Sdelphij if (rbytes != sizeof header1) { 1317166255Sdelphij /* we don't want to fail here. */ 1318166255Sdelphij#ifndef SMALL 1319166255Sdelphij if (fflag) 1320166255Sdelphij goto lose; 1321166255Sdelphij#endif 1322166255Sdelphij if (rbytes == -1) 1323166255Sdelphij maybe_warn("can't read %s", file); 1324166255Sdelphij else 1325166255Sdelphij goto unexpected_EOF; 1326166255Sdelphij goto lose; 1327166255Sdelphij } 1328166255Sdelphij 1329166255Sdelphij method = file_gettype(header1); 1330166255Sdelphij 1331166255Sdelphij#ifndef SMALL 1332166255Sdelphij if (fflag == 0 && method == FT_UNKNOWN) { 1333166255Sdelphij maybe_warnx("%s: not in gzip format", file); 1334166255Sdelphij goto lose; 1335166255Sdelphij } 1336166255Sdelphij 1337166255Sdelphij#endif 1338166255Sdelphij 1339166255Sdelphij#ifndef SMALL 1340166255Sdelphij if (method == FT_GZIP && Nflag) { 1341166255Sdelphij unsigned char ts[4]; /* timestamp */ 1342166255Sdelphij 1343166255Sdelphij rv = pread(fd, ts, sizeof ts, GZIP_TIMESTAMP); 1344166255Sdelphij if (rv >= 0 && (size_t)rv < sizeof ts) 1345166255Sdelphij goto unexpected_EOF; 1346166255Sdelphij if (rv == -1) { 1347166255Sdelphij if (!fflag) 1348166255Sdelphij maybe_warn("can't read %s", file); 1349166255Sdelphij goto lose; 1350166255Sdelphij } 1351166255Sdelphij timestamp = ts[3] << 24 | ts[2] << 16 | ts[1] << 8 | ts[0]; 1352166255Sdelphij 1353166255Sdelphij if (header1[3] & ORIG_NAME) { 1354166255Sdelphij rbytes = pread(fd, name, sizeof name, GZIP_ORIGNAME); 1355166255Sdelphij if (rbytes < 0) { 1356166255Sdelphij maybe_warn("can't read %s", file); 1357166255Sdelphij goto lose; 1358166255Sdelphij } 1359166255Sdelphij if (name[0] != 0) { 1360166255Sdelphij /* preserve original directory name */ 1361166255Sdelphij char *dp = strrchr(file, '/'); 1362166255Sdelphij if (dp == NULL) 1363166255Sdelphij dp = file; 1364166255Sdelphij else 1365166255Sdelphij dp++; 1366166255Sdelphij snprintf(outfile, outsize, "%.*s%.*s", 1367166255Sdelphij (int) (dp - file), 1368166255Sdelphij file, (int) rbytes, name); 1369166255Sdelphij } 1370166255Sdelphij } 1371166255Sdelphij } 1372166255Sdelphij#endif 1373166255Sdelphij lseek(fd, 0, SEEK_SET); 1374166255Sdelphij 1375166255Sdelphij if (cflag == 0 || lflag) { 1376166255Sdelphij if (fstat(fd, &isb) != 0) 1377166255Sdelphij goto lose; 1378166255Sdelphij#ifndef SMALL 1379166255Sdelphij if (isb.st_nlink > 1 && lflag == 0 && fflag == 0) { 1380166255Sdelphij maybe_warnx("%s has %d other links -- skipping", 1381166255Sdelphij file, isb.st_nlink - 1); 1382166255Sdelphij goto lose; 1383166255Sdelphij } 1384166255Sdelphij if (nflag == 0 && timestamp) 1385166255Sdelphij isb.st_mtime = timestamp; 1386166255Sdelphij if (check_outfile(outfile) == 0) 1387166255Sdelphij goto lose; 1388166255Sdelphij#endif 1389166255Sdelphij } 1390166255Sdelphij 1391166255Sdelphij if (cflag == 0 && lflag == 0) { 1392166255Sdelphij zfd = open(outfile, O_WRONLY|O_CREAT|O_EXCL, 0600); 1393166255Sdelphij if (zfd == STDOUT_FILENO) { 1394166255Sdelphij /* We won't close STDOUT_FILENO later... */ 1395166255Sdelphij zfd = dup(zfd); 1396166255Sdelphij close(STDOUT_FILENO); 1397166255Sdelphij } 1398166255Sdelphij if (zfd == -1) { 1399166255Sdelphij maybe_warn("can't open %s", outfile); 1400166255Sdelphij goto lose; 1401166255Sdelphij } 1402166255Sdelphij } else 1403166255Sdelphij zfd = STDOUT_FILENO; 1404166255Sdelphij 1405166255Sdelphij#ifndef NO_BZIP2_SUPPORT 1406166255Sdelphij if (method == FT_BZIP2) { 1407166255Sdelphij 1408166255Sdelphij /* XXX */ 1409166255Sdelphij if (lflag) { 1410166255Sdelphij maybe_warnx("no -l with bzip2 files"); 1411166255Sdelphij goto lose; 1412166255Sdelphij } 1413166255Sdelphij 1414166255Sdelphij size = unbzip2(fd, zfd, NULL, 0, NULL); 1415166255Sdelphij } else 1416166255Sdelphij#endif 1417166255Sdelphij 1418166255Sdelphij#ifndef NO_COMPRESS_SUPPORT 1419166255Sdelphij if (method == FT_Z) { 1420166255Sdelphij FILE *in, *out; 1421166255Sdelphij 1422166255Sdelphij /* XXX */ 1423166255Sdelphij if (lflag) { 1424166255Sdelphij maybe_warnx("no -l with Lempel-Ziv files"); 1425166255Sdelphij goto lose; 1426166255Sdelphij } 1427166255Sdelphij 1428166255Sdelphij if ((in = zdopen(fd)) == NULL) { 1429166255Sdelphij maybe_warn("zdopen for read: %s", file); 1430166255Sdelphij goto lose; 1431166255Sdelphij } 1432166255Sdelphij 1433166255Sdelphij out = fdopen(dup(zfd), "w"); 1434166255Sdelphij if (out == NULL) { 1435166255Sdelphij maybe_warn("fdopen for write: %s", outfile); 1436166255Sdelphij fclose(in); 1437166255Sdelphij goto lose; 1438166255Sdelphij } 1439166255Sdelphij 1440166255Sdelphij size = zuncompress(in, out, NULL, 0, NULL); 1441166255Sdelphij /* need to fclose() if ferror() is true... */ 1442166255Sdelphij if (ferror(in) | fclose(in)) { 1443166255Sdelphij maybe_warn("failed infile fclose"); 1444166255Sdelphij unlink(outfile); 1445166255Sdelphij (void)fclose(out); 1446166255Sdelphij } 1447166255Sdelphij if (fclose(out) != 0) { 1448166255Sdelphij maybe_warn("failed outfile fclose"); 1449166255Sdelphij unlink(outfile); 1450166255Sdelphij goto lose; 1451166255Sdelphij } 1452166255Sdelphij } else 1453166255Sdelphij#endif 1454166255Sdelphij 1455166255Sdelphij#ifndef SMALL 1456166255Sdelphij if (method == FT_UNKNOWN) { 1457166255Sdelphij if (lflag) { 1458166255Sdelphij maybe_warnx("no -l for unknown filetypes"); 1459166255Sdelphij goto lose; 1460166255Sdelphij } 1461166255Sdelphij size = cat_fd(NULL, 0, NULL, fd); 1462166255Sdelphij } else 1463166255Sdelphij#endif 1464166255Sdelphij { 1465166255Sdelphij if (lflag) { 1466166255Sdelphij print_list(fd, isb.st_size, outfile, isb.st_mtime); 1467166255Sdelphij close(fd); 1468166255Sdelphij return -1; /* XXX */ 1469166255Sdelphij } 1470166255Sdelphij 1471166255Sdelphij size = gz_uncompress(fd, zfd, NULL, 0, NULL, file); 1472166255Sdelphij } 1473166255Sdelphij 1474166255Sdelphij if (close(fd) != 0) 1475166255Sdelphij maybe_warn("couldn't close input"); 1476166255Sdelphij if (zfd != STDOUT_FILENO && close(zfd) != 0) 1477166255Sdelphij maybe_warn("couldn't close output"); 1478166255Sdelphij 1479166255Sdelphij if (size == -1) { 1480166255Sdelphij if (cflag == 0) 1481166255Sdelphij unlink(outfile); 1482166255Sdelphij maybe_warnx("%s: uncompress failed", file); 1483166255Sdelphij return -1; 1484166255Sdelphij } 1485166255Sdelphij 1486166255Sdelphij /* if testing, or we uncompressed to stdout, this is all we need */ 1487166255Sdelphij#ifndef SMALL 1488166255Sdelphij if (tflag) 1489166255Sdelphij return size; 1490166255Sdelphij#endif 1491166255Sdelphij /* if we are uncompressing to stdin, don't remove the file. */ 1492166255Sdelphij if (cflag) 1493166255Sdelphij return size; 1494166255Sdelphij 1495166255Sdelphij /* 1496166255Sdelphij * if we create a file... 1497166255Sdelphij */ 1498166255Sdelphij /* 1499166255Sdelphij * if we can't stat the file don't remove the file. 1500166255Sdelphij */ 1501166255Sdelphij 1502166255Sdelphij ofd = open(outfile, O_RDWR, 0); 1503166255Sdelphij if (ofd == -1) { 1504166255Sdelphij maybe_warn("couldn't open (leaving original): %s", 1505166255Sdelphij outfile); 1506166255Sdelphij return -1; 1507166255Sdelphij } 1508166255Sdelphij if (fstat(ofd, &osb) != 0) { 1509166255Sdelphij maybe_warn("couldn't stat (leaving original): %s", 1510166255Sdelphij outfile); 1511166255Sdelphij close(ofd); 1512166255Sdelphij return -1; 1513166255Sdelphij } 1514166255Sdelphij if (osb.st_size != size) { 1515166255Sdelphij maybe_warnx("stat gave different size: %" PRIdOFF 1516166255Sdelphij " != %" PRIdOFF " (leaving original)", 1517166255Sdelphij size, osb.st_size); 1518166255Sdelphij close(ofd); 1519166255Sdelphij unlink(outfile); 1520166255Sdelphij return -1; 1521166255Sdelphij } 1522166255Sdelphij unlink_input(file, &isb); 1523166255Sdelphij#ifndef SMALL 1524166255Sdelphij copymodes(ofd, &isb, outfile); 1525166255Sdelphij#endif 1526166255Sdelphij close(ofd); 1527166255Sdelphij return size; 1528166255Sdelphij 1529166255Sdelphij unexpected_EOF: 1530166255Sdelphij maybe_warnx("%s: unexpected end of file", file); 1531166255Sdelphij lose: 1532166255Sdelphij if (fd != -1) 1533166255Sdelphij close(fd); 1534166255Sdelphij if (zfd != -1 && zfd != STDOUT_FILENO) 1535166255Sdelphij close(fd); 1536166255Sdelphij return -1; 1537166255Sdelphij} 1538166255Sdelphij 1539166255Sdelphij#ifndef SMALL 1540166255Sdelphijstatic off_t 1541166255Sdelphijcat_fd(unsigned char * prepend, size_t count, off_t *gsizep, int fd) 1542166255Sdelphij{ 1543166255Sdelphij char buf[BUFLEN]; 1544166255Sdelphij off_t in_tot; 1545166255Sdelphij ssize_t w; 1546166255Sdelphij 1547166255Sdelphij in_tot = count; 1548166255Sdelphij w = write(STDOUT_FILENO, prepend, count); 1549166255Sdelphij if (w == -1 || (size_t)w != count) { 1550166255Sdelphij maybe_warn("write to stdout"); 1551166255Sdelphij return -1; 1552166255Sdelphij } 1553166255Sdelphij for (;;) { 1554166255Sdelphij ssize_t rv; 1555166255Sdelphij 1556166255Sdelphij rv = read(fd, buf, sizeof buf); 1557166255Sdelphij if (rv == 0) 1558166255Sdelphij break; 1559166255Sdelphij if (rv < 0) { 1560166255Sdelphij maybe_warn("read from fd %d", fd); 1561166255Sdelphij break; 1562166255Sdelphij } 1563166255Sdelphij 1564166255Sdelphij if (write(STDOUT_FILENO, buf, rv) != rv) { 1565166255Sdelphij maybe_warn("write to stdout"); 1566166255Sdelphij break; 1567166255Sdelphij } 1568166255Sdelphij in_tot += rv; 1569166255Sdelphij } 1570166255Sdelphij 1571166255Sdelphij if (gsizep) 1572166255Sdelphij *gsizep = in_tot; 1573166255Sdelphij return (in_tot); 1574166255Sdelphij} 1575166255Sdelphij#endif 1576166255Sdelphij 1577166255Sdelphijstatic void 1578166255Sdelphijhandle_stdin(void) 1579166255Sdelphij{ 1580166255Sdelphij unsigned char header1[4]; 1581166255Sdelphij off_t usize, gsize; 1582166255Sdelphij enum filetype method; 1583166255Sdelphij ssize_t bytes_read; 1584166255Sdelphij#ifndef NO_COMPRESS_SUPPORT 1585166255Sdelphij FILE *in; 1586166255Sdelphij#endif 1587166255Sdelphij 1588166255Sdelphij#ifndef SMALL 1589166255Sdelphij if (fflag == 0 && lflag == 0 && isatty(STDIN_FILENO)) { 1590166255Sdelphij maybe_warnx("standard input is a terminal -- ignoring"); 1591166255Sdelphij return; 1592166255Sdelphij } 1593166255Sdelphij#endif 1594166255Sdelphij 1595166255Sdelphij if (lflag) { 1596166255Sdelphij struct stat isb; 1597166255Sdelphij 1598166255Sdelphij /* XXX could read the whole file, etc. */ 1599166255Sdelphij if (fstat(STDIN_FILENO, &isb) < 0) { 1600166255Sdelphij maybe_warn("fstat"); 1601166255Sdelphij return; 1602166255Sdelphij } 1603166255Sdelphij print_list(STDIN_FILENO, isb.st_size, "stdout", isb.st_mtime); 1604166255Sdelphij return; 1605166255Sdelphij } 1606166255Sdelphij 1607166255Sdelphij bytes_read = read_retry(STDIN_FILENO, header1, sizeof header1); 1608166255Sdelphij if (bytes_read == -1) { 1609166255Sdelphij maybe_warn("can't read stdin"); 1610166255Sdelphij return; 1611166255Sdelphij } else if (bytes_read != sizeof(header1)) { 1612166255Sdelphij maybe_warnx("(stdin): unexpected end of file"); 1613166255Sdelphij return; 1614166255Sdelphij } 1615166255Sdelphij 1616166255Sdelphij method = file_gettype(header1); 1617166255Sdelphij switch (method) { 1618166255Sdelphij default: 1619166255Sdelphij#ifndef SMALL 1620166255Sdelphij if (fflag == 0) { 1621166255Sdelphij maybe_warnx("unknown compression format"); 1622166255Sdelphij return; 1623166255Sdelphij } 1624166255Sdelphij usize = cat_fd(header1, sizeof header1, &gsize, STDIN_FILENO); 1625166255Sdelphij break; 1626166255Sdelphij#endif 1627166255Sdelphij case FT_GZIP: 1628166255Sdelphij usize = gz_uncompress(STDIN_FILENO, STDOUT_FILENO, 1629166255Sdelphij (char *)header1, sizeof header1, &gsize, "(stdin)"); 1630166255Sdelphij break; 1631166255Sdelphij#ifndef NO_BZIP2_SUPPORT 1632166255Sdelphij case FT_BZIP2: 1633166255Sdelphij usize = unbzip2(STDIN_FILENO, STDOUT_FILENO, 1634166255Sdelphij (char *)header1, sizeof header1, &gsize); 1635166255Sdelphij break; 1636166255Sdelphij#endif 1637166255Sdelphij#ifndef NO_COMPRESS_SUPPORT 1638166255Sdelphij case FT_Z: 1639166255Sdelphij if ((in = zdopen(STDIN_FILENO)) == NULL) { 1640166255Sdelphij maybe_warnx("zopen of stdin"); 1641166255Sdelphij return; 1642166255Sdelphij } 1643166255Sdelphij 1644166255Sdelphij usize = zuncompress(in, stdout, (char *)header1, sizeof header1, &gsize); 1645166255Sdelphij fclose(in); 1646166255Sdelphij break; 1647166255Sdelphij#endif 1648166255Sdelphij } 1649166255Sdelphij 1650166255Sdelphij#ifndef SMALL 1651166255Sdelphij if (vflag && !tflag && usize != -1 && gsize != -1) 1652166255Sdelphij print_verbage(NULL, NULL, usize, gsize); 1653166255Sdelphij if (vflag && tflag) 1654166255Sdelphij print_test("(stdin)", usize != -1); 1655166255Sdelphij#endif 1656166255Sdelphij 1657166255Sdelphij} 1658166255Sdelphij 1659166255Sdelphijstatic void 1660166255Sdelphijhandle_stdout(void) 1661166255Sdelphij{ 1662166255Sdelphij off_t gsize, usize; 1663166255Sdelphij struct stat sb; 1664166255Sdelphij time_t systime; 1665166255Sdelphij uint32_t mtime; 1666166255Sdelphij int ret; 1667166255Sdelphij 1668166255Sdelphij#ifndef SMALL 1669166255Sdelphij if (fflag == 0 && isatty(STDOUT_FILENO)) { 1670166255Sdelphij maybe_warnx("standard output is a terminal -- ignoring"); 1671166255Sdelphij return; 1672166255Sdelphij } 1673166255Sdelphij#endif 1674166255Sdelphij /* If stdin is a file use it's mtime, otherwise use current time */ 1675166255Sdelphij ret = fstat(STDIN_FILENO, &sb); 1676166255Sdelphij 1677166255Sdelphij#ifndef SMALL 1678166255Sdelphij if (ret < 0) { 1679166255Sdelphij maybe_warn("Can't stat stdin"); 1680166255Sdelphij return; 1681166255Sdelphij } 1682166255Sdelphij#endif 1683166255Sdelphij 1684166255Sdelphij if (S_ISREG(sb.st_mode)) 1685166255Sdelphij mtime = (uint32_t)sb.st_mtime; 1686166255Sdelphij else { 1687166255Sdelphij systime = time(NULL); 1688166255Sdelphij#ifndef SMALL 1689166255Sdelphij if (systime == -1) { 1690166255Sdelphij maybe_warn("time"); 1691166255Sdelphij return; 1692166255Sdelphij } 1693166255Sdelphij#endif 1694166255Sdelphij mtime = (uint32_t)systime; 1695166255Sdelphij } 1696166255Sdelphij 1697166255Sdelphij usize = gz_compress(STDIN_FILENO, STDOUT_FILENO, &gsize, "", mtime); 1698166255Sdelphij#ifndef SMALL 1699166255Sdelphij if (vflag && !tflag && usize != -1 && gsize != -1) 1700166255Sdelphij print_verbage(NULL, NULL, usize, gsize); 1701166255Sdelphij#endif 1702166255Sdelphij} 1703166255Sdelphij 1704166255Sdelphij/* do what is asked for, for the path name */ 1705166255Sdelphijstatic void 1706166255Sdelphijhandle_pathname(char *path) 1707166255Sdelphij{ 1708166255Sdelphij char *opath = path, *s = NULL; 1709166255Sdelphij ssize_t len; 1710166255Sdelphij int slen; 1711166255Sdelphij struct stat sb; 1712166255Sdelphij 1713166255Sdelphij /* check for stdout/stdin */ 1714166255Sdelphij if (path[0] == '-' && path[1] == '\0') { 1715166255Sdelphij if (dflag) 1716166255Sdelphij handle_stdin(); 1717166255Sdelphij else 1718166255Sdelphij handle_stdout(); 1719166255Sdelphij return; 1720166255Sdelphij } 1721166255Sdelphij 1722166255Sdelphijretry: 1723166255Sdelphij if (stat(path, &sb) != 0) { 1724166255Sdelphij /* lets try <path>.gz if we're decompressing */ 1725166255Sdelphij if (dflag && s == NULL && errno == ENOENT) { 1726166255Sdelphij len = strlen(path); 1727166255Sdelphij slen = suffixes[0].ziplen; 1728166255Sdelphij s = malloc(len + slen + 1); 1729166255Sdelphij if (s == NULL) 1730166255Sdelphij maybe_err("malloc"); 1731166255Sdelphij memcpy(s, path, len); 1732166255Sdelphij memcpy(s + len, suffixes[0].zipped, slen + 1); 1733166255Sdelphij path = s; 1734166255Sdelphij goto retry; 1735166255Sdelphij } 1736166255Sdelphij maybe_warn("can't stat: %s", opath); 1737166255Sdelphij goto out; 1738166255Sdelphij } 1739166255Sdelphij 1740166255Sdelphij if (S_ISDIR(sb.st_mode)) { 1741166255Sdelphij#ifndef SMALL 1742166255Sdelphij if (rflag) 1743166255Sdelphij handle_dir(path); 1744166255Sdelphij else 1745166255Sdelphij#endif 1746166255Sdelphij maybe_warnx("%s is a directory", path); 1747166255Sdelphij goto out; 1748166255Sdelphij } 1749166255Sdelphij 1750166255Sdelphij if (S_ISREG(sb.st_mode)) 1751166255Sdelphij handle_file(path, &sb); 1752166255Sdelphij else 1753166255Sdelphij maybe_warnx("%s is not a regular file", path); 1754166255Sdelphij 1755166255Sdelphijout: 1756166255Sdelphij if (s) 1757166255Sdelphij free(s); 1758166255Sdelphij} 1759166255Sdelphij 1760166255Sdelphij/* compress/decompress a file */ 1761166255Sdelphijstatic void 1762166255Sdelphijhandle_file(char *file, struct stat *sbp) 1763166255Sdelphij{ 1764166255Sdelphij off_t usize, gsize; 1765166255Sdelphij char outfile[PATH_MAX]; 1766166255Sdelphij 1767166255Sdelphij infile = file; 1768166255Sdelphij if (dflag) { 1769166255Sdelphij usize = file_uncompress(file, outfile, sizeof(outfile)); 1770166255Sdelphij#ifndef SMALL 1771166255Sdelphij if (vflag && tflag) 1772166255Sdelphij print_test(file, usize != -1); 1773166255Sdelphij#endif 1774166255Sdelphij if (usize == -1) 1775166255Sdelphij return; 1776166255Sdelphij gsize = sbp->st_size; 1777166255Sdelphij } else { 1778166255Sdelphij gsize = file_compress(file, outfile, sizeof(outfile)); 1779166255Sdelphij if (gsize == -1) 1780166255Sdelphij return; 1781166255Sdelphij usize = sbp->st_size; 1782166255Sdelphij } 1783166255Sdelphij 1784166255Sdelphij 1785166255Sdelphij#ifndef SMALL 1786166255Sdelphij if (vflag && !tflag) 1787166255Sdelphij print_verbage(file, (cflag) ? NULL : outfile, usize, gsize); 1788166255Sdelphij#endif 1789166255Sdelphij} 1790166255Sdelphij 1791166255Sdelphij#ifndef SMALL 1792166255Sdelphij/* this is used with -r to recursively descend directories */ 1793166255Sdelphijstatic void 1794166255Sdelphijhandle_dir(char *dir) 1795166255Sdelphij{ 1796166255Sdelphij char *path_argv[2]; 1797166255Sdelphij FTS *fts; 1798166255Sdelphij FTSENT *entry; 1799166255Sdelphij 1800166255Sdelphij path_argv[0] = dir; 1801166255Sdelphij path_argv[1] = 0; 1802166255Sdelphij fts = fts_open(path_argv, FTS_PHYSICAL, NULL); 1803166255Sdelphij if (fts == NULL) { 1804166255Sdelphij warn("couldn't fts_open %s", dir); 1805166255Sdelphij return; 1806166255Sdelphij } 1807166255Sdelphij 1808166255Sdelphij while ((entry = fts_read(fts))) { 1809166255Sdelphij switch(entry->fts_info) { 1810166255Sdelphij case FTS_D: 1811166255Sdelphij case FTS_DP: 1812166255Sdelphij continue; 1813166255Sdelphij 1814166255Sdelphij case FTS_DNR: 1815166255Sdelphij case FTS_ERR: 1816166255Sdelphij case FTS_NS: 1817166255Sdelphij maybe_warn("%s", entry->fts_path); 1818166255Sdelphij continue; 1819166255Sdelphij case FTS_F: 1820166255Sdelphij handle_file(entry->fts_name, entry->fts_statp); 1821166255Sdelphij } 1822166255Sdelphij } 1823166255Sdelphij (void)fts_close(fts); 1824166255Sdelphij} 1825166255Sdelphij#endif 1826166255Sdelphij 1827166255Sdelphij/* print a ratio - size reduction as a fraction of uncompressed size */ 1828166255Sdelphijstatic void 1829166255Sdelphijprint_ratio(off_t in, off_t out, FILE *where) 1830166255Sdelphij{ 1831166255Sdelphij int percent10; /* 10 * percent */ 1832166255Sdelphij off_t diff; 1833166255Sdelphij char buff[8]; 1834166255Sdelphij int len; 1835166255Sdelphij 1836166255Sdelphij diff = in - out/2; 1837166255Sdelphij if (diff <= 0) 1838166255Sdelphij /* 1839166255Sdelphij * Output is more than double size of input! print -99.9% 1840166255Sdelphij * Quite possibly we've failed to get the original size. 1841166255Sdelphij */ 1842166255Sdelphij percent10 = -999; 1843166255Sdelphij else { 1844166255Sdelphij /* 1845166255Sdelphij * We only need 12 bits of result from the final division, 1846166255Sdelphij * so reduce the values until a 32bit division will suffice. 1847166255Sdelphij */ 1848166255Sdelphij while (in > 0x100000) { 1849166255Sdelphij diff >>= 1; 1850166255Sdelphij in >>= 1; 1851166255Sdelphij } 1852166255Sdelphij if (in != 0) 1853166255Sdelphij percent10 = ((u_int)diff * 2000) / (u_int)in - 1000; 1854166255Sdelphij else 1855166255Sdelphij percent10 = 0; 1856166255Sdelphij } 1857166255Sdelphij 1858166255Sdelphij len = snprintf(buff, sizeof buff, "%2.2d.", percent10); 1859166255Sdelphij /* Move the '.' to before the last digit */ 1860166255Sdelphij buff[len - 1] = buff[len - 2]; 1861166255Sdelphij buff[len - 2] = '.'; 1862166255Sdelphij fprintf(where, "%5s%%", buff); 1863166255Sdelphij} 1864166255Sdelphij 1865166255Sdelphij#ifndef SMALL 1866166255Sdelphij/* print compression statistics, and the new name (if there is one!) */ 1867166255Sdelphijstatic void 1868166255Sdelphijprint_verbage(const char *file, const char *nfile, off_t usize, off_t gsize) 1869166255Sdelphij{ 1870166255Sdelphij if (file) 1871166255Sdelphij fprintf(stderr, "%s:%s ", file, 1872166255Sdelphij strlen(file) < 7 ? "\t\t" : "\t"); 1873166255Sdelphij print_ratio(usize, gsize, stderr); 1874166255Sdelphij if (nfile) 1875166255Sdelphij fprintf(stderr, " -- replaced with %s", nfile); 1876166255Sdelphij fprintf(stderr, "\n"); 1877166255Sdelphij fflush(stderr); 1878166255Sdelphij} 1879166255Sdelphij 1880166255Sdelphij/* print test results */ 1881166255Sdelphijstatic void 1882166255Sdelphijprint_test(const char *file, int ok) 1883166255Sdelphij{ 1884166255Sdelphij 1885166255Sdelphij if (exit_value == 0 && ok == 0) 1886166255Sdelphij exit_value = 1; 1887166255Sdelphij fprintf(stderr, "%s:%s %s\n", file, 1888166255Sdelphij strlen(file) < 7 ? "\t\t" : "\t", ok ? "OK" : "NOT OK"); 1889166255Sdelphij fflush(stderr); 1890166255Sdelphij} 1891166255Sdelphij#endif 1892166255Sdelphij 1893166255Sdelphij/* print a file's info ala --list */ 1894166255Sdelphij/* eg: 1895166255Sdelphij compressed uncompressed ratio uncompressed_name 1896166255Sdelphij 354841 1679360 78.8% /usr/pkgsrc/distfiles/libglade-2.0.1.tar 1897166255Sdelphij*/ 1898166255Sdelphijstatic void 1899166255Sdelphijprint_list(int fd, off_t out, const char *outfile, time_t ts) 1900166255Sdelphij{ 1901166255Sdelphij static int first = 1; 1902166255Sdelphij#ifndef SMALL 1903166255Sdelphij static off_t in_tot, out_tot; 1904166255Sdelphij uint32_t crc = 0; 1905166255Sdelphij#endif 1906166255Sdelphij off_t in = 0, rv; 1907166255Sdelphij 1908166255Sdelphij if (first) { 1909166255Sdelphij#ifndef SMALL 1910166255Sdelphij if (vflag) 1911166255Sdelphij printf("method crc date time "); 1912166255Sdelphij#endif 1913166255Sdelphij if (qflag == 0) 1914166255Sdelphij printf(" compressed uncompressed " 1915166255Sdelphij "ratio uncompressed_name\n"); 1916166255Sdelphij } 1917166255Sdelphij first = 0; 1918166255Sdelphij 1919166255Sdelphij /* print totals? */ 1920166255Sdelphij#ifndef SMALL 1921166255Sdelphij if (fd == -1) { 1922166255Sdelphij in = in_tot; 1923166255Sdelphij out = out_tot; 1924166255Sdelphij } else 1925166255Sdelphij#endif 1926166255Sdelphij { 1927166255Sdelphij /* read the last 4 bytes - this is the uncompressed size */ 1928166255Sdelphij rv = lseek(fd, (off_t)(-8), SEEK_END); 1929166255Sdelphij if (rv != -1) { 1930166255Sdelphij unsigned char buf[8]; 1931166255Sdelphij uint32_t usize; 1932166255Sdelphij 1933166255Sdelphij rv = read(fd, (char *)buf, sizeof(buf)); 1934166255Sdelphij if (rv == -1) 1935166255Sdelphij maybe_warn("read of uncompressed size"); 1936166255Sdelphij else if (rv != sizeof(buf)) 1937166255Sdelphij maybe_warnx("read of uncompressed size"); 1938166255Sdelphij 1939166255Sdelphij else { 1940166255Sdelphij usize = buf[4] | buf[5] << 8 | 1941166255Sdelphij buf[6] << 16 | buf[7] << 24; 1942166255Sdelphij in = (off_t)usize; 1943166255Sdelphij#ifndef SMALL 1944166255Sdelphij crc = buf[0] | buf[1] << 8 | 1945166255Sdelphij buf[2] << 16 | buf[3] << 24; 1946166255Sdelphij#endif 1947166255Sdelphij } 1948166255Sdelphij } 1949166255Sdelphij } 1950166255Sdelphij 1951166255Sdelphij#ifndef SMALL 1952166255Sdelphij if (vflag && fd == -1) 1953166255Sdelphij printf(" "); 1954166255Sdelphij else if (vflag) { 1955166255Sdelphij char *date = ctime(&ts); 1956166255Sdelphij 1957166255Sdelphij /* skip the day, 1/100th second, and year */ 1958166255Sdelphij date += 4; 1959166255Sdelphij date[12] = 0; 1960166255Sdelphij printf("%5s %08x %11s ", "defla"/*XXX*/, crc, date); 1961166255Sdelphij } 1962166255Sdelphij in_tot += in; 1963166255Sdelphij out_tot += out; 1964166255Sdelphij#endif 1965166255Sdelphij printf("%12llu %12llu ", (unsigned long long)out, (unsigned long long)in); 1966166255Sdelphij print_ratio(in, out, stdout); 1967166255Sdelphij printf(" %s\n", outfile); 1968166255Sdelphij} 1969166255Sdelphij 1970166255Sdelphij/* display the usage of NetBSD gzip */ 1971166255Sdelphijstatic void 1972166255Sdelphijusage(void) 1973166255Sdelphij{ 1974166255Sdelphij 1975166255Sdelphij fprintf(stderr, "%s\n", gzip_version); 1976166255Sdelphij fprintf(stderr, 1977166255Sdelphij "usage: %s [-" OPT_LIST "] [<file> [<file> ...]]\n" 1978166255Sdelphij#ifndef SMALL 1979166255Sdelphij " -1 --fast fastest (worst) compression\n" 1980166255Sdelphij " -2 .. -8 set compression level\n" 1981166255Sdelphij " -9 --best best (slowest) compression\n" 1982166255Sdelphij " -c --stdout write to stdout, keep original files\n" 1983166255Sdelphij " --to-stdout\n" 1984166255Sdelphij " -d --decompress uncompress files\n" 1985166255Sdelphij " --uncompress\n" 1986166255Sdelphij " -f --force force overwriting & compress links\n" 1987166255Sdelphij " -h --help display this help\n" 1988166255Sdelphij " -l --list list compressed file contents\n" 1989166255Sdelphij " -N --name save or restore original file name and time stamp\n" 1990166255Sdelphij " -n --no-name don't save original file name or time stamp\n" 1991166255Sdelphij " -q --quiet output no warnings\n" 1992166255Sdelphij " -r --recursive recursively compress files in directories\n" 1993166255Sdelphij " -S .suf use suffix .suf instead of .gz\n" 1994166255Sdelphij " --suffix .suf\n" 1995166255Sdelphij " -t --test test compressed file\n" 1996166255Sdelphij " -V --version display program version\n" 1997166255Sdelphij " -v --verbose print extra statistics\n", 1998166255Sdelphij#else 1999166255Sdelphij , 2000166255Sdelphij#endif 2001166255Sdelphij getprogname()); 2002166255Sdelphij exit(0); 2003166255Sdelphij} 2004166255Sdelphij 2005166255Sdelphij#ifndef SMALL 2006166255Sdelphij/* display the license information of FreeBSD gzip */ 2007166255Sdelphijstatic void 2008166255Sdelphijdisplay_license(void) 2009166255Sdelphij{ 2010166255Sdelphij 2011166255Sdelphij fprintf(stderr, "%s (based on NetBSD gzip 20060927)\n", gzip_version); 2012166255Sdelphij fprintf(stderr, "%s\n", gzip_copyright); 2013166255Sdelphij exit(0); 2014166255Sdelphij} 2015166255Sdelphij#endif 2016166255Sdelphij 2017166255Sdelphij/* display the version of NetBSD gzip */ 2018166255Sdelphijstatic void 2019166255Sdelphijdisplay_version(void) 2020166255Sdelphij{ 2021166255Sdelphij 2022166255Sdelphij fprintf(stderr, "%s\n", gzip_version); 2023166255Sdelphij exit(0); 2024166255Sdelphij} 2025166255Sdelphij 2026166255Sdelphij#ifndef NO_BZIP2_SUPPORT 2027166255Sdelphij#include "unbzip2.c" 2028166255Sdelphij#endif 2029166255Sdelphij#ifndef NO_COMPRESS_SUPPORT 2030166255Sdelphij#include "zuncompress.c" 2031166255Sdelphij#endif 2032166255Sdelphij 2033166255Sdelphijstatic ssize_t 2034166255Sdelphijread_retry(int fd, void *buf, size_t sz) 2035166255Sdelphij{ 2036166255Sdelphij char *cp = buf; 2037166255Sdelphij size_t left = MIN(sz, (size_t) SSIZE_MAX); 2038166255Sdelphij 2039166255Sdelphij while (left > 0) { 2040166255Sdelphij ssize_t ret; 2041166255Sdelphij 2042166255Sdelphij ret = read(fd, cp, left); 2043166255Sdelphij if (ret == -1) { 2044166255Sdelphij return ret; 2045166255Sdelphij } else if (ret == 0) { 2046166255Sdelphij break; /* EOF */ 2047166255Sdelphij } 2048166255Sdelphij cp += ret; 2049166255Sdelphij left -= ret; 2050166255Sdelphij } 2051166255Sdelphij 2052166255Sdelphij return sz - left; 2053166255Sdelphij} 2054166255Sdelphij 2055