plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

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 }