xref: /plan9/sys/src/cmd/bzip2/bunzip2.c (revision 4e47a2bae186af79a55734a785d2843fa45765ae)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include "bzlib.h"
5 
6 static	Biobuf	bin;
7 static	int	debug;
8 static	int	verbose;
9 static	char	*delfile;
10 static	char	*infile;
11 static	int	bunzipf(char *file, int stdout);
12 static	int	bunzip(int ofd, char *ofile, Biobuf *bin);
13 
14 void
usage(void)15 usage(void)
16 {
17 	fprint(2, "usage: bunzip2 [-cvD] [file ...]\n");
18 	exits("usage");
19 }
20 
21 void
main(int argc,char ** argv)22 main(int argc, char **argv)
23 {
24 	int i, ok, stdout;
25 
26 	stdout = 0;
27 	ARGBEGIN{
28 	case 'D':
29 		debug++;
30 		break;
31 	case 'c':
32 		stdout++;
33 		break;
34 	case 'v':
35 		verbose++;
36 		break;
37 	default:
38 		usage();
39 	}ARGEND
40 
41 	if(argc == 0){
42 		Binit(&bin, 0, OREAD);
43 		infile = "<stdin>";
44 		ok = bunzip(1, "<stdout>", &bin);
45 	}else{
46 		ok = 1;
47 		for(i = 0; i < argc; i++)
48 			ok &= bunzipf(argv[i], stdout);
49 	}
50 
51 	exits(ok ? nil: "errors");
52 }
53 
54 static int
bunzipf(char * file,int stdout)55 bunzipf(char *file, int stdout)
56 {
57 	char ofile[64], *s;
58 	int ofd, ifd, ok;
59 
60 	infile = file;
61 	ifd = open(file, OREAD);
62 	if(ifd < 0){
63 		fprint(2, "bunzip2: can't open %s: %r\n", file);
64 		return 0;
65 	}
66 
67 	Binit(&bin, ifd, OREAD);
68 	if(Bgetc(&bin) != 'B' || Bgetc(&bin) != 'Z' || Bgetc(&bin) != 'h'){
69 		fprint(2, "bunzip2: %s is not a bzip2 file\n", file);
70 		Bterm(&bin);
71 		close(ifd);
72 		return 0;
73 	}
74 	Bungetc(&bin);
75 	Bungetc(&bin);
76 	Bungetc(&bin);
77 
78 	if(stdout){
79 		ofd = 1;
80 		strcpy(ofile, "<stdout>");
81 	}else{
82 		s = strrchr(file, '/');
83 		if(s != nil)
84 			s++;
85 		else
86 			s = file;
87 		strecpy(ofile, ofile+sizeof ofile, s);
88 		s = strrchr(ofile, '.');
89 		if(s != nil && s != ofile && strcmp(s, ".bz2") == 0)
90 			*s = '\0';
91 		else if(s != nil && (strcmp(s, ".tbz") == 0 || strcmp(s, ".tbz2") == 0))
92 			strcpy(s, ".tar");
93 		else if(strcmp(file, ofile) == 0){
94 			fprint(2, "bunzip2: can't overwrite %s\n", file);
95 			Bterm(&bin);
96 			close(ifd);
97 			return 0;
98 		}
99 
100 		ofd = create(ofile, OWRITE, 0666);
101 		if(ofd < 0){
102 			fprint(2, "bunzip2: can't create %s: %r\n", ofile);
103 			Bterm(&bin);
104 			close(ifd);
105 			return 0;
106 		}
107 		delfile = ofile;
108 	}
109 
110 	ok = bunzip(ofd, ofile, &bin);
111 	Bterm(&bin);
112 	close(ifd);
113 	if(!ok){
114 		fprint(2, "bunzip2: can't write %s: %r\n", ofile);
115 		if(delfile)
116 			remove(delfile);
117 	}
118 	delfile = nil;
119 	if(!stdout && ofd >= 0)
120 		close(ofd);
121 	return ok;
122 }
123 
124 static int
bunzip(int ofd,char * ofile,Biobuf * bin)125 bunzip(int ofd, char *ofile, Biobuf *bin)
126 {
127 	int e, n, done, onemore;
128 	char buf[8192];
129 	char obuf[8192];
130 	Biobuf bout;
131 	bz_stream strm;
132 
133 	USED(ofile);
134 
135 	memset(&strm, 0, sizeof strm);
136 	BZ2_bzDecompressInit(&strm, verbose, 0);
137 
138 	strm.next_in = buf;
139 	strm.avail_in = 0;
140 	strm.next_out = obuf;
141 	strm.avail_out = sizeof obuf;
142 
143 	done = 0;
144 	Binit(&bout, ofd, OWRITE);
145 
146 	/*
147 	 * onemore is a crummy hack to go 'round the loop
148 	 * once after we finish, to flush the output buffer.
149 	 */
150 	onemore = 1;
151 	SET(e);
152 	do {
153 		if(!done && strm.avail_in < sizeof buf) {
154 			if(strm.avail_in)
155 				memmove(buf, strm.next_in, strm.avail_in);
156 
157 			n = Bread(bin, buf+strm.avail_in, sizeof(buf)-strm.avail_in);
158 			if(n <= 0)
159 				done = 1;
160 			else
161 				strm.avail_in += n;
162 			strm.next_in = buf;
163 		}
164 		if(strm.avail_out < sizeof obuf) {
165 			Bwrite(&bout, obuf, sizeof(obuf)-strm.avail_out);
166 			strm.next_out = obuf;
167 			strm.avail_out = sizeof obuf;
168 		}
169 		if(onemore == 0)
170 			break;
171 		if(strm.avail_in == 0 && strm.avail_out == sizeof obuf)
172 			break;
173 	} while((e=BZ2_bzDecompress(&strm)) == BZ_OK || onemore--);
174 
175 	if(e != BZ_STREAM_END) {
176 		fprint(2, "bunzip2: decompress failed\n");
177 		return 0;
178 	}
179 
180 	if(BZ2_bzDecompressEnd(&strm) != BZ_OK) {
181 		fprint(2, "bunzip2: decompress end failed (can't happen)\n");
182 		return 0;
183 	}
184 
185 	Bterm(&bout);
186 
187 	return 1;
188 }
189