Annotation of src/usr.bin/gzip/gzip.c, Revision 1.102
1.102 ! christos 1: /* $NetBSD: gzip.c,v 1.101 2011/06/19 01:20:19 tsutsui Exp $ */
1.1 mrg 2:
3: /*
1.84 mrg 4: * Copyright (c) 1997, 1998, 2003, 2004, 2006 Matthew R. Green
1.1 mrg 5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: *
16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23: * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26: * SUCH DAMAGE.
27: */
28:
1.4 mrg 29: #include <sys/cdefs.h>
30: #ifndef lint
1.92 lukem 31: __COPYRIGHT("@(#) Copyright (c) 1997, 1998, 2003, 2004, 2006\
32: Matthew R. Green. All rights reserved.");
1.102 ! christos 33: __RCSID("$NetBSD: gzip.c,v 1.101 2011/06/19 01:20:19 tsutsui Exp $");
1.4 mrg 34: #endif /* not lint */
35:
1.1 mrg 36: /*
37: * gzip.c -- GPL free gzip using zlib.
38: *
1.65 dsl 39: * RFC 1950 covers the zlib format
40: * RFC 1951 covers the deflate format
41: * RFC 1952 covers the gzip format
42: *
1.6 mrg 43: * TODO:
1.10 mrg 44: * - use mmap where possible
1.16 wiz 45: * - handle some signals better (remove outfile?)
1.41 mrg 46: * - make bzip2/compress -v/-t/-l support work as well as possible
1.1 mrg 47: */
48:
49: #include <sys/param.h>
50: #include <sys/stat.h>
51: #include <sys/time.h>
52:
1.63 dsl 53: #include <inttypes.h>
1.1 mrg 54: #include <unistd.h>
55: #include <stdio.h>
56: #include <string.h>
57: #include <stdlib.h>
58: #include <err.h>
59: #include <errno.h>
60: #include <fcntl.h>
61: #include <zlib.h>
62: #include <fts.h>
63: #include <libgen.h>
64: #include <stdarg.h>
65: #include <getopt.h>
1.69 jmc 66: #include <time.h>
1.1 mrg 67:
1.63 dsl 68: #ifndef PRIdOFF
69: #define PRIdOFF PRId64
70: #endif
71:
1.10 mrg 72: /* what type of file are we dealing with */
73: enum filetype {
74: FT_GZIP,
1.24 tsutsui 75: #ifndef NO_BZIP2_SUPPORT
1.10 mrg 76: FT_BZIP2,
1.24 tsutsui 77: #endif
78: #ifndef NO_COMPRESS_SUPPORT
1.22 mrg 79: FT_Z,
1.24 tsutsui 80: #endif
1.95 mrg 81: #ifndef NO_PACK_SUPPORT
82: FT_PACK,
83: #endif
1.100 christos 84: #ifndef NO_XZ_SUPPORT
85: FT_XZ,
86: #endif
1.10 mrg 87: FT_LAST,
88: FT_UNKNOWN
89: };
90:
1.24 tsutsui 91: #ifndef NO_BZIP2_SUPPORT
1.10 mrg 92: #include <bzlib.h>
93:
1.24 tsutsui 94: #define BZ2_SUFFIX ".bz2"
95: #define BZIP2_MAGIC "\102\132\150"
96: #endif
97:
98: #ifndef NO_COMPRESS_SUPPORT
1.22 mrg 99: #define Z_SUFFIX ".Z"
100: #define Z_MAGIC "\037\235"
1.24 tsutsui 101: #endif
1.10 mrg 102:
1.95 mrg 103: #ifndef NO_PACK_SUPPORT
104: #define PACK_MAGIC "\037\036"
105: #endif
106:
1.100 christos 107: #ifndef NO_XZ_SUPPORT
108: #include <lzma.h>
109: #define XZ_SUFFIX ".xz"
110: #define XZ_MAGIC "\3757zXZ"
111: #endif
112:
1.10 mrg 113: #define GZ_SUFFIX ".gz"
1.1 mrg 114:
1.37 mrg 115: #define BUFLEN (64 * 1024)
1.1 mrg 116:
1.9 mrg 117: #define GZIP_MAGIC0 0x1F
1.10 mrg 118: #define GZIP_MAGIC1 0x8B
119: #define GZIP_OMAGIC1 0x9E
1.9 mrg 120:
1.48 mrg 121: #define GZIP_TIMESTAMP (off_t)4
1.47 mrg 122: #define GZIP_ORIGNAME (off_t)10
123:
1.37 mrg 124: #define HEAD_CRC 0x02
125: #define EXTRA_FIELD 0x04
126: #define ORIG_NAME 0x08
127: #define COMMENT 0x10
1.1 mrg 128:
1.37 mrg 129: #define OS_CODE 3 /* Unix */
1.1 mrg 130:
1.63 dsl 131: typedef struct {
1.66 dsl 132: const char *zipped;
1.63 dsl 133: int ziplen;
1.66 dsl 134: const char *normal; /* for unzip - must not be longer than zipped */
1.63 dsl 135: } suffixes_t;
136: static suffixes_t suffixes[] = {
1.66 dsl 137: #define SUFFIX(Z, N) {Z, sizeof Z - 1, N}
1.63 dsl 138: SUFFIX(GZ_SUFFIX, ""), /* Overwritten by -S .xxx */
139: #ifndef SMALL
140: SUFFIX(GZ_SUFFIX, ""),
141: SUFFIX(".z", ""),
142: SUFFIX("-gz", ""),
143: SUFFIX("-z", ""),
144: SUFFIX("_z", ""),
145: SUFFIX(".taz", ".tar"),
146: SUFFIX(".tgz", ".tar"),
1.56 mrg 147: #ifndef NO_BZIP2_SUPPORT
1.63 dsl 148: SUFFIX(BZ2_SUFFIX, ""),
1.56 mrg 149: #endif
150: #ifndef NO_COMPRESS_SUPPORT
1.63 dsl 151: SUFFIX(Z_SUFFIX, ""),
1.56 mrg 152: #endif
1.102 ! christos 153: #ifndef NO_XZ_SUPPORT
! 154: SUFFIX(XZ_SUFFIX, ""),
! 155: #endif
1.63 dsl 156: SUFFIX(GZ_SUFFIX, ""), /* Overwritten by -S "" */
157: #endif /* SMALL */
158: #undef SUFFIX
1.56 mrg 159: };
1.63 dsl 160: #define NUM_SUFFIXES (sizeof suffixes / sizeof suffixes[0])
1.96 mrg 161: #define SUFFIX_MAXLEN 30
1.56 mrg 162:
1.98 mrg 163: static const char gzip_version[] = "NetBSD gzip 20101018";
1.1 mrg 164:
165: static int cflag; /* stdout mode */
166: static int dflag; /* decompress mode */
1.25 mrg 167: static int lflag; /* list mode */
1.41 mrg 168: static int numflag = 6; /* gzip -1..-9 value */
1.26 mrg 169:
1.25 mrg 170: #ifndef SMALL
1.1 mrg 171: static int fflag; /* force mode */
1.98 mrg 172: static int kflag; /* don't delete input files */
1.1 mrg 173: static int nflag; /* don't save name/timestamp */
174: static int Nflag; /* don't restore name/timestamp */
175: static int qflag; /* quiet mode */
176: static int rflag; /* recursive mode */
1.26 mrg 177: static int tflag; /* test */
178: static int vflag; /* verbose mode */
1.25 mrg 179: #else
180: #define qflag 0
1.66 dsl 181: #define tflag 0
1.25 mrg 182: #endif
1.26 mrg 183:
1.46 mrg 184: static int exit_value = 0; /* exit value */
185:
1.1 mrg 186: static char *infile; /* name of file coming in */
187:
1.63 dsl 188: static void maybe_err(const char *fmt, ...)
189: __attribute__((__format__(__printf__, 1, 2)));
1.101 tsutsui 190: #if !defined(NO_BZIP2_SUPPORT) || !defined(NO_PACK_SUPPORT) || \
191: !defined(NO_XZ_SUPPORT)
1.63 dsl 192: static void maybe_errx(const char *fmt, ...)
193: __attribute__((__format__(__printf__, 1, 2)));
1.66 dsl 194: #endif
1.63 dsl 195: static void maybe_warn(const char *fmt, ...)
196: __attribute__((__format__(__printf__, 1, 2)));
197: static void maybe_warnx(const char *fmt, ...)
198: __attribute__((__format__(__printf__, 1, 2)));
1.32 mrg 199: static enum filetype file_gettype(u_char *);
1.63 dsl 200: #ifdef SMALL
201: #define gz_compress(if, of, sz, fn, tm) gz_compress(if, of, sz)
202: #endif
203: static off_t gz_compress(int, int, off_t *, const char *, uint32_t);
1.46 mrg 204: static off_t gz_uncompress(int, int, char *, size_t, off_t *, const char *);
1.45 agc 205: static off_t file_compress(char *, char *, size_t);
206: static off_t file_uncompress(char *, char *, size_t);
1.1 mrg 207: static void handle_pathname(char *);
208: static void handle_file(char *, struct stat *);
209: static void handle_stdin(void);
210: static void handle_stdout(void);
1.6 mrg 211: static void print_ratio(off_t, off_t, FILE *);
1.7 mrg 212: static void print_list(int fd, off_t, const char *, time_t);
1.10 mrg 213: static void usage(void);
214: static void display_version(void);
1.63 dsl 215: static const suffixes_t *check_suffix(char *, int);
1.71 yamt 216: static ssize_t read_retry(int, void *, size_t);
1.26 mrg 217:
1.63 dsl 218: #ifdef SMALL
219: #define unlink_input(f, sb) unlink(f)
220: #else
1.66 dsl 221: static off_t cat_fd(unsigned char *, size_t, off_t *, int fd);
1.26 mrg 222: static void prepend_gzip(char *, int *, char ***);
1.74 mrg 223: static void handle_dir(char *);
1.63 dsl 224: static void print_verbage(const char *, const char *, off_t, off_t);
1.45 agc 225: static void print_test(const char *, int);
1.77 mrg 226: static void copymodes(int fd, const struct stat *, const char *file);
227: static int check_outfile(const char *outfile);
1.26 mrg 228: #endif
229:
1.24 tsutsui 230: #ifndef NO_BZIP2_SUPPORT
1.37 mrg 231: static off_t unbzip2(int, int, char *, size_t, off_t *);
1.24 tsutsui 232: #endif
1.26 mrg 233:
1.24 tsutsui 234: #ifndef NO_COMPRESS_SUPPORT
1.63 dsl 235: static FILE *zdopen(int);
1.37 mrg 236: static off_t zuncompress(FILE *, FILE *, char *, size_t, off_t *);
1.24 tsutsui 237: #endif
1.1 mrg 238:
1.95 mrg 239: #ifndef NO_PACK_SUPPORT
240: static off_t unpack(int, int, char *, size_t, off_t *);
241: #endif
242:
1.100 christos 243: #ifndef NO_XZ_SUPPORT
244: static off_t unxz(int, int, char *, size_t, off_t *);
245: #endif
246:
1.1 mrg 247: int main(int, char *p[]);
248:
1.11 mrg 249: #ifdef SMALL
250: #define getopt_long(a,b,c,d,e) getopt(a,b,c)
251: #else
1.3 jdolecek 252: static const struct option longopts[] = {
1.1 mrg 253: { "stdout", no_argument, 0, 'c' },
254: { "to-stdout", no_argument, 0, 'c' },
255: { "decompress", no_argument, 0, 'd' },
256: { "uncompress", no_argument, 0, 'd' },
257: { "force", no_argument, 0, 'f' },
258: { "help", no_argument, 0, 'h' },
1.98 mrg 259: { "keep", no_argument, 0, 'k' },
1.5 mrg 260: { "list", no_argument, 0, 'l' },
1.1 mrg 261: { "no-name", no_argument, 0, 'n' },
262: { "name", no_argument, 0, 'N' },
263: { "quiet", no_argument, 0, 'q' },
264: { "recursive", no_argument, 0, 'r' },
265: { "suffix", required_argument, 0, 'S' },
266: { "test", no_argument, 0, 't' },
267: { "verbose", no_argument, 0, 'v' },
268: { "version", no_argument, 0, 'V' },
269: { "fast", no_argument, 0, '1' },
270: { "best", no_argument, 0, '9' },
271: #if 0
272: /*
1.10 mrg 273: * This is what else GNU gzip implements. --ascii isn't useful
274: * on NetBSD, and I don't care to have a --license.
1.1 mrg 275: */
276: { "ascii", no_argument, 0, 'a' },
277: { "license", no_argument, 0, 'L' },
278: #endif
1.12 mrg 279: { NULL, no_argument, 0, 0 },
1.1 mrg 280: };
1.11 mrg 281: #endif
1.1 mrg 282:
283: int
284: main(int argc, char **argv)
285: {
1.28 mrg 286: const char *progname = getprogname();
1.25 mrg 287: #ifndef SMALL
1.15 mrg 288: char *gzip;
1.63 dsl 289: int len;
1.25 mrg 290: #endif
1.1 mrg 291: int ch;
292:
1.15 mrg 293: /* XXX set up signals */
294:
1.25 mrg 295: #ifndef SMALL
1.15 mrg 296: if ((gzip = getenv("GZIP")) != NULL)
297: prepend_gzip(gzip, &argc, &argv);
1.28 mrg 298: #endif
1.15 mrg 299:
1.1 mrg 300: /*
301: * XXX
302: * handle being called `gunzip', `zcat' and `gzcat'
303: */
304: if (strcmp(progname, "gunzip") == 0)
305: dflag = 1;
306: else if (strcmp(progname, "zcat") == 0 ||
307: strcmp(progname, "gzcat") == 0)
308: dflag = cflag = 1;
1.25 mrg 309:
310: #ifdef SMALL
1.99 tsutsui 311: #define OPT_LIST "123456789cdhlV"
1.25 mrg 312: #else
1.98 mrg 313: #define OPT_LIST "123456789cdfhklNnqrS:tVv"
1.25 mrg 314: #endif
1.1 mrg 315:
1.63 dsl 316: while ((ch = getopt_long(argc, argv, OPT_LIST, longopts, NULL)) != -1) {
1.1 mrg 317: switch (ch) {
1.81 wiz 318: case '1': case '2': case '3':
319: case '4': case '5': case '6':
320: case '7': case '8': case '9':
321: numflag = ch - '0';
322: break;
1.1 mrg 323: case 'c':
324: cflag = 1;
325: break;
326: case 'd':
327: dflag = 1;
328: break;
1.5 mrg 329: case 'l':
330: lflag = 1;
331: dflag = 1;
332: break;
1.26 mrg 333: case 'V':
334: display_version();
335: /* NOTREACHED */
1.25 mrg 336: #ifndef SMALL
337: case 'f':
338: fflag = 1;
339: break;
1.98 mrg 340: case 'k':
341: kflag = 1;
342: break;
1.81 wiz 343: case 'N':
344: nflag = 0;
345: Nflag = 1;
346: break;
1.1 mrg 347: case 'n':
348: nflag = 1;
349: Nflag = 0;
350: break;
351: case 'q':
352: qflag = 1;
353: break;
354: case 'r':
355: rflag = 1;
356: break;
357: case 'S':
1.63 dsl 358: len = strlen(optarg);
359: if (len != 0) {
1.96 mrg 360: if (len > SUFFIX_MAXLEN)
361: errx(1, "incorrect suffix: '%s'", optarg);
1.66 dsl 362: suffixes[0].zipped = optarg;
1.63 dsl 363: suffixes[0].ziplen = len;
364: } else {
1.66 dsl 365: suffixes[NUM_SUFFIXES - 1].zipped = "";
1.63 dsl 366: suffixes[NUM_SUFFIXES - 1].ziplen = 0;
367: }
1.1 mrg 368: break;
369: case 't':
370: cflag = 1;
371: tflag = 1;
372: dflag = 1;
373: break;
374: case 'v':
375: vflag = 1;
376: break;
1.26 mrg 377: #endif
1.12 mrg 378: default:
379: usage();
380: /* NOTREACHED */
1.1 mrg 381: }
1.63 dsl 382: }
1.1 mrg 383: argv += optind;
384: argc -= optind;
385:
386: if (argc == 0) {
387: if (dflag) /* stdin mode */
388: handle_stdin();
389: else /* stdout mode */
390: handle_stdout();
391: } else {
392: do {
393: handle_pathname(argv[0]);
1.5 mrg 394: } while (*++argv);
1.1 mrg 395: }
1.29 mrg 396: #ifndef SMALL
1.6 mrg 397: if (qflag == 0 && lflag && argc > 1)
1.7 mrg 398: print_list(-1, 0, "(totals)", 0);
1.29 mrg 399: #endif
1.46 mrg 400: exit(exit_value);
1.1 mrg 401: }
402:
403: /* maybe print a warning */
404: void
405: maybe_warn(const char *fmt, ...)
406: {
407: va_list ap;
408:
409: if (qflag == 0) {
410: va_start(ap, fmt);
411: vwarn(fmt, ap);
412: va_end(ap);
413: }
1.46 mrg 414: if (exit_value == 0)
415: exit_value = 1;
1.1 mrg 416: }
417:
1.46 mrg 418: /* ... without an errno. */
1.1 mrg 419: void
420: maybe_warnx(const char *fmt, ...)
421: {
422: va_list ap;
423:
424: if (qflag == 0) {
425: va_start(ap, fmt);
426: vwarnx(fmt, ap);
427: va_end(ap);
428: }
1.46 mrg 429: if (exit_value == 0)
430: exit_value = 1;
1.1 mrg 431: }
432:
1.46 mrg 433: /* maybe print an error */
1.1 mrg 434: void
1.46 mrg 435: maybe_err(const char *fmt, ...)
1.1 mrg 436: {
437: va_list ap;
438:
439: if (qflag == 0) {
440: va_start(ap, fmt);
441: vwarn(fmt, ap);
442: va_end(ap);
443: }
1.46 mrg 444: exit(2);
1.1 mrg 445: }
446:
1.101 tsutsui 447: #if !defined(NO_BZIP2_SUPPORT) || !defined(NO_PACK_SUPPORT) || \
448: !defined(NO_XZ_SUPPORT)
1.46 mrg 449: /* ... without an errno. */
1.9 mrg 450: void
1.46 mrg 451: maybe_errx(const char *fmt, ...)
1.9 mrg 452: {
453: va_list ap;
454:
455: if (qflag == 0) {
456: va_start(ap, fmt);
457: vwarnx(fmt, ap);
458: va_end(ap);
459: }
1.46 mrg 460: exit(2);
1.9 mrg 461: }
1.66 dsl 462: #endif
1.9 mrg 463:
1.25 mrg 464: #ifndef SMALL
1.15 mrg 465: /* split up $GZIP and prepend it to the argument list */
466: static void
467: prepend_gzip(char *gzip, int *argc, char ***argv)
468: {
469: char *s, **nargv, **ac;
470: int nenvarg = 0, i;
471:
472: /* scan how many arguments there are */
1.70 enami 473: for (s = gzip;;) {
474: while (*s == ' ' || *s == '\t')
475: s++;
476: if (*s == 0)
477: goto count_done;
1.15 mrg 478: nenvarg++;
1.70 enami 479: while (*s != ' ' && *s != '\t')
480: if (*s++ == 0)
481: goto count_done;
1.15 mrg 482: }
1.70 enami 483: count_done:
1.15 mrg 484: /* punt early */
485: if (nenvarg == 0)
486: return;
487:
488: *argc += nenvarg;
489: ac = *argv;
490:
1.17 simonb 491: nargv = (char **)malloc((*argc + 1) * sizeof(char *));
1.15 mrg 492: if (nargv == NULL)
1.46 mrg 493: maybe_err("malloc");
1.15 mrg 494:
495: /* stash this away */
496: *argv = nargv;
497:
498: /* copy the program name first */
499: i = 0;
500: nargv[i++] = *(ac++);
501:
502: /* take a copy of $GZIP and add it to the array */
503: s = strdup(gzip);
504: if (s == NULL)
1.46 mrg 505: maybe_err("strdup");
1.70 enami 506: for (;;) {
507: /* Skip whitespaces. */
508: while (*s == ' ' || *s == '\t')
509: s++;
510: if (*s == 0)
511: goto copy_done;
1.15 mrg 512: nargv[i++] = s;
1.70 enami 513: /* Find the end of this argument. */
514: while (*s != ' ' && *s != '\t')
515: if (*s++ == 0)
516: /* Argument followed by NUL. */
517: goto copy_done;
518: /* Terminate by overwriting ' ' or '\t' with NUL. */
519: *s++ = 0;
1.15 mrg 520: }
1.70 enami 521: copy_done:
1.15 mrg 522:
523: /* copy the original arguments and a NULL */
524: while (*ac)
525: nargv[i++] = *(ac++);
526: nargv[i] = NULL;
527: }
1.25 mrg 528: #endif
1.15 mrg 529:
1.63 dsl 530: /* compress input to output. Return bytes read, -1 on error */
1.37 mrg 531: static off_t
1.63 dsl 532: gz_compress(int in, int out, off_t *gsizep, const char *origname, uint32_t mtime)
1.1 mrg 533: {
1.37 mrg 534: z_stream z;
1.62 he 535: char *outbufp, *inbufp;
1.37 mrg 536: off_t in_tot = 0, out_tot = 0;
537: ssize_t in_size;
538: int i, error;
539: uLong crc;
1.63 dsl 540: #ifdef SMALL
541: static char header[] = { GZIP_MAGIC0, GZIP_MAGIC1, Z_DEFLATED, 0,
542: 0, 0, 0, 0,
543: 0, OS_CODE };
544: #endif
1.37 mrg 545:
1.63 dsl 546: outbufp = malloc(BUFLEN);
547: inbufp = malloc(BUFLEN);
548: if (outbufp == NULL || inbufp == NULL) {
1.62 he 549: maybe_err("malloc failed");
1.46 mrg 550: goto out;
551: }
1.37 mrg 552:
553: memset(&z, 0, sizeof z);
1.38 mrg 554: z.zalloc = Z_NULL;
555: z.zfree = Z_NULL;
1.37 mrg 556: z.opaque = 0;
557:
1.63 dsl 558: #ifdef SMALL
559: memcpy(outbufp, header, sizeof header);
560: i = sizeof header;
561: #else
562: if (nflag != 0) {
563: mtime = 0;
564: origname = "";
565: }
566:
567: i = snprintf(outbufp, BUFLEN, "%c%c%c%c%c%c%c%c%c%c%s",
568: GZIP_MAGIC0, GZIP_MAGIC1, Z_DEFLATED,
569: *origname ? ORIG_NAME : 0,
570: mtime & 0xff,
571: (mtime >> 8) & 0xff,
572: (mtime >> 16) & 0xff,
573: (mtime >> 24) & 0xff,
1.65 dsl 574: numflag == 1 ? 4 : numflag == 9 ? 2 : 0,
575: OS_CODE, origname);
1.63 dsl 576: if (i >= BUFLEN)
577: /* this need PATH_MAX > BUFLEN ... */
578: maybe_err("snprintf");
579: if (*origname)
580: i++;
581: #endif
582:
583: z.next_out = outbufp + i;
584: z.avail_out = BUFLEN - i;
585:
1.37 mrg 586: error = deflateInit2(&z, numflag, Z_DEFLATED,
1.74 mrg 587: (-MAX_WBITS), 8, Z_DEFAULT_STRATEGY);
1.46 mrg 588: if (error != Z_OK) {
589: maybe_warnx("deflateInit2 failed");
590: in_tot = -1;
591: goto out;
592: }
1.37 mrg 593:
594: crc = crc32(0L, Z_NULL, 0);
595: for (;;) {
596: if (z.avail_out == 0) {
1.62 he 597: if (write(out, outbufp, BUFLEN) != BUFLEN) {
1.46 mrg 598: maybe_warn("write");
1.89 mrg 599: out_tot = -1;
1.46 mrg 600: goto out;
601: }
1.37 mrg 602:
1.62 he 603: out_tot += BUFLEN;
604: z.next_out = outbufp;
605: z.avail_out = BUFLEN;
1.37 mrg 606: }
607:
608: if (z.avail_in == 0) {
1.63 dsl 609: in_size = read(in, inbufp, BUFLEN);
610: if (in_size < 0) {
611: maybe_warn("read");
1.46 mrg 612: in_tot = -1;
613: goto out;
614: }
1.37 mrg 615: if (in_size == 0)
616: break;
617:
1.62 he 618: crc = crc32(crc, (const Bytef *)inbufp, (unsigned)in_size);
1.37 mrg 619: in_tot += in_size;
1.62 he 620: z.next_in = inbufp;
1.37 mrg 621: z.avail_in = in_size;
622: }
623:
624: error = deflate(&z, Z_NO_FLUSH);
1.46 mrg 625: if (error != Z_OK && error != Z_STREAM_END) {
626: maybe_warnx("deflate failed");
627: in_tot = -1;
628: goto out;
629: }
1.37 mrg 630: }
1.1 mrg 631:
1.37 mrg 632: /* clean up */
1.1 mrg 633: for (;;) {
1.37 mrg 634: size_t len;
1.77 mrg 635: ssize_t w;
1.37 mrg 636:
637: error = deflate(&z, Z_FINISH);
1.46 mrg 638: if (error != Z_OK && error != Z_STREAM_END) {
639: maybe_warnx("deflate failed");
640: in_tot = -1;
641: goto out;
642: }
1.37 mrg 643:
1.63 dsl 644: len = (char *)z.next_out - outbufp;
1.37 mrg 645:
1.77 mrg 646: w = write(out, outbufp, len);
647: if (w == -1 || (size_t)w != len) {
1.46 mrg 648: maybe_warn("write");
649: out_tot = -1;
650: goto out;
651: }
1.37 mrg 652: out_tot += len;
1.62 he 653: z.next_out = outbufp;
654: z.avail_out = BUFLEN;
1.37 mrg 655:
656: if (error == Z_STREAM_END)
1.1 mrg 657: break;
1.37 mrg 658: }
659:
1.46 mrg 660: if (deflateEnd(&z) != Z_OK) {
661: maybe_warnx("deflateEnd failed");
662: in_tot = -1;
663: goto out;
664: }
1.37 mrg 665:
1.63 dsl 666: i = snprintf(outbufp, BUFLEN, "%c%c%c%c%c%c%c%c",
1.37 mrg 667: (int)crc & 0xff,
668: (int)(crc >> 8) & 0xff,
669: (int)(crc >> 16) & 0xff,
670: (int)(crc >> 24) & 0xff,
671: (int)in_tot & 0xff,
672: (int)(in_tot >> 8) & 0xff,
673: (int)(in_tot >> 16) & 0xff,
674: (int)(in_tot >> 24) & 0xff);
675: if (i != 8)
1.63 dsl 676: maybe_err("snprintf");
1.79 mrg 677: #if 0
1.73 mrg 678: if (in_tot > 0xffffffff)
679: maybe_warn("input file size >= 4GB cannot be saved");
1.79 mrg 680: #endif
1.63 dsl 681: if (write(out, outbufp, i) != i) {
1.46 mrg 682: maybe_warn("write");
683: in_tot = -1;
1.63 dsl 684: } else
685: out_tot += i;
1.1 mrg 686:
1.46 mrg 687: out:
1.63 dsl 688: if (inbufp != NULL)
689: free(inbufp);
690: if (outbufp != NULL)
691: free(outbufp);
1.37 mrg 692: if (gsizep)
693: *gsizep = out_tot;
694: return in_tot;
1.1 mrg 695: }
696:
1.37 mrg 697: /*
698: * uncompress input to output then close the input. return the
699: * uncompressed size written, and put the compressed sized read
700: * into `*gsizep'.
701: */
1.1 mrg 702: static off_t
1.46 mrg 703: gz_uncompress(int in, int out, char *pre, size_t prelen, off_t *gsizep,
704: const char *filename)
1.1 mrg 705: {
1.37 mrg 706: z_stream z;
1.62 he 707: char *outbufp, *inbufp;
1.72 lukem 708: off_t out_tot = -1, in_tot = 0;
709: uint32_t out_sub_tot = 0;
1.37 mrg 710: enum {
711: GZSTATE_MAGIC0,
712: GZSTATE_MAGIC1,
713: GZSTATE_METHOD,
714: GZSTATE_FLAGS,
715: GZSTATE_SKIPPING,
716: GZSTATE_EXTRA,
717: GZSTATE_EXTRA2,
718: GZSTATE_EXTRA3,
719: GZSTATE_ORIGNAME,
720: GZSTATE_COMMENT,
721: GZSTATE_HEAD_CRC1,
722: GZSTATE_HEAD_CRC2,
723: GZSTATE_INIT,
1.55 mrg 724: GZSTATE_READ,
725: GZSTATE_CRC,
726: GZSTATE_LEN,
1.37 mrg 727: } state = GZSTATE_MAGIC0;
728: int flags = 0, skip_count = 0;
1.72 lukem 729: int error = Z_STREAM_ERROR, done_reading = 0;
730: uLong crc = 0;
1.68 dsl 731: ssize_t wr;
1.71 yamt 732: int needmore = 0;
1.37 mrg 733:
734: #define ADVANCE() { z.next_in++; z.avail_in--; }
735:
1.62 he 736: if ((outbufp = malloc(BUFLEN)) == NULL) {
737: maybe_err("malloc failed");
738: goto out2;
739: }
740: if ((inbufp = malloc(BUFLEN)) == NULL) {
741: maybe_err("malloc failed");
742: goto out1;
743: }
744:
1.37 mrg 745: memset(&z, 0, sizeof z);
746: z.avail_in = prelen;
747: z.next_in = pre;
1.62 he 748: z.avail_out = BUFLEN;
749: z.next_out = outbufp;
1.37 mrg 750: z.zalloc = NULL;
751: z.zfree = NULL;
752: z.opaque = 0;
753:
754: in_tot = prelen;
755: out_tot = 0;
1.1 mrg 756:
1.37 mrg 757: for (;;) {
1.71 yamt 758: if ((z.avail_in == 0 || needmore) && done_reading == 0) {
1.77 mrg 759: ssize_t in_size;
1.71 yamt 760:
761: if (z.avail_in > 0) {
762: memmove(inbufp, z.next_in, z.avail_in);
763: }
764: z.next_in = inbufp;
765: in_size = read(in, z.next_in + z.avail_in,
766: BUFLEN - z.avail_in);
1.1 mrg 767:
1.37 mrg 768: if (in_size == -1) {
1.51 mrg 769: maybe_warn("failed to read stdin");
1.73 mrg 770: goto stop_and_fail;
1.71 yamt 771: } else if (in_size == 0) {
1.37 mrg 772: done_reading = 1;
1.71 yamt 773: }
1.37 mrg 774:
1.71 yamt 775: z.avail_in += in_size;
776: needmore = 0;
1.37 mrg 777:
778: in_tot += in_size;
779: }
1.54 mrg 780: if (z.avail_in == 0) {
1.86 mlelstv 781: if (done_reading && state != GZSTATE_MAGIC0) {
1.55 mrg 782: maybe_warnx("%s: unexpected end of file",
783: filename);
1.86 mlelstv 784: goto stop_and_fail;
785: }
1.54 mrg 786: goto stop;
787: }
1.37 mrg 788: switch (state) {
789: case GZSTATE_MAGIC0:
1.46 mrg 790: if (*z.next_in != GZIP_MAGIC0) {
1.87 mlelstv 791: if (in_tot > 0) {
1.88 mrg 792: maybe_warnx("%s: trailing garbage "
793: "ignored", filename);
1.87 mlelstv 794: goto stop;
795: }
1.55 mrg 796: maybe_warnx("input not gziped (MAGIC0)");
1.73 mrg 797: goto stop_and_fail;
1.46 mrg 798: }
1.37 mrg 799: ADVANCE();
800: state++;
1.54 mrg 801: out_sub_tot = 0;
802: crc = crc32(0L, Z_NULL, 0);
1.37 mrg 803: break;
804:
805: case GZSTATE_MAGIC1:
806: if (*z.next_in != GZIP_MAGIC1 &&
1.46 mrg 807: *z.next_in != GZIP_OMAGIC1) {
1.55 mrg 808: maybe_warnx("input not gziped (MAGIC1)");
1.73 mrg 809: goto stop_and_fail;
1.46 mrg 810: }
1.37 mrg 811: ADVANCE();
812: state++;
813: break;
814:
815: case GZSTATE_METHOD:
1.46 mrg 816: if (*z.next_in != Z_DEFLATED) {
1.51 mrg 817: maybe_warnx("unknown compression method");
1.73 mrg 818: goto stop_and_fail;
1.46 mrg 819: }
1.37 mrg 820: ADVANCE();
821: state++;
822: break;
823:
824: case GZSTATE_FLAGS:
825: flags = *z.next_in;
826: ADVANCE();
827: skip_count = 6;
828: state++;
829: break;
830:
831: case GZSTATE_SKIPPING:
832: if (skip_count > 0) {
833: skip_count--;
834: ADVANCE();
835: } else
836: state++;
837: break;
838:
839: case GZSTATE_EXTRA:
840: if ((flags & EXTRA_FIELD) == 0) {
841: state = GZSTATE_ORIGNAME;
842: break;
843: }
844: skip_count = *z.next_in;
845: ADVANCE();
846: state++;
847: break;
848:
849: case GZSTATE_EXTRA2:
850: skip_count |= ((*z.next_in) << 8);
851: ADVANCE();
852: state++;
853: break;
854:
855: case GZSTATE_EXTRA3:
856: if (skip_count > 0) {
857: skip_count--;
858: ADVANCE();
1.1 mrg 859: } else
1.37 mrg 860: state++;
861: break;
862:
863: case GZSTATE_ORIGNAME:
864: if ((flags & ORIG_NAME) == 0) {
865: state++;
866: break;
867: }
868: if (*z.next_in == 0)
869: state++;
870: ADVANCE();
871: break;
872:
873: case GZSTATE_COMMENT:
874: if ((flags & COMMENT) == 0) {
875: state++;
876: break;
877: }
878: if (*z.next_in == 0)
879: state++;
880: ADVANCE();
881: break;
882:
883: case GZSTATE_HEAD_CRC1:
884: if (flags & HEAD_CRC)
885: skip_count = 2;
886: else
887: skip_count = 0;
888: state++;
889: break;
890:
891: case GZSTATE_HEAD_CRC2:
892: if (skip_count > 0) {
893: skip_count--;
894: ADVANCE();
895: } else
896: state++;
897: break;
898:
899: case GZSTATE_INIT:
900: if (inflateInit2(&z, -MAX_WBITS) != Z_OK) {
1.51 mrg 901: maybe_warnx("failed to inflateInit");
1.73 mrg 902: goto stop_and_fail;
1.37 mrg 903: }
904: state++;
905: break;
906:
907: case GZSTATE_READ:
908: error = inflate(&z, Z_FINISH);
1.73 mrg 909: switch (error) {
1.50 mrg 910: /* Z_BUF_ERROR goes with Z_FINISH... */
1.73 mrg 911: case Z_BUF_ERROR:
1.98 mrg 912: if (z.avail_out > 0 && !done_reading)
913: continue;
914:
1.73 mrg 915: case Z_STREAM_END:
916: case Z_OK:
1.68 dsl 917: break;
1.73 mrg 918:
919: case Z_NEED_DICT:
920: maybe_warnx("Z_NEED_DICT error");
921: goto stop_and_fail;
922: case Z_DATA_ERROR:
923: maybe_warnx("data stream error");
924: goto stop_and_fail;
925: case Z_STREAM_ERROR:
926: maybe_warnx("internal stream error");
927: goto stop_and_fail;
928: case Z_MEM_ERROR:
929: maybe_warnx("memory allocation error");
930: goto stop_and_fail;
931:
932: default:
933: maybe_warn("unknown error from inflate(): %d",
934: error);
935: }
1.68 dsl 936: wr = BUFLEN - z.avail_out;
1.50 mrg 937:
1.68 dsl 938: if (wr != 0) {
1.62 he 939: crc = crc32(crc, (const Bytef *)outbufp, (unsigned)wr);
1.37 mrg 940: if (
941: #ifndef SMALL
942: /* don't write anything with -t */
943: tflag == 0 &&
944: #endif
1.62 he 945: write(out, outbufp, wr) != wr) {
1.52 yamt 946: maybe_warn("error writing to output");
1.73 mrg 947: goto stop_and_fail;
1.46 mrg 948: }
1.39 mrg 949:
950: out_tot += wr;
1.54 mrg 951: out_sub_tot += wr;
1.68 dsl 952: }
1.37 mrg 953:
1.68 dsl 954: if (error == Z_STREAM_END) {
955: inflateEnd(&z);
956: state++;
957: }
1.39 mrg 958:
1.68 dsl 959: z.next_out = outbufp;
960: z.avail_out = BUFLEN;
1.37 mrg 961:
1.68 dsl 962: break;
1.55 mrg 963: case GZSTATE_CRC:
964: {
965: uLong origcrc;
966:
967: if (z.avail_in < 4) {
1.71 yamt 968: if (!done_reading) {
969: needmore = 1;
1.55 mrg 970: continue;
1.71 yamt 971: }
1.55 mrg 972: maybe_warnx("truncated input");
1.73 mrg 973: goto stop_and_fail;
1.55 mrg 974: }
1.57 mrg 975: origcrc = ((unsigned)z.next_in[0] & 0xff) |
976: ((unsigned)z.next_in[1] & 0xff) << 8 |
977: ((unsigned)z.next_in[2] & 0xff) << 16 |
978: ((unsigned)z.next_in[3] & 0xff) << 24;
979: if (origcrc != crc) {
1.55 mrg 980: maybe_warnx("invalid compressed"
981: " data--crc error");
1.73 mrg 982: goto stop_and_fail;
1.57 mrg 983: }
1.55 mrg 984: }
985:
986: z.avail_in -= 4;
987: z.next_in += 4;
988:
1.71 yamt 989: if (!z.avail_in && done_reading) {
1.55 mrg 990: goto stop;
1.71 yamt 991: }
1.55 mrg 992: state++;
993: break;
994: case GZSTATE_LEN:
995: {
996: uLong origlen;
997:
998: if (z.avail_in < 4) {
1.71 yamt 999: if (!done_reading) {
1000: needmore = 1;
1.55 mrg 1001: continue;
1.71 yamt 1002: }
1.55 mrg 1003: maybe_warnx("truncated input");
1.73 mrg 1004: goto stop_and_fail;
1.55 mrg 1005: }
1.57 mrg 1006: origlen = ((unsigned)z.next_in[0] & 0xff) |
1007: ((unsigned)z.next_in[1] & 0xff) << 8 |
1008: ((unsigned)z.next_in[2] & 0xff) << 16 |
1009: ((unsigned)z.next_in[3] & 0xff) << 24;
1.55 mrg 1010:
1.57 mrg 1011: if (origlen != out_sub_tot) {
1.55 mrg 1012: maybe_warnx("invalid compressed"
1013: " data--length error");
1.73 mrg 1014: goto stop_and_fail;
1.57 mrg 1015: }
1.55 mrg 1016: }
1017:
1018: z.avail_in -= 4;
1019: z.next_in += 4;
1020:
1.37 mrg 1021: if (error < 0) {
1.51 mrg 1022: maybe_warnx("decompression error");
1.73 mrg 1023: goto stop_and_fail;
1.37 mrg 1024: }
1.55 mrg 1025: state = GZSTATE_MAGIC0;
1.1 mrg 1026: break;
1027: }
1.37 mrg 1028: continue;
1.73 mrg 1029: stop_and_fail:
1.78 mrg 1030: out_tot = -1;
1.37 mrg 1031: stop:
1032: break;
1033: }
1034: if (state > GZSTATE_INIT)
1035: inflateEnd(&z);
1.1 mrg 1036:
1.62 he 1037: free(inbufp);
1038: out1:
1039: free(outbufp);
1040: out2:
1.37 mrg 1041: if (gsizep)
1042: *gsizep = in_tot;
1043: return (out_tot);
1.1 mrg 1044: }
1045:
1.29 mrg 1046: #ifndef SMALL
1.1 mrg 1047: /*
1.77 mrg 1048: * set the owner, mode, flags & utimes using the given file descriptor.
1049: * file is only used in possible warning messages.
1.1 mrg 1050: */
1051: static void
1.77 mrg 1052: copymodes(int fd, const struct stat *sbp, const char *file)
1.1 mrg 1053: {
1054: struct timeval times[2];
1.77 mrg 1055: struct stat sb;
1.1 mrg 1056:
1057: /*
1058: * If we have no info on the input, give this file some
1059: * default values and return..
1060: */
1061: if (sbp == NULL) {
1062: mode_t mask = umask(022);
1063:
1.77 mrg 1064: (void)fchmod(fd, DEFFILEMODE & ~mask);
1.1 mrg 1065: (void)umask(mask);
1066: return;
1067: }
1.77 mrg 1068: sb = *sbp;
1.1 mrg 1069:
1070: /* if the chown fails, remove set-id bits as-per compress(1) */
1.77 mrg 1071: if (fchown(fd, sb.st_uid, sb.st_gid) < 0) {
1.1 mrg 1072: if (errno != EPERM)
1.77 mrg 1073: maybe_warn("couldn't fchown: %s", file);
1074: sb.st_mode &= ~(S_ISUID|S_ISGID);
1.1 mrg 1075: }
1076:
1077: /* we only allow set-id and the 9 normal permission bits */
1.77 mrg 1078: sb.st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
1079: if (fchmod(fd, sb.st_mode) < 0)
1080: maybe_warn("couldn't fchmod: %s", file);
1.1 mrg 1081:
1082: /* only try flags if they exist already */
1.77 mrg 1083: if (sb.st_flags != 0 && fchflags(fd, sb.st_flags) < 0)
1084: maybe_warn("couldn't fchflags: %s", file);
1.1 mrg 1085:
1.77 mrg 1086: TIMESPEC_TO_TIMEVAL(×[0], &sb.st_atimespec);
1087: TIMESPEC_TO_TIMEVAL(×[1], &sb.st_mtimespec);
1088: if (futimes(fd, times) < 0)
1.1 mrg 1089: maybe_warn("couldn't utimes: %s", file);
1090: }
1.29 mrg 1091: #endif
1.1 mrg 1092:
1.32 mrg 1093: /* what sort of file is this? */
1094: static enum filetype
1095: file_gettype(u_char *buf)
1096: {
1097:
1098: if (buf[0] == GZIP_MAGIC0 &&
1099: (buf[1] == GZIP_MAGIC1 || buf[1] == GZIP_OMAGIC1))
1100: return FT_GZIP;
1101: else
1102: #ifndef NO_BZIP2_SUPPORT
1103: if (memcmp(buf, BZIP2_MAGIC, 3) == 0 &&
1104: buf[3] >= '0' && buf[3] <= '9')
1105: return FT_BZIP2;
1106: else
1107: #endif
1108: #ifndef NO_COMPRESS_SUPPORT
1109: if (memcmp(buf, Z_MAGIC, 2) == 0)
1110: return FT_Z;
1111: else
1112: #endif
1.95 mrg 1113: #ifndef NO_PACK_SUPPORT
1114: if (memcmp(buf, PACK_MAGIC, 2) == 0)
1115: return FT_PACK;
1116: else
1117: #endif
1.100 christos 1118: #ifndef NO_XZ_SUPPORT
1119: if (memcmp(buf, XZ_MAGIC, 4) == 0) /* XXX: We only have 4 bytes */
1120: return FT_XZ;
1121: else
1122: #endif
1.32 mrg 1123: return FT_UNKNOWN;
1124: }
1125:
1.46 mrg 1126: #ifndef SMALL
1127: /* check the outfile is OK. */
1128: static int
1.77 mrg 1129: check_outfile(const char *outfile)
1.46 mrg 1130: {
1.77 mrg 1131: struct stat sb;
1.46 mrg 1132: int ok = 1;
1133:
1.77 mrg 1134: if (lflag == 0 && stat(outfile, &sb) == 0) {
1.59 mrg 1135: if (fflag)
1136: unlink(outfile);
1137: else if (isatty(STDIN_FILENO)) {
1.46 mrg 1138: char ans[10] = { 'n', '\0' }; /* default */
1139:
1140: fprintf(stderr, "%s already exists -- do you wish to "
1141: "overwrite (y or n)? " , outfile);
1142: (void)fgets(ans, sizeof(ans) - 1, stdin);
1143: if (ans[0] != 'y' && ans[0] != 'Y') {
1.90 martin 1144: fprintf(stderr, "\tnot overwriting\n");
1.46 mrg 1145: ok = 0;
1146: } else
1147: unlink(outfile);
1148: } else {
1149: maybe_warnx("%s already exists -- skipping", outfile);
1150: ok = 0;
1151: }
1152: }
1153: return ok;
1154: }
1.56 mrg 1155:
1.63 dsl 1156: static void
1.77 mrg 1157: unlink_input(const char *file, const struct stat *sb)
1.56 mrg 1158: {
1.63 dsl 1159: struct stat nsb;
1160:
1.98 mrg 1161: if (kflag)
1162: return;
1.63 dsl 1163: if (stat(file, &nsb) != 0)
1.98 mrg 1164: /* Must be gone already */
1.63 dsl 1165: return;
1166: if (nsb.st_dev != sb->st_dev || nsb.st_ino != sb->st_ino)
1167: /* Definitely a different file */
1168: return;
1169: unlink(file);
1170: }
1171: #endif
1.56 mrg 1172:
1.63 dsl 1173: static const suffixes_t *
1174: check_suffix(char *file, int xlate)
1175: {
1176: const suffixes_t *s;
1177: int len = strlen(file);
1178: char *sp;
1179:
1180: for (s = suffixes; s != suffixes + NUM_SUFFIXES; s++) {
1.57 mrg 1181: /* if it doesn't fit in "a.suf", don't bother */
1.63 dsl 1182: if (s->ziplen >= len)
1183: continue;
1184: sp = file + len - s->ziplen;
1185: if (strcmp(s->zipped, sp) != 0)
1.57 mrg 1186: continue;
1.63 dsl 1187: if (xlate)
1188: strcpy(sp, s->normal);
1189: return s;
1.56 mrg 1190: }
1191: return NULL;
1192: }
1.46 mrg 1193:
1.1 mrg 1194: /*
1195: * compress the given file: create a corresponding .gz file and remove the
1196: * original.
1197: */
1.31 mrg 1198: static off_t
1.45 agc 1199: file_compress(char *file, char *outfile, size_t outsize)
1.1 mrg 1200: {
1.63 dsl 1201: int in;
1.37 mrg 1202: int out;
1.63 dsl 1203: off_t size, insize;
1204: #ifndef SMALL
1.1 mrg 1205: struct stat isb, osb;
1.63 dsl 1206: const suffixes_t *suff;
1.25 mrg 1207: #endif
1.1 mrg 1208:
1.63 dsl 1209: in = open(file, O_RDONLY);
1210: if (in == -1) {
1211: maybe_warn("can't open %s", file);
1212: return -1;
1213: }
1214:
1.1 mrg 1215: if (cflag == 0) {
1.56 mrg 1216: #ifndef SMALL
1.77 mrg 1217: if (fstat(in, &isb) == 0) {
1218: if (isb.st_nlink > 1 && fflag == 0) {
1219: maybe_warnx("%s has %d other link%s -- "
1220: "skipping", file, isb.st_nlink - 1,
1221: isb.st_nlink == 1 ? "" : "s");
1222: close(in);
1223: return -1;
1224: }
1.63 dsl 1225: }
1.56 mrg 1226:
1.63 dsl 1227: if (fflag == 0 && (suff = check_suffix(file, 0))
1228: && suff->zipped[0] != 0) {
1.56 mrg 1229: maybe_warnx("%s already has %s suffix -- unchanged",
1.63 dsl 1230: file, suff->zipped);
1231: close(in);
1232: return -1;
1.56 mrg 1233: }
1234: #endif
1235:
1.63 dsl 1236: /* Add (usually) .gz to filename */
1.77 mrg 1237: if ((size_t)snprintf(outfile, outsize, "%s%s",
1.63 dsl 1238: file, suffixes[0].zipped) >= outsize)
1.96 mrg 1239: memcpy(outfile + outsize - suffixes[0].ziplen - 1,
1.63 dsl 1240: suffixes[0].zipped, suffixes[0].ziplen + 1);
1.1 mrg 1241:
1.25 mrg 1242: #ifndef SMALL
1.77 mrg 1243: if (check_outfile(outfile) == 0) {
1.63 dsl 1244: close(in);
1245: return -1;
1.34 mrg 1246: }
1.25 mrg 1247: #endif
1.1 mrg 1248: }
1249:
1.43 bouyer 1250: if (cflag == 0) {
1.63 dsl 1251: out = open(outfile, O_WRONLY | O_CREAT | O_EXCL, 0600);
1.39 mrg 1252: if (out == -1) {
1253: maybe_warn("could not create output: %s", outfile);
1.63 dsl 1254: fclose(stdin);
1255: return -1;
1.39 mrg 1256: }
1.1 mrg 1257: } else
1.37 mrg 1258: out = STDOUT_FILENO;
1.1 mrg 1259:
1.63 dsl 1260: insize = gz_compress(in, out, &size, basename(file), (uint32_t)isb.st_mtime);
1.1 mrg 1261:
1.63 dsl 1262: (void)close(in);
1.42 mrg 1263:
1.1 mrg 1264: /*
1.63 dsl 1265: * If there was an error, insize will be -1.
1266: * If we compressed to stdout, just return the size.
1267: * Otherwise stat the file and check it is the correct size.
1268: * We only blow away the file if we can stat the output and it
1269: * has the expected size.
1.1 mrg 1270: */
1.63 dsl 1271: if (cflag != 0)
1272: return insize == -1 ? -1 : size;
1273:
1.29 mrg 1274: #ifndef SMALL
1.77 mrg 1275: if (fstat(out, &osb) != 0) {
1.63 dsl 1276: maybe_warn("couldn't stat: %s", outfile);
1277: goto bad_outfile;
1278: }
1279:
1280: if (osb.st_size != size) {
1281: maybe_warnx("output file: %s wrong size (%" PRIdOFF
1282: " != %" PRIdOFF "), deleting",
1283: outfile, osb.st_size, size);
1284: goto bad_outfile;
1285: }
1286:
1.77 mrg 1287: copymodes(out, &isb, outfile);
1.29 mrg 1288: #endif
1.77 mrg 1289: if (close(out) == -1)
1290: maybe_warn("couldn't close output");
1.1 mrg 1291:
1.63 dsl 1292: /* output is good, ok to delete input */
1293: unlink_input(file, &isb);
1294: return size;
1295:
1296: #ifndef SMALL
1297: bad_outfile:
1.77 mrg 1298: if (close(out) == -1)
1299: maybe_warn("couldn't close output");
1300:
1.63 dsl 1301: maybe_warnx("leaving original %s", file);
1302: unlink(outfile);
1303: return size;
1304: #endif
1.1 mrg 1305: }
1306:
1307: /* uncompress the given file and remove the original */
1.31 mrg 1308: static off_t
1.45 agc 1309: file_uncompress(char *file, char *outfile, size_t outsize)
1.1 mrg 1310: {
1311: struct stat isb, osb;
1312: off_t size;
1.63 dsl 1313: ssize_t rbytes;
1.66 dsl 1314: unsigned char header1[4];
1.10 mrg 1315: enum filetype method;
1.93 skrll 1316: int fd, ofd, zfd = -1;
1.48 mrg 1317: #ifndef SMALL
1.94 lukem 1318: ssize_t rv;
1.48 mrg 1319: time_t timestamp = 0;
1.66 dsl 1320: unsigned char name[PATH_MAX + 1];
1.48 mrg 1321: #endif
1.9 mrg 1322:
1323: /* gather the old name info */
1.1 mrg 1324:
1.9 mrg 1325: fd = open(file, O_RDONLY);
1.46 mrg 1326: if (fd < 0) {
1327: maybe_warn("can't open %s", file);
1328: goto lose;
1329: }
1.63 dsl 1330:
1331: strlcpy(outfile, file, outsize);
1332: if (check_suffix(outfile, 1) == NULL && !(cflag || lflag)) {
1333: maybe_warnx("%s: unknown suffix -- ignored", file);
1334: goto lose;
1335: }
1336:
1.57 mrg 1337: rbytes = read(fd, header1, sizeof header1);
1338: if (rbytes != sizeof header1) {
1.10 mrg 1339: /* we don't want to fail here. */
1.25 mrg 1340: #ifndef SMALL
1.10 mrg 1341: if (fflag)
1.63 dsl 1342: goto lose;
1.25 mrg 1343: #endif
1.57 mrg 1344: if (rbytes == -1)
1345: maybe_warn("can't read %s", file);
1346: else
1.82 mrg 1347: goto unexpected_EOF;
1.63 dsl 1348: goto lose;
1.10 mrg 1349: }
1350:
1.32 mrg 1351: method = file_gettype(header1);
1352: #ifndef SMALL
1.42 mrg 1353: if (fflag == 0 && method == FT_UNKNOWN) {
1354: maybe_warnx("%s: not in gzip format", file);
1.63 dsl 1355: goto lose;
1.42 mrg 1356: }
1.63 dsl 1357:
1.25 mrg 1358: #endif
1.9 mrg 1359:
1.48 mrg 1360: #ifndef SMALL
1.63 dsl 1361: if (method == FT_GZIP && Nflag) {
1362: unsigned char ts[4]; /* timestamp */
1.48 mrg 1363:
1.85 mrg 1364: rv = pread(fd, ts, sizeof ts, GZIP_TIMESTAMP);
1.94 lukem 1365: if (rv >= 0 && rv < (ssize_t)(sizeof ts))
1.85 mrg 1366: goto unexpected_EOF;
1367: if (rv == -1) {
1368: if (!fflag)
1.63 dsl 1369: maybe_warn("can't read %s", file);
1370: goto lose;
1.83 christos 1371: }
1.63 dsl 1372: timestamp = ts[3] << 24 | ts[2] << 16 | ts[1] << 8 | ts[0];
1.48 mrg 1373:
1.9 mrg 1374: if (header1[3] & ORIG_NAME) {
1.63 dsl 1375: rbytes = pread(fd, name, sizeof name, GZIP_ORIGNAME);
1.42 mrg 1376: if (rbytes < 0) {
1377: maybe_warn("can't read %s", file);
1.63 dsl 1378: goto lose;
1.42 mrg 1379: }
1.63 dsl 1380: if (name[0] != 0) {
1381: /* preserve original directory name */
1382: char *dp = strrchr(file, '/');
1383: if (dp == NULL)
1384: dp = file;
1385: else
1386: dp++;
1387: snprintf(outfile, outsize, "%.*s%.*s",
1.64 he 1388: (int) (dp - file),
1389: file, (int) rbytes, name);
1.1 mrg 1390: }
1391: }
1.9 mrg 1392: }
1.63 dsl 1393: #endif
1394: lseek(fd, 0, SEEK_SET);
1.1 mrg 1395:
1.31 mrg 1396: if (cflag == 0 || lflag) {
1.63 dsl 1397: if (fstat(fd, &isb) != 0)
1398: goto lose;
1.25 mrg 1399: #ifndef SMALL
1.63 dsl 1400: if (isb.st_nlink > 1 && lflag == 0 && fflag == 0) {
1401: maybe_warnx("%s has %d other links -- skipping",
1402: file, isb.st_nlink - 1);
1.9 mrg 1403: goto lose;
1.63 dsl 1404: }
1405: if (nflag == 0 && timestamp)
1406: isb.st_mtime = timestamp;
1.77 mrg 1407: if (check_outfile(outfile) == 0)
1.63 dsl 1408: goto lose;
1.31 mrg 1409: #endif
1.1 mrg 1410: }
1.5 mrg 1411:
1.48 mrg 1412: if (cflag == 0 && lflag == 0) {
1.46 mrg 1413: zfd = open(outfile, O_WRONLY|O_CREAT|O_EXCL, 0600);
1.63 dsl 1414: if (zfd == STDOUT_FILENO) {
1415: /* We won't close STDOUT_FILENO later... */
1416: zfd = dup(zfd);
1417: close(STDOUT_FILENO);
1418: }
1.46 mrg 1419: if (zfd == -1) {
1420: maybe_warn("can't open %s", outfile);
1421: goto lose;
1422: }
1423: } else
1424: zfd = STDOUT_FILENO;
1425:
1.100 christos 1426: switch (method) {
1.24 tsutsui 1427: #ifndef NO_BZIP2_SUPPORT
1.100 christos 1428: case FT_BZIP2:
1.30 mrg 1429: /* XXX */
1.46 mrg 1430: if (lflag) {
1431: maybe_warnx("no -l with bzip2 files");
1432: goto lose;
1433: }
1.26 mrg 1434:
1.63 dsl 1435: size = unbzip2(fd, zfd, NULL, 0, NULL);
1.100 christos 1436: break;
1.24 tsutsui 1437: #endif
1.29 mrg 1438:
1.24 tsutsui 1439: #ifndef NO_COMPRESS_SUPPORT
1.100 christos 1440: case FT_Z: {
1.22 mrg 1441: FILE *in, *out;
1442:
1.30 mrg 1443: /* XXX */
1.46 mrg 1444: if (lflag) {
1445: maybe_warnx("no -l with Lempel-Ziv files");
1446: goto lose;
1447: }
1.26 mrg 1448:
1.63 dsl 1449: if ((in = zdopen(fd)) == NULL) {
1450: maybe_warn("zdopen for read: %s", file);
1.46 mrg 1451: goto lose;
1452: }
1.22 mrg 1453:
1.63 dsl 1454: out = fdopen(dup(zfd), "w");
1.46 mrg 1455: if (out == NULL) {
1.63 dsl 1456: maybe_warn("fdopen for write: %s", outfile);
1457: fclose(in);
1.46 mrg 1458: goto lose;
1.22 mrg 1459: }
1460:
1.37 mrg 1461: size = zuncompress(in, out, NULL, 0, NULL);
1.66 dsl 1462: /* need to fclose() if ferror() is true... */
1463: if (ferror(in) | fclose(in)) {
1464: maybe_warn("failed infile fclose");
1.42 mrg 1465: unlink(outfile);
1.46 mrg 1466: (void)fclose(out);
1.42 mrg 1467: }
1.63 dsl 1468: if (fclose(out) != 0) {
1.66 dsl 1469: maybe_warn("failed outfile fclose");
1.63 dsl 1470: unlink(outfile);
1471: goto lose;
1.22 mrg 1472: }
1.100 christos 1473: break;
1474: }
1.24 tsutsui 1475: #endif
1.51 mrg 1476:
1.95 mrg 1477: #ifndef NO_PACK_SUPPORT
1.100 christos 1478: case FT_PACK:
1.95 mrg 1479: if (lflag) {
1480: maybe_warnx("no -l with packed files");
1481: goto lose;
1482: }
1483:
1484: size = unpack(fd, zfd, NULL, 0, NULL);
1.100 christos 1485: break;
1486: #endif
1487:
1488: #ifndef NO_XZ_SUPPORT
1489: case FT_XZ:
1490: if (lflag) {
1491: maybe_warnx("no -l with xz files");
1492: goto lose;
1493: }
1494:
1495: size = unxz(fd, zfd, NULL, 0, NULL);
1496: break;
1.95 mrg 1497: #endif
1498:
1.51 mrg 1499: #ifndef SMALL
1.100 christos 1500: case FT_UNKNOWN:
1.63 dsl 1501: if (lflag) {
1502: maybe_warnx("no -l for unknown filetypes");
1.51 mrg 1503: goto lose;
1504: }
1.63 dsl 1505: size = cat_fd(NULL, 0, NULL, fd);
1.100 christos 1506: break;
1.51 mrg 1507: #endif
1.100 christos 1508: default:
1.10 mrg 1509: if (lflag) {
1.63 dsl 1510: print_list(fd, isb.st_size, outfile, isb.st_mtime);
1511: close(fd);
1.61 yamt 1512: return -1; /* XXX */
1.10 mrg 1513: }
1514:
1.63 dsl 1515: size = gz_uncompress(fd, zfd, NULL, 0, NULL, file);
1.100 christos 1516: break;
1.63 dsl 1517: }
1518:
1519: if (close(fd) != 0)
1520: maybe_warn("couldn't close input");
1521: if (zfd != STDOUT_FILENO && close(zfd) != 0)
1522: maybe_warn("couldn't close output");
1.1 mrg 1523:
1.63 dsl 1524: if (size == -1) {
1525: if (cflag == 0)
1526: unlink(outfile);
1527: maybe_warnx("%s: uncompress failed", file);
1528: return -1;
1.10 mrg 1529: }
1.1 mrg 1530:
1531: /* if testing, or we uncompressed to stdout, this is all we need */
1.26 mrg 1532: #ifndef SMALL
1533: if (tflag)
1.63 dsl 1534: return size;
1.26 mrg 1535: #endif
1.67 dsl 1536: /* if we are uncompressing to stdin, don't remove the file. */
1.26 mrg 1537: if (cflag)
1.63 dsl 1538: return size;
1.1 mrg 1539:
1540: /*
1541: * if we create a file...
1542: */
1.63 dsl 1543: /*
1.67 dsl 1544: * if we can't stat the file don't remove the file.
1.63 dsl 1545: */
1.77 mrg 1546:
1547: ofd = open(outfile, O_RDWR, 0);
1548: if (ofd == -1) {
1549: maybe_warn("couldn't open (leaving original): %s",
1550: outfile);
1551: return -1;
1552: }
1553: if (fstat(ofd, &osb) != 0) {
1.63 dsl 1554: maybe_warn("couldn't stat (leaving original): %s",
1555: outfile);
1.77 mrg 1556: close(ofd);
1.63 dsl 1557: return -1;
1558: }
1559: if (osb.st_size != size) {
1.73 mrg 1560: maybe_warnx("stat gave different size: %" PRIdOFF
1.63 dsl 1561: " != %" PRIdOFF " (leaving original)",
1562: size, osb.st_size);
1.77 mrg 1563: close(ofd);
1.63 dsl 1564: unlink(outfile);
1565: return -1;
1566: }
1567: unlink_input(file, &isb);
1.29 mrg 1568: #ifndef SMALL
1.77 mrg 1569: copymodes(ofd, &isb, outfile);
1.29 mrg 1570: #endif
1.77 mrg 1571: close(ofd);
1.63 dsl 1572: return size;
1.1 mrg 1573:
1.82 mrg 1574: unexpected_EOF:
1575: maybe_warnx("%s: unexpected end of file", file);
1.63 dsl 1576: lose:
1577: if (fd != -1)
1578: close(fd);
1579: if (zfd != -1 && zfd != STDOUT_FILENO)
1580: close(fd);
1.46 mrg 1581: return -1;
1.1 mrg 1582: }
1583:
1.37 mrg 1584: #ifndef SMALL
1585: static off_t
1.51 mrg 1586: cat_fd(unsigned char * prepend, size_t count, off_t *gsizep, int fd)
1.37 mrg 1587: {
1588: char buf[BUFLEN];
1589: off_t in_tot;
1.77 mrg 1590: ssize_t w;
1.37 mrg 1591:
1592: in_tot = count;
1.77 mrg 1593: w = write(STDOUT_FILENO, prepend, count);
1594: if (w == -1 || (size_t)w != count) {
1.46 mrg 1595: maybe_warn("write to stdout");
1596: return -1;
1597: }
1.37 mrg 1598: for (;;) {
1.74 mrg 1599: ssize_t rv;
1600:
1.51 mrg 1601: rv = read(fd, buf, sizeof buf);
1602: if (rv == 0)
1603: break;
1604: if (rv < 0) {
1605: maybe_warn("read from fd %d", fd);
1606: break;
1607: }
1.37 mrg 1608:
1.46 mrg 1609: if (write(STDOUT_FILENO, buf, rv) != rv) {
1610: maybe_warn("write to stdout");
1.51 mrg 1611: break;
1.46 mrg 1612: }
1.37 mrg 1613: in_tot += rv;
1614: }
1615:
1616: if (gsizep)
1617: *gsizep = in_tot;
1618: return (in_tot);
1619: }
1620: #endif
1621:
1.1 mrg 1622: static void
1623: handle_stdin(void)
1624: {
1.37 mrg 1625: unsigned char header1[4];
1626: off_t usize, gsize;
1627: enum filetype method;
1.71 yamt 1628: ssize_t bytes_read;
1.37 mrg 1629: #ifndef NO_COMPRESS_SUPPORT
1630: FILE *in;
1631: #endif
1.1 mrg 1632:
1.25 mrg 1633: #ifndef SMALL
1.5 mrg 1634: if (fflag == 0 && lflag == 0 && isatty(STDIN_FILENO)) {
1.1 mrg 1635: maybe_warnx("standard input is a terminal -- ignoring");
1636: return;
1637: }
1.25 mrg 1638: #endif
1.5 mrg 1639:
1640: if (lflag) {
1641: struct stat isb;
1642:
1.37 mrg 1643: /* XXX could read the whole file, etc. */
1.46 mrg 1644: if (fstat(STDIN_FILENO, &isb) < 0) {
1645: maybe_warn("fstat");
1646: return;
1647: }
1.7 mrg 1648: print_list(STDIN_FILENO, isb.st_size, "stdout", isb.st_mtime);
1.5 mrg 1649: return;
1650: }
1651:
1.71 yamt 1652: bytes_read = read_retry(STDIN_FILENO, header1, sizeof header1);
1653: if (bytes_read == -1) {
1.46 mrg 1654: maybe_warn("can't read stdin");
1655: return;
1.71 yamt 1656: } else if (bytes_read != sizeof(header1)) {
1.82 mrg 1657: maybe_warnx("(stdin): unexpected end of file");
1.71 yamt 1658: return;
1.46 mrg 1659: }
1.37 mrg 1660:
1661: method = file_gettype(header1);
1662: switch (method) {
1663: default:
1664: #ifndef SMALL
1.46 mrg 1665: if (fflag == 0) {
1666: maybe_warnx("unknown compression format");
1667: return;
1668: }
1.51 mrg 1669: usize = cat_fd(header1, sizeof header1, &gsize, STDIN_FILENO);
1.37 mrg 1670: break;
1671: #endif
1672: case FT_GZIP:
1673: usize = gz_uncompress(STDIN_FILENO, STDOUT_FILENO,
1.46 mrg 1674: header1, sizeof header1, &gsize, "(stdin)");
1.37 mrg 1675: break;
1676: #ifndef NO_BZIP2_SUPPORT
1677: case FT_BZIP2:
1678: usize = unbzip2(STDIN_FILENO, STDOUT_FILENO,
1679: header1, sizeof header1, &gsize);
1680: break;
1681: #endif
1682: #ifndef NO_COMPRESS_SUPPORT
1683: case FT_Z:
1.63 dsl 1684: if ((in = zdopen(STDIN_FILENO)) == NULL) {
1.46 mrg 1685: maybe_warnx("zopen of stdin");
1686: return;
1687: }
1.37 mrg 1688:
1689: usize = zuncompress(in, stdout, header1, sizeof header1, &gsize);
1.63 dsl 1690: fclose(in);
1.37 mrg 1691: break;
1692: #endif
1.95 mrg 1693: #ifndef NO_PACK_SUPPORT
1694: case FT_PACK:
1695: usize = unpack(STDIN_FILENO, STDOUT_FILENO,
1696: (char *)header1, sizeof header1, &gsize);
1697: break;
1698: #endif
1.100 christos 1699: #ifndef NO_XZ_SUPPORT
1700: case FT_XZ:
1701: usize = unxz(STDIN_FILENO, STDOUT_FILENO,
1702: (char *)header1, sizeof header1, &gsize);
1703: break;
1704: #endif
1.37 mrg 1705: }
1706:
1707: #ifndef SMALL
1708: if (vflag && !tflag && usize != -1 && gsize != -1)
1.63 dsl 1709: print_verbage(NULL, NULL, usize, gsize);
1.78 mrg 1710: if (vflag && tflag)
1711: print_test("(stdin)", usize != -1);
1.37 mrg 1712: #endif
1713:
1.1 mrg 1714: }
1715:
1716: static void
1717: handle_stdout(void)
1718: {
1.37 mrg 1719: off_t gsize, usize;
1.69 jmc 1720: struct stat sb;
1721: time_t systime;
1722: uint32_t mtime;
1723: int ret;
1.1 mrg 1724:
1.25 mrg 1725: #ifndef SMALL
1.1 mrg 1726: if (fflag == 0 && isatty(STDOUT_FILENO)) {
1727: maybe_warnx("standard output is a terminal -- ignoring");
1728: return;
1729: }
1.25 mrg 1730: #endif
1.69 jmc 1731: /* If stdin is a file use it's mtime, otherwise use current time */
1732: ret = fstat(STDIN_FILENO, &sb);
1733:
1734: #ifndef SMALL
1735: if (ret < 0) {
1736: maybe_warn("Can't stat stdin");
1737: return;
1738: }
1739: #endif
1.37 mrg 1740:
1.69 jmc 1741: if (S_ISREG(sb.st_mode))
1742: mtime = (uint32_t)sb.st_mtime;
1743: else {
1744: systime = time(NULL);
1745: #ifndef SMALL
1746: if (systime == -1) {
1747: maybe_warn("time");
1748: return;
1749: }
1750: #endif
1751: mtime = (uint32_t)systime;
1752: }
1753:
1754: usize = gz_compress(STDIN_FILENO, STDOUT_FILENO, &gsize, "", mtime);
1.37 mrg 1755: #ifndef SMALL
1756: if (vflag && !tflag && usize != -1 && gsize != -1)
1.63 dsl 1757: print_verbage(NULL, NULL, usize, gsize);
1.37 mrg 1758: #endif
1.1 mrg 1759: }
1760:
1761: /* do what is asked for, for the path name */
1762: static void
1763: handle_pathname(char *path)
1764: {
1.44 agc 1765: char *opath = path, *s = NULL;
1.1 mrg 1766: ssize_t len;
1.63 dsl 1767: int slen;
1.1 mrg 1768: struct stat sb;
1769:
1770: /* check for stdout/stdin */
1771: if (path[0] == '-' && path[1] == '\0') {
1772: if (dflag)
1773: handle_stdin();
1774: else
1775: handle_stdout();
1.49 mrg 1776: return;
1.1 mrg 1777: }
1778:
1779: retry:
1.73 mrg 1780: if (stat(path, &sb) != 0) {
1.1 mrg 1781: /* lets try <path>.gz if we're decompressing */
1.44 agc 1782: if (dflag && s == NULL && errno == ENOENT) {
1.1 mrg 1783: len = strlen(path);
1.63 dsl 1784: slen = suffixes[0].ziplen;
1785: s = malloc(len + slen + 1);
1.44 agc 1786: if (s == NULL)
1.46 mrg 1787: maybe_err("malloc");
1.63 dsl 1788: memcpy(s, path, len);
1789: memcpy(s + len, suffixes[0].zipped, slen + 1);
1.1 mrg 1790: path = s;
1791: goto retry;
1792: }
1793: maybe_warn("can't stat: %s", opath);
1794: goto out;
1795: }
1796:
1797: if (S_ISDIR(sb.st_mode)) {
1.25 mrg 1798: #ifndef SMALL
1.1 mrg 1799: if (rflag)
1.74 mrg 1800: handle_dir(path);
1.1 mrg 1801: else
1.25 mrg 1802: #endif
1.60 yamt 1803: maybe_warnx("%s is a directory", path);
1.1 mrg 1804: goto out;
1805: }
1806:
1807: if (S_ISREG(sb.st_mode))
1808: handle_file(path, &sb);
1.63 dsl 1809: else
1810: maybe_warnx("%s is not a regular file", path);
1.1 mrg 1811:
1812: out:
1813: if (s)
1814: free(s);
1815: }
1816:
1817: /* compress/decompress a file */
1818: static void
1819: handle_file(char *file, struct stat *sbp)
1820: {
1.31 mrg 1821: off_t usize, gsize;
1.45 agc 1822: char outfile[PATH_MAX];
1.1 mrg 1823:
1824: infile = file;
1825: if (dflag) {
1.45 agc 1826: usize = file_uncompress(file, outfile, sizeof(outfile));
1.80 he 1827: #ifndef SMALL
1.78 mrg 1828: if (vflag && tflag)
1829: print_test(file, usize != -1);
1.80 he 1830: #endif
1.46 mrg 1831: if (usize == -1)
1.1 mrg 1832: return;
1833: gsize = sbp->st_size;
1834: } else {
1.45 agc 1835: gsize = file_compress(file, outfile, sizeof(outfile));
1.46 mrg 1836: if (gsize == -1)
1.1 mrg 1837: return;
1838: usize = sbp->st_size;
1839: }
1840:
1.26 mrg 1841:
1842: #ifndef SMALL
1.1 mrg 1843: if (vflag && !tflag)
1.45 agc 1844: print_verbage(file, (cflag) ? NULL : outfile, usize, gsize);
1.26 mrg 1845: #endif
1.1 mrg 1846: }
1847:
1.25 mrg 1848: #ifndef SMALL
1.63 dsl 1849: /* this is used with -r to recursively descend directories */
1.1 mrg 1850: static void
1.74 mrg 1851: handle_dir(char *dir)
1.1 mrg 1852: {
1853: char *path_argv[2];
1854: FTS *fts;
1855: FTSENT *entry;
1856:
1857: path_argv[0] = dir;
1858: path_argv[1] = 0;
1859: fts = fts_open(path_argv, FTS_PHYSICAL, NULL);
1860: if (fts == NULL) {
1861: warn("couldn't fts_open %s", dir);
1862: return;
1863: }
1864:
1865: while ((entry = fts_read(fts))) {
1866: switch(entry->fts_info) {
1867: case FTS_D:
1868: case FTS_DP:
1869: continue;
1870:
1871: case FTS_DNR:
1872: case FTS_ERR:
1873: case FTS_NS:
1874: maybe_warn("%s", entry->fts_path);
1875: continue;
1876: case FTS_F:
1877: handle_file(entry->fts_name, entry->fts_statp);
1878: }
1879: }
1880: (void)fts_close(fts);
1881: }
1.25 mrg 1882: #endif
1.1 mrg 1883:
1.66 dsl 1884: /* print a ratio - size reduction as a fraction of uncompressed size */
1.6 mrg 1885: static void
1886: print_ratio(off_t in, off_t out, FILE *where)
1887: {
1.66 dsl 1888: int percent10; /* 10 * percent */
1889: off_t diff;
1890: char buff[8];
1891: int len;
1.35 mrg 1892:
1.66 dsl 1893: diff = in - out/2;
1894: if (diff <= 0)
1895: /*
1896: * Output is more than double size of input! print -99.9%
1897: * Quite possibly we've failed to get the original size.
1898: */
1899: percent10 = -999;
1900: else {
1901: /*
1902: * We only need 12 bits of result from the final division,
1903: * so reduce the values until a 32bit division will suffice.
1904: */
1905: while (in > 0x100000) {
1906: diff >>= 1;
1907: in >>= 1;
1908: }
1909: if (in != 0)
1910: percent10 = ((u_int)diff * 2000) / (u_int)in - 1000;
1911: else
1912: percent10 = 0;
1913: }
1.35 mrg 1914:
1.66 dsl 1915: len = snprintf(buff, sizeof buff, "%2.2d.", percent10);
1916: /* Move the '.' to before the last digit */
1917: buff[len - 1] = buff[len - 2];
1918: buff[len - 2] = '.';
1919: fprintf(where, "%5s%%", buff);
1.6 mrg 1920: }
1921:
1.26 mrg 1922: #ifndef SMALL
1.1 mrg 1923: /* print compression statistics, and the new name (if there is one!) */
1924: static void
1.63 dsl 1925: print_verbage(const char *file, const char *nfile, off_t usize, off_t gsize)
1.1 mrg 1926: {
1.37 mrg 1927: if (file)
1928: fprintf(stderr, "%s:%s ", file,
1929: strlen(file) < 7 ? "\t\t" : "\t");
1.63 dsl 1930: print_ratio(usize, gsize, stderr);
1.4 mrg 1931: if (nfile)
1932: fprintf(stderr, " -- replaced with %s", nfile);
1.1 mrg 1933: fprintf(stderr, "\n");
1934: fflush(stderr);
1935: }
1936:
1937: /* print test results */
1938: static void
1.45 agc 1939: print_test(const char *file, int ok)
1.1 mrg 1940: {
1941:
1.46 mrg 1942: if (exit_value == 0 && ok == 0)
1943: exit_value = 1;
1.1 mrg 1944: fprintf(stderr, "%s:%s %s\n", file,
1945: strlen(file) < 7 ? "\t\t" : "\t", ok ? "OK" : "NOT OK");
1946: fflush(stderr);
1947: }
1.26 mrg 1948: #endif
1.1 mrg 1949:
1.5 mrg 1950: /* print a file's info ala --list */
1951: /* eg:
1952: compressed uncompressed ratio uncompressed_name
1953: 354841 1679360 78.8% /usr/pkgsrc/distfiles/libglade-2.0.1.tar
1954: */
1955: static void
1.35 mrg 1956: print_list(int fd, off_t out, const char *outfile, time_t ts)
1.5 mrg 1957: {
1958: static int first = 1;
1.29 mrg 1959: #ifndef SMALL
1.6 mrg 1960: static off_t in_tot, out_tot;
1.72 lukem 1961: uint32_t crc = 0;
1.29 mrg 1962: #endif
1.77 mrg 1963: off_t in = 0, rv;
1.5 mrg 1964:
1.7 mrg 1965: if (first) {
1.26 mrg 1966: #ifndef SMALL
1.7 mrg 1967: if (vflag)
1968: printf("method crc date time ");
1.26 mrg 1969: #endif
1.7 mrg 1970: if (qflag == 0)
1971: printf(" compressed uncompressed "
1972: "ratio uncompressed_name\n");
1973: }
1.5 mrg 1974: first = 0;
1975:
1.6 mrg 1976: /* print totals? */
1.29 mrg 1977: #ifndef SMALL
1.6 mrg 1978: if (fd == -1) {
1979: in = in_tot;
1980: out = out_tot;
1.29 mrg 1981: } else
1982: #endif
1983: {
1.6 mrg 1984: /* read the last 4 bytes - this is the uncompressed size */
1.7 mrg 1985: rv = lseek(fd, (off_t)(-8), SEEK_END);
1.6 mrg 1986: if (rv != -1) {
1.7 mrg 1987: unsigned char buf[8];
1.63 dsl 1988: uint32_t usize;
1.6 mrg 1989:
1.82 mrg 1990: rv = read(fd, (char *)buf, sizeof(buf));
1991: if (rv == -1)
1.37 mrg 1992: maybe_warn("read of uncompressed size");
1.82 mrg 1993: else if (rv != sizeof(buf))
1994: maybe_warnx("read of uncompressed size");
1995:
1996: else {
1997: usize = buf[4] | buf[5] << 8 |
1998: buf[6] << 16 | buf[7] << 24;
1999: in = (off_t)usize;
1.29 mrg 2000: #ifndef SMALL
1.82 mrg 2001: crc = buf[0] | buf[1] << 8 |
2002: buf[2] << 16 | buf[3] << 24;
1.29 mrg 2003: #endif
1.82 mrg 2004: }
1.6 mrg 2005: }
2006: }
1.5 mrg 2007:
1.26 mrg 2008: #ifndef SMALL
1.7 mrg 2009: if (vflag && fd == -1)
2010: printf(" ");
2011: else if (vflag) {
2012: char *date = ctime(&ts);
2013:
2014: /* skip the day, 1/100th second, and year */
2015: date += 4;
2016: date[12] = 0;
2017: printf("%5s %08x %11s ", "defla"/*XXX*/, crc, date);
2018: }
1.29 mrg 2019: in_tot += in;
2020: out_tot += out;
1.26 mrg 2021: #endif
1.35 mrg 2022: printf("%12llu %12llu ", (unsigned long long)out, (unsigned long long)in);
1.6 mrg 2023: print_ratio(in, out, stdout);
2024: printf(" %s\n", outfile);
1.5 mrg 2025: }
2026:
1.1 mrg 2027: /* display the usage of NetBSD gzip */
2028: static void
2029: usage(void)
2030: {
2031:
2032: fprintf(stderr, "%s\n", gzip_version);
2033: fprintf(stderr,
1.29 mrg 2034: "usage: %s [-" OPT_LIST "] [<file> [<file> ...]]\n"
1.11 mrg 2035: #ifndef SMALL
1.81 wiz 2036: " -1 --fast fastest (worst) compression\n"
2037: " -2 .. -8 set compression level\n"
2038: " -9 --best best (slowest) compression\n"
1.1 mrg 2039: " -c --stdout write to stdout, keep original files\n"
2040: " --to-stdout\n"
2041: " -d --decompress uncompress files\n"
2042: " --uncompress\n"
2043: " -f --force force overwriting & compress links\n"
2044: " -h --help display this help\n"
1.98 mrg 2045: " -k --keep don't delete input files during operation\n"
1.81 wiz 2046: " -l --list list compressed file contents\n"
2047: " -N --name save or restore original file name and time stamp\n"
1.1 mrg 2048: " -n --no-name don't save original file name or time stamp\n"
2049: " -q --quiet output no warnings\n"
2050: " -r --recursive recursively compress files in directories\n"
2051: " -S .suf use suffix .suf instead of .gz\n"
2052: " --suffix .suf\n"
2053: " -t --test test compressed file\n"
2054: " -V --version display program version\n"
1.81 wiz 2055: " -v --verbose print extra statistics\n",
1.11 mrg 2056: #else
2057: ,
2058: #endif
1.1 mrg 2059: getprogname());
2060: exit(0);
2061: }
2062:
2063: /* display the version of NetBSD gzip */
2064: static void
2065: display_version(void)
2066: {
2067:
2068: fprintf(stderr, "%s\n", gzip_version);
2069: exit(0);
2070: }
1.10 mrg 2071:
1.24 tsutsui 2072: #ifndef NO_BZIP2_SUPPORT
1.10 mrg 2073: #include "unbzip2.c"
1.24 tsutsui 2074: #endif
2075: #ifndef NO_COMPRESS_SUPPORT
1.22 mrg 2076: #include "zuncompress.c"
1.24 tsutsui 2077: #endif
1.95 mrg 2078: #ifndef NO_PACK_SUPPORT
2079: #include "unpack.c"
2080: #endif
1.100 christos 2081: #ifndef NO_XZ_SUPPORT
2082: #include "unxz.c"
2083: #endif
1.71 yamt 2084:
2085: static ssize_t
2086: read_retry(int fd, void *buf, size_t sz)
2087: {
2088: char *cp = buf;
1.77 mrg 2089: size_t left = MIN(sz, (size_t) SSIZE_MAX);
1.71 yamt 2090:
2091: while (left > 0) {
2092: ssize_t ret;
2093:
1.77 mrg 2094: ret = read(fd, cp, left);
1.71 yamt 2095: if (ret == -1) {
2096: return ret;
2097: } else if (ret == 0) {
2098: break; /* EOF */
2099: }
2100: cp += ret;
2101: left -= ret;
2102: }
2103:
2104: return sz - left;
2105: }
CVSweb <webmaster@jp.NetBSD.org>