tapefs from plan9

This commit is contained in:
rsc 2006-02-24 21:17:00 +00:00
parent 21b291a64e
commit 64f7506b34
13 changed files with 2465 additions and 0 deletions

208
src/cmd/tapefs/32vfs.c Normal file
View file

@ -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]*BLSIZE, 0);
if (read(tapefile, (char *)indbuf, BLSIZE) != BLSIZE)
return 0;
return ((indbuf[bno%LNINDIR][1]<<8) + indbuf[bno%LNINDIR][0]);
}
return 0;
}

139
src/cmd/tapefs/cpiofs.c Normal file
View file

@ -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, "TRAILER!!!")==0)
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.namesize));
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;
}

600
src/cmd/tapefs/fs.c Normal file
View file

@ -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 minor */
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");
}

13
src/cmd/tapefs/mkfile Normal file
View file

@ -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

95
src/cmd/tapefs/tapefs.h Normal file
View file

@ -0,0 +1,95 @@
#define getpass tapefs_getpass
#define g2byte(x) (((x)[1]<<8) + (x)[0]) /* little-endian */
#define g3byte(x) (((x)[2]<<16) + ((x)[1]<<8) + (x)[0])
#define g4byte(x) (((x)[3]<<24) + ((x)[2]<<16) + ((x)[1]<<8) + (x)[0])
enum
{
OPERM = 0x3, /* mask of all permission types in open mode */
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 file */
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*);

115
src/cmd/tapefs/tapfs.c Normal file
View file

@ -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, ctime(f.mdate));
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;
}

144
src/cmd/tapefs/tarfs.c Normal file
View file

@ -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(dblock.dummy))
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=='1';
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.dbuf.chksum)]; cp++)
*cp = ' ';
i = 0;
for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
i += *cp&0xff;
return(i);
}

108
src/cmd/tapefs/tpfs.c Normal file
View file

@ -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]<<8);
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;
}

153
src/cmd/tapefs/util.c Normal file
View file

@ -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;
}

209
src/cmd/tapefs/v10fs.c Normal file
View file

@ -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+(VNADDR-3)]*BLSIZE, 0);
if (read(tapefile, (char *)indbuf, BLSIZE) != BLSIZE)
return 0;
return ((indbuf[(bno-(VNADDR-3))%LNINDIR][2]<<16) + (indbuf[(bno-(VNADDR-3))%LNINDIR][1]<<8)
+ indbuf[(bno-(VNADDR-3))%LNINDIR][0]);
}
return 0;
}

213
src/cmd/tapefs/v6fs.c Normal file
View file

@ -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 largeness of file */
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;
}

83
src/cmd/tapefs/zip.h Normal file
View file

@ -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 trailer */
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 + 2 + 2 + 4 + 4,
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;
};

385
src/cmd/tapefs/zipfs.c Normal file
View file

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