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