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>
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 off_t bytes_in; /* number of input bytes */
210 off_t bytes_out; /* number of output bytes */
211 static off_t total_in; /* input bytes for all files */
212 static off_t total_out; /* output bytes for all files */
213 char ifname[MAX_PATH_LEN]; /* input file name */
214 char ofname[MAX_PATH_LEN]; /* output file name */
215 static char dfname[MAX_PATH_LEN]; /* name of dir containing output file */
216 static struct stat istat; /* status for input file */
217 int ifd; /* input file descriptor */
218 int ofd; /* output file descriptor */
219 static int dfd = -1; /* output directory file descriptor */
220 unsigned insize; /* valid bytes in inbuf */
221 unsigned inptr; /* index of next byte to be processed in inbuf */
222 unsigned outcnt; /* bytes in output buffer */
223 int rsync = 0; /* make ryncable chunks */
225 static int handled_sig[] =
227 /* SIGINT must be first, as 'foreground' depends on it. */
247 /* For long options that have no equivalent short option, use a
248 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
251 PRESUME_INPUT_TTY_OPTION = CHAR_MAX + 1,
255 /* A value greater than all valid long options, used as a flag to
256 distinguish options derived from the GZIP environment variable. */
260 static char const shortopts[] = "ab:cdfhH?klLmMnNqrS:tvVZ123456789";
262 static const struct option longopts[] =
264 /* { name has_arg *flag val } */
265 {"ascii", 0, 0, 'a'}, /* ascii text mode */
266 {"to-stdout", 0, 0, 'c'}, /* write output on standard output */
267 {"stdout", 0, 0, 'c'}, /* write output on standard output */
268 {"decompress", 0, 0, 'd'}, /* decompress */
269 {"uncompress", 0, 0, 'd'}, /* decompress */
270 /* {"encrypt", 0, 0, 'e'}, encrypt */
271 {"force", 0, 0, 'f'}, /* force overwrite of output file */
272 {"help", 0, 0, 'h'}, /* give help */
273 /* {"pkzip", 0, 0, 'k'}, force output in pkzip format */
274 {"keep", 0, 0, 'k'}, /* keep (don't delete) input files */
275 {"list", 0, 0, 'l'}, /* list .gz file contents */
276 {"license", 0, 0, 'L'}, /* display software license */
277 {"no-name", 0, 0, 'n'}, /* don't save or restore original name & time */
278 {"name", 0, 0, 'N'}, /* save or restore original name & time */
279 {"-presume-input-tty", no_argument, NULL, PRESUME_INPUT_TTY_OPTION},
280 {"quiet", 0, 0, 'q'}, /* quiet mode */
281 {"silent", 0, 0, 'q'}, /* quiet mode */
282 {"synchronous",0, 0, SYNCHRONOUS_OPTION},
283 {"recursive", 0, 0, 'r'}, /* recurse through directories */
284 {"suffix", 1, 0, 'S'}, /* use given suffix instead of .gz */
285 {"test", 0, 0, 't'}, /* test compressed file integrity */
286 {"no-time", 0, 0, 'T'}, /* don't save or restore the time stamp */
287 {"verbose", 0, 0, 'v'}, /* verbose mode */
288 {"version", 0, 0, 'V'}, /* display version number */
289 {"fast", 0, 0, '1'}, /* compress faster */
290 {"best", 0, 0, '9'}, /* compress better */
291 {"lzw", 0, 0, 'Z'}, /* make output compatible with old compress */
292 {"bits", 1, 0, 'b'}, /* max number of bits per code (implies -Z) */
293 {"rsyncable", 0, 0, RSYNCABLE_OPTION}, /* make rsync-friendly archive */
297 /* local functions */
299 local void try_help (void) ATTRIBUTE_NORETURN;
300 local void help (void);
301 local void license (void);
302 local void version (void);
303 local int input_eof (void);
304 local void treat_stdin (void);
305 local void treat_file (char *iname);
306 local int create_outfile (void);
307 local char *get_suffix (char *name);
308 local int open_input_file (char *iname, struct stat *sbuf);
309 local void discard_input_bytes (size_t nbytes, unsigned int flags);
310 local int make_ofname (void);
311 local void shorten_name (char *name);
312 local int get_method (int in);
313 local void do_list (int ifd, int method);
314 local int check_ofname (void);
315 local void copy_stat (struct stat *ifstat);
316 local void install_signal_handlers (void);
317 local void remove_output_file (void);
318 local RETSIGTYPE abort_gzip_signal (int);
319 local void do_exit (int exitcode) ATTRIBUTE_NORETURN;
320 int main (int argc, char **argv);
321 static int (*work) (int infile, int outfile) = zip; /* function to call */
324 local void treat_dir (int fd, char *dir);
327 #define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
332 fprintf (stderr, "Try `%s --help' for more information.\n",
337 /* ======================================================================== */
340 static char const* const help_msg[] = {
341 "Compress or uncompress FILEs (by default, compress FILES in-place).",
343 "Mandatory arguments to long options are mandatory for short options too.",
346 " -a, --ascii ascii text; convert end-of-line using local conventions",
348 " -c, --stdout write on standard output, keep original files unchanged",
349 " -d, --decompress decompress",
350 /* -e, --encrypt encrypt */
351 " -f, --force force overwrite of output file and compress links",
352 " -h, --help give this help",
353 /* -k, --pkzip force output in pkzip format */
354 " -k, --keep keep (don't delete) input files",
355 " -l, --list list compressed file contents",
356 " -L, --license display software license",
358 " -m, --no-time do not save or restore the original modification time",
359 " -M, --time save or restore the original modification time",
361 " -n, --no-name do not save or restore the original name and time stamp",
362 " -N, --name save or restore the original name and time stamp",
363 " -q, --quiet suppress all warnings",
365 " -r, --recursive operate recursively on directories",
367 " --rsyncable make rsync-friendly archive",
368 " -S, --suffix=SUF use suffix SUF on compressed files",
369 " --synchronous synchronous output (safer if system crashes, but slower)",
370 " -t, --test test compressed file integrity",
371 " -v, --verbose verbose mode",
372 " -V, --version display version number",
373 " -1, --fast compress faster",
374 " -9, --best compress better",
376 " -Z, --lzw produce output compatible with old compress",
377 " -b, --bits=BITS max number of bits per code (implies -Z)",
380 "With no FILE, or when FILE is -, read standard input.",
382 "Report bugs to <bug-gzip@gnu.org>.",
384 char const *const *p = help_msg;
386 printf ("Usage: %s [OPTION]... [FILE]...\n", program_name);
387 while (*p) printf ("%s\n", *p++);
390 /* ======================================================================== */
393 char const *const *p = license_msg;
395 printf ("%s %s\n", program_name, Version);
396 while (*p) printf ("%s\n", *p++);
399 /* ======================================================================== */
404 printf ("Written by Jean-loup Gailly.\n");
407 local void progerror (char const *string)
410 fprintf (stderr, "%s: ", program_name);
416 /* ======================================================================== */
417 int main (int argc, char **argv)
419 int file_count; /* number of files to process */
420 size_t proglen; /* length of program_name */
425 EXPAND(argc, argv); /* wild card expansion if necessary */
427 program_name = gzip_base_name (argv[0]);
428 proglen = strlen (program_name);
430 atexit (close_stdin);
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(); do_exit(OK); break;
534 list = decompress = to_stdout = 1; break;
536 license(); do_exit(OK); 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(); do_exit(OK); 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 */
669 /* Output any totals, and check for output errors. */
670 if (!quiet && 1 < file_count)
672 if (fflush (stdout) != 0)
675 if (to_stdout && synchronous && fdatasync (STDOUT_FILENO) != 0
676 && errno != EINVAL && errno != EBADF)
679 return exit_code; /* just to avoid lint warning */
682 /* Return nonzero when at end of file on input. */
686 if (!decompress || last_member)
691 if (insize != INBUFSIZ || fill_inbuf (1) == EOF)
694 /* Unget the char that fill_inbuf got. */
701 /* ========================================================================
702 * Compress or decompress stdin
704 local void treat_stdin()
707 && (presume_input_tty
708 || isatty (decompress ? STDIN_FILENO : STDOUT_FILENO))) {
709 /* Do not send compressed data to the terminal or read it from
710 * the terminal. We get here when user invoked the program
711 * without parameters, so be helpful. According to the GNU standards:
713 * If there is one behavior you think is most useful when the output
714 * is to a terminal, and another that you think is most useful when
715 * the output is a file or a pipe, then it is usually best to make
716 * the default behavior the one that is useful with output to a
717 * terminal, and have an option for the other behavior.
719 * Here we use the --force option to get the other behavior.
723 ("%s: compressed data not %s a terminal."
724 " Use -f to force %scompression.\n"
725 "For help, type: %s -h\n"),
727 decompress ? "read from" : "written to",
728 decompress ? "de" : "",
733 if (decompress || !ascii) {
734 SET_BINARY_MODE (STDIN_FILENO);
736 if (!test && !list && (!decompress || !ascii)) {
737 SET_BINARY_MODE (STDOUT_FILENO);
739 strcpy(ifname, "stdin");
740 strcpy(ofname, "stdout");
742 /* Get the file's time stamp and size. */
743 if (fstat (STDIN_FILENO, &istat) != 0)
745 progerror ("standard input");
748 ifile_size = S_ISREG (istat.st_mode) ? istat.st_size : -1;
749 time_stamp.tv_nsec = -1;
750 if (!no_time || list)
752 if (S_ISREG (istat.st_mode))
753 time_stamp = get_stat_mtime (&istat);
755 gettime (&time_stamp);
758 clear_bufs(); /* clear input and output buffers */
764 method = get_method(ifd);
766 do_exit(exit_code); /* error message already emitted */
770 do_list(ifd, method);
774 /* Actually do the compression/decompression. Loop over zipped members.
777 if (work (STDIN_FILENO, STDOUT_FILENO) != OK)
783 method = get_method(ifd);
784 if (method < 0) return; /* error message already emitted */
785 bytes_out = 0; /* required for length check */
790 fprintf(stderr, " OK\n");
792 } else if (!decompress) {
793 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
794 fprintf(stderr, "\n");
795 #ifdef DISPLAY_STDIN_RATIO
797 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
798 fprintf(stderr, "\n");
804 static char const dot = '.';
806 /* True if the cached directory for calls to openat etc. is DIR, with
807 length DIRLEN. DIR need not be null-terminated. DIRLEN must be
808 less than MAX_PATH_LEN. */
810 atdir_eq (char const *dir, ptrdiff_t dirlen)
813 dir = &dot, dirlen = 1;
814 return memcmp (dfname, dir, dirlen) == 0 && !dfname[dirlen];
817 /* Set the directory used for calls to openat etc. to be the directory
818 DIR, with length DIRLEN. DIR need not be null-terminated.
819 DIRLEN must be less than MAX_PATH_LEN. Return a file descriptor for
820 the directory, or -1 if one could not be obtained. */
822 atdir_set (char const *dir, ptrdiff_t dirlen)
824 /* Don't bother opening directories on older systems that
825 lack openat and unlinkat. It's not worth the porting hassle. */
826 #if HAVE_OPENAT && HAVE_UNLINKAT
827 enum { try_opening_directories = true };
829 enum { try_opening_directories = false };
832 if (try_opening_directories && ! atdir_eq (dir, dirlen))
837 dir = &dot, dirlen = 1;
838 memcpy (dfname, dir, dirlen);
839 dfname[dirlen] = '\0';
840 dfd = open (dfname, O_SEARCH | O_DIRECTORY);
846 /* ========================================================================
847 * Compress or decompress the given file
849 local void treat_file(iname)
852 /* Accept "-" as synonym for stdin */
853 if (strequ(iname, "-")) {
854 int cflag = to_stdout;
860 /* Check if the input file is present, set ifname and istat: */
861 ifd = open_input_file (iname, &istat);
865 /* If the input name is that of a directory, recurse or ignore: */
866 if (S_ISDIR(istat.st_mode)) {
869 treat_dir (ifd, iname);
870 /* Warning: ifname is now garbage */
875 WARN ((stderr, "%s: %s is a directory -- ignored\n",
876 program_name, ifname));
882 if (! S_ISREG (istat.st_mode))
885 "%s: %s is not a directory or a regular file - ignored\n",
886 program_name, ifname));
890 if (istat.st_mode & S_ISUID)
892 WARN ((stderr, "%s: %s is set-user-ID on execution - ignored\n",
893 program_name, ifname));
897 if (istat.st_mode & S_ISGID)
899 WARN ((stderr, "%s: %s is set-group-ID on execution - ignored\n",
900 program_name, ifname));
907 if (istat.st_mode & S_ISVTX)
910 "%s: %s has the sticky bit set - file ignored\n",
911 program_name, ifname));
915 if (2 <= istat.st_nlink)
917 WARN ((stderr, "%s: %s has %lu other link%c -- unchanged\n",
918 program_name, ifname,
919 (unsigned long int) istat.st_nlink - 1,
920 istat.st_nlink == 2 ? ' ' : 's'));
927 ifile_size = S_ISREG (istat.st_mode) ? istat.st_size : -1;
928 time_stamp.tv_nsec = -1;
929 if (!no_time || list)
930 time_stamp = get_stat_mtime (&istat);
932 /* Generate output file name. For -r and (-t or -l), skip files
933 * without a valid gzip suffix (check done in make_ofname).
935 if (to_stdout && !list && !test) {
936 strcpy(ofname, "stdout");
938 } else if (make_ofname() != OK) {
943 clear_bufs(); /* clear input and output buffers */
947 method = get_method(ifd); /* updates ofname if original given */
950 return; /* error message already emitted */
954 do_list(ifd, method);
955 if (close (ifd) != 0)
960 /* If compressing to a file, check if ofname is not ambiguous
961 * because the operating system truncates names. Otherwise, generate
962 * a new ofname and save the original name in the compressed file.
966 /* Keep remove_ofname_fd negative. */
968 if (create_outfile() != OK) return;
970 if (!decompress && save_orig_name && !verbose && !quiet) {
971 fprintf(stderr, "%s: %s compressed to %s\n",
972 program_name, ifname, ofname);
975 /* Keep the name even if not truncated except with --no-name: */
976 if (!save_orig_name) save_orig_name = !no_name;
979 fprintf(stderr, "%s:\t", ifname);
982 /* Actually do the compression/decompression. Loop over zipped members.
985 if ((*work)(ifd, ofd) != OK) {
986 method = -1; /* force cleanup */
993 method = get_method(ifd);
994 if (method < 0) break; /* error message already emitted */
995 bytes_out = 0; /* required for length check */
998 if (close (ifd) != 0)
1006 && ((0 <= dfd && fdatasync (dfd) != 0 && errno != EINVAL)
1007 || (fsync (ofd) != 0 && errno != EINVAL)))
1008 || close (ofd) != 0)
1015 char *ifbase = last_component (ifname);
1016 int ufd = atdir_eq (ifname, ifbase - ifname) ? dfd : -1;
1019 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
1020 remove_ofname_fd = -1;
1021 res = ufd < 0 ? xunlink (ifname) : unlinkat (ufd, ifbase, 0);
1022 unlink_errno = res == 0 ? 0 : errno;
1023 sigprocmask (SIG_SETMASK, &oldset, NULL);
1027 WARN ((stderr, "%s: ", program_name));
1030 errno = unlink_errno;
1039 remove_output_file ();
1043 /* Display statistics */
1046 fprintf(stderr, " OK");
1047 } else if (decompress) {
1048 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
1050 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
1052 if (!test && !to_stdout)
1053 fprintf(stderr, " -- %s %s", keep ? "created" : "replaced with",
1055 fprintf(stderr, "\n");
1059 /* ========================================================================
1060 * Create the output file. Return OK or ERROR.
1061 * Try several times if necessary to avoid truncating the z_suffix. For
1062 * example, do not create a compressed file of name "1234567890123."
1063 * Sets save_orig_name to true if the file name has been truncated.
1064 * IN assertions: the input file has already been open (ifd is set) and
1065 * ofname has already been updated if there was an original name.
1066 * OUT assertions: ifd and ofd are closed in case of error.
1068 local int create_outfile()
1070 int name_shortened = 0;
1071 int flags = (O_WRONLY | O_CREAT | O_EXCL
1072 | (ascii && decompress ? 0 : O_BINARY));
1073 char const *base = ofname;
1074 int atfd = AT_FDCWD;
1078 char const *b = last_component (ofname);
1079 int f = atdir_set (ofname, b - ofname);
1092 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
1093 remove_ofname_fd = ofd = openat (atfd, base, flags, S_IRUSR | S_IWUSR);
1095 sigprocmask (SIG_SETMASK, &oldset, NULL);
1104 shorten_name (ofname);
1110 if (check_ofname () != OK)
1124 if (name_shortened && decompress)
1126 /* name might be too long if an original name was saved */
1127 WARN ((stderr, "%s: %s: warning, name truncated\n",
1128 program_name, ofname));
1134 /* ========================================================================
1135 * Return a pointer to the 'z' suffix of a file name, or NULL. For all
1136 * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
1137 * accepted suffixes, in addition to the value of the --suffix option.
1138 * ".tgz" is a useful convention for tar.z files on systems limited
1139 * to 3 characters extensions. On such systems, ".?z" and ".??z" are
1140 * also accepted suffixes. For Unix, we do not want to accept any
1141 * .??z suffix as indicating a compressed file; some people use .xyz
1142 * to denote volume data.
1143 * On systems allowing multiple versions of the same file (such as VMS),
1144 * this function removes any version suffix in the given name.
1146 local char *get_suffix(name)
1150 char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */
1151 static char const *known_suffixes[] =
1152 {NULL, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
1153 #ifdef MAX_EXT_CHARS
1158 bool suffix_of_builtin = false;
1160 /* Normally put Z_SUFFIX at the start of KNOWN_SUFFIXES, but if it
1161 is a suffix of one of them, put it at the end. */
1162 for (suf = known_suffixes + 1; *suf; suf++)
1164 size_t suflen = strlen (*suf);
1165 if (z_len < suflen && strequ (z_suffix, *suf + suflen - z_len))
1167 suffix_of_builtin = true;
1171 known_suffixes[suffix_of_builtin
1172 ? sizeof known_suffixes / sizeof *known_suffixes - 2
1174 suf = known_suffixes + suffix_of_builtin;
1177 /* strip a version number from the file name */
1179 char *v = strrchr(name, SUFFIX_SEP);
1180 if (v != NULL) *v = '\0';
1183 nlen = strlen(name);
1184 if (nlen <= MAX_SUFFIX+2) {
1185 strcpy(suffix, name);
1187 strcpy(suffix, name+nlen-MAX_SUFFIX-2);
1190 slen = strlen(suffix);
1192 int s = strlen(*suf);
1193 if (slen > s && suffix[slen-s-1] != PATH_SEP
1194 && strequ(suffix + slen - s, *suf)) {
1197 } while (*++suf != NULL);
1203 /* Open file NAME with the given flags and store its status
1204 into *ST. Return a file descriptor to the newly opened file, or -1
1205 (setting errno) on failure. */
1207 open_and_stat (char *name, int flags, struct stat *st)
1210 int atfd = AT_FDCWD;
1211 char const *base = name;
1213 /* Refuse to follow symbolic links unless -c or -f. */
1214 if (!to_stdout && !force)
1216 if (HAVE_WORKING_O_NOFOLLOW)
1217 flags |= O_NOFOLLOW;
1220 #if HAVE_LSTAT || defined lstat
1221 if (lstat (name, st) != 0)
1223 else if (S_ISLNK (st->st_mode))
1234 char const *b = last_component (name);
1235 int f = atdir_set (name, b - name);
1243 fd = openat (atfd, base, flags);
1244 if (0 <= fd && fstat (fd, st) != 0)
1255 /* ========================================================================
1256 * Set ifname to the input file name (with a suffix appended if necessary)
1257 * and istat to its stats. For decompression, if no file exists with the
1258 * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
1259 * For MSDOS, we try only z_suffix and z.
1260 * Return an open file descriptor or -1.
1263 open_input_file (iname, sbuf)
1267 int ilen; /* strlen(ifname) */
1268 int z_suffix_errno = 0;
1269 static char const *suffixes[] = {NULL, ".gz", ".z", "-z", ".Z", NULL};
1270 char const **suf = suffixes;
1272 #ifdef NO_MULTIPLE_DOTS
1273 char *dot; /* pointer to ifname extension, or NULL */
1276 int open_flags = (O_RDONLY | O_NONBLOCK | O_NOCTTY
1277 | (ascii && !decompress ? 0 : O_BINARY));
1281 if (sizeof ifname - 1 <= strlen (iname))
1284 strcpy(ifname, iname);
1286 /* If input file exists, return OK. */
1287 fd = open_and_stat (ifname, open_flags, sbuf);
1291 if (!decompress || errno != ENOENT) {
1295 /* file.ext doesn't exist, try adding a suffix (after removing any
1296 * version number for VMS).
1298 s = get_suffix(ifname);
1300 progerror(ifname); /* ifname already has z suffix and does not exist */
1303 #ifdef NO_MULTIPLE_DOTS
1304 dot = strrchr(ifname, '.');
1306 strcat(ifname, ".");
1307 dot = strrchr(ifname, '.');
1310 ilen = strlen(ifname);
1311 if (strequ(z_suffix, ".gz")) suf++;
1313 /* Search for all suffixes */
1315 char const *s0 = s = *suf;
1316 strcpy (ifname, iname);
1317 #ifdef NO_MULTIPLE_DOTS
1319 if (*dot == '\0') strcpy (dot, ".");
1321 #ifdef MAX_EXT_CHARS
1322 if (MAX_EXT_CHARS < strlen (s) + strlen (dot + 1))
1323 dot[MAX_EXT_CHARS + 1 - strlen (s)] = '\0';
1325 if (sizeof ifname <= ilen + strlen (s))
1328 fd = open_and_stat (ifname, open_flags, sbuf);
1331 if (errno != ENOENT)
1336 if (strequ (s0, z_suffix))
1337 z_suffix_errno = errno;
1338 } while (*++suf != NULL);
1340 /* No suffix found, complain using z_suffix: */
1341 strcpy(ifname, iname);
1342 #ifdef NO_MULTIPLE_DOTS
1343 if (*dot == '\0') strcpy(dot, ".");
1345 #ifdef MAX_EXT_CHARS
1346 if (MAX_EXT_CHARS < z_len + strlen (dot + 1))
1347 dot[MAX_EXT_CHARS + 1 - z_len] = '\0';
1349 strcat(ifname, z_suffix);
1350 errno = z_suffix_errno;
1355 fprintf (stderr, "%s: %s: file name too long\n", program_name, iname);
1360 /* ========================================================================
1361 * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
1362 * Sets save_orig_name to true if the file name has been truncated.
1364 local int make_ofname()
1366 char *suff; /* ofname z suffix */
1368 strcpy(ofname, ifname);
1369 /* strip a version number if any and get the gzip suffix if present: */
1370 suff = get_suffix(ofname);
1374 /* With -t or -l, try all files (even without .gz suffix)
1375 * except with -r (behave as with just -dr).
1377 if (!recursive && (list || test)) return OK;
1379 /* Avoid annoying messages with -r */
1380 if (verbose || (!recursive && !quiet)) {
1381 WARN((stderr,"%s: %s: unknown suffix -- ignored\n",
1382 program_name, ifname));
1386 /* Make a special case for .tgz and .taz: */
1388 if (strequ(suff, ".tgz") || strequ(suff, ".taz")) {
1389 strcpy(suff, ".tar");
1391 *suff = '\0'; /* strip the z suffix */
1393 /* ofname might be changed later if infile contains an original name */
1395 } else if (suff && ! force) {
1396 /* Avoid annoying messages with -r (see treat_dir()) */
1397 if (verbose || (!recursive && !quiet)) {
1398 /* Don't use WARN, as it affects exit status. */
1399 fprintf (stderr, "%s: %s already has %s suffix -- unchanged\n",
1400 program_name, ifname, suff);
1406 #ifdef NO_MULTIPLE_DOTS
1407 suff = strrchr(ofname, '.');
1409 if (sizeof ofname <= strlen (ofname) + 1)
1411 strcat(ofname, ".");
1412 # ifdef MAX_EXT_CHARS
1413 if (strequ(z_suffix, "z")) {
1414 if (sizeof ofname <= strlen (ofname) + 2)
1416 strcat(ofname, "gz"); /* enough room */
1419 /* On the Atari and some versions of MSDOS,
1420 * ENAMETOOLONG does not work correctly. So we
1421 * must truncate here.
1423 } else if (strlen(suff)-1 + z_len > MAX_SUFFIX) {
1424 suff[MAX_SUFFIX+1-z_len] = '\0';
1428 #endif /* NO_MULTIPLE_DOTS */
1429 if (sizeof ofname <= strlen (ofname) + z_len)
1431 strcat(ofname, z_suffix);
1433 } /* decompress ? */
1437 WARN ((stderr, "%s: %s: file name too long\n", program_name, ifname));
1441 /* Discard NBYTES input bytes from the input, or up through the next
1442 zero byte if NBYTES == (size_t) -1. If FLAGS say that the header
1443 CRC should be computed, update the CRC accordingly. */
1445 discard_input_bytes (nbytes, flags)
1451 uch c = get_byte ();
1452 if (flags & HEADER_CRC)
1454 if (nbytes != (size_t) -1)
1461 /* ========================================================================
1462 * Check the magic number of the input file and update ofname if an
1463 * original name was given and to_stdout is not set.
1464 * Return the compression method, -1 for error, -2 for warning.
1465 * Set inptr to the offset of the next byte to be processed.
1466 * Updates time_stamp if there is one and --no-time is not used.
1467 * This function may be called repeatedly for an input file consisting
1468 * of several contiguous gzip'ed members.
1469 * IN assertions: there is at least one remaining compressed member.
1470 * If the member is a zip file, it must be the only one.
1472 local int get_method(in)
1473 int in; /* input file descriptor */
1475 uch flags; /* compression flags */
1476 uch magic[10]; /* magic header */
1477 int imagic0; /* first magic byte or EOF */
1478 int imagic1; /* like magic[1], but can represent EOF */
1479 ulg stamp; /* time stamp */
1481 /* If --force and --stdout, zcat == cat, so do not complain about
1482 * premature end of file: use try_byte instead of get_byte.
1484 if (force && to_stdout) {
1485 imagic0 = try_byte();
1487 imagic1 = try_byte ();
1489 /* If try_byte returned EOF, magic[1] == (char) EOF. */
1491 magic[0] = get_byte ();
1494 magic[1] = get_byte ();
1495 imagic1 = 0; /* avoid lint warning */
1497 imagic1 = try_byte ();
1501 method = -1; /* unknown yet */
1502 part_nb++; /* number of parts in gzip file */
1504 last_member = RECORD_IO;
1505 /* assume multiple members in gzip file except for record oriented I/O */
1507 if (memcmp(magic, GZIP_MAGIC, 2) == 0
1508 || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
1510 method = (int)get_byte();
1511 if (method != DEFLATED) {
1513 "%s: %s: unknown method %d -- not supported\n",
1514 program_name, ifname, method);
1519 flags = (uch)get_byte();
1521 if ((flags & ENCRYPTED) != 0) {
1523 "%s: %s is encrypted -- not supported\n",
1524 program_name, ifname);
1528 if ((flags & RESERVED) != 0) {
1530 "%s: %s has flags 0x%x -- not supported\n",
1531 program_name, ifname, flags);
1533 if (force <= 1) return -1;
1535 stamp = (ulg)get_byte();
1536 stamp |= ((ulg)get_byte()) << 8;
1537 stamp |= ((ulg)get_byte()) << 16;
1538 stamp |= ((ulg)get_byte()) << 24;
1539 if (stamp != 0 && !no_time)
1541 time_stamp.tv_sec = stamp;
1542 time_stamp.tv_nsec = 0;
1545 magic[8] = get_byte (); /* Ignore extra flags. */
1546 magic[9] = get_byte (); /* Ignore OS type. */
1548 if (flags & HEADER_CRC)
1550 magic[2] = DEFLATED;
1552 magic[4] = stamp & 0xff;
1553 magic[5] = (stamp >> 8) & 0xff;
1554 magic[6] = (stamp >> 16) & 0xff;
1555 magic[7] = stamp >> 24;
1560 if ((flags & EXTRA_FIELD) != 0) {
1562 unsigned int len = lenbuf[0] = get_byte ();
1563 len |= (lenbuf[1] = get_byte ()) << 8;
1565 fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n",
1566 program_name, ifname, len);
1568 if (flags & HEADER_CRC)
1570 discard_input_bytes (len, flags);
1573 /* Get original file name if it was truncated */
1574 if ((flags & ORIG_NAME) != 0) {
1575 if (no_name || (to_stdout && !list) || part_nb > 1) {
1576 /* Discard the old name */
1577 discard_input_bytes (-1, flags);
1579 /* Copy the base name. Keep a directory prefix intact. */
1580 char *p = gzip_base_name (ofname);
1583 *p = (char) get_byte ();
1584 if (*p++ == '\0') break;
1585 if (p >= ofname+sizeof(ofname)) {
1586 gzip_error ("corrupted input -- file name too large");
1589 if (flags & HEADER_CRC)
1590 updcrc ((uch *) base, p - base);
1591 p = gzip_base_name (base);
1592 memmove (base, p, strlen (p) + 1);
1593 /* If necessary, adapt the name to local OS conventions: */
1595 MAKE_LEGAL_NAME(base);
1596 if (base) list=0; /* avoid warning about unused variable */
1598 } /* no_name || to_stdout */
1601 /* Discard file comment if any */
1602 if ((flags & COMMENT) != 0) {
1603 discard_input_bytes (-1, flags);
1606 if (flags & HEADER_CRC)
1608 unsigned int crc16 = updcrc (magic, 0) & 0xffff;
1609 unsigned int header16 = get_byte ();
1610 header16 |= ((unsigned int) get_byte ()) << 8;
1611 if (header16 != crc16)
1614 "%s: %s: header checksum 0x%04x != computed checksum 0x%04x\n",
1615 program_name, ifname, header16, crc16);
1623 header_bytes = inptr + 2*4; /* include crc and size */
1626 } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
1627 && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0) {
1628 /* To simplify the code, we support a zip file when alone only.
1629 * We are thus guaranteed that the entire local header fits in inbuf.
1633 if (check_zipfile(in) != OK) return -1;
1634 /* check_zipfile may get ofname from the local header */
1637 } else if (memcmp(magic, PACK_MAGIC, 2) == 0) {
1641 } else if (memcmp(magic, LZW_MAGIC, 2) == 0) {
1643 method = COMPRESSED;
1646 } else if (memcmp(magic, LZH_MAGIC, 2) == 0) {
1651 } else if (force && to_stdout && !list) { /* pass input unchanged */
1657 if (imagic0 != EOF) {
1658 write_buf (STDOUT_FILENO, magic, 1);
1662 if (method >= 0) return method;
1665 fprintf (stderr, "\n%s: %s: not in gzip format\n",
1666 program_name, ifname);
1673 for (inbyte = imagic1; inbyte == 0; inbyte = try_byte ())
1678 WARN ((stderr, "\n%s: %s: decompression OK, trailing zero bytes ignored\n",
1679 program_name, ifname));
1684 WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n",
1685 program_name, ifname));
1690 /* ========================================================================
1691 * Display the characteristics of the compressed file.
1692 * If the given method is < 0, display the accumulated totals.
1693 * IN assertions: time_stamp, header_bytes and ifile_size are initialized.
1695 local void do_list(ifd, method)
1696 int ifd; /* input file descriptor */
1697 int method; /* compression method */
1699 ulg crc; /* original crc */
1700 static int first_time = 1;
1701 static char const *const methods[MAX_METHODS] = {
1706 "", "", "", "", /* 4 to 7 reserved */
1708 int positive_off_t_width = 1;
1711 for (o = OFF_T_MAX; 9 < o; o /= 10) {
1712 positive_off_t_width++;
1715 if (first_time && method >= 0) {
1718 printf("method crc date time ");
1721 printf("%*.*s %*.*s ratio uncompressed_name\n",
1722 positive_off_t_width, positive_off_t_width, "compressed",
1723 positive_off_t_width, positive_off_t_width, "uncompressed");
1725 } else if (method < 0) {
1726 if (total_in <= 0 || total_out <= 0) return;
1730 if (verbose || !quiet) {
1731 fprint_off(stdout, total_in, positive_off_t_width);
1733 fprint_off(stdout, total_out, positive_off_t_width);
1736 display_ratio(total_out-(total_in-header_bytes), total_out, stdout);
1737 /* header_bytes is not meaningful but used to ensure the same
1738 * ratio if there is a single file.
1740 printf(" (totals)\n");
1743 crc = (ulg)~0; /* unknown */
1745 bytes_in = ifile_size;
1747 if (!RECORD_IO && method == DEFLATED && !last_member) {
1748 /* Get the crc and uncompressed size for gzip'ed (not zip'ed) files.
1749 * If the lseek fails, we could use read() to get to the end, but
1750 * --list is used to get quick results.
1751 * Use "gunzip < foo.gz | wc -c" to get the uncompressed size if
1752 * you are not concerned about speed.
1754 bytes_in = lseek(ifd, (off_t)(-8), SEEK_END);
1755 if (bytes_in != -1L) {
1758 if (read(ifd, (char*)buf, sizeof(buf)) != sizeof(buf)) {
1762 bytes_out = LG(buf+4);
1768 static char const month_abbr[][4]
1769 = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1770 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
1771 struct tm *tm = localtime (&time_stamp.tv_sec);
1772 printf ("%5s %08lx ", methods[method], crc);
1774 printf ("%s%3d %02d:%02d ", month_abbr[tm->tm_mon],
1775 tm->tm_mday, tm->tm_hour, tm->tm_min);
1777 printf ("??? ?? ??:?? ");
1779 fprint_off(stdout, bytes_in, positive_off_t_width);
1781 fprint_off(stdout, bytes_out, positive_off_t_width);
1783 if (bytes_in == -1L) {
1785 bytes_in = bytes_out = header_bytes = 0;
1786 } else if (total_in >= 0) {
1787 total_in += bytes_in;
1789 if (bytes_out == -1L) {
1791 bytes_in = bytes_out = header_bytes = 0;
1792 } else if (total_out >= 0) {
1793 total_out += bytes_out;
1795 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out, stdout);
1796 printf(" %s\n", ofname);
1799 /* ========================================================================
1800 * Shorten the given name by one character, or replace a .tar extension
1801 * with .tgz. Truncate the last part of the name which is longer than
1802 * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
1803 * has only parts shorter than MIN_PART truncate the longest part.
1804 * For decompression, just remove the last character of the name.
1806 * IN assertion: for compression, the suffix of the given name is z_suffix.
1808 local void shorten_name(name)
1811 int len; /* length of name without z_suffix */
1812 char *trunc = NULL; /* character to be truncated */
1813 int plen; /* current part length */
1814 int min_part = MIN_PART; /* current minimum part length */
1820 gzip_error ("name too short");
1824 p = get_suffix(name);
1826 gzip_error ("can't recover suffix\n");
1830 /* compress 1234567890.tar to 1234567890.tgz */
1831 if (len > 4 && strequ(p-4, ".tar")) {
1832 strcpy(p-4, ".tgz");
1835 /* Try keeping short extensions intact:
1836 * 1234.678.012.gz -> 123.678.012.gz
1839 p = strrchr(name, PATH_SEP);
1842 plen = strcspn(p, PART_SEP);
1844 if (plen > min_part) trunc = p-1;
1847 } while (trunc == NULL && --min_part != 0);
1849 if (trunc != NULL) {
1851 trunc[0] = trunc[1];
1855 trunc = strrchr(name, PART_SEP[0]);
1857 gzip_error ("internal error in shorten_name");
1858 if (trunc[1] == '\0') trunc--; /* force truncation */
1860 strcpy(trunc, z_suffix);
1863 /* ========================================================================
1864 * The compressed file already exists, so ask for confirmation.
1865 * Return ERROR if the file must be skipped.
1867 local int check_ofname()
1869 /* Ask permission to overwrite the existing file */
1872 fprintf (stderr, "%s: %s already exists;", program_name, ofname);
1873 if (foreground && (presume_input_tty || isatty (STDIN_FILENO))) {
1874 fprintf(stderr, " do you wish to overwrite (y or n)? ");
1879 fprintf(stderr, "\tnot overwritten\n");
1880 if (exit_code == OK) exit_code = WARNING;
1884 if (xunlink (ofname)) {
1891 /* Change the owner and group of a file. FD is a file descriptor for
1892 the file and NAME its name. Change it to user UID and to group GID.
1893 If UID or GID is -1, though, do not change the corresponding user
1896 do_chown (int fd, char const *name, uid_t uid, gid_t gid)
1900 ignore_value (fchown (fd, uid, gid));
1902 ignore_value (chown (name, uid, gid));
1907 /* ========================================================================
1908 * Copy modes, times, ownership from input file to output file.
1909 * IN assertion: to_stdout is false.
1911 local void copy_stat(ifstat)
1912 struct stat *ifstat;
1914 mode_t mode = ifstat->st_mode & S_IRWXUGO;
1918 struct timespec timespec[2];
1919 timespec[0] = get_stat_atime (ifstat);
1920 timespec[1] = get_stat_mtime (ifstat);
1922 if (decompress && 0 <= time_stamp.tv_nsec
1923 && ! (timespec[1].tv_sec == time_stamp.tv_sec
1924 && timespec[1].tv_nsec == time_stamp.tv_nsec))
1926 timespec[1] = time_stamp;
1928 fprintf(stderr, "%s: time stamp restored\n", ofname);
1932 if (fdutimens (ofd, ofname, timespec) != 0)
1935 WARN ((stderr, "%s: ", program_name));
1944 /* Change the group first, then the permissions, then the owner.
1945 That way, the permissions will be correct on systems that allow
1946 users to give away files, without introducing a security hole.
1947 Security depends on permissions not containing the setuid or
1950 do_chown (ofd, ofname, -1, ifstat->st_gid);
1953 r = fchmod (ofd, mode);
1955 r = chmod (ofname, mode);
1959 WARN ((stderr, "%s: ", program_name));
1966 do_chown (ofd, ofname, ifstat->st_uid, -1);
1971 /* ========================================================================
1972 * Recurse through the given directory.
1974 local void treat_dir (fd, dir)
1979 char nbuf[MAX_PATH_LEN];
1984 dirp = fdopendir (fd);
1992 entries = streamsavedir (dirp, SAVEDIR_SORT_NONE);
1995 if (closedir (dirp) != 0)
2000 for (entry = entries; *entry; entry += entrylen + 1) {
2001 size_t len = strlen (dir);
2002 entrylen = strlen (entry);
2003 if (strequ (entry, ".") || strequ (entry, ".."))
2005 if (len + entrylen < MAX_PATH_LEN - 2) {
2007 if (len != 0 /* dir = "" means current dir on Amiga */
2009 && dir[len-1] != PATH_SEP2
2012 && dir[len-1] != PATH_SEP3
2015 nbuf[len++] = PATH_SEP;
2017 strcpy (nbuf + len, entry);
2020 fprintf(stderr,"%s: %s/%s: pathname too long\n",
2021 program_name, dir, entry);
2027 #endif /* ! NO_DIR */
2029 /* Make sure signals get handled properly. */
2032 install_signal_handlers ()
2034 int nsigs = sizeof handled_sig / sizeof handled_sig[0];
2038 struct sigaction act;
2040 sigemptyset (&caught_signals);
2041 for (i = 0; i < nsigs; i++)
2043 sigaction (handled_sig[i], NULL, &act);
2044 if (act.sa_handler != SIG_IGN)
2045 sigaddset (&caught_signals, handled_sig[i]);
2048 act.sa_handler = abort_gzip_signal;
2049 act.sa_mask = caught_signals;
2052 for (i = 0; i < nsigs; i++)
2053 if (sigismember (&caught_signals, handled_sig[i]))
2057 sigaction (handled_sig[i], &act, NULL);
2060 for (i = 0; i < nsigs; i++)
2061 if (signal (handled_sig[i], SIG_IGN) != SIG_IGN)
2065 signal (handled_sig[i], abort_gzip_signal);
2066 siginterrupt (handled_sig[i], 1);
2071 /* ========================================================================
2072 * Free all dynamically allocated variables and exit with the given code.
2074 local void do_exit(exitcode)
2077 static int in_exit = 0;
2079 if (in_exit) exit(exitcode);
2096 /* ========================================================================
2097 * Close and unlink the output file.
2100 remove_output_file ()
2105 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
2106 fd = remove_ofname_fd;
2109 remove_ofname_fd = -1;
2113 sigprocmask (SIG_SETMASK, &oldset, NULL);
2116 /* ========================================================================
2122 remove_output_file ();
2126 /* ========================================================================
2130 abort_gzip_signal (sig)
2134 signal (sig, SIG_IGN);
2135 remove_output_file ();
2136 if (sig == exiting_signal)
2138 signal (sig, SIG_DFL);