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.1.3 christos end-of-file, they cannot be concatenated. 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