123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702 |
- #include <stdio.h> /* fprintf() */
- #include <stdlib.h> /* malloc(), free() */
- #include <string.h> /* strerror(), strcmp(), strlen(), memcpy() */
- #include <errno.h> /* errno */
- #include <fcntl.h> /* open() */
- #include <unistd.h> /* read(), write(), close(), chown(), unlink() */
- #include <sys/types.h>
- #include <sys/stat.h> /* stat(), chmod() */
- #include <utime.h> /* utime() */
- #include "zlib.h"
-
- #define local static
- #define SIZE 32768U
- #define PIECE 16384
- struct ind {
- int infile;
- unsigned char *inbuf;
- };
- local unsigned in(void *in_desc, z_const unsigned char **buf)
- {
- int ret;
- unsigned len;
- unsigned char *next;
- struct ind *me = (struct ind *)in_desc;
- next = me->inbuf;
- *buf = next;
- len = 0;
- do {
- ret = PIECE;
- if ((unsigned)ret > SIZE - len)
- ret = (int)(SIZE - len);
- ret = (int)read(me->infile, next, ret);
- if (ret == -1) {
- len = 0;
- break;
- }
- next += ret;
- len += ret;
- } while (ret != 0 && len < SIZE);
- return len;
- }
- struct outd {
- int outfile;
- int check;
- unsigned long crc;
- unsigned long total;
- };
- local int out(void *out_desc, unsigned char *buf, unsigned len)
- {
- int ret;
- struct outd *me = (struct outd *)out_desc;
- if (me->check) {
- me->crc = crc32(me->crc, buf, len);
- me->total += len;
- }
- if (me->outfile != -1)
- do {
- ret = PIECE;
- if ((unsigned)ret > len)
- ret = (int)len;
- ret = (int)write(me->outfile, buf, ret);
- if (ret == -1)
- return 1;
- buf += ret;
- len -= ret;
- } while (len != 0);
- return 0;
- }
- #define NEXT() (have ? 0 : (have = in(indp, &next)), \
- last = have ? (have--, (int)(*next++)) : -1)
- unsigned char inbuf[SIZE];
- unsigned char outbuf[SIZE];
- unsigned short prefix[65536];
- unsigned char suffix[65536];
- unsigned char match[65280 + 2];
- #define FLUSHCODE() \
- do { \
- left = 0; \
- rem = 0; \
- if (chunk > have) { \
- chunk -= have; \
- have = 0; \
- if (NEXT() == -1) \
- break; \
- chunk--; \
- if (chunk > have) { \
- chunk = have = 0; \
- break; \
- } \
- } \
- have -= chunk; \
- next += chunk; \
- chunk = 0; \
- } while (0)
- local int lunpipe(unsigned have, z_const unsigned char *next, struct ind *indp,
- int outfile, z_stream *strm)
- {
- int last;
- unsigned chunk;
- int left;
- unsigned rem;
- int bits;
- unsigned code;
- unsigned mask;
- int max;
- unsigned flags;
- unsigned end;
- unsigned temp;
- unsigned prev;
- unsigned final;
- unsigned stack;
- unsigned outcnt;
- struct outd outd;
- unsigned char *p;
-
- outd.outfile = outfile;
- outd.check = 0;
-
- flags = NEXT();
- if (last == -1)
- return Z_BUF_ERROR;
- if (flags & 0x60) {
- strm->msg = (char *)"unknown lzw flags set";
- return Z_DATA_ERROR;
- }
- max = flags & 0x1f;
- if (max < 9 || max > 16) {
- strm->msg = (char *)"lzw bits out of range";
- return Z_DATA_ERROR;
- }
- if (max == 9)
- max = 10;
- flags &= 0x80;
-
- bits = 9;
- mask = 0x1ff;
- end = flags ? 256 : 255;
-
- if (NEXT() == -1)
- return Z_OK;
- final = prev = (unsigned)last;
- if (NEXT() == -1)
- return Z_BUF_ERROR;
- if (last & 1) {
- strm->msg = (char *)"invalid lzw code";
- return Z_DATA_ERROR;
- }
- rem = (unsigned)last >> 1;
- left = 7;
- chunk = bits - 2;
- outbuf[0] = (unsigned char)final;
- outcnt = 1;
-
- stack = 0;
- for (;;) {
-
- if (end >= mask && bits < max) {
- FLUSHCODE();
- bits++;
- mask <<= 1;
- mask++;
- }
-
- if (chunk == 0)
- chunk = bits;
- code = rem;
- if (NEXT() == -1) {
-
- if (outcnt && out(&outd, outbuf, outcnt)) {
- strm->next_in = outbuf;
- return Z_BUF_ERROR;
- }
- return Z_OK;
- }
- code += (unsigned)last << left;
- left += 8;
- chunk--;
- if (bits > left) {
- if (NEXT() == -1)
- return Z_BUF_ERROR;
- code += (unsigned)last << left;
- left += 8;
- chunk--;
- }
- code &= mask;
- left -= bits;
- rem = (unsigned)last >> (8 - left);
-
- if (code == 256 && flags) {
- FLUSHCODE();
- bits = 9;
- mask = 0x1ff;
- end = 255;
- continue;
- }
-
- temp = code;
- if (code > end) {
-
- if (code != end + 1 || prev > end) {
- strm->msg = (char *)"invalid lzw code";
- return Z_DATA_ERROR;
- }
- match[stack++] = (unsigned char)final;
- code = prev;
- }
-
- p = match + stack;
- while (code >= 256) {
- *p++ = suffix[code];
- code = prefix[code];
- }
- stack = p - match;
- match[stack++] = (unsigned char)code;
- final = code;
-
- if (end < mask) {
- end++;
- prefix[end] = (unsigned short)prev;
- suffix[end] = (unsigned char)final;
- }
-
- prev = temp;
-
- while (stack > SIZE - outcnt) {
- while (outcnt < SIZE)
- outbuf[outcnt++] = match[--stack];
- if (out(&outd, outbuf, outcnt)) {
- strm->next_in = outbuf;
- return Z_BUF_ERROR;
- }
- outcnt = 0;
- }
- p = match + stack;
- do {
- outbuf[outcnt++] = *--p;
- } while (p > match);
- stack = 0;
-
- }
- }
- local int gunpipe(z_stream *strm, int infile, int outfile)
- {
- int ret, first, last;
- unsigned have, flags, len;
- z_const unsigned char *next = NULL;
- struct ind ind, *indp;
- struct outd outd;
-
- ind.infile = infile;
- ind.inbuf = inbuf;
- indp = &ind;
-
- have = 0;
- first = 1;
- strm->next_in = Z_NULL;
- for (;;) {
-
- if (NEXT() == -1) {
- ret = Z_OK;
- break;
- }
- if (last != 31 || (NEXT() != 139 && last != 157)) {
- strm->msg = (char *)"incorrect header check";
- ret = first ? Z_DATA_ERROR : Z_ERRNO;
- break;
- }
- first = 0;
-
- if (last == 157) {
- ret = lunpipe(have, next, indp, outfile, strm);
- break;
- }
-
- ret = Z_BUF_ERROR;
- if (NEXT() != 8) {
- if (last == -1) break;
- strm->msg = (char *)"unknown compression method";
- ret = Z_DATA_ERROR;
- break;
- }
- flags = NEXT();
- NEXT();
- NEXT();
- NEXT();
- NEXT();
- NEXT();
- NEXT();
- if (last == -1) break;
- if (flags & 0xe0) {
- strm->msg = (char *)"unknown header flags set";
- ret = Z_DATA_ERROR;
- break;
- }
- if (flags & 4) {
- len = NEXT();
- len += (unsigned)(NEXT()) << 8;
- if (last == -1) break;
- while (len > have) {
- len -= have;
- have = 0;
- if (NEXT() == -1) break;
- len--;
- }
- if (last == -1) break;
- have -= len;
- next += len;
- }
- if (flags & 8)
- while (NEXT() != 0 && last != -1)
- ;
- if (flags & 16)
- while (NEXT() != 0 && last != -1)
- ;
- if (flags & 2) {
- NEXT();
- NEXT();
- }
- if (last == -1) break;
-
- outd.outfile = outfile;
- outd.check = 1;
- outd.crc = crc32(0L, Z_NULL, 0);
- outd.total = 0;
-
- strm->next_in = next;
- strm->avail_in = have;
- ret = inflateBack(strm, in, indp, out, &outd);
- if (ret != Z_STREAM_END) break;
- next = strm->next_in;
- have = strm->avail_in;
- strm->next_in = Z_NULL;
-
- ret = Z_BUF_ERROR;
- if (NEXT() != (int)(outd.crc & 0xff) ||
- NEXT() != (int)((outd.crc >> 8) & 0xff) ||
- NEXT() != (int)((outd.crc >> 16) & 0xff) ||
- NEXT() != (int)((outd.crc >> 24) & 0xff)) {
-
- if (last != -1) {
- strm->msg = (char *)"incorrect data check";
- ret = Z_DATA_ERROR;
- }
- break;
- }
- if (NEXT() != (int)(outd.total & 0xff) ||
- NEXT() != (int)((outd.total >> 8) & 0xff) ||
- NEXT() != (int)((outd.total >> 16) & 0xff) ||
- NEXT() != (int)((outd.total >> 24) & 0xff)) {
-
- if (last != -1) {
- strm->msg = (char *)"incorrect length check";
- ret = Z_DATA_ERROR;
- }
- break;
- }
-
- }
-
- return ret;
- }
- local void copymeta(char *from, char *to)
- {
- struct stat was;
- struct utimbuf when;
-
- if (stat(from, &was) != 0 || (was.st_mode & S_IFMT) != S_IFREG)
- return;
-
- (void)chmod(to, was.st_mode & 07777);
-
- (void)chown(to, was.st_uid, was.st_gid);
-
- when.actime = was.st_atime;
- when.modtime = was.st_mtime;
- (void)utime(to, &when);
- }
- local int gunzip(z_stream *strm, char *inname, char *outname, int test)
- {
- int ret;
- int infile, outfile;
-
- if (inname == NULL || *inname == 0) {
- inname = "-";
- infile = 0;
- }
- else {
- infile = open(inname, O_RDONLY, 0);
- if (infile == -1) {
- fprintf(stderr, "gun cannot open %s\n", inname);
- return 0;
- }
- }
- if (test)
- outfile = -1;
- else if (outname == NULL || *outname == 0) {
- outname = "-";
- outfile = 1;
- }
- else {
- outfile = open(outname, O_CREAT | O_TRUNC | O_WRONLY, 0666);
- if (outfile == -1) {
- close(infile);
- fprintf(stderr, "gun cannot create %s\n", outname);
- return 0;
- }
- }
- errno = 0;
-
- ret = gunpipe(strm, infile, outfile);
- if (outfile > 2) close(outfile);
- if (infile > 2) close(infile);
-
- switch (ret) {
- case Z_OK:
- case Z_ERRNO:
- if (infile > 2 && outfile > 2) {
- copymeta(inname, outname);
- unlink(inname);
- }
- if (ret == Z_ERRNO)
- fprintf(stderr, "gun warning: trailing garbage ignored in %s\n",
- inname);
- break;
- case Z_DATA_ERROR:
- if (outfile > 2) unlink(outname);
- fprintf(stderr, "gun data error on %s: %s\n", inname, strm->msg);
- break;
- case Z_MEM_ERROR:
- if (outfile > 2) unlink(outname);
- fprintf(stderr, "gun out of memory error--aborting\n");
- return 1;
- case Z_BUF_ERROR:
- if (outfile > 2) unlink(outname);
- if (strm->next_in != Z_NULL) {
- fprintf(stderr, "gun write error on %s: %s\n",
- outname, strerror(errno));
- }
- else if (errno) {
- fprintf(stderr, "gun read error on %s: %s\n",
- inname, strerror(errno));
- }
- else {
- fprintf(stderr, "gun unexpected end of file on %s\n",
- inname);
- }
- break;
- default:
- if (outfile > 2) unlink(outname);
- fprintf(stderr, "gun internal error--aborting\n");
- return 1;
- }
- return 0;
- }
- int main(int argc, char **argv)
- {
- int ret, len, test;
- char *outname;
- unsigned char *window;
- z_stream strm;
-
- window = match;
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- strm.opaque = Z_NULL;
- ret = inflateBackInit(&strm, 15, window);
- if (ret != Z_OK) {
- fprintf(stderr, "gun out of memory error--aborting\n");
- return 1;
- }
-
- argc--;
- argv++;
- test = 0;
- if (argc && strcmp(*argv, "-h") == 0) {
- fprintf(stderr, "gun 1.6 (17 Jan 2010)\n");
- fprintf(stderr, "Copyright (C) 2003-2010 Mark Adler\n");
- fprintf(stderr, "usage: gun [-t] [file1.gz [file2.Z ...]]\n");
- return 0;
- }
- if (argc && strcmp(*argv, "-t") == 0) {
- test = 1;
- argc--;
- argv++;
- }
- if (argc)
- do {
- if (test)
- outname = NULL;
- else {
- len = (int)strlen(*argv);
- if (strcmp(*argv + len - 3, ".gz") == 0 ||
- strcmp(*argv + len - 3, "-gz") == 0)
- len -= 3;
- else if (strcmp(*argv + len - 2, ".z") == 0 ||
- strcmp(*argv + len - 2, "-z") == 0 ||
- strcmp(*argv + len - 2, "_z") == 0 ||
- strcmp(*argv + len - 2, ".Z") == 0)
- len -= 2;
- else {
- fprintf(stderr, "gun error: no gz type on %s--skipping\n",
- *argv);
- continue;
- }
- outname = malloc(len + 1);
- if (outname == NULL) {
- fprintf(stderr, "gun out of memory error--aborting\n");
- ret = 1;
- break;
- }
- memcpy(outname, *argv, len);
- outname[len] = 0;
- }
- ret = gunzip(&strm, *argv, outname, test);
- if (outname != NULL) free(outname);
- if (ret) break;
- } while (argv++, --argc);
- else
- ret = gunzip(&strm, NULL, NULL, test);
-
- inflateBackEnd(&strm);
- return ret;
- }
|