|
|
researchv10 Norman
#include "sys/param.h"
#include "sys/systm.h"
#include "sys/inode.h"
#include "sys/dir.h"
#include "sys/user.h"
#include "sys/proc.h"
#include "sys/stat.h"
#include "sys/neta.h"
#include "sys/buf.h"
#include "sys/stream.h"
#include "sys/conf.h"
/*
* obsolete network filesystem protocol
*
* i_fsflags is used in various places instead of the
* obsolete i_key
* this is a cheat
* it is allowed only because neta will soon vanish
*/
struct senda nilx;
static long natrannum;
#define ND 100
struct {
char len, s, n;
struct senda x[ND];
struct rcva y[ND];
} netabuf = {ND};
#define addx(z) netabuf.x[netabuf.n] = *z; netabuf.s = 1;
#define addy(z) netabuf.y[netabuf.n++] = *z; if(netabuf.n >= ND) netabuf.n = 0; netabuf.s = 0;
int naput(), naupdat(), naread(), nawrite(), natrunc(), nastat();
int nanami(), namount();
struct fstypsw nafs =
fsinit(naput, naupdat, naread, nawrite, natrunc, nastat,
nanami, namount, nodev, nullopen, nodev);
namount(sip, ip, flag, mnt, fstyp)
struct inode *ip, *sip;
{
if (!suser())
return;
if (mnt)
nadomount(sip, ip, flag, fstyp);
else
naunmount(ip, fstyp);
}
nadomount(cip, dip, flag, fstyp)
register struct inode *cip, *dip;
{
struct inode pi;
register struct inode *rip;
if(cip->i_sptr == NULL) {
u.u_error = ENXIO;
return;
}
if((dip->i_mode & IFMT) != IFDIR) {
u.u_error = ENOTDIR;
return;
}
/*
* take care, because of the stupid user-generated device
*/
if (dip->i_fstyp == fstyp && dip->i_dev == flag) {
u.u_error = EBUSY;
return;
}
pi.i_dev = flag;
pi.i_fstyp = fstyp;
if ((rip = iget(&pi, flag, ROOTINO)) == NULL)
return;
if (rip->i_count > 1) {
iput(rip);
u.u_error = EBUSY;
return;
}
/*
* fake the root, rather than sending NAGET now,
* to avoid a deadlock when a server mounts itself
* the next stat will correct it
*/
rip->i_mode = IFDIR|0555;
rip->i_un.i_tag = (flag<<16)|ROOTINO;
rip->i_un.i_cip = cip;
rip->i_nlink = 2;
rip->i_size = 32;
rip->i_uid = rip->i_gid = -1;
dip->i_mroot = rip;
rip->i_mpoint = dip;
prele(rip);
dip->i_count++;
cip->i_count++;
cip->i_un.i_fsflags = 0;
}
naunmount(mip, fstyp)
register struct inode *mip;
{
register struct inode *rip;
rip = mip->i_mroot;
plock(rip);
xumount(rip); /* shared text from remote root */
if (rip->i_count > 1 || ifsbusy(rip)) {
u.u_error = EBUSY;
prele(rip);
return;
}
plock(mip);
mip->i_mroot = NULL;
iput(mip);
if ((mip = rip->i_un.i_cip) == NULL)
panic("naunmount");
iput(rip);
iput(mip);
}
naput(ip)
struct inode *ip;
{ struct senda x;
struct rcva y;
if (ip->i_un.i_cip == NULL)
return; /* obscure gmount safety */
if(ip->i_flag & ICHG)
naupdat(ip, &time, &time, 0);
x = nilx;
x.trannum = natrannum++;
x.cmd = NPUT;
x.uid = u.u_uid;
x.tag = ip->i_un.i_tag;
x.dev = ip->i_dev;
x.ino = ip->i_number;
send(ip->i_un.i_cip, &x, &y);
if(y.errno)
u.u_error = y.errno;
}
/*
* special case:
* the root is faked up locally
* really just to avoid a silly deadlock in the face server
*/
nafillin(fip, ip)
struct inode *fip;
register struct inode *ip;
{ struct senda x;
struct rcva y;
ip->i_un.i_cip = NULL; /* in case we have to put it */
if (fip->i_un.i_cip == NULL) {
u.u_error = ENXIO;
iput(ip);
return (-1);
}
x = nilx;
x.trannum = natrannum++;
x.cmd = NGET;
x.uid = u.u_uid;
x.dev = ip->i_dev;
x.ino = ip->i_number;
send(fip->i_un.i_cip, &x, &y);
if(y.errno == 0) {
ip->i_mode = y.mode;
ip->i_un.i_tag = y.tag;
ip->i_un.i_cip = fip->i_un.i_cip;
ip->i_nlink = y.nlink;
ip->i_size = y.size;
ip->i_uid = y.uid;
ip->i_gid = y.gid;
return (0);
}
iput(ip);
u.u_error = y.errno;
return(-1);
}
/* this is used by CREAT */
naupdat(ip, ta, tm, waitfor)
struct inode *ip;
time_t *ta, *tm;
{ struct senda x;
struct rcva y;
if (ip->i_un.i_cip == NULL)
return; /* obscure gmount safety */
x = nilx;
x.trannum = natrannum++;
x.cmd = NUPDAT;
x.uid = u.u_uid;
x.gid = u.u_gid;
x.newuid = ip->i_uid;
x.newgid = ip->i_gid;
x.mode = ip->i_mode;
x.tag = ip->i_un.i_tag;
x.dev = ip->i_dev;
x.ino = ip->i_number;
if(ip->i_flag & IACC)
x.ta = *ta;
else
x.ta = 0;
if(ip->i_flag & ICHG)
x.tm = *tm;
else
x.tm = 0;
send(ip->i_un.i_cip, &x, &y);
if(y.errno) {
u.u_error = y.errno;
return;
}
ip->i_mode = y.mode;
ip->i_nlink = y.nlink;
ip->i_size = y.size;
ip->i_uid = y.uid;
ip->i_gid = y.gid;
ip->i_flag &= ~(IUPD|IACC|ICHG);
}
naread(ip)
struct inode *ip;
{ struct senda x;
struct rcva y;
struct buf *bp;
int n;
bp = geteblk();
clrbuf(bp); /* could use user's buffer */
x = nilx;
x.trannum = natrannum++;
x.cmd = NREAD;
x.uid = u.u_uid;
x.tag = ip->i_un.i_tag;
x.dev = ip->i_dev;
x.ino = ip->i_number;
x.buf = bp->b_un.b_addr;
do {
n = u.u_count;
if(n > BUFSIZE)
n = BUFSIZE;
x.count = n;
x.offset = Ltol(u.u_offset);
send(ip->i_un.i_cip, &x, &y);
if((n = y.count) > 0) {
if(u.u_segflg != SEGSYS) {
if(copyout(bp->b_un.b_addr, u.u_base, n)) {
u.u_error = EFAULT;
break;
}
}
else
bcopy(bp->b_un.b_addr, u.u_base, n);
u.u_base += n;
u.u_offset = Lladd(u.u_offset, n);
u.u_count -= n;
}
if(y.errno)
u.u_error = y.errno;
} while(u.u_error == 0 && u.u_count != 0 && n > 0);
brelse(bp);
}
nawrite(ip)
struct inode *ip;
{ struct senda x;
struct rcva y;
struct buf *bp;
int n;
bp = geteblk();
x = nilx;
x.trannum = natrannum++;
x.cmd = NWRT;
x.uid = u.u_uid;
x.tag = ip->i_un.i_tag;
x.dev = ip->i_dev;
x.ino = ip->i_number;
x.buf = bp->b_un.b_addr;
do {
n = u.u_count;
if(n > BUFSIZE) /* should be bufsiz, but ... */
n = BUFSIZE;
if(u.u_segflg != SEGSYS) {
if(copyin(u.u_base, bp->b_un.b_addr, n)) {
u.u_error = EFAULT;
break;
}
}
else
bcopy(u.u_base, bp->b_un.b_addr, n);
x.count = n;
x.offset = Ltol(u.u_offset);
send(ip->i_un.i_cip, &x, &y);
if(y.errno) {
u.u_error = y.errno;
break;
}
ip->i_flag |= IUPD|ICHG;
u.u_count -= n;
u.u_offset = Lladd(u.u_offset, n);
u.u_base += n;
} while(u.u_error == 0 && u.u_count != 0);
brelse(bp);
}
natrunc(ip)
struct inode *ip;
{ struct senda x;
struct rcva y;
x = nilx;
x.trannum = natrannum++;
x.cmd = NTRUNC;
x.uid = u.u_uid;
x.tag = ip->i_un.i_tag;
x.dev = ip->i_dev;
x.ino = ip->i_number;
send(ip->i_un.i_cip, &x, &y);
if(y.errno)
u.u_error = y.errno;
}
nastat(ip, ub)
struct inode *ip;
struct stat *ub;
{ struct senda x;
struct rcva y;
struct stat ds;
x = nilx;
x.trannum = natrannum++;
x.cmd = NSTAT;
x.uid = u.u_uid;
x.tag = ip->i_un.i_tag;
x.dev = ip->i_dev;
x.ino = ip->i_number;
x.ta = time;
send(ip->i_un.i_cip, &x, &y);
if(y.errno) {
u.u_error = y.errno;
return;
}
ds.st_dev = ip->i_dev;
ds.st_ino = ip->i_number;
ip->i_mode = ds.st_mode = y.mode;
ip->i_nlink = ds.st_nlink = y.nlink;
ip->i_uid = ds.st_uid = y.uid;
ip->i_gid = ds.st_gid = y.gid;
ds.st_size = ip->i_size = y.size;
ds.st_atime = y.tm[0];
ds.st_mtime = y.tm[1];
ds.st_ctime = y.tm[2];
if(copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0)
u.u_error = EFAULT;
}
/* a lot like fsnami */
nanami(p, flagp, follow)
struct nx *p;
struct argnamei *flagp;
{ register struct inode *dp, *dip;
register char *cp;
int i, fstyp;
dev_t d;
struct direct dent;
struct senda x;
struct rcva y;
cp = p->cp;
dp = p->dp;
x = nilx;
x.cmd = NNAMI;
x.uid = u.u_uid;
x.gid = u.u_gid;
/*
* dp must be a directory and
* must have X permission.
* cp is a path name relative to that directory.
*/
dirloop:
if((dp->i_mode&IFMT) != IFDIR)
u.u_error = ENOTDIR;
(void) access(dp, IEXEC);
for (i=0; *cp!='\0' && *cp!='/'; i++) {
if (i >= DIRSIZ) {
u.u_error = ENOENT;
break;
}
dent.d_name[i] = *cp++;
}
if(u.u_error)
goto outnull;
while (i < DIRSIZ)
dent.d_name[i++] = '\0';
if (dent.d_name[0] == '\0') { /* null name, e.g. "/" or "" */
if (flagp->flag != NI_SEARCH) {
u.u_error = ENOENT;
goto outnull;
}
goto out;
}
u.u_segflg = SEGSYS;
/* send off the request, get back ino, dev, flagp stuff */
x.trannum = natrannum++;
x.tag = dp->i_un.i_tag;
x.dev = dp->i_dev;
x.ino = dp->i_number;
x.count = DIRSIZ;
x.buf = dent.d_name;
while(*cp == '/')
cp++;
if(*cp=='\0') {
switch(flagp->flag) {
case NI_SEARCH:
x.flags = NSEARCH;
break;
case NI_DEL:
x.flags = NDEL;
break;
case NI_LINK:
x.flags = NLINK;
x.dev = flagp->un.il->i_dev;
x.ino = flagp->un.il->i_number;
break;
case NI_CREAT:
case NI_NXCREAT:
x.flags = NCREAT;
x.mode = flagp->un.mode;
break;
case NI_MKDIR:
x.flags = NMKDIR;
x.mode = flagp->un.mode;
break;
case NI_RMDIR:
x.flags = NRMDIR;
break;
default:
u.u_error = ENXIO;
goto outnull;
}
}
send(dp->i_un.i_cip, &x, &y);
if(y.errno) {
u.u_error = y.errno;
goto outnull;
}
if(y.flags == NOMATCH)
goto nomatch;
dent.d_ino = y.ino;
if (y.ino == 0) {
printf("y.ino 0 in nanami\n");
u.u_error = ENOENT;
goto outnull;
}
d = y.dev;
if(*cp == 0 && (flagp->flag==NI_DEL || flagp->flag==NI_RMDIR)) {
/* delete the entry, server did all but xrele */
dip = iget(dp, d, dent.d_ino);
if (dip == NULL)
goto outnull;
if (dip->i_count == 1) {
dip->i_un.i_cip = NULL;
iput(dip);
goto outnull;
}
if(dip->i_flag&ITEXT)
xrele(dip); /* free busy text */
dip->i_nlink--;
dip->i_flag |= ICHG;
iput(dip);
goto outnull;
}
/*
* Special handling for ".."
*/
fstyp = dp->i_fstyp;
if(y.flags == NROOT) { /* popped out of net fs */
if (dp == u.u_rdir)
dent.d_ino = dp->i_number;
else if (dp != rootdir && dent.d_ino==ROOTINO
&& dp->i_number == ROOTINO) {
if ((dip = dp->i_mpoint) == NULL)
panic("namei: mpoint");
iput(dp);
dp = dip;
plock(dp);
dp->i_count++;
/* was there always .. there? */
if(*cp && cp < p->nbuf + 3)
panic("nanami");
if(!*cp && cp < p->nbuf + 2)
panic("nanami2");
if(*cp)
*--cp = '/';
*--cp = '.';
*--cp = '.';
if(fstyp != dp->i_fstyp)
goto more;
goto dirloop;
}
}
dip = dp;
prele(dip);
dp = iget(dip, d, dent.d_ino);
if(dp == NULL) {
iput(dip);
goto out;
}
if (dp->i_count == 1 && nafillin(dip, dp) < 0) {
iput(dip);
dp = NULL;
goto out;
}
if(fstyp != dp->i_fstyp) {
iput(dip);
goto more;
}
/*
* Check for symbolic link
*/
if ((dp->i_mode&IFMT)==IFLNK && (follow || *cp)) {
char *ocp;
ocp = cp;
while (*cp++)
;
if (dp->i_size + (cp-ocp) >= p->nlen-1
|| ++p->nlink>8) {
u.u_error = ELOOP;
iput(dip);
goto outnull;
}
bcopy(ocp, p->nbuf+dp->i_size + 1, cp-ocp);
*(p->nbuf + dp->i_size) = '/';
u.u_base = p->nbuf;
u.u_count = dp->i_size;
u.u_offset = ltoL(0);
readi(dp);
if(u.u_error) {
iput(dip);
goto outnull;
}
cp = p->nbuf;
iput(dp);
if (*cp == '/') {
iput(dip);
while (*cp == '/')
cp++;
if ((dp = u.u_rdir) == NULL)
dp = rootdir;
plock(dp);
dp->i_count++;
} else {
dp = dip;
plock(dp);
}
if(fstyp != dp->i_fstyp)
goto more;
goto dirloop;
}
iput(dip);
if(*cp)
goto dirloop;
if(flagp->flag == NI_SEARCH && flagp->un.buf)
bcopy((caddr_t)dent.d_name, flagp->un.buf, flagp->len);
goto out;
nomatch:
/*
* Search failed.
*/
switch(flagp->flag) { /* probably creating a new file */
case NI_LINK: /* make a link */
case NI_MKDIR: /* make directory */
goto outnull;
case NI_CREAT: /* create a new file */
case NI_NXCREAT:
if(y.errno == EACCES || y.ino == 0) {
u.u_error = EACCES;
goto outnull;
}
dip = iget(dp, y.dev, y.ino);
if(dip == NULL)
goto outnull;
if (dip->i_count == 1 && nafillin(dp, dip) < 0)
goto outnull;
iput(dp);
dp = dip;
flagp->un.mode = ~flagp->un.mode;
goto out;
default:
u.u_error = ENOENT;
goto outnull;
}
out:
p->dp = dp;
return (0);
outnull:
iput(dp);
p->dp = NULL;
return (0);
more:
p->cp = cp;
p->dp = dp;
return (1);
}
struct {
int tran;
short proc, dev;
} ntx[32]; /* more debuggery */
send(cip, x, y)
struct inode *cip;
struct senda *x;
struct rcva *y;
{ int n, tn, ix;
x->version = NETVERSION;
/* until demux works, use key as a lock */
while(cip->i_un.i_fsflags)
sleep((caddr_t)cip, PZERO);
cip->i_un.i_fsflags = 1;
tn = x->trannum;
netabuf.s = 2;
for(ix = 0; ntx[ix].tran && ix < 32; ix++) {
ntx[ix].tran = tn;
ntx[ix].proc = u.u_procp->p_pid;
ntx[ix].dev = x->dev;
}
n = istwrite(cip, (char *)x, sizeof(*x));
netabuf.s = 3;
if(n == -1) {
y->errno = EIO;
goto bad;
}
netabuf.s = 4;
if(x->count > 0 && x->buf && x->cmd != NREAD) {
n = istwrite(cip, x->buf, x->count);
if(n == -1)
goto bad;
}
readagain:
netabuf.s = 5;
n = istread(cip, (char *)y, sizeof(*y), 0);
netabuf.s = 6;
if(n != sizeof(*y))
goto bad;
if(y->errno == 0 && x->cmd == NREAD) {
n = istread(cip, x->buf, y->count, 0);
if(n != y->count) {
printf("neta: read %d expected %d\n", n, y->count);
/* shut it down */
istwrite(cip, (char *)x, 0);
goto bad;
}
}
if(y->errno == 0) {
if(y->trannum != tn) {
if(y->trannum < tn) /* distant past */
goto readagain;
printf("neta: sent %d got %d\n", tn, y->trannum);
goto bad;
}
addx(x);
addy(y);
if(ix < 32)
ntx[ix].tran = 0;
cip->i_un.i_fsflags = 0;
wakeup((caddr_t)cip);
return;
}
bad:
cip->i_un.i_fsflags = 0;
if(ix < 32)
ntx[ix].tran = 0;
for(ix = 0; ix < 32; ix++)
if(ntx[ix].tran)
printf("tran %d proc %d 0x%x\n", ntx[ix].tran, ntx[ix].proc, ntx[ix].dev);
wakeup((caddr_t)cip);
addx(x);
addy(y);
if(y->errno)
return;
y->errno = EIO;
}
static struct D { struct D *a; char *b;} VER = {&VER,"\n85/6/9:neta.c\n"};
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.