From ff3adf608207084d1454acddfdb8904bb139c5e4 Mon Sep 17 00:00:00 2001 From: rsc Date: Wed, 14 Apr 2004 20:09:21 +0000 Subject: add gzip, bzip2 ' --- src/cmd/gzip/gunzip.c | 360 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 360 insertions(+) create mode 100644 src/cmd/gzip/gunzip.c (limited to 'src/cmd/gzip/gunzip.c') diff --git a/src/cmd/gzip/gunzip.c b/src/cmd/gzip/gunzip.c new file mode 100644 index 00000000..691827d3 --- /dev/null +++ b/src/cmd/gzip/gunzip.c @@ -0,0 +1,360 @@ +#include +#include +#include +#include +#include "gzip.h" + +typedef struct GZHead GZHead; + +struct GZHead +{ + ulong mtime; + char *file; +}; + +static int crcwrite(void *bout, void *buf, int n); +static int get1(Biobuf *b); +static ulong get4(Biobuf *b); +static int gunzipf(char *file, int stdout); +static int gunzip(int ofd, char *ofile, Biobuf *bin); +static void header(Biobuf *bin, GZHead *h); +static void trailer(Biobuf *bin, long wlen); +static void error(char*, ...); +/* #pragma varargck argpos error 1 */ + +static Biobuf bin; +static ulong crc; +static ulong *crctab; +static int debug; +static char *delfile; +static vlong gzok; +static char *infile; +static int settimes; +static int table; +static int verbose; +static int wbad; +static ulong wlen; +static jmp_buf zjmp; + +void +usage(void) +{ + fprint(2, "usage: gunzip [-ctvTD] [file ....]\n"); + exits("usage"); +} + +void +main(int argc, char *argv[]) +{ + int i, ok, stdout; + + stdout = 0; + ARGBEGIN{ + case 'D': + debug++; + break; + case 'c': + stdout++; + break; + case 't': + table++; + break; + case 'T': + settimes++; + break; + case 'v': + verbose++; + break; + default: + usage(); + break; + }ARGEND + + crctab = mkcrctab(GZCRCPOLY); + ok = inflateinit(); + if(ok != FlateOk) + sysfatal("inflateinit failed: %s\n", flateerr(ok)); + + if(argc == 0){ + Binit(&bin, 0, OREAD); + settimes = 0; + infile = ""; + ok = gunzip(1, "", &bin); + }else{ + ok = 1; + if(stdout) + settimes = 0; + for(i = 0; i < argc; i++) + ok &= gunzipf(argv[i], stdout); + } + + exits(ok ? nil: "errors"); +} + +static int +gunzipf(char *file, int stdout) +{ + char ofile[256], *s; + int ofd, ifd, ok; + + infile = file; + ifd = open(file, OREAD); + if(ifd < 0){ + fprint(2, "gunzip: can't open %s: %r\n", file); + return 0; + } + + Binit(&bin, ifd, OREAD); + if(Bgetc(&bin) != GZMAGIC1 || Bgetc(&bin) != GZMAGIC2 || Bgetc(&bin) != GZDEFLATE){ + fprint(2, "gunzip: %s is not a gzip deflate file\n", file); + Bterm(&bin); + close(ifd); + return 0; + } + Bungetc(&bin); + Bungetc(&bin); + Bungetc(&bin); + + if(table) + ofd = -1; + else if(stdout){ + ofd = 1; + strcpy(ofile, ""); + }else{ + s = strrchr(file, '/'); + if(s != nil) + s++; + else + s = file; + strecpy(ofile, ofile+sizeof ofile, s); + s = strrchr(ofile, '.'); + if(s != nil && s != ofile && strcmp(s, ".gz") == 0) + *s = '\0'; + else if(s != nil && strcmp(s, ".tgz") == 0) + strcpy(s, ".tar"); + else if(strcmp(file, ofile) == 0){ + fprint(2, "gunzip: can't overwrite %s\n", file); + Bterm(&bin); + close(ifd); + return 0; + } + + ofd = create(ofile, OWRITE, 0666); + if(ofd < 0){ + fprint(2, "gunzip: can't create %s: %r\n", ofile); + Bterm(&bin); + close(ifd); + return 0; + } + delfile = ofile; + } + + wbad = 0; + ok = gunzip(ofd, ofile, &bin); + Bterm(&bin); + close(ifd); + if(wbad){ + fprint(2, "gunzip: can't write %s: %r\n", ofile); + if(delfile) + remove(delfile); + } + delfile = nil; + if(!stdout && ofd >= 0) + close(ofd); + return ok; +} + +static int +gunzip(int ofd, char *ofile, Biobuf *bin) +{ + Dir *d; + GZHead h; + int err; + + h.file = nil; + gzok = 0; + for(;;){ + if(Bgetc(bin) < 0) + return 1; + Bungetc(bin); + + if(setjmp(zjmp)) + return 0; + header(bin, &h); + gzok = 0; + + wlen = 0; + crc = 0; + + if(!table && verbose) + fprint(2, "extracting %s to %s\n", h.file, ofile); + + err = inflate((void*)ofd, crcwrite, bin, (int(*)(void*))Bgetc); + if(err != FlateOk) + error("inflate failed: %s", flateerr(err)); + + trailer(bin, wlen); + + if(table){ + if(verbose) + print("%-32s %10ld %s", h.file, wlen, ctime(h.mtime)); + else + print("%s\n", h.file); + }else if(settimes && h.mtime && (d=dirfstat(ofd)) != nil){ + d->mtime = h.mtime; + dirfwstat(ofd, d); + free(d); + } + + free(h.file); + h.file = nil; + gzok = Boffset(bin); + } + return 0; +} + +static void +header(Biobuf *bin, GZHead *h) +{ + char *s; + int i, c, flag, ns, nsa; + + if(get1(bin) != GZMAGIC1 || get1(bin) != GZMAGIC2) + error("bad gzip file magic"); + if(get1(bin) != GZDEFLATE) + error("unknown compression type"); + + flag = get1(bin); + if(flag & ~(GZFTEXT|GZFEXTRA|GZFNAME|GZFCOMMENT|GZFHCRC)) + fprint(2, "gunzip: reserved flags set, data may not be decompressed correctly\n"); + + /* mod time */ + h->mtime = get4(bin); + + /* extra flags */ + get1(bin); + + /* OS type */ + get1(bin); + + if(flag & GZFEXTRA) + for(i=get1(bin); i>0; i--) + get1(bin); + + /* name */ + if(flag & GZFNAME){ + nsa = 32; + ns = 0; + s = malloc(nsa); + if(s == nil) + error("out of memory"); + while((c = get1(bin)) != 0){ + s[ns++] = c; + if(ns >= nsa){ + nsa += 32; + s = realloc(s, nsa); + if(s == nil) + error("out of memory"); + } + } + s[ns] = '\0'; + h->file = s; + }else + h->file = strdup(""); + + /* comment */ + if(flag & GZFCOMMENT) + while(get1(bin) != 0) + ; + + /* crc16 */ + if(flag & GZFHCRC){ + get1(bin); + get1(bin); + } +} + +static void +trailer(Biobuf *bin, long wlen) +{ + ulong tcrc; + long len; + + tcrc = get4(bin); + if(tcrc != crc) + error("crc mismatch"); + + len = get4(bin); + + if(len != wlen) + error("bad output length: expected %lud got %lud", wlen, len); +} + +static ulong +get4(Biobuf *b) +{ + ulong v; + int i, c; + + v = 0; + for(i = 0; i < 4; i++){ + c = Bgetc(b); + if(c < 0) + error("unexpected eof reading file information"); + v |= c << (i * 8); + } + return v; +} + +static int +get1(Biobuf *b) +{ + int c; + + c = Bgetc(b); + if(c < 0) + error("unexpected eof reading file information"); + return c; +} + +static int +crcwrite(void *out, void *buf, int n) +{ + int fd, nw; + + wlen += n; + crc = blockcrc(crctab, crc, buf, n); + fd = (int)out; + if(fd < 0) + return n; + nw = write(fd, buf, n); + if(nw != n) + wbad = 1; + return nw; +} + +static void +error(char *fmt, ...) +{ + va_list arg; + + if(gzok) + fprint(2, "gunzip: %s: corrupted data after byte %lld ignored\n", infile, gzok); + else{ + fprint(2, "gunzip: "); + if(infile) + fprint(2, "%s: ", infile); + va_start(arg, fmt); + vfprint(2, fmt, arg); + va_end(arg); + fprint(2, "\n"); + + if(delfile != nil){ + fprint(2, "gunzip: removing output file %s\n", delfile); + remove(delfile); + delfile = nil; + } + } + + longjmp(zjmp, 1); +} -- cgit v1.2.3