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 <flate.h>
5
#include <auth.h>
6
#include <fcall.h>
7
#include <ctype.h>
8
#include "tapefs.h"
9
#include "zip.h"
10
 
11
#define FORCE_LOWER	1	/* force filenames to lower case */
12
#define MUNGE_CR	1	/* replace '\r\n' with ' \n' */
13
#define High64 (1LL<<63)
14
 
15
/*
16
 * File system for zip archives (read-only)
17
 */
18
 
19
enum {
20
	IS_MSDOS = 0,	/* creator OS (interpretation of external flags) */
21
	IS_RDONLY = 1,	/* file was readonly (external flags) */
22
	IS_TEXT = 1,	/* file was text  (internal flags) */
23
};
24
 
25
typedef struct Block Block;
26
struct Block{
27
	uchar *pos;
28
	uchar *limit;
29
};
30
 
31
static Biobuf *bin;
32
static ulong *crctab;
33
static ulong crc;
34
 
35
static int findCDir(Biobuf *);
36
static int header(Biobuf *, ZipHead *);
37
static int cheader(Biobuf *, ZipHead *);
38
static void trailer(Biobuf *, ZipHead *);
39
static char *getname(Biobuf *, int);
40
static int blwrite(void *, void *, int);
41
static ulong get4(Biobuf *);
42
static int get2(Biobuf *);
43
static int get1(Biobuf *);
44
static long msdos2time(int, int);
45
 
46
void
47
populate(char *name)
48
{
49
	char *p;
50
	Fileinf f;
51
	ZipHead zh;
52
	int ok, entries;
53
 
54
	crctab = mkcrctab(ZCrcPoly);
55
	ok = inflateinit();
56
	if(ok != FlateOk)
57
		sysfatal("inflateinit failed: %s", flateerr(ok));
58
 
59
	bin = Bopen(name, OREAD);
60
	if (bin == nil)
61
		error("Can't open argument file");
62
 
63
	entries = findCDir(bin);
64
	if(entries < 0)
65
		sysfatal("empty file");
66
 
67
	while(entries-- > 0){
68
		memset(&zh, 0, sizeof(zh));
69
		if(!cheader(bin, &zh))
70
			break;
71
		f.addr = zh.off;
72
		if(zh.iattr & IS_TEXT)
73
			f.addr |= High64;
74
		f.mode = (zh.madevers == IS_MSDOS && zh.eattr & IS_RDONLY)? 0444: 0644;
75
		if (zh.meth == 0 && zh.uncsize == 0){
76
			p = strchr(zh.file, '\0');
77
			if(p > zh.file && p[-1] == '/')
78
				f.mode |= (DMDIR | 0111);
79
		}
80
		f.uid = 0;
81
		f.gid = 0;
82
		f.size = zh.uncsize;
83
		f.mdate = msdos2time(zh.modtime, zh.moddate);
84
		f.name = zh.file + ((zh.file[0] == '/')? 1: 0);
85
		poppath(f, 1);
86
		free(zh.file);
87
	}
88
	return ;
89
}
90
 
91
void
92
dotrunc(Ram *r)
93
{
94
	USED(r);
95
}
96
 
97
void
98
docreate(Ram *r)
99
{
100
	USED(r);
101
}
102
 
103
char *
104
doread(Ram *r, vlong off, long cnt)
105
{
106
	int i, err;
107
	Block bs;
108
	ZipHead zh;
109
	static Qid oqid;
110
	static char buf[Maxbuf];
111
	static uchar *cache = nil;
112
 
113
	if (cnt > Maxbuf)
114
		sysfatal("file too big (>%d)", Maxbuf);
115
 
116
	if (Bseek(bin, r->addr & 0x7FFFFFFFFFFFFFFFLL, 0) < 0)
117
		sysfatal("seek failed");
118
 
119
	memset(&zh, 0, sizeof(zh));
120
	if (!header(bin, &zh))
121
		sysfatal("cannot get local header");
122
 
123
	switch(zh.meth){
124
	case 0:
125
		if (Bseek(bin, off, 1) < 0)
126
			sysfatal("seek failed");
127
		if (Bread(bin, buf, cnt) != cnt)
128
			sysfatal("read failed");
129
		break;
130
	case 8:
131
		if (r->qid.path != oqid.path){
132
			oqid = r->qid;
133
			if (cache)
134
				free(cache);
135
			cache = emalloc(r->ndata);
136
 
137
			bs.pos = cache;
138
			bs.limit = cache+r->ndata;
139
			if ((err = inflate(&bs, blwrite, bin, (int(*)(void*))Bgetc)) != FlateOk)
140
				sysfatal("inflate failed - %s", flateerr(err));
141
 
142
			if (blockcrc(crctab, crc, cache, r->ndata) != zh.crc)
143
				fprint(2, "%s - crc failed", r->name);
144
 
145
			if ((r->addr & High64) && MUNGE_CR){
146
				for (i = 0; i < r->ndata -1; i++)
147
					if (cache[i] == '\r' && cache[i +1] == '\n')
148
						cache[i] = ' ';
149
			}
150
		}
151
		memcpy(buf, cache+off, cnt);
152
		break;
153
	default:
154
		sysfatal("%d - unsupported compression method", zh.meth);
155
		break;
156
	}
157
 
158
	return buf;
159
}
160
 
161
void
162
popdir(Ram *r)
163
{
164
	USED(r);
165
}
166
 
167
void
168
dowrite(Ram *r, char *buf, long off, long cnt)
169
{
170
	USED(r); USED(buf); USED(off); USED(cnt);
171
}
172
 
173
int
174
dopermw(Ram *r)
175
{
176
	USED(r);
177
	return 0;
178
}
179
 
180
/*************************************************/
181
 
182
static int
183
findCDir(Biobuf *bin)
184
{
185
	vlong ecoff;
186
	long off;
187
	int entries, zclen;
188
 
189
	ecoff = Bseek(bin, -ZECHeadSize, 2);
190
	if(ecoff < 0)
191
		sysfatal("can't seek to header");
192
 
193
	if(get4(bin) != ZECHeader)
194
		sysfatal("bad magic number on directory");
195
 
196
	get2(bin);
197
	get2(bin);
198
	get2(bin);
199
	entries = get2(bin);
200
	get4(bin);
201
	off = get4(bin);
202
	zclen = get2(bin);
203
	while(zclen-- > 0)
204
		get1(bin);
205
 
206
	if(Bseek(bin, off, 0) != off)
207
		sysfatal("can't seek to contents");
208
 
209
	return entries;
210
}
211
 
212
 
213
static int
214
header(Biobuf *bin, ZipHead *zh)
215
{
216
	ulong v;
217
	int flen, xlen;
218
 
219
	v = get4(bin);
220
	if(v != ZHeader){
221
		if(v == ZCHeader)
222
			return 0;
223
		sysfatal("bad magic on local header");
224
	}
225
	zh->extvers = get1(bin);
226
	zh->extos = get1(bin);
227
	zh->flags = get2(bin);
228
	zh->meth = get2(bin);
229
	zh->modtime = get2(bin);
230
	zh->moddate = get2(bin);
231
	zh->crc = get4(bin);
232
	zh->csize = get4(bin);
233
	zh->uncsize = get4(bin);
234
	flen = get2(bin);
235
	xlen = get2(bin);
236
 
237
	zh->file = getname(bin, flen);
238
 
239
	while(xlen-- > 0)
240
		get1(bin);
241
	return 1;
242
}
243
 
244
static int
245
cheader(Biobuf *bin, ZipHead *zh)
246
{
247
	ulong v;
248
	int flen, xlen, fclen;
249
 
250
	v = get4(bin);
251
	if(v != ZCHeader){
252
		if(v == ZECHeader)
253
			return 0;
254
		sysfatal("bad magic number in file");
255
	}
256
	zh->madevers = get1(bin);
257
	zh->madeos = get1(bin);
258
	zh->extvers = get1(bin);
259
	zh->extos = get1(bin);
260
	zh->flags = get2(bin);
261
	zh->meth = get2(bin);
262
	zh->modtime = get2(bin);
263
	zh->moddate = get2(bin);
264
	zh->crc = get4(bin);
265
	zh->csize = get4(bin);
266
	zh->uncsize = get4(bin);
267
	flen = get2(bin);
268
	xlen = get2(bin);
269
	fclen = get2(bin);
270
	get2(bin);		/* disk number start */
271
	zh->iattr = get2(bin);	/* 1 == is-text-file */
272
	zh->eattr = get4(bin);	/* 1 == readonly-file */
273
	zh->off = get4(bin);
274
 
275
	zh->file = getname(bin, flen);
276
 
277
	while(xlen-- > 0)
278
		get1(bin);
279
 
280
	while(fclen-- > 0)
281
		get1(bin);
282
 
283
	return 1;
284
}
285
 
286
static int
287
blwrite(void *vb, void *buf, int n)
288
{
289
	Block *b = vb;
290
	if(n > b->limit - b->pos)
291
		n = b->limit - b->pos;
292
	memmove(b->pos, buf, n);
293
	b->pos += n;
294
	return n;
295
}
296
 
297
 
298
static void
299
trailer(Biobuf *bin, ZipHead *zh)
300
{
301
	if(zh->flags & ZTrailInfo){
302
		zh->crc = get4(bin);
303
		zh->csize = get4(bin);
304
		zh->uncsize = get4(bin);
305
	}
306
}
307
 
308
static char*
309
getname(Biobuf *bin, int len)
310
{
311
	char *s;
312
	int i, c;
313
 
314
	s = emalloc(len + 1);
315
	for(i = 0; i < len; i++){
316
		c = get1(bin);
317
		if(FORCE_LOWER)
318
			c = tolower(c);
319
		s[i] = c;
320
	}
321
	s[i] = '\0';
322
	return s;
323
}
324
 
325
 
326
static ulong
327
get4(Biobuf *b)
328
{
329
	ulong v;
330
	int i, c;
331
 
332
	v = 0;
333
	for(i = 0; i < 4; i++){
334
		c = Bgetc(b);
335
		if(c < 0)
336
			sysfatal("unexpected eof");
337
		v |= c << (i * 8);
338
	}
339
	return v;
340
}
341
 
342
static int
343
get2(Biobuf *b)
344
{
345
	int i, c, v;
346
 
347
	v = 0;
348
	for(i = 0; i < 2; i++){
349
		c = Bgetc(b);
350
		if(c < 0)
351
			sysfatal("unexpected eof");
352
		v |= c << (i * 8);
353
	}
354
	return v;
355
}
356
 
357
static int
358
get1(Biobuf *b)
359
{
360
	int c;
361
 
362
	c = Bgetc(b);
363
	if(c < 0)
364
		sysfatal("unexpected eof");
365
	return c;
366
}
367
 
368
static long
369
msdos2time(int time, int date)
370
{
371
	Tm tm;
372
 
373
	tm.hour = time >> 11;
374
	tm.min = (time >> 5) & 63;
375
	tm.sec = (time & 31) << 1;
376
	tm.year = 80 + (date >> 9);
377
	tm.mon = ((date >> 5) & 15) - 1;
378
	tm.mday = date & 31;
379
	tm.zone[0] = '\0';
380
	tm.yday = 0;
381
 
382
	return tm2sec(&tm);
383
}
384