1/* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface 2 * Copyright (C) 1992-1993 Jean-loup Gailly 3 * The unzip code was written and put in the public domain by Mark Adler. 4 * Portions of the lzw code are derived from the public domain 'compress' 5 * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies, 6 * Ken Turkowski, Dave Mack and Peter Jannesen. 7 * 8 * See the license_msg below and the file COPYING for the software license. 9 * See the file algorithm.doc for the compression algorithms and file formats. 10 */ 11 12static char *license_msg[] = { 13" Copyright (C) 1992-1993 Jean-loup Gailly", 14" This program is free software; you can redistribute it and/or modify", 15" it under the terms of the GNU General Public License as published by", 16" the Free Software Foundation; either version 2, or (at your option)", 17" any later version.", 18"", 19" This program is distributed in the hope that it will be useful,", 20" but WITHOUT ANY WARRANTY; without even the implied warranty of", 21" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", 22" GNU General Public License for more details.", 23"", 24" You should have received a copy of the GNU General Public License", 25" along with this program; if not, write to the Free Software", 26" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.", 270}; 28 29/* Compress files with zip algorithm and 'compress' interface. 30 * See usage() and help() functions below for all options. 31 * Outputs: 32 * file.gz: compressed file with same mode, owner, and utimes 33 * or stdout with -c option or if stdin used as input. 34 * If the output file name had to be truncated, the original name is kept 35 * in the compressed file. 36 * On MSDOS, file.tmp -> file.tmz. On VMS, file.tmp -> file.tmp-gz. 37 * 38 * Using gz on MSDOS would create too many file name conflicts. For 39 * example, foo.txt -> foo.tgz (.tgz must be reserved as shorthand for 40 * tar.gz). Similarly, foo.dir and foo.doc would both be mapped to foo.dgz. 41 * I also considered 12345678.txt -> 12345txt.gz but this truncates the name 42 * too heavily. There is no ideal solution given the MSDOS 8+3 limitation. 43 * 44 * For the meaning of all compilation flags, see comments in Makefile.in. 45 */ 46 47#ifdef RCSID 48static char rcsid[] = "$Id: gzip.c 27050 2008-08-18 21:16:33Z korli $"; 49#endif 50 51#include <ctype.h> 52#include <sys/types.h> 53#include <signal.h> 54#include <sys/stat.h> 55#include <errno.h> 56 57#include "tailor.h" 58#include "gzip.h" 59#include "lzw.h" 60#include "revision.h" 61#include "getopt.h" 62 63 /* configuration */ 64 65#ifdef NO_TIME_H 66# include <sys/time.h> 67#else 68# include <time.h> 69#endif 70 71#ifndef NO_FCNTL_H 72# include <fcntl.h> 73#endif 74 75#ifdef HAVE_UNISTD_H 76# include <unistd.h> 77#endif 78 79#if defined(STDC_HEADERS) || !defined(NO_STDLIB_H) 80# include <stdlib.h> 81#else 82 extern int errno; 83#endif 84 85#if defined(DIRENT) 86# include <dirent.h> 87 typedef struct dirent dir_type; 88# define NLENGTH(dirent) ((int)strlen((dirent)->d_name)) 89# define DIR_OPT "DIRENT" 90#else 91# define NLENGTH(dirent) ((dirent)->d_namlen) 92# ifdef SYSDIR 93# include <sys/dir.h> 94 typedef struct direct dir_type; 95# define DIR_OPT "SYSDIR" 96# else 97# ifdef SYSNDIR 98# include <sys/ndir.h> 99 typedef struct direct dir_type; 100# define DIR_OPT "SYSNDIR" 101# else 102# ifdef NDIR 103# include <ndir.h> 104 typedef struct direct dir_type; 105# define DIR_OPT "NDIR" 106# else 107# define NO_DIR 108# define DIR_OPT "NO_DIR" 109# endif 110# endif 111# endif 112#endif 113 114#ifndef NO_UTIME 115# ifndef NO_UTIME_H 116# include <utime.h> 117# define TIME_OPT "UTIME" 118# else 119# ifdef HAVE_SYS_UTIME_H 120# include <sys/utime.h> 121# define TIME_OPT "SYS_UTIME" 122# else 123 struct utimbuf { 124 time_t actime; 125 time_t modtime; 126 }; 127# define TIME_OPT "" 128# endif 129# endif 130#else 131# define TIME_OPT "NO_UTIME" 132#endif 133 134#if !defined(S_ISDIR) && defined(S_IFDIR) 135# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) 136#endif 137#if !defined(S_ISREG) && defined(S_IFREG) 138# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) 139#endif 140 141typedef RETSIGTYPE (*sig_type) OF((int)); 142 143#ifndef O_BINARY 144# define O_BINARY 0 /* creation mode for open() */ 145#endif 146 147#ifndef O_CREAT 148 /* Pure BSD system? */ 149# include <sys/file.h> 150# ifndef O_CREAT 151# define O_CREAT FCREAT 152# endif 153# ifndef O_EXCL 154# define O_EXCL FEXCL 155# endif 156#endif 157 158#ifndef S_IRUSR 159# define S_IRUSR 0400 160#endif 161#ifndef S_IWUSR 162# define S_IWUSR 0200 163#endif 164#define RW_USER (S_IRUSR | S_IWUSR) /* creation mode for open() */ 165 166#ifndef MAX_PATH_LEN 167# define MAX_PATH_LEN 1024 /* max pathname length */ 168#endif 169 170#ifndef SEEK_END 171# define SEEK_END 2 172#endif 173 174#ifdef NO_OFF_T 175 typedef long off_t; 176 off_t lseek OF((int fd, off_t offset, int whence)); 177#endif 178 179/* Separator for file name parts (see shorten_name()) */ 180#ifdef NO_MULTIPLE_DOTS 181# define PART_SEP "-" 182#else 183# define PART_SEP "." 184#endif 185 186 /* global buffers */ 187 188DECLARE(uch, inbuf, INBUFSIZ +INBUF_EXTRA); 189DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA); 190DECLARE(ush, d_buf, DIST_BUFSIZE); 191DECLARE(uch, window, 2L*WSIZE); 192#ifndef MAXSEG_64K 193 DECLARE(ush, tab_prefix, 1L<<BITS); 194#else 195 DECLARE(ush, tab_prefix0, 1L<<(BITS-1)); 196 DECLARE(ush, tab_prefix1, 1L<<(BITS-1)); 197#endif 198 199 /* local variables */ 200 201int ascii = 0; /* convert end-of-lines to local OS conventions */ 202int to_stdout = 0; /* output to stdout (-c) */ 203int decompress = 0; /* decompress (-d) */ 204int force = 0; /* don't ask questions, compress links (-f) */ 205int no_name = -1; /* don't save or restore the original file name */ 206int no_time = -1; /* don't save or restore the original file time */ 207int recursive = 0; /* recurse through directories (-r) */ 208int list = 0; /* list the file contents (-l) */ 209int verbose = 0; /* be verbose (-v) */ 210int quiet = 0; /* be very quiet (-q) */ 211int do_lzw = 0; /* generate output compatible with old compress (-Z) */ 212int test = 0; /* test .gz file integrity */ 213int foreground; /* set if program run in foreground */ 214char *progname; /* program name */ 215int maxbits = BITS; /* max bits per code for LZW */ 216int method = DEFLATED;/* compression method */ 217int level = 6; /* compression level */ 218int exit_code = OK; /* program exit code */ 219int save_orig_name; /* set if original name must be saved */ 220int last_member; /* set for .zip and .Z files */ 221int part_nb; /* number of parts in .gz file */ 222long time_stamp; /* original time stamp (modification time) */ 223long ifile_size; /* input file size, -1 for devices (debug only) */ 224char *env; /* contents of GZIP env variable */ 225char **args = NULL; /* argv pointer if GZIP env variable defined */ 226char z_suffix[MAX_SUFFIX+1]; /* default suffix (can be set with --suffix) */ 227int z_len; /* strlen(z_suffix) */ 228 229long bytes_in; /* number of input bytes */ 230long bytes_out; /* number of output bytes */ 231long total_in = 0; /* input bytes for all files */ 232long total_out = 0; /* output bytes for all files */ 233char ifname[MAX_PATH_LEN]; /* input file name */ 234char ofname[MAX_PATH_LEN]; /* output file name */ 235int remove_ofname = 0; /* remove output file on error */ 236struct stat istat; /* status for input file */ 237int ifd; /* input file descriptor */ 238int ofd; /* output file descriptor */ 239unsigned insize; /* valid bytes in inbuf */ 240unsigned inptr; /* index of next byte to be processed in inbuf */ 241unsigned outcnt; /* bytes in output buffer */ 242 243struct option longopts[] = 244{ 245 /* { name has_arg *flag val } */ 246 {"ascii", 0, 0, 'a'}, /* ascii text mode */ 247 {"to-stdout", 0, 0, 'c'}, /* write output on standard output */ 248 {"stdout", 0, 0, 'c'}, /* write output on standard output */ 249 {"decompress", 0, 0, 'd'}, /* decompress */ 250 {"uncompress", 0, 0, 'd'}, /* decompress */ 251 /* {"encrypt", 0, 0, 'e'}, encrypt */ 252 {"force", 0, 0, 'f'}, /* force overwrite of output file */ 253 {"help", 0, 0, 'h'}, /* give help */ 254 /* {"pkzip", 0, 0, 'k'}, force output in pkzip format */ 255 {"list", 0, 0, 'l'}, /* list .gz file contents */ 256 {"license", 0, 0, 'L'}, /* display software license */ 257 {"no-name", 0, 0, 'n'}, /* don't save or restore original name & time */ 258 {"name", 0, 0, 'N'}, /* save or restore original name & time */ 259 {"quiet", 0, 0, 'q'}, /* quiet mode */ 260 {"silent", 0, 0, 'q'}, /* quiet mode */ 261 {"recursive", 0, 0, 'r'}, /* recurse through directories */ 262 {"suffix", 1, 0, 'S'}, /* use given suffix instead of .gz */ 263 {"test", 0, 0, 't'}, /* test compressed file integrity */ 264 {"no-time", 0, 0, 'T'}, /* don't save or restore the time stamp */ 265 {"verbose", 0, 0, 'v'}, /* verbose mode */ 266 {"version", 0, 0, 'V'}, /* display version number */ 267 {"fast", 0, 0, '1'}, /* compress faster */ 268 {"best", 0, 0, '9'}, /* compress better */ 269 {"lzw", 0, 0, 'Z'}, /* make output compatible with old compress */ 270 {"bits", 1, 0, 'b'}, /* max number of bits per code (implies -Z) */ 271 { 0, 0, 0, 0 } 272}; 273 274/* local functions */ 275 276local void usage OF((void)); 277local void help OF((void)); 278local void license OF((void)); 279local void version OF((void)); 280local void treat_stdin OF((void)); 281local void treat_file OF((char *iname)); 282local int create_outfile OF((void)); 283local int do_stat OF((char *name, struct stat *sbuf)); 284local char *get_suffix OF((char *name)); 285local int get_istat OF((char *iname, struct stat *sbuf)); 286local int make_ofname OF((void)); 287local int same_file OF((struct stat *stat1, struct stat *stat2)); 288local int name_too_long OF((char *name, struct stat *statb)); 289local void shorten_name OF((char *name)); 290local int get_method OF((int in)); 291local void do_list OF((int ifd, int method)); 292local int check_ofname OF((void)); 293local void copy_stat OF((struct stat *ifstat)); 294local void do_exit OF((int exitcode)); 295 int main OF((int argc, char **argv)); 296int (*work) OF((int infile, int outfile)) = zip; /* function to call */ 297 298#ifndef NO_DIR 299local void treat_dir OF((char *dir)); 300#endif 301#ifndef NO_UTIME 302local void reset_times OF((char *name, struct stat *statb)); 303#endif 304 305#define strequ(s1, s2) (strcmp((s1),(s2)) == 0) 306 307/* ======================================================================== */ 308local void usage() 309{ 310 fprintf(stderr, "usage: %s [-%scdfhlLnN%stvV19] [-S suffix] [file ...]\n", 311 progname, 312#if O_BINARY 313 "a", 314#else 315 "", 316#endif 317#ifdef NO_DIR 318 "" 319#else 320 "r" 321#endif 322 ); 323} 324 325/* ======================================================================== */ 326local void help() 327{ 328 static char *help_msg[] = { 329#if O_BINARY 330 " -a --ascii ascii text; convert end-of-lines using local conventions", 331#endif 332 " -c --stdout write on standard output, keep original files unchanged", 333 " -d --decompress decompress", 334/* -e --encrypt encrypt */ 335 " -f --force force overwrite of output file and compress links", 336 " -h --help give this help", 337/* -k --pkzip force output in pkzip format */ 338 " -l --list list compressed file contents", 339 " -L --license display software license", 340#ifdef UNDOCUMENTED 341 " -m --no-time do not save or restore the original modification time", 342 " -M --time save or restore the original modification time", 343#endif 344 " -n --no-name do not save or restore the original name and time stamp", 345 " -N --name save or restore the original name and time stamp", 346 " -q --quiet suppress all warnings", 347#ifndef NO_DIR 348 " -r --recursive operate recursively on directories", 349#endif 350 " -S .suf --suffix .suf use suffix .suf on compressed files", 351 " -t --test test compressed file integrity", 352 " -v --verbose verbose mode", 353 " -V --version display version number", 354 " -1 --fast compress faster", 355 " -9 --best compress better", 356#ifdef LZW 357 " -Z --lzw produce output compatible with old compress", 358 " -b --bits maxbits max number of bits per code (implies -Z)", 359#endif 360 " file... files to (de)compress. If none given, use standard input.", 361 0}; 362 char **p = help_msg; 363 364 fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE); 365 usage(); 366 while (*p) fprintf(stderr, "%s\n", *p++); 367} 368 369/* ======================================================================== */ 370local void license() 371{ 372 char **p = license_msg; 373 374 fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE); 375 while (*p) fprintf(stderr, "%s\n", *p++); 376} 377 378/* ======================================================================== */ 379local void version() 380{ 381 fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE); 382 383 fprintf(stderr, "Compilation options:\n%s %s ", DIR_OPT, TIME_OPT); 384#ifdef STDC_HEADERS 385 fprintf(stderr, "STDC_HEADERS "); 386#endif 387#ifdef HAVE_UNISTD_H 388 fprintf(stderr, "HAVE_UNISTD_H "); 389#endif 390#ifdef NO_MEMORY_H 391 fprintf(stderr, "NO_MEMORY_H "); 392#endif 393#ifdef NO_STRING_H 394 fprintf(stderr, "NO_STRING_H "); 395#endif 396#ifdef NO_SYMLINK 397 fprintf(stderr, "NO_SYMLINK "); 398#endif 399#ifdef NO_MULTIPLE_DOTS 400 fprintf(stderr, "NO_MULTIPLE_DOTS "); 401#endif 402#ifdef NO_CHOWN 403 fprintf(stderr, "NO_CHOWN "); 404#endif 405#ifdef PROTO 406 fprintf(stderr, "PROTO "); 407#endif 408#ifdef ASMV 409 fprintf(stderr, "ASMV "); 410#endif 411#ifdef DEBUG 412 fprintf(stderr, "DEBUG "); 413#endif 414#ifdef DYN_ALLOC 415 fprintf(stderr, "DYN_ALLOC "); 416#endif 417#ifdef MAXSEG_64K 418 fprintf(stderr, "MAXSEG_64K"); 419#endif 420 fprintf(stderr, "\n"); 421} 422 423/* ======================================================================== */ 424int main (argc, argv) 425 int argc; 426 char **argv; 427{ 428 int file_count; /* number of files to precess */ 429 int proglen; /* length of progname */ 430 int optc; /* current option */ 431 432 EXPAND(argc, argv); /* wild card expansion if necessary */ 433 434 progname = our_basename(argv[0]); 435 proglen = strlen(progname); 436 437 /* Suppress .exe for MSDOS, OS/2 and VMS: */ 438 if (proglen > 4 && strequ(progname+proglen-4, ".exe")) { 439 progname[proglen-4] = '\0'; 440 } 441 442 /* Add options in GZIP environment variable if there is one */ 443 env = add_envopt(&argc, &argv, OPTIONS_VAR); 444 if (env != NULL) args = argv; 445 446 foreground = signal(SIGINT, SIG_IGN) != SIG_IGN; 447 if (foreground) { 448 (void) signal (SIGINT, (sig_type)abort_gzip); 449 } 450#ifdef SIGTERM 451 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { 452 (void) signal(SIGTERM, (sig_type)abort_gzip); 453 } 454#endif 455#ifdef SIGHUP 456 if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { 457 (void) signal(SIGHUP, (sig_type)abort_gzip); 458 } 459#endif 460 461#ifndef GNU_STANDARD 462 /* For compatibility with old compress, use program name as an option. 463 * If you compile with -DGNU_STANDARD, this program will behave as 464 * gzip even if it is invoked under the name gunzip or zcat. 465 * 466 * Systems which do not support links can still use -d or -dc. 467 * Ignore an .exe extension for MSDOS, OS/2 and VMS. 468 */ 469 if ( strncmp(progname, "un", 2) == 0 /* ungzip, uncompress */ 470 || strncmp(progname, "gun", 3) == 0) { /* gunzip */ 471 decompress = 1; 472 } else if (strequ(progname+1, "cat") /* zcat, pcat, gcat */ 473 || strequ(progname, "gzcat")) { /* gzcat */ 474 decompress = to_stdout = 1; 475 } 476#endif 477 478 strncpy(z_suffix, Z_SUFFIX, sizeof(z_suffix)-1); 479 z_len = strlen(z_suffix); 480 481 while ((optc = getopt_long (argc, argv, "ab:cdfhH?lLmMnNqrS:tvVZ123456789", 482 longopts, (int *)0)) != EOF) { 483 switch (optc) { 484 case 'a': 485 ascii = 1; break; 486 case 'b': 487 maxbits = atoi(optarg); 488 break; 489 case 'c': 490 to_stdout = 1; break; 491 case 'd': 492 decompress = 1; break; 493 case 'f': 494 force++; break; 495 case 'h': case 'H': case '?': 496 help(); do_exit(OK); break; 497 case 'l': 498 list = decompress = to_stdout = 1; break; 499 case 'L': 500 license(); do_exit(OK); break; 501 case 'm': /* undocumented, may change later */ 502 no_time = 1; break; 503 case 'M': /* undocumented, may change later */ 504 no_time = 0; break; 505 case 'n': 506 no_name = no_time = 1; break; 507 case 'N': 508 no_name = no_time = 0; break; 509 case 'q': 510 quiet = 1; verbose = 0; break; 511 case 'r': 512#ifdef NO_DIR 513 fprintf(stderr, "%s: -r not supported on this system\n", progname); 514 usage(); 515 do_exit(ERROR); break; 516#else 517 recursive = 1; break; 518#endif 519 case 'S': 520#ifdef NO_MULTIPLE_DOTS 521 if (*optarg == '.') optarg++; 522#endif 523 z_len = strlen(optarg); 524 strcpy(z_suffix, optarg); 525 break; 526 case 't': 527 test = decompress = to_stdout = 1; 528 break; 529 case 'v': 530 verbose++; quiet = 0; break; 531 case 'V': 532 version(); do_exit(OK); break; 533 case 'Z': 534#ifdef LZW 535 do_lzw = 1; break; 536#else 537 fprintf(stderr, "%s: -Z not supported in this version\n", 538 progname); 539 usage(); 540 do_exit(ERROR); break; 541#endif 542 case '1': case '2': case '3': case '4': 543 case '5': case '6': case '7': case '8': case '9': 544 level = optc - '0'; 545 break; 546 default: 547 /* Error message already emitted by getopt_long. */ 548 usage(); 549 do_exit(ERROR); 550 } 551 } /* loop on all arguments */ 552 553 /* By default, save name and timestamp on compression but do not 554 * restore them on decompression. 555 */ 556 if (no_time < 0) no_time = decompress; 557 if (no_name < 0) no_name = decompress; 558 559 file_count = argc - optind; 560 561#if O_BINARY 562#else 563 if (ascii && !quiet) { 564 fprintf(stderr, "%s: option --ascii ignored on this system\n", 565 progname); 566 } 567#endif 568 if ((z_len == 0 && !decompress) || z_len > MAX_SUFFIX) { 569 fprintf(stderr, "%s: incorrect suffix '%s'\n", 570 progname, optarg); 571 do_exit(ERROR); 572 } 573 if (do_lzw && !decompress) work = lzw; 574 575 /* Allocate all global buffers (for DYN_ALLOC option) */ 576 ALLOC(uch, inbuf, INBUFSIZ +INBUF_EXTRA); 577 ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA); 578 ALLOC(ush, d_buf, DIST_BUFSIZE); 579 ALLOC(uch, window, 2L*WSIZE); 580#ifndef MAXSEG_64K 581 ALLOC(ush, tab_prefix, 1L<<BITS); 582#else 583 ALLOC(ush, tab_prefix0, 1L<<(BITS-1)); 584 ALLOC(ush, tab_prefix1, 1L<<(BITS-1)); 585#endif 586 587 /* And get to work */ 588 if (file_count != 0) { 589 if (to_stdout && !test && !list && (!decompress || !ascii)) { 590 SET_BINARY_MODE(fileno(stdout)); 591 } 592 while (optind < argc) { 593 treat_file(argv[optind++]); 594 } 595 } else { /* Standard input */ 596 treat_stdin(); 597 } 598 if (list && !quiet && file_count > 1) { 599 do_list(-1, -1); /* print totals */ 600 } 601 do_exit(exit_code); 602 return exit_code; /* just to avoid lint warning */ 603} 604 605/* ======================================================================== 606 * Compress or decompress stdin 607 */ 608local void treat_stdin() 609{ 610 if (!force && !list && 611 isatty(fileno((FILE *)(decompress ? stdin : stdout)))) { 612 /* Do not send compressed data to the terminal or read it from 613 * the terminal. We get here when user invoked the program 614 * without parameters, so be helpful. According to the GNU standards: 615 * 616 * If there is one behavior you think is most useful when the output 617 * is to a terminal, and another that you think is most useful when 618 * the output is a file or a pipe, then it is usually best to make 619 * the default behavior the one that is useful with output to a 620 * terminal, and have an option for the other behavior. 621 * 622 * Here we use the --force option to get the other behavior. 623 */ 624 fprintf(stderr, 625 "%s: compressed data not %s a terminal. Use -f to force %scompression.\n", 626 progname, decompress ? "read from" : "written to", 627 decompress ? "de" : ""); 628 fprintf(stderr,"For help, type: %s -h\n", progname); 629 do_exit(ERROR); 630 } 631 632 if (decompress || !ascii) { 633 SET_BINARY_MODE(fileno(stdin)); 634 } 635 if (!test && !list && (!decompress || !ascii)) { 636 SET_BINARY_MODE(fileno(stdout)); 637 } 638 strcpy(ifname, "stdin"); 639 strcpy(ofname, "stdout"); 640 641 /* Get the time stamp on the input file. */ 642 time_stamp = 0; /* time unknown by default */ 643 644#ifndef NO_STDIN_FSTAT 645 if (list || !no_time) { 646 if (fstat(fileno(stdin), &istat) != 0) { 647 error("fstat(stdin)"); 648 } 649# ifdef NO_PIPE_TIMESTAMP 650 if (S_ISREG(istat.st_mode)) 651# endif 652 time_stamp = istat.st_mtime; 653#endif /* NO_STDIN_FSTAT */ 654 } 655 ifile_size = -1L; /* convention for unknown size */ 656 657 clear_bufs(); /* clear input and output buffers */ 658 to_stdout = 1; 659 part_nb = 0; 660 661 if (decompress) { 662 method = get_method(ifd); 663 if (method < 0) { 664 do_exit(exit_code); /* error message already emitted */ 665 } 666 } 667 if (list) { 668 do_list(ifd, method); 669 return; 670 } 671 672 /* Actually do the compression/decompression. Loop over zipped members. 673 */ 674 for (;;) { 675 if ((*work)(fileno(stdin), fileno(stdout)) != OK) return; 676 677 if (!decompress || last_member || inptr == insize) break; 678 /* end of file */ 679 680 method = get_method(ifd); 681 if (method < 0) return; /* error message already emitted */ 682 bytes_out = 0; /* required for length check */ 683 } 684 685 if (verbose) { 686 if (test) { 687 fprintf(stderr, " OK\n"); 688 689 } else if (!decompress) { 690 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr); 691 fprintf(stderr, "\n"); 692#ifdef DISPLAY_STDIN_RATIO 693 } else { 694 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr); 695 fprintf(stderr, "\n"); 696#endif 697 } 698 } 699} 700 701/* ======================================================================== 702 * Compress or decompress the given file 703 */ 704local void treat_file(iname) 705 char *iname; 706{ 707 /* Accept "-" as synonym for stdin */ 708 if (strequ(iname, "-")) { 709 int cflag = to_stdout; 710 treat_stdin(); 711 to_stdout = cflag; 712 return; 713 } 714 715 /* Check if the input file is present, set ifname and istat: */ 716 if (get_istat(iname, &istat) != OK) return; 717 718 /* If the input name is that of a directory, recurse or ignore: */ 719 if (S_ISDIR(istat.st_mode)) { 720#ifndef NO_DIR 721 if (recursive) { 722 struct stat st; 723 st = istat; 724 treat_dir(iname); 725 /* Warning: ifname is now garbage */ 726# ifndef NO_UTIME 727 reset_times (iname, &st); 728# endif 729 } else 730#endif 731 WARN((stderr,"%s: %s is a directory -- ignored\n", progname, ifname)); 732 return; 733 } 734 if (!S_ISREG(istat.st_mode)) { 735 WARN((stderr, 736 "%s: %s is not a directory or a regular file - ignored\n", 737 progname, ifname)); 738 return; 739 } 740 if (istat.st_nlink > 1 && !to_stdout && !force) { 741 WARN((stderr, "%s: %s has %d other link%c -- unchanged\n", 742 progname, ifname, 743 (int)istat.st_nlink - 1, istat.st_nlink > 2 ? 's' : ' ')); 744 return; 745 } 746 747 ifile_size = istat.st_size; 748 time_stamp = no_time && !list ? 0 : istat.st_mtime; 749 750 /* Generate output file name. For -r and (-t or -l), skip files 751 * without a valid gzip suffix (check done in make_ofname). 752 */ 753 if (to_stdout && !list && !test) { 754 strcpy(ofname, "stdout"); 755 756 } else if (make_ofname() != OK) { 757 return; 758 } 759 760 /* Open the input file and determine compression method. The mode 761 * parameter is ignored but required by some systems (VMS) and forbidden 762 * on other systems (MacOS). 763 */ 764 ifd = OPEN(ifname, ascii && !decompress ? O_RDONLY : O_RDONLY | O_BINARY, 765 RW_USER); 766 if (ifd == -1) { 767 fprintf(stderr, "%s: ", progname); 768 perror(ifname); 769 exit_code = ERROR; 770 return; 771 } 772 clear_bufs(); /* clear input and output buffers */ 773 part_nb = 0; 774 775 if (decompress) { 776 method = get_method(ifd); /* updates ofname if original given */ 777 if (method < 0) { 778 close(ifd); 779 return; /* error message already emitted */ 780 } 781 } 782 if (list) { 783 do_list(ifd, method); 784 close(ifd); 785 return; 786 } 787 788 /* If compressing to a file, check if ofname is not ambiguous 789 * because the operating system truncates names. Otherwise, generate 790 * a new ofname and save the original name in the compressed file. 791 */ 792 if (to_stdout) { 793 ofd = fileno(stdout); 794 /* keep remove_ofname as zero */ 795 } else { 796 if (create_outfile() != OK) return; 797 798 if (!decompress && save_orig_name && !verbose && !quiet) { 799 fprintf(stderr, "%s: %s compressed to %s\n", 800 progname, ifname, ofname); 801 } 802 } 803 /* Keep the name even if not truncated except with --no-name: */ 804 if (!save_orig_name) save_orig_name = !no_name; 805 806 if (verbose) { 807 fprintf(stderr, "%s:\t%s", ifname, (int)strlen(ifname) >= 15 ? 808 "" : ((int)strlen(ifname) >= 7 ? "\t" : "\t\t")); 809 } 810 811 /* Actually do the compression/decompression. Loop over zipped members. 812 */ 813 for (;;) { 814 if ((*work)(ifd, ofd) != OK) { 815 method = -1; /* force cleanup */ 816 break; 817 } 818 if (!decompress || last_member || inptr == insize) break; 819 /* end of file */ 820 821 method = get_method(ifd); 822 if (method < 0) break; /* error message already emitted */ 823 bytes_out = 0; /* required for length check */ 824 } 825 826 close(ifd); 827 if (!to_stdout && close(ofd)) { 828 write_error(); 829 } 830 if (method == -1) { 831 if (!to_stdout) unlink (ofname); 832 return; 833 } 834 /* Display statistics */ 835 if(verbose) { 836 if (test) { 837 fprintf(stderr, " OK"); 838 } else if (decompress) { 839 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr); 840 } else { 841 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr); 842 } 843 if (!test && !to_stdout) { 844 fprintf(stderr, " -- replaced with %s", ofname); 845 } 846 fprintf(stderr, "\n"); 847 } 848 /* Copy modes, times, ownership, and remove the input file */ 849 if (!to_stdout) { 850 copy_stat(&istat); 851 } 852} 853 854/* ======================================================================== 855 * Create the output file. Return OK or ERROR. 856 * Try several times if necessary to avoid truncating the z_suffix. For 857 * example, do not create a compressed file of name "1234567890123." 858 * Sets save_orig_name to true if the file name has been truncated. 859 * IN assertions: the input file has already been open (ifd is set) and 860 * ofname has already been updated if there was an original name. 861 * OUT assertions: ifd and ofd are closed in case of error. 862 */ 863local int create_outfile() 864{ 865 struct stat ostat; /* stat for ofname */ 866 int flags = O_WRONLY | O_CREAT | O_EXCL | O_BINARY; 867 868 if (ascii && decompress) { 869 flags &= ~O_BINARY; /* force ascii text mode */ 870 } 871 for (;;) { 872 /* Make sure that ofname is not an existing file */ 873 if (check_ofname() != OK) { 874 close(ifd); 875 return ERROR; 876 } 877 /* Create the output file */ 878 remove_ofname = 1; 879 ofd = OPEN(ofname, flags, RW_USER); 880 if (ofd == -1) { 881 perror(ofname); 882 close(ifd); 883 exit_code = ERROR; 884 return ERROR; 885 } 886 887 /* Check for name truncation on new file (1234567890123.gz) */ 888#ifdef NO_FSTAT 889 if (stat(ofname, &ostat) != 0) { 890#else 891 if (fstat(ofd, &ostat) != 0) { 892#endif 893 fprintf(stderr, "%s: ", progname); 894 perror(ofname); 895 close(ifd); close(ofd); 896 unlink(ofname); 897 exit_code = ERROR; 898 return ERROR; 899 } 900 if (!name_too_long(ofname, &ostat)) return OK; 901 902 if (decompress) { 903 /* name might be too long if an original name was saved */ 904 WARN((stderr, "%s: %s: warning, name truncated\n", 905 progname, ofname)); 906 return OK; 907 } 908 close(ofd); 909 unlink(ofname); 910#ifdef NO_MULTIPLE_DOTS 911 /* Should never happen, see check_ofname() */ 912 fprintf(stderr, "%s: %s: name too long\n", progname, ofname); 913 do_exit(ERROR); 914#endif 915 shorten_name(ofname); 916 } 917} 918 919/* ======================================================================== 920 * Use lstat if available, except for -c or -f. Use stat otherwise. 921 * This allows links when not removing the original file. 922 */ 923local int do_stat(name, sbuf) 924 char *name; 925 struct stat *sbuf; 926{ 927 errno = 0; 928#if (defined(S_IFLNK) || defined (S_ISLNK)) && !defined(NO_SYMLINK) 929 if (!to_stdout && !force) { 930 return lstat(name, sbuf); 931 } 932#endif 933 return stat(name, sbuf); 934} 935 936/* ======================================================================== 937 * Return a pointer to the 'z' suffix of a file name, or NULL. For all 938 * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are 939 * accepted suffixes, in addition to the value of the --suffix option. 940 * ".tgz" is a useful convention for tar.z files on systems limited 941 * to 3 characters extensions. On such systems, ".?z" and ".??z" are 942 * also accepted suffixes. For Unix, we do not want to accept any 943 * .??z suffix as indicating a compressed file; some people use .xyz 944 * to denote volume data. 945 * On systems allowing multiple versions of the same file (such as VMS), 946 * this function removes any version suffix in the given name. 947 */ 948local char *get_suffix(name) 949 char *name; 950{ 951 int nlen, slen; 952 char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */ 953 static char *known_suffixes[] = 954 {z_suffix, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z", 955#ifdef MAX_EXT_CHARS 956 "z", 957#endif 958 NULL}; 959 char **suf = known_suffixes; 960 961 if (strequ(z_suffix, "z")) suf++; /* check long suffixes first */ 962 963#ifdef SUFFIX_SEP 964 /* strip a version number from the file name */ 965 { 966 char *v = strrchr(name, SUFFIX_SEP); 967 if (v != NULL) *v = '\0'; 968 } 969#endif 970 nlen = strlen(name); 971 if (nlen <= MAX_SUFFIX+2) { 972 strcpy(suffix, name); 973 } else { 974 strcpy(suffix, name+nlen-MAX_SUFFIX-2); 975 } 976 strlwr(suffix); 977 slen = strlen(suffix); 978 do { 979 int s = strlen(*suf); 980 if (slen > s && suffix[slen-s-1] != PATH_SEP 981 && strequ(suffix + slen - s, *suf)) { 982 return name+nlen-s; 983 } 984 } while (*++suf != NULL); 985 986 return NULL; 987} 988 989 990/* ======================================================================== 991 * Set ifname to the input file name (with a suffix appended if necessary) 992 * and istat to its stats. For decompression, if no file exists with the 993 * original name, try adding successively z_suffix, .gz, .z, -z and .Z. 994 * For MSDOS, we try only z_suffix and z. 995 * Return OK or ERROR. 996 */ 997local int get_istat(iname, sbuf) 998 char *iname; 999 struct stat *sbuf; 1000{ 1001 int ilen; /* strlen(ifname) */ 1002 static char *suffixes[] = {z_suffix, ".gz", ".z", "-z", ".Z", NULL}; 1003 char **suf = suffixes; 1004 char *s; 1005#ifdef NO_MULTIPLE_DOTS 1006 char *dot; /* pointer to ifname extension, or NULL */ 1007#endif 1008 int max_suffix_len = (z_len > 3 ? z_len : 3); 1009 1010 /* Leave enough room in ifname or ofname for suffix: */ 1011 if (strlen(iname) >= sizeof(ifname) - max_suffix_len) { 1012 strncpy(ifname, iname, sizeof(ifname) - 1); 1013 /* last byte of ifname is already zero and never overwritten */ 1014 error("file name too long"); 1015 } 1016 strcpy(ifname, iname); 1017 1018 /* If input file exists, return OK. */ 1019 if (do_stat(ifname, sbuf) == 0) return OK; 1020 1021 if (!decompress || errno != ENOENT) { 1022 perror(ifname); 1023 exit_code = ERROR; 1024 return ERROR; 1025 } 1026 /* file.ext doesn't exist, try adding a suffix (after removing any 1027 * version number for VMS). 1028 */ 1029 s = get_suffix(ifname); 1030 if (s != NULL) { 1031 perror(ifname); /* ifname already has z suffix and does not exist */ 1032 exit_code = ERROR; 1033 return ERROR; 1034 } 1035#ifdef NO_MULTIPLE_DOTS 1036 dot = strrchr(ifname, '.'); 1037 if (dot == NULL) { 1038 strcat(ifname, "."); 1039 dot = strrchr(ifname, '.'); 1040 } 1041#endif 1042 ilen = strlen(ifname); 1043 if (strequ(z_suffix, ".gz")) suf++; 1044 1045 /* Search for all suffixes */ 1046 do { 1047 s = *suf; 1048#ifdef NO_MULTIPLE_DOTS 1049 if (*s == '.') s++; 1050#endif 1051#ifdef MAX_EXT_CHARS 1052 strcpy(ifname, iname); 1053 /* Needed if the suffixes are not sorted by increasing length */ 1054 1055 if (*dot == '\0') strcpy(dot, "."); 1056 dot[MAX_EXT_CHARS+1-strlen(s)] = '\0'; 1057#endif 1058 strcat(ifname, s); 1059 if (do_stat(ifname, sbuf) == 0) return OK; 1060 ifname[ilen] = '\0'; 1061 } while (*++suf != NULL); 1062 1063 /* No suffix found, complain using z_suffix: */ 1064#ifdef MAX_EXT_CHARS 1065 strcpy(ifname, iname); 1066 if (*dot == '\0') strcpy(dot, "."); 1067 dot[MAX_EXT_CHARS+1-z_len] = '\0'; 1068#endif 1069 strcat(ifname, z_suffix); 1070 perror(ifname); 1071 exit_code = ERROR; 1072 return ERROR; 1073} 1074 1075/* ======================================================================== 1076 * Generate ofname given ifname. Return OK, or WARNING if file must be skipped. 1077 * Sets save_orig_name to true if the file name has been truncated. 1078 */ 1079local int make_ofname() 1080{ 1081 char *suff; /* ofname z suffix */ 1082 1083 strcpy(ofname, ifname); 1084 /* strip a version number if any and get the gzip suffix if present: */ 1085 suff = get_suffix(ofname); 1086 1087 if (decompress) { 1088 if (suff == NULL) { 1089 /* Whith -t or -l, try all files (even without .gz suffix) 1090 * except with -r (behave as with just -dr). 1091 */ 1092 if (!recursive && (list || test)) return OK; 1093 1094 /* Avoid annoying messages with -r */ 1095 if (verbose || (!recursive && !quiet)) { 1096 WARN((stderr,"%s: %s: unknown suffix -- ignored\n", 1097 progname, ifname)); 1098 } 1099 return WARNING; 1100 } 1101 /* Make a special case for .tgz and .taz: */ 1102 strlwr(suff); 1103 if (strequ(suff, ".tgz") || strequ(suff, ".taz")) { 1104 strcpy(suff, ".tar"); 1105 } else { 1106 *suff = '\0'; /* strip the z suffix */ 1107 } 1108 /* ofname might be changed later if infile contains an original name */ 1109 1110 } else if (suff != NULL) { 1111 /* Avoid annoying messages with -r (see treat_dir()) */ 1112 if (verbose || (!recursive && !quiet)) { 1113 fprintf(stderr, "%s: %s already has %s suffix -- unchanged\n", 1114 progname, ifname, suff); 1115 } 1116 if (exit_code == OK) exit_code = WARNING; 1117 return WARNING; 1118 } else { 1119 save_orig_name = 0; 1120 1121#ifdef NO_MULTIPLE_DOTS 1122 suff = strrchr(ofname, '.'); 1123 if (suff == NULL) { 1124 strcat(ofname, "."); 1125# ifdef MAX_EXT_CHARS 1126 if (strequ(z_suffix, "z")) { 1127 strcat(ofname, "gz"); /* enough room */ 1128 return OK; 1129 } 1130 /* On the Atari and some versions of MSDOS, name_too_long() 1131 * does not work correctly because of a bug in stat(). So we 1132 * must truncate here. 1133 */ 1134 } else if (strlen(suff)-1 + z_len > MAX_SUFFIX) { 1135 suff[MAX_SUFFIX+1-z_len] = '\0'; 1136 save_orig_name = 1; 1137# endif 1138 } 1139#endif /* NO_MULTIPLE_DOTS */ 1140 strcat(ofname, z_suffix); 1141 1142 } /* decompress ? */ 1143 return OK; 1144} 1145 1146 1147/* ======================================================================== 1148 * Check the magic number of the input file and update ofname if an 1149 * original name was given and to_stdout is not set. 1150 * Return the compression method, -1 for error, -2 for warning. 1151 * Set inptr to the offset of the next byte to be processed. 1152 * Updates time_stamp if there is one and --no-time is not used. 1153 * This function may be called repeatedly for an input file consisting 1154 * of several contiguous gzip'ed members. 1155 * IN assertions: there is at least one remaining compressed member. 1156 * If the member is a zip file, it must be the only one. 1157 */ 1158local int get_method(in) 1159 int in; /* input file descriptor */ 1160{ 1161 uch flags; /* compression flags */ 1162 char magic[2]; /* magic header */ 1163 ulg stamp; /* time stamp */ 1164 1165 /* If --force and --stdout, zcat == cat, so do not complain about 1166 * premature end of file: use try_byte instead of get_byte. 1167 */ 1168 if (force && to_stdout) { 1169 magic[0] = (char)try_byte(); 1170 magic[1] = (char)try_byte(); 1171 /* If try_byte returned EOF, magic[1] == 0xff */ 1172 } else { 1173 magic[0] = (char)get_byte(); 1174 magic[1] = (char)get_byte(); 1175 } 1176 method = -1; /* unknown yet */ 1177 part_nb++; /* number of parts in gzip file */ 1178 header_bytes = 0; 1179 last_member = RECORD_IO; 1180 /* assume multiple members in gzip file except for record oriented I/O */ 1181 1182 if (memcmp(magic, GZIP_MAGIC, 2) == 0 1183 || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) { 1184 1185 method = (int)get_byte(); 1186 if (method != DEFLATED) { 1187 fprintf(stderr, 1188 "%s: %s: unknown method %d -- get newer version of gzip\n", 1189 progname, ifname, method); 1190 exit_code = ERROR; 1191 return -1; 1192 } 1193 work = unzip; 1194 flags = (uch)get_byte(); 1195 1196 if ((flags & ENCRYPTED) != 0) { 1197 fprintf(stderr, 1198 "%s: %s is encrypted -- get newer version of gzip\n", 1199 progname, ifname); 1200 exit_code = ERROR; 1201 return -1; 1202 } 1203 if ((flags & CONTINUATION) != 0) { 1204 fprintf(stderr, 1205 "%s: %s is a a multi-part gzip file -- get newer version of gzip\n", 1206 progname, ifname); 1207 exit_code = ERROR; 1208 if (force <= 1) return -1; 1209 } 1210 if ((flags & RESERVED) != 0) { 1211 fprintf(stderr, 1212 "%s: %s has flags 0x%x -- get newer version of gzip\n", 1213 progname, ifname, flags); 1214 exit_code = ERROR; 1215 if (force <= 1) return -1; 1216 } 1217 stamp = (ulg)get_byte(); 1218 stamp |= ((ulg)get_byte()) << 8; 1219 stamp |= ((ulg)get_byte()) << 16; 1220 stamp |= ((ulg)get_byte()) << 24; 1221 if (stamp != 0 && !no_time) time_stamp = stamp; 1222 1223 (void)get_byte(); /* Ignore extra flags for the moment */ 1224 (void)get_byte(); /* Ignore OS type for the moment */ 1225 1226 if ((flags & CONTINUATION) != 0) { 1227 unsigned part = (unsigned)get_byte(); 1228 part |= ((unsigned)get_byte())<<8; 1229 if (verbose) { 1230 fprintf(stderr,"%s: %s: part number %u\n", 1231 progname, ifname, part); 1232 } 1233 } 1234 if ((flags & EXTRA_FIELD) != 0) { 1235 unsigned len = (unsigned)get_byte(); 1236 len |= ((unsigned)get_byte())<<8; 1237 if (verbose) { 1238 fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n", 1239 progname, ifname, len); 1240 } 1241 while (len--) (void)get_byte(); 1242 } 1243 1244 /* Get original file name if it was truncated */ 1245 if ((flags & ORIG_NAME) != 0) { 1246 if (no_name || (to_stdout && !list) || part_nb > 1) { 1247 /* Discard the old name */ 1248 char c; /* dummy used for NeXTstep 3.0 cc optimizer bug */ 1249 do {c=get_byte();} while (c != 0); 1250 } else { 1251 /* Copy the base name. Keep a directory prefix intact. */ 1252 char *p = our_basename(ofname); 1253 char *base = p; 1254 for (;;) { 1255 *p = (char)get_char(); 1256 if (*p++ == '\0') break; 1257 if (p >= ofname+sizeof(ofname)) { 1258 error("corrupted input -- file name too large"); 1259 } 1260 } 1261 /* If necessary, adapt the name to local OS conventions: */ 1262 if (!list) { 1263 MAKE_LEGAL_NAME(base); 1264 if (base) list=0; /* avoid warning about unused variable */ 1265 } 1266 } /* no_name || to_stdout */ 1267 } /* ORIG_NAME */ 1268 1269 /* Discard file comment if any */ 1270 if ((flags & COMMENT) != 0) { 1271 while (get_char() != 0) /* null */ ; 1272 } 1273 if (part_nb == 1) { 1274 header_bytes = inptr + 2*sizeof(long); /* include crc and size */ 1275 } 1276 1277 } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2 1278 && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0) { 1279 /* To simplify the code, we support a zip file when alone only. 1280 * We are thus guaranteed that the entire local header fits in inbuf. 1281 */ 1282 inptr = 0; 1283 work = unzip; 1284 if (check_zipfile(in) != OK) return -1; 1285 /* check_zipfile may get ofname from the local header */ 1286 last_member = 1; 1287 1288 } else if (memcmp(magic, PACK_MAGIC, 2) == 0) { 1289 work = unpack; 1290 method = PACKED; 1291 1292 } else if (memcmp(magic, LZW_MAGIC, 2) == 0) { 1293 work = unlzw; 1294 method = COMPRESSED; 1295 last_member = 1; 1296 1297 } else if (memcmp(magic, LZH_MAGIC, 2) == 0) { 1298 work = unlzh; 1299 method = LZHED; 1300 last_member = 1; 1301 1302 } else if (force && to_stdout && !list) { /* pass input unchanged */ 1303 method = STORED; 1304 work = copy; 1305 inptr = 0; 1306 last_member = 1; 1307 } 1308 if (method >= 0) return method; 1309 1310 if (part_nb == 1) { 1311 fprintf(stderr, "\n%s: %s: not in gzip format\n", progname, ifname); 1312 exit_code = ERROR; 1313 return -1; 1314 } else { 1315 WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n", 1316 progname, ifname)); 1317 return -2; 1318 } 1319} 1320 1321/* ======================================================================== 1322 * Display the characteristics of the compressed file. 1323 * If the given method is < 0, display the accumulated totals. 1324 * IN assertions: time_stamp, header_bytes and ifile_size are initialized. 1325 */ 1326local void do_list(ifd, method) 1327 int ifd; /* input file descriptor */ 1328 int method; /* compression method */ 1329{ 1330 ulg crc; /* original crc */ 1331 static int first_time = 1; 1332 static char* methods[MAX_METHODS] = { 1333 "store", /* 0 */ 1334 "compr", /* 1 */ 1335 "pack ", /* 2 */ 1336 "lzh ", /* 3 */ 1337 "", "", "", "", /* 4 to 7 reserved */ 1338 "defla"}; /* 8 */ 1339 char *date; 1340 1341 if (first_time && method >= 0) { 1342 first_time = 0; 1343 if (verbose) { 1344 printf("method crc date time "); 1345 } 1346 if (!quiet) { 1347 printf("compressed uncompr. ratio uncompressed_name\n"); 1348 } 1349 } else if (method < 0) { 1350 if (total_in <= 0 || total_out <= 0) return; 1351 if (verbose) { 1352 printf(" %9lu %9lu ", 1353 total_in, total_out); 1354 } else if (!quiet) { 1355 printf("%9ld %9ld ", total_in, total_out); 1356 } 1357 display_ratio(total_out-(total_in-header_bytes), total_out, stdout); 1358 /* header_bytes is not meaningful but used to ensure the same 1359 * ratio if there is a single file. 1360 */ 1361 printf(" (totals)\n"); 1362 return; 1363 } 1364 crc = (ulg)~0; /* unknown */ 1365 bytes_out = -1L; 1366 bytes_in = ifile_size; 1367 1368#if RECORD_IO == 0 1369 if (method == DEFLATED && !last_member) { 1370 /* Get the crc and uncompressed size for gzip'ed (not zip'ed) files. 1371 * If the lseek fails, we could use read() to get to the end, but 1372 * --list is used to get quick results. 1373 * Use "gunzip < foo.gz | wc -c" to get the uncompressed size if 1374 * you are not concerned about speed. 1375 */ 1376 bytes_in = (long)lseek(ifd, (off_t)(-8), SEEK_END); 1377 if (bytes_in != -1L) { 1378 uch buf[8]; 1379 bytes_in += 8L; 1380 if (read(ifd, (char*)buf, sizeof(buf)) != sizeof(buf)) { 1381 read_error(); 1382 } 1383 crc = LG(buf); 1384 bytes_out = LG(buf+4); 1385 } 1386 } 1387#endif /* RECORD_IO */ 1388 date = ctime((time_t*)&time_stamp) + 4; /* skip the day of the week */ 1389 date[12] = '\0'; /* suppress the 1/100sec and the year */ 1390 if (verbose) { 1391 printf("%5s %08lx %11s ", methods[method], crc, date); 1392 } 1393 printf("%9ld %9ld ", bytes_in, bytes_out); 1394 if (bytes_in == -1L) { 1395 total_in = -1L; 1396 bytes_in = bytes_out = header_bytes = 0; 1397 } else if (total_in >= 0) { 1398 total_in += bytes_in; 1399 } 1400 if (bytes_out == -1L) { 1401 total_out = -1L; 1402 bytes_in = bytes_out = header_bytes = 0; 1403 } else if (total_out >= 0) { 1404 total_out += bytes_out; 1405 } 1406 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out, stdout); 1407 printf(" %s\n", ofname); 1408} 1409 1410/* ======================================================================== 1411 * Return true if the two stat structures correspond to the same file. 1412 */ 1413local int same_file(stat1, stat2) 1414 struct stat *stat1; 1415 struct stat *stat2; 1416{ 1417 return stat1->st_ino == stat2->st_ino 1418 && stat1->st_dev == stat2->st_dev 1419#ifdef NO_ST_INO 1420 /* Can't rely on st_ino and st_dev, use other fields: */ 1421 && stat1->st_mode == stat2->st_mode 1422 && stat1->st_uid == stat2->st_uid 1423 && stat1->st_gid == stat2->st_gid 1424 && stat1->st_size == stat2->st_size 1425 && stat1->st_atime == stat2->st_atime 1426 && stat1->st_mtime == stat2->st_mtime 1427 && stat1->st_ctime == stat2->st_ctime 1428#endif 1429 ; 1430} 1431 1432/* ======================================================================== 1433 * Return true if a file name is ambiguous because the operating system 1434 * truncates file names. 1435 */ 1436local int name_too_long(name, statb) 1437 char *name; /* file name to check */ 1438 struct stat *statb; /* stat buf for this file name */ 1439{ 1440 int s = strlen(name); 1441 char c = name[s-1]; 1442 struct stat tstat; /* stat for truncated name */ 1443 int res; 1444 1445 tstat = *statb; /* Just in case OS does not fill all fields */ 1446 name[s-1] = '\0'; 1447 res = stat(name, &tstat) == 0 && same_file(statb, &tstat); 1448 name[s-1] = c; 1449 Trace((stderr, " too_long(%s) => %d\n", name, res)); 1450 return res; 1451} 1452 1453/* ======================================================================== 1454 * Shorten the given name by one character, or replace a .tar extension 1455 * with .tgz. Truncate the last part of the name which is longer than 1456 * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name 1457 * has only parts shorter than MIN_PART truncate the longest part. 1458 * For decompression, just remove the last character of the name. 1459 * 1460 * IN assertion: for compression, the suffix of the given name is z_suffix. 1461 */ 1462local void shorten_name(name) 1463 char *name; 1464{ 1465 int len; /* length of name without z_suffix */ 1466 char *trunc = NULL; /* character to be truncated */ 1467 int plen; /* current part length */ 1468 int min_part = MIN_PART; /* current minimum part length */ 1469 char *p; 1470 1471 len = strlen(name); 1472 if (decompress) { 1473 if (len <= 1) error("name too short"); 1474 name[len-1] = '\0'; 1475 return; 1476 } 1477 p = get_suffix(name); 1478 if (p == NULL) error("can't recover suffix\n"); 1479 *p = '\0'; 1480 save_orig_name = 1; 1481 1482 /* compress 1234567890.tar to 1234567890.tgz */ 1483 if (len > 4 && strequ(p-4, ".tar")) { 1484 strcpy(p-4, ".tgz"); 1485 return; 1486 } 1487 /* Try keeping short extensions intact: 1488 * 1234.678.012.gz -> 123.678.012.gz 1489 */ 1490 do { 1491 p = strrchr(name, PATH_SEP); 1492 p = p ? p+1 : name; 1493 while (*p) { 1494 plen = strcspn(p, PART_SEP); 1495 p += plen; 1496 if (plen > min_part) trunc = p-1; 1497 if (*p) p++; 1498 } 1499 } while (trunc == NULL && --min_part != 0); 1500 1501 if (trunc != NULL) { 1502 do { 1503 trunc[0] = trunc[1]; 1504 } while (*trunc++); 1505 trunc--; 1506 } else { 1507 trunc = strrchr(name, PART_SEP[0]); 1508 if (trunc == NULL) error("internal error in shorten_name"); 1509 if (trunc[1] == '\0') trunc--; /* force truncation */ 1510 } 1511 strcpy(trunc, z_suffix); 1512} 1513 1514/* ======================================================================== 1515 * If compressing to a file, check if ofname is not ambiguous 1516 * because the operating system truncates names. Otherwise, generate 1517 * a new ofname and save the original name in the compressed file. 1518 * If the compressed file already exists, ask for confirmation. 1519 * The check for name truncation is made dynamically, because different 1520 * file systems on the same OS might use different truncation rules (on SVR4 1521 * s5 truncates to 14 chars and ufs does not truncate). 1522 * This function returns -1 if the file must be skipped, and 1523 * updates save_orig_name if necessary. 1524 * IN assertions: save_orig_name is already set if ofname has been 1525 * already truncated because of NO_MULTIPLE_DOTS. The input file has 1526 * already been open and istat is set. 1527 */ 1528local int check_ofname() 1529{ 1530 struct stat ostat; /* stat for ofname */ 1531 1532#ifdef ENAMETOOLONG 1533 /* Check for strictly conforming Posix systems (which return ENAMETOOLONG 1534 * instead of silently truncating filenames). 1535 */ 1536 errno = 0; 1537 while (stat(ofname, &ostat) != 0) { 1538 if (errno != ENAMETOOLONG) return 0; /* ofname does not exist */ 1539 shorten_name(ofname); 1540 } 1541#else 1542 if (stat(ofname, &ostat) != 0) return 0; 1543#endif 1544 /* Check for name truncation on existing file. Do this even on systems 1545 * defining ENAMETOOLONG, because on most systems the strict Posix 1546 * behavior is disabled by default (silent name truncation allowed). 1547 */ 1548 if (!decompress && name_too_long(ofname, &ostat)) { 1549 shorten_name(ofname); 1550 if (stat(ofname, &ostat) != 0) return 0; 1551 } 1552 1553 /* Check that the input and output files are different (could be 1554 * the same by name truncation or links). 1555 */ 1556 if (same_file(&istat, &ostat)) { 1557 if (strequ(ifname, ofname)) { 1558 fprintf(stderr, "%s: %s: cannot %scompress onto itself\n", 1559 progname, ifname, decompress ? "de" : ""); 1560 } else { 1561 fprintf(stderr, "%s: %s and %s are the same file\n", 1562 progname, ifname, ofname); 1563 } 1564 exit_code = ERROR; 1565 return ERROR; 1566 } 1567 /* Ask permission to overwrite the existing file */ 1568 if (!force) { 1569 char response[80]; 1570 strcpy(response,"n"); 1571 fprintf(stderr, "%s: %s already exists;", progname, ofname); 1572 if (foreground && isatty(fileno(stdin))) { 1573 fprintf(stderr, " do you wish to overwrite (y or n)? "); 1574 fflush(stderr); 1575 (void)fgets(response, sizeof(response)-1, stdin); 1576 } 1577 if (tolow(*response) != 'y') { 1578 fprintf(stderr, "\tnot overwritten\n"); 1579 if (exit_code == OK) exit_code = WARNING; 1580 return ERROR; 1581 } 1582 } 1583 (void) chmod(ofname, 0777); 1584 if (unlink(ofname)) { 1585 fprintf(stderr, "%s: ", progname); 1586 perror(ofname); 1587 exit_code = ERROR; 1588 return ERROR; 1589 } 1590 return OK; 1591} 1592 1593 1594#ifndef NO_UTIME 1595/* ======================================================================== 1596 * Set the access and modification times from the given stat buffer. 1597 */ 1598local void reset_times (name, statb) 1599 char *name; 1600 struct stat *statb; 1601{ 1602 struct utimbuf timep; 1603 1604 /* Copy the time stamp */ 1605 timep.actime = statb->st_atime; 1606 timep.modtime = statb->st_mtime; 1607 1608 /* Some systems (at least OS/2) do not support utime on directories */ 1609 if (utime(name, &timep) && !S_ISDIR(statb->st_mode)) { 1610 WARN((stderr, "%s: ", progname)); 1611 if (!quiet) perror(ofname); 1612 } 1613} 1614#endif 1615 1616 1617/* ======================================================================== 1618 * Copy modes, times, ownership from input file to output file. 1619 * IN assertion: to_stdout is false. 1620 */ 1621local void copy_stat(ifstat) 1622 struct stat *ifstat; 1623{ 1624#ifndef NO_UTIME 1625 if (decompress && time_stamp != 0 && ifstat->st_mtime != time_stamp) { 1626 ifstat->st_mtime = time_stamp; 1627 if (verbose > 1) { 1628 fprintf(stderr, "%s: time stamp restored\n", ofname); 1629 } 1630 } 1631 reset_times(ofname, ifstat); 1632#endif 1633 /* Copy the protection modes */ 1634 if (chmod(ofname, ifstat->st_mode & 07777)) { 1635 WARN((stderr, "%s: ", progname)); 1636 if (!quiet) perror(ofname); 1637 } 1638#ifndef NO_CHOWN 1639 chown(ofname, ifstat->st_uid, ifstat->st_gid); /* Copy ownership */ 1640#endif 1641 remove_ofname = 0; 1642 /* It's now safe to remove the input file: */ 1643 (void) chmod(ifname, 0777); 1644 if (unlink(ifname)) { 1645 WARN((stderr, "%s: ", progname)); 1646 if (!quiet) perror(ifname); 1647 } 1648} 1649 1650#ifndef NO_DIR 1651 1652/* ======================================================================== 1653 * Recurse through the given directory. This code is taken from ncompress. 1654 */ 1655local void treat_dir(dir) 1656 char *dir; 1657{ 1658 dir_type *dp; 1659 DIR *dirp; 1660 char nbuf[MAX_PATH_LEN]; 1661 int len; 1662 1663 dirp = opendir(dir); 1664 1665 if (dirp == NULL) { 1666 fprintf(stderr, "%s: %s unreadable\n", progname, dir); 1667 exit_code = ERROR; 1668 return ; 1669 } 1670 /* 1671 ** WARNING: the following algorithm could occasionally cause 1672 ** compress to produce error warnings of the form "<filename>.gz 1673 ** already has .gz suffix - ignored". This occurs when the 1674 ** .gz output file is inserted into the directory below 1675 ** readdir's current pointer. 1676 ** These warnings are harmless but annoying, so they are suppressed 1677 ** with option -r (except when -v is on). An alternative 1678 ** to allowing this would be to store the entire directory 1679 ** list in memory, then compress the entries in the stored 1680 ** list. Given the depth-first recursive algorithm used here, 1681 ** this could use up a tremendous amount of memory. I don't 1682 ** think it's worth it. -- Dave Mack 1683 ** (An other alternative might be two passes to avoid depth-first.) 1684 */ 1685 1686 while ((dp = readdir(dirp)) != NULL) { 1687 1688 if (strequ(dp->d_name,".") || strequ(dp->d_name,"..")) { 1689 continue; 1690 } 1691 len = strlen(dir); 1692 if (len + NLENGTH(dp) + 1 < MAX_PATH_LEN - 1) { 1693 strcpy(nbuf,dir); 1694 if (len != 0 /* dir = "" means current dir on Amiga */ 1695#ifdef PATH_SEP2 1696 && dir[len-1] != PATH_SEP2 1697#endif 1698#ifdef PATH_SEP3 1699 && dir[len-1] != PATH_SEP3 1700#endif 1701 ) { 1702 nbuf[len++] = PATH_SEP; 1703 } 1704 strcpy(nbuf+len, dp->d_name); 1705 treat_file(nbuf); 1706 } else { 1707 fprintf(stderr,"%s: %s/%s: pathname too long\n", 1708 progname, dir, dp->d_name); 1709 exit_code = ERROR; 1710 } 1711 } 1712 closedir(dirp); 1713} 1714#endif /* ? NO_DIR */ 1715 1716/* ======================================================================== 1717 * Free all dynamically allocated variables and exit with the given code. 1718 */ 1719local void do_exit(exitcode) 1720 int exitcode; 1721{ 1722 static int in_exit = 0; 1723 1724 if (in_exit) exit(exitcode); 1725 in_exit = 1; 1726 if (env != NULL) free(env), env = NULL; 1727 if (args != NULL) free((char*)args), args = NULL; 1728 FREE(inbuf); 1729 FREE(outbuf); 1730 FREE(d_buf); 1731 FREE(window); 1732#ifndef MAXSEG_64K 1733 FREE(tab_prefix); 1734#else 1735 FREE(tab_prefix0); 1736 FREE(tab_prefix1); 1737#endif 1738 exit(exitcode); 1739} 1740 1741/* ======================================================================== 1742 * Signal and error handler. 1743 */ 1744RETSIGTYPE abort_gzip() 1745{ 1746 if (remove_ofname) { 1747 close(ofd); 1748 unlink (ofname); 1749 } 1750 do_exit(ERROR); 1751} 1752