1 /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
3 Copyright (C) 1999, 2001-2002, 2006-2007, 2009-2018 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) 2018 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 <https://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"
103 # define MAX_PATH_LEN 1024 /* max pathname length */
115 off_t lseek (int fd, off_t offset, int whence);
118 #ifndef HAVE_WORKING_O_NOFOLLOW
119 # define HAVE_WORKING_O_NOFOLLOW 0
122 /* Separator for file name parts (see shorten_name()) */
123 #ifdef NO_MULTIPLE_DOTS
124 # define PART_SEP "-"
126 # define PART_SEP "."
131 DECLARE(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
132 DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
133 DECLARE(ush, d_buf, DIST_BUFSIZE);
134 DECLARE(uch, window, 2L*WSIZE);
136 DECLARE(ush, tab_prefix, 1L<<BITS);
138 DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
139 DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
142 /* local variables */
144 /* If true, pretend that standard input is a tty. This option
145 is deliberately not documented, and only for testing. */
146 static bool presume_input_tty;
148 /* If true, transfer output data to the output file's storage device
149 when supported. Otherwise, if the system crashes around the time
150 gzip is run, the user might lose both input and output data. See:
151 Pillai TS et al. All file systems are not created equal: on the
152 complexity of crafting crash-consistent applications. OSDI'14. 2014:433-48.
153 https://www.usenix.org/conference/osdi14/technical-sessions/presentation/pillai */
154 static bool synchronous;
156 static int ascii = 0; /* convert end-of-lines to local OS conventions */
157 int to_stdout = 0; /* output to stdout (-c) */
158 static int decompress = 0; /* decompress (-d) */
159 static int force = 0; /* don't ask questions, compress links (-f) */
160 static int keep = 0; /* keep (don't delete) input files */
161 static int no_name = -1; /* don't save or restore the original file name */
162 static int no_time = -1; /* don't save or restore the original file time */
163 static int recursive = 0; /* recurse through directories (-r) */
164 static int list = 0; /* list the file contents (-l) */
165 int verbose = 0; /* be verbose (-v) */
166 int quiet = 0; /* be very quiet (-q) */
167 static int do_lzw = 0; /* generate output compatible with old compress (-Z) */
168 int test = 0; /* test .gz file integrity */
169 static int foreground = 0; /* set if program run in foreground */
170 char *program_name; /* program name */
171 int maxbits = BITS; /* max bits per code for LZW */
172 int method = DEFLATED;/* compression method */
173 int level = 6; /* compression level */
174 int exit_code = OK; /* program exit code */
175 int save_orig_name; /* set if original name must be saved */
176 static int last_member; /* set for .zip and .Z files */
177 static int part_nb; /* number of parts in .gz file */
178 off_t ifile_size; /* input file size, -1 for devices (debug only) */
179 static char *env; /* contents of GZIP env variable */
180 static char const *z_suffix; /* default suffix (can be set with --suffix) */
181 static size_t z_len; /* strlen(z_suffix) */
183 /* The original timestamp (modification time). If the original is
184 unknown, TIME_STAMP.tv_nsec is negative. If the original is
185 greater than struct timespec range, TIME_STAMP is the maximal
186 struct timespec value; this can happen on hosts with 32-bit signed
187 time_t because the gzip format's MTIME is 32-bit unsigned.
188 The original cannot be less than struct timespec range. */
189 struct timespec time_stamp;
191 /* The set of signals that are caught. */
192 static sigset_t caught_signals;
194 /* If nonzero then exit with status WARNING, rather than with the usual
195 signal status, on receipt of a signal with this value. This
196 suppresses a "Broken Pipe" message with some shells. */
197 static int volatile exiting_signal;
199 /* If nonnegative, close this file descriptor and unlink remove_ofname
201 static int volatile remove_ofname_fd = -1;
202 static char volatile remove_ofname[MAX_PATH_LEN];
204 static bool stdin_was_read;
206 off_t bytes_in; /* number of input bytes */
207 off_t bytes_out; /* number of output bytes */
208 static off_t total_in; /* input bytes for all files */
209 static off_t total_out; /* output bytes for all files */
210 char ifname[MAX_PATH_LEN]; /* input file name */
211 char ofname[MAX_PATH_LEN]; /* output file name */
212 static char dfname[MAX_PATH_LEN]; /* name of dir containing output file */
213 static struct stat istat; /* status for input file */
214 int ifd; /* input file descriptor */
215 int ofd; /* output file descriptor */
216 static int dfd = -1; /* output directory file descriptor */
217 unsigned insize; /* valid bytes in inbuf */
218 unsigned inptr; /* index of next byte to be processed in inbuf */
219 unsigned outcnt; /* bytes in output buffer */
220 int rsync = 0; /* make ryncable chunks */
222 static int handled_sig[] =
224 /* SIGINT must be first, as 'foreground' depends on it. */
244 /* For long options that have no equivalent short option, use a
245 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
248 PRESUME_INPUT_TTY_OPTION = CHAR_MAX + 1,
252 /* A value greater than all valid long options, used as a flag to
253 distinguish options derived from the GZIP environment variable. */
257 static char const shortopts[] = "ab:cdfhH?klLmMnNqrS:tvVZ123456789";
259 static const struct option longopts[] =
261 /* { name has_arg *flag val } */
262 {"ascii", 0, 0, 'a'}, /* ascii text mode */
263 {"to-stdout", 0, 0, 'c'}, /* write output on standard output */
264 {"stdout", 0, 0, 'c'}, /* write output on standard output */
265 {"decompress", 0, 0, 'd'}, /* decompress */
266 {"uncompress", 0, 0, 'd'}, /* decompress */
267 /* {"encrypt", 0, 0, 'e'}, encrypt */
268 {"force", 0, 0, 'f'}, /* force overwrite of output file */
269 {"help", 0, 0, 'h'}, /* give help */
270 /* {"pkzip", 0, 0, 'k'}, force output in pkzip format */
271 {"keep", 0, 0, 'k'}, /* keep (don't delete) input files */
272 {"list", 0, 0, 'l'}, /* list .gz file contents */
273 {"license", 0, 0, 'L'}, /* display software license */
274 {"no-name", 0, 0, 'n'}, /* don't save or restore original name & time */
275 {"name", 0, 0, 'N'}, /* save or restore original name & time */
276 {"-presume-input-tty", no_argument, NULL, PRESUME_INPUT_TTY_OPTION},
277 {"quiet", 0, 0, 'q'}, /* quiet mode */
278 {"silent", 0, 0, 'q'}, /* quiet mode */
279 {"synchronous",0, 0, SYNCHRONOUS_OPTION},
280 {"recursive", 0, 0, 'r'}, /* recurse through directories */
281 {"suffix", 1, 0, 'S'}, /* use given suffix instead of .gz */
282 {"test", 0, 0, 't'}, /* test compressed file integrity */
283 {"verbose", 0, 0, 'v'}, /* verbose mode */
284 {"version", 0, 0, 'V'}, /* display version number */
285 {"fast", 0, 0, '1'}, /* compress faster */
286 {"best", 0, 0, '9'}, /* compress better */
287 {"lzw", 0, 0, 'Z'}, /* make output compatible with old compress */
288 {"bits", 1, 0, 'b'}, /* max number of bits per code (implies -Z) */
289 {"rsyncable", 0, 0, RSYNCABLE_OPTION}, /* make rsync-friendly archive */
293 /* local functions */
295 local noreturn void try_help (void);
296 local void help (void);
297 local void license (void);
298 local void version (void);
299 local int input_eof (void);
300 local void treat_stdin (void);
301 local void treat_file (char *iname);
302 local int create_outfile (void);
303 local char *get_suffix (char *name);
304 local int open_input_file (char *iname, struct stat *sbuf);
305 local void discard_input_bytes (size_t nbytes, unsigned int flags);
306 local int make_ofname (void);
307 local void shorten_name (char *name);
308 local int get_method (int in);
309 local void do_list (int ifd, int method);
310 local int check_ofname (void);
311 local void copy_stat (struct stat *ifstat);
312 local void install_signal_handlers (void);
313 static void remove_output_file (bool);
314 static void abort_gzip_signal (int);
315 local noreturn void do_exit (int exitcode);
316 static void finish_out (void);
317 int main (int argc, char **argv);
318 static int (*work) (int infile, int outfile) = zip; /* function to call */
321 local void treat_dir (int fd, char *dir);
324 #define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
329 fprintf (stderr, "Try `%s --help' for more information.\n",
334 /* ======================================================================== */
337 static char const* const help_msg[] = {
338 "Compress or uncompress FILEs (by default, compress FILES in-place).",
340 "Mandatory arguments to long options are mandatory for short options too.",
343 " -a, --ascii ascii text; convert end-of-line using local conventions",
345 " -c, --stdout write on standard output, keep original files unchanged",
346 " -d, --decompress decompress",
347 /* -e, --encrypt encrypt */
348 " -f, --force force overwrite of output file and compress links",
349 " -h, --help give this help",
350 /* -k, --pkzip force output in pkzip format */
351 " -k, --keep keep (don't delete) input files",
352 " -l, --list list compressed file contents",
353 " -L, --license display software license",
355 " -m do not save or restore the original modification time",
356 " -M, --time save or restore the original modification time",
358 " -n, --no-name do not save or restore the original name and timestamp",
359 " -N, --name save or restore the original name and timestamp",
360 " -q, --quiet suppress all warnings",
362 " -r, --recursive operate recursively on directories",
364 " --rsyncable make rsync-friendly archive",
365 " -S, --suffix=SUF use suffix SUF on compressed files",
366 " --synchronous synchronous output (safer if system crashes, but slower)",
367 " -t, --test test compressed file integrity",
368 " -v, --verbose verbose mode",
369 " -V, --version display version number",
370 " -1, --fast compress faster",
371 " -9, --best compress better",
373 " -Z, --lzw produce output compatible with old compress",
374 " -b, --bits=BITS max number of bits per code (implies -Z)",
377 "With no FILE, or when FILE is -, read standard input.",
379 "Report bugs to <bug-gzip@gnu.org>.",
381 char const *const *p = help_msg;
383 printf ("Usage: %s [OPTION]... [FILE]...\n", program_name);
384 while (*p) printf ("%s\n", *p++);
387 /* ======================================================================== */
390 char const *const *p = license_msg;
392 printf ("%s %s\n", program_name, Version);
393 while (*p) printf ("%s\n", *p++);
396 /* ======================================================================== */
401 printf ("Written by Jean-loup Gailly.\n");
404 local void progerror (char const *string)
407 fprintf (stderr, "%s: ", program_name);
413 /* ======================================================================== */
414 int main (int argc, char **argv)
416 int file_count; /* number of files to process */
417 size_t proglen; /* length of program_name */
422 EXPAND(argc, argv); /* wild card expansion if necessary */
424 program_name = gzip_base_name (argv[0]);
425 proglen = strlen (program_name);
427 /* Suppress .exe for MSDOS and OS/2: */
428 if (4 < proglen && strequ (program_name + proglen - 4, ".exe"))
429 program_name[proglen - 4] = '\0';
431 /* Add options in GZIP environment variable if there is one */
433 env = add_envopt (&env_argc, &argv_copy, OPTIONS_VAR);
434 env_argv = env ? argv_copy : NULL;
437 # define GNU_STANDARD 1
440 /* For compatibility with old compress, use program name as an option.
441 * Unless you compile with -DGNU_STANDARD=0, this program will behave as
442 * gzip even if it is invoked under the name gunzip or zcat.
444 * Systems which do not support links can still use -d or -dc.
445 * Ignore an .exe extension for MSDOS and OS/2.
447 if (strncmp (program_name, "un", 2) == 0 /* ungzip, uncompress */
448 || strncmp (program_name, "gun", 3) == 0) /* gunzip */
450 else if (strequ (program_name + 1, "cat") /* zcat, pcat, gcat */
451 || strequ (program_name, "gzcat")) /* gzcat */
452 decompress = to_stdout = 1;
456 z_len = strlen(z_suffix);
464 if (env_argv[optind] && strequ (env_argv[optind], "--"))
465 optc = ENV_OPTION + '-';
468 optc = getopt_long (env_argc, env_argv, shortopts, longopts,
474 if (optind != env_argc)
477 ("%s: %s: non-option in "OPTIONS_VAR
478 " environment variable\n"),
479 program_name, env_argv[optind]);
483 /* Wait until here before warning, so that GZIP='-q'
485 if (env_argc != 1 && !quiet)
487 ("%s: warning: "OPTIONS_VAR" environment variable"
488 " is deprecated; use an alias or script\n"),
491 /* Start processing ARGC and ARGV instead. */
501 optc = getopt_long (argc, argv, shortopts, longopts, &longind);
509 maxbits = atoi(optarg);
510 for (; *optarg; optarg++)
511 if (! ('0' <= *optarg && *optarg <= '9'))
513 fprintf (stderr, "%s: -b operand is not an integer\n",
519 to_stdout = 1; break;
521 decompress = 1; break;
525 help (); finish_out (); break;
529 list = decompress = to_stdout = 1; break;
531 license (); finish_out (); break;
532 case 'm': /* undocumented, may change later */
534 case 'M': /* undocumented, may change later */
537 case 'n' + ENV_OPTION:
538 no_name = no_time = 1; break;
540 case 'N' + ENV_OPTION:
541 no_name = no_time = 0; break;
542 case PRESUME_INPUT_TTY_OPTION:
543 presume_input_tty = true; break;
545 case 'q' + ENV_OPTION:
546 quiet = 1; verbose = 0; break;
549 fprintf (stderr, "%s: -r not supported on this system\n",
557 case RSYNCABLE_OPTION:
558 case RSYNCABLE_OPTION + ENV_OPTION:
562 #ifdef NO_MULTIPLE_DOTS
563 if (*optarg == '.') optarg++;
565 z_len = strlen(optarg);
568 case SYNCHRONOUS_OPTION:
572 test = decompress = to_stdout = 1;
575 case 'v' + ENV_OPTION:
576 verbose++; quiet = 0; break;
578 version (); finish_out (); break;
583 fprintf(stderr, "%s: -Z not supported in this version\n",
588 case '1' + ENV_OPTION: case '2' + ENV_OPTION: case '3' + ENV_OPTION:
589 case '4' + ENV_OPTION: case '5' + ENV_OPTION: case '6' + ENV_OPTION:
590 case '7' + ENV_OPTION: case '8' + ENV_OPTION: case '9' + ENV_OPTION:
593 case '1': case '2': case '3': case '4':
594 case '5': case '6': case '7': case '8': case '9':
599 if (ENV_OPTION <= optc && optc != ENV_OPTION + '?')
601 /* Output a diagnostic, since getopt_long didn't. */
602 fprintf (stderr, "%s: ", program_name);
604 fprintf (stderr, "-%c: ", optc - ENV_OPTION);
606 fprintf (stderr, "--%s: ", longopts[longind].name);
607 fprintf (stderr, ("option not valid in "OPTIONS_VAR
608 " environment variable\n"));
612 } /* loop on all arguments */
614 /* By default, save name and timestamp on compression but do not
615 * restore them on decompression.
617 if (no_time < 0) no_time = decompress;
618 if (no_name < 0) no_name = decompress;
620 file_count = argc - optind;
624 if (ascii && !quiet) {
625 fprintf(stderr, "%s: option --ascii ignored on this system\n",
629 if (z_len == 0 || z_len > MAX_SUFFIX) {
630 fprintf(stderr, "%s: invalid suffix '%s'\n", program_name, z_suffix);
634 if (do_lzw && !decompress) work = lzw;
636 /* Allocate all global buffers (for DYN_ALLOC option) */
637 ALLOC(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
638 ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
639 ALLOC(ush, d_buf, DIST_BUFSIZE);
640 ALLOC(uch, window, 2L*WSIZE);
642 ALLOC(ush, tab_prefix, 1L<<BITS);
644 ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
645 ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
648 exiting_signal = quiet ? SIGPIPE : 0;
649 install_signal_handlers ();
651 /* And get to work */
652 if (file_count != 0) {
653 if (to_stdout && !test && !list && (!decompress || !ascii)) {
654 SET_BINARY_MODE (STDOUT_FILENO);
656 while (optind < argc) {
657 treat_file(argv[optind++]);
659 } else { /* Standard input */
662 if (stdin_was_read && close (STDIN_FILENO) != 0)
664 strcpy (ifname, "stdin");
669 /* Output any totals, and check for output errors. */
670 if (!quiet && 1 < file_count)
672 if (fflush (stdout) != 0)
677 && fdatasync (STDOUT_FILENO) != 0 && errno != EINVAL)
678 || close (STDOUT_FILENO) != 0)
684 /* Return nonzero when at end of file on input. */
688 if (!decompress || last_member)
693 if (insize != INBUFSIZ || fill_inbuf (1) == EOF)
696 /* Unget the char that fill_inbuf got. */
704 get_input_size_and_time (void)
707 time_stamp.tv_nsec = -1;
709 /* Record the input file's size and timestamp only if it is a
710 regular file. Doing this for the timestamp helps to keep gzip's
711 output more reproducible when it is used as part of a
714 if (S_ISREG (istat.st_mode))
716 ifile_size = istat.st_size;
717 if (!no_time || list)
718 time_stamp = get_stat_mtime (&istat);
722 /* ========================================================================
723 * Compress or decompress stdin
725 local void treat_stdin()
728 && (presume_input_tty
729 || isatty (decompress ? STDIN_FILENO : STDOUT_FILENO))) {
730 /* Do not send compressed data to the terminal or read it from
731 * the terminal. We get here when user invoked the program
732 * without parameters, so be helpful. According to the GNU standards:
734 * If there is one behavior you think is most useful when the output
735 * is to a terminal, and another that you think is most useful when
736 * the output is a file or a pipe, then it is usually best to make
737 * the default behavior the one that is useful with output to a
738 * terminal, and have an option for the other behavior.
740 * Here we use the --force option to get the other behavior.
744 ("%s: compressed data not %s a terminal."
745 " Use -f to force %scompression.\n"
746 "For help, type: %s -h\n"),
748 decompress ? "read from" : "written to",
749 decompress ? "de" : "",
754 if (decompress || !ascii) {
755 SET_BINARY_MODE (STDIN_FILENO);
757 if (!test && !list && (!decompress || !ascii)) {
758 SET_BINARY_MODE (STDOUT_FILENO);
760 strcpy(ifname, "stdin");
761 strcpy(ofname, "stdout");
763 /* Get the file's timestamp and size. */
764 if (fstat (STDIN_FILENO, &istat) != 0)
766 progerror ("standard input");
770 get_input_size_and_time ();
772 clear_bufs(); /* clear input and output buffers */
776 stdin_was_read = true;
779 method = get_method(ifd);
781 do_exit(exit_code); /* error message already emitted */
785 do_list(ifd, method);
789 /* Actually do the compression/decompression. Loop over zipped members.
792 if (work (STDIN_FILENO, STDOUT_FILENO) != OK)
798 method = get_method(ifd);
799 if (method < 0) return; /* error message already emitted */
800 bytes_out = 0; /* required for length check */
805 fprintf(stderr, " OK\n");
807 } else if (!decompress) {
808 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
809 fprintf(stderr, "\n");
810 #ifdef DISPLAY_STDIN_RATIO
812 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
813 fprintf(stderr, "\n");
819 static char const dot = '.';
821 /* True if the cached directory for calls to openat etc. is DIR, with
822 length DIRLEN. DIR need not be null-terminated. DIRLEN must be
823 less than MAX_PATH_LEN. */
825 atdir_eq (char const *dir, ptrdiff_t dirlen)
828 dir = &dot, dirlen = 1;
829 return memcmp (dfname, dir, dirlen) == 0 && !dfname[dirlen];
832 /* Set the directory used for calls to openat etc. to be the directory
833 DIR, with length DIRLEN. DIR need not be null-terminated.
834 DIRLEN must be less than MAX_PATH_LEN. Return a file descriptor for
835 the directory, or -1 if one could not be obtained. */
837 atdir_set (char const *dir, ptrdiff_t dirlen)
839 /* Don't bother opening directories on older systems that
840 lack openat and unlinkat. It's not worth the porting hassle. */
841 #if HAVE_OPENAT && HAVE_UNLINKAT
842 enum { try_opening_directories = true };
844 enum { try_opening_directories = false };
847 if (try_opening_directories && ! atdir_eq (dir, dirlen))
852 dir = &dot, dirlen = 1;
853 memcpy (dfname, dir, dirlen);
854 dfname[dirlen] = '\0';
855 dfd = open (dfname, O_SEARCH | O_DIRECTORY);
861 /* ========================================================================
862 * Compress or decompress the given file
864 local void treat_file(iname)
867 /* Accept "-" as synonym for stdin */
868 if (strequ(iname, "-")) {
869 int cflag = to_stdout;
875 /* Check if the input file is present, set ifname and istat: */
876 ifd = open_input_file (iname, &istat);
880 /* If the input name is that of a directory, recurse or ignore: */
881 if (S_ISDIR(istat.st_mode)) {
884 treat_dir (ifd, iname);
885 /* Warning: ifname is now garbage */
890 WARN ((stderr, "%s: %s is a directory -- ignored\n",
891 program_name, ifname));
897 if (! S_ISREG (istat.st_mode))
900 "%s: %s is not a directory or a regular file - ignored\n",
901 program_name, ifname));
905 if (istat.st_mode & S_ISUID)
907 WARN ((stderr, "%s: %s is set-user-ID on execution - ignored\n",
908 program_name, ifname));
912 if (istat.st_mode & S_ISGID)
914 WARN ((stderr, "%s: %s is set-group-ID on execution - ignored\n",
915 program_name, ifname));
922 if (istat.st_mode & S_ISVTX)
925 "%s: %s has the sticky bit set - file ignored\n",
926 program_name, ifname));
930 if (2 <= istat.st_nlink)
932 WARN ((stderr, "%s: %s has %lu other link%c -- unchanged\n",
933 program_name, ifname,
934 (unsigned long int) istat.st_nlink - 1,
935 istat.st_nlink == 2 ? ' ' : 's'));
942 get_input_size_and_time ();
944 /* Generate output file name. For -r and (-t or -l), skip files
945 * without a valid gzip suffix (check done in make_ofname).
947 if (to_stdout && !list && !test) {
948 strcpy(ofname, "stdout");
950 } else if (make_ofname() != OK) {
955 clear_bufs(); /* clear input and output buffers */
959 method = get_method(ifd); /* updates ofname if original given */
962 return; /* error message already emitted */
966 do_list(ifd, method);
967 if (close (ifd) != 0)
972 /* If compressing to a file, check if ofname is not ambiguous
973 * because the operating system truncates names. Otherwise, generate
974 * a new ofname and save the original name in the compressed file.
978 /* Keep remove_ofname_fd negative. */
980 if (create_outfile() != OK) return;
982 if (!decompress && save_orig_name && !verbose && !quiet) {
983 fprintf(stderr, "%s: %s compressed to %s\n",
984 program_name, ifname, ofname);
987 /* Keep the name even if not truncated except with --no-name: */
988 if (!save_orig_name) save_orig_name = !no_name;
991 fprintf(stderr, "%s:\t", ifname);
994 /* Actually do the compression/decompression. Loop over zipped members.
997 if ((*work)(ifd, ofd) != OK) {
998 method = -1; /* force cleanup */
1005 method = get_method(ifd);
1006 if (method < 0) break; /* error message already emitted */
1007 bytes_out = 0; /* required for length check */
1010 if (close (ifd) != 0)
1018 && ((0 <= dfd && fdatasync (dfd) != 0 && errno != EINVAL)
1019 || (fsync (ofd) != 0 && errno != EINVAL)))
1020 || close (ofd) != 0)
1027 char *ifbase = last_component (ifname);
1028 int ufd = atdir_eq (ifname, ifbase - ifname) ? dfd : -1;
1031 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
1032 remove_ofname_fd = -1;
1033 res = ufd < 0 ? xunlink (ifname) : unlinkat (ufd, ifbase, 0);
1034 unlink_errno = res == 0 ? 0 : errno;
1035 sigprocmask (SIG_SETMASK, &oldset, NULL);
1039 WARN ((stderr, "%s: ", program_name));
1042 errno = unlink_errno;
1051 remove_output_file (false);
1055 /* Display statistics */
1058 fprintf(stderr, " OK");
1059 } else if (decompress) {
1060 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
1062 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
1064 if (!test && !to_stdout)
1065 fprintf(stderr, " -- %s %s", keep ? "created" : "replaced with",
1067 fprintf(stderr, "\n");
1072 volatile_strcpy (char volatile *dst, char const volatile *src)
1074 while ((*dst++ = *src++))
1078 /* ========================================================================
1079 * Create the output file. Return OK or ERROR.
1080 * Try several times if necessary to avoid truncating the z_suffix. For
1081 * example, do not create a compressed file of name "1234567890123."
1082 * Sets save_orig_name to true if the file name has been truncated.
1083 * IN assertions: the input file has already been open (ifd is set) and
1084 * ofname has already been updated if there was an original name.
1085 * OUT assertions: ifd and ofd are closed in case of error.
1087 local int create_outfile()
1089 int name_shortened = 0;
1090 int flags = (O_WRONLY | O_CREAT | O_EXCL
1091 | (ascii && decompress ? 0 : O_BINARY));
1092 char const *base = ofname;
1093 int atfd = AT_FDCWD;
1097 char const *b = last_component (ofname);
1098 int f = atdir_set (ofname, b - ofname);
1111 volatile_strcpy (remove_ofname, ofname);
1113 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
1114 remove_ofname_fd = ofd = openat (atfd, base, flags, S_IRUSR | S_IWUSR);
1116 sigprocmask (SIG_SETMASK, &oldset, NULL);
1125 shorten_name (ofname);
1131 if (check_ofname () != OK)
1145 if (name_shortened && decompress)
1147 /* name might be too long if an original name was saved */
1148 WARN ((stderr, "%s: %s: warning, name truncated\n",
1149 program_name, ofname));
1155 /* ========================================================================
1156 * Return a pointer to the 'z' suffix of a file name, or NULL. For all
1157 * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
1158 * accepted suffixes, in addition to the value of the --suffix option.
1159 * ".tgz" is a useful convention for tar.z files on systems limited
1160 * to 3 characters extensions. On such systems, ".?z" and ".??z" are
1161 * also accepted suffixes. For Unix, we do not want to accept any
1162 * .??z suffix as indicating a compressed file; some people use .xyz
1163 * to denote volume data.
1165 local char *get_suffix(name)
1169 char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */
1170 static char const *known_suffixes[] =
1171 {NULL, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
1172 #ifdef MAX_EXT_CHARS
1177 bool suffix_of_builtin = false;
1179 /* Normally put Z_SUFFIX at the start of KNOWN_SUFFIXES, but if it
1180 is a suffix of one of them, put it at the end. */
1181 for (suf = known_suffixes + 1; *suf; suf++)
1183 size_t suflen = strlen (*suf);
1184 if (z_len < suflen && strequ (z_suffix, *suf + suflen - z_len))
1186 suffix_of_builtin = true;
1191 char *z_lower = xstrdup(z_suffix);
1193 known_suffixes[suffix_of_builtin
1194 ? sizeof known_suffixes / sizeof *known_suffixes - 2
1196 suf = known_suffixes + suffix_of_builtin;
1198 nlen = strlen(name);
1199 if (nlen <= MAX_SUFFIX+2) {
1200 strcpy(suffix, name);
1202 strcpy(suffix, name+nlen-MAX_SUFFIX-2);
1205 slen = strlen(suffix);
1208 int s = strlen(*suf);
1209 if (slen > s && ! ISSLASH (suffix[slen - s - 1])
1210 && strequ(suffix + slen - s, *suf)) {
1211 match = name+nlen-s;
1214 } while (*++suf != NULL);
1221 /* Open file NAME with the given flags and store its status
1222 into *ST. Return a file descriptor to the newly opened file, or -1
1223 (setting errno) on failure. */
1225 open_and_stat (char *name, int flags, struct stat *st)
1228 int atfd = AT_FDCWD;
1229 char const *base = name;
1231 /* Refuse to follow symbolic links unless -c or -f. */
1232 if (!to_stdout && !force)
1234 if (HAVE_WORKING_O_NOFOLLOW)
1235 flags |= O_NOFOLLOW;
1239 if (lstat (name, st) != 0)
1241 else if (S_ISLNK (st->st_mode))
1252 char const *b = last_component (name);
1253 int f = atdir_set (name, b - name);
1261 fd = openat (atfd, base, flags);
1262 if (0 <= fd && fstat (fd, st) != 0)
1273 /* ========================================================================
1274 * Set ifname to the input file name (with a suffix appended if necessary)
1275 * and istat to its stats. For decompression, if no file exists with the
1276 * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
1277 * For MSDOS, we try only z_suffix and z.
1278 * Return an open file descriptor or -1.
1281 open_input_file (iname, sbuf)
1285 int ilen; /* strlen(ifname) */
1286 int z_suffix_errno = 0;
1287 static char const *suffixes[] = {NULL, ".gz", ".z", "-z", ".Z", NULL};
1288 char const **suf = suffixes;
1290 #ifdef NO_MULTIPLE_DOTS
1291 char *dot; /* pointer to ifname extension, or NULL */
1294 int open_flags = (O_RDONLY | O_NONBLOCK | O_NOCTTY
1295 | (ascii && !decompress ? 0 : O_BINARY));
1299 if (sizeof ifname - 1 <= strlen (iname))
1302 strcpy(ifname, iname);
1304 /* If input file exists, return OK. */
1305 fd = open_and_stat (ifname, open_flags, sbuf);
1309 if (!decompress || errno != ENOENT) {
1313 /* File.ext doesn't exist. Try adding a suffix. */
1314 s = get_suffix(ifname);
1316 progerror(ifname); /* ifname already has z suffix and does not exist */
1319 #ifdef NO_MULTIPLE_DOTS
1320 dot = strrchr(ifname, '.');
1322 strcat(ifname, ".");
1323 dot = strrchr(ifname, '.');
1326 ilen = strlen(ifname);
1327 if (strequ(z_suffix, ".gz")) suf++;
1329 /* Search for all suffixes */
1331 char const *s0 = s = *suf;
1332 strcpy (ifname, iname);
1333 #ifdef NO_MULTIPLE_DOTS
1335 if (*dot == '\0') strcpy (dot, ".");
1337 #ifdef MAX_EXT_CHARS
1338 if (MAX_EXT_CHARS < strlen (s) + strlen (dot + 1))
1339 dot[MAX_EXT_CHARS + 1 - strlen (s)] = '\0';
1341 if (sizeof ifname <= ilen + strlen (s))
1344 fd = open_and_stat (ifname, open_flags, sbuf);
1347 if (errno != ENOENT)
1352 if (strequ (s0, z_suffix))
1353 z_suffix_errno = errno;
1354 } while (*++suf != NULL);
1356 /* No suffix found, complain using z_suffix: */
1357 strcpy(ifname, iname);
1358 #ifdef NO_MULTIPLE_DOTS
1359 if (*dot == '\0') strcpy(dot, ".");
1361 #ifdef MAX_EXT_CHARS
1362 if (MAX_EXT_CHARS < z_len + strlen (dot + 1))
1363 dot[MAX_EXT_CHARS + 1 - z_len] = '\0';
1365 strcat(ifname, z_suffix);
1366 errno = z_suffix_errno;
1371 fprintf (stderr, "%s: %s: file name too long\n", program_name, iname);
1376 /* ========================================================================
1377 * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
1378 * Sets save_orig_name to true if the file name has been truncated.
1380 local int make_ofname()
1382 char *suff; /* ofname z suffix */
1384 strcpy(ofname, ifname);
1385 /* strip a version number if any and get the gzip suffix if present: */
1386 suff = get_suffix(ofname);
1390 /* With -t or -l, try all files (even without .gz suffix)
1391 * except with -r (behave as with just -dr).
1393 if (!recursive && (list || test)) return OK;
1395 /* Avoid annoying messages with -r */
1396 if (verbose || (!recursive && !quiet)) {
1397 WARN((stderr,"%s: %s: unknown suffix -- ignored\n",
1398 program_name, ifname));
1402 /* Make a special case for .tgz and .taz: */
1404 if (strequ(suff, ".tgz") || strequ(suff, ".taz")) {
1405 strcpy(suff, ".tar");
1407 *suff = '\0'; /* strip the z suffix */
1409 /* ofname might be changed later if infile contains an original name */
1411 } else if (suff && ! force) {
1412 /* Avoid annoying messages with -r (see treat_dir()) */
1413 if (verbose || (!recursive && !quiet)) {
1414 /* Don't use WARN, as it affects exit status. */
1415 fprintf (stderr, "%s: %s already has %s suffix -- unchanged\n",
1416 program_name, ifname, suff);
1422 #ifdef NO_MULTIPLE_DOTS
1423 suff = strrchr(ofname, '.');
1425 if (sizeof ofname <= strlen (ofname) + 1)
1427 strcat(ofname, ".");
1428 # ifdef MAX_EXT_CHARS
1429 if (strequ(z_suffix, "z")) {
1430 if (sizeof ofname <= strlen (ofname) + 2)
1432 strcat(ofname, "gz"); /* enough room */
1435 /* On the Atari and some versions of MSDOS,
1436 * ENAMETOOLONG does not work correctly. So we
1437 * must truncate here.
1439 } else if (strlen(suff)-1 + z_len > MAX_SUFFIX) {
1440 suff[MAX_SUFFIX+1-z_len] = '\0';
1444 #endif /* NO_MULTIPLE_DOTS */
1445 if (sizeof ofname <= strlen (ofname) + z_len)
1447 strcat(ofname, z_suffix);
1449 } /* decompress ? */
1453 WARN ((stderr, "%s: %s: file name too long\n", program_name, ifname));
1457 /* Discard NBYTES input bytes from the input, or up through the next
1458 zero byte if NBYTES == (size_t) -1. If FLAGS say that the header
1459 CRC should be computed, update the CRC accordingly. */
1461 discard_input_bytes (nbytes, flags)
1467 uch c = get_byte ();
1468 if (flags & HEADER_CRC)
1470 if (nbytes != (size_t) -1)
1477 /* ========================================================================
1478 * Check the magic number of the input file and update ofname if an
1479 * original name was given and to_stdout is not set.
1480 * Return the compression method, -1 for error, -2 for warning.
1481 * Set inptr to the offset of the next byte to be processed.
1482 * Updates time_stamp if there is one and neither -m nor -n is used.
1483 * This function may be called repeatedly for an input file consisting
1484 * of several contiguous gzip'ed members.
1485 * IN assertions: there is at least one remaining compressed member.
1486 * If the member is a zip file, it must be the only one.
1488 local int get_method(in)
1489 int in; /* input file descriptor */
1491 uch flags; /* compression flags */
1492 uch magic[10]; /* magic header */
1493 int imagic0; /* first magic byte or EOF */
1494 int imagic1; /* like magic[1], but can represent EOF */
1495 ulg stamp; /* timestamp */
1497 /* If --force and --stdout, zcat == cat, so do not complain about
1498 * premature end of file: use try_byte instead of get_byte.
1500 if (force && to_stdout) {
1501 imagic0 = try_byte();
1503 imagic1 = try_byte ();
1505 /* If try_byte returned EOF, magic[1] == (char) EOF. */
1507 magic[0] = get_byte ();
1510 magic[1] = get_byte ();
1511 imagic1 = 0; /* avoid lint warning */
1513 imagic1 = try_byte ();
1517 method = -1; /* unknown yet */
1518 part_nb++; /* number of parts in gzip file */
1521 /* assume multiple members in gzip file except for record oriented I/O */
1523 if (memcmp(magic, GZIP_MAGIC, 2) == 0
1524 || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
1526 method = (int)get_byte();
1527 if (method != DEFLATED) {
1529 "%s: %s: unknown method %d -- not supported\n",
1530 program_name, ifname, method);
1535 flags = (uch)get_byte();
1537 if ((flags & ENCRYPTED) != 0) {
1539 "%s: %s is encrypted -- not supported\n",
1540 program_name, ifname);
1544 if ((flags & RESERVED) != 0) {
1546 "%s: %s has flags 0x%x -- not supported\n",
1547 program_name, ifname, flags);
1549 if (force <= 1) return -1;
1551 stamp = (ulg)get_byte();
1552 stamp |= ((ulg)get_byte()) << 8;
1553 stamp |= ((ulg)get_byte()) << 16;
1554 stamp |= ((ulg)get_byte()) << 24;
1555 if (stamp != 0 && !no_time)
1557 if (stamp <= TYPE_MAXIMUM (time_t))
1559 time_stamp.tv_sec = stamp;
1560 time_stamp.tv_nsec = 0;
1565 "%s: %s: MTIME %lu out of range for this platform\n",
1566 program_name, ifname, stamp));
1567 time_stamp.tv_sec = TYPE_MAXIMUM (time_t);
1568 time_stamp.tv_nsec = TIMESPEC_RESOLUTION - 1;
1572 magic[8] = get_byte (); /* Ignore extra flags. */
1573 magic[9] = get_byte (); /* Ignore OS type. */
1575 if (flags & HEADER_CRC)
1577 magic[2] = DEFLATED;
1579 magic[4] = stamp & 0xff;
1580 magic[5] = (stamp >> 8) & 0xff;
1581 magic[6] = (stamp >> 16) & 0xff;
1582 magic[7] = stamp >> 24;
1587 if ((flags & EXTRA_FIELD) != 0) {
1589 unsigned int len = lenbuf[0] = get_byte ();
1590 len |= (lenbuf[1] = get_byte ()) << 8;
1592 fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n",
1593 program_name, ifname, len);
1595 if (flags & HEADER_CRC)
1597 discard_input_bytes (len, flags);
1600 /* Get original file name if it was truncated */
1601 if ((flags & ORIG_NAME) != 0) {
1602 if (no_name || (to_stdout && !list) || part_nb > 1) {
1603 /* Discard the old name */
1604 discard_input_bytes (-1, flags);
1606 /* Copy the base name. Keep a directory prefix intact. */
1607 char *p = gzip_base_name (ofname);
1610 *p = (char) get_byte ();
1611 if (*p++ == '\0') break;
1612 if (p >= ofname+sizeof(ofname)) {
1613 gzip_error ("corrupted input -- file name too large");
1616 if (flags & HEADER_CRC)
1617 updcrc ((uch *) base, p - base);
1618 p = gzip_base_name (base);
1619 memmove (base, p, strlen (p) + 1);
1620 /* If necessary, adapt the name to local OS conventions: */
1622 MAKE_LEGAL_NAME(base);
1623 if (base) list=0; /* avoid warning about unused variable */
1625 } /* no_name || to_stdout */
1628 /* Discard file comment if any */
1629 if ((flags & COMMENT) != 0) {
1630 discard_input_bytes (-1, flags);
1633 if (flags & HEADER_CRC)
1635 unsigned int crc16 = updcrc (magic, 0) & 0xffff;
1636 unsigned int header16 = get_byte ();
1637 header16 |= ((unsigned int) get_byte ()) << 8;
1638 if (header16 != crc16)
1641 "%s: %s: header checksum 0x%04x != computed checksum 0x%04x\n",
1642 program_name, ifname, header16, crc16);
1650 header_bytes = inptr + 2*4; /* include crc and size */
1653 } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
1654 && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0) {
1655 /* To simplify the code, we support a zip file when alone only.
1656 * We are thus guaranteed that the entire local header fits in inbuf.
1660 if (check_zipfile(in) != OK) return -1;
1661 /* check_zipfile may get ofname from the local header */
1664 } else if (memcmp(magic, PACK_MAGIC, 2) == 0) {
1668 } else if (memcmp(magic, LZW_MAGIC, 2) == 0) {
1670 method = COMPRESSED;
1673 } else if (memcmp(magic, LZH_MAGIC, 2) == 0) {
1678 } else if (force && to_stdout && !list) { /* pass input unchanged */
1684 if (imagic0 != EOF) {
1685 write_buf (STDOUT_FILENO, magic, 1);
1689 if (method >= 0) return method;
1692 fprintf (stderr, "\n%s: %s: not in gzip format\n",
1693 program_name, ifname);
1700 for (inbyte = imagic1; inbyte == 0; inbyte = try_byte ())
1705 WARN ((stderr, "\n%s: %s: decompression OK, trailing zero bytes ignored\n",
1706 program_name, ifname));
1711 WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n",
1712 program_name, ifname));
1717 /* ========================================================================
1718 * Display the characteristics of the compressed file.
1719 * If the given method is < 0, display the accumulated totals.
1720 * IN assertions: time_stamp, header_bytes and ifile_size are initialized.
1722 local void do_list(ifd, method)
1723 int ifd; /* input file descriptor */
1724 int method; /* compression method */
1726 ulg crc; /* original crc */
1727 static int first_time = 1;
1728 static char const *const methods[MAX_METHODS] = {
1733 "", "", "", "", /* 4 to 7 reserved */
1735 int positive_off_t_width = INT_STRLEN_BOUND (off_t) - 1;
1737 if (first_time && method >= 0) {
1740 printf("method crc date time ");
1743 printf("%*.*s %*.*s ratio uncompressed_name\n",
1744 positive_off_t_width, positive_off_t_width, "compressed",
1745 positive_off_t_width, positive_off_t_width, "uncompressed");
1747 } else if (method < 0) {
1748 if (total_in <= 0 || total_out <= 0) return;
1752 if (verbose || !quiet) {
1753 fprint_off(stdout, total_in, positive_off_t_width);
1755 fprint_off(stdout, total_out, positive_off_t_width);
1758 display_ratio(total_out-(total_in-header_bytes), total_out, stdout);
1759 /* header_bytes is not meaningful but used to ensure the same
1760 * ratio if there is a single file.
1762 printf(" (totals)\n");
1765 crc = (ulg)~0; /* unknown */
1767 bytes_in = ifile_size;
1769 if (method == DEFLATED && !last_member) {
1770 /* Get the crc and uncompressed size for gzip'ed (not zip'ed) files.
1771 * If the lseek fails, we could use read() to get to the end, but
1772 * --list is used to get quick results.
1773 * Use "gunzip < foo.gz | wc -c" to get the uncompressed size if
1774 * you are not concerned about speed.
1776 bytes_in = lseek(ifd, (off_t)(-8), SEEK_END);
1777 if (bytes_in != -1L) {
1780 if (read(ifd, (char*)buf, sizeof(buf)) != sizeof(buf)) {
1784 bytes_out = LG(buf+4);
1790 static char const month_abbr[][4]
1791 = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1792 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
1793 struct tm *tm = localtime (&time_stamp.tv_sec);
1794 printf ("%5s %08lx ", methods[method], crc);
1796 printf ("%s%3d %02d:%02d ", month_abbr[tm->tm_mon],
1797 tm->tm_mday, tm->tm_hour, tm->tm_min);
1799 printf ("??? ?? ??:?? ");
1801 fprint_off(stdout, bytes_in, positive_off_t_width);
1803 fprint_off(stdout, bytes_out, positive_off_t_width);
1805 if (bytes_in == -1L) {
1807 bytes_in = bytes_out = header_bytes = 0;
1808 } else if (total_in >= 0) {
1809 total_in += bytes_in;
1811 if (bytes_out == -1L) {
1813 bytes_in = bytes_out = header_bytes = 0;
1814 } else if (total_out >= 0) {
1815 total_out += bytes_out;
1817 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out, stdout);
1818 printf(" %s\n", ofname);
1821 /* ========================================================================
1822 * Shorten the given name by one character, or replace a .tar extension
1823 * with .tgz. Truncate the last part of the name which is longer than
1824 * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
1825 * has only parts shorter than MIN_PART truncate the longest part.
1826 * For decompression, just remove the last character of the name.
1828 * IN assertion: for compression, the suffix of the given name is z_suffix.
1830 local void shorten_name(name)
1833 int len; /* length of name without z_suffix */
1834 char *trunc = NULL; /* character to be truncated */
1835 int plen; /* current part length */
1836 int min_part = MIN_PART; /* current minimum part length */
1842 gzip_error ("name too short");
1846 p = get_suffix(name);
1848 gzip_error ("can't recover suffix\n");
1852 /* compress 1234567890.tar to 1234567890.tgz */
1853 if (len > 4 && strequ(p-4, ".tar")) {
1854 strcpy(p-4, ".tgz");
1857 /* Try keeping short extensions intact:
1858 * 1234.678.012.gz -> 123.678.012.gz
1861 p = last_component (name);
1863 plen = strcspn(p, PART_SEP);
1865 if (plen > min_part) trunc = p-1;
1868 } while (trunc == NULL && --min_part != 0);
1870 if (trunc != NULL) {
1872 trunc[0] = trunc[1];
1876 trunc = strrchr(name, PART_SEP[0]);
1878 gzip_error ("internal error in shorten_name");
1879 if (trunc[1] == '\0') trunc--; /* force truncation */
1881 strcpy(trunc, z_suffix);
1884 /* ========================================================================
1885 * The compressed file already exists, so ask for confirmation.
1886 * Return ERROR if the file must be skipped.
1888 local int check_ofname()
1890 /* Ask permission to overwrite the existing file */
1893 fprintf (stderr, "%s: %s already exists;", program_name, ofname);
1894 if (foreground && (presume_input_tty || isatty (STDIN_FILENO))) {
1895 fprintf(stderr, " do you wish to overwrite (y or n)? ");
1900 fprintf(stderr, "\tnot overwritten\n");
1901 if (exit_code == OK) exit_code = WARNING;
1905 if (xunlink (ofname)) {
1912 /* Change the owner and group of a file. FD is a file descriptor for
1913 the file and NAME its name. Change it to user UID and to group GID.
1914 If UID or GID is -1, though, do not change the corresponding user
1916 #if ! (HAVE_FCHOWN || HAVE_CHOWN)
1917 /* The types uid_t and gid_t do not exist on mingw, so don't assume them. */
1918 # define do_chown(fd, name, uid, gid) ((void) 0)
1921 do_chown (int fd, char const *name, uid_t uid, gid_t gid)
1924 ignore_value (fchown (fd, uid, gid));
1926 ignore_value (chown (name, uid, gid));
1931 /* ========================================================================
1932 * Copy modes, times, ownership from input file to output file.
1933 * IN assertion: to_stdout is false.
1935 local void copy_stat(ifstat)
1936 struct stat *ifstat;
1938 mode_t mode = ifstat->st_mode & S_IRWXUGO;
1943 struct timespec timespec[2];
1944 timespec[0] = get_stat_atime (ifstat);
1945 timespec[1] = get_stat_mtime (ifstat);
1946 restoring = (decompress && 0 <= time_stamp.tv_nsec
1947 && ! (timespec[1].tv_sec == time_stamp.tv_sec
1948 && timespec[1].tv_nsec == time_stamp.tv_nsec));
1950 timespec[1] = time_stamp;
1952 if (fdutimens (ofd, ofname, timespec) == 0)
1954 if (restoring && 1 < verbose) {
1955 fprintf(stderr, "%s: timestamp restored\n", ofname);
1961 WARN ((stderr, "%s: ", program_name));
1970 /* Change the group first, then the permissions, then the owner.
1971 That way, the permissions will be correct on systems that allow
1972 users to give away files, without introducing a security hole.
1973 Security depends on permissions not containing the setuid or
1976 do_chown (ofd, ofname, -1, ifstat->st_gid);
1979 r = fchmod (ofd, mode);
1981 r = chmod (ofname, mode);
1985 WARN ((stderr, "%s: ", program_name));
1992 do_chown (ofd, ofname, ifstat->st_uid, -1);
1997 /* ========================================================================
1998 * Recurse through the given directory.
2000 local void treat_dir (fd, dir)
2005 char nbuf[MAX_PATH_LEN];
2010 dirp = fdopendir (fd);
2018 entries = streamsavedir (dirp, SAVEDIR_SORT_NONE);
2021 if (closedir (dirp) != 0)
2026 for (entry = entries; *entry; entry += entrylen + 1) {
2027 size_t len = strlen (dir);
2028 entrylen = strlen (entry);
2029 if (strequ (entry, ".") || strequ (entry, ".."))
2031 if (len + entrylen < MAX_PATH_LEN - 2) {
2033 if (*last_component (nbuf) && !ISSLASH (nbuf[len - 1]))
2035 strcpy (nbuf + len, entry);
2038 fprintf(stderr,"%s: %s/%s: pathname too long\n",
2039 program_name, dir, entry);
2045 #endif /* ! NO_DIR */
2047 /* Make sure signals get handled properly. */
2050 install_signal_handlers ()
2052 int nsigs = sizeof handled_sig / sizeof handled_sig[0];
2054 struct sigaction act;
2056 sigemptyset (&caught_signals);
2057 for (i = 0; i < nsigs; i++)
2059 sigaction (handled_sig[i], NULL, &act);
2060 if (act.sa_handler != SIG_IGN)
2061 sigaddset (&caught_signals, handled_sig[i]);
2064 act.sa_handler = abort_gzip_signal;
2065 act.sa_mask = caught_signals;
2068 for (i = 0; i < nsigs; i++)
2069 if (sigismember (&caught_signals, handled_sig[i]))
2073 sigaction (handled_sig[i], &act, NULL);
2077 /* ========================================================================
2078 * Free all dynamically allocated variables and exit with the given code.
2080 local void do_exit(exitcode)
2083 static int in_exit = 0;
2085 if (in_exit) exit(exitcode);
2105 if (fclose (stdout) != 0)
2110 /* ========================================================================
2111 * Close and unlink the output file.
2114 remove_output_file (bool signals_already_blocked)
2119 if (!signals_already_blocked)
2120 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
2121 fd = remove_ofname_fd;
2124 char fname[MAX_PATH_LEN];
2125 remove_ofname_fd = -1;
2127 volatile_strcpy (fname, remove_ofname);
2130 if (!signals_already_blocked)
2131 sigprocmask (SIG_SETMASK, &oldset, NULL);
2134 /* ========================================================================
2140 remove_output_file (false);
2144 /* ========================================================================
2148 abort_gzip_signal (int sig)
2150 remove_output_file (true);
2151 if (sig == exiting_signal)
2153 signal (sig, SIG_DFL);