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) 2017 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);
119 # define OFF_T_MAX TYPE_MAXIMUM (off_t)
122 /* Use SA_NOCLDSTOP as a proxy for whether the sigaction machinery is
125 # define SA_NOCLDSTOP 0
126 # define sigprocmask(how, set, oset) /* empty */
127 # define sigset_t int
128 # if ! HAVE_SIGINTERRUPT
129 # define siginterrupt(sig, flag) /* empty */
133 #ifndef HAVE_WORKING_O_NOFOLLOW
134 # define HAVE_WORKING_O_NOFOLLOW 0
137 /* Separator for file name parts (see shorten_name()) */
138 #ifdef NO_MULTIPLE_DOTS
139 # define PART_SEP "-"
141 # define PART_SEP "."
146 DECLARE(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
147 DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
148 DECLARE(ush, d_buf, DIST_BUFSIZE);
149 DECLARE(uch, window, 2L*WSIZE);
151 DECLARE(ush, tab_prefix, 1L<<BITS);
153 DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
154 DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
157 /* local variables */
159 /* If true, pretend that standard input is a tty. This option
160 is deliberately not documented, and only for testing. */
161 static bool presume_input_tty;
163 /* If true, transfer output data to the output file's storage device
164 when supported. Otherwise, if the system crashes around the time
165 gzip is run, the user might lose both input and output data. See:
166 Pillai TS et al. All file systems are not created equal: on the
167 complexity of crafting crash-consistent applications. OSDI'14. 2014:433-48.
168 https://www.usenix.org/conference/osdi14/technical-sessions/presentation/pillai */
169 static bool synchronous;
171 static int ascii = 0; /* convert end-of-lines to local OS conventions */
172 int to_stdout = 0; /* output to stdout (-c) */
173 static int decompress = 0; /* decompress (-d) */
174 static int force = 0; /* don't ask questions, compress links (-f) */
175 static int keep = 0; /* keep (don't delete) input files */
176 static int no_name = -1; /* don't save or restore the original file name */
177 static int no_time = -1; /* don't save or restore the original file time */
178 static int recursive = 0; /* recurse through directories (-r) */
179 static int list = 0; /* list the file contents (-l) */
180 int verbose = 0; /* be verbose (-v) */
181 int quiet = 0; /* be very quiet (-q) */
182 static int do_lzw = 0; /* generate output compatible with old compress (-Z) */
183 int test = 0; /* test .gz file integrity */
184 static int foreground = 0; /* set if program run in foreground */
185 char *program_name; /* program name */
186 int maxbits = BITS; /* max bits per code for LZW */
187 int method = DEFLATED;/* compression method */
188 int level = 6; /* compression level */
189 int exit_code = OK; /* program exit code */
190 int save_orig_name; /* set if original name must be saved */
191 static int last_member; /* set for .zip and .Z files */
192 static int part_nb; /* number of parts in .gz file */
193 off_t ifile_size; /* input file size, -1 for devices (debug only) */
194 static char *env; /* contents of GZIP env variable */
195 static char const *z_suffix; /* default suffix (can be set with --suffix) */
196 static size_t z_len; /* strlen(z_suffix) */
198 /* The original timestamp (modification time). Its tv_nsec component
199 is negative if the original time is unknown or is out of time_t
200 range; the latter can happen on hosts with 32-bit signed time_t
201 because the gzip format's MTIME is 32-bit unsigned. */
202 struct timespec time_stamp;
204 /* The set of signals that are caught. */
205 static sigset_t caught_signals;
207 /* If nonzero then exit with status WARNING, rather than with the usual
208 signal status, on receipt of a signal with this value. This
209 suppresses a "Broken Pipe" message with some shells. */
210 static int volatile exiting_signal;
212 /* If nonnegative, close this file descriptor and unlink ofname on error. */
213 static int volatile remove_ofname_fd = -1;
215 static bool stdin_was_read;
217 off_t bytes_in; /* number of input bytes */
218 off_t bytes_out; /* number of output bytes */
219 static off_t total_in; /* input bytes for all files */
220 static off_t total_out; /* output bytes for all files */
221 char ifname[MAX_PATH_LEN]; /* input file name */
222 char ofname[MAX_PATH_LEN]; /* output file name */
223 static char dfname[MAX_PATH_LEN]; /* name of dir containing output file */
224 static struct stat istat; /* status for input file */
225 int ifd; /* input file descriptor */
226 int ofd; /* output file descriptor */
227 static int dfd = -1; /* output directory file descriptor */
228 unsigned insize; /* valid bytes in inbuf */
229 unsigned inptr; /* index of next byte to be processed in inbuf */
230 unsigned outcnt; /* bytes in output buffer */
231 int rsync = 0; /* make ryncable chunks */
233 static int handled_sig[] =
235 /* SIGINT must be first, as 'foreground' depends on it. */
255 /* For long options that have no equivalent short option, use a
256 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
259 PRESUME_INPUT_TTY_OPTION = CHAR_MAX + 1,
263 /* A value greater than all valid long options, used as a flag to
264 distinguish options derived from the GZIP environment variable. */
268 static char const shortopts[] = "ab:cdfhH?klLmMnNqrS:tvVZ123456789";
270 static const struct option longopts[] =
272 /* { name has_arg *flag val } */
273 {"ascii", 0, 0, 'a'}, /* ascii text mode */
274 {"to-stdout", 0, 0, 'c'}, /* write output on standard output */
275 {"stdout", 0, 0, 'c'}, /* write output on standard output */
276 {"decompress", 0, 0, 'd'}, /* decompress */
277 {"uncompress", 0, 0, 'd'}, /* decompress */
278 /* {"encrypt", 0, 0, 'e'}, encrypt */
279 {"force", 0, 0, 'f'}, /* force overwrite of output file */
280 {"help", 0, 0, 'h'}, /* give help */
281 /* {"pkzip", 0, 0, 'k'}, force output in pkzip format */
282 {"keep", 0, 0, 'k'}, /* keep (don't delete) input files */
283 {"list", 0, 0, 'l'}, /* list .gz file contents */
284 {"license", 0, 0, 'L'}, /* display software license */
285 {"no-name", 0, 0, 'n'}, /* don't save or restore original name & time */
286 {"name", 0, 0, 'N'}, /* save or restore original name & time */
287 {"-presume-input-tty", no_argument, NULL, PRESUME_INPUT_TTY_OPTION},
288 {"quiet", 0, 0, 'q'}, /* quiet mode */
289 {"silent", 0, 0, 'q'}, /* quiet mode */
290 {"synchronous",0, 0, SYNCHRONOUS_OPTION},
291 {"recursive", 0, 0, 'r'}, /* recurse through directories */
292 {"suffix", 1, 0, 'S'}, /* use given suffix instead of .gz */
293 {"test", 0, 0, 't'}, /* test compressed file integrity */
294 {"verbose", 0, 0, 'v'}, /* verbose mode */
295 {"version", 0, 0, 'V'}, /* display version number */
296 {"fast", 0, 0, '1'}, /* compress faster */
297 {"best", 0, 0, '9'}, /* compress better */
298 {"lzw", 0, 0, 'Z'}, /* make output compatible with old compress */
299 {"bits", 1, 0, 'b'}, /* max number of bits per code (implies -Z) */
300 {"rsyncable", 0, 0, RSYNCABLE_OPTION}, /* make rsync-friendly archive */
304 /* local functions */
306 local void try_help (void) ATTRIBUTE_NORETURN;
307 local void help (void);
308 local void license (void);
309 local void version (void);
310 local int input_eof (void);
311 local void treat_stdin (void);
312 local void treat_file (char *iname);
313 local int create_outfile (void);
314 local char *get_suffix (char *name);
315 local int open_input_file (char *iname, struct stat *sbuf);
316 local void discard_input_bytes (size_t nbytes, unsigned int flags);
317 local int make_ofname (void);
318 local void shorten_name (char *name);
319 local int get_method (int in);
320 local void do_list (int ifd, int method);
321 local int check_ofname (void);
322 local void copy_stat (struct stat *ifstat);
323 local void install_signal_handlers (void);
324 local void remove_output_file (void);
325 local RETSIGTYPE abort_gzip_signal (int);
326 local void do_exit (int exitcode) ATTRIBUTE_NORETURN;
327 static void finish_out (void);
328 int main (int argc, char **argv);
329 static int (*work) (int infile, int outfile) = zip; /* function to call */
332 local void treat_dir (int fd, char *dir);
335 #define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
340 fprintf (stderr, "Try `%s --help' for more information.\n",
345 /* ======================================================================== */
348 static char const* const help_msg[] = {
349 "Compress or uncompress FILEs (by default, compress FILES in-place).",
351 "Mandatory arguments to long options are mandatory for short options too.",
354 " -a, --ascii ascii text; convert end-of-line using local conventions",
356 " -c, --stdout write on standard output, keep original files unchanged",
357 " -d, --decompress decompress",
358 /* -e, --encrypt encrypt */
359 " -f, --force force overwrite of output file and compress links",
360 " -h, --help give this help",
361 /* -k, --pkzip force output in pkzip format */
362 " -k, --keep keep (don't delete) input files",
363 " -l, --list list compressed file contents",
364 " -L, --license display software license",
366 " -m do not save or restore the original modification time",
367 " -M, --time save or restore the original modification time",
369 " -n, --no-name do not save or restore the original name and timestamp",
370 " -N, --name save or restore the original name and timestamp",
371 " -q, --quiet suppress all warnings",
373 " -r, --recursive operate recursively on directories",
375 " --rsyncable make rsync-friendly archive",
376 " -S, --suffix=SUF use suffix SUF on compressed files",
377 " --synchronous synchronous output (safer if system crashes, but slower)",
378 " -t, --test test compressed file integrity",
379 " -v, --verbose verbose mode",
380 " -V, --version display version number",
381 " -1, --fast compress faster",
382 " -9, --best compress better",
384 " -Z, --lzw produce output compatible with old compress",
385 " -b, --bits=BITS max number of bits per code (implies -Z)",
388 "With no FILE, or when FILE is -, read standard input.",
390 "Report bugs to <bug-gzip@gnu.org>.",
392 char const *const *p = help_msg;
394 printf ("Usage: %s [OPTION]... [FILE]...\n", program_name);
395 while (*p) printf ("%s\n", *p++);
398 /* ======================================================================== */
401 char const *const *p = license_msg;
403 printf ("%s %s\n", program_name, Version);
404 while (*p) printf ("%s\n", *p++);
407 /* ======================================================================== */
412 printf ("Written by Jean-loup Gailly.\n");
415 local void progerror (char const *string)
418 fprintf (stderr, "%s: ", program_name);
424 /* ======================================================================== */
425 int main (int argc, char **argv)
427 int file_count; /* number of files to process */
428 size_t proglen; /* length of program_name */
433 EXPAND(argc, argv); /* wild card expansion if necessary */
435 program_name = gzip_base_name (argv[0]);
436 proglen = strlen (program_name);
438 /* Suppress .exe for MSDOS and OS/2: */
439 if (4 < proglen && strequ (program_name + proglen - 4, ".exe"))
440 program_name[proglen - 4] = '\0';
442 /* Add options in GZIP environment variable if there is one */
444 env = add_envopt (&env_argc, &argv_copy, OPTIONS_VAR);
445 env_argv = env ? argv_copy : NULL;
448 # define GNU_STANDARD 1
451 /* For compatibility with old compress, use program name as an option.
452 * Unless you compile with -DGNU_STANDARD=0, this program will behave as
453 * gzip even if it is invoked under the name gunzip or zcat.
455 * Systems which do not support links can still use -d or -dc.
456 * Ignore an .exe extension for MSDOS and OS/2.
458 if (strncmp (program_name, "un", 2) == 0 /* ungzip, uncompress */
459 || strncmp (program_name, "gun", 3) == 0) /* gunzip */
461 else if (strequ (program_name + 1, "cat") /* zcat, pcat, gcat */
462 || strequ (program_name, "gzcat")) /* gzcat */
463 decompress = to_stdout = 1;
467 z_len = strlen(z_suffix);
475 if (env_argv[optind] && strequ (env_argv[optind], "--"))
476 optc = ENV_OPTION + '-';
479 optc = getopt_long (env_argc, env_argv, shortopts, longopts,
485 if (optind != env_argc)
488 ("%s: %s: non-option in "OPTIONS_VAR
489 " environment variable\n"),
490 program_name, env_argv[optind]);
494 /* Wait until here before warning, so that GZIP='-q'
496 if (env_argc != 1 && !quiet)
498 ("%s: warning: "OPTIONS_VAR" environment variable"
499 " is deprecated; use an alias or script\n"),
502 /* Start processing ARGC and ARGV instead. */
512 optc = getopt_long (argc, argv, shortopts, longopts, &longind);
520 maxbits = atoi(optarg);
521 for (; *optarg; optarg++)
522 if (! ('0' <= *optarg && *optarg <= '9'))
524 fprintf (stderr, "%s: -b operand is not an integer\n",
530 to_stdout = 1; break;
532 decompress = 1; break;
536 help (); finish_out (); break;
540 list = decompress = to_stdout = 1; break;
542 license (); finish_out (); break;
543 case 'm': /* undocumented, may change later */
545 case 'M': /* undocumented, may change later */
548 case 'n' + ENV_OPTION:
549 no_name = no_time = 1; break;
551 case 'N' + ENV_OPTION:
552 no_name = no_time = 0; break;
553 case PRESUME_INPUT_TTY_OPTION:
554 presume_input_tty = true; break;
556 case 'q' + ENV_OPTION:
557 quiet = 1; verbose = 0; break;
560 fprintf (stderr, "%s: -r not supported on this system\n",
568 case RSYNCABLE_OPTION:
569 case RSYNCABLE_OPTION + ENV_OPTION:
573 #ifdef NO_MULTIPLE_DOTS
574 if (*optarg == '.') optarg++;
576 z_len = strlen(optarg);
579 case SYNCHRONOUS_OPTION:
583 test = decompress = to_stdout = 1;
586 case 'v' + ENV_OPTION:
587 verbose++; quiet = 0; break;
589 version (); finish_out (); break;
594 fprintf(stderr, "%s: -Z not supported in this version\n",
599 case '1' + ENV_OPTION: case '2' + ENV_OPTION: case '3' + ENV_OPTION:
600 case '4' + ENV_OPTION: case '5' + ENV_OPTION: case '6' + ENV_OPTION:
601 case '7' + ENV_OPTION: case '8' + ENV_OPTION: case '9' + ENV_OPTION:
604 case '1': case '2': case '3': case '4':
605 case '5': case '6': case '7': case '8': case '9':
610 if (ENV_OPTION <= optc && optc != ENV_OPTION + '?')
612 /* Output a diagnostic, since getopt_long didn't. */
613 fprintf (stderr, "%s: ", program_name);
615 fprintf (stderr, "-%c: ", optc - ENV_OPTION);
617 fprintf (stderr, "--%s: ", longopts[longind].name);
618 fprintf (stderr, ("option not valid in "OPTIONS_VAR
619 " environment variable\n"));
623 } /* loop on all arguments */
625 /* By default, save name and timestamp on compression but do not
626 * restore them on decompression.
628 if (no_time < 0) no_time = decompress;
629 if (no_name < 0) no_name = decompress;
631 file_count = argc - optind;
635 if (ascii && !quiet) {
636 fprintf(stderr, "%s: option --ascii ignored on this system\n",
640 if (z_len == 0 || z_len > MAX_SUFFIX) {
641 fprintf(stderr, "%s: invalid suffix '%s'\n", program_name, z_suffix);
645 if (do_lzw && !decompress) work = lzw;
647 /* Allocate all global buffers (for DYN_ALLOC option) */
648 ALLOC(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
649 ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
650 ALLOC(ush, d_buf, DIST_BUFSIZE);
651 ALLOC(uch, window, 2L*WSIZE);
653 ALLOC(ush, tab_prefix, 1L<<BITS);
655 ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
656 ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
659 exiting_signal = quiet ? SIGPIPE : 0;
660 install_signal_handlers ();
662 /* And get to work */
663 if (file_count != 0) {
664 if (to_stdout && !test && !list && (!decompress || !ascii)) {
665 SET_BINARY_MODE (STDOUT_FILENO);
667 while (optind < argc) {
668 treat_file(argv[optind++]);
670 } else { /* Standard input */
673 if (stdin_was_read && close (STDIN_FILENO) != 0)
675 strcpy (ifname, "stdin");
680 /* Output any totals, and check for output errors. */
681 if (!quiet && 1 < file_count)
683 if (fflush (stdout) != 0)
688 && fdatasync (STDOUT_FILENO) != 0 && errno != EINVAL)
689 || close (STDOUT_FILENO) != 0)
693 return exit_code; /* just to avoid lint warning */
696 /* Return nonzero when at end of file on input. */
700 if (!decompress || last_member)
705 if (insize != INBUFSIZ || fill_inbuf (1) == EOF)
708 /* Unget the char that fill_inbuf got. */
715 /* ========================================================================
716 * Compress or decompress stdin
718 local void treat_stdin()
721 && (presume_input_tty
722 || isatty (decompress ? STDIN_FILENO : STDOUT_FILENO))) {
723 /* Do not send compressed data to the terminal or read it from
724 * the terminal. We get here when user invoked the program
725 * without parameters, so be helpful. According to the GNU standards:
727 * If there is one behavior you think is most useful when the output
728 * is to a terminal, and another that you think is most useful when
729 * the output is a file or a pipe, then it is usually best to make
730 * the default behavior the one that is useful with output to a
731 * terminal, and have an option for the other behavior.
733 * Here we use the --force option to get the other behavior.
737 ("%s: compressed data not %s a terminal."
738 " Use -f to force %scompression.\n"
739 "For help, type: %s -h\n"),
741 decompress ? "read from" : "written to",
742 decompress ? "de" : "",
747 if (decompress || !ascii) {
748 SET_BINARY_MODE (STDIN_FILENO);
750 if (!test && !list && (!decompress || !ascii)) {
751 SET_BINARY_MODE (STDOUT_FILENO);
753 strcpy(ifname, "stdin");
754 strcpy(ofname, "stdout");
756 /* Get the file's timestamp and size. */
757 if (fstat (STDIN_FILENO, &istat) != 0)
759 progerror ("standard input");
762 ifile_size = S_ISREG (istat.st_mode) ? istat.st_size : -1;
763 time_stamp.tv_nsec = -1;
764 if (!no_time || list)
766 if (S_ISREG (istat.st_mode))
767 time_stamp = get_stat_mtime (&istat);
769 gettime (&time_stamp);
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 ifile_size = S_ISREG (istat.st_mode) ? istat.st_size : -1;
943 time_stamp.tv_nsec = -1;
944 if (!no_time || list)
945 time_stamp = get_stat_mtime (&istat);
947 /* Generate output file name. For -r and (-t or -l), skip files
948 * without a valid gzip suffix (check done in make_ofname).
950 if (to_stdout && !list && !test) {
951 strcpy(ofname, "stdout");
953 } else if (make_ofname() != OK) {
958 clear_bufs(); /* clear input and output buffers */
962 method = get_method(ifd); /* updates ofname if original given */
965 return; /* error message already emitted */
969 do_list(ifd, method);
970 if (close (ifd) != 0)
975 /* If compressing to a file, check if ofname is not ambiguous
976 * because the operating system truncates names. Otherwise, generate
977 * a new ofname and save the original name in the compressed file.
981 /* Keep remove_ofname_fd negative. */
983 if (create_outfile() != OK) return;
985 if (!decompress && save_orig_name && !verbose && !quiet) {
986 fprintf(stderr, "%s: %s compressed to %s\n",
987 program_name, ifname, ofname);
990 /* Keep the name even if not truncated except with --no-name: */
991 if (!save_orig_name) save_orig_name = !no_name;
994 fprintf(stderr, "%s:\t", ifname);
997 /* Actually do the compression/decompression. Loop over zipped members.
1000 if ((*work)(ifd, ofd) != OK) {
1001 method = -1; /* force cleanup */
1008 method = get_method(ifd);
1009 if (method < 0) break; /* error message already emitted */
1010 bytes_out = 0; /* required for length check */
1013 if (close (ifd) != 0)
1021 && ((0 <= dfd && fdatasync (dfd) != 0 && errno != EINVAL)
1022 || (fsync (ofd) != 0 && errno != EINVAL)))
1023 || close (ofd) != 0)
1030 char *ifbase = last_component (ifname);
1031 int ufd = atdir_eq (ifname, ifbase - ifname) ? dfd : -1;
1034 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
1035 remove_ofname_fd = -1;
1036 res = ufd < 0 ? xunlink (ifname) : unlinkat (ufd, ifbase, 0);
1037 unlink_errno = res == 0 ? 0 : errno;
1038 sigprocmask (SIG_SETMASK, &oldset, NULL);
1042 WARN ((stderr, "%s: ", program_name));
1045 errno = unlink_errno;
1054 remove_output_file ();
1058 /* Display statistics */
1061 fprintf(stderr, " OK");
1062 } else if (decompress) {
1063 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
1065 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
1067 if (!test && !to_stdout)
1068 fprintf(stderr, " -- %s %s", keep ? "created" : "replaced with",
1070 fprintf(stderr, "\n");
1074 /* ========================================================================
1075 * Create the output file. Return OK or ERROR.
1076 * Try several times if necessary to avoid truncating the z_suffix. For
1077 * example, do not create a compressed file of name "1234567890123."
1078 * Sets save_orig_name to true if the file name has been truncated.
1079 * IN assertions: the input file has already been open (ifd is set) and
1080 * ofname has already been updated if there was an original name.
1081 * OUT assertions: ifd and ofd are closed in case of error.
1083 local int create_outfile()
1085 int name_shortened = 0;
1086 int flags = (O_WRONLY | O_CREAT | O_EXCL
1087 | (ascii && decompress ? 0 : O_BINARY));
1088 char const *base = ofname;
1089 int atfd = AT_FDCWD;
1093 char const *b = last_component (ofname);
1094 int f = atdir_set (ofname, b - ofname);
1107 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
1108 remove_ofname_fd = ofd = openat (atfd, base, flags, S_IRUSR | S_IWUSR);
1110 sigprocmask (SIG_SETMASK, &oldset, NULL);
1119 shorten_name (ofname);
1125 if (check_ofname () != OK)
1139 if (name_shortened && decompress)
1141 /* name might be too long if an original name was saved */
1142 WARN ((stderr, "%s: %s: warning, name truncated\n",
1143 program_name, ofname));
1149 /* ========================================================================
1150 * Return a pointer to the 'z' suffix of a file name, or NULL. For all
1151 * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
1152 * accepted suffixes, in addition to the value of the --suffix option.
1153 * ".tgz" is a useful convention for tar.z files on systems limited
1154 * to 3 characters extensions. On such systems, ".?z" and ".??z" are
1155 * also accepted suffixes. For Unix, we do not want to accept any
1156 * .??z suffix as indicating a compressed file; some people use .xyz
1157 * to denote volume data.
1159 local char *get_suffix(name)
1163 char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */
1164 static char const *known_suffixes[] =
1165 {NULL, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
1166 #ifdef MAX_EXT_CHARS
1171 bool suffix_of_builtin = false;
1173 /* Normally put Z_SUFFIX at the start of KNOWN_SUFFIXES, but if it
1174 is a suffix of one of them, put it at the end. */
1175 for (suf = known_suffixes + 1; *suf; suf++)
1177 size_t suflen = strlen (*suf);
1178 if (z_len < suflen && strequ (z_suffix, *suf + suflen - z_len))
1180 suffix_of_builtin = true;
1185 char *z_lower = xstrdup(z_suffix);
1187 known_suffixes[suffix_of_builtin
1188 ? sizeof known_suffixes / sizeof *known_suffixes - 2
1190 suf = known_suffixes + suffix_of_builtin;
1192 nlen = strlen(name);
1193 if (nlen <= MAX_SUFFIX+2) {
1194 strcpy(suffix, name);
1196 strcpy(suffix, name+nlen-MAX_SUFFIX-2);
1199 slen = strlen(suffix);
1202 int s = strlen(*suf);
1203 if (slen > s && ! ISSLASH (suffix[slen - s - 1])
1204 && strequ(suffix + slen - s, *suf)) {
1205 match = name+nlen-s;
1208 } while (*++suf != NULL);
1215 /* Open file NAME with the given flags and store its status
1216 into *ST. Return a file descriptor to the newly opened file, or -1
1217 (setting errno) on failure. */
1219 open_and_stat (char *name, int flags, struct stat *st)
1222 int atfd = AT_FDCWD;
1223 char const *base = name;
1225 /* Refuse to follow symbolic links unless -c or -f. */
1226 if (!to_stdout && !force)
1228 if (HAVE_WORKING_O_NOFOLLOW)
1229 flags |= O_NOFOLLOW;
1233 if (lstat (name, st) != 0)
1235 else if (S_ISLNK (st->st_mode))
1246 char const *b = last_component (name);
1247 int f = atdir_set (name, b - name);
1255 fd = openat (atfd, base, flags);
1256 if (0 <= fd && fstat (fd, st) != 0)
1267 /* ========================================================================
1268 * Set ifname to the input file name (with a suffix appended if necessary)
1269 * and istat to its stats. For decompression, if no file exists with the
1270 * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
1271 * For MSDOS, we try only z_suffix and z.
1272 * Return an open file descriptor or -1.
1275 open_input_file (iname, sbuf)
1279 int ilen; /* strlen(ifname) */
1280 int z_suffix_errno = 0;
1281 static char const *suffixes[] = {NULL, ".gz", ".z", "-z", ".Z", NULL};
1282 char const **suf = suffixes;
1284 #ifdef NO_MULTIPLE_DOTS
1285 char *dot; /* pointer to ifname extension, or NULL */
1288 int open_flags = (O_RDONLY | O_NONBLOCK | O_NOCTTY
1289 | (ascii && !decompress ? 0 : O_BINARY));
1293 if (sizeof ifname - 1 <= strlen (iname))
1296 strcpy(ifname, iname);
1298 /* If input file exists, return OK. */
1299 fd = open_and_stat (ifname, open_flags, sbuf);
1303 if (!decompress || errno != ENOENT) {
1307 /* File.ext doesn't exist. Try adding a suffix. */
1308 s = get_suffix(ifname);
1310 progerror(ifname); /* ifname already has z suffix and does not exist */
1313 #ifdef NO_MULTIPLE_DOTS
1314 dot = strrchr(ifname, '.');
1316 strcat(ifname, ".");
1317 dot = strrchr(ifname, '.');
1320 ilen = strlen(ifname);
1321 if (strequ(z_suffix, ".gz")) suf++;
1323 /* Search for all suffixes */
1325 char const *s0 = s = *suf;
1326 strcpy (ifname, iname);
1327 #ifdef NO_MULTIPLE_DOTS
1329 if (*dot == '\0') strcpy (dot, ".");
1331 #ifdef MAX_EXT_CHARS
1332 if (MAX_EXT_CHARS < strlen (s) + strlen (dot + 1))
1333 dot[MAX_EXT_CHARS + 1 - strlen (s)] = '\0';
1335 if (sizeof ifname <= ilen + strlen (s))
1338 fd = open_and_stat (ifname, open_flags, sbuf);
1341 if (errno != ENOENT)
1346 if (strequ (s0, z_suffix))
1347 z_suffix_errno = errno;
1348 } while (*++suf != NULL);
1350 /* No suffix found, complain using z_suffix: */
1351 strcpy(ifname, iname);
1352 #ifdef NO_MULTIPLE_DOTS
1353 if (*dot == '\0') strcpy(dot, ".");
1355 #ifdef MAX_EXT_CHARS
1356 if (MAX_EXT_CHARS < z_len + strlen (dot + 1))
1357 dot[MAX_EXT_CHARS + 1 - z_len] = '\0';
1359 strcat(ifname, z_suffix);
1360 errno = z_suffix_errno;
1365 fprintf (stderr, "%s: %s: file name too long\n", program_name, iname);
1370 /* ========================================================================
1371 * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
1372 * Sets save_orig_name to true if the file name has been truncated.
1374 local int make_ofname()
1376 char *suff; /* ofname z suffix */
1378 strcpy(ofname, ifname);
1379 /* strip a version number if any and get the gzip suffix if present: */
1380 suff = get_suffix(ofname);
1384 /* With -t or -l, try all files (even without .gz suffix)
1385 * except with -r (behave as with just -dr).
1387 if (!recursive && (list || test)) return OK;
1389 /* Avoid annoying messages with -r */
1390 if (verbose || (!recursive && !quiet)) {
1391 WARN((stderr,"%s: %s: unknown suffix -- ignored\n",
1392 program_name, ifname));
1396 /* Make a special case for .tgz and .taz: */
1398 if (strequ(suff, ".tgz") || strequ(suff, ".taz")) {
1399 strcpy(suff, ".tar");
1401 *suff = '\0'; /* strip the z suffix */
1403 /* ofname might be changed later if infile contains an original name */
1405 } else if (suff && ! force) {
1406 /* Avoid annoying messages with -r (see treat_dir()) */
1407 if (verbose || (!recursive && !quiet)) {
1408 /* Don't use WARN, as it affects exit status. */
1409 fprintf (stderr, "%s: %s already has %s suffix -- unchanged\n",
1410 program_name, ifname, suff);
1416 #ifdef NO_MULTIPLE_DOTS
1417 suff = strrchr(ofname, '.');
1419 if (sizeof ofname <= strlen (ofname) + 1)
1421 strcat(ofname, ".");
1422 # ifdef MAX_EXT_CHARS
1423 if (strequ(z_suffix, "z")) {
1424 if (sizeof ofname <= strlen (ofname) + 2)
1426 strcat(ofname, "gz"); /* enough room */
1429 /* On the Atari and some versions of MSDOS,
1430 * ENAMETOOLONG does not work correctly. So we
1431 * must truncate here.
1433 } else if (strlen(suff)-1 + z_len > MAX_SUFFIX) {
1434 suff[MAX_SUFFIX+1-z_len] = '\0';
1438 #endif /* NO_MULTIPLE_DOTS */
1439 if (sizeof ofname <= strlen (ofname) + z_len)
1441 strcat(ofname, z_suffix);
1443 } /* decompress ? */
1447 WARN ((stderr, "%s: %s: file name too long\n", program_name, ifname));
1451 /* Discard NBYTES input bytes from the input, or up through the next
1452 zero byte if NBYTES == (size_t) -1. If FLAGS say that the header
1453 CRC should be computed, update the CRC accordingly. */
1455 discard_input_bytes (nbytes, flags)
1461 uch c = get_byte ();
1462 if (flags & HEADER_CRC)
1464 if (nbytes != (size_t) -1)
1471 /* ========================================================================
1472 * Check the magic number of the input file and update ofname if an
1473 * original name was given and to_stdout is not set.
1474 * Return the compression method, -1 for error, -2 for warning.
1475 * Set inptr to the offset of the next byte to be processed.
1476 * Updates time_stamp if there is one and neither -m nor -n is used.
1477 * This function may be called repeatedly for an input file consisting
1478 * of several contiguous gzip'ed members.
1479 * IN assertions: there is at least one remaining compressed member.
1480 * If the member is a zip file, it must be the only one.
1482 local int get_method(in)
1483 int in; /* input file descriptor */
1485 uch flags; /* compression flags */
1486 uch magic[10]; /* magic header */
1487 int imagic0; /* first magic byte or EOF */
1488 int imagic1; /* like magic[1], but can represent EOF */
1489 ulg stamp; /* timestamp */
1491 /* If --force and --stdout, zcat == cat, so do not complain about
1492 * premature end of file: use try_byte instead of get_byte.
1494 if (force && to_stdout) {
1495 imagic0 = try_byte();
1497 imagic1 = try_byte ();
1499 /* If try_byte returned EOF, magic[1] == (char) EOF. */
1501 magic[0] = get_byte ();
1504 magic[1] = get_byte ();
1505 imagic1 = 0; /* avoid lint warning */
1507 imagic1 = try_byte ();
1511 method = -1; /* unknown yet */
1512 part_nb++; /* number of parts in gzip file */
1515 /* assume multiple members in gzip file except for record oriented I/O */
1517 if (memcmp(magic, GZIP_MAGIC, 2) == 0
1518 || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
1520 method = (int)get_byte();
1521 if (method != DEFLATED) {
1523 "%s: %s: unknown method %d -- not supported\n",
1524 program_name, ifname, method);
1529 flags = (uch)get_byte();
1531 if ((flags & ENCRYPTED) != 0) {
1533 "%s: %s is encrypted -- not supported\n",
1534 program_name, ifname);
1538 if ((flags & RESERVED) != 0) {
1540 "%s: %s has flags 0x%x -- not supported\n",
1541 program_name, ifname, flags);
1543 if (force <= 1) return -1;
1545 stamp = (ulg)get_byte();
1546 stamp |= ((ulg)get_byte()) << 8;
1547 stamp |= ((ulg)get_byte()) << 16;
1548 stamp |= ((ulg)get_byte()) << 24;
1549 if (!no_time && 0 < stamp && stamp <= TYPE_MAXIMUM (time_t))
1551 time_stamp.tv_sec = stamp;
1552 time_stamp.tv_nsec = 0;
1555 magic[8] = get_byte (); /* Ignore extra flags. */
1556 magic[9] = get_byte (); /* Ignore OS type. */
1558 if (flags & HEADER_CRC)
1560 magic[2] = DEFLATED;
1562 magic[4] = stamp & 0xff;
1563 magic[5] = (stamp >> 8) & 0xff;
1564 magic[6] = (stamp >> 16) & 0xff;
1565 magic[7] = stamp >> 24;
1570 if ((flags & EXTRA_FIELD) != 0) {
1572 unsigned int len = lenbuf[0] = get_byte ();
1573 len |= (lenbuf[1] = get_byte ()) << 8;
1575 fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n",
1576 program_name, ifname, len);
1578 if (flags & HEADER_CRC)
1580 discard_input_bytes (len, flags);
1583 /* Get original file name if it was truncated */
1584 if ((flags & ORIG_NAME) != 0) {
1585 if (no_name || (to_stdout && !list) || part_nb > 1) {
1586 /* Discard the old name */
1587 discard_input_bytes (-1, flags);
1589 /* Copy the base name. Keep a directory prefix intact. */
1590 char *p = gzip_base_name (ofname);
1593 *p = (char) get_byte ();
1594 if (*p++ == '\0') break;
1595 if (p >= ofname+sizeof(ofname)) {
1596 gzip_error ("corrupted input -- file name too large");
1599 if (flags & HEADER_CRC)
1600 updcrc ((uch *) base, p - base);
1601 p = gzip_base_name (base);
1602 memmove (base, p, strlen (p) + 1);
1603 /* If necessary, adapt the name to local OS conventions: */
1605 MAKE_LEGAL_NAME(base);
1606 if (base) list=0; /* avoid warning about unused variable */
1608 } /* no_name || to_stdout */
1611 /* Discard file comment if any */
1612 if ((flags & COMMENT) != 0) {
1613 discard_input_bytes (-1, flags);
1616 if (flags & HEADER_CRC)
1618 unsigned int crc16 = updcrc (magic, 0) & 0xffff;
1619 unsigned int header16 = get_byte ();
1620 header16 |= ((unsigned int) get_byte ()) << 8;
1621 if (header16 != crc16)
1624 "%s: %s: header checksum 0x%04x != computed checksum 0x%04x\n",
1625 program_name, ifname, header16, crc16);
1633 header_bytes = inptr + 2*4; /* include crc and size */
1636 } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
1637 && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0) {
1638 /* To simplify the code, we support a zip file when alone only.
1639 * We are thus guaranteed that the entire local header fits in inbuf.
1643 if (check_zipfile(in) != OK) return -1;
1644 /* check_zipfile may get ofname from the local header */
1647 } else if (memcmp(magic, PACK_MAGIC, 2) == 0) {
1651 } else if (memcmp(magic, LZW_MAGIC, 2) == 0) {
1653 method = COMPRESSED;
1656 } else if (memcmp(magic, LZH_MAGIC, 2) == 0) {
1661 } else if (force && to_stdout && !list) { /* pass input unchanged */
1667 if (imagic0 != EOF) {
1668 write_buf (STDOUT_FILENO, magic, 1);
1672 if (method >= 0) return method;
1675 fprintf (stderr, "\n%s: %s: not in gzip format\n",
1676 program_name, ifname);
1683 for (inbyte = imagic1; inbyte == 0; inbyte = try_byte ())
1688 WARN ((stderr, "\n%s: %s: decompression OK, trailing zero bytes ignored\n",
1689 program_name, ifname));
1694 WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n",
1695 program_name, ifname));
1700 /* ========================================================================
1701 * Display the characteristics of the compressed file.
1702 * If the given method is < 0, display the accumulated totals.
1703 * IN assertions: time_stamp, header_bytes and ifile_size are initialized.
1705 local void do_list(ifd, method)
1706 int ifd; /* input file descriptor */
1707 int method; /* compression method */
1709 ulg crc; /* original crc */
1710 static int first_time = 1;
1711 static char const *const methods[MAX_METHODS] = {
1716 "", "", "", "", /* 4 to 7 reserved */
1718 int positive_off_t_width = 1;
1721 for (o = OFF_T_MAX; 9 < o; o /= 10) {
1722 positive_off_t_width++;
1725 if (first_time && method >= 0) {
1728 printf("method crc date time ");
1731 printf("%*.*s %*.*s ratio uncompressed_name\n",
1732 positive_off_t_width, positive_off_t_width, "compressed",
1733 positive_off_t_width, positive_off_t_width, "uncompressed");
1735 } else if (method < 0) {
1736 if (total_in <= 0 || total_out <= 0) return;
1740 if (verbose || !quiet) {
1741 fprint_off(stdout, total_in, positive_off_t_width);
1743 fprint_off(stdout, total_out, positive_off_t_width);
1746 display_ratio(total_out-(total_in-header_bytes), total_out, stdout);
1747 /* header_bytes is not meaningful but used to ensure the same
1748 * ratio if there is a single file.
1750 printf(" (totals)\n");
1753 crc = (ulg)~0; /* unknown */
1755 bytes_in = ifile_size;
1757 if (method == DEFLATED && !last_member) {
1758 /* Get the crc and uncompressed size for gzip'ed (not zip'ed) files.
1759 * If the lseek fails, we could use read() to get to the end, but
1760 * --list is used to get quick results.
1761 * Use "gunzip < foo.gz | wc -c" to get the uncompressed size if
1762 * you are not concerned about speed.
1764 bytes_in = lseek(ifd, (off_t)(-8), SEEK_END);
1765 if (bytes_in != -1L) {
1768 if (read(ifd, (char*)buf, sizeof(buf)) != sizeof(buf)) {
1772 bytes_out = LG(buf+4);
1778 static char const month_abbr[][4]
1779 = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1780 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
1781 struct tm *tm = (time_stamp.tv_nsec < 0
1783 : localtime (&time_stamp.tv_sec));
1784 printf ("%5s %08lx ", methods[method], crc);
1786 printf ("%s%3d %02d:%02d ", month_abbr[tm->tm_mon],
1787 tm->tm_mday, tm->tm_hour, tm->tm_min);
1789 printf ("??? ?? ??:?? ");
1791 fprint_off(stdout, bytes_in, positive_off_t_width);
1793 fprint_off(stdout, bytes_out, positive_off_t_width);
1795 if (bytes_in == -1L) {
1797 bytes_in = bytes_out = header_bytes = 0;
1798 } else if (total_in >= 0) {
1799 total_in += bytes_in;
1801 if (bytes_out == -1L) {
1803 bytes_in = bytes_out = header_bytes = 0;
1804 } else if (total_out >= 0) {
1805 total_out += bytes_out;
1807 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out, stdout);
1808 printf(" %s\n", ofname);
1811 /* ========================================================================
1812 * Shorten the given name by one character, or replace a .tar extension
1813 * with .tgz. Truncate the last part of the name which is longer than
1814 * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
1815 * has only parts shorter than MIN_PART truncate the longest part.
1816 * For decompression, just remove the last character of the name.
1818 * IN assertion: for compression, the suffix of the given name is z_suffix.
1820 local void shorten_name(name)
1823 int len; /* length of name without z_suffix */
1824 char *trunc = NULL; /* character to be truncated */
1825 int plen; /* current part length */
1826 int min_part = MIN_PART; /* current minimum part length */
1832 gzip_error ("name too short");
1836 p = get_suffix(name);
1838 gzip_error ("can't recover suffix\n");
1842 /* compress 1234567890.tar to 1234567890.tgz */
1843 if (len > 4 && strequ(p-4, ".tar")) {
1844 strcpy(p-4, ".tgz");
1847 /* Try keeping short extensions intact:
1848 * 1234.678.012.gz -> 123.678.012.gz
1851 p = last_component (name);
1853 plen = strcspn(p, PART_SEP);
1855 if (plen > min_part) trunc = p-1;
1858 } while (trunc == NULL && --min_part != 0);
1860 if (trunc != NULL) {
1862 trunc[0] = trunc[1];
1866 trunc = strrchr(name, PART_SEP[0]);
1868 gzip_error ("internal error in shorten_name");
1869 if (trunc[1] == '\0') trunc--; /* force truncation */
1871 strcpy(trunc, z_suffix);
1874 /* ========================================================================
1875 * The compressed file already exists, so ask for confirmation.
1876 * Return ERROR if the file must be skipped.
1878 local int check_ofname()
1880 /* Ask permission to overwrite the existing file */
1883 fprintf (stderr, "%s: %s already exists;", program_name, ofname);
1884 if (foreground && (presume_input_tty || isatty (STDIN_FILENO))) {
1885 fprintf(stderr, " do you wish to overwrite (y or n)? ");
1890 fprintf(stderr, "\tnot overwritten\n");
1891 if (exit_code == OK) exit_code = WARNING;
1895 if (xunlink (ofname)) {
1902 /* Change the owner and group of a file. FD is a file descriptor for
1903 the file and NAME its name. Change it to user UID and to group GID.
1904 If UID or GID is -1, though, do not change the corresponding user
1907 do_chown (int fd, char const *name, uid_t uid, gid_t gid)
1911 ignore_value (fchown (fd, uid, gid));
1913 ignore_value (chown (name, uid, gid));
1918 /* ========================================================================
1919 * Copy modes, times, ownership from input file to output file.
1920 * IN assertion: to_stdout is false.
1922 local void copy_stat(ifstat)
1923 struct stat *ifstat;
1925 mode_t mode = ifstat->st_mode & S_IRWXUGO;
1930 struct timespec timespec[2];
1931 timespec[0] = get_stat_atime (ifstat);
1932 timespec[1] = get_stat_mtime (ifstat);
1933 restoring = (decompress && 0 <= time_stamp.tv_nsec
1934 && ! (timespec[1].tv_sec == time_stamp.tv_sec
1935 && timespec[1].tv_nsec == time_stamp.tv_nsec));
1937 timespec[1] = time_stamp;
1939 if (fdutimens (ofd, ofname, timespec) == 0)
1941 if (restoring && 1 < verbose) {
1942 fprintf(stderr, "%s: timestamp restored\n", ofname);
1948 WARN ((stderr, "%s: ", program_name));
1957 /* Change the group first, then the permissions, then the owner.
1958 That way, the permissions will be correct on systems that allow
1959 users to give away files, without introducing a security hole.
1960 Security depends on permissions not containing the setuid or
1963 do_chown (ofd, ofname, -1, ifstat->st_gid);
1966 r = fchmod (ofd, mode);
1968 r = chmod (ofname, mode);
1972 WARN ((stderr, "%s: ", program_name));
1979 do_chown (ofd, ofname, ifstat->st_uid, -1);
1984 /* ========================================================================
1985 * Recurse through the given directory.
1987 local void treat_dir (fd, dir)
1992 char nbuf[MAX_PATH_LEN];
1997 dirp = fdopendir (fd);
2005 entries = streamsavedir (dirp, SAVEDIR_SORT_NONE);
2008 if (closedir (dirp) != 0)
2013 for (entry = entries; *entry; entry += entrylen + 1) {
2014 size_t len = strlen (dir);
2015 entrylen = strlen (entry);
2016 if (strequ (entry, ".") || strequ (entry, ".."))
2018 if (len + entrylen < MAX_PATH_LEN - 2) {
2020 if (*last_component (nbuf) && !ISSLASH (nbuf[len - 1]))
2022 strcpy (nbuf + len, entry);
2025 fprintf(stderr,"%s: %s/%s: pathname too long\n",
2026 program_name, dir, entry);
2032 #endif /* ! NO_DIR */
2034 /* Make sure signals get handled properly. */
2037 install_signal_handlers ()
2039 int nsigs = sizeof handled_sig / sizeof handled_sig[0];
2043 struct sigaction act;
2045 sigemptyset (&caught_signals);
2046 for (i = 0; i < nsigs; i++)
2048 sigaction (handled_sig[i], NULL, &act);
2049 if (act.sa_handler != SIG_IGN)
2050 sigaddset (&caught_signals, handled_sig[i]);
2053 act.sa_handler = abort_gzip_signal;
2054 act.sa_mask = caught_signals;
2057 for (i = 0; i < nsigs; i++)
2058 if (sigismember (&caught_signals, handled_sig[i]))
2062 sigaction (handled_sig[i], &act, NULL);
2065 for (i = 0; i < nsigs; i++)
2066 if (signal (handled_sig[i], SIG_IGN) != SIG_IGN)
2070 signal (handled_sig[i], abort_gzip_signal);
2071 siginterrupt (handled_sig[i], 1);
2076 /* ========================================================================
2077 * Free all dynamically allocated variables and exit with the given code.
2079 local void do_exit(exitcode)
2082 static int in_exit = 0;
2084 if (in_exit) exit(exitcode);
2104 if (fclose (stdout) != 0)
2109 /* ========================================================================
2110 * Close and unlink the output file.
2113 remove_output_file ()
2118 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
2119 fd = remove_ofname_fd;
2122 remove_ofname_fd = -1;
2126 sigprocmask (SIG_SETMASK, &oldset, NULL);
2129 /* ========================================================================
2135 remove_output_file ();
2139 /* ========================================================================
2143 abort_gzip_signal (sig)
2147 signal (sig, SIG_IGN);
2148 remove_output_file ();
2149 if (sig == exiting_signal)
2151 signal (sig, SIG_DFL);