Introduction
Introduction Statistics Contact Development Disclaimer Help
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);
+}
+
You are viewing proxied material from mx1.adamsgaard.dk. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.