FreeBSD/sys/fs/nfsserver/nfs_nfsdport.c
/*
 * Set up nameidata for a lookup() call and do it.
 */
Set up nameidata for a lookup() call and do it.
Set up nameidata for a lookup () call and do it .
int
nfsvno_namei(struct nfsrv_descript *nd, struct nameidata *ndp,
    struct vnode *dp, int islocked, struct nfsexstuff *exp, struct thread *p,
    struct vnode **retdirp)
{
	struct componentname *cnp = &ndp->ni_cnd;
	int i;
	struct iovec aiov;
	struct uio auio;
	int lockleaf = (cnp->cn_flags & LOCKLEAF) != 0, linklen;
	int error = 0, crossmnt;
	char *cp;
	*retdirp = NULL;
	cnp->cn_nameptr = cnp->cn_pnbuf;
	ndp->ni_strictrelative = 0;
	if (dp->v_type != VDIR) {
		if (islocked)
			vput(dp);
		else
			vrele(dp);
		nfsvno_relpathbuf(ndp);
		error = ENOTDIR;
		goto out1;
	}
	if (islocked)
		NFSVOPUNLOCK(dp, 0);
	VREF(dp);
	*retdirp = dp;
	if (NFSVNO_EXRDONLY(exp))
		cnp->cn_flags |= RDONLY;
	ndp->ni_segflg = UIO_SYSSPACE;
	crossmnt = 1;
	if (nd->nd_flag & ND_PUBLOOKUP) {
		ndp->ni_loopcnt = 0;
		if (cnp->cn_pnbuf[0] == '/') {
			vrele(dp);
			for (i = 1; i < ndp->ni_pathlen; i++)
				if (cnp->cn_pnbuf[i] != '/')
					break;
			if (i == ndp->ni_pathlen) {
				error = NFSERR_ACCES;
				goto out;
			}
			dp = rootvnode;
			VREF(dp);
		}
	} else if ((nfsrv_enable_crossmntpt == 0 && NFSVNO_EXPORTED(exp)) ||
	    (nd->nd_flag & ND_NFSV4) == 0) {
		cnp->cn_flags |= NOCROSSMOUNT;
		crossmnt = 0;
	}
	cnp->cn_thread = p;
	ndp->ni_startdir = dp;
	ndp->ni_rootdir = rootvnode;
	ndp->ni_topdir = NULL;
	if (!lockleaf)
		cnp->cn_flags |= LOCKLEAF;
	for (;;) {
		cnp->cn_nameptr = cnp->cn_pnbuf;
		error = lookup(ndp);
		if (error)
			break;
		if ((cnp->cn_flags & ISSYMLINK) == 0) {
			if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0)
				nfsvno_relpathbuf(ndp);
			if (ndp->ni_vp && !lockleaf)
				NFSVOPUNLOCK(ndp->ni_vp, 0);
			break;
		}
		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
			NFSVOPUNLOCK(ndp->ni_dvp, 0);
		if (!(nd->nd_flag & ND_PUBLOOKUP)) {
			error = EINVAL;
			goto badlink2;
		}
		if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
			error = ELOOP;
			goto badlink2;
		}
		if (ndp->ni_pathlen > 1)
			cp = uma_zalloc(namei_zone, M_WAITOK);
		else
			cp = cnp->cn_pnbuf;
		aiov.iov_base = cp;
		aiov.iov_len = MAXPATHLEN;
		auio.uio_iov = &aiov;
		auio.uio_iovcnt = 1;
		auio.uio_offset = 0;
		auio.uio_rw = UIO_READ;
		auio.uio_segflg = UIO_SYSSPACE;
		auio.uio_td = NULL;
		auio.uio_resid = MAXPATHLEN;
		error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
		if (error) {
		badlink1:
			if (ndp->ni_pathlen > 1)
				uma_zfree(namei_zone, cp);
		badlink2:
			vrele(ndp->ni_dvp);
			vput(ndp->ni_vp);
			break;
		}
		linklen = MAXPATHLEN - auio.uio_resid;
		if (linklen == 0) {
			error = ENOENT;
			goto badlink1;
		}
		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
			error = ENAMETOOLONG;
			goto badlink1;
		}
		if (ndp->ni_pathlen > 1) {
			NFSBCOPY(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
			uma_zfree(namei_zone, cnp->cn_pnbuf);
			cnp->cn_pnbuf = cp;
		} else
			cnp->cn_pnbuf[linklen] = '\0';
		ndp->ni_pathlen += linklen;
		vput(ndp->ni_vp);
		ndp->ni_vp = NULL;
		if (cnp->cn_pnbuf[0] == '/') {
			vrele(ndp->ni_dvp);
			ndp->ni_dvp = ndp->ni_rootdir;
			VREF(ndp->ni_dvp);
		}
		ndp->ni_startdir = ndp->ni_dvp;
		ndp->ni_dvp = NULL;
	}
	if (!lockleaf)
		cnp->cn_flags &= ~LOCKLEAF;
out:
	if (error) {
		nfsvno_relpathbuf(ndp);
		ndp->ni_vp = NULL;
		ndp->ni_dvp = NULL;
		ndp->ni_startdir = NULL;
	} else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
		ndp->ni_dvp = NULL;
	}
out1:
	NFSEXITCODE2(error, nd);
	return (error);
}
int nfsvno_namei ( struct nfsrv_descript * nd , struct nameidata * ndp , struct vnode * dp , int islocked , struct nfsexstuff * exp , struct thread * p , struct vnode * * retdirp ) { struct componentname * cnp = & ndp -> ni_cnd ; int i ; struct iovec aiov ; struct uio auio ; int lockleaf = ( cnp -> cn_flags & LOCKLEAF ) != 0 , linklen ; int error = 0 , crossmnt ; char * cp ; * retdirp = NULL ; cnp -> cn_nameptr = cnp -> cn_pnbuf ; ndp -> ni_strictrelative = 0 ; if ( dp -> v_type != VDIR ) { if ( islocked ) vput ( dp ) ; else vrele ( dp ) ; nfsvno_relpathbuf ( ndp ) ; error = ENOTDIR ; goto out1 ; } if ( islocked ) NFSVOPUNLOCK ( dp , 0 ) ; VREF ( dp ) ; * retdirp = dp ; if ( NFSVNO_EXRDONLY ( exp ) ) cnp -> cn_flags |= RDONLY ; ndp -> ni_segflg = UIO_SYSSPACE ; crossmnt = 1 ; if ( nd -> nd_flag & ND_PUBLOOKUP ) { ndp -> ni_loopcnt = 0 ; if ( cnp -> cn_pnbuf [ 0 ] == ' ' ) { vrele ( dp ) ; for ( i = 1 ; i < ndp -> ni_pathlen ; i ++ ) if ( cnp -> cn_pnbuf [ i ] != ' ' ) break ; if ( i == ndp -> ni_pathlen ) { error = NFSERR_ACCES ; goto out ; } dp = rootvnode ; VREF ( dp ) ; } } else if ( ( nfsrv_enable_crossmntpt == 0 && NFSVNO_EXPORTED ( exp ) ) || ( nd -> nd_flag & ND_NFSV4 ) == 0 ) { cnp -> cn_flags |= NOCROSSMOUNT ; crossmnt = 0 ; } cnp -> cn_thread = p ; ndp -> ni_startdir = dp ; ndp -> ni_rootdir = rootvnode ; ndp -> ni_topdir = NULL ; if ( ! lockleaf ) cnp -> cn_flags |= LOCKLEAF ; for ( ; ; ) { cnp -> cn_nameptr = cnp -> cn_pnbuf ; error = lookup ( ndp ) ; if ( error ) break ; if ( ( cnp -> cn_flags & ISSYMLINK ) == 0 ) { if ( ( cnp -> cn_flags & ( SAVENAME | SAVESTART ) ) == 0 ) nfsvno_relpathbuf ( ndp ) ; if ( ndp -> ni_vp && ! lockleaf ) NFSVOPUNLOCK ( ndp -> ni_vp , 0 ) ; break ; } if ( ( cnp -> cn_flags & LOCKPARENT ) && ndp -> ni_pathlen == 1 ) NFSVOPUNLOCK ( ndp -> ni_dvp , 0 ) ; if ( ! ( nd -> nd_flag & ND_PUBLOOKUP ) ) { error = EINVAL ; goto badlink2 ; } if ( ndp -> ni_loopcnt ++ >= MAXSYMLINKS ) { error = ELOOP ; goto badlink2 ; } if ( ndp -> ni_pathlen > 1 ) cp = uma_zalloc ( namei_zone , M_WAITOK ) ; else cp = cnp -> cn_pnbuf ; aiov . iov_base = cp ; aiov . iov_len = MAXPATHLEN ; auio . uio_iov = & aiov ; auio . uio_iovcnt = 1 ; auio . uio_offset = 0 ; auio . uio_rw = UIO_READ ; auio . uio_segflg = UIO_SYSSPACE ; auio . uio_td = NULL ; auio . uio_resid = MAXPATHLEN ; error = VOP_READLINK ( ndp -> ni_vp , & auio , cnp -> cn_cred ) ; if ( error ) { badlink1 : if ( ndp -> ni_pathlen > 1 ) uma_zfree ( namei_zone , cp ) ; badlink2 : vrele ( ndp -> ni_dvp ) ; vput ( ndp -> ni_vp ) ; break ; } linklen = MAXPATHLEN - auio . uio_resid ; if ( linklen == 0 ) { error = ENOENT ; goto badlink1 ; } if ( linklen + ndp -> ni_pathlen >= MAXPATHLEN ) { error = ENAMETOOLONG ; goto badlink1 ; } if ( ndp -> ni_pathlen > 1 ) { NFSBCOPY ( ndp -> ni_next , cp + linklen , ndp -> ni_pathlen ) ; uma_zfree ( namei_zone , cnp -> cn_pnbuf ) ; cnp -> cn_pnbuf = cp ; } else cnp -> cn_pnbuf [ linklen ] = ' \0 ' ; ndp -> ni_pathlen += linklen ; vput ( ndp -> ni_vp ) ; ndp -> ni_vp = NULL ; if ( cnp -> cn_pnbuf [ 0 ] == ' ' ) { vrele ( ndp -> ni_dvp ) ; ndp -> ni_dvp = ndp -> ni_rootdir ; VREF ( ndp -> ni_dvp ) ; } ndp -> ni_startdir = ndp -> ni_dvp ; ndp -> ni_dvp = NULL ; } if ( ! lockleaf ) cnp -> cn_flags &= ~ LOCKLEAF ; out : if ( error ) { nfsvno_relpathbuf ( ndp ) ; ndp -> ni_vp = NULL ; ndp -> ni_dvp = NULL ; ndp -> ni_startdir = NULL ; } else if ( ( ndp -> ni_cnd . cn_flags & ( WANTPARENT | LOCKPARENT ) ) == 0 ) { ndp -> ni_dvp = NULL ; } out1 : NFSEXITCODE2 ( error , nd ) ; return ( error ) ; }
Set up nameidata for a lookup() call and do it.
Set up nameidata for a lookup () call and do it .
/*
	 * Extract and set starting directory.
	 */ /*
			 * Check for degenerate pathnames here, since lookup()
			 * panics on them.
			 */ /*
		 * Only cross mount points for NFSv4 when doing a
		 * mount while traversing the file system above
		 * the mount point, unless nfsrv_enable_crossmntpt is set.
		 */ /*
	 * Initialize for scan, set ni_startdir and bump ref on dp again
	 * because lookup() will dereference ni_startdir.
	 */ /*
		 * Call lookup() to do the real work.  If an error occurs,
		 * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
		 * we do not have to dereference anything before returning.
		 * In either case ni_startdir will be dereferenced and NULLed
		 * out.
		 */ /*
		 * Check for encountering a symbolic link.  Trivial
		 * termination occurs if no symlink encountered.
		 */ /*
		 * Validate symlink
		 */ /*
		 * Adjust or replace path
		 */ /*
		 * Cleanup refs for next loop and check if root directory
		 * should replace current directory.  Normally ni_dvp
		 * becomes the new base directory and is cleaned up when
		 * we loop.  Explicitly null pointers after invalidation
		 * to clarify operation.
		 */