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