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