1 /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
3 Copyright (C) 1999, 2001-2002, 2006-2007, 2009-2022 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) 2022 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>
78 #include "ignore-value.h"
79 #include "stat-time.h"
100 # include <utimens.h>
104 # define MAX_PATH_LEN 1024 /* max pathname length */
116 off_t
lseek (int fd
, off_t offset
, int whence
);
119 #ifndef HAVE_WORKING_O_NOFOLLOW
120 # define HAVE_WORKING_O_NOFOLLOW 0
123 /* Separator for file name parts (see shorten_name()) */
124 #ifdef NO_MULTIPLE_DOTS
125 # define PART_SEP "-"
127 # define PART_SEP "."
132 /* With IBM_Z_DFLTCC, DEFLATE COMPRESSION works faster with
133 page-aligned input and output buffers, and requires page-aligned
134 windows; the alignment requirement is 4096. On other platforms
135 alignment doesn't hurt, and alignment up to 4096 is portable so
137 #if defined HAVE_C_ALIGNASOF || defined alignas
138 # define BUFFER_ALIGNED alignas (4096)
140 # define BUFFER_ALIGNED /**/
142 DECLARE(uch BUFFER_ALIGNED
, inbuf
, INBUFSIZ
+INBUF_EXTRA
);
143 DECLARE(uch BUFFER_ALIGNED
, outbuf
, OUTBUFSIZ
+OUTBUF_EXTRA
);
144 DECLARE(ush
, d_buf
, DIST_BUFSIZE
);
145 DECLARE(uch BUFFER_ALIGNED
, window
, 2L*WSIZE
);
147 DECLARE(ush
, tab_prefix
, 1L<<BITS
);
149 DECLARE(ush
, tab_prefix0
, 1L<<(BITS
-1));
150 DECLARE(ush
, tab_prefix1
, 1L<<(BITS
-1));
153 /* local variables */
155 /* If true, pretend that standard input is a tty. This option
156 is deliberately not documented, and only for testing. */
157 static bool presume_input_tty
;
159 /* If true, transfer output data to the output file's storage device
160 when supported. Otherwise, if the system crashes around the time
161 gzip is run, the user might lose both input and output data. See:
162 Pillai TS et al. All file systems are not created equal: on the
163 complexity of crafting crash-consistent applications. OSDI'14. 2014:433-48.
164 https://www.usenix.org/conference/osdi14/technical-sessions/presentation/pillai */
165 static bool synchronous
;
167 static int ascii
= 0; /* convert end-of-lines to local OS conventions */
168 int to_stdout
= 0; /* output to stdout (-c) */
169 static int decompress
= 0; /* decompress (-d) */
170 static int force
= 0; /* don't ask questions, compress links (-f) */
171 static int keep
= 0; /* keep (don't delete) input files */
172 static int no_name
= -1; /* don't save or restore the original file name */
173 static int no_time
= -1; /* don't save or restore the original file time */
174 static int recursive
= 0; /* recurse through directories (-r) */
175 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 int test
= 0; /* test .gz file integrity */
182 static int foreground
= 0; /* set if program run in foreground */
183 char *program_name
; /* program name */
184 int maxbits
= BITS
; /* max bits per code for LZW */
185 int method
= DEFLATED
;/* compression method */
186 int level
= 6; /* compression level */
187 int exit_code
= OK
; /* program exit code */
188 int save_orig_name
; /* set if original name must be saved */
189 static int last_member
; /* set for .zip and .Z files */
190 static int part_nb
; /* number of parts in .gz file */
191 off_t ifile_size
; /* input file size, -1 for devices (debug only) */
192 static char *env
; /* contents of GZIP env variable */
193 static char const *z_suffix
; /* default suffix (can be set with --suffix) */
194 static size_t z_len
; /* strlen(z_suffix) */
196 /* The original timestamp (modification time). If the original is
197 unknown, TIME_STAMP.tv_nsec is negative. If the original is
198 greater than struct timespec range, TIME_STAMP is the maximal
199 struct timespec value; this can happen on hosts with 32-bit signed
200 time_t because the gzip format's MTIME is 32-bit unsigned.
201 The original cannot be less than struct timespec range. */
202 struct timespec time_stamp
;
204 /* The set of signals that are caught. */
205 static sigset_t caught_signals
;
207 /* If nonzero then exit with status WARNING, rather than with the usual
208 signal status, on receipt of a signal with this value. This
209 suppresses a "Broken Pipe" message with some shells. */
210 static int volatile exiting_signal
;
212 /* If nonnegative, close this file descriptor and unlink remove_ofname
214 static int volatile remove_ofname_fd
= -1;
215 static char volatile remove_ofname
[MAX_PATH_LEN
];
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 rsyncable 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 _Noreturn
static void try_help (void);
309 static void help (void);
310 static void license (void);
311 static void version (void);
312 static int input_eof (void);
313 static void treat_stdin (void);
314 static void treat_file (char *iname
);
315 static int create_outfile (void);
316 static char *get_suffix (char *name
);
317 static int open_input_file (char *iname
, struct stat
*sbuf
);
318 static void discard_input_bytes (size_t nbytes
, unsigned int flags
);
319 static int make_ofname (void);
320 static void shorten_name (char *name
);
321 static int get_method (int in
);
322 static void do_list (int method
);
323 static int check_ofname (void);
324 static void copy_stat (struct stat
*ifstat
);
325 static void install_signal_handlers (void);
326 static void remove_output_file (bool);
327 static void abort_gzip_signal (int);
328 _Noreturn
static 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 static 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 /* ======================================================================== */
351 static char const* const help_msg
[] = {
352 "Compress or uncompress FILEs (by default, compress FILES in-place).",
354 "Mandatory arguments to long options are mandatory for short options too.",
357 " -a, --ascii ascii text; convert end-of-line using local conventions",
359 " -c, --stdout write on standard output, keep original files unchanged",
360 " -d, --decompress decompress",
361 /* -e, --encrypt encrypt */
362 " -f, --force force overwrite of output file and compress links",
363 " -h, --help give this help",
364 /* -k, --pkzip force output in pkzip format */
365 " -k, --keep keep (don't delete) input files",
366 " -l, --list list compressed file contents",
367 " -L, --license display software license",
369 " -m do not save or restore the original modification time",
370 " -M, --time save or restore the original modification time",
372 " -n, --no-name do not save or restore the original name and timestamp",
373 " -N, --name save or restore the original name and timestamp",
374 " -q, --quiet suppress all warnings",
376 " -r, --recursive operate recursively on directories",
378 " --rsyncable make rsync-friendly archive",
379 " -S, --suffix=SUF use suffix SUF on compressed files",
380 " --synchronous synchronous output (safer if system crashes, but slower)",
381 " -t, --test test compressed file integrity",
382 " -v, --verbose verbose mode",
383 " -V, --version display version number",
384 " -1, --fast compress faster",
385 " -9, --best compress better",
387 "With no FILE, or when FILE is -, read standard input.",
389 "Report bugs to <bug-gzip@gnu.org>.",
391 char const *const *p
= help_msg
;
393 printf ("Usage: %s [OPTION]... [FILE]...\n", program_name
);
394 while (*p
) printf ("%s\n", *p
++);
397 /* ======================================================================== */
401 char const *const *p
= license_msg
;
403 printf ("%s %s\n", program_name
, Version
);
404 while (*p
) printf ("%s\n", *p
++);
407 /* ======================================================================== */
413 printf ("Written by Jean-loup Gailly.\n");
417 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
= test
= 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;
593 fprintf(stderr
, "%s: -Z not supported in this version\n",
597 case '1' + ENV_OPTION
: case '2' + ENV_OPTION
: case '3' + ENV_OPTION
:
598 case '4' + ENV_OPTION
: case '5' + ENV_OPTION
: case '6' + ENV_OPTION
:
599 case '7' + ENV_OPTION
: case '8' + ENV_OPTION
: case '9' + ENV_OPTION
:
602 case '1': case '2': case '3': case '4':
603 case '5': case '6': case '7': case '8': case '9':
608 if (ENV_OPTION
<= optc
&& optc
!= ENV_OPTION
+ '?')
610 /* Output a diagnostic, since getopt_long didn't. */
611 fprintf (stderr
, "%s: ", program_name
);
613 fprintf (stderr
, "-%c: ", optc
- ENV_OPTION
);
615 fprintf (stderr
, "--%s: ", longopts
[longind
].name
);
616 fprintf (stderr
, ("option not valid in "OPTIONS_VAR
617 " environment variable\n"));
621 } /* loop on all arguments */
623 /* By default, save name and timestamp on compression but do not
624 * restore them on decompression.
626 if (no_time
< 0) no_time
= decompress
;
627 if (no_name
< 0) no_name
= decompress
;
629 file_count
= argc
- optind
;
633 if (ascii
&& !quiet
) {
634 fprintf(stderr
, "%s: option --ascii ignored on this system\n",
638 if (z_len
== 0 || z_len
> MAX_SUFFIX
) {
639 fprintf(stderr
, "%s: invalid suffix '%s'\n", program_name
, z_suffix
);
643 /* Allocate all global buffers (for DYN_ALLOC option) */
644 ALLOC(uch
, inbuf
, INBUFSIZ
+INBUF_EXTRA
);
645 ALLOC(uch
, outbuf
, OUTBUFSIZ
+OUTBUF_EXTRA
);
646 ALLOC(ush
, d_buf
, DIST_BUFSIZE
);
647 ALLOC(uch
, window
, 2L*WSIZE
);
649 ALLOC(ush
, tab_prefix
, 1L<<BITS
);
651 ALLOC(ush
, tab_prefix0
, 1L<<(BITS
-1));
652 ALLOC(ush
, tab_prefix1
, 1L<<(BITS
-1));
656 exiting_signal
= quiet
? SIGPIPE
: 0;
658 install_signal_handlers ();
660 /* And get to work */
661 if (file_count
!= 0) {
662 if (to_stdout
&& !test
&& (!decompress
|| !ascii
)) {
663 SET_BINARY_MODE (STDOUT_FILENO
);
665 while (optind
< argc
) {
666 treat_file(argv
[optind
++]);
668 } else { /* Standard input */
671 if (stdin_was_read
&& close (STDIN_FILENO
) != 0)
673 strcpy (ifname
, "stdin");
678 /* Output any totals, and check for output errors. */
679 if (!quiet
&& 1 < file_count
)
681 if (fflush (stdout
) != 0)
686 && fdatasync (STDOUT_FILENO
) != 0 && errno
!= EINVAL
)
687 || close (STDOUT_FILENO
) != 0)
693 /* Return nonzero when at end of file on input. */
697 if (!decompress
|| last_member
)
702 if (insize
!= INBUFSIZ
|| fill_inbuf (1) == EOF
)
705 /* Unget the char that fill_inbuf got. */
713 get_input_size_and_time (void)
716 time_stamp
.tv_nsec
= -1;
718 /* Record the input file's size and timestamp only if it is a
719 regular file. Doing this for the timestamp helps to keep gzip's
720 output more reproducible when it is used as part of a
723 if (S_ISREG (istat
.st_mode
))
725 ifile_size
= istat
.st_size
;
726 if (!no_time
|| list
)
727 time_stamp
= get_stat_mtime (&istat
);
731 /* ========================================================================
732 * Compress or decompress stdin
738 && (presume_input_tty
739 || isatty (decompress
? STDIN_FILENO
: STDOUT_FILENO
))) {
740 /* Do not send compressed data to the terminal or read it from
741 * the terminal. We get here when user invoked the program
742 * without parameters, so be helpful. According to the GNU standards:
744 * If there is one behavior you think is most useful when the output
745 * is to a terminal, and another that you think is most useful when
746 * the output is a file or a pipe, then it is usually best to make
747 * the default behavior the one that is useful with output to a
748 * terminal, and have an option for the other behavior.
750 * Here we use the --force option to get the other behavior.
754 ("%s: compressed data not %s a terminal."
755 " Use -f to force %scompression.\n"
756 "For help, type: %s -h\n"),
758 decompress
? "read from" : "written to",
759 decompress
? "de" : "",
764 if (decompress
|| !ascii
) {
765 SET_BINARY_MODE (STDIN_FILENO
);
767 if (!test
&& (!decompress
|| !ascii
)) {
768 SET_BINARY_MODE (STDOUT_FILENO
);
770 strcpy(ifname
, "stdin");
771 strcpy(ofname
, "stdout");
773 /* Get the file's timestamp and size. */
774 if (fstat (STDIN_FILENO
, &istat
) != 0)
776 progerror ("standard input");
780 get_input_size_and_time ();
782 clear_bufs(); /* clear input and output buffers */
786 stdin_was_read
= true;
789 method
= get_method(ifd
);
791 do_exit(exit_code
); /* error message already emitted */
795 /* Actually do the compression/decompression. Loop over zipped members.
798 if (work (STDIN_FILENO
, STDOUT_FILENO
) != OK
)
804 method
= get_method(ifd
);
805 if (method
< 0) return; /* error message already emitted */
806 bytes_out
= 0; /* required for length check */
817 fprintf(stderr
, " OK\n");
819 } else if (!decompress
) {
820 display_ratio(bytes_in
-(bytes_out
-header_bytes
), bytes_in
, stderr
);
821 fprintf(stderr
, "\n");
822 #ifdef DISPLAY_STDIN_RATIO
824 display_ratio(bytes_out
-(bytes_in
-header_bytes
), bytes_out
,stderr
);
825 fprintf(stderr
, "\n");
831 static char const dot
= '.';
833 /* True if the cached directory for calls to openat etc. is DIR, with
834 length DIRLEN. DIR need not be null-terminated. DIRLEN must be
835 less than MAX_PATH_LEN. */
837 atdir_eq (char const *dir
, ptrdiff_t dirlen
)
840 dir
= &dot
, dirlen
= 1;
841 return memcmp (dfname
, dir
, dirlen
) == 0 && !dfname
[dirlen
];
844 /* Set the directory used for calls to openat etc. to be the directory
845 DIR, with length DIRLEN. DIR need not be null-terminated.
846 DIRLEN must be less than MAX_PATH_LEN. Return a file descriptor for
847 the directory, or -1 if one could not be obtained. */
849 atdir_set (char const *dir
, ptrdiff_t dirlen
)
851 /* Don't bother opening directories on older systems that
852 lack openat and unlinkat. It's not worth the porting hassle. */
853 #if HAVE_OPENAT && HAVE_UNLINKAT
854 enum { try_opening_directories
= true };
856 enum { try_opening_directories
= false };
859 if (try_opening_directories
&& ! atdir_eq (dir
, dirlen
))
864 dir
= &dot
, dirlen
= 1;
865 memcpy (dfname
, dir
, dirlen
);
866 dfname
[dirlen
] = '\0';
867 dfd
= open (dfname
, O_SEARCH
| O_DIRECTORY
);
873 /* ========================================================================
874 * Compress or decompress the given file
877 treat_file (char *iname
)
879 /* Accept "-" as synonym for stdin */
880 if (strequ(iname
, "-")) {
881 int cflag
= to_stdout
;
887 /* Check if the input file is present, set ifname and istat: */
888 ifd
= open_input_file (iname
, &istat
);
892 /* If the input name is that of a directory, recurse or ignore: */
893 if (S_ISDIR(istat
.st_mode
)) {
896 treat_dir (ifd
, iname
);
897 /* Warning: ifname is now garbage */
902 WARN ((stderr
, "%s: %s is a directory -- ignored\n",
903 program_name
, ifname
));
909 if (! S_ISREG (istat
.st_mode
))
912 "%s: %s is not a directory or a regular file - ignored\n",
913 program_name
, ifname
));
917 if (istat
.st_mode
& S_ISUID
)
919 WARN ((stderr
, "%s: %s is set-user-ID on execution - ignored\n",
920 program_name
, ifname
));
924 if (istat
.st_mode
& S_ISGID
)
926 WARN ((stderr
, "%s: %s is set-group-ID on execution - ignored\n",
927 program_name
, ifname
));
934 if (istat
.st_mode
& S_ISVTX
)
937 "%s: %s has the sticky bit set - file ignored\n",
938 program_name
, ifname
));
942 if (2 <= istat
.st_nlink
)
944 WARN ((stderr
, "%s: %s has %lu other link%s -- file ignored\n",
945 program_name
, ifname
,
946 (unsigned long int) istat
.st_nlink
- 1,
947 istat
.st_nlink
== 2 ? "" : "s"));
954 get_input_size_and_time ();
956 /* Generate output file name. For -r and (-t or -l), skip files
957 * without a valid gzip suffix (check done in make_ofname).
959 if (to_stdout
&& !test
) {
960 strcpy(ofname
, "stdout");
962 } else if (make_ofname() != OK
) {
967 clear_bufs(); /* clear input and output buffers */
971 method
= get_method(ifd
); /* updates ofname if original given */
974 return; /* error message already emitted */
978 /* If compressing to a file, check if ofname is not ambiguous
979 * because the operating system truncates names. Otherwise, generate
980 * a new ofname and save the original name in the compressed file.
984 /* Keep remove_ofname_fd negative. */
986 if (create_outfile() != OK
) return;
988 if (!decompress
&& save_orig_name
&& !verbose
&& !quiet
) {
989 fprintf(stderr
, "%s: %s compressed to %s\n",
990 program_name
, ifname
, ofname
);
993 /* Keep the name even if not truncated except with --no-name: */
994 if (!save_orig_name
) save_orig_name
= !no_name
;
996 if (verbose
&& !list
) {
997 fprintf(stderr
, "%s:\t", ifname
);
1000 /* Actually do the compression/decompression. Loop over zipped members.
1003 if ((*work
)(ifd
, ofd
) != OK
) {
1004 method
= -1; /* force cleanup */
1011 method
= get_method(ifd
);
1012 if (method
< 0) break; /* error message already emitted */
1013 bytes_out
= 0; /* required for length check */
1016 if (close (ifd
) != 0)
1030 && ((0 <= dfd
&& fdatasync (dfd
) != 0 && errno
!= EINVAL
)
1031 || (fsync (ofd
) != 0 && errno
!= EINVAL
)))
1032 || close (ofd
) != 0)
1039 char *ifbase
= last_component (ifname
);
1040 int ufd
= atdir_eq (ifname
, ifbase
- ifname
) ? dfd
: -1;
1043 sigprocmask (SIG_BLOCK
, &caught_signals
, &oldset
);
1044 remove_ofname_fd
= -1;
1045 res
= ufd
< 0 ? xunlink (ifname
) : unlinkat (ufd
, ifbase
, 0);
1046 unlink_errno
= res
== 0 ? 0 : errno
;
1047 sigprocmask (SIG_SETMASK
, &oldset
, NULL
);
1051 WARN ((stderr
, "%s: ", program_name
));
1054 errno
= unlink_errno
;
1063 remove_output_file (false);
1067 /* Display statistics */
1070 fprintf(stderr
, " OK");
1071 } else if (decompress
) {
1072 display_ratio(bytes_out
-(bytes_in
-header_bytes
), bytes_out
,stderr
);
1074 display_ratio(bytes_in
-(bytes_out
-header_bytes
), bytes_in
, stderr
);
1077 fprintf(stderr
, " -- %s %s", keep
? "created" : "replaced with",
1079 fprintf(stderr
, "\n");
1084 volatile_strcpy (char volatile *dst
, char const volatile *src
)
1086 while ((*dst
++ = *src
++))
1090 /* ========================================================================
1091 * Create the output file. Return OK or ERROR.
1092 * Try several times if necessary to avoid truncating the z_suffix. For
1093 * example, do not create a compressed file of name "1234567890123."
1094 * Sets save_orig_name to true if the file name has been truncated.
1095 * IN assertions: the input file has already been open (ifd is set) and
1096 * ofname has already been updated if there was an original name.
1097 * OUT assertions: ifd and ofd are closed in case of error.
1102 int name_shortened
= 0;
1103 int flags
= (O_WRONLY
| O_CREAT
| O_EXCL
1104 | (ascii
&& decompress
? 0 : O_BINARY
));
1105 char const *base
= ofname
;
1106 int atfd
= AT_FDCWD
;
1110 char const *b
= last_component (ofname
);
1111 int f
= atdir_set (ofname
, b
- ofname
);
1124 volatile_strcpy (remove_ofname
, ofname
);
1126 sigprocmask (SIG_BLOCK
, &caught_signals
, &oldset
);
1127 remove_ofname_fd
= ofd
= openat (atfd
, base
, flags
, S_IRUSR
| S_IWUSR
);
1129 sigprocmask (SIG_SETMASK
, &oldset
, NULL
);
1138 shorten_name (ofname
);
1144 if (check_ofname () != OK
)
1158 if (name_shortened
&& decompress
)
1160 /* name might be too long if an original name was saved */
1161 WARN ((stderr
, "%s: %s: warning, name truncated\n",
1162 program_name
, ofname
));
1168 /* ========================================================================
1169 * Return a pointer to the 'z' suffix of a file name, or NULL. For all
1170 * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
1171 * accepted suffixes, in addition to the value of the --suffix option.
1172 * ".tgz" is a useful convention for tar.z files on systems limited
1173 * to 3 characters extensions. On such systems, ".?z" and ".??z" are
1174 * also accepted suffixes. For Unix, we do not want to accept any
1175 * .??z suffix as indicating a compressed file; some people use .xyz
1176 * to denote volume data.
1179 get_suffix (char *name
)
1182 char suffix
[MAX_SUFFIX
+3]; /* last chars of name, forced to lower case */
1183 static char const *known_suffixes
[] =
1184 {NULL
, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
1185 #ifdef MAX_EXT_CHARS
1190 bool suffix_of_builtin
= false;
1192 /* Normally put Z_SUFFIX at the start of KNOWN_SUFFIXES, but if it
1193 is a suffix of one of them, put it at the end. */
1194 for (suf
= known_suffixes
+ 1; *suf
; suf
++)
1196 size_t suflen
= strlen (*suf
);
1197 if (z_len
< suflen
&& strequ (z_suffix
, *suf
+ suflen
- z_len
))
1199 suffix_of_builtin
= true;
1204 char *z_lower
= xstrdup(z_suffix
);
1206 known_suffixes
[suffix_of_builtin
1207 ? sizeof known_suffixes
/ sizeof *known_suffixes
- 2
1209 suf
= known_suffixes
+ suffix_of_builtin
;
1211 nlen
= strlen(name
);
1212 if (nlen
<= MAX_SUFFIX
+2) {
1213 strcpy(suffix
, name
);
1215 strcpy(suffix
, name
+nlen
-MAX_SUFFIX
-2);
1218 slen
= strlen(suffix
);
1221 int s
= strlen(*suf
);
1222 if (slen
> s
&& ! ISSLASH (suffix
[slen
- s
- 1])
1223 && strequ(suffix
+ slen
- s
, *suf
)) {
1224 match
= name
+nlen
-s
;
1227 } while (*++suf
!= NULL
);
1234 /* Open file NAME with the given flags and store its status
1235 into *ST. Return a file descriptor to the newly opened file, or -1
1236 (setting errno) on failure. */
1238 open_and_stat (char *name
, int flags
, struct stat
*st
)
1241 int atfd
= AT_FDCWD
;
1242 char const *base
= name
;
1244 /* Refuse to follow symbolic links unless -c or -f. */
1245 if (!to_stdout
&& !force
)
1247 if (HAVE_WORKING_O_NOFOLLOW
)
1248 flags
|= O_NOFOLLOW
;
1252 if (lstat (name
, st
) != 0)
1254 else if (S_ISLNK (st
->st_mode
))
1265 char const *b
= last_component (name
);
1266 int f
= atdir_set (name
, b
- name
);
1274 fd
= openat (atfd
, base
, flags
);
1275 if (0 <= fd
&& fstat (fd
, st
) != 0)
1286 /* ========================================================================
1287 * Set ifname to the input file name (with a suffix appended if necessary)
1288 * and istat to its stats. For decompression, if no file exists with the
1289 * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
1290 * For MSDOS, we try only z_suffix and z.
1291 * Return an open file descriptor or -1.
1294 open_input_file (char *iname
, struct stat
*sbuf
)
1296 int ilen
; /* strlen(ifname) */
1297 int z_suffix_errno
= 0;
1298 static char const *suffixes
[] = {NULL
, ".gz", ".z", "-z", ".Z", NULL
};
1299 char const **suf
= suffixes
;
1301 #ifdef NO_MULTIPLE_DOTS
1302 char *dot
; /* pointer to ifname extension, or NULL */
1305 int open_flags
= (O_RDONLY
| O_NONBLOCK
| O_NOCTTY
1306 | (ascii
&& !decompress
? 0 : O_BINARY
));
1310 if (sizeof ifname
- 1 <= strlen (iname
))
1313 strcpy(ifname
, iname
);
1315 /* If input file exists, return OK. */
1316 fd
= open_and_stat (ifname
, open_flags
, sbuf
);
1320 if (!decompress
|| errno
!= ENOENT
) {
1324 /* File.ext doesn't exist. Try adding a suffix. */
1325 s
= get_suffix(ifname
);
1327 progerror(ifname
); /* ifname already has z suffix and does not exist */
1330 #ifdef NO_MULTIPLE_DOTS
1331 dot
= strrchr(ifname
, '.');
1333 strcat(ifname
, ".");
1334 dot
= strrchr(ifname
, '.');
1337 ilen
= strlen(ifname
);
1338 if (strequ(z_suffix
, ".gz")) suf
++;
1340 /* Search for all suffixes */
1342 char const *s0
= s
= *suf
;
1343 strcpy (ifname
, iname
);
1344 #ifdef NO_MULTIPLE_DOTS
1346 if (*dot
== '\0') strcpy (dot
, ".");
1348 #ifdef MAX_EXT_CHARS
1349 if (MAX_EXT_CHARS
< strlen (s
) + strlen (dot
+ 1))
1350 dot
[MAX_EXT_CHARS
+ 1 - strlen (s
)] = '\0';
1352 if (sizeof ifname
<= ilen
+ strlen (s
))
1355 fd
= open_and_stat (ifname
, open_flags
, sbuf
);
1358 if (errno
!= ENOENT
)
1363 if (strequ (s0
, z_suffix
))
1364 z_suffix_errno
= errno
;
1365 } while (*++suf
!= NULL
);
1367 /* No suffix found, complain using z_suffix: */
1368 strcpy(ifname
, iname
);
1369 #ifdef NO_MULTIPLE_DOTS
1370 if (*dot
== '\0') strcpy(dot
, ".");
1372 #ifdef MAX_EXT_CHARS
1373 if (MAX_EXT_CHARS
< z_len
+ strlen (dot
+ 1))
1374 dot
[MAX_EXT_CHARS
+ 1 - z_len
] = '\0';
1376 strcat(ifname
, z_suffix
);
1377 errno
= z_suffix_errno
;
1382 fprintf (stderr
, "%s: %s: file name too long\n", program_name
, iname
);
1387 /* ========================================================================
1388 * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
1389 * Sets save_orig_name to true if the file name has been truncated.
1394 char *suff
; /* ofname z suffix */
1396 strcpy(ofname
, ifname
);
1397 /* strip a version number if any and get the gzip suffix if present: */
1398 suff
= get_suffix(ofname
);
1402 /* With -t or -l, try all files (even without .gz suffix)
1403 * except with -r (behave as with just -dr).
1405 if (!recursive
&& test
)
1408 /* Avoid annoying messages with -r */
1409 if (verbose
|| (!recursive
&& !quiet
)) {
1410 WARN((stderr
,"%s: %s: unknown suffix -- ignored\n",
1411 program_name
, ifname
));
1415 /* Make a special case for .tgz and .taz: */
1417 if (strequ(suff
, ".tgz") || strequ(suff
, ".taz")) {
1418 strcpy(suff
, ".tar");
1420 *suff
= '\0'; /* strip the z suffix */
1422 /* ofname might be changed later if infile contains an original name */
1424 } else if (suff
&& ! force
) {
1425 /* Avoid annoying messages with -r (see treat_dir()) */
1426 if (verbose
|| (!recursive
&& !quiet
)) {
1427 /* Don't use WARN, as it affects exit status. */
1428 fprintf (stderr
, "%s: %s already has %s suffix -- unchanged\n",
1429 program_name
, ifname
, suff
);
1435 #ifdef NO_MULTIPLE_DOTS
1436 suff
= strrchr(ofname
, '.');
1438 if (sizeof ofname
<= strlen (ofname
) + 1)
1440 strcat(ofname
, ".");
1441 # ifdef MAX_EXT_CHARS
1442 if (strequ(z_suffix
, "z")) {
1443 if (sizeof ofname
<= strlen (ofname
) + 2)
1445 strcat(ofname
, "gz"); /* enough room */
1448 /* On the Atari and some versions of MSDOS,
1449 * ENAMETOOLONG does not work correctly. So we
1450 * must truncate here.
1452 } else if (strlen(suff
)-1 + z_len
> MAX_SUFFIX
) {
1453 suff
[MAX_SUFFIX
+1-z_len
] = '\0';
1457 #endif /* NO_MULTIPLE_DOTS */
1458 if (sizeof ofname
<= strlen (ofname
) + z_len
)
1460 strcat(ofname
, z_suffix
);
1462 } /* decompress ? */
1466 WARN ((stderr
, "%s: %s: file name too long\n", program_name
, ifname
));
1470 /* Discard NBYTES input bytes from the input, or up through the next
1471 zero byte if NBYTES == (size_t) -1. If FLAGS say that the header
1472 CRC should be computed, update the CRC accordingly. */
1474 discard_input_bytes (size_t nbytes
, unsigned int flags
)
1478 uch c
= get_byte ();
1479 if (flags
& HEADER_CRC
)
1481 if (nbytes
!= (size_t) -1)
1488 /* ========================================================================
1489 * Check the magic number of the input file and update ofname if an
1490 * original name was given and to_stdout is not set.
1491 * Return the compression method, -1 for error, -2 for warning.
1492 * Set inptr to the offset of the next byte to be processed.
1493 * Updates time_stamp if there is one and neither -m nor -n is used.
1494 * This function may be called repeatedly for an input file consisting
1495 * of several contiguous gzip'ed members.
1496 * 'in' is the input file descriptor.
1497 * IN assertions: there is at least one remaining compressed member.
1498 * If the member is a zip file, it must be the only one.
1503 uch flags
; /* compression flags */
1504 uch magic
[10]; /* magic header */
1505 int imagic0
; /* first magic byte or EOF */
1506 int imagic1
; /* like magic[1], but can represent EOF */
1507 ulg stamp
; /* timestamp */
1509 /* If --force and --stdout, zcat == cat, so do not complain about
1510 * premature end of file: use try_byte instead of get_byte.
1512 if (force
&& to_stdout
) {
1513 imagic0
= try_byte();
1515 imagic1
= try_byte ();
1517 /* If try_byte returned EOF, magic[1] == (char) EOF. */
1519 magic
[0] = get_byte ();
1522 magic
[1] = get_byte ();
1523 imagic1
= 0; /* avoid lint warning */
1525 imagic1
= try_byte ();
1529 method
= -1; /* unknown yet */
1530 part_nb
++; /* number of parts in gzip file */
1533 /* assume multiple members in gzip file except for record oriented I/O */
1535 if (memcmp(magic
, GZIP_MAGIC
, 2) == 0
1536 || memcmp(magic
, OLD_GZIP_MAGIC
, 2) == 0) {
1538 method
= (int)get_byte();
1539 if (method
!= DEFLATED
) {
1541 "%s: %s: unknown method %d -- not supported\n",
1542 program_name
, ifname
, method
);
1547 flags
= (uch
)get_byte();
1549 if ((flags
& ENCRYPTED
) != 0) {
1551 "%s: %s is encrypted -- not supported\n",
1552 program_name
, ifname
);
1556 if ((flags
& RESERVED
) != 0) {
1558 "%s: %s has flags 0x%x -- not supported\n",
1559 program_name
, ifname
, flags
);
1561 if (force
<= 1) return -1;
1563 stamp
= (ulg
)get_byte();
1564 stamp
|= ((ulg
)get_byte()) << 8;
1565 stamp
|= ((ulg
)get_byte()) << 16;
1566 stamp
|= ((ulg
)get_byte()) << 24;
1567 if (stamp
!= 0 && !no_time
)
1569 if (stamp
<= TYPE_MAXIMUM (time_t))
1571 time_stamp
.tv_sec
= stamp
;
1572 time_stamp
.tv_nsec
= 0;
1577 "%s: %s: MTIME %lu out of range for this platform\n",
1578 program_name
, ifname
, stamp
));
1579 time_stamp
.tv_sec
= TYPE_MAXIMUM (time_t);
1580 time_stamp
.tv_nsec
= TIMESPEC_RESOLUTION
- 1;
1584 magic
[8] = get_byte (); /* Ignore extra flags. */
1585 magic
[9] = get_byte (); /* Ignore OS type. */
1587 if (flags
& HEADER_CRC
)
1589 magic
[2] = DEFLATED
;
1591 magic
[4] = stamp
& 0xff;
1592 magic
[5] = (stamp
>> 8) & 0xff;
1593 magic
[6] = (stamp
>> 16) & 0xff;
1594 magic
[7] = stamp
>> 24;
1599 if ((flags
& EXTRA_FIELD
) != 0) {
1601 unsigned int len
= lenbuf
[0] = get_byte ();
1602 len
|= (lenbuf
[1] = get_byte ()) << 8;
1604 fprintf(stderr
,"%s: %s: extra field of %u bytes ignored\n",
1605 program_name
, ifname
, len
);
1607 if (flags
& HEADER_CRC
)
1609 discard_input_bytes (len
, flags
);
1612 /* Get original file name if it was truncated */
1613 if ((flags
& ORIG_NAME
) != 0) {
1614 if (no_name
|| (to_stdout
&& !list
) || part_nb
> 1) {
1615 /* Discard the old name */
1616 discard_input_bytes (-1, flags
);
1618 /* Copy the base name. Keep a directory prefix intact. */
1619 char *p
= gzip_base_name (ofname
);
1622 *p
= (char) get_byte ();
1623 if (*p
++ == '\0') break;
1624 if (p
>= ofname
+sizeof(ofname
)) {
1625 gzip_error ("corrupted input -- file name too large");
1628 if (flags
& HEADER_CRC
)
1629 updcrc ((uch
*) base
, p
- base
);
1630 p
= gzip_base_name (base
);
1631 memmove (base
, p
, strlen (p
) + 1);
1632 /* If necessary, adapt the name to local OS conventions: */
1634 MAKE_LEGAL_NAME(base
);
1635 if (base
) list
=0; /* avoid warning about unused variable */
1637 } /* no_name || to_stdout */
1640 /* Discard file comment if any */
1641 if ((flags
& COMMENT
) != 0) {
1642 discard_input_bytes (-1, flags
);
1645 if (flags
& HEADER_CRC
)
1647 unsigned int crc16
= updcrc (magic
, 0) & 0xffff;
1648 unsigned int header16
= get_byte ();
1649 header16
|= ((unsigned int) get_byte ()) << 8;
1650 if (header16
!= crc16
)
1653 "%s: %s: header checksum 0x%04x != computed checksum 0x%04x\n",
1654 program_name
, ifname
, header16
, crc16
);
1662 header_bytes
= inptr
+ 2*4; /* include crc and size */
1665 } else if (memcmp(magic
, PKZIP_MAGIC
, 2) == 0 && inptr
== 2
1666 && memcmp((char*)inbuf
, PKZIP_MAGIC
, 4) == 0) {
1667 /* To simplify the code, we support a zip file when alone only.
1668 * We are thus guaranteed that the entire local header fits in inbuf.
1672 if (check_zipfile(in
) != OK
) return -1;
1673 /* check_zipfile may get ofname from the local header */
1676 } else if (memcmp(magic
, PACK_MAGIC
, 2) == 0) {
1680 } else if (memcmp(magic
, LZW_MAGIC
, 2) == 0) {
1682 method
= COMPRESSED
;
1685 } else if (memcmp(magic
, LZH_MAGIC
, 2) == 0) {
1690 } else if (force
&& to_stdout
&& !list
) { /* pass input unchanged */
1696 if (imagic0
!= EOF
) {
1697 write_buf (STDOUT_FILENO
, magic
, 1);
1700 if (method
>= 0) return method
;
1703 fprintf (stderr
, "\n%s: %s: not in gzip format\n",
1704 program_name
, ifname
);
1711 for (inbyte
= imagic1
; inbyte
== 0; inbyte
= try_byte ())
1716 WARN ((stderr
, "\n%s: %s: decompression OK, trailing zero bytes ignored\n",
1717 program_name
, ifname
));
1722 WARN((stderr
, "\n%s: %s: decompression OK, trailing garbage ignored\n",
1723 program_name
, ifname
));
1728 /* ========================================================================
1729 * Display the characteristics of the compressed file.
1730 * If the given method is < 0, display the accumulated totals.
1731 * IN assertions: time_stamp, header_bytes and ifile_size are initialized.
1734 do_list (int method
)
1736 ulg crc
; /* original crc */
1737 static int first_time
= 1;
1738 static char const *const methods
[MAX_METHODS
] = {
1743 "", "", "", "", /* 4 to 7 reserved */
1745 int positive_off_t_width
= INT_STRLEN_BOUND (off_t
) - 1;
1747 if (first_time
&& method
>= 0) {
1750 printf("method crc date time ");
1753 printf("%*.*s %*.*s ratio uncompressed_name\n",
1754 positive_off_t_width
, positive_off_t_width
, "compressed",
1755 positive_off_t_width
, positive_off_t_width
, "uncompressed");
1757 } else if (method
< 0) {
1758 if (total_in
<= 0 || total_out
<= 0) return;
1762 if (verbose
|| !quiet
) {
1763 fprint_off(stdout
, total_in
, positive_off_t_width
);
1765 fprint_off(stdout
, total_out
, positive_off_t_width
);
1768 display_ratio(total_out
-(total_in
-header_bytes
), total_out
, stdout
);
1769 /* header_bytes is not meaningful but used to ensure the same
1770 * ratio if there is a single file.
1772 printf(" (totals)\n");
1775 crc
= (ulg
)~0; /* unknown */
1777 if (method
== DEFLATED
&& !last_member
) {
1783 static char const month_abbr
[][4]
1784 = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1785 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
1786 struct tm
*tm
= localtime (&time_stamp
.tv_sec
);
1787 printf ("%5s %08lx ", methods
[method
], crc
);
1789 printf ("%s%3d %02d:%02d ", month_abbr
[tm
->tm_mon
],
1790 tm
->tm_mday
, tm
->tm_hour
, tm
->tm_min
);
1792 printf ("??? ?? ??:?? ");
1794 fprint_off(stdout
, bytes_in
, positive_off_t_width
);
1796 fprint_off(stdout
, bytes_out
, positive_off_t_width
);
1798 if (bytes_in
== -1L) {
1800 bytes_in
= bytes_out
= header_bytes
= 0;
1801 } else if (total_in
>= 0) {
1802 total_in
+= bytes_in
;
1804 if (bytes_out
== -1L) {
1806 bytes_in
= bytes_out
= header_bytes
= 0;
1807 } else if (total_out
>= 0) {
1808 total_out
+= bytes_out
;
1810 display_ratio(bytes_out
-(bytes_in
-header_bytes
), bytes_out
, stdout
);
1811 printf(" %s\n", ofname
);
1814 /* ========================================================================
1815 * Shorten the given name by one character, or replace a .tar extension
1816 * with .tgz. Truncate the last part of the name which is longer than
1817 * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
1818 * has only parts shorter than MIN_PART truncate the longest part.
1819 * For decompression, just remove the last character of the name.
1821 * IN assertion: for compression, the suffix of the given name is z_suffix.
1824 shorten_name (char *name
)
1826 int len
; /* length of name without z_suffix */
1827 char *trunc
= NULL
; /* character to be truncated */
1828 int plen
; /* current part length */
1829 int min_part
= MIN_PART
; /* current minimum part length */
1835 gzip_error ("name too short");
1839 p
= get_suffix(name
);
1841 gzip_error ("can't recover suffix\n");
1845 /* compress 1234567890.tar to 1234567890.tgz */
1846 if (len
> 4 && strequ(p
-4, ".tar")) {
1847 strcpy(p
-4, ".tgz");
1850 /* Try keeping short extensions intact:
1851 * 1234.678.012.gz -> 123.678.012.gz
1854 p
= last_component (name
);
1856 plen
= strcspn(p
, PART_SEP
);
1858 if (plen
> min_part
) trunc
= p
-1;
1861 } while (trunc
== NULL
&& --min_part
!= 0);
1863 if (trunc
!= NULL
) {
1865 trunc
[0] = trunc
[1];
1869 trunc
= strrchr(name
, PART_SEP
[0]);
1871 gzip_error ("internal error in shorten_name");
1872 if (trunc
[1] == '\0') trunc
--; /* force truncation */
1874 strcpy(trunc
, z_suffix
);
1877 /* ========================================================================
1878 * The compressed file already exists, so ask for confirmation.
1879 * Return ERROR if the file must be skipped.
1884 /* Ask permission to overwrite the existing file */
1887 fprintf (stderr
, "%s: %s already exists;", program_name
, ofname
);
1888 if (foreground
&& (presume_input_tty
|| isatty (STDIN_FILENO
))) {
1889 fprintf(stderr
, " do you wish to overwrite (y or n)? ");
1894 fprintf(stderr
, "\tnot overwritten\n");
1895 if (exit_code
== OK
) exit_code
= WARNING
;
1899 if (xunlink (ofname
)) {
1906 /* Change the owner and group of a file. FD is a file descriptor for
1907 the file and NAME its name. Change it to user UID and to group GID.
1908 If UID or GID is -1, though, do not change the corresponding user
1910 #if ! (HAVE_FCHOWN || HAVE_CHOWN)
1911 /* The types uid_t and gid_t do not exist on mingw, so don't assume them. */
1912 # define do_chown(fd, name, uid, gid) ((void) 0)
1915 do_chown (int fd
, char const *name
, uid_t uid
, gid_t gid
)
1918 ignore_value (fchown (fd
, uid
, gid
));
1920 ignore_value (chown (name
, uid
, gid
));
1925 /* ========================================================================
1926 * Copy modes, times, ownership from input file to output file.
1927 * IN assertion: to_stdout is false.
1930 copy_stat (struct stat
*ifstat
)
1932 mode_t mode
= ifstat
->st_mode
& S_IRWXUGO
;
1937 struct timespec timespec
[2];
1938 timespec
[0] = get_stat_atime (ifstat
);
1939 timespec
[1] = get_stat_mtime (ifstat
);
1940 restoring
= (decompress
&& 0 <= time_stamp
.tv_nsec
1941 && ! (timespec
[1].tv_sec
== time_stamp
.tv_sec
1942 && timespec
[1].tv_nsec
== time_stamp
.tv_nsec
));
1944 timespec
[1] = time_stamp
;
1946 if (fdutimens (ofd
, ofname
, timespec
) == 0)
1948 if (restoring
&& 1 < verbose
) {
1949 fprintf(stderr
, "%s: timestamp restored\n", ofname
);
1955 WARN ((stderr
, "%s: ", program_name
));
1964 /* Change the group first, then the permissions, then the owner.
1965 That way, the permissions will be correct on systems that allow
1966 users to give away files, without introducing a security hole.
1967 Security depends on permissions not containing the setuid or
1970 do_chown (ofd
, ofname
, -1, ifstat
->st_gid
);
1973 r
= fchmod (ofd
, mode
);
1975 r
= chmod (ofname
, mode
);
1979 WARN ((stderr
, "%s: ", program_name
));
1986 do_chown (ofd
, ofname
, ifstat
->st_uid
, -1);
1991 /* ========================================================================
1992 * Recurse through the given directory.
1995 treat_dir (int fd
, char *dir
)
1998 char nbuf
[MAX_PATH_LEN
];
2003 dirp
= fdopendir (fd
);
2011 entries
= streamsavedir (dirp
, SAVEDIR_SORT_NONE
);
2014 if (closedir (dirp
) != 0)
2019 for (entry
= entries
; *entry
; entry
+= entrylen
+ 1) {
2020 size_t len
= strlen (dir
);
2021 entrylen
= strlen (entry
);
2022 if (strequ (entry
, ".") || strequ (entry
, ".."))
2024 if (len
+ entrylen
< MAX_PATH_LEN
- 2) {
2026 if (*last_component (nbuf
) && !ISSLASH (nbuf
[len
- 1]))
2028 strcpy (nbuf
+ len
, entry
);
2031 fprintf(stderr
,"%s: %s/%s: pathname too long\n",
2032 program_name
, dir
, entry
);
2038 #endif /* ! NO_DIR */
2040 /* Make sure signals get handled properly. */
2043 install_signal_handlers ()
2045 int nsigs
= sizeof handled_sig
/ sizeof handled_sig
[0];
2047 struct sigaction act
;
2049 sigemptyset (&caught_signals
);
2050 for (i
= 0; i
< nsigs
; i
++)
2052 sigaction (handled_sig
[i
], NULL
, &act
);
2053 if (act
.sa_handler
!= SIG_IGN
)
2054 sigaddset (&caught_signals
, handled_sig
[i
]);
2057 act
.sa_handler
= abort_gzip_signal
;
2058 act
.sa_mask
= caught_signals
;
2061 for (i
= 0; i
< nsigs
; i
++)
2062 if (sigismember (&caught_signals
, handled_sig
[i
]))
2066 sigaction (handled_sig
[i
], &act
, NULL
);
2070 /* ========================================================================
2071 * Free all dynamically allocated variables and exit with the given code.
2074 do_exit (int exitcode
)
2076 static int in_exit
= 0;
2078 if (in_exit
) exit(exitcode
);
2098 if (fclose (stdout
) != 0)
2103 /* ========================================================================
2104 * Close and unlink the output file.
2107 remove_output_file (bool signals_already_blocked
)
2112 if (!signals_already_blocked
)
2113 sigprocmask (SIG_BLOCK
, &caught_signals
, &oldset
);
2114 fd
= remove_ofname_fd
;
2117 char fname
[MAX_PATH_LEN
];
2118 remove_ofname_fd
= -1;
2120 volatile_strcpy (fname
, remove_ofname
);
2123 if (!signals_already_blocked
)
2124 sigprocmask (SIG_SETMASK
, &oldset
, NULL
);
2127 /* ========================================================================
2133 remove_output_file (false);
2137 /* ========================================================================
2141 abort_gzip_signal (int sig
)
2143 remove_output_file (true);
2144 if (sig
== exiting_signal
)
2146 signal (sig
, SIG_DFL
);