Blob


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"
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)
15 /*
16 * File system for zip archives (read-only)
17 */
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 };
25 typedef struct Block Block;
26 struct Block{
27 uchar *pos;
28 uchar *limit;
29 };
31 static Biobuf *bin;
32 static u32int *crctab;
33 static ulong crc;
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);
46 void
47 populate(char *name)
48 {
49 char *p;
50 Fileinf f;
51 ZipHead zh;
52 int ok, entries;
54 crctab = mkcrctab(ZCrcPoly);
55 ok = inflateinit();
56 if(ok != FlateOk)
57 sysfatal("inflateinit failed: %s", flateerr(ok));
59 bin = Bopen(name, OREAD);
60 if (bin == nil)
61 error("Can't open argument file");
63 entries = findCDir(bin);
64 if(entries < 0)
65 sysfatal("empty file");
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 }
91 void
92 dotrunc(Ram *r)
93 {
94 USED(r);
95 }
97 void
98 docreate(Ram *r)
99 {
100 USED(r);
103 char *
104 doread(Ram *r, vlong off, long cnt)
106 int i, err;
107 Block bs;
108 ZipHead zh;
109 static Qid oqid;
110 static char buf[Maxbuf];
111 static uchar *cache = nil;
113 if (cnt > Maxbuf)
114 sysfatal("file too big (>%d)", Maxbuf);
116 if (Bseek(bin, r->addr & 0x7FFFFFFFFFFFFFFFLL, 0) < 0)
117 sysfatal("seek failed");
119 memset(&zh, 0, sizeof(zh));
120 if (!header(bin, &zh))
121 sysfatal("cannot get local header");
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);
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));
142 if (blockcrc(crctab, crc, cache, r->ndata) != zh.crc)
143 fprint(2, "%s - crc failed", r->name);
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] = ' ';
151 memcpy(buf, cache+off, cnt);
152 break;
153 default:
154 sysfatal("%d - unsupported compression method", zh.meth);
155 break;
158 return buf;
161 void
162 popdir(Ram *r)
164 USED(r);
167 void
168 dowrite(Ram *r, char *buf, long off, long cnt)
170 USED(r); USED(buf); USED(off); USED(cnt);
173 int
174 dopermw(Ram *r)
176 USED(r);
177 return 0;
180 /*************************************************/
182 static int
183 findCDir(Biobuf *bin)
185 vlong ecoff;
186 long off;
187 int entries, zclen;
189 ecoff = Bseek(bin, -ZECHeadSize, 2);
190 if(ecoff < 0)
191 sysfatal("can't seek to header");
193 if(get4(bin) != ZECHeader)
194 sysfatal("bad magic number on directory");
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);
206 if(Bseek(bin, off, 0) != off)
207 sysfatal("can't seek to contents");
209 return entries;
213 static int
214 header(Biobuf *bin, ZipHead *zh)
216 ulong v;
217 int flen, xlen;
219 v = get4(bin);
220 if(v != ZHeader){
221 if(v == ZCHeader)
222 return 0;
223 sysfatal("bad magic on local header");
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);
237 zh->file = getname(bin, flen);
239 while(xlen-- > 0)
240 get1(bin);
241 return 1;
244 static int
245 cheader(Biobuf *bin, ZipHead *zh)
247 ulong v;
248 int flen, xlen, fclen;
250 v = get4(bin);
251 if(v != ZCHeader){
252 if(v == ZECHeader)
253 return 0;
254 sysfatal("bad magic number in file");
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);
275 zh->file = getname(bin, flen);
277 while(xlen-- > 0)
278 get1(bin);
280 while(fclen-- > 0)
281 get1(bin);
283 return 1;
286 static int
287 blwrite(void *vb, void *buf, int n)
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;
297 /*
298 static void
299 trailer(Biobuf *bin, ZipHead *zh)
301 if(zh->flags & ZTrailInfo){
302 zh->crc = get4(bin);
303 zh->csize = get4(bin);
304 zh->uncsize = get4(bin);
307 */
309 static char*
310 getname(Biobuf *bin, int len)
312 char *s;
313 int i, c;
315 s = emalloc(len + 1);
316 for(i = 0; i < len; i++){
317 c = get1(bin);
318 if(FORCE_LOWER)
319 c = tolower(c);
320 s[i] = c;
322 s[i] = '\0';
323 return s;
327 static ulong
328 get4(Biobuf *b)
330 ulong v;
331 int i, c;
333 v = 0;
334 for(i = 0; i < 4; i++){
335 c = Bgetc(b);
336 if(c < 0)
337 sysfatal("unexpected eof");
338 v |= c << (i * 8);
340 return v;
343 static int
344 get2(Biobuf *b)
346 int i, c, v;
348 v = 0;
349 for(i = 0; i < 2; i++){
350 c = Bgetc(b);
351 if(c < 0)
352 sysfatal("unexpected eof");
353 v |= c << (i * 8);
355 return v;
358 static int
359 get1(Biobuf *b)
361 int c;
363 c = Bgetc(b);
364 if(c < 0)
365 sysfatal("unexpected eof");
366 return c;
369 static long
370 msdos2time(int time, int date)
372 Tm tm;
374 tm.hour = time >> 11;
375 tm.min = (time >> 5) & 63;
376 tm.sec = (time & 31) << 1;
377 tm.year = 80 + (date >> 9);
378 tm.mon = ((date >> 5) & 15) - 1;
379 tm.mday = date & 31;
380 tm.zone[0] = '\0';
381 tm.yday = 0;
383 return tm2sec(&tm);