diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/tapefs/zipfs.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/tapefs/zipfs.c')
-rwxr-xr-x | sys/src/cmd/tapefs/zipfs.c | 384 |
1 files changed, 384 insertions, 0 deletions
diff --git a/sys/src/cmd/tapefs/zipfs.c b/sys/src/cmd/tapefs/zipfs.c new file mode 100755 index 000000000..4017a3906 --- /dev/null +++ b/sys/src/cmd/tapefs/zipfs.c @@ -0,0 +1,384 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <flate.h> +#include <auth.h> +#include <fcall.h> +#include <ctype.h> +#include "tapefs.h" +#include "zip.h" + +#define FORCE_LOWER 1 /* force filenames to lower case */ +#define MUNGE_CR 1 /* replace '\r\n' with ' \n' */ +#define High64 (1LL<<63) + +/* + * File system for zip archives (read-only) + */ + +enum { + IS_MSDOS = 0, /* creator OS (interpretation of external flags) */ + IS_RDONLY = 1, /* file was readonly (external flags) */ + IS_TEXT = 1, /* file was text (internal flags) */ +}; + +typedef struct Block Block; +struct Block{ + uchar *pos; + uchar *limit; +}; + +static Biobuf *bin; +static ulong *crctab; +static ulong crc; + +static int findCDir(Biobuf *); +static int header(Biobuf *, ZipHead *); +static int cheader(Biobuf *, ZipHead *); +static void trailer(Biobuf *, ZipHead *); +static char *getname(Biobuf *, int); +static int blwrite(void *, void *, int); +static ulong get4(Biobuf *); +static int get2(Biobuf *); +static int get1(Biobuf *); +static long msdos2time(int, int); + +void +populate(char *name) +{ + char *p; + Fileinf f; + ZipHead zh; + int ok, entries; + + crctab = mkcrctab(ZCrcPoly); + ok = inflateinit(); + if(ok != FlateOk) + sysfatal("inflateinit failed: %s", flateerr(ok)); + + bin = Bopen(name, OREAD); + if (bin == nil) + error("Can't open argument file"); + + entries = findCDir(bin); + if(entries < 0) + sysfatal("empty file"); + + while(entries-- > 0){ + memset(&zh, 0, sizeof(zh)); + if(!cheader(bin, &zh)) + break; + f.addr = zh.off; + if(zh.iattr & IS_TEXT) + f.addr |= High64; + f.mode = (zh.madevers == IS_MSDOS && zh.eattr & IS_RDONLY)? 0444: 0644; + if (zh.meth == 0 && zh.uncsize == 0){ + p = strchr(zh.file, '\0'); + if(p > zh.file && p[-1] == '/') + f.mode |= (DMDIR | 0111); + } + f.uid = 0; + f.gid = 0; + f.size = zh.uncsize; + f.mdate = msdos2time(zh.modtime, zh.moddate); + f.name = zh.file + ((zh.file[0] == '/')? 1: 0); + poppath(f, 1); + free(zh.file); + } + return ; +} + +void +dotrunc(Ram *r) +{ + USED(r); +} + +void +docreate(Ram *r) +{ + USED(r); +} + +char * +doread(Ram *r, vlong off, long cnt) +{ + int i, err; + Block bs; + ZipHead zh; + static Qid oqid; + static char buf[Maxbuf]; + static uchar *cache = nil; + + if (cnt > Maxbuf) + sysfatal("file too big (>%d)", Maxbuf); + + if (Bseek(bin, r->addr & 0x7FFFFFFFFFFFFFFFLL, 0) < 0) + sysfatal("seek failed"); + + memset(&zh, 0, sizeof(zh)); + if (!header(bin, &zh)) + sysfatal("cannot get local header"); + + switch(zh.meth){ + case 0: + if (Bseek(bin, off, 1) < 0) + sysfatal("seek failed"); + if (Bread(bin, buf, cnt) != cnt) + sysfatal("read failed"); + break; + case 8: + if (r->qid.path != oqid.path){ + oqid = r->qid; + if (cache) + free(cache); + cache = emalloc(r->ndata); + + bs.pos = cache; + bs.limit = cache+r->ndata; + if ((err = inflate(&bs, blwrite, bin, (int(*)(void*))Bgetc)) != FlateOk) + sysfatal("inflate failed - %s", flateerr(err)); + + if (blockcrc(crctab, crc, cache, r->ndata) != zh.crc) + fprint(2, "%s - crc failed", r->name); + + if ((r->addr & High64) && MUNGE_CR){ + for (i = 0; i < r->ndata -1; i++) + if (cache[i] == '\r' && cache[i +1] == '\n') + cache[i] = ' '; + } + } + memcpy(buf, cache+off, cnt); + break; + default: + sysfatal("%d - unsupported compression method", zh.meth); + break; + } + + return buf; +} + +void +popdir(Ram *r) +{ + USED(r); +} + +void +dowrite(Ram *r, char *buf, long off, long cnt) +{ + USED(r); USED(buf); USED(off); USED(cnt); +} + +int +dopermw(Ram *r) +{ + USED(r); + return 0; +} + +/*************************************************/ + +static int +findCDir(Biobuf *bin) +{ + vlong ecoff; + long off; + int entries, zclen; + + ecoff = Bseek(bin, -ZECHeadSize, 2); + if(ecoff < 0) + sysfatal("can't seek to header"); + + if(get4(bin) != ZECHeader) + sysfatal("bad magic number on directory"); + + get2(bin); + get2(bin); + get2(bin); + entries = get2(bin); + get4(bin); + off = get4(bin); + zclen = get2(bin); + while(zclen-- > 0) + get1(bin); + + if(Bseek(bin, off, 0) != off) + sysfatal("can't seek to contents"); + + return entries; +} + + +static int +header(Biobuf *bin, ZipHead *zh) +{ + ulong v; + int flen, xlen; + + v = get4(bin); + if(v != ZHeader){ + if(v == ZCHeader) + return 0; + sysfatal("bad magic on local header"); + } + zh->extvers = get1(bin); + zh->extos = get1(bin); + zh->flags = get2(bin); + zh->meth = get2(bin); + zh->modtime = get2(bin); + zh->moddate = get2(bin); + zh->crc = get4(bin); + zh->csize = get4(bin); + zh->uncsize = get4(bin); + flen = get2(bin); + xlen = get2(bin); + + zh->file = getname(bin, flen); + + while(xlen-- > 0) + get1(bin); + return 1; +} + +static int +cheader(Biobuf *bin, ZipHead *zh) +{ + ulong v; + int flen, xlen, fclen; + + v = get4(bin); + if(v != ZCHeader){ + if(v == ZECHeader) + return 0; + sysfatal("bad magic number in file"); + } + zh->madevers = get1(bin); + zh->madeos = get1(bin); + zh->extvers = get1(bin); + zh->extos = get1(bin); + zh->flags = get2(bin); + zh->meth = get2(bin); + zh->modtime = get2(bin); + zh->moddate = get2(bin); + zh->crc = get4(bin); + zh->csize = get4(bin); + zh->uncsize = get4(bin); + flen = get2(bin); + xlen = get2(bin); + fclen = get2(bin); + get2(bin); /* disk number start */ + zh->iattr = get2(bin); /* 1 == is-text-file */ + zh->eattr = get4(bin); /* 1 == readonly-file */ + zh->off = get4(bin); + + zh->file = getname(bin, flen); + + while(xlen-- > 0) + get1(bin); + + while(fclen-- > 0) + get1(bin); + + return 1; +} + +static int +blwrite(void *vb, void *buf, int n) +{ + Block *b = vb; + if(n > b->limit - b->pos) + n = b->limit - b->pos; + memmove(b->pos, buf, n); + b->pos += n; + return n; +} + + +static void +trailer(Biobuf *bin, ZipHead *zh) +{ + if(zh->flags & ZTrailInfo){ + zh->crc = get4(bin); + zh->csize = get4(bin); + zh->uncsize = get4(bin); + } +} + +static char* +getname(Biobuf *bin, int len) +{ + char *s; + int i, c; + + s = emalloc(len + 1); + for(i = 0; i < len; i++){ + c = get1(bin); + if(FORCE_LOWER) + c = tolower(c); + s[i] = c; + } + s[i] = '\0'; + return s; +} + + +static ulong +get4(Biobuf *b) +{ + ulong v; + int i, c; + + v = 0; + for(i = 0; i < 4; i++){ + c = Bgetc(b); + if(c < 0) + sysfatal("unexpected eof"); + v |= c << (i * 8); + } + return v; +} + +static int +get2(Biobuf *b) +{ + int i, c, v; + + v = 0; + for(i = 0; i < 2; i++){ + c = Bgetc(b); + if(c < 0) + sysfatal("unexpected eof"); + v |= c << (i * 8); + } + return v; +} + +static int +get1(Biobuf *b) +{ + int c; + + c = Bgetc(b); + if(c < 0) + sysfatal("unexpected eof"); + return c; +} + +static long +msdos2time(int time, int date) +{ + Tm tm; + + tm.hour = time >> 11; + tm.min = (time >> 5) & 63; + tm.sec = (time & 31) << 1; + tm.year = 80 + (date >> 9); + tm.mon = ((date >> 5) & 15) - 1; + tm.mday = date & 31; + tm.zone[0] = '\0'; + tm.yday = 0; + + return tm2sec(&tm); +} + |