plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

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 }