197 lines · 3.8 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 "bzlib.h" static	Biobuf	bin;static	int	debug;static	int	verbose;static	char	*delfile;static	char	*infile;static	int	bunzipf(char *file, int stdout);static	int	bunzip(int ofd, char *ofile, Biobuf *bin); voidusage(void){	fprint(2, "usage: bunzip2 [-cvD] [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 'v':		verbose++;		break;	default:		usage();	}ARGEND 	if(argc == 0){		Binit(&bin, 0, OREAD);		infile = "<stdin>";		ok = bunzip(1, "<stdout>", &bin);	}else{		ok = 1;		for(i = 0; i < argc; i++)			ok &= bunzipf(argv[i], stdout);	} 	exits(ok ? nil: "errors");} static intbunzipf(char *file, int stdout){	char ofile[64], *s;	int ofd, ifd, ok; 	infile = file;	ifd = open(file, OREAD);	if(ifd < 0){		fprint(2, "bunzip2: can't open %s: %r\n", file);		return 0;	} 	Binit(&bin, ifd, OREAD);	if(Bgetc(&bin) != 'B' || Bgetc(&bin) != 'Z' || Bgetc(&bin) != 'h'){		fprint(2, "bunzip2: %s is not a bzip2 file\n", file);		Bterm(&bin);		close(ifd);		return 0;	}	Bungetc(&bin);	Bungetc(&bin);	Bungetc(&bin); 	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, ".bz2") == 0)			*s = '\0';		else if(s != nil && (strcmp(s, ".tbz") == 0 || strcmp(s, ".tbz2") == 0))			strcpy(s, ".tar");		else if(strcmp(file, ofile) == 0){			fprint(2, "bunzip2: can't overwrite %s\n", file);			Bterm(&bin);			close(ifd);			return 0;		} 		ofd = create(ofile, OWRITE, 0666);		if(ofd < 0){			fprint(2, "bunzip2: can't create %s: %r\n", ofile);			Bterm(&bin);			close(ifd);			return 0;		}		delfile = ofile;	} 	ok = bunzip(ofd, ofile, &bin);	Bterm(&bin);	close(ifd);	if(!ok){		fprint(2, "bunzip2: can't write %s: %r\n", ofile);		if(delfile)			remove(delfile);	}	delfile = nil;	if(!stdout && ofd >= 0)		close(ofd);	return ok;} static intbunzip(int ofd, char *ofile, Biobuf *bin){	int e, n, done, onemore;	char buf[8192];	char obuf[8192];	Biobuf bout;	bz_stream strm; 	USED(ofile); 	memset(&strm, 0, sizeof strm);	BZ2_bzDecompressInit(&strm, verbose, 0); 	strm.next_in = buf;	strm.avail_in = 0;	strm.next_out = obuf;	strm.avail_out = sizeof obuf; 	done = 0;	Binit(&bout, ofd, OWRITE); 	/*	 * onemore is a crummy hack to go 'round the loop	 * once after we finish, to flush the output buffer.	 */	onemore = 1;	SET(e);	do {		if(!done && strm.avail_in < sizeof buf) {			if(strm.avail_in)				memmove(buf, strm.next_in, strm.avail_in);						n = Bread(bin, buf+strm.avail_in, sizeof(buf)-strm.avail_in);			if(n <= 0)				done = 1;			else				strm.avail_in += n;			strm.next_in = buf;		}		if(strm.avail_out < sizeof obuf) {			Bwrite(&bout, obuf, sizeof(obuf)-strm.avail_out);			strm.next_out = obuf;			strm.avail_out = sizeof obuf;		}		if(onemore == 0)			break;		if(strm.avail_in == 0 && strm.avail_out == sizeof obuf)			break;	} while((e=BZ2_bzDecompress(&strm)) == BZ_OK || onemore--); 	if(e != BZ_STREAM_END) {		fprint(2, "bunzip2: decompress failed\n");		return 0;	} 	if(BZ2_bzDecompressEnd(&strm) != BZ_OK) {		fprint(2, "bunzip2: decompress end failed (can't happen)\n");		return 0;	} 	Bterm(&bout); 	return 1;}