123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359 |
- #include <u.h>
- #include <libc.h>
- #include <bio.h>
- #include <flate.h>
- #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 = "<stdin>";
- ok = gunzip(1, "<stdout>", &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, "<stdout>");
- }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);
- }
- }
- 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("<unnamed file>");
- /* 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)(uintptr)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);
- }
|