|  | #include <u.h> | 
|  | #include <libc.h> | 
|  | #include <bio.h> | 
|  | #include <flate.h> | 
|  | #include "gzip.h" | 
|  |  | 
|  | static	int	gzipf(char*, int); | 
|  | static	int	gzip(char*, long, int, Biobuf*); | 
|  | static	int	crcread(void *fd, void *buf, int n); | 
|  | static	int	gzwrite(void *bout, void *buf, int n); | 
|  |  | 
|  | static	Biobuf	bout; | 
|  | static	u32int	crc; | 
|  | static	u32int	*crctab; | 
|  | static	int	debug; | 
|  | static	int	eof; | 
|  | static	int	level; | 
|  | static	u32int	totr; | 
|  | static	int	verbose; | 
|  |  | 
|  | void | 
|  | usage(void) | 
|  | { | 
|  | fprint(2, "usage: gzip [-vcD] [-1-9] [file ...]\n"); | 
|  | exits("usage"); | 
|  | } | 
|  |  | 
|  | void | 
|  | main(int argc, char *argv[]) | 
|  | { | 
|  | int i, ok, stdout; | 
|  | char **oargv; | 
|  |  | 
|  | oargv = argv; | 
|  | level = 6; | 
|  | stdout = 0; | 
|  | ARGBEGIN{ | 
|  | case 'D': | 
|  | debug++; | 
|  | break; | 
|  | case 'd': | 
|  | /* | 
|  | * gnu tar expects gzip -d to decompress | 
|  | * humor it.  ugh. | 
|  | */ | 
|  | /* remove -d from command line - magic! */ | 
|  | if(strcmp(argv[0], "-d") == 0){ | 
|  | while(*argv++) | 
|  | *(argv-1) = *argv; | 
|  | }else | 
|  | memmove(_args-1, _args, strlen(_args)+1); | 
|  | exec("gunzip", oargv); | 
|  | sysfatal("exec gunzip failed"); | 
|  | break; | 
|  | case 'f': | 
|  | /* force */ | 
|  | break; | 
|  | case 'v': | 
|  | verbose++; | 
|  | break; | 
|  | case 'c': | 
|  | stdout = 1; | 
|  | break; | 
|  | case '1': case '2': case '3': case '4': | 
|  | case '5': case '6': case '7': case '8': case '9': | 
|  | level = ARGC() - '0'; | 
|  | break; | 
|  | default: | 
|  | usage(); | 
|  | break; | 
|  | }ARGEND | 
|  |  | 
|  | crctab = mkcrctab(GZCRCPOLY); | 
|  | ok = deflateinit(); | 
|  | if(ok != FlateOk) | 
|  | sysfatal("deflateinit failed: %s\n", flateerr(ok)); | 
|  |  | 
|  | if(argc == 0){ | 
|  | Binit(&bout, 1, OWRITE); | 
|  | ok = gzip(nil, time(0), 0, &bout); | 
|  | Bterm(&bout); | 
|  | }else{ | 
|  | ok = 1; | 
|  | for(i = 0; i < argc; i++) | 
|  | ok &= gzipf(argv[i], stdout); | 
|  | } | 
|  | exits(ok ? nil: "errors"); | 
|  | } | 
|  |  | 
|  | static int | 
|  | gzipf(char *file, int stdout) | 
|  | { | 
|  | Dir *dir; | 
|  | char ofile[256], *f, *s; | 
|  | int ifd, ofd, ok; | 
|  |  | 
|  | ifd = open(file, OREAD); | 
|  | if(ifd < 0){ | 
|  | fprint(2, "gzip: can't open %s: %r\n", file); | 
|  | return 0; | 
|  | } | 
|  | dir = dirfstat(ifd); | 
|  | if(dir == nil){ | 
|  | fprint(2, "gzip: can't stat %s: %r\n", file); | 
|  | close(ifd); | 
|  | return 0; | 
|  | } | 
|  | if(dir->mode & DMDIR){ | 
|  | fprint(2, "gzip: can't compress a directory\n"); | 
|  | close(ifd); | 
|  | free(dir); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if(stdout){ | 
|  | ofd = 1; | 
|  | strcpy(ofile, "<stdout>"); | 
|  | }else{ | 
|  | f = strrchr(file, '/'); | 
|  | if(f != nil) | 
|  | f++; | 
|  | else | 
|  | f = file; | 
|  | s = strrchr(f, '.'); | 
|  | if(s != nil && s != ofile && strcmp(s, ".tar") == 0){ | 
|  | *s = '\0'; | 
|  | snprint(ofile, sizeof(ofile), "%s.tgz", f); | 
|  | }else | 
|  | snprint(ofile, sizeof(ofile), "%s.gz", f); | 
|  | ofd = create(ofile, OWRITE, 0666); | 
|  | if(ofd < 0){ | 
|  | fprint(2, "gzip: can't open %s: %r\n", ofile); | 
|  | close(ifd); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | if(verbose) | 
|  | fprint(2, "compressing %s to %s\n", file, ofile); | 
|  |  | 
|  | Binit(&bout, ofd, OWRITE); | 
|  | ok = gzip(file, dir->mtime, ifd, &bout); | 
|  | if(!ok || Bflush(&bout) < 0){ | 
|  | fprint(2, "gzip: error writing %s: %r\n", ofile); | 
|  | if(!stdout) | 
|  | remove(ofile); | 
|  | } | 
|  | Bterm(&bout); | 
|  | free(dir); | 
|  | close(ifd); | 
|  | close(ofd); | 
|  | return ok; | 
|  | } | 
|  |  | 
|  | static int | 
|  | gzip(char *file, long mtime, int ifd, Biobuf *bout) | 
|  | { | 
|  | int flags, err; | 
|  |  | 
|  | flags = 0; | 
|  | Bputc(bout, GZMAGIC1); | 
|  | Bputc(bout, GZMAGIC2); | 
|  | Bputc(bout, GZDEFLATE); | 
|  |  | 
|  | if(file != nil) | 
|  | flags |= GZFNAME; | 
|  | Bputc(bout, flags); | 
|  |  | 
|  | Bputc(bout, mtime); | 
|  | Bputc(bout, mtime>>8); | 
|  | Bputc(bout, mtime>>16); | 
|  | Bputc(bout, mtime>>24); | 
|  |  | 
|  | Bputc(bout, 0); | 
|  | Bputc(bout, GZOSINFERNO); | 
|  |  | 
|  | if(flags & GZFNAME) | 
|  | Bwrite(bout, file, strlen(file)+1); | 
|  |  | 
|  | crc = 0; | 
|  | eof = 0; | 
|  | totr = 0; | 
|  | err = deflate(bout, gzwrite, (void*)(uintptr)ifd, crcread, level, debug); | 
|  | if(err != FlateOk){ | 
|  | fprint(2, "gzip: deflate failed: %s\n", flateerr(err)); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | Bputc(bout, crc); | 
|  | Bputc(bout, crc>>8); | 
|  | Bputc(bout, crc>>16); | 
|  | Bputc(bout, crc>>24); | 
|  |  | 
|  | Bputc(bout, totr); | 
|  | Bputc(bout, totr>>8); | 
|  | Bputc(bout, totr>>16); | 
|  | Bputc(bout, totr>>24); | 
|  |  | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static int | 
|  | crcread(void *fd, void *buf, int n) | 
|  | { | 
|  | int nr, m; | 
|  |  | 
|  | nr = 0; | 
|  | for(; !eof && n > 0; n -= m){ | 
|  | m = read((int)(uintptr)fd, (char*)buf+nr, n); | 
|  | if(m <= 0){ | 
|  | eof = 1; | 
|  | if(m < 0) | 
|  | return -1; | 
|  | break; | 
|  | } | 
|  | nr += m; | 
|  | } | 
|  | crc = blockcrc(crctab, crc, buf, nr); | 
|  | totr += nr; | 
|  | return nr; | 
|  | } | 
|  |  | 
|  | static int | 
|  | gzwrite(void *bout, void *buf, int n) | 
|  | { | 
|  | if(n != Bwrite(bout, buf, n)){ | 
|  | eof = 1; | 
|  | return -1; | 
|  | } | 
|  | return n; | 
|  | } |