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 #ifdef __alignas_is_defined
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 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 method
);
323 local
int check_ofname (void);
324 local
void copy_stat (struct stat
*ifstat
);
325 local
void install_signal_handlers (void);
326 static void remove_output_file (bool);
327 static void 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 "With no FILE, or when FILE is -, read standard input.",
388 "Report bugs to <bug-gzip@gnu.org>.",
390 char const *const *p
= help_msg
;
392 printf ("Usage: %s [OPTION]... [FILE]...\n", program_name
);
393 while (*p
) printf ("%s\n", *p
++);
396 /* ======================================================================== */
399 char const *const *p
= license_msg
;
401 printf ("%s %s\n", program_name
, Version
);
402 while (*p
) printf ("%s\n", *p
++);
405 /* ======================================================================== */
410 printf ("Written by Jean-loup Gailly.\n");
413 local
void progerror (char const *string
)
416 fprintf (stderr
, "%s: ", program_name
);
422 /* ======================================================================== */
423 int main (int argc
, char **argv
)
425 int file_count
; /* number of files to process */
426 size_t proglen
; /* length of program_name */
431 EXPAND(argc
, argv
); /* wild card expansion if necessary */
433 program_name
= gzip_base_name (argv
[0]);
434 proglen
= strlen (program_name
);
436 /* Suppress .exe for MSDOS and OS/2: */
437 if (4 < proglen
&& strequ (program_name
+ proglen
- 4, ".exe"))
438 program_name
[proglen
- 4] = '\0';
440 /* Add options in GZIP environment variable if there is one */
442 env
= add_envopt (&env_argc
, &argv_copy
, OPTIONS_VAR
);
443 env_argv
= env
? argv_copy
: NULL
;
446 # define GNU_STANDARD 1
449 /* For compatibility with old compress, use program name as an option.
450 * Unless you compile with -DGNU_STANDARD=0, this program will behave as
451 * gzip even if it is invoked under the name gunzip or zcat.
453 * Systems which do not support links can still use -d or -dc.
454 * Ignore an .exe extension for MSDOS and OS/2.
456 if (strncmp (program_name
, "un", 2) == 0 /* ungzip, uncompress */
457 || strncmp (program_name
, "gun", 3) == 0) /* gunzip */
459 else if (strequ (program_name
+ 1, "cat") /* zcat, pcat, gcat */
460 || strequ (program_name
, "gzcat")) /* gzcat */
461 decompress
= to_stdout
= 1;
465 z_len
= strlen(z_suffix
);
473 if (env_argv
[optind
] && strequ (env_argv
[optind
], "--"))
474 optc
= ENV_OPTION
+ '-';
477 optc
= getopt_long (env_argc
, env_argv
, shortopts
, longopts
,
483 if (optind
!= env_argc
)
486 ("%s: %s: non-option in "OPTIONS_VAR
487 " environment variable\n"),
488 program_name
, env_argv
[optind
]);
492 /* Wait until here before warning, so that GZIP='-q'
494 if (env_argc
!= 1 && !quiet
)
496 ("%s: warning: "OPTIONS_VAR
" environment variable"
497 " is deprecated; use an alias or script\n"),
500 /* Start processing ARGC and ARGV instead. */
510 optc
= getopt_long (argc
, argv
, shortopts
, longopts
, &longind
);
518 maxbits
= atoi(optarg
);
519 for (; *optarg
; optarg
++)
520 if (! ('0' <= *optarg
&& *optarg
<= '9'))
522 fprintf (stderr
, "%s: -b operand is not an integer\n",
528 to_stdout
= 1; break;
530 decompress
= 1; break;
534 help (); finish_out (); break;
538 list
= decompress
= test
= to_stdout
= 1; break;
540 license (); finish_out (); break;
541 case 'm': /* undocumented, may change later */
543 case 'M': /* undocumented, may change later */
546 case 'n' + ENV_OPTION
:
547 no_name
= no_time
= 1; break;
549 case 'N' + ENV_OPTION
:
550 no_name
= no_time
= 0; break;
551 case PRESUME_INPUT_TTY_OPTION
:
552 presume_input_tty
= true; break;
554 case 'q' + ENV_OPTION
:
555 quiet
= 1; verbose
= 0; break;
558 fprintf (stderr
, "%s: -r not supported on this system\n",
566 case RSYNCABLE_OPTION
:
567 case RSYNCABLE_OPTION
+ ENV_OPTION
:
571 #ifdef NO_MULTIPLE_DOTS
572 if (*optarg
== '.') optarg
++;
574 z_len
= strlen(optarg
);
577 case SYNCHRONOUS_OPTION
:
581 test
= decompress
= to_stdout
= 1;
584 case 'v' + ENV_OPTION
:
585 verbose
++; quiet
= 0; break;
587 version (); finish_out (); break;
589 fprintf(stderr
, "%s: -Z not supported in this version\n",
593 case '1' + ENV_OPTION
: case '2' + ENV_OPTION
: case '3' + ENV_OPTION
:
594 case '4' + ENV_OPTION
: case '5' + ENV_OPTION
: case '6' + ENV_OPTION
:
595 case '7' + ENV_OPTION
: case '8' + ENV_OPTION
: case '9' + ENV_OPTION
:
598 case '1': case '2': case '3': case '4':
599 case '5': case '6': case '7': case '8': case '9':
604 if (ENV_OPTION
<= optc
&& optc
!= ENV_OPTION
+ '?')
606 /* Output a diagnostic, since getopt_long didn't. */
607 fprintf (stderr
, "%s: ", program_name
);
609 fprintf (stderr
, "-%c: ", optc
- ENV_OPTION
);
611 fprintf (stderr
, "--%s: ", longopts
[longind
].name
);
612 fprintf (stderr
, ("option not valid in "OPTIONS_VAR
613 " environment variable\n"));
617 } /* loop on all arguments */
619 /* By default, save name and timestamp on compression but do not
620 * restore them on decompression.
622 if (no_time
< 0) no_time
= decompress
;
623 if (no_name
< 0) no_name
= decompress
;
625 file_count
= argc
- optind
;
629 if (ascii
&& !quiet
) {
630 fprintf(stderr
, "%s: option --ascii ignored on this system\n",
634 if (z_len
== 0 || z_len
> MAX_SUFFIX
) {
635 fprintf(stderr
, "%s: invalid suffix '%s'\n", program_name
, z_suffix
);
639 /* Allocate all global buffers (for DYN_ALLOC option) */
640 ALLOC(uch
, inbuf
, INBUFSIZ
+INBUF_EXTRA
);
641 ALLOC(uch
, outbuf
, OUTBUFSIZ
+OUTBUF_EXTRA
);
642 ALLOC(ush
, d_buf
, DIST_BUFSIZE
);
643 ALLOC(uch
, window
, 2L*WSIZE
);
645 ALLOC(ush
, tab_prefix
, 1L<<BITS
);
647 ALLOC(ush
, tab_prefix0
, 1L<<(BITS
-1));
648 ALLOC(ush
, tab_prefix1
, 1L<<(BITS
-1));
652 exiting_signal
= quiet
? SIGPIPE
: 0;
654 install_signal_handlers ();
656 /* And get to work */
657 if (file_count
!= 0) {
658 if (to_stdout
&& !test
&& (!decompress
|| !ascii
)) {
659 SET_BINARY_MODE (STDOUT_FILENO
);
661 while (optind
< argc
) {
662 treat_file(argv
[optind
++]);
664 } else { /* Standard input */
667 if (stdin_was_read
&& close (STDIN_FILENO
) != 0)
669 strcpy (ifname
, "stdin");
674 /* Output any totals, and check for output errors. */
675 if (!quiet
&& 1 < file_count
)
677 if (fflush (stdout
) != 0)
682 && fdatasync (STDOUT_FILENO
) != 0 && errno
!= EINVAL
)
683 || close (STDOUT_FILENO
) != 0)
689 /* Return nonzero when at end of file on input. */
693 if (!decompress
|| last_member
)
698 if (insize
!= INBUFSIZ
|| fill_inbuf (1) == EOF
)
701 /* Unget the char that fill_inbuf got. */
709 get_input_size_and_time (void)
712 time_stamp
.tv_nsec
= -1;
714 /* Record the input file's size and timestamp only if it is a
715 regular file. Doing this for the timestamp helps to keep gzip's
716 output more reproducible when it is used as part of a
719 if (S_ISREG (istat
.st_mode
))
721 ifile_size
= istat
.st_size
;
722 if (!no_time
|| list
)
723 time_stamp
= get_stat_mtime (&istat
);
727 /* ========================================================================
728 * Compress or decompress stdin
730 local
void treat_stdin()
733 && (presume_input_tty
734 || isatty (decompress
? STDIN_FILENO
: STDOUT_FILENO
))) {
735 /* Do not send compressed data to the terminal or read it from
736 * the terminal. We get here when user invoked the program
737 * without parameters, so be helpful. According to the GNU standards:
739 * If there is one behavior you think is most useful when the output
740 * is to a terminal, and another that you think is most useful when
741 * the output is a file or a pipe, then it is usually best to make
742 * the default behavior the one that is useful with output to a
743 * terminal, and have an option for the other behavior.
745 * Here we use the --force option to get the other behavior.
749 ("%s: compressed data not %s a terminal."
750 " Use -f to force %scompression.\n"
751 "For help, type: %s -h\n"),
753 decompress
? "read from" : "written to",
754 decompress
? "de" : "",
759 if (decompress
|| !ascii
) {
760 SET_BINARY_MODE (STDIN_FILENO
);
762 if (!test
&& (!decompress
|| !ascii
)) {
763 SET_BINARY_MODE (STDOUT_FILENO
);
765 strcpy(ifname
, "stdin");
766 strcpy(ofname
, "stdout");
768 /* Get the file's timestamp and size. */
769 if (fstat (STDIN_FILENO
, &istat
) != 0)
771 progerror ("standard input");
775 get_input_size_and_time ();
777 clear_bufs(); /* clear input and output buffers */
781 stdin_was_read
= true;
784 method
= get_method(ifd
);
786 do_exit(exit_code
); /* error message already emitted */
790 /* Actually do the compression/decompression. Loop over zipped members.
793 if (work (STDIN_FILENO
, STDOUT_FILENO
) != OK
)
799 method
= get_method(ifd
);
800 if (method
< 0) return; /* error message already emitted */
801 bytes_out
= 0; /* required for length check */
812 fprintf(stderr
, " OK\n");
814 } else if (!decompress
) {
815 display_ratio(bytes_in
-(bytes_out
-header_bytes
), bytes_in
, stderr
);
816 fprintf(stderr
, "\n");
817 #ifdef DISPLAY_STDIN_RATIO
819 display_ratio(bytes_out
-(bytes_in
-header_bytes
), bytes_out
,stderr
);
820 fprintf(stderr
, "\n");
826 static char const dot
= '.';
828 /* True if the cached directory for calls to openat etc. is DIR, with
829 length DIRLEN. DIR need not be null-terminated. DIRLEN must be
830 less than MAX_PATH_LEN. */
832 atdir_eq (char const *dir
, ptrdiff_t dirlen
)
835 dir
= &dot
, dirlen
= 1;
836 return memcmp (dfname
, dir
, dirlen
) == 0 && !dfname
[dirlen
];
839 /* Set the directory used for calls to openat etc. to be the directory
840 DIR, with length DIRLEN. DIR need not be null-terminated.
841 DIRLEN must be less than MAX_PATH_LEN. Return a file descriptor for
842 the directory, or -1 if one could not be obtained. */
844 atdir_set (char const *dir
, ptrdiff_t dirlen
)
846 /* Don't bother opening directories on older systems that
847 lack openat and unlinkat. It's not worth the porting hassle. */
848 #if HAVE_OPENAT && HAVE_UNLINKAT
849 enum { try_opening_directories
= true };
851 enum { try_opening_directories
= false };
854 if (try_opening_directories
&& ! atdir_eq (dir
, dirlen
))
859 dir
= &dot
, dirlen
= 1;
860 memcpy (dfname
, dir
, dirlen
);
861 dfname
[dirlen
] = '\0';
862 dfd
= open (dfname
, O_SEARCH
| O_DIRECTORY
);
868 /* ========================================================================
869 * Compress or decompress the given file
871 local
void treat_file(iname
)
874 /* Accept "-" as synonym for stdin */
875 if (strequ(iname
, "-")) {
876 int cflag
= to_stdout
;
882 /* Check if the input file is present, set ifname and istat: */
883 ifd
= open_input_file (iname
, &istat
);
887 /* If the input name is that of a directory, recurse or ignore: */
888 if (S_ISDIR(istat
.st_mode
)) {
891 treat_dir (ifd
, iname
);
892 /* Warning: ifname is now garbage */
897 WARN ((stderr
, "%s: %s is a directory -- ignored\n",
898 program_name
, ifname
));
904 if (! S_ISREG (istat
.st_mode
))
907 "%s: %s is not a directory or a regular file - ignored\n",
908 program_name
, ifname
));
912 if (istat
.st_mode
& S_ISUID
)
914 WARN ((stderr
, "%s: %s is set-user-ID on execution - ignored\n",
915 program_name
, ifname
));
919 if (istat
.st_mode
& S_ISGID
)
921 WARN ((stderr
, "%s: %s is set-group-ID on execution - ignored\n",
922 program_name
, ifname
));
929 if (istat
.st_mode
& S_ISVTX
)
932 "%s: %s has the sticky bit set - file ignored\n",
933 program_name
, ifname
));
937 if (2 <= istat
.st_nlink
)
939 WARN ((stderr
, "%s: %s has %lu other link%s -- file ignored\n",
940 program_name
, ifname
,
941 (unsigned long int) istat
.st_nlink
- 1,
942 istat
.st_nlink
== 2 ? "" : "s"));
949 get_input_size_and_time ();
951 /* Generate output file name. For -r and (-t or -l), skip files
952 * without a valid gzip suffix (check done in make_ofname).
954 if (to_stdout
&& !test
) {
955 strcpy(ofname
, "stdout");
957 } else if (make_ofname() != OK
) {
962 clear_bufs(); /* clear input and output buffers */
966 method
= get_method(ifd
); /* updates ofname if original given */
969 return; /* error message already emitted */
973 /* If compressing to a file, check if ofname is not ambiguous
974 * because the operating system truncates names. Otherwise, generate
975 * a new ofname and save the original name in the compressed file.
979 /* Keep remove_ofname_fd negative. */
981 if (create_outfile() != OK
) return;
983 if (!decompress
&& save_orig_name
&& !verbose
&& !quiet
) {
984 fprintf(stderr
, "%s: %s compressed to %s\n",
985 program_name
, ifname
, ofname
);
988 /* Keep the name even if not truncated except with --no-name: */
989 if (!save_orig_name
) save_orig_name
= !no_name
;
991 if (verbose
&& !list
) {
992 fprintf(stderr
, "%s:\t", ifname
);
995 /* Actually do the compression/decompression. Loop over zipped members.
998 if ((*work
)(ifd
, ofd
) != OK
) {
999 method
= -1; /* force cleanup */
1006 method
= get_method(ifd
);
1007 if (method
< 0) break; /* error message already emitted */
1008 bytes_out
= 0; /* required for length check */
1011 if (close (ifd
) != 0)
1025 && ((0 <= dfd
&& fdatasync (dfd
) != 0 && errno
!= EINVAL
)
1026 || (fsync (ofd
) != 0 && errno
!= EINVAL
)))
1027 || close (ofd
) != 0)
1034 char *ifbase
= last_component (ifname
);
1035 int ufd
= atdir_eq (ifname
, ifbase
- ifname
) ? dfd
: -1;
1038 sigprocmask (SIG_BLOCK
, &caught_signals
, &oldset
);
1039 remove_ofname_fd
= -1;
1040 res
= ufd
< 0 ? xunlink (ifname
) : unlinkat (ufd
, ifbase
, 0);
1041 unlink_errno
= res
== 0 ? 0 : errno
;
1042 sigprocmask (SIG_SETMASK
, &oldset
, NULL
);
1046 WARN ((stderr
, "%s: ", program_name
));
1049 errno
= unlink_errno
;
1058 remove_output_file (false);
1062 /* Display statistics */
1065 fprintf(stderr
, " OK");
1066 } else if (decompress
) {
1067 display_ratio(bytes_out
-(bytes_in
-header_bytes
), bytes_out
,stderr
);
1069 display_ratio(bytes_in
-(bytes_out
-header_bytes
), bytes_in
, stderr
);
1072 fprintf(stderr
, " -- %s %s", keep
? "created" : "replaced with",
1074 fprintf(stderr
, "\n");
1079 volatile_strcpy (char volatile *dst
, char const volatile *src
)
1081 while ((*dst
++ = *src
++))
1085 /* ========================================================================
1086 * Create the output file. Return OK or ERROR.
1087 * Try several times if necessary to avoid truncating the z_suffix. For
1088 * example, do not create a compressed file of name "1234567890123."
1089 * Sets save_orig_name to true if the file name has been truncated.
1090 * IN assertions: the input file has already been open (ifd is set) and
1091 * ofname has already been updated if there was an original name.
1092 * OUT assertions: ifd and ofd are closed in case of error.
1094 local
int create_outfile()
1096 int name_shortened
= 0;
1097 int flags
= (O_WRONLY
| O_CREAT
| O_EXCL
1098 | (ascii
&& decompress
? 0 : O_BINARY
));
1099 char const *base
= ofname
;
1100 int atfd
= AT_FDCWD
;
1104 char const *b
= last_component (ofname
);
1105 int f
= atdir_set (ofname
, b
- ofname
);
1118 volatile_strcpy (remove_ofname
, ofname
);
1120 sigprocmask (SIG_BLOCK
, &caught_signals
, &oldset
);
1121 remove_ofname_fd
= ofd
= openat (atfd
, base
, flags
, S_IRUSR
| S_IWUSR
);
1123 sigprocmask (SIG_SETMASK
, &oldset
, NULL
);
1132 shorten_name (ofname
);
1138 if (check_ofname () != OK
)
1152 if (name_shortened
&& decompress
)
1154 /* name might be too long if an original name was saved */
1155 WARN ((stderr
, "%s: %s: warning, name truncated\n",
1156 program_name
, ofname
));
1162 /* ========================================================================
1163 * Return a pointer to the 'z' suffix of a file name, or NULL. For all
1164 * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
1165 * accepted suffixes, in addition to the value of the --suffix option.
1166 * ".tgz" is a useful convention for tar.z files on systems limited
1167 * to 3 characters extensions. On such systems, ".?z" and ".??z" are
1168 * also accepted suffixes. For Unix, we do not want to accept any
1169 * .??z suffix as indicating a compressed file; some people use .xyz
1170 * to denote volume data.
1172 local
char *get_suffix(name
)
1176 char suffix
[MAX_SUFFIX
+3]; /* last chars of name, forced to lower case */
1177 static char const *known_suffixes
[] =
1178 {NULL
, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
1179 #ifdef MAX_EXT_CHARS
1184 bool suffix_of_builtin
= false;
1186 /* Normally put Z_SUFFIX at the start of KNOWN_SUFFIXES, but if it
1187 is a suffix of one of them, put it at the end. */
1188 for (suf
= known_suffixes
+ 1; *suf
; suf
++)
1190 size_t suflen
= strlen (*suf
);
1191 if (z_len
< suflen
&& strequ (z_suffix
, *suf
+ suflen
- z_len
))
1193 suffix_of_builtin
= true;
1198 char *z_lower
= xstrdup(z_suffix
);
1200 known_suffixes
[suffix_of_builtin
1201 ? sizeof known_suffixes
/ sizeof *known_suffixes
- 2
1203 suf
= known_suffixes
+ suffix_of_builtin
;
1205 nlen
= strlen(name
);
1206 if (nlen
<= MAX_SUFFIX
+2) {
1207 strcpy(suffix
, name
);
1209 strcpy(suffix
, name
+nlen
-MAX_SUFFIX
-2);
1212 slen
= strlen(suffix
);
1215 int s
= strlen(*suf
);
1216 if (slen
> s
&& ! ISSLASH (suffix
[slen
- s
- 1])
1217 && strequ(suffix
+ slen
- s
, *suf
)) {
1218 match
= name
+nlen
-s
;
1221 } while (*++suf
!= NULL
);
1228 /* Open file NAME with the given flags and store its status
1229 into *ST. Return a file descriptor to the newly opened file, or -1
1230 (setting errno) on failure. */
1232 open_and_stat (char *name
, int flags
, struct stat
*st
)
1235 int atfd
= AT_FDCWD
;
1236 char const *base
= name
;
1238 /* Refuse to follow symbolic links unless -c or -f. */
1239 if (!to_stdout
&& !force
)
1241 if (HAVE_WORKING_O_NOFOLLOW
)
1242 flags
|= O_NOFOLLOW
;
1246 if (lstat (name
, st
) != 0)
1248 else if (S_ISLNK (st
->st_mode
))
1259 char const *b
= last_component (name
);
1260 int f
= atdir_set (name
, b
- name
);
1268 fd
= openat (atfd
, base
, flags
);
1269 if (0 <= fd
&& fstat (fd
, st
) != 0)
1280 /* ========================================================================
1281 * Set ifname to the input file name (with a suffix appended if necessary)
1282 * and istat to its stats. For decompression, if no file exists with the
1283 * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
1284 * For MSDOS, we try only z_suffix and z.
1285 * Return an open file descriptor or -1.
1288 open_input_file (iname
, sbuf
)
1292 int ilen
; /* strlen(ifname) */
1293 int z_suffix_errno
= 0;
1294 static char const *suffixes
[] = {NULL
, ".gz", ".z", "-z", ".Z", NULL
};
1295 char const **suf
= suffixes
;
1297 #ifdef NO_MULTIPLE_DOTS
1298 char *dot
; /* pointer to ifname extension, or NULL */
1301 int open_flags
= (O_RDONLY
| O_NONBLOCK
| O_NOCTTY
1302 | (ascii
&& !decompress
? 0 : O_BINARY
));
1306 if (sizeof ifname
- 1 <= strlen (iname
))
1309 strcpy(ifname
, iname
);
1311 /* If input file exists, return OK. */
1312 fd
= open_and_stat (ifname
, open_flags
, sbuf
);
1316 if (!decompress
|| errno
!= ENOENT
) {
1320 /* File.ext doesn't exist. Try adding a suffix. */
1321 s
= get_suffix(ifname
);
1323 progerror(ifname
); /* ifname already has z suffix and does not exist */
1326 #ifdef NO_MULTIPLE_DOTS
1327 dot
= strrchr(ifname
, '.');
1329 strcat(ifname
, ".");
1330 dot
= strrchr(ifname
, '.');
1333 ilen
= strlen(ifname
);
1334 if (strequ(z_suffix
, ".gz")) suf
++;
1336 /* Search for all suffixes */
1338 char const *s0
= s
= *suf
;
1339 strcpy (ifname
, iname
);
1340 #ifdef NO_MULTIPLE_DOTS
1342 if (*dot
== '\0') strcpy (dot
, ".");
1344 #ifdef MAX_EXT_CHARS
1345 if (MAX_EXT_CHARS
< strlen (s
) + strlen (dot
+ 1))
1346 dot
[MAX_EXT_CHARS
+ 1 - strlen (s
)] = '\0';
1348 if (sizeof ifname
<= ilen
+ strlen (s
))
1351 fd
= open_and_stat (ifname
, open_flags
, sbuf
);
1354 if (errno
!= ENOENT
)
1359 if (strequ (s0
, z_suffix
))
1360 z_suffix_errno
= errno
;
1361 } while (*++suf
!= NULL
);
1363 /* No suffix found, complain using z_suffix: */
1364 strcpy(ifname
, iname
);
1365 #ifdef NO_MULTIPLE_DOTS
1366 if (*dot
== '\0') strcpy(dot
, ".");
1368 #ifdef MAX_EXT_CHARS
1369 if (MAX_EXT_CHARS
< z_len
+ strlen (dot
+ 1))
1370 dot
[MAX_EXT_CHARS
+ 1 - z_len
] = '\0';
1372 strcat(ifname
, z_suffix
);
1373 errno
= z_suffix_errno
;
1378 fprintf (stderr
, "%s: %s: file name too long\n", program_name
, iname
);
1383 /* ========================================================================
1384 * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
1385 * Sets save_orig_name to true if the file name has been truncated.
1387 local
int make_ofname()
1389 char *suff
; /* ofname z suffix */
1391 strcpy(ofname
, ifname
);
1392 /* strip a version number if any and get the gzip suffix if present: */
1393 suff
= get_suffix(ofname
);
1397 /* With -t or -l, try all files (even without .gz suffix)
1398 * except with -r (behave as with just -dr).
1400 if (!recursive
&& test
)
1403 /* Avoid annoying messages with -r */
1404 if (verbose
|| (!recursive
&& !quiet
)) {
1405 WARN((stderr
,"%s: %s: unknown suffix -- ignored\n",
1406 program_name
, ifname
));
1410 /* Make a special case for .tgz and .taz: */
1412 if (strequ(suff
, ".tgz") || strequ(suff
, ".taz")) {
1413 strcpy(suff
, ".tar");
1415 *suff
= '\0'; /* strip the z suffix */
1417 /* ofname might be changed later if infile contains an original name */
1419 } else if (suff
&& ! force
) {
1420 /* Avoid annoying messages with -r (see treat_dir()) */
1421 if (verbose
|| (!recursive
&& !quiet
)) {
1422 /* Don't use WARN, as it affects exit status. */
1423 fprintf (stderr
, "%s: %s already has %s suffix -- unchanged\n",
1424 program_name
, ifname
, suff
);
1430 #ifdef NO_MULTIPLE_DOTS
1431 suff
= strrchr(ofname
, '.');
1433 if (sizeof ofname
<= strlen (ofname
) + 1)
1435 strcat(ofname
, ".");
1436 # ifdef MAX_EXT_CHARS
1437 if (strequ(z_suffix
, "z")) {
1438 if (sizeof ofname
<= strlen (ofname
) + 2)
1440 strcat(ofname
, "gz"); /* enough room */
1443 /* On the Atari and some versions of MSDOS,
1444 * ENAMETOOLONG does not work correctly. So we
1445 * must truncate here.
1447 } else if (strlen(suff
)-1 + z_len
> MAX_SUFFIX
) {
1448 suff
[MAX_SUFFIX
+1-z_len
] = '\0';
1452 #endif /* NO_MULTIPLE_DOTS */
1453 if (sizeof ofname
<= strlen (ofname
) + z_len
)
1455 strcat(ofname
, z_suffix
);
1457 } /* decompress ? */
1461 WARN ((stderr
, "%s: %s: file name too long\n", program_name
, ifname
));
1465 /* Discard NBYTES input bytes from the input, or up through the next
1466 zero byte if NBYTES == (size_t) -1. If FLAGS say that the header
1467 CRC should be computed, update the CRC accordingly. */
1469 discard_input_bytes (nbytes
, flags
)
1475 uch c
= get_byte ();
1476 if (flags
& HEADER_CRC
)
1478 if (nbytes
!= (size_t) -1)
1485 /* ========================================================================
1486 * Check the magic number of the input file and update ofname if an
1487 * original name was given and to_stdout is not set.
1488 * Return the compression method, -1 for error, -2 for warning.
1489 * Set inptr to the offset of the next byte to be processed.
1490 * Updates time_stamp if there is one and neither -m nor -n is used.
1491 * This function may be called repeatedly for an input file consisting
1492 * of several contiguous gzip'ed members.
1493 * IN assertions: there is at least one remaining compressed member.
1494 * If the member is a zip file, it must be the only one.
1496 local
int get_method(in
)
1497 int in
; /* input file descriptor */
1499 uch flags
; /* compression flags */
1500 uch magic
[10]; /* magic header */
1501 int imagic0
; /* first magic byte or EOF */
1502 int imagic1
; /* like magic[1], but can represent EOF */
1503 ulg stamp
; /* timestamp */
1505 /* If --force and --stdout, zcat == cat, so do not complain about
1506 * premature end of file: use try_byte instead of get_byte.
1508 if (force
&& to_stdout
) {
1509 imagic0
= try_byte();
1511 imagic1
= try_byte ();
1513 /* If try_byte returned EOF, magic[1] == (char) EOF. */
1515 magic
[0] = get_byte ();
1518 magic
[1] = get_byte ();
1519 imagic1
= 0; /* avoid lint warning */
1521 imagic1
= try_byte ();
1525 method
= -1; /* unknown yet */
1526 part_nb
++; /* number of parts in gzip file */
1529 /* assume multiple members in gzip file except for record oriented I/O */
1531 if (memcmp(magic
, GZIP_MAGIC
, 2) == 0
1532 || memcmp(magic
, OLD_GZIP_MAGIC
, 2) == 0) {
1534 method
= (int)get_byte();
1535 if (method
!= DEFLATED
) {
1537 "%s: %s: unknown method %d -- not supported\n",
1538 program_name
, ifname
, method
);
1543 flags
= (uch
)get_byte();
1545 if ((flags
& ENCRYPTED
) != 0) {
1547 "%s: %s is encrypted -- not supported\n",
1548 program_name
, ifname
);
1552 if ((flags
& RESERVED
) != 0) {
1554 "%s: %s has flags 0x%x -- not supported\n",
1555 program_name
, ifname
, flags
);
1557 if (force
<= 1) return -1;
1559 stamp
= (ulg
)get_byte();
1560 stamp
|= ((ulg
)get_byte()) << 8;
1561 stamp
|= ((ulg
)get_byte()) << 16;
1562 stamp
|= ((ulg
)get_byte()) << 24;
1563 if (stamp
!= 0 && !no_time
)
1565 if (stamp
<= TYPE_MAXIMUM (time_t))
1567 time_stamp
.tv_sec
= stamp
;
1568 time_stamp
.tv_nsec
= 0;
1573 "%s: %s: MTIME %lu out of range for this platform\n",
1574 program_name
, ifname
, stamp
));
1575 time_stamp
.tv_sec
= TYPE_MAXIMUM (time_t);
1576 time_stamp
.tv_nsec
= TIMESPEC_RESOLUTION
- 1;
1580 magic
[8] = get_byte (); /* Ignore extra flags. */
1581 magic
[9] = get_byte (); /* Ignore OS type. */
1583 if (flags
& HEADER_CRC
)
1585 magic
[2] = DEFLATED
;
1587 magic
[4] = stamp
& 0xff;
1588 magic
[5] = (stamp
>> 8) & 0xff;
1589 magic
[6] = (stamp
>> 16) & 0xff;
1590 magic
[7] = stamp
>> 24;
1595 if ((flags
& EXTRA_FIELD
) != 0) {
1597 unsigned int len
= lenbuf
[0] = get_byte ();
1598 len
|= (lenbuf
[1] = get_byte ()) << 8;
1600 fprintf(stderr
,"%s: %s: extra field of %u bytes ignored\n",
1601 program_name
, ifname
, len
);
1603 if (flags
& HEADER_CRC
)
1605 discard_input_bytes (len
, flags
);
1608 /* Get original file name if it was truncated */
1609 if ((flags
& ORIG_NAME
) != 0) {
1610 if (no_name
|| (to_stdout
&& !list
) || part_nb
> 1) {
1611 /* Discard the old name */
1612 discard_input_bytes (-1, flags
);
1614 /* Copy the base name. Keep a directory prefix intact. */
1615 char *p
= gzip_base_name (ofname
);
1618 *p
= (char) get_byte ();
1619 if (*p
++ == '\0') break;
1620 if (p
>= ofname
+sizeof(ofname
)) {
1621 gzip_error ("corrupted input -- file name too large");
1624 if (flags
& HEADER_CRC
)
1625 updcrc ((uch
*) base
, p
- base
);
1626 p
= gzip_base_name (base
);
1627 memmove (base
, p
, strlen (p
) + 1);
1628 /* If necessary, adapt the name to local OS conventions: */
1630 MAKE_LEGAL_NAME(base
);
1631 if (base
) list
=0; /* avoid warning about unused variable */
1633 } /* no_name || to_stdout */
1636 /* Discard file comment if any */
1637 if ((flags
& COMMENT
) != 0) {
1638 discard_input_bytes (-1, flags
);
1641 if (flags
& HEADER_CRC
)
1643 unsigned int crc16
= updcrc (magic
, 0) & 0xffff;
1644 unsigned int header16
= get_byte ();
1645 header16
|= ((unsigned int) get_byte ()) << 8;
1646 if (header16
!= crc16
)
1649 "%s: %s: header checksum 0x%04x != computed checksum 0x%04x\n",
1650 program_name
, ifname
, header16
, crc16
);
1658 header_bytes
= inptr
+ 2*4; /* include crc and size */
1661 } else if (memcmp(magic
, PKZIP_MAGIC
, 2) == 0 && inptr
== 2
1662 && memcmp((char*)inbuf
, PKZIP_MAGIC
, 4) == 0) {
1663 /* To simplify the code, we support a zip file when alone only.
1664 * We are thus guaranteed that the entire local header fits in inbuf.
1668 if (check_zipfile(in
) != OK
) return -1;
1669 /* check_zipfile may get ofname from the local header */
1672 } else if (memcmp(magic
, PACK_MAGIC
, 2) == 0) {
1676 } else if (memcmp(magic
, LZW_MAGIC
, 2) == 0) {
1678 method
= COMPRESSED
;
1681 } else if (memcmp(magic
, LZH_MAGIC
, 2) == 0) {
1686 } else if (force
&& to_stdout
&& !list
) { /* pass input unchanged */
1692 if (imagic0
!= EOF
) {
1693 write_buf (STDOUT_FILENO
, magic
, 1);
1696 if (method
>= 0) return method
;
1699 fprintf (stderr
, "\n%s: %s: not in gzip format\n",
1700 program_name
, ifname
);
1707 for (inbyte
= imagic1
; inbyte
== 0; inbyte
= try_byte ())
1712 WARN ((stderr
, "\n%s: %s: decompression OK, trailing zero bytes ignored\n",
1713 program_name
, ifname
));
1718 WARN((stderr
, "\n%s: %s: decompression OK, trailing garbage ignored\n",
1719 program_name
, ifname
));
1724 /* ========================================================================
1725 * Display the characteristics of the compressed file.
1726 * If the given method is < 0, display the accumulated totals.
1727 * IN assertions: time_stamp, header_bytes and ifile_size are initialized.
1730 do_list (int method
)
1732 ulg crc
; /* original crc */
1733 static int first_time
= 1;
1734 static char const *const methods
[MAX_METHODS
] = {
1739 "", "", "", "", /* 4 to 7 reserved */
1741 int positive_off_t_width
= INT_STRLEN_BOUND (off_t
) - 1;
1743 if (first_time
&& method
>= 0) {
1746 printf("method crc date time ");
1749 printf("%*.*s %*.*s ratio uncompressed_name\n",
1750 positive_off_t_width
, positive_off_t_width
, "compressed",
1751 positive_off_t_width
, positive_off_t_width
, "uncompressed");
1753 } else if (method
< 0) {
1754 if (total_in
<= 0 || total_out
<= 0) return;
1758 if (verbose
|| !quiet
) {
1759 fprint_off(stdout
, total_in
, positive_off_t_width
);
1761 fprint_off(stdout
, total_out
, positive_off_t_width
);
1764 display_ratio(total_out
-(total_in
-header_bytes
), total_out
, stdout
);
1765 /* header_bytes is not meaningful but used to ensure the same
1766 * ratio if there is a single file.
1768 printf(" (totals)\n");
1771 crc
= (ulg
)~0; /* unknown */
1773 if (method
== DEFLATED
&& !last_member
) {
1779 static char const month_abbr
[][4]
1780 = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1781 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
1782 struct tm
*tm
= localtime (&time_stamp
.tv_sec
);
1783 printf ("%5s %08lx ", methods
[method
], crc
);
1785 printf ("%s%3d %02d:%02d ", month_abbr
[tm
->tm_mon
],
1786 tm
->tm_mday
, tm
->tm_hour
, tm
->tm_min
);
1788 printf ("??? ?? ??:?? ");
1790 fprint_off(stdout
, bytes_in
, positive_off_t_width
);
1792 fprint_off(stdout
, bytes_out
, positive_off_t_width
);
1794 if (bytes_in
== -1L) {
1796 bytes_in
= bytes_out
= header_bytes
= 0;
1797 } else if (total_in
>= 0) {
1798 total_in
+= bytes_in
;
1800 if (bytes_out
== -1L) {
1802 bytes_in
= bytes_out
= header_bytes
= 0;
1803 } else if (total_out
>= 0) {
1804 total_out
+= bytes_out
;
1806 display_ratio(bytes_out
-(bytes_in
-header_bytes
), bytes_out
, stdout
);
1807 printf(" %s\n", ofname
);
1810 /* ========================================================================
1811 * Shorten the given name by one character, or replace a .tar extension
1812 * with .tgz. Truncate the last part of the name which is longer than
1813 * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
1814 * has only parts shorter than MIN_PART truncate the longest part.
1815 * For decompression, just remove the last character of the name.
1817 * IN assertion: for compression, the suffix of the given name is z_suffix.
1819 local
void shorten_name(name
)
1822 int len
; /* length of name without z_suffix */
1823 char *trunc
= NULL
; /* character to be truncated */
1824 int plen
; /* current part length */
1825 int min_part
= MIN_PART
; /* current minimum part length */
1831 gzip_error ("name too short");
1835 p
= get_suffix(name
);
1837 gzip_error ("can't recover suffix\n");
1841 /* compress 1234567890.tar to 1234567890.tgz */
1842 if (len
> 4 && strequ(p
-4, ".tar")) {
1843 strcpy(p
-4, ".tgz");
1846 /* Try keeping short extensions intact:
1847 * 1234.678.012.gz -> 123.678.012.gz
1850 p
= last_component (name
);
1852 plen
= strcspn(p
, PART_SEP
);
1854 if (plen
> min_part
) trunc
= p
-1;
1857 } while (trunc
== NULL
&& --min_part
!= 0);
1859 if (trunc
!= NULL
) {
1861 trunc
[0] = trunc
[1];
1865 trunc
= strrchr(name
, PART_SEP
[0]);
1867 gzip_error ("internal error in shorten_name");
1868 if (trunc
[1] == '\0') trunc
--; /* force truncation */
1870 strcpy(trunc
, z_suffix
);
1873 /* ========================================================================
1874 * The compressed file already exists, so ask for confirmation.
1875 * Return ERROR if the file must be skipped.
1877 local
int check_ofname()
1879 /* Ask permission to overwrite the existing file */
1882 fprintf (stderr
, "%s: %s already exists;", program_name
, ofname
);
1883 if (foreground
&& (presume_input_tty
|| isatty (STDIN_FILENO
))) {
1884 fprintf(stderr
, " do you wish to overwrite (y or n)? ");
1889 fprintf(stderr
, "\tnot overwritten\n");
1890 if (exit_code
== OK
) exit_code
= WARNING
;
1894 if (xunlink (ofname
)) {
1901 /* Change the owner and group of a file. FD is a file descriptor for
1902 the file and NAME its name. Change it to user UID and to group GID.
1903 If UID or GID is -1, though, do not change the corresponding user
1905 #if ! (HAVE_FCHOWN || HAVE_CHOWN)
1906 /* The types uid_t and gid_t do not exist on mingw, so don't assume them. */
1907 # define do_chown(fd, name, uid, gid) ((void) 0)
1910 do_chown (int fd
, char const *name
, uid_t uid
, gid_t gid
)
1913 ignore_value (fchown (fd
, uid
, gid
));
1915 ignore_value (chown (name
, uid
, gid
));
1920 /* ========================================================================
1921 * Copy modes, times, ownership from input file to output file.
1922 * IN assertion: to_stdout is false.
1924 local
void copy_stat(ifstat
)
1925 struct stat
*ifstat
;
1927 mode_t mode
= ifstat
->st_mode
& S_IRWXUGO
;
1932 struct timespec timespec
[2];
1933 timespec
[0] = get_stat_atime (ifstat
);
1934 timespec
[1] = get_stat_mtime (ifstat
);
1935 restoring
= (decompress
&& 0 <= time_stamp
.tv_nsec
1936 && ! (timespec
[1].tv_sec
== time_stamp
.tv_sec
1937 && timespec
[1].tv_nsec
== time_stamp
.tv_nsec
));
1939 timespec
[1] = time_stamp
;
1941 if (fdutimens (ofd
, ofname
, timespec
) == 0)
1943 if (restoring
&& 1 < verbose
) {
1944 fprintf(stderr
, "%s: timestamp restored\n", ofname
);
1950 WARN ((stderr
, "%s: ", program_name
));
1959 /* Change the group first, then the permissions, then the owner.
1960 That way, the permissions will be correct on systems that allow
1961 users to give away files, without introducing a security hole.
1962 Security depends on permissions not containing the setuid or
1965 do_chown (ofd
, ofname
, -1, ifstat
->st_gid
);
1968 r
= fchmod (ofd
, mode
);
1970 r
= chmod (ofname
, mode
);
1974 WARN ((stderr
, "%s: ", program_name
));
1981 do_chown (ofd
, ofname
, ifstat
->st_uid
, -1);
1986 /* ========================================================================
1987 * Recurse through the given directory.
1989 local
void treat_dir (fd
, dir
)
1994 char nbuf
[MAX_PATH_LEN
];
1999 dirp
= fdopendir (fd
);
2007 entries
= streamsavedir (dirp
, SAVEDIR_SORT_NONE
);
2010 if (closedir (dirp
) != 0)
2015 for (entry
= entries
; *entry
; entry
+= entrylen
+ 1) {
2016 size_t len
= strlen (dir
);
2017 entrylen
= strlen (entry
);
2018 if (strequ (entry
, ".") || strequ (entry
, ".."))
2020 if (len
+ entrylen
< MAX_PATH_LEN
- 2) {
2022 if (*last_component (nbuf
) && !ISSLASH (nbuf
[len
- 1]))
2024 strcpy (nbuf
+ len
, entry
);
2027 fprintf(stderr
,"%s: %s/%s: pathname too long\n",
2028 program_name
, dir
, entry
);
2034 #endif /* ! NO_DIR */
2036 /* Make sure signals get handled properly. */
2039 install_signal_handlers ()
2041 int nsigs
= sizeof handled_sig
/ sizeof handled_sig
[0];
2043 struct sigaction act
;
2045 sigemptyset (&caught_signals
);
2046 for (i
= 0; i
< nsigs
; i
++)
2048 sigaction (handled_sig
[i
], NULL
, &act
);
2049 if (act
.sa_handler
!= SIG_IGN
)
2050 sigaddset (&caught_signals
, handled_sig
[i
]);
2053 act
.sa_handler
= abort_gzip_signal
;
2054 act
.sa_mask
= caught_signals
;
2057 for (i
= 0; i
< nsigs
; i
++)
2058 if (sigismember (&caught_signals
, handled_sig
[i
]))
2062 sigaction (handled_sig
[i
], &act
, NULL
);
2066 /* ========================================================================
2067 * Free all dynamically allocated variables and exit with the given code.
2069 local
void do_exit(exitcode
)
2072 static int in_exit
= 0;
2074 if (in_exit
) exit(exitcode
);
2094 if (fclose (stdout
) != 0)
2099 /* ========================================================================
2100 * Close and unlink the output file.
2103 remove_output_file (bool signals_already_blocked
)
2108 if (!signals_already_blocked
)
2109 sigprocmask (SIG_BLOCK
, &caught_signals
, &oldset
);
2110 fd
= remove_ofname_fd
;
2113 char fname
[MAX_PATH_LEN
];
2114 remove_ofname_fd
= -1;
2116 volatile_strcpy (fname
, remove_ofname
);
2119 if (!signals_already_blocked
)
2120 sigprocmask (SIG_SETMASK
, &oldset
, NULL
);
2123 /* ========================================================================
2129 remove_output_file (false);
2133 /* ========================================================================
2137 abort_gzip_signal (int sig
)
2139 remove_output_file (true);
2140 if (sig
== exiting_signal
)
2142 signal (sig
, SIG_DFL
);