Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
}