1 /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
3 Copyright (C) 1999, 2001-2002, 2006-2007, 2009-2024 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) 2024 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>
76 #include "ignore-value.h"
77 #include "stat-time.h"
102 # define MAX_PATH_LEN 1024 /* max pathname length */
110 off_t
lseek (int fd
, off_t offset
, int whence
);
113 #ifndef HAVE_WORKING_O_NOFOLLOW
114 # define HAVE_WORKING_O_NOFOLLOW 0
117 /* Separator for file name parts (see shorten_name()) */
118 #ifdef NO_MULTIPLE_DOTS
119 # define PART_SEP "-"
121 # define PART_SEP "."
126 /* With IBM_Z_DFLTCC, DEFLATE COMPRESSION works faster with
127 page-aligned input and output buffers, and requires page-aligned
128 windows; the alignment requirement is 4096. On other platforms
129 alignment doesn't hurt, and alignment up to 4096 is portable so
131 #if defined HAVE_C_ALIGNASOF || defined alignas
132 # define BUFFER_ALIGNED alignas (4096)
134 # define BUFFER_ALIGNED /**/
136 DECLARE(uch BUFFER_ALIGNED
, inbuf
, INBUFSIZ
+INBUF_EXTRA
);
137 DECLARE(uch BUFFER_ALIGNED
, outbuf
, OUTBUFSIZ
+OUTBUF_EXTRA
);
138 DECLARE(ush
, d_buf
, DIST_BUFSIZE
);
139 DECLARE(uch BUFFER_ALIGNED
, window
, 2L*WSIZE
);
141 DECLARE(ush
, tab_prefix
, 1L<<BITS
);
143 DECLARE(ush
, tab_prefix0
, 1L<<(BITS
-1));
144 DECLARE(ush
, tab_prefix1
, 1L<<(BITS
-1));
147 /* local variables */
149 /* If true, pretend that standard input is a tty. This option
150 is deliberately not documented, and only for testing. */
151 static bool presume_input_tty
;
153 /* If true, transfer output data to the output file's storage device
154 when supported. Otherwise, if the system crashes around the time
155 gzip is run, the user might lose both input and output data. See:
156 Pillai TS et al. All file systems are not created equal: on the
157 complexity of crafting crash-consistent applications. OSDI'14. 2014:433-48.
158 https://www.usenix.org/conference/osdi14/technical-sessions/presentation/pillai */
159 static bool synchronous
;
161 static int ascii
= 0; /* convert end-of-lines to local OS conventions */
162 int to_stdout
= 0; /* output to stdout (-c) */
163 static int decompress
= 0; /* decompress (-d) */
164 static int force
= 0; /* don't ask questions, compress links (-f) */
165 static int keep
= 0; /* keep (don't delete) input files */
166 static int no_name
= -1; /* don't save or restore the original file name */
167 static int no_time
= -1; /* don't save or restore the original file time */
168 static int recursive
= 0; /* recurse through directories (-r) */
169 static int list
= 0; /* list the file contents (-l) */
173 int verbose
= 0; /* be verbose (-v) */
174 int quiet
= 0; /* be very quiet (-q) */
175 int test
= 0; /* test .gz file integrity */
176 static int foreground
= 0; /* set if program run in foreground */
177 char *program_name
; /* program name */
178 int maxbits
= BITS
; /* max bits per code for LZW */
179 int method
= DEFLATED
;/* compression method */
180 int level
= 6; /* compression level */
181 int exit_code
= OK
; /* program exit code */
182 int save_orig_name
; /* set if original name must be saved */
183 static int last_member
; /* set for .zip and .Z files */
184 static int part_nb
; /* number of parts in .gz file */
185 off_t ifile_size
; /* input file size, -1 for devices (debug only) */
186 static char *env
; /* contents of GZIP env variable */
187 static char const *z_suffix
; /* default suffix (can be set with --suffix) */
188 static size_t z_len
; /* strlen(z_suffix) */
190 /* The original timestamp (modification time). If the original is
191 unknown, TIME_STAMP.tv_nsec is negative. If the original is
192 greater than struct timespec range, TIME_STAMP is the maximal
193 struct timespec value; this can happen on hosts with 32-bit signed
194 time_t because the gzip format's MTIME is 32-bit unsigned.
195 The original cannot be less than struct timespec range. */
196 struct timespec time_stamp
;
198 /* The set of signals that are caught. */
199 static sigset_t caught_signals
;
201 /* If nonnegative, close this file descriptor and unlink remove_ofname
203 static int volatile remove_ofname_fd
= -1;
204 static char volatile remove_ofname
[MAX_PATH_LEN
];
206 static bool stdin_was_read
;
208 off_t bytes_in
; /* number of input bytes */
209 off_t bytes_out
; /* number of output bytes */
210 static off_t total_in
; /* input bytes for all files */
211 static off_t total_out
; /* output bytes for all files */
212 char ifname
[MAX_PATH_LEN
]; /* input file name */
213 char ofname
[MAX_PATH_LEN
]; /* output file name */
214 static char dfname
[MAX_PATH_LEN
]; /* name of dir containing output file */
215 static struct stat istat
; /* status for input file */
216 int ifd
; /* input file descriptor */
217 int ofd
; /* output file descriptor */
218 static int dfd
= -1; /* output directory file descriptor */
219 unsigned insize
; /* valid bytes in inbuf */
220 unsigned inptr
; /* index of next byte to be processed in inbuf */
221 unsigned outcnt
; /* bytes in output buffer */
222 int rsync
= 0; /* make rsyncable chunks */
224 static int handled_sig
[] =
226 /* SIGINT must be first, as 'foreground' depends on it. */
246 /* For long options that have no equivalent short option, use a
247 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
250 PRESUME_INPUT_TTY_OPTION
= CHAR_MAX
+ 1,
254 /* A value greater than all valid long options, used as a flag to
255 distinguish options derived from the GZIP environment variable. */
259 static char const shortopts
[] = "ab:cdfhH?klLmMnNqrS:tvVZ123456789";
261 static const struct option longopts
[] =
263 /* { name has_arg *flag val } */
264 {"ascii", 0, 0, 'a'}, /* ascii text mode */
265 {"to-stdout", 0, 0, 'c'}, /* write output on standard output */
266 {"stdout", 0, 0, 'c'}, /* write output on standard output */
267 {"decompress", 0, 0, 'd'}, /* decompress */
268 {"uncompress", 0, 0, 'd'}, /* decompress */
269 /* {"encrypt", 0, 0, 'e'}, encrypt */
270 {"force", 0, 0, 'f'}, /* force overwrite of output file */
271 {"help", 0, 0, 'h'}, /* give help */
272 /* {"pkzip", 0, 0, 'k'}, force output in pkzip format */
273 {"keep", 0, 0, 'k'}, /* keep (don't delete) input files */
274 {"list", 0, 0, 'l'}, /* list .gz file contents */
275 {"license", 0, 0, 'L'}, /* display software license */
276 {"no-name", 0, 0, 'n'}, /* don't save or restore original name & time */
277 {"name", 0, 0, 'N'}, /* save or restore original name & time */
278 {"-presume-input-tty", no_argument
, NULL
, PRESUME_INPUT_TTY_OPTION
},
279 {"quiet", 0, 0, 'q'}, /* quiet mode */
280 {"silent", 0, 0, 'q'}, /* quiet mode */
281 {"synchronous",0, 0, SYNCHRONOUS_OPTION
},
282 {"recursive", 0, 0, 'r'}, /* recurse through directories */
283 {"suffix", 1, 0, 'S'}, /* use given suffix instead of .gz */
284 {"test", 0, 0, 't'}, /* test compressed file integrity */
285 {"verbose", 0, 0, 'v'}, /* verbose mode */
286 {"version", 0, 0, 'V'}, /* display version number */
287 {"fast", 0, 0, '1'}, /* compress faster */
288 {"best", 0, 0, '9'}, /* compress better */
289 {"lzw", 0, 0, 'Z'}, /* make output compatible with old compress */
290 {"bits", 1, 0, 'b'}, /* max number of bits per code (implies -Z) */
291 {"rsyncable", 0, 0, RSYNCABLE_OPTION
}, /* make rsync-friendly archive */
295 /* local functions */
297 _Noreturn
static void try_help (void);
298 static void help (void);
299 static void license (void);
300 static void version (void);
301 static int input_eof (void);
302 static void treat_stdin (void);
303 static void treat_file (char *iname
);
304 static int create_outfile (void);
305 static char *get_suffix (char *name
);
306 static int open_input_file (char *iname
, struct stat
*sbuf
);
307 static void discard_input_bytes (size_t nbytes
, unsigned int flags
);
308 static int make_ofname (void);
309 static void shorten_name (char *name
);
310 static int get_method (int in
);
311 static void do_list (int method
);
312 static int check_ofname (void);
313 static void copy_stat (struct stat
*ifstat
);
314 static void install_signal_handlers (void);
315 static void remove_output_file (bool);
316 static void abort_gzip_signal (int);
317 _Noreturn
static void do_exit (int exitcode
);
318 static void finish_out (void);
319 int main (int argc
, char **argv
);
320 static int (*work
) (int infile
, int outfile
) = zip
; /* function to call */
323 static void treat_dir (int fd
, char *dir
);
326 #define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
331 fprintf (stderr
, "Try `%s --help' for more information.\n",
336 /* ======================================================================== */
340 static char const* const help_msg
[] = {
341 "Compress or uncompress FILEs (by default, compress FILES in-place).",
343 "Mandatory arguments to long options are mandatory for short options too.",
346 " -a, --ascii ascii text; convert end-of-line using local conventions",
348 " -c, --stdout write on standard output, keep original files unchanged",
349 " -d, --decompress decompress",
350 /* -e, --encrypt encrypt */
351 " -f, --force force overwrite of output file and compress links",
352 " -h, --help give this help",
353 /* -k, --pkzip force output in pkzip format */
354 " -k, --keep keep (don't delete) input files",
355 " -l, --list list compressed file contents",
356 " -L, --license display software license",
358 " -m do not save or restore the original modification time",
359 " -M, --time save or restore the original modification time",
361 " -n, --no-name do not save or restore the original name and timestamp",
362 " -N, --name save or restore the original name and timestamp",
363 " -q, --quiet suppress all warnings",
365 " -r, --recursive operate recursively on directories",
367 " --rsyncable make rsync-friendly archive",
368 " -S, --suffix=SUF use suffix SUF on compressed files",
369 " --synchronous synchronous output (safer if system crashes, but slower)",
370 " -t, --test test compressed file integrity",
371 " -v, --verbose verbose mode",
372 " -V, --version display version number",
373 " -1, --fast compress faster",
374 " -9, --best compress better",
376 "With no FILE, or when FILE is -, read standard input.",
378 "Report bugs to <bug-gzip@gnu.org>.",
380 char const *const *p
= help_msg
;
382 printf ("Usage: %s [OPTION]... [FILE]...\n", program_name
);
383 while (*p
) printf ("%s\n", *p
++);
386 /* ======================================================================== */
390 char const *const *p
= license_msg
;
392 printf ("%s %s\n", program_name
, Version
);
393 while (*p
) printf ("%s\n", *p
++);
396 /* ======================================================================== */
402 printf ("Written by Jean-loup Gailly.\n");
406 progerror (char const *string
)
408 fprintf (stderr
, "%s: %s: %s\n", program_name
, string
, strerror (errno
));
412 /* ======================================================================== */
413 int main (int argc
, char **argv
)
415 int file_count
; /* number of files to process */
416 size_t proglen
; /* length of program_name */
421 EXPAND(argc
, argv
); /* wild card expansion if necessary */
423 program_name
= gzip_base_name (argv
[0]);
424 proglen
= strlen (program_name
);
426 /* Suppress .exe for MSDOS and OS/2: */
427 if (4 < proglen
&& strequ (program_name
+ proglen
- 4, ".exe"))
428 program_name
[proglen
- 4] = '\0';
430 /* Add options in GZIP environment variable if there is one */
432 env
= add_envopt (&env_argc
, &argv_copy
, OPTIONS_VAR
);
433 env_argv
= env
? argv_copy
: NULL
;
436 # define GNU_STANDARD 1
439 /* For compatibility with old compress, use program name as an option.
440 * Unless you compile with -DGNU_STANDARD=0, this program will behave as
441 * gzip even if it is invoked under the name gunzip or zcat.
443 * Systems which do not support links can still use -d or -dc.
444 * Ignore an .exe extension for MSDOS and OS/2.
446 if (strncmp (program_name
, "un", 2) == 0 /* ungzip, uncompress */
447 || strncmp (program_name
, "gun", 3) == 0) /* gunzip */
449 else if (strequ (program_name
+ 1, "cat") /* zcat, pcat, gcat */
450 || strequ (program_name
, "gzcat")) /* gzcat */
451 decompress
= to_stdout
= 1;
455 z_len
= strlen(z_suffix
);
463 if (env_argv
[optind
] && strequ (env_argv
[optind
], "--"))
464 optc
= ENV_OPTION
+ '-';
467 optc
= getopt_long (env_argc
, env_argv
, shortopts
, longopts
,
473 if (optind
!= env_argc
)
476 ("%s: %s: non-option in "OPTIONS_VAR
477 " environment variable\n"),
478 program_name
, env_argv
[optind
]);
482 /* Wait until here before warning, so that GZIP='-q'
484 if (env_argc
!= 1 && !quiet
)
486 ("%s: warning: "OPTIONS_VAR
" environment variable"
487 " is deprecated; use an alias or script\n"),
490 /* Start processing ARGC and ARGV instead. */
500 optc
= getopt_long (argc
, argv
, shortopts
, longopts
, &longind
);
508 maxbits
= atoi(optarg
);
509 for (; *optarg
; optarg
++)
510 if (! ('0' <= *optarg
&& *optarg
<= '9'))
512 fprintf (stderr
, "%s: -b operand is not an integer\n",
518 to_stdout
= 1; break;
520 decompress
= 1; break;
524 help (); finish_out (); break;
528 list
= decompress
= test
= to_stdout
= 1; break;
530 license (); finish_out (); break;
531 case 'm': /* undocumented, may change later */
533 case 'M': /* undocumented, may change later */
536 case 'n' + ENV_OPTION
:
537 no_name
= no_time
= 1; break;
539 case 'N' + ENV_OPTION
:
540 no_name
= no_time
= 0; break;
541 case PRESUME_INPUT_TTY_OPTION
:
542 presume_input_tty
= true; break;
544 case 'q' + ENV_OPTION
:
545 quiet
= 1; verbose
= 0; break;
548 fprintf (stderr
, "%s: -r not supported on this system\n",
556 case RSYNCABLE_OPTION
:
557 case RSYNCABLE_OPTION
+ ENV_OPTION
:
561 #ifdef NO_MULTIPLE_DOTS
562 if (*optarg
== '.') optarg
++;
564 for (z_len
= 0; optarg
[z_len
]; z_len
++)
565 if (optarg
[z_len
] == '/')
567 fprintf (stderr
, "%s: suffix contains '/'\n", program_name
);
572 case SYNCHRONOUS_OPTION
:
576 test
= decompress
= to_stdout
= 1;
579 case 'v' + ENV_OPTION
:
580 verbose
++; quiet
= 0; break;
582 version (); finish_out (); break;
584 fprintf(stderr
, "%s: -Z not supported in this version\n",
588 case '1' + ENV_OPTION
: case '2' + ENV_OPTION
: case '3' + ENV_OPTION
:
589 case '4' + ENV_OPTION
: case '5' + ENV_OPTION
: case '6' + ENV_OPTION
:
590 case '7' + ENV_OPTION
: case '8' + ENV_OPTION
: case '9' + ENV_OPTION
:
593 case '1': case '2': case '3': case '4':
594 case '5': case '6': case '7': case '8': case '9':
599 if (ENV_OPTION
<= optc
&& optc
!= ENV_OPTION
+ '?')
601 /* Output a diagnostic, since getopt_long didn't. */
602 fprintf (stderr
, "%s: ", program_name
);
604 fprintf (stderr
, "-%c: ", optc
- ENV_OPTION
);
606 fprintf (stderr
, "--%s: ", longopts
[longind
].name
);
607 fprintf (stderr
, ("option not valid in "OPTIONS_VAR
608 " environment variable\n"));
612 } /* loop on all arguments */
614 /* By default, save name and timestamp on compression but do not
615 * restore them on decompression.
617 if (no_time
< 0) no_time
= decompress
;
618 if (no_name
< 0) no_name
= decompress
;
620 file_count
= argc
- optind
;
624 if (ascii
&& !quiet
) {
625 fprintf(stderr
, "%s: option --ascii ignored on this system\n",
629 if (z_len
== 0 || z_len
> MAX_SUFFIX
) {
630 fprintf(stderr
, "%s: invalid suffix '%s'\n", program_name
, z_suffix
);
634 /* Allocate all global buffers (for DYN_ALLOC option) */
635 ALLOC(uch
, inbuf
, INBUFSIZ
+INBUF_EXTRA
);
636 ALLOC(uch
, outbuf
, OUTBUFSIZ
+OUTBUF_EXTRA
);
637 ALLOC(ush
, d_buf
, DIST_BUFSIZE
);
638 ALLOC(uch
, window
, 2L*WSIZE
);
640 ALLOC(ush
, tab_prefix
, 1L<<BITS
);
642 ALLOC(ush
, tab_prefix0
, 1L<<(BITS
-1));
643 ALLOC(ush
, tab_prefix1
, 1L<<(BITS
-1));
646 /* And get to work */
647 if (file_count
!= 0) {
648 if (to_stdout
&& !test
&& (!decompress
|| !ascii
)) {
649 SET_BINARY_MODE (STDOUT_FILENO
);
651 while (optind
< argc
) {
652 treat_file(argv
[optind
++]);
654 } else { /* Standard input */
657 if (stdin_was_read
&& close (STDIN_FILENO
) != 0)
659 strcpy (ifname
, "stdin");
664 /* Output any totals, and check for output errors. */
665 if (!quiet
&& 1 < file_count
)
667 if (fflush (stdout
) != 0)
672 && fdatasync (STDOUT_FILENO
) != 0 && errno
!= EINVAL
)
673 || close (STDOUT_FILENO
) != 0)
679 /* Return nonzero when at end of file on input. */
683 if (!decompress
|| last_member
)
688 if (insize
!= INBUFSIZ
|| fill_inbuf (1) == EOF
)
691 /* Unget the char that fill_inbuf got. */
699 get_input_size_and_time (void)
702 time_stamp
.tv_nsec
= -1;
704 /* Record the input file's size and timestamp only if it is a
705 regular file. Doing this for the timestamp helps to keep gzip's
706 output more reproducible when it is used as part of a
709 if (S_ISREG (istat
.st_mode
))
711 ifile_size
= istat
.st_size
;
712 if (!no_time
|| list
)
713 time_stamp
= get_stat_mtime (&istat
);
717 /* ========================================================================
718 * Compress or decompress stdin
724 && (presume_input_tty
725 || isatty (decompress
? STDIN_FILENO
: STDOUT_FILENO
))) {
726 /* Do not send compressed data to the terminal or read it from
727 * the terminal. We get here when user invoked the program
728 * without parameters, so be helpful. According to the GNU standards:
730 * If there is one behavior you think is most useful when the output
731 * is to a terminal, and another that you think is most useful when
732 * the output is a file or a pipe, then it is usually best to make
733 * the default behavior the one that is useful with output to a
734 * terminal, and have an option for the other behavior.
736 * Here we use the --force option to get the other behavior.
740 ("%s: compressed data not %s a terminal."
741 " Use -f to force %scompression.\n"
742 "For help, type: %s -h\n"),
744 decompress
? "read from" : "written to",
745 decompress
? "de" : "",
750 if (decompress
|| !ascii
) {
751 SET_BINARY_MODE (STDIN_FILENO
);
753 if (!test
&& (!decompress
|| !ascii
)) {
754 SET_BINARY_MODE (STDOUT_FILENO
);
756 strcpy(ifname
, "stdin");
757 strcpy(ofname
, "stdout");
759 /* Get the file's timestamp and size. */
760 if (fstat (STDIN_FILENO
, &istat
) != 0)
762 progerror ("standard input");
766 get_input_size_and_time ();
768 clear_bufs(); /* clear input and output buffers */
772 stdin_was_read
= true;
775 method
= get_method(ifd
);
777 do_exit(exit_code
); /* error message already emitted */
781 /* Actually do the compression/decompression. Loop over zipped members.
784 if (work (STDIN_FILENO
, STDOUT_FILENO
) != OK
)
790 method
= get_method(ifd
);
791 if (method
< 0) return; /* error message already emitted */
802 fprintf(stderr
, " OK\n");
804 } else if (!decompress
) {
805 display_ratio(bytes_in
-(bytes_out
-header_bytes
), bytes_in
, stderr
);
806 fprintf(stderr
, "\n");
807 #ifdef DISPLAY_STDIN_RATIO
809 display_ratio(bytes_out
-(bytes_in
-header_bytes
), bytes_out
,stderr
);
810 fprintf(stderr
, "\n");
816 static char const dot
= '.';
818 /* True if the cached directory for calls to openat etc. is DIR, with
819 length DIRLEN. DIR need not be null-terminated. DIRLEN must be
820 less than MAX_PATH_LEN. */
822 atdir_eq (char const *dir
, ptrdiff_t dirlen
)
825 dir
= &dot
, dirlen
= 1;
826 return memcmp (dfname
, dir
, dirlen
) == 0 && !dfname
[dirlen
];
829 /* Set the directory used for calls to openat etc. to be the directory
830 DIR, with length DIRLEN. DIR need not be null-terminated.
831 DIRLEN must be less than MAX_PATH_LEN. Return a file descriptor for
832 the directory, or -1 if one could not be obtained. */
834 atdir_set (char const *dir
, ptrdiff_t dirlen
)
836 /* Don't bother opening directories on older systems that
837 lack openat and unlinkat. It's not worth the porting hassle. */
838 #if HAVE_OPENAT && HAVE_UNLINKAT
839 enum { try_opening_directories
= true };
841 enum { try_opening_directories
= false };
844 if (try_opening_directories
&& ! atdir_eq (dir
, dirlen
))
849 dir
= &dot
, dirlen
= 1;
850 memcpy (dfname
, dir
, dirlen
);
851 dfname
[dirlen
] = '\0';
852 dfd
= open (dfname
, O_SEARCH
| O_DIRECTORY
);
858 /* ========================================================================
859 * Compress or decompress the given file
862 treat_file (char *iname
)
864 /* Accept "-" as synonym for stdin */
865 if (strequ(iname
, "-")) {
866 int cflag
= to_stdout
;
872 /* Check if the input file is present, set ifname and istat: */
873 ifd
= open_input_file (iname
, &istat
);
877 /* If the input name is that of a directory, recurse or ignore: */
878 if (S_ISDIR(istat
.st_mode
)) {
881 treat_dir (ifd
, iname
);
882 /* Warning: ifname is now garbage */
887 WARN ((stderr
, "%s: %s is a directory -- ignored\n",
888 program_name
, ifname
));
894 if (! S_ISREG (istat
.st_mode
))
897 "%s: %s is not a directory or a regular file - ignored\n",
898 program_name
, ifname
));
902 if (istat
.st_mode
& S_ISUID
)
904 WARN ((stderr
, "%s: %s is set-user-ID on execution - ignored\n",
905 program_name
, ifname
));
909 if (istat
.st_mode
& S_ISGID
)
911 WARN ((stderr
, "%s: %s is set-group-ID on execution - ignored\n",
912 program_name
, ifname
));
919 if (istat
.st_mode
& S_ISVTX
)
922 "%s: %s has the sticky bit set - file ignored\n",
923 program_name
, ifname
));
927 if (2 <= istat
.st_nlink
)
929 WARN ((stderr
, "%s: %s has %lu other link%s -- file ignored\n",
930 program_name
, ifname
,
931 (unsigned long int) istat
.st_nlink
- 1,
932 istat
.st_nlink
== 2 ? "" : "s"));
939 get_input_size_and_time ();
941 /* Generate output file name. For -r and (-t or -l), skip files
942 * without a valid gzip suffix (check done in make_ofname).
944 if (to_stdout
&& !test
) {
945 strcpy(ofname
, "stdout");
947 } else if (make_ofname() != OK
) {
952 clear_bufs(); /* clear input and output buffers */
956 method
= get_method(ifd
); /* updates ofname if original given */
959 return; /* error message already emitted */
963 /* If compressing to a file, check if ofname is not ambiguous
964 * because the operating system truncates names. Otherwise, generate
965 * a new ofname and save the original name in the compressed file.
969 /* Keep remove_ofname_fd negative. */
971 if (create_outfile() != OK
) return;
973 if (!decompress
&& save_orig_name
&& !verbose
&& !quiet
) {
974 fprintf(stderr
, "%s: %s compressed to %s\n",
975 program_name
, ifname
, ofname
);
978 /* Keep the name even if not truncated except with --no-name: */
979 if (!save_orig_name
) save_orig_name
= !no_name
;
981 if (verbose
&& !list
) {
982 fprintf(stderr
, "%s:\t", ifname
);
985 /* Actually do the compression/decompression. Loop over zipped members.
988 if ((*work
)(ifd
, ofd
) != OK
) {
989 method
= -1; /* force cleanup */
996 method
= get_method(ifd
);
997 if (method
< 0) break; /* error message already emitted */
1000 if (close (ifd
) != 0)
1014 && ((0 <= dfd
&& fdatasync (dfd
) != 0 && errno
!= EINVAL
)
1015 || (fsync (ofd
) != 0 && errno
!= EINVAL
)))
1016 || close (ofd
) != 0)
1023 char *ifbase
= last_component (ifname
);
1024 int ufd
= atdir_eq (ifname
, ifbase
- ifname
) ? dfd
: -1;
1027 sigprocmask (SIG_BLOCK
, &caught_signals
, &oldset
);
1028 remove_ofname_fd
= -1;
1029 res
= ufd
< 0 ? xunlink (ifname
) : unlinkat (ufd
, ifbase
, 0);
1030 unlink_errno
= res
== 0 ? 0 : errno
;
1031 sigprocmask (SIG_SETMASK
, &oldset
, NULL
);
1034 WARN ((stderr
, "%s: %s: %s\n", program_name
, ifname
,
1035 strerror (unlink_errno
)));
1041 remove_output_file (false);
1045 /* Display statistics */
1048 fprintf(stderr
, " OK");
1049 } else if (decompress
) {
1050 display_ratio(bytes_out
-(bytes_in
-header_bytes
), bytes_out
,stderr
);
1052 display_ratio(bytes_in
-(bytes_out
-header_bytes
), bytes_in
, stderr
);
1055 fprintf(stderr
, " -- %s %s", keep
? "created" : "replaced with",
1057 fprintf(stderr
, "\n");
1062 volatile_strcpy (char volatile *dst
, char const volatile *src
)
1064 while ((*dst
++ = *src
++))
1068 /* ========================================================================
1069 * Create the output file. Return OK or ERROR.
1070 * Try several times if necessary to avoid truncating the z_suffix. For
1071 * example, do not create a compressed file of name "1234567890123."
1072 * Sets save_orig_name to true if the file name has been truncated.
1073 * IN assertions: the input file has already been open (ifd is set) and
1074 * ofname has already been updated if there was an original name.
1075 * OUT assertions: ifd and ofd are closed in case of error.
1080 static bool signal_handlers_installed
;
1081 int name_shortened
= 0;
1082 int flags
= (O_WRONLY
| O_CREAT
| O_EXCL
1083 | (ascii
&& decompress
? 0 : O_BINARY
));
1084 char const *base
= ofname
;
1085 int atfd
= AT_FDCWD
;
1089 char const *b
= last_component (ofname
);
1090 int f
= atdir_set (ofname
, b
- ofname
);
1098 if (!signal_handlers_installed
)
1100 signal_handlers_installed
= true;
1101 install_signal_handlers ();
1109 volatile_strcpy (remove_ofname
, ofname
);
1111 sigprocmask (SIG_BLOCK
, &caught_signals
, &oldset
);
1112 remove_ofname_fd
= ofd
= openat (atfd
, base
, flags
, S_IRUSR
| S_IWUSR
);
1114 sigprocmask (SIG_SETMASK
, &oldset
, NULL
);
1123 shorten_name (ofname
);
1129 if (check_ofname () != OK
)
1143 if (name_shortened
&& decompress
)
1145 /* name might be too long if an original name was saved */
1146 WARN ((stderr
, "%s: %s: warning, name truncated\n",
1147 program_name
, ofname
));
1153 /* ========================================================================
1154 * Return a pointer to the 'z' suffix of a file name, or NULL. For all
1155 * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
1156 * accepted suffixes, in addition to the value of the --suffix option.
1157 * ".tgz" is a useful convention for tar.z files on systems limited
1158 * to 3 characters extensions. On such systems, ".?z" and ".??z" are
1159 * also accepted suffixes. For Unix, we do not want to accept any
1160 * .??z suffix as indicating a compressed file; some people use .xyz
1161 * to denote volume data.
1164 get_suffix (char *name
)
1167 char suffix
[MAX_SUFFIX
+3]; /* last chars of name, forced to lower case */
1168 static char const *known_suffixes
[] =
1169 {NULL
, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
1170 #ifdef MAX_EXT_CHARS
1175 bool suffix_of_builtin
= false;
1177 /* Normally put Z_SUFFIX at the start of KNOWN_SUFFIXES, but if it
1178 is a suffix of one of them, put it at the end. */
1179 for (suf
= known_suffixes
+ 1; *suf
; suf
++)
1181 size_t suflen
= strlen (*suf
);
1182 if (z_len
< suflen
&& strequ (z_suffix
, *suf
+ suflen
- z_len
))
1184 suffix_of_builtin
= true;
1189 char *z_lower
= xstrdup(z_suffix
);
1191 known_suffixes
[suffix_of_builtin
1192 ? sizeof known_suffixes
/ sizeof *known_suffixes
- 2
1194 suf
= known_suffixes
+ suffix_of_builtin
;
1196 nlen
= strlen(name
);
1197 if (nlen
<= MAX_SUFFIX
+2) {
1198 strcpy(suffix
, name
);
1200 strcpy(suffix
, name
+nlen
-MAX_SUFFIX
-2);
1203 slen
= strlen(suffix
);
1206 int s
= strlen(*suf
);
1207 if (slen
> s
&& ! ISSLASH (suffix
[slen
- s
- 1])
1208 && strequ(suffix
+ slen
- s
, *suf
)) {
1209 match
= name
+nlen
-s
;
1212 } while (*++suf
!= NULL
);
1219 /* Open file NAME with the given flags and store its status
1220 into *ST. Return a file descriptor to the newly opened file, or -1
1221 (setting errno) on failure. */
1223 open_and_stat (char *name
, int flags
, struct stat
*st
)
1226 int atfd
= AT_FDCWD
;
1227 char const *base
= name
;
1229 /* Refuse to follow symbolic links unless -c or -f. */
1230 if (!to_stdout
&& !force
)
1232 if (HAVE_WORKING_O_NOFOLLOW
)
1233 flags
|= O_NOFOLLOW
;
1237 if (lstat (name
, st
) != 0)
1239 else if (S_ISLNK (st
->st_mode
))
1250 char const *b
= last_component (name
);
1251 int f
= atdir_set (name
, b
- name
);
1259 fd
= openat (atfd
, base
, flags
);
1260 if (0 <= fd
&& fstat (fd
, st
) != 0)
1271 /* ========================================================================
1272 * Set ifname to the input file name (with a suffix appended if necessary)
1273 * and istat to its stats. For decompression, if no file exists with the
1274 * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
1275 * For MSDOS, we try only z_suffix and z.
1276 * Return an open file descriptor or -1.
1279 open_input_file (char *iname
, struct stat
*sbuf
)
1281 int ilen
; /* strlen(ifname) */
1282 int z_suffix_errno
= 0;
1283 static char const *suffixes
[] = {NULL
, ".gz", ".z", "-z", ".Z", NULL
};
1284 char const **suf
= suffixes
;
1286 #ifdef NO_MULTIPLE_DOTS
1287 char *dot
; /* pointer to ifname extension, or NULL */
1290 int open_flags
= (O_RDONLY
| O_NONBLOCK
| O_NOCTTY
1291 | (ascii
&& !decompress
? 0 : O_BINARY
));
1295 if (sizeof ifname
- 1 <= strlen (iname
))
1298 strcpy(ifname
, iname
);
1300 /* If input file exists, return OK. */
1301 fd
= open_and_stat (ifname
, open_flags
, sbuf
);
1305 if (!decompress
|| errno
!= ENOENT
) {
1309 /* File.ext doesn't exist. Try adding a suffix. */
1310 s
= get_suffix(ifname
);
1312 progerror(ifname
); /* ifname already has z suffix and does not exist */
1315 #ifdef NO_MULTIPLE_DOTS
1316 dot
= strrchr(ifname
, '.');
1318 strcat(ifname
, ".");
1319 dot
= strrchr(ifname
, '.');
1322 ilen
= strlen(ifname
);
1323 if (strequ(z_suffix
, ".gz")) suf
++;
1325 /* Search for all suffixes */
1327 char const *s0
= s
= *suf
;
1328 strcpy (ifname
, iname
);
1329 #ifdef NO_MULTIPLE_DOTS
1331 if (*dot
== '\0') strcpy (dot
, ".");
1333 #ifdef MAX_EXT_CHARS
1334 if (MAX_EXT_CHARS
< strlen (s
) + strlen (dot
+ 1))
1335 dot
[MAX_EXT_CHARS
+ 1 - strlen (s
)] = '\0';
1337 if (sizeof ifname
<= ilen
+ strlen (s
))
1340 fd
= open_and_stat (ifname
, open_flags
, sbuf
);
1343 if (errno
!= ENOENT
)
1348 if (strequ (s0
, z_suffix
))
1349 z_suffix_errno
= errno
;
1350 } while (*++suf
!= NULL
);
1352 /* No suffix found, complain using z_suffix: */
1353 strcpy(ifname
, iname
);
1354 #ifdef NO_MULTIPLE_DOTS
1355 if (*dot
== '\0') strcpy(dot
, ".");
1357 #ifdef MAX_EXT_CHARS
1358 if (MAX_EXT_CHARS
< z_len
+ strlen (dot
+ 1))
1359 dot
[MAX_EXT_CHARS
+ 1 - z_len
] = '\0';
1361 strcat(ifname
, z_suffix
);
1362 errno
= z_suffix_errno
;
1367 fprintf (stderr
, "%s: %s: file name too long\n", program_name
, iname
);
1372 /* ========================================================================
1373 * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
1374 * Sets save_orig_name to true if the file name has been truncated.
1379 char *suff
; /* ofname z suffix */
1381 strcpy(ofname
, ifname
);
1382 /* strip a version number if any and get the gzip suffix if present: */
1383 suff
= get_suffix(ofname
);
1387 /* With -t or -l, try all files (even without .gz suffix)
1388 * except with -r (behave as with just -dr).
1390 if (!recursive
&& test
)
1393 /* Avoid annoying messages with -r */
1394 if (verbose
|| (!recursive
&& !quiet
)) {
1395 WARN((stderr
,"%s: %s: unknown suffix -- ignored\n",
1396 program_name
, ifname
));
1400 /* Make a special case for .tgz and .taz: */
1402 if (strequ(suff
, ".tgz") || strequ(suff
, ".taz")) {
1403 strcpy(suff
, ".tar");
1405 *suff
= '\0'; /* strip the z suffix */
1407 /* ofname might be changed later if infile contains an original name */
1409 } else if (suff
&& ! force
) {
1410 /* Avoid annoying messages with -r (see treat_dir()) */
1411 if (verbose
|| (!recursive
&& !quiet
)) {
1412 /* Don't use WARN, as it affects exit status. */
1413 fprintf (stderr
, "%s: %s already has %s suffix -- unchanged\n",
1414 program_name
, ifname
, suff
);
1420 #ifdef NO_MULTIPLE_DOTS
1421 suff
= strrchr(ofname
, '.');
1423 if (sizeof ofname
<= strlen (ofname
) + 1)
1425 strcat(ofname
, ".");
1426 # ifdef MAX_EXT_CHARS
1427 if (strequ(z_suffix
, "z")) {
1428 if (sizeof ofname
<= strlen (ofname
) + 2)
1430 strcat(ofname
, "gz"); /* enough room */
1433 /* On the Atari and some versions of MSDOS,
1434 * ENAMETOOLONG does not work correctly. So we
1435 * must truncate here.
1437 } else if (strlen(suff
)-1 + z_len
> MAX_SUFFIX
) {
1438 suff
[MAX_SUFFIX
+1-z_len
] = '\0';
1442 #endif /* NO_MULTIPLE_DOTS */
1443 if (sizeof ofname
<= strlen (ofname
) + z_len
)
1445 strcat(ofname
, z_suffix
);
1447 } /* decompress ? */
1451 WARN ((stderr
, "%s: %s: file name too long\n", program_name
, ifname
));
1455 /* Discard NBYTES input bytes from the input, or up through the next
1456 zero byte if NBYTES == (size_t) -1. If FLAGS say that the header
1457 CRC should be computed, update the CRC accordingly. */
1459 discard_input_bytes (size_t nbytes
, unsigned int flags
)
1463 uch c
= get_byte ();
1464 if (flags
& HEADER_CRC
)
1466 if (nbytes
!= (size_t) -1)
1473 /* ========================================================================
1474 * Check the magic number of the input file and update ofname if an
1475 * original name was given and to_stdout is not set.
1476 * Return the compression method, -1 for error, -2 for warning.
1477 * Set inptr to the offset of the next byte to be processed.
1478 * Updates time_stamp if there is one and neither -m nor -n is used.
1479 * This function may be called repeatedly for an input file consisting
1480 * of several contiguous gzip'ed members.
1481 * 'in' is the input file descriptor.
1482 * IN assertions: there is at least one remaining compressed member.
1483 * If the member is a zip file, it must be the only one.
1488 uch flags
; /* compression flags */
1489 uch magic
[10]; /* magic header */
1490 int imagic0
; /* first magic byte or EOF */
1491 int imagic1
; /* like magic[1], but can represent EOF */
1492 ulg stamp
; /* timestamp */
1494 /* If --force and --stdout, zcat == cat, so do not complain about
1495 * premature end of file: use try_byte instead of get_byte.
1497 if (force
&& to_stdout
) {
1498 imagic0
= try_byte();
1500 imagic1
= try_byte ();
1502 /* If try_byte returned EOF, magic[1] == (char) EOF. */
1504 magic
[0] = get_byte ();
1507 magic
[1] = get_byte ();
1508 imagic1
= 0; /* avoid lint warning */
1510 imagic1
= try_byte ();
1514 method
= -1; /* unknown yet */
1515 part_nb
++; /* number of parts in gzip file */
1518 /* assume multiple members in gzip file except for record oriented I/O */
1520 if (memcmp(magic
, GZIP_MAGIC
, 2) == 0
1521 || memcmp(magic
, OLD_GZIP_MAGIC
, 2) == 0) {
1523 method
= (int)get_byte();
1524 if (method
!= DEFLATED
) {
1526 "%s: %s: unknown method %d -- not supported\n",
1527 program_name
, ifname
, method
);
1532 flags
= (uch
)get_byte();
1534 if ((flags
& ENCRYPTED
) != 0) {
1536 "%s: %s is encrypted -- not supported\n",
1537 program_name
, ifname
);
1541 if ((flags
& RESERVED
) != 0) {
1543 "%s: %s has flags 0x%x -- not supported\n",
1544 program_name
, ifname
, flags
);
1546 if (force
<= 1) return -1;
1548 stamp
= (ulg
)get_byte();
1549 stamp
|= ((ulg
)get_byte()) << 8;
1550 stamp
|= ((ulg
)get_byte()) << 16;
1551 stamp
|= ((ulg
)get_byte()) << 24;
1552 if (stamp
!= 0 && !no_time
)
1554 if (stamp
<= TYPE_MAXIMUM (time_t))
1556 time_stamp
.tv_sec
= stamp
;
1557 time_stamp
.tv_nsec
= 0;
1562 "%s: %s: MTIME %lu out of range for this platform\n",
1563 program_name
, ifname
, stamp
));
1564 time_stamp
.tv_sec
= TYPE_MAXIMUM (time_t);
1565 time_stamp
.tv_nsec
= TIMESPEC_RESOLUTION
- 1;
1569 magic
[8] = get_byte (); /* Ignore extra flags. */
1570 magic
[9] = get_byte (); /* Ignore OS type. */
1572 if (flags
& HEADER_CRC
)
1574 magic
[2] = DEFLATED
;
1576 magic
[4] = stamp
& 0xff;
1577 magic
[5] = (stamp
>> 8) & 0xff;
1578 magic
[6] = (stamp
>> 16) & 0xff;
1579 magic
[7] = stamp
>> 24;
1584 if ((flags
& EXTRA_FIELD
) != 0) {
1586 unsigned int len
= lenbuf
[0] = get_byte ();
1587 len
|= (lenbuf
[1] = get_byte ()) << 8;
1589 fprintf(stderr
,"%s: %s: extra field of %u bytes ignored\n",
1590 program_name
, ifname
, len
);
1592 if (flags
& HEADER_CRC
)
1594 discard_input_bytes (len
, flags
);
1597 /* Get original file name if it was truncated */
1598 if ((flags
& ORIG_NAME
) != 0) {
1599 if (no_name
|| (to_stdout
&& !list
) || part_nb
> 1) {
1600 /* Discard the old name */
1601 discard_input_bytes (-1, flags
);
1603 /* Copy the base name. Keep a directory prefix intact. */
1604 char *p
= gzip_base_name (ofname
);
1607 *p
= (char) get_byte ();
1608 if (*p
++ == '\0') break;
1609 if (p
>= ofname
+sizeof(ofname
)) {
1610 gzip_error ("corrupted input -- file name too large");
1613 if (flags
& HEADER_CRC
)
1614 updcrc ((uch
*) base
, p
- base
);
1615 p
= gzip_base_name (base
);
1616 memmove (base
, p
, strlen (p
) + 1);
1617 /* If necessary, adapt the name to local OS conventions: */
1619 MAKE_LEGAL_NAME(base
);
1620 if (base
) list
=0; /* avoid warning about unused variable */
1622 } /* no_name || to_stdout */
1625 /* Discard file comment if any */
1626 if ((flags
& COMMENT
) != 0) {
1627 discard_input_bytes (-1, flags
);
1630 if (flags
& HEADER_CRC
)
1632 unsigned int crc16
= updcrc (magic
, 0) & 0xffff;
1633 unsigned int header16
= get_byte ();
1634 header16
|= ((unsigned int) get_byte ()) << 8;
1635 if (header16
!= crc16
)
1638 "%s: %s: header checksum 0x%04x != computed checksum 0x%04x\n",
1639 program_name
, ifname
, header16
, crc16
);
1647 header_bytes
= inptr
+ 2*4; /* include crc and size */
1650 } else if (memcmp(magic
, PKZIP_MAGIC
, 2) == 0 && inptr
== 2
1651 && memcmp((char*)inbuf
, PKZIP_MAGIC
, 4) == 0) {
1652 /* To simplify the code, we support a zip file when alone only.
1653 * We are thus guaranteed that the entire local header fits in inbuf.
1657 if (check_zipfile(in
) != OK
) return -1;
1658 /* check_zipfile may get ofname from the local header */
1661 } else if (memcmp(magic
, PACK_MAGIC
, 2) == 0) {
1665 } else if (memcmp(magic
, LZW_MAGIC
, 2) == 0) {
1667 method
= COMPRESSED
;
1670 } else if (memcmp(magic
, LZH_MAGIC
, 2) == 0) {
1675 } else if (force
&& to_stdout
&& !list
) { /* pass input unchanged */
1681 if (imagic0
!= EOF
) {
1682 write_buf (STDOUT_FILENO
, magic
, 1);
1685 if (method
>= 0) return method
;
1688 fprintf (stderr
, "\n%s: %s: not in gzip format\n",
1689 program_name
, ifname
);
1696 for (inbyte
= imagic1
; inbyte
== 0; inbyte
= try_byte ())
1701 WARN ((stderr
, "\n%s: %s: decompression OK, trailing zero bytes ignored\n",
1702 program_name
, ifname
));
1707 WARN((stderr
, "\n%s: %s: decompression OK, trailing garbage ignored\n",
1708 program_name
, ifname
));
1713 /* ========================================================================
1714 * Display the characteristics of the compressed file.
1715 * If the given method is < 0, display the accumulated totals.
1716 * IN assertions: time_stamp, header_bytes and ifile_size are initialized.
1719 do_list (int method
)
1721 ulg crc
; /* original crc */
1722 static int first_time
= 1;
1723 static char const *const methods
[MAX_METHODS
] = {
1728 "", "", "", "", /* 4 to 7 reserved */
1730 int positive_off_t_width
= INT_STRLEN_BOUND (off_t
) - 1;
1732 if (first_time
&& method
>= 0) {
1735 printf("method crc date time ");
1738 printf("%*.*s %*.*s ratio uncompressed_name\n",
1739 positive_off_t_width
, positive_off_t_width
, "compressed",
1740 positive_off_t_width
, positive_off_t_width
, "uncompressed");
1742 } else if (method
< 0) {
1743 if (total_in
<= 0 || total_out
<= 0) return;
1747 if (verbose
|| !quiet
)
1748 printf ("%*jd %*jd ", positive_off_t_width
, (intmax_t) total_in
,
1749 positive_off_t_width
, (intmax_t) total_out
);
1750 display_ratio(total_out
-(total_in
-header_bytes
), total_out
, stdout
);
1751 /* header_bytes is not meaningful but used to ensure the same
1752 * ratio if there is a single file.
1754 printf(" (totals)\n");
1757 crc
= (ulg
)~0; /* unknown */
1759 if (method
== DEFLATED
&& !last_member
) {
1765 static char const month_abbr
[][4]
1766 = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1767 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
1768 struct tm
*tm
= localtime (&time_stamp
.tv_sec
);
1769 printf ("%5s %08lx ", methods
[method
], crc
);
1771 printf ("%s%3d %02d:%02d ", month_abbr
[tm
->tm_mon
],
1772 tm
->tm_mday
, tm
->tm_hour
, tm
->tm_min
);
1774 printf ("??? ?? ??:?? ");
1776 printf ("%*jd %*jd ", positive_off_t_width
, (intmax_t) bytes_in
,
1777 positive_off_t_width
, (intmax_t) bytes_out
);
1778 if (bytes_in
== -1L) {
1780 bytes_in
= bytes_out
= header_bytes
= 0;
1781 } else if (total_in
>= 0) {
1782 total_in
+= bytes_in
;
1784 if (bytes_out
== -1L) {
1786 bytes_in
= bytes_out
= header_bytes
= 0;
1787 } else if (total_out
>= 0) {
1788 total_out
+= bytes_out
;
1790 display_ratio(bytes_out
-(bytes_in
-header_bytes
), bytes_out
, stdout
);
1791 printf(" %s\n", ofname
);
1794 /* ========================================================================
1795 * Shorten the given name by one character, or replace a .tar extension
1796 * with .tgz. Truncate the last part of the name which is longer than
1797 * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
1798 * has only parts shorter than MIN_PART truncate the longest part.
1799 * For decompression, just remove the last character of the name.
1801 * IN assertion: for compression, the suffix of the given name is z_suffix.
1804 shorten_name (char *name
)
1806 int len
; /* length of name without z_suffix */
1807 char *trunc
= NULL
; /* character to be truncated */
1808 int plen
; /* current part length */
1809 int min_part
= MIN_PART
; /* current minimum part length */
1815 gzip_error ("name too short");
1819 p
= get_suffix(name
);
1821 gzip_error ("can't recover suffix\n");
1825 /* compress 1234567890.tar to 1234567890.tgz */
1826 if (len
> 4 && strequ(p
-4, ".tar")) {
1827 strcpy(p
-4, ".tgz");
1830 /* Try keeping short extensions intact:
1831 * 1234.678.012.gz -> 123.678.012.gz
1834 p
= last_component (name
);
1836 plen
= strcspn(p
, PART_SEP
);
1838 if (plen
> min_part
) trunc
= p
-1;
1841 } while (trunc
== NULL
&& --min_part
!= 0);
1843 if (trunc
!= NULL
) {
1845 trunc
[0] = trunc
[1];
1849 trunc
= strrchr(name
, PART_SEP
[0]);
1851 gzip_error ("internal error in shorten_name");
1852 if (trunc
[1] == '\0') trunc
--; /* force truncation */
1854 strcpy(trunc
, z_suffix
);
1857 /* ========================================================================
1858 * The compressed file already exists, so ask for confirmation.
1859 * Return ERROR if the file must be skipped.
1864 /* Ask permission to overwrite the existing file */
1867 fprintf (stderr
, "%s: %s already exists;", program_name
, ofname
);
1868 if (foreground
&& (presume_input_tty
|| isatty (STDIN_FILENO
))) {
1869 fprintf(stderr
, " do you wish to overwrite (y or n)? ");
1874 fprintf(stderr
, "\tnot overwritten\n");
1875 if (exit_code
== OK
) exit_code
= WARNING
;
1879 if (xunlink (ofname
)) {
1886 /* Change the owner and group of a file. FD is a file descriptor for
1887 the file and NAME its name. Change it to user UID and to group GID.
1888 If UID or GID is -1, though, do not change the corresponding user
1890 #if ! (HAVE_FCHOWN || HAVE_CHOWN)
1891 /* The types uid_t and gid_t do not exist on mingw, so don't assume them. */
1892 # define do_chown(fd, name, uid, gid) ((void) 0)
1895 do_chown (int fd
, char const *name
, uid_t uid
, gid_t gid
)
1898 ignore_value (fchown (fd
, uid
, gid
));
1900 ignore_value (chown (name
, uid
, gid
));
1905 /* ========================================================================
1906 * Copy modes, times, ownership from input file to output file.
1907 * IN assertion: to_stdout is false.
1910 copy_stat (struct stat
*ifstat
)
1912 mode_t mode
= ifstat
->st_mode
& S_IRWXUGO
;
1917 struct timespec timespec
[2];
1918 timespec
[0] = get_stat_atime (ifstat
);
1919 timespec
[1] = get_stat_mtime (ifstat
);
1920 restoring
= (decompress
&& 0 <= time_stamp
.tv_nsec
1921 && ! (timespec
[1].tv_sec
== time_stamp
.tv_sec
1922 && timespec
[1].tv_nsec
== time_stamp
.tv_nsec
));
1924 timespec
[1] = time_stamp
;
1926 if (fdutimens (ofd
, ofname
, timespec
) == 0)
1928 if (restoring
&& 1 < verbose
) {
1929 fprintf(stderr
, "%s: timestamp restored\n", ofname
);
1933 WARN ((stderr
, "%s: %s: %s\n", program_name
, ofname
, strerror (errno
)));
1936 /* Change the group first, then the permissions, then the owner.
1937 That way, the permissions will be correct on systems that allow
1938 users to give away files, without introducing a security hole.
1939 Security depends on permissions not containing the setuid or
1942 do_chown (ofd
, ofname
, -1, ifstat
->st_gid
);
1945 r
= fchmod (ofd
, mode
);
1947 r
= chmod (ofname
, mode
);
1950 WARN ((stderr
, "%s: %s: %s\n", program_name
, ofname
, strerror (errno
)));
1952 do_chown (ofd
, ofname
, ifstat
->st_uid
, -1);
1957 /* ========================================================================
1958 * Recurse through the given directory.
1961 treat_dir (int fd
, char *dir
)
1964 char nbuf
[MAX_PATH_LEN
];
1969 dirp
= fdopendir (fd
);
1977 entries
= streamsavedir (dirp
, SAVEDIR_SORT_NONE
);
1980 if (closedir (dirp
) != 0)
1985 for (entry
= entries
; *entry
; entry
+= entrylen
+ 1) {
1986 size_t len
= strlen (dir
);
1987 entrylen
= strlen (entry
);
1988 if (strequ (entry
, ".") || strequ (entry
, ".."))
1990 if (len
+ entrylen
< MAX_PATH_LEN
- 2) {
1992 if (*last_component (nbuf
) && !ISSLASH (nbuf
[len
- 1]))
1994 strcpy (nbuf
+ len
, entry
);
1997 fprintf(stderr
,"%s: %s/%s: pathname too long\n",
1998 program_name
, dir
, entry
);
2004 #endif /* ! NO_DIR */
2006 /* Make sure signals get handled properly. */
2009 install_signal_handlers ()
2011 int nsigs
= sizeof handled_sig
/ sizeof handled_sig
[0];
2013 struct sigaction act
;
2015 sigemptyset (&caught_signals
);
2016 for (i
= 0; i
< nsigs
; i
++)
2018 sigaction (handled_sig
[i
], NULL
, &act
);
2019 if (act
.sa_handler
!= SIG_IGN
)
2020 sigaddset (&caught_signals
, handled_sig
[i
]);
2023 act
.sa_handler
= abort_gzip_signal
;
2024 act
.sa_mask
= caught_signals
;
2027 for (i
= 0; i
< nsigs
; i
++)
2028 if (sigismember (&caught_signals
, handled_sig
[i
]))
2032 sigaction (handled_sig
[i
], &act
, NULL
);
2036 /* ========================================================================
2037 * Free all dynamically allocated variables and exit with the given code.
2040 do_exit (int exitcode
)
2042 static int in_exit
= 0;
2044 if (in_exit
) exit(exitcode
);
2064 if (fclose (stdout
) != 0)
2069 /* ========================================================================
2070 * Close and unlink the output file.
2073 remove_output_file (bool signals_already_blocked
)
2078 if (!signals_already_blocked
)
2079 sigprocmask (SIG_BLOCK
, &caught_signals
, &oldset
);
2080 fd
= remove_ofname_fd
;
2083 char fname
[MAX_PATH_LEN
];
2084 remove_ofname_fd
= -1;
2086 volatile_strcpy (fname
, remove_ofname
);
2089 if (!signals_already_blocked
)
2090 sigprocmask (SIG_SETMASK
, &oldset
, NULL
);
2093 /* ========================================================================
2097 finish_up_gzip (int exitcode
)
2099 if (0 <= remove_ofname_fd
)
2100 remove_output_file (false);
2106 finish_up_gzip (ERROR
);
2108 /* ========================================================================
2112 abort_gzip_signal (int sig
)
2114 remove_output_file (true);
2115 signal (sig
, SIG_DFL
);