home *** CD-ROM | disk | FTP | other *** search
/ Current Shareware 1994 January / SHAR194.ISO / compress / gnuzip_.zip / GZIP.C < prev    next >
C/C++ Source or Header  |  1993-03-28  |  39KB  |  1,265 lines

  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.  
  12. static 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.",
  27. 0};
  28.  
  29. /* Compress files with zip algorithm and 'compress' interface.
  30.  * See usage() and help() functions below for all options.
  31.  * Outputs:
  32.  *        file.z:   compressed file with same mode, owner, and utimes
  33.  *        file.Z:   same with -Z option (old compress format)
  34.  *     or stdout with -c option or if stdin used as input.
  35.  * If the OS does not support file names with multiple dots (MSDOS, VMS) or
  36.  * if the output file name had to be truncated, the original name is kept
  37.  * in the compressed .z file. (Feature not available in old compress format.)
  38.  * On MSDOS, file.tmp -> file.tmz
  39.  *
  40.  * For the meaning of all compilation flags, see comments in Makefile.in.
  41.  */
  42.  
  43. #ifndef lint
  44. static char rcsid[] = "$Id: gzip.c,v 0.13 1993/02/11 09:47:02 jloup Exp $";
  45. #endif
  46.  
  47. #include "tailor.h"
  48. #include "gzip.h"
  49. #include "lzw.h"
  50. #include "revision.h"
  51. #include "getopt.h"
  52.  
  53. #include <stdio.h>
  54. #include <ctype.h>
  55. #include <sys/types.h>
  56. #include <signal.h>
  57. #include <sys/stat.h>
  58. #include <errno.h>
  59.  
  60.         /* configuration */
  61.  
  62. #ifndef NO_FCNTL_H
  63. #  include <fcntl.h>
  64. #endif
  65.  
  66. #if defined(HAVE_UNISTD_H)
  67. #  include <unistd.h>
  68. #endif
  69.  
  70. #if defined(STDC_HEADERS) || defined(HAVE_STDLIB_H)
  71. #  include <stdlib.h>
  72. #else
  73.    extern int errno;
  74. #endif
  75.  
  76. #if defined(DIRENT) || defined(_POSIX_VERSION)
  77. #  include <dirent.h>
  78.    typedef struct dirent dir_type;
  79. #  define NLENGTH(dirent) ((int)strlen((dirent)->d_name))
  80. #  define DIR_OPT "DIRENT"
  81. #else
  82. #  define NLENGTH(dirent) ((dirent)->d_namlen)
  83. #  ifdef SYSDIR
  84. #    include <sys/dir.h>
  85.      typedef struct direct dir_type;
  86. #    define DIR_OPT "SYSDIR"
  87. #  else
  88. #    ifdef SYSNDIR
  89. #      include <sys/ndir.h>
  90.        typedef struct direct dir_type;
  91. #      define DIR_OPT "SYSNDIR"
  92. #    else
  93. #      ifdef NDIR
  94. #        include <ndir.h>
  95.      typedef struct direct dir_type;
  96. #        define DIR_OPT "NDIR"
  97. #      else
  98. #        define NO_DIR
  99. #        define DIR_OPT "NO_DIR"
  100. #      endif
  101. #    endif
  102. #  endif
  103. #endif
  104.  
  105. #ifdef HAVE_UTIME_H
  106. #  include <utime.h>
  107. #  define TIME_OPT "UTIME"
  108. #else
  109. #  ifdef HAVE_SYS_UTIME_H
  110. #    include <sys/utime.h>
  111. #    define TIME_OPT "SYS_UTIME"
  112. #  else
  113.      struct utimbuf {
  114.      time_t actime;
  115.      time_t modtime;
  116.      };
  117. #    define TIME_OPT ""
  118. #  endif
  119. #endif
  120.  
  121. #if !defined(S_ISDIR) && defined(S_IFDIR)
  122. #  define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
  123. #endif
  124. #if !defined(S_ISREG) && defined(S_IFREG)
  125. #  define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
  126. #endif
  127.  
  128. typedef RETSIGTYPE (*sig_type)();
  129.  
  130. #ifndef O_BINARY
  131. #  define  O_BINARY  0  /* creation mode for open() */
  132. #endif
  133.  
  134. #define RW_USER 0600    /* creation mode for open() */
  135.  
  136. #ifndef MAX_PATH_LEN
  137. #  define MAX_PATH_LEN   1024 /* max pathname length */
  138. #endif
  139.  
  140. #define MAX_HEADER_LEN   16
  141. /* max length of a compressed file header, fixed part only */
  142.  
  143.         /* global buffers */
  144.  
  145. DECLARE(uch, inbuf,  INBUFSIZ +INBUF_EXTRA);
  146. DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
  147. DECLARE(ush, d_buf,  DIST_BUFSIZE);
  148. DECLARE(uch, window, 2L*WSIZE);
  149. #ifndef MAXSEG_64K
  150.     DECLARE(ush, tab_prefix, 1L<<BITS);
  151. #else
  152.     DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
  153.     DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
  154. #endif
  155.  
  156.         /* local variables */
  157.  
  158. int to_stdout = 0;    /* output to stdout (-c) */
  159. int decompress = 0;   /* decompress (-d) */
  160. int force = 0;        /* don't ask questions, compress links (-f) */
  161. int recursive = 0;    /* recurse through directories (-r) */
  162. int verbose = 0;      /* be verbose (-v) */
  163. int do_lzw = 0;       /* generate output compatible with old compress (-Z) */
  164. int test = 0;         /* test .z file integrity */
  165. int foreground;       /* set if program run in foreground */
  166. char *progname;       /* program name */
  167. int maxbits = BITS;   /* max bits per code for LZW */
  168. int method = DEFLATED;/* compression method */
  169. int level = 5;        /* compression level */
  170. int exit_code = OK;   /* program exit code */
  171. int save_orig_name;   /* set if original name must be saved */
  172. int last_member;      /* set for .zip and .Z files */
  173. int part_nb;          /* number of parts in .z file */
  174. ulg time_stamp;       /* original time stamp (modification time) */
  175. long ifile_size;      /* input file size, -1 for devices (debug only) */
  176. char *env;            /* contents of GZIP env variable */
  177. char **args = NULL;   /* argv pointer if GZIP env variable defined */
  178.  
  179. long bytes_in;             /* number of input bytes */
  180. long bytes_out;            /* number of output bytes */
  181. char ifname[MAX_PATH_LEN]; /* input filename */
  182. char ofname[MAX_PATH_LEN]; /* output filename */
  183. int  remove_ofname = 0;    /* remove output file on error */
  184. struct stat istat;         /* status for input file */
  185. int  ifd;                  /* input file descriptor */
  186. int  ofd;                  /* output file descriptor */
  187. unsigned insize;           /* valid bytes in inbuf */
  188. unsigned inptr;            /* index of next byte to be processed in inbuf */
  189. unsigned outcnt;           /* bytes in output buffer */
  190.  
  191. struct option longopts[] =
  192. {
  193.  /* { name  has_arg  *flag  val } */
  194.  /* {"ascii",      0, 0, 'a'},  ascii text mode */
  195.     {"stdout",     0, 0, 'c'}, /* write output on standard output */
  196.     {"decompress", 0, 0, 'd'}, /* decompress */
  197.  /* {"encrypt",    0, 0, 'e'},    encrypt */
  198.     {"force",      0, 0, 'f'}, /* force overwrite of output file */
  199.     {"help",       0, 0, 'h'}, /* give help */
  200.  /* {"pkzip",      0, 0, 'k'},    force output in pkzip format */
  201.  /* {"list",       0, 0, 'l'},    list .z file contents */
  202.     {"license",    0, 0, 'L'}, /* display software license */
  203.     {"recurse",    0, 0, 'r'}, /* recurse through directories */
  204.     {"test",       0, 0, 't'}, /* test compressed file integrity */
  205.     {"verbose",    0, 0, 'v'}, /* verbose mode */
  206.     {"version",    0, 0, 'V'}, /* display version number */
  207.     {"fast",       0, 0, '1'}, /* compress faster */
  208.     {"best",       0, 0, '9'}, /* compress better */
  209.     {"lzw",        0, 0, 'Z'}, /* make output compatible with old compress */
  210.     {"bits",       1, 0, 'b'}, /* max number of bits per code (implies -Z) */
  211.     { 0, 0, 0, 0 }
  212. };
  213.  
  214. /* local functions */
  215.  
  216. local void usage        OF((void));
  217. local void help         OF((void));
  218. local void license      OF((void));
  219. local void version      OF((void));
  220. local void treat_stdin  OF((void));
  221. local void treat_file   OF((char *iname));
  222. local int create_outfile OF((void));
  223. local int  do_stat      OF((char *name, struct stat *sbuf));
  224. local int  get_istat    OF((char *iname, struct stat *sbuf));
  225. local int  make_ofname  OF((void));
  226. local int  same_file    OF((struct stat *stat1, struct stat *stat2));
  227. local int name_too_long OF((char *name, struct stat *statb));
  228. local int  get_method   OF((int in));
  229. local int  check_ofname OF((void));
  230. local void copy_stat    OF((struct stat *ifstat));
  231. local void treat_dir    OF((char *dir));
  232. local void do_exit      OF((int exitcode));
  233.       int main          OF((int argc, char **argv));
  234.  
  235. void (*work) OF((int infile, int outfile)) = zip; /* function to call */
  236.  
  237. /* ======================================================================== */
  238. local void usage()
  239. {
  240.     fprintf(stderr,
  241. #ifdef LZW
  242. #  ifdef NO_DIR
  243.         "usage: %s [-cdfhLtvVZ19] [-b maxbits] [file ...]\n",
  244. #  else
  245.         "usage: %s [-cdfhLrtvVZ19] [-b maxbits] [file ...]\n",
  246. #  endif
  247. #else /* !LZW */
  248. #  ifdef NO_DIR
  249.         "usage: %s [-cdfhLtvV19] [file ...]\n",
  250. #  else
  251.         "usage: %s [-cdfhLrtvV19] [file ...]\n",
  252. #  endif
  253. #endif /* LZW */
  254.          progname);
  255. }
  256. /* ======================================================================== */
  257. local void help()
  258. {
  259.     static char  *help_msg[] = {
  260. /* -a --ascii       ascii text; convert end-of-lines to local OS conventions */
  261.  " -c --stdout      write on standard output, keep original files unchanged",
  262.  " -d --decompress  decompress",
  263. /* -e --encrypt     encrypt */
  264.  " -f --force       force overwrite of output file and compress links",
  265.  " -h --help        give this help",
  266. /* -k --pkzip       force output in pkzip format */
  267. /* -l --list        list .z file contents */
  268.  " -L --license     display software license",
  269. #ifndef NO_DIR
  270.  " -r --recurse     recurse through directories",
  271. #endif
  272.  " -t --test        test compressed file integrity",
  273.  " -v --verbose     verbose mode",
  274.  " -V --version     display version number",
  275.  " -1 --fast        compress faster",
  276.  " -9 --best        compress better",
  277. #ifdef LZW
  278.  " -Z --lzw         produce output compatible with old compress",
  279.  " -b --bits maxbits   max number of bits per code (implies -Z)",
  280. #endif
  281.  " file...          files to (de)compress. If none given, use standard input.",
  282.   0};
  283.     char **p = help_msg;
  284.  
  285.     fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE);
  286.     usage();
  287.     while (*p) fprintf(stderr, "%s\n", *p++);
  288. }
  289.  
  290. /* ======================================================================== */
  291. local void license()
  292. {
  293.     char **p = license_msg;
  294.  
  295.     fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE);
  296.     while (*p) fprintf(stderr, "%s\n", *p++);
  297. }
  298.  
  299. /* ======================================================================== */
  300. local void version()
  301. {
  302.     fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE);
  303.  
  304.     fprintf(stderr, "Compilation options:\n%s %s ", DIR_OPT, TIME_OPT);
  305. #ifdef STDC_HEADERS
  306.     fprintf(stderr, "STDC_HEADERS ");
  307. #endif
  308. #ifdef HAVE_UNISTD_H
  309.     fprintf(stderr, "HAVE_UNISTD_H ");
  310. #endif
  311. #ifdef HAVE_MEMORY_H
  312.     fprintf(stderr, "HAVE_MEMORY_H ");
  313. #endif
  314. #ifdef HAVE_STRING_H
  315.     fprintf(stderr, "HAVE_STRING_H ");
  316. #endif
  317. #ifdef NO_SYMLINK
  318.     fprintf(stderr, "NO_SYMLINK ");
  319. #endif
  320. #ifdef NO_MULTIPLE_DOTS
  321.     fprintf(stderr, "NO_MULTIPLE_DOTS ");
  322. #endif
  323. #ifdef NO_UTIME
  324.     fprintf(stderr, "NO_UTIME ");
  325. #endif
  326. #ifdef NO_CHOWN
  327.     fprintf(stderr, "NO_CHOWN ");
  328. #endif
  329. #ifdef PROTO
  330.     fprintf(stderr, "PROTO ");
  331. #endif
  332. #ifdef ASMV
  333.     fprintf(stderr, "ASMV ");
  334. #endif
  335. #ifdef DEBUG
  336.     fprintf(stderr, "DEBUG ");
  337. #endif
  338. #ifdef DYN_ALLOC
  339.     fprintf(stderr, "DYN_ALLOC ");
  340. #endif
  341. #ifdef MAXSEG_64K
  342.     fprintf(stderr, "MAXSEG_64K");
  343. #endif
  344.     fprintf(stderr, "\n");
  345. }
  346.  
  347. /* ======================================================================== */
  348. int main (argc, argv)
  349.     int argc;
  350.     char **argv;
  351. {
  352.     int file_count = 0; /* number of files to precess */
  353.     int proglen;        /* length of progname */
  354.     int optc;           /* current option */
  355.  
  356.     EXPAND(argc, argv); /* wild card expansion if necessary */
  357.  
  358.     /* Add options in GZIP environment variable if there is one */
  359.     env = add_envopt(&argc, &argv, "GZIP");
  360.     if (env != NULL) args = argv;
  361.  
  362.     foreground = signal(SIGINT, SIG_IGN) != SIG_IGN;
  363.     if (foreground) {
  364.     signal (SIGINT, (sig_type)abort_gzip());
  365.     }
  366. #ifdef SIGTERM
  367.     signal(SIGTERM, (sig_type)abort_gzip());
  368. #endif
  369. #ifdef SIGHUP
  370.     signal(SIGHUP,  (sig_type)abort_gzip);
  371. #endif
  372.  
  373.     progname = basename(argv[0]);
  374.     proglen = strlen(progname);
  375.     /* Suppress .EXE for MSDOS, OS/2 and VMS: */
  376.     if (proglen > 4 && (strcmp(progname+proglen-4, ".EXE") == 0
  377.             || strcmp(progname+proglen-4, ".exe") == 0)) {
  378.     progname[proglen-4] = '\0';
  379.     strlwr(progname);
  380.     }
  381.  
  382.     /* For compatibility with old compress, use program name as an option.
  383.      * Systems which do not support links can still use -d or -dc.
  384.      * Ignore an .exe extension for MSDOS, OS/2 and VMS.
  385.      */
  386.     if (  strncmp(progname, "un",  2) == 0       /* ungzip, uncompress */
  387.        || strncmp(progname, "gun", 3) == 0) {    /* gunzip */
  388.     decompress = 1;
  389.     } else if (strcmp(progname+1, "cat") == 0    /* zcat, pcat */
  390.         || strcmp(progname, "gzcat") == 0) { /* gzcat */
  391.     decompress = to_stdout = 1;
  392.     }
  393.  
  394.     while ((optc = getopt_long (argc, argv, "b:cdfhLqrtvVZ123456789",
  395.                 longopts, (int *)0)) != EOF) {
  396.     switch (optc) {
  397.     case 'b':
  398.         maxbits = atoi(optarg);
  399.         break;
  400.     case 'c':
  401.         to_stdout = 1; break;
  402.     case 'd':
  403.         decompress = 1; break;
  404.     case 'f':
  405.         force++; break;
  406.     case 'h':
  407.         help(); do_exit(OK); break;
  408.     case 'L':
  409.         license(); do_exit(OK); break;
  410.     case 'q':
  411.         /* Cancel -v which could be in GZIP env variable */
  412.         if (verbose) verbose--; break;
  413.     case 'r':
  414. #ifdef NO_DIR
  415.         fprintf(stderr, "-r not supported on this system\n");
  416.         usage();
  417.         do_exit(ERROR); break;
  418. #else
  419.         recursive = 1; break;
  420. #endif
  421.     case 't':
  422.         test = decompress = to_stdout = 1;
  423.         break;
  424.     case 'v':
  425.         verbose++; break;
  426.     case 'V':
  427.         version(); break;
  428.     case 'Z':
  429. #ifdef LZW
  430.         do_lzw = 1; break;
  431. #else
  432.         fprintf(stderr, "-Z not supported in this version\n");
  433.         usage();
  434.         do_exit(ERROR); break;
  435. #endif
  436.     case '1':  case '2':  case '3':  case '4':
  437.     case '5':  case '6':  case '7':  case '8':  case '9':
  438.         level = optc - '0';
  439.         break;
  440.     default:
  441.         /* Error message already emitted by getopt_long. */
  442.         usage();
  443.         do_exit(ERROR);
  444.     }
  445.     } /* loop on all arguments */
  446.  
  447.     file_count = argc - optind;
  448.  
  449.     if (do_lzw && !decompress) work = lzw;
  450.  
  451.     /* Allocate all global buffers (for DYN_ALLOC option) */
  452.     ALLOC(uch, inbuf,  INBUFSIZ +INBUF_EXTRA);
  453.     ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
  454.     ALLOC(ush, d_buf,  DIST_BUFSIZE);
  455.     ALLOC(uch, window, 2L*WSIZE);
  456. #ifndef MAXSEG_64K
  457.     ALLOC(ush, tab_prefix, 1L<<BITS);
  458. #else
  459.     ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
  460.     ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
  461. #endif
  462.  
  463.     /* And get to work */
  464.     if (file_count != 0) {
  465.     if (to_stdout && !test) {
  466.         SET_BINARY_MODE(fileno(stdout));
  467.     }
  468.     while (optind < argc) {
  469.         treat_file(argv[optind++]);
  470.     }
  471.     } else {  /* Standard input */
  472.     treat_stdin();
  473.     }
  474.     do_exit(exit_code);
  475.     return exit_code; /* just to avoid lint warning */
  476. }
  477.  
  478. /* ========================================================================
  479.  * Compress or decompress stdin
  480.  */
  481. local void treat_stdin()
  482. {
  483.     if (isatty(fileno((FILE *)(decompress ? stdin : stdout)))) {
  484.     /* Do not send compressed data to the terminal or read it from
  485.      * the terminal. We get here when user invoked the program
  486.      * without parameters, so be helpful.
  487.      */
  488.     fprintf(stderr,
  489.           "Compressed data not %s a terminal. Redirect %s file or pipe.\n",
  490.         decompress ? "read from" : "written to",
  491.         decompress ? "from" : "to");
  492.     fprintf(stderr,"For help, type: %s -h\n", progname);
  493.     do_exit(ERROR);
  494.     }
  495.     SET_BINARY_MODE(fileno(stdin));
  496.     if (!test) SET_BINARY_MODE(fileno(stdout));
  497.  
  498.     strcpy(ifname, "stdin");
  499.     strcpy(ofname, "stdout");
  500.  
  501.     /* Get the time stamp on the input file */
  502. #ifdef NO_STDIN_FSTAT
  503.     time_stamp = 0; /* time unknown */
  504. #else
  505.     if (fstat(fileno(stdin), &istat) != 0) {
  506.     error("fstat(stdin)");
  507.     } 
  508.     time_stamp = istat.st_mtime;
  509. #endif
  510.     ifile_size = -1L; /* convention for unknown size */
  511.  
  512.     clear_bufs(); /* clear input and output buffers */
  513.     to_stdout = 1;
  514.     part_nb = 0;
  515.  
  516.     if (decompress) {
  517.     method = get_method(ifd);
  518.     if (method == -1) {
  519.         do_exit(exit_code); /* error message already emitted */
  520.     }
  521.     }
  522.  
  523.     /* Actually do the compression/decompression. Loop over zipped members.
  524.      */
  525.     for (;;) {
  526.     (*work)(fileno(stdin), fileno(stdout));
  527.  
  528.     if (!decompress || last_member || inptr == insize) break;
  529.     /* end of file */
  530.  
  531.     method = get_method(ifd);
  532.     if (method == -1) return; /* error message already emitted */
  533.     bytes_out = 0; /* required for length check */
  534.     }
  535.  
  536.     if (verbose) {
  537.     if (test) {
  538.         fprintf(stderr, " OK");
  539.  
  540.     } else if (!decompress) {
  541.         fprintf(stderr, "Compression: ");
  542.         display_ratio(bytes_in-bytes_out-overhead, bytes_in);
  543.     }
  544.     fprintf(stderr, "\n");
  545.     }
  546. }
  547.  
  548. /* ========================================================================
  549.  * Compress or decompress the given file
  550.  */
  551. local void treat_file(iname)
  552.     char *iname;
  553. {
  554.     /* Check if the input file is present, set ifname and istat: */
  555.     if (get_istat(iname, &istat) != 0) return;
  556.  
  557.     /* If the input name is that of a directory, recurse or ignore: */
  558.     if (S_ISDIR(istat.st_mode)) {
  559. #ifndef NO_DIR
  560.     if (recursive) {
  561.         treat_dir(iname);
  562.         /* Warning: ifname is now garbage */
  563.     } else
  564. #endif
  565.     fprintf(stderr,"%s is a directory -- ignored\n", ifname);
  566.     if (exit_code == OK) exit_code = WARNING;
  567.     return;
  568.     }
  569.     if (!S_ISREG(istat.st_mode)) {
  570.     fprintf(stderr,"%s is not a directory or a regular file - ignored\n",
  571.         ifname);
  572.     return;
  573.     }
  574.     if (istat.st_nlink > 1 && !to_stdout && !force) {
  575.     fprintf(stderr, "%s has %d other link%c -- unchanged\n", ifname,
  576.         (int)istat.st_nlink - 1, istat.st_nlink > 2 ? 's' : ' ');
  577.     if (exit_code == OK) exit_code = WARNING;
  578.     return;
  579.     }
  580.  
  581.     ifile_size = istat.st_size;
  582.     time_stamp = istat.st_mtime;
  583.  
  584.     /* Generate output file name */
  585.     if (to_stdout) {
  586.     strcpy(ofname, "stdout");
  587.  
  588.     } else if (make_ofname() != 0) {
  589.     return;
  590.     }
  591.  
  592.     /* Open the input file and determine compression method */
  593.     ifd = open(ifname, O_RDONLY | O_BINARY);
  594.     if (ifd == -1) {
  595.     perror(ifname);
  596.     exit_code = ERROR;
  597.     return;
  598.     }
  599.     clear_bufs(); /* clear input and output buffers */
  600.     part_nb = 0;
  601.  
  602.     if (decompress) {
  603.     method = get_method(ifd); /* updates ofname if original given */
  604.     if (method == -1) return; /* error message already emitted */
  605.     }
  606.  
  607.     /* If compressing to a file, check if ofname is not ambigous
  608.      * because the operating system truncates names. Otherwise, generate
  609.      * a new ofname and save the original name in the compressed file.
  610.      */
  611.     if (to_stdout) {
  612.     ofd = fileno(stdout);
  613.     /* keep remove_ofname as zero */
  614.     } else {
  615.     if (create_outfile() == -1) return;
  616.  
  617.     if (save_orig_name && !verbose && !force) {
  618.         fprintf(stderr, "%s compressed to %s\n", ifname, ofname);
  619.     }
  620.     }
  621.     if (verbose) {
  622.     fprintf(stderr, "%s:\t%s", ifname, (int)strlen(ifname) >= 15 ? 
  623.         "" : ((int)strlen(ifname) >= 7 ? "\t" : "\t\t"));
  624.     }
  625.  
  626.     /* Actually do the compression/decompression. If testing only and
  627.      * input file is in LZW format (which has no CRC) skip it. Loop over
  628.      * zipped members.
  629.      */
  630.     for (;;) {
  631.     (*work)(ifd, ofd);
  632.  
  633.     if (!decompress || last_member || inptr == insize) break;
  634.     /* end of file */
  635.  
  636.     method = get_method(ifd);
  637.     if (method == -1) break; /* error message already emitted */
  638.     bytes_out = 0; /* required for length check */
  639.     }
  640.  
  641.     close(ifd);
  642.     if (!to_stdout && close(ofd)) {
  643.     write_error();
  644.     }
  645.     if (method == -1) return;
  646.  
  647.     /* Display statistics */
  648.     if(verbose) {
  649.     if (!decompress) {
  650.         display_ratio(bytes_in-bytes_out-overhead, bytes_in);
  651.     }
  652.     if (test) {
  653.         fprintf(stderr, " OK");
  654.     } else if (!to_stdout) {
  655.         fprintf(stderr, " -- replaced with %s", ofname);
  656.     }
  657.     fprintf(stderr, "\n");
  658.     }
  659.     /* Copy modes, times, ownership */
  660.     if (!to_stdout) {
  661.     copy_stat(&istat);
  662.     }
  663. }
  664.  
  665. /* ========================================================================
  666.  * Create the output file. Try twice if ofname is exactly one beyond the
  667.  * name limit, to avoid creating a compressed file of name "1234567890123."
  668.  * We could actually loop more than once if the user gives an extra long
  669.  * name, but I prefer generating an error then. (Posix forbids the system
  670.  * to truncate names.) The error message is generated by check_ofname()
  671.  * in this case.
  672.  * IN assertion: the input file has already been open (ifd is set) and
  673.  * ofname has already been updated if there was an original name.
  674.  */
  675. local int create_outfile()
  676. {
  677.     struct stat ostat; /* stat for ofname */
  678.     int n;             /* loop counter */
  679.  
  680.     for (n = 1; n <= 2; n++) {
  681.     if (check_ofname() == -1) {
  682.         close(ifd);
  683.         return -1;
  684.     }
  685.     /* Create the output file */
  686.     remove_ofname = 1;
  687.     ofd = open(ofname, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, RW_USER);
  688.     if (ofd == -1) {
  689.         perror(ofname);
  690.         close(ifd);
  691.         exit_code = ERROR;
  692.         return -1;
  693.     }
  694.  
  695.     /* Check for name truncation on new file (1234567890123.z) */
  696.     if (fstat(ofd, &ostat) != 0) {
  697.         perror(ofname);
  698.         fprintf(stderr, " fstat failed\n");
  699.         close(ifd); close(ofd);
  700.         unlink(ofname);
  701.         exit_code = ERROR;
  702.         return -1;
  703.     }
  704.     if (!name_too_long(ofname, &ostat)) return 0;
  705.  
  706.     if (decompress) {
  707.         /* name might be too long if an original name was saved */
  708.         fprintf(stderr, " warning, name truncated: %s\n", ofname);
  709.         return 0;
  710.     } else {
  711. #ifdef NO_MULTIPLE_DOTS
  712.         /* Should never happen, see check_ofname() */
  713.         fprintf(stderr, "ERROR: name too long: %s\n", ofname);
  714.         do_exit(ERROR);
  715. #else
  716.         close(ofd);
  717.         unlink(ofname);
  718.         save_orig_name = 1;
  719.         strcpy(ofname+strlen(ofname)-3, ".z");
  720.         /* 1234567890123.z -> 123456789012.z */
  721. #endif
  722.     } /* decompress ? */
  723.     } /* for (n) */
  724.  
  725.     close(ifd);
  726.     fprintf(stderr, " name too long: %s\n", ofname);
  727.     exit_code = ERROR;
  728.     return -1;
  729. }
  730.  
  731. /* ========================================================================
  732.  * Use lstat if available, except for -c or -f. Use stat otherwise.
  733.  * This allows links when not removing the original file.
  734.  */
  735. local int do_stat(name, sbuf)
  736.     char *name;
  737.     struct stat *sbuf;
  738. {
  739. #if (defined(S_IFLNK) || defined (S_ISLNK)) && !defined(NO_SYMLINK)
  740.     if (!to_stdout && !force) {
  741.     return lstat(name, sbuf);
  742.     }
  743. #endif
  744.     return stat(name, sbuf);
  745. }
  746.  
  747. /* ========================================================================
  748.  * Set ifname to the input file name (with .z appended if necessary)
  749.  * and istat to its stats. Return 0 if ok, -1 if error.
  750.  */
  751. local int get_istat(iname, sbuf)
  752.     char *iname;
  753.     struct stat *sbuf;
  754. {
  755.     int iexists; /* set if iname exists */
  756.     int ilen = strlen(iname);
  757.  
  758.     strcpy(ifname, iname);
  759.     errno = 0;
  760.  
  761.     /* If input file exists, return OK. */
  762.     if (do_stat(ifname, sbuf) == 0) return 0;
  763.  
  764.     if (!decompress || errno != ENOENT) {
  765.     perror(ifname);
  766.     exit_code = ERROR;
  767.     return -1;
  768.     }
  769.     /* file.ext doesn't exist, try file.ext.z and file.ext.Z (or file.extz) */
  770.     if (ilen < 3 || (strcmp(ifname + ilen - 2, ".Z") != 0
  771.           && strcmp(ifname + ilen - 2, ".z") != 0)) {
  772. #ifdef NO_MULTIPLE_DOTS
  773.     if (strrchr(ifname, '.') != NULL) {
  774.        strcat(ifname, "z"), ilen += 1;
  775.     } else
  776. #endif
  777.     strcat(ifname, ".z"), ilen += 2;
  778.     errno = 0;
  779.     iexists = !do_stat(ifname, sbuf);
  780.     if (!iexists) {
  781.         errno = 0;
  782.         ifname[ilen-1] = 'Z';
  783.         iexists = !do_stat(ifname, sbuf);
  784.     }
  785. #ifdef NO_MULTIPLE_DOTS
  786.     /* One more try just to be nice to you */
  787.     if (!iexists) {
  788.         char c = ifname[ilen-2];
  789.         errno = 0;
  790.         strcpy(ifname+ilen-2, "z");
  791.         iexists = !do_stat(ifname, sbuf);
  792.         if (!iexists) {
  793.         ifname[ilen-2] = c;
  794.         }
  795.     }
  796. #endif
  797.     if (!iexists) {
  798.         ifname[ilen-1] = 'z';
  799.         perror(ifname);
  800.         exit_code = ERROR;
  801.         return -1;
  802.     }
  803.     if (!S_ISREG (sbuf->st_mode)) {
  804.         fprintf(stderr, "%s: Not a regular file -- ignored\n", ifname);
  805.         if (exit_code == OK) exit_code = WARNING;
  806.         return -1;
  807.     }
  808.     return 0; /* ok */
  809.     } /* try file.z */
  810.  
  811.     perror(ifname); /* ifname and ifname.z do not exist */
  812.     exit_code = ERROR;
  813.     return -1;
  814. }
  815.  
  816. /* ========================================================================
  817.  * Generate ofname given ifname. Return 0 if ok, -1 if file must be skipped.
  818.  * Initializes save_orig_name.
  819.  */
  820. local int make_ofname()
  821. {
  822.     int iflen = strlen(ifname);
  823. #ifdef NO_MULTIPLE_DOTS
  824.     int z_suffix = iflen > 2 && tolow(ifname[iflen-1]) == 'z';
  825. #else
  826.     int z_suffix = iflen > 2 && (strcmp(ifname+iflen-2, ".z") == 0
  827.               || strcmp(ifname+iflen-2, ".Z") == 0);
  828. #endif
  829.     int zip_suffix = iflen > 4 && (strcmp(ifname+iflen-4, ".zip") == 0
  830.               || strcmp(ifname+iflen-4, ".ZIP") == 0);
  831.  
  832.     if (decompress) {
  833.     /* Be tolerant for "zcat foo.tar-z | tar xf -" but do not
  834.      * complain for "gunzip -r *". In other words, force .z suffix
  835.      * for gunzip but not zcat.
  836.      */
  837.     if (!to_stdout && !z_suffix && !zip_suffix) {
  838.         if (verbose) {
  839.         fprintf(stderr,"%s -- no z suffix, ignored\n", ifname);
  840.         }
  841.         return -1;
  842.     }
  843.     strcpy(ofname, ifname);
  844.     if (z_suffix) {
  845.        /* Remove the z or .z suffix */
  846. #ifdef NO_MULTIPLE_DOTS
  847.         if (ofname[iflen - 2] != '.') {
  848.         ofname[iflen - 1] = '\0'; /* remove z suffix */
  849.         } else
  850. #endif
  851.         ofname[iflen - 2] = '\0'; /* Remove the .z suffix */
  852.     } else if (zip_suffix) {
  853.         ofname[iflen - 4] = '\0'; /* Remove the .zip suffix */
  854.     }
  855.     /* ofname might be changed later if infile contains an original name */
  856.  
  857.     } else { /* compress */
  858.     if (z_suffix) {
  859.         /* Avoid annoying messages with -r (see treat_dir()) */
  860.         if (verbose || !recursive) {
  861.         fprintf(stderr,"%s already has .%c suffix -- unchanged\n",
  862.             ifname, ifname[iflen-1]);
  863.         }
  864.         return -1;
  865.     }
  866.     if (zip_suffix) {
  867.         fprintf(stderr,"%s already has .zip suffix -- unchanged\n",
  868.             ifname);
  869.         return -1;
  870.     }
  871.     strcpy(ofname, ifname);
  872.     save_orig_name = 0;
  873.  
  874. #ifdef NO_MULTIPLE_DOTS
  875.     {
  876.         char *p = strrchr(ofname, '.');
  877.         if (p != NULL) {
  878.         strcat(ofname, do_lzw ? "Z" : "z");
  879.         save_orig_name = 1;
  880.         return 0;
  881.         }
  882.     }
  883. #endif
  884.     strcat(ofname, do_lzw ? ".Z" : ".z");
  885.  
  886.     } /* decompress ? */
  887.     return 0;
  888. }
  889.  
  890.  
  891. /* ========================================================================
  892.  * Check the magic number of the input file and update ofname if an
  893.  * original name was given and to_stdout is not set.
  894.  * Return the compression method, -1 for error, -2 for warning.
  895.  * Set inptr to the offset of the next byte to be processed.
  896.  * This function may be called repeatedly for an input file consisting
  897.  * of several contiguous gzip'ed members.
  898.  * IN assertions: there is at least one remaining compressed member.
  899.  *   If the member is a zip file, it must be the only one.
  900.  */
  901. local int get_method(in)
  902.     int in;        /* input file descriptor */
  903. {
  904.     uch flags;
  905.     char magic[2]; /* magic header */
  906.  
  907.     magic[0] = (char)get_byte();
  908.     magic[1] = (char)get_byte();
  909.  
  910.     time_stamp = istat.st_mtime; /* may be modified later for some methods */
  911.     method = -1;                 /* unknown yet */
  912.     part_nb++;                   /* number of parts in gzip file */
  913.     last_member = RECORD_IO;
  914.     /* assume multiple members in gzip file except for record oriented I/O */
  915.  
  916.     if (memcmp(magic, GZIP_MAGIC, 2) == 0
  917.     || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
  918.  
  919.     work = unzip;
  920.     method = (int)get_byte();
  921.     flags  = (uch)get_byte();
  922.     if ((flags & ENCRYPTED) != 0) {
  923.         fprintf(stderr, "%s is encrypted -- get newer version of gzip\n",
  924.             ifname);
  925.         exit_code = ERROR;
  926.         return -1;
  927.     }
  928.     if ((flags & CONTINUATION) != 0) {
  929.         fprintf(stderr,
  930.            "%s is a a multi-part gzip file -- get newer version of gzip\n",
  931.             ifname);
  932.         exit_code = ERROR;
  933.         if (force <= 1) return -1;
  934.     }
  935.     if ((flags & RESERVED) != 0) {
  936.         fprintf(stderr, "%s has flags 0x%x -- get newer version of gzip\n",
  937.             ifname, flags);
  938.         exit_code = ERROR;
  939.         if (force <= 1) return -1;
  940.     }
  941.     time_stamp  = (ulg)get_byte();
  942.     time_stamp |= ((ulg)get_byte()) << 8;
  943.     time_stamp |= ((ulg)get_byte()) << 16;
  944.     time_stamp |= ((ulg)get_byte()) << 24;
  945.  
  946.     (void)get_byte();  /* Ignore extra flags for the moment */
  947.     (void)get_byte();  /* Ignore OS type for the moment */
  948.  
  949.     if ((flags & CONTINUATION) != 0) {
  950.         unsigned part = (unsigned)get_byte();
  951.         part |= ((unsigned)get_byte())<<8;
  952.         if (verbose) {
  953.         fprintf(stderr,"%s: part number %u\n",
  954.             ifname, part);
  955.         }
  956.     }
  957.     if ((flags & EXTRA_FIELD) != 0) {
  958.         unsigned len = (unsigned)get_byte();
  959.         len |= ((unsigned)get_byte())<<8;
  960.         if (verbose) {
  961.         fprintf(stderr,"%s: extra field of %u bytes ignored\n",
  962.             ifname, len);
  963.         }
  964.         while (len--) (void)get_byte();
  965.     }
  966.  
  967.     /* Get original file name if it was truncated */
  968.     if ((flags & ORIG_NAME) != 0) {
  969.         if (to_stdout || part_nb > 1) {
  970.         /* Discard the old name */
  971.         while (get_byte() != 0) /* null */ ;
  972.         } else {
  973.         /* Copy the base name. Keep a directory prefix intact. */
  974.         char *p = basename(ofname);
  975.         for (;;) {
  976.             *p = (char)get_byte();
  977.             if (*p++ == '\0') break;
  978.             if (p >= ofname+sizeof(ofname)) {
  979.             error("corrupted input -- file name too large");
  980.             }
  981.         }
  982.         } /* to_stdout */
  983.     } /* orig_name */
  984.  
  985.     /* Discard file comment if any */
  986.     if ((flags & COMMENT) != 0) {
  987.         while (get_byte() != 0) /* null */ ;
  988.     }
  989.  
  990.     } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
  991.         && memcmp(inbuf, PKZIP_MAGIC, 4) == 0) {
  992.     /* To simplify the code, we support a zip file when alone only.
  993.      * We are thus guaranteed that the entire local header fits in inbuf.
  994.      */
  995.     inptr = 0;
  996.     work = unzip;
  997.     if (check_zipfile(in) == -1) return -1;
  998.     /* check_zipfile may get ofname from the local header */
  999.     last_member = 1;
  1000.  
  1001.     } else if (memcmp(magic, PACK_MAGIC, 2) == 0) {
  1002.     work = unpack;
  1003.     method = PACKED;
  1004.     } else if (memcmp(magic, LZW_MAGIC, 2) == 0) {
  1005.     work = unlzw;
  1006.     method = COMPRESSED;
  1007.     last_member = 1;
  1008.     }
  1009.     if (method == -1) {
  1010.     fprintf(stderr, part_nb == 1 ? "%s is not in gzip format\n"
  1011.                      : "trailing garbage ignored in %s\n",
  1012.         ifname);
  1013.     fflush(stderr);
  1014.     if (exit_code != ERROR) exit_code = part_nb == 1 ? ERROR : WARNING;
  1015.     return part_nb == 1 ? -1 : -2;
  1016.     }
  1017.     return method;
  1018. }
  1019.  
  1020. /* ========================================================================
  1021.  * Return true if the two stat structures correspond to the same file.
  1022.  */
  1023. local int same_file(stat1, stat2)
  1024.     struct stat *stat1;
  1025.     struct stat *stat2;
  1026. {
  1027.     return stat1->st_mode  == stat2->st_mode
  1028.     && stat1->st_ino   == stat2->st_ino
  1029.     && stat1->st_dev   == stat2->st_dev
  1030.     && stat1->st_uid   == stat2->st_uid
  1031.     && stat1->st_gid   == stat2->st_gid
  1032.     && stat1->st_size  == stat2->st_size
  1033.     && stat1->st_atime == stat2->st_atime
  1034.     && stat1->st_mtime == stat2->st_mtime
  1035.     && stat1->st_ctime == stat2->st_ctime;
  1036. }
  1037.  
  1038. /* ========================================================================
  1039.  * Return true if a file name is ambigous because the operating system
  1040.  * truncates file names.
  1041.  */
  1042. local int name_too_long(name, statb)
  1043.     char *name;           /* file name to check */
  1044.     struct stat *statb;   /* stat buf for this file name */
  1045. {
  1046.     int s = strlen(name);
  1047.     char c = name[s-1];
  1048.     struct stat tstat; /* stat for truncated name */
  1049.     int res;
  1050.  
  1051.     tstat = *statb;      /* Just in case OS does not fill all fields */
  1052.     name[s-1] = '\0';
  1053.     res = stat(name, &tstat) == 0 && same_file(statb, &tstat);
  1054.     name[s-1] = c;
  1055.     return res;
  1056. }
  1057.  
  1058. /* ========================================================================
  1059.  * If compressing to a file, check if ofname is not ambigous
  1060.  * because the operating system truncates names. Otherwise, generate
  1061.  * a new ofname and save the original name in the compressed file.
  1062.  * If the compressed file already exists, ask for confirmation.
  1063.  *    The check for name truncation is made dynamically, because different
  1064.  * file systems on the same OS might use different truncation rules (on SVR4
  1065.  * s5 truncates to 14 chars and ufs does not truncate).
  1066.  *    This function returns -1 if the file must be skipped, and
  1067.  * updates save_orig_name if necessary.
  1068.  * IN assertions: save_orig_name is already set if ofname has been
  1069.  * already truncated because of NO_MULTIPLE_DOTS. The input file has
  1070.  * already been open and istat is set.
  1071.  */
  1072. local int check_ofname()
  1073. {
  1074.     int s = strlen(ofname);
  1075.     struct stat ostat; /* stat for ofname */
  1076.  
  1077.     if (stat(ofname, &ostat) != 0) return 0;
  1078.  
  1079.     /* Check for name truncation on existing file: */
  1080. #ifdef NO_MULTIPLE_DOTS
  1081.     if (!decompress && name_too_long(ofname, &ostat)) {
  1082. #else
  1083.     if (!decompress && s > 8 && name_too_long(ofname, &ostat)) {
  1084. #endif
  1085.     save_orig_name = 1;
  1086. #ifdef NO_MULTIPLE_DOTS
  1087.     strcpy(ofname+s-2, "z");  /* f.extz -> f.exz  */
  1088. #else
  1089.     strcpy(ofname+s-4, ".z"); /* 12345678901234.z -> 123456789012.z */
  1090. #endif
  1091.     if (stat(ofname, &ostat) != 0) return 0;
  1092.     } /* !decompress && name_too_long */
  1093.  
  1094.     /* Check that the input and output files are different (could be
  1095.      * the same by name truncation or links).
  1096.      */
  1097.     if (same_file(&istat, &ostat)) {
  1098.     fprintf(stderr, "error: %s and %s are the same file\n",
  1099.         ifname, ofname);
  1100.     exit_code = ERROR;
  1101.     return -1;
  1102.     }
  1103.     /* Ask permission to overwrite the existing file */
  1104.     if (!force) {
  1105.     char response[80];
  1106.     strcpy(response,"n");
  1107.     fprintf(stderr, "%s already exists;", ofname);
  1108.     if (foreground && isatty(fileno(stdin))) {
  1109.         fprintf(stderr, " do you wish to overwrite (y or n)? ");
  1110.         fflush(stderr);
  1111.         (void)read(fileno(stdin), response, sizeof(response));
  1112.     }
  1113.     if (tolow(*response) != 'y') {
  1114.         fprintf(stderr, "\tnot overwritten\n");
  1115.         if (exit_code == OK) exit_code = WARNING;
  1116.         return -1;
  1117.     }
  1118.     }
  1119.     if (unlink(ofname)) {
  1120.     fprintf(stderr, "Can't remove old output file\n");
  1121.     perror(ofname);
  1122.     exit_code = ERROR;
  1123.     return -1;
  1124.     }
  1125.     return 0;
  1126. }
  1127.  
  1128.  
  1129. /* ========================================================================
  1130.  * Copy modes, times, ownership.
  1131.  * IN assertion: to_stdout is false.
  1132.  */
  1133. local void copy_stat(ifstat)
  1134.     struct stat *ifstat;
  1135. {
  1136. #ifndef NO_UTIME
  1137.     struct utimbuf      timep;
  1138.  
  1139.     /* Copy the time stamp */
  1140.     timep.actime = ifstat->st_atime;
  1141.     timep.modtime = ifstat->st_mtime;
  1142.  
  1143.     if (decompress && timep.modtime != time_stamp && time_stamp != 0) {
  1144.     timep.modtime = time_stamp;
  1145.     if (verbose) {
  1146.         fprintf(stderr, " (time stamp restored)\n");
  1147.     }
  1148.     }
  1149.     if (utime(ofname, &timep)) {
  1150.     fprintf(stderr, "\nutime error (ignored) ");
  1151.     perror(ofname);
  1152.     if (exit_code == OK) exit_code = WARNING;
  1153.     }
  1154. #endif
  1155.     /* Copy the protection modes */
  1156.     if (chmod(ofname, ifstat->st_mode & 07777)) {
  1157.     fprintf(stderr, "\nchmod error (ignored) ");
  1158.     perror(ofname);
  1159.     if (exit_code == OK) exit_code = WARNING;
  1160.     }
  1161. #ifndef NO_CHOWN
  1162.     chown(ofname, ifstat->st_uid, ifstat->st_gid);  /* Copy ownership */
  1163. #endif
  1164.     remove_ofname = 0;
  1165.     /* It's now safe to remove the input file: */
  1166.     if (unlink(ifname)) {
  1167.     fprintf(stderr, "\nunlink error (ignored) ");
  1168.     perror(ifname);
  1169.     if (exit_code == OK) exit_code = WARNING;
  1170.     }
  1171. }
  1172.  
  1173. #ifndef NO_DIR
  1174.  
  1175. /* ========================================================================
  1176.  * Recurse through the given directory. This code is taken from ncompress.
  1177.  */
  1178. local void treat_dir(dir)
  1179.     char *dir;
  1180. {
  1181.     dir_type *dp;
  1182.     DIR      *dirp;
  1183.     char     nbuf[MAX_PATH_LEN];
  1184.  
  1185.     dirp = opendir(dir);
  1186.     
  1187.     if (dirp == NULL) {
  1188.     fprintf(stderr, "%s unreadable\n", dir);
  1189.     return ;
  1190.     }
  1191.     /*
  1192.      ** WARNING: the following algorithm could occasionally cause
  1193.      ** compress to produce error warnings of the form "<filename>.z
  1194.      ** already has .z suffix - ignored". This occurs when the
  1195.      ** .z output file is inserted into the directory below
  1196.      ** readdir's current pointer.
  1197.      ** These warnings are harmless but annoying, so they are suppressed
  1198.      ** with option -r (except when -v is on). An alternative
  1199.      ** to allowing this would be to store the entire directory
  1200.      ** list in memory, then compress the entries in the stored
  1201.      ** list. Given the depth-first recursive algorithm used here,
  1202.      ** this could use up a tremendous amount of memory. I don't
  1203.      ** think it's worth it. -- Dave Mack
  1204.      ** (An other alternative might be two passes to avoid depth-first.)
  1205.      */
  1206.     
  1207.     while ((dp = readdir(dirp)) != NULL) {
  1208.  
  1209.     if (dp->d_ino == 0) {
  1210.         continue;
  1211.     }
  1212.     if (strcmp(dp->d_name,".") == 0 || strcmp(dp->d_name,"..") == 0) {
  1213.         continue;
  1214.     }
  1215.     if (((int)strlen(dir) + NLENGTH(dp) + 1) < (MAX_PATH_LEN - 1)) {
  1216.         strcpy(nbuf,dir);
  1217.         if (strlen(dir) > 0) { /* dir = "" means current dir on Amiga */
  1218. #ifdef OTHER_PATH_SEP
  1219.         if (dir[strlen(dir)-1] != OTHER_PATH_SEP)
  1220. #endif
  1221.         strcat(nbuf,"/");
  1222.         }
  1223.         strcat(nbuf,dp->d_name);
  1224.         treat_file(nbuf);
  1225.     } else {
  1226.         fprintf(stderr,"Pathname too long: %s/%s\n", dir, dp->d_name);
  1227.     }
  1228.     }
  1229.     closedir(dirp);
  1230. }
  1231. #endif /* ? NO_DIR */
  1232.  
  1233. /* ========================================================================
  1234.  * Free all dynamically allocated variables and exit with the given code.
  1235.  */
  1236. local void do_exit(exitcode)
  1237.     int exitcode;
  1238. {
  1239.     if (env != NULL)  free(env),  env  = NULL;
  1240.     if (args != NULL) free(args), args = NULL;
  1241.     FREE(inbuf);
  1242.     FREE(outbuf);
  1243.     FREE(d_buf);
  1244.     FREE(window);
  1245. #ifndef MAXSEG_64K
  1246.     FREE(tab_prefix);
  1247. #else
  1248.     FREE(tab_prefix0);
  1249.     FREE(tab_prefix1);
  1250. #endif
  1251.     exit(exitcode);
  1252. }
  1253.  
  1254. /* ========================================================================
  1255.  * Signal and error handler.
  1256.  */
  1257. RETSIGTYPE abort_gzip(void)
  1258. {
  1259.    if (remove_ofname) {
  1260.        close(ofd);
  1261.        unlink (ofname);
  1262.    }
  1263.    do_exit(ERROR);
  1264. }
  1265.