14e00368fSchristos /* gun.c -- simple gunzip to give an example of the use of inflateBack()
2ed8eb4c2Schristos * Copyright (C) 2003, 2005, 2008, 2010, 2012 Mark Adler
34e00368fSchristos * For conditions of distribution and use, see copyright notice in zlib.h
4ed8eb4c2Schristos Version 1.7 12 August 2012 Mark Adler */
54e00368fSchristos
64e00368fSchristos /* Version history:
74e00368fSchristos 1.0 16 Feb 2003 First version for testing of inflateBack()
84e00368fSchristos 1.1 21 Feb 2005 Decompress concatenated gzip streams
94e00368fSchristos Remove use of "this" variable (C++ keyword)
104e00368fSchristos Fix return value for in()
114e00368fSchristos Improve allocation failure checking
124e00368fSchristos Add typecasting for void * structures
134e00368fSchristos Add -h option for command version and usage
144e00368fSchristos Add a bunch of comments
154e00368fSchristos 1.2 20 Mar 2005 Add Unix compress (LZW) decompression
164e00368fSchristos Copy file attributes from input file to output file
174e00368fSchristos 1.3 12 Jun 2005 Add casts for error messages [Oberhumer]
184e00368fSchristos 1.4 8 Dec 2006 LZW decompression speed improvements
194e00368fSchristos 1.5 9 Feb 2008 Avoid warning in latest version of gcc
204e00368fSchristos 1.6 17 Jan 2010 Avoid signed/unsigned comparison warnings
21ed8eb4c2Schristos 1.7 12 Aug 2012 Update for z_const usage in zlib 1.2.8
224e00368fSchristos */
234e00368fSchristos
244e00368fSchristos /*
254e00368fSchristos gun [ -t ] [ name ... ]
264e00368fSchristos
274e00368fSchristos decompresses the data in the named gzip files. If no arguments are given,
284e00368fSchristos gun will decompress from stdin to stdout. The names must end in .gz, -gz,
294e00368fSchristos .z, -z, _z, or .Z. The uncompressed data will be written to a file name
304e00368fSchristos with the suffix stripped. On success, the original file is deleted. On
314e00368fSchristos failure, the output file is deleted. For most failures, the command will
324e00368fSchristos continue to process the remaining names on the command line. A memory
334e00368fSchristos allocation failure will abort the command. If -t is specified, then the
344e00368fSchristos listed files or stdin will be tested as gzip files for integrity (without
354e00368fSchristos checking for a proper suffix), no output will be written, and no files
364e00368fSchristos will be deleted.
374e00368fSchristos
384e00368fSchristos Like gzip, gun allows concatenated gzip streams and will decompress them,
394e00368fSchristos writing all of the uncompressed data to the output. Unlike gzip, gun allows
404e00368fSchristos an empty file on input, and will produce no error writing an empty output
414e00368fSchristos file.
424e00368fSchristos
434e00368fSchristos gun will also decompress files made by Unix compress, which uses LZW
444e00368fSchristos compression. These files are automatically detected by virtue of their
454e00368fSchristos magic header bytes. Since the end of Unix compress stream is marked by the
464e00368fSchristos end-of-file, they cannot be concantenated. If a Unix compress stream is
474e00368fSchristos encountered in an input file, it is the last stream in that file.
484e00368fSchristos
49*699b0f92Schristos Like gunzip and uncompress, the file attributes of the original compressed
504e00368fSchristos file are maintained in the final uncompressed file, to the extent that the
514e00368fSchristos user permissions allow it.
524e00368fSchristos
534e00368fSchristos On my Mac OS X PowerPC G4, gun is almost twice as fast as gunzip (version
544e00368fSchristos 1.2.4) is on the same file, when gun is linked with zlib 1.2.2. Also the
554e00368fSchristos LZW decompression provided by gun is about twice as fast as the standard
564e00368fSchristos Unix uncompress command.
574e00368fSchristos */
584e00368fSchristos
594e00368fSchristos /* external functions and related types and constants */
604e00368fSchristos #include <stdio.h> /* fprintf() */
614e00368fSchristos #include <stdlib.h> /* malloc(), free() */
624e00368fSchristos #include <string.h> /* strerror(), strcmp(), strlen(), memcpy() */
634e00368fSchristos #include <errno.h> /* errno */
644e00368fSchristos #include <fcntl.h> /* open() */
654e00368fSchristos #include <unistd.h> /* read(), write(), close(), chown(), unlink() */
664e00368fSchristos #include <sys/types.h>
674e00368fSchristos #include <sys/stat.h> /* stat(), chmod() */
684e00368fSchristos #include <utime.h> /* utime() */
694e00368fSchristos #include "zlib.h" /* inflateBackInit(), inflateBack(), */
704e00368fSchristos /* inflateBackEnd(), crc32() */
714e00368fSchristos
724e00368fSchristos /* function declaration */
734e00368fSchristos #define local static
744e00368fSchristos
754e00368fSchristos /* buffer constants */
764e00368fSchristos #define SIZE 32768U /* input and output buffer sizes */
774e00368fSchristos #define PIECE 16384 /* limits i/o chunks for 16-bit int case */
784e00368fSchristos
794e00368fSchristos /* structure for infback() to pass to input function in() -- it maintains the
804e00368fSchristos input file and a buffer of size SIZE */
814e00368fSchristos struct ind {
824e00368fSchristos int infile;
834e00368fSchristos unsigned char *inbuf;
844e00368fSchristos };
854e00368fSchristos
864e00368fSchristos /* Load input buffer, assumed to be empty, and return bytes loaded and a
874e00368fSchristos pointer to them. read() is called until the buffer is full, or until it
884e00368fSchristos returns end-of-file or error. Return 0 on error. */
in(void * in_desc,z_const unsigned char ** buf)89ed8eb4c2Schristos local unsigned in(void *in_desc, z_const unsigned char **buf)
904e00368fSchristos {
914e00368fSchristos int ret;
924e00368fSchristos unsigned len;
934e00368fSchristos unsigned char *next;
944e00368fSchristos struct ind *me = (struct ind *)in_desc;
954e00368fSchristos
964e00368fSchristos next = me->inbuf;
974e00368fSchristos *buf = next;
984e00368fSchristos len = 0;
994e00368fSchristos do {
1004e00368fSchristos ret = PIECE;
1014e00368fSchristos if ((unsigned)ret > SIZE - len)
1024e00368fSchristos ret = (int)(SIZE - len);
1034e00368fSchristos ret = (int)read(me->infile, next, ret);
1044e00368fSchristos if (ret == -1) {
1054e00368fSchristos len = 0;
1064e00368fSchristos break;
1074e00368fSchristos }
1084e00368fSchristos next += ret;
1094e00368fSchristos len += ret;
1104e00368fSchristos } while (ret != 0 && len < SIZE);
1114e00368fSchristos return len;
1124e00368fSchristos }
1134e00368fSchristos
1144e00368fSchristos /* structure for infback() to pass to output function out() -- it maintains the
1154e00368fSchristos output file, a running CRC-32 check on the output and the total number of
1164e00368fSchristos bytes output, both for checking against the gzip trailer. (The length in
1174e00368fSchristos the gzip trailer is stored modulo 2^32, so it's ok if a long is 32 bits and
1184e00368fSchristos the output is greater than 4 GB.) */
1194e00368fSchristos struct outd {
1204e00368fSchristos int outfile;
1214e00368fSchristos int check; /* true if checking crc and total */
1224e00368fSchristos unsigned long crc;
1234e00368fSchristos unsigned long total;
1244e00368fSchristos };
1254e00368fSchristos
1264e00368fSchristos /* Write output buffer and update the CRC-32 and total bytes written. write()
1274e00368fSchristos is called until all of the output is written or an error is encountered.
1284e00368fSchristos On success out() returns 0. For a write failure, out() returns 1. If the
1294e00368fSchristos output file descriptor is -1, then nothing is written.
1304e00368fSchristos */
out(void * out_desc,unsigned char * buf,unsigned len)1314e00368fSchristos local int out(void *out_desc, unsigned char *buf, unsigned len)
1324e00368fSchristos {
1334e00368fSchristos int ret;
1344e00368fSchristos struct outd *me = (struct outd *)out_desc;
1354e00368fSchristos
1364e00368fSchristos if (me->check) {
1374e00368fSchristos me->crc = crc32(me->crc, buf, len);
1384e00368fSchristos me->total += len;
1394e00368fSchristos }
1404e00368fSchristos if (me->outfile != -1)
1414e00368fSchristos do {
1424e00368fSchristos ret = PIECE;
1434e00368fSchristos if ((unsigned)ret > len)
1444e00368fSchristos ret = (int)len;
1454e00368fSchristos ret = (int)write(me->outfile, buf, ret);
1464e00368fSchristos if (ret == -1)
1474e00368fSchristos return 1;
1484e00368fSchristos buf += ret;
1494e00368fSchristos len -= ret;
1504e00368fSchristos } while (len != 0);
1514e00368fSchristos return 0;
1524e00368fSchristos }
1534e00368fSchristos
1544e00368fSchristos /* next input byte macro for use inside lunpipe() and gunpipe() */
1554e00368fSchristos #define NEXT() (have ? 0 : (have = in(indp, &next)), \
1564e00368fSchristos last = have ? (have--, (int)(*next++)) : -1)
1574e00368fSchristos
1584e00368fSchristos /* memory for gunpipe() and lunpipe() --
1594e00368fSchristos the first 256 entries of prefix[] and suffix[] are never used, could
1604e00368fSchristos have offset the index, but it's faster to waste the memory */
1614e00368fSchristos unsigned char inbuf[SIZE]; /* input buffer */
1624e00368fSchristos unsigned char outbuf[SIZE]; /* output buffer */
1634e00368fSchristos unsigned short prefix[65536]; /* index to LZW prefix string */
1644e00368fSchristos unsigned char suffix[65536]; /* one-character LZW suffix */
1654e00368fSchristos unsigned char match[65280 + 2]; /* buffer for reversed match or gzip
1664e00368fSchristos 32K sliding window */
1674e00368fSchristos
1684e00368fSchristos /* throw out what's left in the current bits byte buffer (this is a vestigial
1694e00368fSchristos aspect of the compressed data format derived from an implementation that
1704e00368fSchristos made use of a special VAX machine instruction!) */
1714e00368fSchristos #define FLUSHCODE() \
1724e00368fSchristos do { \
1734e00368fSchristos left = 0; \
1744e00368fSchristos rem = 0; \
1754e00368fSchristos if (chunk > have) { \
1764e00368fSchristos chunk -= have; \
1774e00368fSchristos have = 0; \
1784e00368fSchristos if (NEXT() == -1) \
1794e00368fSchristos break; \
1804e00368fSchristos chunk--; \
1814e00368fSchristos if (chunk > have) { \
1824e00368fSchristos chunk = have = 0; \
1834e00368fSchristos break; \
1844e00368fSchristos } \
1854e00368fSchristos } \
1864e00368fSchristos have -= chunk; \
1874e00368fSchristos next += chunk; \
1884e00368fSchristos chunk = 0; \
1894e00368fSchristos } while (0)
1904e00368fSchristos
1914e00368fSchristos /* Decompress a compress (LZW) file from indp to outfile. The compress magic
1924e00368fSchristos header (two bytes) has already been read and verified. There are have bytes
1934e00368fSchristos of buffered input at next. strm is used for passing error information back
1944e00368fSchristos to gunpipe().
1954e00368fSchristos
1964e00368fSchristos lunpipe() will return Z_OK on success, Z_BUF_ERROR for an unexpected end of
1974e00368fSchristos file, read error, or write error (a write error indicated by strm->next_in
1984e00368fSchristos not equal to Z_NULL), or Z_DATA_ERROR for invalid input.
1994e00368fSchristos */
lunpipe(unsigned have,z_const unsigned char * next,struct ind * indp,int outfile,z_stream * strm)200ed8eb4c2Schristos local int lunpipe(unsigned have, z_const unsigned char *next, struct ind *indp,
2014e00368fSchristos int outfile, z_stream *strm)
2024e00368fSchristos {
2034e00368fSchristos int last; /* last byte read by NEXT(), or -1 if EOF */
2044e00368fSchristos unsigned chunk; /* bytes left in current chunk */
2054e00368fSchristos int left; /* bits left in rem */
2064e00368fSchristos unsigned rem; /* unused bits from input */
2074e00368fSchristos int bits; /* current bits per code */
2084e00368fSchristos unsigned code; /* code, table traversal index */
2094e00368fSchristos unsigned mask; /* mask for current bits codes */
2104e00368fSchristos int max; /* maximum bits per code for this stream */
2114e00368fSchristos unsigned flags; /* compress flags, then block compress flag */
2124e00368fSchristos unsigned end; /* last valid entry in prefix/suffix tables */
2134e00368fSchristos unsigned temp; /* current code */
2144e00368fSchristos unsigned prev; /* previous code */
2154e00368fSchristos unsigned final; /* last character written for previous code */
2164e00368fSchristos unsigned stack; /* next position for reversed string */
2174e00368fSchristos unsigned outcnt; /* bytes in output buffer */
2184e00368fSchristos struct outd outd; /* output structure */
2194e00368fSchristos unsigned char *p;
2204e00368fSchristos
2214e00368fSchristos /* set up output */
2224e00368fSchristos outd.outfile = outfile;
2234e00368fSchristos outd.check = 0;
2244e00368fSchristos
2254e00368fSchristos /* process remainder of compress header -- a flags byte */
2264e00368fSchristos flags = NEXT();
2274e00368fSchristos if (last == -1)
2284e00368fSchristos return Z_BUF_ERROR;
2294e00368fSchristos if (flags & 0x60) {
2304e00368fSchristos strm->msg = (char *)"unknown lzw flags set";
2314e00368fSchristos return Z_DATA_ERROR;
2324e00368fSchristos }
2334e00368fSchristos max = flags & 0x1f;
2344e00368fSchristos if (max < 9 || max > 16) {
2354e00368fSchristos strm->msg = (char *)"lzw bits out of range";
2364e00368fSchristos return Z_DATA_ERROR;
2374e00368fSchristos }
2384e00368fSchristos if (max == 9) /* 9 doesn't really mean 9 */
2394e00368fSchristos max = 10;
2404e00368fSchristos flags &= 0x80; /* true if block compress */
2414e00368fSchristos
2424e00368fSchristos /* clear table */
2434e00368fSchristos bits = 9;
2444e00368fSchristos mask = 0x1ff;
2454e00368fSchristos end = flags ? 256 : 255;
2464e00368fSchristos
2474e00368fSchristos /* set up: get first 9-bit code, which is the first decompressed byte, but
2484e00368fSchristos don't create a table entry until the next code */
2494e00368fSchristos if (NEXT() == -1) /* no compressed data is ok */
2504e00368fSchristos return Z_OK;
2514e00368fSchristos final = prev = (unsigned)last; /* low 8 bits of code */
2524e00368fSchristos if (NEXT() == -1) /* missing a bit */
2534e00368fSchristos return Z_BUF_ERROR;
2544e00368fSchristos if (last & 1) { /* code must be < 256 */
2554e00368fSchristos strm->msg = (char *)"invalid lzw code";
2564e00368fSchristos return Z_DATA_ERROR;
2574e00368fSchristos }
2584e00368fSchristos rem = (unsigned)last >> 1; /* remaining 7 bits */
2594e00368fSchristos left = 7;
2604e00368fSchristos chunk = bits - 2; /* 7 bytes left in this chunk */
2614e00368fSchristos outbuf[0] = (unsigned char)final; /* write first decompressed byte */
2624e00368fSchristos outcnt = 1;
2634e00368fSchristos
2644e00368fSchristos /* decode codes */
2654e00368fSchristos stack = 0;
2664e00368fSchristos for (;;) {
2674e00368fSchristos /* if the table will be full after this, increment the code size */
2684e00368fSchristos if (end >= mask && bits < max) {
2694e00368fSchristos FLUSHCODE();
2704e00368fSchristos bits++;
2714e00368fSchristos mask <<= 1;
2724e00368fSchristos mask++;
2734e00368fSchristos }
2744e00368fSchristos
2754e00368fSchristos /* get a code of length bits */
2764e00368fSchristos if (chunk == 0) /* decrement chunk modulo bits */
2774e00368fSchristos chunk = bits;
2784e00368fSchristos code = rem; /* low bits of code */
2794e00368fSchristos if (NEXT() == -1) { /* EOF is end of compressed data */
2804e00368fSchristos /* write remaining buffered output */
2814e00368fSchristos if (outcnt && out(&outd, outbuf, outcnt)) {
2824e00368fSchristos strm->next_in = outbuf; /* signal write error */
2834e00368fSchristos return Z_BUF_ERROR;
2844e00368fSchristos }
2854e00368fSchristos return Z_OK;
2864e00368fSchristos }
2874e00368fSchristos code += (unsigned)last << left; /* middle (or high) bits of code */
2884e00368fSchristos left += 8;
2894e00368fSchristos chunk--;
2904e00368fSchristos if (bits > left) { /* need more bits */
2914e00368fSchristos if (NEXT() == -1) /* can't end in middle of code */
2924e00368fSchristos return Z_BUF_ERROR;
2934e00368fSchristos code += (unsigned)last << left; /* high bits of code */
2944e00368fSchristos left += 8;
2954e00368fSchristos chunk--;
2964e00368fSchristos }
2974e00368fSchristos code &= mask; /* mask to current code length */
2984e00368fSchristos left -= bits; /* number of unused bits */
2994e00368fSchristos rem = (unsigned)last >> (8 - left); /* unused bits from last byte */
3004e00368fSchristos
3014e00368fSchristos /* process clear code (256) */
3024e00368fSchristos if (code == 256 && flags) {
3034e00368fSchristos FLUSHCODE();
3044e00368fSchristos bits = 9; /* initialize bits and mask */
3054e00368fSchristos mask = 0x1ff;
3064e00368fSchristos end = 255; /* empty table */
3074e00368fSchristos continue; /* get next code */
3084e00368fSchristos }
3094e00368fSchristos
3104e00368fSchristos /* special code to reuse last match */
3114e00368fSchristos temp = code; /* save the current code */
3124e00368fSchristos if (code > end) {
3134e00368fSchristos /* Be picky on the allowed code here, and make sure that the code
3144e00368fSchristos we drop through (prev) will be a valid index so that random
3154e00368fSchristos input does not cause an exception. The code != end + 1 check is
3164e00368fSchristos empirically derived, and not checked in the original uncompress
3174e00368fSchristos code. If this ever causes a problem, that check could be safely
3184e00368fSchristos removed. Leaving this check in greatly improves gun's ability
3194e00368fSchristos to detect random or corrupted input after a compress header.
3204e00368fSchristos In any case, the prev > end check must be retained. */
3214e00368fSchristos if (code != end + 1 || prev > end) {
3224e00368fSchristos strm->msg = (char *)"invalid lzw code";
3234e00368fSchristos return Z_DATA_ERROR;
3244e00368fSchristos }
3254e00368fSchristos match[stack++] = (unsigned char)final;
3264e00368fSchristos code = prev;
3274e00368fSchristos }
3284e00368fSchristos
3294e00368fSchristos /* walk through linked list to generate output in reverse order */
3304e00368fSchristos p = match + stack;
3314e00368fSchristos while (code >= 256) {
3324e00368fSchristos *p++ = suffix[code];
3334e00368fSchristos code = prefix[code];
3344e00368fSchristos }
3354e00368fSchristos stack = p - match;
3364e00368fSchristos match[stack++] = (unsigned char)code;
3374e00368fSchristos final = code;
3384e00368fSchristos
3394e00368fSchristos /* link new table entry */
3404e00368fSchristos if (end < mask) {
3414e00368fSchristos end++;
3424e00368fSchristos prefix[end] = (unsigned short)prev;
3434e00368fSchristos suffix[end] = (unsigned char)final;
3444e00368fSchristos }
3454e00368fSchristos
3464e00368fSchristos /* set previous code for next iteration */
3474e00368fSchristos prev = temp;
3484e00368fSchristos
3494e00368fSchristos /* write output in forward order */
3504e00368fSchristos while (stack > SIZE - outcnt) {
3514e00368fSchristos while (outcnt < SIZE)
3524e00368fSchristos outbuf[outcnt++] = match[--stack];
3534e00368fSchristos if (out(&outd, outbuf, outcnt)) {
3544e00368fSchristos strm->next_in = outbuf; /* signal write error */
3554e00368fSchristos return Z_BUF_ERROR;
3564e00368fSchristos }
3574e00368fSchristos outcnt = 0;
3584e00368fSchristos }
3594e00368fSchristos p = match + stack;
3604e00368fSchristos do {
3614e00368fSchristos outbuf[outcnt++] = *--p;
3624e00368fSchristos } while (p > match);
3634e00368fSchristos stack = 0;
3644e00368fSchristos
3654e00368fSchristos /* loop for next code with final and prev as the last match, rem and
3664e00368fSchristos left provide the first 0..7 bits of the next code, end is the last
3674e00368fSchristos valid table entry */
3684e00368fSchristos }
3694e00368fSchristos }
3704e00368fSchristos
3714e00368fSchristos /* Decompress a gzip file from infile to outfile. strm is assumed to have been
3724e00368fSchristos successfully initialized with inflateBackInit(). The input file may consist
3734e00368fSchristos of a series of gzip streams, in which case all of them will be decompressed
3744e00368fSchristos to the output file. If outfile is -1, then the gzip stream(s) integrity is
3754e00368fSchristos checked and nothing is written.
3764e00368fSchristos
3774e00368fSchristos The return value is a zlib error code: Z_MEM_ERROR if out of memory,
3784e00368fSchristos Z_DATA_ERROR if the header or the compressed data is invalid, or if the
3794e00368fSchristos trailer CRC-32 check or length doesn't match, Z_BUF_ERROR if the input ends
3804e00368fSchristos prematurely or a write error occurs, or Z_ERRNO if junk (not a another gzip
3814e00368fSchristos stream) follows a valid gzip stream.
3824e00368fSchristos */
gunpipe(z_stream * strm,int infile,int outfile)3834e00368fSchristos local int gunpipe(z_stream *strm, int infile, int outfile)
3844e00368fSchristos {
3854e00368fSchristos int ret, first, last;
3864e00368fSchristos unsigned have, flags, len;
387ed8eb4c2Schristos z_const unsigned char *next = NULL;
3884e00368fSchristos struct ind ind, *indp;
3894e00368fSchristos struct outd outd;
3904e00368fSchristos
3914e00368fSchristos /* setup input buffer */
3924e00368fSchristos ind.infile = infile;
3934e00368fSchristos ind.inbuf = inbuf;
3944e00368fSchristos indp = &ind;
3954e00368fSchristos
3964e00368fSchristos /* decompress concatenated gzip streams */
3974e00368fSchristos have = 0; /* no input data read in yet */
3984e00368fSchristos first = 1; /* looking for first gzip header */
3994e00368fSchristos strm->next_in = Z_NULL; /* so Z_BUF_ERROR means EOF */
4004e00368fSchristos for (;;) {
4014e00368fSchristos /* look for the two magic header bytes for a gzip stream */
4024e00368fSchristos if (NEXT() == -1) {
4034e00368fSchristos ret = Z_OK;
4044e00368fSchristos break; /* empty gzip stream is ok */
4054e00368fSchristos }
4064e00368fSchristos if (last != 31 || (NEXT() != 139 && last != 157)) {
4074e00368fSchristos strm->msg = (char *)"incorrect header check";
4084e00368fSchristos ret = first ? Z_DATA_ERROR : Z_ERRNO;
4094e00368fSchristos break; /* not a gzip or compress header */
4104e00368fSchristos }
4114e00368fSchristos first = 0; /* next non-header is junk */
4124e00368fSchristos
4134e00368fSchristos /* process a compress (LZW) file -- can't be concatenated after this */
4144e00368fSchristos if (last == 157) {
4154e00368fSchristos ret = lunpipe(have, next, indp, outfile, strm);
4164e00368fSchristos break;
4174e00368fSchristos }
4184e00368fSchristos
4194e00368fSchristos /* process remainder of gzip header */
4204e00368fSchristos ret = Z_BUF_ERROR;
4214e00368fSchristos if (NEXT() != 8) { /* only deflate method allowed */
4224e00368fSchristos if (last == -1) break;
4234e00368fSchristos strm->msg = (char *)"unknown compression method";
4244e00368fSchristos ret = Z_DATA_ERROR;
4254e00368fSchristos break;
4264e00368fSchristos }
4274e00368fSchristos flags = NEXT(); /* header flags */
4284e00368fSchristos NEXT(); /* discard mod time, xflgs, os */
4294e00368fSchristos NEXT();
4304e00368fSchristos NEXT();
4314e00368fSchristos NEXT();
4324e00368fSchristos NEXT();
4334e00368fSchristos NEXT();
4344e00368fSchristos if (last == -1) break;
4354e00368fSchristos if (flags & 0xe0) {
4364e00368fSchristos strm->msg = (char *)"unknown header flags set";
4374e00368fSchristos ret = Z_DATA_ERROR;
4384e00368fSchristos break;
4394e00368fSchristos }
4404e00368fSchristos if (flags & 4) { /* extra field */
4414e00368fSchristos len = NEXT();
4424e00368fSchristos len += (unsigned)(NEXT()) << 8;
4434e00368fSchristos if (last == -1) break;
4444e00368fSchristos while (len > have) {
4454e00368fSchristos len -= have;
4464e00368fSchristos have = 0;
4474e00368fSchristos if (NEXT() == -1) break;
4484e00368fSchristos len--;
4494e00368fSchristos }
4504e00368fSchristos if (last == -1) break;
4514e00368fSchristos have -= len;
4524e00368fSchristos next += len;
4534e00368fSchristos }
4544e00368fSchristos if (flags & 8) /* file name */
4554e00368fSchristos while (NEXT() != 0 && last != -1)
4564e00368fSchristos ;
4574e00368fSchristos if (flags & 16) /* comment */
4584e00368fSchristos while (NEXT() != 0 && last != -1)
4594e00368fSchristos ;
4604e00368fSchristos if (flags & 2) { /* header crc */
4614e00368fSchristos NEXT();
4624e00368fSchristos NEXT();
4634e00368fSchristos }
4644e00368fSchristos if (last == -1) break;
4654e00368fSchristos
4664e00368fSchristos /* set up output */
4674e00368fSchristos outd.outfile = outfile;
4684e00368fSchristos outd.check = 1;
4694e00368fSchristos outd.crc = crc32(0L, Z_NULL, 0);
4704e00368fSchristos outd.total = 0;
4714e00368fSchristos
4724e00368fSchristos /* decompress data to output */
4734e00368fSchristos strm->next_in = next;
4744e00368fSchristos strm->avail_in = have;
4754e00368fSchristos ret = inflateBack(strm, in, indp, out, &outd);
4764e00368fSchristos if (ret != Z_STREAM_END) break;
4774e00368fSchristos next = strm->next_in;
4784e00368fSchristos have = strm->avail_in;
4794e00368fSchristos strm->next_in = Z_NULL; /* so Z_BUF_ERROR means EOF */
4804e00368fSchristos
4814e00368fSchristos /* check trailer */
4824e00368fSchristos ret = Z_BUF_ERROR;
4834e00368fSchristos if (NEXT() != (int)(outd.crc & 0xff) ||
4844e00368fSchristos NEXT() != (int)((outd.crc >> 8) & 0xff) ||
4854e00368fSchristos NEXT() != (int)((outd.crc >> 16) & 0xff) ||
4864e00368fSchristos NEXT() != (int)((outd.crc >> 24) & 0xff)) {
4874e00368fSchristos /* crc error */
4884e00368fSchristos if (last != -1) {
4894e00368fSchristos strm->msg = (char *)"incorrect data check";
4904e00368fSchristos ret = Z_DATA_ERROR;
4914e00368fSchristos }
4924e00368fSchristos break;
4934e00368fSchristos }
4944e00368fSchristos if (NEXT() != (int)(outd.total & 0xff) ||
4954e00368fSchristos NEXT() != (int)((outd.total >> 8) & 0xff) ||
4964e00368fSchristos NEXT() != (int)((outd.total >> 16) & 0xff) ||
4974e00368fSchristos NEXT() != (int)((outd.total >> 24) & 0xff)) {
4984e00368fSchristos /* length error */
4994e00368fSchristos if (last != -1) {
5004e00368fSchristos strm->msg = (char *)"incorrect length check";
5014e00368fSchristos ret = Z_DATA_ERROR;
5024e00368fSchristos }
5034e00368fSchristos break;
5044e00368fSchristos }
5054e00368fSchristos
5064e00368fSchristos /* go back and look for another gzip stream */
5074e00368fSchristos }
5084e00368fSchristos
5094e00368fSchristos /* clean up and return */
5104e00368fSchristos return ret;
5114e00368fSchristos }
5124e00368fSchristos
5134e00368fSchristos /* Copy file attributes, from -> to, as best we can. This is best effort, so
5144e00368fSchristos no errors are reported. The mode bits, including suid, sgid, and the sticky
5154e00368fSchristos bit are copied (if allowed), the owner's user id and group id are copied
5164e00368fSchristos (again if allowed), and the access and modify times are copied. */
copymeta(char * from,char * to)5174e00368fSchristos local void copymeta(char *from, char *to)
5184e00368fSchristos {
5194e00368fSchristos struct stat was;
5204e00368fSchristos struct utimbuf when;
5214e00368fSchristos
5224e00368fSchristos /* get all of from's Unix meta data, return if not a regular file */
5234e00368fSchristos if (stat(from, &was) != 0 || (was.st_mode & S_IFMT) != S_IFREG)
5244e00368fSchristos return;
5254e00368fSchristos
5264e00368fSchristos /* set to's mode bits, ignore errors */
5274e00368fSchristos (void)chmod(to, was.st_mode & 07777);
5284e00368fSchristos
5294e00368fSchristos /* copy owner's user and group, ignore errors */
5304e00368fSchristos (void)chown(to, was.st_uid, was.st_gid);
5314e00368fSchristos
5324e00368fSchristos /* copy access and modify times, ignore errors */
5334e00368fSchristos when.actime = was.st_atime;
5344e00368fSchristos when.modtime = was.st_mtime;
5354e00368fSchristos (void)utime(to, &when);
5364e00368fSchristos }
5374e00368fSchristos
5384e00368fSchristos /* Decompress the file inname to the file outnname, of if test is true, just
5394e00368fSchristos decompress without writing and check the gzip trailer for integrity. If
5404e00368fSchristos inname is NULL or an empty string, read from stdin. If outname is NULL or
5414e00368fSchristos an empty string, write to stdout. strm is a pre-initialized inflateBack
5424e00368fSchristos structure. When appropriate, copy the file attributes from inname to
5434e00368fSchristos outname.
5444e00368fSchristos
5454e00368fSchristos gunzip() returns 1 if there is an out-of-memory error or an unexpected
5464e00368fSchristos return code from gunpipe(). Otherwise it returns 0.
5474e00368fSchristos */
gunzip(z_stream * strm,char * inname,char * outname,int test)5484e00368fSchristos local int gunzip(z_stream *strm, char *inname, char *outname, int test)
5494e00368fSchristos {
5504e00368fSchristos int ret;
5514e00368fSchristos int infile, outfile;
5524e00368fSchristos
5534e00368fSchristos /* open files */
5544e00368fSchristos if (inname == NULL || *inname == 0) {
5554e00368fSchristos inname = "-";
5564e00368fSchristos infile = 0; /* stdin */
5574e00368fSchristos }
5584e00368fSchristos else {
5594e00368fSchristos infile = open(inname, O_RDONLY, 0);
5604e00368fSchristos if (infile == -1) {
5614e00368fSchristos fprintf(stderr, "gun cannot open %s\n", inname);
5624e00368fSchristos return 0;
5634e00368fSchristos }
5644e00368fSchristos }
5654e00368fSchristos if (test)
5664e00368fSchristos outfile = -1;
5674e00368fSchristos else if (outname == NULL || *outname == 0) {
5684e00368fSchristos outname = "-";
5694e00368fSchristos outfile = 1; /* stdout */
5704e00368fSchristos }
5714e00368fSchristos else {
5724e00368fSchristos outfile = open(outname, O_CREAT | O_TRUNC | O_WRONLY, 0666);
5734e00368fSchristos if (outfile == -1) {
5744e00368fSchristos close(infile);
5754e00368fSchristos fprintf(stderr, "gun cannot create %s\n", outname);
5764e00368fSchristos return 0;
5774e00368fSchristos }
5784e00368fSchristos }
5794e00368fSchristos errno = 0;
5804e00368fSchristos
5814e00368fSchristos /* decompress */
5824e00368fSchristos ret = gunpipe(strm, infile, outfile);
5834e00368fSchristos if (outfile > 2) close(outfile);
5844e00368fSchristos if (infile > 2) close(infile);
5854e00368fSchristos
5864e00368fSchristos /* interpret result */
5874e00368fSchristos switch (ret) {
5884e00368fSchristos case Z_OK:
5894e00368fSchristos case Z_ERRNO:
5904e00368fSchristos if (infile > 2 && outfile > 2) {
5914e00368fSchristos copymeta(inname, outname); /* copy attributes */
5924e00368fSchristos unlink(inname);
5934e00368fSchristos }
5944e00368fSchristos if (ret == Z_ERRNO)
5954e00368fSchristos fprintf(stderr, "gun warning: trailing garbage ignored in %s\n",
5964e00368fSchristos inname);
5974e00368fSchristos break;
5984e00368fSchristos case Z_DATA_ERROR:
5994e00368fSchristos if (outfile > 2) unlink(outname);
6004e00368fSchristos fprintf(stderr, "gun data error on %s: %s\n", inname, strm->msg);
6014e00368fSchristos break;
6024e00368fSchristos case Z_MEM_ERROR:
6034e00368fSchristos if (outfile > 2) unlink(outname);
6044e00368fSchristos fprintf(stderr, "gun out of memory error--aborting\n");
6054e00368fSchristos return 1;
6064e00368fSchristos case Z_BUF_ERROR:
6074e00368fSchristos if (outfile > 2) unlink(outname);
6084e00368fSchristos if (strm->next_in != Z_NULL) {
6094e00368fSchristos fprintf(stderr, "gun write error on %s: %s\n",
6104e00368fSchristos outname, strerror(errno));
6114e00368fSchristos }
6124e00368fSchristos else if (errno) {
6134e00368fSchristos fprintf(stderr, "gun read error on %s: %s\n",
6144e00368fSchristos inname, strerror(errno));
6154e00368fSchristos }
6164e00368fSchristos else {
6174e00368fSchristos fprintf(stderr, "gun unexpected end of file on %s\n",
6184e00368fSchristos inname);
6194e00368fSchristos }
6204e00368fSchristos break;
6214e00368fSchristos default:
6224e00368fSchristos if (outfile > 2) unlink(outname);
6234e00368fSchristos fprintf(stderr, "gun internal error--aborting\n");
6244e00368fSchristos return 1;
6254e00368fSchristos }
6264e00368fSchristos return 0;
6274e00368fSchristos }
6284e00368fSchristos
6294e00368fSchristos /* Process the gun command line arguments. See the command syntax near the
6304e00368fSchristos beginning of this source file. */
main(int argc,char ** argv)6314e00368fSchristos int main(int argc, char **argv)
6324e00368fSchristos {
6334e00368fSchristos int ret, len, test;
6344e00368fSchristos char *outname;
6354e00368fSchristos unsigned char *window;
6364e00368fSchristos z_stream strm;
6374e00368fSchristos
6384e00368fSchristos /* initialize inflateBack state for repeated use */
6394e00368fSchristos window = match; /* reuse LZW match buffer */
6404e00368fSchristos strm.zalloc = Z_NULL;
6414e00368fSchristos strm.zfree = Z_NULL;
6424e00368fSchristos strm.opaque = Z_NULL;
6434e00368fSchristos ret = inflateBackInit(&strm, 15, window);
6444e00368fSchristos if (ret != Z_OK) {
6454e00368fSchristos fprintf(stderr, "gun out of memory error--aborting\n");
6464e00368fSchristos return 1;
6474e00368fSchristos }
6484e00368fSchristos
6494e00368fSchristos /* decompress each file to the same name with the suffix removed */
6504e00368fSchristos argc--;
6514e00368fSchristos argv++;
6524e00368fSchristos test = 0;
6534e00368fSchristos if (argc && strcmp(*argv, "-h") == 0) {
6544e00368fSchristos fprintf(stderr, "gun 1.6 (17 Jan 2010)\n");
6554e00368fSchristos fprintf(stderr, "Copyright (C) 2003-2010 Mark Adler\n");
6564e00368fSchristos fprintf(stderr, "usage: gun [-t] [file1.gz [file2.Z ...]]\n");
6574e00368fSchristos return 0;
6584e00368fSchristos }
6594e00368fSchristos if (argc && strcmp(*argv, "-t") == 0) {
6604e00368fSchristos test = 1;
6614e00368fSchristos argc--;
6624e00368fSchristos argv++;
6634e00368fSchristos }
6644e00368fSchristos if (argc)
6654e00368fSchristos do {
6664e00368fSchristos if (test)
6674e00368fSchristos outname = NULL;
6684e00368fSchristos else {
6694e00368fSchristos len = (int)strlen(*argv);
6704e00368fSchristos if (strcmp(*argv + len - 3, ".gz") == 0 ||
6714e00368fSchristos strcmp(*argv + len - 3, "-gz") == 0)
6724e00368fSchristos len -= 3;
6734e00368fSchristos else if (strcmp(*argv + len - 2, ".z") == 0 ||
6744e00368fSchristos strcmp(*argv + len - 2, "-z") == 0 ||
6754e00368fSchristos strcmp(*argv + len - 2, "_z") == 0 ||
6764e00368fSchristos strcmp(*argv + len - 2, ".Z") == 0)
6774e00368fSchristos len -= 2;
6784e00368fSchristos else {
6794e00368fSchristos fprintf(stderr, "gun error: no gz type on %s--skipping\n",
6804e00368fSchristos *argv);
6814e00368fSchristos continue;
6824e00368fSchristos }
6834e00368fSchristos outname = malloc(len + 1);
6844e00368fSchristos if (outname == NULL) {
6854e00368fSchristos fprintf(stderr, "gun out of memory error--aborting\n");
6864e00368fSchristos ret = 1;
6874e00368fSchristos break;
6884e00368fSchristos }
6894e00368fSchristos memcpy(outname, *argv, len);
6904e00368fSchristos outname[len] = 0;
6914e00368fSchristos }
6924e00368fSchristos ret = gunzip(&strm, *argv, outname, test);
6934e00368fSchristos if (outname != NULL) free(outname);
6944e00368fSchristos if (ret) break;
6954e00368fSchristos } while (argv++, --argc);
6964e00368fSchristos else
6974e00368fSchristos ret = gunzip(&strm, NULL, NULL, test);
6984e00368fSchristos
6994e00368fSchristos /* clean up */
7004e00368fSchristos inflateBackEnd(&strm);
7014e00368fSchristos return ret;
7024e00368fSchristos }
703