1 /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
2 * Copyright (C) 1999, 2001 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 2001 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"
108 # define CLOSEDIR(d) (closedir(d), 0)
110 # define CLOSEDIR(d) closedir(d)
116 # define TIME_OPT "UTIME"
118 # ifdef HAVE_SYS_UTIME_H
119 # include <sys/utime.h>
120 # define TIME_OPT "SYS_UTIME"
126 # define TIME_OPT "STRUCT_UTIMBUF"
130 # define TIME_OPT "NO_UTIME"
133 #if !defined(S_ISDIR) && defined(S_IFDIR)
134 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
136 #if !defined(S_ISREG) && defined(S_IFREG)
137 # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
140 typedef RETSIGTYPE (*sig_type) OF((int));
143 # define O_BINARY 0 /* creation mode for open() */
147 /* Pure BSD system? */
148 # include <sys/file.h>
150 # define O_CREAT FCREAT
153 # define O_EXCL FEXCL
158 # define S_IRUSR 0400
161 # define S_IWUSR 0200
163 #define RW_USER (S_IRUSR | S_IWUSR) /* creation mode for open() */
166 # define MAX_PATH_LEN 1024 /* max pathname length */
178 off_t lseek OF((int fd, off_t offset, int whence));
182 #define OFF_T_MIN (~ (off_t) 0 << (sizeof (off_t) * CHAR_BIT - 1))
186 #define OFF_T_MAX (~ (off_t) 0 - OFF_T_MIN)
189 /* Separator for file name parts (see shorten_name()) */
190 #ifdef NO_MULTIPLE_DOTS
191 # define PART_SEP "-"
193 # define PART_SEP "."
198 DECLARE(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
199 DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
200 DECLARE(ush, d_buf, DIST_BUFSIZE);
201 DECLARE(uch, window, 2L*WSIZE);
203 DECLARE(ush, tab_prefix, 1L<<BITS);
205 DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
206 DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
209 /* local variables */
211 int ascii = 0; /* convert end-of-lines to local OS conventions */
212 int to_stdout = 0; /* output to stdout (-c) */
213 int decompress = 0; /* decompress (-d) */
214 int force = 0; /* don't ask questions, compress links (-f) */
215 int no_name = -1; /* don't save or restore the original file name */
216 int no_time = -1; /* don't save or restore the original file time */
217 int recursive = 0; /* recurse through directories (-r) */
218 int list = 0; /* list the file contents (-l) */
219 int verbose = 0; /* be verbose (-v) */
220 int quiet = 0; /* be very quiet (-q) */
221 int do_lzw = 0; /* generate output compatible with old compress (-Z) */
222 int test = 0; /* test .gz file integrity */
223 int foreground; /* set if program run in foreground */
224 char *progname; /* program name */
225 int maxbits = BITS; /* max bits per code for LZW */
226 int method = DEFLATED;/* compression method */
227 int level = 6; /* compression level */
228 int exit_code = OK; /* program exit code */
229 int save_orig_name; /* set if original name must be saved */
230 int last_member; /* set for .zip and .Z files */
231 int part_nb; /* number of parts in .gz file */
232 time_t time_stamp; /* original time stamp (modification time) */
233 off_t ifile_size; /* input file size, -1 for devices (debug only) */
234 char *env; /* contents of GZIP env variable */
235 char **args = NULL; /* argv pointer if GZIP env variable defined */
236 char *z_suffix; /* default suffix (can be set with --suffix) */
237 int z_len; /* strlen(z_suffix) */
239 off_t bytes_in; /* number of input bytes */
240 off_t bytes_out; /* number of output bytes */
241 off_t total_in; /* input bytes for all files */
242 off_t total_out; /* output bytes for all files */
243 char ifname[MAX_PATH_LEN]; /* input file name */
244 char ofname[MAX_PATH_LEN]; /* output file name */
245 int remove_ofname = 0; /* remove output file on error */
246 struct stat istat; /* status for input file */
247 int ifd; /* input file descriptor */
248 int ofd; /* output file descriptor */
249 unsigned insize; /* valid bytes in inbuf */
250 unsigned inptr; /* index of next byte to be processed in inbuf */
251 unsigned outcnt; /* bytes in output buffer */
253 struct option longopts[] =
255 /* { name has_arg *flag val } */
256 {"ascii", 0, 0, 'a'}, /* ascii text mode */
257 {"to-stdout", 0, 0, 'c'}, /* write output on standard output */
258 {"stdout", 0, 0, 'c'}, /* write output on standard output */
259 {"decompress", 0, 0, 'd'}, /* decompress */
260 {"uncompress", 0, 0, 'd'}, /* decompress */
261 /* {"encrypt", 0, 0, 'e'}, encrypt */
262 {"force", 0, 0, 'f'}, /* force overwrite of output file */
263 {"help", 0, 0, 'h'}, /* give help */
264 /* {"pkzip", 0, 0, 'k'}, force output in pkzip format */
265 {"list", 0, 0, 'l'}, /* list .gz file contents */
266 {"license", 0, 0, 'L'}, /* display software license */
267 {"no-name", 0, 0, 'n'}, /* don't save or restore original name & time */
268 {"name", 0, 0, 'N'}, /* save or restore original name & time */
269 {"quiet", 0, 0, 'q'}, /* quiet mode */
270 {"silent", 0, 0, 'q'}, /* quiet mode */
271 {"recursive", 0, 0, 'r'}, /* recurse through directories */
272 {"suffix", 1, 0, 'S'}, /* use given suffix instead of .gz */
273 {"test", 0, 0, 't'}, /* test compressed file integrity */
274 {"no-time", 0, 0, 'T'}, /* don't save or restore the time stamp */
275 {"verbose", 0, 0, 'v'}, /* verbose mode */
276 {"version", 0, 0, 'V'}, /* display version number */
277 {"fast", 0, 0, '1'}, /* compress faster */
278 {"best", 0, 0, '9'}, /* compress better */
279 {"lzw", 0, 0, 'Z'}, /* make output compatible with old compress */
280 {"bits", 1, 0, 'b'}, /* max number of bits per code (implies -Z) */
284 /* local functions */
286 local void usage OF((void));
287 local void help OF((void));
288 local void license OF((void));
289 local void version OF((void));
290 local int input_eof OF((void));
291 local void treat_stdin OF((void));
292 local void treat_file OF((char *iname));
293 local int create_outfile OF((void));
294 local int do_stat OF((char *name, struct stat *sbuf));
295 local char *get_suffix OF((char *name));
296 local int get_istat OF((char *iname, struct stat *sbuf));
297 local int make_ofname OF((void));
298 local int same_file OF((struct stat *stat1, struct stat *stat2));
299 local int name_too_long OF((char *name, struct stat *statb));
300 local void shorten_name OF((char *name));
301 local int get_method OF((int in));
302 local void do_list OF((int ifd, int method));
303 local int check_ofname OF((void));
304 local void copy_stat OF((struct stat *ifstat));
305 local void do_exit OF((int exitcode));
306 int main OF((int argc, char **argv));
307 int (*work) OF((int infile, int outfile)) = zip; /* function to call */
310 local void treat_dir OF((char *dir));
313 local void reset_times OF((char *name, struct stat *statb));
316 #define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
318 /* ======================================================================== */
321 printf ("usage: %s [-%scdfhlLnN%stvV19] [-S suffix] [file ...]\n",
336 /* ======================================================================== */
339 static char *help_msg[] = {
341 " -a --ascii ascii text; convert end-of-lines using local conventions",
343 " -c --stdout write on standard output, keep original files unchanged",
344 " -d --decompress decompress",
345 /* -e --encrypt encrypt */
346 " -f --force force overwrite of output file and compress links",
347 " -h --help give this help",
348 /* -k --pkzip force output in pkzip format */
349 " -l --list list compressed file contents",
350 " -L --license display software license",
352 " -m --no-time do not save or restore the original modification time",
353 " -M --time save or restore the original modification time",
355 " -n --no-name do not save or restore the original name and time stamp",
356 " -N --name save or restore the original name and time stamp",
357 " -q --quiet suppress all warnings",
359 " -r --recursive operate recursively on directories",
361 " -S .suf --suffix .suf use suffix .suf on compressed files",
362 " -t --test test compressed file integrity",
363 " -v --verbose verbose mode",
364 " -V --version display version number",
365 " -1 --fast compress faster",
366 " -9 --best compress better",
368 " -Z --lzw produce output compatible with old compress",
369 " -b --bits maxbits max number of bits per code (implies -Z)",
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);
473 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
474 (void) signal(SIGTERM, (sig_type)abort_gzip);
478 if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
479 (void) signal(SIGHUP, (sig_type)abort_gzip);
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;
550 #ifdef NO_MULTIPLE_DOTS
551 if (*optarg == '.') optarg++;
553 z_len = strlen(optarg);
557 test = decompress = to_stdout = 1;
560 verbose++; quiet = 0; break;
562 version(); do_exit(OK); break;
567 fprintf(stderr, "%s: -Z not supported in this version\n",
570 do_exit(ERROR); break;
572 case '1': case '2': case '3': case '4':
573 case '5': case '6': case '7': case '8': case '9':
577 /* Error message already emitted by getopt_long. */
581 } /* loop on all arguments */
584 /* Ignore "Broken Pipe" message with --quiet */
585 if (quiet && signal (SIGPIPE, SIG_IGN) != SIG_IGN)
586 signal (SIGPIPE, (sig_type) abort_gzip);
589 /* By default, save name and timestamp on compression but do not
590 * restore them on decompression.
592 if (no_time < 0) no_time = decompress;
593 if (no_name < 0) no_name = decompress;
595 file_count = argc - optind;
599 if (ascii && !quiet) {
600 fprintf(stderr, "%s: option --ascii ignored on this system\n",
604 if ((z_len == 0 && !decompress) || z_len > MAX_SUFFIX) {
605 fprintf(stderr, "%s: incorrect suffix '%s'\n",
609 if (do_lzw && !decompress) work = lzw;
611 /* Allocate all global buffers (for DYN_ALLOC option) */
612 ALLOC(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
613 ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
614 ALLOC(ush, d_buf, DIST_BUFSIZE);
615 ALLOC(uch, window, 2L*WSIZE);
617 ALLOC(ush, tab_prefix, 1L<<BITS);
619 ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
620 ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
623 /* And get to work */
624 if (file_count != 0) {
625 if (to_stdout && !test && !list && (!decompress || !ascii)) {
626 SET_BINARY_MODE(fileno(stdout));
628 while (optind < argc) {
629 treat_file(argv[optind++]);
631 } else { /* Standard input */
634 if (list && !quiet && file_count > 1) {
635 do_list(-1, -1); /* print totals */
638 return exit_code; /* just to avoid lint warning */
641 /* Return nonzero when at end of file on input. */
645 if (!decompress || last_member)
650 if (insize != INBUFSIZ || fill_inbuf (1) == EOF)
653 /* Unget the char that fill_inbuf got. */
660 /* ========================================================================
661 * Compress or decompress stdin
663 local void treat_stdin()
665 if (!force && !list &&
666 isatty(fileno((FILE *)(decompress ? stdin : stdout)))) {
667 /* Do not send compressed data to the terminal or read it from
668 * the terminal. We get here when user invoked the program
669 * without parameters, so be helpful. According to the GNU standards:
671 * If there is one behavior you think is most useful when the output
672 * is to a terminal, and another that you think is most useful when
673 * the output is a file or a pipe, then it is usually best to make
674 * the default behavior the one that is useful with output to a
675 * terminal, and have an option for the other behavior.
677 * Here we use the --force option to get the other behavior.
680 "%s: compressed data not %s a terminal. Use -f to force %scompression.\n",
681 progname, decompress ? "read from" : "written to",
682 decompress ? "de" : "");
683 fprintf(stderr,"For help, type: %s -h\n", progname);
687 if (decompress || !ascii) {
688 SET_BINARY_MODE(fileno(stdin));
690 if (!test && !list && (!decompress || !ascii)) {
691 SET_BINARY_MODE(fileno(stdout));
693 strcpy(ifname, "stdin");
694 strcpy(ofname, "stdout");
696 /* Get the time stamp on the input file. */
697 time_stamp = 0; /* time unknown by default */
699 #ifndef NO_STDIN_FSTAT
700 if (list || !no_time) {
701 if (fstat(fileno(stdin), &istat) != 0) {
702 progerror("standard input");
705 # ifdef NO_PIPE_TIMESTAMP
706 if (S_ISREG(istat.st_mode))
708 time_stamp = istat.st_mtime;
709 #endif /* NO_STDIN_FSTAT */
711 ifile_size = -1L; /* convention for unknown size */
713 clear_bufs(); /* clear input and output buffers */
718 method = get_method(ifd);
720 do_exit(exit_code); /* error message already emitted */
724 do_list(ifd, method);
728 /* Actually do the compression/decompression. Loop over zipped members.
731 if ((*work)(fileno(stdin), fileno(stdout)) != OK) return;
736 method = get_method(ifd);
737 if (method < 0) return; /* error message already emitted */
738 bytes_out = 0; /* required for length check */
743 fprintf(stderr, " OK\n");
745 } else if (!decompress) {
746 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
747 fprintf(stderr, "\n");
748 #ifdef DISPLAY_STDIN_RATIO
750 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
751 fprintf(stderr, "\n");
757 /* ========================================================================
758 * Compress or decompress the given file
760 local void treat_file(iname)
763 /* Accept "-" as synonym for stdin */
764 if (strequ(iname, "-")) {
765 int cflag = to_stdout;
771 /* Check if the input file is present, set ifname and istat: */
772 if (get_istat(iname, &istat) != OK) return;
774 /* If the input name is that of a directory, recurse or ignore: */
775 if (S_ISDIR(istat.st_mode)) {
781 /* Warning: ifname is now garbage */
783 reset_times (iname, &st);
787 WARN((stderr,"%s: %s is a directory -- ignored\n", progname, ifname));
790 if (!S_ISREG(istat.st_mode)) {
792 "%s: %s is not a directory or a regular file - ignored\n",
796 if (istat.st_nlink > 1 && !to_stdout && !force) {
797 WARN((stderr, "%s: %s has %lu other link%c -- unchanged\n",
798 progname, ifname, (unsigned long) istat.st_nlink - 1,
799 istat.st_nlink > 2 ? 's' : ' '));
803 ifile_size = istat.st_size;
804 time_stamp = no_time && !list ? 0 : istat.st_mtime;
806 /* Generate output file name. For -r and (-t or -l), skip files
807 * without a valid gzip suffix (check done in make_ofname).
809 if (to_stdout && !list && !test) {
810 strcpy(ofname, "stdout");
812 } else if (make_ofname() != OK) {
816 /* Open the input file and determine compression method. The mode
817 * parameter is ignored but required by some systems (VMS) and forbidden
818 * on other systems (MacOS).
820 ifd = OPEN(ifname, ascii && !decompress ? O_RDONLY : O_RDONLY | O_BINARY,
826 clear_bufs(); /* clear input and output buffers */
830 method = get_method(ifd); /* updates ofname if original given */
833 return; /* error message already emitted */
837 do_list(ifd, method);
842 /* If compressing to a file, check if ofname is not ambiguous
843 * because the operating system truncates names. Otherwise, generate
844 * a new ofname and save the original name in the compressed file.
847 ofd = fileno(stdout);
848 /* keep remove_ofname as zero */
850 if (create_outfile() != OK) return;
852 if (!decompress && save_orig_name && !verbose && !quiet) {
853 fprintf(stderr, "%s: %s compressed to %s\n",
854 progname, ifname, ofname);
857 /* Keep the name even if not truncated except with --no-name: */
858 if (!save_orig_name) save_orig_name = !no_name;
861 fprintf(stderr, "%s:\t", ifname);
864 /* Actually do the compression/decompression. Loop over zipped members.
867 if ((*work)(ifd, ofd) != OK) {
868 method = -1; /* force cleanup */
875 method = get_method(ifd);
876 if (method < 0) break; /* error message already emitted */
877 bytes_out = 0; /* required for length check */
882 /* Copy modes, times, ownership, and remove the input file */
888 if (!to_stdout) xunlink (ofname);
891 /* Display statistics */
894 fprintf(stderr, " OK");
895 } else if (decompress) {
896 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
898 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
900 if (!test && !to_stdout) {
901 fprintf(stderr, " -- replaced with %s", ofname);
903 fprintf(stderr, "\n");
907 /* ========================================================================
908 * Create the output file. Return OK or ERROR.
909 * Try several times if necessary to avoid truncating the z_suffix. For
910 * example, do not create a compressed file of name "1234567890123."
911 * Sets save_orig_name to true if the file name has been truncated.
912 * IN assertions: the input file has already been open (ifd is set) and
913 * ofname has already been updated if there was an original name.
914 * OUT assertions: ifd and ofd are closed in case of error.
916 local int create_outfile()
918 struct stat ostat; /* stat for ofname */
919 int flags = O_WRONLY | O_CREAT | O_EXCL | O_BINARY;
921 if (ascii && decompress) {
922 flags &= ~O_BINARY; /* force ascii text mode */
925 /* Make sure that ofname is not an existing file */
926 if (check_ofname() != OK) {
930 /* Create the output file */
932 ofd = OPEN(ofname, flags, RW_USER);
939 /* Check for name truncation on new file (1234567890123.gz) */
941 if (stat(ofname, &ostat) != 0) {
943 if (fstat(ofd, &ostat) != 0) {
946 close(ifd); close(ofd);
950 if (!name_too_long(ofname, &ostat)) return OK;
953 /* name might be too long if an original name was saved */
954 WARN((stderr, "%s: %s: warning, name truncated\n",
960 #ifdef NO_MULTIPLE_DOTS
961 /* Should never happen, see check_ofname() */
962 fprintf(stderr, "%s: %s: name too long\n", progname, ofname);
965 shorten_name(ofname);
969 /* ========================================================================
970 * Use lstat if available, except for -c or -f. Use stat otherwise.
971 * This allows links when not removing the original file.
973 local int do_stat(name, sbuf)
979 if (!to_stdout && !force) {
980 return lstat(name, sbuf);
983 return stat(name, sbuf);
986 /* ========================================================================
987 * Return a pointer to the 'z' suffix of a file name, or NULL. For all
988 * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
989 * accepted suffixes, in addition to the value of the --suffix option.
990 * ".tgz" is a useful convention for tar.z files on systems limited
991 * to 3 characters extensions. On such systems, ".?z" and ".??z" are
992 * also accepted suffixes. For Unix, we do not want to accept any
993 * .??z suffix as indicating a compressed file; some people use .xyz
994 * to denote volume data.
995 * On systems allowing multiple versions of the same file (such as VMS),
996 * this function removes any version suffix in the given name.
998 local char *get_suffix(name)
1002 char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */
1003 static char *known_suffixes[] =
1004 {NULL, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
1005 #ifdef MAX_EXT_CHARS
1009 char **suf = known_suffixes;
1012 if (strequ(z_suffix, "z")) suf++; /* check long suffixes first */
1015 /* strip a version number from the file name */
1017 char *v = strrchr(name, SUFFIX_SEP);
1018 if (v != NULL) *v = '\0';
1021 nlen = strlen(name);
1022 if (nlen <= MAX_SUFFIX+2) {
1023 strcpy(suffix, name);
1025 strcpy(suffix, name+nlen-MAX_SUFFIX-2);
1028 slen = strlen(suffix);
1030 int s = strlen(*suf);
1031 if (slen > s && suffix[slen-s-1] != PATH_SEP
1032 && strequ(suffix + slen - s, *suf)) {
1035 } while (*++suf != NULL);
1041 /* ========================================================================
1042 * Set ifname to the input file name (with a suffix appended if necessary)
1043 * and istat to its stats. For decompression, if no file exists with the
1044 * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
1045 * For MSDOS, we try only z_suffix and z.
1046 * Return OK or ERROR.
1048 local int get_istat(iname, sbuf)
1052 int ilen; /* strlen(ifname) */
1053 int z_suffix_errno = 0;
1054 static char *suffixes[] = {NULL, ".gz", ".z", "-z", ".Z", NULL};
1055 char **suf = suffixes;
1057 #ifdef NO_MULTIPLE_DOTS
1058 char *dot; /* pointer to ifname extension, or NULL */
1063 if (sizeof ifname - 1 <= strlen (iname))
1066 strcpy(ifname, iname);
1068 /* If input file exists, return OK. */
1069 if (do_stat(ifname, sbuf) == 0) return OK;
1071 if (!decompress || errno != ENOENT) {
1075 /* file.ext doesn't exist, try adding a suffix (after removing any
1076 * version number for VMS).
1078 s = get_suffix(ifname);
1080 progerror(ifname); /* ifname already has z suffix and does not exist */
1083 #ifdef NO_MULTIPLE_DOTS
1084 dot = strrchr(ifname, '.');
1086 strcat(ifname, ".");
1087 dot = strrchr(ifname, '.');
1090 ilen = strlen(ifname);
1091 if (strequ(z_suffix, ".gz")) suf++;
1093 /* Search for all suffixes */
1095 char *s0 = s = *suf;
1096 strcpy (ifname, iname);
1097 #ifdef NO_MULTIPLE_DOTS
1099 if (*dot == '\0') strcpy (dot, ".");
1101 #ifdef MAX_EXT_CHARS
1102 if (MAX_EXT_CHARS < strlen (s) + strlen (dot + 1))
1103 dot[MAX_EXT_CHARS + 1 - strlen (s)] = '\0';
1105 if (sizeof ifname <= ilen + strlen (s))
1108 if (do_stat(ifname, sbuf) == 0) return OK;
1109 if (strequ (s0, z_suffix))
1110 z_suffix_errno = errno;
1111 } while (*++suf != NULL);
1113 /* No suffix found, complain using z_suffix: */
1114 strcpy(ifname, iname);
1115 #ifdef NO_MULTIPLE_DOTS
1116 if (*dot == '\0') strcpy(dot, ".");
1118 #ifdef MAX_EXT_CHARS
1119 if (MAX_EXT_CHARS < z_len + strlen (dot + 1))
1120 dot[MAX_EXT_CHARS + 1 - z_len] = '\0';
1122 strcat(ifname, z_suffix);
1123 errno = z_suffix_errno;
1128 fprintf (stderr, "%s: %s: file name too long\n", progname, iname);
1133 /* ========================================================================
1134 * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
1135 * Sets save_orig_name to true if the file name has been truncated.
1137 local int make_ofname()
1139 char *suff; /* ofname z suffix */
1141 strcpy(ofname, ifname);
1142 /* strip a version number if any and get the gzip suffix if present: */
1143 suff = get_suffix(ofname);
1147 /* With -t or -l, try all files (even without .gz suffix)
1148 * except with -r (behave as with just -dr).
1150 if (!recursive && (list || test)) return OK;
1152 /* Avoid annoying messages with -r */
1153 if (verbose || (!recursive && !quiet)) {
1154 WARN((stderr,"%s: %s: unknown suffix -- ignored\n",
1159 /* Make a special case for .tgz and .taz: */
1161 if (strequ(suff, ".tgz") || strequ(suff, ".taz")) {
1162 strcpy(suff, ".tar");
1164 *suff = '\0'; /* strip the z suffix */
1166 /* ofname might be changed later if infile contains an original name */
1168 } else if (suff != NULL) {
1169 /* Avoid annoying messages with -r (see treat_dir()) */
1170 if (verbose || (!recursive && !quiet)) {
1171 WARN((stderr, "%s: %s already has %s suffix -- unchanged\n",
1172 progname, ifname, suff));
1178 #ifdef NO_MULTIPLE_DOTS
1179 suff = strrchr(ofname, '.');
1181 if (sizeof ofname <= strlen (ofname) + 1)
1183 strcat(ofname, ".");
1184 # ifdef MAX_EXT_CHARS
1185 if (strequ(z_suffix, "z")) {
1186 if (sizeof ofname <= strlen (ofname) + 2)
1188 strcat(ofname, "gz"); /* enough room */
1191 /* On the Atari and some versions of MSDOS, name_too_long()
1192 * does not work correctly because of a bug in stat(). So we
1193 * must truncate here.
1195 } else if (strlen(suff)-1 + z_len > MAX_SUFFIX) {
1196 suff[MAX_SUFFIX+1-z_len] = '\0';
1200 #endif /* NO_MULTIPLE_DOTS */
1201 if (sizeof ofname <= strlen (ofname) + z_len)
1203 strcat(ofname, z_suffix);
1205 } /* decompress ? */
1209 WARN ((stderr, "%s: %s: file name too long\n", progname, ifname));
1214 /* ========================================================================
1215 * Check the magic number of the input file and update ofname if an
1216 * original name was given and to_stdout is not set.
1217 * Return the compression method, -1 for error, -2 for warning.
1218 * Set inptr to the offset of the next byte to be processed.
1219 * Updates time_stamp if there is one and --no-time is not used.
1220 * This function may be called repeatedly for an input file consisting
1221 * of several contiguous gzip'ed members.
1222 * IN assertions: there is at least one remaining compressed member.
1223 * If the member is a zip file, it must be the only one.
1225 local int get_method(in)
1226 int in; /* input file descriptor */
1228 uch flags; /* compression flags */
1229 char magic[2]; /* magic header */
1230 int imagic1; /* like magic[1], but can represent EOF */
1231 ulg stamp; /* time stamp */
1233 /* If --force and --stdout, zcat == cat, so do not complain about
1234 * premature end of file: use try_byte instead of get_byte.
1236 if (force && to_stdout) {
1237 magic[0] = (char)try_byte();
1238 imagic1 = try_byte ();
1239 magic[1] = (char) imagic1;
1240 /* If try_byte returned EOF, magic[1] == (char) EOF. */
1242 magic[0] = (char)get_byte();
1243 magic[1] = (char)get_byte();
1244 imagic1 = 0; /* avoid lint warning */
1246 method = -1; /* unknown yet */
1247 part_nb++; /* number of parts in gzip file */
1249 last_member = RECORD_IO;
1250 /* assume multiple members in gzip file except for record oriented I/O */
1252 if (memcmp(magic, GZIP_MAGIC, 2) == 0
1253 || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
1255 method = (int)get_byte();
1256 if (method != DEFLATED) {
1258 "%s: %s: unknown method %d -- not supported\n",
1259 progname, ifname, method);
1264 flags = (uch)get_byte();
1266 if ((flags & ENCRYPTED) != 0) {
1268 "%s: %s is encrypted -- not supported\n",
1273 if ((flags & CONTINUATION) != 0) {
1275 "%s: %s is a a multi-part gzip file -- not supported\n",
1278 if (force <= 1) return -1;
1280 if ((flags & RESERVED) != 0) {
1282 "%s: %s has flags 0x%x -- not supported\n",
1283 progname, ifname, flags);
1285 if (force <= 1) return -1;
1287 stamp = (ulg)get_byte();
1288 stamp |= ((ulg)get_byte()) << 8;
1289 stamp |= ((ulg)get_byte()) << 16;
1290 stamp |= ((ulg)get_byte()) << 24;
1291 if (stamp != 0 && !no_time) time_stamp = stamp;
1293 (void)get_byte(); /* Ignore extra flags for the moment */
1294 (void)get_byte(); /* Ignore OS type for the moment */
1296 if ((flags & CONTINUATION) != 0) {
1297 unsigned part = (unsigned)get_byte();
1298 part |= ((unsigned)get_byte())<<8;
1300 fprintf(stderr,"%s: %s: part number %u\n",
1301 progname, ifname, part);
1304 if ((flags & EXTRA_FIELD) != 0) {
1305 unsigned len = (unsigned)get_byte();
1306 len |= ((unsigned)get_byte())<<8;
1308 fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n",
1309 progname, ifname, len);
1311 while (len--) (void)get_byte();
1314 /* Get original file name if it was truncated */
1315 if ((flags & ORIG_NAME) != 0) {
1316 if (no_name || (to_stdout && !list) || part_nb > 1) {
1317 /* Discard the old name */
1318 char c; /* dummy used for NeXTstep 3.0 cc optimizer bug */
1319 do {c=get_byte();} while (c != 0);
1321 /* Copy the base name. Keep a directory prefix intact. */
1322 char *p = base_name (ofname);
1326 *p = (char)get_char();
1327 if (*p++ == '\0') break;
1328 if (p >= ofname+sizeof(ofname)) {
1329 error("corrupted input -- file name too large");
1332 base2 = base_name (base);
1333 strcpy(base, base2);
1334 /* If necessary, adapt the name to local OS conventions: */
1336 MAKE_LEGAL_NAME(base);
1337 if (base) list=0; /* avoid warning about unused variable */
1339 } /* no_name || to_stdout */
1342 /* Discard file comment if any */
1343 if ((flags & COMMENT) != 0) {
1344 while (get_char() != 0) /* null */ ;
1347 header_bytes = inptr + 2*sizeof(long); /* include crc and size */
1350 } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
1351 && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0) {
1352 /* To simplify the code, we support a zip file when alone only.
1353 * We are thus guaranteed that the entire local header fits in inbuf.
1357 if (check_zipfile(in) != OK) return -1;
1358 /* check_zipfile may get ofname from the local header */
1361 } else if (memcmp(magic, PACK_MAGIC, 2) == 0) {
1365 } else if (memcmp(magic, LZW_MAGIC, 2) == 0) {
1367 method = COMPRESSED;
1370 } else if (memcmp(magic, LZH_MAGIC, 2) == 0) {
1375 } else if (force && to_stdout && !list) { /* pass input unchanged */
1381 if (method >= 0) return method;
1384 fprintf(stderr, "\n%s: %s: not in gzip format\n", progname, ifname);
1391 for (inbyte = imagic1; inbyte == 0; inbyte = try_byte ())
1396 WARN ((stderr, "\n%s: %s: decompression OK, trailing zero bytes ignored\n",
1402 WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n",
1408 /* ========================================================================
1409 * Display the characteristics of the compressed file.
1410 * If the given method is < 0, display the accumulated totals.
1411 * IN assertions: time_stamp, header_bytes and ifile_size are initialized.
1413 local void do_list(ifd, method)
1414 int ifd; /* input file descriptor */
1415 int method; /* compression method */
1417 ulg crc; /* original crc */
1418 static int first_time = 1;
1419 static char* methods[MAX_METHODS] = {
1424 "", "", "", "", /* 4 to 7 reserved */
1427 int positive_off_t_width = 1;
1430 for (o = OFF_T_MAX; 9 < o; o /= 10) {
1431 positive_off_t_width++;
1434 if (first_time && method >= 0) {
1437 printf("method crc date time ");
1440 printf("%*.*s %*.*s ratio uncompressed_name\n",
1441 positive_off_t_width, positive_off_t_width, "compressed",
1442 positive_off_t_width, positive_off_t_width, "uncompressed");
1444 } else if (method < 0) {
1445 if (total_in <= 0 || total_out <= 0) return;
1449 if (verbose || !quiet) {
1450 fprint_off(stdout, total_in, positive_off_t_width);
1452 fprint_off(stdout, total_out, positive_off_t_width);
1455 display_ratio(total_out-(total_in-header_bytes), total_out, stdout);
1456 /* header_bytes is not meaningful but used to ensure the same
1457 * ratio if there is a single file.
1459 printf(" (totals)\n");
1462 crc = (ulg)~0; /* unknown */
1464 bytes_in = ifile_size;
1467 if (method == DEFLATED && !last_member) {
1468 /* Get the crc and uncompressed size for gzip'ed (not zip'ed) files.
1469 * If the lseek fails, we could use read() to get to the end, but
1470 * --list is used to get quick results.
1471 * Use "gunzip < foo.gz | wc -c" to get the uncompressed size if
1472 * you are not concerned about speed.
1474 bytes_in = lseek(ifd, (off_t)(-8), SEEK_END);
1475 if (bytes_in != -1L) {
1478 if (read(ifd, (char*)buf, sizeof(buf)) != sizeof(buf)) {
1482 bytes_out = LG(buf+4);
1485 #endif /* RECORD_IO */
1486 date = ctime((time_t*)&time_stamp) + 4; /* skip the day of the week */
1487 date[12] = '\0'; /* suppress the 1/100sec and the year */
1489 printf("%5s %08lx %11s ", methods[method], crc, date);
1491 fprint_off(stdout, bytes_in, positive_off_t_width);
1493 fprint_off(stdout, bytes_out, positive_off_t_width);
1495 if (bytes_in == -1L) {
1497 bytes_in = bytes_out = header_bytes = 0;
1498 } else if (total_in >= 0) {
1499 total_in += bytes_in;
1501 if (bytes_out == -1L) {
1503 bytes_in = bytes_out = header_bytes = 0;
1504 } else if (total_out >= 0) {
1505 total_out += bytes_out;
1507 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out, stdout);
1508 printf(" %s\n", ofname);
1511 /* ========================================================================
1512 * Return true if the two stat structures correspond to the same file.
1514 local int same_file(stat1, stat2)
1518 return stat1->st_ino == stat2->st_ino
1519 && stat1->st_dev == stat2->st_dev
1521 /* Can't rely on st_ino and st_dev, use other fields: */
1522 && stat1->st_mode == stat2->st_mode
1523 && stat1->st_uid == stat2->st_uid
1524 && stat1->st_gid == stat2->st_gid
1525 && stat1->st_size == stat2->st_size
1526 && stat1->st_atime == stat2->st_atime
1527 && stat1->st_mtime == stat2->st_mtime
1528 && stat1->st_ctime == stat2->st_ctime
1533 /* ========================================================================
1534 * Return true if a file name is ambiguous because the operating system
1535 * truncates file names.
1537 local int name_too_long(name, statb)
1538 char *name; /* file name to check */
1539 struct stat *statb; /* stat buf for this file name */
1541 int s = strlen(name);
1543 struct stat tstat; /* stat for truncated name */
1546 tstat = *statb; /* Just in case OS does not fill all fields */
1548 res = stat(name, &tstat) == 0 && same_file(statb, &tstat);
1550 Trace((stderr, " too_long(%s) => %d\n", name, res));
1554 /* ========================================================================
1555 * Shorten the given name by one character, or replace a .tar extension
1556 * with .tgz. Truncate the last part of the name which is longer than
1557 * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
1558 * has only parts shorter than MIN_PART truncate the longest part.
1559 * For decompression, just remove the last character of the name.
1561 * IN assertion: for compression, the suffix of the given name is z_suffix.
1563 local void shorten_name(name)
1566 int len; /* length of name without z_suffix */
1567 char *trunc = NULL; /* character to be truncated */
1568 int plen; /* current part length */
1569 int min_part = MIN_PART; /* current minimum part length */
1574 if (len <= 1) error("name too short");
1578 p = get_suffix(name);
1579 if (p == NULL) error("can't recover suffix\n");
1583 /* compress 1234567890.tar to 1234567890.tgz */
1584 if (len > 4 && strequ(p-4, ".tar")) {
1585 strcpy(p-4, ".tgz");
1588 /* Try keeping short extensions intact:
1589 * 1234.678.012.gz -> 123.678.012.gz
1592 p = strrchr(name, PATH_SEP);
1595 plen = strcspn(p, PART_SEP);
1597 if (plen > min_part) trunc = p-1;
1600 } while (trunc == NULL && --min_part != 0);
1602 if (trunc != NULL) {
1604 trunc[0] = trunc[1];
1608 trunc = strrchr(name, PART_SEP[0]);
1609 if (trunc == NULL) error("internal error in shorten_name");
1610 if (trunc[1] == '\0') trunc--; /* force truncation */
1612 strcpy(trunc, z_suffix);
1615 /* ========================================================================
1616 * If compressing to a file, check if ofname is not ambiguous
1617 * because the operating system truncates names. Otherwise, generate
1618 * a new ofname and save the original name in the compressed file.
1619 * If the compressed file already exists, ask for confirmation.
1620 * The check for name truncation is made dynamically, because different
1621 * file systems on the same OS might use different truncation rules (on SVR4
1622 * s5 truncates to 14 chars and ufs does not truncate).
1623 * This function returns -1 if the file must be skipped, and
1624 * updates save_orig_name if necessary.
1625 * IN assertions: save_orig_name is already set if ofname has been
1626 * already truncated because of NO_MULTIPLE_DOTS. The input file has
1627 * already been open and istat is set.
1629 local int check_ofname()
1631 struct stat ostat; /* stat for ofname */
1634 /* Check for strictly conforming Posix systems (which return ENAMETOOLONG
1635 * instead of silently truncating filenames).
1638 while (stat(ofname, &ostat) != 0) {
1639 if (errno != ENAMETOOLONG) return 0; /* ofname does not exist */
1640 shorten_name(ofname);
1643 if (stat(ofname, &ostat) != 0) return 0;
1645 /* Check for name truncation on existing file. Do this even on systems
1646 * defining ENAMETOOLONG, because on most systems the strict Posix
1647 * behavior is disabled by default (silent name truncation allowed).
1649 if (!decompress && name_too_long(ofname, &ostat)) {
1650 shorten_name(ofname);
1651 if (stat(ofname, &ostat) != 0) return 0;
1654 /* Check that the input and output files are different (could be
1655 * the same by name truncation or links).
1657 if (same_file(&istat, &ostat)) {
1658 if (strequ(ifname, ofname)) {
1659 fprintf(stderr, "%s: %s: cannot %scompress onto itself\n",
1660 progname, ifname, decompress ? "de" : "");
1662 fprintf(stderr, "%s: %s and %s are the same file\n",
1663 progname, ifname, ofname);
1668 /* Ask permission to overwrite the existing file */
1671 fprintf(stderr, "%s: %s already exists;", progname, ofname);
1672 if (foreground && isatty(fileno(stdin))) {
1673 fprintf(stderr, " do you wish to overwrite (y or n)? ");
1678 fprintf(stderr, "\tnot overwritten\n");
1679 if (exit_code == OK) exit_code = WARNING;
1683 if (xunlink (ofname)) {
1692 /* ========================================================================
1693 * Set the access and modification times from the given stat buffer.
1695 local void reset_times (name, statb)
1699 struct utimbuf timep;
1701 /* Copy the time stamp */
1702 timep.actime = statb->st_atime;
1703 timep.modtime = statb->st_mtime;
1705 /* Some systems (at least OS/2) do not support utime on directories */
1706 if (utime(name, &timep) && !S_ISDIR(statb->st_mode)) {
1708 WARN((stderr, "%s: ", progname));
1718 /* ========================================================================
1719 * Copy modes, times, ownership from input file to output file.
1720 * IN assertion: to_stdout is false.
1722 local void copy_stat(ifstat)
1723 struct stat *ifstat;
1726 if (decompress && time_stamp != 0 && ifstat->st_mtime != time_stamp) {
1727 ifstat->st_mtime = time_stamp;
1729 fprintf(stderr, "%s: time stamp restored\n", ofname);
1732 reset_times(ofname, ifstat);
1734 /* Copy the protection modes */
1735 if (fchmod(ofd, ifstat->st_mode & 07777)) {
1737 WARN((stderr, "%s: ", progname));
1744 (void) fchown(ofd, ifstat->st_uid, ifstat->st_gid); /* Copy ownership */
1747 /* It's now safe to remove the input file: */
1748 if (xunlink (ifname)) {
1750 WARN((stderr, "%s: ", progname));
1760 /* ========================================================================
1761 * Recurse through the given directory. This code is taken from ncompress.
1763 local void treat_dir(dir)
1768 char nbuf[MAX_PATH_LEN];
1771 dirp = opendir(dir);
1778 ** WARNING: the following algorithm could occasionally cause
1779 ** compress to produce error warnings of the form "<filename>.gz
1780 ** already has .gz suffix - ignored". This occurs when the
1781 ** .gz output file is inserted into the directory below
1782 ** readdir's current pointer.
1783 ** These warnings are harmless but annoying, so they are suppressed
1784 ** with option -r (except when -v is on). An alternative
1785 ** to allowing this would be to store the entire directory
1786 ** list in memory, then compress the entries in the stored
1787 ** list. Given the depth-first recursive algorithm used here,
1788 ** this could use up a tremendous amount of memory. I don't
1789 ** think it's worth it. -- Dave Mack
1790 ** (An other alternative might be two passes to avoid depth-first.)
1793 while ((errno = 0, dp = readdir(dirp)) != NULL) {
1795 if (strequ(dp->d_name,".") || strequ(dp->d_name,"..")) {
1799 if (len + NAMLEN(dp) + 1 < MAX_PATH_LEN - 1) {
1801 if (len != 0 /* dir = "" means current dir on Amiga */
1803 && dir[len-1] != PATH_SEP2
1806 && dir[len-1] != PATH_SEP3
1809 nbuf[len++] = PATH_SEP;
1811 strcpy(nbuf+len, dp->d_name);
1814 fprintf(stderr,"%s: %s/%s: pathname too long\n",
1815 progname, dir, dp->d_name);
1821 if (CLOSEDIR(dirp) != 0)
1824 #endif /* ? NO_DIR */
1826 /* ========================================================================
1827 * Free all dynamically allocated variables and exit with the given code.
1829 local void do_exit(exitcode)
1832 static int in_exit = 0;
1834 if (in_exit) exit(exitcode);
1836 if (env != NULL) free(env), env = NULL;
1837 if (args != NULL) free((char*)args), args = NULL;
1851 /* ========================================================================
1852 * Signal and error handler.
1854 RETSIGTYPE abort_gzip()
1856 if (remove_ofname) {