ref: 4dbb99f478d68eaeea4c043a839454cb807c2c7d
dir: /sys/src/cmd/bzip2/bunzip2.c/
#include <u.h> #include <libc.h> #include <bio.h> #include "bzlib.h" static Biobuf bin; static int debug; static int verbose; static char *delfile; static char *infile; static int bunzipf(char *file, int stdout); static int bunzip(int ofd, char *ofile, Biobuf *bin); void usage(void) { fprint(2, "usage: bunzip2 [-cvD] [file ...]\n"); exits("usage"); } void main(int argc, char **argv) { int i, ok, stdout; stdout = 0; ARGBEGIN{ case 'D': debug++; break; case 'c': stdout++; break; case 'v': verbose++; break; default: usage(); }ARGEND if(argc == 0){ Binit(&bin, 0, OREAD); infile = "<stdin>"; ok = bunzip(1, "<stdout>", &bin); }else{ ok = 1; for(i = 0; i < argc; i++) ok &= bunzipf(argv[i], stdout); } exits(ok ? nil: "errors"); } static int bunzipf(char *file, int stdout) { char ofile[64], *s; int ofd, ifd, ok; infile = file; ifd = open(file, OREAD); if(ifd < 0){ fprint(2, "bunzip2: can't open %s: %r\n", file); return 0; } Binit(&bin, ifd, OREAD); if(Bgetc(&bin) != 'B' || Bgetc(&bin) != 'Z' || Bgetc(&bin) != 'h'){ fprint(2, "bunzip2: %s is not a bzip2 file\n", file); Bterm(&bin); close(ifd); return 0; } Bungetc(&bin); Bungetc(&bin); Bungetc(&bin); if(stdout){ ofd = 1; strcpy(ofile, "<stdout>"); }else{ s = strrchr(file, '/'); if(s != nil) s++; else s = file; strecpy(ofile, ofile+sizeof ofile, s); s = strrchr(ofile, '.'); if(s != nil && s != ofile && strcmp(s, ".bz2") == 0) *s = '\0'; else if(s != nil && (strcmp(s, ".tbz") == 0 || strcmp(s, ".tbz2") == 0)) strcpy(s, ".tar"); else if(strcmp(file, ofile) == 0){ fprint(2, "bunzip2: can't overwrite %s\n", file); Bterm(&bin); close(ifd); return 0; } ofd = create(ofile, OWRITE, 0666); if(ofd < 0){ fprint(2, "bunzip2: can't create %s: %r\n", ofile); Bterm(&bin); close(ifd); return 0; } delfile = ofile; } ok = bunzip(ofd, ofile, &bin); Bterm(&bin); close(ifd); if(!ok){ fprint(2, "bunzip2: can't write %s: %r\n", ofile); if(delfile) remove(delfile); } delfile = nil; if(!stdout && ofd >= 0) close(ofd); return ok; } static int bunzip(int ofd, char *ofile, Biobuf *bin) { int e, n, done, onemore; char buf[IOUNIT]; char obuf[IOUNIT]; Biobuf bout; bz_stream strm; USED(ofile); memset(&strm, 0, sizeof strm); BZ2_bzDecompressInit(&strm, verbose, 0); strm.next_in = buf; strm.avail_in = 0; strm.next_out = obuf; strm.avail_out = sizeof obuf; done = 0; Binit(&bout, ofd, OWRITE); /* * onemore is a crummy hack to go 'round the loop * once after we finish, to flush the output buffer. */ onemore = 1; SET(e); do { if(!done && strm.avail_in < sizeof buf) { if(strm.avail_in) memmove(buf, strm.next_in, strm.avail_in); n = Bread(bin, buf+strm.avail_in, sizeof(buf)-strm.avail_in); if(n <= 0) done = 1; else strm.avail_in += n; strm.next_in = buf; } if(strm.avail_out < sizeof obuf) { Bwrite(&bout, obuf, sizeof(obuf)-strm.avail_out); strm.next_out = obuf; strm.avail_out = sizeof obuf; } if(onemore == 0) break; if(strm.avail_in == 0 && strm.avail_out == sizeof obuf) break; } while((e=BZ2_bzDecompress(&strm)) == BZ_OK || onemore--); if(e != BZ_STREAM_END) { fprint(2, "bunzip2: decompress failed\n"); return 0; } if(BZ2_bzDecompressEnd(&strm) != BZ_OK) { fprint(2, "bunzip2: decompress end failed (can't happen)\n"); return 0; } Bterm(&bout); return 1; }