116dce513Schristos /* gun.c -- simple gunzip to give an example of the use of inflateBack()
216dce513Schristos * Copyright (C) 2003, 2005, 2008, 2010, 2012 Mark Adler
316dce513Schristos * For conditions of distribution and use, see copyright notice in zlib.h
416dce513Schristos Version 1.7 12 August 2012 Mark Adler */
516dce513Schristos
616dce513Schristos /* Version history:
716dce513Schristos 1.0 16 Feb 2003 First version for testing of inflateBack()
816dce513Schristos 1.1 21 Feb 2005 Decompress concatenated gzip streams
916dce513Schristos Remove use of "this" variable (C++ keyword)
1016dce513Schristos Fix return value for in()
1116dce513Schristos Improve allocation failure checking
1216dce513Schristos Add typecasting for void * structures
1316dce513Schristos Add -h option for command version and usage
1416dce513Schristos Add a bunch of comments
1516dce513Schristos 1.2 20 Mar 2005 Add Unix compress (LZW) decompression
1616dce513Schristos Copy file attributes from input file to output file
1716dce513Schristos 1.3 12 Jun 2005 Add casts for error messages [Oberhumer]
1816dce513Schristos 1.4 8 Dec 2006 LZW decompression speed improvements
1916dce513Schristos 1.5 9 Feb 2008 Avoid warning in latest version of gcc
2016dce513Schristos 1.6 17 Jan 2010 Avoid signed/unsigned comparison warnings
2116dce513Schristos 1.7 12 Aug 2012 Update for z_const usage in zlib 1.2.8
2216dce513Schristos */
2316dce513Schristos
2416dce513Schristos /*
2516dce513Schristos gun [ -t ] [ name ... ]
2616dce513Schristos
2716dce513Schristos decompresses the data in the named gzip files. If no arguments are given,
2816dce513Schristos gun will decompress from stdin to stdout. The names must end in .gz, -gz,
2916dce513Schristos .z, -z, _z, or .Z. The uncompressed data will be written to a file name
3016dce513Schristos with the suffix stripped. On success, the original file is deleted. On
3116dce513Schristos failure, the output file is deleted. For most failures, the command will
3216dce513Schristos continue to process the remaining names on the command line. A memory
3316dce513Schristos allocation failure will abort the command. If -t is specified, then the
3416dce513Schristos listed files or stdin will be tested as gzip files for integrity (without
3516dce513Schristos checking for a proper suffix), no output will be written, and no files
3616dce513Schristos will be deleted.
3716dce513Schristos
3816dce513Schristos Like gzip, gun allows concatenated gzip streams and will decompress them,
3916dce513Schristos writing all of the uncompressed data to the output. Unlike gzip, gun allows
4016dce513Schristos an empty file on input, and will produce no error writing an empty output
4116dce513Schristos file.
4216dce513Schristos
4316dce513Schristos gun will also decompress files made by Unix compress, which uses LZW
4416dce513Schristos compression. These files are automatically detected by virtue of their
4516dce513Schristos magic header bytes. Since the end of Unix compress stream is marked by the
4616dce513Schristos end-of-file, they cannot be concantenated. If a Unix compress stream is
4716dce513Schristos encountered in an input file, it is the last stream in that file.
4816dce513Schristos
49*ede78133Schristos Like gunzip and uncompress, the file attributes of the original compressed
5016dce513Schristos file are maintained in the final uncompressed file, to the extent that the
5116dce513Schristos user permissions allow it.
5216dce513Schristos
5316dce513Schristos On my Mac OS X PowerPC G4, gun is almost twice as fast as gunzip (version
5416dce513Schristos 1.2.4) is on the same file, when gun is linked with zlib 1.2.2. Also the
5516dce513Schristos LZW decompression provided by gun is about twice as fast as the standard
5616dce513Schristos Unix uncompress command.
5716dce513Schristos */
5816dce513Schristos
5916dce513Schristos /* external functions and related types and constants */
6016dce513Schristos #include <stdio.h> /* fprintf() */
6116dce513Schristos #include <stdlib.h> /* malloc(), free() */
6216dce513Schristos #include <string.h> /* strerror(), strcmp(), strlen(), memcpy() */
6316dce513Schristos #include <errno.h> /* errno */
6416dce513Schristos #include <fcntl.h> /* open() */
6516dce513Schristos #include <unistd.h> /* read(), write(), close(), chown(), unlink() */
6616dce513Schristos #include <sys/types.h>
6716dce513Schristos #include <sys/stat.h> /* stat(), chmod() */
6816dce513Schristos #include <utime.h> /* utime() */
6916dce513Schristos #include "zlib.h" /* inflateBackInit(), inflateBack(), */
7016dce513Schristos /* inflateBackEnd(), crc32() */
7116dce513Schristos
7216dce513Schristos /* function declaration */
7316dce513Schristos #define local static
7416dce513Schristos
7516dce513Schristos /* buffer constants */
7616dce513Schristos #define SIZE 32768U /* input and output buffer sizes */
7716dce513Schristos #define PIECE 16384 /* limits i/o chunks for 16-bit int case */
7816dce513Schristos
7916dce513Schristos /* structure for infback() to pass to input function in() -- it maintains the
8016dce513Schristos input file and a buffer of size SIZE */
8116dce513Schristos struct ind {
8216dce513Schristos int infile;
8316dce513Schristos unsigned char *inbuf;
8416dce513Schristos };
8516dce513Schristos
8616dce513Schristos /* Load input buffer, assumed to be empty, and return bytes loaded and a
8716dce513Schristos pointer to them. read() is called until the buffer is full, or until it
8816dce513Schristos returns end-of-file or error. Return 0 on error. */
in(void * in_desc,z_const unsigned char ** buf)8916dce513Schristos local unsigned in(void *in_desc, z_const unsigned char **buf)
9016dce513Schristos {
9116dce513Schristos int ret;
9216dce513Schristos unsigned len;
9316dce513Schristos unsigned char *next;
9416dce513Schristos struct ind *me = (struct ind *)in_desc;
9516dce513Schristos
9616dce513Schristos next = me->inbuf;
9716dce513Schristos *buf = next;
9816dce513Schristos len = 0;
9916dce513Schristos do {
10016dce513Schristos ret = PIECE;
10116dce513Schristos if ((unsigned)ret > SIZE - len)
10216dce513Schristos ret = (int)(SIZE - len);
10316dce513Schristos ret = (int)read(me->infile, next, ret);
10416dce513Schristos if (ret == -1) {
10516dce513Schristos len = 0;
10616dce513Schristos break;
10716dce513Schristos }
10816dce513Schristos next += ret;
10916dce513Schristos len += ret;
11016dce513Schristos } while (ret != 0 && len < SIZE);
11116dce513Schristos return len;
11216dce513Schristos }
11316dce513Schristos
11416dce513Schristos /* structure for infback() to pass to output function out() -- it maintains the
11516dce513Schristos output file, a running CRC-32 check on the output and the total number of
11616dce513Schristos bytes output, both for checking against the gzip trailer. (The length in
11716dce513Schristos the gzip trailer is stored modulo 2^32, so it's ok if a long is 32 bits and
11816dce513Schristos the output is greater than 4 GB.) */
11916dce513Schristos struct outd {
12016dce513Schristos int outfile;
12116dce513Schristos int check; /* true if checking crc and total */
12216dce513Schristos unsigned long crc;
12316dce513Schristos unsigned long total;
12416dce513Schristos };
12516dce513Schristos
12616dce513Schristos /* Write output buffer and update the CRC-32 and total bytes written. write()
12716dce513Schristos is called until all of the output is written or an error is encountered.
12816dce513Schristos On success out() returns 0. For a write failure, out() returns 1. If the
12916dce513Schristos output file descriptor is -1, then nothing is written.
13016dce513Schristos */
out(void * out_desc,unsigned char * buf,unsigned len)13116dce513Schristos local int out(void *out_desc, unsigned char *buf, unsigned len)
13216dce513Schristos {
13316dce513Schristos int ret;
13416dce513Schristos struct outd *me = (struct outd *)out_desc;
13516dce513Schristos
13616dce513Schristos if (me->check) {
13716dce513Schristos me->crc = crc32(me->crc, buf, len);
13816dce513Schristos me->total += len;
13916dce513Schristos }
14016dce513Schristos if (me->outfile != -1)
14116dce513Schristos do {
14216dce513Schristos ret = PIECE;
14316dce513Schristos if ((unsigned)ret > len)
14416dce513Schristos ret = (int)len;
14516dce513Schristos ret = (int)write(me->outfile, buf, ret);
14616dce513Schristos if (ret == -1)
14716dce513Schristos return 1;
14816dce513Schristos buf += ret;
14916dce513Schristos len -= ret;
15016dce513Schristos } while (len != 0);
15116dce513Schristos return 0;
15216dce513Schristos }
15316dce513Schristos
15416dce513Schristos /* next input byte macro for use inside lunpipe() and gunpipe() */
15516dce513Schristos #define NEXT() (have ? 0 : (have = in(indp, &next)), \
15616dce513Schristos last = have ? (have--, (int)(*next++)) : -1)
15716dce513Schristos
15816dce513Schristos /* memory for gunpipe() and lunpipe() --
15916dce513Schristos the first 256 entries of prefix[] and suffix[] are never used, could
16016dce513Schristos have offset the index, but it's faster to waste the memory */
16116dce513Schristos unsigned char inbuf[SIZE]; /* input buffer */
16216dce513Schristos unsigned char outbuf[SIZE]; /* output buffer */
16316dce513Schristos unsigned short prefix[65536]; /* index to LZW prefix string */
16416dce513Schristos unsigned char suffix[65536]; /* one-character LZW suffix */
16516dce513Schristos unsigned char match[65280 + 2]; /* buffer for reversed match or gzip
16616dce513Schristos 32K sliding window */
16716dce513Schristos
16816dce513Schristos /* throw out what's left in the current bits byte buffer (this is a vestigial
16916dce513Schristos aspect of the compressed data format derived from an implementation that
17016dce513Schristos made use of a special VAX machine instruction!) */
17116dce513Schristos #define FLUSHCODE() \
17216dce513Schristos do { \
17316dce513Schristos left = 0; \
17416dce513Schristos rem = 0; \
17516dce513Schristos if (chunk > have) { \
17616dce513Schristos chunk -= have; \
17716dce513Schristos have = 0; \
17816dce513Schristos if (NEXT() == -1) \
17916dce513Schristos break; \
18016dce513Schristos chunk--; \
18116dce513Schristos if (chunk > have) { \
18216dce513Schristos chunk = have = 0; \
18316dce513Schristos break; \
18416dce513Schristos } \
18516dce513Schristos } \
18616dce513Schristos have -= chunk; \
18716dce513Schristos next += chunk; \
18816dce513Schristos chunk = 0; \
18916dce513Schristos } while (0)
19016dce513Schristos
19116dce513Schristos /* Decompress a compress (LZW) file from indp to outfile. The compress magic
19216dce513Schristos header (two bytes) has already been read and verified. There are have bytes
19316dce513Schristos of buffered input at next. strm is used for passing error information back
19416dce513Schristos to gunpipe().
19516dce513Schristos
19616dce513Schristos lunpipe() will return Z_OK on success, Z_BUF_ERROR for an unexpected end of
19716dce513Schristos file, read error, or write error (a write error indicated by strm->next_in
19816dce513Schristos not equal to Z_NULL), or Z_DATA_ERROR for invalid input.
19916dce513Schristos */
lunpipe(unsigned have,z_const unsigned char * next,struct ind * indp,int outfile,z_stream * strm)20016dce513Schristos local int lunpipe(unsigned have, z_const unsigned char *next, struct ind *indp,
20116dce513Schristos int outfile, z_stream *strm)
20216dce513Schristos {
20316dce513Schristos int last; /* last byte read by NEXT(), or -1 if EOF */
20416dce513Schristos unsigned chunk; /* bytes left in current chunk */
20516dce513Schristos int left; /* bits left in rem */
20616dce513Schristos unsigned rem; /* unused bits from input */
20716dce513Schristos int bits; /* current bits per code */
20816dce513Schristos unsigned code; /* code, table traversal index */
20916dce513Schristos unsigned mask; /* mask for current bits codes */
21016dce513Schristos int max; /* maximum bits per code for this stream */
21116dce513Schristos unsigned flags; /* compress flags, then block compress flag */
21216dce513Schristos unsigned end; /* last valid entry in prefix/suffix tables */
21316dce513Schristos unsigned temp; /* current code */
21416dce513Schristos unsigned prev; /* previous code */
21516dce513Schristos unsigned final; /* last character written for previous code */
21616dce513Schristos unsigned stack; /* next position for reversed string */
21716dce513Schristos unsigned outcnt; /* bytes in output buffer */
21816dce513Schristos struct outd outd; /* output structure */
21916dce513Schristos unsigned char *p;
22016dce513Schristos
22116dce513Schristos /* set up output */
22216dce513Schristos outd.outfile = outfile;
22316dce513Schristos outd.check = 0;
22416dce513Schristos
22516dce513Schristos /* process remainder of compress header -- a flags byte */
22616dce513Schristos flags = NEXT();
22716dce513Schristos if (last == -1)
22816dce513Schristos return Z_BUF_ERROR;
22916dce513Schristos if (flags & 0x60) {
23016dce513Schristos strm->msg = (char *)"unknown lzw flags set";
23116dce513Schristos return Z_DATA_ERROR;
23216dce513Schristos }
23316dce513Schristos max = flags & 0x1f;
23416dce513Schristos if (max < 9 || max > 16) {
23516dce513Schristos strm->msg = (char *)"lzw bits out of range";
23616dce513Schristos return Z_DATA_ERROR;
23716dce513Schristos }
23816dce513Schristos if (max == 9) /* 9 doesn't really mean 9 */
23916dce513Schristos max = 10;
24016dce513Schristos flags &= 0x80; /* true if block compress */
24116dce513Schristos
24216dce513Schristos /* clear table */
24316dce513Schristos bits = 9;
24416dce513Schristos mask = 0x1ff;
24516dce513Schristos end = flags ? 256 : 255;
24616dce513Schristos
24716dce513Schristos /* set up: get first 9-bit code, which is the first decompressed byte, but
24816dce513Schristos don't create a table entry until the next code */
24916dce513Schristos if (NEXT() == -1) /* no compressed data is ok */
25016dce513Schristos return Z_OK;
25116dce513Schristos final = prev = (unsigned)last; /* low 8 bits of code */
25216dce513Schristos if (NEXT() == -1) /* missing a bit */
25316dce513Schristos return Z_BUF_ERROR;
25416dce513Schristos if (last & 1) { /* code must be < 256 */
25516dce513Schristos strm->msg = (char *)"invalid lzw code";
25616dce513Schristos return Z_DATA_ERROR;
25716dce513Schristos }
25816dce513Schristos rem = (unsigned)last >> 1; /* remaining 7 bits */
25916dce513Schristos left = 7;
26016dce513Schristos chunk = bits - 2; /* 7 bytes left in this chunk */
26116dce513Schristos outbuf[0] = (unsigned char)final; /* write first decompressed byte */
26216dce513Schristos outcnt = 1;
26316dce513Schristos
26416dce513Schristos /* decode codes */
26516dce513Schristos stack = 0;
26616dce513Schristos for (;;) {
26716dce513Schristos /* if the table will be full after this, increment the code size */
26816dce513Schristos if (end >= mask && bits < max) {
26916dce513Schristos FLUSHCODE();
27016dce513Schristos bits++;
27116dce513Schristos mask <<= 1;
27216dce513Schristos mask++;
27316dce513Schristos }
27416dce513Schristos
27516dce513Schristos /* get a code of length bits */
27616dce513Schristos if (chunk == 0) /* decrement chunk modulo bits */
27716dce513Schristos chunk = bits;
27816dce513Schristos code = rem; /* low bits of code */
27916dce513Schristos if (NEXT() == -1) { /* EOF is end of compressed data */
28016dce513Schristos /* write remaining buffered output */
28116dce513Schristos if (outcnt && out(&outd, outbuf, outcnt)) {
28216dce513Schristos strm->next_in = outbuf; /* signal write error */
28316dce513Schristos return Z_BUF_ERROR;
28416dce513Schristos }
28516dce513Schristos return Z_OK;
28616dce513Schristos }
28716dce513Schristos code += (unsigned)last << left; /* middle (or high) bits of code */
28816dce513Schristos left += 8;
28916dce513Schristos chunk--;
29016dce513Schristos if (bits > left) { /* need more bits */
29116dce513Schristos if (NEXT() == -1) /* can't end in middle of code */
29216dce513Schristos return Z_BUF_ERROR;
29316dce513Schristos code += (unsigned)last << left; /* high bits of code */
29416dce513Schristos left += 8;
29516dce513Schristos chunk--;
29616dce513Schristos }
29716dce513Schristos code &= mask; /* mask to current code length */
29816dce513Schristos left -= bits; /* number of unused bits */
29916dce513Schristos rem = (unsigned)last >> (8 - left); /* unused bits from last byte */
30016dce513Schristos
30116dce513Schristos /* process clear code (256) */
30216dce513Schristos if (code == 256 && flags) {
30316dce513Schristos FLUSHCODE();
30416dce513Schristos bits = 9; /* initialize bits and mask */
30516dce513Schristos mask = 0x1ff;
30616dce513Schristos end = 255; /* empty table */
30716dce513Schristos continue; /* get next code */
30816dce513Schristos }
30916dce513Schristos
31016dce513Schristos /* special code to reuse last match */
31116dce513Schristos temp = code; /* save the current code */
31216dce513Schristos if (code > end) {
31316dce513Schristos /* Be picky on the allowed code here, and make sure that the code
31416dce513Schristos we drop through (prev) will be a valid index so that random
31516dce513Schristos input does not cause an exception. The code != end + 1 check is
31616dce513Schristos empirically derived, and not checked in the original uncompress
31716dce513Schristos code. If this ever causes a problem, that check could be safely
31816dce513Schristos removed. Leaving this check in greatly improves gun's ability
31916dce513Schristos to detect random or corrupted input after a compress header.
32016dce513Schristos In any case, the prev > end check must be retained. */
32116dce513Schristos if (code != end + 1 || prev > end) {
32216dce513Schristos strm->msg = (char *)"invalid lzw code";
32316dce513Schristos return Z_DATA_ERROR;
32416dce513Schristos }
32516dce513Schristos match[stack++] = (unsigned char)final;
32616dce513Schristos code = prev;
32716dce513Schristos }
32816dce513Schristos
32916dce513Schristos /* walk through linked list to generate output in reverse order */
33016dce513Schristos p = match + stack;
33116dce513Schristos while (code >= 256) {
33216dce513Schristos *p++ = suffix[code];
33316dce513Schristos code = prefix[code];
33416dce513Schristos }
33516dce513Schristos stack = p - match;
33616dce513Schristos match[stack++] = (unsigned char)code;
33716dce513Schristos final = code;
33816dce513Schristos
33916dce513Schristos /* link new table entry */
34016dce513Schristos if (end < mask) {
34116dce513Schristos end++;
34216dce513Schristos prefix[end] = (unsigned short)prev;
34316dce513Schristos suffix[end] = (unsigned char)final;
34416dce513Schristos }
34516dce513Schristos
34616dce513Schristos /* set previous code for next iteration */
34716dce513Schristos prev = temp;
34816dce513Schristos
34916dce513Schristos /* write output in forward order */
35016dce513Schristos while (stack > SIZE - outcnt) {
35116dce513Schristos while (outcnt < SIZE)
35216dce513Schristos outbuf[outcnt++] = match[--stack];
35316dce513Schristos if (out(&outd, outbuf, outcnt)) {
35416dce513Schristos strm->next_in = outbuf; /* signal write error */
35516dce513Schristos return Z_BUF_ERROR;
35616dce513Schristos }
35716dce513Schristos outcnt = 0;
35816dce513Schristos }
35916dce513Schristos p = match + stack;
36016dce513Schristos do {
36116dce513Schristos outbuf[outcnt++] = *--p;
36216dce513Schristos } while (p > match);
36316dce513Schristos stack = 0;
36416dce513Schristos
36516dce513Schristos /* loop for next code with final and prev as the last match, rem and
36616dce513Schristos left provide the first 0..7 bits of the next code, end is the last
36716dce513Schristos valid table entry */
36816dce513Schristos }
36916dce513Schristos }
37016dce513Schristos
37116dce513Schristos /* Decompress a gzip file from infile to outfile. strm is assumed to have been
37216dce513Schristos successfully initialized with inflateBackInit(). The input file may consist
37316dce513Schristos of a series of gzip streams, in which case all of them will be decompressed
37416dce513Schristos to the output file. If outfile is -1, then the gzip stream(s) integrity is
37516dce513Schristos checked and nothing is written.
37616dce513Schristos
37716dce513Schristos The return value is a zlib error code: Z_MEM_ERROR if out of memory,
37816dce513Schristos Z_DATA_ERROR if the header or the compressed data is invalid, or if the
37916dce513Schristos trailer CRC-32 check or length doesn't match, Z_BUF_ERROR if the input ends
38016dce513Schristos prematurely or a write error occurs, or Z_ERRNO if junk (not a another gzip
38116dce513Schristos stream) follows a valid gzip stream.
38216dce513Schristos */
gunpipe(z_stream * strm,int infile,int outfile)38316dce513Schristos local int gunpipe(z_stream *strm, int infile, int outfile)
38416dce513Schristos {
38516dce513Schristos int ret, first, last;
38616dce513Schristos unsigned have, flags, len;
38716dce513Schristos z_const unsigned char *next = NULL;
38816dce513Schristos struct ind ind, *indp;
38916dce513Schristos struct outd outd;
39016dce513Schristos
39116dce513Schristos /* setup input buffer */
39216dce513Schristos ind.infile = infile;
39316dce513Schristos ind.inbuf = inbuf;
39416dce513Schristos indp = &ind;
39516dce513Schristos
39616dce513Schristos /* decompress concatenated gzip streams */
39716dce513Schristos have = 0; /* no input data read in yet */
39816dce513Schristos first = 1; /* looking for first gzip header */
39916dce513Schristos strm->next_in = Z_NULL; /* so Z_BUF_ERROR means EOF */
40016dce513Schristos for (;;) {
40116dce513Schristos /* look for the two magic header bytes for a gzip stream */
40216dce513Schristos if (NEXT() == -1) {
40316dce513Schristos ret = Z_OK;
40416dce513Schristos break; /* empty gzip stream is ok */
40516dce513Schristos }
40616dce513Schristos if (last != 31 || (NEXT() != 139 && last != 157)) {
40716dce513Schristos strm->msg = (char *)"incorrect header check";
40816dce513Schristos ret = first ? Z_DATA_ERROR : Z_ERRNO;
40916dce513Schristos break; /* not a gzip or compress header */
41016dce513Schristos }
41116dce513Schristos first = 0; /* next non-header is junk */
41216dce513Schristos
41316dce513Schristos /* process a compress (LZW) file -- can't be concatenated after this */
41416dce513Schristos if (last == 157) {
41516dce513Schristos ret = lunpipe(have, next, indp, outfile, strm);
41616dce513Schristos break;
41716dce513Schristos }
41816dce513Schristos
41916dce513Schristos /* process remainder of gzip header */
42016dce513Schristos ret = Z_BUF_ERROR;
42116dce513Schristos if (NEXT() != 8) { /* only deflate method allowed */
42216dce513Schristos if (last == -1) break;
42316dce513Schristos strm->msg = (char *)"unknown compression method";
42416dce513Schristos ret = Z_DATA_ERROR;
42516dce513Schristos break;
42616dce513Schristos }
42716dce513Schristos flags = NEXT(); /* header flags */
42816dce513Schristos NEXT(); /* discard mod time, xflgs, os */
42916dce513Schristos NEXT();
43016dce513Schristos NEXT();
43116dce513Schristos NEXT();
43216dce513Schristos NEXT();
43316dce513Schristos NEXT();
43416dce513Schristos if (last == -1) break;
43516dce513Schristos if (flags & 0xe0) {
43616dce513Schristos strm->msg = (char *)"unknown header flags set";
43716dce513Schristos ret = Z_DATA_ERROR;
43816dce513Schristos break;
43916dce513Schristos }
44016dce513Schristos if (flags & 4) { /* extra field */
44116dce513Schristos len = NEXT();
44216dce513Schristos len += (unsigned)(NEXT()) << 8;
44316dce513Schristos if (last == -1) break;
44416dce513Schristos while (len > have) {
44516dce513Schristos len -= have;
44616dce513Schristos have = 0;
44716dce513Schristos if (NEXT() == -1) break;
44816dce513Schristos len--;
44916dce513Schristos }
45016dce513Schristos if (last == -1) break;
45116dce513Schristos have -= len;
45216dce513Schristos next += len;
45316dce513Schristos }
45416dce513Schristos if (flags & 8) /* file name */
45516dce513Schristos while (NEXT() != 0 && last != -1)
45616dce513Schristos ;
45716dce513Schristos if (flags & 16) /* comment */
45816dce513Schristos while (NEXT() != 0 && last != -1)
45916dce513Schristos ;
46016dce513Schristos if (flags & 2) { /* header crc */
46116dce513Schristos NEXT();
46216dce513Schristos NEXT();
46316dce513Schristos }
46416dce513Schristos if (last == -1) break;
46516dce513Schristos
46616dce513Schristos /* set up output */
46716dce513Schristos outd.outfile = outfile;
46816dce513Schristos outd.check = 1;
46916dce513Schristos outd.crc = crc32(0L, Z_NULL, 0);
47016dce513Schristos outd.total = 0;
47116dce513Schristos
47216dce513Schristos /* decompress data to output */
47316dce513Schristos strm->next_in = next;
47416dce513Schristos strm->avail_in = have;
47516dce513Schristos ret = inflateBack(strm, in, indp, out, &outd);
47616dce513Schristos if (ret != Z_STREAM_END) break;
47716dce513Schristos next = strm->next_in;
47816dce513Schristos have = strm->avail_in;
47916dce513Schristos strm->next_in = Z_NULL; /* so Z_BUF_ERROR means EOF */
48016dce513Schristos
48116dce513Schristos /* check trailer */
48216dce513Schristos ret = Z_BUF_ERROR;
48316dce513Schristos if (NEXT() != (int)(outd.crc & 0xff) ||
48416dce513Schristos NEXT() != (int)((outd.crc >> 8) & 0xff) ||
48516dce513Schristos NEXT() != (int)((outd.crc >> 16) & 0xff) ||
48616dce513Schristos NEXT() != (int)((outd.crc >> 24) & 0xff)) {
48716dce513Schristos /* crc error */
48816dce513Schristos if (last != -1) {
48916dce513Schristos strm->msg = (char *)"incorrect data check";
49016dce513Schristos ret = Z_DATA_ERROR;
49116dce513Schristos }
49216dce513Schristos break;
49316dce513Schristos }
49416dce513Schristos if (NEXT() != (int)(outd.total & 0xff) ||
49516dce513Schristos NEXT() != (int)((outd.total >> 8) & 0xff) ||
49616dce513Schristos NEXT() != (int)((outd.total >> 16) & 0xff) ||
49716dce513Schristos NEXT() != (int)((outd.total >> 24) & 0xff)) {
49816dce513Schristos /* length error */
49916dce513Schristos if (last != -1) {
50016dce513Schristos strm->msg = (char *)"incorrect length check";
50116dce513Schristos ret = Z_DATA_ERROR;
50216dce513Schristos }
50316dce513Schristos break;
50416dce513Schristos }
50516dce513Schristos
50616dce513Schristos /* go back and look for another gzip stream */
50716dce513Schristos }
50816dce513Schristos
50916dce513Schristos /* clean up and return */
51016dce513Schristos return ret;
51116dce513Schristos }
51216dce513Schristos
51316dce513Schristos /* Copy file attributes, from -> to, as best we can. This is best effort, so
51416dce513Schristos no errors are reported. The mode bits, including suid, sgid, and the sticky
51516dce513Schristos bit are copied (if allowed), the owner's user id and group id are copied
51616dce513Schristos (again if allowed), and the access and modify times are copied. */
copymeta(char * from,char * to)51716dce513Schristos local void copymeta(char *from, char *to)
51816dce513Schristos {
51916dce513Schristos struct stat was;
52016dce513Schristos struct utimbuf when;
52116dce513Schristos
52216dce513Schristos /* get all of from's Unix meta data, return if not a regular file */
52316dce513Schristos if (stat(from, &was) != 0 || (was.st_mode & S_IFMT) != S_IFREG)
52416dce513Schristos return;
52516dce513Schristos
52616dce513Schristos /* set to's mode bits, ignore errors */
52716dce513Schristos (void)chmod(to, was.st_mode & 07777);
52816dce513Schristos
52916dce513Schristos /* copy owner's user and group, ignore errors */
53016dce513Schristos (void)chown(to, was.st_uid, was.st_gid);
53116dce513Schristos
53216dce513Schristos /* copy access and modify times, ignore errors */
53316dce513Schristos when.actime = was.st_atime;
53416dce513Schristos when.modtime = was.st_mtime;
53516dce513Schristos (void)utime(to, &when);
53616dce513Schristos }
53716dce513Schristos
53816dce513Schristos /* Decompress the file inname to the file outnname, of if test is true, just
53916dce513Schristos decompress without writing and check the gzip trailer for integrity. If
54016dce513Schristos inname is NULL or an empty string, read from stdin. If outname is NULL or
54116dce513Schristos an empty string, write to stdout. strm is a pre-initialized inflateBack
54216dce513Schristos structure. When appropriate, copy the file attributes from inname to
54316dce513Schristos outname.
54416dce513Schristos
54516dce513Schristos gunzip() returns 1 if there is an out-of-memory error or an unexpected
54616dce513Schristos return code from gunpipe(). Otherwise it returns 0.
54716dce513Schristos */
gunzip(z_stream * strm,char * inname,char * outname,int test)54816dce513Schristos local int gunzip(z_stream *strm, char *inname, char *outname, int test)
54916dce513Schristos {
55016dce513Schristos int ret;
55116dce513Schristos int infile, outfile;
55216dce513Schristos
55316dce513Schristos /* open files */
55416dce513Schristos if (inname == NULL || *inname == 0) {
55516dce513Schristos inname = "-";
55616dce513Schristos infile = 0; /* stdin */
55716dce513Schristos }
55816dce513Schristos else {
55916dce513Schristos infile = open(inname, O_RDONLY, 0);
56016dce513Schristos if (infile == -1) {
56116dce513Schristos fprintf(stderr, "gun cannot open %s\n", inname);
56216dce513Schristos return 0;
56316dce513Schristos }
56416dce513Schristos }
56516dce513Schristos if (test)
56616dce513Schristos outfile = -1;
56716dce513Schristos else if (outname == NULL || *outname == 0) {
56816dce513Schristos outname = "-";
56916dce513Schristos outfile = 1; /* stdout */
57016dce513Schristos }
57116dce513Schristos else {
57216dce513Schristos outfile = open(outname, O_CREAT | O_TRUNC | O_WRONLY, 0666);
57316dce513Schristos if (outfile == -1) {
57416dce513Schristos close(infile);
57516dce513Schristos fprintf(stderr, "gun cannot create %s\n", outname);
57616dce513Schristos return 0;
57716dce513Schristos }
57816dce513Schristos }
57916dce513Schristos errno = 0;
58016dce513Schristos
58116dce513Schristos /* decompress */
58216dce513Schristos ret = gunpipe(strm, infile, outfile);
58316dce513Schristos if (outfile > 2) close(outfile);
58416dce513Schristos if (infile > 2) close(infile);
58516dce513Schristos
58616dce513Schristos /* interpret result */
58716dce513Schristos switch (ret) {
58816dce513Schristos case Z_OK:
58916dce513Schristos case Z_ERRNO:
59016dce513Schristos if (infile > 2 && outfile > 2) {
59116dce513Schristos copymeta(inname, outname); /* copy attributes */
59216dce513Schristos unlink(inname);
59316dce513Schristos }
59416dce513Schristos if (ret == Z_ERRNO)
59516dce513Schristos fprintf(stderr, "gun warning: trailing garbage ignored in %s\n",
59616dce513Schristos inname);
59716dce513Schristos break;
59816dce513Schristos case Z_DATA_ERROR:
59916dce513Schristos if (outfile > 2) unlink(outname);
60016dce513Schristos fprintf(stderr, "gun data error on %s: %s\n", inname, strm->msg);
60116dce513Schristos break;
60216dce513Schristos case Z_MEM_ERROR:
60316dce513Schristos if (outfile > 2) unlink(outname);
60416dce513Schristos fprintf(stderr, "gun out of memory error--aborting\n");
60516dce513Schristos return 1;
60616dce513Schristos case Z_BUF_ERROR:
60716dce513Schristos if (outfile > 2) unlink(outname);
60816dce513Schristos if (strm->next_in != Z_NULL) {
60916dce513Schristos fprintf(stderr, "gun write error on %s: %s\n",
61016dce513Schristos outname, strerror(errno));
61116dce513Schristos }
61216dce513Schristos else if (errno) {
61316dce513Schristos fprintf(stderr, "gun read error on %s: %s\n",
61416dce513Schristos inname, strerror(errno));
61516dce513Schristos }
61616dce513Schristos else {
61716dce513Schristos fprintf(stderr, "gun unexpected end of file on %s\n",
61816dce513Schristos inname);
61916dce513Schristos }
62016dce513Schristos break;
62116dce513Schristos default:
62216dce513Schristos if (outfile > 2) unlink(outname);
62316dce513Schristos fprintf(stderr, "gun internal error--aborting\n");
62416dce513Schristos return 1;
62516dce513Schristos }
62616dce513Schristos return 0;
62716dce513Schristos }
62816dce513Schristos
62916dce513Schristos /* Process the gun command line arguments. See the command syntax near the
63016dce513Schristos beginning of this source file. */
main(int argc,char ** argv)63116dce513Schristos int main(int argc, char **argv)
63216dce513Schristos {
63316dce513Schristos int ret, len, test;
63416dce513Schristos char *outname;
63516dce513Schristos unsigned char *window;
63616dce513Schristos z_stream strm;
63716dce513Schristos
63816dce513Schristos /* initialize inflateBack state for repeated use */
63916dce513Schristos window = match; /* reuse LZW match buffer */
64016dce513Schristos strm.zalloc = Z_NULL;
64116dce513Schristos strm.zfree = Z_NULL;
64216dce513Schristos strm.opaque = Z_NULL;
64316dce513Schristos ret = inflateBackInit(&strm, 15, window);
64416dce513Schristos if (ret != Z_OK) {
64516dce513Schristos fprintf(stderr, "gun out of memory error--aborting\n");
64616dce513Schristos return 1;
64716dce513Schristos }
64816dce513Schristos
64916dce513Schristos /* decompress each file to the same name with the suffix removed */
65016dce513Schristos argc--;
65116dce513Schristos argv++;
65216dce513Schristos test = 0;
65316dce513Schristos if (argc && strcmp(*argv, "-h") == 0) {
65416dce513Schristos fprintf(stderr, "gun 1.6 (17 Jan 2010)\n");
65516dce513Schristos fprintf(stderr, "Copyright (C) 2003-2010 Mark Adler\n");
65616dce513Schristos fprintf(stderr, "usage: gun [-t] [file1.gz [file2.Z ...]]\n");
65716dce513Schristos return 0;
65816dce513Schristos }
65916dce513Schristos if (argc && strcmp(*argv, "-t") == 0) {
66016dce513Schristos test = 1;
66116dce513Schristos argc--;
66216dce513Schristos argv++;
66316dce513Schristos }
66416dce513Schristos if (argc)
66516dce513Schristos do {
66616dce513Schristos if (test)
66716dce513Schristos outname = NULL;
66816dce513Schristos else {
66916dce513Schristos len = (int)strlen(*argv);
67016dce513Schristos if (strcmp(*argv + len - 3, ".gz") == 0 ||
67116dce513Schristos strcmp(*argv + len - 3, "-gz") == 0)
67216dce513Schristos len -= 3;
67316dce513Schristos else if (strcmp(*argv + len - 2, ".z") == 0 ||
67416dce513Schristos strcmp(*argv + len - 2, "-z") == 0 ||
67516dce513Schristos strcmp(*argv + len - 2, "_z") == 0 ||
67616dce513Schristos strcmp(*argv + len - 2, ".Z") == 0)
67716dce513Schristos len -= 2;
67816dce513Schristos else {
67916dce513Schristos fprintf(stderr, "gun error: no gz type on %s--skipping\n",
68016dce513Schristos *argv);
68116dce513Schristos continue;
68216dce513Schristos }
68316dce513Schristos outname = malloc(len + 1);
68416dce513Schristos if (outname == NULL) {
68516dce513Schristos fprintf(stderr, "gun out of memory error--aborting\n");
68616dce513Schristos ret = 1;
68716dce513Schristos break;
68816dce513Schristos }
68916dce513Schristos memcpy(outname, *argv, len);
69016dce513Schristos outname[len] = 0;
69116dce513Schristos }
69216dce513Schristos ret = gunzip(&strm, *argv, outname, test);
69316dce513Schristos if (outname != NULL) free(outname);
69416dce513Schristos if (ret) break;
69516dce513Schristos } while (argv++, --argc);
69616dce513Schristos else
69716dce513Schristos ret = gunzip(&strm, NULL, NULL, test);
69816dce513Schristos
69916dce513Schristos /* clean up */
70016dce513Schristos inflateBackEnd(&strm);
70116dce513Schristos return ret;
70216dce513Schristos }
703