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