9660srv: import from Plan 9
This commit is contained in:
parent
29e9b5683e
commit
78a779a383
9 changed files with 2135 additions and 0 deletions
896
src/cmd/9660srv/9660srv.c
Normal file
896
src/cmd/9660srv/9660srv.c
Normal file
|
|
@ -0,0 +1,896 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <auth.h>
|
||||
#include <fcall.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "iso9660.h"
|
||||
|
||||
static void ireset(void);
|
||||
static int iattach(Xfile*);
|
||||
static void iclone(Xfile*, Xfile*);
|
||||
static void iwalkup(Xfile*);
|
||||
static void iwalk(Xfile*, char*);
|
||||
static void iopen(Xfile*, int);
|
||||
static void icreate(Xfile*, char*, long, int);
|
||||
static long ireaddir(Xfile*, uchar*, long, long);
|
||||
static long iread(Xfile*, char*, vlong, long);
|
||||
static long iwrite(Xfile*, char*, vlong, long);
|
||||
static void iclunk(Xfile*);
|
||||
static void iremove(Xfile*);
|
||||
static void istat(Xfile*, Dir*);
|
||||
static void iwstat(Xfile*, Dir*);
|
||||
|
||||
static char* nstr(uchar*, int);
|
||||
static char* rdate(uchar*, int);
|
||||
static int getcontin(Xdata*, uchar*, uchar**);
|
||||
static int getdrec(Xfile*, void*);
|
||||
static void ungetdrec(Xfile*);
|
||||
static int opendotdot(Xfile*, Xfile*);
|
||||
static int showdrec(int, int, void*);
|
||||
static long gtime(uchar*);
|
||||
static long l16(void*);
|
||||
static long l32(void*);
|
||||
static void newdrec(Xfile*, Drec*);
|
||||
static int rzdir(Xfs*, Dir*, int, Drec*);
|
||||
|
||||
Xfsub isosub =
|
||||
{
|
||||
ireset, iattach, iclone, iwalkup, iwalk, iopen, icreate,
|
||||
ireaddir, iread, iwrite, iclunk, iremove, istat, iwstat
|
||||
};
|
||||
|
||||
static void
|
||||
ireset(void)
|
||||
{}
|
||||
|
||||
static int
|
||||
iattach(Xfile *root)
|
||||
{
|
||||
Xfs *cd = root->xf;
|
||||
Iobuf *p; Voldesc *v; Isofile *fp; Drec *dp;
|
||||
int fmt, blksize, i, n, l, haveplan9;
|
||||
Iobuf *dirp;
|
||||
uchar dbuf[256];
|
||||
Drec *rd = (Drec *)dbuf;
|
||||
uchar *q, *s;
|
||||
|
||||
dirp = nil;
|
||||
blksize = 0;
|
||||
fmt = 0;
|
||||
dp = nil;
|
||||
haveplan9 = 0;
|
||||
for(i=VOLDESC;i<VOLDESC+100; i++){ /* +100 for sanity */
|
||||
p = getbuf(cd->d, i);
|
||||
v = (Voldesc*)(p->iobuf);
|
||||
if(memcmp(v->byte, "\01CD001\01", 7) == 0){ /* iso */
|
||||
if(dirp)
|
||||
putbuf(dirp);
|
||||
dirp = p;
|
||||
fmt = 'z';
|
||||
dp = (Drec*)v->z.desc.rootdir;
|
||||
blksize = l16(v->z.desc.blksize);
|
||||
chat("iso, blksize=%d...", blksize);
|
||||
|
||||
v = (Voldesc*)(dirp->iobuf);
|
||||
haveplan9 = (strncmp((char*)v->z.boot.sysid, "PLAN 9", 6)==0);
|
||||
if(haveplan9){
|
||||
if(noplan9) {
|
||||
chat("ignoring plan9");
|
||||
haveplan9 = 0;
|
||||
} else {
|
||||
fmt = '9';
|
||||
chat("plan9 iso...");
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if(memcmp(&v->byte[8], "\01CDROM\01", 7) == 0){ /* high sierra */
|
||||
if(dirp)
|
||||
putbuf(dirp);
|
||||
dirp = p;
|
||||
fmt = 'r';
|
||||
dp = (Drec*)v->r.desc.rootdir;
|
||||
blksize = l16(v->r.desc.blksize);
|
||||
chat("high sierra, blksize=%d...", blksize);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(haveplan9==0 && !nojoliet
|
||||
&& memcmp(v->byte, "\02CD001\01", 7) == 0){
|
||||
chat("%d %d\n", haveplan9, nojoliet);
|
||||
/*
|
||||
* The right thing to do is walk the escape sequences looking
|
||||
* for one of 25 2F 4[035], but Microsoft seems to not honor
|
||||
* the format, which makes it hard to walk over.
|
||||
*/
|
||||
q = v->z.desc.escapes;
|
||||
if(q[0] == 0x25 && q[1] == 0x2F && (q[2] == 0x40 || q[2] == 0x43 || q[2] == 0x45)){ /* Joliet, it appears */
|
||||
if(dirp)
|
||||
putbuf(dirp);
|
||||
dirp = p;
|
||||
fmt = 'J';
|
||||
dp = (Drec*)v->z.desc.rootdir;
|
||||
if(blksize != l16(v->z.desc.blksize))
|
||||
fprint(2, "warning: suspicious Joliet blocksize\n");
|
||||
chat("joliet...");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
putbuf(p);
|
||||
if(v->byte[0] == 0xFF)
|
||||
break;
|
||||
}
|
||||
|
||||
if(fmt == 0){
|
||||
if(dirp)
|
||||
putbuf(dirp);
|
||||
return -1;
|
||||
}
|
||||
assert(dirp != nil);
|
||||
|
||||
if(chatty)
|
||||
showdrec(2, fmt, dp);
|
||||
if(blksize > Sectorsize){
|
||||
chat("blksize too big...");
|
||||
putbuf(dirp);
|
||||
return -1;
|
||||
}
|
||||
if(waserror()){
|
||||
putbuf(dirp);
|
||||
nexterror();
|
||||
}
|
||||
root->len = sizeof(Isofile) - sizeof(Drec) + dp->reclen;
|
||||
root->ptr = fp = ealloc(root->len);
|
||||
|
||||
if(haveplan9)
|
||||
root->xf->isplan9 = 1;
|
||||
|
||||
fp->fmt = fmt;
|
||||
fp->blksize = blksize;
|
||||
fp->offset = 0;
|
||||
fp->doffset = 0;
|
||||
memmove(&fp->d, dp, dp->reclen);
|
||||
root->qid.path = l32(dp->addr);
|
||||
root->qid.type = QTDIR;
|
||||
putbuf(dirp);
|
||||
poperror();
|
||||
if(getdrec(root, rd) >= 0){
|
||||
n = rd->reclen-(34+rd->namelen);
|
||||
s = (uchar*)rd->name + rd->namelen;
|
||||
if((uintptr)s & 1){
|
||||
s++;
|
||||
n--;
|
||||
}
|
||||
if(n >= 7 && s[0] == 'S' && s[1] == 'P' && s[2] == 7 &&
|
||||
s[3] == 1 && s[4] == 0xBE && s[5] == 0xEF){
|
||||
root->xf->issusp = 1;
|
||||
root->xf->suspoff = s[6];
|
||||
n -= root->xf->suspoff;
|
||||
s += root->xf->suspoff;
|
||||
for(; n >= 4; s += l, n -= l){
|
||||
l = s[2];
|
||||
if(s[0] == 'E' && s[1] == 'R'){
|
||||
if(!norock && s[4] == 10 && memcmp(s+8, "RRIP_1991A", 10) == 0)
|
||||
root->xf->isrock = 1;
|
||||
break;
|
||||
} else if(s[0] == 'C' && s[1] == 'E' && s[2] >= 28){
|
||||
n = getcontin(root->xf->d, s, &s);
|
||||
continue;
|
||||
} else if(s[0] == 'R' && s[1] == 'R'){
|
||||
if(!norock)
|
||||
root->xf->isrock = 1;
|
||||
break;
|
||||
} else if(s[0] == 'S' && s[1] == 'T')
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(root->xf->isrock)
|
||||
chat("Rock Ridge...");
|
||||
fp->offset = 0;
|
||||
fp->doffset = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
iclone(Xfile *of, Xfile *nf)
|
||||
{
|
||||
USED(of);
|
||||
USED(nf);
|
||||
}
|
||||
|
||||
static void
|
||||
iwalkup(Xfile *f)
|
||||
{
|
||||
long paddr;
|
||||
uchar dbuf[256];
|
||||
Drec *d = (Drec *)dbuf;
|
||||
Xfile pf, ppf;
|
||||
Isofile piso, ppiso;
|
||||
|
||||
memset(&pf, 0, sizeof pf);
|
||||
memset(&ppf, 0, sizeof ppf);
|
||||
pf.ptr = &piso;
|
||||
ppf.ptr = &ppiso;
|
||||
if(opendotdot(f, &pf) < 0)
|
||||
error("can't open pf");
|
||||
paddr = l32(pf.ptr->d.addr);
|
||||
if(l32(f->ptr->d.addr) == paddr)
|
||||
return;
|
||||
if(opendotdot(&pf, &ppf) < 0)
|
||||
error("can't open ppf");
|
||||
while(getdrec(&ppf, d) >= 0){
|
||||
if(l32(d->addr) == paddr){
|
||||
newdrec(f, d);
|
||||
f->qid.path = paddr;
|
||||
f->qid.type = QTDIR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
error("can't find addr of ..");
|
||||
}
|
||||
|
||||
static int
|
||||
casestrcmp(int isplan9, char *a, char *b)
|
||||
{
|
||||
int ca, cb;
|
||||
|
||||
if(isplan9)
|
||||
return strcmp(a, b);
|
||||
for(;;) {
|
||||
ca = *a++;
|
||||
cb = *b++;
|
||||
if(ca >= 'A' && ca <= 'Z')
|
||||
ca += 'a' - 'A';
|
||||
if(cb >= 'A' && cb <= 'Z')
|
||||
cb += 'a' - 'A';
|
||||
if(ca != cb) {
|
||||
if(ca > cb)
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
if(ca == 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
iwalk(Xfile *f, char *name)
|
||||
{
|
||||
Isofile *ip = f->ptr;
|
||||
uchar dbuf[256];
|
||||
char nbuf[4*Maxname];
|
||||
Drec *d = (Drec*)dbuf;
|
||||
Dir dir;
|
||||
char *p;
|
||||
int len, vers, dvers;
|
||||
|
||||
vers = -1;
|
||||
if(p = strchr(name, ';')) { /* assign = */
|
||||
len = p-name;
|
||||
if(len >= Maxname)
|
||||
len = Maxname-1;
|
||||
memmove(nbuf, name, len);
|
||||
vers = strtoul(p+1, 0, 10);
|
||||
name = nbuf;
|
||||
}
|
||||
/*
|
||||
len = strlen(name);
|
||||
if(len >= Maxname){
|
||||
len = Maxname-1;
|
||||
if(name != nbuf){
|
||||
memmove(nbuf, name, len);
|
||||
name = nbuf;
|
||||
}
|
||||
name[len] = 0;
|
||||
}
|
||||
*/
|
||||
|
||||
chat("%d \"%s\"...", strlen(name), name);
|
||||
ip->offset = 0;
|
||||
setnames(&dir, nbuf);
|
||||
while(getdrec(f, d) >= 0) {
|
||||
dvers = rzdir(f->xf, &dir, ip->fmt, d);
|
||||
if(casestrcmp(f->xf->isplan9||f->xf->isrock, name, dir.name) != 0)
|
||||
continue;
|
||||
newdrec(f, d);
|
||||
f->qid.path = dir.qid.path;
|
||||
f->qid.type = dir.qid.type;
|
||||
USED(dvers);
|
||||
return;
|
||||
}
|
||||
USED(vers);
|
||||
error(Enonexist);
|
||||
}
|
||||
|
||||
static void
|
||||
iopen(Xfile *f, int mode)
|
||||
{
|
||||
mode &= ~OCEXEC;
|
||||
if(mode != OREAD && mode != OEXEC)
|
||||
error(Eperm);
|
||||
f->ptr->offset = 0;
|
||||
f->ptr->doffset = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
icreate(Xfile *f, char *name, long perm, int mode)
|
||||
{
|
||||
USED(f);
|
||||
USED(name);
|
||||
USED(perm);
|
||||
USED(mode);
|
||||
error(Eperm);
|
||||
}
|
||||
|
||||
static long
|
||||
ireaddir(Xfile *f, uchar *buf, long offset, long count)
|
||||
{
|
||||
Isofile *ip = f->ptr;
|
||||
Dir d;
|
||||
char names[4*Maxname];
|
||||
uchar dbuf[256];
|
||||
Drec *drec = (Drec *)dbuf;
|
||||
int n, rcnt;
|
||||
|
||||
if(offset==0){
|
||||
ip->offset = 0;
|
||||
ip->doffset = 0;
|
||||
}else if(offset != ip->doffset)
|
||||
error("seek in directory not allowed");
|
||||
|
||||
rcnt = 0;
|
||||
setnames(&d, names);
|
||||
while(rcnt < count && getdrec(f, drec) >= 0){
|
||||
if(drec->namelen == 1){
|
||||
if(drec->name[0] == 0)
|
||||
continue;
|
||||
if(drec->name[0] == 1)
|
||||
continue;
|
||||
}
|
||||
rzdir(f->xf, &d, ip->fmt, drec);
|
||||
d.qid.vers = f->qid.vers;
|
||||
if((n = convD2M(&d, buf+rcnt, count-rcnt)) <= BIT16SZ){
|
||||
ungetdrec(f);
|
||||
break;
|
||||
}
|
||||
rcnt += n;
|
||||
}
|
||||
ip->doffset += rcnt;
|
||||
return rcnt;
|
||||
}
|
||||
|
||||
static long
|
||||
iread(Xfile *f, char *buf, vlong offset, long count)
|
||||
{
|
||||
int n, o, rcnt = 0;
|
||||
long size;
|
||||
vlong addr;
|
||||
Isofile *ip = f->ptr;
|
||||
Iobuf *p;
|
||||
|
||||
size = l32(ip->d.size);
|
||||
if(offset >= size)
|
||||
return 0;
|
||||
if(offset+count > size)
|
||||
count = size - offset;
|
||||
addr = ((vlong)l32(ip->d.addr) + ip->d.attrlen)*ip->blksize + offset;
|
||||
o = addr % Sectorsize;
|
||||
addr /= Sectorsize;
|
||||
/*chat("d.addr=%ld, addr=%lld, o=%d...", l32(ip->d.addr), addr, o);*/
|
||||
n = Sectorsize - o;
|
||||
|
||||
while(count > 0){
|
||||
if(n > count)
|
||||
n = count;
|
||||
p = getbuf(f->xf->d, addr);
|
||||
memmove(&buf[rcnt], &p->iobuf[o], n);
|
||||
putbuf(p);
|
||||
count -= n;
|
||||
rcnt += n;
|
||||
++addr;
|
||||
o = 0;
|
||||
n = Sectorsize;
|
||||
}
|
||||
return rcnt;
|
||||
}
|
||||
|
||||
static long
|
||||
iwrite(Xfile *f, char *buf, vlong offset, long count)
|
||||
{
|
||||
USED(f);
|
||||
USED(buf);
|
||||
USED(offset);
|
||||
USED(count);
|
||||
error(Eperm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
iclunk(Xfile *f)
|
||||
{
|
||||
USED(f);
|
||||
}
|
||||
|
||||
static void
|
||||
iremove(Xfile *f)
|
||||
{
|
||||
USED(f);
|
||||
error(Eperm);
|
||||
}
|
||||
|
||||
static void
|
||||
istat(Xfile *f, Dir *d)
|
||||
{
|
||||
Isofile *ip = f->ptr;
|
||||
|
||||
rzdir(f->xf, d, ip->fmt, &ip->d);
|
||||
d->qid.vers = f->qid.vers;
|
||||
if(d->qid.path==f->xf->rootqid.path){
|
||||
d->qid.path = 0;
|
||||
d->qid.type = QTDIR;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
iwstat(Xfile *f, Dir *d)
|
||||
{
|
||||
USED(f);
|
||||
USED(d);
|
||||
error(Eperm);
|
||||
}
|
||||
|
||||
static int
|
||||
showdrec(int fd, int fmt, void *x)
|
||||
{
|
||||
Drec *d = (Drec *)x;
|
||||
int namelen;
|
||||
int syslen;
|
||||
|
||||
if(d->reclen == 0)
|
||||
return 0;
|
||||
fprint(fd, "%d %d %ld %ld ",
|
||||
d->reclen, d->attrlen, l32(d->addr), l32(d->size));
|
||||
fprint(fd, "%s 0x%2.2x %d %d %ld ",
|
||||
rdate(d->date, fmt), (fmt=='z' ? d->flags : d->r_flags),
|
||||
d->unitsize, d->gapsize, l16(d->vseqno));
|
||||
fprint(fd, "%d %s", d->namelen, nstr(d->name, d->namelen));
|
||||
if(fmt != 'J'){
|
||||
namelen = d->namelen + (1-(d->namelen&1));
|
||||
syslen = d->reclen - 33 - namelen;
|
||||
if(syslen != 0)
|
||||
fprint(fd, " %s", nstr(&d->name[namelen], syslen));
|
||||
}
|
||||
fprint(fd, "\n");
|
||||
return d->reclen + (d->reclen&1);
|
||||
}
|
||||
|
||||
static void
|
||||
newdrec(Xfile *f, Drec *dp)
|
||||
{
|
||||
Isofile *x = f->ptr;
|
||||
Isofile *n;
|
||||
int len;
|
||||
|
||||
len = sizeof(Isofile) - sizeof(Drec) + dp->reclen;
|
||||
n = ealloc(len);
|
||||
n->fmt = x->fmt;
|
||||
n->blksize = x->blksize;
|
||||
n->offset = 0;
|
||||
n->doffset = 0;
|
||||
memmove(&n->d, dp, dp->reclen);
|
||||
free(x);
|
||||
f->ptr = n;
|
||||
f->len = len;
|
||||
}
|
||||
|
||||
static void
|
||||
ungetdrec(Xfile *f)
|
||||
{
|
||||
Isofile *ip = f->ptr;
|
||||
|
||||
if(ip->offset >= ip->odelta){
|
||||
ip->offset -= ip->odelta;
|
||||
ip->odelta = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
getdrec(Xfile *f, void *buf)
|
||||
{
|
||||
Isofile *ip = f->ptr;
|
||||
int len = 0, boff = 0;
|
||||
ulong size;
|
||||
vlong addr;
|
||||
Iobuf *p = 0;
|
||||
|
||||
if(!ip)
|
||||
return -1;
|
||||
size = l32(ip->d.size);
|
||||
while(ip->offset < size){
|
||||
addr = (l32(ip->d.addr)+ip->d.attrlen)*ip->blksize + ip->offset;
|
||||
boff = addr % Sectorsize;
|
||||
if(boff > Sectorsize-34){
|
||||
ip->offset += Sectorsize-boff;
|
||||
continue;
|
||||
}
|
||||
p = getbuf(f->xf->d, addr/Sectorsize);
|
||||
len = p->iobuf[boff];
|
||||
if(len >= 34)
|
||||
break;
|
||||
putbuf(p);
|
||||
p = 0;
|
||||
ip->offset += Sectorsize-boff;
|
||||
}
|
||||
if(p) {
|
||||
memmove(buf, &p->iobuf[boff], len);
|
||||
putbuf(p);
|
||||
ip->odelta = len + (len&1);
|
||||
ip->offset += ip->odelta;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
opendotdot(Xfile *f, Xfile *pf)
|
||||
{
|
||||
uchar dbuf[256];
|
||||
Drec *d = (Drec *)dbuf;
|
||||
Isofile *ip = f->ptr, *pip = pf->ptr;
|
||||
|
||||
ip->offset = 0;
|
||||
if(getdrec(f, d) < 0){
|
||||
chat("opendotdot: getdrec(.) failed...");
|
||||
return -1;
|
||||
}
|
||||
if(d->namelen != 1 || d->name[0] != 0){
|
||||
chat("opendotdot: no . entry...");
|
||||
return -1;
|
||||
}
|
||||
if(l32(d->addr) != l32(ip->d.addr)){
|
||||
chat("opendotdot: bad . address...");
|
||||
return -1;
|
||||
}
|
||||
if(getdrec(f, d) < 0){
|
||||
chat("opendotdot: getdrec(..) failed...");
|
||||
return -1;
|
||||
}
|
||||
if(d->namelen != 1 || d->name[0] != 1){
|
||||
chat("opendotdot: no .. entry...");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pf->xf = f->xf;
|
||||
pip->fmt = ip->fmt;
|
||||
pip->blksize = ip->blksize;
|
||||
pip->offset = 0;
|
||||
pip->doffset = 0;
|
||||
pip->d = *d;
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum {
|
||||
Hname = 1,
|
||||
Hmode = 2,
|
||||
};
|
||||
|
||||
static int
|
||||
rzdir(Xfs *fs, Dir *d, int fmt, Drec *dp)
|
||||
{
|
||||
int n, flags, i, j, lj, nl, vers, sysl, mode, l, have;
|
||||
uchar *s;
|
||||
char *p;
|
||||
char buf[Maxname+UTFmax+1];
|
||||
uchar *q;
|
||||
Rune r;
|
||||
enum { ONAMELEN = 28 }; /* old Plan 9 directory name length */
|
||||
|
||||
have = 0;
|
||||
flags = 0;
|
||||
vers = -1;
|
||||
d->qid.path = l32(dp->addr);
|
||||
d->qid.type = 0;
|
||||
d->qid.vers = 0;
|
||||
n = dp->namelen;
|
||||
memset(d->name, 0, Maxname);
|
||||
if(n == 1) {
|
||||
switch(dp->name[0]){
|
||||
case 1:
|
||||
d->name[1] = '.';
|
||||
/* fall through */
|
||||
case 0:
|
||||
d->name[0] = '.';
|
||||
have = Hname;
|
||||
break;
|
||||
default:
|
||||
d->name[0] = tolower(dp->name[0]);
|
||||
}
|
||||
} else {
|
||||
if(fmt == 'J'){ /* Joliet, 16-bit Unicode */
|
||||
q = (uchar*)dp->name;
|
||||
for(i=j=lj=0; i<n && j<Maxname; i+=2){
|
||||
lj = j;
|
||||
r = (q[i]<<8)|q[i+1];
|
||||
j += runetochar(buf+j, &r);
|
||||
}
|
||||
if(j >= Maxname)
|
||||
j = lj;
|
||||
memmove(d->name, buf, j);
|
||||
}else{
|
||||
if(n >= Maxname)
|
||||
n = Maxname-1;
|
||||
for(i=0; i<n; i++)
|
||||
d->name[i] = tolower(dp->name[i]);
|
||||
}
|
||||
}
|
||||
|
||||
sysl = dp->reclen-(34+dp->namelen);
|
||||
s = (uchar*)dp->name + dp->namelen;
|
||||
if(((uintptr)s) & 1) {
|
||||
s++;
|
||||
sysl--;
|
||||
}
|
||||
if(fs->isplan9 && sysl > 0) {
|
||||
/*
|
||||
* get gid, uid, mode and possibly name
|
||||
* from plan9 directory extension
|
||||
*/
|
||||
nl = *s;
|
||||
if(nl >= ONAMELEN)
|
||||
nl = ONAMELEN-1;
|
||||
if(nl) {
|
||||
memset(d->name, 0, ONAMELEN);
|
||||
memmove(d->name, s+1, nl);
|
||||
}
|
||||
s += 1 + *s;
|
||||
nl = *s;
|
||||
if(nl >= ONAMELEN)
|
||||
nl = ONAMELEN-1;
|
||||
memset(d->uid, 0, ONAMELEN);
|
||||
memmove(d->uid, s+1, nl);
|
||||
s += 1 + *s;
|
||||
nl = *s;
|
||||
if(nl >= ONAMELEN)
|
||||
nl = ONAMELEN-1;
|
||||
memset(d->gid, 0, ONAMELEN);
|
||||
memmove(d->gid, s+1, nl);
|
||||
s += 1 + *s;
|
||||
if(((uintptr)s) & 1)
|
||||
s++;
|
||||
d->mode = l32(s);
|
||||
if(d->mode & DMDIR)
|
||||
d->qid.type |= QTDIR;
|
||||
} else {
|
||||
d->mode = 0444;
|
||||
switch(fmt) {
|
||||
case 'z':
|
||||
if(fs->isrock)
|
||||
strcpy(d->gid, "ridge");
|
||||
else
|
||||
strcpy(d->gid, "iso9660");
|
||||
flags = dp->flags;
|
||||
break;
|
||||
case 'r':
|
||||
strcpy(d->gid, "sierra");
|
||||
flags = dp->r_flags;
|
||||
break;
|
||||
case 'J':
|
||||
strcpy(d->gid, "joliet");
|
||||
flags = dp->flags;
|
||||
break;
|
||||
case '9':
|
||||
strcpy(d->gid, "plan9");
|
||||
flags = dp->flags;
|
||||
break;
|
||||
}
|
||||
if(flags & 0x02){
|
||||
d->qid.type |= QTDIR;
|
||||
d->mode |= DMDIR|0111;
|
||||
}
|
||||
strcpy(d->uid, "cdrom");
|
||||
if(fmt!='9' && !(d->mode&DMDIR)){
|
||||
/*
|
||||
* ISO 9660 actually requires that you always have a . and a ;,
|
||||
* even if there is no version and no extension. Very few writers
|
||||
* do this. If the version is present, we use it for qid.vers.
|
||||
* If there is no extension but there is a dot, we strip it off.
|
||||
* (VMS heads couldn't comprehend the dot as a file name character
|
||||
* rather than as just a separator between name and extension.)
|
||||
*
|
||||
* We don't do this for directory names because directories are
|
||||
* not allowed to have extensions and versions.
|
||||
*/
|
||||
if((p=strchr(d->name, ';')) != nil){
|
||||
vers = strtoul(p+1, 0, 0);
|
||||
d->qid.vers = vers;
|
||||
*p = '\0';
|
||||
}
|
||||
if((p=strchr(d->name, '.')) != nil && *(p+1)=='\0')
|
||||
*p = '\0';
|
||||
}
|
||||
if(fs->issusp){
|
||||
nl = 0;
|
||||
s += fs->suspoff;
|
||||
sysl -= fs->suspoff;
|
||||
for(; sysl >= 4 && have != (Hname|Hmode); sysl -= l, s += l){
|
||||
if(s[0] == 0 && ((uintptr)s & 1)){
|
||||
/* MacOS pads individual entries, contrary to spec */
|
||||
s++;
|
||||
sysl--;
|
||||
}
|
||||
l = s[2];
|
||||
if(s[0] == 'P' && s[1] == 'X' && s[3] == 1){
|
||||
/* posix file attributes */
|
||||
mode = l32(s+4);
|
||||
d->mode = mode & 0777;
|
||||
if((mode & 0170000) == 040000){
|
||||
d->mode |= DMDIR;
|
||||
d->qid.type |= QTDIR;
|
||||
}
|
||||
have |= Hmode;
|
||||
} else if(s[0] == 'N' && s[1] == 'M' && s[3] == 1){
|
||||
/* alternative name */
|
||||
if((s[4] & ~1) == 0){
|
||||
i = nl+l-5;
|
||||
if(i >= Maxname)
|
||||
i = Maxname-1;
|
||||
if((i -= nl) > 0){
|
||||
memmove(d->name+nl, s+5, i);
|
||||
nl += i;
|
||||
}
|
||||
if(s[4] == 0)
|
||||
have |= Hname;
|
||||
}
|
||||
} else if(s[0] == 'C' && s[1] == 'E' && s[2] >= 28){
|
||||
sysl = getcontin(fs->d, s, &s);
|
||||
continue;
|
||||
} else if(s[0] == 'S' && s[1] == 'T')
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
d->length = 0;
|
||||
if((d->mode & DMDIR) == 0)
|
||||
d->length = l32(dp->size);
|
||||
d->type = 0;
|
||||
d->dev = 0;
|
||||
d->atime = gtime(dp->date);
|
||||
d->mtime = d->atime;
|
||||
return vers;
|
||||
}
|
||||
|
||||
static int
|
||||
getcontin(Xdata *dev, uchar *p, uchar **s)
|
||||
{
|
||||
long bn, off, len;
|
||||
Iobuf *b;
|
||||
|
||||
bn = l32(p+4);
|
||||
off = l32(p+12);
|
||||
len = l32(p+20);
|
||||
chat("getcontin %d...", bn);
|
||||
b = getbuf(dev, bn);
|
||||
if(b == 0){
|
||||
*s = 0;
|
||||
return 0;
|
||||
}
|
||||
*s = b->iobuf+off;
|
||||
putbuf(b);
|
||||
return len;
|
||||
}
|
||||
|
||||
static char *
|
||||
nstr(uchar *p, int n)
|
||||
{
|
||||
static char buf[132];
|
||||
char *q = buf;
|
||||
|
||||
while(--n >= 0){
|
||||
if(*p == '\\')
|
||||
*q++ = '\\';
|
||||
if(' ' <= *p && *p <= '~')
|
||||
*q++ = *p++;
|
||||
else
|
||||
q += sprint(q, "\\%2.2ux", *p++);
|
||||
}
|
||||
*q = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
static char *
|
||||
rdate(uchar *p, int fmt)
|
||||
{
|
||||
static char buf[64];
|
||||
int htz, s, n;
|
||||
|
||||
n = sprint(buf, "%2.2d.%2.2d.%2.2d %2.2d:%2.2d:%2.2d",
|
||||
p[0], p[1], p[2], p[3], p[4], p[5]);
|
||||
if(fmt == 'z'){
|
||||
htz = p[6];
|
||||
if(htz >= 128){
|
||||
htz = 256-htz;
|
||||
s = '-';
|
||||
}else
|
||||
s = '+';
|
||||
sprint(&buf[n], " (%c%.1f)", s, (float)htz/2);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
static char
|
||||
dmsize[12] =
|
||||
{
|
||||
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
|
||||
};
|
||||
|
||||
#define dysize mydysize
|
||||
|
||||
static int
|
||||
dysize(int y)
|
||||
{
|
||||
|
||||
if((y%4) == 0)
|
||||
return 366;
|
||||
return 365;
|
||||
}
|
||||
|
||||
static long
|
||||
gtime(uchar *p) /* yMdhmsz */
|
||||
{
|
||||
long t;
|
||||
int i, y, M, d, h, m, s, tz;
|
||||
|
||||
y=p[0]; M=p[1]; d=p[2];
|
||||
h=p[3]; m=p[4]; s=p[5]; tz=p[6];
|
||||
USED(tz);
|
||||
y += 1900;
|
||||
if (y < 1970)
|
||||
return 0;
|
||||
if (M < 1 || M > 12)
|
||||
return 0;
|
||||
if (d < 1 || d > dmsize[M-1])
|
||||
if (!(M == 2 && d == 29 && dysize(y) == 366))
|
||||
return 0;
|
||||
if (h > 23)
|
||||
return 0;
|
||||
if (m > 59)
|
||||
return 0;
|
||||
if (s > 59)
|
||||
return 0;
|
||||
t = 0;
|
||||
for(i=1970; i<y; i++)
|
||||
t += dysize(i);
|
||||
if (dysize(y)==366 && M >= 3)
|
||||
t++;
|
||||
while(--M)
|
||||
t += dmsize[M-1];
|
||||
t += d-1;
|
||||
t = 24*t + h;
|
||||
t = 60*t + m;
|
||||
t = 60*t + s;
|
||||
return t;
|
||||
}
|
||||
|
||||
#define p ((uchar*)arg)
|
||||
|
||||
static long
|
||||
l16(void *arg)
|
||||
{
|
||||
long v;
|
||||
|
||||
v = ((long)p[1]<<8)|p[0];
|
||||
if (v >= 0x8000L)
|
||||
v -= 0x10000L;
|
||||
return v;
|
||||
}
|
||||
|
||||
static long
|
||||
l32(void *arg)
|
||||
{
|
||||
return ((((((long)p[3]<<8)|p[2])<<8)|p[1])<<8)|p[0];
|
||||
}
|
||||
|
||||
#undef p
|
||||
118
src/cmd/9660srv/dat.h
Normal file
118
src/cmd/9660srv/dat.h
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
typedef struct Ioclust Ioclust;
|
||||
typedef struct Iobuf Iobuf;
|
||||
typedef struct Isofile Isofile;
|
||||
typedef struct Xdata Xdata;
|
||||
typedef struct Xfile Xfile;
|
||||
typedef struct Xfs Xfs;
|
||||
typedef struct Xfsub Xfsub;
|
||||
|
||||
#pragma incomplete Isofile
|
||||
|
||||
enum
|
||||
{
|
||||
Sectorsize = 2048,
|
||||
Maxname = 256,
|
||||
};
|
||||
|
||||
struct Iobuf
|
||||
{
|
||||
Ioclust* clust;
|
||||
long addr;
|
||||
uchar* iobuf;
|
||||
};
|
||||
|
||||
struct Ioclust
|
||||
{
|
||||
long addr; /* in sectors; good to 8TB */
|
||||
Xdata* dev;
|
||||
Ioclust* next;
|
||||
Ioclust* prev;
|
||||
int busy;
|
||||
int nbuf;
|
||||
Iobuf* buf;
|
||||
uchar* iobuf;
|
||||
};
|
||||
|
||||
struct Xdata
|
||||
{
|
||||
Xdata* next;
|
||||
char* name; /* of underlying file */
|
||||
Qid qid;
|
||||
short type;
|
||||
short fdev;
|
||||
int ref; /* attach count */
|
||||
int dev; /* for read/write */
|
||||
};
|
||||
|
||||
struct Xfsub
|
||||
{
|
||||
void (*reset)(void);
|
||||
int (*attach)(Xfile*);
|
||||
void (*clone)(Xfile*, Xfile*);
|
||||
void (*walkup)(Xfile*);
|
||||
void (*walk)(Xfile*, char*);
|
||||
void (*open)(Xfile*, int);
|
||||
void (*create)(Xfile*, char*, long, int);
|
||||
long (*readdir)(Xfile*, uchar*, long, long);
|
||||
long (*read)(Xfile*, char*, vlong, long);
|
||||
long (*write)(Xfile*, char*, vlong, long);
|
||||
void (*clunk)(Xfile*);
|
||||
void (*remove)(Xfile*);
|
||||
void (*stat)(Xfile*, Dir*);
|
||||
void (*wstat)(Xfile*, Dir*);
|
||||
};
|
||||
|
||||
struct Xfs
|
||||
{
|
||||
Xdata* d; /* how to get the bits */
|
||||
Xfsub* s; /* how to use them */
|
||||
int ref;
|
||||
int issusp; /* follows system use sharing protocol */
|
||||
long suspoff; /* if so, offset at which SUSP area begins */
|
||||
int isrock; /* Rock Ridge format */
|
||||
int isplan9; /* has Plan 9-specific directory info */
|
||||
Qid rootqid;
|
||||
Isofile* ptr; /* private data */
|
||||
};
|
||||
|
||||
struct Xfile
|
||||
{
|
||||
Xfile* next; /* in fid hash bucket */
|
||||
Xfs* xf;
|
||||
long fid;
|
||||
ulong flags;
|
||||
Qid qid;
|
||||
int len; /* of private data */
|
||||
Isofile* ptr;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
Asis,
|
||||
Clean,
|
||||
Clunk
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
Oread = 1,
|
||||
Owrite = 2,
|
||||
Orclose = 4,
|
||||
Omodes = 3,
|
||||
};
|
||||
|
||||
extern char Enonexist[]; /* file does not exist */
|
||||
extern char Eperm[]; /* permission denied */
|
||||
extern char Enofile[]; /* no file system specified */
|
||||
extern char Eauth[]; /* authentication failed */
|
||||
|
||||
extern char *srvname;
|
||||
extern char *deffile;
|
||||
extern int chatty;
|
||||
extern jmp_buf err_lab[];
|
||||
extern int nerr_lab;
|
||||
extern char err_msg[];
|
||||
|
||||
extern int nojoliet;
|
||||
extern int noplan9;
|
||||
extern int norock;
|
||||
22
src/cmd/9660srv/data.c
Normal file
22
src/cmd/9660srv/data.c
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <auth.h>
|
||||
#include <fcall.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
char Enonexist[] = "file does not exist";
|
||||
char Eperm[] = "permission denied";
|
||||
char Enofile[] = "no file system specified";
|
||||
char Eauth[] = "authentication failed";
|
||||
|
||||
char *srvname = "9660";
|
||||
char *deffile = 0;
|
||||
|
||||
extern Xfsub isosub;
|
||||
|
||||
Xfsub* xsublist[] =
|
||||
{
|
||||
&isosub,
|
||||
0
|
||||
};
|
||||
17
src/cmd/9660srv/fns.h
Normal file
17
src/cmd/9660srv/fns.h
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
void chat(char*, ...);
|
||||
void* ealloc(long);
|
||||
void error(char*);
|
||||
Iobuf* getbuf(Xdata*, ulong);
|
||||
Xdata* getxdata(char*);
|
||||
void iobuf_init(void);
|
||||
void nexterror(void);
|
||||
void panic(int, char*, ...);
|
||||
void purgebuf(Xdata*);
|
||||
void putbuf(Iobuf*);
|
||||
void refxfs(Xfs*, int);
|
||||
void showdir(int, Dir*);
|
||||
Xfile* xfile(int, int);
|
||||
void setnames(Dir*, char*);
|
||||
|
||||
#define waserror() (++nerr_lab, setjmp(err_lab[nerr_lab-1]))
|
||||
#define poperror() (--nerr_lab)
|
||||
177
src/cmd/9660srv/iobuf.c
Normal file
177
src/cmd/9660srv/iobuf.c
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <auth.h>
|
||||
#include <fcall.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
/*
|
||||
* We used to use 100 i/o buffers of size 2kb (Sectorsize).
|
||||
* Unfortunately, reading 2kb at a time often hopping around
|
||||
* the disk doesn't let us get near the disk bandwidth.
|
||||
*
|
||||
* Based on a trace of iobuf address accesses taken while
|
||||
* tarring up a Plan 9 distribution CD, we now use 16 128kb
|
||||
* buffers. This works for ISO9660 because data is required
|
||||
* to be laid out contiguously; effectively we're doing agressive
|
||||
* readahead. Because the buffers are so big and the typical
|
||||
* disk accesses so concentrated, it's okay that we have so few
|
||||
* of them.
|
||||
*
|
||||
* If this is used to access multiple discs at once, it's not clear
|
||||
* how gracefully the scheme degrades, but I'm not convinced
|
||||
* it's worth worrying about. -rsc
|
||||
*/
|
||||
|
||||
/* trying a larger value to get greater throughput - geoff */
|
||||
#define BUFPERCLUST 256 /* sectors/cluster; was 64, 64*Sectorsize = 128kb */
|
||||
#define NCLUST 16
|
||||
|
||||
int nclust = NCLUST;
|
||||
|
||||
static Ioclust* iohead;
|
||||
static Ioclust* iotail;
|
||||
|
||||
static Ioclust* getclust(Xdata*, long);
|
||||
static void putclust(Ioclust*);
|
||||
static void xread(Ioclust*);
|
||||
|
||||
void
|
||||
iobuf_init(void)
|
||||
{
|
||||
int i, j, n;
|
||||
Ioclust *c;
|
||||
Iobuf *b;
|
||||
uchar *mem;
|
||||
|
||||
n = nclust*sizeof(Ioclust) +
|
||||
nclust*BUFPERCLUST*(sizeof(Iobuf)+Sectorsize);
|
||||
mem = sbrk(n);
|
||||
if(mem == (void*)-1)
|
||||
panic(0, "iobuf_init");
|
||||
memset(mem, 0, n);
|
||||
|
||||
for(i=0; i<nclust; i++){
|
||||
c = (Ioclust*)mem;
|
||||
mem += sizeof(Ioclust);
|
||||
c->addr = -1;
|
||||
c->prev = iotail;
|
||||
if(iotail)
|
||||
iotail->next = c;
|
||||
iotail = c;
|
||||
if(iohead == nil)
|
||||
iohead = c;
|
||||
|
||||
c->buf = (Iobuf*)mem;
|
||||
mem += BUFPERCLUST*sizeof(Iobuf);
|
||||
c->iobuf = mem;
|
||||
mem += BUFPERCLUST*Sectorsize;
|
||||
for(j=0; j<BUFPERCLUST; j++){
|
||||
b = &c->buf[j];
|
||||
b->clust = c;
|
||||
b->addr = -1;
|
||||
b->iobuf = c->iobuf+j*Sectorsize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
purgebuf(Xdata *dev)
|
||||
{
|
||||
Ioclust *p;
|
||||
|
||||
for(p=iohead; p!=nil; p=p->next)
|
||||
if(p->dev == dev){
|
||||
p->addr = -1;
|
||||
p->busy = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static Ioclust*
|
||||
getclust(Xdata *dev, long addr)
|
||||
{
|
||||
Ioclust *c, *f;
|
||||
|
||||
f = nil;
|
||||
for(c=iohead; c; c=c->next){
|
||||
if(!c->busy)
|
||||
f = c;
|
||||
if(c->addr == addr && c->dev == dev){
|
||||
c->busy++;
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
if(f == nil)
|
||||
panic(0, "out of buffers");
|
||||
|
||||
f->addr = addr;
|
||||
f->dev = dev;
|
||||
f->busy++;
|
||||
if(waserror()){
|
||||
f->addr = -1; /* stop caching */
|
||||
putclust(f);
|
||||
nexterror();
|
||||
}
|
||||
xread(f);
|
||||
poperror();
|
||||
return f;
|
||||
}
|
||||
|
||||
static void
|
||||
putclust(Ioclust *c)
|
||||
{
|
||||
if(c->busy <= 0)
|
||||
panic(0, "putbuf");
|
||||
c->busy--;
|
||||
|
||||
/* Link onto head for LRU */
|
||||
if(c == iohead)
|
||||
return;
|
||||
c->prev->next = c->next;
|
||||
|
||||
if(c->next)
|
||||
c->next->prev = c->prev;
|
||||
else
|
||||
iotail = c->prev;
|
||||
|
||||
c->prev = nil;
|
||||
c->next = iohead;
|
||||
iohead->prev = c;
|
||||
iohead = c;
|
||||
}
|
||||
|
||||
Iobuf*
|
||||
getbuf(Xdata *dev, ulong addr)
|
||||
{
|
||||
int off;
|
||||
Ioclust *c;
|
||||
|
||||
off = addr%BUFPERCLUST;
|
||||
c = getclust(dev, addr - off);
|
||||
if(c->nbuf < off){
|
||||
c->busy--;
|
||||
error("I/O read error");
|
||||
}
|
||||
return &c->buf[off];
|
||||
}
|
||||
|
||||
void
|
||||
putbuf(Iobuf *b)
|
||||
{
|
||||
putclust(b->clust);
|
||||
}
|
||||
|
||||
static void
|
||||
xread(Ioclust *c)
|
||||
{
|
||||
int n;
|
||||
Xdata *dev;
|
||||
|
||||
dev = c->dev;
|
||||
seek(dev->dev, (vlong)c->addr * Sectorsize, 0);
|
||||
n = readn(dev->dev, c->iobuf, BUFPERCLUST*Sectorsize);
|
||||
if(n < Sectorsize)
|
||||
error("I/O read error");
|
||||
c->nbuf = n/Sectorsize;
|
||||
}
|
||||
142
src/cmd/9660srv/iso9660.h
Normal file
142
src/cmd/9660srv/iso9660.h
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
#define VOLDESC 16 /* sector number */
|
||||
|
||||
/*
|
||||
* L means little-endian, M means big-endian, and LM means little-endian
|
||||
* then again big-endian.
|
||||
*/
|
||||
typedef uchar Byte2L[2];
|
||||
typedef uchar Byte2M[2];
|
||||
typedef uchar Byte4LM[4];
|
||||
typedef uchar Byte4L[4];
|
||||
typedef uchar Byte4M[4];
|
||||
typedef uchar Byte8LM[8];
|
||||
typedef union Drec Drec;
|
||||
typedef union Voldesc Voldesc;
|
||||
|
||||
enum
|
||||
{
|
||||
Boot = 0,
|
||||
Primary = 1,
|
||||
Supplementary = 2,
|
||||
Partition = 3,
|
||||
Terminator = 255
|
||||
};
|
||||
|
||||
union Voldesc
|
||||
{ /* volume descriptor */
|
||||
uchar byte[Sectorsize];
|
||||
union { /* for CD001, the ECMA standard */
|
||||
struct
|
||||
{
|
||||
uchar type;
|
||||
uchar stdid[5];
|
||||
uchar version;
|
||||
uchar unused;
|
||||
uchar sysid[32];
|
||||
uchar bootid[32];
|
||||
uchar data[1977];
|
||||
} boot;
|
||||
struct
|
||||
{
|
||||
uchar type;
|
||||
uchar stdid[5];
|
||||
uchar version;
|
||||
uchar flags;
|
||||
uchar sysid[32];
|
||||
uchar volid[32];
|
||||
Byte8LM partloc;
|
||||
Byte8LM size;
|
||||
uchar escapes[32];
|
||||
Byte4LM vsetsize;
|
||||
Byte4LM vseqno;
|
||||
Byte4LM blksize;
|
||||
Byte8LM ptabsize;
|
||||
Byte4L lptable;
|
||||
Byte4L optlptable;
|
||||
Byte4M mptable;
|
||||
Byte4M optmptable;
|
||||
uchar rootdir[34];
|
||||
uchar volsetid[128];
|
||||
uchar pubid[128];
|
||||
uchar prepid[128];
|
||||
uchar appid[128];
|
||||
uchar copyright[37];
|
||||
uchar abstract[37];
|
||||
uchar bibliography[37];
|
||||
uchar cdate[17];
|
||||
uchar mdate[17];
|
||||
uchar expdate[17];
|
||||
uchar effdate[17];
|
||||
uchar fsversion;
|
||||
uchar unused3[1];
|
||||
uchar appuse[512];
|
||||
uchar unused4[653];
|
||||
} desc;
|
||||
} z;
|
||||
union
|
||||
{ /* for CDROM, the `High Sierra' standard */
|
||||
struct
|
||||
{
|
||||
Byte8LM number;
|
||||
uchar type;
|
||||
uchar stdid[5];
|
||||
uchar version;
|
||||
uchar flags;
|
||||
uchar sysid[32];
|
||||
uchar volid[32];
|
||||
Byte8LM partloc;
|
||||
Byte8LM size;
|
||||
uchar escapes[32];
|
||||
Byte4LM vsetsize;
|
||||
Byte4LM vseqno;
|
||||
Byte4LM blksize;
|
||||
uchar quux[40];
|
||||
uchar rootdir[34];
|
||||
uchar volsetid[128];
|
||||
uchar pubid[128];
|
||||
uchar prepid[128];
|
||||
uchar appid[128];
|
||||
uchar copyright[32];
|
||||
uchar abstract[32];
|
||||
uchar cdate[16];
|
||||
uchar mdate[16];
|
||||
uchar expdate[16];
|
||||
uchar effdate[16];
|
||||
uchar fsversion;
|
||||
} desc;
|
||||
} r;
|
||||
};
|
||||
|
||||
union Drec
|
||||
{
|
||||
struct
|
||||
{
|
||||
uchar reclen;
|
||||
uchar attrlen;
|
||||
Byte8LM addr;
|
||||
Byte8LM size;
|
||||
uchar date[6];
|
||||
uchar tzone; /* flags in high sierra */
|
||||
uchar flags; /* ? in high sierra */
|
||||
uchar unitsize; /* ? in high sierra */
|
||||
uchar gapsize; /* ? in high sierra */
|
||||
Byte4LM vseqno; /* ? in high sierra */
|
||||
uchar namelen;
|
||||
uchar name[1];
|
||||
};
|
||||
struct
|
||||
{
|
||||
uchar r_pad[24];
|
||||
uchar r_flags;
|
||||
};
|
||||
};
|
||||
|
||||
struct Isofile
|
||||
{
|
||||
short fmt; /* 'z' if iso, 'r' if high sierra */
|
||||
short blksize;
|
||||
long offset; /* true offset when reading directory */
|
||||
long odelta; /* true size of directory just read */
|
||||
long doffset; /* plan9 offset when reading directory */
|
||||
Drec d;
|
||||
};
|
||||
576
src/cmd/9660srv/main.c
Normal file
576
src/cmd/9660srv/main.c
Normal file
|
|
@ -0,0 +1,576 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <auth.h>
|
||||
#include <fcall.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
enum
|
||||
{
|
||||
Maxfdata = 8192,
|
||||
Maxiosize = IOHDRSZ+Maxfdata,
|
||||
};
|
||||
|
||||
void io(int);
|
||||
void rversion(void);
|
||||
void rattach(void);
|
||||
void rauth(void);
|
||||
void rclunk(void);
|
||||
void rcreate(void);
|
||||
void rflush(void);
|
||||
void ropen(void);
|
||||
void rread(void);
|
||||
void rremove(void);
|
||||
void rsession(void);
|
||||
void rstat(void);
|
||||
void rwalk(void);
|
||||
void rwrite(void);
|
||||
void rwstat(void);
|
||||
|
||||
static int openflags(int);
|
||||
static void usage(void);
|
||||
|
||||
#define Reqsize (sizeof(Fcall)+Maxfdata)
|
||||
|
||||
Fcall *req;
|
||||
Fcall *rep;
|
||||
|
||||
uchar mdata[Maxiosize];
|
||||
char fdata[Maxfdata];
|
||||
uchar statbuf[STATMAX];
|
||||
int errno;
|
||||
|
||||
|
||||
extern Xfsub *xsublist[];
|
||||
extern int nclust;
|
||||
|
||||
jmp_buf err_lab[16];
|
||||
int nerr_lab;
|
||||
char err_msg[ERRMAX];
|
||||
|
||||
int chatty;
|
||||
int nojoliet;
|
||||
int noplan9;
|
||||
int norock;
|
||||
|
||||
void (*fcalls[])(void) = {
|
||||
[Tversion] rversion,
|
||||
[Tflush] rflush,
|
||||
[Tauth] rauth,
|
||||
[Tattach] rattach,
|
||||
[Twalk] rwalk,
|
||||
[Topen] ropen,
|
||||
[Tcreate] rcreate,
|
||||
[Tread] rread,
|
||||
[Twrite] rwrite,
|
||||
[Tclunk] rclunk,
|
||||
[Tremove] rremove,
|
||||
[Tstat] rstat,
|
||||
[Twstat] rwstat,
|
||||
};
|
||||
|
||||
void
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int srvfd, pipefd[2], stdio;
|
||||
Xfsub **xs;
|
||||
char *mtpt;
|
||||
|
||||
stdio = 0;
|
||||
mtpt = nil;
|
||||
ARGBEGIN {
|
||||
case '9':
|
||||
noplan9 = 1;
|
||||
break;
|
||||
case 'c':
|
||||
nclust = atoi(EARGF(usage()));
|
||||
if (nclust <= 0)
|
||||
sysfatal("nclust %d non-positive", nclust);
|
||||
break;
|
||||
case 'f':
|
||||
deffile = EARGF(usage());
|
||||
break;
|
||||
case 'r':
|
||||
norock = 1;
|
||||
break;
|
||||
case 's':
|
||||
stdio = 1;
|
||||
break;
|
||||
case 'v':
|
||||
chatty = 1;
|
||||
break;
|
||||
case 'J':
|
||||
nojoliet = 1;
|
||||
break;
|
||||
case 'm':
|
||||
mtpt = EARGF(usage());
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
} ARGEND
|
||||
|
||||
switch(argc) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
srvname = argv[0];
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
|
||||
iobuf_init();
|
||||
for(xs=xsublist; *xs; xs++)
|
||||
(*(*xs)->reset)();
|
||||
|
||||
if(stdio) {
|
||||
pipefd[0] = 0;
|
||||
pipefd[1] = 1;
|
||||
} else {
|
||||
close(0);
|
||||
close(1);
|
||||
open("/dev/null", OREAD);
|
||||
open("/dev/null", OWRITE);
|
||||
if(pipe(pipefd) < 0)
|
||||
panic(1, "pipe");
|
||||
|
||||
if(post9pservice(pipefd[0], srvname, mtpt) < 0)
|
||||
sysfatal("post9pservice: %r");
|
||||
close(pipefd[0]);
|
||||
}
|
||||
srvfd = pipefd[1];
|
||||
|
||||
switch(rfork(RFNOWAIT|RFNOTEG|RFFDG|RFPROC)){
|
||||
case -1:
|
||||
panic(1, "fork");
|
||||
default:
|
||||
_exits(0);
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
|
||||
io(srvfd);
|
||||
exits(0);
|
||||
}
|
||||
|
||||
void
|
||||
io(int srvfd)
|
||||
{
|
||||
int n, pid;
|
||||
Fcall xreq, xrep;
|
||||
|
||||
req = &xreq;
|
||||
rep = &xrep;
|
||||
pid = getpid();
|
||||
fmtinstall('F', fcallfmt);
|
||||
|
||||
for(;;){
|
||||
/*
|
||||
* 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(srvfd, mdata, sizeof mdata);
|
||||
if(n < 0)
|
||||
break;
|
||||
if(n == 0)
|
||||
continue;
|
||||
if(convM2S(mdata, n, req) == 0)
|
||||
continue;
|
||||
|
||||
if(chatty)
|
||||
fprint(2, "9660srv %d:<-%F\n", pid, req);
|
||||
|
||||
errno = 0;
|
||||
if(!waserror()){
|
||||
err_msg[0] = 0;
|
||||
if(req->type >= nelem(fcalls) || !fcalls[req->type])
|
||||
error("bad fcall type");
|
||||
(*fcalls[req->type])();
|
||||
poperror();
|
||||
}
|
||||
|
||||
if(err_msg[0]){
|
||||
rep->type = Rerror;
|
||||
rep->ename = err_msg;
|
||||
}else{
|
||||
rep->type = req->type + 1;
|
||||
rep->fid = req->fid;
|
||||
}
|
||||
rep->tag = req->tag;
|
||||
|
||||
if(chatty)
|
||||
fprint(2, "9660srv %d:->%F\n", pid, rep);
|
||||
n = convS2M(rep, mdata, sizeof mdata);
|
||||
if(n == 0)
|
||||
panic(1, "convS2M error on write");
|
||||
if(write(srvfd, mdata, n) != n)
|
||||
panic(1, "mount write");
|
||||
if(nerr_lab != 0)
|
||||
panic(0, "err stack %d");
|
||||
}
|
||||
chat("server shut down");
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage: %s [-v] [-9Jr] [-s] [-f devicefile] [srvname]\n", argv0);
|
||||
exits("usage");
|
||||
}
|
||||
|
||||
void
|
||||
error(char *p)
|
||||
{
|
||||
strecpy(err_msg, err_msg+sizeof err_msg, p);
|
||||
nexterror();
|
||||
}
|
||||
|
||||
void
|
||||
nexterror(void)
|
||||
{
|
||||
longjmp(err_lab[--nerr_lab], 1);
|
||||
}
|
||||
|
||||
void*
|
||||
ealloc(long n)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = malloc(n);
|
||||
if(p == 0)
|
||||
error("no memory");
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
setnames(Dir *d, char *n)
|
||||
{
|
||||
d->name = n;
|
||||
d->uid = n+Maxname;
|
||||
d->gid = n+Maxname*2;
|
||||
d->muid = n+Maxname*3;
|
||||
|
||||
d->name[0] = '\0';
|
||||
d->uid[0] = '\0';
|
||||
d->gid[0] = '\0';
|
||||
d->muid[0] = '\0';
|
||||
}
|
||||
|
||||
void
|
||||
rversion(void)
|
||||
{
|
||||
if(req->msize > Maxiosize)
|
||||
rep->msize = Maxiosize;
|
||||
else
|
||||
rep->msize = req->msize;
|
||||
rep->version = "9P2000";
|
||||
}
|
||||
|
||||
void
|
||||
rauth(void)
|
||||
{
|
||||
error("9660srv: authentication not required");
|
||||
}
|
||||
|
||||
void
|
||||
rflush(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
rattach(void)
|
||||
{
|
||||
Xfs *xf;
|
||||
Xfile *root;
|
||||
Xfsub **xs;
|
||||
|
||||
chat("attach(fid=%d,uname=\"%s\",aname=\"%s\")...",
|
||||
req->fid, req->uname, req->aname);
|
||||
|
||||
if(waserror()){
|
||||
xfile(req->fid, Clunk);
|
||||
nexterror();
|
||||
}
|
||||
root = xfile(req->fid, Clean);
|
||||
root->qid = (Qid){0, 0, QTDIR};
|
||||
root->xf = xf = ealloc(sizeof(Xfs));
|
||||
memset(xf, 0, sizeof(Xfs));
|
||||
xf->ref = 1;
|
||||
xf->d = getxdata(req->aname);
|
||||
|
||||
for(xs=xsublist; *xs; xs++)
|
||||
if((*(*xs)->attach)(root) >= 0){
|
||||
poperror();
|
||||
xf->s = *xs;
|
||||
xf->rootqid = root->qid;
|
||||
rep->qid = root->qid;
|
||||
return;
|
||||
}
|
||||
error("unknown format");
|
||||
}
|
||||
|
||||
Xfile*
|
||||
doclone(Xfile *of, int newfid)
|
||||
{
|
||||
Xfile *nf, *next;
|
||||
|
||||
nf = xfile(newfid, Clean);
|
||||
if(waserror()){
|
||||
xfile(newfid, Clunk);
|
||||
nexterror();
|
||||
}
|
||||
next = nf->next;
|
||||
*nf = *of;
|
||||
nf->next = next;
|
||||
nf->fid = newfid;
|
||||
refxfs(nf->xf, 1);
|
||||
if(nf->len){
|
||||
nf->ptr = ealloc(nf->len);
|
||||
memmove(nf->ptr, of->ptr, nf->len);
|
||||
}else
|
||||
nf->ptr = of->ptr;
|
||||
(*of->xf->s->clone)(of, nf);
|
||||
poperror();
|
||||
return nf;
|
||||
}
|
||||
|
||||
void
|
||||
rwalk(void)
|
||||
{
|
||||
Xfile *f, *nf;
|
||||
Isofile *oldptr;
|
||||
int oldlen;
|
||||
Qid oldqid;
|
||||
|
||||
rep->nwqid = 0;
|
||||
nf = nil;
|
||||
f = xfile(req->fid, Asis);
|
||||
if(req->fid != req->newfid)
|
||||
f = nf = doclone(f, req->newfid);
|
||||
|
||||
/* save old state in case of error */
|
||||
oldqid = f->qid;
|
||||
oldlen = f->len;
|
||||
oldptr = f->ptr;
|
||||
if(oldlen){
|
||||
oldptr = ealloc(oldlen);
|
||||
memmove(oldptr, f->ptr, oldlen);
|
||||
}
|
||||
|
||||
if(waserror()){
|
||||
if(nf != nil)
|
||||
xfile(req->newfid, Clunk);
|
||||
if(rep->nwqid == req->nwname){
|
||||
if(oldlen)
|
||||
free(oldptr);
|
||||
}else{
|
||||
/* restore previous state */
|
||||
f->qid = oldqid;
|
||||
if(f->len)
|
||||
free(f->ptr);
|
||||
f->ptr = oldptr;
|
||||
f->len = oldlen;
|
||||
}
|
||||
if(rep->nwqid==req->nwname || rep->nwqid > 0){
|
||||
err_msg[0] = '\0';
|
||||
return;
|
||||
}
|
||||
nexterror();
|
||||
}
|
||||
|
||||
for(rep->nwqid=0; rep->nwqid < req->nwname && rep->nwqid < MAXWELEM; rep->nwqid++){
|
||||
chat("\twalking %s\n", req->wname[rep->nwqid]);
|
||||
if(!(f->qid.type & QTDIR)){
|
||||
chat("\tnot dir: type=%#x\n", f->qid.type);
|
||||
error("walk in non-directory");
|
||||
}
|
||||
|
||||
if(strcmp(req->wname[rep->nwqid], "..")==0){
|
||||
if(f->qid.path != f->xf->rootqid.path)
|
||||
(*f->xf->s->walkup)(f);
|
||||
}else
|
||||
(*f->xf->s->walk)(f, req->wname[rep->nwqid]);
|
||||
rep->wqid[rep->nwqid] = f->qid;
|
||||
}
|
||||
poperror();
|
||||
if(oldlen)
|
||||
free(oldptr);
|
||||
}
|
||||
|
||||
void
|
||||
ropen(void)
|
||||
{
|
||||
Xfile *f;
|
||||
|
||||
f = xfile(req->fid, Asis);
|
||||
if(f->flags&Omodes)
|
||||
error("open on open file");
|
||||
if(req->mode&ORCLOSE)
|
||||
error("no removes");
|
||||
(*f->xf->s->open)(f, req->mode);
|
||||
f->flags = openflags(req->mode);
|
||||
rep->qid = f->qid;
|
||||
rep->iounit = 0;
|
||||
}
|
||||
|
||||
void
|
||||
rcreate(void)
|
||||
{
|
||||
error("no creates");
|
||||
/*
|
||||
Xfile *f;
|
||||
|
||||
if(strcmp(req->name, ".") == 0 || strcmp(req->name, "..") == 0)
|
||||
error("create . or ..");
|
||||
f = xfile(req->fid, Asis);
|
||||
if(f->flags&Omodes)
|
||||
error("create on open file");
|
||||
if(!(f->qid.path&CHDIR))
|
||||
error("create in non-directory");
|
||||
(*f->xf->s->create)(f, req->name, req->perm, req->mode);
|
||||
chat("f->qid=0x%8.8lux...", f->qid.path);
|
||||
f->flags = openflags(req->mode);
|
||||
rep->qid = f->qid;
|
||||
*/
|
||||
}
|
||||
|
||||
void
|
||||
rread(void)
|
||||
{
|
||||
Xfile *f;
|
||||
|
||||
f=xfile(req->fid, Asis);
|
||||
if (!(f->flags&Oread))
|
||||
error("file not opened for reading");
|
||||
if(f->qid.type & QTDIR)
|
||||
rep->count = (*f->xf->s->readdir)(f, (uchar*)fdata, req->offset, req->count);
|
||||
else
|
||||
rep->count = (*f->xf->s->read)(f, fdata, req->offset, req->count);
|
||||
rep->data = fdata;
|
||||
}
|
||||
|
||||
void
|
||||
rwrite(void)
|
||||
{
|
||||
Xfile *f;
|
||||
|
||||
f=xfile(req->fid, Asis);
|
||||
if(!(f->flags&Owrite))
|
||||
error("file not opened for writing");
|
||||
rep->count = (*f->xf->s->write)(f, req->data, req->offset, req->count);
|
||||
}
|
||||
|
||||
void
|
||||
rclunk(void)
|
||||
{
|
||||
Xfile *f;
|
||||
|
||||
if(!waserror()){
|
||||
f = xfile(req->fid, Asis);
|
||||
(*f->xf->s->clunk)(f);
|
||||
poperror();
|
||||
}
|
||||
xfile(req->fid, Clunk);
|
||||
}
|
||||
|
||||
void
|
||||
rremove(void)
|
||||
{
|
||||
error("no removes");
|
||||
}
|
||||
|
||||
void
|
||||
rstat(void)
|
||||
{
|
||||
Xfile *f;
|
||||
Dir dir;
|
||||
|
||||
chat("stat(fid=%d)...", req->fid);
|
||||
f=xfile(req->fid, Asis);
|
||||
setnames(&dir, fdata);
|
||||
(*f->xf->s->stat)(f, &dir);
|
||||
if(chatty)
|
||||
showdir(2, &dir);
|
||||
rep->nstat = convD2M(&dir, statbuf, sizeof statbuf);
|
||||
rep->stat = statbuf;
|
||||
}
|
||||
|
||||
void
|
||||
rwstat(void)
|
||||
{
|
||||
error("no wstat");
|
||||
}
|
||||
|
||||
static int
|
||||
openflags(int mode)
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
switch(mode & ~(OTRUNC|OCEXEC|ORCLOSE)){
|
||||
case OREAD:
|
||||
case OEXEC:
|
||||
flags = Oread; break;
|
||||
case OWRITE:
|
||||
flags = Owrite; break;
|
||||
case ORDWR:
|
||||
flags = Oread|Owrite; break;
|
||||
}
|
||||
if(mode & ORCLOSE)
|
||||
flags |= Orclose;
|
||||
return flags;
|
||||
}
|
||||
|
||||
void
|
||||
showdir(int fd, Dir *s)
|
||||
{
|
||||
char a_time[32], m_time[32];
|
||||
char *p;
|
||||
|
||||
strcpy(a_time, ctime(s->atime));
|
||||
if(p=strchr(a_time, '\n')) /* assign = */
|
||||
*p = 0;
|
||||
strcpy(m_time, ctime(s->mtime));
|
||||
if(p=strchr(m_time, '\n')) /* assign = */
|
||||
*p = 0;
|
||||
fprint(fd, "name=\"%s\" qid=(0x%llux,%lud) type=%d dev=%d \
|
||||
mode=0x%8.8lux=0%luo atime=%s mtime=%s length=%lld uid=\"%s\" gid=\"%s\"...",
|
||||
s->name, s->qid.path, s->qid.vers, s->type, s->dev,
|
||||
s->mode, s->mode,
|
||||
a_time, m_time, s->length, s->uid, s->gid);
|
||||
}
|
||||
|
||||
#define SIZE 1024
|
||||
|
||||
void
|
||||
chat(char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
|
||||
if(chatty){
|
||||
va_start(arg, fmt);
|
||||
vfprint(2, fmt, arg);
|
||||
va_end(arg);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
panic(int rflag, char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
char buf[SIZE]; int n;
|
||||
|
||||
n = sprint(buf, "%s %d: ", argv0, getpid());
|
||||
va_start(arg, fmt);
|
||||
vseprint(buf+n, buf+SIZE, fmt, arg);
|
||||
va_end(arg);
|
||||
fprint(2, (rflag ? "%s: %r\n" : "%s\n"), buf);
|
||||
if(chatty){
|
||||
fprint(2, "abort\n");
|
||||
abort();
|
||||
}
|
||||
exits("panic");
|
||||
}
|
||||
17
src/cmd/9660srv/mkfile
Normal file
17
src/cmd/9660srv/mkfile
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<$PLAN9/src/mkhdr
|
||||
|
||||
TARG=9660srv
|
||||
|
||||
OFILES=\
|
||||
main.$O\
|
||||
9660srv.$O\
|
||||
xfile.$O\
|
||||
iobuf.$O\
|
||||
data.$O\
|
||||
|
||||
HFILES=dat.h fns.h
|
||||
|
||||
<$PLAN9/src/mkone
|
||||
|
||||
9660srv.$O: iso9660.h
|
||||
|
||||
170
src/cmd/9660srv/xfile.c
Normal file
170
src/cmd/9660srv/xfile.c
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <auth.h>
|
||||
#include <fcall.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
static Xfile* clean(Xfile*);
|
||||
|
||||
#define FIDMOD 127 /* prime */
|
||||
|
||||
static Xdata* xhead;
|
||||
static Xfile* xfiles[FIDMOD];
|
||||
static Xfile* freelist;
|
||||
|
||||
Xdata*
|
||||
getxdata(char *name)
|
||||
{
|
||||
int fd;
|
||||
Dir *dir;
|
||||
Xdata *xf, *fxf;
|
||||
int flag;
|
||||
|
||||
if(name[0] == 0)
|
||||
name = deffile;
|
||||
if(name == 0)
|
||||
error(Enofile);
|
||||
flag = (access(name, 6) == 0) ? ORDWR : OREAD;
|
||||
fd = open(name, flag);
|
||||
if(fd < 0)
|
||||
error(Enonexist);
|
||||
dir = nil;
|
||||
if(waserror()){
|
||||
close(fd);
|
||||
free(dir);
|
||||
nexterror();
|
||||
}
|
||||
if((dir = dirfstat(fd)) == nil)
|
||||
error("I/O error");
|
||||
if((dir->qid.type & ~QTTMP) != QTFILE)
|
||||
error("attach name not a plain file");
|
||||
for(fxf=0,xf=xhead; xf; xf=xf->next){
|
||||
if(xf->name == 0){
|
||||
if(fxf == 0)
|
||||
fxf = xf;
|
||||
continue;
|
||||
}
|
||||
if(xf->qid.path != dir->qid.path || xf->qid.vers != dir->qid.vers)
|
||||
continue;
|
||||
if(xf->type != dir->type || xf->fdev != dir->dev)
|
||||
continue;
|
||||
xf->ref++;
|
||||
chat("incref=%d, \"%s\", dev=%d...", xf->ref, xf->name, xf->dev);
|
||||
close(fd);
|
||||
poperror();
|
||||
free(dir);
|
||||
return xf;
|
||||
}
|
||||
if(fxf==0){
|
||||
fxf = ealloc(sizeof(Xfs));
|
||||
fxf->next = xhead;
|
||||
xhead = fxf;
|
||||
}
|
||||
chat("alloc \"%s\", dev=%d...", name, fd);
|
||||
fxf->ref = 1;
|
||||
fxf->name = strcpy(ealloc(strlen(name)+1), name);
|
||||
fxf->qid = dir->qid;
|
||||
fxf->type = dir->type;
|
||||
fxf->fdev = dir->dev;
|
||||
fxf->dev = fd;
|
||||
free(dir);
|
||||
poperror();
|
||||
return fxf;
|
||||
}
|
||||
|
||||
static void
|
||||
putxdata(Xdata *d)
|
||||
{
|
||||
if(d->ref <= 0)
|
||||
panic(0, "putxdata");
|
||||
d->ref--;
|
||||
chat("decref=%d, \"%s\", dev=%d...", d->ref, d->name, d->dev);
|
||||
if(d->ref == 0){
|
||||
chat("purgebuf...");
|
||||
purgebuf(d);
|
||||
close(d->dev);
|
||||
free(d->name);
|
||||
d->name = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
refxfs(Xfs *xf, int delta)
|
||||
{
|
||||
xf->ref += delta;
|
||||
if(xf->ref == 0){
|
||||
if(xf->d)
|
||||
putxdata(xf->d);
|
||||
if(xf->ptr)
|
||||
free(xf->ptr);
|
||||
free(xf);
|
||||
}
|
||||
}
|
||||
|
||||
Xfile*
|
||||
xfile(int fid, int flag)
|
||||
{
|
||||
int k = fid%FIDMOD;
|
||||
Xfile **hp=&xfiles[k], *f, *pf;
|
||||
|
||||
for(f=*hp,pf=0; f; pf=f,f=f->next)
|
||||
if(f->fid == fid)
|
||||
break;
|
||||
if(f && pf){
|
||||
pf->next = f->next;
|
||||
f->next = *hp;
|
||||
*hp = f;
|
||||
}
|
||||
switch(flag){
|
||||
default:
|
||||
panic(0, "xfile");
|
||||
case Asis:
|
||||
if(f == 0)
|
||||
error("unassigned fid");
|
||||
return f;
|
||||
case Clean:
|
||||
break;
|
||||
case Clunk:
|
||||
if(f){
|
||||
*hp = f->next;
|
||||
clean(f);
|
||||
f->next = freelist;
|
||||
freelist = f;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if(f)
|
||||
return clean(f);
|
||||
if(f = freelist) /* assign = */
|
||||
freelist = f->next;
|
||||
else
|
||||
f = ealloc(sizeof(Xfile));
|
||||
f->next = *hp;
|
||||
*hp = f;
|
||||
f->xf = 0;
|
||||
f->fid = fid;
|
||||
f->flags = 0;
|
||||
f->qid = (Qid){0,0,0};
|
||||
f->len = 0;
|
||||
f->ptr = 0;
|
||||
return f;
|
||||
}
|
||||
|
||||
static Xfile *
|
||||
clean(Xfile *f)
|
||||
{
|
||||
if(f->xf){
|
||||
refxfs(f->xf, -1);
|
||||
f->xf = 0;
|
||||
}
|
||||
if(f->len){
|
||||
free(f->ptr);
|
||||
f->len = 0;
|
||||
}
|
||||
f->ptr = 0;
|
||||
f->flags = 0;
|
||||
f->qid = (Qid){0,0,0};
|
||||
return f;
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue