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 385