gzip.c revision 337521
1336323Spfg/* $NetBSD: gzip.c,v 1.113 2018/06/12 00:42:17 kamil 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 337521 2018-08-09 02:27:18Z 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 87166255Sdelphij FT_LAST, 88166255Sdelphij FT_UNKNOWN 89166255Sdelphij}; 90166255Sdelphij 91166255Sdelphij#ifndef NO_BZIP2_SUPPORT 92166255Sdelphij#include <bzlib.h> 93166255Sdelphij 94166255Sdelphij#define BZ2_SUFFIX ".bz2" 95309850Sdelphij#define BZIP2_MAGIC "BZh" 96166255Sdelphij#endif 97166255Sdelphij 98166255Sdelphij#ifndef NO_COMPRESS_SUPPORT 99166255Sdelphij#define Z_SUFFIX ".Z" 100166255Sdelphij#define Z_MAGIC "\037\235" 101166255Sdelphij#endif 102166255Sdelphij 103194579Sdelphij#ifndef NO_PACK_SUPPORT 104194579Sdelphij#define PACK_MAGIC "\037\036" 105194579Sdelphij#endif 106194579Sdelphij 107226184Sdelphij#ifndef NO_XZ_SUPPORT 108226184Sdelphij#include <lzma.h> 109226184Sdelphij#define XZ_SUFFIX ".xz" 110226184Sdelphij#define XZ_MAGIC "\3757zXZ" 111226184Sdelphij#endif 112226184Sdelphij 113166255Sdelphij#define GZ_SUFFIX ".gz" 114166255Sdelphij 115166255Sdelphij#define BUFLEN (64 * 1024) 116166255Sdelphij 117166255Sdelphij#define GZIP_MAGIC0 0x1F 118166255Sdelphij#define GZIP_MAGIC1 0x8B 119166255Sdelphij#define GZIP_OMAGIC1 0x9E 120166255Sdelphij 121166255Sdelphij#define GZIP_TIMESTAMP (off_t)4 122166255Sdelphij#define GZIP_ORIGNAME (off_t)10 123166255Sdelphij 124166255Sdelphij#define HEAD_CRC 0x02 125166255Sdelphij#define EXTRA_FIELD 0x04 126166255Sdelphij#define ORIG_NAME 0x08 127166255Sdelphij#define COMMENT 0x10 128166255Sdelphij 129166255Sdelphij#define OS_CODE 3 /* Unix */ 130166255Sdelphij 131166255Sdelphijtypedef struct { 132166255Sdelphij const char *zipped; 133166255Sdelphij int ziplen; 134166255Sdelphij const char *normal; /* for unzip - must not be longer than zipped */ 135166255Sdelphij} suffixes_t; 136166255Sdelphijstatic suffixes_t suffixes[] = { 137166255Sdelphij#define SUFFIX(Z, N) {Z, sizeof Z - 1, N} 138166255Sdelphij SUFFIX(GZ_SUFFIX, ""), /* Overwritten by -S .xxx */ 139166255Sdelphij#ifndef SMALL 140166255Sdelphij SUFFIX(GZ_SUFFIX, ""), 141166255Sdelphij SUFFIX(".z", ""), 142166255Sdelphij SUFFIX("-gz", ""), 143166255Sdelphij SUFFIX("-z", ""), 144166255Sdelphij SUFFIX("_z", ""), 145166255Sdelphij SUFFIX(".taz", ".tar"), 146166255Sdelphij SUFFIX(".tgz", ".tar"), 147166255Sdelphij#ifndef NO_BZIP2_SUPPORT 148166255Sdelphij SUFFIX(BZ2_SUFFIX, ""), 149176980Srwatson SUFFIX(".tbz", ".tar"), 150176980Srwatson SUFFIX(".tbz2", ".tar"), 151166255Sdelphij#endif 152166255Sdelphij#ifndef NO_COMPRESS_SUPPORT 153166255Sdelphij SUFFIX(Z_SUFFIX, ""), 154166255Sdelphij#endif 155226184Sdelphij#ifndef NO_XZ_SUPPORT 156226184Sdelphij SUFFIX(XZ_SUFFIX, ""), 157226184Sdelphij#endif 158166255Sdelphij SUFFIX(GZ_SUFFIX, ""), /* Overwritten by -S "" */ 159166255Sdelphij#endif /* SMALL */ 160166255Sdelphij#undef SUFFIX 161166255Sdelphij}; 162307697Saraujo#define NUM_SUFFIXES (nitems(suffixes)) 163195988Sdelphij#define SUFFIX_MAXLEN 30 164195988Sdelphij 165326559Sdelphijstatic const char gzip_version[] = "FreeBSD gzip 20171121"; 166166255Sdelphij 167166255Sdelphij#ifndef SMALL 168166255Sdelphijstatic const char gzip_copyright[] = \ 169166255Sdelphij" Copyright (c) 1997, 1998, 2003, 2004, 2006 Matthew R. Green\n" 170166255Sdelphij" All rights reserved.\n" 171166255Sdelphij"\n" 172166255Sdelphij" Redistribution and use in source and binary forms, with or without\n" 173166255Sdelphij" modification, are permitted provided that the following conditions\n" 174166255Sdelphij" are met:\n" 175166255Sdelphij" 1. Redistributions of source code must retain the above copyright\n" 176166255Sdelphij" notice, this list of conditions and the following disclaimer.\n" 177166255Sdelphij" 2. Redistributions in binary form must reproduce the above copyright\n" 178166255Sdelphij" notice, this list of conditions and the following disclaimer in the\n" 179166255Sdelphij" documentation and/or other materials provided with the distribution.\n" 180166255Sdelphij"\n" 181166255Sdelphij" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n" 182166255Sdelphij" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n" 183166255Sdelphij" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n" 184166255Sdelphij" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n" 185166255Sdelphij" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n" 186166255Sdelphij" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n" 187166255Sdelphij" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\n" 188166255Sdelphij" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n" 189166255Sdelphij" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n" 190166255Sdelphij" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n" 191166255Sdelphij" SUCH DAMAGE."; 192166255Sdelphij#endif 193166255Sdelphij 194166255Sdelphijstatic int cflag; /* stdout mode */ 195166255Sdelphijstatic int dflag; /* decompress mode */ 196166255Sdelphijstatic int lflag; /* list mode */ 197166255Sdelphijstatic int numflag = 6; /* gzip -1..-9 value */ 198166255Sdelphij 199326559Sdelphijstatic const char *remove_file = NULL; /* file to be removed upon SIGINT */ 200326559Sdelphij 201326559Sdelphijstatic int fflag; /* force mode */ 202166255Sdelphij#ifndef SMALL 203170053Sdelphijstatic int kflag; /* don't delete input files */ 204166255Sdelphijstatic int nflag; /* don't save name/timestamp */ 205166255Sdelphijstatic int Nflag; /* don't restore name/timestamp */ 206166255Sdelphijstatic int qflag; /* quiet mode */ 207166255Sdelphijstatic int rflag; /* recursive mode */ 208166255Sdelphijstatic int tflag; /* test */ 209166255Sdelphijstatic int vflag; /* verbose mode */ 210326559Sdelphijstatic sig_atomic_t print_info = 0; 211166255Sdelphij#else 212166255Sdelphij#define qflag 0 213166255Sdelphij#define tflag 0 214166255Sdelphij#endif 215166255Sdelphij 216166255Sdelphijstatic int exit_value = 0; /* exit value */ 217166255Sdelphij 218326559Sdelphijstatic const char *infile; /* name of file coming in */ 219166255Sdelphij 220226184Sdelphijstatic void maybe_err(const char *fmt, ...) __printflike(1, 2) __dead2; 221226184Sdelphij#if !defined(NO_BZIP2_SUPPORT) || !defined(NO_PACK_SUPPORT) || \ 222226184Sdelphij !defined(NO_XZ_SUPPORT) 223226184Sdelphijstatic void maybe_errx(const char *fmt, ...) __printflike(1, 2) __dead2; 224166255Sdelphij#endif 225226184Sdelphijstatic void maybe_warn(const char *fmt, ...) __printflike(1, 2); 226226184Sdelphijstatic void maybe_warnx(const char *fmt, ...) __printflike(1, 2); 227166255Sdelphijstatic enum filetype file_gettype(u_char *); 228166255Sdelphij#ifdef SMALL 229166255Sdelphij#define gz_compress(if, of, sz, fn, tm) gz_compress(if, of, sz) 230166255Sdelphij#endif 231166255Sdelphijstatic off_t gz_compress(int, int, off_t *, const char *, uint32_t); 232166255Sdelphijstatic off_t gz_uncompress(int, int, char *, size_t, off_t *, const char *); 233166255Sdelphijstatic off_t file_compress(char *, char *, size_t); 234166255Sdelphijstatic off_t file_uncompress(char *, char *, size_t); 235166255Sdelphijstatic void handle_pathname(char *); 236166255Sdelphijstatic void handle_file(char *, struct stat *); 237166255Sdelphijstatic void handle_stdin(void); 238166255Sdelphijstatic void handle_stdout(void); 239166255Sdelphijstatic void print_ratio(off_t, off_t, FILE *); 240166255Sdelphijstatic void print_list(int fd, off_t, const char *, time_t); 241226184Sdelphijstatic void usage(void) __dead2; 242226184Sdelphijstatic void display_version(void) __dead2; 243166255Sdelphij#ifndef SMALL 244166255Sdelphijstatic void display_license(void); 245166255Sdelphij#endif 246166255Sdelphijstatic const suffixes_t *check_suffix(char *, int); 247166255Sdelphijstatic ssize_t read_retry(int, void *, size_t); 248326559Sdelphijstatic ssize_t write_retry(int, const void *, size_t); 249166255Sdelphij 250166255Sdelphij#ifdef SMALL 251326559Sdelphij#define infile_set(f,t) infile_set(f) 252326559Sdelphij#endif 253326559Sdelphijstatic void infile_set(const char *newinfile, off_t total); 254326559Sdelphij 255326559Sdelphij#ifdef SMALL 256166255Sdelphij#define unlink_input(f, sb) unlink(f) 257326559Sdelphij#define check_siginfo() /* nothing */ 258326559Sdelphij#define setup_signals() /* nothing */ 259326559Sdelphij#define infile_newdata(t) /* nothing */ 260166255Sdelphij#else 261326559Sdelphijstatic off_t infile_total; /* total expected to read/write */ 262326559Sdelphijstatic off_t infile_current; /* current read/write */ 263326559Sdelphij 264326559Sdelphijstatic void check_siginfo(void); 265166255Sdelphijstatic off_t cat_fd(unsigned char *, size_t, off_t *, int fd); 266166255Sdelphijstatic void prepend_gzip(char *, int *, char ***); 267166255Sdelphijstatic void handle_dir(char *); 268166255Sdelphijstatic void print_verbage(const char *, const char *, off_t, off_t); 269166255Sdelphijstatic void print_test(const char *, int); 270166255Sdelphijstatic void copymodes(int fd, const struct stat *, const char *file); 271166255Sdelphijstatic int check_outfile(const char *outfile); 272326559Sdelphijstatic void setup_signals(void); 273326559Sdelphijstatic void infile_newdata(size_t newdata); 274326559Sdelphijstatic void infile_clear(void); 275166255Sdelphij#endif 276166255Sdelphij 277166255Sdelphij#ifndef NO_BZIP2_SUPPORT 278166255Sdelphijstatic off_t unbzip2(int, int, char *, size_t, off_t *); 279166255Sdelphij#endif 280166255Sdelphij 281166255Sdelphij#ifndef NO_COMPRESS_SUPPORT 282166255Sdelphijstatic FILE *zdopen(int); 283166255Sdelphijstatic off_t zuncompress(FILE *, FILE *, char *, size_t, off_t *); 284166255Sdelphij#endif 285166255Sdelphij 286194579Sdelphij#ifndef NO_PACK_SUPPORT 287194579Sdelphijstatic off_t unpack(int, int, char *, size_t, off_t *); 288194579Sdelphij#endif 289194579Sdelphij 290226184Sdelphij#ifndef NO_XZ_SUPPORT 291226184Sdelphijstatic off_t unxz(int, int, char *, size_t, off_t *); 292226184Sdelphij#endif 293166255Sdelphij 294166255Sdelphij#ifdef SMALL 295166255Sdelphij#define getopt_long(a,b,c,d,e) getopt(a,b,c) 296166255Sdelphij#else 297166255Sdelphijstatic const struct option longopts[] = { 298166255Sdelphij { "stdout", no_argument, 0, 'c' }, 299166255Sdelphij { "to-stdout", no_argument, 0, 'c' }, 300166255Sdelphij { "decompress", no_argument, 0, 'd' }, 301166255Sdelphij { "uncompress", no_argument, 0, 'd' }, 302166255Sdelphij { "force", no_argument, 0, 'f' }, 303166255Sdelphij { "help", no_argument, 0, 'h' }, 304170053Sdelphij { "keep", no_argument, 0, 'k' }, 305166255Sdelphij { "list", no_argument, 0, 'l' }, 306166255Sdelphij { "no-name", no_argument, 0, 'n' }, 307166255Sdelphij { "name", no_argument, 0, 'N' }, 308166255Sdelphij { "quiet", no_argument, 0, 'q' }, 309166255Sdelphij { "recursive", no_argument, 0, 'r' }, 310166255Sdelphij { "suffix", required_argument, 0, 'S' }, 311166255Sdelphij { "test", no_argument, 0, 't' }, 312166255Sdelphij { "verbose", no_argument, 0, 'v' }, 313166255Sdelphij { "version", no_argument, 0, 'V' }, 314166255Sdelphij { "fast", no_argument, 0, '1' }, 315166255Sdelphij { "best", no_argument, 0, '9' }, 316166255Sdelphij { "ascii", no_argument, 0, 'a' }, 317166255Sdelphij { "license", no_argument, 0, 'L' }, 318166255Sdelphij { NULL, no_argument, 0, 0 }, 319166255Sdelphij}; 320166255Sdelphij#endif 321166255Sdelphij 322166255Sdelphijint 323166255Sdelphijmain(int argc, char **argv) 324166255Sdelphij{ 325166255Sdelphij const char *progname = getprogname(); 326166255Sdelphij#ifndef SMALL 327166255Sdelphij char *gzip; 328166255Sdelphij int len; 329166255Sdelphij#endif 330166255Sdelphij int ch; 331166255Sdelphij 332326559Sdelphij setup_signals(); 333326559Sdelphij 334166255Sdelphij#ifndef SMALL 335166255Sdelphij if ((gzip = getenv("GZIP")) != NULL) 336166255Sdelphij prepend_gzip(gzip, &argc, &argv); 337166255Sdelphij#endif 338166255Sdelphij 339166255Sdelphij /* 340166255Sdelphij * XXX 341166255Sdelphij * handle being called `gunzip', `zcat' and `gzcat' 342166255Sdelphij */ 343166255Sdelphij if (strcmp(progname, "gunzip") == 0) 344166255Sdelphij dflag = 1; 345166255Sdelphij else if (strcmp(progname, "zcat") == 0 || 346166255Sdelphij strcmp(progname, "gzcat") == 0) 347166255Sdelphij dflag = cflag = 1; 348166255Sdelphij 349166255Sdelphij#ifdef SMALL 350222210Sdelphij#define OPT_LIST "123456789cdhlV" 351166255Sdelphij#else 352170053Sdelphij#define OPT_LIST "123456789acdfhklLNnqrS:tVv" 353166255Sdelphij#endif 354166255Sdelphij 355166255Sdelphij while ((ch = getopt_long(argc, argv, OPT_LIST, longopts, NULL)) != -1) { 356166255Sdelphij switch (ch) { 357166255Sdelphij case '1': case '2': case '3': 358166255Sdelphij case '4': case '5': case '6': 359166255Sdelphij case '7': case '8': case '9': 360166255Sdelphij numflag = ch - '0'; 361166255Sdelphij break; 362166255Sdelphij case 'c': 363166255Sdelphij cflag = 1; 364166255Sdelphij break; 365166255Sdelphij case 'd': 366166255Sdelphij dflag = 1; 367166255Sdelphij break; 368166255Sdelphij case 'l': 369166255Sdelphij lflag = 1; 370166255Sdelphij dflag = 1; 371166255Sdelphij break; 372166255Sdelphij case 'V': 373166255Sdelphij display_version(); 374166255Sdelphij /* NOTREACHED */ 375166255Sdelphij#ifndef SMALL 376166255Sdelphij case 'a': 377166255Sdelphij fprintf(stderr, "%s: option --ascii ignored on this system\n", progname); 378166255Sdelphij break; 379166255Sdelphij case 'f': 380166255Sdelphij fflag = 1; 381166255Sdelphij break; 382170053Sdelphij case 'k': 383170053Sdelphij kflag = 1; 384170053Sdelphij break; 385166255Sdelphij case 'L': 386166255Sdelphij display_license(); 387166255Sdelphij /* NOT REACHED */ 388166255Sdelphij case 'N': 389166255Sdelphij nflag = 0; 390166255Sdelphij Nflag = 1; 391166255Sdelphij break; 392166255Sdelphij case 'n': 393166255Sdelphij nflag = 1; 394166255Sdelphij Nflag = 0; 395166255Sdelphij break; 396166255Sdelphij case 'q': 397166255Sdelphij qflag = 1; 398166255Sdelphij break; 399166255Sdelphij case 'r': 400166255Sdelphij rflag = 1; 401166255Sdelphij break; 402166255Sdelphij case 'S': 403166255Sdelphij len = strlen(optarg); 404166255Sdelphij if (len != 0) { 405195988Sdelphij if (len > SUFFIX_MAXLEN) 406195988Sdelphij errx(1, "incorrect suffix: '%s': too long", optarg); 407166255Sdelphij suffixes[0].zipped = optarg; 408166255Sdelphij suffixes[0].ziplen = len; 409166255Sdelphij } else { 410166255Sdelphij suffixes[NUM_SUFFIXES - 1].zipped = ""; 411166255Sdelphij suffixes[NUM_SUFFIXES - 1].ziplen = 0; 412166255Sdelphij } 413166255Sdelphij break; 414166255Sdelphij case 't': 415166255Sdelphij cflag = 1; 416166255Sdelphij tflag = 1; 417166255Sdelphij dflag = 1; 418166255Sdelphij break; 419166255Sdelphij case 'v': 420166255Sdelphij vflag = 1; 421166255Sdelphij break; 422166255Sdelphij#endif 423166255Sdelphij default: 424166255Sdelphij usage(); 425166255Sdelphij /* NOTREACHED */ 426166255Sdelphij } 427166255Sdelphij } 428166255Sdelphij argv += optind; 429166255Sdelphij argc -= optind; 430166255Sdelphij 431166255Sdelphij if (argc == 0) { 432166255Sdelphij if (dflag) /* stdin mode */ 433166255Sdelphij handle_stdin(); 434166255Sdelphij else /* stdout mode */ 435166255Sdelphij handle_stdout(); 436166255Sdelphij } else { 437166255Sdelphij do { 438166255Sdelphij handle_pathname(argv[0]); 439166255Sdelphij } while (*++argv); 440166255Sdelphij } 441166255Sdelphij#ifndef SMALL 442166255Sdelphij if (qflag == 0 && lflag && argc > 1) 443166255Sdelphij print_list(-1, 0, "(totals)", 0); 444166255Sdelphij#endif 445166255Sdelphij exit(exit_value); 446166255Sdelphij} 447166255Sdelphij 448166255Sdelphij/* maybe print a warning */ 449166255Sdelphijvoid 450166255Sdelphijmaybe_warn(const char *fmt, ...) 451166255Sdelphij{ 452166255Sdelphij va_list ap; 453166255Sdelphij 454166255Sdelphij if (qflag == 0) { 455166255Sdelphij va_start(ap, fmt); 456166255Sdelphij vwarn(fmt, ap); 457166255Sdelphij va_end(ap); 458166255Sdelphij } 459166255Sdelphij if (exit_value == 0) 460166255Sdelphij exit_value = 1; 461166255Sdelphij} 462166255Sdelphij 463166255Sdelphij/* ... without an errno. */ 464166255Sdelphijvoid 465166255Sdelphijmaybe_warnx(const char *fmt, ...) 466166255Sdelphij{ 467166255Sdelphij va_list ap; 468166255Sdelphij 469166255Sdelphij if (qflag == 0) { 470166255Sdelphij va_start(ap, fmt); 471166255Sdelphij vwarnx(fmt, ap); 472166255Sdelphij va_end(ap); 473166255Sdelphij } 474166255Sdelphij if (exit_value == 0) 475166255Sdelphij exit_value = 1; 476166255Sdelphij} 477166255Sdelphij 478166255Sdelphij/* maybe print an error */ 479166255Sdelphijvoid 480166255Sdelphijmaybe_err(const char *fmt, ...) 481166255Sdelphij{ 482166255Sdelphij va_list ap; 483166255Sdelphij 484166255Sdelphij if (qflag == 0) { 485166255Sdelphij va_start(ap, fmt); 486166255Sdelphij vwarn(fmt, ap); 487166255Sdelphij va_end(ap); 488166255Sdelphij } 489166255Sdelphij exit(2); 490166255Sdelphij} 491166255Sdelphij 492226184Sdelphij#if !defined(NO_BZIP2_SUPPORT) || !defined(NO_PACK_SUPPORT) || \ 493226184Sdelphij !defined(NO_XZ_SUPPORT) 494166255Sdelphij/* ... without an errno. */ 495166255Sdelphijvoid 496166255Sdelphijmaybe_errx(const char *fmt, ...) 497166255Sdelphij{ 498166255Sdelphij va_list ap; 499166255Sdelphij 500166255Sdelphij if (qflag == 0) { 501166255Sdelphij va_start(ap, fmt); 502166255Sdelphij vwarnx(fmt, ap); 503166255Sdelphij va_end(ap); 504166255Sdelphij } 505166255Sdelphij exit(2); 506166255Sdelphij} 507166255Sdelphij#endif 508166255Sdelphij 509166255Sdelphij#ifndef SMALL 510166255Sdelphij/* split up $GZIP and prepend it to the argument list */ 511166255Sdelphijstatic void 512166255Sdelphijprepend_gzip(char *gzip, int *argc, char ***argv) 513166255Sdelphij{ 514166255Sdelphij char *s, **nargv, **ac; 515166255Sdelphij int nenvarg = 0, i; 516166255Sdelphij 517166255Sdelphij /* scan how many arguments there are */ 518166255Sdelphij for (s = gzip;;) { 519166255Sdelphij while (*s == ' ' || *s == '\t') 520166255Sdelphij s++; 521166255Sdelphij if (*s == 0) 522166255Sdelphij goto count_done; 523166255Sdelphij nenvarg++; 524166255Sdelphij while (*s != ' ' && *s != '\t') 525166255Sdelphij if (*s++ == 0) 526166255Sdelphij goto count_done; 527166255Sdelphij } 528166255Sdelphijcount_done: 529166255Sdelphij /* punt early */ 530166255Sdelphij if (nenvarg == 0) 531166255Sdelphij return; 532166255Sdelphij 533166255Sdelphij *argc += nenvarg; 534166255Sdelphij ac = *argv; 535166255Sdelphij 536166255Sdelphij nargv = (char **)malloc((*argc + 1) * sizeof(char *)); 537166255Sdelphij if (nargv == NULL) 538166255Sdelphij maybe_err("malloc"); 539166255Sdelphij 540166255Sdelphij /* stash this away */ 541166255Sdelphij *argv = nargv; 542166255Sdelphij 543166255Sdelphij /* copy the program name first */ 544166255Sdelphij i = 0; 545166255Sdelphij nargv[i++] = *(ac++); 546166255Sdelphij 547166255Sdelphij /* take a copy of $GZIP and add it to the array */ 548166255Sdelphij s = strdup(gzip); 549166255Sdelphij if (s == NULL) 550166255Sdelphij maybe_err("strdup"); 551166255Sdelphij for (;;) { 552166255Sdelphij /* Skip whitespaces. */ 553166255Sdelphij while (*s == ' ' || *s == '\t') 554166255Sdelphij s++; 555166255Sdelphij if (*s == 0) 556166255Sdelphij goto copy_done; 557166255Sdelphij nargv[i++] = s; 558166255Sdelphij /* Find the end of this argument. */ 559166255Sdelphij while (*s != ' ' && *s != '\t') 560166255Sdelphij if (*s++ == 0) 561166255Sdelphij /* Argument followed by NUL. */ 562166255Sdelphij goto copy_done; 563166255Sdelphij /* Terminate by overwriting ' ' or '\t' with NUL. */ 564166255Sdelphij *s++ = 0; 565166255Sdelphij } 566166255Sdelphijcopy_done: 567166255Sdelphij 568166255Sdelphij /* copy the original arguments and a NULL */ 569166255Sdelphij while (*ac) 570166255Sdelphij nargv[i++] = *(ac++); 571166255Sdelphij nargv[i] = NULL; 572166255Sdelphij} 573166255Sdelphij#endif 574166255Sdelphij 575166255Sdelphij/* compress input to output. Return bytes read, -1 on error */ 576166255Sdelphijstatic off_t 577166255Sdelphijgz_compress(int in, int out, off_t *gsizep, const char *origname, uint32_t mtime) 578166255Sdelphij{ 579166255Sdelphij z_stream z; 580166255Sdelphij char *outbufp, *inbufp; 581166255Sdelphij off_t in_tot = 0, out_tot = 0; 582166255Sdelphij ssize_t in_size; 583166255Sdelphij int i, error; 584166255Sdelphij uLong crc; 585166255Sdelphij#ifdef SMALL 586166255Sdelphij static char header[] = { GZIP_MAGIC0, GZIP_MAGIC1, Z_DEFLATED, 0, 587166255Sdelphij 0, 0, 0, 0, 588166255Sdelphij 0, OS_CODE }; 589166255Sdelphij#endif 590166255Sdelphij 591166255Sdelphij outbufp = malloc(BUFLEN); 592166255Sdelphij inbufp = malloc(BUFLEN); 593166255Sdelphij if (outbufp == NULL || inbufp == NULL) { 594166255Sdelphij maybe_err("malloc failed"); 595166255Sdelphij goto out; 596166255Sdelphij } 597166255Sdelphij 598166255Sdelphij memset(&z, 0, sizeof z); 599166255Sdelphij z.zalloc = Z_NULL; 600166255Sdelphij z.zfree = Z_NULL; 601166255Sdelphij z.opaque = 0; 602166255Sdelphij 603166255Sdelphij#ifdef SMALL 604166255Sdelphij memcpy(outbufp, header, sizeof header); 605166255Sdelphij i = sizeof header; 606166255Sdelphij#else 607166255Sdelphij if (nflag != 0) { 608166255Sdelphij mtime = 0; 609166255Sdelphij origname = ""; 610166255Sdelphij } 611166255Sdelphij 612326559Sdelphij i = snprintf(outbufp, BUFLEN, "%c%c%c%c%c%c%c%c%c%c%s", 613166255Sdelphij GZIP_MAGIC0, GZIP_MAGIC1, Z_DEFLATED, 614166255Sdelphij *origname ? ORIG_NAME : 0, 615166255Sdelphij mtime & 0xff, 616166255Sdelphij (mtime >> 8) & 0xff, 617166255Sdelphij (mtime >> 16) & 0xff, 618166255Sdelphij (mtime >> 24) & 0xff, 619166255Sdelphij numflag == 1 ? 4 : numflag == 9 ? 2 : 0, 620166255Sdelphij OS_CODE, origname); 621326559Sdelphij if (i >= BUFLEN) 622166255Sdelphij /* this need PATH_MAX > BUFLEN ... */ 623166255Sdelphij maybe_err("snprintf"); 624166255Sdelphij if (*origname) 625166255Sdelphij i++; 626166255Sdelphij#endif 627166255Sdelphij 628166255Sdelphij z.next_out = (unsigned char *)outbufp + i; 629166255Sdelphij z.avail_out = BUFLEN - i; 630166255Sdelphij 631166255Sdelphij error = deflateInit2(&z, numflag, Z_DEFLATED, 632166255Sdelphij (-MAX_WBITS), 8, Z_DEFAULT_STRATEGY); 633166255Sdelphij if (error != Z_OK) { 634166255Sdelphij maybe_warnx("deflateInit2 failed"); 635166255Sdelphij in_tot = -1; 636166255Sdelphij goto out; 637166255Sdelphij } 638166255Sdelphij 639166255Sdelphij crc = crc32(0L, Z_NULL, 0); 640166255Sdelphij for (;;) { 641166255Sdelphij if (z.avail_out == 0) { 642326559Sdelphij if (write_retry(out, outbufp, BUFLEN) != BUFLEN) { 643166255Sdelphij maybe_warn("write"); 644166255Sdelphij out_tot = -1; 645166255Sdelphij goto out; 646166255Sdelphij } 647166255Sdelphij 648166255Sdelphij out_tot += BUFLEN; 649166255Sdelphij z.next_out = (unsigned char *)outbufp; 650166255Sdelphij z.avail_out = BUFLEN; 651166255Sdelphij } 652166255Sdelphij 653166255Sdelphij if (z.avail_in == 0) { 654166255Sdelphij in_size = read(in, inbufp, BUFLEN); 655166255Sdelphij if (in_size < 0) { 656166255Sdelphij maybe_warn("read"); 657166255Sdelphij in_tot = -1; 658166255Sdelphij goto out; 659166255Sdelphij } 660166255Sdelphij if (in_size == 0) 661166255Sdelphij break; 662326559Sdelphij infile_newdata(in_size); 663166255Sdelphij 664166255Sdelphij crc = crc32(crc, (const Bytef *)inbufp, (unsigned)in_size); 665166255Sdelphij in_tot += in_size; 666166255Sdelphij z.next_in = (unsigned char *)inbufp; 667166255Sdelphij z.avail_in = in_size; 668166255Sdelphij } 669166255Sdelphij 670166255Sdelphij error = deflate(&z, Z_NO_FLUSH); 671166255Sdelphij if (error != Z_OK && error != Z_STREAM_END) { 672166255Sdelphij maybe_warnx("deflate failed"); 673166255Sdelphij in_tot = -1; 674166255Sdelphij goto out; 675166255Sdelphij } 676166255Sdelphij } 677166255Sdelphij 678166255Sdelphij /* clean up */ 679166255Sdelphij for (;;) { 680166255Sdelphij size_t len; 681166255Sdelphij ssize_t w; 682166255Sdelphij 683166255Sdelphij error = deflate(&z, Z_FINISH); 684166255Sdelphij if (error != Z_OK && error != Z_STREAM_END) { 685166255Sdelphij maybe_warnx("deflate failed"); 686166255Sdelphij in_tot = -1; 687166255Sdelphij goto out; 688166255Sdelphij } 689166255Sdelphij 690166255Sdelphij len = (char *)z.next_out - outbufp; 691166255Sdelphij 692326559Sdelphij w = write_retry(out, outbufp, len); 693166255Sdelphij if (w == -1 || (size_t)w != len) { 694166255Sdelphij maybe_warn("write"); 695166255Sdelphij out_tot = -1; 696166255Sdelphij goto out; 697166255Sdelphij } 698166255Sdelphij out_tot += len; 699166255Sdelphij z.next_out = (unsigned char *)outbufp; 700166255Sdelphij z.avail_out = BUFLEN; 701166255Sdelphij 702166255Sdelphij if (error == Z_STREAM_END) 703166255Sdelphij break; 704166255Sdelphij } 705166255Sdelphij 706166255Sdelphij if (deflateEnd(&z) != Z_OK) { 707166255Sdelphij maybe_warnx("deflateEnd failed"); 708166255Sdelphij in_tot = -1; 709166255Sdelphij goto out; 710166255Sdelphij } 711166255Sdelphij 712326559Sdelphij i = snprintf(outbufp, BUFLEN, "%c%c%c%c%c%c%c%c", 713166255Sdelphij (int)crc & 0xff, 714166255Sdelphij (int)(crc >> 8) & 0xff, 715166255Sdelphij (int)(crc >> 16) & 0xff, 716166255Sdelphij (int)(crc >> 24) & 0xff, 717166255Sdelphij (int)in_tot & 0xff, 718166255Sdelphij (int)(in_tot >> 8) & 0xff, 719166255Sdelphij (int)(in_tot >> 16) & 0xff, 720166255Sdelphij (int)(in_tot >> 24) & 0xff); 721166255Sdelphij if (i != 8) 722166255Sdelphij maybe_err("snprintf"); 723326559Sdelphij if (write_retry(out, outbufp, i) != i) { 724166255Sdelphij maybe_warn("write"); 725166255Sdelphij in_tot = -1; 726166255Sdelphij } else 727166255Sdelphij out_tot += i; 728166255Sdelphij 729166255Sdelphijout: 730166255Sdelphij if (inbufp != NULL) 731166255Sdelphij free(inbufp); 732166255Sdelphij if (outbufp != NULL) 733166255Sdelphij free(outbufp); 734166255Sdelphij if (gsizep) 735166255Sdelphij *gsizep = out_tot; 736166255Sdelphij return in_tot; 737166255Sdelphij} 738166255Sdelphij 739166255Sdelphij/* 740166255Sdelphij * uncompress input to output then close the input. return the 741166255Sdelphij * uncompressed size written, and put the compressed sized read 742166255Sdelphij * into `*gsizep'. 743166255Sdelphij */ 744166255Sdelphijstatic off_t 745166255Sdelphijgz_uncompress(int in, int out, char *pre, size_t prelen, off_t *gsizep, 746166255Sdelphij const char *filename) 747166255Sdelphij{ 748166255Sdelphij z_stream z; 749166255Sdelphij char *outbufp, *inbufp; 750166255Sdelphij off_t out_tot = -1, in_tot = 0; 751166255Sdelphij uint32_t out_sub_tot = 0; 752166255Sdelphij enum { 753166255Sdelphij GZSTATE_MAGIC0, 754166255Sdelphij GZSTATE_MAGIC1, 755166255Sdelphij GZSTATE_METHOD, 756166255Sdelphij GZSTATE_FLAGS, 757166255Sdelphij GZSTATE_SKIPPING, 758166255Sdelphij GZSTATE_EXTRA, 759166255Sdelphij GZSTATE_EXTRA2, 760166255Sdelphij GZSTATE_EXTRA3, 761166255Sdelphij GZSTATE_ORIGNAME, 762166255Sdelphij GZSTATE_COMMENT, 763166255Sdelphij GZSTATE_HEAD_CRC1, 764166255Sdelphij GZSTATE_HEAD_CRC2, 765166255Sdelphij GZSTATE_INIT, 766166255Sdelphij GZSTATE_READ, 767166255Sdelphij GZSTATE_CRC, 768166255Sdelphij GZSTATE_LEN, 769166255Sdelphij } state = GZSTATE_MAGIC0; 770166255Sdelphij int flags = 0, skip_count = 0; 771166255Sdelphij int error = Z_STREAM_ERROR, done_reading = 0; 772166255Sdelphij uLong crc = 0; 773166255Sdelphij ssize_t wr; 774166255Sdelphij int needmore = 0; 775166255Sdelphij 776166255Sdelphij#define ADVANCE() { z.next_in++; z.avail_in--; } 777166255Sdelphij 778166255Sdelphij if ((outbufp = malloc(BUFLEN)) == NULL) { 779166255Sdelphij maybe_err("malloc failed"); 780166255Sdelphij goto out2; 781166255Sdelphij } 782166255Sdelphij if ((inbufp = malloc(BUFLEN)) == NULL) { 783166255Sdelphij maybe_err("malloc failed"); 784166255Sdelphij goto out1; 785166255Sdelphij } 786166255Sdelphij 787166255Sdelphij memset(&z, 0, sizeof z); 788166255Sdelphij z.avail_in = prelen; 789166255Sdelphij z.next_in = (unsigned char *)pre; 790166255Sdelphij z.avail_out = BUFLEN; 791166255Sdelphij z.next_out = (unsigned char *)outbufp; 792166255Sdelphij z.zalloc = NULL; 793166255Sdelphij z.zfree = NULL; 794166255Sdelphij z.opaque = 0; 795166255Sdelphij 796166255Sdelphij in_tot = prelen; 797166255Sdelphij out_tot = 0; 798166255Sdelphij 799166255Sdelphij for (;;) { 800326559Sdelphij check_siginfo(); 801166255Sdelphij if ((z.avail_in == 0 || needmore) && done_reading == 0) { 802166255Sdelphij ssize_t in_size; 803166255Sdelphij 804166255Sdelphij if (z.avail_in > 0) { 805166255Sdelphij memmove(inbufp, z.next_in, z.avail_in); 806166255Sdelphij } 807166255Sdelphij z.next_in = (unsigned char *)inbufp; 808166255Sdelphij in_size = read(in, z.next_in + z.avail_in, 809166255Sdelphij BUFLEN - z.avail_in); 810166255Sdelphij 811166255Sdelphij if (in_size == -1) { 812166255Sdelphij maybe_warn("failed to read stdin"); 813166255Sdelphij goto stop_and_fail; 814166255Sdelphij } else if (in_size == 0) { 815166255Sdelphij done_reading = 1; 816166255Sdelphij } 817326559Sdelphij infile_newdata(in_size); 818166255Sdelphij 819166255Sdelphij z.avail_in += in_size; 820166255Sdelphij needmore = 0; 821166255Sdelphij 822166255Sdelphij in_tot += in_size; 823166255Sdelphij } 824166255Sdelphij if (z.avail_in == 0) { 825166255Sdelphij if (done_reading && state != GZSTATE_MAGIC0) { 826166255Sdelphij maybe_warnx("%s: unexpected end of file", 827166255Sdelphij filename); 828166255Sdelphij goto stop_and_fail; 829166255Sdelphij } 830166255Sdelphij goto stop; 831166255Sdelphij } 832166255Sdelphij switch (state) { 833166255Sdelphij case GZSTATE_MAGIC0: 834166255Sdelphij if (*z.next_in != GZIP_MAGIC0) { 835166255Sdelphij if (in_tot > 0) { 836166255Sdelphij maybe_warnx("%s: trailing garbage " 837166255Sdelphij "ignored", filename); 838290024Sdelphij exit_value = 2; 839166255Sdelphij goto stop; 840166255Sdelphij } 841166255Sdelphij maybe_warnx("input not gziped (MAGIC0)"); 842166255Sdelphij goto stop_and_fail; 843166255Sdelphij } 844166255Sdelphij ADVANCE(); 845166255Sdelphij state++; 846166255Sdelphij out_sub_tot = 0; 847166255Sdelphij crc = crc32(0L, Z_NULL, 0); 848166255Sdelphij break; 849166255Sdelphij 850166255Sdelphij case GZSTATE_MAGIC1: 851166255Sdelphij if (*z.next_in != GZIP_MAGIC1 && 852166255Sdelphij *z.next_in != GZIP_OMAGIC1) { 853166255Sdelphij maybe_warnx("input not gziped (MAGIC1)"); 854166255Sdelphij goto stop_and_fail; 855166255Sdelphij } 856166255Sdelphij ADVANCE(); 857166255Sdelphij state++; 858166255Sdelphij break; 859166255Sdelphij 860166255Sdelphij case GZSTATE_METHOD: 861166255Sdelphij if (*z.next_in != Z_DEFLATED) { 862166255Sdelphij maybe_warnx("unknown compression method"); 863166255Sdelphij goto stop_and_fail; 864166255Sdelphij } 865166255Sdelphij ADVANCE(); 866166255Sdelphij state++; 867166255Sdelphij break; 868166255Sdelphij 869166255Sdelphij case GZSTATE_FLAGS: 870166255Sdelphij flags = *z.next_in; 871166255Sdelphij ADVANCE(); 872166255Sdelphij skip_count = 6; 873166255Sdelphij state++; 874166255Sdelphij break; 875166255Sdelphij 876166255Sdelphij case GZSTATE_SKIPPING: 877166255Sdelphij if (skip_count > 0) { 878166255Sdelphij skip_count--; 879166255Sdelphij ADVANCE(); 880166255Sdelphij } else 881166255Sdelphij state++; 882166255Sdelphij break; 883166255Sdelphij 884166255Sdelphij case GZSTATE_EXTRA: 885166255Sdelphij if ((flags & EXTRA_FIELD) == 0) { 886166255Sdelphij state = GZSTATE_ORIGNAME; 887166255Sdelphij break; 888166255Sdelphij } 889166255Sdelphij skip_count = *z.next_in; 890166255Sdelphij ADVANCE(); 891166255Sdelphij state++; 892166255Sdelphij break; 893166255Sdelphij 894166255Sdelphij case GZSTATE_EXTRA2: 895166255Sdelphij skip_count |= ((*z.next_in) << 8); 896166255Sdelphij ADVANCE(); 897166255Sdelphij state++; 898166255Sdelphij break; 899166255Sdelphij 900166255Sdelphij case GZSTATE_EXTRA3: 901166255Sdelphij if (skip_count > 0) { 902166255Sdelphij skip_count--; 903166255Sdelphij ADVANCE(); 904166255Sdelphij } else 905166255Sdelphij state++; 906166255Sdelphij break; 907166255Sdelphij 908166255Sdelphij case GZSTATE_ORIGNAME: 909166255Sdelphij if ((flags & ORIG_NAME) == 0) { 910166255Sdelphij state++; 911166255Sdelphij break; 912166255Sdelphij } 913166255Sdelphij if (*z.next_in == 0) 914166255Sdelphij state++; 915166255Sdelphij ADVANCE(); 916166255Sdelphij break; 917166255Sdelphij 918166255Sdelphij case GZSTATE_COMMENT: 919166255Sdelphij if ((flags & COMMENT) == 0) { 920166255Sdelphij state++; 921166255Sdelphij break; 922166255Sdelphij } 923166255Sdelphij if (*z.next_in == 0) 924166255Sdelphij state++; 925166255Sdelphij ADVANCE(); 926166255Sdelphij break; 927166255Sdelphij 928166255Sdelphij case GZSTATE_HEAD_CRC1: 929166255Sdelphij if (flags & HEAD_CRC) 930166255Sdelphij skip_count = 2; 931166255Sdelphij else 932166255Sdelphij skip_count = 0; 933166255Sdelphij state++; 934166255Sdelphij break; 935166255Sdelphij 936166255Sdelphij case GZSTATE_HEAD_CRC2: 937166255Sdelphij if (skip_count > 0) { 938166255Sdelphij skip_count--; 939166255Sdelphij ADVANCE(); 940166255Sdelphij } else 941166255Sdelphij state++; 942166255Sdelphij break; 943166255Sdelphij 944166255Sdelphij case GZSTATE_INIT: 945166255Sdelphij if (inflateInit2(&z, -MAX_WBITS) != Z_OK) { 946166255Sdelphij maybe_warnx("failed to inflateInit"); 947166255Sdelphij goto stop_and_fail; 948166255Sdelphij } 949166255Sdelphij state++; 950166255Sdelphij break; 951166255Sdelphij 952166255Sdelphij case GZSTATE_READ: 953166255Sdelphij error = inflate(&z, Z_FINISH); 954166255Sdelphij switch (error) { 955166255Sdelphij /* Z_BUF_ERROR goes with Z_FINISH... */ 956166255Sdelphij case Z_BUF_ERROR: 957213044Sdelphij if (z.avail_out > 0 && !done_reading) 958213044Sdelphij continue; 959222210Sdelphij 960166255Sdelphij case Z_STREAM_END: 961166255Sdelphij case Z_OK: 962166255Sdelphij break; 963166255Sdelphij 964166255Sdelphij case Z_NEED_DICT: 965166255Sdelphij maybe_warnx("Z_NEED_DICT error"); 966166255Sdelphij goto stop_and_fail; 967166255Sdelphij case Z_DATA_ERROR: 968166255Sdelphij maybe_warnx("data stream error"); 969166255Sdelphij goto stop_and_fail; 970166255Sdelphij case Z_STREAM_ERROR: 971166255Sdelphij maybe_warnx("internal stream error"); 972166255Sdelphij goto stop_and_fail; 973166255Sdelphij case Z_MEM_ERROR: 974166255Sdelphij maybe_warnx("memory allocation error"); 975166255Sdelphij goto stop_and_fail; 976166255Sdelphij 977166255Sdelphij default: 978166255Sdelphij maybe_warn("unknown error from inflate(): %d", 979166255Sdelphij error); 980166255Sdelphij } 981166255Sdelphij wr = BUFLEN - z.avail_out; 982166255Sdelphij 983166255Sdelphij if (wr != 0) { 984166255Sdelphij crc = crc32(crc, (const Bytef *)outbufp, (unsigned)wr); 985166255Sdelphij if ( 986166255Sdelphij#ifndef SMALL 987166255Sdelphij /* don't write anything with -t */ 988166255Sdelphij tflag == 0 && 989166255Sdelphij#endif 990326559Sdelphij write_retry(out, outbufp, wr) != wr) { 991166255Sdelphij maybe_warn("error writing to output"); 992166255Sdelphij goto stop_and_fail; 993166255Sdelphij } 994166255Sdelphij 995166255Sdelphij out_tot += wr; 996166255Sdelphij out_sub_tot += wr; 997166255Sdelphij } 998166255Sdelphij 999166255Sdelphij if (error == Z_STREAM_END) { 1000166255Sdelphij inflateEnd(&z); 1001166255Sdelphij state++; 1002166255Sdelphij } 1003166255Sdelphij 1004166255Sdelphij z.next_out = (unsigned char *)outbufp; 1005166255Sdelphij z.avail_out = BUFLEN; 1006166255Sdelphij 1007166255Sdelphij break; 1008166255Sdelphij case GZSTATE_CRC: 1009166255Sdelphij { 1010166255Sdelphij uLong origcrc; 1011166255Sdelphij 1012166255Sdelphij if (z.avail_in < 4) { 1013166255Sdelphij if (!done_reading) { 1014166255Sdelphij needmore = 1; 1015166255Sdelphij continue; 1016166255Sdelphij } 1017166255Sdelphij maybe_warnx("truncated input"); 1018166255Sdelphij goto stop_and_fail; 1019166255Sdelphij } 1020336661Sdelphij origcrc = le32dec(&z.next_in[0]); 1021166255Sdelphij if (origcrc != crc) { 1022166255Sdelphij maybe_warnx("invalid compressed" 1023166255Sdelphij " data--crc error"); 1024166255Sdelphij goto stop_and_fail; 1025166255Sdelphij } 1026166255Sdelphij } 1027166255Sdelphij 1028166255Sdelphij z.avail_in -= 4; 1029166255Sdelphij z.next_in += 4; 1030166255Sdelphij 1031166255Sdelphij if (!z.avail_in && done_reading) { 1032166255Sdelphij goto stop; 1033166255Sdelphij } 1034166255Sdelphij state++; 1035166255Sdelphij break; 1036166255Sdelphij case GZSTATE_LEN: 1037166255Sdelphij { 1038166255Sdelphij uLong origlen; 1039166255Sdelphij 1040166255Sdelphij if (z.avail_in < 4) { 1041166255Sdelphij if (!done_reading) { 1042166255Sdelphij needmore = 1; 1043166255Sdelphij continue; 1044166255Sdelphij } 1045166255Sdelphij maybe_warnx("truncated input"); 1046166255Sdelphij goto stop_and_fail; 1047166255Sdelphij } 1048336661Sdelphij origlen = le32dec(&z.next_in[0]); 1049166255Sdelphij 1050166255Sdelphij if (origlen != out_sub_tot) { 1051166255Sdelphij maybe_warnx("invalid compressed" 1052166255Sdelphij " data--length error"); 1053166255Sdelphij goto stop_and_fail; 1054166255Sdelphij } 1055166255Sdelphij } 1056166255Sdelphij 1057166255Sdelphij z.avail_in -= 4; 1058166255Sdelphij z.next_in += 4; 1059166255Sdelphij 1060166255Sdelphij if (error < 0) { 1061166255Sdelphij maybe_warnx("decompression error"); 1062166255Sdelphij goto stop_and_fail; 1063166255Sdelphij } 1064166255Sdelphij state = GZSTATE_MAGIC0; 1065166255Sdelphij break; 1066166255Sdelphij } 1067166255Sdelphij continue; 1068166255Sdelphijstop_and_fail: 1069166255Sdelphij out_tot = -1; 1070166255Sdelphijstop: 1071166255Sdelphij break; 1072166255Sdelphij } 1073166255Sdelphij if (state > GZSTATE_INIT) 1074166255Sdelphij inflateEnd(&z); 1075166255Sdelphij 1076166255Sdelphij free(inbufp); 1077166255Sdelphijout1: 1078166255Sdelphij free(outbufp); 1079166255Sdelphijout2: 1080166255Sdelphij if (gsizep) 1081166255Sdelphij *gsizep = in_tot; 1082166255Sdelphij return (out_tot); 1083166255Sdelphij} 1084166255Sdelphij 1085166255Sdelphij#ifndef SMALL 1086166255Sdelphij/* 1087166255Sdelphij * set the owner, mode, flags & utimes using the given file descriptor. 1088166255Sdelphij * file is only used in possible warning messages. 1089166255Sdelphij */ 1090166255Sdelphijstatic void 1091166255Sdelphijcopymodes(int fd, const struct stat *sbp, const char *file) 1092166255Sdelphij{ 1093278896Sjilles struct timespec times[2]; 1094166255Sdelphij struct stat sb; 1095166255Sdelphij 1096166255Sdelphij /* 1097166255Sdelphij * If we have no info on the input, give this file some 1098166255Sdelphij * default values and return.. 1099166255Sdelphij */ 1100166255Sdelphij if (sbp == NULL) { 1101166255Sdelphij mode_t mask = umask(022); 1102166255Sdelphij 1103166255Sdelphij (void)fchmod(fd, DEFFILEMODE & ~mask); 1104166255Sdelphij (void)umask(mask); 1105326559Sdelphij return; 1106166255Sdelphij } 1107166255Sdelphij sb = *sbp; 1108166255Sdelphij 1109166255Sdelphij /* if the chown fails, remove set-id bits as-per compress(1) */ 1110166255Sdelphij if (fchown(fd, sb.st_uid, sb.st_gid) < 0) { 1111166255Sdelphij if (errno != EPERM) 1112166255Sdelphij maybe_warn("couldn't fchown: %s", file); 1113166255Sdelphij sb.st_mode &= ~(S_ISUID|S_ISGID); 1114166255Sdelphij } 1115166255Sdelphij 1116166255Sdelphij /* we only allow set-id and the 9 normal permission bits */ 1117166255Sdelphij sb.st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO; 1118166255Sdelphij if (fchmod(fd, sb.st_mode) < 0) 1119166255Sdelphij maybe_warn("couldn't fchmod: %s", file); 1120166255Sdelphij 1121278896Sjilles times[0] = sb.st_atim; 1122278896Sjilles times[1] = sb.st_mtim; 1123278896Sjilles if (futimens(fd, times) < 0) 1124278896Sjilles maybe_warn("couldn't futimens: %s", file); 1125176970Srwatson 1126176970Srwatson /* only try flags if they exist already */ 1127176970Srwatson if (sb.st_flags != 0 && fchflags(fd, sb.st_flags) < 0) 1128176970Srwatson maybe_warn("couldn't fchflags: %s", file); 1129166255Sdelphij} 1130166255Sdelphij#endif 1131166255Sdelphij 1132166255Sdelphij/* what sort of file is this? */ 1133166255Sdelphijstatic enum filetype 1134166255Sdelphijfile_gettype(u_char *buf) 1135166255Sdelphij{ 1136166255Sdelphij 1137166255Sdelphij if (buf[0] == GZIP_MAGIC0 && 1138166255Sdelphij (buf[1] == GZIP_MAGIC1 || buf[1] == GZIP_OMAGIC1)) 1139166255Sdelphij return FT_GZIP; 1140166255Sdelphij else 1141166255Sdelphij#ifndef NO_BZIP2_SUPPORT 1142166255Sdelphij if (memcmp(buf, BZIP2_MAGIC, 3) == 0 && 1143166255Sdelphij buf[3] >= '0' && buf[3] <= '9') 1144166255Sdelphij return FT_BZIP2; 1145166255Sdelphij else 1146166255Sdelphij#endif 1147166255Sdelphij#ifndef NO_COMPRESS_SUPPORT 1148166255Sdelphij if (memcmp(buf, Z_MAGIC, 2) == 0) 1149166255Sdelphij return FT_Z; 1150166255Sdelphij else 1151166255Sdelphij#endif 1152194579Sdelphij#ifndef NO_PACK_SUPPORT 1153194579Sdelphij if (memcmp(buf, PACK_MAGIC, 2) == 0) 1154194579Sdelphij return FT_PACK; 1155194579Sdelphij else 1156194579Sdelphij#endif 1157226184Sdelphij#ifndef NO_XZ_SUPPORT 1158226184Sdelphij if (memcmp(buf, XZ_MAGIC, 4) == 0) /* XXX: We only have 4 bytes */ 1159226184Sdelphij return FT_XZ; 1160226184Sdelphij else 1161226184Sdelphij#endif 1162166255Sdelphij return FT_UNKNOWN; 1163166255Sdelphij} 1164166255Sdelphij 1165166255Sdelphij#ifndef SMALL 1166166255Sdelphij/* check the outfile is OK. */ 1167166255Sdelphijstatic int 1168166255Sdelphijcheck_outfile(const char *outfile) 1169166255Sdelphij{ 1170166255Sdelphij struct stat sb; 1171166255Sdelphij int ok = 1; 1172166255Sdelphij 1173166255Sdelphij if (lflag == 0 && stat(outfile, &sb) == 0) { 1174166255Sdelphij if (fflag) 1175166255Sdelphij unlink(outfile); 1176166255Sdelphij else if (isatty(STDIN_FILENO)) { 1177166255Sdelphij char ans[10] = { 'n', '\0' }; /* default */ 1178166255Sdelphij 1179166255Sdelphij fprintf(stderr, "%s already exists -- do you wish to " 1180166255Sdelphij "overwrite (y or n)? " , outfile); 1181166255Sdelphij (void)fgets(ans, sizeof(ans) - 1, stdin); 1182166255Sdelphij if (ans[0] != 'y' && ans[0] != 'Y') { 1183166363Sdelphij fprintf(stderr, "\tnot overwriting\n"); 1184166255Sdelphij ok = 0; 1185166255Sdelphij } else 1186166255Sdelphij unlink(outfile); 1187166255Sdelphij } else { 1188166255Sdelphij maybe_warnx("%s already exists -- skipping", outfile); 1189166255Sdelphij ok = 0; 1190166255Sdelphij } 1191166255Sdelphij } 1192166255Sdelphij return ok; 1193166255Sdelphij} 1194166255Sdelphij 1195166255Sdelphijstatic void 1196166255Sdelphijunlink_input(const char *file, const struct stat *sb) 1197166255Sdelphij{ 1198166255Sdelphij struct stat nsb; 1199166255Sdelphij 1200170053Sdelphij if (kflag) 1201170053Sdelphij return; 1202166255Sdelphij if (stat(file, &nsb) != 0) 1203213927Sbcr /* Must be gone already */ 1204166255Sdelphij return; 1205166255Sdelphij if (nsb.st_dev != sb->st_dev || nsb.st_ino != sb->st_ino) 1206166255Sdelphij /* Definitely a different file */ 1207166255Sdelphij return; 1208166255Sdelphij unlink(file); 1209166255Sdelphij} 1210207247Sdelphij 1211207247Sdelphijstatic void 1212326559Sdelphijgot_sigint(int signo __unused) 1213207247Sdelphij{ 1214207247Sdelphij 1215207247Sdelphij if (remove_file != NULL) 1216207247Sdelphij unlink(remove_file); 1217207284Sdelphij _exit(2); 1218207247Sdelphij} 1219326559Sdelphij 1220326559Sdelphijstatic void 1221326559Sdelphijgot_siginfo(int signo __unused) 1222326559Sdelphij{ 1223326559Sdelphij 1224326559Sdelphij print_info = 1; 1225326559Sdelphij} 1226326559Sdelphij 1227326559Sdelphijstatic void 1228326559Sdelphijsetup_signals(void) 1229326559Sdelphij{ 1230326559Sdelphij 1231326559Sdelphij signal(SIGINFO, got_siginfo); 1232326559Sdelphij signal(SIGINT, got_sigint); 1233326559Sdelphij} 1234326559Sdelphij 1235326559Sdelphijstatic void 1236326559Sdelphijinfile_newdata(size_t newdata) 1237326559Sdelphij{ 1238326559Sdelphij 1239326559Sdelphij infile_current += newdata; 1240326559Sdelphij} 1241166255Sdelphij#endif 1242166255Sdelphij 1243326559Sdelphijstatic void 1244326559Sdelphijinfile_set(const char *newinfile, off_t total) 1245326559Sdelphij{ 1246326559Sdelphij 1247326559Sdelphij if (newinfile) 1248326559Sdelphij infile = newinfile; 1249326559Sdelphij#ifndef SMALL 1250326559Sdelphij infile_total = total; 1251326559Sdelphij#endif 1252326559Sdelphij} 1253326559Sdelphij 1254326559Sdelphijstatic void 1255326559Sdelphijinfile_clear(void) 1256326559Sdelphij{ 1257326559Sdelphij 1258326559Sdelphij infile = NULL; 1259326559Sdelphij#ifndef SMALL 1260326559Sdelphij infile_total = infile_current = 0; 1261326559Sdelphij#endif 1262326559Sdelphij} 1263326559Sdelphij 1264166255Sdelphijstatic const suffixes_t * 1265166255Sdelphijcheck_suffix(char *file, int xlate) 1266166255Sdelphij{ 1267166255Sdelphij const suffixes_t *s; 1268166255Sdelphij int len = strlen(file); 1269166255Sdelphij char *sp; 1270166255Sdelphij 1271166255Sdelphij for (s = suffixes; s != suffixes + NUM_SUFFIXES; s++) { 1272166255Sdelphij /* if it doesn't fit in "a.suf", don't bother */ 1273166255Sdelphij if (s->ziplen >= len) 1274166255Sdelphij continue; 1275166255Sdelphij sp = file + len - s->ziplen; 1276166255Sdelphij if (strcmp(s->zipped, sp) != 0) 1277166255Sdelphij continue; 1278166255Sdelphij if (xlate) 1279166255Sdelphij strcpy(sp, s->normal); 1280166255Sdelphij return s; 1281166255Sdelphij } 1282166255Sdelphij return NULL; 1283166255Sdelphij} 1284166255Sdelphij 1285166255Sdelphij/* 1286166255Sdelphij * compress the given file: create a corresponding .gz file and remove the 1287166255Sdelphij * original. 1288166255Sdelphij */ 1289166255Sdelphijstatic off_t 1290166255Sdelphijfile_compress(char *file, char *outfile, size_t outsize) 1291166255Sdelphij{ 1292166255Sdelphij int in; 1293166255Sdelphij int out; 1294326559Sdelphij off_t size, in_size; 1295166255Sdelphij#ifndef SMALL 1296166255Sdelphij struct stat isb, osb; 1297166255Sdelphij const suffixes_t *suff; 1298166255Sdelphij#endif 1299166255Sdelphij 1300166255Sdelphij in = open(file, O_RDONLY); 1301166255Sdelphij if (in == -1) { 1302166255Sdelphij maybe_warn("can't open %s", file); 1303209017Sdelphij return (-1); 1304166255Sdelphij } 1305166255Sdelphij 1306208888Sdelphij#ifndef SMALL 1307208888Sdelphij if (fstat(in, &isb) != 0) { 1308208888Sdelphij maybe_warn("couldn't stat: %s", file); 1309208888Sdelphij close(in); 1310209017Sdelphij return (-1); 1311208888Sdelphij } 1312208888Sdelphij#endif 1313208888Sdelphij 1314326559Sdelphij#ifndef SMALL 1315326559Sdelphij if (fstat(in, &isb) != 0) { 1316326559Sdelphij close(in); 1317326559Sdelphij maybe_warn("can't stat %s", file); 1318326559Sdelphij return -1; 1319326559Sdelphij } 1320326559Sdelphij infile_set(file, isb.st_size); 1321326559Sdelphij#endif 1322326559Sdelphij 1323166255Sdelphij if (cflag == 0) { 1324166255Sdelphij#ifndef SMALL 1325209017Sdelphij if (isb.st_nlink > 1 && fflag == 0) { 1326326559Sdelphij maybe_warnx("%s has %ju other link%s -- " 1327326559Sdelphij "skipping", file, 1328326559Sdelphij (uintmax_t)isb.st_nlink - 1, 1329326559Sdelphij isb.st_nlink == 1 ? "" : "s"); 1330208889Sdelphij close(in); 1331326559Sdelphij return -1; 1332208889Sdelphij } 1333166255Sdelphij 1334209017Sdelphij if (fflag == 0 && (suff = check_suffix(file, 0)) && 1335209017Sdelphij suff->zipped[0] != 0) { 1336166255Sdelphij maybe_warnx("%s already has %s suffix -- unchanged", 1337209017Sdelphij file, suff->zipped); 1338166255Sdelphij close(in); 1339209017Sdelphij return (-1); 1340166255Sdelphij } 1341166255Sdelphij#endif 1342166255Sdelphij 1343166255Sdelphij /* Add (usually) .gz to filename */ 1344166255Sdelphij if ((size_t)snprintf(outfile, outsize, "%s%s", 1345209017Sdelphij file, suffixes[0].zipped) >= outsize) 1346195988Sdelphij memcpy(outfile + outsize - suffixes[0].ziplen - 1, 1347209017Sdelphij suffixes[0].zipped, suffixes[0].ziplen + 1); 1348166255Sdelphij 1349166255Sdelphij#ifndef SMALL 1350166255Sdelphij if (check_outfile(outfile) == 0) { 1351166255Sdelphij close(in); 1352209017Sdelphij return (-1); 1353166255Sdelphij } 1354166255Sdelphij#endif 1355166255Sdelphij } 1356166255Sdelphij 1357166255Sdelphij if (cflag == 0) { 1358166255Sdelphij out = open(outfile, O_WRONLY | O_CREAT | O_EXCL, 0600); 1359166255Sdelphij if (out == -1) { 1360166255Sdelphij maybe_warn("could not create output: %s", outfile); 1361166255Sdelphij fclose(stdin); 1362209017Sdelphij return (-1); 1363166255Sdelphij } 1364207247Sdelphij#ifndef SMALL 1365207247Sdelphij remove_file = outfile; 1366207247Sdelphij#endif 1367166255Sdelphij } else 1368166255Sdelphij out = STDOUT_FILENO; 1369166255Sdelphij 1370326559Sdelphij in_size = gz_compress(in, out, &size, basename(file), (uint32_t)isb.st_mtime); 1371166255Sdelphij 1372166255Sdelphij (void)close(in); 1373166255Sdelphij 1374166255Sdelphij /* 1375326559Sdelphij * If there was an error, in_size will be -1. 1376166255Sdelphij * If we compressed to stdout, just return the size. 1377166255Sdelphij * Otherwise stat the file and check it is the correct size. 1378166255Sdelphij * We only blow away the file if we can stat the output and it 1379166255Sdelphij * has the expected size. 1380166255Sdelphij */ 1381166255Sdelphij if (cflag != 0) 1382326559Sdelphij return in_size == -1 ? -1 : size; 1383166255Sdelphij 1384166255Sdelphij#ifndef SMALL 1385166255Sdelphij if (fstat(out, &osb) != 0) { 1386166255Sdelphij maybe_warn("couldn't stat: %s", outfile); 1387166255Sdelphij goto bad_outfile; 1388166255Sdelphij } 1389166255Sdelphij 1390166255Sdelphij if (osb.st_size != size) { 1391209017Sdelphij maybe_warnx("output file: %s wrong size (%ju != %ju), deleting", 1392209017Sdelphij outfile, (uintmax_t)osb.st_size, (uintmax_t)size); 1393166255Sdelphij goto bad_outfile; 1394166255Sdelphij } 1395166255Sdelphij 1396166255Sdelphij copymodes(out, &isb, outfile); 1397207247Sdelphij remove_file = NULL; 1398166255Sdelphij#endif 1399166255Sdelphij if (close(out) == -1) 1400166255Sdelphij maybe_warn("couldn't close output"); 1401166255Sdelphij 1402166255Sdelphij /* output is good, ok to delete input */ 1403166255Sdelphij unlink_input(file, &isb); 1404209017Sdelphij return (size); 1405166255Sdelphij 1406166255Sdelphij#ifndef SMALL 1407166255Sdelphij bad_outfile: 1408166255Sdelphij if (close(out) == -1) 1409166255Sdelphij maybe_warn("couldn't close output"); 1410166255Sdelphij 1411166255Sdelphij maybe_warnx("leaving original %s", file); 1412166255Sdelphij unlink(outfile); 1413209017Sdelphij return (size); 1414166255Sdelphij#endif 1415166255Sdelphij} 1416166255Sdelphij 1417166255Sdelphij/* uncompress the given file and remove the original */ 1418166255Sdelphijstatic off_t 1419166255Sdelphijfile_uncompress(char *file, char *outfile, size_t outsize) 1420166255Sdelphij{ 1421166255Sdelphij struct stat isb, osb; 1422166255Sdelphij off_t size; 1423166255Sdelphij ssize_t rbytes; 1424166255Sdelphij unsigned char header1[4]; 1425166255Sdelphij enum filetype method; 1426194508Sdelphij int fd, ofd, zfd = -1; 1427337521Sdelphij int error; 1428326559Sdelphij size_t in_size; 1429166255Sdelphij#ifndef SMALL 1430206387Sdelphij ssize_t rv; 1431166255Sdelphij time_t timestamp = 0; 1432281500Sdelphij char name[PATH_MAX + 1]; 1433166255Sdelphij#endif 1434166255Sdelphij 1435166255Sdelphij /* gather the old name info */ 1436166255Sdelphij 1437166255Sdelphij fd = open(file, O_RDONLY); 1438166255Sdelphij if (fd < 0) { 1439166255Sdelphij maybe_warn("can't open %s", file); 1440166255Sdelphij goto lose; 1441166255Sdelphij } 1442326559Sdelphij if (fstat(fd, &isb) != 0) { 1443326559Sdelphij close(fd); 1444326559Sdelphij maybe_warn("can't stat %s", file); 1445326559Sdelphij goto lose; 1446326559Sdelphij } 1447326559Sdelphij if (S_ISREG(isb.st_mode)) 1448326559Sdelphij in_size = isb.st_size; 1449326559Sdelphij else 1450326559Sdelphij in_size = 0; 1451326559Sdelphij infile_set(file, in_size); 1452166255Sdelphij 1453166255Sdelphij strlcpy(outfile, file, outsize); 1454166255Sdelphij if (check_suffix(outfile, 1) == NULL && !(cflag || lflag)) { 1455166255Sdelphij maybe_warnx("%s: unknown suffix -- ignored", file); 1456166255Sdelphij goto lose; 1457166255Sdelphij } 1458166255Sdelphij 1459166255Sdelphij rbytes = read(fd, header1, sizeof header1); 1460166255Sdelphij if (rbytes != sizeof header1) { 1461166255Sdelphij /* we don't want to fail here. */ 1462166255Sdelphij#ifndef SMALL 1463166255Sdelphij if (fflag) 1464166255Sdelphij goto lose; 1465166255Sdelphij#endif 1466166255Sdelphij if (rbytes == -1) 1467166255Sdelphij maybe_warn("can't read %s", file); 1468166255Sdelphij else 1469166255Sdelphij goto unexpected_EOF; 1470166255Sdelphij goto lose; 1471166255Sdelphij } 1472326559Sdelphij infile_newdata(rbytes); 1473166255Sdelphij 1474166255Sdelphij method = file_gettype(header1); 1475166255Sdelphij#ifndef SMALL 1476166255Sdelphij if (fflag == 0 && method == FT_UNKNOWN) { 1477166255Sdelphij maybe_warnx("%s: not in gzip format", file); 1478166255Sdelphij goto lose; 1479166255Sdelphij } 1480166255Sdelphij 1481166255Sdelphij#endif 1482166255Sdelphij 1483166255Sdelphij#ifndef SMALL 1484166255Sdelphij if (method == FT_GZIP && Nflag) { 1485166255Sdelphij unsigned char ts[4]; /* timestamp */ 1486166255Sdelphij 1487166255Sdelphij rv = pread(fd, ts, sizeof ts, GZIP_TIMESTAMP); 1488194916Sdelphij if (rv >= 0 && rv < (ssize_t)(sizeof ts)) 1489166255Sdelphij goto unexpected_EOF; 1490166255Sdelphij if (rv == -1) { 1491166255Sdelphij if (!fflag) 1492166255Sdelphij maybe_warn("can't read %s", file); 1493166255Sdelphij goto lose; 1494166255Sdelphij } 1495326559Sdelphij infile_newdata(rv); 1496336661Sdelphij timestamp = le32dec(&ts[0]); 1497166255Sdelphij 1498166255Sdelphij if (header1[3] & ORIG_NAME) { 1499281540Sdelphij rbytes = pread(fd, name, sizeof(name) - 1, GZIP_ORIGNAME); 1500166255Sdelphij if (rbytes < 0) { 1501166255Sdelphij maybe_warn("can't read %s", file); 1502166255Sdelphij goto lose; 1503166255Sdelphij } 1504281540Sdelphij if (name[0] != '\0') { 1505281500Sdelphij char *dp, *nf; 1506281500Sdelphij 1507281540Sdelphij /* Make sure that name is NUL-terminated */ 1508281540Sdelphij name[rbytes] = '\0'; 1509281540Sdelphij 1510281500Sdelphij /* strip saved directory name */ 1511281500Sdelphij nf = strrchr(name, '/'); 1512281500Sdelphij if (nf == NULL) 1513281500Sdelphij nf = name; 1514281500Sdelphij else 1515281500Sdelphij nf++; 1516281500Sdelphij 1517166255Sdelphij /* preserve original directory name */ 1518281500Sdelphij dp = strrchr(file, '/'); 1519166255Sdelphij if (dp == NULL) 1520166255Sdelphij dp = file; 1521166255Sdelphij else 1522166255Sdelphij dp++; 1523166255Sdelphij snprintf(outfile, outsize, "%.*s%.*s", 1524326559Sdelphij (int) (dp - file), 1525281500Sdelphij file, (int) rbytes, nf); 1526166255Sdelphij } 1527166255Sdelphij } 1528166255Sdelphij } 1529166255Sdelphij#endif 1530166255Sdelphij lseek(fd, 0, SEEK_SET); 1531166255Sdelphij 1532166255Sdelphij if (cflag == 0 || lflag) { 1533166255Sdelphij#ifndef SMALL 1534166255Sdelphij if (isb.st_nlink > 1 && lflag == 0 && fflag == 0) { 1535312072Skib maybe_warnx("%s has %ju other links -- skipping", 1536312072Skib file, (uintmax_t)isb.st_nlink - 1); 1537166255Sdelphij goto lose; 1538166255Sdelphij } 1539166255Sdelphij if (nflag == 0 && timestamp) 1540166255Sdelphij isb.st_mtime = timestamp; 1541166255Sdelphij if (check_outfile(outfile) == 0) 1542166255Sdelphij goto lose; 1543166255Sdelphij#endif 1544166255Sdelphij } 1545166255Sdelphij 1546326559Sdelphij if (cflag) 1547326559Sdelphij zfd = STDOUT_FILENO; 1548326559Sdelphij else if (lflag) 1549326559Sdelphij zfd = -1; 1550326559Sdelphij else { 1551166255Sdelphij zfd = open(outfile, O_WRONLY|O_CREAT|O_EXCL, 0600); 1552166255Sdelphij if (zfd == STDOUT_FILENO) { 1553166255Sdelphij /* We won't close STDOUT_FILENO later... */ 1554166255Sdelphij zfd = dup(zfd); 1555166255Sdelphij close(STDOUT_FILENO); 1556166255Sdelphij } 1557166255Sdelphij if (zfd == -1) { 1558166255Sdelphij maybe_warn("can't open %s", outfile); 1559166255Sdelphij goto lose; 1560166255Sdelphij } 1561207247Sdelphij remove_file = outfile; 1562326559Sdelphij } 1563166255Sdelphij 1564226184Sdelphij switch (method) { 1565166255Sdelphij#ifndef NO_BZIP2_SUPPORT 1566226184Sdelphij case FT_BZIP2: 1567166255Sdelphij /* XXX */ 1568166255Sdelphij if (lflag) { 1569166255Sdelphij maybe_warnx("no -l with bzip2 files"); 1570166255Sdelphij goto lose; 1571166255Sdelphij } 1572166255Sdelphij 1573166255Sdelphij size = unbzip2(fd, zfd, NULL, 0, NULL); 1574226184Sdelphij break; 1575166255Sdelphij#endif 1576166255Sdelphij 1577166255Sdelphij#ifndef NO_COMPRESS_SUPPORT 1578226184Sdelphij case FT_Z: { 1579166255Sdelphij FILE *in, *out; 1580166255Sdelphij 1581166255Sdelphij /* XXX */ 1582166255Sdelphij if (lflag) { 1583166255Sdelphij maybe_warnx("no -l with Lempel-Ziv files"); 1584166255Sdelphij goto lose; 1585166255Sdelphij } 1586166255Sdelphij 1587166255Sdelphij if ((in = zdopen(fd)) == NULL) { 1588166255Sdelphij maybe_warn("zdopen for read: %s", file); 1589166255Sdelphij goto lose; 1590166255Sdelphij } 1591166255Sdelphij 1592166255Sdelphij out = fdopen(dup(zfd), "w"); 1593166255Sdelphij if (out == NULL) { 1594166255Sdelphij maybe_warn("fdopen for write: %s", outfile); 1595166255Sdelphij fclose(in); 1596166255Sdelphij goto lose; 1597166255Sdelphij } 1598166255Sdelphij 1599166255Sdelphij size = zuncompress(in, out, NULL, 0, NULL); 1600166255Sdelphij /* need to fclose() if ferror() is true... */ 1601337521Sdelphij error = ferror(in); 1602337521Sdelphij if (error | fclose(in)) { 1603337521Sdelphij if (error) 1604337521Sdelphij maybe_warn("failed infile"); 1605337521Sdelphij else 1606337521Sdelphij maybe_warn("failed infile fclose"); 1607337521Sdelphij if (cflag == 0) 1608337521Sdelphij unlink(outfile); 1609166255Sdelphij (void)fclose(out); 1610337521Sdelphij goto lose; 1611166255Sdelphij } 1612166255Sdelphij if (fclose(out) != 0) { 1613166255Sdelphij maybe_warn("failed outfile fclose"); 1614337521Sdelphij if (cflag == 0) 1615337521Sdelphij unlink(outfile); 1616166255Sdelphij goto lose; 1617166255Sdelphij } 1618226184Sdelphij break; 1619226184Sdelphij } 1620166255Sdelphij#endif 1621166255Sdelphij 1622194579Sdelphij#ifndef NO_PACK_SUPPORT 1623226184Sdelphij case FT_PACK: 1624194579Sdelphij if (lflag) { 1625194579Sdelphij maybe_warnx("no -l with packed files"); 1626194579Sdelphij goto lose; 1627194579Sdelphij } 1628194579Sdelphij 1629194579Sdelphij size = unpack(fd, zfd, NULL, 0, NULL); 1630226184Sdelphij break; 1631194579Sdelphij#endif 1632194579Sdelphij 1633226184Sdelphij#ifndef NO_XZ_SUPPORT 1634226184Sdelphij case FT_XZ: 1635226184Sdelphij if (lflag) { 1636226184Sdelphij maybe_warnx("no -l with xz files"); 1637226184Sdelphij goto lose; 1638226184Sdelphij } 1639226184Sdelphij 1640226184Sdelphij size = unxz(fd, zfd, NULL, 0, NULL); 1641226184Sdelphij break; 1642226184Sdelphij#endif 1643226184Sdelphij 1644166255Sdelphij#ifndef SMALL 1645226184Sdelphij case FT_UNKNOWN: 1646166255Sdelphij if (lflag) { 1647166255Sdelphij maybe_warnx("no -l for unknown filetypes"); 1648166255Sdelphij goto lose; 1649166255Sdelphij } 1650166255Sdelphij size = cat_fd(NULL, 0, NULL, fd); 1651226184Sdelphij break; 1652166255Sdelphij#endif 1653226184Sdelphij default: 1654166255Sdelphij if (lflag) { 1655326559Sdelphij print_list(fd, in_size, outfile, isb.st_mtime); 1656166255Sdelphij close(fd); 1657166255Sdelphij return -1; /* XXX */ 1658166255Sdelphij } 1659166255Sdelphij 1660166255Sdelphij size = gz_uncompress(fd, zfd, NULL, 0, NULL, file); 1661226184Sdelphij break; 1662166255Sdelphij } 1663166255Sdelphij 1664166255Sdelphij if (close(fd) != 0) 1665166255Sdelphij maybe_warn("couldn't close input"); 1666166255Sdelphij if (zfd != STDOUT_FILENO && close(zfd) != 0) 1667166255Sdelphij maybe_warn("couldn't close output"); 1668166255Sdelphij 1669166255Sdelphij if (size == -1) { 1670166255Sdelphij if (cflag == 0) 1671166255Sdelphij unlink(outfile); 1672166255Sdelphij maybe_warnx("%s: uncompress failed", file); 1673166255Sdelphij return -1; 1674166255Sdelphij } 1675166255Sdelphij 1676166255Sdelphij /* if testing, or we uncompressed to stdout, this is all we need */ 1677166255Sdelphij#ifndef SMALL 1678166255Sdelphij if (tflag) 1679166255Sdelphij return size; 1680166255Sdelphij#endif 1681166255Sdelphij /* if we are uncompressing to stdin, don't remove the file. */ 1682166255Sdelphij if (cflag) 1683166255Sdelphij return size; 1684166255Sdelphij 1685166255Sdelphij /* 1686166255Sdelphij * if we create a file... 1687166255Sdelphij */ 1688166255Sdelphij /* 1689166255Sdelphij * if we can't stat the file don't remove the file. 1690166255Sdelphij */ 1691166255Sdelphij 1692166255Sdelphij ofd = open(outfile, O_RDWR, 0); 1693166255Sdelphij if (ofd == -1) { 1694166255Sdelphij maybe_warn("couldn't open (leaving original): %s", 1695166255Sdelphij outfile); 1696166255Sdelphij return -1; 1697166255Sdelphij } 1698166255Sdelphij if (fstat(ofd, &osb) != 0) { 1699166255Sdelphij maybe_warn("couldn't stat (leaving original): %s", 1700166255Sdelphij outfile); 1701166255Sdelphij close(ofd); 1702166255Sdelphij return -1; 1703166255Sdelphij } 1704166255Sdelphij if (osb.st_size != size) { 1705209017Sdelphij maybe_warnx("stat gave different size: %ju != %ju (leaving original)", 1706209017Sdelphij (uintmax_t)size, (uintmax_t)osb.st_size); 1707166255Sdelphij close(ofd); 1708166255Sdelphij unlink(outfile); 1709166255Sdelphij return -1; 1710166255Sdelphij } 1711166255Sdelphij#ifndef SMALL 1712166255Sdelphij copymodes(ofd, &isb, outfile); 1713207247Sdelphij remove_file = NULL; 1714166255Sdelphij#endif 1715166255Sdelphij close(ofd); 1716207247Sdelphij unlink_input(file, &isb); 1717166255Sdelphij return size; 1718166255Sdelphij 1719166255Sdelphij unexpected_EOF: 1720166255Sdelphij maybe_warnx("%s: unexpected end of file", file); 1721166255Sdelphij lose: 1722166255Sdelphij if (fd != -1) 1723166255Sdelphij close(fd); 1724166255Sdelphij if (zfd != -1 && zfd != STDOUT_FILENO) 1725327191Sdelphij close(zfd); 1726166255Sdelphij return -1; 1727166255Sdelphij} 1728166255Sdelphij 1729166255Sdelphij#ifndef SMALL 1730326559Sdelphijstatic void 1731326559Sdelphijcheck_siginfo(void) 1732326559Sdelphij{ 1733326559Sdelphij if (print_info == 0) 1734326559Sdelphij return; 1735326559Sdelphij if (infile) { 1736326559Sdelphij if (infile_total) { 1737326559Sdelphij int pcent = (int)((100.0 * infile_current) / infile_total); 1738326559Sdelphij 1739326559Sdelphij fprintf(stderr, "%s: done %llu/%llu bytes %d%%\n", 1740326559Sdelphij infile, (unsigned long long)infile_current, 1741326559Sdelphij (unsigned long long)infile_total, pcent); 1742326559Sdelphij } else 1743326559Sdelphij fprintf(stderr, "%s: done %llu bytes\n", 1744326559Sdelphij infile, (unsigned long long)infile_current); 1745326559Sdelphij } 1746326559Sdelphij print_info = 0; 1747326559Sdelphij} 1748326559Sdelphij 1749166255Sdelphijstatic off_t 1750166255Sdelphijcat_fd(unsigned char * prepend, size_t count, off_t *gsizep, int fd) 1751166255Sdelphij{ 1752166255Sdelphij char buf[BUFLEN]; 1753166255Sdelphij off_t in_tot; 1754166255Sdelphij ssize_t w; 1755166255Sdelphij 1756166255Sdelphij in_tot = count; 1757326559Sdelphij w = write_retry(STDOUT_FILENO, prepend, count); 1758166255Sdelphij if (w == -1 || (size_t)w != count) { 1759166255Sdelphij maybe_warn("write to stdout"); 1760166255Sdelphij return -1; 1761166255Sdelphij } 1762166255Sdelphij for (;;) { 1763166255Sdelphij ssize_t rv; 1764166255Sdelphij 1765166255Sdelphij rv = read(fd, buf, sizeof buf); 1766166255Sdelphij if (rv == 0) 1767166255Sdelphij break; 1768166255Sdelphij if (rv < 0) { 1769166255Sdelphij maybe_warn("read from fd %d", fd); 1770166255Sdelphij break; 1771166255Sdelphij } 1772326559Sdelphij infile_newdata(rv); 1773166255Sdelphij 1774326559Sdelphij if (write_retry(STDOUT_FILENO, buf, rv) != rv) { 1775166255Sdelphij maybe_warn("write to stdout"); 1776166255Sdelphij break; 1777166255Sdelphij } 1778166255Sdelphij in_tot += rv; 1779166255Sdelphij } 1780166255Sdelphij 1781166255Sdelphij if (gsizep) 1782166255Sdelphij *gsizep = in_tot; 1783166255Sdelphij return (in_tot); 1784166255Sdelphij} 1785166255Sdelphij#endif 1786166255Sdelphij 1787166255Sdelphijstatic void 1788166255Sdelphijhandle_stdin(void) 1789166255Sdelphij{ 1790326559Sdelphij struct stat isb; 1791166255Sdelphij unsigned char header1[4]; 1792326559Sdelphij size_t in_size; 1793166255Sdelphij off_t usize, gsize; 1794166255Sdelphij enum filetype method; 1795166255Sdelphij ssize_t bytes_read; 1796166255Sdelphij#ifndef NO_COMPRESS_SUPPORT 1797166255Sdelphij FILE *in; 1798166255Sdelphij#endif 1799166255Sdelphij 1800166255Sdelphij#ifndef SMALL 1801166255Sdelphij if (fflag == 0 && lflag == 0 && isatty(STDIN_FILENO)) { 1802166255Sdelphij maybe_warnx("standard input is a terminal -- ignoring"); 1803326559Sdelphij goto out; 1804166255Sdelphij } 1805166255Sdelphij#endif 1806166255Sdelphij 1807326559Sdelphij if (fstat(STDIN_FILENO, &isb) < 0) { 1808326559Sdelphij maybe_warn("fstat"); 1809326559Sdelphij goto out; 1810326559Sdelphij } 1811326559Sdelphij if (S_ISREG(isb.st_mode)) 1812326559Sdelphij in_size = isb.st_size; 1813326559Sdelphij else 1814326559Sdelphij in_size = 0; 1815326559Sdelphij infile_set("(stdin)", in_size); 1816326559Sdelphij 1817166255Sdelphij if (lflag) { 1818326559Sdelphij print_list(STDIN_FILENO, in_size, infile, isb.st_mtime); 1819326559Sdelphij goto out; 1820166255Sdelphij } 1821166255Sdelphij 1822166255Sdelphij bytes_read = read_retry(STDIN_FILENO, header1, sizeof header1); 1823166255Sdelphij if (bytes_read == -1) { 1824166255Sdelphij maybe_warn("can't read stdin"); 1825326559Sdelphij goto out; 1826166255Sdelphij } else if (bytes_read != sizeof(header1)) { 1827166255Sdelphij maybe_warnx("(stdin): unexpected end of file"); 1828326559Sdelphij goto out; 1829166255Sdelphij } 1830166255Sdelphij 1831166255Sdelphij method = file_gettype(header1); 1832166255Sdelphij switch (method) { 1833166255Sdelphij default: 1834166255Sdelphij#ifndef SMALL 1835166255Sdelphij if (fflag == 0) { 1836166255Sdelphij maybe_warnx("unknown compression format"); 1837326559Sdelphij goto out; 1838166255Sdelphij } 1839166255Sdelphij usize = cat_fd(header1, sizeof header1, &gsize, STDIN_FILENO); 1840166255Sdelphij break; 1841166255Sdelphij#endif 1842166255Sdelphij case FT_GZIP: 1843326559Sdelphij usize = gz_uncompress(STDIN_FILENO, STDOUT_FILENO, 1844166255Sdelphij (char *)header1, sizeof header1, &gsize, "(stdin)"); 1845166255Sdelphij break; 1846166255Sdelphij#ifndef NO_BZIP2_SUPPORT 1847166255Sdelphij case FT_BZIP2: 1848166255Sdelphij usize = unbzip2(STDIN_FILENO, STDOUT_FILENO, 1849166255Sdelphij (char *)header1, sizeof header1, &gsize); 1850166255Sdelphij break; 1851166255Sdelphij#endif 1852166255Sdelphij#ifndef NO_COMPRESS_SUPPORT 1853166255Sdelphij case FT_Z: 1854166255Sdelphij if ((in = zdopen(STDIN_FILENO)) == NULL) { 1855166255Sdelphij maybe_warnx("zopen of stdin"); 1856326559Sdelphij goto out; 1857166255Sdelphij } 1858166255Sdelphij 1859226184Sdelphij usize = zuncompress(in, stdout, (char *)header1, 1860226184Sdelphij sizeof header1, &gsize); 1861166255Sdelphij fclose(in); 1862166255Sdelphij break; 1863166255Sdelphij#endif 1864194579Sdelphij#ifndef NO_PACK_SUPPORT 1865194579Sdelphij case FT_PACK: 1866194579Sdelphij usize = unpack(STDIN_FILENO, STDOUT_FILENO, 1867194579Sdelphij (char *)header1, sizeof header1, &gsize); 1868194579Sdelphij break; 1869194579Sdelphij#endif 1870226184Sdelphij#ifndef NO_XZ_SUPPORT 1871226184Sdelphij case FT_XZ: 1872226184Sdelphij usize = unxz(STDIN_FILENO, STDOUT_FILENO, 1873226184Sdelphij (char *)header1, sizeof header1, &gsize); 1874226184Sdelphij break; 1875226184Sdelphij#endif 1876166255Sdelphij } 1877166255Sdelphij 1878166255Sdelphij#ifndef SMALL 1879166255Sdelphij if (vflag && !tflag && usize != -1 && gsize != -1) 1880166255Sdelphij print_verbage(NULL, NULL, usize, gsize); 1881166255Sdelphij if (vflag && tflag) 1882166255Sdelphij print_test("(stdin)", usize != -1); 1883326559Sdelphij#else 1884326559Sdelphij (void)&usize; 1885326559Sdelphij#endif 1886166255Sdelphij 1887326559Sdelphijout: 1888326559Sdelphij infile_clear(); 1889166255Sdelphij} 1890166255Sdelphij 1891166255Sdelphijstatic void 1892166255Sdelphijhandle_stdout(void) 1893166255Sdelphij{ 1894326559Sdelphij off_t gsize; 1895326559Sdelphij#ifndef SMALL 1896326559Sdelphij off_t usize; 1897166255Sdelphij struct stat sb; 1898166255Sdelphij time_t systime; 1899166255Sdelphij uint32_t mtime; 1900166255Sdelphij int ret; 1901166255Sdelphij 1902326559Sdelphij infile_set("(stdout)", 0); 1903326559Sdelphij 1904166255Sdelphij if (fflag == 0 && isatty(STDOUT_FILENO)) { 1905166255Sdelphij maybe_warnx("standard output is a terminal -- ignoring"); 1906166255Sdelphij return; 1907166255Sdelphij } 1908326559Sdelphij 1909273507Sdelphij /* If stdin is a file use its mtime, otherwise use current time */ 1910166255Sdelphij ret = fstat(STDIN_FILENO, &sb); 1911166255Sdelphij if (ret < 0) { 1912166255Sdelphij maybe_warn("Can't stat stdin"); 1913166255Sdelphij return; 1914166255Sdelphij } 1915166255Sdelphij 1916326559Sdelphij if (S_ISREG(sb.st_mode)) { 1917326559Sdelphij infile_set("(stdout)", sb.st_size); 1918166255Sdelphij mtime = (uint32_t)sb.st_mtime; 1919326559Sdelphij } else { 1920166255Sdelphij systime = time(NULL); 1921166255Sdelphij if (systime == -1) { 1922166255Sdelphij maybe_warn("time"); 1923166255Sdelphij return; 1924326559Sdelphij } 1925166255Sdelphij mtime = (uint32_t)systime; 1926166255Sdelphij } 1927166255Sdelphij 1928326559Sdelphij usize = 1929326559Sdelphij#endif 1930326559Sdelphij gz_compress(STDIN_FILENO, STDOUT_FILENO, &gsize, "", mtime); 1931166255Sdelphij#ifndef SMALL 1932166255Sdelphij if (vflag && !tflag && usize != -1 && gsize != -1) 1933166255Sdelphij print_verbage(NULL, NULL, usize, gsize); 1934326559Sdelphij#endif 1935166255Sdelphij} 1936166255Sdelphij 1937166255Sdelphij/* do what is asked for, for the path name */ 1938166255Sdelphijstatic void 1939166255Sdelphijhandle_pathname(char *path) 1940166255Sdelphij{ 1941166255Sdelphij char *opath = path, *s = NULL; 1942166255Sdelphij ssize_t len; 1943166255Sdelphij int slen; 1944166255Sdelphij struct stat sb; 1945166255Sdelphij 1946166255Sdelphij /* check for stdout/stdin */ 1947166255Sdelphij if (path[0] == '-' && path[1] == '\0') { 1948166255Sdelphij if (dflag) 1949166255Sdelphij handle_stdin(); 1950166255Sdelphij else 1951166255Sdelphij handle_stdout(); 1952166255Sdelphij return; 1953166255Sdelphij } 1954166255Sdelphij 1955166255Sdelphijretry: 1956222287Sdelphij if (stat(path, &sb) != 0 || (fflag == 0 && cflag == 0 && 1957222287Sdelphij lstat(path, &sb) != 0)) { 1958166255Sdelphij /* lets try <path>.gz if we're decompressing */ 1959166255Sdelphij if (dflag && s == NULL && errno == ENOENT) { 1960166255Sdelphij len = strlen(path); 1961166255Sdelphij slen = suffixes[0].ziplen; 1962166255Sdelphij s = malloc(len + slen + 1); 1963166255Sdelphij if (s == NULL) 1964166255Sdelphij maybe_err("malloc"); 1965166255Sdelphij memcpy(s, path, len); 1966166255Sdelphij memcpy(s + len, suffixes[0].zipped, slen + 1); 1967166255Sdelphij path = s; 1968166255Sdelphij goto retry; 1969166255Sdelphij } 1970166255Sdelphij maybe_warn("can't stat: %s", opath); 1971166255Sdelphij goto out; 1972166255Sdelphij } 1973166255Sdelphij 1974166255Sdelphij if (S_ISDIR(sb.st_mode)) { 1975166255Sdelphij#ifndef SMALL 1976166255Sdelphij if (rflag) 1977166255Sdelphij handle_dir(path); 1978166255Sdelphij else 1979166255Sdelphij#endif 1980166255Sdelphij maybe_warnx("%s is a directory", path); 1981166255Sdelphij goto out; 1982166255Sdelphij } 1983166255Sdelphij 1984166255Sdelphij if (S_ISREG(sb.st_mode)) 1985166255Sdelphij handle_file(path, &sb); 1986166255Sdelphij else 1987166255Sdelphij maybe_warnx("%s is not a regular file", path); 1988166255Sdelphij 1989166255Sdelphijout: 1990166255Sdelphij if (s) 1991166255Sdelphij free(s); 1992166255Sdelphij} 1993166255Sdelphij 1994166255Sdelphij/* compress/decompress a file */ 1995166255Sdelphijstatic void 1996166255Sdelphijhandle_file(char *file, struct stat *sbp) 1997166255Sdelphij{ 1998166255Sdelphij off_t usize, gsize; 1999166255Sdelphij char outfile[PATH_MAX]; 2000166255Sdelphij 2001326559Sdelphij infile_set(file, sbp->st_size); 2002166255Sdelphij if (dflag) { 2003166255Sdelphij usize = file_uncompress(file, outfile, sizeof(outfile)); 2004166255Sdelphij#ifndef SMALL 2005166255Sdelphij if (vflag && tflag) 2006166255Sdelphij print_test(file, usize != -1); 2007166255Sdelphij#endif 2008166255Sdelphij if (usize == -1) 2009166255Sdelphij return; 2010166255Sdelphij gsize = sbp->st_size; 2011166255Sdelphij } else { 2012166255Sdelphij gsize = file_compress(file, outfile, sizeof(outfile)); 2013166255Sdelphij if (gsize == -1) 2014166255Sdelphij return; 2015166255Sdelphij usize = sbp->st_size; 2016166255Sdelphij } 2017326559Sdelphij infile_clear(); 2018166255Sdelphij 2019166255Sdelphij#ifndef SMALL 2020166255Sdelphij if (vflag && !tflag) 2021166255Sdelphij print_verbage(file, (cflag) ? NULL : outfile, usize, gsize); 2022166255Sdelphij#endif 2023166255Sdelphij} 2024166255Sdelphij 2025166255Sdelphij#ifndef SMALL 2026166255Sdelphij/* this is used with -r to recursively descend directories */ 2027166255Sdelphijstatic void 2028166255Sdelphijhandle_dir(char *dir) 2029166255Sdelphij{ 2030166255Sdelphij char *path_argv[2]; 2031166255Sdelphij FTS *fts; 2032166255Sdelphij FTSENT *entry; 2033166255Sdelphij 2034166255Sdelphij path_argv[0] = dir; 2035166255Sdelphij path_argv[1] = 0; 2036171389Sdelphij fts = fts_open(path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL); 2037166255Sdelphij if (fts == NULL) { 2038166255Sdelphij warn("couldn't fts_open %s", dir); 2039166255Sdelphij return; 2040166255Sdelphij } 2041166255Sdelphij 2042166255Sdelphij while ((entry = fts_read(fts))) { 2043166255Sdelphij switch(entry->fts_info) { 2044166255Sdelphij case FTS_D: 2045166255Sdelphij case FTS_DP: 2046166255Sdelphij continue; 2047166255Sdelphij 2048166255Sdelphij case FTS_DNR: 2049166255Sdelphij case FTS_ERR: 2050166255Sdelphij case FTS_NS: 2051166255Sdelphij maybe_warn("%s", entry->fts_path); 2052166255Sdelphij continue; 2053166255Sdelphij case FTS_F: 2054171389Sdelphij handle_file(entry->fts_path, entry->fts_statp); 2055166255Sdelphij } 2056166255Sdelphij } 2057166255Sdelphij (void)fts_close(fts); 2058166255Sdelphij} 2059166255Sdelphij#endif 2060166255Sdelphij 2061166255Sdelphij/* print a ratio - size reduction as a fraction of uncompressed size */ 2062166255Sdelphijstatic void 2063166255Sdelphijprint_ratio(off_t in, off_t out, FILE *where) 2064166255Sdelphij{ 2065166255Sdelphij int percent10; /* 10 * percent */ 2066166255Sdelphij off_t diff; 2067166255Sdelphij char buff[8]; 2068166255Sdelphij int len; 2069166255Sdelphij 2070166255Sdelphij diff = in - out/2; 2071326559Sdelphij if (in == 0 && out == 0) 2072326559Sdelphij percent10 = 0; 2073326559Sdelphij else if (diff < 0) 2074166255Sdelphij /* 2075166255Sdelphij * Output is more than double size of input! print -99.9% 2076166255Sdelphij * Quite possibly we've failed to get the original size. 2077166255Sdelphij */ 2078166255Sdelphij percent10 = -999; 2079166255Sdelphij else { 2080166255Sdelphij /* 2081166255Sdelphij * We only need 12 bits of result from the final division, 2082166255Sdelphij * so reduce the values until a 32bit division will suffice. 2083166255Sdelphij */ 2084166255Sdelphij while (in > 0x100000) { 2085166255Sdelphij diff >>= 1; 2086166255Sdelphij in >>= 1; 2087166255Sdelphij } 2088166255Sdelphij if (in != 0) 2089166255Sdelphij percent10 = ((u_int)diff * 2000) / (u_int)in - 1000; 2090166255Sdelphij else 2091166255Sdelphij percent10 = 0; 2092166255Sdelphij } 2093166255Sdelphij 2094166255Sdelphij len = snprintf(buff, sizeof buff, "%2.2d.", percent10); 2095166255Sdelphij /* Move the '.' to before the last digit */ 2096166255Sdelphij buff[len - 1] = buff[len - 2]; 2097166255Sdelphij buff[len - 2] = '.'; 2098166255Sdelphij fprintf(where, "%5s%%", buff); 2099166255Sdelphij} 2100166255Sdelphij 2101166255Sdelphij#ifndef SMALL 2102166255Sdelphij/* print compression statistics, and the new name (if there is one!) */ 2103166255Sdelphijstatic void 2104166255Sdelphijprint_verbage(const char *file, const char *nfile, off_t usize, off_t gsize) 2105166255Sdelphij{ 2106166255Sdelphij if (file) 2107166255Sdelphij fprintf(stderr, "%s:%s ", file, 2108166255Sdelphij strlen(file) < 7 ? "\t\t" : "\t"); 2109166255Sdelphij print_ratio(usize, gsize, stderr); 2110166255Sdelphij if (nfile) 2111166255Sdelphij fprintf(stderr, " -- replaced with %s", nfile); 2112166255Sdelphij fprintf(stderr, "\n"); 2113166255Sdelphij fflush(stderr); 2114166255Sdelphij} 2115166255Sdelphij 2116166255Sdelphij/* print test results */ 2117166255Sdelphijstatic void 2118166255Sdelphijprint_test(const char *file, int ok) 2119166255Sdelphij{ 2120166255Sdelphij 2121166255Sdelphij if (exit_value == 0 && ok == 0) 2122166255Sdelphij exit_value = 1; 2123166255Sdelphij fprintf(stderr, "%s:%s %s\n", file, 2124166255Sdelphij strlen(file) < 7 ? "\t\t" : "\t", ok ? "OK" : "NOT OK"); 2125166255Sdelphij fflush(stderr); 2126166255Sdelphij} 2127166255Sdelphij#endif 2128166255Sdelphij 2129166255Sdelphij/* print a file's info ala --list */ 2130166255Sdelphij/* eg: 2131166255Sdelphij compressed uncompressed ratio uncompressed_name 2132166255Sdelphij 354841 1679360 78.8% /usr/pkgsrc/distfiles/libglade-2.0.1.tar 2133166255Sdelphij*/ 2134166255Sdelphijstatic void 2135166255Sdelphijprint_list(int fd, off_t out, const char *outfile, time_t ts) 2136166255Sdelphij{ 2137166255Sdelphij static int first = 1; 2138166255Sdelphij#ifndef SMALL 2139166255Sdelphij static off_t in_tot, out_tot; 2140166255Sdelphij uint32_t crc = 0; 2141166255Sdelphij#endif 2142166255Sdelphij off_t in = 0, rv; 2143166255Sdelphij 2144166255Sdelphij if (first) { 2145166255Sdelphij#ifndef SMALL 2146166255Sdelphij if (vflag) 2147166255Sdelphij printf("method crc date time "); 2148166255Sdelphij#endif 2149166255Sdelphij if (qflag == 0) 2150166255Sdelphij printf(" compressed uncompressed " 2151166255Sdelphij "ratio uncompressed_name\n"); 2152166255Sdelphij } 2153166255Sdelphij first = 0; 2154166255Sdelphij 2155166255Sdelphij /* print totals? */ 2156166255Sdelphij#ifndef SMALL 2157166255Sdelphij if (fd == -1) { 2158166255Sdelphij in = in_tot; 2159166255Sdelphij out = out_tot; 2160166255Sdelphij } else 2161166255Sdelphij#endif 2162166255Sdelphij { 2163166255Sdelphij /* read the last 4 bytes - this is the uncompressed size */ 2164166255Sdelphij rv = lseek(fd, (off_t)(-8), SEEK_END); 2165166255Sdelphij if (rv != -1) { 2166166255Sdelphij unsigned char buf[8]; 2167166255Sdelphij uint32_t usize; 2168166255Sdelphij 2169166255Sdelphij rv = read(fd, (char *)buf, sizeof(buf)); 2170166255Sdelphij if (rv == -1) 2171166255Sdelphij maybe_warn("read of uncompressed size"); 2172166255Sdelphij else if (rv != sizeof(buf)) 2173166255Sdelphij maybe_warnx("read of uncompressed size"); 2174166255Sdelphij 2175166255Sdelphij else { 2176336661Sdelphij usize = le32dec(&buf[4]); 2177166255Sdelphij in = (off_t)usize; 2178166255Sdelphij#ifndef SMALL 2179336661Sdelphij crc = le32dec(&buf[0]); 2180166255Sdelphij#endif 2181166255Sdelphij } 2182166255Sdelphij } 2183166255Sdelphij } 2184166255Sdelphij 2185166255Sdelphij#ifndef SMALL 2186166255Sdelphij if (vflag && fd == -1) 2187166255Sdelphij printf(" "); 2188166255Sdelphij else if (vflag) { 2189166255Sdelphij char *date = ctime(&ts); 2190166255Sdelphij 2191166255Sdelphij /* skip the day, 1/100th second, and year */ 2192166255Sdelphij date += 4; 2193166255Sdelphij date[12] = 0; 2194166255Sdelphij printf("%5s %08x %11s ", "defla"/*XXX*/, crc, date); 2195166255Sdelphij } 2196166255Sdelphij in_tot += in; 2197166255Sdelphij out_tot += out; 2198194508Sdelphij#else 2199194508Sdelphij (void)&ts; /* XXX */ 2200166255Sdelphij#endif 2201166255Sdelphij printf("%12llu %12llu ", (unsigned long long)out, (unsigned long long)in); 2202166255Sdelphij print_ratio(in, out, stdout); 2203166255Sdelphij printf(" %s\n", outfile); 2204166255Sdelphij} 2205166255Sdelphij 2206166255Sdelphij/* display the usage of NetBSD gzip */ 2207166255Sdelphijstatic void 2208166255Sdelphijusage(void) 2209166255Sdelphij{ 2210166255Sdelphij 2211166255Sdelphij fprintf(stderr, "%s\n", gzip_version); 2212166255Sdelphij fprintf(stderr, 2213171389Sdelphij#ifdef SMALL 2214171389Sdelphij "usage: %s [-" OPT_LIST "] [<file> [<file> ...]]\n", 2215171389Sdelphij#else 2216171389Sdelphij "usage: %s [-123456789acdfhklLNnqrtVv] [-S .suffix] [<file> [<file> ...]]\n" 2217166255Sdelphij " -1 --fast fastest (worst) compression\n" 2218166255Sdelphij " -2 .. -8 set compression level\n" 2219166255Sdelphij " -9 --best best (slowest) compression\n" 2220166255Sdelphij " -c --stdout write to stdout, keep original files\n" 2221166255Sdelphij " --to-stdout\n" 2222166255Sdelphij " -d --decompress uncompress files\n" 2223166255Sdelphij " --uncompress\n" 2224166255Sdelphij " -f --force force overwriting & compress links\n" 2225166255Sdelphij " -h --help display this help\n" 2226170053Sdelphij " -k --keep don't delete input files during operation\n" 2227166255Sdelphij " -l --list list compressed file contents\n" 2228166255Sdelphij " -N --name save or restore original file name and time stamp\n" 2229166255Sdelphij " -n --no-name don't save original file name or time stamp\n" 2230166255Sdelphij " -q --quiet output no warnings\n" 2231166255Sdelphij " -r --recursive recursively compress files in directories\n" 2232166255Sdelphij " -S .suf use suffix .suf instead of .gz\n" 2233166255Sdelphij " --suffix .suf\n" 2234166255Sdelphij " -t --test test compressed file\n" 2235166255Sdelphij " -V --version display program version\n" 2236166255Sdelphij " -v --verbose print extra statistics\n", 2237166255Sdelphij#endif 2238166255Sdelphij getprogname()); 2239166255Sdelphij exit(0); 2240166255Sdelphij} 2241166255Sdelphij 2242166255Sdelphij#ifndef SMALL 2243166255Sdelphij/* display the license information of FreeBSD gzip */ 2244166255Sdelphijstatic void 2245166255Sdelphijdisplay_license(void) 2246166255Sdelphij{ 2247166255Sdelphij 2248281500Sdelphij fprintf(stderr, "%s (based on NetBSD gzip 20150113)\n", gzip_version); 2249166255Sdelphij fprintf(stderr, "%s\n", gzip_copyright); 2250166255Sdelphij exit(0); 2251166255Sdelphij} 2252166255Sdelphij#endif 2253166255Sdelphij 2254166255Sdelphij/* display the version of NetBSD gzip */ 2255166255Sdelphijstatic void 2256166255Sdelphijdisplay_version(void) 2257166255Sdelphij{ 2258166255Sdelphij 2259166255Sdelphij fprintf(stderr, "%s\n", gzip_version); 2260166255Sdelphij exit(0); 2261166255Sdelphij} 2262166255Sdelphij 2263166255Sdelphij#ifndef NO_BZIP2_SUPPORT 2264166255Sdelphij#include "unbzip2.c" 2265166255Sdelphij#endif 2266166255Sdelphij#ifndef NO_COMPRESS_SUPPORT 2267166255Sdelphij#include "zuncompress.c" 2268166255Sdelphij#endif 2269194579Sdelphij#ifndef NO_PACK_SUPPORT 2270194579Sdelphij#include "unpack.c" 2271194579Sdelphij#endif 2272226184Sdelphij#ifndef NO_XZ_SUPPORT 2273226184Sdelphij#include "unxz.c" 2274226184Sdelphij#endif 2275166255Sdelphij 2276166255Sdelphijstatic ssize_t 2277166255Sdelphijread_retry(int fd, void *buf, size_t sz) 2278166255Sdelphij{ 2279166255Sdelphij char *cp = buf; 2280166255Sdelphij size_t left = MIN(sz, (size_t) SSIZE_MAX); 2281166255Sdelphij 2282166255Sdelphij while (left > 0) { 2283166255Sdelphij ssize_t ret; 2284166255Sdelphij 2285166255Sdelphij ret = read(fd, cp, left); 2286166255Sdelphij if (ret == -1) { 2287166255Sdelphij return ret; 2288166255Sdelphij } else if (ret == 0) { 2289166255Sdelphij break; /* EOF */ 2290166255Sdelphij } 2291166255Sdelphij cp += ret; 2292166255Sdelphij left -= ret; 2293166255Sdelphij } 2294166255Sdelphij 2295166255Sdelphij return sz - left; 2296166255Sdelphij} 2297326559Sdelphij 2298326559Sdelphijstatic ssize_t 2299326559Sdelphijwrite_retry(int fd, const void *buf, size_t sz) 2300326559Sdelphij{ 2301326559Sdelphij const char *cp = buf; 2302326559Sdelphij size_t left = MIN(sz, (size_t) SSIZE_MAX); 2303326559Sdelphij 2304326559Sdelphij while (left > 0) { 2305326559Sdelphij ssize_t ret; 2306326559Sdelphij 2307326559Sdelphij ret = write(fd, cp, left); 2308326559Sdelphij if (ret == -1) { 2309326559Sdelphij return ret; 2310326559Sdelphij } else if (ret == 0) { 2311326559Sdelphij abort(); /* Can't happen */ 2312326559Sdelphij } 2313326559Sdelphij cp += ret; 2314326559Sdelphij left -= ret; 2315326559Sdelphij } 2316326559Sdelphij 2317326559Sdelphij return sz - left; 2318326559Sdelphij} 2319