summaryrefslogtreecommitdiff
path: root/sys/src/cmd/tapefs/zipfs.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /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-xsys/src/cmd/tapefs/zipfs.c384
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);
+}
+