1 /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
3 Copyright (C) 1999, 2001-2002, 2006-2007, 2009-2017 Free Software
5 Copyright (C) 1992-1993 Jean-loup Gailly
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)
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.
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. */
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.
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.
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.",
39 /* Compress files with zip algorithm and 'compress' interface.
40 * See help() function below for all options.
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.
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.
54 * For the meaning of all compilation flags, see comments in Makefile.in.
59 #include <sys/types.h>
77 #include "ignore-value.h"
78 #include "stat-time.h"
102 # define MAX_PATH_LEN 1024 /* max pathname length */
114 off_t lseek (int fd, off_t offset, int whence);
118 # define OFF_T_MAX TYPE_MAXIMUM (off_t)
121 /* Use SA_NOCLDSTOP as a proxy for whether the sigaction machinery is
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 */
132 #ifndef HAVE_WORKING_O_NOFOLLOW
133 # define HAVE_WORKING_O_NOFOLLOW 0
136 /* Separator for file name parts (see shorten_name()) */
137 #ifdef NO_MULTIPLE_DOTS
138 # define PART_SEP "-"
140 # define PART_SEP "."
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);
150 DECLARE(ush, tab_prefix, 1L<<BITS);
152 DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
153 DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
156 /* local variables */
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;
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;
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 off_t ifile_size; /* input file size, -1 for devices (debug only) */
193 static char *env; /* contents of GZIP env variable */
194 static char const *z_suffix; /* default suffix (can be set with --suffix) */
195 static size_t z_len; /* strlen(z_suffix) */
197 /* The original timestamp (modification time). Its tv_nsec component
198 is negative if the original time is unknown or is out of time_t
199 range; the latter can happen on hosts with 32-bit signed time_t
200 because the gzip format's MTIME is 32-bit unsigned. */
201 struct timespec time_stamp;
203 /* The set of signals that are caught. */
204 static sigset_t caught_signals;
206 /* If nonzero then exit with status WARNING, rather than with the usual
207 signal status, on receipt of a signal with this value. This
208 suppresses a "Broken Pipe" message with some shells. */
209 static int volatile exiting_signal;
211 /* If nonnegative, close this file descriptor and unlink ofname on error. */
212 static int volatile remove_ofname_fd = -1;
214 static bool stdin_was_read;
216 off_t bytes_in; /* number of input bytes */
217 off_t bytes_out; /* number of output bytes */
218 static off_t total_in; /* input bytes for all files */
219 static off_t total_out; /* output bytes for all files */
220 char ifname[MAX_PATH_LEN]; /* input file name */
221 char ofname[MAX_PATH_LEN]; /* output file name */
222 static char dfname[MAX_PATH_LEN]; /* name of dir containing output file */
223 static struct stat istat; /* status for input file */
224 int ifd; /* input file descriptor */
225 int ofd; /* output file descriptor */
226 static int dfd = -1; /* output directory file descriptor */
227 unsigned insize; /* valid bytes in inbuf */
228 unsigned inptr; /* index of next byte to be processed in inbuf */
229 unsigned outcnt; /* bytes in output buffer */
230 int rsync = 0; /* make ryncable chunks */
232 static int handled_sig[] =
234 /* SIGINT must be first, as 'foreground' depends on it. */
254 /* For long options that have no equivalent short option, use a
255 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
258 PRESUME_INPUT_TTY_OPTION = CHAR_MAX + 1,
262 /* A value greater than all valid long options, used as a flag to
263 distinguish options derived from the GZIP environment variable. */
267 static char const shortopts[] = "ab:cdfhH?klLmMnNqrS:tvVZ123456789";
269 static const struct option longopts[] =
271 /* { name has_arg *flag val } */
272 {"ascii", 0, 0, 'a'}, /* ascii text mode */
273 {"to-stdout", 0, 0, 'c'}, /* write output on standard output */
274 {"stdout", 0, 0, 'c'}, /* write output on standard output */
275 {"decompress", 0, 0, 'd'}, /* decompress */
276 {"uncompress", 0, 0, 'd'}, /* decompress */
277 /* {"encrypt", 0, 0, 'e'}, encrypt */
278 {"force", 0, 0, 'f'}, /* force overwrite of output file */
279 {"help", 0, 0, 'h'}, /* give help */
280 /* {"pkzip", 0, 0, 'k'}, force output in pkzip format */
281 {"keep", 0, 0, 'k'}, /* keep (don't delete) input files */
282 {"list", 0, 0, 'l'}, /* list .gz file contents */
283 {"license", 0, 0, 'L'}, /* display software license */
284 {"no-name", 0, 0, 'n'}, /* don't save or restore original name & time */
285 {"name", 0, 0, 'N'}, /* save or restore original name & time */
286 {"-presume-input-tty", no_argument, NULL, PRESUME_INPUT_TTY_OPTION},
287 {"quiet", 0, 0, 'q'}, /* quiet mode */
288 {"silent", 0, 0, 'q'}, /* quiet mode */
289 {"synchronous",0, 0, SYNCHRONOUS_OPTION},
290 {"recursive", 0, 0, 'r'}, /* recurse through directories */
291 {"suffix", 1, 0, 'S'}, /* use given suffix instead of .gz */
292 {"test", 0, 0, 't'}, /* test compressed file integrity */
293 {"verbose", 0, 0, 'v'}, /* verbose mode */
294 {"version", 0, 0, 'V'}, /* display version number */
295 {"fast", 0, 0, '1'}, /* compress faster */
296 {"best", 0, 0, '9'}, /* compress better */
297 {"lzw", 0, 0, 'Z'}, /* make output compatible with old compress */
298 {"bits", 1, 0, 'b'}, /* max number of bits per code (implies -Z) */
299 {"rsyncable", 0, 0, RSYNCABLE_OPTION}, /* make rsync-friendly archive */
303 /* local functions */
305 local void try_help (void) ATTRIBUTE_NORETURN;
306 local void help (void);
307 local void license (void);
308 local void version (void);
309 local int input_eof (void);
310 local void treat_stdin (void);
311 local void treat_file (char *iname);
312 local int create_outfile (void);
313 local char *get_suffix (char *name);
314 local int open_input_file (char *iname, struct stat *sbuf);
315 local void discard_input_bytes (size_t nbytes, unsigned int flags);
316 local int make_ofname (void);
317 local void shorten_name (char *name);
318 local int get_method (int in);
319 local void do_list (int ifd, int method);
320 local int check_ofname (void);
321 local void copy_stat (struct stat *ifstat);
322 local void install_signal_handlers (void);
323 local void remove_output_file (void);
324 local RETSIGTYPE abort_gzip_signal (int);
325 local void do_exit (int exitcode) ATTRIBUTE_NORETURN;
326 static void finish_out (void);
327 int main (int argc, char **argv);
328 static int (*work) (int infile, int outfile) = zip; /* function to call */
331 local void treat_dir (int fd, char *dir);
334 #define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
339 fprintf (stderr, "Try `%s --help' for more information.\n",
344 /* ======================================================================== */
347 static char const* const help_msg[] = {
348 "Compress or uncompress FILEs (by default, compress FILES in-place).",
350 "Mandatory arguments to long options are mandatory for short options too.",
353 " -a, --ascii ascii text; convert end-of-line using local conventions",
355 " -c, --stdout write on standard output, keep original files unchanged",
356 " -d, --decompress decompress",
357 /* -e, --encrypt encrypt */
358 " -f, --force force overwrite of output file and compress links",
359 " -h, --help give this help",
360 /* -k, --pkzip force output in pkzip format */
361 " -k, --keep keep (don't delete) input files",
362 " -l, --list list compressed file contents",
363 " -L, --license display software license",
365 " -m do not save or restore the original modification time",
366 " -M, --time save or restore the original modification time",
368 " -n, --no-name do not save or restore the original name and timestamp",
369 " -N, --name save or restore the original name and timestamp",
370 " -q, --quiet suppress all warnings",
372 " -r, --recursive operate recursively on directories",
374 " --rsyncable make rsync-friendly archive",
375 " -S, --suffix=SUF use suffix SUF on compressed files",
376 " --synchronous synchronous output (safer if system crashes, but slower)",
377 " -t, --test test compressed file integrity",
378 " -v, --verbose verbose mode",
379 " -V, --version display version number",
380 " -1, --fast compress faster",
381 " -9, --best compress better",
383 " -Z, --lzw produce output compatible with old compress",
384 " -b, --bits=BITS max number of bits per code (implies -Z)",
387 "With no FILE, or when FILE is -, read standard input.",
389 "Report bugs to <bug-gzip@gnu.org>.",
391 char const *const *p = help_msg;
393 printf ("Usage: %s [OPTION]... [FILE]...\n", program_name);
394 while (*p) printf ("%s\n", *p++);
397 /* ======================================================================== */
400 char const *const *p = license_msg;
402 printf ("%s %s\n", program_name, Version);
403 while (*p) printf ("%s\n", *p++);
406 /* ======================================================================== */
411 printf ("Written by Jean-loup Gailly.\n");
414 local void progerror (char const *string)
417 fprintf (stderr, "%s: ", program_name);
423 /* ======================================================================== */
424 int main (int argc, char **argv)
426 int file_count; /* number of files to process */
427 size_t proglen; /* length of program_name */
432 EXPAND(argc, argv); /* wild card expansion if necessary */
434 program_name = gzip_base_name (argv[0]);
435 proglen = strlen (program_name);
437 /* Suppress .exe for MSDOS and OS/2: */
438 if (4 < proglen && strequ (program_name + proglen - 4, ".exe"))
439 program_name[proglen - 4] = '\0';
441 /* Add options in GZIP environment variable if there is one */
443 env = add_envopt (&env_argc, &argv_copy, OPTIONS_VAR);
444 env_argv = env ? argv_copy : NULL;
447 # define GNU_STANDARD 1
450 /* For compatibility with old compress, use program name as an option.
451 * Unless you compile with -DGNU_STANDARD=0, this program will behave as
452 * gzip even if it is invoked under the name gunzip or zcat.
454 * Systems which do not support links can still use -d or -dc.
455 * Ignore an .exe extension for MSDOS and OS/2.
457 if (strncmp (program_name, "un", 2) == 0 /* ungzip, uncompress */
458 || strncmp (program_name, "gun", 3) == 0) /* gunzip */
460 else if (strequ (program_name + 1, "cat") /* zcat, pcat, gcat */
461 || strequ (program_name, "gzcat")) /* gzcat */
462 decompress = to_stdout = 1;
466 z_len = strlen(z_suffix);
474 if (env_argv[optind] && strequ (env_argv[optind], "--"))
475 optc = ENV_OPTION + '-';
478 optc = getopt_long (env_argc, env_argv, shortopts, longopts,
484 if (optind != env_argc)
487 ("%s: %s: non-option in "OPTIONS_VAR
488 " environment variable\n"),
489 program_name, env_argv[optind]);
493 /* Wait until here before warning, so that GZIP='-q'
495 if (env_argc != 1 && !quiet)
497 ("%s: warning: "OPTIONS_VAR" environment variable"
498 " is deprecated; use an alias or script\n"),
501 /* Start processing ARGC and ARGV instead. */
511 optc = getopt_long (argc, argv, shortopts, longopts, &longind);
519 maxbits = atoi(optarg);
520 for (; *optarg; optarg++)
521 if (! ('0' <= *optarg && *optarg <= '9'))
523 fprintf (stderr, "%s: -b operand is not an integer\n",
529 to_stdout = 1; break;
531 decompress = 1; break;
535 help (); finish_out (); break;
539 list = decompress = to_stdout = 1; break;
541 license (); finish_out (); break;
542 case 'm': /* undocumented, may change later */
544 case 'M': /* undocumented, may change later */
547 case 'n' + ENV_OPTION:
548 no_name = no_time = 1; break;
550 case 'N' + ENV_OPTION:
551 no_name = no_time = 0; break;
552 case PRESUME_INPUT_TTY_OPTION:
553 presume_input_tty = true; break;
555 case 'q' + ENV_OPTION:
556 quiet = 1; verbose = 0; break;
559 fprintf (stderr, "%s: -r not supported on this system\n",
567 case RSYNCABLE_OPTION:
568 case RSYNCABLE_OPTION + ENV_OPTION:
572 #ifdef NO_MULTIPLE_DOTS
573 if (*optarg == '.') optarg++;
575 z_len = strlen(optarg);
578 case SYNCHRONOUS_OPTION:
582 test = decompress = to_stdout = 1;
585 case 'v' + ENV_OPTION:
586 verbose++; quiet = 0; break;
588 version (); finish_out (); break;
593 fprintf(stderr, "%s: -Z not supported in this version\n",
598 case '1' + ENV_OPTION: case '2' + ENV_OPTION: case '3' + ENV_OPTION:
599 case '4' + ENV_OPTION: case '5' + ENV_OPTION: case '6' + ENV_OPTION:
600 case '7' + ENV_OPTION: case '8' + ENV_OPTION: case '9' + ENV_OPTION:
603 case '1': case '2': case '3': case '4':
604 case '5': case '6': case '7': case '8': case '9':
609 if (ENV_OPTION <= optc && optc != ENV_OPTION + '?')
611 /* Output a diagnostic, since getopt_long didn't. */
612 fprintf (stderr, "%s: ", program_name);
614 fprintf (stderr, "-%c: ", optc - ENV_OPTION);
616 fprintf (stderr, "--%s: ", longopts[longind].name);
617 fprintf (stderr, ("option not valid in "OPTIONS_VAR
618 " environment variable\n"));
622 } /* loop on all arguments */
624 /* By default, save name and timestamp on compression but do not
625 * restore them on decompression.
627 if (no_time < 0) no_time = decompress;
628 if (no_name < 0) no_name = decompress;
630 file_count = argc - optind;
634 if (ascii && !quiet) {
635 fprintf(stderr, "%s: option --ascii ignored on this system\n",
639 if (z_len == 0 || z_len > MAX_SUFFIX) {
640 fprintf(stderr, "%s: invalid suffix '%s'\n", program_name, z_suffix);
644 if (do_lzw && !decompress) work = lzw;
646 /* Allocate all global buffers (for DYN_ALLOC option) */
647 ALLOC(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
648 ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
649 ALLOC(ush, d_buf, DIST_BUFSIZE);
650 ALLOC(uch, window, 2L*WSIZE);
652 ALLOC(ush, tab_prefix, 1L<<BITS);
654 ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
655 ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
658 exiting_signal = quiet ? SIGPIPE : 0;
659 install_signal_handlers ();
661 /* And get to work */
662 if (file_count != 0) {
663 if (to_stdout && !test && !list && (!decompress || !ascii)) {
664 SET_BINARY_MODE (STDOUT_FILENO);
666 while (optind < argc) {
667 treat_file(argv[optind++]);
669 } else { /* Standard input */
672 if (stdin_was_read && close (STDIN_FILENO) != 0)
674 strcpy (ifname, "stdin");
679 /* Output any totals, and check for output errors. */
680 if (!quiet && 1 < file_count)
682 if (fflush (stdout) != 0)
687 && fdatasync (STDOUT_FILENO) != 0 && errno != EINVAL)
688 || close (STDOUT_FILENO) != 0)
692 return exit_code; /* just to avoid lint warning */
695 /* Return nonzero when at end of file on input. */
699 if (!decompress || last_member)
704 if (insize != INBUFSIZ || fill_inbuf (1) == EOF)
707 /* Unget the char that fill_inbuf got. */
714 /* ========================================================================
715 * Compress or decompress stdin
717 local void treat_stdin()
720 && (presume_input_tty
721 || isatty (decompress ? STDIN_FILENO : STDOUT_FILENO))) {
722 /* Do not send compressed data to the terminal or read it from
723 * the terminal. We get here when user invoked the program
724 * without parameters, so be helpful. According to the GNU standards:
726 * If there is one behavior you think is most useful when the output
727 * is to a terminal, and another that you think is most useful when
728 * the output is a file or a pipe, then it is usually best to make
729 * the default behavior the one that is useful with output to a
730 * terminal, and have an option for the other behavior.
732 * Here we use the --force option to get the other behavior.
736 ("%s: compressed data not %s a terminal."
737 " Use -f to force %scompression.\n"
738 "For help, type: %s -h\n"),
740 decompress ? "read from" : "written to",
741 decompress ? "de" : "",
746 if (decompress || !ascii) {
747 SET_BINARY_MODE (STDIN_FILENO);
749 if (!test && !list && (!decompress || !ascii)) {
750 SET_BINARY_MODE (STDOUT_FILENO);
752 strcpy(ifname, "stdin");
753 strcpy(ofname, "stdout");
755 /* Get the file's timestamp and size. */
756 if (fstat (STDIN_FILENO, &istat) != 0)
758 progerror ("standard input");
761 ifile_size = S_ISREG (istat.st_mode) ? istat.st_size : -1;
762 time_stamp.tv_nsec = -1;
763 if (!no_time || list)
765 if (S_ISREG (istat.st_mode))
766 time_stamp = get_stat_mtime (&istat);
768 gettime (&time_stamp);
771 clear_bufs(); /* clear input and output buffers */
775 stdin_was_read = true;
778 method = get_method(ifd);
780 do_exit(exit_code); /* error message already emitted */
784 do_list(ifd, method);
788 /* Actually do the compression/decompression. Loop over zipped members.
791 if (work (STDIN_FILENO, STDOUT_FILENO) != OK)
797 method = get_method(ifd);
798 if (method < 0) return; /* error message already emitted */
799 bytes_out = 0; /* required for length check */
804 fprintf(stderr, " OK\n");
806 } else if (!decompress) {
807 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
808 fprintf(stderr, "\n");
809 #ifdef DISPLAY_STDIN_RATIO
811 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
812 fprintf(stderr, "\n");
818 static char const dot = '.';
820 /* True if the cached directory for calls to openat etc. is DIR, with
821 length DIRLEN. DIR need not be null-terminated. DIRLEN must be
822 less than MAX_PATH_LEN. */
824 atdir_eq (char const *dir, ptrdiff_t dirlen)
827 dir = &dot, dirlen = 1;
828 return memcmp (dfname, dir, dirlen) == 0 && !dfname[dirlen];
831 /* Set the directory used for calls to openat etc. to be the directory
832 DIR, with length DIRLEN. DIR need not be null-terminated.
833 DIRLEN must be less than MAX_PATH_LEN. Return a file descriptor for
834 the directory, or -1 if one could not be obtained. */
836 atdir_set (char const *dir, ptrdiff_t dirlen)
838 /* Don't bother opening directories on older systems that
839 lack openat and unlinkat. It's not worth the porting hassle. */
840 #if HAVE_OPENAT && HAVE_UNLINKAT
841 enum { try_opening_directories = true };
843 enum { try_opening_directories = false };
846 if (try_opening_directories && ! atdir_eq (dir, dirlen))
851 dir = &dot, dirlen = 1;
852 memcpy (dfname, dir, dirlen);
853 dfname[dirlen] = '\0';
854 dfd = open (dfname, O_SEARCH | O_DIRECTORY);
860 /* ========================================================================
861 * Compress or decompress the given file
863 local void treat_file(iname)
866 /* Accept "-" as synonym for stdin */
867 if (strequ(iname, "-")) {
868 int cflag = to_stdout;
874 /* Check if the input file is present, set ifname and istat: */
875 ifd = open_input_file (iname, &istat);
879 /* If the input name is that of a directory, recurse or ignore: */
880 if (S_ISDIR(istat.st_mode)) {
883 treat_dir (ifd, iname);
884 /* Warning: ifname is now garbage */
889 WARN ((stderr, "%s: %s is a directory -- ignored\n",
890 program_name, ifname));
896 if (! S_ISREG (istat.st_mode))
899 "%s: %s is not a directory or a regular file - ignored\n",
900 program_name, ifname));
904 if (istat.st_mode & S_ISUID)
906 WARN ((stderr, "%s: %s is set-user-ID on execution - ignored\n",
907 program_name, ifname));
911 if (istat.st_mode & S_ISGID)
913 WARN ((stderr, "%s: %s is set-group-ID on execution - ignored\n",
914 program_name, ifname));
921 if (istat.st_mode & S_ISVTX)
924 "%s: %s has the sticky bit set - file ignored\n",
925 program_name, ifname));
929 if (2 <= istat.st_nlink)
931 WARN ((stderr, "%s: %s has %lu other link%c -- unchanged\n",
932 program_name, ifname,
933 (unsigned long int) istat.st_nlink - 1,
934 istat.st_nlink == 2 ? ' ' : 's'));
941 ifile_size = S_ISREG (istat.st_mode) ? istat.st_size : -1;
942 time_stamp.tv_nsec = -1;
943 if (!no_time || list)
944 time_stamp = get_stat_mtime (&istat);
946 /* Generate output file name. For -r and (-t or -l), skip files
947 * without a valid gzip suffix (check done in make_ofname).
949 if (to_stdout && !list && !test) {
950 strcpy(ofname, "stdout");
952 } else if (make_ofname() != OK) {
957 clear_bufs(); /* clear input and output buffers */
961 method = get_method(ifd); /* updates ofname if original given */
964 return; /* error message already emitted */
968 do_list(ifd, method);
969 if (close (ifd) != 0)
974 /* If compressing to a file, check if ofname is not ambiguous
975 * because the operating system truncates names. Otherwise, generate
976 * a new ofname and save the original name in the compressed file.
980 /* Keep remove_ofname_fd negative. */
982 if (create_outfile() != OK) return;
984 if (!decompress && save_orig_name && !verbose && !quiet) {
985 fprintf(stderr, "%s: %s compressed to %s\n",
986 program_name, ifname, ofname);
989 /* Keep the name even if not truncated except with --no-name: */
990 if (!save_orig_name) save_orig_name = !no_name;
993 fprintf(stderr, "%s:\t", ifname);
996 /* Actually do the compression/decompression. Loop over zipped members.
999 if ((*work)(ifd, ofd) != OK) {
1000 method = -1; /* force cleanup */
1007 method = get_method(ifd);
1008 if (method < 0) break; /* error message already emitted */
1009 bytes_out = 0; /* required for length check */
1012 if (close (ifd) != 0)
1020 && ((0 <= dfd && fdatasync (dfd) != 0 && errno != EINVAL)
1021 || (fsync (ofd) != 0 && errno != EINVAL)))
1022 || close (ofd) != 0)
1029 char *ifbase = last_component (ifname);
1030 int ufd = atdir_eq (ifname, ifbase - ifname) ? dfd : -1;
1033 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
1034 remove_ofname_fd = -1;
1035 res = ufd < 0 ? xunlink (ifname) : unlinkat (ufd, ifbase, 0);
1036 unlink_errno = res == 0 ? 0 : errno;
1037 sigprocmask (SIG_SETMASK, &oldset, NULL);
1041 WARN ((stderr, "%s: ", program_name));
1044 errno = unlink_errno;
1053 remove_output_file ();
1057 /* Display statistics */
1060 fprintf(stderr, " OK");
1061 } else if (decompress) {
1062 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
1064 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
1066 if (!test && !to_stdout)
1067 fprintf(stderr, " -- %s %s", keep ? "created" : "replaced with",
1069 fprintf(stderr, "\n");
1073 /* ========================================================================
1074 * Create the output file. Return OK or ERROR.
1075 * Try several times if necessary to avoid truncating the z_suffix. For
1076 * example, do not create a compressed file of name "1234567890123."
1077 * Sets save_orig_name to true if the file name has been truncated.
1078 * IN assertions: the input file has already been open (ifd is set) and
1079 * ofname has already been updated if there was an original name.
1080 * OUT assertions: ifd and ofd are closed in case of error.
1082 local int create_outfile()
1084 int name_shortened = 0;
1085 int flags = (O_WRONLY | O_CREAT | O_EXCL
1086 | (ascii && decompress ? 0 : O_BINARY));
1087 char const *base = ofname;
1088 int atfd = AT_FDCWD;
1092 char const *b = last_component (ofname);
1093 int f = atdir_set (ofname, b - ofname);
1106 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
1107 remove_ofname_fd = ofd = openat (atfd, base, flags, S_IRUSR | S_IWUSR);
1109 sigprocmask (SIG_SETMASK, &oldset, NULL);
1118 shorten_name (ofname);
1124 if (check_ofname () != OK)
1138 if (name_shortened && decompress)
1140 /* name might be too long if an original name was saved */
1141 WARN ((stderr, "%s: %s: warning, name truncated\n",
1142 program_name, ofname));
1148 /* ========================================================================
1149 * Return a pointer to the 'z' suffix of a file name, or NULL. For all
1150 * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
1151 * accepted suffixes, in addition to the value of the --suffix option.
1152 * ".tgz" is a useful convention for tar.z files on systems limited
1153 * to 3 characters extensions. On such systems, ".?z" and ".??z" are
1154 * also accepted suffixes. For Unix, we do not want to accept any
1155 * .??z suffix as indicating a compressed file; some people use .xyz
1156 * to denote volume data.
1158 local char *get_suffix(name)
1162 char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */
1163 static char const *known_suffixes[] =
1164 {NULL, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
1165 #ifdef MAX_EXT_CHARS
1170 bool suffix_of_builtin = false;
1172 /* Normally put Z_SUFFIX at the start of KNOWN_SUFFIXES, but if it
1173 is a suffix of one of them, put it at the end. */
1174 for (suf = known_suffixes + 1; *suf; suf++)
1176 size_t suflen = strlen (*suf);
1177 if (z_len < suflen && strequ (z_suffix, *suf + suflen - z_len))
1179 suffix_of_builtin = true;
1183 known_suffixes[suffix_of_builtin
1184 ? sizeof known_suffixes / sizeof *known_suffixes - 2
1186 suf = known_suffixes + suffix_of_builtin;
1188 nlen = strlen(name);
1189 if (nlen <= MAX_SUFFIX+2) {
1190 strcpy(suffix, name);
1192 strcpy(suffix, name+nlen-MAX_SUFFIX-2);
1195 slen = strlen(suffix);
1197 int s = strlen(*suf);
1198 if (slen > s && ! ISSLASH (suffix[slen - s - 1])
1199 && strequ(suffix + slen - s, *suf)) {
1202 } while (*++suf != NULL);
1208 /* Open file NAME with the given flags and store its status
1209 into *ST. Return a file descriptor to the newly opened file, or -1
1210 (setting errno) on failure. */
1212 open_and_stat (char *name, int flags, struct stat *st)
1215 int atfd = AT_FDCWD;
1216 char const *base = name;
1218 /* Refuse to follow symbolic links unless -c or -f. */
1219 if (!to_stdout && !force)
1221 if (HAVE_WORKING_O_NOFOLLOW)
1222 flags |= O_NOFOLLOW;
1226 if (lstat (name, st) != 0)
1228 else if (S_ISLNK (st->st_mode))
1239 char const *b = last_component (name);
1240 int f = atdir_set (name, b - name);
1248 fd = openat (atfd, base, flags);
1249 if (0 <= fd && fstat (fd, st) != 0)
1260 /* ========================================================================
1261 * Set ifname to the input file name (with a suffix appended if necessary)
1262 * and istat to its stats. For decompression, if no file exists with the
1263 * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
1264 * For MSDOS, we try only z_suffix and z.
1265 * Return an open file descriptor or -1.
1268 open_input_file (iname, sbuf)
1272 int ilen; /* strlen(ifname) */
1273 int z_suffix_errno = 0;
1274 static char const *suffixes[] = {NULL, ".gz", ".z", "-z", ".Z", NULL};
1275 char const **suf = suffixes;
1277 #ifdef NO_MULTIPLE_DOTS
1278 char *dot; /* pointer to ifname extension, or NULL */
1281 int open_flags = (O_RDONLY | O_NONBLOCK | O_NOCTTY
1282 | (ascii && !decompress ? 0 : O_BINARY));
1286 if (sizeof ifname - 1 <= strlen (iname))
1289 strcpy(ifname, iname);
1291 /* If input file exists, return OK. */
1292 fd = open_and_stat (ifname, open_flags, sbuf);
1296 if (!decompress || errno != ENOENT) {
1300 /* File.ext doesn't exist. Try adding a suffix. */
1301 s = get_suffix(ifname);
1303 progerror(ifname); /* ifname already has z suffix and does not exist */
1306 #ifdef NO_MULTIPLE_DOTS
1307 dot = strrchr(ifname, '.');
1309 strcat(ifname, ".");
1310 dot = strrchr(ifname, '.');
1313 ilen = strlen(ifname);
1314 if (strequ(z_suffix, ".gz")) suf++;
1316 /* Search for all suffixes */
1318 char const *s0 = s = *suf;
1319 strcpy (ifname, iname);
1320 #ifdef NO_MULTIPLE_DOTS
1322 if (*dot == '\0') strcpy (dot, ".");
1324 #ifdef MAX_EXT_CHARS
1325 if (MAX_EXT_CHARS < strlen (s) + strlen (dot + 1))
1326 dot[MAX_EXT_CHARS + 1 - strlen (s)] = '\0';
1328 if (sizeof ifname <= ilen + strlen (s))
1331 fd = open_and_stat (ifname, open_flags, sbuf);
1334 if (errno != ENOENT)
1339 if (strequ (s0, z_suffix))
1340 z_suffix_errno = errno;
1341 } while (*++suf != NULL);
1343 /* No suffix found, complain using z_suffix: */
1344 strcpy(ifname, iname);
1345 #ifdef NO_MULTIPLE_DOTS
1346 if (*dot == '\0') strcpy(dot, ".");
1348 #ifdef MAX_EXT_CHARS
1349 if (MAX_EXT_CHARS < z_len + strlen (dot + 1))
1350 dot[MAX_EXT_CHARS + 1 - z_len] = '\0';
1352 strcat(ifname, z_suffix);
1353 errno = z_suffix_errno;
1358 fprintf (stderr, "%s: %s: file name too long\n", program_name, iname);
1363 /* ========================================================================
1364 * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
1365 * Sets save_orig_name to true if the file name has been truncated.
1367 local int make_ofname()
1369 char *suff; /* ofname z suffix */
1371 strcpy(ofname, ifname);
1372 /* strip a version number if any and get the gzip suffix if present: */
1373 suff = get_suffix(ofname);
1377 /* With -t or -l, try all files (even without .gz suffix)
1378 * except with -r (behave as with just -dr).
1380 if (!recursive && (list || test)) return OK;
1382 /* Avoid annoying messages with -r */
1383 if (verbose || (!recursive && !quiet)) {
1384 WARN((stderr,"%s: %s: unknown suffix -- ignored\n",
1385 program_name, ifname));
1389 /* Make a special case for .tgz and .taz: */
1391 if (strequ(suff, ".tgz") || strequ(suff, ".taz")) {
1392 strcpy(suff, ".tar");
1394 *suff = '\0'; /* strip the z suffix */
1396 /* ofname might be changed later if infile contains an original name */
1398 } else if (suff && ! force) {
1399 /* Avoid annoying messages with -r (see treat_dir()) */
1400 if (verbose || (!recursive && !quiet)) {
1401 /* Don't use WARN, as it affects exit status. */
1402 fprintf (stderr, "%s: %s already has %s suffix -- unchanged\n",
1403 program_name, ifname, suff);
1409 #ifdef NO_MULTIPLE_DOTS
1410 suff = strrchr(ofname, '.');
1412 if (sizeof ofname <= strlen (ofname) + 1)
1414 strcat(ofname, ".");
1415 # ifdef MAX_EXT_CHARS
1416 if (strequ(z_suffix, "z")) {
1417 if (sizeof ofname <= strlen (ofname) + 2)
1419 strcat(ofname, "gz"); /* enough room */
1422 /* On the Atari and some versions of MSDOS,
1423 * ENAMETOOLONG does not work correctly. So we
1424 * must truncate here.
1426 } else if (strlen(suff)-1 + z_len > MAX_SUFFIX) {
1427 suff[MAX_SUFFIX+1-z_len] = '\0';
1431 #endif /* NO_MULTIPLE_DOTS */
1432 if (sizeof ofname <= strlen (ofname) + z_len)
1434 strcat(ofname, z_suffix);
1436 } /* decompress ? */
1440 WARN ((stderr, "%s: %s: file name too long\n", program_name, ifname));
1444 /* Discard NBYTES input bytes from the input, or up through the next
1445 zero byte if NBYTES == (size_t) -1. If FLAGS say that the header
1446 CRC should be computed, update the CRC accordingly. */
1448 discard_input_bytes (nbytes, flags)
1454 uch c = get_byte ();
1455 if (flags & HEADER_CRC)
1457 if (nbytes != (size_t) -1)
1464 /* ========================================================================
1465 * Check the magic number of the input file and update ofname if an
1466 * original name was given and to_stdout is not set.
1467 * Return the compression method, -1 for error, -2 for warning.
1468 * Set inptr to the offset of the next byte to be processed.
1469 * Updates time_stamp if there is one and neither -m nor -n is used.
1470 * This function may be called repeatedly for an input file consisting
1471 * of several contiguous gzip'ed members.
1472 * IN assertions: there is at least one remaining compressed member.
1473 * If the member is a zip file, it must be the only one.
1475 local int get_method(in)
1476 int in; /* input file descriptor */
1478 uch flags; /* compression flags */
1479 uch magic[10]; /* magic header */
1480 int imagic0; /* first magic byte or EOF */
1481 int imagic1; /* like magic[1], but can represent EOF */
1482 ulg stamp; /* timestamp */
1484 /* If --force and --stdout, zcat == cat, so do not complain about
1485 * premature end of file: use try_byte instead of get_byte.
1487 if (force && to_stdout) {
1488 imagic0 = try_byte();
1490 imagic1 = try_byte ();
1492 /* If try_byte returned EOF, magic[1] == (char) EOF. */
1494 magic[0] = get_byte ();
1497 magic[1] = get_byte ();
1498 imagic1 = 0; /* avoid lint warning */
1500 imagic1 = try_byte ();
1504 method = -1; /* unknown yet */
1505 part_nb++; /* number of parts in gzip file */
1508 /* assume multiple members in gzip file except for record oriented I/O */
1510 if (memcmp(magic, GZIP_MAGIC, 2) == 0
1511 || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
1513 method = (int)get_byte();
1514 if (method != DEFLATED) {
1516 "%s: %s: unknown method %d -- not supported\n",
1517 program_name, ifname, method);
1522 flags = (uch)get_byte();
1524 if ((flags & ENCRYPTED) != 0) {
1526 "%s: %s is encrypted -- not supported\n",
1527 program_name, ifname);
1531 if ((flags & RESERVED) != 0) {
1533 "%s: %s has flags 0x%x -- not supported\n",
1534 program_name, ifname, flags);
1536 if (force <= 1) return -1;
1538 stamp = (ulg)get_byte();
1539 stamp |= ((ulg)get_byte()) << 8;
1540 stamp |= ((ulg)get_byte()) << 16;
1541 stamp |= ((ulg)get_byte()) << 24;
1542 if (!no_time && 0 < stamp && stamp <= TYPE_MAXIMUM (time_t))
1544 time_stamp.tv_sec = stamp;
1545 time_stamp.tv_nsec = 0;
1548 magic[8] = get_byte (); /* Ignore extra flags. */
1549 magic[9] = get_byte (); /* Ignore OS type. */
1551 if (flags & HEADER_CRC)
1553 magic[2] = DEFLATED;
1555 magic[4] = stamp & 0xff;
1556 magic[5] = (stamp >> 8) & 0xff;
1557 magic[6] = (stamp >> 16) & 0xff;
1558 magic[7] = stamp >> 24;
1563 if ((flags & EXTRA_FIELD) != 0) {
1565 unsigned int len = lenbuf[0] = get_byte ();
1566 len |= (lenbuf[1] = get_byte ()) << 8;
1568 fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n",
1569 program_name, ifname, len);
1571 if (flags & HEADER_CRC)
1573 discard_input_bytes (len, flags);
1576 /* Get original file name if it was truncated */
1577 if ((flags & ORIG_NAME) != 0) {
1578 if (no_name || (to_stdout && !list) || part_nb > 1) {
1579 /* Discard the old name */
1580 discard_input_bytes (-1, flags);
1582 /* Copy the base name. Keep a directory prefix intact. */
1583 char *p = gzip_base_name (ofname);
1586 *p = (char) get_byte ();
1587 if (*p++ == '\0') break;
1588 if (p >= ofname+sizeof(ofname)) {
1589 gzip_error ("corrupted input -- file name too large");
1592 if (flags & HEADER_CRC)
1593 updcrc ((uch *) base, p - base);
1594 p = gzip_base_name (base);
1595 memmove (base, p, strlen (p) + 1);
1596 /* If necessary, adapt the name to local OS conventions: */
1598 MAKE_LEGAL_NAME(base);
1599 if (base) list=0; /* avoid warning about unused variable */
1601 } /* no_name || to_stdout */
1604 /* Discard file comment if any */
1605 if ((flags & COMMENT) != 0) {
1606 discard_input_bytes (-1, flags);
1609 if (flags & HEADER_CRC)
1611 unsigned int crc16 = updcrc (magic, 0) & 0xffff;
1612 unsigned int header16 = get_byte ();
1613 header16 |= ((unsigned int) get_byte ()) << 8;
1614 if (header16 != crc16)
1617 "%s: %s: header checksum 0x%04x != computed checksum 0x%04x\n",
1618 program_name, ifname, header16, crc16);
1626 header_bytes = inptr + 2*4; /* include crc and size */
1629 } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
1630 && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0) {
1631 /* To simplify the code, we support a zip file when alone only.
1632 * We are thus guaranteed that the entire local header fits in inbuf.
1636 if (check_zipfile(in) != OK) return -1;
1637 /* check_zipfile may get ofname from the local header */
1640 } else if (memcmp(magic, PACK_MAGIC, 2) == 0) {
1644 } else if (memcmp(magic, LZW_MAGIC, 2) == 0) {
1646 method = COMPRESSED;
1649 } else if (memcmp(magic, LZH_MAGIC, 2) == 0) {
1654 } else if (force && to_stdout && !list) { /* pass input unchanged */
1660 if (imagic0 != EOF) {
1661 write_buf (STDOUT_FILENO, magic, 1);
1665 if (method >= 0) return method;
1668 fprintf (stderr, "\n%s: %s: not in gzip format\n",
1669 program_name, ifname);
1676 for (inbyte = imagic1; inbyte == 0; inbyte = try_byte ())
1681 WARN ((stderr, "\n%s: %s: decompression OK, trailing zero bytes ignored\n",
1682 program_name, ifname));
1687 WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n",
1688 program_name, ifname));
1693 /* ========================================================================
1694 * Display the characteristics of the compressed file.
1695 * If the given method is < 0, display the accumulated totals.
1696 * IN assertions: time_stamp, header_bytes and ifile_size are initialized.
1698 local void do_list(ifd, method)
1699 int ifd; /* input file descriptor */
1700 int method; /* compression method */
1702 ulg crc; /* original crc */
1703 static int first_time = 1;
1704 static char const *const methods[MAX_METHODS] = {
1709 "", "", "", "", /* 4 to 7 reserved */
1711 int positive_off_t_width = 1;
1714 for (o = OFF_T_MAX; 9 < o; o /= 10) {
1715 positive_off_t_width++;
1718 if (first_time && method >= 0) {
1721 printf("method crc date time ");
1724 printf("%*.*s %*.*s ratio uncompressed_name\n",
1725 positive_off_t_width, positive_off_t_width, "compressed",
1726 positive_off_t_width, positive_off_t_width, "uncompressed");
1728 } else if (method < 0) {
1729 if (total_in <= 0 || total_out <= 0) return;
1733 if (verbose || !quiet) {
1734 fprint_off(stdout, total_in, positive_off_t_width);
1736 fprint_off(stdout, total_out, positive_off_t_width);
1739 display_ratio(total_out-(total_in-header_bytes), total_out, stdout);
1740 /* header_bytes is not meaningful but used to ensure the same
1741 * ratio if there is a single file.
1743 printf(" (totals)\n");
1746 crc = (ulg)~0; /* unknown */
1748 bytes_in = ifile_size;
1750 if (method == DEFLATED && !last_member) {
1751 /* Get the crc and uncompressed size for gzip'ed (not zip'ed) files.
1752 * If the lseek fails, we could use read() to get to the end, but
1753 * --list is used to get quick results.
1754 * Use "gunzip < foo.gz | wc -c" to get the uncompressed size if
1755 * you are not concerned about speed.
1757 bytes_in = lseek(ifd, (off_t)(-8), SEEK_END);
1758 if (bytes_in != -1L) {
1761 if (read(ifd, (char*)buf, sizeof(buf)) != sizeof(buf)) {
1765 bytes_out = LG(buf+4);
1771 static char const month_abbr[][4]
1772 = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1773 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
1774 struct tm *tm = (time_stamp.tv_nsec < 0
1776 : localtime (&time_stamp.tv_sec));
1777 printf ("%5s %08lx ", methods[method], crc);
1779 printf ("%s%3d %02d:%02d ", month_abbr[tm->tm_mon],
1780 tm->tm_mday, tm->tm_hour, tm->tm_min);
1782 printf ("??? ?? ??:?? ");
1784 fprint_off(stdout, bytes_in, positive_off_t_width);
1786 fprint_off(stdout, bytes_out, positive_off_t_width);
1788 if (bytes_in == -1L) {
1790 bytes_in = bytes_out = header_bytes = 0;
1791 } else if (total_in >= 0) {
1792 total_in += bytes_in;
1794 if (bytes_out == -1L) {
1796 bytes_in = bytes_out = header_bytes = 0;
1797 } else if (total_out >= 0) {
1798 total_out += bytes_out;
1800 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out, stdout);
1801 printf(" %s\n", ofname);
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.
1811 * IN assertion: for compression, the suffix of the given name is z_suffix.
1813 local void shorten_name(name)
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 */
1825 gzip_error ("name too short");
1829 p = get_suffix(name);
1831 gzip_error ("can't recover suffix\n");
1835 /* compress 1234567890.tar to 1234567890.tgz */
1836 if (len > 4 && strequ(p-4, ".tar")) {
1837 strcpy(p-4, ".tgz");
1840 /* Try keeping short extensions intact:
1841 * 1234.678.012.gz -> 123.678.012.gz
1844 p = last_component (name);
1846 plen = strcspn(p, PART_SEP);
1848 if (plen > min_part) trunc = p-1;
1851 } while (trunc == NULL && --min_part != 0);
1853 if (trunc != NULL) {
1855 trunc[0] = trunc[1];
1859 trunc = strrchr(name, PART_SEP[0]);
1861 gzip_error ("internal error in shorten_name");
1862 if (trunc[1] == '\0') trunc--; /* force truncation */
1864 strcpy(trunc, z_suffix);
1867 /* ========================================================================
1868 * The compressed file already exists, so ask for confirmation.
1869 * Return ERROR if the file must be skipped.
1871 local int check_ofname()
1873 /* Ask permission to overwrite the existing file */
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)? ");
1883 fprintf(stderr, "\tnot overwritten\n");
1884 if (exit_code == OK) exit_code = WARNING;
1888 if (xunlink (ofname)) {
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
1900 do_chown (int fd, char const *name, uid_t uid, gid_t gid)
1904 ignore_value (fchown (fd, uid, gid));
1906 ignore_value (chown (name, uid, gid));
1911 /* ========================================================================
1912 * Copy modes, times, ownership from input file to output file.
1913 * IN assertion: to_stdout is false.
1915 local void copy_stat(ifstat)
1916 struct stat *ifstat;
1918 mode_t mode = ifstat->st_mode & S_IRWXUGO;
1923 struct timespec timespec[2];
1924 timespec[0] = get_stat_atime (ifstat);
1925 timespec[1] = get_stat_mtime (ifstat);
1926 restoring = (decompress && 0 <= time_stamp.tv_nsec
1927 && ! (timespec[1].tv_sec == time_stamp.tv_sec
1928 && timespec[1].tv_nsec == time_stamp.tv_nsec));
1930 timespec[1] = time_stamp;
1932 if (fdutimens (ofd, ofname, timespec) == 0)
1934 if (restoring && 1 < verbose) {
1935 fprintf(stderr, "%s: timestamp restored\n", ofname);
1941 WARN ((stderr, "%s: ", program_name));
1950 /* Change the group first, then the permissions, then the owner.
1951 That way, the permissions will be correct on systems that allow
1952 users to give away files, without introducing a security hole.
1953 Security depends on permissions not containing the setuid or
1956 do_chown (ofd, ofname, -1, ifstat->st_gid);
1959 r = fchmod (ofd, mode);
1961 r = chmod (ofname, mode);
1965 WARN ((stderr, "%s: ", program_name));
1972 do_chown (ofd, ofname, ifstat->st_uid, -1);
1977 /* ========================================================================
1978 * Recurse through the given directory.
1980 local void treat_dir (fd, dir)
1985 char nbuf[MAX_PATH_LEN];
1990 dirp = fdopendir (fd);
1998 entries = streamsavedir (dirp, SAVEDIR_SORT_NONE);
2001 if (closedir (dirp) != 0)
2006 for (entry = entries; *entry; entry += entrylen + 1) {
2007 size_t len = strlen (dir);
2008 entrylen = strlen (entry);
2009 if (strequ (entry, ".") || strequ (entry, ".."))
2011 if (len + entrylen < MAX_PATH_LEN - 2) {
2013 if (*last_component (nbuf) && !ISSLASH (nbuf[len - 1]))
2015 strcpy (nbuf + len, entry);
2018 fprintf(stderr,"%s: %s/%s: pathname too long\n",
2019 program_name, dir, entry);
2025 #endif /* ! NO_DIR */
2027 /* Make sure signals get handled properly. */
2030 install_signal_handlers ()
2032 int nsigs = sizeof handled_sig / sizeof handled_sig[0];
2036 struct sigaction act;
2038 sigemptyset (&caught_signals);
2039 for (i = 0; i < nsigs; i++)
2041 sigaction (handled_sig[i], NULL, &act);
2042 if (act.sa_handler != SIG_IGN)
2043 sigaddset (&caught_signals, handled_sig[i]);
2046 act.sa_handler = abort_gzip_signal;
2047 act.sa_mask = caught_signals;
2050 for (i = 0; i < nsigs; i++)
2051 if (sigismember (&caught_signals, handled_sig[i]))
2055 sigaction (handled_sig[i], &act, NULL);
2058 for (i = 0; i < nsigs; i++)
2059 if (signal (handled_sig[i], SIG_IGN) != SIG_IGN)
2063 signal (handled_sig[i], abort_gzip_signal);
2064 siginterrupt (handled_sig[i], 1);
2069 /* ========================================================================
2070 * Free all dynamically allocated variables and exit with the given code.
2072 local void do_exit(exitcode)
2075 static int in_exit = 0;
2077 if (in_exit) exit(exitcode);
2097 if (fclose (stdout) != 0)
2102 /* ========================================================================
2103 * Close and unlink the output file.
2106 remove_output_file ()
2111 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
2112 fd = remove_ofname_fd;
2115 remove_ofname_fd = -1;
2119 sigprocmask (SIG_SETMASK, &oldset, NULL);
2122 /* ========================================================================
2128 remove_output_file ();
2132 /* ========================================================================
2136 abort_gzip_signal (sig)
2140 signal (sig, SIG_IGN);
2141 remove_output_file ();
2142 if (sig == exiting_signal)
2144 signal (sig, SIG_DFL);