19573673dSchristos /* gun.c -- simple gunzip to give an example of the use of inflateBack()
28cbf5cb7Schristos * Copyright (C) 2003, 2005, 2008, 2010, 2012 Mark Adler
39573673dSchristos * For conditions of distribution and use, see copyright notice in zlib.h
48cbf5cb7Schristos Version 1.7 12 August 2012 Mark Adler */
59573673dSchristos
69573673dSchristos /* Version history:
79573673dSchristos 1.0 16 Feb 2003 First version for testing of inflateBack()
89573673dSchristos 1.1 21 Feb 2005 Decompress concatenated gzip streams
99573673dSchristos Remove use of "this" variable (C++ keyword)
109573673dSchristos Fix return value for in()
119573673dSchristos Improve allocation failure checking
129573673dSchristos Add typecasting for void * structures
139573673dSchristos Add -h option for command version and usage
149573673dSchristos Add a bunch of comments
159573673dSchristos 1.2 20 Mar 2005 Add Unix compress (LZW) decompression
169573673dSchristos Copy file attributes from input file to output file
179573673dSchristos 1.3 12 Jun 2005 Add casts for error messages [Oberhumer]
189573673dSchristos 1.4 8 Dec 2006 LZW decompression speed improvements
199573673dSchristos 1.5 9 Feb 2008 Avoid warning in latest version of gcc
209573673dSchristos 1.6 17 Jan 2010 Avoid signed/unsigned comparison warnings
218cbf5cb7Schristos 1.7 12 Aug 2012 Update for z_const usage in zlib 1.2.8
229573673dSchristos */
239573673dSchristos
249573673dSchristos /*
259573673dSchristos gun [ -t ] [ name ... ]
269573673dSchristos
279573673dSchristos decompresses the data in the named gzip files. If no arguments are given,
289573673dSchristos gun will decompress from stdin to stdout. The names must end in .gz, -gz,
299573673dSchristos .z, -z, _z, or .Z. The uncompressed data will be written to a file name
309573673dSchristos with the suffix stripped. On success, the original file is deleted. On
319573673dSchristos failure, the output file is deleted. For most failures, the command will
329573673dSchristos continue to process the remaining names on the command line. A memory
339573673dSchristos allocation failure will abort the command. If -t is specified, then the
349573673dSchristos listed files or stdin will be tested as gzip files for integrity (without
359573673dSchristos checking for a proper suffix), no output will be written, and no files
369573673dSchristos will be deleted.
379573673dSchristos
389573673dSchristos Like gzip, gun allows concatenated gzip streams and will decompress them,
399573673dSchristos writing all of the uncompressed data to the output. Unlike gzip, gun allows
409573673dSchristos an empty file on input, and will produce no error writing an empty output
419573673dSchristos file.
429573673dSchristos
439573673dSchristos gun will also decompress files made by Unix compress, which uses LZW
449573673dSchristos compression. These files are automatically detected by virtue of their
459573673dSchristos magic header bytes. Since the end of Unix compress stream is marked by the
469573673dSchristos end-of-file, they cannot be concantenated. If a Unix compress stream is
479573673dSchristos encountered in an input file, it is the last stream in that file.
489573673dSchristos
49*fc4f4269Schristos Like gunzip and uncompress, the file attributes of the original compressed
509573673dSchristos file are maintained in the final uncompressed file, to the extent that the
519573673dSchristos user permissions allow it.
529573673dSchristos
539573673dSchristos On my Mac OS X PowerPC G4, gun is almost twice as fast as gunzip (version
549573673dSchristos 1.2.4) is on the same file, when gun is linked with zlib 1.2.2. Also the
559573673dSchristos LZW decompression provided by gun is about twice as fast as the standard
569573673dSchristos Unix uncompress command.
579573673dSchristos */
589573673dSchristos
599573673dSchristos /* external functions and related types and constants */
609573673dSchristos #include <stdio.h> /* fprintf() */
619573673dSchristos #include <stdlib.h> /* malloc(), free() */
629573673dSchristos #include <string.h> /* strerror(), strcmp(), strlen(), memcpy() */
639573673dSchristos #include <errno.h> /* errno */
649573673dSchristos #include <fcntl.h> /* open() */
659573673dSchristos #include <unistd.h> /* read(), write(), close(), chown(), unlink() */
669573673dSchristos #include <sys/types.h>
679573673dSchristos #include <sys/stat.h> /* stat(), chmod() */
689573673dSchristos #include <utime.h> /* utime() */
699573673dSchristos #include "zlib.h" /* inflateBackInit(), inflateBack(), */
709573673dSchristos /* inflateBackEnd(), crc32() */
719573673dSchristos
729573673dSchristos /* function declaration */
739573673dSchristos #define local static
749573673dSchristos
759573673dSchristos /* buffer constants */
769573673dSchristos #define SIZE 32768U /* input and output buffer sizes */
779573673dSchristos #define PIECE 16384 /* limits i/o chunks for 16-bit int case */
789573673dSchristos
799573673dSchristos /* structure for infback() to pass to input function in() -- it maintains the
809573673dSchristos input file and a buffer of size SIZE */
819573673dSchristos struct ind {
829573673dSchristos int infile;
839573673dSchristos unsigned char *inbuf;
849573673dSchristos };
859573673dSchristos
869573673dSchristos /* Load input buffer, assumed to be empty, and return bytes loaded and a
879573673dSchristos pointer to them. read() is called until the buffer is full, or until it
889573673dSchristos returns end-of-file or error. Return 0 on error. */
in(void * in_desc,z_const unsigned char ** buf)898cbf5cb7Schristos local unsigned in(void *in_desc, z_const unsigned char **buf)
909573673dSchristos {
919573673dSchristos int ret;
929573673dSchristos unsigned len;
939573673dSchristos unsigned char *next;
949573673dSchristos struct ind *me = (struct ind *)in_desc;
959573673dSchristos
969573673dSchristos next = me->inbuf;
979573673dSchristos *buf = next;
989573673dSchristos len = 0;
999573673dSchristos do {
1009573673dSchristos ret = PIECE;
1019573673dSchristos if ((unsigned)ret > SIZE - len)
1029573673dSchristos ret = (int)(SIZE - len);
1039573673dSchristos ret = (int)read(me->infile, next, ret);
1049573673dSchristos if (ret == -1) {
1059573673dSchristos len = 0;
1069573673dSchristos break;
1079573673dSchristos }
1089573673dSchristos next += ret;
1099573673dSchristos len += ret;
1109573673dSchristos } while (ret != 0 && len < SIZE);
1119573673dSchristos return len;
1129573673dSchristos }
1139573673dSchristos
1149573673dSchristos /* structure for infback() to pass to output function out() -- it maintains the
1159573673dSchristos output file, a running CRC-32 check on the output and the total number of
1169573673dSchristos bytes output, both for checking against the gzip trailer. (The length in
1179573673dSchristos the gzip trailer is stored modulo 2^32, so it's ok if a long is 32 bits and
1189573673dSchristos the output is greater than 4 GB.) */
1199573673dSchristos struct outd {
1209573673dSchristos int outfile;
1219573673dSchristos int check; /* true if checking crc and total */
1229573673dSchristos unsigned long crc;
1239573673dSchristos unsigned long total;
1249573673dSchristos };
1259573673dSchristos
1269573673dSchristos /* Write output buffer and update the CRC-32 and total bytes written. write()
1279573673dSchristos is called until all of the output is written or an error is encountered.
1289573673dSchristos On success out() returns 0. For a write failure, out() returns 1. If the
1299573673dSchristos output file descriptor is -1, then nothing is written.
1309573673dSchristos */
out(void * out_desc,unsigned char * buf,unsigned len)1319573673dSchristos local int out(void *out_desc, unsigned char *buf, unsigned len)
1329573673dSchristos {
1339573673dSchristos int ret;
1349573673dSchristos struct outd *me = (struct outd *)out_desc;
1359573673dSchristos
1369573673dSchristos if (me->check) {
1379573673dSchristos me->crc = crc32(me->crc, buf, len);
1389573673dSchristos me->total += len;
1399573673dSchristos }
1409573673dSchristos if (me->outfile != -1)
1419573673dSchristos do {
1429573673dSchristos ret = PIECE;
1439573673dSchristos if ((unsigned)ret > len)
1449573673dSchristos ret = (int)len;
1459573673dSchristos ret = (int)write(me->outfile, buf, ret);
1469573673dSchristos if (ret == -1)
1479573673dSchristos return 1;
1489573673dSchristos buf += ret;
1499573673dSchristos len -= ret;
1509573673dSchristos } while (len != 0);
1519573673dSchristos return 0;
1529573673dSchristos }
1539573673dSchristos
1549573673dSchristos /* next input byte macro for use inside lunpipe() and gunpipe() */
1559573673dSchristos #define NEXT() (have ? 0 : (have = in(indp, &next)), \
1569573673dSchristos last = have ? (have--, (int)(*next++)) : -1)
1579573673dSchristos
1589573673dSchristos /* memory for gunpipe() and lunpipe() --
1599573673dSchristos the first 256 entries of prefix[] and suffix[] are never used, could
1609573673dSchristos have offset the index, but it's faster to waste the memory */
1619573673dSchristos unsigned char inbuf[SIZE]; /* input buffer */
1629573673dSchristos unsigned char outbuf[SIZE]; /* output buffer */
1639573673dSchristos unsigned short prefix[65536]; /* index to LZW prefix string */
1649573673dSchristos unsigned char suffix[65536]; /* one-character LZW suffix */
1659573673dSchristos unsigned char match[65280 + 2]; /* buffer for reversed match or gzip
1669573673dSchristos 32K sliding window */
1679573673dSchristos
1689573673dSchristos /* throw out what's left in the current bits byte buffer (this is a vestigial
1699573673dSchristos aspect of the compressed data format derived from an implementation that
1709573673dSchristos made use of a special VAX machine instruction!) */
1719573673dSchristos #define FLUSHCODE() \
1729573673dSchristos do { \
1739573673dSchristos left = 0; \
1749573673dSchristos rem = 0; \
1759573673dSchristos if (chunk > have) { \
1769573673dSchristos chunk -= have; \
1779573673dSchristos have = 0; \
1789573673dSchristos if (NEXT() == -1) \
1799573673dSchristos break; \
1809573673dSchristos chunk--; \
1819573673dSchristos if (chunk > have) { \
1829573673dSchristos chunk = have = 0; \
1839573673dSchristos break; \
1849573673dSchristos } \
1859573673dSchristos } \
1869573673dSchristos have -= chunk; \
1879573673dSchristos next += chunk; \
1889573673dSchristos chunk = 0; \
1899573673dSchristos } while (0)
1909573673dSchristos
1919573673dSchristos /* Decompress a compress (LZW) file from indp to outfile. The compress magic
1929573673dSchristos header (two bytes) has already been read and verified. There are have bytes
1939573673dSchristos of buffered input at next. strm is used for passing error information back
1949573673dSchristos to gunpipe().
1959573673dSchristos
1969573673dSchristos lunpipe() will return Z_OK on success, Z_BUF_ERROR for an unexpected end of
1979573673dSchristos file, read error, or write error (a write error indicated by strm->next_in
1989573673dSchristos not equal to Z_NULL), or Z_DATA_ERROR for invalid input.
1999573673dSchristos */
lunpipe(unsigned have,z_const unsigned char * next,struct ind * indp,int outfile,z_stream * strm)2008cbf5cb7Schristos local int lunpipe(unsigned have, z_const unsigned char *next, struct ind *indp,
2019573673dSchristos int outfile, z_stream *strm)
2029573673dSchristos {
2039573673dSchristos int last; /* last byte read by NEXT(), or -1 if EOF */
2049573673dSchristos unsigned chunk; /* bytes left in current chunk */
2059573673dSchristos int left; /* bits left in rem */
2069573673dSchristos unsigned rem; /* unused bits from input */
2079573673dSchristos int bits; /* current bits per code */
2089573673dSchristos unsigned code; /* code, table traversal index */
2099573673dSchristos unsigned mask; /* mask for current bits codes */
2109573673dSchristos int max; /* maximum bits per code for this stream */
2119573673dSchristos unsigned flags; /* compress flags, then block compress flag */
2129573673dSchristos unsigned end; /* last valid entry in prefix/suffix tables */
2139573673dSchristos unsigned temp; /* current code */
2149573673dSchristos unsigned prev; /* previous code */
2159573673dSchristos unsigned final; /* last character written for previous code */
2169573673dSchristos unsigned stack; /* next position for reversed string */
2179573673dSchristos unsigned outcnt; /* bytes in output buffer */
2189573673dSchristos struct outd outd; /* output structure */
2199573673dSchristos unsigned char *p;
2209573673dSchristos
2219573673dSchristos /* set up output */
2229573673dSchristos outd.outfile = outfile;
2239573673dSchristos outd.check = 0;
2249573673dSchristos
2259573673dSchristos /* process remainder of compress header -- a flags byte */
2269573673dSchristos flags = NEXT();
2279573673dSchristos if (last == -1)
2289573673dSchristos return Z_BUF_ERROR;
2299573673dSchristos if (flags & 0x60) {
2309573673dSchristos strm->msg = (char *)"unknown lzw flags set";
2319573673dSchristos return Z_DATA_ERROR;
2329573673dSchristos }
2339573673dSchristos max = flags & 0x1f;
2349573673dSchristos if (max < 9 || max > 16) {
2359573673dSchristos strm->msg = (char *)"lzw bits out of range";
2369573673dSchristos return Z_DATA_ERROR;
2379573673dSchristos }
2389573673dSchristos if (max == 9) /* 9 doesn't really mean 9 */
2399573673dSchristos max = 10;
2409573673dSchristos flags &= 0x80; /* true if block compress */
2419573673dSchristos
2429573673dSchristos /* clear table */
2439573673dSchristos bits = 9;
2449573673dSchristos mask = 0x1ff;
2459573673dSchristos end = flags ? 256 : 255;
2469573673dSchristos
2479573673dSchristos /* set up: get first 9-bit code, which is the first decompressed byte, but
2489573673dSchristos don't create a table entry until the next code */
2499573673dSchristos if (NEXT() == -1) /* no compressed data is ok */
2509573673dSchristos return Z_OK;
2519573673dSchristos final = prev = (unsigned)last; /* low 8 bits of code */
2529573673dSchristos if (NEXT() == -1) /* missing a bit */
2539573673dSchristos return Z_BUF_ERROR;
2549573673dSchristos if (last & 1) { /* code must be < 256 */
2559573673dSchristos strm->msg = (char *)"invalid lzw code";
2569573673dSchristos return Z_DATA_ERROR;
2579573673dSchristos }
2589573673dSchristos rem = (unsigned)last >> 1; /* remaining 7 bits */
2599573673dSchristos left = 7;
2609573673dSchristos chunk = bits - 2; /* 7 bytes left in this chunk */
2619573673dSchristos outbuf[0] = (unsigned char)final; /* write first decompressed byte */
2629573673dSchristos outcnt = 1;
2639573673dSchristos
2649573673dSchristos /* decode codes */
2659573673dSchristos stack = 0;
2669573673dSchristos for (;;) {
2679573673dSchristos /* if the table will be full after this, increment the code size */
2689573673dSchristos if (end >= mask && bits < max) {
2699573673dSchristos FLUSHCODE();
2709573673dSchristos bits++;
2719573673dSchristos mask <<= 1;
2729573673dSchristos mask++;
2739573673dSchristos }
2749573673dSchristos
2759573673dSchristos /* get a code of length bits */
2769573673dSchristos if (chunk == 0) /* decrement chunk modulo bits */
2779573673dSchristos chunk = bits;
2789573673dSchristos code = rem; /* low bits of code */
2799573673dSchristos if (NEXT() == -1) { /* EOF is end of compressed data */
2809573673dSchristos /* write remaining buffered output */
2819573673dSchristos if (outcnt && out(&outd, outbuf, outcnt)) {
2829573673dSchristos strm->next_in = outbuf; /* signal write error */
2839573673dSchristos return Z_BUF_ERROR;
2849573673dSchristos }
2859573673dSchristos return Z_OK;
2869573673dSchristos }
2879573673dSchristos code += (unsigned)last << left; /* middle (or high) bits of code */
2889573673dSchristos left += 8;
2899573673dSchristos chunk--;
2909573673dSchristos if (bits > left) { /* need more bits */
2919573673dSchristos if (NEXT() == -1) /* can't end in middle of code */
2929573673dSchristos return Z_BUF_ERROR;
2939573673dSchristos code += (unsigned)last << left; /* high bits of code */
2949573673dSchristos left += 8;
2959573673dSchristos chunk--;
2969573673dSchristos }
2979573673dSchristos code &= mask; /* mask to current code length */
2989573673dSchristos left -= bits; /* number of unused bits */
2999573673dSchristos rem = (unsigned)last >> (8 - left); /* unused bits from last byte */
3009573673dSchristos
3019573673dSchristos /* process clear code (256) */
3029573673dSchristos if (code == 256 && flags) {
3039573673dSchristos FLUSHCODE();
3049573673dSchristos bits = 9; /* initialize bits and mask */
3059573673dSchristos mask = 0x1ff;
3069573673dSchristos end = 255; /* empty table */
3079573673dSchristos continue; /* get next code */
3089573673dSchristos }
3099573673dSchristos
3109573673dSchristos /* special code to reuse last match */
3119573673dSchristos temp = code; /* save the current code */
3129573673dSchristos if (code > end) {
3139573673dSchristos /* Be picky on the allowed code here, and make sure that the code
3149573673dSchristos we drop through (prev) will be a valid index so that random
3159573673dSchristos input does not cause an exception. The code != end + 1 check is
3169573673dSchristos empirically derived, and not checked in the original uncompress
3179573673dSchristos code. If this ever causes a problem, that check could be safely
3189573673dSchristos removed. Leaving this check in greatly improves gun's ability
3199573673dSchristos to detect random or corrupted input after a compress header.
3209573673dSchristos In any case, the prev > end check must be retained. */
3219573673dSchristos if (code != end + 1 || prev > end) {
3229573673dSchristos strm->msg = (char *)"invalid lzw code";
3239573673dSchristos return Z_DATA_ERROR;
3249573673dSchristos }
3259573673dSchristos match[stack++] = (unsigned char)final;
3269573673dSchristos code = prev;
3279573673dSchristos }
3289573673dSchristos
3299573673dSchristos /* walk through linked list to generate output in reverse order */
3309573673dSchristos p = match + stack;
3319573673dSchristos while (code >= 256) {
3329573673dSchristos *p++ = suffix[code];
3339573673dSchristos code = prefix[code];
3349573673dSchristos }
3359573673dSchristos stack = p - match;
3369573673dSchristos match[stack++] = (unsigned char)code;
3379573673dSchristos final = code;
3389573673dSchristos
3399573673dSchristos /* link new table entry */
3409573673dSchristos if (end < mask) {
3419573673dSchristos end++;
3429573673dSchristos prefix[end] = (unsigned short)prev;
3439573673dSchristos suffix[end] = (unsigned char)final;
3449573673dSchristos }
3459573673dSchristos
3469573673dSchristos /* set previous code for next iteration */
3479573673dSchristos prev = temp;
3489573673dSchristos
3499573673dSchristos /* write output in forward order */
3509573673dSchristos while (stack > SIZE - outcnt) {
3519573673dSchristos while (outcnt < SIZE)
3529573673dSchristos outbuf[outcnt++] = match[--stack];
3539573673dSchristos if (out(&outd, outbuf, outcnt)) {
3549573673dSchristos strm->next_in = outbuf; /* signal write error */
3559573673dSchristos return Z_BUF_ERROR;
3569573673dSchristos }
3579573673dSchristos outcnt = 0;
3589573673dSchristos }
3599573673dSchristos p = match + stack;
3609573673dSchristos do {
3619573673dSchristos outbuf[outcnt++] = *--p;
3629573673dSchristos } while (p > match);
3639573673dSchristos stack = 0;
3649573673dSchristos
3659573673dSchristos /* loop for next code with final and prev as the last match, rem and
3669573673dSchristos left provide the first 0..7 bits of the next code, end is the last
3679573673dSchristos valid table entry */
3689573673dSchristos }
3699573673dSchristos }
3709573673dSchristos
3719573673dSchristos /* Decompress a gzip file from infile to outfile. strm is assumed to have been
3729573673dSchristos successfully initialized with inflateBackInit(). The input file may consist
3739573673dSchristos of a series of gzip streams, in which case all of them will be decompressed
3749573673dSchristos to the output file. If outfile is -1, then the gzip stream(s) integrity is
3759573673dSchristos checked and nothing is written.
3769573673dSchristos
3779573673dSchristos The return value is a zlib error code: Z_MEM_ERROR if out of memory,
3789573673dSchristos Z_DATA_ERROR if the header or the compressed data is invalid, or if the
3799573673dSchristos trailer CRC-32 check or length doesn't match, Z_BUF_ERROR if the input ends
3809573673dSchristos prematurely or a write error occurs, or Z_ERRNO if junk (not a another gzip
3819573673dSchristos stream) follows a valid gzip stream.
3829573673dSchristos */
gunpipe(z_stream * strm,int infile,int outfile)3839573673dSchristos local int gunpipe(z_stream *strm, int infile, int outfile)
3849573673dSchristos {
3859573673dSchristos int ret, first, last;
3869573673dSchristos unsigned have, flags, len;
3878cbf5cb7Schristos z_const unsigned char *next = NULL;
3889573673dSchristos struct ind ind, *indp;
3899573673dSchristos struct outd outd;
3909573673dSchristos
3919573673dSchristos /* setup input buffer */
3929573673dSchristos ind.infile = infile;
3939573673dSchristos ind.inbuf = inbuf;
3949573673dSchristos indp = &ind;
3959573673dSchristos
3969573673dSchristos /* decompress concatenated gzip streams */
3979573673dSchristos have = 0; /* no input data read in yet */
3989573673dSchristos first = 1; /* looking for first gzip header */
3999573673dSchristos strm->next_in = Z_NULL; /* so Z_BUF_ERROR means EOF */
4009573673dSchristos for (;;) {
4019573673dSchristos /* look for the two magic header bytes for a gzip stream */
4029573673dSchristos if (NEXT() == -1) {
4039573673dSchristos ret = Z_OK;
4049573673dSchristos break; /* empty gzip stream is ok */
4059573673dSchristos }
4069573673dSchristos if (last != 31 || (NEXT() != 139 && last != 157)) {
4079573673dSchristos strm->msg = (char *)"incorrect header check";
4089573673dSchristos ret = first ? Z_DATA_ERROR : Z_ERRNO;
4099573673dSchristos break; /* not a gzip or compress header */
4109573673dSchristos }
4119573673dSchristos first = 0; /* next non-header is junk */
4129573673dSchristos
4139573673dSchristos /* process a compress (LZW) file -- can't be concatenated after this */
4149573673dSchristos if (last == 157) {
4159573673dSchristos ret = lunpipe(have, next, indp, outfile, strm);
4169573673dSchristos break;
4179573673dSchristos }
4189573673dSchristos
4199573673dSchristos /* process remainder of gzip header */
4209573673dSchristos ret = Z_BUF_ERROR;
4219573673dSchristos if (NEXT() != 8) { /* only deflate method allowed */
4229573673dSchristos if (last == -1) break;
4239573673dSchristos strm->msg = (char *)"unknown compression method";
4249573673dSchristos ret = Z_DATA_ERROR;
4259573673dSchristos break;
4269573673dSchristos }
4279573673dSchristos flags = NEXT(); /* header flags */
4289573673dSchristos NEXT(); /* discard mod time, xflgs, os */
4299573673dSchristos NEXT();
4309573673dSchristos NEXT();
4319573673dSchristos NEXT();
4329573673dSchristos NEXT();
4339573673dSchristos NEXT();
4349573673dSchristos if (last == -1) break;
4359573673dSchristos if (flags & 0xe0) {
4369573673dSchristos strm->msg = (char *)"unknown header flags set";
4379573673dSchristos ret = Z_DATA_ERROR;
4389573673dSchristos break;
4399573673dSchristos }
4409573673dSchristos if (flags & 4) { /* extra field */
4419573673dSchristos len = NEXT();
4429573673dSchristos len += (unsigned)(NEXT()) << 8;
4439573673dSchristos if (last == -1) break;
4449573673dSchristos while (len > have) {
4459573673dSchristos len -= have;
4469573673dSchristos have = 0;
4479573673dSchristos if (NEXT() == -1) break;
4489573673dSchristos len--;
4499573673dSchristos }
4509573673dSchristos if (last == -1) break;
4519573673dSchristos have -= len;
4529573673dSchristos next += len;
4539573673dSchristos }
4549573673dSchristos if (flags & 8) /* file name */
4559573673dSchristos while (NEXT() != 0 && last != -1)
4569573673dSchristos ;
4579573673dSchristos if (flags & 16) /* comment */
4589573673dSchristos while (NEXT() != 0 && last != -1)
4599573673dSchristos ;
4609573673dSchristos if (flags & 2) { /* header crc */
4619573673dSchristos NEXT();
4629573673dSchristos NEXT();
4639573673dSchristos }
4649573673dSchristos if (last == -1) break;
4659573673dSchristos
4669573673dSchristos /* set up output */
4679573673dSchristos outd.outfile = outfile;
4689573673dSchristos outd.check = 1;
4699573673dSchristos outd.crc = crc32(0L, Z_NULL, 0);
4709573673dSchristos outd.total = 0;
4719573673dSchristos
4729573673dSchristos /* decompress data to output */
4739573673dSchristos strm->next_in = next;
4749573673dSchristos strm->avail_in = have;
4759573673dSchristos ret = inflateBack(strm, in, indp, out, &outd);
4769573673dSchristos if (ret != Z_STREAM_END) break;
4779573673dSchristos next = strm->next_in;
4789573673dSchristos have = strm->avail_in;
4799573673dSchristos strm->next_in = Z_NULL; /* so Z_BUF_ERROR means EOF */
4809573673dSchristos
4819573673dSchristos /* check trailer */
4829573673dSchristos ret = Z_BUF_ERROR;
4839573673dSchristos if (NEXT() != (int)(outd.crc & 0xff) ||
4849573673dSchristos NEXT() != (int)((outd.crc >> 8) & 0xff) ||
4859573673dSchristos NEXT() != (int)((outd.crc >> 16) & 0xff) ||
4869573673dSchristos NEXT() != (int)((outd.crc >> 24) & 0xff)) {
4879573673dSchristos /* crc error */
4889573673dSchristos if (last != -1) {
4899573673dSchristos strm->msg = (char *)"incorrect data check";
4909573673dSchristos ret = Z_DATA_ERROR;
4919573673dSchristos }
4929573673dSchristos break;
4939573673dSchristos }
4949573673dSchristos if (NEXT() != (int)(outd.total & 0xff) ||
4959573673dSchristos NEXT() != (int)((outd.total >> 8) & 0xff) ||
4969573673dSchristos NEXT() != (int)((outd.total >> 16) & 0xff) ||
4979573673dSchristos NEXT() != (int)((outd.total >> 24) & 0xff)) {
4989573673dSchristos /* length error */
4999573673dSchristos if (last != -1) {
5009573673dSchristos strm->msg = (char *)"incorrect length check";
5019573673dSchristos ret = Z_DATA_ERROR;
5029573673dSchristos }
5039573673dSchristos break;
5049573673dSchristos }
5059573673dSchristos
5069573673dSchristos /* go back and look for another gzip stream */
5079573673dSchristos }
5089573673dSchristos
5099573673dSchristos /* clean up and return */
5109573673dSchristos return ret;
5119573673dSchristos }
5129573673dSchristos
5139573673dSchristos /* Copy file attributes, from -> to, as best we can. This is best effort, so
5149573673dSchristos no errors are reported. The mode bits, including suid, sgid, and the sticky
5159573673dSchristos bit are copied (if allowed), the owner's user id and group id are copied
5169573673dSchristos (again if allowed), and the access and modify times are copied. */
copymeta(char * from,char * to)5179573673dSchristos local void copymeta(char *from, char *to)
5189573673dSchristos {
5199573673dSchristos struct stat was;
5209573673dSchristos struct utimbuf when;
5219573673dSchristos
5229573673dSchristos /* get all of from's Unix meta data, return if not a regular file */
5239573673dSchristos if (stat(from, &was) != 0 || (was.st_mode & S_IFMT) != S_IFREG)
5249573673dSchristos return;
5259573673dSchristos
5269573673dSchristos /* set to's mode bits, ignore errors */
5279573673dSchristos (void)chmod(to, was.st_mode & 07777);
5289573673dSchristos
5299573673dSchristos /* copy owner's user and group, ignore errors */
5309573673dSchristos (void)chown(to, was.st_uid, was.st_gid);
5319573673dSchristos
5329573673dSchristos /* copy access and modify times, ignore errors */
5339573673dSchristos when.actime = was.st_atime;
5349573673dSchristos when.modtime = was.st_mtime;
5359573673dSchristos (void)utime(to, &when);
5369573673dSchristos }
5379573673dSchristos
5389573673dSchristos /* Decompress the file inname to the file outnname, of if test is true, just
5399573673dSchristos decompress without writing and check the gzip trailer for integrity. If
5409573673dSchristos inname is NULL or an empty string, read from stdin. If outname is NULL or
5419573673dSchristos an empty string, write to stdout. strm is a pre-initialized inflateBack
5429573673dSchristos structure. When appropriate, copy the file attributes from inname to
5439573673dSchristos outname.
5449573673dSchristos
5459573673dSchristos gunzip() returns 1 if there is an out-of-memory error or an unexpected
5469573673dSchristos return code from gunpipe(). Otherwise it returns 0.
5479573673dSchristos */
gunzip(z_stream * strm,char * inname,char * outname,int test)5489573673dSchristos local int gunzip(z_stream *strm, char *inname, char *outname, int test)
5499573673dSchristos {
5509573673dSchristos int ret;
5519573673dSchristos int infile, outfile;
5529573673dSchristos
5539573673dSchristos /* open files */
5549573673dSchristos if (inname == NULL || *inname == 0) {
5559573673dSchristos inname = "-";
5569573673dSchristos infile = 0; /* stdin */
5579573673dSchristos }
5589573673dSchristos else {
5599573673dSchristos infile = open(inname, O_RDONLY, 0);
5609573673dSchristos if (infile == -1) {
5619573673dSchristos fprintf(stderr, "gun cannot open %s\n", inname);
5629573673dSchristos return 0;
5639573673dSchristos }
5649573673dSchristos }
5659573673dSchristos if (test)
5669573673dSchristos outfile = -1;
5679573673dSchristos else if (outname == NULL || *outname == 0) {
5689573673dSchristos outname = "-";
5699573673dSchristos outfile = 1; /* stdout */
5709573673dSchristos }
5719573673dSchristos else {
5729573673dSchristos outfile = open(outname, O_CREAT | O_TRUNC | O_WRONLY, 0666);
5739573673dSchristos if (outfile == -1) {
5749573673dSchristos close(infile);
5759573673dSchristos fprintf(stderr, "gun cannot create %s\n", outname);
5769573673dSchristos return 0;
5779573673dSchristos }
5789573673dSchristos }
5799573673dSchristos errno = 0;
5809573673dSchristos
5819573673dSchristos /* decompress */
5829573673dSchristos ret = gunpipe(strm, infile, outfile);
5839573673dSchristos if (outfile > 2) close(outfile);
5849573673dSchristos if (infile > 2) close(infile);
5859573673dSchristos
5869573673dSchristos /* interpret result */
5879573673dSchristos switch (ret) {
5889573673dSchristos case Z_OK:
5899573673dSchristos case Z_ERRNO:
5909573673dSchristos if (infile > 2 && outfile > 2) {
5919573673dSchristos copymeta(inname, outname); /* copy attributes */
5929573673dSchristos unlink(inname);
5939573673dSchristos }
5949573673dSchristos if (ret == Z_ERRNO)
5959573673dSchristos fprintf(stderr, "gun warning: trailing garbage ignored in %s\n",
5969573673dSchristos inname);
5979573673dSchristos break;
5989573673dSchristos case Z_DATA_ERROR:
5999573673dSchristos if (outfile > 2) unlink(outname);
6009573673dSchristos fprintf(stderr, "gun data error on %s: %s\n", inname, strm->msg);
6019573673dSchristos break;
6029573673dSchristos case Z_MEM_ERROR:
6039573673dSchristos if (outfile > 2) unlink(outname);
6049573673dSchristos fprintf(stderr, "gun out of memory error--aborting\n");
6059573673dSchristos return 1;
6069573673dSchristos case Z_BUF_ERROR:
6079573673dSchristos if (outfile > 2) unlink(outname);
6089573673dSchristos if (strm->next_in != Z_NULL) {
6099573673dSchristos fprintf(stderr, "gun write error on %s: %s\n",
6109573673dSchristos outname, strerror(errno));
6119573673dSchristos }
6129573673dSchristos else if (errno) {
6139573673dSchristos fprintf(stderr, "gun read error on %s: %s\n",
6149573673dSchristos inname, strerror(errno));
6159573673dSchristos }
6169573673dSchristos else {
6179573673dSchristos fprintf(stderr, "gun unexpected end of file on %s\n",
6189573673dSchristos inname);
6199573673dSchristos }
6209573673dSchristos break;
6219573673dSchristos default:
6229573673dSchristos if (outfile > 2) unlink(outname);
6239573673dSchristos fprintf(stderr, "gun internal error--aborting\n");
6249573673dSchristos return 1;
6259573673dSchristos }
6269573673dSchristos return 0;
6279573673dSchristos }
6289573673dSchristos
6299573673dSchristos /* Process the gun command line arguments. See the command syntax near the
6309573673dSchristos beginning of this source file. */
main(int argc,char ** argv)6319573673dSchristos int main(int argc, char **argv)
6329573673dSchristos {
6339573673dSchristos int ret, len, test;
6349573673dSchristos char *outname;
6359573673dSchristos unsigned char *window;
6369573673dSchristos z_stream strm;
6379573673dSchristos
6389573673dSchristos /* initialize inflateBack state for repeated use */
6399573673dSchristos window = match; /* reuse LZW match buffer */
6409573673dSchristos strm.zalloc = Z_NULL;
6419573673dSchristos strm.zfree = Z_NULL;
6429573673dSchristos strm.opaque = Z_NULL;
6439573673dSchristos ret = inflateBackInit(&strm, 15, window);
6449573673dSchristos if (ret != Z_OK) {
6459573673dSchristos fprintf(stderr, "gun out of memory error--aborting\n");
6469573673dSchristos return 1;
6479573673dSchristos }
6489573673dSchristos
6499573673dSchristos /* decompress each file to the same name with the suffix removed */
6509573673dSchristos argc--;
6519573673dSchristos argv++;
6529573673dSchristos test = 0;
6539573673dSchristos if (argc && strcmp(*argv, "-h") == 0) {
6549573673dSchristos fprintf(stderr, "gun 1.6 (17 Jan 2010)\n");
6559573673dSchristos fprintf(stderr, "Copyright (C) 2003-2010 Mark Adler\n");
6569573673dSchristos fprintf(stderr, "usage: gun [-t] [file1.gz [file2.Z ...]]\n");
6579573673dSchristos return 0;
6589573673dSchristos }
6599573673dSchristos if (argc && strcmp(*argv, "-t") == 0) {
6609573673dSchristos test = 1;
6619573673dSchristos argc--;
6629573673dSchristos argv++;
6639573673dSchristos }
6649573673dSchristos if (argc)
6659573673dSchristos do {
6669573673dSchristos if (test)
6679573673dSchristos outname = NULL;
6689573673dSchristos else {
6699573673dSchristos len = (int)strlen(*argv);
6709573673dSchristos if (strcmp(*argv + len - 3, ".gz") == 0 ||
6719573673dSchristos strcmp(*argv + len - 3, "-gz") == 0)
6729573673dSchristos len -= 3;
6739573673dSchristos else if (strcmp(*argv + len - 2, ".z") == 0 ||
6749573673dSchristos strcmp(*argv + len - 2, "-z") == 0 ||
6759573673dSchristos strcmp(*argv + len - 2, "_z") == 0 ||
6769573673dSchristos strcmp(*argv + len - 2, ".Z") == 0)
6779573673dSchristos len -= 2;
6789573673dSchristos else {
6799573673dSchristos fprintf(stderr, "gun error: no gz type on %s--skipping\n",
6809573673dSchristos *argv);
6819573673dSchristos continue;
6829573673dSchristos }
6839573673dSchristos outname = malloc(len + 1);
6849573673dSchristos if (outname == NULL) {
6859573673dSchristos fprintf(stderr, "gun out of memory error--aborting\n");
6869573673dSchristos ret = 1;
6879573673dSchristos break;
6889573673dSchristos }
6899573673dSchristos memcpy(outname, *argv, len);
6909573673dSchristos outname[len] = 0;
6919573673dSchristos }
6929573673dSchristos ret = gunzip(&strm, *argv, outname, test);
6939573673dSchristos if (outname != NULL) free(outname);
6949573673dSchristos if (ret) break;
6959573673dSchristos } while (argv++, --argc);
6969573673dSchristos else
6979573673dSchristos ret = gunzip(&strm, NULL, NULL, test);
6989573673dSchristos
6999573673dSchristos /* clean up */
7009573673dSchristos inflateBackEnd(&strm);
7019573673dSchristos return ret;
7029573673dSchristos }
703