xref: /plan9/sys/src/cmd/bzip2/bzip2.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
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	int	bzipf(char*, int);
759cc4ca5SDavid du Colombier static	int	bzip(char*, long, int, Biobuf*);
859cc4ca5SDavid du Colombier 
959cc4ca5SDavid du Colombier static	Biobuf	bout;
1059cc4ca5SDavid du Colombier static	int	level;
1159cc4ca5SDavid du Colombier static	int	debug;
1259cc4ca5SDavid du Colombier static	int	verbose;
1359cc4ca5SDavid du Colombier 
1459cc4ca5SDavid du Colombier 
1559cc4ca5SDavid du Colombier static void
usage(void)1659cc4ca5SDavid du Colombier usage(void)
1759cc4ca5SDavid du Colombier {
1859cc4ca5SDavid du Colombier 	fprint(2, "usage: bzip2 [-vcD] [-1-9] [file ...]\n");
1959cc4ca5SDavid du Colombier 	exits("usage");
2059cc4ca5SDavid du Colombier }
2159cc4ca5SDavid du Colombier 
2259cc4ca5SDavid du Colombier void
main(int argc,char ** argv)2359cc4ca5SDavid du Colombier main(int argc, char **argv)
2459cc4ca5SDavid du Colombier {
2559cc4ca5SDavid du Colombier 	int i, ok, stdout;
2659cc4ca5SDavid du Colombier 
2759cc4ca5SDavid du Colombier 	level = 6;
2859cc4ca5SDavid du Colombier 	stdout = 0;
2959cc4ca5SDavid du Colombier 	ARGBEGIN{
3059cc4ca5SDavid du Colombier 	case 'D':
3159cc4ca5SDavid du Colombier 		debug++;
3259cc4ca5SDavid du Colombier 		break;
3359cc4ca5SDavid du Colombier 	case 'v':
3459cc4ca5SDavid du Colombier 		verbose++;
3559cc4ca5SDavid du Colombier 		break;
3659cc4ca5SDavid du Colombier 	case 'c':
3759cc4ca5SDavid du Colombier 		stdout++;
3859cc4ca5SDavid du Colombier 		break;
3959cc4ca5SDavid du Colombier 	case '1': case '2': case '3': case '4':
4059cc4ca5SDavid du Colombier 	case '5': case '6': case '7': case '8': case '9':
4159cc4ca5SDavid du Colombier 		level = ARGC() - '0';
4259cc4ca5SDavid du Colombier 		break;
4359cc4ca5SDavid du Colombier 	default:
4459cc4ca5SDavid du Colombier 		usage();
4559cc4ca5SDavid du Colombier 		break;
4659cc4ca5SDavid du Colombier 	}ARGEND
4759cc4ca5SDavid du Colombier 
4859cc4ca5SDavid du Colombier 	if(argc == 0){
4959cc4ca5SDavid du Colombier 		Binit(&bout, 1, OWRITE);
5059cc4ca5SDavid du Colombier 		ok = bzip(nil, time(0), 0, &bout);
5159cc4ca5SDavid du Colombier 		Bterm(&bout);
5259cc4ca5SDavid du Colombier 	}else{
5359cc4ca5SDavid du Colombier 		ok = 1;
5459cc4ca5SDavid du Colombier 		for(i = 0; i < argc; i++)
5559cc4ca5SDavid du Colombier 			ok &= bzipf(argv[i], stdout);
5659cc4ca5SDavid du Colombier 	}
5759cc4ca5SDavid du Colombier 	exits(ok ? nil: "errors");
5859cc4ca5SDavid du Colombier }
5959cc4ca5SDavid du Colombier 
6059cc4ca5SDavid du Colombier static int
bzipf(char * file,int stdout)6159cc4ca5SDavid du Colombier bzipf(char *file, int stdout)
6259cc4ca5SDavid du Colombier {
63*9a747e4fSDavid du Colombier 	Dir *dir;
64*9a747e4fSDavid du Colombier 	char ofile[128], *f, *s;
6559cc4ca5SDavid du Colombier 	int ifd, ofd, ok;
6659cc4ca5SDavid du Colombier 
6759cc4ca5SDavid du Colombier 	ifd = open(file, OREAD);
6859cc4ca5SDavid du Colombier 	if(ifd < 0){
6959cc4ca5SDavid du Colombier 		fprint(2, "bzip2: can't open %s: %r\n", file);
7059cc4ca5SDavid du Colombier 		return 0;
7159cc4ca5SDavid du Colombier 	}
72*9a747e4fSDavid du Colombier 	dir = dirfstat(ifd);
73*9a747e4fSDavid du Colombier 	if(dir == nil){
7459cc4ca5SDavid du Colombier 		fprint(2, "bzip2: can't stat %s: %r\n", file);
7559cc4ca5SDavid du Colombier 		close(ifd);
7659cc4ca5SDavid du Colombier 		return 0;
7759cc4ca5SDavid du Colombier 	}
78*9a747e4fSDavid du Colombier 	if(dir->mode & DMDIR){
7959cc4ca5SDavid du Colombier 		fprint(2, "bzip2: can't compress a directory\n");
8059cc4ca5SDavid du Colombier 		close(ifd);
81*9a747e4fSDavid du Colombier 		free(dir);
8259cc4ca5SDavid du Colombier 		return 0;
8359cc4ca5SDavid du Colombier 	}
8459cc4ca5SDavid du Colombier 
8559cc4ca5SDavid du Colombier 	if(stdout){
8659cc4ca5SDavid du Colombier 		ofd = 1;
8759cc4ca5SDavid du Colombier 		strcpy(ofile, "<stdout>");
8859cc4ca5SDavid du Colombier 	}else{
8959cc4ca5SDavid du Colombier 		f = strrchr(file, '/');
9059cc4ca5SDavid du Colombier 		if(f != nil)
9159cc4ca5SDavid du Colombier 			f++;
9259cc4ca5SDavid du Colombier 		else
9359cc4ca5SDavid du Colombier 			f = file;
9459cc4ca5SDavid du Colombier 		s = strrchr(f, '.');
9559cc4ca5SDavid du Colombier 		if(s != nil && s != ofile && strcmp(s, ".tar") == 0){
9659cc4ca5SDavid du Colombier 			*s = '\0';
9759cc4ca5SDavid du Colombier 			snprint(ofile, sizeof(ofile), "%s.tbz", f);
9859cc4ca5SDavid du Colombier 		}else
9959cc4ca5SDavid du Colombier 			snprint(ofile, sizeof(ofile), "%s.bz2", f);
10059cc4ca5SDavid du Colombier 		ofd = create(ofile, OWRITE, 0666);
10159cc4ca5SDavid du Colombier 		if(ofd < 0){
10259cc4ca5SDavid du Colombier 			fprint(2, "bzip2: can't open %s: %r\n", ofile);
103*9a747e4fSDavid du Colombier 			free(dir);
10459cc4ca5SDavid du Colombier 			close(ifd);
10559cc4ca5SDavid du Colombier 			return 0;
10659cc4ca5SDavid du Colombier 		}
10759cc4ca5SDavid du Colombier 	}
10859cc4ca5SDavid du Colombier 
10959cc4ca5SDavid du Colombier 	if(verbose)
11059cc4ca5SDavid du Colombier 		fprint(2, "compressing %s to %s\n", file, ofile);
11159cc4ca5SDavid du Colombier 
11259cc4ca5SDavid du Colombier 	Binit(&bout, ofd, OWRITE);
113*9a747e4fSDavid du Colombier 	ok = bzip(file, dir->mtime, ifd, &bout);
11459cc4ca5SDavid du Colombier 	if(!ok || Bflush(&bout) < 0){
11559cc4ca5SDavid du Colombier 		fprint(2, "bzip2: error writing %s: %r\n", ofile);
11659cc4ca5SDavid du Colombier 		if(!stdout)
11759cc4ca5SDavid du Colombier 			remove(ofile);
11859cc4ca5SDavid du Colombier 	}
11959cc4ca5SDavid du Colombier 	Bterm(&bout);
120*9a747e4fSDavid du Colombier 	free(dir);
12159cc4ca5SDavid du Colombier 	close(ifd);
12259cc4ca5SDavid du Colombier 	close(ofd);
12359cc4ca5SDavid du Colombier 	return ok;
12459cc4ca5SDavid du Colombier }
12559cc4ca5SDavid du Colombier 
12659cc4ca5SDavid du Colombier static int
bzip(char * file,long mtime,int ifd,Biobuf * bout)12759cc4ca5SDavid du Colombier bzip(char *file, long mtime, int ifd, Biobuf *bout)
12859cc4ca5SDavid du Colombier {
12959cc4ca5SDavid du Colombier 	int e, n, done, onemore;
13059cc4ca5SDavid du Colombier 	char buf[8192];
13159cc4ca5SDavid du Colombier 	char obuf[8192];
13259cc4ca5SDavid du Colombier 	Biobuf bin;
13359cc4ca5SDavid du Colombier 	bz_stream strm;
13459cc4ca5SDavid du Colombier 
13559cc4ca5SDavid du Colombier 	USED(file);
13659cc4ca5SDavid du Colombier 	USED(mtime);
13759cc4ca5SDavid du Colombier 
13859cc4ca5SDavid du Colombier 	memset(&strm, 0, sizeof strm);
13959cc4ca5SDavid du Colombier 	BZ2_bzCompressInit(&strm, level, verbose, 0);
14059cc4ca5SDavid du Colombier 
14159cc4ca5SDavid du Colombier 	strm.next_in = buf;
14259cc4ca5SDavid du Colombier 	strm.avail_in = 0;
14359cc4ca5SDavid du Colombier 	strm.next_out = obuf;
14459cc4ca5SDavid du Colombier 	strm.avail_out = sizeof obuf;
14559cc4ca5SDavid du Colombier 
14659cc4ca5SDavid du Colombier 	done = 0;
14759cc4ca5SDavid du Colombier 	Binit(&bin, ifd, OREAD);
14859cc4ca5SDavid du Colombier 
14959cc4ca5SDavid du Colombier 	/*
15059cc4ca5SDavid du Colombier 	 * onemore is a crummy hack to go 'round the loop
15159cc4ca5SDavid du Colombier 	 * once after we finish, to flush the output buffer.
15259cc4ca5SDavid du Colombier 	 */
15359cc4ca5SDavid du Colombier 	onemore = 1;
15459cc4ca5SDavid du Colombier 	SET(e);
15559cc4ca5SDavid du Colombier 	do {
15659cc4ca5SDavid du Colombier 		if(!done && strm.avail_in < sizeof buf) {
15759cc4ca5SDavid du Colombier 			if(strm.avail_in)
15859cc4ca5SDavid du Colombier 				memmove(buf, strm.next_in, strm.avail_in);
15959cc4ca5SDavid du Colombier 
16059cc4ca5SDavid du Colombier 			n = Bread(&bin, buf+strm.avail_in, sizeof(buf)-strm.avail_in);
16159cc4ca5SDavid du Colombier 			if(n <= 0)
16259cc4ca5SDavid du Colombier 				done = 1;
16359cc4ca5SDavid du Colombier 			else
16459cc4ca5SDavid du Colombier 				strm.avail_in += n;
16559cc4ca5SDavid du Colombier 			strm.next_in = buf;
16659cc4ca5SDavid du Colombier 		}
16759cc4ca5SDavid du Colombier 		if(strm.avail_out < sizeof obuf) {
16859cc4ca5SDavid du Colombier 			Bwrite(bout, obuf, sizeof(obuf)-strm.avail_out);
16959cc4ca5SDavid du Colombier 			strm.next_out = obuf;
17059cc4ca5SDavid du Colombier 			strm.avail_out = sizeof obuf;
17159cc4ca5SDavid du Colombier 		}
17259cc4ca5SDavid du Colombier 
17359cc4ca5SDavid du Colombier 		if(onemore == 0)
17459cc4ca5SDavid du Colombier 			break;
17559cc4ca5SDavid du Colombier 	} while((e=BZ2_bzCompress(&strm, done ? BZ_FINISH : BZ_RUN)) == BZ_RUN_OK || e == BZ_FINISH_OK || onemore--);
17659cc4ca5SDavid du Colombier 
17759cc4ca5SDavid du Colombier 	if(e != BZ_STREAM_END) {
17859cc4ca5SDavid du Colombier 		fprint(2, "bzip2: compress failed\n");
17959cc4ca5SDavid du Colombier 		return 0;
18059cc4ca5SDavid du Colombier 	}
18159cc4ca5SDavid du Colombier 
18259cc4ca5SDavid du Colombier 	if(BZ2_bzCompressEnd(&strm) != BZ_OK) {
18359cc4ca5SDavid du Colombier 		fprint(2, "bzip2: compress end failed (can't happen)\n");
18459cc4ca5SDavid du Colombier 		return 0;
18559cc4ca5SDavid du Colombier 	}
18659cc4ca5SDavid du Colombier 
187*9a747e4fSDavid du Colombier 	Bterm(&bin);
188*9a747e4fSDavid du Colombier 
18959cc4ca5SDavid du Colombier 	return 1;
19059cc4ca5SDavid du Colombier }
191