Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include "bzlib.h"
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);
14 void
15 usage(void)
16 {
17 fprint(2, "usage: bunzip2 [-cvD] [file ...]\n");
18 exits("usage");
19 }
21 void
22 main(int argc, char **argv)
23 {
24 int i, ok, stdout;
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 }ARGEND
39 if(argc == 0){
40 Binit(&bin, 0, OREAD);
41 infile = "<stdin>";
42 ok = bunzip(1, "<stdout>", &bin);
43 }else{
44 ok = 1;
45 for(i = 0; i < argc; i++)
46 ok &= bunzipf(argv[i], stdout);
47 }
49 exits(ok ? nil: "errors");
50 }
52 static int
53 bunzipf(char *file, int stdout)
54 {
55 char ofile[64], *s;
56 int ofd, ifd, ok;
58 infile = file;
59 ifd = open(file, OREAD);
60 if(ifd < 0){
61 fprint(2, "gunzip: can't open %s: %r\n", file);
62 return 0;
63 }
65 Binit(&bin, ifd, OREAD);
66 if(Bgetc(&bin) != 'B' || Bgetc(&bin) != 'Z' || Bgetc(&bin) != 'h'){
67 fprint(2, "bunzip2: %s is not a bzip2 file\n", file);
68 Bterm(&bin);
69 close(ifd);
70 return 0;
71 }
72 Bungetc(&bin);
73 Bungetc(&bin);
74 Bungetc(&bin);
76 if(stdout){
77 ofd = 1;
78 strcpy(ofile, "<stdout>");
79 }else{
80 s = strrchr(file, '/');
81 if(s != nil)
82 s++;
83 else
84 s = file;
85 strecpy(ofile, ofile+sizeof ofile, s);
86 s = strrchr(ofile, '.');
87 if(s != nil && s != ofile && strcmp(s, ".bz2") == 0)
88 *s = '\0';
89 else if(s != nil && (strcmp(s, ".tbz") == 0 || strcmp(s, ".tbz2") == 0))
90 strcpy(s, ".tar");
91 else if(strcmp(file, ofile) == 0){
92 fprint(2, "bunzip2: can't overwrite %s\n", file);
93 Bterm(&bin);
94 close(ifd);
95 return 0;
96 }
98 ofd = create(ofile, OWRITE, 0666);
99 if(ofd < 0){
100 fprint(2, "bunzip2: can't create %s: %r\n", ofile);
101 Bterm(&bin);
102 close(ifd);
103 return 0;
105 delfile = ofile;
108 ok = bunzip(ofd, ofile, &bin);
109 Bterm(&bin);
110 close(ifd);
111 if(!ok){
112 fprint(2, "bunzip2: can't write %s: %r\n", ofile);
113 if(delfile)
114 remove(delfile);
116 delfile = nil;
117 if(!stdout && ofd >= 0)
118 close(ofd);
119 return ok;
122 static int
123 bunzip(int ofd, char *ofile, Biobuf *bin)
125 int e, n, done, onemore;
126 char buf[8192];
127 char obuf[8192];
128 Biobuf bout;
129 bz_stream strm;
131 USED(ofile);
133 memset(&strm, 0, sizeof strm);
134 BZ2_bzDecompressInit(&strm, verbose, 0);
136 strm.next_in = buf;
137 strm.avail_in = 0;
138 strm.next_out = obuf;
139 strm.avail_out = sizeof obuf;
141 done = 0;
142 Binit(&bout, ofd, OWRITE);
144 /*
145 * onemore is a crummy hack to go 'round the loop
146 * once after we finish, to flush the output buffer.
147 */
148 onemore = 1;
149 SET(e);
150 do {
151 if(!done && strm.avail_in < sizeof buf) {
152 if(strm.avail_in)
153 memmove(buf, strm.next_in, strm.avail_in);
155 n = Bread(bin, buf+strm.avail_in, sizeof(buf)-strm.avail_in);
156 if(n <= 0)
157 done = 1;
158 else
159 strm.avail_in += n;
160 strm.next_in = buf;
162 if(strm.avail_out < sizeof obuf) {
163 Bwrite(&bout, obuf, sizeof(obuf)-strm.avail_out);
164 strm.next_out = obuf;
165 strm.avail_out = sizeof obuf;
167 if(onemore == 0)
168 break;
169 if(strm.avail_in == 0 && strm.avail_out == sizeof obuf)
170 break;
171 } while((e=BZ2_bzDecompress(&strm)) == BZ_OK || onemore--);
173 if(e != BZ_STREAM_END) {
174 fprint(2, "bunzip2: decompress failed\n");
175 return 0;
178 if(BZ2_bzDecompressEnd(&strm) != BZ_OK) {
179 fprint(2, "bunzip2: decompress end failed (can't happen)\n");
180 return 0;
183 Bterm(&bout);
185 return 1;