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