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