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