]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/bzip2/bunzip2.c
etheriwl: don't break controller on command flush timeout
[plan9front.git] / sys / src / cmd / bzip2 / bunzip2.c
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
15 usage(void)
16 {
17         fprint(2, "usage: bunzip2 [-cvD] [file ...]\n");
18         exits("usage");
19 }
20
21 void
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
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
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 }