1aaf4ece6Schristos /* gun.c -- simple gunzip to give an example of the use of inflateBack()
2c3423655Schristos * Copyright (C) 2003, 2005, 2008, 2010, 2012 Mark Adler
3aaf4ece6Schristos * For conditions of distribution and use, see copyright notice in zlib.h
4c3423655Schristos Version 1.7 12 August 2012 Mark Adler */
5aaf4ece6Schristos
6aaf4ece6Schristos /* Version history:
7aaf4ece6Schristos 1.0 16 Feb 2003 First version for testing of inflateBack()
8aaf4ece6Schristos 1.1 21 Feb 2005 Decompress concatenated gzip streams
9aaf4ece6Schristos Remove use of "this" variable (C++ keyword)
10aaf4ece6Schristos Fix return value for in()
11aaf4ece6Schristos Improve allocation failure checking
12aaf4ece6Schristos Add typecasting for void * structures
13aaf4ece6Schristos Add -h option for command version and usage
14aaf4ece6Schristos Add a bunch of comments
15aaf4ece6Schristos 1.2 20 Mar 2005 Add Unix compress (LZW) decompression
16aaf4ece6Schristos Copy file attributes from input file to output file
17aaf4ece6Schristos 1.3 12 Jun 2005 Add casts for error messages [Oberhumer]
18c3423655Schristos 1.4 8 Dec 2006 LZW decompression speed improvements
19c3423655Schristos 1.5 9 Feb 2008 Avoid warning in latest version of gcc
20c3423655Schristos 1.6 17 Jan 2010 Avoid signed/unsigned comparison warnings
21c3423655Schristos 1.7 12 Aug 2012 Update for z_const usage in zlib 1.2.8
22aaf4ece6Schristos */
23aaf4ece6Schristos
24aaf4ece6Schristos /*
25aaf4ece6Schristos gun [ -t ] [ name ... ]
26aaf4ece6Schristos
27aaf4ece6Schristos decompresses the data in the named gzip files. If no arguments are given,
28aaf4ece6Schristos gun will decompress from stdin to stdout. The names must end in .gz, -gz,
29aaf4ece6Schristos .z, -z, _z, or .Z. The uncompressed data will be written to a file name
30aaf4ece6Schristos with the suffix stripped. On success, the original file is deleted. On
31aaf4ece6Schristos failure, the output file is deleted. For most failures, the command will
32aaf4ece6Schristos continue to process the remaining names on the command line. A memory
33aaf4ece6Schristos allocation failure will abort the command. If -t is specified, then the
34aaf4ece6Schristos listed files or stdin will be tested as gzip files for integrity (without
35aaf4ece6Schristos checking for a proper suffix), no output will be written, and no files
36aaf4ece6Schristos will be deleted.
37aaf4ece6Schristos
38aaf4ece6Schristos Like gzip, gun allows concatenated gzip streams and will decompress them,
39aaf4ece6Schristos writing all of the uncompressed data to the output. Unlike gzip, gun allows
40aaf4ece6Schristos an empty file on input, and will produce no error writing an empty output
41aaf4ece6Schristos file.
42aaf4ece6Schristos
43aaf4ece6Schristos gun will also decompress files made by Unix compress, which uses LZW
44aaf4ece6Schristos compression. These files are automatically detected by virtue of their
45aaf4ece6Schristos magic header bytes. Since the end of Unix compress stream is marked by the
46*ec47cc4bSchristos end-of-file, they cannot be concatenated. If a Unix compress stream is
47aaf4ece6Schristos encountered in an input file, it is the last stream in that file.
48aaf4ece6Schristos
49c3423655Schristos Like gunzip and uncompress, the file attributes of the original compressed
50aaf4ece6Schristos file are maintained in the final uncompressed file, to the extent that the
51aaf4ece6Schristos user permissions allow it.
52aaf4ece6Schristos
53aaf4ece6Schristos On my Mac OS X PowerPC G4, gun is almost twice as fast as gunzip (version
54aaf4ece6Schristos 1.2.4) is on the same file, when gun is linked with zlib 1.2.2. Also the
55aaf4ece6Schristos LZW decompression provided by gun is about twice as fast as the standard
56aaf4ece6Schristos Unix uncompress command.
57aaf4ece6Schristos */
58aaf4ece6Schristos
59aaf4ece6Schristos /* external functions and related types and constants */
60aaf4ece6Schristos #include <stdio.h> /* fprintf() */
61aaf4ece6Schristos #include <stdlib.h> /* malloc(), free() */
62aaf4ece6Schristos #include <string.h> /* strerror(), strcmp(), strlen(), memcpy() */
63aaf4ece6Schristos #include <errno.h> /* errno */
64aaf4ece6Schristos #include <fcntl.h> /* open() */
65aaf4ece6Schristos #include <unistd.h> /* read(), write(), close(), chown(), unlink() */
66aaf4ece6Schristos #include <sys/types.h>
67aaf4ece6Schristos #include <sys/stat.h> /* stat(), chmod() */
68aaf4ece6Schristos #include <utime.h> /* utime() */
69aaf4ece6Schristos #include "zlib.h" /* inflateBackInit(), inflateBack(), */
70aaf4ece6Schristos /* inflateBackEnd(), crc32() */
71aaf4ece6Schristos
72aaf4ece6Schristos /* function declaration */
73aaf4ece6Schristos #define local static
74aaf4ece6Schristos
75aaf4ece6Schristos /* buffer constants */
76aaf4ece6Schristos #define SIZE 32768U /* input and output buffer sizes */
77aaf4ece6Schristos #define PIECE 16384 /* limits i/o chunks for 16-bit int case */
78aaf4ece6Schristos
79aaf4ece6Schristos /* structure for infback() to pass to input function in() -- it maintains the
80aaf4ece6Schristos input file and a buffer of size SIZE */
81aaf4ece6Schristos struct ind {
82aaf4ece6Schristos int infile;
83aaf4ece6Schristos unsigned char *inbuf;
84aaf4ece6Schristos };
85aaf4ece6Schristos
86aaf4ece6Schristos /* Load input buffer, assumed to be empty, and return bytes loaded and a
87aaf4ece6Schristos pointer to them. read() is called until the buffer is full, or until it
88aaf4ece6Schristos returns end-of-file or error. Return 0 on error. */
in(void * in_desc,z_const unsigned char ** buf)89c3423655Schristos local unsigned in(void *in_desc, z_const unsigned char **buf)
90aaf4ece6Schristos {
91aaf4ece6Schristos int ret;
92aaf4ece6Schristos unsigned len;
93aaf4ece6Schristos unsigned char *next;
94aaf4ece6Schristos struct ind *me = (struct ind *)in_desc;
95aaf4ece6Schristos
96aaf4ece6Schristos next = me->inbuf;
97aaf4ece6Schristos *buf = next;
98aaf4ece6Schristos len = 0;
99aaf4ece6Schristos do {
100aaf4ece6Schristos ret = PIECE;
101aaf4ece6Schristos if ((unsigned)ret > SIZE - len)
102aaf4ece6Schristos ret = (int)(SIZE - len);
103aaf4ece6Schristos ret = (int)read(me->infile, next, ret);
104aaf4ece6Schristos if (ret == -1) {
105aaf4ece6Schristos len = 0;
106aaf4ece6Schristos break;
107aaf4ece6Schristos }
108aaf4ece6Schristos next += ret;
109aaf4ece6Schristos len += ret;
110aaf4ece6Schristos } while (ret != 0 && len < SIZE);
111aaf4ece6Schristos return len;
112aaf4ece6Schristos }
113aaf4ece6Schristos
114aaf4ece6Schristos /* structure for infback() to pass to output function out() -- it maintains the
115aaf4ece6Schristos output file, a running CRC-32 check on the output and the total number of
116aaf4ece6Schristos bytes output, both for checking against the gzip trailer. (The length in
117aaf4ece6Schristos the gzip trailer is stored modulo 2^32, so it's ok if a long is 32 bits and
118aaf4ece6Schristos the output is greater than 4 GB.) */
119aaf4ece6Schristos struct outd {
120aaf4ece6Schristos int outfile;
121aaf4ece6Schristos int check; /* true if checking crc and total */
122aaf4ece6Schristos unsigned long crc;
123aaf4ece6Schristos unsigned long total;
124aaf4ece6Schristos };
125aaf4ece6Schristos
126aaf4ece6Schristos /* Write output buffer and update the CRC-32 and total bytes written. write()
127aaf4ece6Schristos is called until all of the output is written or an error is encountered.
128aaf4ece6Schristos On success out() returns 0. For a write failure, out() returns 1. If the
129aaf4ece6Schristos output file descriptor is -1, then nothing is written.
130aaf4ece6Schristos */
out(void * out_desc,unsigned char * buf,unsigned len)131aaf4ece6Schristos local int out(void *out_desc, unsigned char *buf, unsigned len)
132aaf4ece6Schristos {
133aaf4ece6Schristos int ret;
134aaf4ece6Schristos struct outd *me = (struct outd *)out_desc;
135aaf4ece6Schristos
136aaf4ece6Schristos if (me->check) {
137aaf4ece6Schristos me->crc = crc32(me->crc, buf, len);
138aaf4ece6Schristos me->total += len;
139aaf4ece6Schristos }
140aaf4ece6Schristos if (me->outfile != -1)
141aaf4ece6Schristos do {
142aaf4ece6Schristos ret = PIECE;
143aaf4ece6Schristos if ((unsigned)ret > len)
144aaf4ece6Schristos ret = (int)len;
145aaf4ece6Schristos ret = (int)write(me->outfile, buf, ret);
146aaf4ece6Schristos if (ret == -1)
147aaf4ece6Schristos return 1;
148aaf4ece6Schristos buf += ret;
149aaf4ece6Schristos len -= ret;
150aaf4ece6Schristos } while (len != 0);
151aaf4ece6Schristos return 0;
152aaf4ece6Schristos }
153aaf4ece6Schristos
154aaf4ece6Schristos /* next input byte macro for use inside lunpipe() and gunpipe() */
155aaf4ece6Schristos #define NEXT() (have ? 0 : (have = in(indp, &next)), \
156aaf4ece6Schristos last = have ? (have--, (int)(*next++)) : -1)
157aaf4ece6Schristos
158aaf4ece6Schristos /* memory for gunpipe() and lunpipe() --
159aaf4ece6Schristos the first 256 entries of prefix[] and suffix[] are never used, could
160aaf4ece6Schristos have offset the index, but it's faster to waste the memory */
161aaf4ece6Schristos unsigned char inbuf[SIZE]; /* input buffer */
162aaf4ece6Schristos unsigned char outbuf[SIZE]; /* output buffer */
163aaf4ece6Schristos unsigned short prefix[65536]; /* index to LZW prefix string */
164aaf4ece6Schristos unsigned char suffix[65536]; /* one-character LZW suffix */
165aaf4ece6Schristos unsigned char match[65280 + 2]; /* buffer for reversed match or gzip
166aaf4ece6Schristos 32K sliding window */
167aaf4ece6Schristos
168aaf4ece6Schristos /* throw out what's left in the current bits byte buffer (this is a vestigial
169aaf4ece6Schristos aspect of the compressed data format derived from an implementation that
170aaf4ece6Schristos made use of a special VAX machine instruction!) */
171aaf4ece6Schristos #define FLUSHCODE() \
172aaf4ece6Schristos do { \
173aaf4ece6Schristos left = 0; \
174aaf4ece6Schristos rem = 0; \
175aaf4ece6Schristos if (chunk > have) { \
176aaf4ece6Schristos chunk -= have; \
177aaf4ece6Schristos have = 0; \
178aaf4ece6Schristos if (NEXT() == -1) \
179aaf4ece6Schristos break; \
180aaf4ece6Schristos chunk--; \
181aaf4ece6Schristos if (chunk > have) { \
182aaf4ece6Schristos chunk = have = 0; \
183aaf4ece6Schristos break; \
184aaf4ece6Schristos } \
185aaf4ece6Schristos } \
186aaf4ece6Schristos have -= chunk; \
187aaf4ece6Schristos next += chunk; \
188aaf4ece6Schristos chunk = 0; \
189aaf4ece6Schristos } while (0)
190aaf4ece6Schristos
191aaf4ece6Schristos /* Decompress a compress (LZW) file from indp to outfile. The compress magic
192aaf4ece6Schristos header (two bytes) has already been read and verified. There are have bytes
193aaf4ece6Schristos of buffered input at next. strm is used for passing error information back
194aaf4ece6Schristos to gunpipe().
195aaf4ece6Schristos
196aaf4ece6Schristos lunpipe() will return Z_OK on success, Z_BUF_ERROR for an unexpected end of
197aaf4ece6Schristos file, read error, or write error (a write error indicated by strm->next_in
198aaf4ece6Schristos not equal to Z_NULL), or Z_DATA_ERROR for invalid input.
199aaf4ece6Schristos */
lunpipe(unsigned have,z_const unsigned char * next,struct ind * indp,int outfile,z_stream * strm)200c3423655Schristos local int lunpipe(unsigned have, z_const unsigned char *next, struct ind *indp,
201aaf4ece6Schristos int outfile, z_stream *strm)
202aaf4ece6Schristos {
203aaf4ece6Schristos int last; /* last byte read by NEXT(), or -1 if EOF */
204c3423655Schristos unsigned chunk; /* bytes left in current chunk */
205aaf4ece6Schristos int left; /* bits left in rem */
206aaf4ece6Schristos unsigned rem; /* unused bits from input */
207aaf4ece6Schristos int bits; /* current bits per code */
208aaf4ece6Schristos unsigned code; /* code, table traversal index */
209aaf4ece6Schristos unsigned mask; /* mask for current bits codes */
210aaf4ece6Schristos int max; /* maximum bits per code for this stream */
211c3423655Schristos unsigned flags; /* compress flags, then block compress flag */
212aaf4ece6Schristos unsigned end; /* last valid entry in prefix/suffix tables */
213aaf4ece6Schristos unsigned temp; /* current code */
214aaf4ece6Schristos unsigned prev; /* previous code */
215aaf4ece6Schristos unsigned final; /* last character written for previous code */
216aaf4ece6Schristos unsigned stack; /* next position for reversed string */
217aaf4ece6Schristos unsigned outcnt; /* bytes in output buffer */
218aaf4ece6Schristos struct outd outd; /* output structure */
219c3423655Schristos unsigned char *p;
220aaf4ece6Schristos
221aaf4ece6Schristos /* set up output */
222aaf4ece6Schristos outd.outfile = outfile;
223aaf4ece6Schristos outd.check = 0;
224aaf4ece6Schristos
225aaf4ece6Schristos /* process remainder of compress header -- a flags byte */
226aaf4ece6Schristos flags = NEXT();
227aaf4ece6Schristos if (last == -1)
228aaf4ece6Schristos return Z_BUF_ERROR;
229aaf4ece6Schristos if (flags & 0x60) {
230aaf4ece6Schristos strm->msg = (char *)"unknown lzw flags set";
231aaf4ece6Schristos return Z_DATA_ERROR;
232aaf4ece6Schristos }
233aaf4ece6Schristos max = flags & 0x1f;
234aaf4ece6Schristos if (max < 9 || max > 16) {
235aaf4ece6Schristos strm->msg = (char *)"lzw bits out of range";
236aaf4ece6Schristos return Z_DATA_ERROR;
237aaf4ece6Schristos }
238aaf4ece6Schristos if (max == 9) /* 9 doesn't really mean 9 */
239aaf4ece6Schristos max = 10;
240aaf4ece6Schristos flags &= 0x80; /* true if block compress */
241aaf4ece6Schristos
242aaf4ece6Schristos /* clear table */
243aaf4ece6Schristos bits = 9;
244aaf4ece6Schristos mask = 0x1ff;
245aaf4ece6Schristos end = flags ? 256 : 255;
246aaf4ece6Schristos
247aaf4ece6Schristos /* set up: get first 9-bit code, which is the first decompressed byte, but
248aaf4ece6Schristos don't create a table entry until the next code */
249aaf4ece6Schristos if (NEXT() == -1) /* no compressed data is ok */
250aaf4ece6Schristos return Z_OK;
251aaf4ece6Schristos final = prev = (unsigned)last; /* low 8 bits of code */
252aaf4ece6Schristos if (NEXT() == -1) /* missing a bit */
253aaf4ece6Schristos return Z_BUF_ERROR;
254aaf4ece6Schristos if (last & 1) { /* code must be < 256 */
255aaf4ece6Schristos strm->msg = (char *)"invalid lzw code";
256aaf4ece6Schristos return Z_DATA_ERROR;
257aaf4ece6Schristos }
258aaf4ece6Schristos rem = (unsigned)last >> 1; /* remaining 7 bits */
259aaf4ece6Schristos left = 7;
260aaf4ece6Schristos chunk = bits - 2; /* 7 bytes left in this chunk */
261aaf4ece6Schristos outbuf[0] = (unsigned char)final; /* write first decompressed byte */
262aaf4ece6Schristos outcnt = 1;
263aaf4ece6Schristos
264aaf4ece6Schristos /* decode codes */
265aaf4ece6Schristos stack = 0;
266aaf4ece6Schristos for (;;) {
267aaf4ece6Schristos /* if the table will be full after this, increment the code size */
268aaf4ece6Schristos if (end >= mask && bits < max) {
269aaf4ece6Schristos FLUSHCODE();
270aaf4ece6Schristos bits++;
271aaf4ece6Schristos mask <<= 1;
272aaf4ece6Schristos mask++;
273aaf4ece6Schristos }
274aaf4ece6Schristos
275aaf4ece6Schristos /* get a code of length bits */
276aaf4ece6Schristos if (chunk == 0) /* decrement chunk modulo bits */
277aaf4ece6Schristos chunk = bits;
278aaf4ece6Schristos code = rem; /* low bits of code */
279aaf4ece6Schristos if (NEXT() == -1) { /* EOF is end of compressed data */
280aaf4ece6Schristos /* write remaining buffered output */
281aaf4ece6Schristos if (outcnt && out(&outd, outbuf, outcnt)) {
282aaf4ece6Schristos strm->next_in = outbuf; /* signal write error */
283aaf4ece6Schristos return Z_BUF_ERROR;
284aaf4ece6Schristos }
285aaf4ece6Schristos return Z_OK;
286aaf4ece6Schristos }
287aaf4ece6Schristos code += (unsigned)last << left; /* middle (or high) bits of code */
288aaf4ece6Schristos left += 8;
289aaf4ece6Schristos chunk--;
290aaf4ece6Schristos if (bits > left) { /* need more bits */
291aaf4ece6Schristos if (NEXT() == -1) /* can't end in middle of code */
292aaf4ece6Schristos return Z_BUF_ERROR;
293aaf4ece6Schristos code += (unsigned)last << left; /* high bits of code */
294aaf4ece6Schristos left += 8;
295aaf4ece6Schristos chunk--;
296aaf4ece6Schristos }
297aaf4ece6Schristos code &= mask; /* mask to current code length */
298aaf4ece6Schristos left -= bits; /* number of unused bits */
299aaf4ece6Schristos rem = (unsigned)last >> (8 - left); /* unused bits from last byte */
300aaf4ece6Schristos
301aaf4ece6Schristos /* process clear code (256) */
302aaf4ece6Schristos if (code == 256 && flags) {
303aaf4ece6Schristos FLUSHCODE();
304aaf4ece6Schristos bits = 9; /* initialize bits and mask */
305aaf4ece6Schristos mask = 0x1ff;
306aaf4ece6Schristos end = 255; /* empty table */
307aaf4ece6Schristos continue; /* get next code */
308aaf4ece6Schristos }
309aaf4ece6Schristos
310aaf4ece6Schristos /* special code to reuse last match */
311aaf4ece6Schristos temp = code; /* save the current code */
312aaf4ece6Schristos if (code > end) {
313aaf4ece6Schristos /* Be picky on the allowed code here, and make sure that the code
314aaf4ece6Schristos we drop through (prev) will be a valid index so that random
315aaf4ece6Schristos input does not cause an exception. The code != end + 1 check is
316aaf4ece6Schristos empirically derived, and not checked in the original uncompress
317aaf4ece6Schristos code. If this ever causes a problem, that check could be safely
318aaf4ece6Schristos removed. Leaving this check in greatly improves gun's ability
319aaf4ece6Schristos to detect random or corrupted input after a compress header.
320aaf4ece6Schristos In any case, the prev > end check must be retained. */
321aaf4ece6Schristos if (code != end + 1 || prev > end) {
322aaf4ece6Schristos strm->msg = (char *)"invalid lzw code";
323aaf4ece6Schristos return Z_DATA_ERROR;
324aaf4ece6Schristos }
325aaf4ece6Schristos match[stack++] = (unsigned char)final;
326aaf4ece6Schristos code = prev;
327aaf4ece6Schristos }
328aaf4ece6Schristos
329aaf4ece6Schristos /* walk through linked list to generate output in reverse order */
330c3423655Schristos p = match + stack;
331aaf4ece6Schristos while (code >= 256) {
332c3423655Schristos *p++ = suffix[code];
333aaf4ece6Schristos code = prefix[code];
334aaf4ece6Schristos }
335c3423655Schristos stack = p - match;
336aaf4ece6Schristos match[stack++] = (unsigned char)code;
337aaf4ece6Schristos final = code;
338aaf4ece6Schristos
339aaf4ece6Schristos /* link new table entry */
340aaf4ece6Schristos if (end < mask) {
341aaf4ece6Schristos end++;
342aaf4ece6Schristos prefix[end] = (unsigned short)prev;
343aaf4ece6Schristos suffix[end] = (unsigned char)final;
344aaf4ece6Schristos }
345aaf4ece6Schristos
346aaf4ece6Schristos /* set previous code for next iteration */
347aaf4ece6Schristos prev = temp;
348aaf4ece6Schristos
349aaf4ece6Schristos /* write output in forward order */
350aaf4ece6Schristos while (stack > SIZE - outcnt) {
351aaf4ece6Schristos while (outcnt < SIZE)
352aaf4ece6Schristos outbuf[outcnt++] = match[--stack];
353aaf4ece6Schristos if (out(&outd, outbuf, outcnt)) {
354aaf4ece6Schristos strm->next_in = outbuf; /* signal write error */
355aaf4ece6Schristos return Z_BUF_ERROR;
356aaf4ece6Schristos }
357aaf4ece6Schristos outcnt = 0;
358aaf4ece6Schristos }
359c3423655Schristos p = match + stack;
360aaf4ece6Schristos do {
361c3423655Schristos outbuf[outcnt++] = *--p;
362c3423655Schristos } while (p > match);
363c3423655Schristos stack = 0;
364aaf4ece6Schristos
365aaf4ece6Schristos /* loop for next code with final and prev as the last match, rem and
366aaf4ece6Schristos left provide the first 0..7 bits of the next code, end is the last
367aaf4ece6Schristos valid table entry */
368aaf4ece6Schristos }
369aaf4ece6Schristos }
370aaf4ece6Schristos
371aaf4ece6Schristos /* Decompress a gzip file from infile to outfile. strm is assumed to have been
372aaf4ece6Schristos successfully initialized with inflateBackInit(). The input file may consist
373aaf4ece6Schristos of a series of gzip streams, in which case all of them will be decompressed
374aaf4ece6Schristos to the output file. If outfile is -1, then the gzip stream(s) integrity is
375aaf4ece6Schristos checked and nothing is written.
376aaf4ece6Schristos
377aaf4ece6Schristos The return value is a zlib error code: Z_MEM_ERROR if out of memory,
378aaf4ece6Schristos Z_DATA_ERROR if the header or the compressed data is invalid, or if the
379aaf4ece6Schristos trailer CRC-32 check or length doesn't match, Z_BUF_ERROR if the input ends
380aaf4ece6Schristos prematurely or a write error occurs, or Z_ERRNO if junk (not a another gzip
381aaf4ece6Schristos stream) follows a valid gzip stream.
382aaf4ece6Schristos */
gunpipe(z_stream * strm,int infile,int outfile)383aaf4ece6Schristos local int gunpipe(z_stream *strm, int infile, int outfile)
384aaf4ece6Schristos {
385aaf4ece6Schristos int ret, first, last;
386aaf4ece6Schristos unsigned have, flags, len;
387c3423655Schristos z_const unsigned char *next = NULL;
388aaf4ece6Schristos struct ind ind, *indp;
389aaf4ece6Schristos struct outd outd;
390aaf4ece6Schristos
391aaf4ece6Schristos /* setup input buffer */
392aaf4ece6Schristos ind.infile = infile;
393aaf4ece6Schristos ind.inbuf = inbuf;
394aaf4ece6Schristos indp = &ind;
395aaf4ece6Schristos
396aaf4ece6Schristos /* decompress concatenated gzip streams */
397aaf4ece6Schristos have = 0; /* no input data read in yet */
398aaf4ece6Schristos first = 1; /* looking for first gzip header */
399aaf4ece6Schristos strm->next_in = Z_NULL; /* so Z_BUF_ERROR means EOF */
400aaf4ece6Schristos for (;;) {
401aaf4ece6Schristos /* look for the two magic header bytes for a gzip stream */
402aaf4ece6Schristos if (NEXT() == -1) {
403aaf4ece6Schristos ret = Z_OK;
404aaf4ece6Schristos break; /* empty gzip stream is ok */
405aaf4ece6Schristos }
406aaf4ece6Schristos if (last != 31 || (NEXT() != 139 && last != 157)) {
407aaf4ece6Schristos strm->msg = (char *)"incorrect header check";
408aaf4ece6Schristos ret = first ? Z_DATA_ERROR : Z_ERRNO;
409aaf4ece6Schristos break; /* not a gzip or compress header */
410aaf4ece6Schristos }
411aaf4ece6Schristos first = 0; /* next non-header is junk */
412aaf4ece6Schristos
413aaf4ece6Schristos /* process a compress (LZW) file -- can't be concatenated after this */
414aaf4ece6Schristos if (last == 157) {
415aaf4ece6Schristos ret = lunpipe(have, next, indp, outfile, strm);
416aaf4ece6Schristos break;
417aaf4ece6Schristos }
418aaf4ece6Schristos
419aaf4ece6Schristos /* process remainder of gzip header */
420aaf4ece6Schristos ret = Z_BUF_ERROR;
421aaf4ece6Schristos if (NEXT() != 8) { /* only deflate method allowed */
422aaf4ece6Schristos if (last == -1) break;
423aaf4ece6Schristos strm->msg = (char *)"unknown compression method";
424aaf4ece6Schristos ret = Z_DATA_ERROR;
425aaf4ece6Schristos break;
426aaf4ece6Schristos }
427aaf4ece6Schristos flags = NEXT(); /* header flags */
428aaf4ece6Schristos NEXT(); /* discard mod time, xflgs, os */
429aaf4ece6Schristos NEXT();
430aaf4ece6Schristos NEXT();
431aaf4ece6Schristos NEXT();
432aaf4ece6Schristos NEXT();
433aaf4ece6Schristos NEXT();
434aaf4ece6Schristos if (last == -1) break;
435aaf4ece6Schristos if (flags & 0xe0) {
436aaf4ece6Schristos strm->msg = (char *)"unknown header flags set";
437aaf4ece6Schristos ret = Z_DATA_ERROR;
438aaf4ece6Schristos break;
439aaf4ece6Schristos }
440aaf4ece6Schristos if (flags & 4) { /* extra field */
441aaf4ece6Schristos len = NEXT();
442aaf4ece6Schristos len += (unsigned)(NEXT()) << 8;
443aaf4ece6Schristos if (last == -1) break;
444aaf4ece6Schristos while (len > have) {
445aaf4ece6Schristos len -= have;
446aaf4ece6Schristos have = 0;
447aaf4ece6Schristos if (NEXT() == -1) break;
448aaf4ece6Schristos len--;
449aaf4ece6Schristos }
450aaf4ece6Schristos if (last == -1) break;
451aaf4ece6Schristos have -= len;
452aaf4ece6Schristos next += len;
453aaf4ece6Schristos }
454aaf4ece6Schristos if (flags & 8) /* file name */
455aaf4ece6Schristos while (NEXT() != 0 && last != -1)
456aaf4ece6Schristos ;
457aaf4ece6Schristos if (flags & 16) /* comment */
458aaf4ece6Schristos while (NEXT() != 0 && last != -1)
459aaf4ece6Schristos ;
460aaf4ece6Schristos if (flags & 2) { /* header crc */
461aaf4ece6Schristos NEXT();
462aaf4ece6Schristos NEXT();
463aaf4ece6Schristos }
464aaf4ece6Schristos if (last == -1) break;
465aaf4ece6Schristos
466aaf4ece6Schristos /* set up output */
467aaf4ece6Schristos outd.outfile = outfile;
468aaf4ece6Schristos outd.check = 1;
469aaf4ece6Schristos outd.crc = crc32(0L, Z_NULL, 0);
470aaf4ece6Schristos outd.total = 0;
471aaf4ece6Schristos
472aaf4ece6Schristos /* decompress data to output */
473aaf4ece6Schristos strm->next_in = next;
474aaf4ece6Schristos strm->avail_in = have;
475aaf4ece6Schristos ret = inflateBack(strm, in, indp, out, &outd);
476aaf4ece6Schristos if (ret != Z_STREAM_END) break;
477aaf4ece6Schristos next = strm->next_in;
478aaf4ece6Schristos have = strm->avail_in;
479aaf4ece6Schristos strm->next_in = Z_NULL; /* so Z_BUF_ERROR means EOF */
480aaf4ece6Schristos
481aaf4ece6Schristos /* check trailer */
482aaf4ece6Schristos ret = Z_BUF_ERROR;
483c3423655Schristos if (NEXT() != (int)(outd.crc & 0xff) ||
484c3423655Schristos NEXT() != (int)((outd.crc >> 8) & 0xff) ||
485c3423655Schristos NEXT() != (int)((outd.crc >> 16) & 0xff) ||
486c3423655Schristos NEXT() != (int)((outd.crc >> 24) & 0xff)) {
487aaf4ece6Schristos /* crc error */
488aaf4ece6Schristos if (last != -1) {
489aaf4ece6Schristos strm->msg = (char *)"incorrect data check";
490aaf4ece6Schristos ret = Z_DATA_ERROR;
491aaf4ece6Schristos }
492aaf4ece6Schristos break;
493aaf4ece6Schristos }
494c3423655Schristos if (NEXT() != (int)(outd.total & 0xff) ||
495c3423655Schristos NEXT() != (int)((outd.total >> 8) & 0xff) ||
496c3423655Schristos NEXT() != (int)((outd.total >> 16) & 0xff) ||
497c3423655Schristos NEXT() != (int)((outd.total >> 24) & 0xff)) {
498aaf4ece6Schristos /* length error */
499aaf4ece6Schristos if (last != -1) {
500aaf4ece6Schristos strm->msg = (char *)"incorrect length check";
501aaf4ece6Schristos ret = Z_DATA_ERROR;
502aaf4ece6Schristos }
503aaf4ece6Schristos break;
504aaf4ece6Schristos }
505aaf4ece6Schristos
506aaf4ece6Schristos /* go back and look for another gzip stream */
507aaf4ece6Schristos }
508aaf4ece6Schristos
509aaf4ece6Schristos /* clean up and return */
510aaf4ece6Schristos return ret;
511aaf4ece6Schristos }
512aaf4ece6Schristos
513aaf4ece6Schristos /* Copy file attributes, from -> to, as best we can. This is best effort, so
514aaf4ece6Schristos no errors are reported. The mode bits, including suid, sgid, and the sticky
515aaf4ece6Schristos bit are copied (if allowed), the owner's user id and group id are copied
516aaf4ece6Schristos (again if allowed), and the access and modify times are copied. */
copymeta(char * from,char * to)517aaf4ece6Schristos local void copymeta(char *from, char *to)
518aaf4ece6Schristos {
519aaf4ece6Schristos struct stat was;
520aaf4ece6Schristos struct utimbuf when;
521aaf4ece6Schristos
522aaf4ece6Schristos /* get all of from's Unix meta data, return if not a regular file */
523aaf4ece6Schristos if (stat(from, &was) != 0 || (was.st_mode & S_IFMT) != S_IFREG)
524aaf4ece6Schristos return;
525aaf4ece6Schristos
526aaf4ece6Schristos /* set to's mode bits, ignore errors */
527aaf4ece6Schristos (void)chmod(to, was.st_mode & 07777);
528aaf4ece6Schristos
529aaf4ece6Schristos /* copy owner's user and group, ignore errors */
530aaf4ece6Schristos (void)chown(to, was.st_uid, was.st_gid);
531aaf4ece6Schristos
532aaf4ece6Schristos /* copy access and modify times, ignore errors */
533aaf4ece6Schristos when.actime = was.st_atime;
534aaf4ece6Schristos when.modtime = was.st_mtime;
535aaf4ece6Schristos (void)utime(to, &when);
536aaf4ece6Schristos }
537aaf4ece6Schristos
538aaf4ece6Schristos /* Decompress the file inname to the file outnname, of if test is true, just
539aaf4ece6Schristos decompress without writing and check the gzip trailer for integrity. If
540aaf4ece6Schristos inname is NULL or an empty string, read from stdin. If outname is NULL or
541aaf4ece6Schristos an empty string, write to stdout. strm is a pre-initialized inflateBack
542aaf4ece6Schristos structure. When appropriate, copy the file attributes from inname to
543aaf4ece6Schristos outname.
544aaf4ece6Schristos
545aaf4ece6Schristos gunzip() returns 1 if there is an out-of-memory error or an unexpected
546aaf4ece6Schristos return code from gunpipe(). Otherwise it returns 0.
547aaf4ece6Schristos */
gunzip(z_stream * strm,char * inname,char * outname,int test)548aaf4ece6Schristos local int gunzip(z_stream *strm, char *inname, char *outname, int test)
549aaf4ece6Schristos {
550aaf4ece6Schristos int ret;
551aaf4ece6Schristos int infile, outfile;
552aaf4ece6Schristos
553aaf4ece6Schristos /* open files */
554aaf4ece6Schristos if (inname == NULL || *inname == 0) {
555aaf4ece6Schristos inname = "-";
556aaf4ece6Schristos infile = 0; /* stdin */
557aaf4ece6Schristos }
558aaf4ece6Schristos else {
559aaf4ece6Schristos infile = open(inname, O_RDONLY, 0);
560aaf4ece6Schristos if (infile == -1) {
561aaf4ece6Schristos fprintf(stderr, "gun cannot open %s\n", inname);
562aaf4ece6Schristos return 0;
563aaf4ece6Schristos }
564aaf4ece6Schristos }
565aaf4ece6Schristos if (test)
566aaf4ece6Schristos outfile = -1;
567aaf4ece6Schristos else if (outname == NULL || *outname == 0) {
568aaf4ece6Schristos outname = "-";
569aaf4ece6Schristos outfile = 1; /* stdout */
570aaf4ece6Schristos }
571aaf4ece6Schristos else {
572aaf4ece6Schristos outfile = open(outname, O_CREAT | O_TRUNC | O_WRONLY, 0666);
573aaf4ece6Schristos if (outfile == -1) {
574aaf4ece6Schristos close(infile);
575aaf4ece6Schristos fprintf(stderr, "gun cannot create %s\n", outname);
576aaf4ece6Schristos return 0;
577aaf4ece6Schristos }
578aaf4ece6Schristos }
579aaf4ece6Schristos errno = 0;
580aaf4ece6Schristos
581aaf4ece6Schristos /* decompress */
582aaf4ece6Schristos ret = gunpipe(strm, infile, outfile);
583aaf4ece6Schristos if (outfile > 2) close(outfile);
584aaf4ece6Schristos if (infile > 2) close(infile);
585aaf4ece6Schristos
586aaf4ece6Schristos /* interpret result */
587aaf4ece6Schristos switch (ret) {
588aaf4ece6Schristos case Z_OK:
589aaf4ece6Schristos case Z_ERRNO:
590aaf4ece6Schristos if (infile > 2 && outfile > 2) {
591aaf4ece6Schristos copymeta(inname, outname); /* copy attributes */
592aaf4ece6Schristos unlink(inname);
593aaf4ece6Schristos }
594aaf4ece6Schristos if (ret == Z_ERRNO)
595aaf4ece6Schristos fprintf(stderr, "gun warning: trailing garbage ignored in %s\n",
596aaf4ece6Schristos inname);
597aaf4ece6Schristos break;
598aaf4ece6Schristos case Z_DATA_ERROR:
599aaf4ece6Schristos if (outfile > 2) unlink(outname);
600aaf4ece6Schristos fprintf(stderr, "gun data error on %s: %s\n", inname, strm->msg);
601aaf4ece6Schristos break;
602aaf4ece6Schristos case Z_MEM_ERROR:
603aaf4ece6Schristos if (outfile > 2) unlink(outname);
604aaf4ece6Schristos fprintf(stderr, "gun out of memory error--aborting\n");
605aaf4ece6Schristos return 1;
606aaf4ece6Schristos case Z_BUF_ERROR:
607aaf4ece6Schristos if (outfile > 2) unlink(outname);
608aaf4ece6Schristos if (strm->next_in != Z_NULL) {
609aaf4ece6Schristos fprintf(stderr, "gun write error on %s: %s\n",
610aaf4ece6Schristos outname, strerror(errno));
611aaf4ece6Schristos }
612aaf4ece6Schristos else if (errno) {
613aaf4ece6Schristos fprintf(stderr, "gun read error on %s: %s\n",
614aaf4ece6Schristos inname, strerror(errno));
615aaf4ece6Schristos }
616aaf4ece6Schristos else {
617aaf4ece6Schristos fprintf(stderr, "gun unexpected end of file on %s\n",
618aaf4ece6Schristos inname);
619aaf4ece6Schristos }
620aaf4ece6Schristos break;
621aaf4ece6Schristos default:
622aaf4ece6Schristos if (outfile > 2) unlink(outname);
623aaf4ece6Schristos fprintf(stderr, "gun internal error--aborting\n");
624aaf4ece6Schristos return 1;
625aaf4ece6Schristos }
626aaf4ece6Schristos return 0;
627aaf4ece6Schristos }
628aaf4ece6Schristos
629aaf4ece6Schristos /* Process the gun command line arguments. See the command syntax near the
630aaf4ece6Schristos beginning of this source file. */
main(int argc,char ** argv)631aaf4ece6Schristos int main(int argc, char **argv)
632aaf4ece6Schristos {
633aaf4ece6Schristos int ret, len, test;
634aaf4ece6Schristos char *outname;
635aaf4ece6Schristos unsigned char *window;
636aaf4ece6Schristos z_stream strm;
637aaf4ece6Schristos
638aaf4ece6Schristos /* initialize inflateBack state for repeated use */
639aaf4ece6Schristos window = match; /* reuse LZW match buffer */
640aaf4ece6Schristos strm.zalloc = Z_NULL;
641aaf4ece6Schristos strm.zfree = Z_NULL;
642aaf4ece6Schristos strm.opaque = Z_NULL;
643aaf4ece6Schristos ret = inflateBackInit(&strm, 15, window);
644aaf4ece6Schristos if (ret != Z_OK) {
645aaf4ece6Schristos fprintf(stderr, "gun out of memory error--aborting\n");
646aaf4ece6Schristos return 1;
647aaf4ece6Schristos }
648aaf4ece6Schristos
649aaf4ece6Schristos /* decompress each file to the same name with the suffix removed */
650aaf4ece6Schristos argc--;
651aaf4ece6Schristos argv++;
652aaf4ece6Schristos test = 0;
653aaf4ece6Schristos if (argc && strcmp(*argv, "-h") == 0) {
654c3423655Schristos fprintf(stderr, "gun 1.6 (17 Jan 2010)\n");
655c3423655Schristos fprintf(stderr, "Copyright (C) 2003-2010 Mark Adler\n");
656aaf4ece6Schristos fprintf(stderr, "usage: gun [-t] [file1.gz [file2.Z ...]]\n");
657aaf4ece6Schristos return 0;
658aaf4ece6Schristos }
659aaf4ece6Schristos if (argc && strcmp(*argv, "-t") == 0) {
660aaf4ece6Schristos test = 1;
661aaf4ece6Schristos argc--;
662aaf4ece6Schristos argv++;
663aaf4ece6Schristos }
664aaf4ece6Schristos if (argc)
665aaf4ece6Schristos do {
666aaf4ece6Schristos if (test)
667aaf4ece6Schristos outname = NULL;
668aaf4ece6Schristos else {
669aaf4ece6Schristos len = (int)strlen(*argv);
670aaf4ece6Schristos if (strcmp(*argv + len - 3, ".gz") == 0 ||
671aaf4ece6Schristos strcmp(*argv + len - 3, "-gz") == 0)
672aaf4ece6Schristos len -= 3;
673aaf4ece6Schristos else if (strcmp(*argv + len - 2, ".z") == 0 ||
674aaf4ece6Schristos strcmp(*argv + len - 2, "-z") == 0 ||
675aaf4ece6Schristos strcmp(*argv + len - 2, "_z") == 0 ||
676aaf4ece6Schristos strcmp(*argv + len - 2, ".Z") == 0)
677aaf4ece6Schristos len -= 2;
678aaf4ece6Schristos else {
679aaf4ece6Schristos fprintf(stderr, "gun error: no gz type on %s--skipping\n",
680aaf4ece6Schristos *argv);
681aaf4ece6Schristos continue;
682aaf4ece6Schristos }
683aaf4ece6Schristos outname = malloc(len + 1);
684aaf4ece6Schristos if (outname == NULL) {
685aaf4ece6Schristos fprintf(stderr, "gun out of memory error--aborting\n");
686aaf4ece6Schristos ret = 1;
687aaf4ece6Schristos break;
688aaf4ece6Schristos }
689aaf4ece6Schristos memcpy(outname, *argv, len);
690aaf4ece6Schristos outname[len] = 0;
691aaf4ece6Schristos }
692aaf4ece6Schristos ret = gunzip(&strm, *argv, outname, test);
693aaf4ece6Schristos if (outname != NULL) free(outname);
694aaf4ece6Schristos if (ret) break;
695aaf4ece6Schristos } while (argv++, --argc);
696aaf4ece6Schristos else
697aaf4ece6Schristos ret = gunzip(&strm, NULL, NULL, test);
698aaf4ece6Schristos
699aaf4ece6Schristos /* clean up */
700aaf4ece6Schristos inflateBackEnd(&strm);
701aaf4ece6Schristos return ret;
702aaf4ece6Schristos }
703