gzip: pacify clang
[debian/gzip] / gzip.c
1 /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
2
3    Copyright (C) 1999, 2001-2002, 2006-2007, 2009-2016 Free Software
4    Foundation, Inc.
5    Copyright (C) 1992-1993 Jean-loup Gailly
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3, or (at your option)
10    any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software Foundation,
19    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
20
21 /*
22  * The unzip code was written and put in the public domain by Mark Adler.
23  * Portions of the lzw code are derived from the public domain 'compress'
24  * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
25  * Ken Turkowski, Dave Mack and Peter Jannesen.
26  *
27  * See the license_msg below and the file COPYING for the software license.
28  * See the file algorithm.doc for the compression algorithms and file formats.
29  */
30
31 static char const *const license_msg[] = {
32 "Copyright (C) 2016 Free Software Foundation, Inc.",
33 "Copyright (C) 1993 Jean-loup Gailly.",
34 "This is free software.  You may redistribute copies of it under the terms of",
35 "the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.",
36 "There is NO WARRANTY, to the extent permitted by law.",
37 0};
38
39 /* Compress files with zip algorithm and 'compress' interface.
40  * See help() function below for all options.
41  * Outputs:
42  *        file.gz:   compressed file with same mode, owner, and utimes
43  *     or stdout with -c option or if stdin used as input.
44  * If the output file name had to be truncated, the original name is kept
45  * in the compressed file.
46  * On MSDOS, file.tmp -> file.tmz. On VMS, file.tmp -> file.tmp-gz.
47  *
48  * Using gz on MSDOS would create too many file name conflicts. For
49  * example, foo.txt -> foo.tgz (.tgz must be reserved as shorthand for
50  * tar.gz). Similarly, foo.dir and foo.doc would both be mapped to foo.dgz.
51  * I also considered 12345678.txt -> 12345txt.gz but this truncates the name
52  * too heavily. There is no ideal solution given the MSDOS 8+3 limitation.
53  *
54  * For the meaning of all compilation flags, see comments in Makefile.in.
55  */
56
57 #include <config.h>
58 #include <ctype.h>
59 #include <sys/types.h>
60 #include <signal.h>
61 #include <stdbool.h>
62 #include <stddef.h>
63 #include <sys/stat.h>
64 #include <errno.h>
65
66 #include "closein.h"
67 #include "tailor.h"
68 #include "gzip.h"
69 #include "intprops.h"
70 #include "lzw.h"
71 #include "revision.h"
72 #include "timespec.h"
73
74 #include "dirname.h"
75 #include "fcntl--.h"
76 #include "getopt.h"
77 #include "ignore-value.h"
78 #include "stat-time.h"
79 #include "version.h"
80 #include "yesno.h"
81
82                 /* configuration */
83
84 #include <limits.h>
85 #include <unistd.h>
86 #include <stdlib.h>
87 #include <errno.h>
88
89 #ifndef NO_DIR
90 # define NO_DIR 0
91 #endif
92 #if !NO_DIR
93 # include <dirent.h>
94 # include <savedir.h>
95 #endif
96
97 #ifndef NO_UTIME
98 #  include <utimens.h>
99 #endif
100
101 #ifndef MAX_PATH_LEN
102 #  define MAX_PATH_LEN   1024 /* max pathname length */
103 #endif
104
105 #ifndef SEEK_END
106 #  define SEEK_END 2
107 #endif
108
109 #ifndef CHAR_BIT
110 #  define CHAR_BIT 8
111 #endif
112
113 #ifdef off_t
114   off_t lseek (int fd, off_t offset, int whence);
115 #endif
116
117 #ifndef OFF_T_MAX
118 # define OFF_T_MAX TYPE_MAXIMUM (off_t)
119 #endif
120
121 /* Use SA_NOCLDSTOP as a proxy for whether the sigaction machinery is
122    present.  */
123 #ifndef SA_NOCLDSTOP
124 # define SA_NOCLDSTOP 0
125 # define sigprocmask(how, set, oset) /* empty */
126 # define sigset_t int
127 # if ! HAVE_SIGINTERRUPT
128 #  define siginterrupt(sig, flag) /* empty */
129 # endif
130 #endif
131
132 #ifndef HAVE_WORKING_O_NOFOLLOW
133 # define HAVE_WORKING_O_NOFOLLOW 0
134 #endif
135
136 /* Separator for file name parts (see shorten_name()) */
137 #ifdef NO_MULTIPLE_DOTS
138 #  define PART_SEP "-"
139 #else
140 #  define PART_SEP "."
141 #endif
142
143                 /* global buffers */
144
145 DECLARE(uch, inbuf,  INBUFSIZ +INBUF_EXTRA);
146 DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
147 DECLARE(ush, d_buf,  DIST_BUFSIZE);
148 DECLARE(uch, window, 2L*WSIZE);
149 #ifndef MAXSEG_64K
150     DECLARE(ush, tab_prefix, 1L<<BITS);
151 #else
152     DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
153     DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
154 #endif
155
156                 /* local variables */
157
158 /* If true, pretend that standard input is a tty.  This option
159    is deliberately not documented, and only for testing.  */
160 static bool presume_input_tty;
161
162 /* If true, transfer output data to the output file's storage device
163    when supported.  Otherwise, if the system crashes around the time
164    gzip is run, the user might lose both input and output data.  See:
165    Pillai TS et al.  All file systems are not created equal: on the
166    complexity of crafting crash-consistent applications. OSDI'14. 2014:433-48.
167    https://www.usenix.org/conference/osdi14/technical-sessions/presentation/pillai */
168 static bool synchronous;
169
170 static int ascii = 0;        /* convert end-of-lines to local OS conventions */
171        int to_stdout = 0;    /* output to stdout (-c) */
172 static int decompress = 0;   /* decompress (-d) */
173 static int force = 0;        /* don't ask questions, compress links (-f) */
174 static int keep = 0;         /* keep (don't delete) input files */
175 static int no_name = -1;     /* don't save or restore the original file name */
176 static int no_time = -1;     /* don't save or restore the original file time */
177 static int recursive = 0;    /* recurse through directories (-r) */
178 static int list = 0;         /* list the file contents (-l) */
179        int verbose = 0;      /* be verbose (-v) */
180        int quiet = 0;        /* be very quiet (-q) */
181 static int do_lzw = 0;       /* generate output compatible with old compress (-Z) */
182        int test = 0;         /* test .gz file integrity */
183 static int foreground = 0;   /* set if program run in foreground */
184        char *program_name;   /* program name */
185        int maxbits = BITS;   /* max bits per code for LZW */
186        int method = DEFLATED;/* compression method */
187        int level = 6;        /* compression level */
188        int exit_code = OK;   /* program exit code */
189        int save_orig_name;   /* set if original name must be saved */
190 static int last_member;      /* set for .zip and .Z files */
191 static int part_nb;          /* number of parts in .gz file */
192        struct timespec time_stamp; /* original time stamp (modification time) */
193        off_t ifile_size;      /* input file size, -1 for devices (debug only) */
194 static char *env;            /* contents of GZIP env variable */
195 static char const *z_suffix; /* default suffix (can be set with --suffix) */
196 static size_t z_len;         /* strlen(z_suffix) */
197
198 /* The set of signals that are caught.  */
199 static sigset_t caught_signals;
200
201 /* If nonzero then exit with status WARNING, rather than with the usual
202    signal status, on receipt of a signal with this value.  This
203    suppresses a "Broken Pipe" message with some shells.  */
204 static int volatile exiting_signal;
205
206 /* If nonnegative, close this file descriptor and unlink ofname on error.  */
207 static int volatile remove_ofname_fd = -1;
208
209 off_t bytes_in;             /* number of input bytes */
210 off_t bytes_out;            /* number of output bytes */
211 static off_t total_in;      /* input bytes for all files */
212 static off_t total_out;     /* output bytes for all files */
213 char ifname[MAX_PATH_LEN]; /* input file name */
214 char ofname[MAX_PATH_LEN]; /* output file name */
215 static char dfname[MAX_PATH_LEN]; /* name of dir containing output file */
216 static struct stat istat;         /* status for input file */
217 int  ifd;                  /* input file descriptor */
218 int  ofd;                  /* output file descriptor */
219 static int dfd = -1;       /* output directory file descriptor */
220 unsigned insize;           /* valid bytes in inbuf */
221 unsigned inptr;            /* index of next byte to be processed in inbuf */
222 unsigned outcnt;           /* bytes in output buffer */
223 int rsync = 0;             /* make ryncable chunks */
224
225 static int handled_sig[] =
226   {
227     /* SIGINT must be first, as 'foreground' depends on it.  */
228     SIGINT
229
230 #ifdef SIGHUP
231     , SIGHUP
232 #endif
233 #if SIGPIPE
234     , SIGPIPE
235 #endif
236 #ifdef SIGTERM
237     , SIGTERM
238 #endif
239 #ifdef SIGXCPU
240     , SIGXCPU
241 #endif
242 #ifdef SIGXFSZ
243     , SIGXFSZ
244 #endif
245   };
246
247 /* For long options that have no equivalent short option, use a
248    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
249 enum
250 {
251   PRESUME_INPUT_TTY_OPTION = CHAR_MAX + 1,
252   RSYNCABLE_OPTION,
253   SYNCHRONOUS_OPTION,
254
255   /* A value greater than all valid long options, used as a flag to
256      distinguish options derived from the GZIP environment variable.  */
257   ENV_OPTION
258 };
259
260 static char const shortopts[] = "ab:cdfhH?klLmMnNqrS:tvVZ123456789";
261
262 static const struct option longopts[] =
263 {
264  /* { name  has_arg  *flag  val } */
265     {"ascii",      0, 0, 'a'}, /* ascii text mode */
266     {"to-stdout",  0, 0, 'c'}, /* write output on standard output */
267     {"stdout",     0, 0, 'c'}, /* write output on standard output */
268     {"decompress", 0, 0, 'd'}, /* decompress */
269     {"uncompress", 0, 0, 'd'}, /* decompress */
270  /* {"encrypt",    0, 0, 'e'},    encrypt */
271     {"force",      0, 0, 'f'}, /* force overwrite of output file */
272     {"help",       0, 0, 'h'}, /* give help */
273  /* {"pkzip",      0, 0, 'k'},    force output in pkzip format */
274     {"keep",       0, 0, 'k'}, /* keep (don't delete) input files */
275     {"list",       0, 0, 'l'}, /* list .gz file contents */
276     {"license",    0, 0, 'L'}, /* display software license */
277     {"no-name",    0, 0, 'n'}, /* don't save or restore original name & time */
278     {"name",       0, 0, 'N'}, /* save or restore original name & time */
279     {"-presume-input-tty", no_argument, NULL, PRESUME_INPUT_TTY_OPTION},
280     {"quiet",      0, 0, 'q'}, /* quiet mode */
281     {"silent",     0, 0, 'q'}, /* quiet mode */
282     {"synchronous",0, 0, SYNCHRONOUS_OPTION},
283     {"recursive",  0, 0, 'r'}, /* recurse through directories */
284     {"suffix",     1, 0, 'S'}, /* use given suffix instead of .gz */
285     {"test",       0, 0, 't'}, /* test compressed file integrity */
286     {"no-time",    0, 0, 'T'}, /* don't save or restore the time stamp */
287     {"verbose",    0, 0, 'v'}, /* verbose mode */
288     {"version",    0, 0, 'V'}, /* display version number */
289     {"fast",       0, 0, '1'}, /* compress faster */
290     {"best",       0, 0, '9'}, /* compress better */
291     {"lzw",        0, 0, 'Z'}, /* make output compatible with old compress */
292     {"bits",       1, 0, 'b'}, /* max number of bits per code (implies -Z) */
293     {"rsyncable",  0, 0, RSYNCABLE_OPTION}, /* make rsync-friendly archive */
294     { 0, 0, 0, 0 }
295 };
296
297 /* local functions */
298
299 local void try_help     (void) ATTRIBUTE_NORETURN;
300 local void help         (void);
301 local void license      (void);
302 local void version      (void);
303 local int input_eof     (void);
304 local void treat_stdin  (void);
305 local void treat_file   (char *iname);
306 local int create_outfile (void);
307 local char *get_suffix  (char *name);
308 local int  open_input_file (char *iname, struct stat *sbuf);
309 local void discard_input_bytes (size_t nbytes, unsigned int flags);
310 local int  make_ofname  (void);
311 local void shorten_name  (char *name);
312 local int  get_method   (int in);
313 local void do_list      (int ifd, int method);
314 local int  check_ofname (void);
315 local void copy_stat    (struct stat *ifstat);
316 local void install_signal_handlers (void);
317 local void remove_output_file (void);
318 local RETSIGTYPE abort_gzip_signal (int);
319 local void do_exit      (int exitcode) ATTRIBUTE_NORETURN;
320       int main          (int argc, char **argv);
321 static int (*work) (int infile, int outfile) = zip; /* function to call */
322
323 #if ! NO_DIR
324 local void treat_dir    (int fd, char *dir);
325 #endif
326
327 #define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
328
329 static void
330 try_help ()
331 {
332   fprintf (stderr, "Try `%s --help' for more information.\n",
333            program_name);
334   do_exit (ERROR);
335 }
336
337 /* ======================================================================== */
338 local void help()
339 {
340     static char const* const help_msg[] = {
341  "Compress or uncompress FILEs (by default, compress FILES in-place).",
342  "",
343  "Mandatory arguments to long options are mandatory for short options too.",
344  "",
345 #if O_BINARY
346  "  -a, --ascii       ascii text; convert end-of-line using local conventions",
347 #endif
348  "  -c, --stdout      write on standard output, keep original files unchanged",
349  "  -d, --decompress  decompress",
350 /*  -e, --encrypt     encrypt */
351  "  -f, --force       force overwrite of output file and compress links",
352  "  -h, --help        give this help",
353 /*  -k, --pkzip       force output in pkzip format */
354  "  -k, --keep        keep (don't delete) input files",
355  "  -l, --list        list compressed file contents",
356  "  -L, --license     display software license",
357 #ifdef UNDOCUMENTED
358  "  -m, --no-time     do not save or restore the original modification time",
359  "  -M, --time        save or restore the original modification time",
360 #endif
361  "  -n, --no-name     do not save or restore the original name and time stamp",
362  "  -N, --name        save or restore the original name and time stamp",
363  "  -q, --quiet       suppress all warnings",
364 #if ! NO_DIR
365  "  -r, --recursive   operate recursively on directories",
366 #endif
367  "      --rsyncable   make rsync-friendly archive",
368  "  -S, --suffix=SUF  use suffix SUF on compressed files",
369  "      --synchronous synchronous output (safer if system crashes, but slower)",
370  "  -t, --test        test compressed file integrity",
371  "  -v, --verbose     verbose mode",
372  "  -V, --version     display version number",
373  "  -1, --fast        compress faster",
374  "  -9, --best        compress better",
375 #ifdef LZW
376  "  -Z, --lzw         produce output compatible with old compress",
377  "  -b, --bits=BITS   max number of bits per code (implies -Z)",
378 #endif
379  "",
380  "With no FILE, or when FILE is -, read standard input.",
381  "",
382  "Report bugs to <bug-gzip@gnu.org>.",
383   0};
384     char const *const *p = help_msg;
385
386     printf ("Usage: %s [OPTION]... [FILE]...\n", program_name);
387     while (*p) printf ("%s\n", *p++);
388 }
389
390 /* ======================================================================== */
391 local void license()
392 {
393     char const *const *p = license_msg;
394
395     printf ("%s %s\n", program_name, Version);
396     while (*p) printf ("%s\n", *p++);
397 }
398
399 /* ======================================================================== */
400 local void version()
401 {
402     license ();
403     printf ("\n");
404     printf ("Written by Jean-loup Gailly.\n");
405 }
406
407 local void progerror (char const *string)
408 {
409     int e = errno;
410     fprintf (stderr, "%s: ", program_name);
411     errno = e;
412     perror(string);
413     exit_code = ERROR;
414 }
415
416 /* ======================================================================== */
417 int main (int argc, char **argv)
418 {
419     int file_count;     /* number of files to process */
420     size_t proglen;     /* length of program_name */
421     char **argv_copy;
422     int env_argc;
423     char **env_argv;
424
425     EXPAND(argc, argv); /* wild card expansion if necessary */
426
427     program_name = gzip_base_name (argv[0]);
428     proglen = strlen (program_name);
429
430     atexit (close_stdin);
431
432     /* Suppress .exe for MSDOS, OS/2 and VMS: */
433     if (4 < proglen && strequ (program_name + proglen - 4, ".exe"))
434       program_name[proglen - 4] = '\0';
435
436     /* Add options in GZIP environment variable if there is one */
437     argv_copy = argv;
438     env = add_envopt (&env_argc, &argv_copy, OPTIONS_VAR);
439     env_argv = env ? argv_copy : NULL;
440
441 #ifndef GNU_STANDARD
442 # define GNU_STANDARD 1
443 #endif
444 #if !GNU_STANDARD
445     /* For compatibility with old compress, use program name as an option.
446      * Unless you compile with -DGNU_STANDARD=0, this program will behave as
447      * gzip even if it is invoked under the name gunzip or zcat.
448      *
449      * Systems which do not support links can still use -d or -dc.
450      * Ignore an .exe extension for MSDOS, OS/2 and VMS.
451      */
452     if (strncmp (program_name, "un",  2) == 0     /* ungzip, uncompress */
453         || strncmp (program_name, "gun", 3) == 0) /* gunzip */
454         decompress = 1;
455     else if (strequ (program_name + 1, "cat")     /* zcat, pcat, gcat */
456              || strequ (program_name, "gzcat"))   /* gzcat */
457         decompress = to_stdout = 1;
458 #endif
459
460     z_suffix = Z_SUFFIX;
461     z_len = strlen(z_suffix);
462
463     while (true) {
464         int optc;
465         int longind = -1;
466
467         if (env_argv)
468           {
469             if (env_argv[optind] && strequ (env_argv[optind], "--"))
470               optc = ENV_OPTION + '-';
471             else
472               {
473                 optc = getopt_long (env_argc, env_argv, shortopts, longopts,
474                                     &longind);
475                 if (0 <= optc)
476                   optc += ENV_OPTION;
477                 else
478                   {
479                     if (optind != env_argc)
480                       {
481                         fprintf (stderr,
482                                  ("%s: %s: non-option in "OPTIONS_VAR
483                                   " environment variable\n"),
484                                  program_name, env_argv[optind]);
485                         try_help ();
486                       }
487
488                     /* Wait until here before warning, so that GZIP='-q'
489                        doesn't warn.  */
490                     if (env_argc != 1 && !quiet)
491                       fprintf (stderr,
492                                ("%s: warning: "OPTIONS_VAR" environment variable"
493                                 " is deprecated; use an alias or script\n"),
494                                program_name);
495
496                     /* Start processing ARGC and ARGV instead.  */
497                     free (env_argv);
498                     env_argv = NULL;
499                     optind = 1;
500                     longind = -1;
501                   }
502               }
503           }
504
505         if (!env_argv)
506           optc = getopt_long (argc, argv, shortopts, longopts, &longind);
507         if (optc < 0)
508           break;
509
510         switch (optc) {
511         case 'a':
512             ascii = 1; break;
513         case 'b':
514             maxbits = atoi(optarg);
515             for (; *optarg; optarg++)
516               if (! ('0' <= *optarg && *optarg <= '9'))
517                 {
518                   fprintf (stderr, "%s: -b operand is not an integer\n",
519                            program_name);
520                   try_help ();
521                 }
522             break;
523         case 'c':
524             to_stdout = 1; break;
525         case 'd':
526             decompress = 1; break;
527         case 'f':
528             force++; break;
529         case 'h': case 'H':
530             help(); do_exit(OK); break;
531         case 'k':
532             keep = 1; break;
533         case 'l':
534             list = decompress = to_stdout = 1; break;
535         case 'L':
536             license(); do_exit(OK); break;
537         case 'm': /* undocumented, may change later */
538             no_time = 1; break;
539         case 'M': /* undocumented, may change later */
540             no_time = 0; break;
541         case 'n':
542         case 'n' + ENV_OPTION:
543             no_name = no_time = 1; break;
544         case 'N':
545         case 'N' + ENV_OPTION:
546             no_name = no_time = 0; break;
547         case PRESUME_INPUT_TTY_OPTION:
548             presume_input_tty = true; break;
549         case 'q':
550         case 'q' + ENV_OPTION:
551             quiet = 1; verbose = 0; break;
552         case 'r':
553 #if NO_DIR
554             fprintf (stderr, "%s: -r not supported on this system\n",
555                      program_name);
556             try_help ();
557 #else
558             recursive = 1;
559 #endif
560             break;
561
562         case RSYNCABLE_OPTION:
563             rsync = 1;
564             break;
565         case 'S':
566 #ifdef NO_MULTIPLE_DOTS
567             if (*optarg == '.') optarg++;
568 #endif
569             z_len = strlen(optarg);
570             z_suffix = optarg;
571             break;
572         case SYNCHRONOUS_OPTION:
573             synchronous = true;
574             break;
575         case 't':
576             test = decompress = to_stdout = 1;
577             break;
578         case 'v':
579         case 'v' + ENV_OPTION:
580             verbose++; quiet = 0; break;
581         case 'V':
582             version(); do_exit(OK); break;
583         case 'Z':
584 #ifdef LZW
585             do_lzw = 1; break;
586 #else
587             fprintf(stderr, "%s: -Z not supported in this version\n",
588                     program_name);
589             try_help ();
590             break;
591 #endif
592         case '1' + ENV_OPTION:  case '2' + ENV_OPTION:  case '3' + ENV_OPTION:
593         case '4' + ENV_OPTION:  case '5' + ENV_OPTION:  case '6' + ENV_OPTION:
594         case '7' + ENV_OPTION:  case '8' + ENV_OPTION:  case '9' + ENV_OPTION:
595             optc -= ENV_OPTION;
596             /* Fall through.  */
597         case '1':  case '2':  case '3':  case '4':
598         case '5':  case '6':  case '7':  case '8':  case '9':
599             level = optc - '0';
600             break;
601
602         default:
603             if (ENV_OPTION <= optc && optc != ENV_OPTION + '?')
604               {
605                 /* Output a diagnostic, since getopt_long didn't.  */
606                 fprintf (stderr, "%s: ", program_name);
607                 if (longind < 0)
608                   fprintf (stderr, "-%c: ", optc - ENV_OPTION);
609                 else
610                   fprintf (stderr, "--%s: ", longopts[longind].name);
611                 fprintf (stderr, ("option not valid in "OPTIONS_VAR
612                                   " environment variable\n"));
613               }
614             try_help ();
615         }
616     } /* loop on all arguments */
617
618     /* By default, save name and timestamp on compression but do not
619      * restore them on decompression.
620      */
621     if (no_time < 0) no_time = decompress;
622     if (no_name < 0) no_name = decompress;
623
624     file_count = argc - optind;
625
626 #if O_BINARY
627 #else
628     if (ascii && !quiet) {
629         fprintf(stderr, "%s: option --ascii ignored on this system\n",
630                 program_name);
631     }
632 #endif
633     if (z_len == 0 || z_len > MAX_SUFFIX) {
634         fprintf(stderr, "%s: invalid suffix '%s'\n", program_name, z_suffix);
635         do_exit(ERROR);
636     }
637
638     if (do_lzw && !decompress) work = lzw;
639
640     /* Allocate all global buffers (for DYN_ALLOC option) */
641     ALLOC(uch, inbuf,  INBUFSIZ +INBUF_EXTRA);
642     ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
643     ALLOC(ush, d_buf,  DIST_BUFSIZE);
644     ALLOC(uch, window, 2L*WSIZE);
645 #ifndef MAXSEG_64K
646     ALLOC(ush, tab_prefix, 1L<<BITS);
647 #else
648     ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
649     ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
650 #endif
651
652     exiting_signal = quiet ? SIGPIPE : 0;
653     install_signal_handlers ();
654
655     /* And get to work */
656     if (file_count != 0) {
657         if (to_stdout && !test && !list && (!decompress || !ascii)) {
658             SET_BINARY_MODE (STDOUT_FILENO);
659         }
660         while (optind < argc) {
661             treat_file(argv[optind++]);
662         }
663     } else {  /* Standard input */
664         treat_stdin();
665     }
666     if (list && !quiet && file_count > 1) {
667         do_list(-1, -1); /* print totals */
668     }
669     if (to_stdout
670         && ((synchronous
671              && (fdatasync (STDOUT_FILENO) != 0 && errno != EINVAL))
672             || close (STDOUT_FILENO) != 0)
673         && errno != EBADF)
674       write_error ();
675     do_exit(exit_code);
676     return exit_code; /* just to avoid lint warning */
677 }
678
679 /* Return nonzero when at end of file on input.  */
680 local int
681 input_eof ()
682 {
683   if (!decompress || last_member)
684     return 1;
685
686   if (inptr == insize)
687     {
688       if (insize != INBUFSIZ || fill_inbuf (1) == EOF)
689         return 1;
690
691       /* Unget the char that fill_inbuf got.  */
692       inptr = 0;
693     }
694
695   return 0;
696 }
697
698 /* ========================================================================
699  * Compress or decompress stdin
700  */
701 local void treat_stdin()
702 {
703     if (!force && !list
704         && (presume_input_tty
705             || isatty (decompress ? STDIN_FILENO : STDOUT_FILENO))) {
706         /* Do not send compressed data to the terminal or read it from
707          * the terminal. We get here when user invoked the program
708          * without parameters, so be helpful. According to the GNU standards:
709          *
710          *   If there is one behavior you think is most useful when the output
711          *   is to a terminal, and another that you think is most useful when
712          *   the output is a file or a pipe, then it is usually best to make
713          *   the default behavior the one that is useful with output to a
714          *   terminal, and have an option for the other behavior.
715          *
716          * Here we use the --force option to get the other behavior.
717          */
718         if (! quiet)
719           fprintf (stderr,
720                    ("%s: compressed data not %s a terminal."
721                     " Use -f to force %scompression.\n"
722                     "For help, type: %s -h\n"),
723                    program_name,
724                    decompress ? "read from" : "written to",
725                    decompress ? "de" : "",
726                    program_name);
727         do_exit(ERROR);
728     }
729
730     if (decompress || !ascii) {
731       SET_BINARY_MODE (STDIN_FILENO);
732     }
733     if (!test && !list && (!decompress || !ascii)) {
734       SET_BINARY_MODE (STDOUT_FILENO);
735     }
736     strcpy(ifname, "stdin");
737     strcpy(ofname, "stdout");
738
739     /* Get the file's time stamp and size.  */
740     if (fstat (STDIN_FILENO, &istat) != 0)
741       {
742         progerror ("standard input");
743         do_exit (ERROR);
744       }
745     ifile_size = S_ISREG (istat.st_mode) ? istat.st_size : -1;
746     time_stamp.tv_nsec = -1;
747     if (!no_time || list)
748       {
749         if (S_ISREG (istat.st_mode))
750           time_stamp = get_stat_mtime (&istat);
751         else
752           gettime (&time_stamp);
753       }
754
755     clear_bufs(); /* clear input and output buffers */
756     to_stdout = 1;
757     part_nb = 0;
758     ifd = STDIN_FILENO;
759
760     if (decompress) {
761         method = get_method(ifd);
762         if (method < 0) {
763             do_exit(exit_code); /* error message already emitted */
764         }
765     }
766     if (list) {
767         do_list(ifd, method);
768         return;
769     }
770
771     /* Actually do the compression/decompression. Loop over zipped members.
772      */
773     for (;;) {
774         if (work (STDIN_FILENO, STDOUT_FILENO) != OK)
775           return;
776
777         if (input_eof ())
778           break;
779
780         method = get_method(ifd);
781         if (method < 0) return; /* error message already emitted */
782         bytes_out = 0;            /* required for length check */
783     }
784
785     if (verbose) {
786         if (test) {
787             fprintf(stderr, " OK\n");
788
789         } else if (!decompress) {
790             display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
791             fprintf(stderr, "\n");
792 #ifdef DISPLAY_STDIN_RATIO
793         } else {
794             display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
795             fprintf(stderr, "\n");
796 #endif
797         }
798     }
799 }
800
801 static char const dot = '.';
802
803 /* True if the cached directory for calls to openat etc. is DIR, with
804    length DIRLEN.  DIR need not be null-terminated.  DIRLEN must be
805    less than MAX_PATH_LEN.  */
806 static bool
807 atdir_eq (char const *dir, ptrdiff_t dirlen)
808 {
809   if (dirlen == 0)
810     dir = &dot, dirlen = 1;
811   return memcmp (dfname, dir, dirlen) == 0 && !dfname[dirlen];
812 }
813
814 /* Set the directory used for calls to openat etc. to be the directory
815    DIR, with length DIRLEN.  DIR need not be null-terminated.
816    DIRLEN must be less than MAX_PATH_LEN.  Return a file descriptor for
817    the directory, or -1 if one could not be obtained.  */
818 static int
819 atdir_set (char const *dir, ptrdiff_t dirlen)
820 {
821   /* Don't bother opening directories on older systems that
822      lack openat and unlinkat.  It's not worth the porting hassle.  */
823   #if HAVE_OPENAT && HAVE_UNLINKAT
824     enum { try_opening_directories = true };
825   #else
826     enum { try_opening_directories = false };
827   #endif
828
829   if (try_opening_directories && ! atdir_eq (dir, dirlen))
830     {
831       if (0 <= dfd)
832         close (dfd);
833       if (dirlen == 0)
834         dir = &dot, dirlen = 1;
835       memcpy (dfname, dir, dirlen);
836       dfname[dirlen] = '\0';
837       dfd = open (dfname, O_SEARCH | O_DIRECTORY);
838     }
839
840   return dfd;
841 }
842
843 /* ========================================================================
844  * Compress or decompress the given file
845  */
846 local void treat_file(iname)
847     char *iname;
848 {
849     /* Accept "-" as synonym for stdin */
850     if (strequ(iname, "-")) {
851         int cflag = to_stdout;
852         treat_stdin();
853         to_stdout = cflag;
854         return;
855     }
856
857     /* Check if the input file is present, set ifname and istat: */
858     ifd = open_input_file (iname, &istat);
859     if (ifd < 0)
860       return;
861
862     /* If the input name is that of a directory, recurse or ignore: */
863     if (S_ISDIR(istat.st_mode)) {
864 #if ! NO_DIR
865         if (recursive) {
866             treat_dir (ifd, iname);
867             /* Warning: ifname is now garbage */
868             return;
869         }
870 #endif
871         close (ifd);
872         WARN ((stderr, "%s: %s is a directory -- ignored\n",
873                program_name, ifname));
874         return;
875     }
876
877     if (! to_stdout)
878       {
879         if (! S_ISREG (istat.st_mode))
880           {
881             WARN ((stderr,
882                    "%s: %s is not a directory or a regular file - ignored\n",
883                    program_name, ifname));
884             close (ifd);
885             return;
886           }
887         if (istat.st_mode & S_ISUID)
888           {
889             WARN ((stderr, "%s: %s is set-user-ID on execution - ignored\n",
890                    program_name, ifname));
891             close (ifd);
892             return;
893           }
894         if (istat.st_mode & S_ISGID)
895           {
896             WARN ((stderr, "%s: %s is set-group-ID on execution - ignored\n",
897                    program_name, ifname));
898             close (ifd);
899             return;
900           }
901
902         if (! force)
903           {
904             if (istat.st_mode & S_ISVTX)
905               {
906                 WARN ((stderr,
907                        "%s: %s has the sticky bit set - file ignored\n",
908                        program_name, ifname));
909                 close (ifd);
910                 return;
911               }
912             if (2 <= istat.st_nlink)
913               {
914                 WARN ((stderr, "%s: %s has %lu other link%c -- unchanged\n",
915                        program_name, ifname,
916                        (unsigned long int) istat.st_nlink - 1,
917                        istat.st_nlink == 2 ? ' ' : 's'));
918                 close (ifd);
919                 return;
920               }
921           }
922       }
923
924     ifile_size = S_ISREG (istat.st_mode) ? istat.st_size : -1;
925     time_stamp.tv_nsec = -1;
926     if (!no_time || list)
927       time_stamp = get_stat_mtime (&istat);
928
929     /* Generate output file name. For -r and (-t or -l), skip files
930      * without a valid gzip suffix (check done in make_ofname).
931      */
932     if (to_stdout && !list && !test) {
933         strcpy(ofname, "stdout");
934
935     } else if (make_ofname() != OK) {
936         close (ifd);
937         return;
938     }
939
940     clear_bufs(); /* clear input and output buffers */
941     part_nb = 0;
942
943     if (decompress) {
944         method = get_method(ifd); /* updates ofname if original given */
945         if (method < 0) {
946             close(ifd);
947             return;               /* error message already emitted */
948         }
949     }
950     if (list) {
951         do_list(ifd, method);
952         if (close (ifd) != 0)
953           read_error ();
954         return;
955     }
956
957     /* If compressing to a file, check if ofname is not ambiguous
958      * because the operating system truncates names. Otherwise, generate
959      * a new ofname and save the original name in the compressed file.
960      */
961     if (to_stdout) {
962         ofd = STDOUT_FILENO;
963         /* Keep remove_ofname_fd negative.  */
964     } else {
965         if (create_outfile() != OK) return;
966
967         if (!decompress && save_orig_name && !verbose && !quiet) {
968             fprintf(stderr, "%s: %s compressed to %s\n",
969                     program_name, ifname, ofname);
970         }
971     }
972     /* Keep the name even if not truncated except with --no-name: */
973     if (!save_orig_name) save_orig_name = !no_name;
974
975     if (verbose) {
976         fprintf(stderr, "%s:\t", ifname);
977     }
978
979     /* Actually do the compression/decompression. Loop over zipped members.
980      */
981     for (;;) {
982         if ((*work)(ifd, ofd) != OK) {
983             method = -1; /* force cleanup */
984             break;
985         }
986
987         if (input_eof ())
988           break;
989
990         method = get_method(ifd);
991         if (method < 0) break;    /* error message already emitted */
992         bytes_out = 0;            /* required for length check */
993     }
994
995     if (close (ifd) != 0)
996       read_error ();
997
998     if (!to_stdout)
999       {
1000         copy_stat (&istat);
1001
1002         if ((synchronous
1003              && ((0 <= dfd && fdatasync (dfd) != 0 && errno != EINVAL)
1004                  || (fsync (ofd) != 0 && errno != EINVAL)))
1005             || close (ofd) != 0)
1006           write_error ();
1007
1008         if (!keep)
1009           {
1010             sigset_t oldset;
1011             int unlink_errno;
1012             char *ifbase = last_component (ifname);
1013             int ufd = atdir_eq (ifname, ifbase - ifname) ? dfd : -1;
1014             int res;
1015
1016             sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
1017             remove_ofname_fd = -1;
1018             res = ufd < 0 ? xunlink (ifname) : unlinkat (ufd, ifbase, 0);
1019             unlink_errno = res == 0 ? 0 : errno;
1020             sigprocmask (SIG_SETMASK, &oldset, NULL);
1021
1022             if (unlink_errno)
1023               {
1024                 WARN ((stderr, "%s: ", program_name));
1025                 if (!quiet)
1026                   {
1027                     errno = unlink_errno;
1028                     perror (ifname);
1029                   }
1030               }
1031           }
1032       }
1033
1034     if (method == -1) {
1035         if (!to_stdout)
1036           remove_output_file ();
1037         return;
1038     }
1039
1040     /* Display statistics */
1041     if(verbose) {
1042         if (test) {
1043             fprintf(stderr, " OK");
1044         } else if (decompress) {
1045             display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
1046         } else {
1047             display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
1048         }
1049         if (!test && !to_stdout)
1050           fprintf(stderr, " -- %s %s", keep ? "created" : "replaced with",
1051                   ofname);
1052         fprintf(stderr, "\n");
1053     }
1054 }
1055
1056 /* ========================================================================
1057  * Create the output file. Return OK or ERROR.
1058  * Try several times if necessary to avoid truncating the z_suffix. For
1059  * example, do not create a compressed file of name "1234567890123."
1060  * Sets save_orig_name to true if the file name has been truncated.
1061  * IN assertions: the input file has already been open (ifd is set) and
1062  *   ofname has already been updated if there was an original name.
1063  * OUT assertions: ifd and ofd are closed in case of error.
1064  */
1065 local int create_outfile()
1066 {
1067   int name_shortened = 0;
1068   int flags = (O_WRONLY | O_CREAT | O_EXCL
1069                | (ascii && decompress ? 0 : O_BINARY));
1070   char const *base = ofname;
1071   int atfd = AT_FDCWD;
1072
1073   if (!keep)
1074     {
1075       char const *b = last_component (ofname);
1076       int f = atdir_set (ofname, b - ofname);
1077       if (0 <= f)
1078         {
1079           base = b;
1080           atfd = f;
1081         }
1082     }
1083
1084   for (;;)
1085     {
1086       int open_errno;
1087       sigset_t oldset;
1088
1089       sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
1090       remove_ofname_fd = ofd = openat (atfd, base, flags, S_IRUSR | S_IWUSR);
1091       open_errno = errno;
1092       sigprocmask (SIG_SETMASK, &oldset, NULL);
1093
1094       if (0 <= ofd)
1095         break;
1096
1097       switch (open_errno)
1098         {
1099 #ifdef ENAMETOOLONG
1100         case ENAMETOOLONG:
1101           shorten_name (ofname);
1102           name_shortened = 1;
1103           break;
1104 #endif
1105
1106         case EEXIST:
1107           if (check_ofname () != OK)
1108             {
1109               close (ifd);
1110               return ERROR;
1111             }
1112           break;
1113
1114         default:
1115           progerror (ofname);
1116           close (ifd);
1117           return ERROR;
1118         }
1119     }
1120
1121   if (name_shortened && decompress)
1122     {
1123       /* name might be too long if an original name was saved */
1124       WARN ((stderr, "%s: %s: warning, name truncated\n",
1125              program_name, ofname));
1126     }
1127
1128   return OK;
1129 }
1130
1131 /* ========================================================================
1132  * Return a pointer to the 'z' suffix of a file name, or NULL. For all
1133  * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
1134  * accepted suffixes, in addition to the value of the --suffix option.
1135  * ".tgz" is a useful convention for tar.z files on systems limited
1136  * to 3 characters extensions. On such systems, ".?z" and ".??z" are
1137  * also accepted suffixes. For Unix, we do not want to accept any
1138  * .??z suffix as indicating a compressed file; some people use .xyz
1139  * to denote volume data.
1140  *   On systems allowing multiple versions of the same file (such as VMS),
1141  * this function removes any version suffix in the given name.
1142  */
1143 local char *get_suffix(name)
1144     char *name;
1145 {
1146     int nlen, slen;
1147     char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */
1148     static char const *known_suffixes[] =
1149        {NULL, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
1150 #ifdef MAX_EXT_CHARS
1151           "z",
1152 #endif
1153         NULL, NULL};
1154     char const **suf;
1155     bool suffix_of_builtin = false;
1156
1157     /* Normally put Z_SUFFIX at the start of KNOWN_SUFFIXES, but if it
1158        is a suffix of one of them, put it at the end.  */
1159     for (suf = known_suffixes + 1; *suf; suf++)
1160       {
1161         size_t suflen = strlen (*suf);
1162         if (z_len < suflen && strequ (z_suffix, *suf + suflen - z_len))
1163           {
1164             suffix_of_builtin = true;
1165             break;
1166           }
1167       }
1168     known_suffixes[suffix_of_builtin
1169                    ? sizeof known_suffixes / sizeof *known_suffixes - 2
1170                    : 0] = z_suffix;
1171     suf = known_suffixes + suffix_of_builtin;
1172
1173 #ifdef SUFFIX_SEP
1174     /* strip a version number from the file name */
1175     {
1176         char *v = strrchr(name, SUFFIX_SEP);
1177         if (v != NULL) *v = '\0';
1178     }
1179 #endif
1180     nlen = strlen(name);
1181     if (nlen <= MAX_SUFFIX+2) {
1182         strcpy(suffix, name);
1183     } else {
1184         strcpy(suffix, name+nlen-MAX_SUFFIX-2);
1185     }
1186     strlwr(suffix);
1187     slen = strlen(suffix);
1188     do {
1189        int s = strlen(*suf);
1190        if (slen > s && suffix[slen-s-1] != PATH_SEP
1191            && strequ(suffix + slen - s, *suf)) {
1192            return name+nlen-s;
1193        }
1194     } while (*++suf != NULL);
1195
1196     return NULL;
1197 }
1198
1199
1200 /* Open file NAME with the given flags and store its status
1201    into *ST.  Return a file descriptor to the newly opened file, or -1
1202    (setting errno) on failure.  */
1203 static int
1204 open_and_stat (char *name, int flags, struct stat *st)
1205 {
1206   int fd;
1207   int atfd = AT_FDCWD;
1208   char const *base = name;
1209
1210   /* Refuse to follow symbolic links unless -c or -f.  */
1211   if (!to_stdout && !force)
1212     {
1213       if (HAVE_WORKING_O_NOFOLLOW)
1214         flags |= O_NOFOLLOW;
1215       else
1216         {
1217 #if HAVE_LSTAT || defined lstat
1218           if (lstat (name, st) != 0)
1219             return -1;
1220           else if (S_ISLNK (st->st_mode))
1221             {
1222               errno = ELOOP;
1223               return -1;
1224             }
1225 #endif
1226         }
1227     }
1228
1229   if (!keep)
1230     {
1231       char const *b = last_component (name);
1232       int f = atdir_set (name, b - name);
1233       if (0 <= f)
1234         {
1235           base = b;
1236           atfd = f;
1237         }
1238     }
1239
1240   fd = openat (atfd, base, flags);
1241   if (0 <= fd && fstat (fd, st) != 0)
1242     {
1243       int e = errno;
1244       close (fd);
1245       errno = e;
1246       return -1;
1247     }
1248   return fd;
1249 }
1250
1251
1252 /* ========================================================================
1253  * Set ifname to the input file name (with a suffix appended if necessary)
1254  * and istat to its stats. For decompression, if no file exists with the
1255  * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
1256  * For MSDOS, we try only z_suffix and z.
1257  * Return an open file descriptor or -1.
1258  */
1259 static int
1260 open_input_file (iname, sbuf)
1261     char *iname;
1262     struct stat *sbuf;
1263 {
1264     int ilen;  /* strlen(ifname) */
1265     int z_suffix_errno = 0;
1266     static char const *suffixes[] = {NULL, ".gz", ".z", "-z", ".Z", NULL};
1267     char const **suf = suffixes;
1268     char const *s;
1269 #ifdef NO_MULTIPLE_DOTS
1270     char *dot; /* pointer to ifname extension, or NULL */
1271 #endif
1272     int fd;
1273     int open_flags = (O_RDONLY | O_NONBLOCK | O_NOCTTY
1274                       | (ascii && !decompress ? 0 : O_BINARY));
1275
1276     *suf = z_suffix;
1277
1278     if (sizeof ifname - 1 <= strlen (iname))
1279         goto name_too_long;
1280
1281     strcpy(ifname, iname);
1282
1283     /* If input file exists, return OK. */
1284     fd = open_and_stat (ifname, open_flags, sbuf);
1285     if (0 <= fd)
1286       return fd;
1287
1288     if (!decompress || errno != ENOENT) {
1289         progerror(ifname);
1290         return -1;
1291     }
1292     /* file.ext doesn't exist, try adding a suffix (after removing any
1293      * version number for VMS).
1294      */
1295     s = get_suffix(ifname);
1296     if (s != NULL) {
1297         progerror(ifname); /* ifname already has z suffix and does not exist */
1298         return -1;
1299     }
1300 #ifdef NO_MULTIPLE_DOTS
1301     dot = strrchr(ifname, '.');
1302     if (dot == NULL) {
1303         strcat(ifname, ".");
1304         dot = strrchr(ifname, '.');
1305     }
1306 #endif
1307     ilen = strlen(ifname);
1308     if (strequ(z_suffix, ".gz")) suf++;
1309
1310     /* Search for all suffixes */
1311     do {
1312         char const *s0 = s = *suf;
1313         strcpy (ifname, iname);
1314 #ifdef NO_MULTIPLE_DOTS
1315         if (*s == '.') s++;
1316         if (*dot == '\0') strcpy (dot, ".");
1317 #endif
1318 #ifdef MAX_EXT_CHARS
1319         if (MAX_EXT_CHARS < strlen (s) + strlen (dot + 1))
1320           dot[MAX_EXT_CHARS + 1 - strlen (s)] = '\0';
1321 #endif
1322         if (sizeof ifname <= ilen + strlen (s))
1323           goto name_too_long;
1324         strcat(ifname, s);
1325         fd = open_and_stat (ifname, open_flags, sbuf);
1326         if (0 <= fd)
1327           return fd;
1328         if (errno != ENOENT)
1329           {
1330             progerror (ifname);
1331             return -1;
1332           }
1333         if (strequ (s0, z_suffix))
1334           z_suffix_errno = errno;
1335     } while (*++suf != NULL);
1336
1337     /* No suffix found, complain using z_suffix: */
1338     strcpy(ifname, iname);
1339 #ifdef NO_MULTIPLE_DOTS
1340     if (*dot == '\0') strcpy(dot, ".");
1341 #endif
1342 #ifdef MAX_EXT_CHARS
1343     if (MAX_EXT_CHARS < z_len + strlen (dot + 1))
1344       dot[MAX_EXT_CHARS + 1 - z_len] = '\0';
1345 #endif
1346     strcat(ifname, z_suffix);
1347     errno = z_suffix_errno;
1348     progerror(ifname);
1349     return -1;
1350
1351  name_too_long:
1352     fprintf (stderr, "%s: %s: file name too long\n", program_name, iname);
1353     exit_code = ERROR;
1354     return -1;
1355 }
1356
1357 /* ========================================================================
1358  * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
1359  * Sets save_orig_name to true if the file name has been truncated.
1360  */
1361 local int make_ofname()
1362 {
1363     char *suff;            /* ofname z suffix */
1364
1365     strcpy(ofname, ifname);
1366     /* strip a version number if any and get the gzip suffix if present: */
1367     suff = get_suffix(ofname);
1368
1369     if (decompress) {
1370         if (suff == NULL) {
1371             /* With -t or -l, try all files (even without .gz suffix)
1372              * except with -r (behave as with just -dr).
1373              */
1374             if (!recursive && (list || test)) return OK;
1375
1376             /* Avoid annoying messages with -r */
1377             if (verbose || (!recursive && !quiet)) {
1378                 WARN((stderr,"%s: %s: unknown suffix -- ignored\n",
1379                       program_name, ifname));
1380             }
1381             return WARNING;
1382         }
1383         /* Make a special case for .tgz and .taz: */
1384         strlwr(suff);
1385         if (strequ(suff, ".tgz") || strequ(suff, ".taz")) {
1386             strcpy(suff, ".tar");
1387         } else {
1388             *suff = '\0'; /* strip the z suffix */
1389         }
1390         /* ofname might be changed later if infile contains an original name */
1391
1392     } else if (suff && ! force) {
1393         /* Avoid annoying messages with -r (see treat_dir()) */
1394         if (verbose || (!recursive && !quiet)) {
1395             /* Don't use WARN, as it affects exit status.  */
1396             fprintf (stderr, "%s: %s already has %s suffix -- unchanged\n",
1397                      program_name, ifname, suff);
1398         }
1399         return WARNING;
1400     } else {
1401         save_orig_name = 0;
1402
1403 #ifdef NO_MULTIPLE_DOTS
1404         suff = strrchr(ofname, '.');
1405         if (suff == NULL) {
1406             if (sizeof ofname <= strlen (ofname) + 1)
1407                 goto name_too_long;
1408             strcat(ofname, ".");
1409 #  ifdef MAX_EXT_CHARS
1410             if (strequ(z_suffix, "z")) {
1411                 if (sizeof ofname <= strlen (ofname) + 2)
1412                     goto name_too_long;
1413                 strcat(ofname, "gz"); /* enough room */
1414                 return OK;
1415             }
1416         /* On the Atari and some versions of MSDOS,
1417          * ENAMETOOLONG does not work correctly.  So we
1418          * must truncate here.
1419          */
1420         } else if (strlen(suff)-1 + z_len > MAX_SUFFIX) {
1421             suff[MAX_SUFFIX+1-z_len] = '\0';
1422             save_orig_name = 1;
1423 #  endif
1424         }
1425 #endif /* NO_MULTIPLE_DOTS */
1426         if (sizeof ofname <= strlen (ofname) + z_len)
1427             goto name_too_long;
1428         strcat(ofname, z_suffix);
1429
1430     } /* decompress ? */
1431     return OK;
1432
1433  name_too_long:
1434     WARN ((stderr, "%s: %s: file name too long\n", program_name, ifname));
1435     return WARNING;
1436 }
1437
1438 /* Discard NBYTES input bytes from the input, or up through the next
1439    zero byte if NBYTES == (size_t) -1.  If FLAGS say that the header
1440    CRC should be computed, update the CRC accordingly.  */
1441 static void
1442 discard_input_bytes (nbytes, flags)
1443     size_t nbytes;
1444     unsigned int flags;
1445 {
1446   while (nbytes != 0)
1447     {
1448       uch c = get_byte ();
1449       if (flags & HEADER_CRC)
1450         updcrc (&c, 1);
1451       if (nbytes != (size_t) -1)
1452         nbytes--;
1453       else if (! c)
1454         break;
1455     }
1456 }
1457
1458 /* ========================================================================
1459  * Check the magic number of the input file and update ofname if an
1460  * original name was given and to_stdout is not set.
1461  * Return the compression method, -1 for error, -2 for warning.
1462  * Set inptr to the offset of the next byte to be processed.
1463  * Updates time_stamp if there is one and --no-time is not used.
1464  * This function may be called repeatedly for an input file consisting
1465  * of several contiguous gzip'ed members.
1466  * IN assertions: there is at least one remaining compressed member.
1467  *   If the member is a zip file, it must be the only one.
1468  */
1469 local int get_method(in)
1470     int in;        /* input file descriptor */
1471 {
1472     uch flags;     /* compression flags */
1473     uch magic[10]; /* magic header */
1474     int imagic0;   /* first magic byte or EOF */
1475     int imagic1;   /* like magic[1], but can represent EOF */
1476     ulg stamp;     /* time stamp */
1477
1478     /* If --force and --stdout, zcat == cat, so do not complain about
1479      * premature end of file: use try_byte instead of get_byte.
1480      */
1481     if (force && to_stdout) {
1482         imagic0 = try_byte();
1483         magic[0] = imagic0;
1484         imagic1 = try_byte ();
1485         magic[1] = imagic1;
1486         /* If try_byte returned EOF, magic[1] == (char) EOF.  */
1487     } else {
1488         magic[0] = get_byte ();
1489         imagic0 = 0;
1490         if (magic[0]) {
1491             magic[1] = get_byte ();
1492             imagic1 = 0; /* avoid lint warning */
1493         } else {
1494             imagic1 = try_byte ();
1495             magic[1] = imagic1;
1496         }
1497     }
1498     method = -1;                 /* unknown yet */
1499     part_nb++;                   /* number of parts in gzip file */
1500     header_bytes = 0;
1501     last_member = RECORD_IO;
1502     /* assume multiple members in gzip file except for record oriented I/O */
1503
1504     if (memcmp(magic, GZIP_MAGIC, 2) == 0
1505         || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
1506
1507         method = (int)get_byte();
1508         if (method != DEFLATED) {
1509             fprintf(stderr,
1510                     "%s: %s: unknown method %d -- not supported\n",
1511                     program_name, ifname, method);
1512             exit_code = ERROR;
1513             return -1;
1514         }
1515         work = unzip;
1516         flags  = (uch)get_byte();
1517
1518         if ((flags & ENCRYPTED) != 0) {
1519             fprintf(stderr,
1520                     "%s: %s is encrypted -- not supported\n",
1521                     program_name, ifname);
1522             exit_code = ERROR;
1523             return -1;
1524         }
1525         if ((flags & RESERVED) != 0) {
1526             fprintf(stderr,
1527                     "%s: %s has flags 0x%x -- not supported\n",
1528                     program_name, ifname, flags);
1529             exit_code = ERROR;
1530             if (force <= 1) return -1;
1531         }
1532         stamp  = (ulg)get_byte();
1533         stamp |= ((ulg)get_byte()) << 8;
1534         stamp |= ((ulg)get_byte()) << 16;
1535         stamp |= ((ulg)get_byte()) << 24;
1536         if (stamp != 0 && !no_time)
1537           {
1538             time_stamp.tv_sec = stamp;
1539             time_stamp.tv_nsec = 0;
1540           }
1541
1542         magic[8] = get_byte ();  /* Ignore extra flags.  */
1543         magic[9] = get_byte ();  /* Ignore OS type.  */
1544
1545         if (flags & HEADER_CRC)
1546           {
1547             magic[2] = DEFLATED;
1548             magic[3] = flags;
1549             magic[4] = stamp & 0xff;
1550             magic[5] = (stamp >> 8) & 0xff;
1551             magic[6] = (stamp >> 16) & 0xff;
1552             magic[7] = stamp >> 24;
1553             updcrc (NULL, 0);
1554             updcrc (magic, 10);
1555           }
1556
1557         if ((flags & EXTRA_FIELD) != 0) {
1558             uch lenbuf[2];
1559             unsigned int len = lenbuf[0] = get_byte ();
1560             len |= (lenbuf[1] = get_byte ()) << 8;
1561             if (verbose) {
1562                 fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n",
1563                         program_name, ifname, len);
1564             }
1565             if (flags & HEADER_CRC)
1566               updcrc (lenbuf, 2);
1567             discard_input_bytes (len, flags);
1568         }
1569
1570         /* Get original file name if it was truncated */
1571         if ((flags & ORIG_NAME) != 0) {
1572             if (no_name || (to_stdout && !list) || part_nb > 1) {
1573                 /* Discard the old name */
1574                 discard_input_bytes (-1, flags);
1575             } else {
1576                 /* Copy the base name. Keep a directory prefix intact. */
1577                 char *p = gzip_base_name (ofname);
1578                 char *base = p;
1579                 for (;;) {
1580                     *p = (char) get_byte ();
1581                     if (*p++ == '\0') break;
1582                     if (p >= ofname+sizeof(ofname)) {
1583                         gzip_error ("corrupted input -- file name too large");
1584                     }
1585                 }
1586                 if (flags & HEADER_CRC)
1587                   updcrc ((uch *) base, p - base);
1588                 p = gzip_base_name (base);
1589                 memmove (base, p, strlen (p) + 1);
1590                 /* If necessary, adapt the name to local OS conventions: */
1591                 if (!list) {
1592                    MAKE_LEGAL_NAME(base);
1593                    if (base) list=0; /* avoid warning about unused variable */
1594                 }
1595             } /* no_name || to_stdout */
1596         } /* ORIG_NAME */
1597
1598         /* Discard file comment if any */
1599         if ((flags & COMMENT) != 0) {
1600             discard_input_bytes (-1, flags);
1601         }
1602
1603         if (flags & HEADER_CRC)
1604           {
1605             unsigned int crc16 = updcrc (magic, 0) & 0xffff;
1606             unsigned int header16 = get_byte ();
1607             header16 |= ((unsigned int) get_byte ()) << 8;
1608             if (header16 != crc16)
1609               {
1610                 fprintf (stderr,
1611                          "%s: %s: header checksum 0x%04x != computed checksum 0x%04x\n",
1612                          program_name, ifname, header16, crc16);
1613                 exit_code = ERROR;
1614                 if (force <= 1)
1615                   return -1;
1616               }
1617           }
1618
1619         if (part_nb == 1) {
1620             header_bytes = inptr + 2*4; /* include crc and size */
1621         }
1622
1623     } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
1624             && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0) {
1625         /* To simplify the code, we support a zip file when alone only.
1626          * We are thus guaranteed that the entire local header fits in inbuf.
1627          */
1628         inptr = 0;
1629         work = unzip;
1630         if (check_zipfile(in) != OK) return -1;
1631         /* check_zipfile may get ofname from the local header */
1632         last_member = 1;
1633
1634     } else if (memcmp(magic, PACK_MAGIC, 2) == 0) {
1635         work = unpack;
1636         method = PACKED;
1637
1638     } else if (memcmp(magic, LZW_MAGIC, 2) == 0) {
1639         work = unlzw;
1640         method = COMPRESSED;
1641         last_member = 1;
1642
1643     } else if (memcmp(magic, LZH_MAGIC, 2) == 0) {
1644         work = unlzh;
1645         method = LZHED;
1646         last_member = 1;
1647
1648     } else if (force && to_stdout && !list) { /* pass input unchanged */
1649         method = STORED;
1650         work = copy;
1651         if (imagic1 != EOF)
1652             inptr--;
1653         last_member = 1;
1654         if (imagic0 != EOF) {
1655             write_buf (STDOUT_FILENO, magic, 1);
1656             bytes_out++;
1657         }
1658     }
1659     if (method >= 0) return method;
1660
1661     if (part_nb == 1) {
1662         fprintf (stderr, "\n%s: %s: not in gzip format\n",
1663                  program_name, ifname);
1664         exit_code = ERROR;
1665         return -1;
1666     } else {
1667         if (magic[0] == 0)
1668           {
1669             int inbyte;
1670             for (inbyte = imagic1;  inbyte == 0;  inbyte = try_byte ())
1671               continue;
1672             if (inbyte == EOF)
1673               {
1674                 if (verbose)
1675                   WARN ((stderr, "\n%s: %s: decompression OK, trailing zero bytes ignored\n",
1676                          program_name, ifname));
1677                 return -3;
1678               }
1679           }
1680
1681         WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n",
1682               program_name, ifname));
1683         return -2;
1684     }
1685 }
1686
1687 /* ========================================================================
1688  * Display the characteristics of the compressed file.
1689  * If the given method is < 0, display the accumulated totals.
1690  * IN assertions: time_stamp, header_bytes and ifile_size are initialized.
1691  */
1692 local void do_list(ifd, method)
1693     int ifd;     /* input file descriptor */
1694     int method;  /* compression method */
1695 {
1696     ulg crc;  /* original crc */
1697     static int first_time = 1;
1698     static char const *const methods[MAX_METHODS] = {
1699         "store",  /* 0 */
1700         "compr",  /* 1 */
1701         "pack ",  /* 2 */
1702         "lzh  ",  /* 3 */
1703         "", "", "", "", /* 4 to 7 reserved */
1704         "defla"}; /* 8 */
1705     int positive_off_t_width = 1;
1706     off_t o;
1707
1708     for (o = OFF_T_MAX;  9 < o;  o /= 10) {
1709         positive_off_t_width++;
1710     }
1711
1712     if (first_time && method >= 0) {
1713         first_time = 0;
1714         if (verbose)  {
1715             printf("method  crc     date  time  ");
1716         }
1717         if (!quiet) {
1718             printf("%*.*s %*.*s  ratio uncompressed_name\n",
1719                    positive_off_t_width, positive_off_t_width, "compressed",
1720                    positive_off_t_width, positive_off_t_width, "uncompressed");
1721         }
1722     } else if (method < 0) {
1723         if (total_in <= 0 || total_out <= 0) return;
1724         if (verbose) {
1725             printf("                            ");
1726         }
1727         if (verbose || !quiet) {
1728             fprint_off(stdout, total_in, positive_off_t_width);
1729             printf(" ");
1730             fprint_off(stdout, total_out, positive_off_t_width);
1731             printf(" ");
1732         }
1733         display_ratio(total_out-(total_in-header_bytes), total_out, stdout);
1734         /* header_bytes is not meaningful but used to ensure the same
1735          * ratio if there is a single file.
1736          */
1737         printf(" (totals)\n");
1738         return;
1739     }
1740     crc = (ulg)~0; /* unknown */
1741     bytes_out = -1L;
1742     bytes_in = ifile_size;
1743
1744     if (!RECORD_IO && method == DEFLATED && !last_member) {
1745         /* Get the crc and uncompressed size for gzip'ed (not zip'ed) files.
1746          * If the lseek fails, we could use read() to get to the end, but
1747          * --list is used to get quick results.
1748          * Use "gunzip < foo.gz | wc -c" to get the uncompressed size if
1749          * you are not concerned about speed.
1750          */
1751         bytes_in = lseek(ifd, (off_t)(-8), SEEK_END);
1752         if (bytes_in != -1L) {
1753             uch buf[8];
1754             bytes_in += 8L;
1755             if (read(ifd, (char*)buf, sizeof(buf)) != sizeof(buf)) {
1756                 read_error();
1757             }
1758             crc       = LG(buf);
1759             bytes_out = LG(buf+4);
1760         }
1761     }
1762
1763     if (verbose)
1764       {
1765         static char const month_abbr[][4]
1766           = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1767               "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
1768         struct tm *tm = localtime (&time_stamp.tv_sec);
1769         printf ("%5s %08lx ", methods[method], crc);
1770         if (tm)
1771           printf ("%s%3d %02d:%02d ", month_abbr[tm->tm_mon],
1772                   tm->tm_mday, tm->tm_hour, tm->tm_min);
1773         else
1774           printf ("??? ?? ??:?? ");
1775       }
1776     fprint_off(stdout, bytes_in, positive_off_t_width);
1777     printf(" ");
1778     fprint_off(stdout, bytes_out, positive_off_t_width);
1779     printf(" ");
1780     if (bytes_in  == -1L) {
1781         total_in = -1L;
1782         bytes_in = bytes_out = header_bytes = 0;
1783     } else if (total_in >= 0) {
1784         total_in  += bytes_in;
1785     }
1786     if (bytes_out == -1L) {
1787         total_out = -1L;
1788         bytes_in = bytes_out = header_bytes = 0;
1789     } else if (total_out >= 0) {
1790         total_out += bytes_out;
1791     }
1792     display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out, stdout);
1793     printf(" %s\n", ofname);
1794 }
1795
1796 /* ========================================================================
1797  * Shorten the given name by one character, or replace a .tar extension
1798  * with .tgz. Truncate the last part of the name which is longer than
1799  * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
1800  * has only parts shorter than MIN_PART truncate the longest part.
1801  * For decompression, just remove the last character of the name.
1802  *
1803  * IN assertion: for compression, the suffix of the given name is z_suffix.
1804  */
1805 local void shorten_name(name)
1806     char *name;
1807 {
1808     int len;                 /* length of name without z_suffix */
1809     char *trunc = NULL;      /* character to be truncated */
1810     int plen;                /* current part length */
1811     int min_part = MIN_PART; /* current minimum part length */
1812     char *p;
1813
1814     len = strlen(name);
1815     if (decompress) {
1816         if (len <= 1)
1817           gzip_error ("name too short");
1818         name[len-1] = '\0';
1819         return;
1820     }
1821     p = get_suffix(name);
1822     if (! p)
1823       gzip_error ("can't recover suffix\n");
1824     *p = '\0';
1825     save_orig_name = 1;
1826
1827     /* compress 1234567890.tar to 1234567890.tgz */
1828     if (len > 4 && strequ(p-4, ".tar")) {
1829         strcpy(p-4, ".tgz");
1830         return;
1831     }
1832     /* Try keeping short extensions intact:
1833      * 1234.678.012.gz -> 123.678.012.gz
1834      */
1835     do {
1836         p = strrchr(name, PATH_SEP);
1837         p = p ? p+1 : name;
1838         while (*p) {
1839             plen = strcspn(p, PART_SEP);
1840             p += plen;
1841             if (plen > min_part) trunc = p-1;
1842             if (*p) p++;
1843         }
1844     } while (trunc == NULL && --min_part != 0);
1845
1846     if (trunc != NULL) {
1847         do {
1848             trunc[0] = trunc[1];
1849         } while (*trunc++);
1850         trunc--;
1851     } else {
1852         trunc = strrchr(name, PART_SEP[0]);
1853         if (!trunc)
1854           gzip_error ("internal error in shorten_name");
1855         if (trunc[1] == '\0') trunc--; /* force truncation */
1856     }
1857     strcpy(trunc, z_suffix);
1858 }
1859
1860 /* ========================================================================
1861  * The compressed file already exists, so ask for confirmation.
1862  * Return ERROR if the file must be skipped.
1863  */
1864 local int check_ofname()
1865 {
1866     /* Ask permission to overwrite the existing file */
1867     if (!force) {
1868         int ok = 0;
1869         fprintf (stderr, "%s: %s already exists;", program_name, ofname);
1870         if (foreground && (presume_input_tty || isatty (STDIN_FILENO))) {
1871             fprintf(stderr, " do you wish to overwrite (y or n)? ");
1872             fflush(stderr);
1873             ok = yesno();
1874         }
1875         if (!ok) {
1876             fprintf(stderr, "\tnot overwritten\n");
1877             if (exit_code == OK) exit_code = WARNING;
1878             return ERROR;
1879         }
1880     }
1881     if (xunlink (ofname)) {
1882         progerror(ofname);
1883         return ERROR;
1884     }
1885     return OK;
1886 }
1887
1888 /* Change the owner and group of a file.  FD is a file descriptor for
1889    the file and NAME its name.  Change it to user UID and to group GID.
1890    If UID or GID is -1, though, do not change the corresponding user
1891    or group.  */
1892 static void
1893 do_chown (int fd, char const *name, uid_t uid, gid_t gid)
1894 {
1895 #ifndef NO_CHOWN
1896 # if HAVE_FCHOWN
1897   ignore_value (fchown (fd, uid, gid));
1898 # else
1899   ignore_value (chown (name, uid, gid));
1900 # endif
1901 #endif
1902 }
1903
1904 /* ========================================================================
1905  * Copy modes, times, ownership from input file to output file.
1906  * IN assertion: to_stdout is false.
1907  */
1908 local void copy_stat(ifstat)
1909     struct stat *ifstat;
1910 {
1911     mode_t mode = ifstat->st_mode & S_IRWXUGO;
1912     int r;
1913
1914 #ifndef NO_UTIME
1915     struct timespec timespec[2];
1916     timespec[0] = get_stat_atime (ifstat);
1917     timespec[1] = get_stat_mtime (ifstat);
1918
1919     if (decompress && 0 <= time_stamp.tv_nsec
1920         && ! (timespec[1].tv_sec == time_stamp.tv_sec
1921               && timespec[1].tv_nsec == time_stamp.tv_nsec))
1922       {
1923         timespec[1] = time_stamp;
1924         if (verbose > 1) {
1925             fprintf(stderr, "%s: time stamp restored\n", ofname);
1926         }
1927       }
1928
1929     if (fdutimens (ofd, ofname, timespec) != 0)
1930       {
1931         int e = errno;
1932         WARN ((stderr, "%s: ", program_name));
1933         if (!quiet)
1934           {
1935             errno = e;
1936             perror (ofname);
1937           }
1938       }
1939 #endif
1940
1941     /* Change the group first, then the permissions, then the owner.
1942        That way, the permissions will be correct on systems that allow
1943        users to give away files, without introducing a security hole.
1944        Security depends on permissions not containing the setuid or
1945        setgid bits.  */
1946
1947     do_chown (ofd, ofname, -1, ifstat->st_gid);
1948
1949 #if HAVE_FCHMOD
1950     r = fchmod (ofd, mode);
1951 #else
1952     r = chmod (ofname, mode);
1953 #endif
1954     if (r != 0) {
1955         int e = errno;
1956         WARN ((stderr, "%s: ", program_name));
1957         if (!quiet) {
1958             errno = e;
1959             perror(ofname);
1960         }
1961     }
1962
1963     do_chown (ofd, ofname, ifstat->st_uid, -1);
1964 }
1965
1966 #if ! NO_DIR
1967
1968 /* ========================================================================
1969  * Recurse through the given directory.
1970  */
1971 local void treat_dir (fd, dir)
1972     int fd;
1973     char *dir;
1974 {
1975     DIR      *dirp;
1976     char     nbuf[MAX_PATH_LEN];
1977     char *entries;
1978     char const *entry;
1979     size_t entrylen;
1980
1981     dirp = fdopendir (fd);
1982
1983     if (dirp == NULL) {
1984         progerror(dir);
1985         close (fd);
1986         return ;
1987     }
1988
1989     entries = streamsavedir (dirp, SAVEDIR_SORT_NONE);
1990     if (! entries)
1991       progerror (dir);
1992     if (closedir (dirp) != 0)
1993       progerror (dir);
1994     if (! entries)
1995       return;
1996
1997     for (entry = entries; *entry; entry += entrylen + 1) {
1998         size_t len = strlen (dir);
1999         entrylen = strlen (entry);
2000         if (strequ (entry, ".") || strequ (entry, ".."))
2001           continue;
2002         if (len + entrylen < MAX_PATH_LEN - 2) {
2003             strcpy(nbuf,dir);
2004             if (len != 0 /* dir = "" means current dir on Amiga */
2005 #ifdef PATH_SEP2
2006                 && dir[len-1] != PATH_SEP2
2007 #endif
2008 #ifdef PATH_SEP3
2009                 && dir[len-1] != PATH_SEP3
2010 #endif
2011             ) {
2012                 nbuf[len++] = PATH_SEP;
2013             }
2014             strcpy (nbuf + len, entry);
2015             treat_file(nbuf);
2016         } else {
2017             fprintf(stderr,"%s: %s/%s: pathname too long\n",
2018                     program_name, dir, entry);
2019             exit_code = ERROR;
2020         }
2021     }
2022     free (entries);
2023 }
2024 #endif /* ! NO_DIR */
2025
2026 /* Make sure signals get handled properly.  */
2027
2028 static void
2029 install_signal_handlers ()
2030 {
2031   int nsigs = sizeof handled_sig / sizeof handled_sig[0];
2032   int i;
2033
2034 #if SA_NOCLDSTOP
2035   struct sigaction act;
2036
2037   sigemptyset (&caught_signals);
2038   for (i = 0; i < nsigs; i++)
2039     {
2040       sigaction (handled_sig[i], NULL, &act);
2041       if (act.sa_handler != SIG_IGN)
2042         sigaddset (&caught_signals, handled_sig[i]);
2043     }
2044
2045   act.sa_handler = abort_gzip_signal;
2046   act.sa_mask = caught_signals;
2047   act.sa_flags = 0;
2048
2049   for (i = 0; i < nsigs; i++)
2050     if (sigismember (&caught_signals, handled_sig[i]))
2051       {
2052         if (i == 0)
2053           foreground = 1;
2054         sigaction (handled_sig[i], &act, NULL);
2055       }
2056 #else
2057   for (i = 0; i < nsigs; i++)
2058     if (signal (handled_sig[i], SIG_IGN) != SIG_IGN)
2059       {
2060         if (i == 0)
2061           foreground = 1;
2062         signal (handled_sig[i], abort_gzip_signal);
2063         siginterrupt (handled_sig[i], 1);
2064       }
2065 #endif
2066 }
2067
2068 /* ========================================================================
2069  * Free all dynamically allocated variables and exit with the given code.
2070  */
2071 local void do_exit(exitcode)
2072     int exitcode;
2073 {
2074     static int in_exit = 0;
2075
2076     if (in_exit) exit(exitcode);
2077     in_exit = 1;
2078     free(env);
2079     env  = NULL;
2080     FREE(inbuf);
2081     FREE(outbuf);
2082     FREE(d_buf);
2083     FREE(window);
2084 #ifndef MAXSEG_64K
2085     FREE(tab_prefix);
2086 #else
2087     FREE(tab_prefix0);
2088     FREE(tab_prefix1);
2089 #endif
2090     exit(exitcode);
2091 }
2092
2093 /* ========================================================================
2094  * Close and unlink the output file.
2095  */
2096 static void
2097 remove_output_file ()
2098 {
2099   int fd;
2100   sigset_t oldset;
2101
2102   sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
2103   fd = remove_ofname_fd;
2104   if (0 <= fd)
2105     {
2106       remove_ofname_fd = -1;
2107       close (fd);
2108       xunlink (ofname);
2109     }
2110   sigprocmask (SIG_SETMASK, &oldset, NULL);
2111 }
2112
2113 /* ========================================================================
2114  * Error handler.
2115  */
2116 void
2117 abort_gzip ()
2118 {
2119    remove_output_file ();
2120    do_exit(ERROR);
2121 }
2122
2123 /* ========================================================================
2124  * Signal handler.
2125  */
2126 static RETSIGTYPE
2127 abort_gzip_signal (sig)
2128      int sig;
2129 {
2130   if (! SA_NOCLDSTOP)
2131     signal (sig, SIG_IGN);
2132    remove_output_file ();
2133    if (sig == exiting_signal)
2134      _exit (WARNING);
2135    signal (sig, SIG_DFL);
2136    raise (sig);
2137 }