📄 gunzip.c
字号:
#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 1static 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;voidusage(void){ fprint(2, "usage: gunzip [-ctvTD] [file ....]\n"); exits("usage");}voidmain(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 intgunzipf(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 intgunzip(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 voidheader(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 voidtrailer(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 ulongget4(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 intget1(Biobuf *b){ int c; c = Bgetc(b); if(c < 0) error("unexpected eof reading file information"); return c;}static intcrcwrite(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 voiderror(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);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -