V8/usr/sys/sys/nami.c

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

#include "../h/param.h"
#include "../h/systm.h"
#include "../h/inode.h"
#include "../h/mount.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/buf.h"
#include "../h/conf.h"

/*
 * Convert a pathname into a pointer to
 * a locked inode.
 *
 * func = function called to get next char of name
 *	&uchar if name is in user space
 *	&schar if name is in system space
 *	length guaranteed <= BUFSIZE if func != uchar
 * flagp
	0 for ordinary searches
	else ->flag structure with more parameters
 * follow = 1 if links are to be followed at the end of the name
 */

struct inode *
namei(func, flagp, follow)
int		(*func)();
struct argnamei	*flagp;
int		follow;
{
	register int	i;
	register char	*cp;
	struct nx	p;

	p.nbp = geteblk();
	if(func == uchar) {
		if((i = fustrlen(u.u_dirp)) < 0) {
			u.u_error = EFAULT;
			brelse(p.nbp);
			return NULL;
		}
		if(i > BUFSIZE) {
			u.u_error = ENOENT;
			brelse(p.nbp);
			return NULL;
		}
		bcopy(u.u_dirp, p.nbp->b_un.b_addr, i);
#ifdef	CHAOS
		u.u_dirp += i;
#endif
	} else {
		cp = p.nbp->b_un.b_addr;
		do; while(*cp++ = (*func)());
	}
	if(flagp != NULL) {
		cp = p.nbp->b_un.b_addr;
		while(i = *cp++) {
			if(i & 0200) {
				u.u_error = ENOENT;
				brelse(p.nbp);
				return NULL;
			}
		}
	}
	cp = p.nbp->b_un.b_addr;
	if(*cp == '/') {
		while(*cp == '/')
			cp++;
		if((p.dp = u.u_rdir) == NULL)
			p.dp = rootdir;
	} else
		p.dp = u.u_cdir;
	p.nlink = 0;
	p.cp = cp;
	plock(p.dp);
	p.dp->i_count++;

	for (;;) {
		if(p.dp->i_fstyp >= nfstyp)
			panic("namei nfstyp");
		switch((*fstypsw[p.dp->i_fstyp].t_nami)(&p, &flagp, follow)) {
		case 1:
			iput(p.dp);
			brelse(p.nbp);
			return NULL;
		case 2:
			if(*p.cp)
				break;
		case 0:
			brelse(p.nbp);
			if(flagp &&
			  (flagp->flag == NI_LINK || flagp->flag == NI_NXCREAT) &&
			   p.dp) {
				u.u_error = EEXIST;
				iput(p.dp);
				return NULL;
			}
			return p.dp;
		default:
			panic("namei ret");
		}
	}
}

ino_t
dsearch(ip, eop)
struct inode	*ip;
off_t		*eop;
{
	register struct direct	*dp;
	register char		*nm;
	register int		i;
	register int		n;
	register int		empty;
	register int		size;
	int			dpb;
	ino_t			ino;
	struct buf		*bp;

	bp = NULL;
	empty = -1;
	ino = 0;
	i = 0;
	n = 0;
	nm = u.u_dbuf;
	dpb = BSIZE(ip->i_dev) / sizeof (struct direct);
	size = ip->i_size / sizeof (struct direct);

	while (--size >= 0) {
		if (--n < 0) {
			if (bp)
				brelse(bp);
			bp = bread(ip->i_dev, bmap(ip, (daddr_t)(i/dpb), B_READ));
			if (bp->b_flags & B_ERROR) {
				brelse(bp);
				return 0;
			}
			dp = (struct direct *)bp->b_un.b_addr;
			n = dpb - 1;
		}
		if (dp->d_ino == 0) {
			if (empty < 0)
				empty = i;
		} else {
#if	DIRSIZ == 14
			if (*(long *)&nm[0] == *(long *)&dp->d_name[0] &&
			    *(long *)&nm[4] == *(long *)&dp->d_name[4] &&
			    *(long *)&nm[8] == *(long *)&dp->d_name[8] &&
			    *(short *)&nm[12] == *(short *)&dp->d_name[12]) {
#else
			if (strncmp(nm, dp->d_name, DIRSIZ) == 0) {
#endif
				bcopy((caddr_t)dp, (caddr_t)&u.u_dent, sizeof (struct direct));
				ino = dp->d_ino;
				break;
			}
		}
		i++;
		dp++;
	}
	if (bp)
		brelse(bp);
	u.u_offset = i * sizeof (struct direct);
	*eop = empty * sizeof (struct direct);
	return ino;
}

     /* USED TO BE rnami */
fsnami(p, pflagp, follow)
struct nx *p;
struct argnamei **pflagp;
{	register struct inode *dp;
	register char *cp;
	register struct buf *bp, *nbp;
	register struct direct *ep;
	register struct inode *dip;
	int i, fstyp;
	dev_t d;
	ino_t ino;
	off_t eo;
	struct argnamei *flagp = *pflagp;
	struct mount *mp;
#ifdef	CHAOS
	extern long cdevpath;
#endif	CHAOS

	cp = p->cp;
	dp = p->dp;

	/*
	 * 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;
		}
		u.u_dbuf[i] = *cp++;
	}
	if(u.u_error)
		goto out;
	while (i < DIRSIZ)
		u.u_dbuf[i++] = '\0';
	if (u.u_dbuf[0] == '\0') {		/* null name, e.g. "/" or "" */
		if (flagp) {
			u.u_error = ENOENT;
			goto out;
		}
		goto out1;
	}
	u.u_segflg = 1;
#ifdef	OLD_FSNAMI
	eo = -1;
	bp = NULL;

	for (u.u_offset=0; u.u_offset < dp->i_size;
	   u.u_offset += sizeof(struct direct), ep++) {
		/*
		 * If offset is on a block boundary,
		 * read the next directory block.
		 * Release previous if it exists.
		 */
		if((u.u_offset&BMASK(dp->i_dev)) == 0) {
			if(bp != NULL)
				brelse(bp);
			bp = bread(dp->i_dev,
				bmap(dp,(daddr_t)(u.u_offset>>BSHIFT(dp->i_dev))
					, B_READ));
			if (bp->b_flags & B_ERROR) {
				brelse(bp);
				goto out;
			}
			ep = (struct direct *)bp->b_un.b_addr;
		}
		/*
		 * Note first empty directory slot
		 * in eo for possible creat.
		 * String compare the directory entry
		 * and the current component.
		 */
		if(ep->d_ino == 0) {
			if(eo < 0)
				eo = u.u_offset;
			continue;
		}
		if (strncmp(u.u_dbuf, ep->d_name, DIRSIZ) != 0)
			continue;
		/*
		 * Here a component matched in a directory.
		 * If there is more pathname, go back to
		 * dirloop, otherwise return.
		 */
		bcopy((caddr_t)ep, (caddr_t)&u.u_dent, sizeof(struct direct));
		brelse(bp);
#else	OLD_FSNAMI
	if (dsearch(dp, &eo)) {
#endif	OLD_FSNAMI
		if(flagp && flagp->flag == NI_DEL && *cp == 0) {
			/* delete the entry */
			if(access(dp, IWRITE))
				goto out;
			if(dp->i_number == u.u_dent.d_ino) {	/* for '.' */
				dip = dp;
				dp->i_count++;
			} else
				dip = iget(dp->i_dev, u.u_dent.d_ino,
					dp->i_fstyp);
			if(dip == NULL)
				goto out;
			if(dip->i_dev != dp->i_dev) {	/* mounted FS */
				u.u_error = EBUSY;
				iput(dip);
				goto out;
			}
			if((dip->i_mode&IFMT) == IFDIR && !suser()) {
				iput(dip);
				goto out;
			}
			if(dip->i_flag&ITEXT)
				xrele(dip);		/* free busy text */
			u.u_base = (caddr_t)&u.u_dent;
			u.u_count = sizeof(struct direct);
			u.u_dent.d_ino = 0;
			writei(dp);		/* offset, segflg already set*/
			dip->i_nlink--;
			dip->i_flag |= ICHG;
			iput(dip);
			goto out;
		}
		if(flagp && flagp->flag == NI_RMDIR && *cp == 0) {
			/* can't rmdir ., .., or ROOTINO */
			/* can rmdir non-empty directory */
			if(access(dp, IWRITE))
				goto out;
			if(dp->i_number == u.u_dent.d_ino) {
rmdir:
				u.u_error = EINVAL;
				goto out;
			}
			if(u.u_dent.d_name[0] == '.' && u.u_dent.d_name[1] == '.' && u.u_dent.d_name[2] == 0)
				goto rmdir;
			if((dip = iget(dp->i_dev, u.u_dent.d_ino, dp->i_fstyp)) == NULL)
				goto rmdir;
			if(dip->i_number <= ROOTINO) {
				iput(dip);
				goto rmdir;
			}
			if(dip->i_dev != dp->i_dev || dip->i_count > 1) {
				u.u_error = EBUSY;
				iput(dip);
				goto out;
			}
			if((dip->i_mode & IFMT) != IFDIR) {
				u.u_error = ENOTDIR;
				iput(dip);
				goto out;
			}
			u.u_base = (caddr_t)&u.u_dent;
			u.u_count = sizeof(struct direct);
			u.u_dent.d_ino = 0;
			if(dp->i_nlink > 0)
				dp->i_nlink--;
			if(dip->i_nlink <= 2)
				dip->i_nlink = 0;
			else {
				u.u_error = EBUSY;
				iput(dip);
				goto out;
			}
			writei(dp);
			dip->i_flag |= ICHG;
			iput(dip);
			goto out;
		}
		/*
		 * Special handling for ".."
		 */
		if (u.u_dent.d_name[0]=='.' && u.u_dent.d_name[1]=='.' &&
		    u.u_dent.d_name[2]=='\0') {
			if (dp == u.u_rdir)
				u.u_dent.d_ino = dp->i_number;
			else if (dp != rootdir && u.u_dent.d_ino==ROOTINO &&
			   dp->i_number == ROOTINO) {
				mp = findmount(dp->i_fstyp, dp->i_dev);
				if (mp == NULL)
					panic("namei: findmount");
				iput(dp);
				dp = mp->m_inodp;
				plock(dp);
				dp->i_count++;
				cp -= 2;     /* back over .. */
				goto dirloop;
			}
		}
		d = dp->i_dev;
		ino = dp->i_number;
		fstyp = dp->i_fstyp;
		iput(dp);
		dp = iget(d, u.u_dent.d_ino, fstyp);
		if(dp == NULL)
			goto out1;
		if(fstyp != dp->i_fstyp)
			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) >= BSIZE(dp->i_dev)-1
			|| ++p->nlink>8) {
				u.u_error = ELOOP;
				goto out;
			}
			bcopy(ocp, p->nbp->b_un.b_addr+dp->i_size, cp-ocp);
			bp = bread(dp->i_dev, bmap(dp, (daddr_t)0, B_READ));
			if (bp->b_flags & B_ERROR) {
				brelse(bp);
				goto out;
			}
			bcopy(bp->b_un.b_addr, p->nbp->b_un.b_addr, dp->i_size);
			brelse(bp);
			cp = p->nbp->b_un.b_addr;
			iput(dp);
			if (*cp == '/') {
				while (*cp == '/')
					cp++;
				if ((dp = u.u_rdir) == NULL)
					dp = rootdir;
				plock(dp);
				dp->i_count++;
			} else {
				dp = iget(d, ino, fstyp);	/* retrieve original directory */
				if (dp == NULL)	/* how can this happen? */
					goto out1;
			}
			goto dirloop;
		}
#ifdef	CHAOS
#define	CHDEV_OFFSET	32
		if ((dp->i_mode & IFMT) == IFCHR && (cdevpath & (1L << (major(dp->i_un.i_rdev) - CHDEV_OFFSET))))
		{
 			char *ocp;
 
 			while (*cp == '/')
 				cp++;
 			ocp = cp;
 			while (*cp++)
 				;
 			u.u_dirp -= (cp - ocp);
 			goto out1;
		}
#endif	CHAOS
		if (*cp == '/') {
			while (*cp == '/')
				cp++;
			goto dirloop;
		}
		goto out1;
	}
	if (u.u_error)
		goto out;
	/*
	 * Search failed.
	 */
	if(flagp) {		/* probably creating a new file */
		register struct inode *dip;

		while(*cp == '/')
			cp++;
		if(*cp != 0) {
			u.u_error = ENOENT;
			goto out;
		}
		bcopy((caddr_t)u.u_dbuf, (caddr_t)u.u_dent.d_name, DIRSIZ);
		u.u_count = sizeof(struct direct);
		u.u_base = (caddr_t)&u.u_dent;
		if(eo >= 0)
			u.u_offset = eo;
		switch(flagp->flag) {
		case NI_LINK:	/* make a link */
			if(access(dp, IWRITE))
				goto out;
			if(dp->i_dev != flagp->idev) {
				u.u_error = EXDEV;
				goto out;
			}
			u.u_dent.d_ino = flagp->ino;
			writei(dp);
			goto out;
		case NI_CREAT:	/* create a new file */
		case NI_NXCREAT:
			if(access(dp, IWRITE))
				goto out;
			dip = ialloc(dp->i_dev);
			if(dip == NULL)
				goto out;
			dip->i_flag |= IACC|IUPD|ICHG;
			dip->i_mode = flagp->mode & ~u.u_cmask;
			if((dip->i_mode & IFMT) == 0)
				dip->i_mode |= IFREG;
			dip->i_nlink = 1;
			dip->i_uid = u.u_uid;
			dip->i_gid = u.u_gid;
			iupdat(dip, &time, &time, 1);
			u.u_dent.d_ino = dip->i_number;
			writei(dp);
			iput(dp);
			dp = dip;
			flagp->ino = dip->i_number;
			*pflagp = 0;
			goto out1;
		case NI_MKDIR:	/* make a new directory */
			if(access(dp, IWRITE))
				goto out;
			dip = ialloc(dp->i_dev);
			if(dip == NULL)
				goto out;
			dip->i_flag = IACC|IUPD|ICHG;
			dip->i_mode = flagp->mode & ~u.u_cmask;
			dip->i_nlink = 2;
			dip->i_uid = u.u_uid;
			dip->i_gid = u.u_gid;
			iupdat(dip, &time, &time, 1);
			dp->i_nlink++;
			u.u_dent.d_ino = dip->i_number;
			writei(dp);
			flagp->ino = dp->i_number;
			iput(dp);
			dp = dip;
			*pflagp = 0;
			goto out1;
		}
	}
	u.u_error = ENOENT;
out:
	p->dp = dp;
	return(1);
out1:
	p->dp = dp;
	return(0);
more:
	for(; *cp == '/'; cp++)
		;
	p->dp = dp;
	p->cp = cp;
	return(2);
}

/*
 * Return the next character from the
 * kernel string pointed at by dirp.
 */
schar()
{

	return(*u.u_dirp++ & 0377);
}

/*
 * Return the next character from the
 * user string pointed at by dirp.
 */
uchar()
{
	register c;

	c = fubyte(u.u_dirp++);
	if(c == -1) {
		u.u_error = EFAULT;
		c = 0;
	}
	return(c);
}

/*  (handled by asm.sed)
strncmp(s1, s2, len)
register char *s1, *s2;
register len;
{
	do {
		if (*s1 != *s2++)
			return(1);
		if (*s1++ == '\0')
			return(0);
	} while (--len);
	return(0);
}
*/