tapefs from plan9
This commit is contained in:
parent
21b291a64e
commit
64f7506b34
13 changed files with 2465 additions and 0 deletions
385
src/cmd/tapefs/zipfs.c
Normal file
385
src/cmd/tapefs/zipfs.c
Normal file
|
|
@ -0,0 +1,385 @@
|
|||
#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);
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue