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 */
224 static int handled_sig[] =
226 /* SIGINT must be first, as 'foreground' depends on it. */
246 /* For long options that have no equivalent short option, use a
247 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
250 PRESUME_INPUT_TTY_OPTION = CHAR_MAX + 1,
253 /* A value greater than all valid long options, used as a flag to
254 distinguish options derived from the GZIP environment variable. */
258 static char const shortopts[] = "ab:cdfhH?klLmMnNqrS:tvVZ123456789";
260 static const struct option longopts[] =
262 /* { name has_arg *flag val } */
263 {"ascii", 0, 0, 'a'}, /* ascii text mode */
264 {"to-stdout", 0, 0, 'c'}, /* write output on standard output */
265 {"stdout", 0, 0, 'c'}, /* write output on standard output */
266 {"decompress", 0, 0, 'd'}, /* decompress */
267 {"uncompress", 0, 0, 'd'}, /* decompress */
268 /* {"encrypt", 0, 0, 'e'}, encrypt */
269 {"force", 0, 0, 'f'}, /* force overwrite of output file */
270 {"help", 0, 0, 'h'}, /* give help */
271 /* {"pkzip", 0, 0, 'k'}, force output in pkzip format */
272 {"keep", 0, 0, 'k'}, /* keep (don't delete) input files */
273 {"list", 0, 0, 'l'}, /* list .gz file contents */
274 {"license", 0, 0, 'L'}, /* display software license */
275 {"no-name", 0, 0, 'n'}, /* don't save or restore original name & time */
276 {"name", 0, 0, 'N'}, /* save or restore original name & time */
277 {"-presume-input-tty", no_argument, NULL, PRESUME_INPUT_TTY_OPTION},
278 {"quiet", 0, 0, 'q'}, /* quiet mode */
279 {"silent", 0, 0, 'q'}, /* quiet mode */
280 {"synchronous",0, 0, SYNCHRONOUS_OPTION},
281 {"recursive", 0, 0, 'r'}, /* recurse through directories */
282 {"suffix", 1, 0, 'S'}, /* use given suffix instead of .gz */
283 {"test", 0, 0, 't'}, /* test compressed file integrity */
284 {"no-time", 0, 0, 'T'}, /* don't save or restore the time stamp */
285 {"verbose", 0, 0, 'v'}, /* verbose mode */
286 {"version", 0, 0, 'V'}, /* display version number */
287 {"fast", 0, 0, '1'}, /* compress faster */
288 {"best", 0, 0, '9'}, /* compress better */
289 {"lzw", 0, 0, 'Z'}, /* make output compatible with old compress */
290 {"bits", 1, 0, 'b'}, /* max number of bits per code (implies -Z) */
295 /* local functions */
297 local void try_help (void) ATTRIBUTE_NORETURN;
298 local void help (void);
299 local void license (void);
300 local void version (void);
301 local int input_eof (void);
302 local void treat_stdin (void);
303 local void treat_file (char *iname);
304 local int create_outfile (void);
305 local char *get_suffix (char *name);
306 local int open_input_file (char *iname, struct stat *sbuf);
307 local void discard_input_bytes (size_t nbytes, unsigned int flags);
308 local int make_ofname (void);
309 local void shorten_name (char *name);
310 local int get_method (int in);
311 local void do_list (int ifd, int method);
312 local int check_ofname (void);
313 local void copy_stat (struct stat *ifstat);
314 local void install_signal_handlers (void);
315 local void remove_output_file (void);
316 local RETSIGTYPE abort_gzip_signal (int);
317 local void do_exit (int exitcode) ATTRIBUTE_NORETURN;
318 int main (int argc, char **argv);
319 static int (*work) (int infile, int outfile) = zip; /* function to call */
322 local void treat_dir (int fd, char *dir);
325 #define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
330 fprintf (stderr, "Try `%s --help' for more information.\n",
335 /* ======================================================================== */
338 static char const* const help_msg[] = {
339 "Compress or uncompress FILEs (by default, compress FILES in-place).",
341 "Mandatory arguments to long options are mandatory for short options too.",
344 " -a, --ascii ascii text; convert end-of-line using local conventions",
346 " -c, --stdout write on standard output, keep original files unchanged",
347 " -d, --decompress decompress",
348 /* -e, --encrypt encrypt */
349 " -f, --force force overwrite of output file and compress links",
350 " -h, --help give this help",
351 /* -k, --pkzip force output in pkzip format */
352 " -k, --keep keep (don't delete) input files",
353 " -l, --list list compressed file contents",
354 " -L, --license display software license",
356 " -m, --no-time do not save or restore the original modification time",
357 " -M, --time save or restore the original modification time",
359 " -n, --no-name do not save or restore the original name and time stamp",
360 " -N, --name save or restore the original name and time stamp",
361 " -q, --quiet suppress all warnings",
363 " -r, --recursive operate recursively on directories",
365 " -S, --suffix=SUF use suffix SUF on compressed files",
366 " --synchronous synchronous output (safer if system crashes, but slower)",
367 " -t, --test test compressed file integrity",
368 " -v, --verbose verbose mode",
369 " -V, --version display version number",
370 " -1, --fast compress faster",
371 " -9, --best compress better",
373 " -Z, --lzw produce output compatible with old compress",
374 " -b, --bits=BITS max number of bits per code (implies -Z)",
377 "With no FILE, or when FILE is -, read standard input.",
379 "Report bugs to <bug-gzip@gnu.org>.",
381 char const *const *p = help_msg;
383 printf ("Usage: %s [OPTION]... [FILE]...\n", program_name);
384 while (*p) printf ("%s\n", *p++);
387 /* ======================================================================== */
390 char const *const *p = license_msg;
392 printf ("%s %s\n", program_name, Version);
393 while (*p) printf ("%s\n", *p++);
396 /* ======================================================================== */
401 printf ("Written by Jean-loup Gailly.\n");
404 local void progerror (char const *string)
407 fprintf (stderr, "%s: ", program_name);
413 /* ======================================================================== */
414 int main (int argc, char **argv)
416 int file_count; /* number of files to process */
417 size_t proglen; /* length of program_name */
422 EXPAND(argc, argv); /* wild card expansion if necessary */
424 program_name = gzip_base_name (argv[0]);
425 proglen = strlen (program_name);
427 atexit (close_stdin);
429 /* Suppress .exe for MSDOS, OS/2 and VMS: */
430 if (4 < proglen && strequ (program_name + proglen - 4, ".exe"))
431 program_name[proglen - 4] = '\0';
433 /* Add options in GZIP environment variable if there is one */
435 env = add_envopt (&env_argc, &argv_copy, OPTIONS_VAR);
436 env_argv = env ? argv_copy : NULL;
439 # define GNU_STANDARD 1
442 /* For compatibility with old compress, use program name as an option.
443 * Unless you compile with -DGNU_STANDARD=0, this program will behave as
444 * gzip even if it is invoked under the name gunzip or zcat.
446 * Systems which do not support links can still use -d or -dc.
447 * Ignore an .exe extension for MSDOS, OS/2 and VMS.
449 if (strncmp (program_name, "un", 2) == 0 /* ungzip, uncompress */
450 || strncmp (program_name, "gun", 3) == 0) /* gunzip */
452 else if (strequ (program_name + 1, "cat") /* zcat, pcat, gcat */
453 || strequ (program_name, "gzcat")) /* gzcat */
454 decompress = to_stdout = 1;
458 z_len = strlen(z_suffix);
466 if (env_argv[optind] && strequ (env_argv[optind], "--"))
467 optc = ENV_OPTION + '-';
470 optc = getopt_long (env_argc, env_argv, shortopts, longopts,
476 if (optind != env_argc)
479 ("%s: %s: non-option in "OPTIONS_VAR
480 " environment variable\n"),
481 program_name, env_argv[optind]);
485 /* Wait until here before warning, so that GZIP='-q'
487 if (env_argc != 1 && !quiet)
489 ("%s: warning: "OPTIONS_VAR" environment variable"
490 " is deprecated; use an alias or script\n"),
493 /* Start processing ARGC and ARGV instead. */
503 optc = getopt_long (argc, argv, shortopts, longopts, &longind);
511 maxbits = atoi(optarg);
512 for (; *optarg; optarg++)
513 if (! ('0' <= *optarg && *optarg <= '9'))
515 fprintf (stderr, "%s: -b operand is not an integer\n",
521 to_stdout = 1; break;
523 decompress = 1; break;
527 help(); do_exit(OK); break;
531 list = decompress = to_stdout = 1; break;
533 license(); do_exit(OK); break;
534 case 'm': /* undocumented, may change later */
536 case 'M': /* undocumented, may change later */
539 case 'n' + ENV_OPTION:
540 no_name = no_time = 1; break;
542 case 'N' + ENV_OPTION:
543 no_name = no_time = 0; break;
544 case PRESUME_INPUT_TTY_OPTION:
545 presume_input_tty = true; break;
547 case 'q' + ENV_OPTION:
548 quiet = 1; verbose = 0; break;
551 fprintf (stderr, "%s: -r not supported on this system\n",
559 #ifdef NO_MULTIPLE_DOTS
560 if (*optarg == '.') optarg++;
562 z_len = strlen(optarg);
565 case SYNCHRONOUS_OPTION:
569 test = decompress = to_stdout = 1;
572 case 'v' + ENV_OPTION:
573 verbose++; quiet = 0; break;
575 version(); do_exit(OK); break;
580 fprintf(stderr, "%s: -Z not supported in this version\n",
585 case '1' + ENV_OPTION: case '2' + ENV_OPTION: case '3' + ENV_OPTION:
586 case '4' + ENV_OPTION: case '5' + ENV_OPTION: case '6' + ENV_OPTION:
587 case '7' + ENV_OPTION: case '8' + ENV_OPTION: case '9' + ENV_OPTION:
590 case '1': case '2': case '3': case '4':
591 case '5': case '6': case '7': case '8': case '9':
596 if (ENV_OPTION <= optc && optc != ENV_OPTION + '?')
598 /* Output a diagnostic, since getopt_long didn't. */
599 fprintf (stderr, "%s: ", program_name);
601 fprintf (stderr, "-%c: ", optc - ENV_OPTION);
603 fprintf (stderr, "--%s: ", longopts[longind].name);
604 fprintf (stderr, ("option not valid in "OPTIONS_VAR
605 " environment variable\n"));
609 } /* loop on all arguments */
611 /* By default, save name and timestamp on compression but do not
612 * restore them on decompression.
614 if (no_time < 0) no_time = decompress;
615 if (no_name < 0) no_name = decompress;
617 file_count = argc - optind;
621 if (ascii && !quiet) {
622 fprintf(stderr, "%s: option --ascii ignored on this system\n",
626 if (z_len == 0 || z_len > MAX_SUFFIX) {
627 fprintf(stderr, "%s: invalid suffix '%s'\n", program_name, z_suffix);
631 if (do_lzw && !decompress) work = lzw;
633 /* Allocate all global buffers (for DYN_ALLOC option) */
634 ALLOC(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
635 ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
636 ALLOC(ush, d_buf, DIST_BUFSIZE);
637 ALLOC(uch, window, 2L*WSIZE);
639 ALLOC(ush, tab_prefix, 1L<<BITS);
641 ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
642 ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
645 exiting_signal = quiet ? SIGPIPE : 0;
646 install_signal_handlers ();
648 /* And get to work */
649 if (file_count != 0) {
650 if (to_stdout && !test && !list && (!decompress || !ascii)) {
651 SET_BINARY_MODE (STDOUT_FILENO);
653 while (optind < argc) {
654 treat_file(argv[optind++]);
656 } else { /* Standard input */
659 if (list && !quiet && file_count > 1) {
660 do_list(-1, -1); /* print totals */
664 && (fdatasync (STDOUT_FILENO) != 0 && errno != EINVAL))
665 || close (STDOUT_FILENO) != 0)
669 return exit_code; /* just to avoid lint warning */
672 /* Return nonzero when at end of file on input. */
676 if (!decompress || last_member)
681 if (insize != INBUFSIZ || fill_inbuf (1) == EOF)
684 /* Unget the char that fill_inbuf got. */
691 /* ========================================================================
692 * Compress or decompress stdin
694 local void treat_stdin()
697 && (presume_input_tty
698 || isatty (decompress ? STDIN_FILENO : STDOUT_FILENO))) {
699 /* Do not send compressed data to the terminal or read it from
700 * the terminal. We get here when user invoked the program
701 * without parameters, so be helpful. According to the GNU standards:
703 * If there is one behavior you think is most useful when the output
704 * is to a terminal, and another that you think is most useful when
705 * the output is a file or a pipe, then it is usually best to make
706 * the default behavior the one that is useful with output to a
707 * terminal, and have an option for the other behavior.
709 * Here we use the --force option to get the other behavior.
713 ("%s: compressed data not %s a terminal."
714 " Use -f to force %scompression.\n"
715 "For help, type: %s -h\n"),
717 decompress ? "read from" : "written to",
718 decompress ? "de" : "",
723 if (decompress || !ascii) {
724 SET_BINARY_MODE (STDIN_FILENO);
726 if (!test && !list && (!decompress || !ascii)) {
727 SET_BINARY_MODE (STDOUT_FILENO);
729 strcpy(ifname, "stdin");
730 strcpy(ofname, "stdout");
732 /* Get the file's time stamp and size. */
733 if (fstat (STDIN_FILENO, &istat) != 0)
735 progerror ("standard input");
738 ifile_size = S_ISREG (istat.st_mode) ? istat.st_size : -1;
739 time_stamp.tv_nsec = -1;
740 if (!no_time || list)
742 if (S_ISREG (istat.st_mode))
743 time_stamp = get_stat_mtime (&istat);
745 gettime (&time_stamp);
748 clear_bufs(); /* clear input and output buffers */
754 method = get_method(ifd);
756 do_exit(exit_code); /* error message already emitted */
760 do_list(ifd, method);
764 /* Actually do the compression/decompression. Loop over zipped members.
767 if (work (STDIN_FILENO, STDOUT_FILENO) != OK)
773 method = get_method(ifd);
774 if (method < 0) return; /* error message already emitted */
775 bytes_out = 0; /* required for length check */
780 fprintf(stderr, " OK\n");
782 } else if (!decompress) {
783 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
784 fprintf(stderr, "\n");
785 #ifdef DISPLAY_STDIN_RATIO
787 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
788 fprintf(stderr, "\n");
794 static char const dot = '.';
796 /* True if the cached directory for calls to openat etc. is DIR, with
797 length DIRLEN. DIR need not be null-terminated. DIRLEN must be
798 less than MAX_PATH_LEN. */
800 atdir_eq (char const *dir, ptrdiff_t dirlen)
803 dir = &dot, dirlen = 1;
804 return memcmp (dfname, dir, dirlen) == 0 && !dfname[dirlen];
807 /* Set the directory used for calls to openat etc. to be the directory
808 DIR, with length DIRLEN. DIR need not be null-terminated.
809 DIRLEN must be less than MAX_PATH_LEN. Return a file descriptor for
810 the directory, or -1 if one could not be obtained. */
812 atdir_set (char const *dir, ptrdiff_t dirlen)
814 /* Don't bother opening directories on older systems that
815 lack openat and unlinkat. It's not worth the porting hassle. */
816 #if HAVE_OPENAT && HAVE_UNLINKAT
817 enum { try_opening_directories = true };
819 enum { try_opening_directories = false };
822 if (try_opening_directories && ! atdir_eq (dir, dirlen))
827 dir = &dot, dirlen = 1;
828 memcpy (dfname, dir, dirlen);
829 dfname[dirlen] = '\0';
830 dfd = open (dfname, O_SEARCH | O_DIRECTORY);
836 /* ========================================================================
837 * Compress or decompress the given file
839 local void treat_file(iname)
842 /* Accept "-" as synonym for stdin */
843 if (strequ(iname, "-")) {
844 int cflag = to_stdout;
850 /* Check if the input file is present, set ifname and istat: */
851 ifd = open_input_file (iname, &istat);
855 /* If the input name is that of a directory, recurse or ignore: */
856 if (S_ISDIR(istat.st_mode)) {
859 treat_dir (ifd, iname);
860 /* Warning: ifname is now garbage */
865 WARN ((stderr, "%s: %s is a directory -- ignored\n",
866 program_name, ifname));
872 if (! S_ISREG (istat.st_mode))
875 "%s: %s is not a directory or a regular file - ignored\n",
876 program_name, ifname));
880 if (istat.st_mode & S_ISUID)
882 WARN ((stderr, "%s: %s is set-user-ID on execution - ignored\n",
883 program_name, ifname));
887 if (istat.st_mode & S_ISGID)
889 WARN ((stderr, "%s: %s is set-group-ID on execution - ignored\n",
890 program_name, ifname));
897 if (istat.st_mode & S_ISVTX)
900 "%s: %s has the sticky bit set - file ignored\n",
901 program_name, ifname));
905 if (2 <= istat.st_nlink)
907 WARN ((stderr, "%s: %s has %lu other link%c -- unchanged\n",
908 program_name, ifname,
909 (unsigned long int) istat.st_nlink - 1,
910 istat.st_nlink == 2 ? ' ' : 's'));
917 ifile_size = S_ISREG (istat.st_mode) ? istat.st_size : -1;
918 time_stamp.tv_nsec = -1;
919 if (!no_time || list)
920 time_stamp = get_stat_mtime (&istat);
922 /* Generate output file name. For -r and (-t or -l), skip files
923 * without a valid gzip suffix (check done in make_ofname).
925 if (to_stdout && !list && !test) {
926 strcpy(ofname, "stdout");
928 } else if (make_ofname() != OK) {
933 clear_bufs(); /* clear input and output buffers */
937 method = get_method(ifd); /* updates ofname if original given */
940 return; /* error message already emitted */
944 do_list(ifd, method);
945 if (close (ifd) != 0)
950 /* If compressing to a file, check if ofname is not ambiguous
951 * because the operating system truncates names. Otherwise, generate
952 * a new ofname and save the original name in the compressed file.
956 /* Keep remove_ofname_fd negative. */
958 if (create_outfile() != OK) return;
960 if (!decompress && save_orig_name && !verbose && !quiet) {
961 fprintf(stderr, "%s: %s compressed to %s\n",
962 program_name, ifname, ofname);
965 /* Keep the name even if not truncated except with --no-name: */
966 if (!save_orig_name) save_orig_name = !no_name;
969 fprintf(stderr, "%s:\t", ifname);
972 /* Actually do the compression/decompression. Loop over zipped members.
975 if ((*work)(ifd, ofd) != OK) {
976 method = -1; /* force cleanup */
983 method = get_method(ifd);
984 if (method < 0) break; /* error message already emitted */
985 bytes_out = 0; /* required for length check */
988 if (close (ifd) != 0)
996 && ((0 <= dfd && fdatasync (dfd) != 0 && errno != EINVAL)
997 || (fsync (ofd) != 0 && errno != EINVAL)))
1005 char *ifbase = last_component (ifname);
1006 int ufd = atdir_eq (ifname, ifbase - ifname) ? dfd : -1;
1009 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
1010 remove_ofname_fd = -1;
1011 res = ufd < 0 ? xunlink (ifname) : unlinkat (ufd, ifbase, 0);
1012 unlink_errno = res == 0 ? 0 : errno;
1013 sigprocmask (SIG_SETMASK, &oldset, NULL);
1017 WARN ((stderr, "%s: ", program_name));
1020 errno = unlink_errno;
1029 remove_output_file ();
1033 /* Display statistics */
1036 fprintf(stderr, " OK");
1037 } else if (decompress) {
1038 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
1040 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
1042 if (!test && !to_stdout)
1043 fprintf(stderr, " -- %s %s", keep ? "created" : "replaced with",
1045 fprintf(stderr, "\n");
1049 /* ========================================================================
1050 * Create the output file. Return OK or ERROR.
1051 * Try several times if necessary to avoid truncating the z_suffix. For
1052 * example, do not create a compressed file of name "1234567890123."
1053 * Sets save_orig_name to true if the file name has been truncated.
1054 * IN assertions: the input file has already been open (ifd is set) and
1055 * ofname has already been updated if there was an original name.
1056 * OUT assertions: ifd and ofd are closed in case of error.
1058 local int create_outfile()
1060 int name_shortened = 0;
1061 int flags = (O_WRONLY | O_CREAT | O_EXCL
1062 | (ascii && decompress ? 0 : O_BINARY));
1063 char const *base = ofname;
1064 int atfd = AT_FDCWD;
1068 char const *b = last_component (ofname);
1069 int f = atdir_set (ofname, b - ofname);
1082 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
1083 remove_ofname_fd = ofd = openat (atfd, base, flags, S_IRUSR | S_IWUSR);
1085 sigprocmask (SIG_SETMASK, &oldset, NULL);
1094 shorten_name (ofname);
1100 if (check_ofname () != OK)
1114 if (name_shortened && decompress)
1116 /* name might be too long if an original name was saved */
1117 WARN ((stderr, "%s: %s: warning, name truncated\n",
1118 program_name, ofname));
1124 /* ========================================================================
1125 * Return a pointer to the 'z' suffix of a file name, or NULL. For all
1126 * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
1127 * accepted suffixes, in addition to the value of the --suffix option.
1128 * ".tgz" is a useful convention for tar.z files on systems limited
1129 * to 3 characters extensions. On such systems, ".?z" and ".??z" are
1130 * also accepted suffixes. For Unix, we do not want to accept any
1131 * .??z suffix as indicating a compressed file; some people use .xyz
1132 * to denote volume data.
1133 * On systems allowing multiple versions of the same file (such as VMS),
1134 * this function removes any version suffix in the given name.
1136 local char *get_suffix(name)
1140 char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */
1141 static char const *known_suffixes[] =
1142 {NULL, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
1143 #ifdef MAX_EXT_CHARS
1148 bool suffix_of_builtin = false;
1150 /* Normally put Z_SUFFIX at the start of KNOWN_SUFFIXES, but if it
1151 is a suffix of one of them, put it at the end. */
1152 for (suf = known_suffixes + 1; *suf; suf++)
1154 size_t suflen = strlen (*suf);
1155 if (z_len < suflen && strequ (z_suffix, *suf + suflen - z_len))
1157 suffix_of_builtin = true;
1161 known_suffixes[suffix_of_builtin
1162 ? sizeof known_suffixes / sizeof *known_suffixes - 2
1164 suf = known_suffixes + suffix_of_builtin;
1167 /* strip a version number from the file name */
1169 char *v = strrchr(name, SUFFIX_SEP);
1170 if (v != NULL) *v = '\0';
1173 nlen = strlen(name);
1174 if (nlen <= MAX_SUFFIX+2) {
1175 strcpy(suffix, name);
1177 strcpy(suffix, name+nlen-MAX_SUFFIX-2);
1180 slen = strlen(suffix);
1182 int s = strlen(*suf);
1183 if (slen > s && suffix[slen-s-1] != PATH_SEP
1184 && strequ(suffix + slen - s, *suf)) {
1187 } while (*++suf != NULL);
1193 /* Open file NAME with the given flags and store its status
1194 into *ST. Return a file descriptor to the newly opened file, or -1
1195 (setting errno) on failure. */
1197 open_and_stat (char *name, int flags, struct stat *st)
1200 int atfd = AT_FDCWD;
1201 char const *base = name;
1203 /* Refuse to follow symbolic links unless -c or -f. */
1204 if (!to_stdout && !force)
1206 if (HAVE_WORKING_O_NOFOLLOW)
1207 flags |= O_NOFOLLOW;
1210 #if HAVE_LSTAT || defined lstat
1211 if (lstat (name, st) != 0)
1213 else if (S_ISLNK (st->st_mode))
1224 char const *b = last_component (name);
1225 int f = atdir_set (name, b - name);
1233 fd = openat (atfd, base, flags);
1234 if (0 <= fd && fstat (fd, st) != 0)
1245 /* ========================================================================
1246 * Set ifname to the input file name (with a suffix appended if necessary)
1247 * and istat to its stats. For decompression, if no file exists with the
1248 * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
1249 * For MSDOS, we try only z_suffix and z.
1250 * Return an open file descriptor or -1.
1253 open_input_file (iname, sbuf)
1257 int ilen; /* strlen(ifname) */
1258 int z_suffix_errno = 0;
1259 static char const *suffixes[] = {NULL, ".gz", ".z", "-z", ".Z", NULL};
1260 char const **suf = suffixes;
1262 #ifdef NO_MULTIPLE_DOTS
1263 char *dot; /* pointer to ifname extension, or NULL */
1266 int open_flags = (O_RDONLY | O_NONBLOCK | O_NOCTTY
1267 | (ascii && !decompress ? 0 : O_BINARY));
1271 if (sizeof ifname - 1 <= strlen (iname))
1274 strcpy(ifname, iname);
1276 /* If input file exists, return OK. */
1277 fd = open_and_stat (ifname, open_flags, sbuf);
1281 if (!decompress || errno != ENOENT) {
1285 /* file.ext doesn't exist, try adding a suffix (after removing any
1286 * version number for VMS).
1288 s = get_suffix(ifname);
1290 progerror(ifname); /* ifname already has z suffix and does not exist */
1293 #ifdef NO_MULTIPLE_DOTS
1294 dot = strrchr(ifname, '.');
1296 strcat(ifname, ".");
1297 dot = strrchr(ifname, '.');
1300 ilen = strlen(ifname);
1301 if (strequ(z_suffix, ".gz")) suf++;
1303 /* Search for all suffixes */
1305 char const *s0 = s = *suf;
1306 strcpy (ifname, iname);
1307 #ifdef NO_MULTIPLE_DOTS
1309 if (*dot == '\0') strcpy (dot, ".");
1311 #ifdef MAX_EXT_CHARS
1312 if (MAX_EXT_CHARS < strlen (s) + strlen (dot + 1))
1313 dot[MAX_EXT_CHARS + 1 - strlen (s)] = '\0';
1315 if (sizeof ifname <= ilen + strlen (s))
1318 fd = open_and_stat (ifname, open_flags, sbuf);
1321 if (errno != ENOENT)
1326 if (strequ (s0, z_suffix))
1327 z_suffix_errno = errno;
1328 } while (*++suf != NULL);
1330 /* No suffix found, complain using z_suffix: */
1331 strcpy(ifname, iname);
1332 #ifdef NO_MULTIPLE_DOTS
1333 if (*dot == '\0') strcpy(dot, ".");
1335 #ifdef MAX_EXT_CHARS
1336 if (MAX_EXT_CHARS < z_len + strlen (dot + 1))
1337 dot[MAX_EXT_CHARS + 1 - z_len] = '\0';
1339 strcat(ifname, z_suffix);
1340 errno = z_suffix_errno;
1345 fprintf (stderr, "%s: %s: file name too long\n", program_name, iname);
1350 /* ========================================================================
1351 * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
1352 * Sets save_orig_name to true if the file name has been truncated.
1354 local int make_ofname()
1356 char *suff; /* ofname z suffix */
1358 strcpy(ofname, ifname);
1359 /* strip a version number if any and get the gzip suffix if present: */
1360 suff = get_suffix(ofname);
1364 /* With -t or -l, try all files (even without .gz suffix)
1365 * except with -r (behave as with just -dr).
1367 if (!recursive && (list || test)) return OK;
1369 /* Avoid annoying messages with -r */
1370 if (verbose || (!recursive && !quiet)) {
1371 WARN((stderr,"%s: %s: unknown suffix -- ignored\n",
1372 program_name, ifname));
1376 /* Make a special case for .tgz and .taz: */
1378 if (strequ(suff, ".tgz") || strequ(suff, ".taz")) {
1379 strcpy(suff, ".tar");
1381 *suff = '\0'; /* strip the z suffix */
1383 /* ofname might be changed later if infile contains an original name */
1385 } else if (suff && ! force) {
1386 /* Avoid annoying messages with -r (see treat_dir()) */
1387 if (verbose || (!recursive && !quiet)) {
1388 /* Don't use WARN, as it affects exit status. */
1389 fprintf (stderr, "%s: %s already has %s suffix -- unchanged\n",
1390 program_name, ifname, suff);
1396 #ifdef NO_MULTIPLE_DOTS
1397 suff = strrchr(ofname, '.');
1399 if (sizeof ofname <= strlen (ofname) + 1)
1401 strcat(ofname, ".");
1402 # ifdef MAX_EXT_CHARS
1403 if (strequ(z_suffix, "z")) {
1404 if (sizeof ofname <= strlen (ofname) + 2)
1406 strcat(ofname, "gz"); /* enough room */
1409 /* On the Atari and some versions of MSDOS,
1410 * ENAMETOOLONG does not work correctly. So we
1411 * must truncate here.
1413 } else if (strlen(suff)-1 + z_len > MAX_SUFFIX) {
1414 suff[MAX_SUFFIX+1-z_len] = '\0';
1418 #endif /* NO_MULTIPLE_DOTS */
1419 if (sizeof ofname <= strlen (ofname) + z_len)
1421 strcat(ofname, z_suffix);
1423 } /* decompress ? */
1427 WARN ((stderr, "%s: %s: file name too long\n", program_name, ifname));
1431 /* Discard NBYTES input bytes from the input, or up through the next
1432 zero byte if NBYTES == (size_t) -1. If FLAGS say that the header
1433 CRC should be computed, update the CRC accordingly. */
1435 discard_input_bytes (nbytes, flags)
1441 uch c = get_byte ();
1442 if (flags & HEADER_CRC)
1444 if (nbytes != (size_t) -1)
1451 /* ========================================================================
1452 * Check the magic number of the input file and update ofname if an
1453 * original name was given and to_stdout is not set.
1454 * Return the compression method, -1 for error, -2 for warning.
1455 * Set inptr to the offset of the next byte to be processed.
1456 * Updates time_stamp if there is one and --no-time is not used.
1457 * This function may be called repeatedly for an input file consisting
1458 * of several contiguous gzip'ed members.
1459 * IN assertions: there is at least one remaining compressed member.
1460 * If the member is a zip file, it must be the only one.
1462 local int get_method(in)
1463 int in; /* input file descriptor */
1465 uch flags; /* compression flags */
1466 uch magic[10]; /* magic header */
1467 int imagic0; /* first magic byte or EOF */
1468 int imagic1; /* like magic[1], but can represent EOF */
1469 ulg stamp; /* time stamp */
1471 /* If --force and --stdout, zcat == cat, so do not complain about
1472 * premature end of file: use try_byte instead of get_byte.
1474 if (force && to_stdout) {
1475 imagic0 = try_byte();
1477 imagic1 = try_byte ();
1479 /* If try_byte returned EOF, magic[1] == (char) EOF. */
1481 magic[0] = get_byte ();
1484 magic[1] = get_byte ();
1485 imagic1 = 0; /* avoid lint warning */
1487 imagic1 = try_byte ();
1491 method = -1; /* unknown yet */
1492 part_nb++; /* number of parts in gzip file */
1494 last_member = RECORD_IO;
1495 /* assume multiple members in gzip file except for record oriented I/O */
1497 if (memcmp(magic, GZIP_MAGIC, 2) == 0
1498 || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
1500 method = (int)get_byte();
1501 if (method != DEFLATED) {
1503 "%s: %s: unknown method %d -- not supported\n",
1504 program_name, ifname, method);
1509 flags = (uch)get_byte();
1511 if ((flags & ENCRYPTED) != 0) {
1513 "%s: %s is encrypted -- not supported\n",
1514 program_name, ifname);
1518 if ((flags & RESERVED) != 0) {
1520 "%s: %s has flags 0x%x -- not supported\n",
1521 program_name, ifname, flags);
1523 if (force <= 1) return -1;
1525 stamp = (ulg)get_byte();
1526 stamp |= ((ulg)get_byte()) << 8;
1527 stamp |= ((ulg)get_byte()) << 16;
1528 stamp |= ((ulg)get_byte()) << 24;
1529 if (stamp != 0 && !no_time)
1531 time_stamp.tv_sec = stamp;
1532 time_stamp.tv_nsec = 0;
1535 magic[8] = get_byte (); /* Ignore extra flags. */
1536 magic[9] = get_byte (); /* Ignore OS type. */
1538 if (flags & HEADER_CRC)
1540 magic[2] = DEFLATED;
1542 magic[4] = stamp & 0xff;
1543 magic[5] = (stamp >> 8) & 0xff;
1544 magic[6] = (stamp >> 16) & 0xff;
1545 magic[7] = stamp >> 24;
1550 if ((flags & EXTRA_FIELD) != 0) {
1552 unsigned int len = lenbuf[0] = get_byte ();
1553 len |= (lenbuf[1] = get_byte ()) << 8;
1555 fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n",
1556 program_name, ifname, len);
1558 if (flags & HEADER_CRC)
1560 discard_input_bytes (len, flags);
1563 /* Get original file name if it was truncated */
1564 if ((flags & ORIG_NAME) != 0) {
1565 if (no_name || (to_stdout && !list) || part_nb > 1) {
1566 /* Discard the old name */
1567 discard_input_bytes (-1, flags);
1569 /* Copy the base name. Keep a directory prefix intact. */
1570 char *p = gzip_base_name (ofname);
1573 *p = (char) get_byte ();
1574 if (*p++ == '\0') break;
1575 if (p >= ofname+sizeof(ofname)) {
1576 gzip_error ("corrupted input -- file name too large");
1579 if (flags & HEADER_CRC)
1580 updcrc ((uch *) base, p - base);
1581 p = gzip_base_name (base);
1582 memmove (base, p, strlen (p) + 1);
1583 /* If necessary, adapt the name to local OS conventions: */
1585 MAKE_LEGAL_NAME(base);
1586 if (base) list=0; /* avoid warning about unused variable */
1588 } /* no_name || to_stdout */
1591 /* Discard file comment if any */
1592 if ((flags & COMMENT) != 0) {
1593 discard_input_bytes (-1, flags);
1596 if (flags & HEADER_CRC)
1598 unsigned int crc16 = updcrc (magic, 0) & 0xffff;
1599 unsigned int header16 = get_byte ();
1600 header16 |= ((unsigned int) get_byte ()) << 8;
1601 if (header16 != crc16)
1604 "%s: %s: header checksum 0x%04x != computed checksum 0x%04x\n",
1605 program_name, ifname, header16, crc16);
1613 header_bytes = inptr + 2*4; /* include crc and size */
1616 } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
1617 && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0) {
1618 /* To simplify the code, we support a zip file when alone only.
1619 * We are thus guaranteed that the entire local header fits in inbuf.
1623 if (check_zipfile(in) != OK) return -1;
1624 /* check_zipfile may get ofname from the local header */
1627 } else if (memcmp(magic, PACK_MAGIC, 2) == 0) {
1631 } else if (memcmp(magic, LZW_MAGIC, 2) == 0) {
1633 method = COMPRESSED;
1636 } else if (memcmp(magic, LZH_MAGIC, 2) == 0) {
1641 } else if (force && to_stdout && !list) { /* pass input unchanged */
1647 if (imagic0 != EOF) {
1648 write_buf (STDOUT_FILENO, magic, 1);
1652 if (method >= 0) return method;
1655 fprintf (stderr, "\n%s: %s: not in gzip format\n",
1656 program_name, ifname);
1663 for (inbyte = imagic1; inbyte == 0; inbyte = try_byte ())
1668 WARN ((stderr, "\n%s: %s: decompression OK, trailing zero bytes ignored\n",
1669 program_name, ifname));
1674 WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n",
1675 program_name, ifname));
1680 /* ========================================================================
1681 * Display the characteristics of the compressed file.
1682 * If the given method is < 0, display the accumulated totals.
1683 * IN assertions: time_stamp, header_bytes and ifile_size are initialized.
1685 local void do_list(ifd, method)
1686 int ifd; /* input file descriptor */
1687 int method; /* compression method */
1689 ulg crc; /* original crc */
1690 static int first_time = 1;
1691 static char const *const methods[MAX_METHODS] = {
1696 "", "", "", "", /* 4 to 7 reserved */
1698 int positive_off_t_width = 1;
1701 for (o = OFF_T_MAX; 9 < o; o /= 10) {
1702 positive_off_t_width++;
1705 if (first_time && method >= 0) {
1708 printf("method crc date time ");
1711 printf("%*.*s %*.*s ratio uncompressed_name\n",
1712 positive_off_t_width, positive_off_t_width, "compressed",
1713 positive_off_t_width, positive_off_t_width, "uncompressed");
1715 } else if (method < 0) {
1716 if (total_in <= 0 || total_out <= 0) return;
1720 if (verbose || !quiet) {
1721 fprint_off(stdout, total_in, positive_off_t_width);
1723 fprint_off(stdout, total_out, positive_off_t_width);
1726 display_ratio(total_out-(total_in-header_bytes), total_out, stdout);
1727 /* header_bytes is not meaningful but used to ensure the same
1728 * ratio if there is a single file.
1730 printf(" (totals)\n");
1733 crc = (ulg)~0; /* unknown */
1735 bytes_in = ifile_size;
1737 if (!RECORD_IO && method == DEFLATED && !last_member) {
1738 /* Get the crc and uncompressed size for gzip'ed (not zip'ed) files.
1739 * If the lseek fails, we could use read() to get to the end, but
1740 * --list is used to get quick results.
1741 * Use "gunzip < foo.gz | wc -c" to get the uncompressed size if
1742 * you are not concerned about speed.
1744 bytes_in = lseek(ifd, (off_t)(-8), SEEK_END);
1745 if (bytes_in != -1L) {
1748 if (read(ifd, (char*)buf, sizeof(buf)) != sizeof(buf)) {
1752 bytes_out = LG(buf+4);
1758 struct tm *tm = localtime (&time_stamp.tv_sec);
1759 printf ("%5s %08lx ", methods[method], crc);
1761 printf ("%s%3d %02d:%02d ",
1762 ("Jan\0Feb\0Mar\0Apr\0May\0Jun\0Jul\0Aug\0Sep\0Oct\0Nov\0Dec"
1764 tm->tm_mday, tm->tm_hour, tm->tm_min);
1766 printf ("??? ?? ??:?? ");
1768 fprint_off(stdout, bytes_in, positive_off_t_width);
1770 fprint_off(stdout, bytes_out, positive_off_t_width);
1772 if (bytes_in == -1L) {
1774 bytes_in = bytes_out = header_bytes = 0;
1775 } else if (total_in >= 0) {
1776 total_in += bytes_in;
1778 if (bytes_out == -1L) {
1780 bytes_in = bytes_out = header_bytes = 0;
1781 } else if (total_out >= 0) {
1782 total_out += bytes_out;
1784 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out, stdout);
1785 printf(" %s\n", ofname);
1788 /* ========================================================================
1789 * Shorten the given name by one character, or replace a .tar extension
1790 * with .tgz. Truncate the last part of the name which is longer than
1791 * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
1792 * has only parts shorter than MIN_PART truncate the longest part.
1793 * For decompression, just remove the last character of the name.
1795 * IN assertion: for compression, the suffix of the given name is z_suffix.
1797 local void shorten_name(name)
1800 int len; /* length of name without z_suffix */
1801 char *trunc = NULL; /* character to be truncated */
1802 int plen; /* current part length */
1803 int min_part = MIN_PART; /* current minimum part length */
1809 gzip_error ("name too short");
1813 p = get_suffix(name);
1815 gzip_error ("can't recover suffix\n");
1819 /* compress 1234567890.tar to 1234567890.tgz */
1820 if (len > 4 && strequ(p-4, ".tar")) {
1821 strcpy(p-4, ".tgz");
1824 /* Try keeping short extensions intact:
1825 * 1234.678.012.gz -> 123.678.012.gz
1828 p = strrchr(name, PATH_SEP);
1831 plen = strcspn(p, PART_SEP);
1833 if (plen > min_part) trunc = p-1;
1836 } while (trunc == NULL && --min_part != 0);
1838 if (trunc != NULL) {
1840 trunc[0] = trunc[1];
1844 trunc = strrchr(name, PART_SEP[0]);
1846 gzip_error ("internal error in shorten_name");
1847 if (trunc[1] == '\0') trunc--; /* force truncation */
1849 strcpy(trunc, z_suffix);
1852 /* ========================================================================
1853 * The compressed file already exists, so ask for confirmation.
1854 * Return ERROR if the file must be skipped.
1856 local int check_ofname()
1858 /* Ask permission to overwrite the existing file */
1861 fprintf (stderr, "%s: %s already exists;", program_name, ofname);
1862 if (foreground && (presume_input_tty || isatty (STDIN_FILENO))) {
1863 fprintf(stderr, " do you wish to overwrite (y or n)? ");
1868 fprintf(stderr, "\tnot overwritten\n");
1869 if (exit_code == OK) exit_code = WARNING;
1873 if (xunlink (ofname)) {
1880 /* Change the owner and group of a file. FD is a file descriptor for
1881 the file and NAME its name. Change it to user UID and to group GID.
1882 If UID or GID is -1, though, do not change the corresponding user
1885 do_chown (int fd, char const *name, uid_t uid, gid_t gid)
1889 ignore_value (fchown (fd, uid, gid));
1891 ignore_value (chown (name, uid, gid));
1896 /* ========================================================================
1897 * Copy modes, times, ownership from input file to output file.
1898 * IN assertion: to_stdout is false.
1900 local void copy_stat(ifstat)
1901 struct stat *ifstat;
1903 mode_t mode = ifstat->st_mode & S_IRWXUGO;
1907 struct timespec timespec[2];
1908 timespec[0] = get_stat_atime (ifstat);
1909 timespec[1] = get_stat_mtime (ifstat);
1911 if (decompress && 0 <= time_stamp.tv_nsec
1912 && ! (timespec[1].tv_sec == time_stamp.tv_sec
1913 && timespec[1].tv_nsec == time_stamp.tv_nsec))
1915 timespec[1] = time_stamp;
1917 fprintf(stderr, "%s: time stamp restored\n", ofname);
1921 if (fdutimens (ofd, ofname, timespec) != 0)
1924 WARN ((stderr, "%s: ", program_name));
1933 /* Change the group first, then the permissions, then the owner.
1934 That way, the permissions will be correct on systems that allow
1935 users to give away files, without introducing a security hole.
1936 Security depends on permissions not containing the setuid or
1939 do_chown (ofd, ofname, -1, ifstat->st_gid);
1942 r = fchmod (ofd, mode);
1944 r = chmod (ofname, mode);
1948 WARN ((stderr, "%s: ", program_name));
1955 do_chown (ofd, ofname, ifstat->st_uid, -1);
1960 /* ========================================================================
1961 * Recurse through the given directory.
1963 local void treat_dir (fd, dir)
1968 char nbuf[MAX_PATH_LEN];
1973 dirp = fdopendir (fd);
1981 entries = streamsavedir (dirp, SAVEDIR_SORT_NONE);
1984 if (closedir (dirp) != 0)
1989 for (entry = entries; *entry; entry += entrylen + 1) {
1990 size_t len = strlen (dir);
1991 entrylen = strlen (entry);
1992 if (strequ (entry, ".") || strequ (entry, ".."))
1994 if (len + entrylen < MAX_PATH_LEN - 2) {
1996 if (len != 0 /* dir = "" means current dir on Amiga */
1998 && dir[len-1] != PATH_SEP2
2001 && dir[len-1] != PATH_SEP3
2004 nbuf[len++] = PATH_SEP;
2006 strcpy (nbuf + len, entry);
2009 fprintf(stderr,"%s: %s/%s: pathname too long\n",
2010 program_name, dir, entry);
2016 #endif /* ! NO_DIR */
2018 /* Make sure signals get handled properly. */
2021 install_signal_handlers ()
2023 int nsigs = sizeof handled_sig / sizeof handled_sig[0];
2027 struct sigaction act;
2029 sigemptyset (&caught_signals);
2030 for (i = 0; i < nsigs; i++)
2032 sigaction (handled_sig[i], NULL, &act);
2033 if (act.sa_handler != SIG_IGN)
2034 sigaddset (&caught_signals, handled_sig[i]);
2037 act.sa_handler = abort_gzip_signal;
2038 act.sa_mask = caught_signals;
2041 for (i = 0; i < nsigs; i++)
2042 if (sigismember (&caught_signals, handled_sig[i]))
2046 sigaction (handled_sig[i], &act, NULL);
2049 for (i = 0; i < nsigs; i++)
2050 if (signal (handled_sig[i], SIG_IGN) != SIG_IGN)
2054 signal (handled_sig[i], abort_gzip_signal);
2055 siginterrupt (handled_sig[i], 1);
2060 /* ========================================================================
2061 * Free all dynamically allocated variables and exit with the given code.
2063 local void do_exit(exitcode)
2066 static int in_exit = 0;
2068 if (in_exit) exit(exitcode);
2085 /* ========================================================================
2086 * Close and unlink the output file.
2089 remove_output_file ()
2094 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
2095 fd = remove_ofname_fd;
2098 remove_ofname_fd = -1;
2102 sigprocmask (SIG_SETMASK, &oldset, NULL);
2105 /* ========================================================================
2111 remove_output_file ();
2115 /* ========================================================================
2119 abort_gzip_signal (sig)
2123 signal (sig, SIG_IGN);
2124 remove_output_file ();
2125 if (sig == exiting_signal)
2127 signal (sig, SIG_DFL);