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