1 /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
3 Copyright (C) 1999, 2001-2002, 2006-2007, 2009-2016 Free Software
5 Copyright (C) 1992-1993 Jean-loup Gailly
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software Foundation,
19 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
22 * The unzip code was written and put in the public domain by Mark Adler.
23 * Portions of the lzw code are derived from the public domain 'compress'
24 * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
25 * Ken Turkowski, Dave Mack and Peter Jannesen.
27 * See the license_msg below and the file COPYING for the software license.
28 * See the file algorithm.doc for the compression algorithms and file formats.
31 static char const *const license_msg[] = {
32 "Copyright (C) 2016 Free Software Foundation, Inc.",
33 "Copyright (C) 1993 Jean-loup Gailly.",
34 "This is free software. You may redistribute copies of it under the terms of",
35 "the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.",
36 "There is NO WARRANTY, to the extent permitted by law.",
39 /* Compress files with zip algorithm and 'compress' interface.
40 * See help() function below for all options.
42 * file.gz: compressed file with same mode, owner, and utimes
43 * or stdout with -c option or if stdin used as input.
44 * If the output file name had to be truncated, the original name is kept
45 * in the compressed file.
46 * On MSDOS, file.tmp -> file.tmz. On VMS, file.tmp -> file.tmp-gz.
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>
76 #include "ignore-value.h"
77 #include "stat-time.h"
101 # define MAX_PATH_LEN 1024 /* max pathname length */
113 off_t lseek (int fd, off_t offset, int whence);
117 # define OFF_T_MAX TYPE_MAXIMUM (off_t)
120 /* Use SA_NOCLDSTOP as a proxy for whether the sigaction machinery is
123 # define SA_NOCLDSTOP 0
124 # define sigprocmask(how, set, oset) /* empty */
125 # define sigset_t int
126 # if ! HAVE_SIGINTERRUPT
127 # define siginterrupt(sig, flag) /* empty */
131 #ifndef HAVE_WORKING_O_NOFOLLOW
132 # define HAVE_WORKING_O_NOFOLLOW 0
135 /* Separator for file name parts (see shorten_name()) */
136 #ifdef NO_MULTIPLE_DOTS
137 # define PART_SEP "-"
139 # define PART_SEP "."
144 DECLARE(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
145 DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
146 DECLARE(ush, d_buf, DIST_BUFSIZE);
147 DECLARE(uch, window, 2L*WSIZE);
149 DECLARE(ush, tab_prefix, 1L<<BITS);
151 DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
152 DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
155 /* local variables */
157 /* If true, pretend that standard input is a tty. This option
158 is deliberately not documented, and only for testing. */
159 static bool presume_input_tty;
161 /* If true, transfer output data to the output file's storage device
162 when supported. Otherwise, if the system crashes around the time
163 gzip is run, the user might lose both input and output data. See:
164 Pillai TS et al. All file systems are not created equal: on the
165 complexity of crafting crash-consistent applications. OSDI'14. 2014:433-48.
166 https://www.usenix.org/conference/osdi14/technical-sessions/presentation/pillai */
167 static bool synchronous;
169 static int ascii = 0; /* convert end-of-lines to local OS conventions */
170 int to_stdout = 0; /* output to stdout (-c) */
171 static int decompress = 0; /* decompress (-d) */
172 static int force = 0; /* don't ask questions, compress links (-f) */
173 static int keep = 0; /* keep (don't delete) input files */
174 static int no_name = -1; /* don't save or restore the original file name */
175 static int no_time = -1; /* don't save or restore the original file time */
176 static int recursive = 0; /* recurse through directories (-r) */
177 static int list = 0; /* list the file contents (-l) */
178 int verbose = 0; /* be verbose (-v) */
179 int quiet = 0; /* be very quiet (-q) */
180 static int do_lzw = 0; /* generate output compatible with old compress (-Z) */
181 int test = 0; /* test .gz file integrity */
182 static int foreground = 0; /* set if program run in foreground */
183 char *program_name; /* program name */
184 int maxbits = BITS; /* max bits per code for LZW */
185 int method = DEFLATED;/* compression method */
186 int level = 6; /* compression level */
187 int exit_code = OK; /* program exit code */
188 int save_orig_name; /* set if original name must be saved */
189 static int last_member; /* set for .zip and .Z files */
190 static int part_nb; /* number of parts in .gz file */
191 struct timespec time_stamp; /* original time stamp (modification time) */
192 off_t ifile_size; /* input file size, -1 for devices (debug only) */
193 static char *env; /* contents of GZIP env variable */
194 static char const *z_suffix; /* default suffix (can be set with --suffix) */
195 static size_t z_len; /* strlen(z_suffix) */
197 /* The set of signals that are caught. */
198 static sigset_t caught_signals;
200 /* If nonzero then exit with status WARNING, rather than with the usual
201 signal status, on receipt of a signal with this value. This
202 suppresses a "Broken Pipe" message with some shells. */
203 static int volatile exiting_signal;
205 /* If nonnegative, close this file descriptor and unlink ofname on error. */
206 static int volatile remove_ofname_fd = -1;
208 static bool stdin_was_read;
210 off_t bytes_in; /* number of input bytes */
211 off_t bytes_out; /* number of output bytes */
212 static off_t total_in; /* input bytes for all files */
213 static off_t total_out; /* output bytes for all files */
214 char ifname[MAX_PATH_LEN]; /* input file name */
215 char ofname[MAX_PATH_LEN]; /* output file name */
216 static char dfname[MAX_PATH_LEN]; /* name of dir containing output file */
217 static struct stat istat; /* status for input file */
218 int ifd; /* input file descriptor */
219 int ofd; /* output file descriptor */
220 static int dfd = -1; /* output directory file descriptor */
221 unsigned insize; /* valid bytes in inbuf */
222 unsigned inptr; /* index of next byte to be processed in inbuf */
223 unsigned outcnt; /* bytes in output buffer */
224 int rsync = 0; /* make ryncable chunks */
226 static int handled_sig[] =
228 /* SIGINT must be first, as 'foreground' depends on it. */
248 /* For long options that have no equivalent short option, use a
249 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
252 PRESUME_INPUT_TTY_OPTION = CHAR_MAX + 1,
256 /* A value greater than all valid long options, used as a flag to
257 distinguish options derived from the GZIP environment variable. */
261 static char const shortopts[] = "ab:cdfhH?klLmMnNqrS:tvVZ123456789";
263 static const struct option longopts[] =
265 /* { name has_arg *flag val } */
266 {"ascii", 0, 0, 'a'}, /* ascii text mode */
267 {"to-stdout", 0, 0, 'c'}, /* write output on standard output */
268 {"stdout", 0, 0, 'c'}, /* write output on standard output */
269 {"decompress", 0, 0, 'd'}, /* decompress */
270 {"uncompress", 0, 0, 'd'}, /* decompress */
271 /* {"encrypt", 0, 0, 'e'}, encrypt */
272 {"force", 0, 0, 'f'}, /* force overwrite of output file */
273 {"help", 0, 0, 'h'}, /* give help */
274 /* {"pkzip", 0, 0, 'k'}, force output in pkzip format */
275 {"keep", 0, 0, 'k'}, /* keep (don't delete) input files */
276 {"list", 0, 0, 'l'}, /* list .gz file contents */
277 {"license", 0, 0, 'L'}, /* display software license */
278 {"no-name", 0, 0, 'n'}, /* don't save or restore original name & time */
279 {"name", 0, 0, 'N'}, /* save or restore original name & time */
280 {"-presume-input-tty", no_argument, NULL, PRESUME_INPUT_TTY_OPTION},
281 {"quiet", 0, 0, 'q'}, /* quiet mode */
282 {"silent", 0, 0, 'q'}, /* quiet mode */
283 {"synchronous",0, 0, SYNCHRONOUS_OPTION},
284 {"recursive", 0, 0, 'r'}, /* recurse through directories */
285 {"suffix", 1, 0, 'S'}, /* use given suffix instead of .gz */
286 {"test", 0, 0, 't'}, /* test compressed file integrity */
287 {"no-time", 0, 0, 'T'}, /* don't save or restore the time stamp */
288 {"verbose", 0, 0, 'v'}, /* verbose mode */
289 {"version", 0, 0, 'V'}, /* display version number */
290 {"fast", 0, 0, '1'}, /* compress faster */
291 {"best", 0, 0, '9'}, /* compress better */
292 {"lzw", 0, 0, 'Z'}, /* make output compatible with old compress */
293 {"bits", 1, 0, 'b'}, /* max number of bits per code (implies -Z) */
294 {"rsyncable", 0, 0, RSYNCABLE_OPTION}, /* make rsync-friendly archive */
298 /* local functions */
300 local void try_help (void) ATTRIBUTE_NORETURN;
301 local void help (void);
302 local void license (void);
303 local void version (void);
304 local int input_eof (void);
305 local void treat_stdin (void);
306 local void treat_file (char *iname);
307 local int create_outfile (void);
308 local char *get_suffix (char *name);
309 local int open_input_file (char *iname, struct stat *sbuf);
310 local void discard_input_bytes (size_t nbytes, unsigned int flags);
311 local int make_ofname (void);
312 local void shorten_name (char *name);
313 local int get_method (int in);
314 local void do_list (int ifd, int method);
315 local int check_ofname (void);
316 local void copy_stat (struct stat *ifstat);
317 local void install_signal_handlers (void);
318 local void remove_output_file (void);
319 local RETSIGTYPE abort_gzip_signal (int);
320 local void do_exit (int exitcode) ATTRIBUTE_NORETURN;
321 static void finish_out (void);
322 int main (int argc, char **argv);
323 static int (*work) (int infile, int outfile) = zip; /* function to call */
326 local void treat_dir (int fd, char *dir);
329 #define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
334 fprintf (stderr, "Try `%s --help' for more information.\n",
339 /* ======================================================================== */
342 static char const* const help_msg[] = {
343 "Compress or uncompress FILEs (by default, compress FILES in-place).",
345 "Mandatory arguments to long options are mandatory for short options too.",
348 " -a, --ascii ascii text; convert end-of-line using local conventions",
350 " -c, --stdout write on standard output, keep original files unchanged",
351 " -d, --decompress decompress",
352 /* -e, --encrypt encrypt */
353 " -f, --force force overwrite of output file and compress links",
354 " -h, --help give this help",
355 /* -k, --pkzip force output in pkzip format */
356 " -k, --keep keep (don't delete) input files",
357 " -l, --list list compressed file contents",
358 " -L, --license display software license",
360 " -m, --no-time do not save or restore the original modification time",
361 " -M, --time save or restore the original modification time",
363 " -n, --no-name do not save or restore the original name and time stamp",
364 " -N, --name save or restore the original name and time stamp",
365 " -q, --quiet suppress all warnings",
367 " -r, --recursive operate recursively on directories",
369 " --rsyncable make rsync-friendly archive",
370 " -S, --suffix=SUF use suffix SUF on compressed files",
371 " --synchronous synchronous output (safer if system crashes, but slower)",
372 " -t, --test test compressed file integrity",
373 " -v, --verbose verbose mode",
374 " -V, --version display version number",
375 " -1, --fast compress faster",
376 " -9, --best compress better",
378 " -Z, --lzw produce output compatible with old compress",
379 " -b, --bits=BITS max number of bits per code (implies -Z)",
382 "With no FILE, or when FILE is -, read standard input.",
384 "Report bugs to <bug-gzip@gnu.org>.",
386 char const *const *p = help_msg;
388 printf ("Usage: %s [OPTION]... [FILE]...\n", program_name);
389 while (*p) printf ("%s\n", *p++);
392 /* ======================================================================== */
395 char const *const *p = license_msg;
397 printf ("%s %s\n", program_name, Version);
398 while (*p) printf ("%s\n", *p++);
401 /* ======================================================================== */
406 printf ("Written by Jean-loup Gailly.\n");
409 local void progerror (char const *string)
412 fprintf (stderr, "%s: ", program_name);
418 /* ======================================================================== */
419 int main (int argc, char **argv)
421 int file_count; /* number of files to process */
422 size_t proglen; /* length of program_name */
427 EXPAND(argc, argv); /* wild card expansion if necessary */
429 program_name = gzip_base_name (argv[0]);
430 proglen = strlen (program_name);
432 /* Suppress .exe for MSDOS, OS/2 and VMS: */
433 if (4 < proglen && strequ (program_name + proglen - 4, ".exe"))
434 program_name[proglen - 4] = '\0';
436 /* Add options in GZIP environment variable if there is one */
438 env = add_envopt (&env_argc, &argv_copy, OPTIONS_VAR);
439 env_argv = env ? argv_copy : NULL;
442 # define GNU_STANDARD 1
445 /* For compatibility with old compress, use program name as an option.
446 * Unless you compile with -DGNU_STANDARD=0, this program will behave as
447 * gzip even if it is invoked under the name gunzip or zcat.
449 * Systems which do not support links can still use -d or -dc.
450 * Ignore an .exe extension for MSDOS, OS/2 and VMS.
452 if (strncmp (program_name, "un", 2) == 0 /* ungzip, uncompress */
453 || strncmp (program_name, "gun", 3) == 0) /* gunzip */
455 else if (strequ (program_name + 1, "cat") /* zcat, pcat, gcat */
456 || strequ (program_name, "gzcat")) /* gzcat */
457 decompress = to_stdout = 1;
461 z_len = strlen(z_suffix);
469 if (env_argv[optind] && strequ (env_argv[optind], "--"))
470 optc = ENV_OPTION + '-';
473 optc = getopt_long (env_argc, env_argv, shortopts, longopts,
479 if (optind != env_argc)
482 ("%s: %s: non-option in "OPTIONS_VAR
483 " environment variable\n"),
484 program_name, env_argv[optind]);
488 /* Wait until here before warning, so that GZIP='-q'
490 if (env_argc != 1 && !quiet)
492 ("%s: warning: "OPTIONS_VAR" environment variable"
493 " is deprecated; use an alias or script\n"),
496 /* Start processing ARGC and ARGV instead. */
506 optc = getopt_long (argc, argv, shortopts, longopts, &longind);
514 maxbits = atoi(optarg);
515 for (; *optarg; optarg++)
516 if (! ('0' <= *optarg && *optarg <= '9'))
518 fprintf (stderr, "%s: -b operand is not an integer\n",
524 to_stdout = 1; break;
526 decompress = 1; break;
530 help (); finish_out (); break;
534 list = decompress = to_stdout = 1; break;
536 license (); finish_out (); break;
537 case 'm': /* undocumented, may change later */
539 case 'M': /* undocumented, may change later */
542 case 'n' + ENV_OPTION:
543 no_name = no_time = 1; break;
545 case 'N' + ENV_OPTION:
546 no_name = no_time = 0; break;
547 case PRESUME_INPUT_TTY_OPTION:
548 presume_input_tty = true; break;
550 case 'q' + ENV_OPTION:
551 quiet = 1; verbose = 0; break;
554 fprintf (stderr, "%s: -r not supported on this system\n",
562 case RSYNCABLE_OPTION:
563 case RSYNCABLE_OPTION + ENV_OPTION:
567 #ifdef NO_MULTIPLE_DOTS
568 if (*optarg == '.') optarg++;
570 z_len = strlen(optarg);
573 case SYNCHRONOUS_OPTION:
577 test = decompress = to_stdout = 1;
580 case 'v' + ENV_OPTION:
581 verbose++; quiet = 0; break;
583 version (); finish_out (); break;
588 fprintf(stderr, "%s: -Z not supported in this version\n",
593 case '1' + ENV_OPTION: case '2' + ENV_OPTION: case '3' + ENV_OPTION:
594 case '4' + ENV_OPTION: case '5' + ENV_OPTION: case '6' + ENV_OPTION:
595 case '7' + ENV_OPTION: case '8' + ENV_OPTION: case '9' + ENV_OPTION:
598 case '1': case '2': case '3': case '4':
599 case '5': case '6': case '7': case '8': case '9':
604 if (ENV_OPTION <= optc && optc != ENV_OPTION + '?')
606 /* Output a diagnostic, since getopt_long didn't. */
607 fprintf (stderr, "%s: ", program_name);
609 fprintf (stderr, "-%c: ", optc - ENV_OPTION);
611 fprintf (stderr, "--%s: ", longopts[longind].name);
612 fprintf (stderr, ("option not valid in "OPTIONS_VAR
613 " environment variable\n"));
617 } /* loop on all arguments */
619 /* By default, save name and timestamp on compression but do not
620 * restore them on decompression.
622 if (no_time < 0) no_time = decompress;
623 if (no_name < 0) no_name = decompress;
625 file_count = argc - optind;
629 if (ascii && !quiet) {
630 fprintf(stderr, "%s: option --ascii ignored on this system\n",
634 if (z_len == 0 || z_len > MAX_SUFFIX) {
635 fprintf(stderr, "%s: invalid suffix '%s'\n", program_name, z_suffix);
639 if (do_lzw && !decompress) work = lzw;
641 /* Allocate all global buffers (for DYN_ALLOC option) */
642 ALLOC(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
643 ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
644 ALLOC(ush, d_buf, DIST_BUFSIZE);
645 ALLOC(uch, window, 2L*WSIZE);
647 ALLOC(ush, tab_prefix, 1L<<BITS);
649 ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
650 ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
653 exiting_signal = quiet ? SIGPIPE : 0;
654 install_signal_handlers ();
656 /* And get to work */
657 if (file_count != 0) {
658 if (to_stdout && !test && !list && (!decompress || !ascii)) {
659 SET_BINARY_MODE (STDOUT_FILENO);
661 while (optind < argc) {
662 treat_file(argv[optind++]);
664 } else { /* Standard input */
667 if (stdin_was_read && close (STDIN_FILENO) != 0)
669 strcpy (ifname, "stdin");
674 /* Output any totals, and check for output errors. */
675 if (!quiet && 1 < file_count)
677 if (fflush (stdout) != 0)
682 && fdatasync (STDOUT_FILENO) != 0 && errno != EINVAL)
683 || close (STDOUT_FILENO) != 0)
687 return exit_code; /* just to avoid lint warning */
690 /* Return nonzero when at end of file on input. */
694 if (!decompress || last_member)
699 if (insize != INBUFSIZ || fill_inbuf (1) == EOF)
702 /* Unget the char that fill_inbuf got. */
709 /* ========================================================================
710 * Compress or decompress stdin
712 local void treat_stdin()
715 && (presume_input_tty
716 || isatty (decompress ? STDIN_FILENO : STDOUT_FILENO))) {
717 /* Do not send compressed data to the terminal or read it from
718 * the terminal. We get here when user invoked the program
719 * without parameters, so be helpful. According to the GNU standards:
721 * If there is one behavior you think is most useful when the output
722 * is to a terminal, and another that you think is most useful when
723 * the output is a file or a pipe, then it is usually best to make
724 * the default behavior the one that is useful with output to a
725 * terminal, and have an option for the other behavior.
727 * Here we use the --force option to get the other behavior.
731 ("%s: compressed data not %s a terminal."
732 " Use -f to force %scompression.\n"
733 "For help, type: %s -h\n"),
735 decompress ? "read from" : "written to",
736 decompress ? "de" : "",
741 if (decompress || !ascii) {
742 SET_BINARY_MODE (STDIN_FILENO);
744 if (!test && !list && (!decompress || !ascii)) {
745 SET_BINARY_MODE (STDOUT_FILENO);
747 strcpy(ifname, "stdin");
748 strcpy(ofname, "stdout");
750 /* Get the file's time stamp and size. */
751 if (fstat (STDIN_FILENO, &istat) != 0)
753 progerror ("standard input");
756 ifile_size = S_ISREG (istat.st_mode) ? istat.st_size : -1;
757 time_stamp.tv_nsec = -1;
758 if (!no_time || list)
760 if (S_ISREG (istat.st_mode))
761 time_stamp = get_stat_mtime (&istat);
763 gettime (&time_stamp);
766 clear_bufs(); /* clear input and output buffers */
770 stdin_was_read = true;
773 method = get_method(ifd);
775 do_exit(exit_code); /* error message already emitted */
779 do_list(ifd, method);
783 /* Actually do the compression/decompression. Loop over zipped members.
786 if (work (STDIN_FILENO, STDOUT_FILENO) != OK)
792 method = get_method(ifd);
793 if (method < 0) return; /* error message already emitted */
794 bytes_out = 0; /* required for length check */
799 fprintf(stderr, " OK\n");
801 } else if (!decompress) {
802 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
803 fprintf(stderr, "\n");
804 #ifdef DISPLAY_STDIN_RATIO
806 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
807 fprintf(stderr, "\n");
813 static char const dot = '.';
815 /* True if the cached directory for calls to openat etc. is DIR, with
816 length DIRLEN. DIR need not be null-terminated. DIRLEN must be
817 less than MAX_PATH_LEN. */
819 atdir_eq (char const *dir, ptrdiff_t dirlen)
822 dir = &dot, dirlen = 1;
823 return memcmp (dfname, dir, dirlen) == 0 && !dfname[dirlen];
826 /* Set the directory used for calls to openat etc. to be the directory
827 DIR, with length DIRLEN. DIR need not be null-terminated.
828 DIRLEN must be less than MAX_PATH_LEN. Return a file descriptor for
829 the directory, or -1 if one could not be obtained. */
831 atdir_set (char const *dir, ptrdiff_t dirlen)
833 /* Don't bother opening directories on older systems that
834 lack openat and unlinkat. It's not worth the porting hassle. */
835 #if HAVE_OPENAT && HAVE_UNLINKAT
836 enum { try_opening_directories = true };
838 enum { try_opening_directories = false };
841 if (try_opening_directories && ! atdir_eq (dir, dirlen))
846 dir = &dot, dirlen = 1;
847 memcpy (dfname, dir, dirlen);
848 dfname[dirlen] = '\0';
849 dfd = open (dfname, O_SEARCH | O_DIRECTORY);
855 /* ========================================================================
856 * Compress or decompress the given file
858 local void treat_file(iname)
861 /* Accept "-" as synonym for stdin */
862 if (strequ(iname, "-")) {
863 int cflag = to_stdout;
869 /* Check if the input file is present, set ifname and istat: */
870 ifd = open_input_file (iname, &istat);
874 /* If the input name is that of a directory, recurse or ignore: */
875 if (S_ISDIR(istat.st_mode)) {
878 treat_dir (ifd, iname);
879 /* Warning: ifname is now garbage */
884 WARN ((stderr, "%s: %s is a directory -- ignored\n",
885 program_name, ifname));
891 if (! S_ISREG (istat.st_mode))
894 "%s: %s is not a directory or a regular file - ignored\n",
895 program_name, ifname));
899 if (istat.st_mode & S_ISUID)
901 WARN ((stderr, "%s: %s is set-user-ID on execution - ignored\n",
902 program_name, ifname));
906 if (istat.st_mode & S_ISGID)
908 WARN ((stderr, "%s: %s is set-group-ID on execution - ignored\n",
909 program_name, ifname));
916 if (istat.st_mode & S_ISVTX)
919 "%s: %s has the sticky bit set - file ignored\n",
920 program_name, ifname));
924 if (2 <= istat.st_nlink)
926 WARN ((stderr, "%s: %s has %lu other link%c -- unchanged\n",
927 program_name, ifname,
928 (unsigned long int) istat.st_nlink - 1,
929 istat.st_nlink == 2 ? ' ' : 's'));
936 ifile_size = S_ISREG (istat.st_mode) ? istat.st_size : -1;
937 time_stamp.tv_nsec = -1;
938 if (!no_time || list)
939 time_stamp = get_stat_mtime (&istat);
941 /* Generate output file name. For -r and (-t or -l), skip files
942 * without a valid gzip suffix (check done in make_ofname).
944 if (to_stdout && !list && !test) {
945 strcpy(ofname, "stdout");
947 } else if (make_ofname() != OK) {
952 clear_bufs(); /* clear input and output buffers */
956 method = get_method(ifd); /* updates ofname if original given */
959 return; /* error message already emitted */
963 do_list(ifd, method);
964 if (close (ifd) != 0)
969 /* If compressing to a file, check if ofname is not ambiguous
970 * because the operating system truncates names. Otherwise, generate
971 * a new ofname and save the original name in the compressed file.
975 /* Keep remove_ofname_fd negative. */
977 if (create_outfile() != OK) return;
979 if (!decompress && save_orig_name && !verbose && !quiet) {
980 fprintf(stderr, "%s: %s compressed to %s\n",
981 program_name, ifname, ofname);
984 /* Keep the name even if not truncated except with --no-name: */
985 if (!save_orig_name) save_orig_name = !no_name;
988 fprintf(stderr, "%s:\t", ifname);
991 /* Actually do the compression/decompression. Loop over zipped members.
994 if ((*work)(ifd, ofd) != OK) {
995 method = -1; /* force cleanup */
1002 method = get_method(ifd);
1003 if (method < 0) break; /* error message already emitted */
1004 bytes_out = 0; /* required for length check */
1007 if (close (ifd) != 0)
1015 && ((0 <= dfd && fdatasync (dfd) != 0 && errno != EINVAL)
1016 || (fsync (ofd) != 0 && errno != EINVAL)))
1017 || close (ofd) != 0)
1024 char *ifbase = last_component (ifname);
1025 int ufd = atdir_eq (ifname, ifbase - ifname) ? dfd : -1;
1028 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
1029 remove_ofname_fd = -1;
1030 res = ufd < 0 ? xunlink (ifname) : unlinkat (ufd, ifbase, 0);
1031 unlink_errno = res == 0 ? 0 : errno;
1032 sigprocmask (SIG_SETMASK, &oldset, NULL);
1036 WARN ((stderr, "%s: ", program_name));
1039 errno = unlink_errno;
1048 remove_output_file ();
1052 /* Display statistics */
1055 fprintf(stderr, " OK");
1056 } else if (decompress) {
1057 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
1059 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
1061 if (!test && !to_stdout)
1062 fprintf(stderr, " -- %s %s", keep ? "created" : "replaced with",
1064 fprintf(stderr, "\n");
1068 /* ========================================================================
1069 * Create the output file. Return OK or ERROR.
1070 * Try several times if necessary to avoid truncating the z_suffix. For
1071 * example, do not create a compressed file of name "1234567890123."
1072 * Sets save_orig_name to true if the file name has been truncated.
1073 * IN assertions: the input file has already been open (ifd is set) and
1074 * ofname has already been updated if there was an original name.
1075 * OUT assertions: ifd and ofd are closed in case of error.
1077 local int create_outfile()
1079 int name_shortened = 0;
1080 int flags = (O_WRONLY | O_CREAT | O_EXCL
1081 | (ascii && decompress ? 0 : O_BINARY));
1082 char const *base = ofname;
1083 int atfd = AT_FDCWD;
1087 char const *b = last_component (ofname);
1088 int f = atdir_set (ofname, b - ofname);
1101 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
1102 remove_ofname_fd = ofd = openat (atfd, base, flags, S_IRUSR | S_IWUSR);
1104 sigprocmask (SIG_SETMASK, &oldset, NULL);
1113 shorten_name (ofname);
1119 if (check_ofname () != OK)
1133 if (name_shortened && decompress)
1135 /* name might be too long if an original name was saved */
1136 WARN ((stderr, "%s: %s: warning, name truncated\n",
1137 program_name, ofname));
1143 /* ========================================================================
1144 * Return a pointer to the 'z' suffix of a file name, or NULL. For all
1145 * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
1146 * accepted suffixes, in addition to the value of the --suffix option.
1147 * ".tgz" is a useful convention for tar.z files on systems limited
1148 * to 3 characters extensions. On such systems, ".?z" and ".??z" are
1149 * also accepted suffixes. For Unix, we do not want to accept any
1150 * .??z suffix as indicating a compressed file; some people use .xyz
1151 * to denote volume data.
1152 * On systems allowing multiple versions of the same file (such as VMS),
1153 * this function removes any version suffix in the given name.
1155 local char *get_suffix(name)
1159 char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */
1160 static char const *known_suffixes[] =
1161 {NULL, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
1162 #ifdef MAX_EXT_CHARS
1167 bool suffix_of_builtin = false;
1169 /* Normally put Z_SUFFIX at the start of KNOWN_SUFFIXES, but if it
1170 is a suffix of one of them, put it at the end. */
1171 for (suf = known_suffixes + 1; *suf; suf++)
1173 size_t suflen = strlen (*suf);
1174 if (z_len < suflen && strequ (z_suffix, *suf + suflen - z_len))
1176 suffix_of_builtin = true;
1180 known_suffixes[suffix_of_builtin
1181 ? sizeof known_suffixes / sizeof *known_suffixes - 2
1183 suf = known_suffixes + suffix_of_builtin;
1186 /* strip a version number from the file name */
1188 char *v = strrchr(name, SUFFIX_SEP);
1189 if (v != NULL) *v = '\0';
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);
1201 int s = strlen(*suf);
1202 if (slen > s && suffix[slen-s-1] != PATH_SEP
1203 && strequ(suffix + slen - s, *suf)) {
1206 } while (*++suf != NULL);
1212 /* Open file NAME with the given flags and store its status
1213 into *ST. Return a file descriptor to the newly opened file, or -1
1214 (setting errno) on failure. */
1216 open_and_stat (char *name, int flags, struct stat *st)
1219 int atfd = AT_FDCWD;
1220 char const *base = name;
1222 /* Refuse to follow symbolic links unless -c or -f. */
1223 if (!to_stdout && !force)
1225 if (HAVE_WORKING_O_NOFOLLOW)
1226 flags |= O_NOFOLLOW;
1229 #if HAVE_LSTAT || defined lstat
1230 if (lstat (name, st) != 0)
1232 else if (S_ISLNK (st->st_mode))
1243 char const *b = last_component (name);
1244 int f = atdir_set (name, b - name);
1252 fd = openat (atfd, base, flags);
1253 if (0 <= fd && fstat (fd, st) != 0)
1264 /* ========================================================================
1265 * Set ifname to the input file name (with a suffix appended if necessary)
1266 * and istat to its stats. For decompression, if no file exists with the
1267 * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
1268 * For MSDOS, we try only z_suffix and z.
1269 * Return an open file descriptor or -1.
1272 open_input_file (iname, sbuf)
1276 int ilen; /* strlen(ifname) */
1277 int z_suffix_errno = 0;
1278 static char const *suffixes[] = {NULL, ".gz", ".z", "-z", ".Z", NULL};
1279 char const **suf = suffixes;
1281 #ifdef NO_MULTIPLE_DOTS
1282 char *dot; /* pointer to ifname extension, or NULL */
1285 int open_flags = (O_RDONLY | O_NONBLOCK | O_NOCTTY
1286 | (ascii && !decompress ? 0 : O_BINARY));
1290 if (sizeof ifname - 1 <= strlen (iname))
1293 strcpy(ifname, iname);
1295 /* If input file exists, return OK. */
1296 fd = open_and_stat (ifname, open_flags, sbuf);
1300 if (!decompress || errno != ENOENT) {
1304 /* file.ext doesn't exist, try adding a suffix (after removing any
1305 * version number for VMS).
1307 s = get_suffix(ifname);
1309 progerror(ifname); /* ifname already has z suffix and does not exist */
1312 #ifdef NO_MULTIPLE_DOTS
1313 dot = strrchr(ifname, '.');
1315 strcat(ifname, ".");
1316 dot = strrchr(ifname, '.');
1319 ilen = strlen(ifname);
1320 if (strequ(z_suffix, ".gz")) suf++;
1322 /* Search for all suffixes */
1324 char const *s0 = s = *suf;
1325 strcpy (ifname, iname);
1326 #ifdef NO_MULTIPLE_DOTS
1328 if (*dot == '\0') strcpy (dot, ".");
1330 #ifdef MAX_EXT_CHARS
1331 if (MAX_EXT_CHARS < strlen (s) + strlen (dot + 1))
1332 dot[MAX_EXT_CHARS + 1 - strlen (s)] = '\0';
1334 if (sizeof ifname <= ilen + strlen (s))
1337 fd = open_and_stat (ifname, open_flags, sbuf);
1340 if (errno != ENOENT)
1345 if (strequ (s0, z_suffix))
1346 z_suffix_errno = errno;
1347 } while (*++suf != NULL);
1349 /* No suffix found, complain using z_suffix: */
1350 strcpy(ifname, iname);
1351 #ifdef NO_MULTIPLE_DOTS
1352 if (*dot == '\0') strcpy(dot, ".");
1354 #ifdef MAX_EXT_CHARS
1355 if (MAX_EXT_CHARS < z_len + strlen (dot + 1))
1356 dot[MAX_EXT_CHARS + 1 - z_len] = '\0';
1358 strcat(ifname, z_suffix);
1359 errno = z_suffix_errno;
1364 fprintf (stderr, "%s: %s: file name too long\n", program_name, iname);
1369 /* ========================================================================
1370 * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
1371 * Sets save_orig_name to true if the file name has been truncated.
1373 local int make_ofname()
1375 char *suff; /* ofname z suffix */
1377 strcpy(ofname, ifname);
1378 /* strip a version number if any and get the gzip suffix if present: */
1379 suff = get_suffix(ofname);
1383 /* With -t or -l, try all files (even without .gz suffix)
1384 * except with -r (behave as with just -dr).
1386 if (!recursive && (list || test)) return OK;
1388 /* Avoid annoying messages with -r */
1389 if (verbose || (!recursive && !quiet)) {
1390 WARN((stderr,"%s: %s: unknown suffix -- ignored\n",
1391 program_name, ifname));
1395 /* Make a special case for .tgz and .taz: */
1397 if (strequ(suff, ".tgz") || strequ(suff, ".taz")) {
1398 strcpy(suff, ".tar");
1400 *suff = '\0'; /* strip the z suffix */
1402 /* ofname might be changed later if infile contains an original name */
1404 } else if (suff && ! force) {
1405 /* Avoid annoying messages with -r (see treat_dir()) */
1406 if (verbose || (!recursive && !quiet)) {
1407 /* Don't use WARN, as it affects exit status. */
1408 fprintf (stderr, "%s: %s already has %s suffix -- unchanged\n",
1409 program_name, ifname, suff);
1415 #ifdef NO_MULTIPLE_DOTS
1416 suff = strrchr(ofname, '.');
1418 if (sizeof ofname <= strlen (ofname) + 1)
1420 strcat(ofname, ".");
1421 # ifdef MAX_EXT_CHARS
1422 if (strequ(z_suffix, "z")) {
1423 if (sizeof ofname <= strlen (ofname) + 2)
1425 strcat(ofname, "gz"); /* enough room */
1428 /* On the Atari and some versions of MSDOS,
1429 * ENAMETOOLONG does not work correctly. So we
1430 * must truncate here.
1432 } else if (strlen(suff)-1 + z_len > MAX_SUFFIX) {
1433 suff[MAX_SUFFIX+1-z_len] = '\0';
1437 #endif /* NO_MULTIPLE_DOTS */
1438 if (sizeof ofname <= strlen (ofname) + z_len)
1440 strcat(ofname, z_suffix);
1442 } /* decompress ? */
1446 WARN ((stderr, "%s: %s: file name too long\n", program_name, ifname));
1450 /* Discard NBYTES input bytes from the input, or up through the next
1451 zero byte if NBYTES == (size_t) -1. If FLAGS say that the header
1452 CRC should be computed, update the CRC accordingly. */
1454 discard_input_bytes (nbytes, flags)
1460 uch c = get_byte ();
1461 if (flags & HEADER_CRC)
1463 if (nbytes != (size_t) -1)
1470 /* ========================================================================
1471 * Check the magic number of the input file and update ofname if an
1472 * original name was given and to_stdout is not set.
1473 * Return the compression method, -1 for error, -2 for warning.
1474 * Set inptr to the offset of the next byte to be processed.
1475 * Updates time_stamp if there is one and --no-time is not used.
1476 * This function may be called repeatedly for an input file consisting
1477 * of several contiguous gzip'ed members.
1478 * IN assertions: there is at least one remaining compressed member.
1479 * If the member is a zip file, it must be the only one.
1481 local int get_method(in)
1482 int in; /* input file descriptor */
1484 uch flags; /* compression flags */
1485 uch magic[10]; /* magic header */
1486 int imagic0; /* first magic byte or EOF */
1487 int imagic1; /* like magic[1], but can represent EOF */
1488 ulg stamp; /* time stamp */
1490 /* If --force and --stdout, zcat == cat, so do not complain about
1491 * premature end of file: use try_byte instead of get_byte.
1493 if (force && to_stdout) {
1494 imagic0 = try_byte();
1496 imagic1 = try_byte ();
1498 /* If try_byte returned EOF, magic[1] == (char) EOF. */
1500 magic[0] = get_byte ();
1503 magic[1] = get_byte ();
1504 imagic1 = 0; /* avoid lint warning */
1506 imagic1 = try_byte ();
1510 method = -1; /* unknown yet */
1511 part_nb++; /* number of parts in gzip file */
1513 last_member = RECORD_IO;
1514 /* assume multiple members in gzip file except for record oriented I/O */
1516 if (memcmp(magic, GZIP_MAGIC, 2) == 0
1517 || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
1519 method = (int)get_byte();
1520 if (method != DEFLATED) {
1522 "%s: %s: unknown method %d -- not supported\n",
1523 program_name, ifname, method);
1528 flags = (uch)get_byte();
1530 if ((flags & ENCRYPTED) != 0) {
1532 "%s: %s is encrypted -- not supported\n",
1533 program_name, ifname);
1537 if ((flags & RESERVED) != 0) {
1539 "%s: %s has flags 0x%x -- not supported\n",
1540 program_name, ifname, flags);
1542 if (force <= 1) return -1;
1544 stamp = (ulg)get_byte();
1545 stamp |= ((ulg)get_byte()) << 8;
1546 stamp |= ((ulg)get_byte()) << 16;
1547 stamp |= ((ulg)get_byte()) << 24;
1548 if (stamp != 0 && !no_time)
1550 time_stamp.tv_sec = stamp;
1551 time_stamp.tv_nsec = 0;
1554 magic[8] = get_byte (); /* Ignore extra flags. */
1555 magic[9] = get_byte (); /* Ignore OS type. */
1557 if (flags & HEADER_CRC)
1559 magic[2] = DEFLATED;
1561 magic[4] = stamp & 0xff;
1562 magic[5] = (stamp >> 8) & 0xff;
1563 magic[6] = (stamp >> 16) & 0xff;
1564 magic[7] = stamp >> 24;
1569 if ((flags & EXTRA_FIELD) != 0) {
1571 unsigned int len = lenbuf[0] = get_byte ();
1572 len |= (lenbuf[1] = get_byte ()) << 8;
1574 fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n",
1575 program_name, ifname, len);
1577 if (flags & HEADER_CRC)
1579 discard_input_bytes (len, flags);
1582 /* Get original file name if it was truncated */
1583 if ((flags & ORIG_NAME) != 0) {
1584 if (no_name || (to_stdout && !list) || part_nb > 1) {
1585 /* Discard the old name */
1586 discard_input_bytes (-1, flags);
1588 /* Copy the base name. Keep a directory prefix intact. */
1589 char *p = gzip_base_name (ofname);
1592 *p = (char) get_byte ();
1593 if (*p++ == '\0') break;
1594 if (p >= ofname+sizeof(ofname)) {
1595 gzip_error ("corrupted input -- file name too large");
1598 if (flags & HEADER_CRC)
1599 updcrc ((uch *) base, p - base);
1600 p = gzip_base_name (base);
1601 memmove (base, p, strlen (p) + 1);
1602 /* If necessary, adapt the name to local OS conventions: */
1604 MAKE_LEGAL_NAME(base);
1605 if (base) list=0; /* avoid warning about unused variable */
1607 } /* no_name || to_stdout */
1610 /* Discard file comment if any */
1611 if ((flags & COMMENT) != 0) {
1612 discard_input_bytes (-1, flags);
1615 if (flags & HEADER_CRC)
1617 unsigned int crc16 = updcrc (magic, 0) & 0xffff;
1618 unsigned int header16 = get_byte ();
1619 header16 |= ((unsigned int) get_byte ()) << 8;
1620 if (header16 != crc16)
1623 "%s: %s: header checksum 0x%04x != computed checksum 0x%04x\n",
1624 program_name, ifname, header16, crc16);
1632 header_bytes = inptr + 2*4; /* include crc and size */
1635 } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
1636 && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0) {
1637 /* To simplify the code, we support a zip file when alone only.
1638 * We are thus guaranteed that the entire local header fits in inbuf.
1642 if (check_zipfile(in) != OK) return -1;
1643 /* check_zipfile may get ofname from the local header */
1646 } else if (memcmp(magic, PACK_MAGIC, 2) == 0) {
1650 } else if (memcmp(magic, LZW_MAGIC, 2) == 0) {
1652 method = COMPRESSED;
1655 } else if (memcmp(magic, LZH_MAGIC, 2) == 0) {
1660 } else if (force && to_stdout && !list) { /* pass input unchanged */
1666 if (imagic0 != EOF) {
1667 write_buf (STDOUT_FILENO, magic, 1);
1671 if (method >= 0) return method;
1674 fprintf (stderr, "\n%s: %s: not in gzip format\n",
1675 program_name, ifname);
1682 for (inbyte = imagic1; inbyte == 0; inbyte = try_byte ())
1687 WARN ((stderr, "\n%s: %s: decompression OK, trailing zero bytes ignored\n",
1688 program_name, ifname));
1693 WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n",
1694 program_name, ifname));
1699 /* ========================================================================
1700 * Display the characteristics of the compressed file.
1701 * If the given method is < 0, display the accumulated totals.
1702 * IN assertions: time_stamp, header_bytes and ifile_size are initialized.
1704 local void do_list(ifd, method)
1705 int ifd; /* input file descriptor */
1706 int method; /* compression method */
1708 ulg crc; /* original crc */
1709 static int first_time = 1;
1710 static char const *const methods[MAX_METHODS] = {
1715 "", "", "", "", /* 4 to 7 reserved */
1717 int positive_off_t_width = 1;
1720 for (o = OFF_T_MAX; 9 < o; o /= 10) {
1721 positive_off_t_width++;
1724 if (first_time && method >= 0) {
1727 printf("method crc date time ");
1730 printf("%*.*s %*.*s ratio uncompressed_name\n",
1731 positive_off_t_width, positive_off_t_width, "compressed",
1732 positive_off_t_width, positive_off_t_width, "uncompressed");
1734 } else if (method < 0) {
1735 if (total_in <= 0 || total_out <= 0) return;
1739 if (verbose || !quiet) {
1740 fprint_off(stdout, total_in, positive_off_t_width);
1742 fprint_off(stdout, total_out, positive_off_t_width);
1745 display_ratio(total_out-(total_in-header_bytes), total_out, stdout);
1746 /* header_bytes is not meaningful but used to ensure the same
1747 * ratio if there is a single file.
1749 printf(" (totals)\n");
1752 crc = (ulg)~0; /* unknown */
1754 bytes_in = ifile_size;
1756 if (!RECORD_IO && method == DEFLATED && !last_member) {
1757 /* Get the crc and uncompressed size for gzip'ed (not zip'ed) files.
1758 * If the lseek fails, we could use read() to get to the end, but
1759 * --list is used to get quick results.
1760 * Use "gunzip < foo.gz | wc -c" to get the uncompressed size if
1761 * you are not concerned about speed.
1763 bytes_in = lseek(ifd, (off_t)(-8), SEEK_END);
1764 if (bytes_in != -1L) {
1767 if (read(ifd, (char*)buf, sizeof(buf)) != sizeof(buf)) {
1771 bytes_out = LG(buf+4);
1777 static char const month_abbr[][4]
1778 = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1779 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
1780 struct tm *tm = localtime (&time_stamp.tv_sec);
1781 printf ("%5s %08lx ", methods[method], crc);
1783 printf ("%s%3d %02d:%02d ", month_abbr[tm->tm_mon],
1784 tm->tm_mday, tm->tm_hour, tm->tm_min);
1786 printf ("??? ?? ??:?? ");
1788 fprint_off(stdout, bytes_in, positive_off_t_width);
1790 fprint_off(stdout, bytes_out, positive_off_t_width);
1792 if (bytes_in == -1L) {
1794 bytes_in = bytes_out = header_bytes = 0;
1795 } else if (total_in >= 0) {
1796 total_in += bytes_in;
1798 if (bytes_out == -1L) {
1800 bytes_in = bytes_out = header_bytes = 0;
1801 } else if (total_out >= 0) {
1802 total_out += bytes_out;
1804 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out, stdout);
1805 printf(" %s\n", ofname);
1808 /* ========================================================================
1809 * Shorten the given name by one character, or replace a .tar extension
1810 * with .tgz. Truncate the last part of the name which is longer than
1811 * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
1812 * has only parts shorter than MIN_PART truncate the longest part.
1813 * For decompression, just remove the last character of the name.
1815 * IN assertion: for compression, the suffix of the given name is z_suffix.
1817 local void shorten_name(name)
1820 int len; /* length of name without z_suffix */
1821 char *trunc = NULL; /* character to be truncated */
1822 int plen; /* current part length */
1823 int min_part = MIN_PART; /* current minimum part length */
1829 gzip_error ("name too short");
1833 p = get_suffix(name);
1835 gzip_error ("can't recover suffix\n");
1839 /* compress 1234567890.tar to 1234567890.tgz */
1840 if (len > 4 && strequ(p-4, ".tar")) {
1841 strcpy(p-4, ".tgz");
1844 /* Try keeping short extensions intact:
1845 * 1234.678.012.gz -> 123.678.012.gz
1848 p = strrchr(name, PATH_SEP);
1851 plen = strcspn(p, PART_SEP);
1853 if (plen > min_part) trunc = p-1;
1856 } while (trunc == NULL && --min_part != 0);
1858 if (trunc != NULL) {
1860 trunc[0] = trunc[1];
1864 trunc = strrchr(name, PART_SEP[0]);
1866 gzip_error ("internal error in shorten_name");
1867 if (trunc[1] == '\0') trunc--; /* force truncation */
1869 strcpy(trunc, z_suffix);
1872 /* ========================================================================
1873 * The compressed file already exists, so ask for confirmation.
1874 * Return ERROR if the file must be skipped.
1876 local int check_ofname()
1878 /* Ask permission to overwrite the existing file */
1881 fprintf (stderr, "%s: %s already exists;", program_name, ofname);
1882 if (foreground && (presume_input_tty || isatty (STDIN_FILENO))) {
1883 fprintf(stderr, " do you wish to overwrite (y or n)? ");
1888 fprintf(stderr, "\tnot overwritten\n");
1889 if (exit_code == OK) exit_code = WARNING;
1893 if (xunlink (ofname)) {
1900 /* Change the owner and group of a file. FD is a file descriptor for
1901 the file and NAME its name. Change it to user UID and to group GID.
1902 If UID or GID is -1, though, do not change the corresponding user
1905 do_chown (int fd, char const *name, uid_t uid, gid_t gid)
1909 ignore_value (fchown (fd, uid, gid));
1911 ignore_value (chown (name, uid, gid));
1916 /* ========================================================================
1917 * Copy modes, times, ownership from input file to output file.
1918 * IN assertion: to_stdout is false.
1920 local void copy_stat(ifstat)
1921 struct stat *ifstat;
1923 mode_t mode = ifstat->st_mode & S_IRWXUGO;
1927 struct timespec timespec[2];
1928 timespec[0] = get_stat_atime (ifstat);
1929 timespec[1] = get_stat_mtime (ifstat);
1931 if (decompress && 0 <= time_stamp.tv_nsec
1932 && ! (timespec[1].tv_sec == time_stamp.tv_sec
1933 && timespec[1].tv_nsec == time_stamp.tv_nsec))
1935 timespec[1] = time_stamp;
1937 fprintf(stderr, "%s: time stamp restored\n", ofname);
1941 if (fdutimens (ofd, ofname, timespec) != 0)
1944 WARN ((stderr, "%s: ", program_name));
1953 /* Change the group first, then the permissions, then the owner.
1954 That way, the permissions will be correct on systems that allow
1955 users to give away files, without introducing a security hole.
1956 Security depends on permissions not containing the setuid or
1959 do_chown (ofd, ofname, -1, ifstat->st_gid);
1962 r = fchmod (ofd, mode);
1964 r = chmod (ofname, mode);
1968 WARN ((stderr, "%s: ", program_name));
1975 do_chown (ofd, ofname, ifstat->st_uid, -1);
1980 /* ========================================================================
1981 * Recurse through the given directory.
1983 local void treat_dir (fd, dir)
1988 char nbuf[MAX_PATH_LEN];
1993 dirp = fdopendir (fd);
2001 entries = streamsavedir (dirp, SAVEDIR_SORT_NONE);
2004 if (closedir (dirp) != 0)
2009 for (entry = entries; *entry; entry += entrylen + 1) {
2010 size_t len = strlen (dir);
2011 entrylen = strlen (entry);
2012 if (strequ (entry, ".") || strequ (entry, ".."))
2014 if (len + entrylen < MAX_PATH_LEN - 2) {
2016 if (len != 0 /* dir = "" means current dir on Amiga */
2018 && dir[len-1] != PATH_SEP2
2021 && dir[len-1] != PATH_SEP3
2024 nbuf[len++] = PATH_SEP;
2026 strcpy (nbuf + len, entry);
2029 fprintf(stderr,"%s: %s/%s: pathname too long\n",
2030 program_name, dir, entry);
2036 #endif /* ! NO_DIR */
2038 /* Make sure signals get handled properly. */
2041 install_signal_handlers ()
2043 int nsigs = sizeof handled_sig / sizeof handled_sig[0];
2047 struct sigaction act;
2049 sigemptyset (&caught_signals);
2050 for (i = 0; i < nsigs; i++)
2052 sigaction (handled_sig[i], NULL, &act);
2053 if (act.sa_handler != SIG_IGN)
2054 sigaddset (&caught_signals, handled_sig[i]);
2057 act.sa_handler = abort_gzip_signal;
2058 act.sa_mask = caught_signals;
2061 for (i = 0; i < nsigs; i++)
2062 if (sigismember (&caught_signals, handled_sig[i]))
2066 sigaction (handled_sig[i], &act, NULL);
2069 for (i = 0; i < nsigs; i++)
2070 if (signal (handled_sig[i], SIG_IGN) != SIG_IGN)
2074 signal (handled_sig[i], abort_gzip_signal);
2075 siginterrupt (handled_sig[i], 1);
2080 /* ========================================================================
2081 * Free all dynamically allocated variables and exit with the given code.
2083 local void do_exit(exitcode)
2086 static int in_exit = 0;
2088 if (in_exit) exit(exitcode);
2108 if (fclose (stdout) != 0)
2113 /* ========================================================================
2114 * Close and unlink the output file.
2117 remove_output_file ()
2122 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
2123 fd = remove_ofname_fd;
2126 remove_ofname_fd = -1;
2130 sigprocmask (SIG_SETMASK, &oldset, NULL);
2133 /* ========================================================================
2139 remove_output_file ();
2143 /* ========================================================================
2147 abort_gzip_signal (sig)
2151 signal (sig, SIG_IGN);
2152 remove_output_file ();
2153 if (sig == exiting_signal)
2155 signal (sig, SIG_DFL);