1 /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
3 Copyright (C) 1999, 2001-2002, 2006-2007, 2009-2017 Free Software
5 Copyright (C) 1992-1993 Jean-loup Gailly
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software Foundation,
19 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
22 * The unzip code was written and put in the public domain by Mark Adler.
23 * Portions of the lzw code are derived from the public domain 'compress'
24 * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
25 * Ken Turkowski, Dave Mack and Peter Jannesen.
27 * See the license_msg below and the file COPYING for the software license.
28 * See the file algorithm.doc for the compression algorithms and file formats.
31 static char const *const license_msg[] = {
32 "Copyright (C) 2017 Free Software Foundation, Inc.",
33 "Copyright (C) 1993 Jean-loup Gailly.",
34 "This is free software. You may redistribute copies of it under the terms of",
35 "the GNU General Public License <https://www.gnu.org/licenses/gpl.html>.",
36 "There is NO WARRANTY, to the extent permitted by law.",
39 /* Compress files with zip algorithm and 'compress' interface.
40 * See help() function below for all options.
42 * file.gz: compressed file with same mode, owner, and utimes
43 * or stdout with -c option or if stdin used as input.
44 * If the output file name had to be truncated, the original name is kept
45 * in the compressed file.
46 * On MSDOS, file.tmp -> file.tmz.
48 * Using gz on MSDOS would create too many file name conflicts. For
49 * example, foo.txt -> foo.tgz (.tgz must be reserved as shorthand for
50 * tar.gz). Similarly, foo.dir and foo.doc would both be mapped to foo.dgz.
51 * I also considered 12345678.txt -> 12345txt.gz but this truncates the name
52 * too heavily. There is no ideal solution given the MSDOS 8+3 limitation.
54 * For the meaning of all compilation flags, see comments in Makefile.in.
59 #include <sys/types.h>
77 #include "ignore-value.h"
78 #include "stat-time.h"
103 # define MAX_PATH_LEN 1024 /* max pathname length */
115 off_t lseek (int fd, off_t offset, int whence);
119 # define OFF_T_MAX TYPE_MAXIMUM (off_t)
122 /* Use SA_NOCLDSTOP as a proxy for whether the sigaction machinery is
125 # define SA_NOCLDSTOP 0
126 # define sigprocmask(how, set, oset) /* empty */
127 # define sigset_t int
128 # if ! HAVE_SIGINTERRUPT
129 # define siginterrupt(sig, flag) /* empty */
133 #ifndef HAVE_WORKING_O_NOFOLLOW
134 # define HAVE_WORKING_O_NOFOLLOW 0
137 /* Separator for file name parts (see shorten_name()) */
138 #ifdef NO_MULTIPLE_DOTS
139 # define PART_SEP "-"
141 # define PART_SEP "."
146 DECLARE(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
147 DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
148 DECLARE(ush, d_buf, DIST_BUFSIZE);
149 DECLARE(uch, window, 2L*WSIZE);
151 DECLARE(ush, tab_prefix, 1L<<BITS);
153 DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
154 DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
157 /* local variables */
159 /* If true, pretend that standard input is a tty. This option
160 is deliberately not documented, and only for testing. */
161 static bool presume_input_tty;
163 /* If true, transfer output data to the output file's storage device
164 when supported. Otherwise, if the system crashes around the time
165 gzip is run, the user might lose both input and output data. See:
166 Pillai TS et al. All file systems are not created equal: on the
167 complexity of crafting crash-consistent applications. OSDI'14. 2014:433-48.
168 https://www.usenix.org/conference/osdi14/technical-sessions/presentation/pillai */
169 static bool synchronous;
171 static int ascii = 0; /* convert end-of-lines to local OS conventions */
172 int to_stdout = 0; /* output to stdout (-c) */
173 static int decompress = 0; /* decompress (-d) */
174 static int force = 0; /* don't ask questions, compress links (-f) */
175 static int keep = 0; /* keep (don't delete) input files */
176 static int no_name = -1; /* don't save or restore the original file name */
177 static int no_time = -1; /* don't save or restore the original file time */
178 static int recursive = 0; /* recurse through directories (-r) */
179 static int list = 0; /* list the file contents (-l) */
180 int verbose = 0; /* be verbose (-v) */
181 int quiet = 0; /* be very quiet (-q) */
182 static int do_lzw = 0; /* generate output compatible with old compress (-Z) */
183 int test = 0; /* test .gz file integrity */
184 static int foreground = 0; /* set if program run in foreground */
185 char *program_name; /* program name */
186 int maxbits = BITS; /* max bits per code for LZW */
187 int method = DEFLATED;/* compression method */
188 int level = 6; /* compression level */
189 int exit_code = OK; /* program exit code */
190 int save_orig_name; /* set if original name must be saved */
191 static int last_member; /* set for .zip and .Z files */
192 static int part_nb; /* number of parts in .gz file */
193 off_t ifile_size; /* input file size, -1 for devices (debug only) */
194 static char *env; /* contents of GZIP env variable */
195 static char const *z_suffix; /* default suffix (can be set with --suffix) */
196 static size_t z_len; /* strlen(z_suffix) */
198 /* The original timestamp (modification time). If the original is
199 unknown, TIME_STAMP.tv_nsec is negative. If the original is
200 greater than struct timespec range, TIME_STAMP is the maximal
201 struct timespec value; this can happen on hosts with 32-bit signed
202 time_t because the gzip format's MTIME is 32-bit unsigned.
203 The original cannot be less than struct timespec range. */
204 struct timespec time_stamp;
206 /* The set of signals that are caught. */
207 static sigset_t caught_signals;
209 /* If nonzero then exit with status WARNING, rather than with the usual
210 signal status, on receipt of a signal with this value. This
211 suppresses a "Broken Pipe" message with some shells. */
212 static int volatile exiting_signal;
214 /* If nonnegative, close this file descriptor and unlink ofname on error. */
215 static int volatile remove_ofname_fd = -1;
217 static bool stdin_was_read;
219 off_t bytes_in; /* number of input bytes */
220 off_t bytes_out; /* number of output bytes */
221 static off_t total_in; /* input bytes for all files */
222 static off_t total_out; /* output bytes for all files */
223 char ifname[MAX_PATH_LEN]; /* input file name */
224 char ofname[MAX_PATH_LEN]; /* output file name */
225 static char dfname[MAX_PATH_LEN]; /* name of dir containing output file */
226 static struct stat istat; /* status for input file */
227 int ifd; /* input file descriptor */
228 int ofd; /* output file descriptor */
229 static int dfd = -1; /* output directory file descriptor */
230 unsigned insize; /* valid bytes in inbuf */
231 unsigned inptr; /* index of next byte to be processed in inbuf */
232 unsigned outcnt; /* bytes in output buffer */
233 int rsync = 0; /* make ryncable chunks */
235 static int handled_sig[] =
237 /* SIGINT must be first, as 'foreground' depends on it. */
257 /* For long options that have no equivalent short option, use a
258 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
261 PRESUME_INPUT_TTY_OPTION = CHAR_MAX + 1,
265 /* A value greater than all valid long options, used as a flag to
266 distinguish options derived from the GZIP environment variable. */
270 static char const shortopts[] = "ab:cdfhH?klLmMnNqrS:tvVZ123456789";
272 static const struct option longopts[] =
274 /* { name has_arg *flag val } */
275 {"ascii", 0, 0, 'a'}, /* ascii text mode */
276 {"to-stdout", 0, 0, 'c'}, /* write output on standard output */
277 {"stdout", 0, 0, 'c'}, /* write output on standard output */
278 {"decompress", 0, 0, 'd'}, /* decompress */
279 {"uncompress", 0, 0, 'd'}, /* decompress */
280 /* {"encrypt", 0, 0, 'e'}, encrypt */
281 {"force", 0, 0, 'f'}, /* force overwrite of output file */
282 {"help", 0, 0, 'h'}, /* give help */
283 /* {"pkzip", 0, 0, 'k'}, force output in pkzip format */
284 {"keep", 0, 0, 'k'}, /* keep (don't delete) input files */
285 {"list", 0, 0, 'l'}, /* list .gz file contents */
286 {"license", 0, 0, 'L'}, /* display software license */
287 {"no-name", 0, 0, 'n'}, /* don't save or restore original name & time */
288 {"name", 0, 0, 'N'}, /* save or restore original name & time */
289 {"-presume-input-tty", no_argument, NULL, PRESUME_INPUT_TTY_OPTION},
290 {"quiet", 0, 0, 'q'}, /* quiet mode */
291 {"silent", 0, 0, 'q'}, /* quiet mode */
292 {"synchronous",0, 0, SYNCHRONOUS_OPTION},
293 {"recursive", 0, 0, 'r'}, /* recurse through directories */
294 {"suffix", 1, 0, 'S'}, /* use given suffix instead of .gz */
295 {"test", 0, 0, 't'}, /* test compressed file integrity */
296 {"verbose", 0, 0, 'v'}, /* verbose mode */
297 {"version", 0, 0, 'V'}, /* display version number */
298 {"fast", 0, 0, '1'}, /* compress faster */
299 {"best", 0, 0, '9'}, /* compress better */
300 {"lzw", 0, 0, 'Z'}, /* make output compatible with old compress */
301 {"bits", 1, 0, 'b'}, /* max number of bits per code (implies -Z) */
302 {"rsyncable", 0, 0, RSYNCABLE_OPTION}, /* make rsync-friendly archive */
306 /* local functions */
308 local noreturn void try_help (void);
309 local void help (void);
310 local void license (void);
311 local void version (void);
312 local int input_eof (void);
313 local void treat_stdin (void);
314 local void treat_file (char *iname);
315 local int create_outfile (void);
316 local char *get_suffix (char *name);
317 local int open_input_file (char *iname, struct stat *sbuf);
318 local void discard_input_bytes (size_t nbytes, unsigned int flags);
319 local int make_ofname (void);
320 local void shorten_name (char *name);
321 local int get_method (int in);
322 local void do_list (int ifd, int method);
323 local int check_ofname (void);
324 local void copy_stat (struct stat *ifstat);
325 local void install_signal_handlers (void);
326 local void remove_output_file (void);
327 local RETSIGTYPE abort_gzip_signal (int);
328 local noreturn void do_exit (int exitcode);
329 static void finish_out (void);
330 int main (int argc, char **argv);
331 static int (*work) (int infile, int outfile) = zip; /* function to call */
334 local void treat_dir (int fd, char *dir);
337 #define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
342 fprintf (stderr, "Try `%s --help' for more information.\n",
347 /* ======================================================================== */
350 static char const* const help_msg[] = {
351 "Compress or uncompress FILEs (by default, compress FILES in-place).",
353 "Mandatory arguments to long options are mandatory for short options too.",
356 " -a, --ascii ascii text; convert end-of-line using local conventions",
358 " -c, --stdout write on standard output, keep original files unchanged",
359 " -d, --decompress decompress",
360 /* -e, --encrypt encrypt */
361 " -f, --force force overwrite of output file and compress links",
362 " -h, --help give this help",
363 /* -k, --pkzip force output in pkzip format */
364 " -k, --keep keep (don't delete) input files",
365 " -l, --list list compressed file contents",
366 " -L, --license display software license",
368 " -m do not save or restore the original modification time",
369 " -M, --time save or restore the original modification time",
371 " -n, --no-name do not save or restore the original name and timestamp",
372 " -N, --name save or restore the original name and timestamp",
373 " -q, --quiet suppress all warnings",
375 " -r, --recursive operate recursively on directories",
377 " --rsyncable make rsync-friendly archive",
378 " -S, --suffix=SUF use suffix SUF on compressed files",
379 " --synchronous synchronous output (safer if system crashes, but slower)",
380 " -t, --test test compressed file integrity",
381 " -v, --verbose verbose mode",
382 " -V, --version display version number",
383 " -1, --fast compress faster",
384 " -9, --best compress better",
386 " -Z, --lzw produce output compatible with old compress",
387 " -b, --bits=BITS max number of bits per code (implies -Z)",
390 "With no FILE, or when FILE is -, read standard input.",
392 "Report bugs to <bug-gzip@gnu.org>.",
394 char const *const *p = help_msg;
396 printf ("Usage: %s [OPTION]... [FILE]...\n", program_name);
397 while (*p) printf ("%s\n", *p++);
400 /* ======================================================================== */
403 char const *const *p = license_msg;
405 printf ("%s %s\n", program_name, Version);
406 while (*p) printf ("%s\n", *p++);
409 /* ======================================================================== */
414 printf ("Written by Jean-loup Gailly.\n");
417 local void progerror (char const *string)
420 fprintf (stderr, "%s: ", program_name);
426 /* ======================================================================== */
427 int main (int argc, char **argv)
429 int file_count; /* number of files to process */
430 size_t proglen; /* length of program_name */
435 EXPAND(argc, argv); /* wild card expansion if necessary */
437 program_name = gzip_base_name (argv[0]);
438 proglen = strlen (program_name);
440 /* Suppress .exe for MSDOS and OS/2: */
441 if (4 < proglen && strequ (program_name + proglen - 4, ".exe"))
442 program_name[proglen - 4] = '\0';
444 /* Add options in GZIP environment variable if there is one */
446 env = add_envopt (&env_argc, &argv_copy, OPTIONS_VAR);
447 env_argv = env ? argv_copy : NULL;
450 # define GNU_STANDARD 1
453 /* For compatibility with old compress, use program name as an option.
454 * Unless you compile with -DGNU_STANDARD=0, this program will behave as
455 * gzip even if it is invoked under the name gunzip or zcat.
457 * Systems which do not support links can still use -d or -dc.
458 * Ignore an .exe extension for MSDOS and OS/2.
460 if (strncmp (program_name, "un", 2) == 0 /* ungzip, uncompress */
461 || strncmp (program_name, "gun", 3) == 0) /* gunzip */
463 else if (strequ (program_name + 1, "cat") /* zcat, pcat, gcat */
464 || strequ (program_name, "gzcat")) /* gzcat */
465 decompress = to_stdout = 1;
469 z_len = strlen(z_suffix);
477 if (env_argv[optind] && strequ (env_argv[optind], "--"))
478 optc = ENV_OPTION + '-';
481 optc = getopt_long (env_argc, env_argv, shortopts, longopts,
487 if (optind != env_argc)
490 ("%s: %s: non-option in "OPTIONS_VAR
491 " environment variable\n"),
492 program_name, env_argv[optind]);
496 /* Wait until here before warning, so that GZIP='-q'
498 if (env_argc != 1 && !quiet)
500 ("%s: warning: "OPTIONS_VAR" environment variable"
501 " is deprecated; use an alias or script\n"),
504 /* Start processing ARGC and ARGV instead. */
514 optc = getopt_long (argc, argv, shortopts, longopts, &longind);
522 maxbits = atoi(optarg);
523 for (; *optarg; optarg++)
524 if (! ('0' <= *optarg && *optarg <= '9'))
526 fprintf (stderr, "%s: -b operand is not an integer\n",
532 to_stdout = 1; break;
534 decompress = 1; break;
538 help (); finish_out (); break;
542 list = decompress = to_stdout = 1; break;
544 license (); finish_out (); break;
545 case 'm': /* undocumented, may change later */
547 case 'M': /* undocumented, may change later */
550 case 'n' + ENV_OPTION:
551 no_name = no_time = 1; break;
553 case 'N' + ENV_OPTION:
554 no_name = no_time = 0; break;
555 case PRESUME_INPUT_TTY_OPTION:
556 presume_input_tty = true; break;
558 case 'q' + ENV_OPTION:
559 quiet = 1; verbose = 0; break;
562 fprintf (stderr, "%s: -r not supported on this system\n",
570 case RSYNCABLE_OPTION:
571 case RSYNCABLE_OPTION + ENV_OPTION:
575 #ifdef NO_MULTIPLE_DOTS
576 if (*optarg == '.') optarg++;
578 z_len = strlen(optarg);
581 case SYNCHRONOUS_OPTION:
585 test = decompress = to_stdout = 1;
588 case 'v' + ENV_OPTION:
589 verbose++; quiet = 0; break;
591 version (); finish_out (); break;
596 fprintf(stderr, "%s: -Z not supported in this version\n",
601 case '1' + ENV_OPTION: case '2' + ENV_OPTION: case '3' + ENV_OPTION:
602 case '4' + ENV_OPTION: case '5' + ENV_OPTION: case '6' + ENV_OPTION:
603 case '7' + ENV_OPTION: case '8' + ENV_OPTION: case '9' + ENV_OPTION:
606 case '1': case '2': case '3': case '4':
607 case '5': case '6': case '7': case '8': case '9':
612 if (ENV_OPTION <= optc && optc != ENV_OPTION + '?')
614 /* Output a diagnostic, since getopt_long didn't. */
615 fprintf (stderr, "%s: ", program_name);
617 fprintf (stderr, "-%c: ", optc - ENV_OPTION);
619 fprintf (stderr, "--%s: ", longopts[longind].name);
620 fprintf (stderr, ("option not valid in "OPTIONS_VAR
621 " environment variable\n"));
625 } /* loop on all arguments */
627 /* By default, save name and timestamp on compression but do not
628 * restore them on decompression.
630 if (no_time < 0) no_time = decompress;
631 if (no_name < 0) no_name = decompress;
633 file_count = argc - optind;
637 if (ascii && !quiet) {
638 fprintf(stderr, "%s: option --ascii ignored on this system\n",
642 if (z_len == 0 || z_len > MAX_SUFFIX) {
643 fprintf(stderr, "%s: invalid suffix '%s'\n", program_name, z_suffix);
647 if (do_lzw && !decompress) work = lzw;
649 /* Allocate all global buffers (for DYN_ALLOC option) */
650 ALLOC(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
651 ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
652 ALLOC(ush, d_buf, DIST_BUFSIZE);
653 ALLOC(uch, window, 2L*WSIZE);
655 ALLOC(ush, tab_prefix, 1L<<BITS);
657 ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
658 ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
661 exiting_signal = quiet ? SIGPIPE : 0;
662 install_signal_handlers ();
664 /* And get to work */
665 if (file_count != 0) {
666 if (to_stdout && !test && !list && (!decompress || !ascii)) {
667 SET_BINARY_MODE (STDOUT_FILENO);
669 while (optind < argc) {
670 treat_file(argv[optind++]);
672 } else { /* Standard input */
675 if (stdin_was_read && close (STDIN_FILENO) != 0)
677 strcpy (ifname, "stdin");
682 /* Output any totals, and check for output errors. */
683 if (!quiet && 1 < file_count)
685 if (fflush (stdout) != 0)
690 && fdatasync (STDOUT_FILENO) != 0 && errno != EINVAL)
691 || close (STDOUT_FILENO) != 0)
695 return exit_code; /* just to avoid lint warning */
698 /* Return nonzero when at end of file on input. */
702 if (!decompress || last_member)
707 if (insize != INBUFSIZ || fill_inbuf (1) == EOF)
710 /* Unget the char that fill_inbuf got. */
717 /* ========================================================================
718 * Compress or decompress stdin
720 local void treat_stdin()
723 && (presume_input_tty
724 || isatty (decompress ? STDIN_FILENO : STDOUT_FILENO))) {
725 /* Do not send compressed data to the terminal or read it from
726 * the terminal. We get here when user invoked the program
727 * without parameters, so be helpful. According to the GNU standards:
729 * If there is one behavior you think is most useful when the output
730 * is to a terminal, and another that you think is most useful when
731 * the output is a file or a pipe, then it is usually best to make
732 * the default behavior the one that is useful with output to a
733 * terminal, and have an option for the other behavior.
735 * Here we use the --force option to get the other behavior.
739 ("%s: compressed data not %s a terminal."
740 " Use -f to force %scompression.\n"
741 "For help, type: %s -h\n"),
743 decompress ? "read from" : "written to",
744 decompress ? "de" : "",
749 if (decompress || !ascii) {
750 SET_BINARY_MODE (STDIN_FILENO);
752 if (!test && !list && (!decompress || !ascii)) {
753 SET_BINARY_MODE (STDOUT_FILENO);
755 strcpy(ifname, "stdin");
756 strcpy(ofname, "stdout");
758 /* Get the file's timestamp and size. */
759 if (fstat (STDIN_FILENO, &istat) != 0)
761 progerror ("standard input");
764 ifile_size = S_ISREG (istat.st_mode) ? istat.st_size : -1;
765 time_stamp.tv_nsec = -1;
766 if (!no_time || list)
768 if (S_ISREG (istat.st_mode))
769 time_stamp = get_stat_mtime (&istat);
771 gettime (&time_stamp);
774 clear_bufs(); /* clear input and output buffers */
778 stdin_was_read = true;
781 method = get_method(ifd);
783 do_exit(exit_code); /* error message already emitted */
787 do_list(ifd, method);
791 /* Actually do the compression/decompression. Loop over zipped members.
794 if (work (STDIN_FILENO, STDOUT_FILENO) != OK)
800 method = get_method(ifd);
801 if (method < 0) return; /* error message already emitted */
802 bytes_out = 0; /* required for length check */
807 fprintf(stderr, " OK\n");
809 } else if (!decompress) {
810 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
811 fprintf(stderr, "\n");
812 #ifdef DISPLAY_STDIN_RATIO
814 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
815 fprintf(stderr, "\n");
821 static char const dot = '.';
823 /* True if the cached directory for calls to openat etc. is DIR, with
824 length DIRLEN. DIR need not be null-terminated. DIRLEN must be
825 less than MAX_PATH_LEN. */
827 atdir_eq (char const *dir, ptrdiff_t dirlen)
830 dir = &dot, dirlen = 1;
831 return memcmp (dfname, dir, dirlen) == 0 && !dfname[dirlen];
834 /* Set the directory used for calls to openat etc. to be the directory
835 DIR, with length DIRLEN. DIR need not be null-terminated.
836 DIRLEN must be less than MAX_PATH_LEN. Return a file descriptor for
837 the directory, or -1 if one could not be obtained. */
839 atdir_set (char const *dir, ptrdiff_t dirlen)
841 /* Don't bother opening directories on older systems that
842 lack openat and unlinkat. It's not worth the porting hassle. */
843 #if HAVE_OPENAT && HAVE_UNLINKAT
844 enum { try_opening_directories = true };
846 enum { try_opening_directories = false };
849 if (try_opening_directories && ! atdir_eq (dir, dirlen))
854 dir = &dot, dirlen = 1;
855 memcpy (dfname, dir, dirlen);
856 dfname[dirlen] = '\0';
857 dfd = open (dfname, O_SEARCH | O_DIRECTORY);
863 /* ========================================================================
864 * Compress or decompress the given file
866 local void treat_file(iname)
869 /* Accept "-" as synonym for stdin */
870 if (strequ(iname, "-")) {
871 int cflag = to_stdout;
877 /* Check if the input file is present, set ifname and istat: */
878 ifd = open_input_file (iname, &istat);
882 /* If the input name is that of a directory, recurse or ignore: */
883 if (S_ISDIR(istat.st_mode)) {
886 treat_dir (ifd, iname);
887 /* Warning: ifname is now garbage */
892 WARN ((stderr, "%s: %s is a directory -- ignored\n",
893 program_name, ifname));
899 if (! S_ISREG (istat.st_mode))
902 "%s: %s is not a directory or a regular file - ignored\n",
903 program_name, ifname));
907 if (istat.st_mode & S_ISUID)
909 WARN ((stderr, "%s: %s is set-user-ID on execution - ignored\n",
910 program_name, ifname));
914 if (istat.st_mode & S_ISGID)
916 WARN ((stderr, "%s: %s is set-group-ID on execution - ignored\n",
917 program_name, ifname));
924 if (istat.st_mode & S_ISVTX)
927 "%s: %s has the sticky bit set - file ignored\n",
928 program_name, ifname));
932 if (2 <= istat.st_nlink)
934 WARN ((stderr, "%s: %s has %lu other link%c -- unchanged\n",
935 program_name, ifname,
936 (unsigned long int) istat.st_nlink - 1,
937 istat.st_nlink == 2 ? ' ' : 's'));
944 ifile_size = S_ISREG (istat.st_mode) ? istat.st_size : -1;
945 time_stamp.tv_nsec = -1;
946 if (!no_time || list)
947 time_stamp = get_stat_mtime (&istat);
949 /* Generate output file name. For -r and (-t or -l), skip files
950 * without a valid gzip suffix (check done in make_ofname).
952 if (to_stdout && !list && !test) {
953 strcpy(ofname, "stdout");
955 } else if (make_ofname() != OK) {
960 clear_bufs(); /* clear input and output buffers */
964 method = get_method(ifd); /* updates ofname if original given */
967 return; /* error message already emitted */
971 do_list(ifd, method);
972 if (close (ifd) != 0)
977 /* If compressing to a file, check if ofname is not ambiguous
978 * because the operating system truncates names. Otherwise, generate
979 * a new ofname and save the original name in the compressed file.
983 /* Keep remove_ofname_fd negative. */
985 if (create_outfile() != OK) return;
987 if (!decompress && save_orig_name && !verbose && !quiet) {
988 fprintf(stderr, "%s: %s compressed to %s\n",
989 program_name, ifname, ofname);
992 /* Keep the name even if not truncated except with --no-name: */
993 if (!save_orig_name) save_orig_name = !no_name;
996 fprintf(stderr, "%s:\t", ifname);
999 /* Actually do the compression/decompression. Loop over zipped members.
1002 if ((*work)(ifd, ofd) != OK) {
1003 method = -1; /* force cleanup */
1010 method = get_method(ifd);
1011 if (method < 0) break; /* error message already emitted */
1012 bytes_out = 0; /* required for length check */
1015 if (close (ifd) != 0)
1023 && ((0 <= dfd && fdatasync (dfd) != 0 && errno != EINVAL)
1024 || (fsync (ofd) != 0 && errno != EINVAL)))
1025 || close (ofd) != 0)
1032 char *ifbase = last_component (ifname);
1033 int ufd = atdir_eq (ifname, ifbase - ifname) ? dfd : -1;
1036 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
1037 remove_ofname_fd = -1;
1038 res = ufd < 0 ? xunlink (ifname) : unlinkat (ufd, ifbase, 0);
1039 unlink_errno = res == 0 ? 0 : errno;
1040 sigprocmask (SIG_SETMASK, &oldset, NULL);
1044 WARN ((stderr, "%s: ", program_name));
1047 errno = unlink_errno;
1056 remove_output_file ();
1060 /* Display statistics */
1063 fprintf(stderr, " OK");
1064 } else if (decompress) {
1065 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
1067 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
1069 if (!test && !to_stdout)
1070 fprintf(stderr, " -- %s %s", keep ? "created" : "replaced with",
1072 fprintf(stderr, "\n");
1076 /* ========================================================================
1077 * Create the output file. Return OK or ERROR.
1078 * Try several times if necessary to avoid truncating the z_suffix. For
1079 * example, do not create a compressed file of name "1234567890123."
1080 * Sets save_orig_name to true if the file name has been truncated.
1081 * IN assertions: the input file has already been open (ifd is set) and
1082 * ofname has already been updated if there was an original name.
1083 * OUT assertions: ifd and ofd are closed in case of error.
1085 local int create_outfile()
1087 int name_shortened = 0;
1088 int flags = (O_WRONLY | O_CREAT | O_EXCL
1089 | (ascii && decompress ? 0 : O_BINARY));
1090 char const *base = ofname;
1091 int atfd = AT_FDCWD;
1095 char const *b = last_component (ofname);
1096 int f = atdir_set (ofname, b - ofname);
1109 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
1110 remove_ofname_fd = ofd = openat (atfd, base, flags, S_IRUSR | S_IWUSR);
1112 sigprocmask (SIG_SETMASK, &oldset, NULL);
1121 shorten_name (ofname);
1127 if (check_ofname () != OK)
1141 if (name_shortened && decompress)
1143 /* name might be too long if an original name was saved */
1144 WARN ((stderr, "%s: %s: warning, name truncated\n",
1145 program_name, ofname));
1151 /* ========================================================================
1152 * Return a pointer to the 'z' suffix of a file name, or NULL. For all
1153 * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
1154 * accepted suffixes, in addition to the value of the --suffix option.
1155 * ".tgz" is a useful convention for tar.z files on systems limited
1156 * to 3 characters extensions. On such systems, ".?z" and ".??z" are
1157 * also accepted suffixes. For Unix, we do not want to accept any
1158 * .??z suffix as indicating a compressed file; some people use .xyz
1159 * to denote volume data.
1161 local char *get_suffix(name)
1165 char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */
1166 static char const *known_suffixes[] =
1167 {NULL, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
1168 #ifdef MAX_EXT_CHARS
1173 bool suffix_of_builtin = false;
1175 /* Normally put Z_SUFFIX at the start of KNOWN_SUFFIXES, but if it
1176 is a suffix of one of them, put it at the end. */
1177 for (suf = known_suffixes + 1; *suf; suf++)
1179 size_t suflen = strlen (*suf);
1180 if (z_len < suflen && strequ (z_suffix, *suf + suflen - z_len))
1182 suffix_of_builtin = true;
1187 char *z_lower = xstrdup(z_suffix);
1189 known_suffixes[suffix_of_builtin
1190 ? sizeof known_suffixes / sizeof *known_suffixes - 2
1192 suf = known_suffixes + suffix_of_builtin;
1194 nlen = strlen(name);
1195 if (nlen <= MAX_SUFFIX+2) {
1196 strcpy(suffix, name);
1198 strcpy(suffix, name+nlen-MAX_SUFFIX-2);
1201 slen = strlen(suffix);
1204 int s = strlen(*suf);
1205 if (slen > s && ! ISSLASH (suffix[slen - s - 1])
1206 && strequ(suffix + slen - s, *suf)) {
1207 match = name+nlen-s;
1210 } while (*++suf != NULL);
1217 /* Open file NAME with the given flags and store its status
1218 into *ST. Return a file descriptor to the newly opened file, or -1
1219 (setting errno) on failure. */
1221 open_and_stat (char *name, int flags, struct stat *st)
1224 int atfd = AT_FDCWD;
1225 char const *base = name;
1227 /* Refuse to follow symbolic links unless -c or -f. */
1228 if (!to_stdout && !force)
1230 if (HAVE_WORKING_O_NOFOLLOW)
1231 flags |= O_NOFOLLOW;
1235 if (lstat (name, st) != 0)
1237 else if (S_ISLNK (st->st_mode))
1248 char const *b = last_component (name);
1249 int f = atdir_set (name, b - name);
1257 fd = openat (atfd, base, flags);
1258 if (0 <= fd && fstat (fd, st) != 0)
1269 /* ========================================================================
1270 * Set ifname to the input file name (with a suffix appended if necessary)
1271 * and istat to its stats. For decompression, if no file exists with the
1272 * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
1273 * For MSDOS, we try only z_suffix and z.
1274 * Return an open file descriptor or -1.
1277 open_input_file (iname, sbuf)
1281 int ilen; /* strlen(ifname) */
1282 int z_suffix_errno = 0;
1283 static char const *suffixes[] = {NULL, ".gz", ".z", "-z", ".Z", NULL};
1284 char const **suf = suffixes;
1286 #ifdef NO_MULTIPLE_DOTS
1287 char *dot; /* pointer to ifname extension, or NULL */
1290 int open_flags = (O_RDONLY | O_NONBLOCK | O_NOCTTY
1291 | (ascii && !decompress ? 0 : O_BINARY));
1295 if (sizeof ifname - 1 <= strlen (iname))
1298 strcpy(ifname, iname);
1300 /* If input file exists, return OK. */
1301 fd = open_and_stat (ifname, open_flags, sbuf);
1305 if (!decompress || errno != ENOENT) {
1309 /* File.ext doesn't exist. Try adding a suffix. */
1310 s = get_suffix(ifname);
1312 progerror(ifname); /* ifname already has z suffix and does not exist */
1315 #ifdef NO_MULTIPLE_DOTS
1316 dot = strrchr(ifname, '.');
1318 strcat(ifname, ".");
1319 dot = strrchr(ifname, '.');
1322 ilen = strlen(ifname);
1323 if (strequ(z_suffix, ".gz")) suf++;
1325 /* Search for all suffixes */
1327 char const *s0 = s = *suf;
1328 strcpy (ifname, iname);
1329 #ifdef NO_MULTIPLE_DOTS
1331 if (*dot == '\0') strcpy (dot, ".");
1333 #ifdef MAX_EXT_CHARS
1334 if (MAX_EXT_CHARS < strlen (s) + strlen (dot + 1))
1335 dot[MAX_EXT_CHARS + 1 - strlen (s)] = '\0';
1337 if (sizeof ifname <= ilen + strlen (s))
1340 fd = open_and_stat (ifname, open_flags, sbuf);
1343 if (errno != ENOENT)
1348 if (strequ (s0, z_suffix))
1349 z_suffix_errno = errno;
1350 } while (*++suf != NULL);
1352 /* No suffix found, complain using z_suffix: */
1353 strcpy(ifname, iname);
1354 #ifdef NO_MULTIPLE_DOTS
1355 if (*dot == '\0') strcpy(dot, ".");
1357 #ifdef MAX_EXT_CHARS
1358 if (MAX_EXT_CHARS < z_len + strlen (dot + 1))
1359 dot[MAX_EXT_CHARS + 1 - z_len] = '\0';
1361 strcat(ifname, z_suffix);
1362 errno = z_suffix_errno;
1367 fprintf (stderr, "%s: %s: file name too long\n", program_name, iname);
1372 /* ========================================================================
1373 * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
1374 * Sets save_orig_name to true if the file name has been truncated.
1376 local int make_ofname()
1378 char *suff; /* ofname z suffix */
1380 strcpy(ofname, ifname);
1381 /* strip a version number if any and get the gzip suffix if present: */
1382 suff = get_suffix(ofname);
1386 /* With -t or -l, try all files (even without .gz suffix)
1387 * except with -r (behave as with just -dr).
1389 if (!recursive && (list || test)) return OK;
1391 /* Avoid annoying messages with -r */
1392 if (verbose || (!recursive && !quiet)) {
1393 WARN((stderr,"%s: %s: unknown suffix -- ignored\n",
1394 program_name, ifname));
1398 /* Make a special case for .tgz and .taz: */
1400 if (strequ(suff, ".tgz") || strequ(suff, ".taz")) {
1401 strcpy(suff, ".tar");
1403 *suff = '\0'; /* strip the z suffix */
1405 /* ofname might be changed later if infile contains an original name */
1407 } else if (suff && ! force) {
1408 /* Avoid annoying messages with -r (see treat_dir()) */
1409 if (verbose || (!recursive && !quiet)) {
1410 /* Don't use WARN, as it affects exit status. */
1411 fprintf (stderr, "%s: %s already has %s suffix -- unchanged\n",
1412 program_name, ifname, suff);
1418 #ifdef NO_MULTIPLE_DOTS
1419 suff = strrchr(ofname, '.');
1421 if (sizeof ofname <= strlen (ofname) + 1)
1423 strcat(ofname, ".");
1424 # ifdef MAX_EXT_CHARS
1425 if (strequ(z_suffix, "z")) {
1426 if (sizeof ofname <= strlen (ofname) + 2)
1428 strcat(ofname, "gz"); /* enough room */
1431 /* On the Atari and some versions of MSDOS,
1432 * ENAMETOOLONG does not work correctly. So we
1433 * must truncate here.
1435 } else if (strlen(suff)-1 + z_len > MAX_SUFFIX) {
1436 suff[MAX_SUFFIX+1-z_len] = '\0';
1440 #endif /* NO_MULTIPLE_DOTS */
1441 if (sizeof ofname <= strlen (ofname) + z_len)
1443 strcat(ofname, z_suffix);
1445 } /* decompress ? */
1449 WARN ((stderr, "%s: %s: file name too long\n", program_name, ifname));
1453 /* Discard NBYTES input bytes from the input, or up through the next
1454 zero byte if NBYTES == (size_t) -1. If FLAGS say that the header
1455 CRC should be computed, update the CRC accordingly. */
1457 discard_input_bytes (nbytes, flags)
1463 uch c = get_byte ();
1464 if (flags & HEADER_CRC)
1466 if (nbytes != (size_t) -1)
1473 /* ========================================================================
1474 * Check the magic number of the input file and update ofname if an
1475 * original name was given and to_stdout is not set.
1476 * Return the compression method, -1 for error, -2 for warning.
1477 * Set inptr to the offset of the next byte to be processed.
1478 * Updates time_stamp if there is one and neither -m nor -n is used.
1479 * This function may be called repeatedly for an input file consisting
1480 * of several contiguous gzip'ed members.
1481 * IN assertions: there is at least one remaining compressed member.
1482 * If the member is a zip file, it must be the only one.
1484 local int get_method(in)
1485 int in; /* input file descriptor */
1487 uch flags; /* compression flags */
1488 uch magic[10]; /* magic header */
1489 int imagic0; /* first magic byte or EOF */
1490 int imagic1; /* like magic[1], but can represent EOF */
1491 ulg stamp; /* timestamp */
1493 /* If --force and --stdout, zcat == cat, so do not complain about
1494 * premature end of file: use try_byte instead of get_byte.
1496 if (force && to_stdout) {
1497 imagic0 = try_byte();
1499 imagic1 = try_byte ();
1501 /* If try_byte returned EOF, magic[1] == (char) EOF. */
1503 magic[0] = get_byte ();
1506 magic[1] = get_byte ();
1507 imagic1 = 0; /* avoid lint warning */
1509 imagic1 = try_byte ();
1513 method = -1; /* unknown yet */
1514 part_nb++; /* number of parts in gzip file */
1517 /* assume multiple members in gzip file except for record oriented I/O */
1519 if (memcmp(magic, GZIP_MAGIC, 2) == 0
1520 || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
1522 method = (int)get_byte();
1523 if (method != DEFLATED) {
1525 "%s: %s: unknown method %d -- not supported\n",
1526 program_name, ifname, method);
1531 flags = (uch)get_byte();
1533 if ((flags & ENCRYPTED) != 0) {
1535 "%s: %s is encrypted -- not supported\n",
1536 program_name, ifname);
1540 if ((flags & RESERVED) != 0) {
1542 "%s: %s has flags 0x%x -- not supported\n",
1543 program_name, ifname, flags);
1545 if (force <= 1) return -1;
1547 stamp = (ulg)get_byte();
1548 stamp |= ((ulg)get_byte()) << 8;
1549 stamp |= ((ulg)get_byte()) << 16;
1550 stamp |= ((ulg)get_byte()) << 24;
1551 if (stamp != 0 && !no_time)
1553 if (stamp <= TYPE_MAXIMUM (time_t))
1555 time_stamp.tv_sec = stamp;
1556 time_stamp.tv_nsec = 0;
1561 "%s: %s: MTIME %lu out of range for this platform\n",
1562 program_name, ifname, stamp));
1563 time_stamp.tv_sec = TYPE_MAXIMUM (time_t);
1564 time_stamp.tv_nsec = TIMESPEC_RESOLUTION - 1;
1568 magic[8] = get_byte (); /* Ignore extra flags. */
1569 magic[9] = get_byte (); /* Ignore OS type. */
1571 if (flags & HEADER_CRC)
1573 magic[2] = DEFLATED;
1575 magic[4] = stamp & 0xff;
1576 magic[5] = (stamp >> 8) & 0xff;
1577 magic[6] = (stamp >> 16) & 0xff;
1578 magic[7] = stamp >> 24;
1583 if ((flags & EXTRA_FIELD) != 0) {
1585 unsigned int len = lenbuf[0] = get_byte ();
1586 len |= (lenbuf[1] = get_byte ()) << 8;
1588 fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n",
1589 program_name, ifname, len);
1591 if (flags & HEADER_CRC)
1593 discard_input_bytes (len, flags);
1596 /* Get original file name if it was truncated */
1597 if ((flags & ORIG_NAME) != 0) {
1598 if (no_name || (to_stdout && !list) || part_nb > 1) {
1599 /* Discard the old name */
1600 discard_input_bytes (-1, flags);
1602 /* Copy the base name. Keep a directory prefix intact. */
1603 char *p = gzip_base_name (ofname);
1606 *p = (char) get_byte ();
1607 if (*p++ == '\0') break;
1608 if (p >= ofname+sizeof(ofname)) {
1609 gzip_error ("corrupted input -- file name too large");
1612 if (flags & HEADER_CRC)
1613 updcrc ((uch *) base, p - base);
1614 p = gzip_base_name (base);
1615 memmove (base, p, strlen (p) + 1);
1616 /* If necessary, adapt the name to local OS conventions: */
1618 MAKE_LEGAL_NAME(base);
1619 if (base) list=0; /* avoid warning about unused variable */
1621 } /* no_name || to_stdout */
1624 /* Discard file comment if any */
1625 if ((flags & COMMENT) != 0) {
1626 discard_input_bytes (-1, flags);
1629 if (flags & HEADER_CRC)
1631 unsigned int crc16 = updcrc (magic, 0) & 0xffff;
1632 unsigned int header16 = get_byte ();
1633 header16 |= ((unsigned int) get_byte ()) << 8;
1634 if (header16 != crc16)
1637 "%s: %s: header checksum 0x%04x != computed checksum 0x%04x\n",
1638 program_name, ifname, header16, crc16);
1646 header_bytes = inptr + 2*4; /* include crc and size */
1649 } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
1650 && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0) {
1651 /* To simplify the code, we support a zip file when alone only.
1652 * We are thus guaranteed that the entire local header fits in inbuf.
1656 if (check_zipfile(in) != OK) return -1;
1657 /* check_zipfile may get ofname from the local header */
1660 } else if (memcmp(magic, PACK_MAGIC, 2) == 0) {
1664 } else if (memcmp(magic, LZW_MAGIC, 2) == 0) {
1666 method = COMPRESSED;
1669 } else if (memcmp(magic, LZH_MAGIC, 2) == 0) {
1674 } else if (force && to_stdout && !list) { /* pass input unchanged */
1680 if (imagic0 != EOF) {
1681 write_buf (STDOUT_FILENO, magic, 1);
1685 if (method >= 0) return method;
1688 fprintf (stderr, "\n%s: %s: not in gzip format\n",
1689 program_name, ifname);
1696 for (inbyte = imagic1; inbyte == 0; inbyte = try_byte ())
1701 WARN ((stderr, "\n%s: %s: decompression OK, trailing zero bytes ignored\n",
1702 program_name, ifname));
1707 WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n",
1708 program_name, ifname));
1713 /* ========================================================================
1714 * Display the characteristics of the compressed file.
1715 * If the given method is < 0, display the accumulated totals.
1716 * IN assertions: time_stamp, header_bytes and ifile_size are initialized.
1718 local void do_list(ifd, method)
1719 int ifd; /* input file descriptor */
1720 int method; /* compression method */
1722 ulg crc; /* original crc */
1723 static int first_time = 1;
1724 static char const *const methods[MAX_METHODS] = {
1729 "", "", "", "", /* 4 to 7 reserved */
1731 int positive_off_t_width = 1;
1734 for (o = OFF_T_MAX; 9 < o; o /= 10) {
1735 positive_off_t_width++;
1738 if (first_time && method >= 0) {
1741 printf("method crc date time ");
1744 printf("%*.*s %*.*s ratio uncompressed_name\n",
1745 positive_off_t_width, positive_off_t_width, "compressed",
1746 positive_off_t_width, positive_off_t_width, "uncompressed");
1748 } else if (method < 0) {
1749 if (total_in <= 0 || total_out <= 0) return;
1753 if (verbose || !quiet) {
1754 fprint_off(stdout, total_in, positive_off_t_width);
1756 fprint_off(stdout, total_out, positive_off_t_width);
1759 display_ratio(total_out-(total_in-header_bytes), total_out, stdout);
1760 /* header_bytes is not meaningful but used to ensure the same
1761 * ratio if there is a single file.
1763 printf(" (totals)\n");
1766 crc = (ulg)~0; /* unknown */
1768 bytes_in = ifile_size;
1770 if (method == DEFLATED && !last_member) {
1771 /* Get the crc and uncompressed size for gzip'ed (not zip'ed) files.
1772 * If the lseek fails, we could use read() to get to the end, but
1773 * --list is used to get quick results.
1774 * Use "gunzip < foo.gz | wc -c" to get the uncompressed size if
1775 * you are not concerned about speed.
1777 bytes_in = lseek(ifd, (off_t)(-8), SEEK_END);
1778 if (bytes_in != -1L) {
1781 if (read(ifd, (char*)buf, sizeof(buf)) != sizeof(buf)) {
1785 bytes_out = LG(buf+4);
1791 static char const month_abbr[][4]
1792 = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1793 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
1794 struct tm *tm = localtime (&time_stamp.tv_sec);
1795 printf ("%5s %08lx ", methods[method], crc);
1797 printf ("%s%3d %02d:%02d ", month_abbr[tm->tm_mon],
1798 tm->tm_mday, tm->tm_hour, tm->tm_min);
1800 printf ("??? ?? ??:?? ");
1802 fprint_off(stdout, bytes_in, positive_off_t_width);
1804 fprint_off(stdout, bytes_out, positive_off_t_width);
1806 if (bytes_in == -1L) {
1808 bytes_in = bytes_out = header_bytes = 0;
1809 } else if (total_in >= 0) {
1810 total_in += bytes_in;
1812 if (bytes_out == -1L) {
1814 bytes_in = bytes_out = header_bytes = 0;
1815 } else if (total_out >= 0) {
1816 total_out += bytes_out;
1818 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out, stdout);
1819 printf(" %s\n", ofname);
1822 /* ========================================================================
1823 * Shorten the given name by one character, or replace a .tar extension
1824 * with .tgz. Truncate the last part of the name which is longer than
1825 * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
1826 * has only parts shorter than MIN_PART truncate the longest part.
1827 * For decompression, just remove the last character of the name.
1829 * IN assertion: for compression, the suffix of the given name is z_suffix.
1831 local void shorten_name(name)
1834 int len; /* length of name without z_suffix */
1835 char *trunc = NULL; /* character to be truncated */
1836 int plen; /* current part length */
1837 int min_part = MIN_PART; /* current minimum part length */
1843 gzip_error ("name too short");
1847 p = get_suffix(name);
1849 gzip_error ("can't recover suffix\n");
1853 /* compress 1234567890.tar to 1234567890.tgz */
1854 if (len > 4 && strequ(p-4, ".tar")) {
1855 strcpy(p-4, ".tgz");
1858 /* Try keeping short extensions intact:
1859 * 1234.678.012.gz -> 123.678.012.gz
1862 p = last_component (name);
1864 plen = strcspn(p, PART_SEP);
1866 if (plen > min_part) trunc = p-1;
1869 } while (trunc == NULL && --min_part != 0);
1871 if (trunc != NULL) {
1873 trunc[0] = trunc[1];
1877 trunc = strrchr(name, PART_SEP[0]);
1879 gzip_error ("internal error in shorten_name");
1880 if (trunc[1] == '\0') trunc--; /* force truncation */
1882 strcpy(trunc, z_suffix);
1885 /* ========================================================================
1886 * The compressed file already exists, so ask for confirmation.
1887 * Return ERROR if the file must be skipped.
1889 local int check_ofname()
1891 /* Ask permission to overwrite the existing file */
1894 fprintf (stderr, "%s: %s already exists;", program_name, ofname);
1895 if (foreground && (presume_input_tty || isatty (STDIN_FILENO))) {
1896 fprintf(stderr, " do you wish to overwrite (y or n)? ");
1901 fprintf(stderr, "\tnot overwritten\n");
1902 if (exit_code == OK) exit_code = WARNING;
1906 if (xunlink (ofname)) {
1913 /* Change the owner and group of a file. FD is a file descriptor for
1914 the file and NAME its name. Change it to user UID and to group GID.
1915 If UID or GID is -1, though, do not change the corresponding user
1918 do_chown (int fd, char const *name, uid_t uid, gid_t gid)
1922 ignore_value (fchown (fd, uid, gid));
1924 ignore_value (chown (name, uid, gid));
1929 /* ========================================================================
1930 * Copy modes, times, ownership from input file to output file.
1931 * IN assertion: to_stdout is false.
1933 local void copy_stat(ifstat)
1934 struct stat *ifstat;
1936 mode_t mode = ifstat->st_mode & S_IRWXUGO;
1941 struct timespec timespec[2];
1942 timespec[0] = get_stat_atime (ifstat);
1943 timespec[1] = get_stat_mtime (ifstat);
1944 restoring = (decompress && 0 <= time_stamp.tv_nsec
1945 && ! (timespec[1].tv_sec == time_stamp.tv_sec
1946 && timespec[1].tv_nsec == time_stamp.tv_nsec));
1948 timespec[1] = time_stamp;
1950 if (fdutimens (ofd, ofname, timespec) == 0)
1952 if (restoring && 1 < verbose) {
1953 fprintf(stderr, "%s: timestamp restored\n", ofname);
1959 WARN ((stderr, "%s: ", program_name));
1968 /* Change the group first, then the permissions, then the owner.
1969 That way, the permissions will be correct on systems that allow
1970 users to give away files, without introducing a security hole.
1971 Security depends on permissions not containing the setuid or
1974 do_chown (ofd, ofname, -1, ifstat->st_gid);
1977 r = fchmod (ofd, mode);
1979 r = chmod (ofname, mode);
1983 WARN ((stderr, "%s: ", program_name));
1990 do_chown (ofd, ofname, ifstat->st_uid, -1);
1995 /* ========================================================================
1996 * Recurse through the given directory.
1998 local void treat_dir (fd, dir)
2003 char nbuf[MAX_PATH_LEN];
2008 dirp = fdopendir (fd);
2016 entries = streamsavedir (dirp, SAVEDIR_SORT_NONE);
2019 if (closedir (dirp) != 0)
2024 for (entry = entries; *entry; entry += entrylen + 1) {
2025 size_t len = strlen (dir);
2026 entrylen = strlen (entry);
2027 if (strequ (entry, ".") || strequ (entry, ".."))
2029 if (len + entrylen < MAX_PATH_LEN - 2) {
2031 if (*last_component (nbuf) && !ISSLASH (nbuf[len - 1]))
2033 strcpy (nbuf + len, entry);
2036 fprintf(stderr,"%s: %s/%s: pathname too long\n",
2037 program_name, dir, entry);
2043 #endif /* ! NO_DIR */
2045 /* Make sure signals get handled properly. */
2048 install_signal_handlers ()
2050 int nsigs = sizeof handled_sig / sizeof handled_sig[0];
2054 struct sigaction act;
2056 sigemptyset (&caught_signals);
2057 for (i = 0; i < nsigs; i++)
2059 sigaction (handled_sig[i], NULL, &act);
2060 if (act.sa_handler != SIG_IGN)
2061 sigaddset (&caught_signals, handled_sig[i]);
2064 act.sa_handler = abort_gzip_signal;
2065 act.sa_mask = caught_signals;
2068 for (i = 0; i < nsigs; i++)
2069 if (sigismember (&caught_signals, handled_sig[i]))
2073 sigaction (handled_sig[i], &act, NULL);
2076 for (i = 0; i < nsigs; i++)
2077 if (signal (handled_sig[i], SIG_IGN) != SIG_IGN)
2081 signal (handled_sig[i], abort_gzip_signal);
2082 siginterrupt (handled_sig[i], 1);
2087 /* ========================================================================
2088 * Free all dynamically allocated variables and exit with the given code.
2090 local void do_exit(exitcode)
2093 static int in_exit = 0;
2095 if (in_exit) exit(exitcode);
2115 if (fclose (stdout) != 0)
2120 /* ========================================================================
2121 * Close and unlink the output file.
2124 remove_output_file ()
2129 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
2130 fd = remove_ofname_fd;
2133 remove_ofname_fd = -1;
2137 sigprocmask (SIG_SETMASK, &oldset, NULL);
2140 /* ========================================================================
2146 remove_output_file ();
2150 /* ========================================================================
2154 abort_gzip_signal (sig)
2158 signal (sig, SIG_IGN);
2159 remove_output_file ();
2160 if (sig == exiting_signal)
2162 signal (sig, SIG_DFL);