xref: /plan9-contrib/sys/src/cmd/bzip2/bunzip2.c (revision 4e47a2bae186af79a55734a785d2843fa45765ae)
159cc4ca5SDavid du Colombier #include <u.h>
259cc4ca5SDavid du Colombier #include <libc.h>
359cc4ca5SDavid du Colombier #include <bio.h>
459cc4ca5SDavid du Colombier #include "bzlib.h"
559cc4ca5SDavid du Colombier 
659cc4ca5SDavid du Colombier static	Biobuf	bin;
759cc4ca5SDavid du Colombier static	int	debug;
859cc4ca5SDavid du Colombier static	int	verbose;
959cc4ca5SDavid du Colombier static	char	*delfile;
1059cc4ca5SDavid du Colombier static	char	*infile;
1159cc4ca5SDavid du Colombier static	int	bunzipf(char *file, int stdout);
1259cc4ca5SDavid du Colombier static	int	bunzip(int ofd, char *ofile, Biobuf *bin);
1359cc4ca5SDavid du Colombier 
1459cc4ca5SDavid du Colombier void
usage(void)1559cc4ca5SDavid du Colombier usage(void)
1659cc4ca5SDavid du Colombier {
1759cc4ca5SDavid du Colombier 	fprint(2, "usage: bunzip2 [-cvD] [file ...]\n");
1859cc4ca5SDavid du Colombier 	exits("usage");
1959cc4ca5SDavid du Colombier }
2059cc4ca5SDavid du Colombier 
2159cc4ca5SDavid du Colombier void
main(int argc,char ** argv)2259cc4ca5SDavid du Colombier main(int argc, char **argv)
2359cc4ca5SDavid du Colombier {
2459cc4ca5SDavid du Colombier 	int i, ok, stdout;
2559cc4ca5SDavid du Colombier 
2659cc4ca5SDavid du Colombier 	stdout = 0;
2759cc4ca5SDavid du Colombier 	ARGBEGIN{
2859cc4ca5SDavid du Colombier 	case 'D':
2959cc4ca5SDavid du Colombier 		debug++;
3059cc4ca5SDavid du Colombier 		break;
3159cc4ca5SDavid du Colombier 	case 'c':
3259cc4ca5SDavid du Colombier 		stdout++;
3359cc4ca5SDavid du Colombier 		break;
3459cc4ca5SDavid du Colombier 	case 'v':
3559cc4ca5SDavid du Colombier 		verbose++;
3659cc4ca5SDavid du Colombier 		break;
3707c70eb6SDavid du Colombier 	default:
3807c70eb6SDavid du Colombier 		usage();
3959cc4ca5SDavid du Colombier 	}ARGEND
4059cc4ca5SDavid du Colombier 
4159cc4ca5SDavid du Colombier 	if(argc == 0){
4259cc4ca5SDavid du Colombier 		Binit(&bin, 0, OREAD);
4359cc4ca5SDavid du Colombier 		infile = "<stdin>";
4459cc4ca5SDavid du Colombier 		ok = bunzip(1, "<stdout>", &bin);
4559cc4ca5SDavid du Colombier 	}else{
4659cc4ca5SDavid du Colombier 		ok = 1;
4759cc4ca5SDavid du Colombier 		for(i = 0; i < argc; i++)
4859cc4ca5SDavid du Colombier 			ok &= bunzipf(argv[i], stdout);
4959cc4ca5SDavid du Colombier 	}
5059cc4ca5SDavid du Colombier 
5159cc4ca5SDavid du Colombier 	exits(ok ? nil: "errors");
5259cc4ca5SDavid du Colombier }
5359cc4ca5SDavid du Colombier 
5459cc4ca5SDavid du Colombier static int
bunzipf(char * file,int stdout)5559cc4ca5SDavid du Colombier bunzipf(char *file, int stdout)
5659cc4ca5SDavid du Colombier {
579a747e4fSDavid du Colombier 	char ofile[64], *s;
5859cc4ca5SDavid du Colombier 	int ofd, ifd, ok;
5959cc4ca5SDavid du Colombier 
6059cc4ca5SDavid du Colombier 	infile = file;
6159cc4ca5SDavid du Colombier 	ifd = open(file, OREAD);
6259cc4ca5SDavid du Colombier 	if(ifd < 0){
63*4e47a2baSDavid du Colombier 		fprint(2, "bunzip2: can't open %s: %r\n", file);
6459cc4ca5SDavid du Colombier 		return 0;
6559cc4ca5SDavid du Colombier 	}
6659cc4ca5SDavid du Colombier 
6759cc4ca5SDavid du Colombier 	Binit(&bin, ifd, OREAD);
6859cc4ca5SDavid du Colombier 	if(Bgetc(&bin) != 'B' || Bgetc(&bin) != 'Z' || Bgetc(&bin) != 'h'){
6959cc4ca5SDavid du Colombier 		fprint(2, "bunzip2: %s is not a bzip2 file\n", file);
7059cc4ca5SDavid du Colombier 		Bterm(&bin);
7159cc4ca5SDavid du Colombier 		close(ifd);
7259cc4ca5SDavid du Colombier 		return 0;
7359cc4ca5SDavid du Colombier 	}
7459cc4ca5SDavid du Colombier 	Bungetc(&bin);
7559cc4ca5SDavid du Colombier 	Bungetc(&bin);
7659cc4ca5SDavid du Colombier 	Bungetc(&bin);
7759cc4ca5SDavid du Colombier 
7859cc4ca5SDavid du Colombier 	if(stdout){
7959cc4ca5SDavid du Colombier 		ofd = 1;
8059cc4ca5SDavid du Colombier 		strcpy(ofile, "<stdout>");
8159cc4ca5SDavid du Colombier 	}else{
8259cc4ca5SDavid du Colombier 		s = strrchr(file, '/');
8359cc4ca5SDavid du Colombier 		if(s != nil)
8459cc4ca5SDavid du Colombier 			s++;
8559cc4ca5SDavid du Colombier 		else
8659cc4ca5SDavid du Colombier 			s = file;
879a747e4fSDavid du Colombier 		strecpy(ofile, ofile+sizeof ofile, s);
8859cc4ca5SDavid du Colombier 		s = strrchr(ofile, '.');
8959cc4ca5SDavid du Colombier 		if(s != nil && s != ofile && strcmp(s, ".bz2") == 0)
9059cc4ca5SDavid du Colombier 			*s = '\0';
9159cc4ca5SDavid du Colombier 		else if(s != nil && (strcmp(s, ".tbz") == 0 || strcmp(s, ".tbz2") == 0))
9259cc4ca5SDavid du Colombier 			strcpy(s, ".tar");
9359cc4ca5SDavid du Colombier 		else if(strcmp(file, ofile) == 0){
9459cc4ca5SDavid du Colombier 			fprint(2, "bunzip2: can't overwrite %s\n", file);
9559cc4ca5SDavid du Colombier 			Bterm(&bin);
9659cc4ca5SDavid du Colombier 			close(ifd);
9759cc4ca5SDavid du Colombier 			return 0;
9859cc4ca5SDavid du Colombier 		}
9959cc4ca5SDavid du Colombier 
10059cc4ca5SDavid du Colombier 		ofd = create(ofile, OWRITE, 0666);
10159cc4ca5SDavid du Colombier 		if(ofd < 0){
10259cc4ca5SDavid du Colombier 			fprint(2, "bunzip2: can't create %s: %r\n", ofile);
10359cc4ca5SDavid du Colombier 			Bterm(&bin);
10459cc4ca5SDavid du Colombier 			close(ifd);
10559cc4ca5SDavid du Colombier 			return 0;
10659cc4ca5SDavid du Colombier 		}
10759cc4ca5SDavid du Colombier 		delfile = ofile;
10859cc4ca5SDavid du Colombier 	}
10959cc4ca5SDavid du Colombier 
11059cc4ca5SDavid du Colombier 	ok = bunzip(ofd, ofile, &bin);
11159cc4ca5SDavid du Colombier 	Bterm(&bin);
11259cc4ca5SDavid du Colombier 	close(ifd);
11359cc4ca5SDavid du Colombier 	if(!ok){
11459cc4ca5SDavid du Colombier 		fprint(2, "bunzip2: can't write %s: %r\n", ofile);
11559cc4ca5SDavid du Colombier 		if(delfile)
11659cc4ca5SDavid du Colombier 			remove(delfile);
11759cc4ca5SDavid du Colombier 	}
11859cc4ca5SDavid du Colombier 	delfile = nil;
11959cc4ca5SDavid du Colombier 	if(!stdout && ofd >= 0)
12059cc4ca5SDavid du Colombier 		close(ofd);
12159cc4ca5SDavid du Colombier 	return ok;
12259cc4ca5SDavid du Colombier }
12359cc4ca5SDavid du Colombier 
12459cc4ca5SDavid du Colombier static int
bunzip(int ofd,char * ofile,Biobuf * bin)12559cc4ca5SDavid du Colombier bunzip(int ofd, char *ofile, Biobuf *bin)
12659cc4ca5SDavid du Colombier {
12759cc4ca5SDavid du Colombier 	int e, n, done, onemore;
12859cc4ca5SDavid du Colombier 	char buf[8192];
12959cc4ca5SDavid du Colombier 	char obuf[8192];
13059cc4ca5SDavid du Colombier 	Biobuf bout;
13159cc4ca5SDavid du Colombier 	bz_stream strm;
13259cc4ca5SDavid du Colombier 
13359cc4ca5SDavid du Colombier 	USED(ofile);
13459cc4ca5SDavid du Colombier 
13559cc4ca5SDavid du Colombier 	memset(&strm, 0, sizeof strm);
13659cc4ca5SDavid du Colombier 	BZ2_bzDecompressInit(&strm, verbose, 0);
13759cc4ca5SDavid du Colombier 
13859cc4ca5SDavid du Colombier 	strm.next_in = buf;
13959cc4ca5SDavid du Colombier 	strm.avail_in = 0;
14059cc4ca5SDavid du Colombier 	strm.next_out = obuf;
14159cc4ca5SDavid du Colombier 	strm.avail_out = sizeof obuf;
14259cc4ca5SDavid du Colombier 
14359cc4ca5SDavid du Colombier 	done = 0;
14459cc4ca5SDavid du Colombier 	Binit(&bout, ofd, OWRITE);
14559cc4ca5SDavid du Colombier 
14659cc4ca5SDavid du Colombier 	/*
14759cc4ca5SDavid du Colombier 	 * onemore is a crummy hack to go 'round the loop
14859cc4ca5SDavid du Colombier 	 * once after we finish, to flush the output buffer.
14959cc4ca5SDavid du Colombier 	 */
15059cc4ca5SDavid du Colombier 	onemore = 1;
15159cc4ca5SDavid du Colombier 	SET(e);
15259cc4ca5SDavid du Colombier 	do {
15359cc4ca5SDavid du Colombier 		if(!done && strm.avail_in < sizeof buf) {
15459cc4ca5SDavid du Colombier 			if(strm.avail_in)
15559cc4ca5SDavid du Colombier 				memmove(buf, strm.next_in, strm.avail_in);
15659cc4ca5SDavid du Colombier 
15759cc4ca5SDavid du Colombier 			n = Bread(bin, buf+strm.avail_in, sizeof(buf)-strm.avail_in);
15859cc4ca5SDavid du Colombier 			if(n <= 0)
15959cc4ca5SDavid du Colombier 				done = 1;
16059cc4ca5SDavid du Colombier 			else
16159cc4ca5SDavid du Colombier 				strm.avail_in += n;
16259cc4ca5SDavid du Colombier 			strm.next_in = buf;
16359cc4ca5SDavid du Colombier 		}
16459cc4ca5SDavid du Colombier 		if(strm.avail_out < sizeof obuf) {
16559cc4ca5SDavid du Colombier 			Bwrite(&bout, obuf, sizeof(obuf)-strm.avail_out);
16659cc4ca5SDavid du Colombier 			strm.next_out = obuf;
16759cc4ca5SDavid du Colombier 			strm.avail_out = sizeof obuf;
16859cc4ca5SDavid du Colombier 		}
16959cc4ca5SDavid du Colombier 		if(onemore == 0)
17059cc4ca5SDavid du Colombier 			break;
1715d459b5aSDavid du Colombier 		if(strm.avail_in == 0 && strm.avail_out == sizeof obuf)
1725d459b5aSDavid du Colombier 			break;
17359cc4ca5SDavid du Colombier 	} while((e=BZ2_bzDecompress(&strm)) == BZ_OK || onemore--);
17459cc4ca5SDavid du Colombier 
17559cc4ca5SDavid du Colombier 	if(e != BZ_STREAM_END) {
17659cc4ca5SDavid du Colombier 		fprint(2, "bunzip2: decompress failed\n");
17759cc4ca5SDavid du Colombier 		return 0;
17859cc4ca5SDavid du Colombier 	}
17959cc4ca5SDavid du Colombier 
18059cc4ca5SDavid du Colombier 	if(BZ2_bzDecompressEnd(&strm) != BZ_OK) {
18159cc4ca5SDavid du Colombier 		fprint(2, "bunzip2: decompress end failed (can't happen)\n");
18259cc4ca5SDavid du Colombier 		return 0;
18359cc4ca5SDavid du Colombier 	}
18459cc4ca5SDavid du Colombier 
1859a747e4fSDavid du Colombier 	Bterm(&bout);
1869a747e4fSDavid du Colombier 
18759cc4ca5SDavid du Colombier 	return 1;
18859cc4ca5SDavid du Colombier }
189