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