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