1 64f7506b 2006-02-24 devnull #include <u.h>
2 64f7506b 2006-02-24 devnull #include <libc.h>
3 64f7506b 2006-02-24 devnull #include <bio.h>
4 64f7506b 2006-02-24 devnull #include <flate.h>
5 64f7506b 2006-02-24 devnull #include <auth.h>
6 64f7506b 2006-02-24 devnull #include <fcall.h>
7 64f7506b 2006-02-24 devnull #include <ctype.h>
8 64f7506b 2006-02-24 devnull #include "tapefs.h"
9 64f7506b 2006-02-24 devnull #include "zip.h"
11 64f7506b 2006-02-24 devnull #define FORCE_LOWER 1 /* force filenames to lower case */
12 64f7506b 2006-02-24 devnull #define MUNGE_CR 1 /* replace '\r\n' with ' \n' */
13 64f7506b 2006-02-24 devnull #define High64 (1LL<<63)
16 64f7506b 2006-02-24 devnull * File system for zip archives (read-only)
20 64f7506b 2006-02-24 devnull IS_MSDOS = 0, /* creator OS (interpretation of external flags) */
21 64f7506b 2006-02-24 devnull IS_RDONLY = 1, /* file was readonly (external flags) */
22 cbeb0b26 2006-04-01 devnull IS_TEXT = 1 /* file was text (internal flags) */
25 64f7506b 2006-02-24 devnull typedef struct Block Block;
26 64f7506b 2006-02-24 devnull struct Block{
27 64f7506b 2006-02-24 devnull uchar *pos;
28 64f7506b 2006-02-24 devnull uchar *limit;
31 64f7506b 2006-02-24 devnull static Biobuf *bin;
32 64f7506b 2006-02-24 devnull static ulong *crctab;
33 64f7506b 2006-02-24 devnull static ulong crc;
35 64f7506b 2006-02-24 devnull static int findCDir(Biobuf *);
36 64f7506b 2006-02-24 devnull static int header(Biobuf *, ZipHead *);
37 64f7506b 2006-02-24 devnull static int cheader(Biobuf *, ZipHead *);
38 64f7506b 2006-02-24 devnull /* static void trailer(Biobuf *, ZipHead *); */
39 64f7506b 2006-02-24 devnull static char *getname(Biobuf *, int);
40 64f7506b 2006-02-24 devnull static int blwrite(void *, void *, int);
41 64f7506b 2006-02-24 devnull static ulong get4(Biobuf *);
42 64f7506b 2006-02-24 devnull static int get2(Biobuf *);
43 64f7506b 2006-02-24 devnull static int get1(Biobuf *);
44 64f7506b 2006-02-24 devnull static long msdos2time(int, int);
47 64f7506b 2006-02-24 devnull populate(char *name)
50 64f7506b 2006-02-24 devnull Fileinf f;
51 64f7506b 2006-02-24 devnull ZipHead zh;
52 64f7506b 2006-02-24 devnull int ok, entries;
54 64f7506b 2006-02-24 devnull crctab = mkcrctab(ZCrcPoly);
55 64f7506b 2006-02-24 devnull ok = inflateinit();
56 64f7506b 2006-02-24 devnull if(ok != FlateOk)
57 64f7506b 2006-02-24 devnull sysfatal("inflateinit failed: %s", flateerr(ok));
59 64f7506b 2006-02-24 devnull bin = Bopen(name, OREAD);
60 64f7506b 2006-02-24 devnull if (bin == nil)
61 64f7506b 2006-02-24 devnull error("Can't open argument file");
63 64f7506b 2006-02-24 devnull entries = findCDir(bin);
64 64f7506b 2006-02-24 devnull if(entries < 0)
65 64f7506b 2006-02-24 devnull sysfatal("empty file");
67 64f7506b 2006-02-24 devnull while(entries-- > 0){
68 64f7506b 2006-02-24 devnull memset(&zh, 0, sizeof(zh));
69 64f7506b 2006-02-24 devnull if(!cheader(bin, &zh))
71 64f7506b 2006-02-24 devnull f.addr = zh.off;
72 64f7506b 2006-02-24 devnull if(zh.iattr & IS_TEXT)
73 64f7506b 2006-02-24 devnull f.addr |= High64;
74 64f7506b 2006-02-24 devnull f.mode = (zh.madevers == IS_MSDOS && zh.eattr & IS_RDONLY)? 0444: 0644;
75 64f7506b 2006-02-24 devnull if (zh.meth == 0 && zh.uncsize == 0){
76 64f7506b 2006-02-24 devnull p = strchr(zh.file, '\0');
77 64f7506b 2006-02-24 devnull if(p > zh.file && p[-1] == '/')
78 64f7506b 2006-02-24 devnull f.mode |= (DMDIR | 0111);
80 64f7506b 2006-02-24 devnull f.uid = 0;
81 64f7506b 2006-02-24 devnull f.gid = 0;
82 64f7506b 2006-02-24 devnull f.size = zh.uncsize;
83 64f7506b 2006-02-24 devnull f.mdate = msdos2time(zh.modtime, zh.moddate);
84 64f7506b 2006-02-24 devnull f.name = zh.file + ((zh.file[0] == '/')? 1: 0);
85 64f7506b 2006-02-24 devnull poppath(f, 1);
86 64f7506b 2006-02-24 devnull free(zh.file);
92 64f7506b 2006-02-24 devnull dotrunc(Ram *r)
98 64f7506b 2006-02-24 devnull docreate(Ram *r)
100 64f7506b 2006-02-24 devnull USED(r);
104 64f7506b 2006-02-24 devnull doread(Ram *r, vlong off, long cnt)
106 64f7506b 2006-02-24 devnull int i, err;
107 64f7506b 2006-02-24 devnull Block bs;
108 64f7506b 2006-02-24 devnull ZipHead zh;
109 64f7506b 2006-02-24 devnull static Qid oqid;
110 64f7506b 2006-02-24 devnull static char buf[Maxbuf];
111 64f7506b 2006-02-24 devnull static uchar *cache = nil;
113 64f7506b 2006-02-24 devnull if (cnt > Maxbuf)
114 64f7506b 2006-02-24 devnull sysfatal("file too big (>%d)", Maxbuf);
116 64f7506b 2006-02-24 devnull if (Bseek(bin, r->addr & 0x7FFFFFFFFFFFFFFFLL, 0) < 0)
117 64f7506b 2006-02-24 devnull sysfatal("seek failed");
119 64f7506b 2006-02-24 devnull memset(&zh, 0, sizeof(zh));
120 64f7506b 2006-02-24 devnull if (!header(bin, &zh))
121 64f7506b 2006-02-24 devnull sysfatal("cannot get local header");
123 64f7506b 2006-02-24 devnull switch(zh.meth){
125 64f7506b 2006-02-24 devnull if (Bseek(bin, off, 1) < 0)
126 64f7506b 2006-02-24 devnull sysfatal("seek failed");
127 64f7506b 2006-02-24 devnull if (Bread(bin, buf, cnt) != cnt)
128 64f7506b 2006-02-24 devnull sysfatal("read failed");
131 64f7506b 2006-02-24 devnull if (r->qid.path != oqid.path){
132 64f7506b 2006-02-24 devnull oqid = r->qid;
133 64f7506b 2006-02-24 devnull if (cache)
134 64f7506b 2006-02-24 devnull free(cache);
135 64f7506b 2006-02-24 devnull cache = emalloc(r->ndata);
137 64f7506b 2006-02-24 devnull bs.pos = cache;
138 64f7506b 2006-02-24 devnull bs.limit = cache+r->ndata;
139 64f7506b 2006-02-24 devnull if ((err = inflate(&bs, blwrite, bin, (int(*)(void*))Bgetc)) != FlateOk)
140 64f7506b 2006-02-24 devnull sysfatal("inflate failed - %s", flateerr(err));
142 64f7506b 2006-02-24 devnull if (blockcrc(crctab, crc, cache, r->ndata) != zh.crc)
143 64f7506b 2006-02-24 devnull fprint(2, "%s - crc failed", r->name);
145 64f7506b 2006-02-24 devnull if ((r->addr & High64) && MUNGE_CR){
146 64f7506b 2006-02-24 devnull for (i = 0; i < r->ndata -1; i++)
147 64f7506b 2006-02-24 devnull if (cache[i] == '\r' && cache[i +1] == '\n')
148 64f7506b 2006-02-24 devnull cache[i] = ' ';
151 64f7506b 2006-02-24 devnull memcpy(buf, cache+off, cnt);
153 64f7506b 2006-02-24 devnull default:
154 64f7506b 2006-02-24 devnull sysfatal("%d - unsupported compression method", zh.meth);
158 64f7506b 2006-02-24 devnull return buf;
162 64f7506b 2006-02-24 devnull popdir(Ram *r)
164 64f7506b 2006-02-24 devnull USED(r);
168 64f7506b 2006-02-24 devnull dowrite(Ram *r, char *buf, long off, long cnt)
170 64f7506b 2006-02-24 devnull USED(r); USED(buf); USED(off); USED(cnt);
174 64f7506b 2006-02-24 devnull dopermw(Ram *r)
176 64f7506b 2006-02-24 devnull USED(r);
177 64f7506b 2006-02-24 devnull return 0;
180 64f7506b 2006-02-24 devnull /*************************************************/
182 64f7506b 2006-02-24 devnull static int
183 64f7506b 2006-02-24 devnull findCDir(Biobuf *bin)
185 64f7506b 2006-02-24 devnull vlong ecoff;
186 64f7506b 2006-02-24 devnull long off;
187 64f7506b 2006-02-24 devnull int entries, zclen;
189 64f7506b 2006-02-24 devnull ecoff = Bseek(bin, -ZECHeadSize, 2);
190 64f7506b 2006-02-24 devnull if(ecoff < 0)
191 64f7506b 2006-02-24 devnull sysfatal("can't seek to header");
193 64f7506b 2006-02-24 devnull if(get4(bin) != ZECHeader)
194 64f7506b 2006-02-24 devnull sysfatal("bad magic number on directory");
196 64f7506b 2006-02-24 devnull get2(bin);
197 64f7506b 2006-02-24 devnull get2(bin);
198 64f7506b 2006-02-24 devnull get2(bin);
199 64f7506b 2006-02-24 devnull entries = get2(bin);
200 64f7506b 2006-02-24 devnull get4(bin);
201 64f7506b 2006-02-24 devnull off = get4(bin);
202 64f7506b 2006-02-24 devnull zclen = get2(bin);
203 64f7506b 2006-02-24 devnull while(zclen-- > 0)
204 64f7506b 2006-02-24 devnull get1(bin);
206 64f7506b 2006-02-24 devnull if(Bseek(bin, off, 0) != off)
207 64f7506b 2006-02-24 devnull sysfatal("can't seek to contents");
209 64f7506b 2006-02-24 devnull return entries;
213 64f7506b 2006-02-24 devnull static int
214 64f7506b 2006-02-24 devnull header(Biobuf *bin, ZipHead *zh)
216 64f7506b 2006-02-24 devnull ulong v;
217 64f7506b 2006-02-24 devnull int flen, xlen;
219 64f7506b 2006-02-24 devnull v = get4(bin);
220 64f7506b 2006-02-24 devnull if(v != ZHeader){
221 64f7506b 2006-02-24 devnull if(v == ZCHeader)
222 64f7506b 2006-02-24 devnull return 0;
223 64f7506b 2006-02-24 devnull sysfatal("bad magic on local header");
225 64f7506b 2006-02-24 devnull zh->extvers = get1(bin);
226 64f7506b 2006-02-24 devnull zh->extos = get1(bin);
227 64f7506b 2006-02-24 devnull zh->flags = get2(bin);
228 64f7506b 2006-02-24 devnull zh->meth = get2(bin);
229 64f7506b 2006-02-24 devnull zh->modtime = get2(bin);
230 64f7506b 2006-02-24 devnull zh->moddate = get2(bin);
231 64f7506b 2006-02-24 devnull zh->crc = get4(bin);
232 64f7506b 2006-02-24 devnull zh->csize = get4(bin);
233 64f7506b 2006-02-24 devnull zh->uncsize = get4(bin);
234 64f7506b 2006-02-24 devnull flen = get2(bin);
235 64f7506b 2006-02-24 devnull xlen = get2(bin);
237 64f7506b 2006-02-24 devnull zh->file = getname(bin, flen);
239 64f7506b 2006-02-24 devnull while(xlen-- > 0)
240 64f7506b 2006-02-24 devnull get1(bin);
241 64f7506b 2006-02-24 devnull return 1;
244 64f7506b 2006-02-24 devnull static int
245 64f7506b 2006-02-24 devnull cheader(Biobuf *bin, ZipHead *zh)
247 64f7506b 2006-02-24 devnull ulong v;
248 64f7506b 2006-02-24 devnull int flen, xlen, fclen;
250 64f7506b 2006-02-24 devnull v = get4(bin);
251 64f7506b 2006-02-24 devnull if(v != ZCHeader){
252 64f7506b 2006-02-24 devnull if(v == ZECHeader)
253 64f7506b 2006-02-24 devnull return 0;
254 64f7506b 2006-02-24 devnull sysfatal("bad magic number in file");
256 64f7506b 2006-02-24 devnull zh->madevers = get1(bin);
257 64f7506b 2006-02-24 devnull zh->madeos = get1(bin);
258 64f7506b 2006-02-24 devnull zh->extvers = get1(bin);
259 64f7506b 2006-02-24 devnull zh->extos = get1(bin);
260 64f7506b 2006-02-24 devnull zh->flags = get2(bin);
261 64f7506b 2006-02-24 devnull zh->meth = get2(bin);
262 64f7506b 2006-02-24 devnull zh->modtime = get2(bin);
263 64f7506b 2006-02-24 devnull zh->moddate = get2(bin);
264 64f7506b 2006-02-24 devnull zh->crc = get4(bin);
265 64f7506b 2006-02-24 devnull zh->csize = get4(bin);
266 64f7506b 2006-02-24 devnull zh->uncsize = get4(bin);
267 64f7506b 2006-02-24 devnull flen = get2(bin);
268 64f7506b 2006-02-24 devnull xlen = get2(bin);
269 64f7506b 2006-02-24 devnull fclen = get2(bin);
270 64f7506b 2006-02-24 devnull get2(bin); /* disk number start */
271 64f7506b 2006-02-24 devnull zh->iattr = get2(bin); /* 1 == is-text-file */
272 64f7506b 2006-02-24 devnull zh->eattr = get4(bin); /* 1 == readonly-file */
273 64f7506b 2006-02-24 devnull zh->off = get4(bin);
275 64f7506b 2006-02-24 devnull zh->file = getname(bin, flen);
277 64f7506b 2006-02-24 devnull while(xlen-- > 0)
278 64f7506b 2006-02-24 devnull get1(bin);
280 64f7506b 2006-02-24 devnull while(fclen-- > 0)
281 64f7506b 2006-02-24 devnull get1(bin);
283 64f7506b 2006-02-24 devnull return 1;
286 64f7506b 2006-02-24 devnull static int
287 64f7506b 2006-02-24 devnull blwrite(void *vb, void *buf, int n)
289 64f7506b 2006-02-24 devnull Block *b = vb;
290 64f7506b 2006-02-24 devnull if(n > b->limit - b->pos)
291 64f7506b 2006-02-24 devnull n = b->limit - b->pos;
292 64f7506b 2006-02-24 devnull memmove(b->pos, buf, n);
293 64f7506b 2006-02-24 devnull b->pos += n;
294 64f7506b 2006-02-24 devnull return n;
298 64f7506b 2006-02-24 devnull static void
299 64f7506b 2006-02-24 devnull trailer(Biobuf *bin, ZipHead *zh)
301 64f7506b 2006-02-24 devnull if(zh->flags & ZTrailInfo){
302 64f7506b 2006-02-24 devnull zh->crc = get4(bin);
303 64f7506b 2006-02-24 devnull zh->csize = get4(bin);
304 64f7506b 2006-02-24 devnull zh->uncsize = get4(bin);
309 64f7506b 2006-02-24 devnull static char*
310 64f7506b 2006-02-24 devnull getname(Biobuf *bin, int len)
312 64f7506b 2006-02-24 devnull char *s;
313 64f7506b 2006-02-24 devnull int i, c;
315 64f7506b 2006-02-24 devnull s = emalloc(len + 1);
316 64f7506b 2006-02-24 devnull for(i = 0; i < len; i++){
317 64f7506b 2006-02-24 devnull c = get1(bin);
318 64f7506b 2006-02-24 devnull if(FORCE_LOWER)
319 64f7506b 2006-02-24 devnull c = tolower(c);
320 64f7506b 2006-02-24 devnull s[i] = c;
322 64f7506b 2006-02-24 devnull s[i] = '\0';
323 64f7506b 2006-02-24 devnull return s;
327 64f7506b 2006-02-24 devnull static ulong
328 64f7506b 2006-02-24 devnull get4(Biobuf *b)
330 64f7506b 2006-02-24 devnull ulong v;
331 64f7506b 2006-02-24 devnull int i, c;
334 64f7506b 2006-02-24 devnull for(i = 0; i < 4; i++){
335 64f7506b 2006-02-24 devnull c = Bgetc(b);
336 64f7506b 2006-02-24 devnull if(c < 0)
337 64f7506b 2006-02-24 devnull sysfatal("unexpected eof");
338 64f7506b 2006-02-24 devnull v |= c << (i * 8);
340 64f7506b 2006-02-24 devnull return v;
343 64f7506b 2006-02-24 devnull static int
344 64f7506b 2006-02-24 devnull get2(Biobuf *b)
346 64f7506b 2006-02-24 devnull int i, c, v;
349 64f7506b 2006-02-24 devnull for(i = 0; i < 2; i++){
350 64f7506b 2006-02-24 devnull c = Bgetc(b);
351 64f7506b 2006-02-24 devnull if(c < 0)
352 64f7506b 2006-02-24 devnull sysfatal("unexpected eof");
353 64f7506b 2006-02-24 devnull v |= c << (i * 8);
355 64f7506b 2006-02-24 devnull return v;
358 64f7506b 2006-02-24 devnull static int
359 64f7506b 2006-02-24 devnull get1(Biobuf *b)
363 64f7506b 2006-02-24 devnull c = Bgetc(b);
364 64f7506b 2006-02-24 devnull if(c < 0)
365 64f7506b 2006-02-24 devnull sysfatal("unexpected eof");
366 64f7506b 2006-02-24 devnull return c;
369 64f7506b 2006-02-24 devnull static long
370 64f7506b 2006-02-24 devnull msdos2time(int time, int date)
374 64f7506b 2006-02-24 devnull tm.hour = time >> 11;
375 64f7506b 2006-02-24 devnull tm.min = (time >> 5) & 63;
376 64f7506b 2006-02-24 devnull tm.sec = (time & 31) << 1;
377 64f7506b 2006-02-24 devnull tm.year = 80 + (date >> 9);
378 64f7506b 2006-02-24 devnull tm.mon = ((date >> 5) & 15) - 1;
379 64f7506b 2006-02-24 devnull tm.mday = date & 31;
380 64f7506b 2006-02-24 devnull tm.zone[0] = '\0';
381 64f7506b 2006-02-24 devnull tm.yday = 0;
383 64f7506b 2006-02-24 devnull return tm2sec(&tm);