221 lines · 4.0 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #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	ulong	crc;static	ulong	*crctab;static	int	debug;static	int	eof;static	int	level;static	ulong	totr;static	int	verbose; voidusage(void){	fprint(2, "usage: gzip [-vcD] [-1-9] [file ...]\n");	exits("usage");} voidmain(int argc, char *argv[]){	int i, ok, stdout; 	level = 6;	stdout = 0;	ARGBEGIN{	case 'D':		debug++;		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", 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 intgzipf(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 intgzip(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*)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 intcrcread(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 intgzwrite(void *bout, void *buf, int n){	if(n != Bwrite(bout, buf, n)){		eof = 1;		return -1;	}	return n;}