bunzip2.c (3453B)
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 }ARGEND 38 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 } 48 49 exits(ok ? nil: "errors"); 50 } 51 52 static int 53 bunzipf(char *file, int stdout) 54 { 55 char ofile[64], *s; 56 int ofd, ifd, ok; 57 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 } 64 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); 75 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 } 97 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; 104 } 105 delfile = ofile; 106 } 107 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); 115 } 116 delfile = nil; 117 if(!stdout && ofd >= 0) 118 close(ofd); 119 return ok; 120 } 121 122 static int 123 bunzip(int ofd, char *ofile, Biobuf *bin) 124 { 125 int e, n, done, onemore; 126 char buf[8192]; 127 char obuf[8192]; 128 Biobuf bout; 129 bz_stream strm; 130 131 USED(ofile); 132 133 memset(&strm, 0, sizeof strm); 134 BZ2_bzDecompressInit(&strm, verbose, 0); 135 136 strm.next_in = buf; 137 strm.avail_in = 0; 138 strm.next_out = obuf; 139 strm.avail_out = sizeof obuf; 140 141 done = 0; 142 Binit(&bout, ofd, OWRITE); 143 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); 154 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; 161 } 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; 166 } 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--); 172 173 if(e != BZ_STREAM_END) { 174 fprint(2, "bunzip2: decompress failed\n"); 175 return 0; 176 } 177 178 if(BZ2_bzDecompressEnd(&strm) != BZ_OK) { 179 fprint(2, "bunzip2: decompress end failed (can't happen)\n"); 180 return 0; 181 } 182 183 Bterm(&bout); 184 185 return 1; 186 }