Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_posix/sys/src/cmd/gzip/gunzip.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | 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 <flate.h>
5
#include "gzip.h"
6
 
7
typedef struct	GZHead	GZHead;
8
 
9
struct GZHead
10
{
11
	ulong	mtime;
12
	char	*file;
13
};
14
 
15
static	int	crcwrite(void *bout, void *buf, int n);
16
static	int	get1(Biobuf *b);
17
static	ulong	get4(Biobuf *b);
18
static	int	gunzipf(char *file, int stdout);
19
static	int	gunzip(int ofd, char *ofile, Biobuf *bin);
20
static	void	header(Biobuf *bin, GZHead *h);
21
static	void	trailer(Biobuf *bin, long wlen);
22
static	void	error(char*, ...);
23
#pragma	varargck	argpos	error	1
24
 
25
static	Biobuf	bin;
26
static	ulong	crc;
27
static	ulong	*crctab;
28
static	int	debug;
29
static	char	*delfile;
30
static	vlong	gzok;
31
static	char	*infile;
32
static	int	settimes;
33
static	int	table;
34
static	int	verbose;
35
static	int	wbad;
36
static	ulong	wlen;
37
static	jmp_buf	zjmp;
38
 
39
void
40
usage(void)
41
{
42
	fprint(2, "usage: gunzip [-ctvTD] [file ....]\n");
43
	exits("usage");
44
}
45
 
46
void
47
main(int argc, char *argv[])
48
{
49
	int i, ok, stdout;
50
 
51
	stdout = 0;
52
	ARGBEGIN{
53
	case 'D':
54
		debug++;
55
		break;
56
	case 'c':
57
		stdout++;
58
		break;
59
	case 't':
60
		table++;
61
		break;
62
	case 'T':
63
		settimes++;
64
		break;
65
	case 'v':
66
		verbose++;
67
		break;
68
	default:
69
		usage();
70
		break;
71
	}ARGEND
72
 
73
	crctab = mkcrctab(GZCRCPOLY);
74
	ok = inflateinit();
75
	if(ok != FlateOk)
76
		sysfatal("inflateinit failed: %s", flateerr(ok));
77
 
78
	if(argc == 0){
79
		Binit(&bin, 0, OREAD);
80
		settimes = 0;
81
		infile = "<stdin>";
82
		ok = gunzip(1, "<stdout>", &bin);
83
	}else{
84
		ok = 1;
85
		if(stdout)
86
			settimes = 0;
87
		for(i = 0; i < argc; i++)
88
			ok &= gunzipf(argv[i], stdout);
89
	}
90
 
91
	exits(ok ? nil: "errors");
92
}
93
 
94
static int
95
gunzipf(char *file, int stdout)
96
{
97
	char ofile[256], *s;
98
	int ofd, ifd, ok;
99
 
100
	infile = file;
101
	ifd = open(file, OREAD);
102
	if(ifd < 0){
103
		fprint(2, "gunzip: can't open %s: %r\n", file);
104
		return 0;
105
	}
106
 
107
	Binit(&bin, ifd, OREAD);
108
	if(Bgetc(&bin) != GZMAGIC1 || Bgetc(&bin) != GZMAGIC2 || Bgetc(&bin) != GZDEFLATE){
109
		fprint(2, "gunzip: %s is not a gzip deflate file\n", file);
110
		Bterm(&bin);
111
		close(ifd);
112
		return 0;
113
	}
114
	Bungetc(&bin);
115
	Bungetc(&bin);
116
	Bungetc(&bin);
117
 
118
	if(table)
119
		ofd = -1;
120
	else if(stdout){
121
		ofd = 1;
122
		strcpy(ofile, "<stdout>");
123
	}else{
124
		s = strrchr(file, '/');
125
		if(s != nil)
126
			s++;
127
		else
128
			s = file;
129
		strecpy(ofile, ofile+sizeof ofile, s);
130
		s = strrchr(ofile, '.');
131
		if(s != nil && s != ofile && strcmp(s, ".gz") == 0)
132
			*s = '\0';
133
		else if(s != nil && strcmp(s, ".tgz") == 0)
134
			strcpy(s, ".tar");
135
		else if(strcmp(file, ofile) == 0){
136
			fprint(2, "gunzip: can't overwrite %s\n", file);
137
			Bterm(&bin);
138
			close(ifd);
139
			return 0;
140
		}
141
 
142
		ofd = create(ofile, OWRITE, 0666);
143
		if(ofd < 0){
144
			fprint(2, "gunzip: can't create %s: %r\n", ofile);
145
			Bterm(&bin);
146
			close(ifd);
147
			return 0;
148
		}
149
		delfile = ofile;
150
	}
151
 
152
	wbad = 0;
153
	ok = gunzip(ofd, ofile, &bin);
154
	Bterm(&bin);
155
	close(ifd);
156
	if(wbad){
157
		fprint(2, "gunzip: can't write %s: %r\n", ofile);
158
		if(delfile)
159
			remove(delfile);
160
	}
161
	delfile = nil;
162
	if(!stdout && ofd >= 0)
163
		close(ofd);
164
	return ok;
165
}
166
 
167
static int
168
gunzip(int ofd, char *ofile, Biobuf *bin)
169
{
170
	Dir *d;
171
	GZHead h;
172
	int err;
173
 
174
	h.file = nil;
175
	gzok = 0;
176
	for(;;){
177
		if(Bgetc(bin) < 0)
178
			return 1;
179
		Bungetc(bin);
180
 
181
		if(setjmp(zjmp))
182
			return 0;
183
		header(bin, &h);
184
		gzok = 0;
185
 
186
		wlen = 0;
187
		crc = 0;
188
 
189
		if(!table && verbose)
190
			fprint(2, "extracting %s to %s\n", h.file, ofile);
191
 
192
		err = inflate((void*)ofd, crcwrite, bin, (int(*)(void*))Bgetc);
193
		if(err != FlateOk)
194
			error("inflate failed: %s", flateerr(err));
195
 
196
		trailer(bin, wlen);
197
 
198
		if(table){
199
			if(verbose)
200
				print("%-32s %10ld %s", h.file, wlen, ctime(h.mtime));
201
			else
202
				print("%s\n", h.file);
203
		}else if(settimes && h.mtime && (d=dirfstat(ofd)) != nil){
204
			d->mtime = h.mtime;
205
			dirfwstat(ofd, d);
206
			free(d);
207
		}
208
 
209
		free(h.file);
210
		h.file = nil;
211
		gzok = Boffset(bin);
212
	}
213
}
214
 
215
static void
216
header(Biobuf *bin, GZHead *h)
217
{
218
	char *s;
219
	int i, c, flag, ns, nsa;
220
 
221
	if(get1(bin) != GZMAGIC1 || get1(bin) != GZMAGIC2)
222
		error("bad gzip file magic");
223
	if(get1(bin) != GZDEFLATE)
224
		error("unknown compression type");
225
 
226
	flag = get1(bin);
227
	if(flag & ~(GZFTEXT|GZFEXTRA|GZFNAME|GZFCOMMENT|GZFHCRC))
228
		fprint(2, "gunzip: reserved flags set, data may not be decompressed correctly\n");
229
 
230
	/* mod time */
231
	h->mtime = get4(bin);
232
 
233
	/* extra flags */
234
	get1(bin);
235
 
236
	/* OS type */
237
	get1(bin);
238
 
239
	if(flag & GZFEXTRA)
240
		for(i=get1(bin); i>0; i--)
241
			get1(bin);
242
 
243
	/* name */
244
	if(flag & GZFNAME){
245
		nsa = 32;
246
		ns = 0;
247
		s = malloc(nsa);
248
		if(s == nil)
249
			error("out of memory");
250
		while((c = get1(bin)) != 0){
251
			s[ns++] = c;
252
			if(ns >= nsa){
253
				nsa += 32;
254
				s = realloc(s, nsa);
255
				if(s == nil)
256
					error("out of memory");
257
			}
258
		}
259
		s[ns] = '\0';
260
		h->file = s;
261
	}else
262
		h->file = strdup("<unnamed file>");
263
 
264
	/* comment */
265
	if(flag & GZFCOMMENT)
266
		while(get1(bin) != 0)
267
			;
268
 
269
	/* crc16 */
270
	if(flag & GZFHCRC){
271
		get1(bin);
272
		get1(bin);
273
	}
274
}
275
 
276
static void
277
trailer(Biobuf *bin, long wlen)
278
{
279
	ulong tcrc;
280
	long len;
281
 
282
	tcrc = get4(bin);
283
	if(tcrc != crc)
284
		error("crc mismatch");
285
 
286
	len = get4(bin);
287
 
288
	if(len != wlen)
289
		error("bad output length: expected %lud got %lud", wlen, len);
290
}
291
 
292
static ulong
293
get4(Biobuf *b)
294
{
295
	ulong v;
296
	int i, c;
297
 
298
	v = 0;
299
	for(i = 0; i < 4; i++){
300
		c = Bgetc(b);
301
		if(c < 0)
302
			error("unexpected eof reading file information");
303
		v |= c << (i * 8);
304
	}
305
	return v;
306
}
307
 
308
static int
309
get1(Biobuf *b)
310
{
311
	int c;
312
 
313
	c = Bgetc(b);
314
	if(c < 0)
315
		error("unexpected eof reading file information");
316
	return c;
317
}
318
 
319
static int
320
crcwrite(void *out, void *buf, int n)
321
{
322
	int fd, nw;
323
 
324
	wlen += n;
325
	crc = blockcrc(crctab, crc, buf, n);
326
	fd = (int)(uintptr)out;
327
	if(fd < 0)
328
		return n;
329
	nw = write(fd, buf, n);
330
	if(nw != n)
331
		wbad = 1;
332
	return nw;
333
}
334
 
335
static void
336
error(char *fmt, ...)
337
{
338
	va_list arg;
339
 
340
	if(gzok)
341
		fprint(2, "gunzip: %s: corrupted data after byte %lld ignored\n", infile, gzok);
342
	else{
343
		fprint(2, "gunzip: ");
344
		if(infile)
345
			fprint(2, "%s: ", infile);
346
		va_start(arg, fmt);
347
		vfprint(2, fmt, arg);
348
		va_end(arg);
349
		fprint(2, "\n");
350
 
351
		if(delfile != nil){
352
			fprint(2, "gunzip: removing output file %s\n", delfile);
353
			remove(delfile);
354
			delfile = nil;
355
		}
356
	}
357
 
358
	longjmp(zjmp, 1);
359
}