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