1343251Sdelphij/* $NetBSD: gzip.c,v 1.116 2018/10/27 11:39:12 skrll Exp $ */ 2166255Sdelphij 3166255Sdelphij/*- 4330449Seadler * SPDX-License-Identifier: BSD-2-Clause-NetBSD 5330449Seadler * 6326559Sdelphij * Copyright (c) 1997, 1998, 2003, 2004, 2006, 2008, 2009, 2010, 2011, 2015, 2017 7326559Sdelphij * Matthew R. Green 8166255Sdelphij * All rights reserved. 9166255Sdelphij * 10166255Sdelphij * Redistribution and use in source and binary forms, with or without 11166255Sdelphij * modification, are permitted provided that the following conditions 12166255Sdelphij * are met: 13166255Sdelphij * 1. Redistributions of source code must retain the above copyright 14166255Sdelphij * notice, this list of conditions and the following disclaimer. 15166255Sdelphij * 2. Redistributions in binary form must reproduce the above copyright 16166255Sdelphij * notice, this list of conditions and the following disclaimer in the 17166255Sdelphij * documentation and/or other materials provided with the distribution. 18166255Sdelphij * 19166255Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20166255Sdelphij * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21166255Sdelphij * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22166255Sdelphij * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23166255Sdelphij * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24166255Sdelphij * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25166255Sdelphij * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 26166255Sdelphij * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27166255Sdelphij * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28166255Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29166255Sdelphij * SUCH DAMAGE. 30166255Sdelphij * 31166255Sdelphij */ 32166255Sdelphij 33166255Sdelphij#include <sys/cdefs.h> 34166255Sdelphij#ifndef lint 35326559Sdelphij__COPYRIGHT("@(#) Copyright (c) 1997, 1998, 2003, 2004, 2006, 2008,\ 36326559Sdelphij 2009, 2010, 2011, 2015, 2017 Matthew R. Green. All rights reserved."); 37222210Sdelphij__FBSDID("$FreeBSD: stable/11/usr.bin/gzip/gzip.c 343251 2019-01-21 06:52:35Z delphij $"); 38166255Sdelphij#endif /* not lint */ 39166255Sdelphij 40166255Sdelphij/* 41166255Sdelphij * gzip.c -- GPL free gzip using zlib. 42166255Sdelphij * 43166255Sdelphij * RFC 1950 covers the zlib format 44166255Sdelphij * RFC 1951 covers the deflate format 45166255Sdelphij * RFC 1952 covers the gzip format 46166255Sdelphij * 47166255Sdelphij * TODO: 48166255Sdelphij * - use mmap where possible 49166255Sdelphij * - make bzip2/compress -v/-t/-l support work as well as possible 50166255Sdelphij */ 51166255Sdelphij 52336661Sdelphij#include <sys/endian.h> 53166255Sdelphij#include <sys/param.h> 54166255Sdelphij#include <sys/stat.h> 55166255Sdelphij#include <sys/time.h> 56166255Sdelphij 57166255Sdelphij#include <inttypes.h> 58166255Sdelphij#include <unistd.h> 59166255Sdelphij#include <stdio.h> 60166255Sdelphij#include <string.h> 61166255Sdelphij#include <stdlib.h> 62166255Sdelphij#include <err.h> 63166255Sdelphij#include <errno.h> 64166255Sdelphij#include <fcntl.h> 65166255Sdelphij#include <zlib.h> 66166255Sdelphij#include <fts.h> 67166255Sdelphij#include <libgen.h> 68166255Sdelphij#include <stdarg.h> 69166255Sdelphij#include <getopt.h> 70166255Sdelphij#include <time.h> 71166255Sdelphij 72166255Sdelphij/* what type of file are we dealing with */ 73166255Sdelphijenum filetype { 74166255Sdelphij FT_GZIP, 75166255Sdelphij#ifndef NO_BZIP2_SUPPORT 76166255Sdelphij FT_BZIP2, 77166255Sdelphij#endif 78166255Sdelphij#ifndef NO_COMPRESS_SUPPORT 79166255Sdelphij FT_Z, 80166255Sdelphij#endif 81194579Sdelphij#ifndef NO_PACK_SUPPORT 82194579Sdelphij FT_PACK, 83194579Sdelphij#endif 84226184Sdelphij#ifndef NO_XZ_SUPPORT 85226184Sdelphij FT_XZ, 86226184Sdelphij#endif 87343251Sdelphij#ifndef NO_LZ_SUPPORT 88343251Sdelphij FT_LZ, 89343251Sdelphij#endif 90166255Sdelphij FT_LAST, 91166255Sdelphij FT_UNKNOWN 92166255Sdelphij}; 93166255Sdelphij 94166255Sdelphij#ifndef NO_BZIP2_SUPPORT 95166255Sdelphij#include <bzlib.h> 96166255Sdelphij 97166255Sdelphij#define BZ2_SUFFIX ".bz2" 98309850Sdelphij#define BZIP2_MAGIC "BZh" 99166255Sdelphij#endif 100166255Sdelphij 101166255Sdelphij#ifndef NO_COMPRESS_SUPPORT 102166255Sdelphij#define Z_SUFFIX ".Z" 103166255Sdelphij#define Z_MAGIC "\037\235" 104166255Sdelphij#endif 105166255Sdelphij 106194579Sdelphij#ifndef NO_PACK_SUPPORT 107194579Sdelphij#define PACK_MAGIC "\037\036" 108194579Sdelphij#endif 109194579Sdelphij 110226184Sdelphij#ifndef NO_XZ_SUPPORT 111226184Sdelphij#include <lzma.h> 112226184Sdelphij#define XZ_SUFFIX ".xz" 113226184Sdelphij#define XZ_MAGIC "\3757zXZ" 114226184Sdelphij#endif 115226184Sdelphij 116343251Sdelphij#ifndef NO_LZ_SUPPORT 117343251Sdelphij#define LZ_SUFFIX ".lz" 118343251Sdelphij#define LZ_MAGIC "LZIP" 119343251Sdelphij#endif 120343251Sdelphij 121166255Sdelphij#define GZ_SUFFIX ".gz" 122166255Sdelphij 123166255Sdelphij#define BUFLEN (64 * 1024) 124166255Sdelphij 125166255Sdelphij#define GZIP_MAGIC0 0x1F 126166255Sdelphij#define GZIP_MAGIC1 0x8B 127166255Sdelphij#define GZIP_OMAGIC1 0x9E 128166255Sdelphij 129166255Sdelphij#define GZIP_TIMESTAMP (off_t)4 130166255Sdelphij#define GZIP_ORIGNAME (off_t)10 131166255Sdelphij 132166255Sdelphij#define HEAD_CRC 0x02 133166255Sdelphij#define EXTRA_FIELD 0x04 134166255Sdelphij#define ORIG_NAME 0x08 135166255Sdelphij#define COMMENT 0x10 136166255Sdelphij 137166255Sdelphij#define OS_CODE 3 /* Unix */ 138166255Sdelphij 139166255Sdelphijtypedef struct { 140166255Sdelphij const char *zipped; 141166255Sdelphij int ziplen; 142166255Sdelphij const char *normal; /* for unzip - must not be longer than zipped */ 143166255Sdelphij} suffixes_t; 144166255Sdelphijstatic suffixes_t suffixes[] = { 145166255Sdelphij#define SUFFIX(Z, N) {Z, sizeof Z - 1, N} 146166255Sdelphij SUFFIX(GZ_SUFFIX, ""), /* Overwritten by -S .xxx */ 147166255Sdelphij#ifndef SMALL 148166255Sdelphij SUFFIX(GZ_SUFFIX, ""), 149166255Sdelphij SUFFIX(".z", ""), 150166255Sdelphij SUFFIX("-gz", ""), 151166255Sdelphij SUFFIX("-z", ""), 152166255Sdelphij SUFFIX("_z", ""), 153166255Sdelphij SUFFIX(".taz", ".tar"), 154166255Sdelphij SUFFIX(".tgz", ".tar"), 155166255Sdelphij#ifndef NO_BZIP2_SUPPORT 156166255Sdelphij SUFFIX(BZ2_SUFFIX, ""), 157176980Srwatson SUFFIX(".tbz", ".tar"), 158176980Srwatson SUFFIX(".tbz2", ".tar"), 159166255Sdelphij#endif 160166255Sdelphij#ifndef NO_COMPRESS_SUPPORT 161166255Sdelphij SUFFIX(Z_SUFFIX, ""), 162166255Sdelphij#endif 163226184Sdelphij#ifndef NO_XZ_SUPPORT 164226184Sdelphij SUFFIX(XZ_SUFFIX, ""), 165226184Sdelphij#endif 166343251Sdelphij#ifndef NO_LZ_SUPPORT 167343251Sdelphij SUFFIX(LZ_SUFFIX, ""), 168343251Sdelphij#endif 169166255Sdelphij SUFFIX(GZ_SUFFIX, ""), /* Overwritten by -S "" */ 170166255Sdelphij#endif /* SMALL */ 171166255Sdelphij#undef SUFFIX 172166255Sdelphij}; 173307697Saraujo#define NUM_SUFFIXES (nitems(suffixes)) 174195988Sdelphij#define SUFFIX_MAXLEN 30 175195988Sdelphij 176343251Sdelphijstatic const char gzip_version[] = "FreeBSD gzip 20190107"; 177166255Sdelphij 178166255Sdelphij#ifndef SMALL 179166255Sdelphijstatic const char gzip_copyright[] = \ 180166255Sdelphij" Copyright (c) 1997, 1998, 2003, 2004, 2006 Matthew R. Green\n" 181166255Sdelphij" All rights reserved.\n" 182166255Sdelphij"\n" 183166255Sdelphij" Redistribution and use in source and binary forms, with or without\n" 184166255Sdelphij" modification, are permitted provided that the following conditions\n" 185166255Sdelphij" are met:\n" 186166255Sdelphij" 1. Redistributions of source code must retain the above copyright\n" 187166255Sdelphij" notice, this list of conditions and the following disclaimer.\n" 188166255Sdelphij" 2. Redistributions in binary form must reproduce the above copyright\n" 189166255Sdelphij" notice, this list of conditions and the following disclaimer in the\n" 190166255Sdelphij" documentation and/or other materials provided with the distribution.\n" 191166255Sdelphij"\n" 192166255Sdelphij" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n" 193166255Sdelphij" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n" 194166255Sdelphij" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n" 195166255Sdelphij" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n" 196166255Sdelphij" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n" 197166255Sdelphij" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n" 198166255Sdelphij" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\n" 199166255Sdelphij" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n" 200166255Sdelphij" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n" 201166255Sdelphij" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n" 202166255Sdelphij" SUCH DAMAGE."; 203166255Sdelphij#endif 204166255Sdelphij 205166255Sdelphijstatic int cflag; /* stdout mode */ 206166255Sdelphijstatic int dflag; /* decompress mode */ 207166255Sdelphijstatic int lflag; /* list mode */ 208166255Sdelphijstatic int numflag = 6; /* gzip -1..-9 value */ 209166255Sdelphij 210326559Sdelphijstatic const char *remove_file = NULL; /* file to be removed upon SIGINT */ 211326559Sdelphij 212326559Sdelphijstatic int fflag; /* force mode */ 213166255Sdelphij#ifndef SMALL 214170053Sdelphijstatic int kflag; /* don't delete input files */ 215166255Sdelphijstatic int nflag; /* don't save name/timestamp */ 216166255Sdelphijstatic int Nflag; /* don't restore name/timestamp */ 217166255Sdelphijstatic int qflag; /* quiet mode */ 218166255Sdelphijstatic int rflag; /* recursive mode */ 219166255Sdelphijstatic int tflag; /* test */ 220166255Sdelphijstatic int vflag; /* verbose mode */ 221326559Sdelphijstatic sig_atomic_t print_info = 0; 222166255Sdelphij#else 223166255Sdelphij#define qflag 0 224166255Sdelphij#define tflag 0 225166255Sdelphij#endif 226166255Sdelphij 227166255Sdelphijstatic int exit_value = 0; /* exit value */ 228166255Sdelphij 229326559Sdelphijstatic const char *infile; /* name of file coming in */ 230166255Sdelphij 231226184Sdelphijstatic void maybe_err(const char *fmt, ...) __printflike(1, 2) __dead2; 232226184Sdelphij#if !defined(NO_BZIP2_SUPPORT) || !defined(NO_PACK_SUPPORT) || \ 233226184Sdelphij !defined(NO_XZ_SUPPORT) 234226184Sdelphijstatic void maybe_errx(const char *fmt, ...) __printflike(1, 2) __dead2; 235166255Sdelphij#endif 236226184Sdelphijstatic void maybe_warn(const char *fmt, ...) __printflike(1, 2); 237226184Sdelphijstatic void maybe_warnx(const char *fmt, ...) __printflike(1, 2); 238166255Sdelphijstatic enum filetype file_gettype(u_char *); 239166255Sdelphij#ifdef SMALL 240166255Sdelphij#define gz_compress(if, of, sz, fn, tm) gz_compress(if, of, sz) 241166255Sdelphij#endif 242166255Sdelphijstatic off_t gz_compress(int, int, off_t *, const char *, uint32_t); 243166255Sdelphijstatic off_t gz_uncompress(int, int, char *, size_t, off_t *, const char *); 244166255Sdelphijstatic off_t file_compress(char *, char *, size_t); 245166255Sdelphijstatic off_t file_uncompress(char *, char *, size_t); 246166255Sdelphijstatic void handle_pathname(char *); 247166255Sdelphijstatic void handle_file(char *, struct stat *); 248166255Sdelphijstatic void handle_stdin(void); 249166255Sdelphijstatic void handle_stdout(void); 250166255Sdelphijstatic void print_ratio(off_t, off_t, FILE *); 251166255Sdelphijstatic void print_list(int fd, off_t, const char *, time_t); 252226184Sdelphijstatic void usage(void) __dead2; 253226184Sdelphijstatic void display_version(void) __dead2; 254166255Sdelphij#ifndef SMALL 255166255Sdelphijstatic void display_license(void); 256166255Sdelphij#endif 257166255Sdelphijstatic const suffixes_t *check_suffix(char *, int); 258166255Sdelphijstatic ssize_t read_retry(int, void *, size_t); 259326559Sdelphijstatic ssize_t write_retry(int, const void *, size_t); 260343251Sdelphijstatic void print_list_out(off_t, off_t, const char*); 261166255Sdelphij 262166255Sdelphij#ifdef SMALL 263326559Sdelphij#define infile_set(f,t) infile_set(f) 264326559Sdelphij#endif 265326559Sdelphijstatic void infile_set(const char *newinfile, off_t total); 266326559Sdelphij 267326559Sdelphij#ifdef SMALL 268166255Sdelphij#define unlink_input(f, sb) unlink(f) 269326559Sdelphij#define check_siginfo() /* nothing */ 270326559Sdelphij#define setup_signals() /* nothing */ 271326559Sdelphij#define infile_newdata(t) /* nothing */ 272166255Sdelphij#else 273326559Sdelphijstatic off_t infile_total; /* total expected to read/write */ 274326559Sdelphijstatic off_t infile_current; /* current read/write */ 275326559Sdelphij 276326559Sdelphijstatic void check_siginfo(void); 277166255Sdelphijstatic off_t cat_fd(unsigned char *, size_t, off_t *, int fd); 278166255Sdelphijstatic void prepend_gzip(char *, int *, char ***); 279166255Sdelphijstatic void handle_dir(char *); 280166255Sdelphijstatic void print_verbage(const char *, const char *, off_t, off_t); 281166255Sdelphijstatic void print_test(const char *, int); 282166255Sdelphijstatic void copymodes(int fd, const struct stat *, const char *file); 283166255Sdelphijstatic int check_outfile(const char *outfile); 284326559Sdelphijstatic void setup_signals(void); 285326559Sdelphijstatic void infile_newdata(size_t newdata); 286326559Sdelphijstatic void infile_clear(void); 287166255Sdelphij#endif 288166255Sdelphij 289166255Sdelphij#ifndef NO_BZIP2_SUPPORT 290166255Sdelphijstatic off_t unbzip2(int, int, char *, size_t, off_t *); 291166255Sdelphij#endif 292166255Sdelphij 293166255Sdelphij#ifndef NO_COMPRESS_SUPPORT 294166255Sdelphijstatic FILE *zdopen(int); 295166255Sdelphijstatic off_t zuncompress(FILE *, FILE *, char *, size_t, off_t *); 296166255Sdelphij#endif 297166255Sdelphij 298194579Sdelphij#ifndef NO_PACK_SUPPORT 299194579Sdelphijstatic off_t unpack(int, int, char *, size_t, off_t *); 300194579Sdelphij#endif 301194579Sdelphij 302226184Sdelphij#ifndef NO_XZ_SUPPORT 303226184Sdelphijstatic off_t unxz(int, int, char *, size_t, off_t *); 304343251Sdelphijstatic off_t unxz_len(int); 305226184Sdelphij#endif 306166255Sdelphij 307343251Sdelphij#ifndef NO_LZ_SUPPORT 308343251Sdelphijstatic off_t unlz(int, int, char *, size_t, off_t *); 309343251Sdelphij#endif 310343251Sdelphij 311166255Sdelphij#ifdef SMALL 312166255Sdelphij#define getopt_long(a,b,c,d,e) getopt(a,b,c) 313166255Sdelphij#else 314166255Sdelphijstatic const struct option longopts[] = { 315166255Sdelphij { "stdout", no_argument, 0, 'c' }, 316166255Sdelphij { "to-stdout", no_argument, 0, 'c' }, 317166255Sdelphij { "decompress", no_argument, 0, 'd' }, 318166255Sdelphij { "uncompress", no_argument, 0, 'd' }, 319166255Sdelphij { "force", no_argument, 0, 'f' }, 320166255Sdelphij { "help", no_argument, 0, 'h' }, 321170053Sdelphij { "keep", no_argument, 0, 'k' }, 322166255Sdelphij { "list", no_argument, 0, 'l' }, 323166255Sdelphij { "no-name", no_argument, 0, 'n' }, 324166255Sdelphij { "name", no_argument, 0, 'N' }, 325166255Sdelphij { "quiet", no_argument, 0, 'q' }, 326166255Sdelphij { "recursive", no_argument, 0, 'r' }, 327166255Sdelphij { "suffix", required_argument, 0, 'S' }, 328166255Sdelphij { "test", no_argument, 0, 't' }, 329166255Sdelphij { "verbose", no_argument, 0, 'v' }, 330166255Sdelphij { "version", no_argument, 0, 'V' }, 331166255Sdelphij { "fast", no_argument, 0, '1' }, 332166255Sdelphij { "best", no_argument, 0, '9' }, 333166255Sdelphij { "ascii", no_argument, 0, 'a' }, 334166255Sdelphij { "license", no_argument, 0, 'L' }, 335166255Sdelphij { NULL, no_argument, 0, 0 }, 336166255Sdelphij}; 337166255Sdelphij#endif 338166255Sdelphij 339166255Sdelphijint 340166255Sdelphijmain(int argc, char **argv) 341166255Sdelphij{ 342166255Sdelphij const char *progname = getprogname(); 343166255Sdelphij#ifndef SMALL 344166255Sdelphij char *gzip; 345166255Sdelphij int len; 346166255Sdelphij#endif 347166255Sdelphij int ch; 348166255Sdelphij 349326559Sdelphij setup_signals(); 350326559Sdelphij 351166255Sdelphij#ifndef SMALL 352166255Sdelphij if ((gzip = getenv("GZIP")) != NULL) 353166255Sdelphij prepend_gzip(gzip, &argc, &argv); 354166255Sdelphij#endif 355166255Sdelphij 356166255Sdelphij /* 357166255Sdelphij * XXX 358166255Sdelphij * handle being called `gunzip', `zcat' and `gzcat' 359166255Sdelphij */ 360166255Sdelphij if (strcmp(progname, "gunzip") == 0) 361166255Sdelphij dflag = 1; 362166255Sdelphij else if (strcmp(progname, "zcat") == 0 || 363166255Sdelphij strcmp(progname, "gzcat") == 0) 364166255Sdelphij dflag = cflag = 1; 365166255Sdelphij 366166255Sdelphij#ifdef SMALL 367222210Sdelphij#define OPT_LIST "123456789cdhlV" 368166255Sdelphij#else 369170053Sdelphij#define OPT_LIST "123456789acdfhklLNnqrS:tVv" 370166255Sdelphij#endif 371166255Sdelphij 372166255Sdelphij while ((ch = getopt_long(argc, argv, OPT_LIST, longopts, NULL)) != -1) { 373166255Sdelphij switch (ch) { 374166255Sdelphij case '1': case '2': case '3': 375166255Sdelphij case '4': case '5': case '6': 376166255Sdelphij case '7': case '8': case '9': 377166255Sdelphij numflag = ch - '0'; 378166255Sdelphij break; 379166255Sdelphij case 'c': 380166255Sdelphij cflag = 1; 381166255Sdelphij break; 382166255Sdelphij case 'd': 383166255Sdelphij dflag = 1; 384166255Sdelphij break; 385166255Sdelphij case 'l': 386166255Sdelphij lflag = 1; 387166255Sdelphij dflag = 1; 388166255Sdelphij break; 389166255Sdelphij case 'V': 390166255Sdelphij display_version(); 391166255Sdelphij /* NOTREACHED */ 392166255Sdelphij#ifndef SMALL 393166255Sdelphij case 'a': 394166255Sdelphij fprintf(stderr, "%s: option --ascii ignored on this system\n", progname); 395166255Sdelphij break; 396166255Sdelphij case 'f': 397166255Sdelphij fflag = 1; 398166255Sdelphij break; 399170053Sdelphij case 'k': 400170053Sdelphij kflag = 1; 401170053Sdelphij break; 402166255Sdelphij case 'L': 403166255Sdelphij display_license(); 404166255Sdelphij /* NOT REACHED */ 405166255Sdelphij case 'N': 406166255Sdelphij nflag = 0; 407166255Sdelphij Nflag = 1; 408166255Sdelphij break; 409166255Sdelphij case 'n': 410166255Sdelphij nflag = 1; 411166255Sdelphij Nflag = 0; 412166255Sdelphij break; 413166255Sdelphij case 'q': 414166255Sdelphij qflag = 1; 415166255Sdelphij break; 416166255Sdelphij case 'r': 417166255Sdelphij rflag = 1; 418166255Sdelphij break; 419166255Sdelphij case 'S': 420166255Sdelphij len = strlen(optarg); 421166255Sdelphij if (len != 0) { 422195988Sdelphij if (len > SUFFIX_MAXLEN) 423195988Sdelphij errx(1, "incorrect suffix: '%s': too long", optarg); 424166255Sdelphij suffixes[0].zipped = optarg; 425166255Sdelphij suffixes[0].ziplen = len; 426166255Sdelphij } else { 427166255Sdelphij suffixes[NUM_SUFFIXES - 1].zipped = ""; 428166255Sdelphij suffixes[NUM_SUFFIXES - 1].ziplen = 0; 429166255Sdelphij } 430166255Sdelphij break; 431166255Sdelphij case 't': 432166255Sdelphij cflag = 1; 433166255Sdelphij tflag = 1; 434166255Sdelphij dflag = 1; 435166255Sdelphij break; 436166255Sdelphij case 'v': 437166255Sdelphij vflag = 1; 438166255Sdelphij break; 439166255Sdelphij#endif 440166255Sdelphij default: 441166255Sdelphij usage(); 442166255Sdelphij /* NOTREACHED */ 443166255Sdelphij } 444166255Sdelphij } 445166255Sdelphij argv += optind; 446166255Sdelphij argc -= optind; 447166255Sdelphij 448166255Sdelphij if (argc == 0) { 449166255Sdelphij if (dflag) /* stdin mode */ 450166255Sdelphij handle_stdin(); 451166255Sdelphij else /* stdout mode */ 452166255Sdelphij handle_stdout(); 453166255Sdelphij } else { 454166255Sdelphij do { 455166255Sdelphij handle_pathname(argv[0]); 456166255Sdelphij } while (*++argv); 457166255Sdelphij } 458166255Sdelphij#ifndef SMALL 459166255Sdelphij if (qflag == 0 && lflag && argc > 1) 460166255Sdelphij print_list(-1, 0, "(totals)", 0); 461166255Sdelphij#endif 462166255Sdelphij exit(exit_value); 463166255Sdelphij} 464166255Sdelphij 465166255Sdelphij/* maybe print a warning */ 466166255Sdelphijvoid 467166255Sdelphijmaybe_warn(const char *fmt, ...) 468166255Sdelphij{ 469166255Sdelphij va_list ap; 470166255Sdelphij 471166255Sdelphij if (qflag == 0) { 472166255Sdelphij va_start(ap, fmt); 473166255Sdelphij vwarn(fmt, ap); 474166255Sdelphij va_end(ap); 475166255Sdelphij } 476166255Sdelphij if (exit_value == 0) 477166255Sdelphij exit_value = 1; 478166255Sdelphij} 479166255Sdelphij 480166255Sdelphij/* ... without an errno. */ 481166255Sdelphijvoid 482166255Sdelphijmaybe_warnx(const char *fmt, ...) 483166255Sdelphij{ 484166255Sdelphij va_list ap; 485166255Sdelphij 486166255Sdelphij if (qflag == 0) { 487166255Sdelphij va_start(ap, fmt); 488166255Sdelphij vwarnx(fmt, ap); 489166255Sdelphij va_end(ap); 490166255Sdelphij } 491166255Sdelphij if (exit_value == 0) 492166255Sdelphij exit_value = 1; 493166255Sdelphij} 494166255Sdelphij 495166255Sdelphij/* maybe print an error */ 496166255Sdelphijvoid 497166255Sdelphijmaybe_err(const char *fmt, ...) 498166255Sdelphij{ 499166255Sdelphij va_list ap; 500166255Sdelphij 501166255Sdelphij if (qflag == 0) { 502166255Sdelphij va_start(ap, fmt); 503166255Sdelphij vwarn(fmt, ap); 504166255Sdelphij va_end(ap); 505166255Sdelphij } 506166255Sdelphij exit(2); 507166255Sdelphij} 508166255Sdelphij 509226184Sdelphij#if !defined(NO_BZIP2_SUPPORT) || !defined(NO_PACK_SUPPORT) || \ 510226184Sdelphij !defined(NO_XZ_SUPPORT) 511166255Sdelphij/* ... without an errno. */ 512166255Sdelphijvoid 513166255Sdelphijmaybe_errx(const char *fmt, ...) 514166255Sdelphij{ 515166255Sdelphij va_list ap; 516166255Sdelphij 517166255Sdelphij if (qflag == 0) { 518166255Sdelphij va_start(ap, fmt); 519166255Sdelphij vwarnx(fmt, ap); 520166255Sdelphij va_end(ap); 521166255Sdelphij } 522166255Sdelphij exit(2); 523166255Sdelphij} 524166255Sdelphij#endif 525166255Sdelphij 526166255Sdelphij#ifndef SMALL 527166255Sdelphij/* split up $GZIP and prepend it to the argument list */ 528166255Sdelphijstatic void 529166255Sdelphijprepend_gzip(char *gzip, int *argc, char ***argv) 530166255Sdelphij{ 531166255Sdelphij char *s, **nargv, **ac; 532166255Sdelphij int nenvarg = 0, i; 533166255Sdelphij 534166255Sdelphij /* scan how many arguments there are */ 535166255Sdelphij for (s = gzip;;) { 536166255Sdelphij while (*s == ' ' || *s == '\t') 537166255Sdelphij s++; 538166255Sdelphij if (*s == 0) 539166255Sdelphij goto count_done; 540166255Sdelphij nenvarg++; 541166255Sdelphij while (*s != ' ' && *s != '\t') 542166255Sdelphij if (*s++ == 0) 543166255Sdelphij goto count_done; 544166255Sdelphij } 545166255Sdelphijcount_done: 546166255Sdelphij /* punt early */ 547166255Sdelphij if (nenvarg == 0) 548166255Sdelphij return; 549166255Sdelphij 550166255Sdelphij *argc += nenvarg; 551166255Sdelphij ac = *argv; 552166255Sdelphij 553166255Sdelphij nargv = (char **)malloc((*argc + 1) * sizeof(char *)); 554166255Sdelphij if (nargv == NULL) 555166255Sdelphij maybe_err("malloc"); 556166255Sdelphij 557166255Sdelphij /* stash this away */ 558166255Sdelphij *argv = nargv; 559166255Sdelphij 560166255Sdelphij /* copy the program name first */ 561166255Sdelphij i = 0; 562166255Sdelphij nargv[i++] = *(ac++); 563166255Sdelphij 564166255Sdelphij /* take a copy of $GZIP and add it to the array */ 565166255Sdelphij s = strdup(gzip); 566166255Sdelphij if (s == NULL) 567166255Sdelphij maybe_err("strdup"); 568166255Sdelphij for (;;) { 569166255Sdelphij /* Skip whitespaces. */ 570166255Sdelphij while (*s == ' ' || *s == '\t') 571166255Sdelphij s++; 572166255Sdelphij if (*s == 0) 573166255Sdelphij goto copy_done; 574166255Sdelphij nargv[i++] = s; 575166255Sdelphij /* Find the end of this argument. */ 576166255Sdelphij while (*s != ' ' && *s != '\t') 577166255Sdelphij if (*s++ == 0) 578166255Sdelphij /* Argument followed by NUL. */ 579166255Sdelphij goto copy_done; 580166255Sdelphij /* Terminate by overwriting ' ' or '\t' with NUL. */ 581166255Sdelphij *s++ = 0; 582166255Sdelphij } 583166255Sdelphijcopy_done: 584166255Sdelphij 585166255Sdelphij /* copy the original arguments and a NULL */ 586166255Sdelphij while (*ac) 587166255Sdelphij nargv[i++] = *(ac++); 588166255Sdelphij nargv[i] = NULL; 589166255Sdelphij} 590166255Sdelphij#endif 591166255Sdelphij 592166255Sdelphij/* compress input to output. Return bytes read, -1 on error */ 593166255Sdelphijstatic off_t 594166255Sdelphijgz_compress(int in, int out, off_t *gsizep, const char *origname, uint32_t mtime) 595166255Sdelphij{ 596166255Sdelphij z_stream z; 597166255Sdelphij char *outbufp, *inbufp; 598166255Sdelphij off_t in_tot = 0, out_tot = 0; 599166255Sdelphij ssize_t in_size; 600166255Sdelphij int i, error; 601166255Sdelphij uLong crc; 602166255Sdelphij#ifdef SMALL 603166255Sdelphij static char header[] = { GZIP_MAGIC0, GZIP_MAGIC1, Z_DEFLATED, 0, 604166255Sdelphij 0, 0, 0, 0, 605166255Sdelphij 0, OS_CODE }; 606166255Sdelphij#endif 607166255Sdelphij 608166255Sdelphij outbufp = malloc(BUFLEN); 609166255Sdelphij inbufp = malloc(BUFLEN); 610166255Sdelphij if (outbufp == NULL || inbufp == NULL) { 611166255Sdelphij maybe_err("malloc failed"); 612166255Sdelphij goto out; 613166255Sdelphij } 614166255Sdelphij 615166255Sdelphij memset(&z, 0, sizeof z); 616166255Sdelphij z.zalloc = Z_NULL; 617166255Sdelphij z.zfree = Z_NULL; 618166255Sdelphij z.opaque = 0; 619166255Sdelphij 620166255Sdelphij#ifdef SMALL 621166255Sdelphij memcpy(outbufp, header, sizeof header); 622166255Sdelphij i = sizeof header; 623166255Sdelphij#else 624166255Sdelphij if (nflag != 0) { 625166255Sdelphij mtime = 0; 626166255Sdelphij origname = ""; 627166255Sdelphij } 628166255Sdelphij 629326559Sdelphij i = snprintf(outbufp, BUFLEN, "%c%c%c%c%c%c%c%c%c%c%s", 630166255Sdelphij GZIP_MAGIC0, GZIP_MAGIC1, Z_DEFLATED, 631166255Sdelphij *origname ? ORIG_NAME : 0, 632166255Sdelphij mtime & 0xff, 633166255Sdelphij (mtime >> 8) & 0xff, 634166255Sdelphij (mtime >> 16) & 0xff, 635166255Sdelphij (mtime >> 24) & 0xff, 636166255Sdelphij numflag == 1 ? 4 : numflag == 9 ? 2 : 0, 637166255Sdelphij OS_CODE, origname); 638326559Sdelphij if (i >= BUFLEN) 639166255Sdelphij /* this need PATH_MAX > BUFLEN ... */ 640166255Sdelphij maybe_err("snprintf"); 641166255Sdelphij if (*origname) 642166255Sdelphij i++; 643166255Sdelphij#endif 644166255Sdelphij 645166255Sdelphij z.next_out = (unsigned char *)outbufp + i; 646166255Sdelphij z.avail_out = BUFLEN - i; 647166255Sdelphij 648166255Sdelphij error = deflateInit2(&z, numflag, Z_DEFLATED, 649166255Sdelphij (-MAX_WBITS), 8, Z_DEFAULT_STRATEGY); 650166255Sdelphij if (error != Z_OK) { 651166255Sdelphij maybe_warnx("deflateInit2 failed"); 652166255Sdelphij in_tot = -1; 653166255Sdelphij goto out; 654166255Sdelphij } 655166255Sdelphij 656166255Sdelphij crc = crc32(0L, Z_NULL, 0); 657166255Sdelphij for (;;) { 658166255Sdelphij if (z.avail_out == 0) { 659326559Sdelphij if (write_retry(out, outbufp, BUFLEN) != BUFLEN) { 660166255Sdelphij maybe_warn("write"); 661166255Sdelphij out_tot = -1; 662166255Sdelphij goto out; 663166255Sdelphij } 664166255Sdelphij 665166255Sdelphij out_tot += BUFLEN; 666166255Sdelphij z.next_out = (unsigned char *)outbufp; 667166255Sdelphij z.avail_out = BUFLEN; 668166255Sdelphij } 669166255Sdelphij 670166255Sdelphij if (z.avail_in == 0) { 671166255Sdelphij in_size = read(in, inbufp, BUFLEN); 672166255Sdelphij if (in_size < 0) { 673166255Sdelphij maybe_warn("read"); 674166255Sdelphij in_tot = -1; 675166255Sdelphij goto out; 676166255Sdelphij } 677166255Sdelphij if (in_size == 0) 678166255Sdelphij break; 679326559Sdelphij infile_newdata(in_size); 680166255Sdelphij 681166255Sdelphij crc = crc32(crc, (const Bytef *)inbufp, (unsigned)in_size); 682166255Sdelphij in_tot += in_size; 683166255Sdelphij z.next_in = (unsigned char *)inbufp; 684166255Sdelphij z.avail_in = in_size; 685166255Sdelphij } 686166255Sdelphij 687166255Sdelphij error = deflate(&z, Z_NO_FLUSH); 688166255Sdelphij if (error != Z_OK && error != Z_STREAM_END) { 689166255Sdelphij maybe_warnx("deflate failed"); 690166255Sdelphij in_tot = -1; 691166255Sdelphij goto out; 692166255Sdelphij } 693166255Sdelphij } 694166255Sdelphij 695166255Sdelphij /* clean up */ 696166255Sdelphij for (;;) { 697166255Sdelphij size_t len; 698166255Sdelphij ssize_t w; 699166255Sdelphij 700166255Sdelphij error = deflate(&z, Z_FINISH); 701166255Sdelphij if (error != Z_OK && error != Z_STREAM_END) { 702166255Sdelphij maybe_warnx("deflate failed"); 703166255Sdelphij in_tot = -1; 704166255Sdelphij goto out; 705166255Sdelphij } 706166255Sdelphij 707166255Sdelphij len = (char *)z.next_out - outbufp; 708166255Sdelphij 709326559Sdelphij w = write_retry(out, outbufp, len); 710166255Sdelphij if (w == -1 || (size_t)w != len) { 711166255Sdelphij maybe_warn("write"); 712166255Sdelphij out_tot = -1; 713166255Sdelphij goto out; 714166255Sdelphij } 715166255Sdelphij out_tot += len; 716166255Sdelphij z.next_out = (unsigned char *)outbufp; 717166255Sdelphij z.avail_out = BUFLEN; 718166255Sdelphij 719166255Sdelphij if (error == Z_STREAM_END) 720166255Sdelphij break; 721166255Sdelphij } 722166255Sdelphij 723166255Sdelphij if (deflateEnd(&z) != Z_OK) { 724166255Sdelphij maybe_warnx("deflateEnd failed"); 725166255Sdelphij in_tot = -1; 726166255Sdelphij goto out; 727166255Sdelphij } 728166255Sdelphij 729326559Sdelphij i = snprintf(outbufp, BUFLEN, "%c%c%c%c%c%c%c%c", 730166255Sdelphij (int)crc & 0xff, 731166255Sdelphij (int)(crc >> 8) & 0xff, 732166255Sdelphij (int)(crc >> 16) & 0xff, 733166255Sdelphij (int)(crc >> 24) & 0xff, 734166255Sdelphij (int)in_tot & 0xff, 735166255Sdelphij (int)(in_tot >> 8) & 0xff, 736166255Sdelphij (int)(in_tot >> 16) & 0xff, 737166255Sdelphij (int)(in_tot >> 24) & 0xff); 738166255Sdelphij if (i != 8) 739166255Sdelphij maybe_err("snprintf"); 740326559Sdelphij if (write_retry(out, outbufp, i) != i) { 741166255Sdelphij maybe_warn("write"); 742166255Sdelphij in_tot = -1; 743166255Sdelphij } else 744166255Sdelphij out_tot += i; 745166255Sdelphij 746166255Sdelphijout: 747166255Sdelphij if (inbufp != NULL) 748166255Sdelphij free(inbufp); 749166255Sdelphij if (outbufp != NULL) 750166255Sdelphij free(outbufp); 751166255Sdelphij if (gsizep) 752166255Sdelphij *gsizep = out_tot; 753166255Sdelphij return in_tot; 754166255Sdelphij} 755166255Sdelphij 756166255Sdelphij/* 757166255Sdelphij * uncompress input to output then close the input. return the 758166255Sdelphij * uncompressed size written, and put the compressed sized read 759166255Sdelphij * into `*gsizep'. 760166255Sdelphij */ 761166255Sdelphijstatic off_t 762166255Sdelphijgz_uncompress(int in, int out, char *pre, size_t prelen, off_t *gsizep, 763166255Sdelphij const char *filename) 764166255Sdelphij{ 765166255Sdelphij z_stream z; 766166255Sdelphij char *outbufp, *inbufp; 767166255Sdelphij off_t out_tot = -1, in_tot = 0; 768166255Sdelphij uint32_t out_sub_tot = 0; 769166255Sdelphij enum { 770166255Sdelphij GZSTATE_MAGIC0, 771166255Sdelphij GZSTATE_MAGIC1, 772166255Sdelphij GZSTATE_METHOD, 773166255Sdelphij GZSTATE_FLAGS, 774166255Sdelphij GZSTATE_SKIPPING, 775166255Sdelphij GZSTATE_EXTRA, 776166255Sdelphij GZSTATE_EXTRA2, 777166255Sdelphij GZSTATE_EXTRA3, 778166255Sdelphij GZSTATE_ORIGNAME, 779166255Sdelphij GZSTATE_COMMENT, 780166255Sdelphij GZSTATE_HEAD_CRC1, 781166255Sdelphij GZSTATE_HEAD_CRC2, 782166255Sdelphij GZSTATE_INIT, 783166255Sdelphij GZSTATE_READ, 784166255Sdelphij GZSTATE_CRC, 785166255Sdelphij GZSTATE_LEN, 786166255Sdelphij } state = GZSTATE_MAGIC0; 787166255Sdelphij int flags = 0, skip_count = 0; 788166255Sdelphij int error = Z_STREAM_ERROR, done_reading = 0; 789166255Sdelphij uLong crc = 0; 790166255Sdelphij ssize_t wr; 791166255Sdelphij int needmore = 0; 792166255Sdelphij 793166255Sdelphij#define ADVANCE() { z.next_in++; z.avail_in--; } 794166255Sdelphij 795166255Sdelphij if ((outbufp = malloc(BUFLEN)) == NULL) { 796166255Sdelphij maybe_err("malloc failed"); 797166255Sdelphij goto out2; 798166255Sdelphij } 799166255Sdelphij if ((inbufp = malloc(BUFLEN)) == NULL) { 800166255Sdelphij maybe_err("malloc failed"); 801166255Sdelphij goto out1; 802166255Sdelphij } 803166255Sdelphij 804166255Sdelphij memset(&z, 0, sizeof z); 805166255Sdelphij z.avail_in = prelen; 806166255Sdelphij z.next_in = (unsigned char *)pre; 807166255Sdelphij z.avail_out = BUFLEN; 808166255Sdelphij z.next_out = (unsigned char *)outbufp; 809166255Sdelphij z.zalloc = NULL; 810166255Sdelphij z.zfree = NULL; 811166255Sdelphij z.opaque = 0; 812166255Sdelphij 813166255Sdelphij in_tot = prelen; 814166255Sdelphij out_tot = 0; 815166255Sdelphij 816166255Sdelphij for (;;) { 817326559Sdelphij check_siginfo(); 818166255Sdelphij if ((z.avail_in == 0 || needmore) && done_reading == 0) { 819166255Sdelphij ssize_t in_size; 820166255Sdelphij 821166255Sdelphij if (z.avail_in > 0) { 822166255Sdelphij memmove(inbufp, z.next_in, z.avail_in); 823166255Sdelphij } 824166255Sdelphij z.next_in = (unsigned char *)inbufp; 825166255Sdelphij in_size = read(in, z.next_in + z.avail_in, 826166255Sdelphij BUFLEN - z.avail_in); 827166255Sdelphij 828166255Sdelphij if (in_size == -1) { 829166255Sdelphij maybe_warn("failed to read stdin"); 830166255Sdelphij goto stop_and_fail; 831166255Sdelphij } else if (in_size == 0) { 832166255Sdelphij done_reading = 1; 833166255Sdelphij } 834326559Sdelphij infile_newdata(in_size); 835166255Sdelphij 836166255Sdelphij z.avail_in += in_size; 837166255Sdelphij needmore = 0; 838166255Sdelphij 839166255Sdelphij in_tot += in_size; 840166255Sdelphij } 841166255Sdelphij if (z.avail_in == 0) { 842166255Sdelphij if (done_reading && state != GZSTATE_MAGIC0) { 843166255Sdelphij maybe_warnx("%s: unexpected end of file", 844166255Sdelphij filename); 845166255Sdelphij goto stop_and_fail; 846166255Sdelphij } 847166255Sdelphij goto stop; 848166255Sdelphij } 849166255Sdelphij switch (state) { 850166255Sdelphij case GZSTATE_MAGIC0: 851166255Sdelphij if (*z.next_in != GZIP_MAGIC0) { 852166255Sdelphij if (in_tot > 0) { 853166255Sdelphij maybe_warnx("%s: trailing garbage " 854166255Sdelphij "ignored", filename); 855290024Sdelphij exit_value = 2; 856166255Sdelphij goto stop; 857166255Sdelphij } 858166255Sdelphij maybe_warnx("input not gziped (MAGIC0)"); 859166255Sdelphij goto stop_and_fail; 860166255Sdelphij } 861166255Sdelphij ADVANCE(); 862166255Sdelphij state++; 863166255Sdelphij out_sub_tot = 0; 864166255Sdelphij crc = crc32(0L, Z_NULL, 0); 865166255Sdelphij break; 866166255Sdelphij 867166255Sdelphij case GZSTATE_MAGIC1: 868166255Sdelphij if (*z.next_in != GZIP_MAGIC1 && 869166255Sdelphij *z.next_in != GZIP_OMAGIC1) { 870166255Sdelphij maybe_warnx("input not gziped (MAGIC1)"); 871166255Sdelphij goto stop_and_fail; 872166255Sdelphij } 873166255Sdelphij ADVANCE(); 874166255Sdelphij state++; 875166255Sdelphij break; 876166255Sdelphij 877166255Sdelphij case GZSTATE_METHOD: 878166255Sdelphij if (*z.next_in != Z_DEFLATED) { 879166255Sdelphij maybe_warnx("unknown compression method"); 880166255Sdelphij goto stop_and_fail; 881166255Sdelphij } 882166255Sdelphij ADVANCE(); 883166255Sdelphij state++; 884166255Sdelphij break; 885166255Sdelphij 886166255Sdelphij case GZSTATE_FLAGS: 887166255Sdelphij flags = *z.next_in; 888166255Sdelphij ADVANCE(); 889166255Sdelphij skip_count = 6; 890166255Sdelphij state++; 891166255Sdelphij break; 892166255Sdelphij 893166255Sdelphij case GZSTATE_SKIPPING: 894166255Sdelphij if (skip_count > 0) { 895166255Sdelphij skip_count--; 896166255Sdelphij ADVANCE(); 897166255Sdelphij } else 898166255Sdelphij state++; 899166255Sdelphij break; 900166255Sdelphij 901166255Sdelphij case GZSTATE_EXTRA: 902166255Sdelphij if ((flags & EXTRA_FIELD) == 0) { 903166255Sdelphij state = GZSTATE_ORIGNAME; 904166255Sdelphij break; 905166255Sdelphij } 906166255Sdelphij skip_count = *z.next_in; 907166255Sdelphij ADVANCE(); 908166255Sdelphij state++; 909166255Sdelphij break; 910166255Sdelphij 911166255Sdelphij case GZSTATE_EXTRA2: 912166255Sdelphij skip_count |= ((*z.next_in) << 8); 913166255Sdelphij ADVANCE(); 914166255Sdelphij state++; 915166255Sdelphij break; 916166255Sdelphij 917166255Sdelphij case GZSTATE_EXTRA3: 918166255Sdelphij if (skip_count > 0) { 919166255Sdelphij skip_count--; 920166255Sdelphij ADVANCE(); 921166255Sdelphij } else 922166255Sdelphij state++; 923166255Sdelphij break; 924166255Sdelphij 925166255Sdelphij case GZSTATE_ORIGNAME: 926166255Sdelphij if ((flags & ORIG_NAME) == 0) { 927166255Sdelphij state++; 928166255Sdelphij break; 929166255Sdelphij } 930166255Sdelphij if (*z.next_in == 0) 931166255Sdelphij state++; 932166255Sdelphij ADVANCE(); 933166255Sdelphij break; 934166255Sdelphij 935166255Sdelphij case GZSTATE_COMMENT: 936166255Sdelphij if ((flags & COMMENT) == 0) { 937166255Sdelphij state++; 938166255Sdelphij break; 939166255Sdelphij } 940166255Sdelphij if (*z.next_in == 0) 941166255Sdelphij state++; 942166255Sdelphij ADVANCE(); 943166255Sdelphij break; 944166255Sdelphij 945166255Sdelphij case GZSTATE_HEAD_CRC1: 946166255Sdelphij if (flags & HEAD_CRC) 947166255Sdelphij skip_count = 2; 948166255Sdelphij else 949166255Sdelphij skip_count = 0; 950166255Sdelphij state++; 951166255Sdelphij break; 952166255Sdelphij 953166255Sdelphij case GZSTATE_HEAD_CRC2: 954166255Sdelphij if (skip_count > 0) { 955166255Sdelphij skip_count--; 956166255Sdelphij ADVANCE(); 957166255Sdelphij } else 958166255Sdelphij state++; 959166255Sdelphij break; 960166255Sdelphij 961166255Sdelphij case GZSTATE_INIT: 962166255Sdelphij if (inflateInit2(&z, -MAX_WBITS) != Z_OK) { 963166255Sdelphij maybe_warnx("failed to inflateInit"); 964166255Sdelphij goto stop_and_fail; 965166255Sdelphij } 966166255Sdelphij state++; 967166255Sdelphij break; 968166255Sdelphij 969166255Sdelphij case GZSTATE_READ: 970166255Sdelphij error = inflate(&z, Z_FINISH); 971166255Sdelphij switch (error) { 972166255Sdelphij /* Z_BUF_ERROR goes with Z_FINISH... */ 973166255Sdelphij case Z_BUF_ERROR: 974213044Sdelphij if (z.avail_out > 0 && !done_reading) 975213044Sdelphij continue; 976222210Sdelphij 977166255Sdelphij case Z_STREAM_END: 978166255Sdelphij case Z_OK: 979166255Sdelphij break; 980166255Sdelphij 981166255Sdelphij case Z_NEED_DICT: 982166255Sdelphij maybe_warnx("Z_NEED_DICT error"); 983166255Sdelphij goto stop_and_fail; 984166255Sdelphij case Z_DATA_ERROR: 985166255Sdelphij maybe_warnx("data stream error"); 986166255Sdelphij goto stop_and_fail; 987166255Sdelphij case Z_STREAM_ERROR: 988166255Sdelphij maybe_warnx("internal stream error"); 989166255Sdelphij goto stop_and_fail; 990166255Sdelphij case Z_MEM_ERROR: 991166255Sdelphij maybe_warnx("memory allocation error"); 992166255Sdelphij goto stop_and_fail; 993166255Sdelphij 994166255Sdelphij default: 995166255Sdelphij maybe_warn("unknown error from inflate(): %d", 996166255Sdelphij error); 997166255Sdelphij } 998166255Sdelphij wr = BUFLEN - z.avail_out; 999166255Sdelphij 1000166255Sdelphij if (wr != 0) { 1001166255Sdelphij crc = crc32(crc, (const Bytef *)outbufp, (unsigned)wr); 1002166255Sdelphij if ( 1003166255Sdelphij#ifndef SMALL 1004166255Sdelphij /* don't write anything with -t */ 1005166255Sdelphij tflag == 0 && 1006166255Sdelphij#endif 1007326559Sdelphij write_retry(out, outbufp, wr) != wr) { 1008166255Sdelphij maybe_warn("error writing to output"); 1009166255Sdelphij goto stop_and_fail; 1010166255Sdelphij } 1011166255Sdelphij 1012166255Sdelphij out_tot += wr; 1013166255Sdelphij out_sub_tot += wr; 1014166255Sdelphij } 1015166255Sdelphij 1016166255Sdelphij if (error == Z_STREAM_END) { 1017166255Sdelphij inflateEnd(&z); 1018166255Sdelphij state++; 1019166255Sdelphij } 1020166255Sdelphij 1021166255Sdelphij z.next_out = (unsigned char *)outbufp; 1022166255Sdelphij z.avail_out = BUFLEN; 1023166255Sdelphij 1024166255Sdelphij break; 1025166255Sdelphij case GZSTATE_CRC: 1026166255Sdelphij { 1027166255Sdelphij uLong origcrc; 1028166255Sdelphij 1029166255Sdelphij if (z.avail_in < 4) { 1030166255Sdelphij if (!done_reading) { 1031166255Sdelphij needmore = 1; 1032166255Sdelphij continue; 1033166255Sdelphij } 1034166255Sdelphij maybe_warnx("truncated input"); 1035166255Sdelphij goto stop_and_fail; 1036166255Sdelphij } 1037336661Sdelphij origcrc = le32dec(&z.next_in[0]); 1038166255Sdelphij if (origcrc != crc) { 1039166255Sdelphij maybe_warnx("invalid compressed" 1040166255Sdelphij " data--crc error"); 1041166255Sdelphij goto stop_and_fail; 1042166255Sdelphij } 1043166255Sdelphij } 1044166255Sdelphij 1045166255Sdelphij z.avail_in -= 4; 1046166255Sdelphij z.next_in += 4; 1047166255Sdelphij 1048166255Sdelphij if (!z.avail_in && done_reading) { 1049166255Sdelphij goto stop; 1050166255Sdelphij } 1051166255Sdelphij state++; 1052166255Sdelphij break; 1053166255Sdelphij case GZSTATE_LEN: 1054166255Sdelphij { 1055166255Sdelphij uLong origlen; 1056166255Sdelphij 1057166255Sdelphij if (z.avail_in < 4) { 1058166255Sdelphij if (!done_reading) { 1059166255Sdelphij needmore = 1; 1060166255Sdelphij continue; 1061166255Sdelphij } 1062166255Sdelphij maybe_warnx("truncated input"); 1063166255Sdelphij goto stop_and_fail; 1064166255Sdelphij } 1065336661Sdelphij origlen = le32dec(&z.next_in[0]); 1066166255Sdelphij 1067166255Sdelphij if (origlen != out_sub_tot) { 1068166255Sdelphij maybe_warnx("invalid compressed" 1069166255Sdelphij " data--length error"); 1070166255Sdelphij goto stop_and_fail; 1071166255Sdelphij } 1072166255Sdelphij } 1073166255Sdelphij 1074166255Sdelphij z.avail_in -= 4; 1075166255Sdelphij z.next_in += 4; 1076166255Sdelphij 1077166255Sdelphij if (error < 0) { 1078166255Sdelphij maybe_warnx("decompression error"); 1079166255Sdelphij goto stop_and_fail; 1080166255Sdelphij } 1081166255Sdelphij state = GZSTATE_MAGIC0; 1082166255Sdelphij break; 1083166255Sdelphij } 1084166255Sdelphij continue; 1085166255Sdelphijstop_and_fail: 1086166255Sdelphij out_tot = -1; 1087166255Sdelphijstop: 1088166255Sdelphij break; 1089166255Sdelphij } 1090166255Sdelphij if (state > GZSTATE_INIT) 1091166255Sdelphij inflateEnd(&z); 1092166255Sdelphij 1093166255Sdelphij free(inbufp); 1094166255Sdelphijout1: 1095166255Sdelphij free(outbufp); 1096166255Sdelphijout2: 1097166255Sdelphij if (gsizep) 1098166255Sdelphij *gsizep = in_tot; 1099166255Sdelphij return (out_tot); 1100166255Sdelphij} 1101166255Sdelphij 1102166255Sdelphij#ifndef SMALL 1103166255Sdelphij/* 1104166255Sdelphij * set the owner, mode, flags & utimes using the given file descriptor. 1105166255Sdelphij * file is only used in possible warning messages. 1106166255Sdelphij */ 1107166255Sdelphijstatic void 1108166255Sdelphijcopymodes(int fd, const struct stat *sbp, const char *file) 1109166255Sdelphij{ 1110278896Sjilles struct timespec times[2]; 1111166255Sdelphij struct stat sb; 1112166255Sdelphij 1113166255Sdelphij /* 1114166255Sdelphij * If we have no info on the input, give this file some 1115166255Sdelphij * default values and return.. 1116166255Sdelphij */ 1117166255Sdelphij if (sbp == NULL) { 1118166255Sdelphij mode_t mask = umask(022); 1119166255Sdelphij 1120166255Sdelphij (void)fchmod(fd, DEFFILEMODE & ~mask); 1121166255Sdelphij (void)umask(mask); 1122326559Sdelphij return; 1123166255Sdelphij } 1124166255Sdelphij sb = *sbp; 1125166255Sdelphij 1126166255Sdelphij /* if the chown fails, remove set-id bits as-per compress(1) */ 1127166255Sdelphij if (fchown(fd, sb.st_uid, sb.st_gid) < 0) { 1128166255Sdelphij if (errno != EPERM) 1129166255Sdelphij maybe_warn("couldn't fchown: %s", file); 1130166255Sdelphij sb.st_mode &= ~(S_ISUID|S_ISGID); 1131166255Sdelphij } 1132166255Sdelphij 1133166255Sdelphij /* we only allow set-id and the 9 normal permission bits */ 1134166255Sdelphij sb.st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO; 1135166255Sdelphij if (fchmod(fd, sb.st_mode) < 0) 1136166255Sdelphij maybe_warn("couldn't fchmod: %s", file); 1137166255Sdelphij 1138278896Sjilles times[0] = sb.st_atim; 1139278896Sjilles times[1] = sb.st_mtim; 1140278896Sjilles if (futimens(fd, times) < 0) 1141278896Sjilles maybe_warn("couldn't futimens: %s", file); 1142176970Srwatson 1143176970Srwatson /* only try flags if they exist already */ 1144176970Srwatson if (sb.st_flags != 0 && fchflags(fd, sb.st_flags) < 0) 1145176970Srwatson maybe_warn("couldn't fchflags: %s", file); 1146166255Sdelphij} 1147166255Sdelphij#endif 1148166255Sdelphij 1149166255Sdelphij/* what sort of file is this? */ 1150166255Sdelphijstatic enum filetype 1151166255Sdelphijfile_gettype(u_char *buf) 1152166255Sdelphij{ 1153166255Sdelphij 1154166255Sdelphij if (buf[0] == GZIP_MAGIC0 && 1155166255Sdelphij (buf[1] == GZIP_MAGIC1 || buf[1] == GZIP_OMAGIC1)) 1156166255Sdelphij return FT_GZIP; 1157166255Sdelphij else 1158166255Sdelphij#ifndef NO_BZIP2_SUPPORT 1159166255Sdelphij if (memcmp(buf, BZIP2_MAGIC, 3) == 0 && 1160166255Sdelphij buf[3] >= '0' && buf[3] <= '9') 1161166255Sdelphij return FT_BZIP2; 1162166255Sdelphij else 1163166255Sdelphij#endif 1164166255Sdelphij#ifndef NO_COMPRESS_SUPPORT 1165166255Sdelphij if (memcmp(buf, Z_MAGIC, 2) == 0) 1166166255Sdelphij return FT_Z; 1167166255Sdelphij else 1168166255Sdelphij#endif 1169194579Sdelphij#ifndef NO_PACK_SUPPORT 1170194579Sdelphij if (memcmp(buf, PACK_MAGIC, 2) == 0) 1171194579Sdelphij return FT_PACK; 1172194579Sdelphij else 1173194579Sdelphij#endif 1174226184Sdelphij#ifndef NO_XZ_SUPPORT 1175226184Sdelphij if (memcmp(buf, XZ_MAGIC, 4) == 0) /* XXX: We only have 4 bytes */ 1176226184Sdelphij return FT_XZ; 1177226184Sdelphij else 1178226184Sdelphij#endif 1179343251Sdelphij#ifndef NO_LZ_SUPPORT 1180343251Sdelphij if (memcmp(buf, LZ_MAGIC, 4) == 0) 1181343251Sdelphij return FT_LZ; 1182343251Sdelphij else 1183343251Sdelphij#endif 1184166255Sdelphij return FT_UNKNOWN; 1185166255Sdelphij} 1186166255Sdelphij 1187166255Sdelphij#ifndef SMALL 1188166255Sdelphij/* check the outfile is OK. */ 1189166255Sdelphijstatic int 1190166255Sdelphijcheck_outfile(const char *outfile) 1191166255Sdelphij{ 1192166255Sdelphij struct stat sb; 1193166255Sdelphij int ok = 1; 1194166255Sdelphij 1195166255Sdelphij if (lflag == 0 && stat(outfile, &sb) == 0) { 1196166255Sdelphij if (fflag) 1197166255Sdelphij unlink(outfile); 1198166255Sdelphij else if (isatty(STDIN_FILENO)) { 1199166255Sdelphij char ans[10] = { 'n', '\0' }; /* default */ 1200166255Sdelphij 1201166255Sdelphij fprintf(stderr, "%s already exists -- do you wish to " 1202166255Sdelphij "overwrite (y or n)? " , outfile); 1203166255Sdelphij (void)fgets(ans, sizeof(ans) - 1, stdin); 1204166255Sdelphij if (ans[0] != 'y' && ans[0] != 'Y') { 1205166363Sdelphij fprintf(stderr, "\tnot overwriting\n"); 1206166255Sdelphij ok = 0; 1207166255Sdelphij } else 1208166255Sdelphij unlink(outfile); 1209166255Sdelphij } else { 1210166255Sdelphij maybe_warnx("%s already exists -- skipping", outfile); 1211166255Sdelphij ok = 0; 1212166255Sdelphij } 1213166255Sdelphij } 1214166255Sdelphij return ok; 1215166255Sdelphij} 1216166255Sdelphij 1217166255Sdelphijstatic void 1218166255Sdelphijunlink_input(const char *file, const struct stat *sb) 1219166255Sdelphij{ 1220166255Sdelphij struct stat nsb; 1221166255Sdelphij 1222170053Sdelphij if (kflag) 1223170053Sdelphij return; 1224166255Sdelphij if (stat(file, &nsb) != 0) 1225213927Sbcr /* Must be gone already */ 1226166255Sdelphij return; 1227166255Sdelphij if (nsb.st_dev != sb->st_dev || nsb.st_ino != sb->st_ino) 1228166255Sdelphij /* Definitely a different file */ 1229166255Sdelphij return; 1230166255Sdelphij unlink(file); 1231166255Sdelphij} 1232207247Sdelphij 1233207247Sdelphijstatic void 1234326559Sdelphijgot_sigint(int signo __unused) 1235207247Sdelphij{ 1236207247Sdelphij 1237207247Sdelphij if (remove_file != NULL) 1238207247Sdelphij unlink(remove_file); 1239207284Sdelphij _exit(2); 1240207247Sdelphij} 1241326559Sdelphij 1242326559Sdelphijstatic void 1243326559Sdelphijgot_siginfo(int signo __unused) 1244326559Sdelphij{ 1245326559Sdelphij 1246326559Sdelphij print_info = 1; 1247326559Sdelphij} 1248326559Sdelphij 1249326559Sdelphijstatic void 1250326559Sdelphijsetup_signals(void) 1251326559Sdelphij{ 1252326559Sdelphij 1253326559Sdelphij signal(SIGINFO, got_siginfo); 1254326559Sdelphij signal(SIGINT, got_sigint); 1255326559Sdelphij} 1256326559Sdelphij 1257326559Sdelphijstatic void 1258326559Sdelphijinfile_newdata(size_t newdata) 1259326559Sdelphij{ 1260326559Sdelphij 1261326559Sdelphij infile_current += newdata; 1262326559Sdelphij} 1263166255Sdelphij#endif 1264166255Sdelphij 1265326559Sdelphijstatic void 1266326559Sdelphijinfile_set(const char *newinfile, off_t total) 1267326559Sdelphij{ 1268326559Sdelphij 1269326559Sdelphij if (newinfile) 1270326559Sdelphij infile = newinfile; 1271326559Sdelphij#ifndef SMALL 1272326559Sdelphij infile_total = total; 1273326559Sdelphij#endif 1274326559Sdelphij} 1275326559Sdelphij 1276326559Sdelphijstatic void 1277326559Sdelphijinfile_clear(void) 1278326559Sdelphij{ 1279326559Sdelphij 1280326559Sdelphij infile = NULL; 1281326559Sdelphij#ifndef SMALL 1282326559Sdelphij infile_total = infile_current = 0; 1283326559Sdelphij#endif 1284326559Sdelphij} 1285326559Sdelphij 1286166255Sdelphijstatic const suffixes_t * 1287166255Sdelphijcheck_suffix(char *file, int xlate) 1288166255Sdelphij{ 1289166255Sdelphij const suffixes_t *s; 1290166255Sdelphij int len = strlen(file); 1291166255Sdelphij char *sp; 1292166255Sdelphij 1293166255Sdelphij for (s = suffixes; s != suffixes + NUM_SUFFIXES; s++) { 1294166255Sdelphij /* if it doesn't fit in "a.suf", don't bother */ 1295166255Sdelphij if (s->ziplen >= len) 1296166255Sdelphij continue; 1297166255Sdelphij sp = file + len - s->ziplen; 1298166255Sdelphij if (strcmp(s->zipped, sp) != 0) 1299166255Sdelphij continue; 1300166255Sdelphij if (xlate) 1301166255Sdelphij strcpy(sp, s->normal); 1302166255Sdelphij return s; 1303166255Sdelphij } 1304166255Sdelphij return NULL; 1305166255Sdelphij} 1306166255Sdelphij 1307166255Sdelphij/* 1308166255Sdelphij * compress the given file: create a corresponding .gz file and remove the 1309166255Sdelphij * original. 1310166255Sdelphij */ 1311166255Sdelphijstatic off_t 1312166255Sdelphijfile_compress(char *file, char *outfile, size_t outsize) 1313166255Sdelphij{ 1314166255Sdelphij int in; 1315166255Sdelphij int out; 1316326559Sdelphij off_t size, in_size; 1317166255Sdelphij#ifndef SMALL 1318166255Sdelphij struct stat isb, osb; 1319166255Sdelphij const suffixes_t *suff; 1320166255Sdelphij#endif 1321166255Sdelphij 1322166255Sdelphij in = open(file, O_RDONLY); 1323166255Sdelphij if (in == -1) { 1324166255Sdelphij maybe_warn("can't open %s", file); 1325209017Sdelphij return (-1); 1326166255Sdelphij } 1327166255Sdelphij 1328208888Sdelphij#ifndef SMALL 1329208888Sdelphij if (fstat(in, &isb) != 0) { 1330208888Sdelphij maybe_warn("couldn't stat: %s", file); 1331208888Sdelphij close(in); 1332209017Sdelphij return (-1); 1333208888Sdelphij } 1334208888Sdelphij#endif 1335208888Sdelphij 1336326559Sdelphij#ifndef SMALL 1337326559Sdelphij if (fstat(in, &isb) != 0) { 1338326559Sdelphij close(in); 1339326559Sdelphij maybe_warn("can't stat %s", file); 1340326559Sdelphij return -1; 1341326559Sdelphij } 1342326559Sdelphij infile_set(file, isb.st_size); 1343326559Sdelphij#endif 1344326559Sdelphij 1345166255Sdelphij if (cflag == 0) { 1346166255Sdelphij#ifndef SMALL 1347209017Sdelphij if (isb.st_nlink > 1 && fflag == 0) { 1348326559Sdelphij maybe_warnx("%s has %ju other link%s -- " 1349326559Sdelphij "skipping", file, 1350326559Sdelphij (uintmax_t)isb.st_nlink - 1, 1351326559Sdelphij isb.st_nlink == 1 ? "" : "s"); 1352208889Sdelphij close(in); 1353326559Sdelphij return -1; 1354208889Sdelphij } 1355166255Sdelphij 1356209017Sdelphij if (fflag == 0 && (suff = check_suffix(file, 0)) && 1357209017Sdelphij suff->zipped[0] != 0) { 1358166255Sdelphij maybe_warnx("%s already has %s suffix -- unchanged", 1359209017Sdelphij file, suff->zipped); 1360166255Sdelphij close(in); 1361209017Sdelphij return (-1); 1362166255Sdelphij } 1363166255Sdelphij#endif 1364166255Sdelphij 1365166255Sdelphij /* Add (usually) .gz to filename */ 1366166255Sdelphij if ((size_t)snprintf(outfile, outsize, "%s%s", 1367209017Sdelphij file, suffixes[0].zipped) >= outsize) 1368195988Sdelphij memcpy(outfile + outsize - suffixes[0].ziplen - 1, 1369209017Sdelphij suffixes[0].zipped, suffixes[0].ziplen + 1); 1370166255Sdelphij 1371166255Sdelphij#ifndef SMALL 1372166255Sdelphij if (check_outfile(outfile) == 0) { 1373166255Sdelphij close(in); 1374209017Sdelphij return (-1); 1375166255Sdelphij } 1376166255Sdelphij#endif 1377166255Sdelphij } 1378166255Sdelphij 1379166255Sdelphij if (cflag == 0) { 1380166255Sdelphij out = open(outfile, O_WRONLY | O_CREAT | O_EXCL, 0600); 1381166255Sdelphij if (out == -1) { 1382166255Sdelphij maybe_warn("could not create output: %s", outfile); 1383166255Sdelphij fclose(stdin); 1384209017Sdelphij return (-1); 1385166255Sdelphij } 1386207247Sdelphij#ifndef SMALL 1387207247Sdelphij remove_file = outfile; 1388207247Sdelphij#endif 1389166255Sdelphij } else 1390166255Sdelphij out = STDOUT_FILENO; 1391166255Sdelphij 1392326559Sdelphij in_size = gz_compress(in, out, &size, basename(file), (uint32_t)isb.st_mtime); 1393166255Sdelphij 1394166255Sdelphij (void)close(in); 1395166255Sdelphij 1396166255Sdelphij /* 1397326559Sdelphij * If there was an error, in_size will be -1. 1398166255Sdelphij * If we compressed to stdout, just return the size. 1399166255Sdelphij * Otherwise stat the file and check it is the correct size. 1400166255Sdelphij * We only blow away the file if we can stat the output and it 1401166255Sdelphij * has the expected size. 1402166255Sdelphij */ 1403166255Sdelphij if (cflag != 0) 1404326559Sdelphij return in_size == -1 ? -1 : size; 1405166255Sdelphij 1406166255Sdelphij#ifndef SMALL 1407166255Sdelphij if (fstat(out, &osb) != 0) { 1408166255Sdelphij maybe_warn("couldn't stat: %s", outfile); 1409166255Sdelphij goto bad_outfile; 1410166255Sdelphij } 1411166255Sdelphij 1412166255Sdelphij if (osb.st_size != size) { 1413209017Sdelphij maybe_warnx("output file: %s wrong size (%ju != %ju), deleting", 1414209017Sdelphij outfile, (uintmax_t)osb.st_size, (uintmax_t)size); 1415166255Sdelphij goto bad_outfile; 1416166255Sdelphij } 1417166255Sdelphij 1418166255Sdelphij copymodes(out, &isb, outfile); 1419207247Sdelphij remove_file = NULL; 1420166255Sdelphij#endif 1421166255Sdelphij if (close(out) == -1) 1422166255Sdelphij maybe_warn("couldn't close output"); 1423166255Sdelphij 1424166255Sdelphij /* output is good, ok to delete input */ 1425166255Sdelphij unlink_input(file, &isb); 1426209017Sdelphij return (size); 1427166255Sdelphij 1428166255Sdelphij#ifndef SMALL 1429166255Sdelphij bad_outfile: 1430166255Sdelphij if (close(out) == -1) 1431166255Sdelphij maybe_warn("couldn't close output"); 1432166255Sdelphij 1433166255Sdelphij maybe_warnx("leaving original %s", file); 1434166255Sdelphij unlink(outfile); 1435209017Sdelphij return (size); 1436166255Sdelphij#endif 1437166255Sdelphij} 1438166255Sdelphij 1439166255Sdelphij/* uncompress the given file and remove the original */ 1440166255Sdelphijstatic off_t 1441166255Sdelphijfile_uncompress(char *file, char *outfile, size_t outsize) 1442166255Sdelphij{ 1443166255Sdelphij struct stat isb, osb; 1444166255Sdelphij off_t size; 1445166255Sdelphij ssize_t rbytes; 1446166255Sdelphij unsigned char header1[4]; 1447166255Sdelphij enum filetype method; 1448194508Sdelphij int fd, ofd, zfd = -1; 1449337521Sdelphij int error; 1450326559Sdelphij size_t in_size; 1451166255Sdelphij#ifndef SMALL 1452206387Sdelphij ssize_t rv; 1453166255Sdelphij time_t timestamp = 0; 1454281500Sdelphij char name[PATH_MAX + 1]; 1455166255Sdelphij#endif 1456166255Sdelphij 1457166255Sdelphij /* gather the old name info */ 1458166255Sdelphij 1459166255Sdelphij fd = open(file, O_RDONLY); 1460166255Sdelphij if (fd < 0) { 1461166255Sdelphij maybe_warn("can't open %s", file); 1462166255Sdelphij goto lose; 1463166255Sdelphij } 1464326559Sdelphij if (fstat(fd, &isb) != 0) { 1465326559Sdelphij close(fd); 1466326559Sdelphij maybe_warn("can't stat %s", file); 1467326559Sdelphij goto lose; 1468326559Sdelphij } 1469326559Sdelphij if (S_ISREG(isb.st_mode)) 1470326559Sdelphij in_size = isb.st_size; 1471326559Sdelphij else 1472326559Sdelphij in_size = 0; 1473326559Sdelphij infile_set(file, in_size); 1474166255Sdelphij 1475166255Sdelphij strlcpy(outfile, file, outsize); 1476166255Sdelphij if (check_suffix(outfile, 1) == NULL && !(cflag || lflag)) { 1477166255Sdelphij maybe_warnx("%s: unknown suffix -- ignored", file); 1478166255Sdelphij goto lose; 1479166255Sdelphij } 1480166255Sdelphij 1481166255Sdelphij rbytes = read(fd, header1, sizeof header1); 1482166255Sdelphij if (rbytes != sizeof header1) { 1483166255Sdelphij /* we don't want to fail here. */ 1484166255Sdelphij#ifndef SMALL 1485166255Sdelphij if (fflag) 1486166255Sdelphij goto lose; 1487166255Sdelphij#endif 1488166255Sdelphij if (rbytes == -1) 1489166255Sdelphij maybe_warn("can't read %s", file); 1490166255Sdelphij else 1491166255Sdelphij goto unexpected_EOF; 1492166255Sdelphij goto lose; 1493166255Sdelphij } 1494326559Sdelphij infile_newdata(rbytes); 1495166255Sdelphij 1496166255Sdelphij method = file_gettype(header1); 1497166255Sdelphij#ifndef SMALL 1498166255Sdelphij if (fflag == 0 && method == FT_UNKNOWN) { 1499166255Sdelphij maybe_warnx("%s: not in gzip format", file); 1500166255Sdelphij goto lose; 1501166255Sdelphij } 1502166255Sdelphij 1503166255Sdelphij#endif 1504166255Sdelphij 1505166255Sdelphij#ifndef SMALL 1506166255Sdelphij if (method == FT_GZIP && Nflag) { 1507166255Sdelphij unsigned char ts[4]; /* timestamp */ 1508166255Sdelphij 1509166255Sdelphij rv = pread(fd, ts, sizeof ts, GZIP_TIMESTAMP); 1510194916Sdelphij if (rv >= 0 && rv < (ssize_t)(sizeof ts)) 1511166255Sdelphij goto unexpected_EOF; 1512166255Sdelphij if (rv == -1) { 1513166255Sdelphij if (!fflag) 1514166255Sdelphij maybe_warn("can't read %s", file); 1515166255Sdelphij goto lose; 1516166255Sdelphij } 1517326559Sdelphij infile_newdata(rv); 1518336661Sdelphij timestamp = le32dec(&ts[0]); 1519166255Sdelphij 1520166255Sdelphij if (header1[3] & ORIG_NAME) { 1521281540Sdelphij rbytes = pread(fd, name, sizeof(name) - 1, GZIP_ORIGNAME); 1522166255Sdelphij if (rbytes < 0) { 1523166255Sdelphij maybe_warn("can't read %s", file); 1524166255Sdelphij goto lose; 1525166255Sdelphij } 1526281540Sdelphij if (name[0] != '\0') { 1527281500Sdelphij char *dp, *nf; 1528281500Sdelphij 1529281540Sdelphij /* Make sure that name is NUL-terminated */ 1530281540Sdelphij name[rbytes] = '\0'; 1531281540Sdelphij 1532281500Sdelphij /* strip saved directory name */ 1533281500Sdelphij nf = strrchr(name, '/'); 1534281500Sdelphij if (nf == NULL) 1535281500Sdelphij nf = name; 1536281500Sdelphij else 1537281500Sdelphij nf++; 1538281500Sdelphij 1539166255Sdelphij /* preserve original directory name */ 1540281500Sdelphij dp = strrchr(file, '/'); 1541166255Sdelphij if (dp == NULL) 1542166255Sdelphij dp = file; 1543166255Sdelphij else 1544166255Sdelphij dp++; 1545166255Sdelphij snprintf(outfile, outsize, "%.*s%.*s", 1546326559Sdelphij (int) (dp - file), 1547281500Sdelphij file, (int) rbytes, nf); 1548166255Sdelphij } 1549166255Sdelphij } 1550166255Sdelphij } 1551166255Sdelphij#endif 1552166255Sdelphij lseek(fd, 0, SEEK_SET); 1553166255Sdelphij 1554166255Sdelphij if (cflag == 0 || lflag) { 1555166255Sdelphij#ifndef SMALL 1556166255Sdelphij if (isb.st_nlink > 1 && lflag == 0 && fflag == 0) { 1557312072Skib maybe_warnx("%s has %ju other links -- skipping", 1558312072Skib file, (uintmax_t)isb.st_nlink - 1); 1559166255Sdelphij goto lose; 1560166255Sdelphij } 1561166255Sdelphij if (nflag == 0 && timestamp) 1562166255Sdelphij isb.st_mtime = timestamp; 1563166255Sdelphij if (check_outfile(outfile) == 0) 1564166255Sdelphij goto lose; 1565166255Sdelphij#endif 1566166255Sdelphij } 1567166255Sdelphij 1568326559Sdelphij if (cflag) 1569326559Sdelphij zfd = STDOUT_FILENO; 1570326559Sdelphij else if (lflag) 1571326559Sdelphij zfd = -1; 1572326559Sdelphij else { 1573166255Sdelphij zfd = open(outfile, O_WRONLY|O_CREAT|O_EXCL, 0600); 1574166255Sdelphij if (zfd == STDOUT_FILENO) { 1575166255Sdelphij /* We won't close STDOUT_FILENO later... */ 1576166255Sdelphij zfd = dup(zfd); 1577166255Sdelphij close(STDOUT_FILENO); 1578166255Sdelphij } 1579166255Sdelphij if (zfd == -1) { 1580166255Sdelphij maybe_warn("can't open %s", outfile); 1581166255Sdelphij goto lose; 1582166255Sdelphij } 1583207247Sdelphij remove_file = outfile; 1584326559Sdelphij } 1585166255Sdelphij 1586226184Sdelphij switch (method) { 1587166255Sdelphij#ifndef NO_BZIP2_SUPPORT 1588226184Sdelphij case FT_BZIP2: 1589166255Sdelphij /* XXX */ 1590166255Sdelphij if (lflag) { 1591166255Sdelphij maybe_warnx("no -l with bzip2 files"); 1592166255Sdelphij goto lose; 1593166255Sdelphij } 1594166255Sdelphij 1595166255Sdelphij size = unbzip2(fd, zfd, NULL, 0, NULL); 1596226184Sdelphij break; 1597166255Sdelphij#endif 1598166255Sdelphij 1599166255Sdelphij#ifndef NO_COMPRESS_SUPPORT 1600226184Sdelphij case FT_Z: { 1601166255Sdelphij FILE *in, *out; 1602166255Sdelphij 1603166255Sdelphij /* XXX */ 1604166255Sdelphij if (lflag) { 1605166255Sdelphij maybe_warnx("no -l with Lempel-Ziv files"); 1606166255Sdelphij goto lose; 1607166255Sdelphij } 1608166255Sdelphij 1609166255Sdelphij if ((in = zdopen(fd)) == NULL) { 1610166255Sdelphij maybe_warn("zdopen for read: %s", file); 1611166255Sdelphij goto lose; 1612166255Sdelphij } 1613166255Sdelphij 1614166255Sdelphij out = fdopen(dup(zfd), "w"); 1615166255Sdelphij if (out == NULL) { 1616166255Sdelphij maybe_warn("fdopen for write: %s", outfile); 1617166255Sdelphij fclose(in); 1618166255Sdelphij goto lose; 1619166255Sdelphij } 1620166255Sdelphij 1621166255Sdelphij size = zuncompress(in, out, NULL, 0, NULL); 1622166255Sdelphij /* need to fclose() if ferror() is true... */ 1623337521Sdelphij error = ferror(in); 1624337521Sdelphij if (error | fclose(in)) { 1625337521Sdelphij if (error) 1626337521Sdelphij maybe_warn("failed infile"); 1627337521Sdelphij else 1628337521Sdelphij maybe_warn("failed infile fclose"); 1629337521Sdelphij if (cflag == 0) 1630337521Sdelphij unlink(outfile); 1631166255Sdelphij (void)fclose(out); 1632337521Sdelphij goto lose; 1633166255Sdelphij } 1634166255Sdelphij if (fclose(out) != 0) { 1635166255Sdelphij maybe_warn("failed outfile fclose"); 1636337521Sdelphij if (cflag == 0) 1637337521Sdelphij unlink(outfile); 1638166255Sdelphij goto lose; 1639166255Sdelphij } 1640226184Sdelphij break; 1641226184Sdelphij } 1642166255Sdelphij#endif 1643166255Sdelphij 1644194579Sdelphij#ifndef NO_PACK_SUPPORT 1645226184Sdelphij case FT_PACK: 1646194579Sdelphij if (lflag) { 1647194579Sdelphij maybe_warnx("no -l with packed files"); 1648194579Sdelphij goto lose; 1649194579Sdelphij } 1650194579Sdelphij 1651194579Sdelphij size = unpack(fd, zfd, NULL, 0, NULL); 1652226184Sdelphij break; 1653194579Sdelphij#endif 1654194579Sdelphij 1655226184Sdelphij#ifndef NO_XZ_SUPPORT 1656226184Sdelphij case FT_XZ: 1657226184Sdelphij if (lflag) { 1658343251Sdelphij size = unxz_len(fd); 1659343251Sdelphij print_list_out(in_size, size, file); 1660343251Sdelphij return -1; 1661226184Sdelphij } 1662226184Sdelphij size = unxz(fd, zfd, NULL, 0, NULL); 1663226184Sdelphij break; 1664226184Sdelphij#endif 1665226184Sdelphij 1666343251Sdelphij#ifndef NO_LZ_SUPPORT 1667343251Sdelphij case FT_LZ: 1668343251Sdelphij if (lflag) { 1669343251Sdelphij maybe_warnx("no -l with lzip files"); 1670343251Sdelphij goto lose; 1671343251Sdelphij } 1672343251Sdelphij size = unlz(fd, zfd, NULL, 0, NULL); 1673343251Sdelphij break; 1674343251Sdelphij#endif 1675166255Sdelphij#ifndef SMALL 1676226184Sdelphij case FT_UNKNOWN: 1677166255Sdelphij if (lflag) { 1678166255Sdelphij maybe_warnx("no -l for unknown filetypes"); 1679166255Sdelphij goto lose; 1680166255Sdelphij } 1681166255Sdelphij size = cat_fd(NULL, 0, NULL, fd); 1682226184Sdelphij break; 1683166255Sdelphij#endif 1684226184Sdelphij default: 1685166255Sdelphij if (lflag) { 1686326559Sdelphij print_list(fd, in_size, outfile, isb.st_mtime); 1687166255Sdelphij close(fd); 1688166255Sdelphij return -1; /* XXX */ 1689166255Sdelphij } 1690166255Sdelphij 1691166255Sdelphij size = gz_uncompress(fd, zfd, NULL, 0, NULL, file); 1692226184Sdelphij break; 1693166255Sdelphij } 1694166255Sdelphij 1695166255Sdelphij if (close(fd) != 0) 1696166255Sdelphij maybe_warn("couldn't close input"); 1697166255Sdelphij if (zfd != STDOUT_FILENO && close(zfd) != 0) 1698166255Sdelphij maybe_warn("couldn't close output"); 1699166255Sdelphij 1700166255Sdelphij if (size == -1) { 1701166255Sdelphij if (cflag == 0) 1702166255Sdelphij unlink(outfile); 1703166255Sdelphij maybe_warnx("%s: uncompress failed", file); 1704166255Sdelphij return -1; 1705166255Sdelphij } 1706166255Sdelphij 1707166255Sdelphij /* if testing, or we uncompressed to stdout, this is all we need */ 1708166255Sdelphij#ifndef SMALL 1709166255Sdelphij if (tflag) 1710166255Sdelphij return size; 1711166255Sdelphij#endif 1712166255Sdelphij /* if we are uncompressing to stdin, don't remove the file. */ 1713166255Sdelphij if (cflag) 1714166255Sdelphij return size; 1715166255Sdelphij 1716166255Sdelphij /* 1717166255Sdelphij * if we create a file... 1718166255Sdelphij */ 1719166255Sdelphij /* 1720166255Sdelphij * if we can't stat the file don't remove the file. 1721166255Sdelphij */ 1722166255Sdelphij 1723166255Sdelphij ofd = open(outfile, O_RDWR, 0); 1724166255Sdelphij if (ofd == -1) { 1725166255Sdelphij maybe_warn("couldn't open (leaving original): %s", 1726166255Sdelphij outfile); 1727166255Sdelphij return -1; 1728166255Sdelphij } 1729166255Sdelphij if (fstat(ofd, &osb) != 0) { 1730166255Sdelphij maybe_warn("couldn't stat (leaving original): %s", 1731166255Sdelphij outfile); 1732166255Sdelphij close(ofd); 1733166255Sdelphij return -1; 1734166255Sdelphij } 1735166255Sdelphij if (osb.st_size != size) { 1736209017Sdelphij maybe_warnx("stat gave different size: %ju != %ju (leaving original)", 1737209017Sdelphij (uintmax_t)size, (uintmax_t)osb.st_size); 1738166255Sdelphij close(ofd); 1739166255Sdelphij unlink(outfile); 1740166255Sdelphij return -1; 1741166255Sdelphij } 1742166255Sdelphij#ifndef SMALL 1743166255Sdelphij copymodes(ofd, &isb, outfile); 1744207247Sdelphij remove_file = NULL; 1745166255Sdelphij#endif 1746166255Sdelphij close(ofd); 1747207247Sdelphij unlink_input(file, &isb); 1748166255Sdelphij return size; 1749166255Sdelphij 1750166255Sdelphij unexpected_EOF: 1751166255Sdelphij maybe_warnx("%s: unexpected end of file", file); 1752166255Sdelphij lose: 1753166255Sdelphij if (fd != -1) 1754166255Sdelphij close(fd); 1755166255Sdelphij if (zfd != -1 && zfd != STDOUT_FILENO) 1756327191Sdelphij close(zfd); 1757166255Sdelphij return -1; 1758166255Sdelphij} 1759166255Sdelphij 1760166255Sdelphij#ifndef SMALL 1761326559Sdelphijstatic void 1762326559Sdelphijcheck_siginfo(void) 1763326559Sdelphij{ 1764326559Sdelphij if (print_info == 0) 1765326559Sdelphij return; 1766326559Sdelphij if (infile) { 1767326559Sdelphij if (infile_total) { 1768326559Sdelphij int pcent = (int)((100.0 * infile_current) / infile_total); 1769326559Sdelphij 1770326559Sdelphij fprintf(stderr, "%s: done %llu/%llu bytes %d%%\n", 1771326559Sdelphij infile, (unsigned long long)infile_current, 1772326559Sdelphij (unsigned long long)infile_total, pcent); 1773326559Sdelphij } else 1774326559Sdelphij fprintf(stderr, "%s: done %llu bytes\n", 1775326559Sdelphij infile, (unsigned long long)infile_current); 1776326559Sdelphij } 1777326559Sdelphij print_info = 0; 1778326559Sdelphij} 1779326559Sdelphij 1780166255Sdelphijstatic off_t 1781166255Sdelphijcat_fd(unsigned char * prepend, size_t count, off_t *gsizep, int fd) 1782166255Sdelphij{ 1783166255Sdelphij char buf[BUFLEN]; 1784166255Sdelphij off_t in_tot; 1785166255Sdelphij ssize_t w; 1786166255Sdelphij 1787166255Sdelphij in_tot = count; 1788326559Sdelphij w = write_retry(STDOUT_FILENO, prepend, count); 1789166255Sdelphij if (w == -1 || (size_t)w != count) { 1790166255Sdelphij maybe_warn("write to stdout"); 1791166255Sdelphij return -1; 1792166255Sdelphij } 1793166255Sdelphij for (;;) { 1794166255Sdelphij ssize_t rv; 1795166255Sdelphij 1796166255Sdelphij rv = read(fd, buf, sizeof buf); 1797166255Sdelphij if (rv == 0) 1798166255Sdelphij break; 1799166255Sdelphij if (rv < 0) { 1800166255Sdelphij maybe_warn("read from fd %d", fd); 1801166255Sdelphij break; 1802166255Sdelphij } 1803326559Sdelphij infile_newdata(rv); 1804166255Sdelphij 1805326559Sdelphij if (write_retry(STDOUT_FILENO, buf, rv) != rv) { 1806166255Sdelphij maybe_warn("write to stdout"); 1807166255Sdelphij break; 1808166255Sdelphij } 1809166255Sdelphij in_tot += rv; 1810166255Sdelphij } 1811166255Sdelphij 1812166255Sdelphij if (gsizep) 1813166255Sdelphij *gsizep = in_tot; 1814166255Sdelphij return (in_tot); 1815166255Sdelphij} 1816166255Sdelphij#endif 1817166255Sdelphij 1818166255Sdelphijstatic void 1819166255Sdelphijhandle_stdin(void) 1820166255Sdelphij{ 1821326559Sdelphij struct stat isb; 1822166255Sdelphij unsigned char header1[4]; 1823326559Sdelphij size_t in_size; 1824166255Sdelphij off_t usize, gsize; 1825166255Sdelphij enum filetype method; 1826166255Sdelphij ssize_t bytes_read; 1827166255Sdelphij#ifndef NO_COMPRESS_SUPPORT 1828166255Sdelphij FILE *in; 1829166255Sdelphij#endif 1830166255Sdelphij 1831166255Sdelphij#ifndef SMALL 1832166255Sdelphij if (fflag == 0 && lflag == 0 && isatty(STDIN_FILENO)) { 1833166255Sdelphij maybe_warnx("standard input is a terminal -- ignoring"); 1834326559Sdelphij goto out; 1835166255Sdelphij } 1836166255Sdelphij#endif 1837166255Sdelphij 1838326559Sdelphij if (fstat(STDIN_FILENO, &isb) < 0) { 1839326559Sdelphij maybe_warn("fstat"); 1840326559Sdelphij goto out; 1841326559Sdelphij } 1842326559Sdelphij if (S_ISREG(isb.st_mode)) 1843326559Sdelphij in_size = isb.st_size; 1844326559Sdelphij else 1845326559Sdelphij in_size = 0; 1846326559Sdelphij infile_set("(stdin)", in_size); 1847326559Sdelphij 1848166255Sdelphij if (lflag) { 1849326559Sdelphij print_list(STDIN_FILENO, in_size, infile, isb.st_mtime); 1850326559Sdelphij goto out; 1851166255Sdelphij } 1852166255Sdelphij 1853166255Sdelphij bytes_read = read_retry(STDIN_FILENO, header1, sizeof header1); 1854166255Sdelphij if (bytes_read == -1) { 1855166255Sdelphij maybe_warn("can't read stdin"); 1856326559Sdelphij goto out; 1857166255Sdelphij } else if (bytes_read != sizeof(header1)) { 1858166255Sdelphij maybe_warnx("(stdin): unexpected end of file"); 1859326559Sdelphij goto out; 1860166255Sdelphij } 1861166255Sdelphij 1862166255Sdelphij method = file_gettype(header1); 1863166255Sdelphij switch (method) { 1864166255Sdelphij default: 1865166255Sdelphij#ifndef SMALL 1866166255Sdelphij if (fflag == 0) { 1867166255Sdelphij maybe_warnx("unknown compression format"); 1868326559Sdelphij goto out; 1869166255Sdelphij } 1870166255Sdelphij usize = cat_fd(header1, sizeof header1, &gsize, STDIN_FILENO); 1871166255Sdelphij break; 1872166255Sdelphij#endif 1873166255Sdelphij case FT_GZIP: 1874326559Sdelphij usize = gz_uncompress(STDIN_FILENO, STDOUT_FILENO, 1875166255Sdelphij (char *)header1, sizeof header1, &gsize, "(stdin)"); 1876166255Sdelphij break; 1877166255Sdelphij#ifndef NO_BZIP2_SUPPORT 1878166255Sdelphij case FT_BZIP2: 1879166255Sdelphij usize = unbzip2(STDIN_FILENO, STDOUT_FILENO, 1880166255Sdelphij (char *)header1, sizeof header1, &gsize); 1881166255Sdelphij break; 1882166255Sdelphij#endif 1883166255Sdelphij#ifndef NO_COMPRESS_SUPPORT 1884166255Sdelphij case FT_Z: 1885166255Sdelphij if ((in = zdopen(STDIN_FILENO)) == NULL) { 1886166255Sdelphij maybe_warnx("zopen of stdin"); 1887326559Sdelphij goto out; 1888166255Sdelphij } 1889166255Sdelphij 1890226184Sdelphij usize = zuncompress(in, stdout, (char *)header1, 1891226184Sdelphij sizeof header1, &gsize); 1892166255Sdelphij fclose(in); 1893166255Sdelphij break; 1894166255Sdelphij#endif 1895194579Sdelphij#ifndef NO_PACK_SUPPORT 1896194579Sdelphij case FT_PACK: 1897194579Sdelphij usize = unpack(STDIN_FILENO, STDOUT_FILENO, 1898194579Sdelphij (char *)header1, sizeof header1, &gsize); 1899194579Sdelphij break; 1900194579Sdelphij#endif 1901226184Sdelphij#ifndef NO_XZ_SUPPORT 1902226184Sdelphij case FT_XZ: 1903226184Sdelphij usize = unxz(STDIN_FILENO, STDOUT_FILENO, 1904226184Sdelphij (char *)header1, sizeof header1, &gsize); 1905226184Sdelphij break; 1906226184Sdelphij#endif 1907343251Sdelphij#ifndef NO_LZ_SUPPORT 1908343251Sdelphij case FT_LZ: 1909343251Sdelphij usize = unlz(STDIN_FILENO, STDOUT_FILENO, 1910343251Sdelphij (char *)header1, sizeof header1, &gsize); 1911343251Sdelphij break; 1912343251Sdelphij#endif 1913166255Sdelphij } 1914166255Sdelphij 1915166255Sdelphij#ifndef SMALL 1916166255Sdelphij if (vflag && !tflag && usize != -1 && gsize != -1) 1917166255Sdelphij print_verbage(NULL, NULL, usize, gsize); 1918166255Sdelphij if (vflag && tflag) 1919166255Sdelphij print_test("(stdin)", usize != -1); 1920326559Sdelphij#else 1921326559Sdelphij (void)&usize; 1922326559Sdelphij#endif 1923166255Sdelphij 1924326559Sdelphijout: 1925326559Sdelphij infile_clear(); 1926166255Sdelphij} 1927166255Sdelphij 1928166255Sdelphijstatic void 1929166255Sdelphijhandle_stdout(void) 1930166255Sdelphij{ 1931326559Sdelphij off_t gsize; 1932326559Sdelphij#ifndef SMALL 1933326559Sdelphij off_t usize; 1934166255Sdelphij struct stat sb; 1935166255Sdelphij time_t systime; 1936166255Sdelphij uint32_t mtime; 1937166255Sdelphij int ret; 1938166255Sdelphij 1939326559Sdelphij infile_set("(stdout)", 0); 1940326559Sdelphij 1941166255Sdelphij if (fflag == 0 && isatty(STDOUT_FILENO)) { 1942166255Sdelphij maybe_warnx("standard output is a terminal -- ignoring"); 1943166255Sdelphij return; 1944166255Sdelphij } 1945326559Sdelphij 1946273507Sdelphij /* If stdin is a file use its mtime, otherwise use current time */ 1947166255Sdelphij ret = fstat(STDIN_FILENO, &sb); 1948166255Sdelphij if (ret < 0) { 1949166255Sdelphij maybe_warn("Can't stat stdin"); 1950166255Sdelphij return; 1951166255Sdelphij } 1952166255Sdelphij 1953326559Sdelphij if (S_ISREG(sb.st_mode)) { 1954326559Sdelphij infile_set("(stdout)", sb.st_size); 1955166255Sdelphij mtime = (uint32_t)sb.st_mtime; 1956326559Sdelphij } else { 1957166255Sdelphij systime = time(NULL); 1958166255Sdelphij if (systime == -1) { 1959166255Sdelphij maybe_warn("time"); 1960166255Sdelphij return; 1961326559Sdelphij } 1962166255Sdelphij mtime = (uint32_t)systime; 1963166255Sdelphij } 1964166255Sdelphij 1965326559Sdelphij usize = 1966326559Sdelphij#endif 1967326559Sdelphij gz_compress(STDIN_FILENO, STDOUT_FILENO, &gsize, "", mtime); 1968166255Sdelphij#ifndef SMALL 1969166255Sdelphij if (vflag && !tflag && usize != -1 && gsize != -1) 1970166255Sdelphij print_verbage(NULL, NULL, usize, gsize); 1971326559Sdelphij#endif 1972166255Sdelphij} 1973166255Sdelphij 1974166255Sdelphij/* do what is asked for, for the path name */ 1975166255Sdelphijstatic void 1976166255Sdelphijhandle_pathname(char *path) 1977166255Sdelphij{ 1978166255Sdelphij char *opath = path, *s = NULL; 1979166255Sdelphij ssize_t len; 1980166255Sdelphij int slen; 1981166255Sdelphij struct stat sb; 1982166255Sdelphij 1983166255Sdelphij /* check for stdout/stdin */ 1984166255Sdelphij if (path[0] == '-' && path[1] == '\0') { 1985166255Sdelphij if (dflag) 1986166255Sdelphij handle_stdin(); 1987166255Sdelphij else 1988166255Sdelphij handle_stdout(); 1989166255Sdelphij return; 1990166255Sdelphij } 1991166255Sdelphij 1992166255Sdelphijretry: 1993222287Sdelphij if (stat(path, &sb) != 0 || (fflag == 0 && cflag == 0 && 1994222287Sdelphij lstat(path, &sb) != 0)) { 1995166255Sdelphij /* lets try <path>.gz if we're decompressing */ 1996166255Sdelphij if (dflag && s == NULL && errno == ENOENT) { 1997166255Sdelphij len = strlen(path); 1998166255Sdelphij slen = suffixes[0].ziplen; 1999166255Sdelphij s = malloc(len + slen + 1); 2000166255Sdelphij if (s == NULL) 2001166255Sdelphij maybe_err("malloc"); 2002166255Sdelphij memcpy(s, path, len); 2003166255Sdelphij memcpy(s + len, suffixes[0].zipped, slen + 1); 2004166255Sdelphij path = s; 2005166255Sdelphij goto retry; 2006166255Sdelphij } 2007166255Sdelphij maybe_warn("can't stat: %s", opath); 2008166255Sdelphij goto out; 2009166255Sdelphij } 2010166255Sdelphij 2011166255Sdelphij if (S_ISDIR(sb.st_mode)) { 2012166255Sdelphij#ifndef SMALL 2013166255Sdelphij if (rflag) 2014166255Sdelphij handle_dir(path); 2015166255Sdelphij else 2016166255Sdelphij#endif 2017166255Sdelphij maybe_warnx("%s is a directory", path); 2018166255Sdelphij goto out; 2019166255Sdelphij } 2020166255Sdelphij 2021166255Sdelphij if (S_ISREG(sb.st_mode)) 2022166255Sdelphij handle_file(path, &sb); 2023166255Sdelphij else 2024166255Sdelphij maybe_warnx("%s is not a regular file", path); 2025166255Sdelphij 2026166255Sdelphijout: 2027166255Sdelphij if (s) 2028166255Sdelphij free(s); 2029166255Sdelphij} 2030166255Sdelphij 2031166255Sdelphij/* compress/decompress a file */ 2032166255Sdelphijstatic void 2033166255Sdelphijhandle_file(char *file, struct stat *sbp) 2034166255Sdelphij{ 2035166255Sdelphij off_t usize, gsize; 2036166255Sdelphij char outfile[PATH_MAX]; 2037166255Sdelphij 2038326559Sdelphij infile_set(file, sbp->st_size); 2039166255Sdelphij if (dflag) { 2040166255Sdelphij usize = file_uncompress(file, outfile, sizeof(outfile)); 2041166255Sdelphij#ifndef SMALL 2042166255Sdelphij if (vflag && tflag) 2043166255Sdelphij print_test(file, usize != -1); 2044166255Sdelphij#endif 2045166255Sdelphij if (usize == -1) 2046166255Sdelphij return; 2047166255Sdelphij gsize = sbp->st_size; 2048166255Sdelphij } else { 2049166255Sdelphij gsize = file_compress(file, outfile, sizeof(outfile)); 2050166255Sdelphij if (gsize == -1) 2051166255Sdelphij return; 2052166255Sdelphij usize = sbp->st_size; 2053166255Sdelphij } 2054326559Sdelphij infile_clear(); 2055166255Sdelphij 2056166255Sdelphij#ifndef SMALL 2057166255Sdelphij if (vflag && !tflag) 2058166255Sdelphij print_verbage(file, (cflag) ? NULL : outfile, usize, gsize); 2059166255Sdelphij#endif 2060166255Sdelphij} 2061166255Sdelphij 2062166255Sdelphij#ifndef SMALL 2063166255Sdelphij/* this is used with -r to recursively descend directories */ 2064166255Sdelphijstatic void 2065166255Sdelphijhandle_dir(char *dir) 2066166255Sdelphij{ 2067166255Sdelphij char *path_argv[2]; 2068166255Sdelphij FTS *fts; 2069166255Sdelphij FTSENT *entry; 2070166255Sdelphij 2071166255Sdelphij path_argv[0] = dir; 2072166255Sdelphij path_argv[1] = 0; 2073171389Sdelphij fts = fts_open(path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL); 2074166255Sdelphij if (fts == NULL) { 2075166255Sdelphij warn("couldn't fts_open %s", dir); 2076166255Sdelphij return; 2077166255Sdelphij } 2078166255Sdelphij 2079166255Sdelphij while ((entry = fts_read(fts))) { 2080166255Sdelphij switch(entry->fts_info) { 2081166255Sdelphij case FTS_D: 2082166255Sdelphij case FTS_DP: 2083166255Sdelphij continue; 2084166255Sdelphij 2085166255Sdelphij case FTS_DNR: 2086166255Sdelphij case FTS_ERR: 2087166255Sdelphij case FTS_NS: 2088166255Sdelphij maybe_warn("%s", entry->fts_path); 2089166255Sdelphij continue; 2090166255Sdelphij case FTS_F: 2091171389Sdelphij handle_file(entry->fts_path, entry->fts_statp); 2092166255Sdelphij } 2093166255Sdelphij } 2094166255Sdelphij (void)fts_close(fts); 2095166255Sdelphij} 2096166255Sdelphij#endif 2097166255Sdelphij 2098166255Sdelphij/* print a ratio - size reduction as a fraction of uncompressed size */ 2099166255Sdelphijstatic void 2100166255Sdelphijprint_ratio(off_t in, off_t out, FILE *where) 2101166255Sdelphij{ 2102166255Sdelphij int percent10; /* 10 * percent */ 2103166255Sdelphij off_t diff; 2104166255Sdelphij char buff[8]; 2105166255Sdelphij int len; 2106166255Sdelphij 2107166255Sdelphij diff = in - out/2; 2108326559Sdelphij if (in == 0 && out == 0) 2109326559Sdelphij percent10 = 0; 2110326559Sdelphij else if (diff < 0) 2111166255Sdelphij /* 2112166255Sdelphij * Output is more than double size of input! print -99.9% 2113166255Sdelphij * Quite possibly we've failed to get the original size. 2114166255Sdelphij */ 2115166255Sdelphij percent10 = -999; 2116166255Sdelphij else { 2117166255Sdelphij /* 2118166255Sdelphij * We only need 12 bits of result from the final division, 2119166255Sdelphij * so reduce the values until a 32bit division will suffice. 2120166255Sdelphij */ 2121166255Sdelphij while (in > 0x100000) { 2122166255Sdelphij diff >>= 1; 2123166255Sdelphij in >>= 1; 2124166255Sdelphij } 2125166255Sdelphij if (in != 0) 2126166255Sdelphij percent10 = ((u_int)diff * 2000) / (u_int)in - 1000; 2127166255Sdelphij else 2128166255Sdelphij percent10 = 0; 2129166255Sdelphij } 2130166255Sdelphij 2131166255Sdelphij len = snprintf(buff, sizeof buff, "%2.2d.", percent10); 2132166255Sdelphij /* Move the '.' to before the last digit */ 2133166255Sdelphij buff[len - 1] = buff[len - 2]; 2134166255Sdelphij buff[len - 2] = '.'; 2135166255Sdelphij fprintf(where, "%5s%%", buff); 2136166255Sdelphij} 2137166255Sdelphij 2138166255Sdelphij#ifndef SMALL 2139166255Sdelphij/* print compression statistics, and the new name (if there is one!) */ 2140166255Sdelphijstatic void 2141166255Sdelphijprint_verbage(const char *file, const char *nfile, off_t usize, off_t gsize) 2142166255Sdelphij{ 2143166255Sdelphij if (file) 2144166255Sdelphij fprintf(stderr, "%s:%s ", file, 2145166255Sdelphij strlen(file) < 7 ? "\t\t" : "\t"); 2146166255Sdelphij print_ratio(usize, gsize, stderr); 2147166255Sdelphij if (nfile) 2148166255Sdelphij fprintf(stderr, " -- replaced with %s", nfile); 2149166255Sdelphij fprintf(stderr, "\n"); 2150166255Sdelphij fflush(stderr); 2151166255Sdelphij} 2152166255Sdelphij 2153166255Sdelphij/* print test results */ 2154166255Sdelphijstatic void 2155166255Sdelphijprint_test(const char *file, int ok) 2156166255Sdelphij{ 2157166255Sdelphij 2158166255Sdelphij if (exit_value == 0 && ok == 0) 2159166255Sdelphij exit_value = 1; 2160166255Sdelphij fprintf(stderr, "%s:%s %s\n", file, 2161166255Sdelphij strlen(file) < 7 ? "\t\t" : "\t", ok ? "OK" : "NOT OK"); 2162166255Sdelphij fflush(stderr); 2163166255Sdelphij} 2164166255Sdelphij#endif 2165166255Sdelphij 2166166255Sdelphij/* print a file's info ala --list */ 2167166255Sdelphij/* eg: 2168166255Sdelphij compressed uncompressed ratio uncompressed_name 2169166255Sdelphij 354841 1679360 78.8% /usr/pkgsrc/distfiles/libglade-2.0.1.tar 2170166255Sdelphij*/ 2171166255Sdelphijstatic void 2172166255Sdelphijprint_list(int fd, off_t out, const char *outfile, time_t ts) 2173166255Sdelphij{ 2174166255Sdelphij static int first = 1; 2175166255Sdelphij#ifndef SMALL 2176166255Sdelphij static off_t in_tot, out_tot; 2177166255Sdelphij uint32_t crc = 0; 2178166255Sdelphij#endif 2179166255Sdelphij off_t in = 0, rv; 2180166255Sdelphij 2181166255Sdelphij if (first) { 2182166255Sdelphij#ifndef SMALL 2183166255Sdelphij if (vflag) 2184166255Sdelphij printf("method crc date time "); 2185166255Sdelphij#endif 2186166255Sdelphij if (qflag == 0) 2187166255Sdelphij printf(" compressed uncompressed " 2188166255Sdelphij "ratio uncompressed_name\n"); 2189166255Sdelphij } 2190166255Sdelphij first = 0; 2191166255Sdelphij 2192166255Sdelphij /* print totals? */ 2193166255Sdelphij#ifndef SMALL 2194166255Sdelphij if (fd == -1) { 2195166255Sdelphij in = in_tot; 2196166255Sdelphij out = out_tot; 2197166255Sdelphij } else 2198166255Sdelphij#endif 2199166255Sdelphij { 2200166255Sdelphij /* read the last 4 bytes - this is the uncompressed size */ 2201166255Sdelphij rv = lseek(fd, (off_t)(-8), SEEK_END); 2202166255Sdelphij if (rv != -1) { 2203166255Sdelphij unsigned char buf[8]; 2204166255Sdelphij uint32_t usize; 2205166255Sdelphij 2206166255Sdelphij rv = read(fd, (char *)buf, sizeof(buf)); 2207166255Sdelphij if (rv == -1) 2208166255Sdelphij maybe_warn("read of uncompressed size"); 2209166255Sdelphij else if (rv != sizeof(buf)) 2210166255Sdelphij maybe_warnx("read of uncompressed size"); 2211166255Sdelphij 2212166255Sdelphij else { 2213336661Sdelphij usize = le32dec(&buf[4]); 2214166255Sdelphij in = (off_t)usize; 2215166255Sdelphij#ifndef SMALL 2216336661Sdelphij crc = le32dec(&buf[0]); 2217166255Sdelphij#endif 2218166255Sdelphij } 2219166255Sdelphij } 2220166255Sdelphij } 2221166255Sdelphij 2222166255Sdelphij#ifndef SMALL 2223166255Sdelphij if (vflag && fd == -1) 2224166255Sdelphij printf(" "); 2225166255Sdelphij else if (vflag) { 2226166255Sdelphij char *date = ctime(&ts); 2227166255Sdelphij 2228166255Sdelphij /* skip the day, 1/100th second, and year */ 2229166255Sdelphij date += 4; 2230166255Sdelphij date[12] = 0; 2231166255Sdelphij printf("%5s %08x %11s ", "defla"/*XXX*/, crc, date); 2232166255Sdelphij } 2233166255Sdelphij in_tot += in; 2234166255Sdelphij out_tot += out; 2235194508Sdelphij#else 2236194508Sdelphij (void)&ts; /* XXX */ 2237166255Sdelphij#endif 2238343251Sdelphij print_list_out(out, in, outfile); 2239343251Sdelphij} 2240343251Sdelphij 2241343251Sdelphijstatic void 2242343251Sdelphijprint_list_out(off_t out, off_t in, const char *outfile) 2243343251Sdelphij{ 2244166255Sdelphij printf("%12llu %12llu ", (unsigned long long)out, (unsigned long long)in); 2245166255Sdelphij print_ratio(in, out, stdout); 2246166255Sdelphij printf(" %s\n", outfile); 2247166255Sdelphij} 2248166255Sdelphij 2249166255Sdelphij/* display the usage of NetBSD gzip */ 2250166255Sdelphijstatic void 2251166255Sdelphijusage(void) 2252166255Sdelphij{ 2253166255Sdelphij 2254166255Sdelphij fprintf(stderr, "%s\n", gzip_version); 2255166255Sdelphij fprintf(stderr, 2256171389Sdelphij#ifdef SMALL 2257171389Sdelphij "usage: %s [-" OPT_LIST "] [<file> [<file> ...]]\n", 2258171389Sdelphij#else 2259171389Sdelphij "usage: %s [-123456789acdfhklLNnqrtVv] [-S .suffix] [<file> [<file> ...]]\n" 2260166255Sdelphij " -1 --fast fastest (worst) compression\n" 2261166255Sdelphij " -2 .. -8 set compression level\n" 2262166255Sdelphij " -9 --best best (slowest) compression\n" 2263166255Sdelphij " -c --stdout write to stdout, keep original files\n" 2264166255Sdelphij " --to-stdout\n" 2265166255Sdelphij " -d --decompress uncompress files\n" 2266166255Sdelphij " --uncompress\n" 2267166255Sdelphij " -f --force force overwriting & compress links\n" 2268166255Sdelphij " -h --help display this help\n" 2269170053Sdelphij " -k --keep don't delete input files during operation\n" 2270166255Sdelphij " -l --list list compressed file contents\n" 2271166255Sdelphij " -N --name save or restore original file name and time stamp\n" 2272166255Sdelphij " -n --no-name don't save original file name or time stamp\n" 2273166255Sdelphij " -q --quiet output no warnings\n" 2274166255Sdelphij " -r --recursive recursively compress files in directories\n" 2275166255Sdelphij " -S .suf use suffix .suf instead of .gz\n" 2276166255Sdelphij " --suffix .suf\n" 2277166255Sdelphij " -t --test test compressed file\n" 2278166255Sdelphij " -V --version display program version\n" 2279166255Sdelphij " -v --verbose print extra statistics\n", 2280166255Sdelphij#endif 2281166255Sdelphij getprogname()); 2282166255Sdelphij exit(0); 2283166255Sdelphij} 2284166255Sdelphij 2285166255Sdelphij#ifndef SMALL 2286166255Sdelphij/* display the license information of FreeBSD gzip */ 2287166255Sdelphijstatic void 2288166255Sdelphijdisplay_license(void) 2289166255Sdelphij{ 2290166255Sdelphij 2291281500Sdelphij fprintf(stderr, "%s (based on NetBSD gzip 20150113)\n", gzip_version); 2292166255Sdelphij fprintf(stderr, "%s\n", gzip_copyright); 2293166255Sdelphij exit(0); 2294166255Sdelphij} 2295166255Sdelphij#endif 2296166255Sdelphij 2297166255Sdelphij/* display the version of NetBSD gzip */ 2298166255Sdelphijstatic void 2299166255Sdelphijdisplay_version(void) 2300166255Sdelphij{ 2301166255Sdelphij 2302166255Sdelphij fprintf(stderr, "%s\n", gzip_version); 2303166255Sdelphij exit(0); 2304166255Sdelphij} 2305166255Sdelphij 2306166255Sdelphij#ifndef NO_BZIP2_SUPPORT 2307166255Sdelphij#include "unbzip2.c" 2308166255Sdelphij#endif 2309166255Sdelphij#ifndef NO_COMPRESS_SUPPORT 2310166255Sdelphij#include "zuncompress.c" 2311166255Sdelphij#endif 2312194579Sdelphij#ifndef NO_PACK_SUPPORT 2313194579Sdelphij#include "unpack.c" 2314194579Sdelphij#endif 2315226184Sdelphij#ifndef NO_XZ_SUPPORT 2316226184Sdelphij#include "unxz.c" 2317226184Sdelphij#endif 2318343251Sdelphij#ifndef NO_LZ_SUPPORT 2319343251Sdelphij#include "unlz.c" 2320343251Sdelphij#endif 2321166255Sdelphij 2322166255Sdelphijstatic ssize_t 2323166255Sdelphijread_retry(int fd, void *buf, size_t sz) 2324166255Sdelphij{ 2325166255Sdelphij char *cp = buf; 2326166255Sdelphij size_t left = MIN(sz, (size_t) SSIZE_MAX); 2327166255Sdelphij 2328166255Sdelphij while (left > 0) { 2329166255Sdelphij ssize_t ret; 2330166255Sdelphij 2331166255Sdelphij ret = read(fd, cp, left); 2332166255Sdelphij if (ret == -1) { 2333166255Sdelphij return ret; 2334166255Sdelphij } else if (ret == 0) { 2335166255Sdelphij break; /* EOF */ 2336166255Sdelphij } 2337166255Sdelphij cp += ret; 2338166255Sdelphij left -= ret; 2339166255Sdelphij } 2340166255Sdelphij 2341166255Sdelphij return sz - left; 2342166255Sdelphij} 2343326559Sdelphij 2344326559Sdelphijstatic ssize_t 2345326559Sdelphijwrite_retry(int fd, const void *buf, size_t sz) 2346326559Sdelphij{ 2347326559Sdelphij const char *cp = buf; 2348326559Sdelphij size_t left = MIN(sz, (size_t) SSIZE_MAX); 2349326559Sdelphij 2350326559Sdelphij while (left > 0) { 2351326559Sdelphij ssize_t ret; 2352326559Sdelphij 2353326559Sdelphij ret = write(fd, cp, left); 2354326559Sdelphij if (ret == -1) { 2355326559Sdelphij return ret; 2356326559Sdelphij } else if (ret == 0) { 2357326559Sdelphij abort(); /* Can't happen */ 2358326559Sdelphij } 2359326559Sdelphij cp += ret; 2360326559Sdelphij left -= ret; 2361326559Sdelphij } 2362326559Sdelphij 2363326559Sdelphij return sz - left; 2364326559Sdelphij} 2365