xref: /csrg-svn/sys/nfs/nfs_subs.c (revision 38421)
138420Smckusick /*
238420Smckusick  * Copyright (c) 1989 The Regents of the University of California.
338420Smckusick  * All rights reserved.
438420Smckusick  *
538420Smckusick  * This code is derived from software contributed to Berkeley by
638420Smckusick  * Rick Macklem at The University of Guelph.
738420Smckusick  *
838420Smckusick  * Redistribution and use in source and binary forms are permitted
938420Smckusick  * provided that the above copyright notice and this paragraph are
1038420Smckusick  * duplicated in all such forms and that any documentation,
1138420Smckusick  * advertising materials, and other materials related to such
1238420Smckusick  * distribution and use acknowledge that the software was developed
1338420Smckusick  * by the University of California, Berkeley.  The name of the
1438420Smckusick  * University may not be used to endorse or promote products derived
1538420Smckusick  * from this software without specific prior written permission.
1638420Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1738420Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1838420Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1938420Smckusick  *
20*38421Smckusick  *	@(#)nfs_subs.c	7.2 (Berkeley) 07/05/89
2138420Smckusick  */
2238420Smckusick 
2338420Smckusick /*
2438420Smckusick  * These functions support the macros and help fiddle mbuf chains for
2538420Smckusick  * the nfs op functions. They do things like create the rpc header and
2638420Smckusick  * copy data between mbuf chains and uio lists.
2738420Smckusick  */
2838420Smckusick #include "strings.h"
2938420Smckusick #include "types.h"
3038420Smckusick #include "param.h"
3138420Smckusick #include "mount.h"
3238420Smckusick #include "dir.h"
3338420Smckusick #include "time.h"
3438420Smckusick #include "errno.h"
3538420Smckusick #include "kernel.h"
3638420Smckusick #include "malloc.h"
3738420Smckusick #include "mbuf.h"
3838420Smckusick #include "file.h"
3938420Smckusick #include "vnode.h"
4038420Smckusick #include "uio.h"
4138420Smckusick #include "namei.h"
4238420Smckusick #include "ucred.h"
4338420Smckusick #include "rpcv2.h"
4438420Smckusick #include "nfsv2.h"
4538420Smckusick #include "nfsnode.h"
4638420Smckusick #include "nfs.h"
4738420Smckusick #include "xdr_subs.h"
4838420Smckusick #include "nfsm_subs.h"
4938420Smckusick 
5038420Smckusick #define TRUE	1
5138420Smckusick #define	FALSE	0
5238420Smckusick 
5338420Smckusick /*
5438420Smckusick  * Data items converted to xdr at startup, since they are constant
5538420Smckusick  * This is kinda hokey, but may save a little time doing byte swaps
5638420Smckusick  */
5738420Smckusick u_long nfs_procids[NFS_NPROCS];
5838420Smckusick u_long nfs_xdrneg1;
5938420Smckusick u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied,
6038420Smckusick 	rpc_mismatch, rpc_auth_unix, rpc_msgaccepted;
6138420Smckusick u_long nfs_vers, nfs_prog, nfs_true, nfs_false;
6238420Smckusick /* And other global data */
6338420Smckusick static u_long *rpc_uidp = (u_long *)0;
6438420Smckusick static u_long nfs_xid = 1;
6538420Smckusick static char *rpc_unixauth;
6638420Smckusick extern long hostid;
6738420Smckusick extern enum vtype v_type[NFLNK+1];
6838420Smckusick 
6938420Smckusick /* Function ret types */
7038420Smckusick static char *nfs_unixauth();
7138420Smckusick 
7238420Smckusick /*
7338420Smckusick  * Create the header for an rpc request packet
7438420Smckusick  * The function nfs_unixauth() creates a unix style authorization string
7538420Smckusick  * and returns a ptr to it.
7638420Smckusick  * The hsiz is the size of the rest of the nfs request header.
7738420Smckusick  * (just used to decide if a cluster is a good idea)
7838420Smckusick  * nb: Note that the prog, vers and proc args are already in xdr byte order
7938420Smckusick  */
8038420Smckusick struct mbuf *nfsm_reqh(prog, vers, proc, cred, hsiz, bpos, mb, retxid)
8138420Smckusick 	u_long prog;
8238420Smckusick 	u_long vers;
8338420Smckusick 	u_long proc;
8438420Smckusick 	struct ucred *cred;
8538420Smckusick 	int hsiz;
8638420Smckusick 	caddr_t *bpos;
8738420Smckusick 	struct mbuf **mb;
8838420Smckusick 	u_long *retxid;
8938420Smckusick {
9038420Smckusick 	register struct mbuf *mreq, *m;
9138420Smckusick 	register u_long *p;
9238420Smckusick 	struct mbuf *m1;
9338420Smckusick 	char *ap;
9438420Smckusick 	int asiz, siz;
9538420Smckusick 
9638420Smckusick 	NFSMGETHDR(mreq);
9738420Smckusick 	asiz = (((cred->cr_ngroups > 10) ? 10 : cred->cr_ngroups)<<2);
9838420Smckusick 	asiz += nfsm_rndup(hostnamelen)+(9*NFSX_UNSIGNED);
9938420Smckusick 
10038420Smckusick 	/* If we need a lot, alloc a cluster ?? */
10138420Smckusick 	if ((asiz+hsiz+RPC_SIZ) > MHLEN)
10238420Smckusick 		NFSMCLGET(mreq, M_WAIT);
10338420Smckusick 	mreq->m_len = NFSMSIZ(mreq);
10438420Smckusick 	siz = mreq->m_len;
10538420Smckusick 	m1 = mreq;
10638420Smckusick 	/*
10738420Smckusick 	 * Alloc enough mbufs
10838420Smckusick 	 * We do it now to avoid all sleeps after the call to nfs_unixauth()
10938420Smckusick 	 */
11038420Smckusick 	while ((asiz+RPC_SIZ) > siz) {
11138420Smckusick 		MGET(m, M_WAIT, MT_DATA);
11238420Smckusick 		m1->m_next = m;
11338420Smckusick 		m->m_len = MLEN;
11438420Smckusick 		siz += MLEN;
11538420Smckusick 		m1 = m;
11638420Smckusick 	}
11738420Smckusick 	p = mtod(mreq, u_long *);
11838420Smckusick 	*p++ = *retxid = txdr_unsigned(++nfs_xid);
11938420Smckusick 	*p++ = rpc_call;
12038420Smckusick 	*p++ = rpc_vers;
12138420Smckusick 	*p++ = prog;
12238420Smckusick 	*p++ = vers;
12338420Smckusick 	*p++ = proc;
12438420Smckusick 
12538420Smckusick 	/* Now we can call nfs_unixauth() and copy it in */
12638420Smckusick 	ap = nfs_unixauth(cred);
12738420Smckusick 	m = mreq;
12838420Smckusick 	siz = m->m_len-RPC_SIZ;
12938420Smckusick 	if (asiz <= siz) {
13038420Smckusick 		bcopy(ap, (caddr_t)p, asiz);
13138420Smckusick 		m->m_len = asiz+RPC_SIZ;
13238420Smckusick 	} else {
13338420Smckusick 		bcopy(ap, (caddr_t)p, siz);
13438420Smckusick 		ap += siz;
13538420Smckusick 		asiz -= siz;
13638420Smckusick 		while (asiz > 0) {
13738420Smckusick 			siz = (asiz > MLEN) ? MLEN : asiz;
13838420Smckusick 			m = m->m_next;
13938420Smckusick 			bcopy(ap, mtod(m, caddr_t), siz);
14038420Smckusick 			m->m_len = siz;
14138420Smckusick 			asiz -= siz;
14238420Smckusick 			ap += siz;
14338420Smckusick 		}
14438420Smckusick 	}
14538420Smckusick 
14638420Smckusick 	/* Finally, return values */
14738420Smckusick 	*mb = m;
14838420Smckusick 	*bpos = mtod(m, caddr_t)+m->m_len;
14938420Smckusick 	return (mreq);
15038420Smckusick }
15138420Smckusick 
15238420Smckusick /*
15338420Smckusick  * copies mbuf chain to the uio scatter/gather list
15438420Smckusick  */
15538420Smckusick nfsm_mbuftouio(mrep, uiop, siz, dpos)
15638420Smckusick 	struct mbuf **mrep;
15738420Smckusick 	struct uio *uiop;
15838420Smckusick 	int siz;
15938420Smckusick 	caddr_t *dpos;
16038420Smckusick {
16138420Smckusick 	register int xfer, left, len;
16238420Smckusick 	register struct mbuf *mp;
16338420Smckusick 	register char *mbufcp, *uiocp;
16438420Smckusick 	long uiosiz, rem;
16538420Smckusick 
16638420Smckusick 	mp = *mrep;
16738420Smckusick 	mbufcp = *dpos;
16838420Smckusick 	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
16938420Smckusick 	rem = nfsm_rndup(siz)-siz;
17038420Smckusick 	while (siz > 0) {
17138420Smckusick 		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
17238420Smckusick 			return(EFBIG);
17338420Smckusick 		left = uiop->uio_iov->iov_len;
17438420Smckusick 		uiocp = uiop->uio_iov->iov_base;
17538420Smckusick 		if (left > siz)
17638420Smckusick 			left = siz;
17738420Smckusick 		uiosiz = left;
17838420Smckusick 		while (left > 0) {
17938420Smckusick 			while (len == 0) {
18038420Smckusick 				mp = mp->m_next;
18138420Smckusick 				if (mp == NULL)
18238420Smckusick 					return (EBADRPC);
18338420Smckusick 				mbufcp = mtod(mp, caddr_t);
18438420Smckusick 				len = mp->m_len;
18538420Smckusick 			}
18638420Smckusick 			xfer = (left > len) ? len : left;
18738420Smckusick #ifdef notdef
18838420Smckusick 			/* Not Yet.. */
18938420Smckusick 			if (uiop->uio_iov->iov_op != NULL)
19038420Smckusick 				(*(uiop->uio_iov->iov_op))
19138420Smckusick 				(mbufcp, uiocp, xfer);
19238420Smckusick 			else
19338420Smckusick #endif
19438420Smckusick 			if (uiop->uio_segflg == UIO_SYSSPACE)
19538420Smckusick 				bcopy(mbufcp, uiocp, xfer);
19638420Smckusick 			else
19738420Smckusick 				copyout(mbufcp, uiocp, xfer);
19838420Smckusick 			left -= xfer;
19938420Smckusick 			len -= xfer;
20038420Smckusick 			mbufcp += xfer;
20138420Smckusick 			uiocp += xfer;
20238420Smckusick 			uiop->uio_resid -= xfer;
20338420Smckusick 		}
20438420Smckusick 		if (uiop->uio_iov->iov_len <= siz) {
20538420Smckusick 			uiop->uio_iovcnt--;
20638420Smckusick 			uiop->uio_iov++;
20738420Smckusick 		} else {
20838420Smckusick 			uiop->uio_iov->iov_base += uiosiz;
20938420Smckusick 			uiop->uio_iov->iov_len -= uiosiz;
21038420Smckusick 		}
21138420Smckusick 		siz -= uiosiz;
21238420Smckusick 	}
21338420Smckusick 	if (rem > 0)
21438420Smckusick 		mbufcp += rem;
21538420Smckusick 	*dpos = mbufcp;
21638420Smckusick 	*mrep = mp;
21738420Smckusick 	return(0);
21838420Smckusick }
21938420Smckusick 
22038420Smckusick /*
22138420Smckusick  * copies a uio scatter/gather list to an mbuf chain...
22238420Smckusick  */
22338420Smckusick nfsm_uiotombuf(uiop, mq, siz, bpos)
22438420Smckusick 	register struct uio *uiop;
22538420Smckusick 	struct mbuf **mq;
22638420Smckusick 	int siz;
22738420Smckusick 	caddr_t *bpos;
22838420Smckusick {
22938420Smckusick 	register struct mbuf *mp;
23038420Smckusick 	struct mbuf *mp2;
23138420Smckusick 	long xfer, left, uiosiz, off;
23238420Smckusick 	int clflg;
23338420Smckusick 	int rem, len;
23438420Smckusick 	char *cp, *uiocp;
23538420Smckusick 
23638420Smckusick 	if (siz > MLEN)		/* or should it >= MCLBYTES ?? */
23738420Smckusick 		clflg = 1;
23838420Smckusick 	else
23938420Smckusick 		clflg = 0;
24038420Smckusick 	rem = nfsm_rndup(siz)-siz;
24138420Smckusick 	mp2 = *mq;
24238420Smckusick 	while (siz > 0) {
24338420Smckusick 		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
24438420Smckusick 			return(EINVAL);
24538420Smckusick 		left = uiop->uio_iov->iov_len;
24638420Smckusick 		uiocp = uiop->uio_iov->iov_base;
24738420Smckusick 		if (left > siz)
24838420Smckusick 			left = siz;
24938420Smckusick 		uiosiz = left;
25038420Smckusick 		while (left > 0) {
25138420Smckusick 			MGET(mp, M_WAIT, MT_DATA);
25238420Smckusick 			if (clflg)
25338420Smckusick 				NFSMCLGET(mp, M_WAIT);
25438420Smckusick 			mp->m_len = NFSMSIZ(mp);
25538420Smckusick 			mp2->m_next = mp;
25638420Smckusick 			mp2 = mp;
25738420Smckusick 			xfer = (left > mp->m_len) ? mp->m_len : left;
25838420Smckusick #ifdef notdef
25938420Smckusick 			/* Not Yet.. */
26038420Smckusick 			if (uiop->uio_iov->iov_op != NULL)
26138420Smckusick 				(*(uiop->uio_iov->iov_op))
26238420Smckusick 				(uiocp, mtod(mp, caddr_t), xfer);
26338420Smckusick 			else
26438420Smckusick #endif
26538420Smckusick 			if (uiop->uio_segflg == UIO_SYSSPACE)
26638420Smckusick 				bcopy(uiocp, mtod(mp, caddr_t), xfer);
26738420Smckusick 			else
26838420Smckusick 				copyin(uiocp, mtod(mp, caddr_t), xfer);
26938420Smckusick 			len = mp->m_len;
27038420Smckusick 			mp->m_len = xfer;
27138420Smckusick 			left -= xfer;
27238420Smckusick 			uiocp += xfer;
27338420Smckusick 			uiop->uio_resid -= xfer;
27438420Smckusick 		}
27538420Smckusick 		if (uiop->uio_iov->iov_len <= siz) {
27638420Smckusick 			uiop->uio_iovcnt--;
27738420Smckusick 			uiop->uio_iov++;
27838420Smckusick 		} else {
27938420Smckusick 			uiop->uio_iov->iov_base += uiosiz;
28038420Smckusick 			uiop->uio_iov->iov_len -= uiosiz;
28138420Smckusick 		}
28238420Smckusick 		siz -= uiosiz;
28338420Smckusick 	}
28438420Smckusick 	if (rem > 0) {
28538420Smckusick 		if (rem > (len-mp->m_len)) {
28638420Smckusick 			MGET(mp, M_WAIT, MT_DATA);
28738420Smckusick 			mp->m_len = 0;
28838420Smckusick 			mp2->m_next = mp;
28938420Smckusick 		}
29038420Smckusick 		cp = mtod(mp, caddr_t)+mp->m_len;
29138420Smckusick 		for (left = 0; left < rem; left++)
29238420Smckusick 			*cp++ = '\0';
29338420Smckusick 		mp->m_len += rem;
29438420Smckusick 		*bpos = cp;
29538420Smckusick 	} else
29638420Smckusick 		*bpos = mtod(mp, caddr_t)+mp->m_len;
29738420Smckusick 	*mq = mp;
29838420Smckusick 	return(0);
29938420Smckusick }
30038420Smckusick 
30138420Smckusick /*
30238420Smckusick  * Help break down an mbuf chain by setting the first siz bytes contiguous
30338420Smckusick  * pointed to by returned val.
30438420Smckusick  * If Updateflg == True we can overwrite the first part of the mbuf data
30538420Smckusick  * This is used by the macros nfsm_disect and nfsm_disecton for tough
30638420Smckusick  * cases. (The macros use the vars. dpos and dpos2)
30738420Smckusick  */
30838420Smckusick nfsm_disct(mdp, dposp, siz, left, updateflg, cp2)
30938420Smckusick 	struct mbuf **mdp;
31038420Smckusick 	caddr_t *dposp;
31138420Smckusick 	int siz;
31238420Smckusick 	int left;
31338420Smckusick 	int updateflg;
31438420Smckusick 	caddr_t *cp2;
31538420Smckusick {
31638420Smckusick 	register struct mbuf *mp, *mp2;
31738420Smckusick 	register int siz2, xfer;
31838420Smckusick 	register caddr_t p;
31938420Smckusick 	caddr_t p2;
32038420Smckusick 
32138420Smckusick 	mp = *mdp;
32238420Smckusick 	while (left == 0) {
32338420Smckusick 		*mdp = mp = mp->m_next;
32438420Smckusick 		if (mp == NULL)
32538420Smckusick 			return(EBADRPC);
32638420Smckusick 		left = mp->m_len;
32738420Smckusick 		*dposp = mtod(mp, caddr_t);
32838420Smckusick 	}
32938420Smckusick 	if (left >= siz) {
33038420Smckusick 		*cp2 = *dposp;
33138420Smckusick 		*dposp += siz;
33238420Smckusick 		return(0);
33338420Smckusick 	} else if (mp->m_next == NULL) {
33438420Smckusick 		return(EBADRPC);
33538420Smckusick 	} else if (siz > MCLBYTES) {
33638420Smckusick 		panic("nfs S too big");
33738420Smckusick 	} else {
33838420Smckusick 		/* Iff update, you can overwrite, else must alloc new mbuf */
33938420Smckusick 		if (updateflg) {
34038420Smckusick 			NFSMINOFF(mp);
34138420Smckusick 		} else {
34238420Smckusick 			MGET(mp2, M_WAIT, MT_DATA);
34338420Smckusick 			mp2->m_next = mp->m_next;
34438420Smckusick 			mp->m_next = mp2;
34538420Smckusick 			mp->m_len -= left;
34638420Smckusick 			mp = mp2;
34738420Smckusick 		}
34838420Smckusick 		/* Alloc cluster iff we need it */
34938420Smckusick 		if (!M_HASCL(mp) && siz > NFSMSIZ(mp)) {
35038420Smckusick 			NFSMCLGET(mp, M_WAIT);
35138420Smckusick 			if (!M_HASCL(mp))
35238420Smckusick 				return(ENOBUFS);
35338420Smckusick 		}
35438420Smckusick 		*cp2 = p = mtod(mp, caddr_t);
35538420Smckusick 		bcopy(*dposp, p, left);		/* Copy what was left */
35638420Smckusick 		siz2 = siz-left;
35738420Smckusick 		p += left;
35838420Smckusick 		mp2 = mp->m_next;
35938420Smckusick 		/* Loop arround copying up the siz2 bytes */
36038420Smckusick 		while (siz2 > 0) {
36138420Smckusick 			if (mp2 == NULL)
36238420Smckusick 				return (EBADRPC);
36338420Smckusick 			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
36438420Smckusick 			bcopy(mtod(mp2, caddr_t), p, xfer);
36538420Smckusick 			NFSMADV(mp2, xfer);
36638420Smckusick 			mp2->m_len -= xfer;
36738420Smckusick 			siz2 -= xfer;
36838420Smckusick 			if (siz2 > 0)
36938420Smckusick 				mp2 = mp2->m_next;
37038420Smckusick 		}
37138420Smckusick 		mp->m_len = siz;
37238420Smckusick 		*mdp = mp2;
37338420Smckusick 		*dposp = mtod(mp2, caddr_t);
37438420Smckusick 		return (0);
37538420Smckusick 	}
37638420Smckusick }
37738420Smckusick 
37838420Smckusick /*
37938420Smckusick  * Advance the position in the mbuf chain with/without freeing mbufs
38038420Smckusick  */
38138420Smckusick nfs_adv(mdp, dposp, offs, left)
38238420Smckusick 	struct mbuf **mdp;
38338420Smckusick 	caddr_t *dposp;
38438420Smckusick 	int offs;
38538420Smckusick 	int left;
38638420Smckusick {
38738420Smckusick 	register struct mbuf *m;
38838420Smckusick 	register int s;
38938420Smckusick 
39038420Smckusick 	m = *mdp;
39138420Smckusick 	s = left;
39238420Smckusick 	while (s < offs) {
39338420Smckusick 		offs -= s;
39438420Smckusick 		m = m->m_next;
39538420Smckusick 		if (m == NULL)
39638420Smckusick 			return(EBADRPC);
39738420Smckusick 		s = m->m_len;
39838420Smckusick 	}
39938420Smckusick 	*mdp = m;
40038420Smckusick 	*dposp = mtod(m, caddr_t)+offs;
40138420Smckusick 	return(0);
40238420Smckusick }
40338420Smckusick 
40438420Smckusick /*
40538420Smckusick  * Copy a string into mbufs for the hard cases...
40638420Smckusick  */
40738420Smckusick nfsm_strtmbuf(mb, bpos, cp, siz)
40838420Smckusick 	struct mbuf **mb;
40938420Smckusick 	char **bpos;
41038420Smckusick 	char *cp;
41138420Smckusick 	long siz;
41238420Smckusick {
41338420Smckusick 	register struct mbuf *m1, *m2;
41438420Smckusick 	long left, xfer, len, tlen;
41538420Smckusick 	u_long *p;
41638420Smckusick 	int putsize;
41738420Smckusick 
41838420Smckusick 	putsize = 1;
41938420Smckusick 	m2 = *mb;
42038420Smckusick 	left = NFSMSIZ(m2)-m2->m_len;
42138420Smckusick 	if (left > 0) {
42238420Smckusick 		p = ((u_long *)(*bpos));
42338420Smckusick 		*p++ = txdr_unsigned(siz);
42438420Smckusick 		putsize = 0;
42538420Smckusick 		left -= NFSX_UNSIGNED;
42638420Smckusick 		m2->m_len += NFSX_UNSIGNED;
42738420Smckusick 		if (left > 0) {
42838420Smckusick 			bcopy(cp, (caddr_t) p, left);
42938420Smckusick 			siz -= left;
43038420Smckusick 			cp += left;
43138420Smckusick 			m2->m_len += left;
43238420Smckusick 			left = 0;
43338420Smckusick 		}
43438420Smckusick 	}
43538420Smckusick 	/* Loop arround adding mbufs */
43638420Smckusick 	while (siz > 0) {
43738420Smckusick 		MGET(m1, M_WAIT, MT_DATA);
43838420Smckusick 		if (siz > MLEN)
43938420Smckusick 			NFSMCLGET(m1, M_WAIT);
44038420Smckusick 		m1->m_len = NFSMSIZ(m1);
44138420Smckusick 		m2->m_next = m1;
44238420Smckusick 		m2 = m1;
44338420Smckusick 		p = mtod(m1, u_long *);
44438420Smckusick 		tlen = 0;
44538420Smckusick 		if (putsize) {
44638420Smckusick 			*p++ = txdr_unsigned(siz);
44738420Smckusick 			m1->m_len -= NFSX_UNSIGNED;
44838420Smckusick 			tlen = NFSX_UNSIGNED;
44938420Smckusick 			putsize = 0;
45038420Smckusick 		}
45138420Smckusick 		if (siz < m1->m_len) {
45238420Smckusick 			len = nfsm_rndup(siz);
45338420Smckusick 			xfer = siz;
45438420Smckusick 			if (xfer < len)
45538420Smckusick 				*(p+(xfer>>2)) = 0;
45638420Smckusick 		} else {
45738420Smckusick 			xfer = len = m1->m_len;
45838420Smckusick 		}
45938420Smckusick 		bcopy(cp, (caddr_t) p, xfer);
46038420Smckusick 		m1->m_len = len+tlen;
46138420Smckusick 		siz -= xfer;
46238420Smckusick 		cp += xfer;
46338420Smckusick 	}
46438420Smckusick 	*mb = m1;
46538420Smckusick 	*bpos = mtod(m1, caddr_t)+m1->m_len;
46638420Smckusick 	return(0);
46738420Smckusick }
46838420Smckusick 
46938420Smckusick /*
47038420Smckusick  * Called once to initialize data structures...
47138420Smckusick  */
47238420Smckusick nfsinit()
47338420Smckusick {
47438420Smckusick 	register int i;
47538420Smckusick 
47638420Smckusick 	rpc_vers = txdr_unsigned(RPC_VER2);
47738420Smckusick 	rpc_call = txdr_unsigned(RPC_CALL);
47838420Smckusick 	rpc_reply = txdr_unsigned(RPC_REPLY);
47938420Smckusick 	rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
48038420Smckusick 	rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
48138420Smckusick 	rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
48238420Smckusick 	rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
48338420Smckusick 	nfs_vers = txdr_unsigned(NFS_VER2);
48438420Smckusick 	nfs_prog = txdr_unsigned(NFS_PROG);
48538420Smckusick 	nfs_true = txdr_unsigned(TRUE);
48638420Smckusick 	nfs_false = txdr_unsigned(FALSE);
48738420Smckusick 	/* Loop thru nfs procids */
48838420Smckusick 	for (i = 0; i < NFS_NPROCS; i++)
48938420Smckusick 		nfs_procids[i] = txdr_unsigned(i);
49038420Smckusick 	v_type[0] = VNON;
49138420Smckusick 	v_type[1] = VREG;
49238420Smckusick 	v_type[2] = VDIR;
49338420Smckusick 	v_type[3] = VBLK;
49438420Smckusick 	v_type[4] = VCHR;
49538420Smckusick 	v_type[5] = VLNK;
49638420Smckusick 	nfs_xdrneg1 = txdr_unsigned(-1);
49738420Smckusick 	nfs_nhinit();			/* Init the nfsnode table */
49838420Smckusick 	/* And start timer */
49938420Smckusick 	nfs_timer();
50038420Smckusick }
50138420Smckusick 
50238420Smckusick /*
50338420Smckusick  * Fill in the rest of the rpc_unixauth and return it
50438420Smckusick  */
50538420Smckusick static char *nfs_unixauth(cr)
50638420Smckusick 	register struct ucred *cr;
50738420Smckusick {
50838420Smckusick 	register u_long *p;
50938420Smckusick 	register int i;
51038420Smckusick 	int ngr;
51138420Smckusick 
51238420Smckusick 	/* Maybe someday there should be a cache of AUTH_SHORT's */
51338420Smckusick 	if ((p = rpc_uidp) == NULL) {
51438420Smckusick 		i = nfsm_rndup(hostnamelen)+(19*NFSX_UNSIGNED);
51538420Smckusick 		MALLOC(p, u_long *, i, M_TEMP, M_WAITOK);
51638420Smckusick 		bzero((caddr_t)p, i);
51738420Smckusick 		rpc_unixauth = (caddr_t)p;
51838420Smckusick 		*p++ = txdr_unsigned(RPCAUTH_UNIX);
51938420Smckusick 		p++;	/* Fill in size later */
52038420Smckusick 		*p++ = hostid;
52138420Smckusick 		*p++ = txdr_unsigned(hostnamelen);
52238420Smckusick 		i = nfsm_rndup(hostnamelen);
52338420Smckusick 		bcopy(hostname, (caddr_t)p, hostnamelen);
52438420Smckusick 		p += (i>>2);
52538420Smckusick 		rpc_uidp = p;
52638420Smckusick 	}
52738420Smckusick 	*p++ = txdr_unsigned(cr->cr_uid);
52838420Smckusick 	*p++ = txdr_unsigned(cr->cr_groups[0]);
52938420Smckusick 	ngr = (cr->cr_ngroups > 10) ? 10 : cr->cr_ngroups;
53038420Smckusick 	*p++ = txdr_unsigned(ngr);
53138420Smckusick 	for (i = 0; i < ngr; i++)
53238420Smckusick 		*p++ = txdr_unsigned(cr->cr_groups[i]);
53338420Smckusick 	/* And add the AUTH_NULL */
53438420Smckusick 	*p++ = 0;
53538420Smckusick 	*p = 0;
53638420Smckusick 	i = (((caddr_t)p)-rpc_unixauth)-12;
53738420Smckusick 	p = (u_long *)(rpc_unixauth+4);
53838420Smckusick 	*p = txdr_unsigned(i);
53938420Smckusick 	return(rpc_unixauth);
54038420Smckusick }
54138420Smckusick 
54238420Smckusick /*
54338420Smckusick  * Attribute cache routines.
54438420Smckusick  * nfs_loadattrcache() - loads or updates the cache contents from attributes
54538420Smckusick  *	that are on the mbuf list
54638420Smckusick  * nfs_getattrcache() - returns valid attributes if found in cache, returns
54738420Smckusick  *	error otherwise
54838420Smckusick  */
54938420Smckusick 
55038420Smckusick /*
55138420Smckusick  * Load the attribute cache (that lives in the nfsnode table) with
55238420Smckusick  * the values on the mbuf list and
55338420Smckusick  * Iff vap not NULL
55438420Smckusick  *    copy the attributes to *vaper
55538420Smckusick  */
55638420Smckusick nfs_loadattrcache(vp, mdp, dposp, vaper)
55738420Smckusick 	register struct vnode *vp;
55838420Smckusick 	struct mbuf **mdp;
55938420Smckusick 	caddr_t *dposp;
56038420Smckusick 	struct vattr *vaper;
56138420Smckusick {
56238420Smckusick 	register struct vattr *vap;
56338420Smckusick 	nfsm_vars;
56438420Smckusick 	struct nfsnode *np;
56538420Smckusick 
56638420Smckusick 	md = *mdp;
56738420Smckusick 	dpos = *dposp;
56838420Smckusick 	t1 = (mtod(md, caddr_t)+md->m_len)-dpos;
56938420Smckusick 	if (error = nfsm_disct(&md, &dpos, NFSX_FATTR, t1, TRUE, &cp2))
57038420Smckusick 		return (error);
57138420Smckusick 	p = (u_long *)cp2;
57238420Smckusick 	np = VTONFS(vp);
57338420Smckusick 	vap = &np->n_vattr;
57438420Smckusick 	vap->va_type = nfstov_type(*p++);
57538420Smckusick 	vap->va_mode = nfstov_mode(*p++);
57638420Smckusick 	vap->va_nlink = fxdr_unsigned(u_short, *p++);
57738420Smckusick 	vap->va_uid = fxdr_unsigned(uid_t, *p++);
57838420Smckusick 	vap->va_gid = fxdr_unsigned(gid_t, *p++);
57938420Smckusick 	vap->va_size = fxdr_unsigned(u_long, *p++);
58038420Smckusick 	vap->va_size1 = 0;		/* OR -1 ?? */
58138420Smckusick 	vap->va_blocksize = fxdr_unsigned(long, *p++);
58238420Smckusick 	vap->va_rdev = fxdr_unsigned(dev_t, *p++);
58338420Smckusick 	vap->va_bytes = fxdr_unsigned(long, *p++);
58438420Smckusick 	vap->va_bytes1 = -1;
58538420Smckusick 	vap->va_fsid = fxdr_unsigned(long, *p++);
58638420Smckusick 	vap->va_fileid = fxdr_unsigned(long, *p++);
58738420Smckusick 	fxdr_time(p, &(vap->va_atime));
58838420Smckusick 	p += 2;
58938420Smckusick 	fxdr_time(p, &(vap->va_mtime));
59038420Smckusick 	p += 2;
59138420Smckusick 	fxdr_time(p, &(vap->va_ctime));
59238420Smckusick 	np->n_attrstamp = time.tv_sec;
59338420Smckusick 	*dposp = dpos;
59438420Smckusick 	*mdp = md;
59538420Smckusick 	if (vaper != NULL)
59638420Smckusick 		bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
59738420Smckusick 	return (0);
59838420Smckusick }
59938420Smckusick 
60038420Smckusick /*
60138420Smckusick  * Check the time stamp
60238420Smckusick  * If the cache is valid, copy contents to *vap and return 0
60338420Smckusick  * otherwise return an error
60438420Smckusick  */
60538420Smckusick nfs_getattrcache(vp, vap)
60638420Smckusick 	register struct vnode *vp;
60738420Smckusick 	struct vattr *vap;
60838420Smckusick {
60938420Smckusick 	register struct nfsnode *np;
61038420Smckusick 
61138420Smckusick 	np = VTONFS(vp);
61238420Smckusick 	if ((time.tv_sec-np->n_attrstamp) < NFS_ATTRTIMEO) {
61338420Smckusick 		nfsstats.attrcache_hits++;
61438420Smckusick 		bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr));
61538420Smckusick 		return (0);
61638420Smckusick 	} else {
61738420Smckusick 		nfsstats.attrcache_misses++;
61838420Smckusick 		return (ENOENT);
61938420Smckusick 	}
62038420Smckusick }
62138420Smckusick 
62238420Smckusick #ifndef OPFLAG
62338420Smckusick #define	OPFLAG	(CREATE | DELETE | LOOKUP)
62438420Smckusick #endif
62538420Smckusick 
62638420Smckusick /*
62738420Smckusick  * nfs_namei - a liitle like namei(), but for one element only
62838420Smckusick  *	essentially look up file handle, fill in ndp and call VOP_LOOKUP()
62938420Smckusick  */
63038420Smckusick nfs_namei(ndp, fhp, len, mdp, dposp)
63138420Smckusick 	register struct nameidata *ndp;
63238420Smckusick 	fhandle_t *fhp;
63338420Smckusick 	int len;
63438420Smckusick 	struct mbuf **mdp;
63538420Smckusick 	caddr_t *dposp;
63638420Smckusick {
63738420Smckusick 	register int i, rem;
63838420Smckusick 	register struct mbuf *md;
63938420Smckusick 	register char *cp;
64038420Smckusick 	struct vnode *dp = (struct vnode *)0;
64138420Smckusick 	struct vnode *tdp;
64238420Smckusick 	struct mount *mp;
64338420Smckusick 	int flag;
64438420Smckusick 	int docache;
64538420Smckusick 	int wantparent;
64638420Smckusick 	int lockparent;
64738420Smckusick 	int rootflg = 0;
64838420Smckusick 	int error = 0;
64938420Smckusick 
65038420Smckusick 	ndp->ni_vp = ndp->ni_dvp = (struct vnode *)0;
65138420Smckusick 	flag = ndp->ni_nameiop & OPFLAG;
65238420Smckusick 	wantparent = ndp->ni_nameiop & (LOCKPARENT | WANTPARENT);
65338420Smckusick 	lockparent = ndp->ni_nameiop & LOCKPARENT;
65438420Smckusick 	docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE;
65538420Smckusick 	if (flag == DELETE || wantparent)
65638420Smckusick 		docache = 0;
65738420Smckusick 
65838420Smckusick 	/* Fill in the nameidata and call lookup */
65938420Smckusick 	cp = *dposp;
66038420Smckusick 	md = *mdp;
66138420Smckusick 	rem = mtod(md, caddr_t)+md->m_len-cp;
66238420Smckusick 	ndp->ni_hash = 0;
66338420Smckusick 	for (i = 0; i < len;) {
66438420Smckusick 		if (rem == 0) {
66538420Smckusick 			md = md->m_next;
66638420Smckusick 			if (md == NULL)
66738420Smckusick 				return (EBADRPC);
66838420Smckusick 			cp = mtod(md, caddr_t);
66938420Smckusick 			rem = md->m_len;
67038420Smckusick 		}
67138420Smckusick 		if (*cp == '\0' || *cp == '/')
67238420Smckusick 			return (EINVAL);
67338420Smckusick 		if (*cp & 0200)
67438420Smckusick 			if ((*cp&0377) == ('/'|0200) || flag != DELETE)
67538420Smckusick 				return (EINVAL);
67638420Smckusick 		ndp->ni_dent.d_name[i++] = *cp;
67738420Smckusick 		ndp->ni_hash += (unsigned char)*cp * i;
67838420Smckusick 		cp++;
67938420Smckusick 		rem--;
68038420Smckusick 	}
68138420Smckusick 	*mdp = md;
68238420Smckusick 	len = nfsm_rndup(len)-len;
68338420Smckusick 	if (len > 0)
68438420Smckusick 		*dposp = cp+len;
68538420Smckusick 	else
68638420Smckusick 		*dposp = cp;
68738420Smckusick 	ndp->ni_namelen = i;
68838420Smckusick 	ndp->ni_dent.d_namlen = i;
68938420Smckusick 	ndp->ni_dent.d_name[i] = '\0';
69038420Smckusick 	ndp->ni_pathlen = 0;
69138420Smckusick 	ndp->ni_dirp = ndp->ni_ptr = &ndp->ni_dent.d_name[0];
69238420Smckusick 	ndp->ni_next = &ndp->ni_dent.d_name[i];
69338420Smckusick 	ndp->ni_loopcnt = 0;	/* Not actually used for now */
69438420Smckusick 	ndp->ni_endoff = 0;
69538420Smckusick 	if (docache)
69638420Smckusick 		ndp->ni_makeentry = 1;
69738420Smckusick 	else
69838420Smckusick 		ndp->ni_makeentry = 0;
69938420Smckusick 	ndp->ni_isdotdot = (i == 2 &&
70038420Smckusick 		ndp->ni_dent.d_name[1] == '.' && ndp->ni_dent.d_name[0] == '.');
70138420Smckusick 
70238420Smckusick 	/*
70338420Smckusick 	 * Must remember if this is root so that cr_uid can be set to
70438420Smckusick 	 * mp->m_exroot at mount points
70538420Smckusick 	 * Then call nfsrv_fhtovp() to get the locked directory vnode
70638420Smckusick 	 */
70738420Smckusick 	if (ndp->ni_cred->cr_uid == 0)
70838420Smckusick 		rootflg++;
70938420Smckusick 	if (error = nfsrv_fhtovp(fhp, TRUE, &dp, ndp->ni_cred))
71038420Smckusick 		return (error);
71138420Smckusick 
71238420Smckusick 	/*
71338420Smckusick 	 * Handle "..": two special cases.
71438420Smckusick 	 * 1. If at root directory (e.g. after chroot)
71538420Smckusick 	 *    then ignore it so can't get out.
71638420Smckusick 	 * 2. If this vnode is the root of a mounted
71738420Smckusick 	 *    file system, then replace it with the
71838420Smckusick 	 *    vnode which was mounted on so we take the
71938420Smckusick 	 *    .. in the other file system.
72038420Smckusick 	 */
72138420Smckusick 	if (ndp->ni_isdotdot) {
72238420Smckusick 		for (;;) {
72338420Smckusick 			if (dp == rootdir) {
72438420Smckusick 				ndp->ni_dvp = dp;
72538420Smckusick 				dp->v_count++;
72638420Smckusick 				goto nextname;
72738420Smckusick 			}
72838420Smckusick 			if ((dp->v_flag & VROOT) == 0)
72938420Smckusick 				break;
73038420Smckusick 			tdp = dp;
73138420Smckusick 			dp = dp->v_mount->m_vnodecovered;
73238420Smckusick 			vput(tdp);
73338420Smckusick 			if ((dp->v_mount->m_flag & M_EXPORTED) == 0)
73438420Smckusick 				return (EACCES);
73538420Smckusick 			VOP_LOCK(dp);
73638420Smckusick 			dp->v_count++;
73738420Smckusick 			if (rootflg)
73838420Smckusick 				ndp->ni_cred->cr_uid = dp->v_mount->m_exroot;
73938420Smckusick 		}
74038420Smckusick 	}
74138420Smckusick 
74238420Smckusick 	/*
74338420Smckusick 	 * We now have a segment name to search for, and a directory to search.
74438420Smckusick 	 */
74538420Smckusick 	if (error = VOP_LOOKUP(dp, ndp)) {
74638420Smckusick 		if (ndp->ni_vp != NULL)
74738420Smckusick 			panic("leaf should be empty");
74838420Smckusick 		/*
74938420Smckusick 		 * If creating and at end of pathname, then can consider
75038420Smckusick 		 * allowing file to be created.
75138420Smckusick 		 */
75238420Smckusick 		if (ndp->ni_dvp->v_mount->m_flag & (M_RDONLY | M_EXRDONLY))
75338420Smckusick 			error = EROFS;
75438420Smckusick 		if (flag == LOOKUP || flag == DELETE || error != ENOENT)
75538420Smckusick 			goto bad;
75638420Smckusick 		/*
75738420Smckusick 		 * We return with ni_vp NULL to indicate that the entry
75838420Smckusick 		 * doesn't currently exist, leaving a pointer to the
75938420Smckusick 		 * (possibly locked) directory inode in ndp->ni_dvp.
76038420Smckusick 		 */
76138420Smckusick 		return (0);	/* should this be ENOENT? */
76238420Smckusick 	}
76338420Smckusick 
76438420Smckusick 	/*
76538420Smckusick 	 * Check for symbolic link
76638420Smckusick 	 */
76738420Smckusick 	dp = ndp->ni_vp;
76838420Smckusick #ifdef notdef
76938420Smckusick 	if ((dp->v_type == VLNK) &&
77038420Smckusick 	    (ndp->ni_nameiop & FOLLOW)) {
77138420Smckusick 		struct iovec aiov;
77238420Smckusick 		struct uio auio;
77338420Smckusick 		int linklen;
77438420Smckusick 
77538420Smckusick 		if (++ndp->ni_loopcnt > MAXSYMLINKS) {
77638420Smckusick 			error = ELOOP;
77738420Smckusick 			goto bad2;
77838420Smckusick 		}
77938420Smckusick 		MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
78038420Smckusick 		aiov.iov_base = cp;
78138420Smckusick 		aiov.iov_len = MAXPATHLEN;
78238420Smckusick 		auio.uio_iov = &aiov;
78338420Smckusick 		auio.uio_iovcnt = 1;
78438420Smckusick 		auio.uio_offset = 0;
78538420Smckusick 		auio.uio_rw = UIO_READ;
78638420Smckusick 		auio.uio_segflg = UIO_SYSSPACE;
78738420Smckusick 		auio.uio_resid = MAXPATHLEN;
78838420Smckusick 		if (error = VOP_READLINK(dp, &auio, ndp->ni_cred)) {
78938420Smckusick 			free(cp, M_NAMEI);
79038420Smckusick 			goto bad2;
79138420Smckusick 		}
79238420Smckusick 		linklen = MAXPATHLEN - auio.uio_resid;
79338420Smckusick 		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
79438420Smckusick 			free(cp, M_NAMEI);
79538420Smckusick 			error = ENAMETOOLONG;
79638420Smckusick 			goto bad2;
79738420Smckusick 		}
79838420Smckusick 		bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
79938420Smckusick 		ndp->ni_pnbuf = cp;
80038420Smckusick 		} else
80138420Smckusick 			ndp->ni_pnbuf[linklen] = '\0';
80238420Smckusick 		ndp->ni_ptr = cp;
80338420Smckusick 		ndp->ni_pathlen += linklen;
80438420Smckusick 		vput(dp);
80538420Smckusick 		dp = ndp->ni_dvp;
80638420Smckusick 		goto start;
80738420Smckusick 	}
80838420Smckusick #endif
80938420Smckusick 
81038420Smckusick 	/*
81138420Smckusick 	 * Check to see if the vnode has been mounted on;
81238420Smckusick 	 * if so find the root of the mounted file system.
81338420Smckusick 	 * Ignore NFS mount points
81438420Smckusick 	 */
81538420Smckusick mntloop:
81638420Smckusick 	while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
81738420Smckusick 		mp->m_fsid.val[1] != MOUNT_NFS) {
81838420Smckusick 		while(mp->m_flag & M_MLOCK) {
81938420Smckusick 			mp->m_flag |= M_MWAIT;
82038420Smckusick 			sleep((caddr_t)mp, PVFS);
82138420Smckusick 			goto mntloop;
82238420Smckusick 		}
82338420Smckusick 		error = VFS_ROOT(mp, &tdp);
82438420Smckusick 		if (error || (mp->m_flag & M_EXPORTED) == 0)
82538420Smckusick 			goto bad2;
82638420Smckusick 		vput(dp);
82738420Smckusick 		ndp->ni_vp = dp = tdp;
82838420Smckusick 		if (rootflg)
82938420Smckusick 			ndp->ni_cred->cr_uid = mp->m_exroot;
83038420Smckusick 	}
83138420Smckusick 
83238420Smckusick nextname:
83338420Smckusick 	/*
834*38421Smckusick 	 * Check for read-only file systems.
83538420Smckusick 	 */
836*38421Smckusick 	if (flag == DELETE || flag == RENAME) {
837*38421Smckusick 		/*
838*38421Smckusick 		 * Disallow directory write attempts on read-only
839*38421Smckusick 		 * file systems.
840*38421Smckusick 		 */
841*38421Smckusick 		if ((dp->v_mount->m_flag & (M_RDONLY|M_EXRDONLY)) ||
842*38421Smckusick 		    (wantparent && (ndp->ni_dvp->v_mount->m_flag & M_RDONLY))) {
843*38421Smckusick 			error = EROFS;
844*38421Smckusick 			goto bad2;
845*38421Smckusick 		}
846*38421Smckusick 	}
84738420Smckusick 
84838420Smckusick 	/*
84938420Smckusick 	 * Kludge city... This is hokey, but since ufs_rename() calls
85038420Smckusick 	 * namei() and namei() expects ni_cdir to be set, what can I
85138420Smckusick 	 * do. Fortunately rename() holds onto the parent so I don't
85238420Smckusick 	 * have to increment the v_count.
85338420Smckusick 	 */
85438420Smckusick 	if (!wantparent)
85538420Smckusick 		vrele(ndp->ni_dvp);
85638420Smckusick 	else
85738420Smckusick 		ndp->ni_cdir = ndp->ni_dvp;
85838420Smckusick 
85938420Smckusick 	if ((ndp->ni_nameiop & LOCKLEAF) == 0)
86038420Smckusick 		VOP_UNLOCK(dp);
86138420Smckusick 	return (0);
86238420Smckusick 
86338420Smckusick bad2:
86438420Smckusick 	if (lockparent)
86538420Smckusick 		VOP_UNLOCK(ndp->ni_dvp);
86638420Smckusick 	vrele(ndp->ni_dvp);
86738420Smckusick bad:
86838420Smckusick 	vput(dp);
86938420Smckusick 	ndp->ni_vp = NULL;
87038420Smckusick 	return (error);
87138420Smckusick }
87238420Smckusick 
87338420Smckusick /*
87438420Smckusick  * A fiddled version of m_adj() that ensures null fill to a long
87538420Smckusick  * boundary and only trims off the back end
87638420Smckusick  */
87738420Smckusick nfsm_adj(mp, len, nul)
87838420Smckusick 	struct mbuf *mp;
87938420Smckusick 	register int len;
88038420Smckusick 	int nul;
88138420Smckusick {
88238420Smckusick 	register struct mbuf *m;
88338420Smckusick 	register int count, i;
88438420Smckusick 	register char *cp;
88538420Smckusick 
88638420Smckusick 	/*
88738420Smckusick 	 * Trim from tail.  Scan the mbuf chain,
88838420Smckusick 	 * calculating its length and finding the last mbuf.
88938420Smckusick 	 * If the adjustment only affects this mbuf, then just
89038420Smckusick 	 * adjust and return.  Otherwise, rescan and truncate
89138420Smckusick 	 * after the remaining size.
89238420Smckusick 	 */
89338420Smckusick 	count = 0;
89438420Smckusick 	m = mp;
89538420Smckusick 	for (;;) {
89638420Smckusick 		count += m->m_len;
89738420Smckusick 		if (m->m_next == (struct mbuf *)0)
89838420Smckusick 			break;
89938420Smckusick 		m = m->m_next;
90038420Smckusick 	}
90138420Smckusick 	if (m->m_len >= len) {
90238420Smckusick 		m->m_len -= len;
90338420Smckusick 		if (nul > 0) {
90438420Smckusick 			cp = mtod(m, caddr_t)+m->m_len-nul;
90538420Smckusick 			for (i = 0; i < nul; i++)
90638420Smckusick 				*cp++ = '\0';
90738420Smckusick 		}
90838420Smckusick 		return;
90938420Smckusick 	}
91038420Smckusick 	count -= len;
91138420Smckusick 	if (count < 0)
91238420Smckusick 		count = 0;
91338420Smckusick 	/*
91438420Smckusick 	 * Correct length for chain is "count".
91538420Smckusick 	 * Find the mbuf with last data, adjust its length,
91638420Smckusick 	 * and toss data from remaining mbufs on chain.
91738420Smckusick 	 */
91838420Smckusick 	for (m = mp; m; m = m->m_next) {
91938420Smckusick 		if (m->m_len >= count) {
92038420Smckusick 			m->m_len = count;
92138420Smckusick 			if (nul > 0) {
92238420Smckusick 				cp = mtod(m, caddr_t)+m->m_len-nul;
92338420Smckusick 				for (i = 0; i < nul; i++)
92438420Smckusick 					*cp++ = '\0';
92538420Smckusick 			}
92638420Smckusick 			break;
92738420Smckusick 		}
92838420Smckusick 		count -= m->m_len;
92938420Smckusick 	}
93038420Smckusick 	while (m = m->m_next)
93138420Smckusick 		m->m_len = 0;
93238420Smckusick }
93338420Smckusick 
93438420Smckusick /*
93538420Smckusick  * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
93638420Smckusick  * 	- look up fsid in mount list (if not found ret error)
93738420Smckusick  *	- check that it is exported
93838420Smckusick  *	- get vp by calling VFS_FHTOVP() macro
93938420Smckusick  *	- if not lockflag unlock it with VOP_UNLOCK()
94038420Smckusick  *	- if cred->cr_uid == 0 set it to m_exroot
94138420Smckusick  */
94238420Smckusick nfsrv_fhtovp(fhp, lockflag, vpp, cred)
94338420Smckusick 	fhandle_t *fhp;
94438420Smckusick 	int lockflag;
94538420Smckusick 	struct vnode **vpp;
94638420Smckusick 	struct ucred *cred;
94738420Smckusick {
94838420Smckusick 	register struct mount *mp;
94938420Smckusick 	int error;
95038420Smckusick 
95138420Smckusick 	if ((mp = getvfs(&fhp->fh_fsid)) == NULL)
95238420Smckusick 		return (ESTALE);
95338420Smckusick 	if ((mp->m_flag & M_EXPORTED) == 0)
95438420Smckusick 		return (EACCES);
95538420Smckusick 	if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp))
95638420Smckusick 		return (ESTALE);
95738420Smckusick 	if (cred->cr_uid == 0)
95838420Smckusick 		cred->cr_uid = mp->m_exroot;
95938420Smckusick 	if (!lockflag)
96038420Smckusick 		VOP_UNLOCK(*vpp);
96138420Smckusick 	return (0);
96238420Smckusick }
96338420Smckusick 
964