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.
48 * Using gz on MSDOS would create too many file name conflicts. For
49 * example, foo.txt -> foo.tgz (.tgz must be reserved as shorthand for
50 * tar.gz). Similarly, foo.dir and foo.doc would both be mapped to foo.dgz.
51 * I also considered 12345678.txt -> 12345txt.gz but this truncates the name
52 * too heavily. There is no ideal solution given the MSDOS 8+3 limitation.
54 * For the meaning of all compilation flags, see comments in Makefile.in.
59 #include <sys/types.h>
77 #include "ignore-value.h"
78 #include "stat-time.h"
102 # define MAX_PATH_LEN 1024 /* max pathname length */
114 off_t lseek (int fd, off_t offset, int whence);
118 # define OFF_T_MAX TYPE_MAXIMUM (off_t)
121 /* Use SA_NOCLDSTOP as a proxy for whether the sigaction machinery is
124 # define SA_NOCLDSTOP 0
125 # define sigprocmask(how, set, oset) /* empty */
126 # define sigset_t int
127 # if ! HAVE_SIGINTERRUPT
128 # define siginterrupt(sig, flag) /* empty */
132 #ifndef HAVE_WORKING_O_NOFOLLOW
133 # define HAVE_WORKING_O_NOFOLLOW 0
136 /* Separator for file name parts (see shorten_name()) */
137 #ifdef NO_MULTIPLE_DOTS
138 # define PART_SEP "-"
140 # define PART_SEP "."
145 DECLARE(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
146 DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
147 DECLARE(ush, d_buf, DIST_BUFSIZE);
148 DECLARE(uch, window, 2L*WSIZE);
150 DECLARE(ush, tab_prefix, 1L<<BITS);
152 DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
153 DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
156 /* local variables */
158 /* If true, pretend that standard input is a tty. This option
159 is deliberately not documented, and only for testing. */
160 static bool presume_input_tty;
162 /* If true, transfer output data to the output file's storage device
163 when supported. Otherwise, if the system crashes around the time
164 gzip is run, the user might lose both input and output data. See:
165 Pillai TS et al. All file systems are not created equal: on the
166 complexity of crafting crash-consistent applications. OSDI'14. 2014:433-48.
167 https://www.usenix.org/conference/osdi14/technical-sessions/presentation/pillai */
168 static bool synchronous;
170 static int ascii = 0; /* convert end-of-lines to local OS conventions */
171 int to_stdout = 0; /* output to stdout (-c) */
172 static int decompress = 0; /* decompress (-d) */
173 static int force = 0; /* don't ask questions, compress links (-f) */
174 static int keep = 0; /* keep (don't delete) input files */
175 static int no_name = -1; /* don't save or restore the original file name */
176 static int no_time = -1; /* don't save or restore the original file time */
177 static int recursive = 0; /* recurse through directories (-r) */
178 static int list = 0; /* list the file contents (-l) */
179 int verbose = 0; /* be verbose (-v) */
180 int quiet = 0; /* be very quiet (-q) */
181 static int do_lzw = 0; /* generate output compatible with old compress (-Z) */
182 int test = 0; /* test .gz file integrity */
183 static int foreground = 0; /* set if program run in foreground */
184 char *program_name; /* program name */
185 int maxbits = BITS; /* max bits per code for LZW */
186 int method = DEFLATED;/* compression method */
187 int level = 6; /* compression level */
188 int exit_code = OK; /* program exit code */
189 int save_orig_name; /* set if original name must be saved */
190 static int last_member; /* set for .zip and .Z files */
191 static int part_nb; /* number of parts in .gz file */
192 struct timespec time_stamp; /* original time stamp (modification time) */
193 off_t ifile_size; /* input file size, -1 for devices (debug only) */
194 static char *env; /* contents of GZIP env variable */
195 static char const *z_suffix; /* default suffix (can be set with --suffix) */
196 static size_t z_len; /* strlen(z_suffix) */
198 /* The set of signals that are caught. */
199 static sigset_t caught_signals;
201 /* If nonzero then exit with status WARNING, rather than with the usual
202 signal status, on receipt of a signal with this value. This
203 suppresses a "Broken Pipe" message with some shells. */
204 static int volatile exiting_signal;
206 /* If nonnegative, close this file descriptor and unlink ofname on error. */
207 static int volatile remove_ofname_fd = -1;
209 static bool stdin_was_read;
211 off_t bytes_in; /* number of input bytes */
212 off_t bytes_out; /* number of output bytes */
213 static off_t total_in; /* input bytes for all files */
214 static off_t total_out; /* output bytes for all files */
215 char ifname[MAX_PATH_LEN]; /* input file name */
216 char ofname[MAX_PATH_LEN]; /* output file name */
217 static char dfname[MAX_PATH_LEN]; /* name of dir containing output file */
218 static struct stat istat; /* status for input file */
219 int ifd; /* input file descriptor */
220 int ofd; /* output file descriptor */
221 static int dfd = -1; /* output directory file descriptor */
222 unsigned insize; /* valid bytes in inbuf */
223 unsigned inptr; /* index of next byte to be processed in inbuf */
224 unsigned outcnt; /* bytes in output buffer */
225 int rsync = 0; /* make ryncable chunks */
227 static int handled_sig[] =
229 /* SIGINT must be first, as 'foreground' depends on it. */
249 /* For long options that have no equivalent short option, use a
250 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
253 PRESUME_INPUT_TTY_OPTION = CHAR_MAX + 1,
257 /* A value greater than all valid long options, used as a flag to
258 distinguish options derived from the GZIP environment variable. */
262 static char const shortopts[] = "ab:cdfhH?klLmMnNqrS:tvVZ123456789";
264 static const struct option longopts[] =
266 /* { name has_arg *flag val } */
267 {"ascii", 0, 0, 'a'}, /* ascii text mode */
268 {"to-stdout", 0, 0, 'c'}, /* write output on standard output */
269 {"stdout", 0, 0, 'c'}, /* write output on standard output */
270 {"decompress", 0, 0, 'd'}, /* decompress */
271 {"uncompress", 0, 0, 'd'}, /* decompress */
272 /* {"encrypt", 0, 0, 'e'}, encrypt */
273 {"force", 0, 0, 'f'}, /* force overwrite of output file */
274 {"help", 0, 0, 'h'}, /* give help */
275 /* {"pkzip", 0, 0, 'k'}, force output in pkzip format */
276 {"keep", 0, 0, 'k'}, /* keep (don't delete) input files */
277 {"list", 0, 0, 'l'}, /* list .gz file contents */
278 {"license", 0, 0, 'L'}, /* display software license */
279 {"no-name", 0, 0, 'n'}, /* don't save or restore original name & time */
280 {"name", 0, 0, 'N'}, /* save or restore original name & time */
281 {"-presume-input-tty", no_argument, NULL, PRESUME_INPUT_TTY_OPTION},
282 {"quiet", 0, 0, 'q'}, /* quiet mode */
283 {"silent", 0, 0, 'q'}, /* quiet mode */
284 {"synchronous",0, 0, SYNCHRONOUS_OPTION},
285 {"recursive", 0, 0, 'r'}, /* recurse through directories */
286 {"suffix", 1, 0, 'S'}, /* use given suffix instead of .gz */
287 {"test", 0, 0, 't'}, /* test compressed file integrity */
288 {"no-time", 0, 0, 'T'}, /* don't save or restore the time stamp */
289 {"verbose", 0, 0, 'v'}, /* verbose mode */
290 {"version", 0, 0, 'V'}, /* display version number */
291 {"fast", 0, 0, '1'}, /* compress faster */
292 {"best", 0, 0, '9'}, /* compress better */
293 {"lzw", 0, 0, 'Z'}, /* make output compatible with old compress */
294 {"bits", 1, 0, 'b'}, /* max number of bits per code (implies -Z) */
295 {"rsyncable", 0, 0, RSYNCABLE_OPTION}, /* make rsync-friendly archive */
299 /* local functions */
301 local void try_help (void) ATTRIBUTE_NORETURN;
302 local void help (void);
303 local void license (void);
304 local void version (void);
305 local int input_eof (void);
306 local void treat_stdin (void);
307 local void treat_file (char *iname);
308 local int create_outfile (void);
309 local char *get_suffix (char *name);
310 local int open_input_file (char *iname, struct stat *sbuf);
311 local void discard_input_bytes (size_t nbytes, unsigned int flags);
312 local int make_ofname (void);
313 local void shorten_name (char *name);
314 local int get_method (int in);
315 local void do_list (int ifd, int method);
316 local int check_ofname (void);
317 local void copy_stat (struct stat *ifstat);
318 local void install_signal_handlers (void);
319 local void remove_output_file (void);
320 local RETSIGTYPE abort_gzip_signal (int);
321 local void do_exit (int exitcode) ATTRIBUTE_NORETURN;
322 static void finish_out (void);
323 int main (int argc, char **argv);
324 static int (*work) (int infile, int outfile) = zip; /* function to call */
327 local void treat_dir (int fd, char *dir);
330 #define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
335 fprintf (stderr, "Try `%s --help' for more information.\n",
340 /* ======================================================================== */
343 static char const* const help_msg[] = {
344 "Compress or uncompress FILEs (by default, compress FILES in-place).",
346 "Mandatory arguments to long options are mandatory for short options too.",
349 " -a, --ascii ascii text; convert end-of-line using local conventions",
351 " -c, --stdout write on standard output, keep original files unchanged",
352 " -d, --decompress decompress",
353 /* -e, --encrypt encrypt */
354 " -f, --force force overwrite of output file and compress links",
355 " -h, --help give this help",
356 /* -k, --pkzip force output in pkzip format */
357 " -k, --keep keep (don't delete) input files",
358 " -l, --list list compressed file contents",
359 " -L, --license display software license",
361 " -m, --no-time do not save or restore the original modification time",
362 " -M, --time save or restore the original modification time",
364 " -n, --no-name do not save or restore the original name and time stamp",
365 " -N, --name save or restore the original name and time stamp",
366 " -q, --quiet suppress all warnings",
368 " -r, --recursive operate recursively on directories",
370 " --rsyncable make rsync-friendly archive",
371 " -S, --suffix=SUF use suffix SUF on compressed files",
372 " --synchronous synchronous output (safer if system crashes, but slower)",
373 " -t, --test test compressed file integrity",
374 " -v, --verbose verbose mode",
375 " -V, --version display version number",
376 " -1, --fast compress faster",
377 " -9, --best compress better",
379 " -Z, --lzw produce output compatible with old compress",
380 " -b, --bits=BITS max number of bits per code (implies -Z)",
383 "With no FILE, or when FILE is -, read standard input.",
385 "Report bugs to <bug-gzip@gnu.org>.",
387 char const *const *p = help_msg;
389 printf ("Usage: %s [OPTION]... [FILE]...\n", program_name);
390 while (*p) printf ("%s\n", *p++);
393 /* ======================================================================== */
396 char const *const *p = license_msg;
398 printf ("%s %s\n", program_name, Version);
399 while (*p) printf ("%s\n", *p++);
402 /* ======================================================================== */
407 printf ("Written by Jean-loup Gailly.\n");
410 local void progerror (char const *string)
413 fprintf (stderr, "%s: ", program_name);
419 /* ======================================================================== */
420 int main (int argc, char **argv)
422 int file_count; /* number of files to process */
423 size_t proglen; /* length of program_name */
428 EXPAND(argc, argv); /* wild card expansion if necessary */
430 program_name = gzip_base_name (argv[0]);
431 proglen = strlen (program_name);
433 /* Suppress .exe for MSDOS and OS/2: */
434 if (4 < proglen && strequ (program_name + proglen - 4, ".exe"))
435 program_name[proglen - 4] = '\0';
437 /* Add options in GZIP environment variable if there is one */
439 env = add_envopt (&env_argc, &argv_copy, OPTIONS_VAR);
440 env_argv = env ? argv_copy : NULL;
443 # define GNU_STANDARD 1
446 /* For compatibility with old compress, use program name as an option.
447 * Unless you compile with -DGNU_STANDARD=0, this program will behave as
448 * gzip even if it is invoked under the name gunzip or zcat.
450 * Systems which do not support links can still use -d or -dc.
451 * Ignore an .exe extension for MSDOS and OS/2.
453 if (strncmp (program_name, "un", 2) == 0 /* ungzip, uncompress */
454 || strncmp (program_name, "gun", 3) == 0) /* gunzip */
456 else if (strequ (program_name + 1, "cat") /* zcat, pcat, gcat */
457 || strequ (program_name, "gzcat")) /* gzcat */
458 decompress = to_stdout = 1;
462 z_len = strlen(z_suffix);
470 if (env_argv[optind] && strequ (env_argv[optind], "--"))
471 optc = ENV_OPTION + '-';
474 optc = getopt_long (env_argc, env_argv, shortopts, longopts,
480 if (optind != env_argc)
483 ("%s: %s: non-option in "OPTIONS_VAR
484 " environment variable\n"),
485 program_name, env_argv[optind]);
489 /* Wait until here before warning, so that GZIP='-q'
491 if (env_argc != 1 && !quiet)
493 ("%s: warning: "OPTIONS_VAR" environment variable"
494 " is deprecated; use an alias or script\n"),
497 /* Start processing ARGC and ARGV instead. */
507 optc = getopt_long (argc, argv, shortopts, longopts, &longind);
515 maxbits = atoi(optarg);
516 for (; *optarg; optarg++)
517 if (! ('0' <= *optarg && *optarg <= '9'))
519 fprintf (stderr, "%s: -b operand is not an integer\n",
525 to_stdout = 1; break;
527 decompress = 1; break;
531 help (); finish_out (); break;
535 list = decompress = to_stdout = 1; break;
537 license (); finish_out (); break;
538 case 'm': /* undocumented, may change later */
540 case 'M': /* undocumented, may change later */
543 case 'n' + ENV_OPTION:
544 no_name = no_time = 1; break;
546 case 'N' + ENV_OPTION:
547 no_name = no_time = 0; break;
548 case PRESUME_INPUT_TTY_OPTION:
549 presume_input_tty = true; break;
551 case 'q' + ENV_OPTION:
552 quiet = 1; verbose = 0; break;
555 fprintf (stderr, "%s: -r not supported on this system\n",
563 case RSYNCABLE_OPTION:
564 case RSYNCABLE_OPTION + ENV_OPTION:
568 #ifdef NO_MULTIPLE_DOTS
569 if (*optarg == '.') optarg++;
571 z_len = strlen(optarg);
574 case SYNCHRONOUS_OPTION:
578 test = decompress = to_stdout = 1;
581 case 'v' + ENV_OPTION:
582 verbose++; quiet = 0; break;
584 version (); finish_out (); break;
589 fprintf(stderr, "%s: -Z not supported in this version\n",
594 case '1' + ENV_OPTION: case '2' + ENV_OPTION: case '3' + ENV_OPTION:
595 case '4' + ENV_OPTION: case '5' + ENV_OPTION: case '6' + ENV_OPTION:
596 case '7' + ENV_OPTION: case '8' + ENV_OPTION: case '9' + ENV_OPTION:
599 case '1': case '2': case '3': case '4':
600 case '5': case '6': case '7': case '8': case '9':
605 if (ENV_OPTION <= optc && optc != ENV_OPTION + '?')
607 /* Output a diagnostic, since getopt_long didn't. */
608 fprintf (stderr, "%s: ", program_name);
610 fprintf (stderr, "-%c: ", optc - ENV_OPTION);
612 fprintf (stderr, "--%s: ", longopts[longind].name);
613 fprintf (stderr, ("option not valid in "OPTIONS_VAR
614 " environment variable\n"));
618 } /* loop on all arguments */
620 /* By default, save name and timestamp on compression but do not
621 * restore them on decompression.
623 if (no_time < 0) no_time = decompress;
624 if (no_name < 0) no_name = decompress;
626 file_count = argc - optind;
630 if (ascii && !quiet) {
631 fprintf(stderr, "%s: option --ascii ignored on this system\n",
635 if (z_len == 0 || z_len > MAX_SUFFIX) {
636 fprintf(stderr, "%s: invalid suffix '%s'\n", program_name, z_suffix);
640 if (do_lzw && !decompress) work = lzw;
642 /* Allocate all global buffers (for DYN_ALLOC option) */
643 ALLOC(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
644 ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
645 ALLOC(ush, d_buf, DIST_BUFSIZE);
646 ALLOC(uch, window, 2L*WSIZE);
648 ALLOC(ush, tab_prefix, 1L<<BITS);
650 ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
651 ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
654 exiting_signal = quiet ? SIGPIPE : 0;
655 install_signal_handlers ();
657 /* And get to work */
658 if (file_count != 0) {
659 if (to_stdout && !test && !list && (!decompress || !ascii)) {
660 SET_BINARY_MODE (STDOUT_FILENO);
662 while (optind < argc) {
663 treat_file(argv[optind++]);
665 } else { /* Standard input */
668 if (stdin_was_read && close (STDIN_FILENO) != 0)
670 strcpy (ifname, "stdin");
675 /* Output any totals, and check for output errors. */
676 if (!quiet && 1 < file_count)
678 if (fflush (stdout) != 0)
683 && fdatasync (STDOUT_FILENO) != 0 && errno != EINVAL)
684 || close (STDOUT_FILENO) != 0)
688 return exit_code; /* just to avoid lint warning */
691 /* Return nonzero when at end of file on input. */
695 if (!decompress || last_member)
700 if (insize != INBUFSIZ || fill_inbuf (1) == EOF)
703 /* Unget the char that fill_inbuf got. */
710 /* ========================================================================
711 * Compress or decompress stdin
713 local void treat_stdin()
716 && (presume_input_tty
717 || isatty (decompress ? STDIN_FILENO : STDOUT_FILENO))) {
718 /* Do not send compressed data to the terminal or read it from
719 * the terminal. We get here when user invoked the program
720 * without parameters, so be helpful. According to the GNU standards:
722 * If there is one behavior you think is most useful when the output
723 * is to a terminal, and another that you think is most useful when
724 * the output is a file or a pipe, then it is usually best to make
725 * the default behavior the one that is useful with output to a
726 * terminal, and have an option for the other behavior.
728 * Here we use the --force option to get the other behavior.
732 ("%s: compressed data not %s a terminal."
733 " Use -f to force %scompression.\n"
734 "For help, type: %s -h\n"),
736 decompress ? "read from" : "written to",
737 decompress ? "de" : "",
742 if (decompress || !ascii) {
743 SET_BINARY_MODE (STDIN_FILENO);
745 if (!test && !list && (!decompress || !ascii)) {
746 SET_BINARY_MODE (STDOUT_FILENO);
748 strcpy(ifname, "stdin");
749 strcpy(ofname, "stdout");
751 /* Get the file's time stamp and size. */
752 if (fstat (STDIN_FILENO, &istat) != 0)
754 progerror ("standard input");
757 ifile_size = S_ISREG (istat.st_mode) ? istat.st_size : -1;
758 time_stamp.tv_nsec = -1;
759 if (!no_time || list)
761 if (S_ISREG (istat.st_mode))
762 time_stamp = get_stat_mtime (&istat);
764 gettime (&time_stamp);
767 clear_bufs(); /* clear input and output buffers */
771 stdin_was_read = true;
774 method = get_method(ifd);
776 do_exit(exit_code); /* error message already emitted */
780 do_list(ifd, method);
784 /* Actually do the compression/decompression. Loop over zipped members.
787 if (work (STDIN_FILENO, STDOUT_FILENO) != OK)
793 method = get_method(ifd);
794 if (method < 0) return; /* error message already emitted */
795 bytes_out = 0; /* required for length check */
800 fprintf(stderr, " OK\n");
802 } else if (!decompress) {
803 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
804 fprintf(stderr, "\n");
805 #ifdef DISPLAY_STDIN_RATIO
807 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
808 fprintf(stderr, "\n");
814 static char const dot = '.';
816 /* True if the cached directory for calls to openat etc. is DIR, with
817 length DIRLEN. DIR need not be null-terminated. DIRLEN must be
818 less than MAX_PATH_LEN. */
820 atdir_eq (char const *dir, ptrdiff_t dirlen)
823 dir = &dot, dirlen = 1;
824 return memcmp (dfname, dir, dirlen) == 0 && !dfname[dirlen];
827 /* Set the directory used for calls to openat etc. to be the directory
828 DIR, with length DIRLEN. DIR need not be null-terminated.
829 DIRLEN must be less than MAX_PATH_LEN. Return a file descriptor for
830 the directory, or -1 if one could not be obtained. */
832 atdir_set (char const *dir, ptrdiff_t dirlen)
834 /* Don't bother opening directories on older systems that
835 lack openat and unlinkat. It's not worth the porting hassle. */
836 #if HAVE_OPENAT && HAVE_UNLINKAT
837 enum { try_opening_directories = true };
839 enum { try_opening_directories = false };
842 if (try_opening_directories && ! atdir_eq (dir, dirlen))
847 dir = &dot, dirlen = 1;
848 memcpy (dfname, dir, dirlen);
849 dfname[dirlen] = '\0';
850 dfd = open (dfname, O_SEARCH | O_DIRECTORY);
856 /* ========================================================================
857 * Compress or decompress the given file
859 local void treat_file(iname)
862 /* Accept "-" as synonym for stdin */
863 if (strequ(iname, "-")) {
864 int cflag = to_stdout;
870 /* Check if the input file is present, set ifname and istat: */
871 ifd = open_input_file (iname, &istat);
875 /* If the input name is that of a directory, recurse or ignore: */
876 if (S_ISDIR(istat.st_mode)) {
879 treat_dir (ifd, iname);
880 /* Warning: ifname is now garbage */
885 WARN ((stderr, "%s: %s is a directory -- ignored\n",
886 program_name, ifname));
892 if (! S_ISREG (istat.st_mode))
895 "%s: %s is not a directory or a regular file - ignored\n",
896 program_name, ifname));
900 if (istat.st_mode & S_ISUID)
902 WARN ((stderr, "%s: %s is set-user-ID on execution - ignored\n",
903 program_name, ifname));
907 if (istat.st_mode & S_ISGID)
909 WARN ((stderr, "%s: %s is set-group-ID on execution - ignored\n",
910 program_name, ifname));
917 if (istat.st_mode & S_ISVTX)
920 "%s: %s has the sticky bit set - file ignored\n",
921 program_name, ifname));
925 if (2 <= istat.st_nlink)
927 WARN ((stderr, "%s: %s has %lu other link%c -- unchanged\n",
928 program_name, ifname,
929 (unsigned long int) istat.st_nlink - 1,
930 istat.st_nlink == 2 ? ' ' : 's'));
937 ifile_size = S_ISREG (istat.st_mode) ? istat.st_size : -1;
938 time_stamp.tv_nsec = -1;
939 if (!no_time || list)
940 time_stamp = get_stat_mtime (&istat);
942 /* Generate output file name. For -r and (-t or -l), skip files
943 * without a valid gzip suffix (check done in make_ofname).
945 if (to_stdout && !list && !test) {
946 strcpy(ofname, "stdout");
948 } else if (make_ofname() != OK) {
953 clear_bufs(); /* clear input and output buffers */
957 method = get_method(ifd); /* updates ofname if original given */
960 return; /* error message already emitted */
964 do_list(ifd, method);
965 if (close (ifd) != 0)
970 /* If compressing to a file, check if ofname is not ambiguous
971 * because the operating system truncates names. Otherwise, generate
972 * a new ofname and save the original name in the compressed file.
976 /* Keep remove_ofname_fd negative. */
978 if (create_outfile() != OK) return;
980 if (!decompress && save_orig_name && !verbose && !quiet) {
981 fprintf(stderr, "%s: %s compressed to %s\n",
982 program_name, ifname, ofname);
985 /* Keep the name even if not truncated except with --no-name: */
986 if (!save_orig_name) save_orig_name = !no_name;
989 fprintf(stderr, "%s:\t", ifname);
992 /* Actually do the compression/decompression. Loop over zipped members.
995 if ((*work)(ifd, ofd) != OK) {
996 method = -1; /* force cleanup */
1003 method = get_method(ifd);
1004 if (method < 0) break; /* error message already emitted */
1005 bytes_out = 0; /* required for length check */
1008 if (close (ifd) != 0)
1016 && ((0 <= dfd && fdatasync (dfd) != 0 && errno != EINVAL)
1017 || (fsync (ofd) != 0 && errno != EINVAL)))
1018 || close (ofd) != 0)
1025 char *ifbase = last_component (ifname);
1026 int ufd = atdir_eq (ifname, ifbase - ifname) ? dfd : -1;
1029 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
1030 remove_ofname_fd = -1;
1031 res = ufd < 0 ? xunlink (ifname) : unlinkat (ufd, ifbase, 0);
1032 unlink_errno = res == 0 ? 0 : errno;
1033 sigprocmask (SIG_SETMASK, &oldset, NULL);
1037 WARN ((stderr, "%s: ", program_name));
1040 errno = unlink_errno;
1049 remove_output_file ();
1053 /* Display statistics */
1056 fprintf(stderr, " OK");
1057 } else if (decompress) {
1058 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
1060 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
1062 if (!test && !to_stdout)
1063 fprintf(stderr, " -- %s %s", keep ? "created" : "replaced with",
1065 fprintf(stderr, "\n");
1069 /* ========================================================================
1070 * Create the output file. Return OK or ERROR.
1071 * Try several times if necessary to avoid truncating the z_suffix. For
1072 * example, do not create a compressed file of name "1234567890123."
1073 * Sets save_orig_name to true if the file name has been truncated.
1074 * IN assertions: the input file has already been open (ifd is set) and
1075 * ofname has already been updated if there was an original name.
1076 * OUT assertions: ifd and ofd are closed in case of error.
1078 local int create_outfile()
1080 int name_shortened = 0;
1081 int flags = (O_WRONLY | O_CREAT | O_EXCL
1082 | (ascii && decompress ? 0 : O_BINARY));
1083 char const *base = ofname;
1084 int atfd = AT_FDCWD;
1088 char const *b = last_component (ofname);
1089 int f = atdir_set (ofname, b - ofname);
1102 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
1103 remove_ofname_fd = ofd = openat (atfd, base, flags, S_IRUSR | S_IWUSR);
1105 sigprocmask (SIG_SETMASK, &oldset, NULL);
1114 shorten_name (ofname);
1120 if (check_ofname () != OK)
1134 if (name_shortened && decompress)
1136 /* name might be too long if an original name was saved */
1137 WARN ((stderr, "%s: %s: warning, name truncated\n",
1138 program_name, ofname));
1144 /* ========================================================================
1145 * Return a pointer to the 'z' suffix of a file name, or NULL. For all
1146 * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
1147 * accepted suffixes, in addition to the value of the --suffix option.
1148 * ".tgz" is a useful convention for tar.z files on systems limited
1149 * to 3 characters extensions. On such systems, ".?z" and ".??z" are
1150 * also accepted suffixes. For Unix, we do not want to accept any
1151 * .??z suffix as indicating a compressed file; some people use .xyz
1152 * to denote volume data.
1154 local char *get_suffix(name)
1158 char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */
1159 static char const *known_suffixes[] =
1160 {NULL, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
1161 #ifdef MAX_EXT_CHARS
1166 bool suffix_of_builtin = false;
1168 /* Normally put Z_SUFFIX at the start of KNOWN_SUFFIXES, but if it
1169 is a suffix of one of them, put it at the end. */
1170 for (suf = known_suffixes + 1; *suf; suf++)
1172 size_t suflen = strlen (*suf);
1173 if (z_len < suflen && strequ (z_suffix, *suf + suflen - z_len))
1175 suffix_of_builtin = true;
1179 known_suffixes[suffix_of_builtin
1180 ? sizeof known_suffixes / sizeof *known_suffixes - 2
1182 suf = known_suffixes + suffix_of_builtin;
1184 nlen = strlen(name);
1185 if (nlen <= MAX_SUFFIX+2) {
1186 strcpy(suffix, name);
1188 strcpy(suffix, name+nlen-MAX_SUFFIX-2);
1191 slen = strlen(suffix);
1193 int s = strlen(*suf);
1194 if (slen > s && ! ISSLASH (suffix[slen - s - 1])
1195 && strequ(suffix + slen - s, *suf)) {
1198 } while (*++suf != NULL);
1204 /* Open file NAME with the given flags and store its status
1205 into *ST. Return a file descriptor to the newly opened file, or -1
1206 (setting errno) on failure. */
1208 open_and_stat (char *name, int flags, struct stat *st)
1211 int atfd = AT_FDCWD;
1212 char const *base = name;
1214 /* Refuse to follow symbolic links unless -c or -f. */
1215 if (!to_stdout && !force)
1217 if (HAVE_WORKING_O_NOFOLLOW)
1218 flags |= O_NOFOLLOW;
1222 if (lstat (name, st) != 0)
1224 else if (S_ISLNK (st->st_mode))
1235 char const *b = last_component (name);
1236 int f = atdir_set (name, b - name);
1244 fd = openat (atfd, base, flags);
1245 if (0 <= fd && fstat (fd, st) != 0)
1256 /* ========================================================================
1257 * Set ifname to the input file name (with a suffix appended if necessary)
1258 * and istat to its stats. For decompression, if no file exists with the
1259 * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
1260 * For MSDOS, we try only z_suffix and z.
1261 * Return an open file descriptor or -1.
1264 open_input_file (iname, sbuf)
1268 int ilen; /* strlen(ifname) */
1269 int z_suffix_errno = 0;
1270 static char const *suffixes[] = {NULL, ".gz", ".z", "-z", ".Z", NULL};
1271 char const **suf = suffixes;
1273 #ifdef NO_MULTIPLE_DOTS
1274 char *dot; /* pointer to ifname extension, or NULL */
1277 int open_flags = (O_RDONLY | O_NONBLOCK | O_NOCTTY
1278 | (ascii && !decompress ? 0 : O_BINARY));
1282 if (sizeof ifname - 1 <= strlen (iname))
1285 strcpy(ifname, iname);
1287 /* If input file exists, return OK. */
1288 fd = open_and_stat (ifname, open_flags, sbuf);
1292 if (!decompress || errno != ENOENT) {
1296 /* File.ext doesn't exist. Try adding a suffix. */
1297 s = get_suffix(ifname);
1299 progerror(ifname); /* ifname already has z suffix and does not exist */
1302 #ifdef NO_MULTIPLE_DOTS
1303 dot = strrchr(ifname, '.');
1305 strcat(ifname, ".");
1306 dot = strrchr(ifname, '.');
1309 ilen = strlen(ifname);
1310 if (strequ(z_suffix, ".gz")) suf++;
1312 /* Search for all suffixes */
1314 char const *s0 = s = *suf;
1315 strcpy (ifname, iname);
1316 #ifdef NO_MULTIPLE_DOTS
1318 if (*dot == '\0') strcpy (dot, ".");
1320 #ifdef MAX_EXT_CHARS
1321 if (MAX_EXT_CHARS < strlen (s) + strlen (dot + 1))
1322 dot[MAX_EXT_CHARS + 1 - strlen (s)] = '\0';
1324 if (sizeof ifname <= ilen + strlen (s))
1327 fd = open_and_stat (ifname, open_flags, sbuf);
1330 if (errno != ENOENT)
1335 if (strequ (s0, z_suffix))
1336 z_suffix_errno = errno;
1337 } while (*++suf != NULL);
1339 /* No suffix found, complain using z_suffix: */
1340 strcpy(ifname, iname);
1341 #ifdef NO_MULTIPLE_DOTS
1342 if (*dot == '\0') strcpy(dot, ".");
1344 #ifdef MAX_EXT_CHARS
1345 if (MAX_EXT_CHARS < z_len + strlen (dot + 1))
1346 dot[MAX_EXT_CHARS + 1 - z_len] = '\0';
1348 strcat(ifname, z_suffix);
1349 errno = z_suffix_errno;
1354 fprintf (stderr, "%s: %s: file name too long\n", program_name, iname);
1359 /* ========================================================================
1360 * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
1361 * Sets save_orig_name to true if the file name has been truncated.
1363 local int make_ofname()
1365 char *suff; /* ofname z suffix */
1367 strcpy(ofname, ifname);
1368 /* strip a version number if any and get the gzip suffix if present: */
1369 suff = get_suffix(ofname);
1373 /* With -t or -l, try all files (even without .gz suffix)
1374 * except with -r (behave as with just -dr).
1376 if (!recursive && (list || test)) return OK;
1378 /* Avoid annoying messages with -r */
1379 if (verbose || (!recursive && !quiet)) {
1380 WARN((stderr,"%s: %s: unknown suffix -- ignored\n",
1381 program_name, ifname));
1385 /* Make a special case for .tgz and .taz: */
1387 if (strequ(suff, ".tgz") || strequ(suff, ".taz")) {
1388 strcpy(suff, ".tar");
1390 *suff = '\0'; /* strip the z suffix */
1392 /* ofname might be changed later if infile contains an original name */
1394 } else if (suff && ! force) {
1395 /* Avoid annoying messages with -r (see treat_dir()) */
1396 if (verbose || (!recursive && !quiet)) {
1397 /* Don't use WARN, as it affects exit status. */
1398 fprintf (stderr, "%s: %s already has %s suffix -- unchanged\n",
1399 program_name, ifname, suff);
1405 #ifdef NO_MULTIPLE_DOTS
1406 suff = strrchr(ofname, '.');
1408 if (sizeof ofname <= strlen (ofname) + 1)
1410 strcat(ofname, ".");
1411 # ifdef MAX_EXT_CHARS
1412 if (strequ(z_suffix, "z")) {
1413 if (sizeof ofname <= strlen (ofname) + 2)
1415 strcat(ofname, "gz"); /* enough room */
1418 /* On the Atari and some versions of MSDOS,
1419 * ENAMETOOLONG does not work correctly. So we
1420 * must truncate here.
1422 } else if (strlen(suff)-1 + z_len > MAX_SUFFIX) {
1423 suff[MAX_SUFFIX+1-z_len] = '\0';
1427 #endif /* NO_MULTIPLE_DOTS */
1428 if (sizeof ofname <= strlen (ofname) + z_len)
1430 strcat(ofname, z_suffix);
1432 } /* decompress ? */
1436 WARN ((stderr, "%s: %s: file name too long\n", program_name, ifname));
1440 /* Discard NBYTES input bytes from the input, or up through the next
1441 zero byte if NBYTES == (size_t) -1. If FLAGS say that the header
1442 CRC should be computed, update the CRC accordingly. */
1444 discard_input_bytes (nbytes, flags)
1450 uch c = get_byte ();
1451 if (flags & HEADER_CRC)
1453 if (nbytes != (size_t) -1)
1460 /* ========================================================================
1461 * Check the magic number of the input file and update ofname if an
1462 * original name was given and to_stdout is not set.
1463 * Return the compression method, -1 for error, -2 for warning.
1464 * Set inptr to the offset of the next byte to be processed.
1465 * Updates time_stamp if there is one and --no-time is not used.
1466 * This function may be called repeatedly for an input file consisting
1467 * of several contiguous gzip'ed members.
1468 * IN assertions: there is at least one remaining compressed member.
1469 * If the member is a zip file, it must be the only one.
1471 local int get_method(in)
1472 int in; /* input file descriptor */
1474 uch flags; /* compression flags */
1475 uch magic[10]; /* magic header */
1476 int imagic0; /* first magic byte or EOF */
1477 int imagic1; /* like magic[1], but can represent EOF */
1478 ulg stamp; /* time stamp */
1480 /* If --force and --stdout, zcat == cat, so do not complain about
1481 * premature end of file: use try_byte instead of get_byte.
1483 if (force && to_stdout) {
1484 imagic0 = try_byte();
1486 imagic1 = try_byte ();
1488 /* If try_byte returned EOF, magic[1] == (char) EOF. */
1490 magic[0] = get_byte ();
1493 magic[1] = get_byte ();
1494 imagic1 = 0; /* avoid lint warning */
1496 imagic1 = try_byte ();
1500 method = -1; /* unknown yet */
1501 part_nb++; /* number of parts in gzip file */
1504 /* assume multiple members in gzip file except for record oriented I/O */
1506 if (memcmp(magic, GZIP_MAGIC, 2) == 0
1507 || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
1509 method = (int)get_byte();
1510 if (method != DEFLATED) {
1512 "%s: %s: unknown method %d -- not supported\n",
1513 program_name, ifname, method);
1518 flags = (uch)get_byte();
1520 if ((flags & ENCRYPTED) != 0) {
1522 "%s: %s is encrypted -- not supported\n",
1523 program_name, ifname);
1527 if ((flags & RESERVED) != 0) {
1529 "%s: %s has flags 0x%x -- not supported\n",
1530 program_name, ifname, flags);
1532 if (force <= 1) return -1;
1534 stamp = (ulg)get_byte();
1535 stamp |= ((ulg)get_byte()) << 8;
1536 stamp |= ((ulg)get_byte()) << 16;
1537 stamp |= ((ulg)get_byte()) << 24;
1538 if (stamp != 0 && !no_time)
1540 time_stamp.tv_sec = stamp;
1541 time_stamp.tv_nsec = 0;
1544 magic[8] = get_byte (); /* Ignore extra flags. */
1545 magic[9] = get_byte (); /* Ignore OS type. */
1547 if (flags & HEADER_CRC)
1549 magic[2] = DEFLATED;
1551 magic[4] = stamp & 0xff;
1552 magic[5] = (stamp >> 8) & 0xff;
1553 magic[6] = (stamp >> 16) & 0xff;
1554 magic[7] = stamp >> 24;
1559 if ((flags & EXTRA_FIELD) != 0) {
1561 unsigned int len = lenbuf[0] = get_byte ();
1562 len |= (lenbuf[1] = get_byte ()) << 8;
1564 fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n",
1565 program_name, ifname, len);
1567 if (flags & HEADER_CRC)
1569 discard_input_bytes (len, flags);
1572 /* Get original file name if it was truncated */
1573 if ((flags & ORIG_NAME) != 0) {
1574 if (no_name || (to_stdout && !list) || part_nb > 1) {
1575 /* Discard the old name */
1576 discard_input_bytes (-1, flags);
1578 /* Copy the base name. Keep a directory prefix intact. */
1579 char *p = gzip_base_name (ofname);
1582 *p = (char) get_byte ();
1583 if (*p++ == '\0') break;
1584 if (p >= ofname+sizeof(ofname)) {
1585 gzip_error ("corrupted input -- file name too large");
1588 if (flags & HEADER_CRC)
1589 updcrc ((uch *) base, p - base);
1590 p = gzip_base_name (base);
1591 memmove (base, p, strlen (p) + 1);
1592 /* If necessary, adapt the name to local OS conventions: */
1594 MAKE_LEGAL_NAME(base);
1595 if (base) list=0; /* avoid warning about unused variable */
1597 } /* no_name || to_stdout */
1600 /* Discard file comment if any */
1601 if ((flags & COMMENT) != 0) {
1602 discard_input_bytes (-1, flags);
1605 if (flags & HEADER_CRC)
1607 unsigned int crc16 = updcrc (magic, 0) & 0xffff;
1608 unsigned int header16 = get_byte ();
1609 header16 |= ((unsigned int) get_byte ()) << 8;
1610 if (header16 != crc16)
1613 "%s: %s: header checksum 0x%04x != computed checksum 0x%04x\n",
1614 program_name, ifname, header16, crc16);
1622 header_bytes = inptr + 2*4; /* include crc and size */
1625 } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
1626 && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0) {
1627 /* To simplify the code, we support a zip file when alone only.
1628 * We are thus guaranteed that the entire local header fits in inbuf.
1632 if (check_zipfile(in) != OK) return -1;
1633 /* check_zipfile may get ofname from the local header */
1636 } else if (memcmp(magic, PACK_MAGIC, 2) == 0) {
1640 } else if (memcmp(magic, LZW_MAGIC, 2) == 0) {
1642 method = COMPRESSED;
1645 } else if (memcmp(magic, LZH_MAGIC, 2) == 0) {
1650 } else if (force && to_stdout && !list) { /* pass input unchanged */
1656 if (imagic0 != EOF) {
1657 write_buf (STDOUT_FILENO, magic, 1);
1661 if (method >= 0) return method;
1664 fprintf (stderr, "\n%s: %s: not in gzip format\n",
1665 program_name, ifname);
1672 for (inbyte = imagic1; inbyte == 0; inbyte = try_byte ())
1677 WARN ((stderr, "\n%s: %s: decompression OK, trailing zero bytes ignored\n",
1678 program_name, ifname));
1683 WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n",
1684 program_name, ifname));
1689 /* ========================================================================
1690 * Display the characteristics of the compressed file.
1691 * If the given method is < 0, display the accumulated totals.
1692 * IN assertions: time_stamp, header_bytes and ifile_size are initialized.
1694 local void do_list(ifd, method)
1695 int ifd; /* input file descriptor */
1696 int method; /* compression method */
1698 ulg crc; /* original crc */
1699 static int first_time = 1;
1700 static char const *const methods[MAX_METHODS] = {
1705 "", "", "", "", /* 4 to 7 reserved */
1707 int positive_off_t_width = 1;
1710 for (o = OFF_T_MAX; 9 < o; o /= 10) {
1711 positive_off_t_width++;
1714 if (first_time && method >= 0) {
1717 printf("method crc date time ");
1720 printf("%*.*s %*.*s ratio uncompressed_name\n",
1721 positive_off_t_width, positive_off_t_width, "compressed",
1722 positive_off_t_width, positive_off_t_width, "uncompressed");
1724 } else if (method < 0) {
1725 if (total_in <= 0 || total_out <= 0) return;
1729 if (verbose || !quiet) {
1730 fprint_off(stdout, total_in, positive_off_t_width);
1732 fprint_off(stdout, total_out, positive_off_t_width);
1735 display_ratio(total_out-(total_in-header_bytes), total_out, stdout);
1736 /* header_bytes is not meaningful but used to ensure the same
1737 * ratio if there is a single file.
1739 printf(" (totals)\n");
1742 crc = (ulg)~0; /* unknown */
1744 bytes_in = ifile_size;
1746 if (method == DEFLATED && !last_member) {
1747 /* Get the crc and uncompressed size for gzip'ed (not zip'ed) files.
1748 * If the lseek fails, we could use read() to get to the end, but
1749 * --list is used to get quick results.
1750 * Use "gunzip < foo.gz | wc -c" to get the uncompressed size if
1751 * you are not concerned about speed.
1753 bytes_in = lseek(ifd, (off_t)(-8), SEEK_END);
1754 if (bytes_in != -1L) {
1757 if (read(ifd, (char*)buf, sizeof(buf)) != sizeof(buf)) {
1761 bytes_out = LG(buf+4);
1767 static char const month_abbr[][4]
1768 = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1769 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
1770 struct tm *tm = localtime (&time_stamp.tv_sec);
1771 printf ("%5s %08lx ", methods[method], crc);
1773 printf ("%s%3d %02d:%02d ", month_abbr[tm->tm_mon],
1774 tm->tm_mday, tm->tm_hour, tm->tm_min);
1776 printf ("??? ?? ??:?? ");
1778 fprint_off(stdout, bytes_in, positive_off_t_width);
1780 fprint_off(stdout, bytes_out, positive_off_t_width);
1782 if (bytes_in == -1L) {
1784 bytes_in = bytes_out = header_bytes = 0;
1785 } else if (total_in >= 0) {
1786 total_in += bytes_in;
1788 if (bytes_out == -1L) {
1790 bytes_in = bytes_out = header_bytes = 0;
1791 } else if (total_out >= 0) {
1792 total_out += bytes_out;
1794 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out, stdout);
1795 printf(" %s\n", ofname);
1798 /* ========================================================================
1799 * Shorten the given name by one character, or replace a .tar extension
1800 * with .tgz. Truncate the last part of the name which is longer than
1801 * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
1802 * has only parts shorter than MIN_PART truncate the longest part.
1803 * For decompression, just remove the last character of the name.
1805 * IN assertion: for compression, the suffix of the given name is z_suffix.
1807 local void shorten_name(name)
1810 int len; /* length of name without z_suffix */
1811 char *trunc = NULL; /* character to be truncated */
1812 int plen; /* current part length */
1813 int min_part = MIN_PART; /* current minimum part length */
1819 gzip_error ("name too short");
1823 p = get_suffix(name);
1825 gzip_error ("can't recover suffix\n");
1829 /* compress 1234567890.tar to 1234567890.tgz */
1830 if (len > 4 && strequ(p-4, ".tar")) {
1831 strcpy(p-4, ".tgz");
1834 /* Try keeping short extensions intact:
1835 * 1234.678.012.gz -> 123.678.012.gz
1838 p = last_component (name);
1840 plen = strcspn(p, PART_SEP);
1842 if (plen > min_part) trunc = p-1;
1845 } while (trunc == NULL && --min_part != 0);
1847 if (trunc != NULL) {
1849 trunc[0] = trunc[1];
1853 trunc = strrchr(name, PART_SEP[0]);
1855 gzip_error ("internal error in shorten_name");
1856 if (trunc[1] == '\0') trunc--; /* force truncation */
1858 strcpy(trunc, z_suffix);
1861 /* ========================================================================
1862 * The compressed file already exists, so ask for confirmation.
1863 * Return ERROR if the file must be skipped.
1865 local int check_ofname()
1867 /* Ask permission to overwrite the existing file */
1870 fprintf (stderr, "%s: %s already exists;", program_name, ofname);
1871 if (foreground && (presume_input_tty || isatty (STDIN_FILENO))) {
1872 fprintf(stderr, " do you wish to overwrite (y or n)? ");
1877 fprintf(stderr, "\tnot overwritten\n");
1878 if (exit_code == OK) exit_code = WARNING;
1882 if (xunlink (ofname)) {
1889 /* Change the owner and group of a file. FD is a file descriptor for
1890 the file and NAME its name. Change it to user UID and to group GID.
1891 If UID or GID is -1, though, do not change the corresponding user
1894 do_chown (int fd, char const *name, uid_t uid, gid_t gid)
1898 ignore_value (fchown (fd, uid, gid));
1900 ignore_value (chown (name, uid, gid));
1905 /* ========================================================================
1906 * Copy modes, times, ownership from input file to output file.
1907 * IN assertion: to_stdout is false.
1909 local void copy_stat(ifstat)
1910 struct stat *ifstat;
1912 mode_t mode = ifstat->st_mode & S_IRWXUGO;
1916 struct timespec timespec[2];
1917 timespec[0] = get_stat_atime (ifstat);
1918 timespec[1] = get_stat_mtime (ifstat);
1920 if (decompress && 0 <= time_stamp.tv_nsec
1921 && ! (timespec[1].tv_sec == time_stamp.tv_sec
1922 && timespec[1].tv_nsec == time_stamp.tv_nsec))
1924 timespec[1] = time_stamp;
1926 fprintf(stderr, "%s: time stamp restored\n", ofname);
1930 if (fdutimens (ofd, ofname, timespec) != 0)
1933 WARN ((stderr, "%s: ", program_name));
1942 /* Change the group first, then the permissions, then the owner.
1943 That way, the permissions will be correct on systems that allow
1944 users to give away files, without introducing a security hole.
1945 Security depends on permissions not containing the setuid or
1948 do_chown (ofd, ofname, -1, ifstat->st_gid);
1951 r = fchmod (ofd, mode);
1953 r = chmod (ofname, mode);
1957 WARN ((stderr, "%s: ", program_name));
1964 do_chown (ofd, ofname, ifstat->st_uid, -1);
1969 /* ========================================================================
1970 * Recurse through the given directory.
1972 local void treat_dir (fd, dir)
1977 char nbuf[MAX_PATH_LEN];
1982 dirp = fdopendir (fd);
1990 entries = streamsavedir (dirp, SAVEDIR_SORT_NONE);
1993 if (closedir (dirp) != 0)
1998 for (entry = entries; *entry; entry += entrylen + 1) {
1999 size_t len = strlen (dir);
2000 entrylen = strlen (entry);
2001 if (strequ (entry, ".") || strequ (entry, ".."))
2003 if (len + entrylen < MAX_PATH_LEN - 2) {
2005 if (*last_component (nbuf) && !ISSLASH (nbuf[len - 1]))
2007 strcpy (nbuf + len, entry);
2010 fprintf(stderr,"%s: %s/%s: pathname too long\n",
2011 program_name, dir, entry);
2017 #endif /* ! NO_DIR */
2019 /* Make sure signals get handled properly. */
2022 install_signal_handlers ()
2024 int nsigs = sizeof handled_sig / sizeof handled_sig[0];
2028 struct sigaction act;
2030 sigemptyset (&caught_signals);
2031 for (i = 0; i < nsigs; i++)
2033 sigaction (handled_sig[i], NULL, &act);
2034 if (act.sa_handler != SIG_IGN)
2035 sigaddset (&caught_signals, handled_sig[i]);
2038 act.sa_handler = abort_gzip_signal;
2039 act.sa_mask = caught_signals;
2042 for (i = 0; i < nsigs; i++)
2043 if (sigismember (&caught_signals, handled_sig[i]))
2047 sigaction (handled_sig[i], &act, NULL);
2050 for (i = 0; i < nsigs; i++)
2051 if (signal (handled_sig[i], SIG_IGN) != SIG_IGN)
2055 signal (handled_sig[i], abort_gzip_signal);
2056 siginterrupt (handled_sig[i], 1);
2061 /* ========================================================================
2062 * Free all dynamically allocated variables and exit with the given code.
2064 local void do_exit(exitcode)
2067 static int in_exit = 0;
2069 if (in_exit) exit(exitcode);
2089 if (fclose (stdout) != 0)
2094 /* ========================================================================
2095 * Close and unlink the output file.
2098 remove_output_file ()
2103 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
2104 fd = remove_ofname_fd;
2107 remove_ofname_fd = -1;
2111 sigprocmask (SIG_SETMASK, &oldset, NULL);
2114 /* ========================================================================
2120 remove_output_file ();
2124 /* ========================================================================
2128 abort_gzip_signal (sig)
2132 signal (sig, SIG_IGN);
2133 remove_output_file ();
2134 if (sig == exiting_signal)
2136 signal (sig, SIG_DFL);