1 /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
2 * Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
3 * Copyright (C) 1992-1993 Jean-loup Gailly
4 * The unzip code was written and put in the public domain by Mark Adler.
5 * Portions of the lzw code are derived from the public domain 'compress'
6 * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
7 * Ken Turkowski, Dave Mack and Peter Jannesen.
9 * See the license_msg below and the file COPYING for the software license.
10 * See the file algorithm.doc for the compression algorithms and file formats.
13 static char *license_msg[] = {
14 "Copyright 2002 Free Software Foundation",
15 "Copyright 1992-1993 Jean-loup Gailly",
16 "This program comes with ABSOLUTELY NO WARRANTY.",
17 "You may redistribute copies of this program",
18 "under the terms of the GNU General Public License.",
19 "For more information about these matters, see the file named COPYING.",
22 /* Compress files with zip algorithm and 'compress' interface.
23 * See usage() and help() functions below for all options.
25 * file.gz: compressed file with same mode, owner, and utimes
26 * or stdout with -c option or if stdin used as input.
27 * If the output file name had to be truncated, the original name is kept
28 * in the compressed file.
29 * On MSDOS, file.tmp -> file.tmz. On VMS, file.tmp -> file.tmp-gz.
31 * Using gz on MSDOS would create too many file name conflicts. For
32 * example, foo.txt -> foo.tgz (.tgz must be reserved as shorthand for
33 * tar.gz). Similarly, foo.dir and foo.doc would both be mapped to foo.dgz.
34 * I also considered 12345678.txt -> 12345txt.gz but this truncates the name
35 * too heavily. There is no ideal solution given the MSDOS 8+3 limitation.
37 * For the meaning of all compilation flags, see comments in Makefile.in.
41 static char rcsid[] = "$Id: gzip.c,v 0.24 1993/06/24 10:52:07 jloup Exp $";
46 #include <sys/types.h>
62 # include <sys/time.h>
77 #if defined STDC_HEADERS || defined HAVE_STDLIB_H
85 # define NAMLEN(direct) strlen((direct)->d_name)
86 # define DIR_OPT "DIRENT"
88 # define dirent direct
89 # define NAMLEN(direct) ((direct)->d_namlen)
90 # ifdef HAVE_SYS_NDIR_H
91 # include <sys/ndir.h>
92 # define DIR_OPT "SYS_NDIR"
94 # ifdef HAVE_SYS_DIR_H
96 # define DIR_OPT "SYS_DIR"
100 # define DIR_OPT "NDIR"
103 # define DIR_OPT "NO_DIR"
111 # define CLOSEDIR(d) (closedir(d), 0)
113 # define CLOSEDIR(d) closedir(d)
116 #if !defined(HAVE_LSTAT) && !defined(lstat)
117 # define lstat(name, buf) stat(name, buf)
123 # define TIME_OPT "UTIME"
125 # ifdef HAVE_SYS_UTIME_H
126 # include <sys/utime.h>
127 # define TIME_OPT "SYS_UTIME"
133 # define TIME_OPT "STRUCT_UTIMBUF"
137 # define TIME_OPT "NO_UTIME"
140 #if !defined(S_ISDIR) && defined(S_IFDIR)
141 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
143 #if !defined(S_ISREG) && defined(S_IFREG)
144 # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
147 typedef RETSIGTYPE (*sig_type) OF((int));
150 # define O_BINARY 0 /* creation mode for open() */
154 /* Pure BSD system? */
155 # include <sys/file.h>
157 # define O_CREAT FCREAT
160 # define O_EXCL FEXCL
165 # define S_IRUSR 0400
168 # define S_IWUSR 0200
170 #define RW_USER (S_IRUSR | S_IWUSR) /* creation mode for open() */
173 # define MAX_PATH_LEN 1024 /* max pathname length */
185 off_t lseek OF((int fd, off_t offset, int whence));
189 #define OFF_T_MIN (~ (off_t) 0 << (sizeof (off_t) * CHAR_BIT - 1))
193 #define OFF_T_MAX (~ (off_t) 0 - OFF_T_MIN)
196 /* Separator for file name parts (see shorten_name()) */
197 #ifdef NO_MULTIPLE_DOTS
198 # define PART_SEP "-"
200 # define PART_SEP "."
205 DECLARE(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
206 DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
207 DECLARE(ush, d_buf, DIST_BUFSIZE);
208 DECLARE(uch, window, 2L*WSIZE);
210 DECLARE(ush, tab_prefix, 1L<<BITS);
212 DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
213 DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
216 /* local variables */
218 int ascii = 0; /* convert end-of-lines to local OS conventions */
219 int to_stdout = 0; /* output to stdout (-c) */
220 int decompress = 0; /* decompress (-d) */
221 int force = 0; /* don't ask questions, compress links (-f) */
222 int no_name = -1; /* don't save or restore the original file name */
223 int no_time = -1; /* don't save or restore the original file time */
224 int recursive = 0; /* recurse through directories (-r) */
225 int list = 0; /* list the file contents (-l) */
226 int verbose = 0; /* be verbose (-v) */
227 int quiet = 0; /* be very quiet (-q) */
228 int do_lzw = 0; /* generate output compatible with old compress (-Z) */
229 int test = 0; /* test .gz file integrity */
230 int foreground; /* set if program run in foreground */
231 char *progname; /* program name */
232 int maxbits = BITS; /* max bits per code for LZW */
233 int method = DEFLATED;/* compression method */
234 int level = 6; /* compression level */
235 int exit_code = OK; /* program exit code */
236 int save_orig_name; /* set if original name must be saved */
237 int last_member; /* set for .zip and .Z files */
238 int part_nb; /* number of parts in .gz file */
239 time_t time_stamp; /* original time stamp (modification time) */
240 off_t ifile_size; /* input file size, -1 for devices (debug only) */
241 char *env; /* contents of GZIP env variable */
242 char **args = NULL; /* argv pointer if GZIP env variable defined */
243 char *z_suffix; /* default suffix (can be set with --suffix) */
244 size_t z_len; /* strlen(z_suffix) */
246 off_t bytes_in; /* number of input bytes */
247 off_t bytes_out; /* number of output bytes */
248 off_t total_in; /* input bytes for all files */
249 off_t total_out; /* output bytes for all files */
250 char ifname[MAX_PATH_LEN]; /* input file name */
251 char ofname[MAX_PATH_LEN]; /* output file name */
252 int remove_ofname = 0; /* remove output file on error */
253 struct stat istat; /* status for input file */
254 int ifd; /* input file descriptor */
255 int ofd; /* output file descriptor */
256 unsigned insize; /* valid bytes in inbuf */
257 unsigned inptr; /* index of next byte to be processed in inbuf */
258 unsigned outcnt; /* bytes in output buffer */
259 int rsync = 0; /* make ryncable chunks */
261 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 {"list", 0, 0, 'l'}, /* list .gz file contents */
274 {"license", 0, 0, 'L'}, /* display software license */
275 {"no-name", 0, 0, 'n'}, /* don't save or restore original name & time */
276 {"name", 0, 0, 'N'}, /* save or restore original name & time */
277 {"quiet", 0, 0, 'q'}, /* quiet mode */
278 {"silent", 0, 0, 'q'}, /* quiet mode */
279 {"recursive", 0, 0, 'r'}, /* recurse through directories */
280 {"suffix", 1, 0, 'S'}, /* use given suffix instead of .gz */
281 {"test", 0, 0, 't'}, /* test compressed file integrity */
282 {"no-time", 0, 0, 'T'}, /* don't save or restore the time stamp */
283 {"verbose", 0, 0, 'v'}, /* verbose mode */
284 {"version", 0, 0, 'V'}, /* display version number */
285 {"fast", 0, 0, '1'}, /* compress faster */
286 {"best", 0, 0, '9'}, /* compress better */
287 {"lzw", 0, 0, 'Z'}, /* make output compatible with old compress */
288 {"bits", 1, 0, 'b'}, /* max number of bits per code (implies -Z) */
289 {"rsyncable", 0, 0, 'R'}, /* make rsync-friendly archive */
293 /* local functions */
295 local void usage OF((void));
296 local void help OF((void));
297 local void license OF((void));
298 local void version OF((void));
299 local int input_eof OF((void));
300 local void treat_stdin OF((void));
301 local void treat_file OF((char *iname));
302 local int create_outfile OF((void));
303 local int do_stat OF((char *name, struct stat *sbuf));
304 local char *get_suffix OF((char *name));
305 local int get_istat OF((char *iname, struct stat *sbuf));
306 local int make_ofname OF((void));
307 local int same_file OF((struct stat *stat1, struct stat *stat2));
308 local int name_too_long OF((char *name, struct stat *statb));
309 local void shorten_name OF((char *name));
310 local int get_method OF((int in));
311 local void do_list OF((int ifd, int method));
312 local int check_ofname OF((void));
313 local void copy_stat OF((struct stat *ifstat));
314 local void do_exit OF((int exitcode));
315 int main OF((int argc, char **argv));
316 int (*work) OF((int infile, int outfile)) = zip; /* function to call */
319 local void treat_dir OF((char *dir));
322 local void reset_times OF((char *name, struct stat *statb));
325 #define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
327 /* ======================================================================== */
330 printf ("usage: %s [-%scdfhlLnN%stvV19] [-S suffix] [file ...]\n",
332 O_BINARY ? "a" : "", NO_DIR ? "" : "r");
335 /* ======================================================================== */
338 static char *help_msg[] = {
340 " -a --ascii ascii text; convert end-of-lines using local conventions",
342 " -c --stdout write on standard output, keep original files unchanged",
343 " -d --decompress decompress",
344 /* -e --encrypt encrypt */
345 " -f --force force overwrite of output file and compress links",
346 " -h --help give this help",
347 /* -k --pkzip force output in pkzip format */
348 " -l --list list compressed file contents",
349 " -L --license display software license",
351 " -m --no-time do not save or restore the original modification time",
352 " -M --time save or restore the original modification time",
354 " -n --no-name do not save or restore the original name and time stamp",
355 " -N --name save or restore the original name and time stamp",
356 " -q --quiet suppress all warnings",
358 " -r --recursive operate recursively on directories",
360 " -S .suf --suffix .suf use suffix .suf on compressed files",
361 " -t --test test compressed file integrity",
362 " -v --verbose verbose mode",
363 " -V --version display version number",
364 " -1 --fast compress faster",
365 " -9 --best compress better",
367 " -Z --lzw produce output compatible with old compress",
368 " -b --bits maxbits max number of bits per code (implies -Z)",
370 " --rsyncable Make rsync-friendly archive",
371 " file... files to (de)compress. If none given, use standard input.",
372 "Report bugs to <bug-gzip@gnu.org>.",
376 printf ("%s %s\n(%s)\n", progname, VERSION, REVDATE);
378 while (*p) printf ("%s\n", *p++);
381 /* ======================================================================== */
384 char **p = license_msg;
386 printf ("%s %s\n(%s)\n", progname, VERSION, REVDATE);
387 while (*p) printf ("%s\n", *p++);
390 /* ======================================================================== */
394 printf ("Compilation options:\n%s %s ", DIR_OPT, TIME_OPT);
396 printf ("STDC_HEADERS ");
399 printf ("HAVE_UNISTD_H ");
402 printf ("HAVE_MEMORY_H ");
405 printf ("HAVE_STRING_H ");
408 printf ("HAVE_LSTAT ");
410 #ifdef NO_MULTIPLE_DOTS
411 printf ("NO_MULTIPLE_DOTS ");
414 printf ("HAVE_CHOWN ");
426 printf ("DYN_ALLOC ");
429 printf ("MAXSEG_64K");
432 printf ("Written by Jean-loup Gailly.\n");
435 local void progerror (string)
439 fprintf(stderr, "%s: ", progname);
445 /* ======================================================================== */
446 int main (argc, argv)
450 int file_count; /* number of files to precess */
451 int proglen; /* length of progname */
452 int optc; /* current option */
454 EXPAND(argc, argv); /* wild card expansion if necessary */
456 progname = base_name (argv[0]);
457 proglen = strlen(progname);
459 /* Suppress .exe for MSDOS, OS/2 and VMS: */
460 if (proglen > 4 && strequ(progname+proglen-4, ".exe")) {
461 progname[proglen-4] = '\0';
464 /* Add options in GZIP environment variable if there is one */
465 env = add_envopt(&argc, &argv, OPTIONS_VAR);
466 if (env != NULL) args = argv;
468 foreground = signal(SIGINT, SIG_IGN) != SIG_IGN;
470 (void) signal (SIGINT, (sig_type)abort_gzip_signal);
473 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
474 (void) signal(SIGTERM, (sig_type)abort_gzip_signal);
478 if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
479 (void) signal(SIGHUP, (sig_type)abort_gzip_signal);
484 /* For compatibility with old compress, use program name as an option.
485 * If you compile with -DGNU_STANDARD, this program will behave as
486 * gzip even if it is invoked under the name gunzip or zcat.
488 * Systems which do not support links can still use -d or -dc.
489 * Ignore an .exe extension for MSDOS, OS/2 and VMS.
491 if ( strncmp(progname, "un", 2) == 0 /* ungzip, uncompress */
492 || strncmp(progname, "gun", 3) == 0) { /* gunzip */
494 } else if (strequ(progname+1, "cat") /* zcat, pcat, gcat */
495 || strequ(progname, "gzcat")) { /* gzcat */
496 decompress = to_stdout = 1;
501 z_len = strlen(z_suffix);
503 while ((optc = getopt_long (argc, argv, "ab:cdfhH?lLmMnNqrS:tvVZ123456789",
504 longopts, (int *)0)) != -1) {
509 maxbits = atoi(optarg);
510 for (; *optarg; optarg++)
511 if (! ('0' <= *optarg && *optarg <= '9'))
513 fprintf (stderr, "%s: -b operand is not an integer\n",
520 to_stdout = 1; break;
522 decompress = 1; break;
525 case 'h': case 'H': case '?':
526 help(); do_exit(OK); break;
528 list = decompress = to_stdout = 1; break;
530 license(); do_exit(OK); break;
531 case 'm': /* undocumented, may change later */
533 case 'M': /* undocumented, may change later */
536 no_name = no_time = 1; break;
538 no_name = no_time = 0; break;
540 quiet = 1; verbose = 0; break;
543 fprintf(stderr, "%s: -r not supported on this system\n", progname);
545 do_exit(ERROR); break;
547 recursive = 1; break;
553 #ifdef NO_MULTIPLE_DOTS
554 if (*optarg == '.') optarg++;
556 z_len = strlen(optarg);
560 test = decompress = to_stdout = 1;
563 verbose++; quiet = 0; break;
565 version(); do_exit(OK); break;
570 fprintf(stderr, "%s: -Z not supported in this version\n",
573 do_exit(ERROR); break;
575 case '1': case '2': case '3': case '4':
576 case '5': case '6': case '7': case '8': case '9':
580 /* Error message already emitted by getopt_long. */
584 } /* loop on all arguments */
587 /* Ignore "Broken Pipe" message with --quiet */
588 if (quiet && signal (SIGPIPE, SIG_IGN) != SIG_IGN)
589 signal (SIGPIPE, (sig_type) abort_gzip_signal);
592 /* By default, save name and timestamp on compression but do not
593 * restore them on decompression.
595 if (no_time < 0) no_time = decompress;
596 if (no_name < 0) no_name = decompress;
598 file_count = argc - optind;
602 if (ascii && !quiet) {
603 fprintf(stderr, "%s: option --ascii ignored on this system\n",
607 if ((z_len == 0 && !decompress) || z_len > MAX_SUFFIX) {
608 fprintf(stderr, "%s: incorrect suffix '%s'\n",
612 if (do_lzw && !decompress) work = lzw;
614 /* Allocate all global buffers (for DYN_ALLOC option) */
615 ALLOC(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
616 ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
617 ALLOC(ush, d_buf, DIST_BUFSIZE);
618 ALLOC(uch, window, 2L*WSIZE);
620 ALLOC(ush, tab_prefix, 1L<<BITS);
622 ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
623 ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
626 /* And get to work */
627 if (file_count != 0) {
628 if (to_stdout && !test && !list && (!decompress || !ascii)) {
629 SET_BINARY_MODE(fileno(stdout));
631 while (optind < argc) {
632 treat_file(argv[optind++]);
634 } else { /* Standard input */
637 if (list && !quiet && file_count > 1) {
638 do_list(-1, -1); /* print totals */
641 return exit_code; /* just to avoid lint warning */
644 /* Return nonzero when at end of file on input. */
648 if (!decompress || last_member)
653 if (insize != INBUFSIZ || fill_inbuf (1) == EOF)
656 /* Unget the char that fill_inbuf got. */
663 /* ========================================================================
664 * Compress or decompress stdin
666 local void treat_stdin()
668 if (!force && !list &&
669 isatty(fileno((FILE *)(decompress ? stdin : stdout)))) {
670 /* Do not send compressed data to the terminal or read it from
671 * the terminal. We get here when user invoked the program
672 * without parameters, so be helpful. According to the GNU standards:
674 * If there is one behavior you think is most useful when the output
675 * is to a terminal, and another that you think is most useful when
676 * the output is a file or a pipe, then it is usually best to make
677 * the default behavior the one that is useful with output to a
678 * terminal, and have an option for the other behavior.
680 * Here we use the --force option to get the other behavior.
683 "%s: compressed data not %s a terminal. Use -f to force %scompression.\n",
684 progname, decompress ? "read from" : "written to",
685 decompress ? "de" : "");
686 fprintf(stderr,"For help, type: %s -h\n", progname);
690 if (decompress || !ascii) {
691 SET_BINARY_MODE(fileno(stdin));
693 if (!test && !list && (!decompress || !ascii)) {
694 SET_BINARY_MODE(fileno(stdout));
696 strcpy(ifname, "stdin");
697 strcpy(ofname, "stdout");
699 /* Get the time stamp on the input file. */
700 time_stamp = 0; /* time unknown by default */
702 #ifndef NO_STDIN_FSTAT
703 if (list || !no_time) {
704 if (fstat(fileno(stdin), &istat) != 0) {
705 progerror("standard input");
708 # ifdef NO_PIPE_TIMESTAMP
709 if (S_ISREG(istat.st_mode))
711 time_stamp = istat.st_mtime;
712 #endif /* NO_STDIN_FSTAT */
714 ifile_size = -1L; /* convention for unknown size */
716 clear_bufs(); /* clear input and output buffers */
721 method = get_method(ifd);
723 do_exit(exit_code); /* error message already emitted */
727 do_list(ifd, method);
731 /* Actually do the compression/decompression. Loop over zipped members.
734 if ((*work)(fileno(stdin), fileno(stdout)) != OK) return;
739 method = get_method(ifd);
740 if (method < 0) return; /* error message already emitted */
741 bytes_out = 0; /* required for length check */
746 fprintf(stderr, " OK\n");
748 } else if (!decompress) {
749 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
750 fprintf(stderr, "\n");
751 #ifdef DISPLAY_STDIN_RATIO
753 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
754 fprintf(stderr, "\n");
760 /* ========================================================================
761 * Compress or decompress the given file
763 local void treat_file(iname)
766 /* Accept "-" as synonym for stdin */
767 if (strequ(iname, "-")) {
768 int cflag = to_stdout;
774 /* Check if the input file is present, set ifname and istat: */
775 if (get_istat(iname, &istat) != OK) return;
777 /* If the input name is that of a directory, recurse or ignore: */
778 if (S_ISDIR(istat.st_mode)) {
784 /* Warning: ifname is now garbage */
786 reset_times (iname, &st);
790 WARN((stderr,"%s: %s is a directory -- ignored\n", progname, ifname));
793 if (!S_ISREG(istat.st_mode)) {
795 "%s: %s is not a directory or a regular file - ignored\n",
799 if (istat.st_nlink > 1 && !to_stdout && !force) {
800 WARN((stderr, "%s: %s has %lu other link%c -- unchanged\n",
801 progname, ifname, (unsigned long) istat.st_nlink - 1,
802 istat.st_nlink > 2 ? 's' : ' '));
806 ifile_size = istat.st_size;
807 time_stamp = no_time && !list ? 0 : istat.st_mtime;
809 /* Generate output file name. For -r and (-t or -l), skip files
810 * without a valid gzip suffix (check done in make_ofname).
812 if (to_stdout && !list && !test) {
813 strcpy(ofname, "stdout");
815 } else if (make_ofname() != OK) {
819 /* Open the input file and determine compression method. The mode
820 * parameter is ignored but required by some systems (VMS) and forbidden
821 * on other systems (MacOS).
823 ifd = OPEN(ifname, ascii && !decompress ? O_RDONLY : O_RDONLY | O_BINARY,
829 clear_bufs(); /* clear input and output buffers */
833 method = get_method(ifd); /* updates ofname if original given */
836 return; /* error message already emitted */
840 do_list(ifd, method);
845 /* If compressing to a file, check if ofname is not ambiguous
846 * because the operating system truncates names. Otherwise, generate
847 * a new ofname and save the original name in the compressed file.
850 ofd = fileno(stdout);
851 /* keep remove_ofname as zero */
853 if (create_outfile() != OK) return;
855 if (!decompress && save_orig_name && !verbose && !quiet) {
856 fprintf(stderr, "%s: %s compressed to %s\n",
857 progname, ifname, ofname);
860 /* Keep the name even if not truncated except with --no-name: */
861 if (!save_orig_name) save_orig_name = !no_name;
864 fprintf(stderr, "%s:\t", ifname);
867 /* Actually do the compression/decompression. Loop over zipped members.
870 if ((*work)(ifd, ofd) != OK) {
871 method = -1; /* force cleanup */
878 method = get_method(ifd);
879 if (method < 0) break; /* error message already emitted */
880 bytes_out = 0; /* required for length check */
885 /* Copy modes, times, and ownership */
891 /* It's now safe to remove the input file: */
892 if (xunlink (ifname)) {
894 WARN((stderr, "%s: ", progname));
902 if (!to_stdout) xunlink (ofname);
905 /* Display statistics */
908 fprintf(stderr, " OK");
909 } else if (decompress) {
910 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
912 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
914 if (!test && !to_stdout) {
915 fprintf(stderr, " -- replaced with %s", ofname);
917 fprintf(stderr, "\n");
921 /* ========================================================================
922 * Create the output file. Return OK or ERROR.
923 * Try several times if necessary to avoid truncating the z_suffix. For
924 * example, do not create a compressed file of name "1234567890123."
925 * Sets save_orig_name to true if the file name has been truncated.
926 * IN assertions: the input file has already been open (ifd is set) and
927 * ofname has already been updated if there was an original name.
928 * OUT assertions: ifd and ofd are closed in case of error.
930 local int create_outfile()
932 struct stat ostat; /* stat for ofname */
933 int flags = O_WRONLY | O_CREAT | O_EXCL | O_BINARY;
935 if (ascii && decompress) {
936 flags &= ~O_BINARY; /* force ascii text mode */
939 /* Make sure that ofname is not an existing file */
940 if (check_ofname() != OK) {
944 /* Create the output file */
946 ofd = OPEN(ofname, flags, RW_USER);
953 /* Check for name truncation on new file (1234567890123.gz) */
955 if (stat(ofname, &ostat) != 0) {
957 if (fstat(ofd, &ostat) != 0) {
960 close(ifd); close(ofd);
964 if (!name_too_long(ofname, &ostat)) return OK;
967 /* name might be too long if an original name was saved */
968 WARN((stderr, "%s: %s: warning, name truncated\n",
974 #ifdef NO_MULTIPLE_DOTS
975 /* Should never happen, see check_ofname() */
976 fprintf(stderr, "%s: %s: name too long\n", progname, ofname);
979 shorten_name(ofname);
983 /* ========================================================================
984 * Use lstat if available, except for -c or -f. Use stat otherwise.
985 * This allows links when not removing the original file.
987 local int do_stat(name, sbuf)
992 if (!to_stdout && !force) {
993 return lstat(name, sbuf);
995 return stat(name, sbuf);
998 /* ========================================================================
999 * Return a pointer to the 'z' suffix of a file name, or NULL. For all
1000 * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
1001 * accepted suffixes, in addition to the value of the --suffix option.
1002 * ".tgz" is a useful convention for tar.z files on systems limited
1003 * to 3 characters extensions. On such systems, ".?z" and ".??z" are
1004 * also accepted suffixes. For Unix, we do not want to accept any
1005 * .??z suffix as indicating a compressed file; some people use .xyz
1006 * to denote volume data.
1007 * On systems allowing multiple versions of the same file (such as VMS),
1008 * this function removes any version suffix in the given name.
1010 local char *get_suffix(name)
1014 char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */
1015 static char *known_suffixes[] =
1016 {NULL, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
1017 #ifdef MAX_EXT_CHARS
1021 char **suf = known_suffixes;
1024 if (strequ(z_suffix, "z")) suf++; /* check long suffixes first */
1027 /* strip a version number from the file name */
1029 char *v = strrchr(name, SUFFIX_SEP);
1030 if (v != NULL) *v = '\0';
1033 nlen = strlen(name);
1034 if (nlen <= MAX_SUFFIX+2) {
1035 strcpy(suffix, name);
1037 strcpy(suffix, name+nlen-MAX_SUFFIX-2);
1040 slen = strlen(suffix);
1042 int s = strlen(*suf);
1043 if (slen > s && suffix[slen-s-1] != PATH_SEP
1044 && strequ(suffix + slen - s, *suf)) {
1047 } while (*++suf != NULL);
1053 /* ========================================================================
1054 * Set ifname to the input file name (with a suffix appended if necessary)
1055 * and istat to its stats. For decompression, if no file exists with the
1056 * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
1057 * For MSDOS, we try only z_suffix and z.
1058 * Return OK or ERROR.
1060 local int get_istat(iname, sbuf)
1064 int ilen; /* strlen(ifname) */
1065 int z_suffix_errno = 0;
1066 static char *suffixes[] = {NULL, ".gz", ".z", "-z", ".Z", NULL};
1067 char **suf = suffixes;
1069 #ifdef NO_MULTIPLE_DOTS
1070 char *dot; /* pointer to ifname extension, or NULL */
1075 if (sizeof ifname - 1 <= strlen (iname))
1078 strcpy(ifname, iname);
1080 /* If input file exists, return OK. */
1081 if (do_stat(ifname, sbuf) == 0) return OK;
1083 if (!decompress || errno != ENOENT) {
1087 /* file.ext doesn't exist, try adding a suffix (after removing any
1088 * version number for VMS).
1090 s = get_suffix(ifname);
1092 progerror(ifname); /* ifname already has z suffix and does not exist */
1095 #ifdef NO_MULTIPLE_DOTS
1096 dot = strrchr(ifname, '.');
1098 strcat(ifname, ".");
1099 dot = strrchr(ifname, '.');
1102 ilen = strlen(ifname);
1103 if (strequ(z_suffix, ".gz")) suf++;
1105 /* Search for all suffixes */
1107 char *s0 = s = *suf;
1108 strcpy (ifname, iname);
1109 #ifdef NO_MULTIPLE_DOTS
1111 if (*dot == '\0') strcpy (dot, ".");
1113 #ifdef MAX_EXT_CHARS
1114 if (MAX_EXT_CHARS < strlen (s) + strlen (dot + 1))
1115 dot[MAX_EXT_CHARS + 1 - strlen (s)] = '\0';
1117 if (sizeof ifname <= ilen + strlen (s))
1120 if (do_stat(ifname, sbuf) == 0) return OK;
1121 if (strequ (s0, z_suffix))
1122 z_suffix_errno = errno;
1123 } while (*++suf != NULL);
1125 /* No suffix found, complain using z_suffix: */
1126 strcpy(ifname, iname);
1127 #ifdef NO_MULTIPLE_DOTS
1128 if (*dot == '\0') strcpy(dot, ".");
1130 #ifdef MAX_EXT_CHARS
1131 if (MAX_EXT_CHARS < z_len + strlen (dot + 1))
1132 dot[MAX_EXT_CHARS + 1 - z_len] = '\0';
1134 strcat(ifname, z_suffix);
1135 errno = z_suffix_errno;
1140 fprintf (stderr, "%s: %s: file name too long\n", progname, iname);
1145 /* ========================================================================
1146 * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
1147 * Sets save_orig_name to true if the file name has been truncated.
1149 local int make_ofname()
1151 char *suff; /* ofname z suffix */
1153 strcpy(ofname, ifname);
1154 /* strip a version number if any and get the gzip suffix if present: */
1155 suff = get_suffix(ofname);
1159 /* With -t or -l, try all files (even without .gz suffix)
1160 * except with -r (behave as with just -dr).
1162 if (!recursive && (list || test)) return OK;
1164 /* Avoid annoying messages with -r */
1165 if (verbose || (!recursive && !quiet)) {
1166 WARN((stderr,"%s: %s: unknown suffix -- ignored\n",
1171 /* Make a special case for .tgz and .taz: */
1173 if (strequ(suff, ".tgz") || strequ(suff, ".taz")) {
1174 strcpy(suff, ".tar");
1176 *suff = '\0'; /* strip the z suffix */
1178 /* ofname might be changed later if infile contains an original name */
1180 } else if (suff != NULL) {
1181 /* Avoid annoying messages with -r (see treat_dir()) */
1182 if (verbose || (!recursive && !quiet)) {
1183 /* don't use WARN -- it will cause an exit_code of 2 */
1184 fprintf(stderr, "%s: %s already has %s suffix -- unchanged\n",
1185 progname, ifname, suff);
1191 #ifdef NO_MULTIPLE_DOTS
1192 suff = strrchr(ofname, '.');
1194 if (sizeof ofname <= strlen (ofname) + 1)
1196 strcat(ofname, ".");
1197 # ifdef MAX_EXT_CHARS
1198 if (strequ(z_suffix, "z")) {
1199 if (sizeof ofname <= strlen (ofname) + 2)
1201 strcat(ofname, "gz"); /* enough room */
1204 /* On the Atari and some versions of MSDOS, name_too_long()
1205 * does not work correctly because of a bug in stat(). So we
1206 * must truncate here.
1208 } else if (strlen(suff)-1 + z_len > MAX_SUFFIX) {
1209 suff[MAX_SUFFIX+1-z_len] = '\0';
1213 #endif /* NO_MULTIPLE_DOTS */
1214 if (sizeof ofname <= strlen (ofname) + z_len)
1216 strcat(ofname, z_suffix);
1218 } /* decompress ? */
1222 WARN ((stderr, "%s: %s: file name too long\n", progname, ifname));
1227 /* ========================================================================
1228 * Check the magic number of the input file and update ofname if an
1229 * original name was given and to_stdout is not set.
1230 * Return the compression method, -1 for error, -2 for warning.
1231 * Set inptr to the offset of the next byte to be processed.
1232 * Updates time_stamp if there is one and --no-time is not used.
1233 * This function may be called repeatedly for an input file consisting
1234 * of several contiguous gzip'ed members.
1235 * IN assertions: there is at least one remaining compressed member.
1236 * If the member is a zip file, it must be the only one.
1238 local int get_method(in)
1239 int in; /* input file descriptor */
1241 uch flags; /* compression flags */
1242 char magic[2]; /* magic header */
1243 int imagic1; /* like magic[1], but can represent EOF */
1244 ulg stamp; /* time stamp */
1246 /* If --force and --stdout, zcat == cat, so do not complain about
1247 * premature end of file: use try_byte instead of get_byte.
1249 if (force && to_stdout) {
1250 magic[0] = (char)try_byte();
1251 imagic1 = try_byte ();
1252 magic[1] = (char) imagic1;
1253 /* If try_byte returned EOF, magic[1] == (char) EOF. */
1255 magic[0] = (char)get_byte();
1256 magic[1] = (char)get_byte();
1257 imagic1 = 0; /* avoid lint warning */
1259 method = -1; /* unknown yet */
1260 part_nb++; /* number of parts in gzip file */
1262 last_member = RECORD_IO;
1263 /* assume multiple members in gzip file except for record oriented I/O */
1265 if (memcmp(magic, GZIP_MAGIC, 2) == 0
1266 || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
1268 method = (int)get_byte();
1269 if (method != DEFLATED) {
1271 "%s: %s: unknown method %d -- not supported\n",
1272 progname, ifname, method);
1277 flags = (uch)get_byte();
1279 if ((flags & ENCRYPTED) != 0) {
1281 "%s: %s is encrypted -- not supported\n",
1286 if ((flags & CONTINUATION) != 0) {
1288 "%s: %s is a a multi-part gzip file -- not supported\n",
1291 if (force <= 1) return -1;
1293 if ((flags & RESERVED) != 0) {
1295 "%s: %s has flags 0x%x -- not supported\n",
1296 progname, ifname, flags);
1298 if (force <= 1) return -1;
1300 stamp = (ulg)get_byte();
1301 stamp |= ((ulg)get_byte()) << 8;
1302 stamp |= ((ulg)get_byte()) << 16;
1303 stamp |= ((ulg)get_byte()) << 24;
1304 if (stamp != 0 && !no_time) time_stamp = stamp;
1306 (void)get_byte(); /* Ignore extra flags for the moment */
1307 (void)get_byte(); /* Ignore OS type for the moment */
1309 if ((flags & CONTINUATION) != 0) {
1310 unsigned part = (unsigned)get_byte();
1311 part |= ((unsigned)get_byte())<<8;
1313 fprintf(stderr,"%s: %s: part number %u\n",
1314 progname, ifname, part);
1317 if ((flags & EXTRA_FIELD) != 0) {
1318 unsigned len = (unsigned)get_byte();
1319 len |= ((unsigned)get_byte())<<8;
1321 fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n",
1322 progname, ifname, len);
1324 while (len--) (void)get_byte();
1327 /* Get original file name if it was truncated */
1328 if ((flags & ORIG_NAME) != 0) {
1329 if (no_name || (to_stdout && !list) || part_nb > 1) {
1330 /* Discard the old name */
1331 char c; /* dummy used for NeXTstep 3.0 cc optimizer bug */
1332 do {c=get_byte();} while (c != 0);
1334 /* Copy the base name. Keep a directory prefix intact. */
1335 char *p = base_name (ofname);
1339 *p = (char)get_char();
1340 if (*p++ == '\0') break;
1341 if (p >= ofname+sizeof(ofname)) {
1342 error("corrupted input -- file name too large");
1345 base2 = base_name (base);
1346 strcpy(base, base2);
1347 /* If necessary, adapt the name to local OS conventions: */
1349 MAKE_LEGAL_NAME(base);
1350 if (base) list=0; /* avoid warning about unused variable */
1352 } /* no_name || to_stdout */
1355 /* Discard file comment if any */
1356 if ((flags & COMMENT) != 0) {
1357 while (get_char() != 0) /* null */ ;
1360 header_bytes = inptr + 2*sizeof(long); /* include crc and size */
1363 } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
1364 && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0) {
1365 /* To simplify the code, we support a zip file when alone only.
1366 * We are thus guaranteed that the entire local header fits in inbuf.
1370 if (check_zipfile(in) != OK) return -1;
1371 /* check_zipfile may get ofname from the local header */
1374 } else if (memcmp(magic, PACK_MAGIC, 2) == 0) {
1378 } else if (memcmp(magic, LZW_MAGIC, 2) == 0) {
1380 method = COMPRESSED;
1383 } else if (memcmp(magic, LZH_MAGIC, 2) == 0) {
1388 } else if (force && to_stdout && !list) { /* pass input unchanged */
1394 if (method >= 0) return method;
1397 fprintf(stderr, "\n%s: %s: not in gzip format\n", progname, ifname);
1404 for (inbyte = imagic1; inbyte == 0; inbyte = try_byte ())
1409 WARN ((stderr, "\n%s: %s: decompression OK, trailing zero bytes ignored\n",
1415 WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n",
1421 /* ========================================================================
1422 * Display the characteristics of the compressed file.
1423 * If the given method is < 0, display the accumulated totals.
1424 * IN assertions: time_stamp, header_bytes and ifile_size are initialized.
1426 local void do_list(ifd, method)
1427 int ifd; /* input file descriptor */
1428 int method; /* compression method */
1430 ulg crc; /* original crc */
1431 static int first_time = 1;
1432 static char* methods[MAX_METHODS] = {
1437 "", "", "", "", /* 4 to 7 reserved */
1440 int positive_off_t_width = 1;
1443 for (o = OFF_T_MAX; 9 < o; o /= 10) {
1444 positive_off_t_width++;
1447 if (first_time && method >= 0) {
1450 printf("method crc date time ");
1453 printf("%*.*s %*.*s ratio uncompressed_name\n",
1454 positive_off_t_width, positive_off_t_width, "compressed",
1455 positive_off_t_width, positive_off_t_width, "uncompressed");
1457 } else if (method < 0) {
1458 if (total_in <= 0 || total_out <= 0) return;
1462 if (verbose || !quiet) {
1463 fprint_off(stdout, total_in, positive_off_t_width);
1465 fprint_off(stdout, total_out, positive_off_t_width);
1468 display_ratio(total_out-(total_in-header_bytes), total_out, stdout);
1469 /* header_bytes is not meaningful but used to ensure the same
1470 * ratio if there is a single file.
1472 printf(" (totals)\n");
1475 crc = (ulg)~0; /* unknown */
1477 bytes_in = ifile_size;
1480 if (method == DEFLATED && !last_member) {
1481 /* Get the crc and uncompressed size for gzip'ed (not zip'ed) files.
1482 * If the lseek fails, we could use read() to get to the end, but
1483 * --list is used to get quick results.
1484 * Use "gunzip < foo.gz | wc -c" to get the uncompressed size if
1485 * you are not concerned about speed.
1487 bytes_in = lseek(ifd, (off_t)(-8), SEEK_END);
1488 if (bytes_in != -1L) {
1491 if (read(ifd, (char*)buf, sizeof(buf)) != sizeof(buf)) {
1495 bytes_out = LG(buf+4);
1498 #endif /* RECORD_IO */
1499 date = ctime((time_t*)&time_stamp) + 4; /* skip the day of the week */
1500 date[12] = '\0'; /* suppress the 1/100sec and the year */
1502 printf("%5s %08lx %11s ", methods[method], crc, date);
1504 fprint_off(stdout, bytes_in, positive_off_t_width);
1506 fprint_off(stdout, bytes_out, positive_off_t_width);
1508 if (bytes_in == -1L) {
1510 bytes_in = bytes_out = header_bytes = 0;
1511 } else if (total_in >= 0) {
1512 total_in += bytes_in;
1514 if (bytes_out == -1L) {
1516 bytes_in = bytes_out = header_bytes = 0;
1517 } else if (total_out >= 0) {
1518 total_out += bytes_out;
1520 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out, stdout);
1521 printf(" %s\n", ofname);
1524 /* ========================================================================
1525 * Return true if the two stat structures correspond to the same file.
1527 local int same_file(stat1, stat2)
1531 return stat1->st_ino == stat2->st_ino
1532 && stat1->st_dev == stat2->st_dev
1534 /* Can't rely on st_ino and st_dev, use other fields: */
1535 && stat1->st_mode == stat2->st_mode
1536 && stat1->st_uid == stat2->st_uid
1537 && stat1->st_gid == stat2->st_gid
1538 && stat1->st_size == stat2->st_size
1539 && stat1->st_atime == stat2->st_atime
1540 && stat1->st_mtime == stat2->st_mtime
1541 && stat1->st_ctime == stat2->st_ctime
1546 /* ========================================================================
1547 * Return true if a file name is ambiguous because the operating system
1548 * truncates file names.
1550 local int name_too_long(name, statb)
1551 char *name; /* file name to check */
1552 struct stat *statb; /* stat buf for this file name */
1554 int s = strlen(name);
1556 struct stat tstat; /* stat for truncated name */
1559 tstat = *statb; /* Just in case OS does not fill all fields */
1561 res = lstat(name, &tstat) == 0 && same_file(statb, &tstat);
1563 Trace((stderr, " too_long(%s) => %d\n", name, res));
1567 /* ========================================================================
1568 * Shorten the given name by one character, or replace a .tar extension
1569 * with .tgz. Truncate the last part of the name which is longer than
1570 * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
1571 * has only parts shorter than MIN_PART truncate the longest part.
1572 * For decompression, just remove the last character of the name.
1574 * IN assertion: for compression, the suffix of the given name is z_suffix.
1576 local void shorten_name(name)
1579 int len; /* length of name without z_suffix */
1580 char *trunc = NULL; /* character to be truncated */
1581 int plen; /* current part length */
1582 int min_part = MIN_PART; /* current minimum part length */
1587 if (len <= 1) error("name too short");
1591 p = get_suffix(name);
1592 if (p == NULL) error("can't recover suffix\n");
1596 /* compress 1234567890.tar to 1234567890.tgz */
1597 if (len > 4 && strequ(p-4, ".tar")) {
1598 strcpy(p-4, ".tgz");
1601 /* Try keeping short extensions intact:
1602 * 1234.678.012.gz -> 123.678.012.gz
1605 p = strrchr(name, PATH_SEP);
1608 plen = strcspn(p, PART_SEP);
1610 if (plen > min_part) trunc = p-1;
1613 } while (trunc == NULL && --min_part != 0);
1615 if (trunc != NULL) {
1617 trunc[0] = trunc[1];
1621 trunc = strrchr(name, PART_SEP[0]);
1622 if (trunc == NULL) error("internal error in shorten_name");
1623 if (trunc[1] == '\0') trunc--; /* force truncation */
1625 strcpy(trunc, z_suffix);
1628 /* ========================================================================
1629 * If compressing to a file, check if ofname is not ambiguous
1630 * because the operating system truncates names. Otherwise, generate
1631 * a new ofname and save the original name in the compressed file.
1632 * If the compressed file already exists, ask for confirmation.
1633 * The check for name truncation is made dynamically, because different
1634 * file systems on the same OS might use different truncation rules (on SVR4
1635 * s5 truncates to 14 chars and ufs does not truncate).
1636 * This function returns -1 if the file must be skipped, and
1637 * updates save_orig_name if necessary.
1638 * IN assertions: save_orig_name is already set if ofname has been
1639 * already truncated because of NO_MULTIPLE_DOTS. The input file has
1640 * already been open and istat is set.
1642 local int check_ofname()
1644 struct stat ostat; /* stat for ofname */
1647 /* Check for strictly conforming Posix systems (which return ENAMETOOLONG
1648 * instead of silently truncating filenames).
1651 while (lstat(ofname, &ostat) != 0) {
1652 if (errno != ENAMETOOLONG) return 0; /* ofname does not exist */
1653 shorten_name(ofname);
1656 if (lstat(ofname, &ostat) != 0) return 0;
1658 /* Check for name truncation on existing file. Do this even on systems
1659 * defining ENAMETOOLONG, because on most systems the strict Posix
1660 * behavior is disabled by default (silent name truncation allowed).
1662 if (!decompress && name_too_long(ofname, &ostat)) {
1663 shorten_name(ofname);
1664 if (lstat(ofname, &ostat) != 0) return 0;
1667 /* Check that the input and output files are different (could be
1668 * the same by name truncation or links).
1670 if (same_file(&istat, &ostat)) {
1671 if (strequ(ifname, ofname)) {
1672 fprintf(stderr, "%s: %s: cannot %scompress onto itself\n",
1673 progname, ifname, decompress ? "de" : "");
1675 fprintf(stderr, "%s: %s and %s are the same file\n",
1676 progname, ifname, ofname);
1681 /* Ask permission to overwrite the existing file */
1684 fprintf(stderr, "%s: %s already exists;", progname, ofname);
1685 if (foreground && isatty(fileno(stdin))) {
1686 fprintf(stderr, " do you wish to overwrite (y or n)? ");
1691 fprintf(stderr, "\tnot overwritten\n");
1692 if (exit_code == OK) exit_code = WARNING;
1696 if (xunlink (ofname)) {
1705 /* ========================================================================
1706 * Set the access and modification times from the given stat buffer.
1708 local void reset_times (name, statb)
1712 struct utimbuf timep;
1714 /* Copy the time stamp */
1715 timep.actime = statb->st_atime;
1716 timep.modtime = statb->st_mtime;
1718 /* Some systems (at least OS/2) do not support utime on directories */
1719 if (utime(name, &timep) && !S_ISDIR(statb->st_mode)) {
1721 WARN((stderr, "%s: ", progname));
1731 /* ========================================================================
1732 * Copy modes, times, ownership from input file to output file.
1733 * IN assertion: to_stdout is false.
1735 local void copy_stat(ifstat)
1736 struct stat *ifstat;
1739 if (decompress && time_stamp != 0 && ifstat->st_mtime != time_stamp) {
1740 ifstat->st_mtime = time_stamp;
1742 fprintf(stderr, "%s: time stamp restored\n", ofname);
1745 reset_times(ofname, ifstat);
1747 /* Copy the protection modes */
1748 if (fchmod(ofd, ifstat->st_mode & 07777)) {
1750 WARN((stderr, "%s: ", progname));
1757 fchown(ofd, ifstat->st_uid, ifstat->st_gid); /* Copy ownership */
1763 /* ========================================================================
1764 * Recurse through the given directory. This code is taken from ncompress.
1766 local void treat_dir(dir)
1771 char nbuf[MAX_PATH_LEN];
1774 dirp = opendir(dir);
1781 ** WARNING: the following algorithm could occasionally cause
1782 ** compress to produce error warnings of the form "<filename>.gz
1783 ** already has .gz suffix - ignored". This occurs when the
1784 ** .gz output file is inserted into the directory below
1785 ** readdir's current pointer.
1786 ** These warnings are harmless but annoying, so they are suppressed
1787 ** with option -r (except when -v is on). An alternative
1788 ** to allowing this would be to store the entire directory
1789 ** list in memory, then compress the entries in the stored
1790 ** list. Given the depth-first recursive algorithm used here,
1791 ** this could use up a tremendous amount of memory. I don't
1792 ** think it's worth it. -- Dave Mack
1793 ** (An other alternative might be two passes to avoid depth-first.)
1796 while ((errno = 0, dp = readdir(dirp)) != NULL) {
1798 if (strequ(dp->d_name,".") || strequ(dp->d_name,"..")) {
1802 if (len + NAMLEN(dp) + 1 < MAX_PATH_LEN - 1) {
1804 if (len != 0 /* dir = "" means current dir on Amiga */
1806 && dir[len-1] != PATH_SEP2
1809 && dir[len-1] != PATH_SEP3
1812 nbuf[len++] = PATH_SEP;
1814 strcpy(nbuf+len, dp->d_name);
1817 fprintf(stderr,"%s: %s/%s: pathname too long\n",
1818 progname, dir, dp->d_name);
1824 if (CLOSEDIR(dirp) != 0)
1827 #endif /* ! NO_DIR */
1829 /* ========================================================================
1830 * Free all dynamically allocated variables and exit with the given code.
1832 local void do_exit(exitcode)
1835 static int in_exit = 0;
1837 if (in_exit) exit(exitcode);
1839 if (env != NULL) free(env), env = NULL;
1840 if (args != NULL) free((char*)args), args = NULL;
1854 /* ========================================================================
1855 * Close and unlink the output file if appropriate. This routine must be
1856 * async-signal-safe.
1858 local void do_remove() {
1859 if (remove_ofname) {
1865 /* ========================================================================
1868 RETSIGTYPE abort_gzip()
1874 /* ========================================================================
1877 RETSIGTYPE abort_gzip_signal()