| ttapefs from plan9 - plan9port - [fork] Plan 9 from user space | |
| git clone git://src.adamsgaard.dk/plan9port | |
| Log | |
| Files | |
| Refs | |
| README | |
| LICENSE | |
| --- | |
| commit 64f7506b34106955fbbd5f6bf944ecd839610672 | |
| parent 21b291a64e4f059744b4094a8f8e52784ad323f4 | |
| Author: rsc <devnull@localhost> | |
| Date: Fri, 24 Feb 2006 21:17:00 +0000 | |
| ttapefs from plan9 | |
| Diffstat: | |
| A src/cmd/tapefs/32vfs.c | 208 +++++++++++++++++++++++++++++… | |
| A src/cmd/tapefs/cpiofs.c | 139 ++++++++++++++++++++++++++++++ | |
| A src/cmd/tapefs/fs.c | 600 +++++++++++++++++++++++++++++… | |
| A src/cmd/tapefs/mkfile | 13 +++++++++++++ | |
| A src/cmd/tapefs/tapefs.h | 95 ++++++++++++++++++++++++++++++ | |
| A src/cmd/tapefs/tapfs.c | 115 +++++++++++++++++++++++++++++… | |
| A src/cmd/tapefs/tarfs.c | 144 +++++++++++++++++++++++++++++… | |
| A src/cmd/tapefs/tpfs.c | 108 +++++++++++++++++++++++++++++… | |
| A src/cmd/tapefs/util.c | 153 +++++++++++++++++++++++++++++… | |
| A src/cmd/tapefs/v10fs.c | 209 +++++++++++++++++++++++++++++… | |
| A src/cmd/tapefs/v6fs.c | 213 +++++++++++++++++++++++++++++… | |
| A src/cmd/tapefs/zip.h | 83 +++++++++++++++++++++++++++++… | |
| A src/cmd/tapefs/zipfs.c | 385 +++++++++++++++++++++++++++++… | |
| 13 files changed, 2465 insertions(+), 0 deletions(-) | |
| --- | |
| diff --git a/src/cmd/tapefs/32vfs.c b/src/cmd/tapefs/32vfs.c | |
| t@@ -0,0 +1,208 @@ | |
| +/* | |
| + * Vax 32V Unix filesystem (same as pre-FFS Berkeley) | |
| + */ | |
| +#include <u.h> | |
| +#include <libc.h> | |
| +#include <auth.h> | |
| +#include <fcall.h> | |
| +#include "tapefs.h" | |
| + | |
| +/* | |
| + * v32 disk inode | |
| + */ | |
| +#define VNADDR 13 | |
| +#define VFMT 0160000 | |
| +#define VIFREG 0100000 | |
| +#define VIFDIR 0040000 | |
| +#define VIFCHR 0120000 | |
| +#define VIFBLK 0160000 | |
| +#define VMODE 0777 | |
| +#define VSUPERB 1 | |
| +#define VROOT 2 /* root inode */ | |
| +#define VNAMELEN 14 | |
| +#define BLSIZE 512 | |
| +#define LINOPB (BLSIZE/sizeof(struct v32dinode)) | |
| +#define LNINDIR (BLSIZE/sizeof(unsigned long)) | |
| + | |
| +struct v32dinode { | |
| + unsigned char flags[2]; | |
| + unsigned char nlinks[2]; | |
| + unsigned char uid[2]; | |
| + unsigned char gid[2]; | |
| + unsigned char size[4]; | |
| + unsigned char addr[40]; | |
| + unsigned char atime[4]; | |
| + unsigned char mtime[4]; | |
| + unsigned char ctime[4]; | |
| +}; | |
| + | |
| +struct v32dir { | |
| + uchar ino[2]; | |
| + char name[VNAMELEN]; | |
| +}; | |
| + | |
| +int tapefile; | |
| +Fileinf iget(int ino); | |
| +long bmap(Ram *r, long bno); | |
| +void getblk(Ram *r, long bno, char *buf); | |
| + | |
| +void | |
| +populate(char *name) | |
| +{ | |
| + Fileinf f; | |
| + | |
| + replete = 0; | |
| + tapefile = open(name, OREAD); | |
| + if (tapefile<0) | |
| + error("Can't open argument file"); | |
| + f = iget(VROOT); | |
| + ram->perm = f.mode; | |
| + ram->mtime = f.mdate; | |
| + ram->addr = f.addr; | |
| + ram->data = f.data; | |
| + ram->ndata = f.size; | |
| +} | |
| + | |
| +void | |
| +popdir(Ram *r) | |
| +{ | |
| + int i, ino; | |
| + char *cp; | |
| + struct v32dir *dp; | |
| + Fileinf f; | |
| + char name[VNAMELEN+1]; | |
| + | |
| + cp = 0; | |
| + for (i=0; i<r->ndata; i+=sizeof(struct v32dir)) { | |
| + if (i%BLSIZE==0) | |
| + cp = doread(r, i, BLSIZE); | |
| + dp = (struct v32dir *)(cp+i%BLSIZE); | |
| + ino = g2byte(dp->ino); | |
| + if (strcmp(dp->name, ".")==0 || strcmp(dp->name, "..")==0) | |
| + continue; | |
| + if (ino==0) | |
| + continue; | |
| + f = iget(ino); | |
| + strncpy(name, dp->name, VNAMELEN); | |
| + name[VNAMELEN+1] = '\0'; | |
| + f.name = name; | |
| + popfile(r, f); | |
| + } | |
| + r->replete = 1; | |
| +} | |
| + | |
| +void | |
| +dotrunc(Ram *r) | |
| +{ | |
| + USED(r); | |
| +} | |
| + | |
| +void | |
| +docreate(Ram *r) | |
| +{ | |
| + USED(r); | |
| +} | |
| + | |
| +char * | |
| +doread(Ram *r, vlong off, long cnt) | |
| +{ | |
| + static char buf[Maxbuf+BLSIZE]; | |
| + int bno, i; | |
| + | |
| + bno = off/BLSIZE; | |
| + off -= bno*BLSIZE; | |
| + if (cnt>Maxbuf) | |
| + error("count too large"); | |
| + if (off) | |
| + cnt += off; | |
| + i = 0; | |
| + while (cnt>0) { | |
| + getblk(r, bno, &buf[i*BLSIZE]); | |
| + cnt -= BLSIZE; | |
| + bno++; | |
| + i++; | |
| + } | |
| + return buf; | |
| +} | |
| + | |
| +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; | |
| +} | |
| + | |
| +/* | |
| + * fetch an i-node | |
| + * -- no sanity check for now | |
| + * -- magic inode-to-disk-block stuff here | |
| + */ | |
| + | |
| +Fileinf | |
| +iget(int ino) | |
| +{ | |
| + char buf[BLSIZE]; | |
| + struct v32dinode *dp; | |
| + long flags, i; | |
| + Fileinf f; | |
| + | |
| + seek(tapefile, BLSIZE*((ino-1)/LINOPB + VSUPERB + 1), 0); | |
| + if (read(tapefile, buf, BLSIZE) != BLSIZE) | |
| + error("Can't read inode"); | |
| + dp = ((struct v32dinode *)buf) + ((ino-1)%LINOPB); | |
| + flags = g2byte(dp->flags); | |
| + f.size = g4byte(dp->size); | |
| + if ((flags&VFMT)==VIFCHR || (flags&VFMT)==VIFBLK) | |
| + f.size = 0; | |
| + f.data = emalloc(VNADDR*sizeof(long)); | |
| + for (i = 0; i < VNADDR; i++) | |
| + ((long*)f.data)[i] = g3byte(dp->addr+3*i); | |
| + f.mode = flags & VMODE; | |
| + if ((flags&VFMT)==VIFDIR) | |
| + f.mode |= DMDIR; | |
| + f.uid = g2byte(dp->uid); | |
| + f.gid = g2byte(dp->gid); | |
| + f.mdate = g4byte(dp->mtime); | |
| + return f; | |
| +} | |
| + | |
| +void | |
| +getblk(Ram *r, long bno, char *buf) | |
| +{ | |
| + long dbno; | |
| + | |
| + if ((dbno = bmap(r, bno)) == 0) { | |
| + memset(buf, 0, BLSIZE); | |
| + return; | |
| + } | |
| + seek(tapefile, dbno*BLSIZE, 0); | |
| + if (read(tapefile, buf, BLSIZE) != BLSIZE) | |
| + error("bad read"); | |
| +} | |
| + | |
| +/* | |
| + * logical to physical block | |
| + * only singly-indirect files for now | |
| + */ | |
| + | |
| +long | |
| +bmap(Ram *r, long bno) | |
| +{ | |
| + unsigned char indbuf[LNINDIR][sizeof(long)]; | |
| + | |
| + if (bno < VNADDR-3) | |
| + return ((long*)r->data)[bno]; | |
| + if (bno < VNADDR*LNINDIR) { | |
| + seek(tapefile, ((long *)r->data)[(bno-(VNADDR-3))/LNINDIR]*BLS… | |
| + if (read(tapefile, (char *)indbuf, BLSIZE) != BLSIZE) | |
| + return 0; | |
| + return ((indbuf[bno%LNINDIR][1]<<8) + indbuf[bno%LNINDIR][0]); | |
| + } | |
| + return 0; | |
| +} | |
| diff --git a/src/cmd/tapefs/cpiofs.c b/src/cmd/tapefs/cpiofs.c | |
| t@@ -0,0 +1,139 @@ | |
| +#include <u.h> | |
| +#include <libc.h> | |
| +#include <auth.h> | |
| +#include <fcall.h> | |
| +#include "tapefs.h" | |
| + | |
| +/* | |
| + * File system for cpio tapes (read-only) | |
| + */ | |
| + | |
| +#define TBLOCK 512 | |
| +#define NBLOCK 40 /* maximum blocksize */ | |
| +#define DBLOCK 20 /* default blocksize */ | |
| +#define TNAMSIZ 100 | |
| + | |
| +union hblock { | |
| + char dummy[TBLOCK]; | |
| + char tbuf[Maxbuf]; | |
| + struct header { | |
| + char magic[6]; | |
| + char dev[6]; | |
| + char ino[6]; | |
| + char mode[6]; | |
| + char uid[6]; | |
| + char gid[6]; | |
| + char nlink[6]; | |
| + char rdev[6]; | |
| + char mtime[11]; | |
| + char namesize[6]; | |
| + char size[11]; | |
| + } dbuf; | |
| + struct hname { | |
| + struct header x; | |
| + char name[1]; | |
| + } nbuf; | |
| +} dblock; | |
| + | |
| +int tapefile; | |
| +vlong getoct(char*, int); | |
| + | |
| +void | |
| +populate(char *name) | |
| +{ | |
| + vlong offset; | |
| + long isabs, magic, namesize, mode; | |
| + Fileinf f; | |
| + | |
| + tapefile = open(name, OREAD); | |
| + if (tapefile<0) | |
| + error("Can't open argument file"); | |
| + replete = 1; | |
| + for (offset = 0;;) { | |
| + seek(tapefile, offset, 0); | |
| + if (read(tapefile, (char *)&dblock.dbuf, TBLOCK)<TBLOCK) | |
| + break; | |
| + magic = getoct(dblock.dbuf.magic, sizeof(dblock.dbuf.magic)); | |
| + if (magic != 070707){ | |
| + print("%lo\n", magic); | |
| + error("out of phase--get help"); | |
| + } | |
| + if (dblock.nbuf.name[0]=='\0' || strcmp(dblock.nbuf.name, "TRA… | |
| + break; | |
| + mode = getoct(dblock.dbuf.mode, sizeof(dblock.dbuf.mode)); | |
| + f.mode = mode&0777; | |
| + switch(mode & 0170000) { | |
| + case 0040000: | |
| + f.mode |= DMDIR; | |
| + break; | |
| + case 0100000: | |
| + break; | |
| + default: | |
| + f.mode = 0; | |
| + break; | |
| + } | |
| + f.uid = getoct(dblock.dbuf.uid, sizeof(dblock.dbuf.uid)); | |
| + f.gid = getoct(dblock.dbuf.gid, sizeof(dblock.dbuf.gid)); | |
| + f.size = getoct(dblock.dbuf.size, sizeof(dblock.dbuf.size)); | |
| + f.mdate = getoct(dblock.dbuf.mtime, sizeof(dblock.dbuf.mtime)); | |
| + namesize = getoct(dblock.dbuf.namesize, sizeof(dblock.dbuf.nam… | |
| + f.addr = offset+sizeof(struct header)+namesize; | |
| + isabs = dblock.nbuf.name[0]=='/'; | |
| + f.name = &dblock.nbuf.name[isabs]; | |
| + poppath(f, 1); | |
| + offset += sizeof(struct header)+namesize+f.size; | |
| + } | |
| +} | |
| + | |
| +vlong | |
| +getoct(char *p, int l) | |
| +{ | |
| + vlong r; | |
| + | |
| + for (r=0; l>0; p++, l--){ | |
| + r <<= 3; | |
| + r += *p-'0'; | |
| + } | |
| + return r; | |
| +} | |
| + | |
| +void | |
| +dotrunc(Ram *r) | |
| +{ | |
| + USED(r); | |
| +} | |
| + | |
| +void | |
| +docreate(Ram *r) | |
| +{ | |
| + USED(r); | |
| +} | |
| + | |
| +char * | |
| +doread(Ram *r, vlong off, long cnt) | |
| +{ | |
| + seek(tapefile, r->addr+off, 0); | |
| + if (cnt>sizeof(dblock.tbuf)) | |
| + error("read too big"); | |
| + read(tapefile, dblock.tbuf, cnt); | |
| + return dblock.tbuf; | |
| +} | |
| + | |
| +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; | |
| +} | |
| diff --git a/src/cmd/tapefs/fs.c b/src/cmd/tapefs/fs.c | |
| t@@ -0,0 +1,600 @@ | |
| +#include <u.h> | |
| +#include <libc.h> | |
| +#include <authsrv.h> | |
| +#include <fcall.h> | |
| +#include "tapefs.h" | |
| + | |
| +Fid *fids; | |
| +Ram *ram; | |
| +int mfd[2]; | |
| +char *user; | |
| +uchar mdata[Maxbuf+IOHDRSZ]; | |
| +int messagesize = Maxbuf+IOHDRSZ; | |
| +Fcall rhdr; | |
| +Fcall thdr; | |
| +ulong path; | |
| +Idmap *uidmap; | |
| +Idmap *gidmap; | |
| +int replete; | |
| +int verbose; | |
| +int newtap; /* tap with time in sec */ | |
| + | |
| +Fid * newfid(int); | |
| +int ramstat(Ram*, uchar*, int); | |
| +void io(void); | |
| +void usage(void); | |
| +int perm(int); | |
| + | |
| +char *rflush(Fid*), *rversion(Fid*), *rauth(Fid*), | |
| + *rattach(Fid*), *rwalk(Fid*), | |
| + *ropen(Fid*), *rcreate(Fid*), | |
| + *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*), | |
| + *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*); | |
| + | |
| +char *(*fcalls[])(Fid*) = { | |
| + [Tflush] rflush, | |
| + [Tversion] rversion, | |
| + [Tauth] rauth, | |
| + [Tattach] rattach, | |
| + [Twalk] rwalk, | |
| + [Topen] ropen, | |
| + [Tcreate] rcreate, | |
| + [Tread] rread, | |
| + [Twrite] rwrite, | |
| + [Tclunk] rclunk, | |
| + [Tremove] rremove, | |
| + [Tstat] rstat, | |
| + [Twstat] rwstat, | |
| +}; | |
| + | |
| +char Eperm[] = "permission denied"; | |
| +char Enotdir[] = "not a directory"; | |
| +char Enoauth[] = "tapefs: authentication not required"; | |
| +char Enotexist[] = "file does not exist"; | |
| +char Einuse[] = "file in use"; | |
| +char Eexist[] = "file exists"; | |
| +char Enotowner[] = "not owner"; | |
| +char Eisopen[] = "file already open for I/O"; | |
| +char Excl[] = "exclusive use file already open"; | |
| +char Ename[] = "illegal name"; | |
| + | |
| +void | |
| +notifyf(void *a, char *s) | |
| +{ | |
| + USED(a); | |
| + if(strncmp(s, "interrupt", 9) == 0) | |
| + noted(NCONT); | |
| + noted(NDFLT); | |
| +} | |
| + | |
| +void | |
| +main(int argc, char *argv[]) | |
| +{ | |
| + Ram *r; | |
| + char *defmnt; | |
| + int p[2]; | |
| + char buf[TICKREQLEN]; | |
| + | |
| + fmtinstall('F', fcallfmt); | |
| + | |
| + defmnt = "/n/tapefs"; | |
| + ARGBEGIN{ | |
| + case 'm': | |
| + defmnt = ARGF(); | |
| + break; | |
| + case 'p': /* password file */ | |
| + uidmap = getpass(ARGF()); | |
| + break; | |
| + case 'g': /* group file */ | |
| + gidmap = getpass(ARGF()); | |
| + break; | |
| + case 'v': | |
| + verbose++; | |
| + | |
| + case 'n': | |
| + newtap++; | |
| + break; | |
| + default: | |
| + usage(); | |
| + }ARGEND | |
| + | |
| + if(argc==0) | |
| + error("no file to mount"); | |
| + user = getuser(); | |
| + if(user == nil) | |
| + user = "dmr"; | |
| + ram = r = (Ram *)emalloc(sizeof(Ram)); | |
| + r->busy = 1; | |
| + r->data = 0; | |
| + r->ndata = 0; | |
| + r->perm = DMDIR | 0775; | |
| + r->qid.path = 0; | |
| + r->qid.vers = 0; | |
| + r->qid.type = QTDIR; | |
| + r->parent = 0; | |
| + r->child = 0; | |
| + r->next = 0; | |
| + r->user = user; | |
| + r->group = user; | |
| + r->atime = time(0); | |
| + r->mtime = r->atime; | |
| + r->replete = 0; | |
| + r->name = estrdup("."); | |
| + populate(argv[0]); | |
| + r->replete |= replete; | |
| + if(pipe(p) < 0) | |
| + error("pipe failed"); | |
| + mfd[0] = mfd[1] = p[0]; | |
| + notify(notifyf); | |
| + | |
| + switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){ | |
| + case -1: | |
| + error("fork"); | |
| + case 0: | |
| + close(p[1]); | |
| + notify(notifyf); | |
| + io(); | |
| + break; | |
| + default: | |
| + close(p[0]); /* don't deadlock if child fails */ | |
| + if(post9pservice(p[1], defmnt) < 0) { | |
| + sprint(buf, "post on `%s' failed", defmnt); | |
| + error(buf); | |
| + } | |
| + } | |
| + exits(0); | |
| +} | |
| + | |
| +char* | |
| +rversion(Fid *unused) | |
| +{ | |
| + Fid *f; | |
| + | |
| + USED(unused); | |
| + | |
| + if(rhdr.msize < 256) | |
| + return "version: message too small"; | |
| + if(rhdr.msize > messagesize) | |
| + rhdr.msize = messagesize; | |
| + else | |
| + messagesize = rhdr.msize; | |
| + thdr.msize = messagesize; | |
| + if(strncmp(rhdr.version, "9P2000", 6) != 0) | |
| + return "unrecognized 9P version"; | |
| + thdr.version = "9P2000"; | |
| + | |
| + for(f = fids; f; f = f->next) | |
| + if(f->busy) | |
| + rclunk(f); | |
| + return 0; | |
| +} | |
| + | |
| +char* | |
| +rauth(Fid *unused) | |
| +{ | |
| + USED(unused); | |
| + | |
| + return Enoauth; | |
| +} | |
| + | |
| +char* | |
| +rflush(Fid *f) | |
| +{ | |
| + USED(f); | |
| + return 0; | |
| +} | |
| + | |
| +char* | |
| +rattach(Fid *f) | |
| +{ | |
| + /* no authentication! */ | |
| + f->busy = 1; | |
| + f->rclose = 0; | |
| + f->ram = ram; | |
| + thdr.qid = f->ram->qid; | |
| + if(rhdr.uname[0]) | |
| + f->user = strdup(rhdr.uname); | |
| + else | |
| + f->user = "none"; | |
| + return 0; | |
| +} | |
| + | |
| +char* | |
| +rwalk(Fid *f) | |
| +{ | |
| + Fid *nf; | |
| + Ram *r; | |
| + char *err; | |
| + char *name; | |
| + Ram *dir; | |
| + int i; | |
| + | |
| + nf = nil; | |
| + if(f->ram->busy == 0) | |
| + return Enotexist; | |
| + if(f->open) | |
| + return Eisopen; | |
| + if(rhdr.newfid != rhdr.fid){ | |
| + nf = newfid(rhdr.newfid); | |
| + nf->busy = 1; | |
| + nf->open = 0; | |
| + nf->rclose = 0; | |
| + nf->ram = f->ram; | |
| + nf->user = f->user; /* no ref count; the leakage is min… | |
| + f = nf; | |
| + } | |
| + | |
| + thdr.nwqid = 0; | |
| + err = nil; | |
| + r = f->ram; | |
| + | |
| + if(rhdr.nwname > 0){ | |
| + for(i=0; i<rhdr.nwname; i++){ | |
| + if((r->qid.type & QTDIR) == 0){ | |
| + err = Enotdir; | |
| + break; | |
| + } | |
| + if(r->busy == 0){ | |
| + err = Enotexist; | |
| + break; | |
| + } | |
| + r->atime = time(0); | |
| + name = rhdr.wname[i]; | |
| + dir = r; | |
| + if(!perm(Pexec)){ | |
| + err = Eperm; | |
| + break; | |
| + } | |
| + if(strcmp(name, "..") == 0){ | |
| + r = dir->parent; | |
| + Accept: | |
| + if(i == MAXWELEM){ | |
| + err = "name too long"; | |
| + break; | |
| + } | |
| + thdr.wqid[thdr.nwqid++] = r->qid; | |
| + continue; | |
| + } | |
| + if(!dir->replete) | |
| + popdir(dir); | |
| + for(r=dir->child; r; r=r->next) | |
| + if(r->busy && strcmp(name, r->name)==0) | |
| + goto Accept; | |
| + break; /* file not found */ | |
| + } | |
| + | |
| + if(i==0 && err == nil) | |
| + err = Enotexist; | |
| + } | |
| + | |
| + if(err!=nil || thdr.nwqid<rhdr.nwname){ | |
| + if(nf){ | |
| + nf->busy = 0; | |
| + nf->open = 0; | |
| + nf->ram = 0; | |
| + } | |
| + }else if(thdr.nwqid == rhdr.nwname) | |
| + f->ram = r; | |
| + | |
| + return err; | |
| + | |
| +} | |
| + | |
| +char * | |
| +ropen(Fid *f) | |
| +{ | |
| + Ram *r; | |
| + int mode, trunc; | |
| + | |
| + if(f->open) | |
| + return Eisopen; | |
| + r = f->ram; | |
| + if(r->busy == 0) | |
| + return Enotexist; | |
| + if(r->perm & DMEXCL) | |
| + if(r->open) | |
| + return Excl; | |
| + mode = rhdr.mode; | |
| + if(r->qid.type & QTDIR){ | |
| + if(mode != OREAD) | |
| + return Eperm; | |
| + thdr.qid = r->qid; | |
| + return 0; | |
| + } | |
| + if(mode & ORCLOSE) | |
| + return Eperm; | |
| + trunc = mode & OTRUNC; | |
| + mode &= OPERM; | |
| + if(mode==OWRITE || mode==ORDWR || trunc) | |
| + if(!perm(Pwrite)) | |
| + return Eperm; | |
| + if(mode==OREAD || mode==ORDWR) | |
| + if(!perm(Pread)) | |
| + return Eperm; | |
| + if(mode==OEXEC) | |
| + if(!perm(Pexec)) | |
| + return Eperm; | |
| + if(trunc && (r->perm&DMAPPEND)==0){ | |
| + r->ndata = 0; | |
| + dotrunc(r); | |
| + r->qid.vers++; | |
| + } | |
| + thdr.qid = r->qid; | |
| + thdr.iounit = messagesize-IOHDRSZ; | |
| + f->open = 1; | |
| + r->open++; | |
| + return 0; | |
| +} | |
| + | |
| +char * | |
| +rcreate(Fid *f) | |
| +{ | |
| + USED(f); | |
| + | |
| + return Eperm; | |
| +} | |
| + | |
| +char* | |
| +rread(Fid *f) | |
| +{ | |
| + int i, len; | |
| + Ram *r; | |
| + char *buf; | |
| + uvlong off, end; | |
| + int n, cnt; | |
| + | |
| + if(f->ram->busy == 0) | |
| + return Enotexist; | |
| + n = 0; | |
| + thdr.count = 0; | |
| + off = rhdr.offset; | |
| + end = rhdr.offset + rhdr.count; | |
| + cnt = rhdr.count; | |
| + if(cnt > messagesize-IOHDRSZ) | |
| + cnt = messagesize-IOHDRSZ; | |
| + buf = thdr.data; | |
| + if(f->ram->qid.type & QTDIR){ | |
| + if(!f->ram->replete) | |
| + popdir(f->ram); | |
| + for(i=0,r=f->ram->child; r!=nil && i<end; r=r->next){ | |
| + if(!r->busy) | |
| + continue; | |
| + len = ramstat(r, (uchar*)buf+n, cnt-n); | |
| + if(len <= BIT16SZ) | |
| + break; | |
| + if(i >= off) | |
| + n += len; | |
| + i += len; | |
| + } | |
| + thdr.count = n; | |
| + return 0; | |
| + } | |
| + r = f->ram; | |
| + if(off >= r->ndata) | |
| + return 0; | |
| + r->atime = time(0); | |
| + n = cnt; | |
| + if(off+n > r->ndata) | |
| + n = r->ndata - off; | |
| + thdr.data = doread(r, off, n); | |
| + thdr.count = n; | |
| + return 0; | |
| +} | |
| + | |
| +char* | |
| +rwrite(Fid *f) | |
| +{ | |
| + Ram *r; | |
| + ulong off; | |
| + int cnt; | |
| + | |
| + r = f->ram; | |
| + if(dopermw(f->ram)==0) | |
| + return Eperm; | |
| + if(r->busy == 0) | |
| + return Enotexist; | |
| + off = rhdr.offset; | |
| + if(r->perm & DMAPPEND) | |
| + off = r->ndata; | |
| + cnt = rhdr.count; | |
| + if(r->qid.type & QTDIR) | |
| + return "file is a directory"; | |
| + if(off > 100*1024*1024) /* sanity check */ | |
| + return "write too big"; | |
| + dowrite(r, rhdr.data, off, cnt); | |
| + r->qid.vers++; | |
| + r->mtime = time(0); | |
| + thdr.count = cnt; | |
| + return 0; | |
| +} | |
| + | |
| +char * | |
| +rclunk(Fid *f) | |
| +{ | |
| + if(f->open) | |
| + f->ram->open--; | |
| + f->busy = 0; | |
| + f->open = 0; | |
| + f->ram = 0; | |
| + return 0; | |
| +} | |
| + | |
| +char * | |
| +rremove(Fid *f) | |
| +{ | |
| + USED(f); | |
| + return Eperm; | |
| +} | |
| + | |
| +char * | |
| +rstat(Fid *f) | |
| +{ | |
| + if(f->ram->busy == 0) | |
| + return Enotexist; | |
| + thdr.nstat = ramstat(f->ram, thdr.stat, messagesize-IOHDRSZ); | |
| + return 0; | |
| +} | |
| + | |
| +char * | |
| +rwstat(Fid *f) | |
| +{ | |
| + if(f->ram->busy == 0) | |
| + return Enotexist; | |
| + return Eperm; | |
| +} | |
| + | |
| +int | |
| +ramstat(Ram *r, uchar *buf, int nbuf) | |
| +{ | |
| + Dir dir; | |
| + | |
| + dir.name = r->name; | |
| + dir.qid = r->qid; | |
| + dir.mode = r->perm; | |
| + dir.length = r->ndata; | |
| + dir.uid = r->user; | |
| + dir.gid = r->group; | |
| + dir.muid = r->user; | |
| + dir.atime = r->atime; | |
| + dir.mtime = r->mtime; | |
| + return convD2M(&dir, buf, nbuf); | |
| +} | |
| + | |
| +Fid * | |
| +newfid(int fid) | |
| +{ | |
| + Fid *f, *ff; | |
| + | |
| + ff = 0; | |
| + for(f = fids; f; f = f->next) | |
| + if(f->fid == fid) | |
| + return f; | |
| + else if(!ff && !f->busy) | |
| + ff = f; | |
| + if(ff){ | |
| + ff->fid = fid; | |
| + ff->open = 0; | |
| + ff->busy = 1; | |
| + } | |
| + f = emalloc(sizeof *f); | |
| + f->ram = 0; | |
| + f->fid = fid; | |
| + f->busy = 1; | |
| + f->open = 0; | |
| + f->next = fids; | |
| + fids = f; | |
| + return f; | |
| +} | |
| + | |
| +void | |
| +io(void) | |
| +{ | |
| + char *err; | |
| + int n, nerr; | |
| + char buf[ERRMAX]; | |
| + | |
| + errstr(buf, sizeof buf); | |
| + for(nerr=0, buf[0]='\0'; nerr<100; nerr++){ | |
| + /* | |
| + * reading from a pipe or a network device | |
| + * will give an error after a few eof reads | |
| + * however, we cannot tell the difference | |
| + * between a zero-length read and an interrupt | |
| + * on the processes writing to us, | |
| + * so we wait for the error | |
| + */ | |
| + n = read9pmsg(mfd[0], mdata, sizeof mdata); | |
| + if(n==0) | |
| + continue; | |
| + if(n < 0){ | |
| + if(buf[0]=='\0') | |
| + errstr(buf, sizeof buf); | |
| + continue; | |
| + } | |
| + nerr = 0; | |
| + buf[0] = '\0'; | |
| + if(convM2S(mdata, n, &rhdr) != n) | |
| + error("convert error in convM2S"); | |
| + | |
| + if(verbose) | |
| + fprint(2, "tapefs: <=%F\n", &rhdr);/**/ | |
| + | |
| + thdr.data = (char*)mdata + IOHDRSZ; | |
| + thdr.stat = mdata + IOHDRSZ; | |
| + if(!fcalls[rhdr.type]) | |
| + err = "bad fcall type"; | |
| + else | |
| + err = (*fcalls[rhdr.type])(newfid(rhdr.fid)); | |
| + if(err){ | |
| + thdr.type = Rerror; | |
| + thdr.ename = err; | |
| + }else{ | |
| + thdr.type = rhdr.type + 1; | |
| + thdr.fid = rhdr.fid; | |
| + } | |
| + thdr.tag = rhdr.tag; | |
| + n = convS2M(&thdr, mdata, messagesize); | |
| + if(n <= 0) | |
| + error("convert error in convS2M"); | |
| + if(verbose) | |
| + fprint(2, "tapefs: =>%F\n", &thdr);/**/ | |
| + if(write(mfd[1], mdata, n) != n) | |
| + error("mount write"); | |
| + } | |
| + if(buf[0]=='\0' || strstr(buf, "hungup")) | |
| + exits(""); | |
| + fprint(2, "%s: mount read: %s\n", argv0, buf); | |
| + exits(buf); | |
| +} | |
| + | |
| +int | |
| +perm(int p) | |
| +{ | |
| + if(p==Pwrite) | |
| + return 0; | |
| + return 1; | |
| +} | |
| + | |
| +void | |
| +error(char *s) | |
| +{ | |
| + fprint(2, "%s: %s: ", argv0, s); | |
| + perror(""); | |
| + exits(s); | |
| +} | |
| + | |
| +char* | |
| +estrdup(char *s) | |
| +{ | |
| + char *t; | |
| + | |
| + t = emalloc(strlen(s)+1); | |
| + strcpy(t, s); | |
| + return t; | |
| +} | |
| + | |
| +void * | |
| +emalloc(ulong n) | |
| +{ | |
| + void *p; | |
| + p = mallocz(n, 1); | |
| + if(!p) | |
| + error("out of memory"); | |
| + return p; | |
| +} | |
| + | |
| +void * | |
| +erealloc(void *p, ulong n) | |
| +{ | |
| + p = realloc(p, n); | |
| + if(!p) | |
| + error("out of memory"); | |
| + return p; | |
| +} | |
| + | |
| +void | |
| +usage(void) | |
| +{ | |
| + fprint(2, "usage: %s [-s] [-m mountpoint]\n", argv0); | |
| + exits("usage"); | |
| +} | |
| diff --git a/src/cmd/tapefs/mkfile b/src/cmd/tapefs/mkfile | |
| t@@ -0,0 +1,13 @@ | |
| +<$PLAN9/src/mkhdr | |
| + | |
| +TARG=tarfs tpfs v6fs 32vfs cpiofs tapfs v10fs zipfs | |
| +OFILES=\ | |
| + fs.$O\ | |
| + util.$O\ | |
| + | |
| +HFILES=tapefs.h | |
| + | |
| +BIN=$BIN/fs | |
| +<$PLAN9/src/mkmany | |
| + | |
| +zipfs.$O: zip.h | |
| diff --git a/src/cmd/tapefs/tapefs.h b/src/cmd/tapefs/tapefs.h | |
| t@@ -0,0 +1,95 @@ | |
| +#define getpass tapefs_getpass | |
| + | |
| +#define g2byte(x) (((x)[1]<<8) + (x)[0]) /* littl… | |
| +#define g3byte(x) (((x)[2]<<16) + ((x)[1]<<8) + (x)[0]) | |
| +#define g4byte(x) (((x)[3]<<24) + ((x)[2]<<16) + ((x)[1]<<8) + (… | |
| + | |
| +enum | |
| +{ | |
| + OPERM = 0x3, /* mask of all permission types in … | |
| + Nram = 512, | |
| + Maxbuf = 8192, /* max buffer size */ | |
| +}; | |
| + | |
| +typedef struct Fid Fid; | |
| +typedef struct Ram Ram; | |
| + | |
| +struct Fid | |
| +{ | |
| + short busy; | |
| + short open; | |
| + short rclose; | |
| + int fid; | |
| + Fid *next; | |
| + char *user; | |
| + Ram *ram; | |
| +}; | |
| + | |
| +struct Ram | |
| +{ | |
| + char busy; | |
| + char open; | |
| + char replete; | |
| + Ram *parent; /* parent directory */ | |
| + Ram *child; /* first member of directory */ | |
| + Ram *next; /* next member of file's directory */ | |
| + Qid qid; | |
| + long perm; | |
| + char *name; | |
| + ulong atime; | |
| + ulong mtime; | |
| + char *user; | |
| + char *group; | |
| + vlong addr; | |
| + void *data; | |
| + long ndata; | |
| +}; | |
| + | |
| +enum | |
| +{ | |
| + Pexec = 1, | |
| + Pwrite = 2, | |
| + Pread = 4, | |
| + Pother = 1, | |
| + Pgroup = 8, | |
| + Powner = 64, | |
| +}; | |
| + | |
| +typedef struct idmap { | |
| + char *name; | |
| + int id; | |
| +} Idmap; | |
| + | |
| +typedef struct fileinf { | |
| + char *name; | |
| + vlong addr; | |
| + void *data; | |
| + vlong size; | |
| + int mode; | |
| + int uid; | |
| + int gid; | |
| + long mdate; | |
| +} Fileinf; | |
| + | |
| +extern ulong path; /* incremented for each new fi… | |
| +extern Ram *ram; | |
| +extern char *user; | |
| +extern Idmap *uidmap; | |
| +extern Idmap *gidmap; | |
| +extern int replete; | |
| +void error(char*); | |
| +void *erealloc(void*, ulong); | |
| +void *emalloc(ulong); | |
| +char *estrdup(char*); | |
| +void populate(char *); | |
| +void dotrunc(Ram*); | |
| +void docreate(Ram*); | |
| +char *doread(Ram*, vlong, long); | |
| +void dowrite(Ram*, char*, long, long); | |
| +int dopermw(Ram*); | |
| +Idmap *getpass(char*); | |
| +char *mapid(Idmap*,int); | |
| +Ram *poppath(Fileinf fi, int new); | |
| +Ram *popfile(Ram *dir, Fileinf fi); | |
| +void popdir(Ram*); | |
| +Ram *lookup(Ram*, char*); | |
| diff --git a/src/cmd/tapefs/tapfs.c b/src/cmd/tapefs/tapfs.c | |
| t@@ -0,0 +1,115 @@ | |
| +#include <u.h> | |
| +#include <libc.h> | |
| +#include "tapefs.h" | |
| + | |
| +/* | |
| + * File system for old tap tapes. | |
| + */ | |
| + | |
| +struct tap { | |
| + unsigned char name[32]; | |
| + unsigned char mode[1]; | |
| + unsigned char uid[1]; | |
| + unsigned char size[2]; | |
| + unsigned char tmod[4]; | |
| + unsigned char taddress[2]; | |
| + unsigned char unused[20]; | |
| + unsigned char checksum[2]; | |
| +} dir[192]; | |
| + | |
| +int tapefile; | |
| +char buffer[8192]; | |
| +long cvtime(unsigned char *); | |
| +extern int verbose; | |
| +extern int newtap; | |
| + | |
| +void | |
| +populate(char *name) | |
| +{ | |
| + int i, isabs; | |
| + struct tap *tpp; | |
| + Fileinf f; | |
| + | |
| + replete = 1; | |
| + tapefile = open(name, OREAD); | |
| + if (tapefile<0) | |
| + error("Can't open argument file"); | |
| + read(tapefile, dir, sizeof dir); | |
| + for (i=0, tpp=&dir[8]; i<192; i++, tpp++) { | |
| + unsigned char *sp = (unsigned char *)tpp; | |
| + int j, cksum = 0; | |
| + for (j=0; j<32; j++, sp+=2) | |
| + cksum += sp[0] + (sp[1]<<8); | |
| + cksum &= 0xFFFF; | |
| + if (cksum!=0) { | |
| + print("cksum failure\n"); | |
| + continue; | |
| + } | |
| + if (tpp->name[0]=='\0') | |
| + continue; | |
| + f.addr = tpp->taddress[0] + (tpp->taddress[1]<<8); | |
| + if (f.addr==0) | |
| + continue; | |
| + f.size = tpp->size[0] + (tpp->size[1]<<8); | |
| + f.mdate = cvtime(tpp->tmod); | |
| + f.mode = tpp->mode[0]&0777; | |
| + f.uid = tpp->uid[0]&0377; | |
| + isabs = tpp->name[0]=='/'; | |
| + f.name = (char *)tpp->name+isabs; | |
| + if (verbose) | |
| + print("%s mode %o uid %d, %s", f.name, f.mode, f.uid, … | |
| + poppath(f, 1); | |
| + } | |
| +} | |
| + | |
| +long | |
| +cvtime(unsigned char *tp) | |
| +{ | |
| + unsigned long t = (tp[1]<<24)+(tp[0]<<16)+(tp[3]<<8)+(tp[2]<<0); | |
| + if (!newtap) { | |
| + t /= 60; | |
| + t += 3*365*24*3600; | |
| + } | |
| + return t; | |
| +} | |
| + | |
| +void | |
| +popdir(Ram *r) | |
| +{ | |
| + USED(r); | |
| +} | |
| + | |
| +void | |
| +dotrunc(Ram *r) | |
| +{ | |
| + USED(r); | |
| +} | |
| + | |
| +void | |
| +docreate(Ram *r) | |
| +{ | |
| + USED(r); | |
| +} | |
| + | |
| +char * | |
| +doread(Ram *r, vlong off, long cnt) | |
| +{ | |
| + if (cnt>sizeof(buffer)) | |
| + print("count too big\n"); | |
| + seek(tapefile, 512*r->addr+off, 0); | |
| + read(tapefile, buffer, cnt); | |
| + return buffer; | |
| +} | |
| + | |
| +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; | |
| +} | |
| diff --git a/src/cmd/tapefs/tarfs.c b/src/cmd/tapefs/tarfs.c | |
| t@@ -0,0 +1,144 @@ | |
| +#include <u.h> | |
| +#include <libc.h> | |
| +#include <auth.h> | |
| +#include <fcall.h> | |
| +#include "tapefs.h" | |
| + | |
| +/* | |
| + * File system for tar tapes (read-only) | |
| + */ | |
| + | |
| +#define TBLOCK 512 | |
| +#define NBLOCK 40 /* maximum blocksize */ | |
| +#define DBLOCK 20 /* default blocksize */ | |
| +#define TNAMSIZ 100 | |
| + | |
| +union hblock { | |
| + char dummy[TBLOCK]; | |
| + char tbuf[Maxbuf]; | |
| + struct header { | |
| + char name[TNAMSIZ]; | |
| + char mode[8]; | |
| + char uid[8]; | |
| + char gid[8]; | |
| + char size[12]; | |
| + char mtime[12]; | |
| + char chksum[8]; | |
| + char linkflag; | |
| + char linkname[TNAMSIZ]; | |
| + } dbuf; | |
| +} dblock; | |
| + | |
| +int tapefile; | |
| +int checksum(void); | |
| + | |
| +void | |
| +populate(char *name) | |
| +{ | |
| + long blkno, isabs, chksum, linkflg; | |
| + Fileinf f; | |
| + | |
| + tapefile = open(name, OREAD); | |
| + if (tapefile<0) | |
| + error("Can't open argument file"); | |
| + replete = 1; | |
| + for (blkno = 0;;) { | |
| + seek(tapefile, TBLOCK*blkno, 0); | |
| + if (read(tapefile, dblock.dummy, sizeof(dblock.dummy))<sizeof(… | |
| + break; | |
| + if (dblock.dbuf.name[0]=='\0') | |
| + break; | |
| + f.addr = blkno+1; | |
| + f.mode = strtoul(dblock.dbuf.mode, 0, 8); | |
| + f.uid = strtoul(dblock.dbuf.uid, 0, 8); | |
| + f.gid = strtoul(dblock.dbuf.gid, 0, 8); | |
| + if((uchar)dblock.dbuf.size[0] == 0x80) | |
| + f.size = g8byte(dblock.dbuf.size+3); | |
| + else | |
| + f.size = strtoull(dblock.dbuf.size, 0, 8); | |
| + f.mdate = strtoul(dblock.dbuf.mtime, 0, 8); | |
| + chksum = strtoul(dblock.dbuf.chksum, 0, 8); | |
| + /* the mode test is ugly but sometimes necessary */ | |
| + if (dblock.dbuf.linkflag == '5' | |
| + || (f.mode&0170000) == 040000 | |
| + || strrchr(dblock.dbuf.name, '\0')[-1] == '/'){ | |
| + f.mode |= DMDIR; | |
| + f.size = 0; | |
| + } | |
| + f.mode &= DMDIR|0777; | |
| + linkflg = dblock.dbuf.linkflag=='s' || dblock.dbuf.linkflag=='… | |
| + isabs = dblock.dbuf.name[0]=='/'; | |
| + if (chksum != checksum()){ | |
| + fprint(1, "bad checksum on %.28s\n", dblock.dbuf.name); | |
| + exits("checksum"); | |
| + } | |
| + if (linkflg) { | |
| + /*fprint(2, "link %s->%s skipped\n", dblock.dbuf.name, | |
| + dblock.dbuf.linkname);*/ | |
| + f.size = 0; | |
| + blkno += 1; | |
| + continue; | |
| + } | |
| + f.name = dblock.dbuf.name+isabs; | |
| + if (f.name[0]=='\0') | |
| + fprint(1, "null name skipped\n"); | |
| + else | |
| + poppath(f, 1); | |
| + blkno += 1 + (f.size+TBLOCK-1)/TBLOCK; | |
| + } | |
| +} | |
| + | |
| +void | |
| +dotrunc(Ram *r) | |
| +{ | |
| + USED(r); | |
| +} | |
| + | |
| +void | |
| +docreate(Ram *r) | |
| +{ | |
| + USED(r); | |
| +} | |
| + | |
| +char * | |
| +doread(Ram *r, vlong off, long cnt) | |
| +{ | |
| + seek(tapefile, TBLOCK*r->addr+off, 0); | |
| + if (cnt>sizeof(dblock.tbuf)) | |
| + error("read too big"); | |
| + read(tapefile, dblock.tbuf, cnt); | |
| + return dblock.tbuf; | |
| +} | |
| + | |
| +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; | |
| +} | |
| + | |
| +int | |
| +checksum() | |
| +{ | |
| + int i; | |
| + char *cp; | |
| + | |
| + for (cp = dblock.dbuf.chksum; cp < &dblock.dbuf.chksum[sizeof(dblock.d… | |
| + *cp = ' '; | |
| + i = 0; | |
| + for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) | |
| + i += *cp&0xff; | |
| + return(i); | |
| +} | |
| diff --git a/src/cmd/tapefs/tpfs.c b/src/cmd/tapefs/tpfs.c | |
| t@@ -0,0 +1,108 @@ | |
| +#include <u.h> | |
| +#include <libc.h> | |
| +#include "tapefs.h" | |
| + | |
| +/* | |
| + * File system for tp tapes. dectape versions have 192 | |
| + * entries, magtape have 496. This treats the same | |
| + * by ignoring entries with bad header checksums | |
| + */ | |
| + | |
| +struct tp { | |
| + unsigned char name[32]; | |
| + unsigned char mode[2]; | |
| + unsigned char uid[1]; | |
| + unsigned char gid[1]; | |
| + unsigned char unused[1]; | |
| + unsigned char size[3]; | |
| + unsigned char tmod[4]; | |
| + unsigned char taddress[2]; | |
| + unsigned char unused2[16]; | |
| + unsigned char checksum[2]; | |
| +} dir[496+8]; | |
| + | |
| +char buffer[8192]; | |
| +int tapefile; | |
| + | |
| +void | |
| +populate(char *name) | |
| +{ | |
| + int i, isabs, badcksum, goodcksum; | |
| + struct tp *tpp; | |
| + Fileinf f; | |
| + | |
| + replete = 1; | |
| + tapefile = open(name, OREAD); | |
| + if (tapefile<0) | |
| + error("Can't open argument file"); | |
| + read(tapefile, dir, sizeof dir); | |
| + badcksum = goodcksum = 0; | |
| + for (i=0, tpp=&dir[8]; i<496; i++, tpp++) { | |
| + unsigned char *sp = (unsigned char *)tpp; | |
| + int j, cksum = 0; | |
| + for (j=0; j<32; j++, sp+=2) | |
| + cksum += sp[0] + (sp[1]<<8); | |
| + cksum &= 0xFFFF; | |
| + if (cksum!=0) { | |
| + badcksum++; | |
| + continue; | |
| + } | |
| + goodcksum++; | |
| + if (tpp->name[0]=='\0') | |
| + continue; | |
| + f.addr = tpp->taddress[0] + (tpp->taddress[1]<<8); | |
| + if (f.addr==0) | |
| + continue; | |
| + f.size = (tpp->size[0]<<16) + (tpp->size[1]<<0) + (tpp->size[2… | |
| + f.mdate = (tpp->tmod[2]<<0) + (tpp->tmod[3]<<8) | |
| + +(tpp->tmod[0]<<16) + (tpp->tmod[1]<<24); | |
| + f.mode = tpp->mode[0]&0777; | |
| + f.uid = tpp->uid[0]; | |
| + f.gid = tpp->gid[0]; | |
| + isabs = tpp->name[0]=='/'; | |
| + f.name = (char *)tpp->name+isabs; | |
| + poppath(f, 1); | |
| + } | |
| + fprint(2, "%d bad checksums, %d good\n", badcksum, goodcksum); | |
| +} | |
| + | |
| +void | |
| +popdir(Ram *r) | |
| +{ | |
| + USED(r); | |
| +} | |
| + | |
| +void | |
| +dotrunc(Ram *r) | |
| +{ | |
| + USED(r); | |
| +} | |
| + | |
| +void | |
| +docreate(Ram *r) | |
| +{ | |
| + USED(r); | |
| +} | |
| + | |
| +char * | |
| +doread(Ram *r, vlong off, long cnt) | |
| +{ | |
| + if (cnt>sizeof(buffer)) | |
| + print("count too big\n"); | |
| + seek(tapefile, 512*r->addr+off, 0); | |
| + read(tapefile, buffer, cnt); | |
| + return buffer; | |
| +} | |
| + | |
| +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; | |
| +} | |
| diff --git a/src/cmd/tapefs/util.c b/src/cmd/tapefs/util.c | |
| t@@ -0,0 +1,153 @@ | |
| +#include <u.h> | |
| +#include <libc.h> | |
| +#include <auth.h> | |
| +#include <fcall.h> | |
| +#include <bio.h> | |
| +#include "tapefs.h" | |
| + | |
| +Idmap * | |
| +getpass(char *file) | |
| +{ | |
| + Biobuf *bp; | |
| + char *cp; | |
| + Idmap *up; | |
| + int nid, maxid; | |
| + char *line[4]; | |
| + | |
| + if ((bp = Bopen(file, OREAD)) == 0) | |
| + error("Can't open passwd/group"); | |
| + up = emalloc(1*sizeof(Idmap)); | |
| + maxid = 1; | |
| + nid = 0; | |
| + while ((cp = Brdline(bp, '\n'))) { | |
| + int nf; | |
| + cp[Blinelen(bp)-1] = 0; | |
| + nf = getfields(cp, line, 3, 0, ":\n"); | |
| + if (nf<3) { | |
| + fprint(2, "bad format in %s\n", file); | |
| + break; | |
| + } | |
| + if (nid>=maxid) { | |
| + maxid *= 2; | |
| + up = (Idmap *)erealloc(up, maxid*sizeof(Idmap)); | |
| + } | |
| + up[nid].id = atoi(line[2]); | |
| + up[nid].name = strdup(line[0]); | |
| + nid++; | |
| + } | |
| + Bterm(bp); | |
| + up[nid].name = 0; | |
| + return up; | |
| +} | |
| + | |
| +char * | |
| +mapid(Idmap *up, int id) | |
| +{ | |
| + char buf[16]; | |
| + | |
| + if (up) | |
| + while (up->name){ | |
| + if (up->id==id) | |
| + return strdup(up->name); | |
| + up++; | |
| + } | |
| + sprint(buf, "%d", id); | |
| + return strdup(buf); | |
| +} | |
| + | |
| +Ram * | |
| +poppath(Fileinf fi, int new) | |
| +{ | |
| + char *suffix; | |
| + Ram *dir, *ent; | |
| + Fileinf f; | |
| + | |
| + if (*fi.name=='\0') | |
| + return 0; | |
| + if (suffix=strrchr(fi.name, '/')){ | |
| + *suffix = 0; | |
| + suffix++; | |
| + if (*suffix=='\0'){ | |
| + fi.mode |= DMDIR; | |
| + return poppath(fi, 1); | |
| + } | |
| + f = fi; | |
| + f.size = 0; | |
| + f.addr = 0; | |
| + f.mode = 0555|DMDIR; | |
| + dir = poppath(f, 0); | |
| + if (dir==0) | |
| + dir = ram; | |
| + } else { | |
| + suffix = fi.name; | |
| + dir = ram; | |
| + if (strcmp(suffix, ".")==0) | |
| + return dir; | |
| + } | |
| + ent = lookup(dir, suffix); | |
| + fi.mode |= 0400; /* at least user read */ | |
| + if (ent){ | |
| + if (((fi.mode&DMDIR)!=0) != ((ent->qid.type&QTDIR)!=0)){ | |
| + fprint(2, "%s/%s directory botch\n", fi.name, suffix); | |
| + exits(""); | |
| + } | |
| + if (new) { | |
| + ent->ndata = fi.size; | |
| + ent->addr = fi.addr; | |
| + ent->data = fi.data; | |
| + ent->perm = fi.mode; | |
| + ent->mtime = fi.mdate; | |
| + ent->user = mapid(uidmap, fi.uid); | |
| + ent->group = mapid(gidmap, fi.gid); | |
| + } | |
| + } else { | |
| + fi.name = suffix; | |
| + ent = popfile(dir, fi); | |
| + } | |
| + return ent; | |
| +} | |
| + | |
| +Ram * | |
| +popfile(Ram *dir, Fileinf fi) | |
| +{ | |
| + Ram *ent = (Ram *)emalloc(sizeof(Ram)); | |
| + if (*fi.name=='\0') | |
| + return 0; | |
| + ent->busy = 1; | |
| + ent->open = 0; | |
| + ent->parent = dir; | |
| + ent->next = dir->child; | |
| + dir->child = ent; | |
| + ent->child = 0; | |
| + ent->qid.path = ++path; | |
| + ent->qid.vers = 0; | |
| + if(fi.mode&DMDIR) | |
| + ent->qid.type = QTDIR; | |
| + else | |
| + ent->qid.type = QTFILE; | |
| + ent->perm = fi.mode; | |
| + ent->name = estrdup(fi.name); | |
| + ent->atime = ent->mtime = fi.mdate; | |
| + ent->user = mapid(uidmap, fi.uid); | |
| + ent->group = mapid(gidmap, fi.gid); | |
| + ent->ndata = fi.size; | |
| + ent->data = fi.data; | |
| + ent->addr = fi.addr; | |
| + ent->replete |= replete; | |
| + return ent; | |
| +} | |
| + | |
| +Ram * | |
| +lookup(Ram *dir, char *name) | |
| +{ | |
| + Ram *r; | |
| + | |
| + if (dir==0) | |
| + return 0; | |
| + for (r=dir->child; r; r=r->next){ | |
| + if (r->busy==0 || strcmp(r->name, name)!=0) | |
| + continue; | |
| + return r; | |
| + } | |
| + return 0; | |
| +} | |
| diff --git a/src/cmd/tapefs/v10fs.c b/src/cmd/tapefs/v10fs.c | |
| t@@ -0,0 +1,209 @@ | |
| +/* | |
| + * 10th edition 4K file system | |
| + */ | |
| +#include <u.h> | |
| +#include <libc.h> | |
| +#include <auth.h> | |
| +#include <fcall.h> | |
| +#include "tapefs.h" | |
| + | |
| +/* | |
| + * v10 disk inode | |
| + */ | |
| +#define VNADDR 13 | |
| +#define VFMT 0160000 | |
| +#define VIFREG 0100000 | |
| +#define VIFDIR 0040000 | |
| +#define VIFCHR 0120000 | |
| +#define VIFBLK 0160000 | |
| +#define VMODE 0777 | |
| +#define VSUPERB 1 | |
| +#define VROOT 2 /* root inode */ | |
| +#define VNAMELEN 14 | |
| +#define BLSIZE 4096 | |
| +#define LINOPB (BLSIZE/sizeof(struct v10dinode)) | |
| +#define LNINDIR (BLSIZE/sizeof(unsigned long)) | |
| + | |
| +struct v10dinode { | |
| + unsigned char flags[2]; | |
| + unsigned char nlinks[2]; | |
| + unsigned char uid[2]; | |
| + unsigned char gid[2]; | |
| + unsigned char size[4]; | |
| + unsigned char addr[40]; | |
| + unsigned char atime[4]; | |
| + unsigned char mtime[4]; | |
| + unsigned char ctime[4]; | |
| +}; | |
| + | |
| +struct v10dir { | |
| + uchar ino[2]; | |
| + char name[VNAMELEN]; | |
| +}; | |
| + | |
| +int tapefile; | |
| +Fileinf iget(int ino); | |
| +long bmap(Ram *r, long bno); | |
| +void getblk(Ram *r, long bno, char *buf); | |
| + | |
| +void | |
| +populate(char *name) | |
| +{ | |
| + Fileinf f; | |
| + | |
| + replete = 0; | |
| + tapefile = open(name, OREAD); | |
| + if (tapefile<0) | |
| + error("Can't open argument file"); | |
| + f = iget(VROOT); | |
| + ram->perm = f.mode; | |
| + ram->mtime = f.mdate; | |
| + ram->addr = f.addr; | |
| + ram->data = f.data; | |
| + ram->ndata = f.size; | |
| +} | |
| + | |
| +void | |
| +popdir(Ram *r) | |
| +{ | |
| + int i, ino; | |
| + char *cp; | |
| + struct v10dir *dp; | |
| + Fileinf f; | |
| + char name[VNAMELEN+1]; | |
| + | |
| + cp = 0; | |
| + for (i=0; i<r->ndata; i+=sizeof(struct v10dir)) { | |
| + if (i%BLSIZE==0) | |
| + cp = doread(r, i, BLSIZE); | |
| + dp = (struct v10dir *)(cp+i%BLSIZE); | |
| + ino = g2byte(dp->ino); | |
| + if (strcmp(dp->name, ".")==0 || strcmp(dp->name, "..")==0) | |
| + continue; | |
| + if (ino==0) | |
| + continue; | |
| + f = iget(ino); | |
| + strncpy(name, dp->name, VNAMELEN); | |
| + name[VNAMELEN+1] = '\0'; | |
| + f.name = name; | |
| + popfile(r, f); | |
| + } | |
| + r->replete = 1; | |
| +} | |
| + | |
| +void | |
| +dotrunc(Ram *r) | |
| +{ | |
| + USED(r); | |
| +} | |
| + | |
| +void | |
| +docreate(Ram *r) | |
| +{ | |
| + USED(r); | |
| +} | |
| + | |
| +char * | |
| +doread(Ram *r, vlong off, long cnt) | |
| +{ | |
| + static char buf[Maxbuf+BLSIZE]; | |
| + int bno, i; | |
| + | |
| + bno = off/BLSIZE; | |
| + off -= bno*BLSIZE; | |
| + if (cnt>Maxbuf) | |
| + error("count too large"); | |
| + if (off) | |
| + cnt += off; | |
| + i = 0; | |
| + while (cnt>0) { | |
| + getblk(r, bno, &buf[i*BLSIZE]); | |
| + cnt -= BLSIZE; | |
| + bno++; | |
| + i++; | |
| + } | |
| + return buf+off; | |
| +} | |
| + | |
| +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; | |
| +} | |
| + | |
| +/* | |
| + * fetch an i-node | |
| + * -- no sanity check for now | |
| + * -- magic inode-to-disk-block stuff here | |
| + */ | |
| + | |
| +Fileinf | |
| +iget(int ino) | |
| +{ | |
| + char buf[BLSIZE]; | |
| + struct v10dinode *dp; | |
| + long flags, i; | |
| + Fileinf f; | |
| + | |
| + seek(tapefile, BLSIZE*((ino-1)/LINOPB + VSUPERB + 1), 0); | |
| + if (read(tapefile, buf, BLSIZE) != BLSIZE) | |
| + error("Can't read inode"); | |
| + dp = ((struct v10dinode *)buf) + ((ino-1)%LINOPB); | |
| + flags = g2byte(dp->flags); | |
| + f.size = g4byte(dp->size); | |
| + if ((flags&VFMT)==VIFCHR || (flags&VFMT)==VIFBLK) | |
| + f.size = 0; | |
| + f.data = emalloc(VNADDR*sizeof(long)); | |
| + for (i = 0; i < VNADDR; i++) | |
| + ((long*)f.data)[i] = g3byte(dp->addr+3*i); | |
| + f.mode = flags & VMODE; | |
| + if ((flags&VFMT)==VIFDIR) | |
| + f.mode |= DMDIR; | |
| + f.uid = g2byte(dp->uid); | |
| + f.gid = g2byte(dp->gid); | |
| + f.mdate = g4byte(dp->mtime); | |
| + return f; | |
| +} | |
| + | |
| +void | |
| +getblk(Ram *r, long bno, char *buf) | |
| +{ | |
| + long dbno; | |
| + | |
| + if ((dbno = bmap(r, bno)) == 0) { | |
| + memset(buf, 0, BLSIZE); | |
| + return; | |
| + } | |
| + seek(tapefile, dbno*BLSIZE, 0); | |
| + if (read(tapefile, buf, BLSIZE) != BLSIZE) | |
| + error("bad read"); | |
| +} | |
| + | |
| +/* | |
| + * logical to physical block | |
| + * only singly-indirect files for now | |
| + */ | |
| + | |
| +long | |
| +bmap(Ram *r, long bno) | |
| +{ | |
| + unsigned char indbuf[LNINDIR][sizeof(long)]; | |
| + | |
| + if (bno < VNADDR-3) | |
| + return ((long*)r->data)[bno]; | |
| + if (bno < VNADDR*LNINDIR) { | |
| + seek(tapefile, ((long *)r->data)[(bno-(VNADDR-3))/LNINDIR+(VNA… | |
| + if (read(tapefile, (char *)indbuf, BLSIZE) != BLSIZE) | |
| + return 0; | |
| + return ((indbuf[(bno-(VNADDR-3))%LNINDIR][2]<<16) + (indbuf[(b… | |
| + + indbuf[(bno-(VNADDR-3))%LNINDIR][0]); | |
| + } | |
| + return 0; | |
| +} | |
| diff --git a/src/cmd/tapefs/v6fs.c b/src/cmd/tapefs/v6fs.c | |
| t@@ -0,0 +1,213 @@ | |
| +/* | |
| + * old (V6 and before) PDP-11 Unix filesystem | |
| + */ | |
| +#include <u.h> | |
| +#include <libc.h> | |
| +#include <auth.h> | |
| +#include <fcall.h> | |
| +#include "tapefs.h" | |
| + | |
| +/* | |
| + * v6 disk inode | |
| + */ | |
| +#define V6NADDR 8 | |
| +#define V6FMT 0160000 | |
| +#define V6IFREG 0100000 | |
| +#define V6IFDIR 0140000 | |
| +#define V6IFCHR 0120000 | |
| +#define V6IFBLK 0160000 | |
| +#define V6MODE 0777 | |
| +#define V6LARGE 010000 | |
| +#define V6SUPERB 1 | |
| +#define V6ROOT 1 /* root inode */ | |
| +#define V6NAMELEN 14 | |
| +#define BLSIZE 512 | |
| +#define LINOPB (BLSIZE/sizeof(struct v6dinode)) | |
| +#define LNINDIR (BLSIZE/sizeof(unsigned short)) | |
| + | |
| +struct v6dinode { | |
| + unsigned char flags[2]; | |
| + unsigned char nlinks; | |
| + unsigned char uid; | |
| + unsigned char gid; | |
| + unsigned char hisize; | |
| + unsigned char losize[2]; | |
| + unsigned char addr[V6NADDR][2]; | |
| + unsigned char atime[4]; /* pdp-11 order */ | |
| + unsigned char mtime[4]; /* pdp-11 order */ | |
| +}; | |
| + | |
| +struct v6dir { | |
| + uchar ino[2]; | |
| + char name[V6NAMELEN]; | |
| +}; | |
| + | |
| +int tapefile; | |
| +Fileinf iget(int ino); | |
| +long bmap(Ram *r, long bno); | |
| +void getblk(Ram *r, long bno, char *buf); | |
| + | |
| +void | |
| +populate(char *name) | |
| +{ | |
| + Fileinf f; | |
| + | |
| + replete = 0; | |
| + tapefile = open(name, OREAD); | |
| + if (tapefile<0) | |
| + error("Can't open argument file"); | |
| + f = iget(V6ROOT); | |
| + ram->perm = f.mode; | |
| + ram->mtime = f.mdate; | |
| + ram->addr = f.addr; | |
| + ram->data = f.data; | |
| + ram->ndata = f.size; | |
| +} | |
| + | |
| +void | |
| +popdir(Ram *r) | |
| +{ | |
| + int i, ino; | |
| + char *cp; | |
| + struct v6dir *dp; | |
| + Fileinf f; | |
| + char name[V6NAMELEN+1]; | |
| + | |
| + cp = 0; | |
| + for (i=0; i<r->ndata; i+=sizeof(struct v6dir)) { | |
| + if (i%BLSIZE==0) | |
| + cp = doread(r, i, BLSIZE); | |
| + dp = (struct v6dir *)(cp+i%BLSIZE); | |
| + ino = dp->ino[0] + (dp->ino[1]<<8); | |
| + if (strcmp(dp->name, ".")==0 || strcmp(dp->name, "..")==0) | |
| + continue; | |
| + if (ino==0) | |
| + continue; | |
| + f = iget(ino); | |
| + strncpy(name, dp->name, V6NAMELEN); | |
| + name[V6NAMELEN+1] = '\0'; | |
| + f.name = name; | |
| + popfile(r, f); | |
| + } | |
| + r->replete = 1; | |
| +} | |
| + | |
| +void | |
| +dotrunc(Ram *r) | |
| +{ | |
| + USED(r); | |
| +} | |
| + | |
| +void | |
| +docreate(Ram *r) | |
| +{ | |
| + USED(r); | |
| +} | |
| + | |
| +char * | |
| +doread(Ram *r, vlong off, long cnt) | |
| +{ | |
| + static char buf[Maxbuf+BLSIZE]; | |
| + int bno, i; | |
| + | |
| + bno = off/BLSIZE; | |
| + off -= bno*BLSIZE; | |
| + if (cnt>Maxbuf) | |
| + error("count too large"); | |
| + if (off) | |
| + cnt += off; | |
| + i = 0; | |
| + while (cnt>0) { | |
| + getblk(r, bno, &buf[i*BLSIZE]); | |
| + cnt -= BLSIZE; | |
| + bno++; | |
| + i++; | |
| + } | |
| + return buf; | |
| +} | |
| + | |
| +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; | |
| +} | |
| + | |
| +/* | |
| + * fetch an i-node | |
| + * -- no sanity check for now | |
| + * -- magic inode-to-disk-block stuff here | |
| + */ | |
| + | |
| +Fileinf | |
| +iget(int ino) | |
| +{ | |
| + char buf[BLSIZE]; | |
| + struct v6dinode *dp; | |
| + long flags, i; | |
| + Fileinf f; | |
| + | |
| + seek(tapefile, BLSIZE*((ino-1)/LINOPB + V6SUPERB + 1), 0); | |
| + if (read(tapefile, buf, BLSIZE) != BLSIZE) | |
| + error("Can't read inode"); | |
| + dp = ((struct v6dinode *)buf) + ((ino-1)%LINOPB); | |
| + flags = (dp->flags[1]<<8) + dp->flags[0]; | |
| + f.size = (dp->hisize << 16) + (dp->losize[1]<<8) + dp->losize[0]; | |
| + if ((flags&V6FMT)==V6IFCHR || (flags&V6FMT)==V6IFBLK) | |
| + f.size = 0; | |
| + f.data = emalloc(V6NADDR*sizeof(ushort)); | |
| + for (i = 0; i < V6NADDR; i++) | |
| + ((ushort*)f.data)[i] = (dp->addr[i][1]<<8) + dp->addr[i][0]; | |
| + f.mode = flags & V6MODE; | |
| + if ((flags&V6FMT)==V6IFDIR) | |
| + f.mode |= DMDIR; | |
| + f.uid = dp->uid; | |
| + f.gid = dp->gid; | |
| + f.mdate = (dp->mtime[2]<<0) + (dp->mtime[3]<<8) | |
| + +(dp->mtime[0]<<16) + (dp->mtime[1]<<24); | |
| + return f; | |
| +} | |
| + | |
| +void | |
| +getblk(Ram *r, long bno, char *buf) | |
| +{ | |
| + long dbno; | |
| + | |
| + if ((dbno = bmap(r, bno)) == 0) { | |
| + memset(buf, 0, BLSIZE); | |
| + return; | |
| + } | |
| + seek(tapefile, dbno*BLSIZE, 0); | |
| + if (read(tapefile, buf, BLSIZE) != BLSIZE) | |
| + error("bad read"); | |
| +} | |
| + | |
| +/* | |
| + * logical to physical block | |
| + * only singly-indirect files for now | |
| + */ | |
| + | |
| +long | |
| +bmap(Ram *r, long bno) | |
| +{ | |
| + unsigned char indbuf[LNINDIR][2]; | |
| + | |
| + if (r->ndata <= V6NADDR*BLSIZE) { /* assume size predicts large… | |
| + if (bno < V6NADDR) | |
| + return ((ushort*)r->data)[bno]; | |
| + return 0; | |
| + } | |
| + if (bno < V6NADDR*LNINDIR) { | |
| + seek(tapefile, ((ushort *)r->data)[bno/LNINDIR]*BLSIZE, 0); | |
| + if (read(tapefile, (char *)indbuf, BLSIZE) != BLSIZE) | |
| + return 0; | |
| + return ((indbuf[bno%LNINDIR][1]<<8) + indbuf[bno%LNINDIR][0]); | |
| + } | |
| + return 0; | |
| +} | |
| diff --git a/src/cmd/tapefs/zip.h b/src/cmd/tapefs/zip.h | |
| t@@ -0,0 +1,83 @@ | |
| +typedef struct ZipHead ZipHead; | |
| + | |
| +enum | |
| +{ | |
| + /* | |
| + * magic numbers | |
| + */ | |
| + ZHeader = 0x04034b50, | |
| + ZCHeader = 0x02014b50, | |
| + ZECHeader = 0x06054b50, | |
| + | |
| + /* | |
| + * "general purpose flag" bits | |
| + */ | |
| + ZEncrypted = 1 << 0, | |
| + ZTrailInfo = 1 << 3, /* uncsize, csize, and crc are in t… | |
| + ZCompPatch = 1 << 5, /* compression patched data */ | |
| + | |
| + ZCrcPoly = 0xedb88320, | |
| + | |
| + /* | |
| + * compression method | |
| + */ | |
| + ZDeflate = 8, | |
| + | |
| + /* | |
| + * internal file attributes | |
| + */ | |
| + ZIsText = 1 << 0, | |
| + | |
| + /* | |
| + * file attribute interpretation, from high byte of version | |
| + */ | |
| + ZDos = 0, | |
| + ZAmiga = 1, | |
| + ZVMS = 2, | |
| + ZUnix = 3, | |
| + ZVMCMS = 4, | |
| + ZAtariST = 5, | |
| + ZOS2HPFS = 6, | |
| + ZMac = 7, | |
| + ZZsys = 8, | |
| + ZCPM = 9, | |
| + ZNtfs = 10, | |
| + | |
| + /* | |
| + * external attribute flags for ZDos | |
| + */ | |
| + ZDROnly = 0x01, | |
| + ZDHidden = 0x02, | |
| + ZDSystem = 0x04, | |
| + ZDVLable = 0x08, | |
| + ZDDir = 0x10, | |
| + ZDArch = 0x20, | |
| + | |
| + ZHeadSize = 4 + 2 + 2 + 2 + 2 + 2 + 4 + 4 + 4 + 2 + 2, | |
| + ZHeadCrc = 4 + 2 + 2 + 2 + 2 + 2, | |
| + ZTrailSize = 4 + 4 + 4, | |
| + ZCHeadSize = 4 + 2 + 2 + 2 + 2 + 2 + 2 + 4 + 4 + 4 + 2 + 2 + 2 … | |
| + ZECHeadSize = 4 + 2 + 2 + 2 + 2 + 4 + 4 + 2, | |
| +}; | |
| + | |
| +/* | |
| + * interesting info from a zip header | |
| + */ | |
| +struct ZipHead | |
| +{ | |
| + int madeos; /* version made by */ | |
| + int madevers; | |
| + int extos; /* version needed to extract … | |
| + int extvers; | |
| + int flags; /* general purpose bit flag */ | |
| + int meth; | |
| + int modtime; | |
| + int moddate; | |
| + ulong crc; | |
| + ulong csize; | |
| + ulong uncsize; | |
| + int iattr; | |
| + ulong eattr; | |
| + ulong off; | |
| + char *file; | |
| +}; | |
| diff --git a/src/cmd/tapefs/zipfs.c b/src/cmd/tapefs/zipfs.c | |
| t@@ -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)? 04… | |
| + 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*))B… | |
| + 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] ==… | |
| + 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); | |
| +} | |
| + |