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