zipfs.c (6597B)
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 u32int *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 309 static char* 310 getname(Biobuf *bin, int len) 311 { 312 char *s; 313 int i, c; 314 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; 321 } 322 s[i] = '\0'; 323 return s; 324 } 325 326 327 static ulong 328 get4(Biobuf *b) 329 { 330 ulong v; 331 int i, c; 332 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); 339 } 340 return v; 341 } 342 343 static int 344 get2(Biobuf *b) 345 { 346 int i, c, v; 347 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); 354 } 355 return v; 356 } 357 358 static int 359 get1(Biobuf *b) 360 { 361 int c; 362 363 c = Bgetc(b); 364 if(c < 0) 365 sysfatal("unexpected eof"); 366 return c; 367 } 368 369 static long 370 msdos2time(int time, int date) 371 { 372 Tm tm; 373 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; 382 383 return tm2sec(&tm); 384 }