V10/sys/fs/neta.c

Compare this file to the similar file:
Show the results in this format:

#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"};