blob: 653ebc33e820ff9dcbce4ddb5d70e6cbe5f1f04c [file] [log] [blame]
#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;
}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, "gunzip: 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[8192];
char obuf[8192];
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;
}