Home | History | Annotate | Line # | Download | only in server
nfs_nfsdserv.c revision 1.1
      1 /*	$NetBSD: nfs_nfsdserv.c,v 1.1 2013/09/30 07:19:55 dholland Exp $	*/
      2 /*-
      3  * Copyright (c) 1989, 1993
      4  *	The Regents of the University of California.  All rights reserved.
      5  *
      6  * This code is derived from software contributed to Berkeley by
      7  * Rick Macklem at The University of Guelph.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  * 4. Neither the name of the University nor the names of its contributors
     18  *    may be used to endorse or promote products derived from this software
     19  *    without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  *
     33  */
     34 
     35 #include <sys/cdefs.h>
     36 /* __FBSDID("FreeBSD: head/sys/fs/nfsserver/nfs_nfsdserv.c 245613 2013-01-18 19:42:08Z delphij "); */
     37 __RCSID("$NetBSD: nfs_nfsdserv.c,v 1.1 2013/09/30 07:19:55 dholland Exp $");
     38 
     39 /*
     40  * nfs version 2, 3 and 4 server calls to vnode ops
     41  * - these routines generally have 3 phases
     42  *   1 - break down and validate rpc request in mbuf list
     43  *   2 - do the vnode ops for the request, usually by calling a nfsvno_XXX()
     44  *       function in nfsd_port.c
     45  *   3 - build the rpc reply in an mbuf list
     46  * For nfsv4, these functions are called for each Op within the Compound RPC.
     47  */
     48 
     49 #ifndef APPLEKEXT
     50 #include <fs/nfs/nfsport.h>
     51 
     52 /* Global vars */
     53 extern u_int32_t newnfs_false, newnfs_true;
     54 extern enum vtype nv34tov_type[8];
     55 extern struct timeval nfsboottime;
     56 extern int nfs_rootfhset;
     57 extern int nfsrv_enable_crossmntpt;
     58 #endif	/* !APPLEKEXT */
     59 
     60 static int	nfs_async = 0;
     61 SYSCTL_DECL(_vfs_nfsd);
     62 SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0,
     63     "Tell client that writes were synced even though they were not");
     64 
     65 /*
     66  * This list defines the GSS mechanisms supported.
     67  * (Don't ask me how you get these strings from the RFC stuff like
     68  *  iso(1), org(3)... but someone did it, so I don't need to know.)
     69  */
     70 static struct nfsgss_mechlist nfsgss_mechlist[] = {
     71 	{ 9, "\052\206\110\206\367\022\001\002\002", 11 },
     72 	{ 0, "", 0 },
     73 };
     74 
     75 /* local functions */
     76 static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
     77     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
     78     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
     79     int *diraft_retp, nfsattrbit_t *attrbitp,
     80     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
     81     int pathlen);
     82 static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
     83     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
     84     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
     85     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
     86     NFSPROC_T *p, struct nfsexstuff *exp);
     87 
     88 /*
     89  * nfs access service (not a part of NFS V2)
     90  */
     91 APPLESTATIC int
     92 nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
     93     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
     94 {
     95 	u_int32_t *tl;
     96 	int getret, error = 0;
     97 	struct nfsvattr nva;
     98 	u_int32_t testmode, nfsmode, supported = 0;
     99 	accmode_t deletebit;
    100 
    101 	if (nd->nd_repstat) {
    102 		nfsrv_postopattr(nd, 1, &nva);
    103 		goto out;
    104 	}
    105 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
    106 	nfsmode = fxdr_unsigned(u_int32_t, *tl);
    107 	if ((nd->nd_flag & ND_NFSV4) &&
    108 	    (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
    109 	     NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
    110 	     NFSACCESS_EXECUTE))) {
    111 		nd->nd_repstat = NFSERR_INVAL;
    112 		vput(vp);
    113 		goto out;
    114 	}
    115 	if (nfsmode & NFSACCESS_READ) {
    116 		supported |= NFSACCESS_READ;
    117 		if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
    118 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
    119 			nfsmode &= ~NFSACCESS_READ;
    120 	}
    121 	if (nfsmode & NFSACCESS_MODIFY) {
    122 		supported |= NFSACCESS_MODIFY;
    123 		if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
    124 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
    125 			nfsmode &= ~NFSACCESS_MODIFY;
    126 	}
    127 	if (nfsmode & NFSACCESS_EXTEND) {
    128 		supported |= NFSACCESS_EXTEND;
    129 		if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
    130 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
    131 			nfsmode &= ~NFSACCESS_EXTEND;
    132 	}
    133 	if (nfsmode & NFSACCESS_DELETE) {
    134 		supported |= NFSACCESS_DELETE;
    135 		if (vp->v_type == VDIR)
    136 			deletebit = VDELETE_CHILD;
    137 		else
    138 			deletebit = VDELETE;
    139 		if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
    140 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
    141 			nfsmode &= ~NFSACCESS_DELETE;
    142 	}
    143 	if (vnode_vtype(vp) == VDIR)
    144 		testmode = NFSACCESS_LOOKUP;
    145 	else
    146 		testmode = NFSACCESS_EXECUTE;
    147 	if (nfsmode & testmode) {
    148 		supported |= (nfsmode & testmode);
    149 		if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
    150 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
    151 			nfsmode &= ~testmode;
    152 	}
    153 	nfsmode &= supported;
    154 	if (nd->nd_flag & ND_NFSV3) {
    155 		getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
    156 		nfsrv_postopattr(nd, getret, &nva);
    157 	}
    158 	vput(vp);
    159 	if (nd->nd_flag & ND_NFSV4) {
    160 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
    161 		*tl++ = txdr_unsigned(supported);
    162 	} else
    163 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
    164 	*tl = txdr_unsigned(nfsmode);
    165 
    166 out:
    167 	NFSEXITCODE2(0, nd);
    168 	return (0);
    169 nfsmout:
    170 	vput(vp);
    171 	NFSEXITCODE2(error, nd);
    172 	return (error);
    173 }
    174 
    175 /*
    176  * nfs getattr service
    177  */
    178 APPLESTATIC int
    179 nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
    180     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
    181 {
    182 	struct nfsvattr nva;
    183 	fhandle_t fh;
    184 	int at_root = 0, error = 0, supports_nfsv4acls;
    185 	struct nfsreferral *refp;
    186 	nfsattrbit_t attrbits, tmpbits;
    187 	struct mount *mp;
    188 	struct vnode *tvp = NULL;
    189 	struct vattr va;
    190 	uint64_t mounted_on_fileno = 0;
    191 	accmode_t accmode;
    192 
    193 	if (nd->nd_repstat)
    194 		goto out;
    195 	if (nd->nd_flag & ND_NFSV4) {
    196 		error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
    197 		if (error) {
    198 			vput(vp);
    199 			goto out;
    200 		}
    201 
    202 		/*
    203 		 * Check for a referral.
    204 		 */
    205 		refp = nfsv4root_getreferral(vp, NULL, 0);
    206 		if (refp != NULL) {
    207 			(void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
    208 			    &nd->nd_repstat);
    209 			vput(vp);
    210 			goto out;
    211 		}
    212 		if (nd->nd_repstat == 0) {
    213 			accmode = 0;
    214 			NFSSET_ATTRBIT(&tmpbits, &attrbits);
    215 			if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) {
    216 				NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL);
    217 				accmode |= VREAD_ACL;
    218 			}
    219 			if (NFSNONZERO_ATTRBIT(&tmpbits))
    220 				accmode |= VREAD_ATTRIBUTES;
    221 			if (accmode != 0)
    222 				nd->nd_repstat = nfsvno_accchk(vp, accmode,
    223 				    nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
    224 				    NFSACCCHK_VPISLOCKED, NULL);
    225 		}
    226 	}
    227 	if (!nd->nd_repstat)
    228 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
    229 	if (!nd->nd_repstat) {
    230 		if (nd->nd_flag & ND_NFSV4) {
    231 			if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
    232 				nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
    233 			if (!nd->nd_repstat)
    234 				nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
    235 				    &nva, &attrbits, nd->nd_cred, p);
    236 			if (nd->nd_repstat == 0) {
    237 				supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
    238 				mp = vp->v_mount;
    239 				if (nfsrv_enable_crossmntpt != 0 &&
    240 				    vp->v_type == VDIR &&
    241 				    (vp->v_vflag & VV_ROOT) != 0 &&
    242 				    vp != rootvnode) {
    243 					tvp = mp->mnt_vnodecovered;
    244 					VREF(tvp);
    245 					at_root = 1;
    246 				} else
    247 					at_root = 0;
    248 				vfs_ref(mp);
    249 				NFSVOPUNLOCK(vp, 0);
    250 				if (at_root != 0) {
    251 					if ((nd->nd_repstat =
    252 					     NFSVOPLOCK(tvp, LK_SHARED)) == 0) {
    253 						nd->nd_repstat = VOP_GETATTR(
    254 						    tvp, &va, nd->nd_cred);
    255 						vput(tvp);
    256 					} else
    257 						vrele(tvp);
    258 					if (nd->nd_repstat == 0)
    259 						mounted_on_fileno = (uint64_t)
    260 						    va.va_fileid;
    261 					else
    262 						at_root = 0;
    263 				}
    264 				if (nd->nd_repstat == 0)
    265 					nd->nd_repstat = vfs_busy(mp, 0);
    266 				vfs_rel(mp);
    267 				if (nd->nd_repstat == 0) {
    268 					(void)nfsvno_fillattr(nd, mp, vp, &nva,
    269 					    &fh, 0, &attrbits, nd->nd_cred, p,
    270 					    isdgram, 1, supports_nfsv4acls,
    271 					    at_root, mounted_on_fileno);
    272 					vfs_unbusy(mp);
    273 				}
    274 				vrele(vp);
    275 			} else
    276 				vput(vp);
    277 		} else {
    278 			nfsrv_fillattr(nd, &nva);
    279 			vput(vp);
    280 		}
    281 	} else {
    282 		vput(vp);
    283 	}
    284 
    285 out:
    286 	NFSEXITCODE2(error, nd);
    287 	return (error);
    288 }
    289 
    290 /*
    291  * nfs setattr service
    292  */
    293 APPLESTATIC int
    294 nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
    295     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
    296 {
    297 	struct nfsvattr nva, nva2;
    298 	u_int32_t *tl;
    299 	int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
    300 	struct timespec guard = { 0, 0 };
    301 	nfsattrbit_t attrbits, retbits;
    302 	nfsv4stateid_t stateid;
    303 	NFSACL_T *aclp = NULL;
    304 
    305 	if (nd->nd_repstat) {
    306 		nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
    307 		goto out;
    308 	}
    309 #ifdef NFS4_ACL_EXTATTR_NAME
    310 	aclp = acl_alloc(M_WAITOK);
    311 	aclp->acl_cnt = 0;
    312 #endif
    313 	NFSVNO_ATTRINIT(&nva);
    314 	NFSZERO_ATTRBIT(&retbits);
    315 	if (nd->nd_flag & ND_NFSV4) {
    316 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
    317 		stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
    318 		NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
    319 	}
    320 	error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p);
    321 	if (error)
    322 		goto nfsmout;
    323 	preat_ret = nfsvno_getattr(vp, &nva2, nd->nd_cred, p, 1);
    324 	if (!nd->nd_repstat)
    325 		nd->nd_repstat = preat_ret;
    326 	if (nd->nd_flag & ND_NFSV3) {
    327 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
    328 		gcheck = fxdr_unsigned(int, *tl);
    329 		if (gcheck) {
    330 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
    331 			fxdr_nfsv3time(tl, &guard);
    332 		}
    333 		if (!nd->nd_repstat && gcheck &&
    334 		    (nva2.na_ctime.tv_sec != guard.tv_sec ||
    335 		     nva2.na_ctime.tv_nsec != guard.tv_nsec))
    336 			nd->nd_repstat = NFSERR_NOT_SYNC;
    337 		if (nd->nd_repstat) {
    338 			vput(vp);
    339 #ifdef NFS4_ACL_EXTATTR_NAME
    340 			acl_free(aclp);
    341 #endif
    342 			nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
    343 			goto out;
    344 		}
    345 	} else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
    346 		nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
    347 
    348 	/*
    349 	 * Now that we have all the fields, lets do it.
    350 	 * If the size is being changed write access is required, otherwise
    351 	 * just check for a read only file system.
    352 	 */
    353 	if (!nd->nd_repstat) {
    354 		if (NFSVNO_NOTSETSIZE(&nva)) {
    355 			if (NFSVNO_EXRDONLY(exp) ||
    356 			    (vfs_flags(vnode_mount(vp)) & MNT_RDONLY))
    357 				nd->nd_repstat = EROFS;
    358 		} else {
    359 			if (vnode_vtype(vp) != VREG)
    360 				nd->nd_repstat = EINVAL;
    361 			else if (nva2.na_uid != nd->nd_cred->cr_uid ||
    362 			    NFSVNO_EXSTRICTACCESS(exp))
    363 				nd->nd_repstat = nfsvno_accchk(vp,
    364 				    VWRITE, nd->nd_cred, exp, p,
    365 				    NFSACCCHK_NOOVERRIDE,
    366 				    NFSACCCHK_VPISLOCKED, NULL);
    367 		}
    368 	}
    369 	if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
    370 		nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
    371 		    &nva, &attrbits, exp, p);
    372 
    373 	if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
    374 	    /*
    375 	     * For V4, try setting the attrbutes in sets, so that the
    376 	     * reply bitmap will be correct for an error case.
    377 	     */
    378 	    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
    379 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
    380 		NFSVNO_ATTRINIT(&nva2);
    381 		NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
    382 		NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
    383 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
    384 		    exp);
    385 		if (!nd->nd_repstat) {
    386 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
    387 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
    388 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
    389 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
    390 		}
    391 	    }
    392 	    if (!nd->nd_repstat &&
    393 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
    394 		NFSVNO_ATTRINIT(&nva2);
    395 		NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
    396 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
    397 		    exp);
    398 		if (!nd->nd_repstat)
    399 		    NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
    400 	    }
    401 	    if (!nd->nd_repstat &&
    402 		(NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
    403 		 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
    404 		NFSVNO_ATTRINIT(&nva2);
    405 		NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
    406 		NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
    407 		if (nva.na_vaflags & VA_UTIMES_NULL) {
    408 			nva2.na_vaflags |= VA_UTIMES_NULL;
    409 			NFSVNO_SETACTIVE(&nva2, vaflags);
    410 		}
    411 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
    412 		    exp);
    413 		if (!nd->nd_repstat) {
    414 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
    415 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
    416 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
    417 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
    418 		}
    419 	    }
    420 	    if (!nd->nd_repstat &&
    421 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) {
    422 		NFSVNO_ATTRINIT(&nva2);
    423 		NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
    424 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
    425 		    exp);
    426 		if (!nd->nd_repstat)
    427 		    NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
    428 	    }
    429 
    430 #ifdef NFS4_ACL_EXTATTR_NAME
    431 	    if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
    432 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
    433 		nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
    434 		if (!nd->nd_repstat)
    435 		    NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
    436 	    }
    437 #endif
    438 	} else if (!nd->nd_repstat) {
    439 		nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
    440 		    exp);
    441 	}
    442 	if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
    443 		postat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
    444 		if (!nd->nd_repstat)
    445 			nd->nd_repstat = postat_ret;
    446 	}
    447 	vput(vp);
    448 #ifdef NFS4_ACL_EXTATTR_NAME
    449 	acl_free(aclp);
    450 #endif
    451 	if (nd->nd_flag & ND_NFSV3)
    452 		nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
    453 	else if (nd->nd_flag & ND_NFSV4)
    454 		(void) nfsrv_putattrbit(nd, &retbits);
    455 	else if (!nd->nd_repstat)
    456 		nfsrv_fillattr(nd, &nva);
    457 
    458 out:
    459 	NFSEXITCODE2(0, nd);
    460 	return (0);
    461 nfsmout:
    462 	vput(vp);
    463 #ifdef NFS4_ACL_EXTATTR_NAME
    464 	acl_free(aclp);
    465 #endif
    466 	if (nd->nd_flag & ND_NFSV4) {
    467 		/*
    468 		 * For all nd_repstat, the V4 reply includes a bitmap,
    469 		 * even NFSERR_BADXDR, which is what this will end up
    470 		 * returning.
    471 		 */
    472 		(void) nfsrv_putattrbit(nd, &retbits);
    473 	}
    474 	NFSEXITCODE2(error, nd);
    475 	return (error);
    476 }
    477 
    478 /*
    479  * nfs lookup rpc
    480  * (Also performs lookup parent for v4)
    481  */
    482 APPLESTATIC int
    483 nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
    484     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
    485     struct nfsexstuff *exp)
    486 {
    487 	struct nameidata named;
    488 	vnode_t vp, dirp = NULL;
    489 	int error = 0, dattr_ret = 1;
    490 	struct nfsvattr nva, dattr;
    491 	char *bufp;
    492 	u_long *hashp;
    493 
    494 	if (nd->nd_repstat) {
    495 		nfsrv_postopattr(nd, dattr_ret, &dattr);
    496 		goto out;
    497 	}
    498 
    499 	/*
    500 	 * For some reason, if dp is a symlink, the error
    501 	 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
    502 	 */
    503 	if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
    504 		nd->nd_repstat = NFSERR_SYMLINK;
    505 		vrele(dp);
    506 		goto out;
    507 	}
    508 
    509 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
    510 	    LOCKLEAF | SAVESTART);
    511 	nfsvno_setpathbuf(&named, &bufp, &hashp);
    512 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
    513 	if (error) {
    514 		vrele(dp);
    515 		nfsvno_relpathbuf(&named);
    516 		goto out;
    517 	}
    518 	if (!nd->nd_repstat) {
    519 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
    520 	} else {
    521 		vrele(dp);
    522 		nfsvno_relpathbuf(&named);
    523 	}
    524 	if (nd->nd_repstat) {
    525 		if (dirp) {
    526 			if (nd->nd_flag & ND_NFSV3)
    527 				dattr_ret = nfsvno_getattr(dirp, &dattr,
    528 				    nd->nd_cred, p, 0);
    529 			vrele(dirp);
    530 		}
    531 		if (nd->nd_flag & ND_NFSV3)
    532 			nfsrv_postopattr(nd, dattr_ret, &dattr);
    533 		goto out;
    534 	}
    535 	if (named.ni_startdir)
    536 		vrele(named.ni_startdir);
    537 	nfsvno_relpathbuf(&named);
    538 	vp = named.ni_vp;
    539 	if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) &&
    540 	    vp->v_type != VDIR && vp->v_type != VLNK)
    541 		/*
    542 		 * Only allow lookup of VDIR and VLNK for traversal of
    543 		 * non-exported volumes during NFSv4 mounting.
    544 		 */
    545 		nd->nd_repstat = ENOENT;
    546 	if (nd->nd_repstat == 0)
    547 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
    548 	if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
    549 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
    550 	if (vpp != NULL && nd->nd_repstat == 0)
    551 		*vpp = vp;
    552 	else
    553 		vput(vp);
    554 	if (dirp) {
    555 		if (nd->nd_flag & ND_NFSV3)
    556 			dattr_ret = nfsvno_getattr(dirp, &dattr, nd->nd_cred,
    557 			    p, 0);
    558 		vrele(dirp);
    559 	}
    560 	if (nd->nd_repstat) {
    561 		if (nd->nd_flag & ND_NFSV3)
    562 			nfsrv_postopattr(nd, dattr_ret, &dattr);
    563 		goto out;
    564 	}
    565 	if (nd->nd_flag & ND_NFSV2) {
    566 		(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
    567 		nfsrv_fillattr(nd, &nva);
    568 	} else if (nd->nd_flag & ND_NFSV3) {
    569 		(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
    570 		nfsrv_postopattr(nd, 0, &nva);
    571 		nfsrv_postopattr(nd, dattr_ret, &dattr);
    572 	}
    573 
    574 out:
    575 	NFSEXITCODE2(error, nd);
    576 	return (error);
    577 }
    578 
    579 /*
    580  * nfs readlink service
    581  */
    582 APPLESTATIC int
    583 nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
    584     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
    585 {
    586 	u_int32_t *tl;
    587 	mbuf_t mp = NULL, mpend = NULL;
    588 	int getret = 1, len;
    589 	struct nfsvattr nva;
    590 
    591 	if (nd->nd_repstat) {
    592 		nfsrv_postopattr(nd, getret, &nva);
    593 		goto out;
    594 	}
    595 	if (vnode_vtype(vp) != VLNK) {
    596 		if (nd->nd_flag & ND_NFSV2)
    597 			nd->nd_repstat = ENXIO;
    598 		else
    599 			nd->nd_repstat = EINVAL;
    600 	}
    601 	if (!nd->nd_repstat)
    602 		nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p,
    603 		    &mp, &mpend, &len);
    604 	if (nd->nd_flag & ND_NFSV3)
    605 		getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
    606 	vput(vp);
    607 	if (nd->nd_flag & ND_NFSV3)
    608 		nfsrv_postopattr(nd, getret, &nva);
    609 	if (nd->nd_repstat)
    610 		goto out;
    611 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
    612 	*tl = txdr_unsigned(len);
    613 	mbuf_setnext(nd->nd_mb, mp);
    614 	nd->nd_mb = mpend;
    615 	nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend);
    616 
    617 out:
    618 	NFSEXITCODE2(0, nd);
    619 	return (0);
    620 }
    621 
    622 /*
    623  * nfs read service
    624  */
    625 APPLESTATIC int
    626 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
    627     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
    628 {
    629 	u_int32_t *tl;
    630 	int error = 0, cnt, getret = 1, reqlen, eof = 0;
    631 	mbuf_t m2, m3;
    632 	struct nfsvattr nva;
    633 	off_t off = 0x0;
    634 	struct nfsstate st, *stp = &st;
    635 	struct nfslock lo, *lop = &lo;
    636 	nfsv4stateid_t stateid;
    637 	nfsquad_t clientid;
    638 
    639 	if (nd->nd_repstat) {
    640 		nfsrv_postopattr(nd, getret, &nva);
    641 		goto out;
    642 	}
    643 	if (nd->nd_flag & ND_NFSV2) {
    644 		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
    645 		off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
    646 		reqlen = fxdr_unsigned(int, *tl);
    647 	} else if (nd->nd_flag & ND_NFSV3) {
    648 		NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
    649 		off = fxdr_hyper(tl);
    650 		tl += 2;
    651 		reqlen = fxdr_unsigned(int, *tl);
    652 	} else {
    653 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
    654 		reqlen = fxdr_unsigned(int, *(tl + 6));
    655 	}
    656 	if (reqlen > NFS_SRVMAXDATA(nd)) {
    657 		reqlen = NFS_SRVMAXDATA(nd);
    658 	} else if (reqlen < 0) {
    659 		error = EBADRPC;
    660 		goto nfsmout;
    661 	}
    662 	if (nd->nd_flag & ND_NFSV4) {
    663 		stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
    664 		lop->lo_flags = NFSLCK_READ;
    665 		stp->ls_ownerlen = 0;
    666 		stp->ls_op = NULL;
    667 		stp->ls_uid = nd->nd_cred->cr_uid;
    668 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
    669 		clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
    670 		clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
    671 		if (nd->nd_flag & ND_IMPLIEDCLID) {
    672 			if (nd->nd_clientid.qval != clientid.qval)
    673 				printf("EEK! multiple clids\n");
    674 		} else {
    675 			nd->nd_flag |= ND_IMPLIEDCLID;
    676 			nd->nd_clientid.qval = clientid.qval;
    677 		}
    678 		stp->ls_stateid.other[2] = *tl++;
    679 		off = fxdr_hyper(tl);
    680 		lop->lo_first = off;
    681 		tl += 2;
    682 		lop->lo_end = off + reqlen;
    683 		/*
    684 		 * Paranoia, just in case it wraps around.
    685 		 */
    686 		if (lop->lo_end < off)
    687 			lop->lo_end = NFS64BITSSET;
    688 	}
    689 	if (vnode_vtype(vp) != VREG) {
    690 		if (nd->nd_flag & ND_NFSV3)
    691 			nd->nd_repstat = EINVAL;
    692 		else
    693 			nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
    694 			    EINVAL;
    695 	}
    696 	getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
    697 	if (!nd->nd_repstat)
    698 		nd->nd_repstat = getret;
    699 	if (!nd->nd_repstat &&
    700 	    (nva.na_uid != nd->nd_cred->cr_uid ||
    701 	     NFSVNO_EXSTRICTACCESS(exp))) {
    702 		nd->nd_repstat = nfsvno_accchk(vp, VREAD,
    703 		    nd->nd_cred, exp, p,
    704 		    NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
    705 		if (nd->nd_repstat)
    706 			nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
    707 			    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
    708 			    NFSACCCHK_VPISLOCKED, NULL);
    709 	}
    710 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
    711 		nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
    712 		    &stateid, exp, nd, p);
    713 	if (nd->nd_repstat) {
    714 		vput(vp);
    715 		if (nd->nd_flag & ND_NFSV3)
    716 			nfsrv_postopattr(nd, getret, &nva);
    717 		goto out;
    718 	}
    719 	if (off >= nva.na_size) {
    720 		cnt = 0;
    721 		eof = 1;
    722 	} else if (reqlen == 0)
    723 		cnt = 0;
    724 	else if ((off + reqlen) >= nva.na_size) {
    725 		cnt = nva.na_size - off;
    726 		eof = 1;
    727 	} else
    728 		cnt = reqlen;
    729 	m3 = NULL;
    730 	if (cnt > 0) {
    731 		nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
    732 		    &m3, &m2);
    733 		if (!(nd->nd_flag & ND_NFSV4)) {
    734 			getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
    735 			if (!nd->nd_repstat)
    736 				nd->nd_repstat = getret;
    737 		}
    738 		if (nd->nd_repstat) {
    739 			vput(vp);
    740 			if (m3)
    741 				mbuf_freem(m3);
    742 			if (nd->nd_flag & ND_NFSV3)
    743 				nfsrv_postopattr(nd, getret, &nva);
    744 			goto out;
    745 		}
    746 	}
    747 	vput(vp);
    748 	if (nd->nd_flag & ND_NFSV2) {
    749 		nfsrv_fillattr(nd, &nva);
    750 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
    751 	} else {
    752 		if (nd->nd_flag & ND_NFSV3) {
    753 			nfsrv_postopattr(nd, getret, &nva);
    754 			NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
    755 			*tl++ = txdr_unsigned(cnt);
    756 		} else
    757 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
    758 		if (eof)
    759 			*tl++ = newnfs_true;
    760 		else
    761 			*tl++ = newnfs_false;
    762 	}
    763 	*tl = txdr_unsigned(cnt);
    764 	if (m3) {
    765 		mbuf_setnext(nd->nd_mb, m3);
    766 		nd->nd_mb = m2;
    767 		nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
    768 	}
    769 
    770 out:
    771 	NFSEXITCODE2(0, nd);
    772 	return (0);
    773 nfsmout:
    774 	vput(vp);
    775 	NFSEXITCODE2(error, nd);
    776 	return (error);
    777 }
    778 
    779 /*
    780  * nfs write service
    781  */
    782 APPLESTATIC int
    783 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
    784     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
    785 {
    786 	int i, cnt;
    787 	u_int32_t *tl;
    788 	mbuf_t mp;
    789 	struct nfsvattr nva, forat;
    790 	int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
    791 	int stable = NFSWRITE_FILESYNC;
    792 	off_t off;
    793 	struct nfsstate st, *stp = &st;
    794 	struct nfslock lo, *lop = &lo;
    795 	nfsv4stateid_t stateid;
    796 	nfsquad_t clientid;
    797 
    798 	if (nd->nd_repstat) {
    799 		nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
    800 		goto out;
    801 	}
    802 	if (nd->nd_flag & ND_NFSV2) {
    803 		NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
    804 		off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
    805 		tl += 2;
    806 		retlen = len = fxdr_unsigned(int32_t, *tl);
    807 	} else if (nd->nd_flag & ND_NFSV3) {
    808 		NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
    809 		off = fxdr_hyper(tl);
    810 		tl += 3;
    811 		stable = fxdr_unsigned(int, *tl++);
    812 		retlen = len = fxdr_unsigned(int32_t, *tl);
    813 	} else {
    814 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
    815 		stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
    816 		lop->lo_flags = NFSLCK_WRITE;
    817 		stp->ls_ownerlen = 0;
    818 		stp->ls_op = NULL;
    819 		stp->ls_uid = nd->nd_cred->cr_uid;
    820 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
    821 		clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
    822 		clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
    823 		if (nd->nd_flag & ND_IMPLIEDCLID) {
    824 			if (nd->nd_clientid.qval != clientid.qval)
    825 				printf("EEK! multiple clids\n");
    826 		} else {
    827 			nd->nd_flag |= ND_IMPLIEDCLID;
    828 			nd->nd_clientid.qval = clientid.qval;
    829 		}
    830 		stp->ls_stateid.other[2] = *tl++;
    831 		off = fxdr_hyper(tl);
    832 		lop->lo_first = off;
    833 		tl += 2;
    834 		stable = fxdr_unsigned(int, *tl++);
    835 		retlen = len = fxdr_unsigned(int32_t, *tl);
    836 		lop->lo_end = off + len;
    837 		/*
    838 		 * Paranoia, just in case it wraps around, which shouldn't
    839 		 * ever happen anyhow.
    840 		 */
    841 		if (lop->lo_end < lop->lo_first)
    842 			lop->lo_end = NFS64BITSSET;
    843 	}
    844 
    845 	/*
    846 	 * Loop through the mbuf chain, counting how many mbufs are a
    847 	 * part of this write operation, so the iovec size is known.
    848 	 */
    849 	cnt = 0;
    850 	mp = nd->nd_md;
    851 	i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos;
    852 	while (len > 0) {
    853 		if (i > 0) {
    854 			len -= i;
    855 			cnt++;
    856 		}
    857 		mp = mbuf_next(mp);
    858 		if (!mp) {
    859 			if (len > 0) {
    860 				error = EBADRPC;
    861 				goto nfsmout;
    862 			}
    863 		} else
    864 			i = mbuf_len(mp);
    865 	}
    866 
    867 	if (retlen > NFS_MAXDATA || retlen < 0)
    868 		nd->nd_repstat = EIO;
    869 	if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
    870 		if (nd->nd_flag & ND_NFSV3)
    871 			nd->nd_repstat = EINVAL;
    872 		else
    873 			nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
    874 			    EINVAL;
    875 	}
    876 	forat_ret = nfsvno_getattr(vp, &forat, nd->nd_cred, p, 1);
    877 	if (!nd->nd_repstat)
    878 		nd->nd_repstat = forat_ret;
    879 	if (!nd->nd_repstat &&
    880 	    (forat.na_uid != nd->nd_cred->cr_uid ||
    881 	     NFSVNO_EXSTRICTACCESS(exp)))
    882 		nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
    883 		    nd->nd_cred, exp, p,
    884 		    NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
    885 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
    886 		nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
    887 		    &stateid, exp, nd, p);
    888 	}
    889 	if (nd->nd_repstat) {
    890 		vput(vp);
    891 		if (nd->nd_flag & ND_NFSV3)
    892 			nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
    893 		goto out;
    894 	}
    895 
    896 	/*
    897 	 * For NFS Version 2, it is not obvious what a write of zero length
    898 	 * should do, but I might as well be consistent with Version 3,
    899 	 * which is to return ok so long as there are no permission problems.
    900 	 */
    901 	if (retlen > 0) {
    902 		nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, stable,
    903 		    nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
    904 		error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
    905 		if (error)
    906 			panic("nfsrv_write mbuf");
    907 	}
    908 	if (nd->nd_flag & ND_NFSV4)
    909 		aftat_ret = 0;
    910 	else
    911 		aftat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
    912 	vput(vp);
    913 	if (!nd->nd_repstat)
    914 		nd->nd_repstat = aftat_ret;
    915 	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
    916 		if (nd->nd_flag & ND_NFSV3)
    917 			nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
    918 		if (nd->nd_repstat)
    919 			goto out;
    920 		NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
    921 		*tl++ = txdr_unsigned(retlen);
    922 		/*
    923 		 * If nfs_async is set, then pretend the write was FILESYNC.
    924 		 * Warning: Doing this violates RFC1813 and runs a risk
    925 		 * of data written by a client being lost when the server
    926 		 * crashes/reboots.
    927 		 */
    928 		if (stable == NFSWRITE_UNSTABLE && nfs_async == 0)
    929 			*tl++ = txdr_unsigned(stable);
    930 		else
    931 			*tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
    932 		/*
    933 		 * Actually, there is no need to txdr these fields,
    934 		 * but it may make the values more human readable,
    935 		 * for debugging purposes.
    936 		 */
    937 		*tl++ = txdr_unsigned(nfsboottime.tv_sec);
    938 		*tl = txdr_unsigned(nfsboottime.tv_usec);
    939 	} else if (!nd->nd_repstat)
    940 		nfsrv_fillattr(nd, &nva);
    941 
    942 out:
    943 	NFSEXITCODE2(0, nd);
    944 	return (0);
    945 nfsmout:
    946 	vput(vp);
    947 	NFSEXITCODE2(error, nd);
    948 	return (error);
    949 }
    950 
    951 /*
    952  * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
    953  * now does a truncate to 0 length via. setattr if it already exists
    954  * The core creation routine has been extracted out into nfsrv_creatsub(),
    955  * so it can also be used by nfsrv_open() for V4.
    956  */
    957 APPLESTATIC int
    958 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
    959     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
    960 {
    961 	struct nfsvattr nva, dirfor, diraft;
    962 	struct nfsv2_sattr *sp;
    963 	struct nameidata named;
    964 	u_int32_t *tl;
    965 	int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
    966 	int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
    967 	NFSDEV_T rdev = 0;
    968 	vnode_t vp = NULL, dirp = NULL;
    969 	fhandle_t fh;
    970 	char *bufp;
    971 	u_long *hashp;
    972 	enum vtype vtyp;
    973 	int32_t cverf[2], tverf[2] = { 0, 0 };
    974 
    975 	if (nd->nd_repstat) {
    976 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
    977 		goto out;
    978 	}
    979 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
    980 	    LOCKPARENT | LOCKLEAF | SAVESTART);
    981 	nfsvno_setpathbuf(&named, &bufp, &hashp);
    982 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
    983 	if (error)
    984 		goto nfsmout;
    985 	if (!nd->nd_repstat) {
    986 		NFSVNO_ATTRINIT(&nva);
    987 		if (nd->nd_flag & ND_NFSV2) {
    988 			NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
    989 			vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
    990 			if (vtyp == VNON)
    991 				vtyp = VREG;
    992 			NFSVNO_SETATTRVAL(&nva, type, vtyp);
    993 			NFSVNO_SETATTRVAL(&nva, mode,
    994 			    nfstov_mode(sp->sa_mode));
    995 			switch (nva.na_type) {
    996 			case VREG:
    997 				tsize = fxdr_unsigned(int32_t, sp->sa_size);
    998 				if (tsize != -1)
    999 					NFSVNO_SETATTRVAL(&nva, size,
   1000 					    (u_quad_t)tsize);
   1001 				break;
   1002 			case VCHR:
   1003 			case VBLK:
   1004 			case VFIFO:
   1005 				rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
   1006 				break;
   1007 			default:
   1008 				break;
   1009 			};
   1010 		} else {
   1011 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1012 			how = fxdr_unsigned(int, *tl);
   1013 			switch (how) {
   1014 			case NFSCREATE_GUARDED:
   1015 			case NFSCREATE_UNCHECKED:
   1016 				error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
   1017 				if (error)
   1018 					goto nfsmout;
   1019 				break;
   1020 			case NFSCREATE_EXCLUSIVE:
   1021 				NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
   1022 				cverf[0] = *tl++;
   1023 				cverf[1] = *tl;
   1024 				exclusive_flag = 1;
   1025 				break;
   1026 			};
   1027 			NFSVNO_SETATTRVAL(&nva, type, VREG);
   1028 		}
   1029 	}
   1030 	if (nd->nd_repstat) {
   1031 		nfsvno_relpathbuf(&named);
   1032 		if (nd->nd_flag & ND_NFSV3) {
   1033 			dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred,
   1034 			    p, 1);
   1035 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
   1036 			    &diraft);
   1037 		}
   1038 		vput(dp);
   1039 		goto out;
   1040 	}
   1041 
   1042 	nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
   1043 	if (dirp) {
   1044 		if (nd->nd_flag & ND_NFSV2) {
   1045 			vrele(dirp);
   1046 			dirp = NULL;
   1047 		} else {
   1048 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
   1049 			    p, 0);
   1050 		}
   1051 	}
   1052 	if (nd->nd_repstat) {
   1053 		if (nd->nd_flag & ND_NFSV3)
   1054 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
   1055 			    &diraft);
   1056 		if (dirp)
   1057 			vrele(dirp);
   1058 		goto out;
   1059 	}
   1060 
   1061 	if (!(nd->nd_flag & ND_NFSV2)) {
   1062 		switch (how) {
   1063 		case NFSCREATE_GUARDED:
   1064 			if (named.ni_vp)
   1065 				nd->nd_repstat = EEXIST;
   1066 			break;
   1067 		case NFSCREATE_UNCHECKED:
   1068 			break;
   1069 		case NFSCREATE_EXCLUSIVE:
   1070 			if (named.ni_vp == NULL)
   1071 				NFSVNO_SETATTRVAL(&nva, mode, 0);
   1072 			break;
   1073 		};
   1074 	}
   1075 
   1076 	/*
   1077 	 * Iff doesn't exist, create it
   1078 	 * otherwise just truncate to 0 length
   1079 	 *   should I set the mode too ?
   1080 	 */
   1081 	nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
   1082 	    &exclusive_flag, cverf, rdev, p, exp);
   1083 
   1084 	if (!nd->nd_repstat) {
   1085 		nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
   1086 		if (!nd->nd_repstat)
   1087 			nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
   1088 			    p, 1);
   1089 		vput(vp);
   1090 		if (!nd->nd_repstat) {
   1091 			tverf[0] = nva.na_atime.tv_sec;
   1092 			tverf[1] = nva.na_atime.tv_nsec;
   1093 		}
   1094 	}
   1095 	if (nd->nd_flag & ND_NFSV2) {
   1096 		if (!nd->nd_repstat) {
   1097 			(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
   1098 			nfsrv_fillattr(nd, &nva);
   1099 		}
   1100 	} else {
   1101 		if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
   1102 		    || cverf[1] != tverf[1]))
   1103 			nd->nd_repstat = EEXIST;
   1104 		diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
   1105 		vrele(dirp);
   1106 		if (!nd->nd_repstat) {
   1107 			(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
   1108 			nfsrv_postopattr(nd, 0, &nva);
   1109 		}
   1110 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
   1111 	}
   1112 
   1113 out:
   1114 	NFSEXITCODE2(0, nd);
   1115 	return (0);
   1116 nfsmout:
   1117 	vput(dp);
   1118 	nfsvno_relpathbuf(&named);
   1119 	NFSEXITCODE2(error, nd);
   1120 	return (error);
   1121 }
   1122 
   1123 /*
   1124  * nfs v3 mknod service (and v4 create)
   1125  */
   1126 APPLESTATIC int
   1127 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
   1128     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
   1129     struct nfsexstuff *exp)
   1130 {
   1131 	struct nfsvattr nva, dirfor, diraft;
   1132 	u_int32_t *tl;
   1133 	struct nameidata named;
   1134 	int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
   1135 	u_int32_t major, minor;
   1136 	enum vtype vtyp = VNON;
   1137 	nfstype nfs4type = NFNON;
   1138 	vnode_t vp, dirp = NULL;
   1139 	nfsattrbit_t attrbits;
   1140 	char *bufp = NULL, *pathcp = NULL;
   1141 	u_long *hashp, cnflags;
   1142 	NFSACL_T *aclp = NULL;
   1143 
   1144 	NFSVNO_ATTRINIT(&nva);
   1145 	cnflags = (LOCKPARENT | SAVESTART);
   1146 	if (nd->nd_repstat) {
   1147 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
   1148 		goto out;
   1149 	}
   1150 #ifdef NFS4_ACL_EXTATTR_NAME
   1151 	aclp = acl_alloc(M_WAITOK);
   1152 	aclp->acl_cnt = 0;
   1153 #endif
   1154 
   1155 	/*
   1156 	 * For V4, the creation stuff is here, Yuck!
   1157 	 */
   1158 	if (nd->nd_flag & ND_NFSV4) {
   1159 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1160 		vtyp = nfsv34tov_type(*tl);
   1161 		nfs4type = fxdr_unsigned(nfstype, *tl);
   1162 		switch (nfs4type) {
   1163 		case NFLNK:
   1164 			error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
   1165 			    &pathlen);
   1166 			if (error)
   1167 				goto nfsmout;
   1168 			break;
   1169 		case NFCHR:
   1170 		case NFBLK:
   1171 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   1172 			major = fxdr_unsigned(u_int32_t, *tl++);
   1173 			minor = fxdr_unsigned(u_int32_t, *tl);
   1174 			nva.na_rdev = NFSMAKEDEV(major, minor);
   1175 			break;
   1176 		case NFSOCK:
   1177 		case NFFIFO:
   1178 			break;
   1179 		case NFDIR:
   1180 			cnflags = (LOCKPARENT | SAVENAME);
   1181 			break;
   1182 		default:
   1183 			nd->nd_repstat = NFSERR_BADTYPE;
   1184 			vrele(dp);
   1185 #ifdef NFS4_ACL_EXTATTR_NAME
   1186 			acl_free(aclp);
   1187 #endif
   1188 			goto out;
   1189 		}
   1190 	}
   1191 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags);
   1192 	nfsvno_setpathbuf(&named, &bufp, &hashp);
   1193 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
   1194 	if (error)
   1195 		goto nfsmout;
   1196 	if (!nd->nd_repstat) {
   1197 		if (nd->nd_flag & ND_NFSV3) {
   1198 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1199 			vtyp = nfsv34tov_type(*tl);
   1200 		}
   1201 		error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p);
   1202 		if (error)
   1203 			goto nfsmout;
   1204 		nva.na_type = vtyp;
   1205 		if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
   1206 		    (vtyp == VCHR || vtyp == VBLK)) {
   1207 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   1208 			major = fxdr_unsigned(u_int32_t, *tl++);
   1209 			minor = fxdr_unsigned(u_int32_t, *tl);
   1210 			nva.na_rdev = NFSMAKEDEV(major, minor);
   1211 		}
   1212 	}
   1213 
   1214 	dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
   1215 	if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
   1216 		if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
   1217 		    dirfor.na_gid == nva.na_gid)
   1218 			NFSVNO_UNSET(&nva, gid);
   1219 		nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
   1220 	}
   1221 	if (nd->nd_repstat) {
   1222 		vrele(dp);
   1223 #ifdef NFS4_ACL_EXTATTR_NAME
   1224 		acl_free(aclp);
   1225 #endif
   1226 		nfsvno_relpathbuf(&named);
   1227 		if (pathcp)
   1228 			FREE(pathcp, M_TEMP);
   1229 		if (nd->nd_flag & ND_NFSV3)
   1230 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
   1231 			    &diraft);
   1232 		goto out;
   1233 	}
   1234 
   1235 	/*
   1236 	 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
   1237 	 * in va_mode, so we'll have to set a default here.
   1238 	 */
   1239 	if (NFSVNO_NOTSETMODE(&nva)) {
   1240 		if (vtyp == VLNK)
   1241 			nva.na_mode = 0755;
   1242 		else
   1243 			nva.na_mode = 0400;
   1244 	}
   1245 
   1246 	if (vtyp == VDIR)
   1247 		named.ni_cnd.cn_flags |= WILLBEDIR;
   1248 	nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
   1249 	if (nd->nd_repstat) {
   1250 		if (dirp) {
   1251 			if (nd->nd_flag & ND_NFSV3)
   1252 				dirfor_ret = nfsvno_getattr(dirp, &dirfor,
   1253 				    nd->nd_cred, p, 0);
   1254 			vrele(dirp);
   1255 		}
   1256 #ifdef NFS4_ACL_EXTATTR_NAME
   1257 		acl_free(aclp);
   1258 #endif
   1259 		if (nd->nd_flag & ND_NFSV3)
   1260 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
   1261 			    &diraft);
   1262 		goto out;
   1263 	}
   1264 	if (dirp)
   1265 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
   1266 
   1267 	if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
   1268 		if (vtyp == VDIR) {
   1269 			nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
   1270 			    &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
   1271 			    exp);
   1272 #ifdef NFS4_ACL_EXTATTR_NAME
   1273 			acl_free(aclp);
   1274 #endif
   1275 			goto out;
   1276 		} else if (vtyp == VLNK) {
   1277 			nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
   1278 			    &dirfor, &diraft, &diraft_ret, &attrbits,
   1279 			    aclp, p, exp, pathcp, pathlen);
   1280 #ifdef NFS4_ACL_EXTATTR_NAME
   1281 			acl_free(aclp);
   1282 #endif
   1283 			FREE(pathcp, M_TEMP);
   1284 			goto out;
   1285 		}
   1286 	}
   1287 
   1288 	nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
   1289 	if (!nd->nd_repstat) {
   1290 		vp = named.ni_vp;
   1291 		nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
   1292 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
   1293 		if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
   1294 			nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
   1295 			    p, 1);
   1296 		if (vpp != NULL && nd->nd_repstat == 0) {
   1297 			NFSVOPUNLOCK(vp, 0);
   1298 			*vpp = vp;
   1299 		} else
   1300 			vput(vp);
   1301 	}
   1302 
   1303 	diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
   1304 	vrele(dirp);
   1305 	if (!nd->nd_repstat) {
   1306 		if (nd->nd_flag & ND_NFSV3) {
   1307 			(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
   1308 			nfsrv_postopattr(nd, 0, &nva);
   1309 		} else {
   1310 			NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
   1311 			*tl++ = newnfs_false;
   1312 			txdr_hyper(dirfor.na_filerev, tl);
   1313 			tl += 2;
   1314 			txdr_hyper(diraft.na_filerev, tl);
   1315 			(void) nfsrv_putattrbit(nd, &attrbits);
   1316 		}
   1317 	}
   1318 	if (nd->nd_flag & ND_NFSV3)
   1319 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
   1320 #ifdef NFS4_ACL_EXTATTR_NAME
   1321 	acl_free(aclp);
   1322 #endif
   1323 
   1324 out:
   1325 	NFSEXITCODE2(0, nd);
   1326 	return (0);
   1327 nfsmout:
   1328 	vrele(dp);
   1329 #ifdef NFS4_ACL_EXTATTR_NAME
   1330 	acl_free(aclp);
   1331 #endif
   1332 	if (bufp)
   1333 		nfsvno_relpathbuf(&named);
   1334 	if (pathcp)
   1335 		FREE(pathcp, M_TEMP);
   1336 
   1337 	NFSEXITCODE2(error, nd);
   1338 	return (error);
   1339 }
   1340 
   1341 /*
   1342  * nfs remove service
   1343  */
   1344 APPLESTATIC int
   1345 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
   1346     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
   1347 {
   1348 	struct nameidata named;
   1349 	u_int32_t *tl;
   1350 	int error = 0, dirfor_ret = 1, diraft_ret = 1;
   1351 	vnode_t dirp = NULL;
   1352 	struct nfsvattr dirfor, diraft;
   1353 	char *bufp;
   1354 	u_long *hashp;
   1355 
   1356 	if (nd->nd_repstat) {
   1357 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
   1358 		goto out;
   1359 	}
   1360 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
   1361 	    LOCKPARENT | LOCKLEAF);
   1362 	nfsvno_setpathbuf(&named, &bufp, &hashp);
   1363 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
   1364 	if (error) {
   1365 		vput(dp);
   1366 		nfsvno_relpathbuf(&named);
   1367 		goto out;
   1368 	}
   1369 	if (!nd->nd_repstat) {
   1370 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
   1371 	} else {
   1372 		vput(dp);
   1373 		nfsvno_relpathbuf(&named);
   1374 	}
   1375 	if (dirp) {
   1376 		if (!(nd->nd_flag & ND_NFSV2)) {
   1377 			dirfor_ret = nfsvno_getattr(dirp, &dirfor,
   1378 			    nd->nd_cred, p, 0);
   1379 		} else {
   1380 			vrele(dirp);
   1381 			dirp = NULL;
   1382 		}
   1383 	}
   1384 	if (!nd->nd_repstat) {
   1385 		if (nd->nd_flag & ND_NFSV4) {
   1386 			if (vnode_vtype(named.ni_vp) == VDIR)
   1387 				nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
   1388 				    nd->nd_cred, p, exp);
   1389 			else
   1390 				nd->nd_repstat = nfsvno_removesub(&named, 1,
   1391 				    nd->nd_cred, p, exp);
   1392 		} else if (nd->nd_procnum == NFSPROC_RMDIR) {
   1393 			nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
   1394 			    nd->nd_cred, p, exp);
   1395 		} else {
   1396 			nd->nd_repstat = nfsvno_removesub(&named, 0,
   1397 			    nd->nd_cred, p, exp);
   1398 		}
   1399 	}
   1400 	if (!(nd->nd_flag & ND_NFSV2)) {
   1401 		if (dirp) {
   1402 			diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred,
   1403 			    p, 0);
   1404 			vrele(dirp);
   1405 		}
   1406 		if (nd->nd_flag & ND_NFSV3) {
   1407 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
   1408 			    &diraft);
   1409 		} else if (!nd->nd_repstat) {
   1410 			NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
   1411 			*tl++ = newnfs_false;
   1412 			txdr_hyper(dirfor.na_filerev, tl);
   1413 			tl += 2;
   1414 			txdr_hyper(diraft.na_filerev, tl);
   1415 		}
   1416 	}
   1417 
   1418 out:
   1419 	NFSEXITCODE2(error, nd);
   1420 	return (error);
   1421 }
   1422 
   1423 /*
   1424  * nfs rename service
   1425  */
   1426 APPLESTATIC int
   1427 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
   1428     vnode_t dp, vnode_t todp, NFSPROC_T *p, struct nfsexstuff *exp,
   1429     struct nfsexstuff *toexp)
   1430 {
   1431 	u_int32_t *tl;
   1432 	int error = 0, fdirfor_ret = 1, fdiraft_ret = 1;
   1433 	int tdirfor_ret = 1, tdiraft_ret = 1;
   1434 	struct nameidata fromnd, tond;
   1435 	vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
   1436 	struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
   1437 	struct nfsexstuff tnes;
   1438 	struct nfsrvfh tfh;
   1439 	char *bufp, *tbufp = NULL;
   1440 	u_long *hashp;
   1441 	fhandle_t fh;
   1442 
   1443 	if (nd->nd_repstat) {
   1444 		nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
   1445 		nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
   1446 		goto out;
   1447 	}
   1448 	if (!(nd->nd_flag & ND_NFSV2))
   1449 		fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd->nd_cred, p, 1);
   1450 	tond.ni_cnd.cn_nameiop = 0;
   1451 	tond.ni_startdir = NULL;
   1452 	NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
   1453 	nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
   1454 	error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
   1455 	if (error) {
   1456 		vput(dp);
   1457 		if (todp)
   1458 			vrele(todp);
   1459 		nfsvno_relpathbuf(&fromnd);
   1460 		goto out;
   1461 	}
   1462 	if (nd->nd_flag & ND_NFSV4) {
   1463 		tdp = todp;
   1464 		tnes = *toexp;
   1465 		tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, p, 0);
   1466 	} else {
   1467 		tfh.nfsrvfh_len = 0;
   1468 		error = nfsrv_mtofh(nd, &tfh);
   1469 		if (error == 0)
   1470 			error = nfsvno_getfh(dp, &fh, p);
   1471 		if (error) {
   1472 			vput(dp);
   1473 			/* todp is always NULL except NFSv4 */
   1474 			nfsvno_relpathbuf(&fromnd);
   1475 			goto out;
   1476 		}
   1477 
   1478 		/* If this is the same file handle, just VREF() the vnode. */
   1479 		if (tfh.nfsrvfh_len == NFSX_MYFH &&
   1480 		    !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
   1481 			VREF(dp);
   1482 			tdp = dp;
   1483 			tnes = *exp;
   1484 			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
   1485 			    p, 1);
   1486 		} else {
   1487 			nd->nd_cred->cr_uid = nd->nd_saveduid;
   1488 			nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
   1489 			    0, p);
   1490 			if (tdp) {
   1491 				tdirfor_ret = nfsvno_getattr(tdp, &tdirfor,
   1492 				    nd->nd_cred, p, 1);
   1493 				NFSVOPUNLOCK(tdp, 0);
   1494 			}
   1495 		}
   1496 	}
   1497 	NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
   1498 	nfsvno_setpathbuf(&tond, &tbufp, &hashp);
   1499 	if (!nd->nd_repstat) {
   1500 		error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
   1501 		if (error) {
   1502 			if (tdp)
   1503 				vrele(tdp);
   1504 			vput(dp);
   1505 			nfsvno_relpathbuf(&fromnd);
   1506 			nfsvno_relpathbuf(&tond);
   1507 			goto out;
   1508 		}
   1509 	}
   1510 	if (nd->nd_repstat) {
   1511 		if (nd->nd_flag & ND_NFSV3) {
   1512 			nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
   1513 			    &fdiraft);
   1514 			nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
   1515 			    &tdiraft);
   1516 		}
   1517 		if (tdp)
   1518 			vrele(tdp);
   1519 		vput(dp);
   1520 		nfsvno_relpathbuf(&fromnd);
   1521 		nfsvno_relpathbuf(&tond);
   1522 		goto out;
   1523 	}
   1524 
   1525 	/*
   1526 	 * Done parsing, now down to business.
   1527 	 */
   1528 	nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 1, exp, p, &fdirp);
   1529 	if (nd->nd_repstat) {
   1530 		if (nd->nd_flag & ND_NFSV3) {
   1531 			nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
   1532 			    &fdiraft);
   1533 			nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
   1534 			    &tdiraft);
   1535 		}
   1536 		if (fdirp)
   1537 			vrele(fdirp);
   1538 		if (tdp)
   1539 			vrele(tdp);
   1540 		nfsvno_relpathbuf(&tond);
   1541 		goto out;
   1542 	}
   1543 	if (vnode_vtype(fromnd.ni_vp) == VDIR)
   1544 		tond.ni_cnd.cn_flags |= WILLBEDIR;
   1545 	nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
   1546 	nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
   1547 	    nd->nd_flag, nd->nd_cred, p);
   1548 	if (fdirp)
   1549 		fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p,
   1550 		    0);
   1551 	if (tdirp)
   1552 		tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p,
   1553 		    0);
   1554 	if (fdirp)
   1555 		vrele(fdirp);
   1556 	if (tdirp)
   1557 		vrele(tdirp);
   1558 	if (nd->nd_flag & ND_NFSV3) {
   1559 		nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
   1560 		nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
   1561 	} else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
   1562 		NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
   1563 		*tl++ = newnfs_false;
   1564 		txdr_hyper(fdirfor.na_filerev, tl);
   1565 		tl += 2;
   1566 		txdr_hyper(fdiraft.na_filerev, tl);
   1567 		tl += 2;
   1568 		*tl++ = newnfs_false;
   1569 		txdr_hyper(tdirfor.na_filerev, tl);
   1570 		tl += 2;
   1571 		txdr_hyper(tdiraft.na_filerev, tl);
   1572 	}
   1573 
   1574 out:
   1575 	NFSEXITCODE2(error, nd);
   1576 	return (error);
   1577 }
   1578 
   1579 /*
   1580  * nfs link service
   1581  */
   1582 APPLESTATIC int
   1583 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
   1584     vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp,
   1585     struct nfsexstuff *toexp)
   1586 {
   1587 	struct nameidata named;
   1588 	u_int32_t *tl;
   1589 	int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
   1590 	vnode_t dirp = NULL, dp = NULL;
   1591 	struct nfsvattr dirfor, diraft, at;
   1592 	struct nfsexstuff tnes;
   1593 	struct nfsrvfh dfh;
   1594 	char *bufp;
   1595 	u_long *hashp;
   1596 
   1597 	if (nd->nd_repstat) {
   1598 		nfsrv_postopattr(nd, getret, &at);
   1599 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
   1600 		goto out;
   1601 	}
   1602 	NFSVOPUNLOCK(vp, 0);
   1603 	if (vnode_vtype(vp) == VDIR) {
   1604 		if (nd->nd_flag & ND_NFSV4)
   1605 			nd->nd_repstat = NFSERR_ISDIR;
   1606 		else
   1607 			nd->nd_repstat = NFSERR_INVAL;
   1608 		if (tovp)
   1609 			vrele(tovp);
   1610 	} else if (vnode_vtype(vp) == VLNK) {
   1611 		if (nd->nd_flag & ND_NFSV2)
   1612 			nd->nd_repstat = NFSERR_INVAL;
   1613 		else
   1614 			nd->nd_repstat = NFSERR_NOTSUPP;
   1615 		if (tovp)
   1616 			vrele(tovp);
   1617 	}
   1618 	if (!nd->nd_repstat) {
   1619 		if (nd->nd_flag & ND_NFSV4) {
   1620 			dp = tovp;
   1621 			tnes = *toexp;
   1622 		} else {
   1623 			error = nfsrv_mtofh(nd, &dfh);
   1624 			if (error) {
   1625 				vrele(vp);
   1626 				/* tovp is always NULL unless NFSv4 */
   1627 				goto out;
   1628 			}
   1629 			nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0,
   1630 			    p);
   1631 			if (dp)
   1632 				NFSVOPUNLOCK(dp, 0);
   1633 		}
   1634 	}
   1635 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
   1636 	    LOCKPARENT | SAVENAME);
   1637 	if (!nd->nd_repstat) {
   1638 		nfsvno_setpathbuf(&named, &bufp, &hashp);
   1639 		error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
   1640 		if (error) {
   1641 			vrele(vp);
   1642 			if (dp)
   1643 				vrele(dp);
   1644 			nfsvno_relpathbuf(&named);
   1645 			goto out;
   1646 		}
   1647 		if (!nd->nd_repstat) {
   1648 			nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
   1649 			    p, &dirp);
   1650 		} else {
   1651 			if (dp)
   1652 				vrele(dp);
   1653 			nfsvno_relpathbuf(&named);
   1654 		}
   1655 	}
   1656 	if (dirp) {
   1657 		if (nd->nd_flag & ND_NFSV2) {
   1658 			vrele(dirp);
   1659 			dirp = NULL;
   1660 		} else {
   1661 			dirfor_ret = nfsvno_getattr(dirp, &dirfor,
   1662 			    nd->nd_cred, p, 0);
   1663 		}
   1664 	}
   1665 	if (!nd->nd_repstat)
   1666 		nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
   1667 	if (nd->nd_flag & ND_NFSV3)
   1668 		getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0);
   1669 	if (dirp) {
   1670 		diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
   1671 		vrele(dirp);
   1672 	}
   1673 	vrele(vp);
   1674 	if (nd->nd_flag & ND_NFSV3) {
   1675 		nfsrv_postopattr(nd, getret, &at);
   1676 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
   1677 	} else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
   1678 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
   1679 		*tl++ = newnfs_false;
   1680 		txdr_hyper(dirfor.na_filerev, tl);
   1681 		tl += 2;
   1682 		txdr_hyper(diraft.na_filerev, tl);
   1683 	}
   1684 
   1685 out:
   1686 	NFSEXITCODE2(error, nd);
   1687 	return (error);
   1688 }
   1689 
   1690 /*
   1691  * nfs symbolic link service
   1692  */
   1693 APPLESTATIC int
   1694 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
   1695     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
   1696     struct nfsexstuff *exp)
   1697 {
   1698 	struct nfsvattr nva, dirfor, diraft;
   1699 	struct nameidata named;
   1700 	int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
   1701 	vnode_t dirp = NULL;
   1702 	char *bufp, *pathcp = NULL;
   1703 	u_long *hashp;
   1704 
   1705 	if (nd->nd_repstat) {
   1706 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
   1707 		goto out;
   1708 	}
   1709 	if (vpp)
   1710 		*vpp = NULL;
   1711 	NFSVNO_ATTRINIT(&nva);
   1712 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
   1713 	    LOCKPARENT | SAVESTART);
   1714 	nfsvno_setpathbuf(&named, &bufp, &hashp);
   1715 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
   1716 	if (!error && !nd->nd_repstat)
   1717 		error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
   1718 	if (error) {
   1719 		vrele(dp);
   1720 		nfsvno_relpathbuf(&named);
   1721 		goto out;
   1722 	}
   1723 	if (!nd->nd_repstat) {
   1724 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
   1725 	} else {
   1726 		vrele(dp);
   1727 		nfsvno_relpathbuf(&named);
   1728 	}
   1729 	if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
   1730 		vrele(dirp);
   1731 		dirp = NULL;
   1732 	}
   1733 
   1734 	/*
   1735 	 * And call nfsrvd_symlinksub() to do the common code. It will
   1736 	 * return EBADRPC upon a parsing error, 0 otherwise.
   1737 	 */
   1738 	if (!nd->nd_repstat) {
   1739 		if (dirp != NULL)
   1740 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
   1741 			    p, 0);
   1742 		nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
   1743 		    &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
   1744 		    pathcp, pathlen);
   1745 	} else if (dirp != NULL) {
   1746 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
   1747 		vrele(dirp);
   1748 	}
   1749 	if (pathcp)
   1750 		FREE(pathcp, M_TEMP);
   1751 
   1752 	if (nd->nd_flag & ND_NFSV3) {
   1753 		if (!nd->nd_repstat) {
   1754 			(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
   1755 			nfsrv_postopattr(nd, 0, &nva);
   1756 		}
   1757 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
   1758 	}
   1759 
   1760 out:
   1761 	NFSEXITCODE2(error, nd);
   1762 	return (error);
   1763 }
   1764 
   1765 /*
   1766  * Common code for creating a symbolic link.
   1767  */
   1768 static void
   1769 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
   1770     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
   1771     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
   1772     int *diraft_retp, nfsattrbit_t *attrbitp,
   1773     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
   1774     int pathlen)
   1775 {
   1776 	u_int32_t *tl;
   1777 
   1778 	nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
   1779 	    !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
   1780 	if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
   1781 		nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
   1782 		if (nd->nd_flag & ND_NFSV3) {
   1783 			nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
   1784 			if (!nd->nd_repstat)
   1785 				nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
   1786 				    nvap, nd->nd_cred, p, 1);
   1787 		}
   1788 		if (vpp != NULL && nd->nd_repstat == 0) {
   1789 			NFSVOPUNLOCK(ndp->ni_vp, 0);
   1790 			*vpp = ndp->ni_vp;
   1791 		} else
   1792 			vput(ndp->ni_vp);
   1793 	}
   1794 	if (dirp) {
   1795 		*diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
   1796 		vrele(dirp);
   1797 	}
   1798 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
   1799 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
   1800 		*tl++ = newnfs_false;
   1801 		txdr_hyper(dirforp->na_filerev, tl);
   1802 		tl += 2;
   1803 		txdr_hyper(diraftp->na_filerev, tl);
   1804 		(void) nfsrv_putattrbit(nd, attrbitp);
   1805 	}
   1806 
   1807 	NFSEXITCODE2(0, nd);
   1808 }
   1809 
   1810 /*
   1811  * nfs mkdir service
   1812  */
   1813 APPLESTATIC int
   1814 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
   1815     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
   1816     struct nfsexstuff *exp)
   1817 {
   1818 	struct nfsvattr nva, dirfor, diraft;
   1819 	struct nameidata named;
   1820 	u_int32_t *tl;
   1821 	int error = 0, dirfor_ret = 1, diraft_ret = 1;
   1822 	vnode_t dirp = NULL;
   1823 	char *bufp;
   1824 	u_long *hashp;
   1825 
   1826 	if (nd->nd_repstat) {
   1827 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
   1828 		goto out;
   1829 	}
   1830 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
   1831 	    LOCKPARENT | SAVENAME);
   1832 	nfsvno_setpathbuf(&named, &bufp, &hashp);
   1833 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
   1834 	if (error)
   1835 		goto nfsmout;
   1836 	if (!nd->nd_repstat) {
   1837 		NFSVNO_ATTRINIT(&nva);
   1838 		if (nd->nd_flag & ND_NFSV3) {
   1839 			error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
   1840 			if (error)
   1841 				goto nfsmout;
   1842 		} else {
   1843 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1844 			nva.na_mode = nfstov_mode(*tl++);
   1845 		}
   1846 	}
   1847 	if (!nd->nd_repstat) {
   1848 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
   1849 	} else {
   1850 		vrele(dp);
   1851 		nfsvno_relpathbuf(&named);
   1852 	}
   1853 	if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
   1854 		vrele(dirp);
   1855 		dirp = NULL;
   1856 	}
   1857 	if (nd->nd_repstat) {
   1858 		if (dirp != NULL) {
   1859 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
   1860 			    p, 0);
   1861 			vrele(dirp);
   1862 		}
   1863 		if (nd->nd_flag & ND_NFSV3)
   1864 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
   1865 			    &diraft);
   1866 		goto out;
   1867 	}
   1868 	if (dirp != NULL)
   1869 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
   1870 
   1871 	/*
   1872 	 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
   1873 	 */
   1874 	nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
   1875 	    &diraft_ret, NULL, NULL, p, exp);
   1876 
   1877 	if (nd->nd_flag & ND_NFSV3) {
   1878 		if (!nd->nd_repstat) {
   1879 			(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
   1880 			nfsrv_postopattr(nd, 0, &nva);
   1881 		}
   1882 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
   1883 	} else if (!nd->nd_repstat) {
   1884 		(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
   1885 		nfsrv_fillattr(nd, &nva);
   1886 	}
   1887 
   1888 out:
   1889 	NFSEXITCODE2(0, nd);
   1890 	return (0);
   1891 nfsmout:
   1892 	vrele(dp);
   1893 	nfsvno_relpathbuf(&named);
   1894 	NFSEXITCODE2(error, nd);
   1895 	return (error);
   1896 }
   1897 
   1898 /*
   1899  * Code common to mkdir for V2,3 and 4.
   1900  */
   1901 static void
   1902 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
   1903     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
   1904     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
   1905     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
   1906     NFSPROC_T *p, struct nfsexstuff *exp)
   1907 {
   1908 	vnode_t vp;
   1909 	u_int32_t *tl;
   1910 
   1911 	NFSVNO_SETATTRVAL(nvap, type, VDIR);
   1912 	nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
   1913 	    nd->nd_cred, p, exp);
   1914 	if (!nd->nd_repstat) {
   1915 		vp = ndp->ni_vp;
   1916 		nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
   1917 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
   1918 		if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
   1919 			nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred,
   1920 			    p, 1);
   1921 		if (vpp && !nd->nd_repstat) {
   1922 			NFSVOPUNLOCK(vp, 0);
   1923 			*vpp = vp;
   1924 		} else {
   1925 			vput(vp);
   1926 		}
   1927 	}
   1928 	if (dirp) {
   1929 		*diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
   1930 		vrele(dirp);
   1931 	}
   1932 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
   1933 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
   1934 		*tl++ = newnfs_false;
   1935 		txdr_hyper(dirforp->na_filerev, tl);
   1936 		tl += 2;
   1937 		txdr_hyper(diraftp->na_filerev, tl);
   1938 		(void) nfsrv_putattrbit(nd, attrbitp);
   1939 	}
   1940 
   1941 	NFSEXITCODE2(0, nd);
   1942 }
   1943 
   1944 /*
   1945  * nfs commit service
   1946  */
   1947 APPLESTATIC int
   1948 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
   1949     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   1950 {
   1951 	struct nfsvattr bfor, aft;
   1952 	u_int32_t *tl;
   1953 	int error = 0, for_ret = 1, aft_ret = 1, cnt;
   1954 	u_int64_t off;
   1955 
   1956 	if (nd->nd_repstat) {
   1957 		nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
   1958 		goto out;
   1959 	}
   1960 	NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
   1961 	/*
   1962 	 * XXX At this time VOP_FSYNC() does not accept offset and byte
   1963 	 * count parameters, so these arguments are useless (someday maybe).
   1964 	 */
   1965 	off = fxdr_hyper(tl);
   1966 	tl += 2;
   1967 	cnt = fxdr_unsigned(int, *tl);
   1968 	if (nd->nd_flag & ND_NFSV3)
   1969 		for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1);
   1970 	nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
   1971 	if (nd->nd_flag & ND_NFSV3) {
   1972 		aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1);
   1973 		nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
   1974 	}
   1975 	vput(vp);
   1976 	if (!nd->nd_repstat) {
   1977 		NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
   1978 		*tl++ = txdr_unsigned(nfsboottime.tv_sec);
   1979 		*tl = txdr_unsigned(nfsboottime.tv_usec);
   1980 	}
   1981 
   1982 out:
   1983 	NFSEXITCODE2(0, nd);
   1984 	return (0);
   1985 nfsmout:
   1986 	vput(vp);
   1987 	NFSEXITCODE2(error, nd);
   1988 	return (error);
   1989 }
   1990 
   1991 /*
   1992  * nfs statfs service
   1993  */
   1994 APPLESTATIC int
   1995 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
   1996     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   1997 {
   1998 	struct statfs *sf;
   1999 	u_int32_t *tl;
   2000 	int getret = 1;
   2001 	struct nfsvattr at;
   2002 	struct statfs sfs;
   2003 	u_quad_t tval;
   2004 
   2005 	if (nd->nd_repstat) {
   2006 		nfsrv_postopattr(nd, getret, &at);
   2007 		goto out;
   2008 	}
   2009 	sf = &sfs;
   2010 	nd->nd_repstat = nfsvno_statfs(vp, sf);
   2011 	getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
   2012 	vput(vp);
   2013 	if (nd->nd_flag & ND_NFSV3)
   2014 		nfsrv_postopattr(nd, getret, &at);
   2015 	if (nd->nd_repstat)
   2016 		goto out;
   2017 	if (nd->nd_flag & ND_NFSV2) {
   2018 		NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
   2019 		*tl++ = txdr_unsigned(NFS_V2MAXDATA);
   2020 		*tl++ = txdr_unsigned(sf->f_bsize);
   2021 		*tl++ = txdr_unsigned(sf->f_blocks);
   2022 		*tl++ = txdr_unsigned(sf->f_bfree);
   2023 		*tl = txdr_unsigned(sf->f_bavail);
   2024 	} else {
   2025 		NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
   2026 		tval = (u_quad_t)sf->f_blocks;
   2027 		tval *= (u_quad_t)sf->f_bsize;
   2028 		txdr_hyper(tval, tl); tl += 2;
   2029 		tval = (u_quad_t)sf->f_bfree;
   2030 		tval *= (u_quad_t)sf->f_bsize;
   2031 		txdr_hyper(tval, tl); tl += 2;
   2032 		tval = (u_quad_t)sf->f_bavail;
   2033 		tval *= (u_quad_t)sf->f_bsize;
   2034 		txdr_hyper(tval, tl); tl += 2;
   2035 		tval = (u_quad_t)sf->f_files;
   2036 		txdr_hyper(tval, tl); tl += 2;
   2037 		tval = (u_quad_t)sf->f_ffree;
   2038 		txdr_hyper(tval, tl); tl += 2;
   2039 		tval = (u_quad_t)sf->f_ffree;
   2040 		txdr_hyper(tval, tl); tl += 2;
   2041 		*tl = 0;
   2042 	}
   2043 
   2044 out:
   2045 	NFSEXITCODE2(0, nd);
   2046 	return (0);
   2047 }
   2048 
   2049 /*
   2050  * nfs fsinfo service
   2051  */
   2052 APPLESTATIC int
   2053 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
   2054     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   2055 {
   2056 	u_int32_t *tl;
   2057 	struct nfsfsinfo fs;
   2058 	int getret = 1;
   2059 	struct nfsvattr at;
   2060 
   2061 	if (nd->nd_repstat) {
   2062 		nfsrv_postopattr(nd, getret, &at);
   2063 		goto out;
   2064 	}
   2065 	getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
   2066 	nfsvno_getfs(&fs, isdgram);
   2067 	vput(vp);
   2068 	nfsrv_postopattr(nd, getret, &at);
   2069 	NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
   2070 	*tl++ = txdr_unsigned(fs.fs_rtmax);
   2071 	*tl++ = txdr_unsigned(fs.fs_rtpref);
   2072 	*tl++ = txdr_unsigned(fs.fs_rtmult);
   2073 	*tl++ = txdr_unsigned(fs.fs_wtmax);
   2074 	*tl++ = txdr_unsigned(fs.fs_wtpref);
   2075 	*tl++ = txdr_unsigned(fs.fs_wtmult);
   2076 	*tl++ = txdr_unsigned(fs.fs_dtpref);
   2077 	txdr_hyper(fs.fs_maxfilesize, tl);
   2078 	tl += 2;
   2079 	txdr_nfsv3time(&fs.fs_timedelta, tl);
   2080 	tl += 2;
   2081 	*tl = txdr_unsigned(fs.fs_properties);
   2082 
   2083 out:
   2084 	NFSEXITCODE2(0, nd);
   2085 	return (0);
   2086 }
   2087 
   2088 /*
   2089  * nfs pathconf service
   2090  */
   2091 APPLESTATIC int
   2092 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
   2093     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   2094 {
   2095 	struct nfsv3_pathconf *pc;
   2096 	int getret = 1;
   2097 	register_t linkmax, namemax, chownres, notrunc;
   2098 	struct nfsvattr at;
   2099 
   2100 	if (nd->nd_repstat) {
   2101 		nfsrv_postopattr(nd, getret, &at);
   2102 		goto out;
   2103 	}
   2104 	nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
   2105 	    nd->nd_cred, p);
   2106 	if (!nd->nd_repstat)
   2107 		nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
   2108 		    nd->nd_cred, p);
   2109 	if (!nd->nd_repstat)
   2110 		nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
   2111 		    &chownres, nd->nd_cred, p);
   2112 	if (!nd->nd_repstat)
   2113 		nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, &notrunc,
   2114 		    nd->nd_cred, p);
   2115 	getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
   2116 	vput(vp);
   2117 	nfsrv_postopattr(nd, getret, &at);
   2118 	if (!nd->nd_repstat) {
   2119 		NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
   2120 		pc->pc_linkmax = txdr_unsigned(linkmax);
   2121 		pc->pc_namemax = txdr_unsigned(namemax);
   2122 		pc->pc_notrunc = txdr_unsigned(notrunc);
   2123 		pc->pc_chownrestricted = txdr_unsigned(chownres);
   2124 
   2125 		/*
   2126 		 * These should probably be supported by VOP_PATHCONF(), but
   2127 		 * until msdosfs is exportable (why would you want to?), the
   2128 		 * Unix defaults should be ok.
   2129 		 */
   2130 		pc->pc_caseinsensitive = newnfs_false;
   2131 		pc->pc_casepreserving = newnfs_true;
   2132 	}
   2133 
   2134 out:
   2135 	NFSEXITCODE2(0, nd);
   2136 	return (0);
   2137 }
   2138 
   2139 /*
   2140  * nfsv4 lock service
   2141  */
   2142 APPLESTATIC int
   2143 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
   2144     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
   2145 {
   2146 	u_int32_t *tl;
   2147 	int i;
   2148 	struct nfsstate *stp = NULL;
   2149 	struct nfslock *lop;
   2150 	struct nfslockconflict cf;
   2151 	int error = 0;
   2152 	u_short flags = NFSLCK_LOCK, lflags;
   2153 	u_int64_t offset, len;
   2154 	nfsv4stateid_t stateid;
   2155 	nfsquad_t clientid;
   2156 
   2157 	NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
   2158 	i = fxdr_unsigned(int, *tl++);
   2159 	switch (i) {
   2160 	case NFSV4LOCKT_READW:
   2161 		flags |= NFSLCK_BLOCKING;
   2162 	case NFSV4LOCKT_READ:
   2163 		lflags = NFSLCK_READ;
   2164 		break;
   2165 	case NFSV4LOCKT_WRITEW:
   2166 		flags |= NFSLCK_BLOCKING;
   2167 	case NFSV4LOCKT_WRITE:
   2168 		lflags = NFSLCK_WRITE;
   2169 		break;
   2170 	default:
   2171 		nd->nd_repstat = NFSERR_BADXDR;
   2172 		goto nfsmout;
   2173 	};
   2174 	if (*tl++ == newnfs_true)
   2175 		flags |= NFSLCK_RECLAIM;
   2176 	offset = fxdr_hyper(tl);
   2177 	tl += 2;
   2178 	len = fxdr_hyper(tl);
   2179 	tl += 2;
   2180 	if (*tl == newnfs_true)
   2181 		flags |= NFSLCK_OPENTOLOCK;
   2182 	if (flags & NFSLCK_OPENTOLOCK) {
   2183 		NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
   2184 		i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
   2185 		if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
   2186 			nd->nd_repstat = NFSERR_BADXDR;
   2187 			goto nfsmout;
   2188 		}
   2189 		MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
   2190 			M_NFSDSTATE, M_WAITOK);
   2191 		stp->ls_ownerlen = i;
   2192 		stp->ls_op = nd->nd_rp;
   2193 		stp->ls_seq = fxdr_unsigned(int, *tl++);
   2194 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
   2195 		NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
   2196 			NFSX_STATEIDOTHER);
   2197 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
   2198 		stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
   2199 		clientid.lval[0] = *tl++;
   2200 		clientid.lval[1] = *tl++;
   2201 		if (nd->nd_flag & ND_IMPLIEDCLID) {
   2202 			if (nd->nd_clientid.qval != clientid.qval)
   2203 				printf("EEK! multiple clids\n");
   2204 		} else {
   2205 			nd->nd_flag |= ND_IMPLIEDCLID;
   2206 			nd->nd_clientid.qval = clientid.qval;
   2207 		}
   2208 		error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
   2209 		if (error)
   2210 			goto nfsmout;
   2211 	} else {
   2212 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
   2213 		MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
   2214 			M_NFSDSTATE, M_WAITOK);
   2215 		stp->ls_ownerlen = 0;
   2216 		stp->ls_op = nd->nd_rp;
   2217 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
   2218 		NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
   2219 			NFSX_STATEIDOTHER);
   2220 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
   2221 		stp->ls_seq = fxdr_unsigned(int, *tl);
   2222 		clientid.lval[0] = stp->ls_stateid.other[0];
   2223 		clientid.lval[1] = stp->ls_stateid.other[1];
   2224 		if (nd->nd_flag & ND_IMPLIEDCLID) {
   2225 			if (nd->nd_clientid.qval != clientid.qval)
   2226 				printf("EEK! multiple clids\n");
   2227 		} else {
   2228 			nd->nd_flag |= ND_IMPLIEDCLID;
   2229 			nd->nd_clientid.qval = clientid.qval;
   2230 		}
   2231 	}
   2232 	MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
   2233 		M_NFSDLOCK, M_WAITOK);
   2234 	lop->lo_first = offset;
   2235 	if (len == NFS64BITSSET) {
   2236 		lop->lo_end = NFS64BITSSET;
   2237 	} else {
   2238 		lop->lo_end = offset + len;
   2239 		if (lop->lo_end <= lop->lo_first)
   2240 			nd->nd_repstat = NFSERR_INVAL;
   2241 	}
   2242 	lop->lo_flags = lflags;
   2243 	stp->ls_flags = flags;
   2244 	stp->ls_uid = nd->nd_cred->cr_uid;
   2245 
   2246 	/*
   2247 	 * Do basic access checking.
   2248 	 */
   2249 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
   2250 	    if (vnode_vtype(vp) == VDIR)
   2251 		nd->nd_repstat = NFSERR_ISDIR;
   2252 	    else
   2253 		nd->nd_repstat = NFSERR_INVAL;
   2254 	}
   2255 	if (!nd->nd_repstat) {
   2256 	    if (lflags & NFSLCK_WRITE) {
   2257 		nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
   2258 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
   2259 		    NFSACCCHK_VPISLOCKED, NULL);
   2260 	    } else {
   2261 		nd->nd_repstat = nfsvno_accchk(vp, VREAD,
   2262 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
   2263 		    NFSACCCHK_VPISLOCKED, NULL);
   2264 		if (nd->nd_repstat)
   2265 		    nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
   2266 			nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
   2267 			NFSACCCHK_VPISLOCKED, NULL);
   2268 	    }
   2269 	}
   2270 
   2271 	/*
   2272 	 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
   2273 	 * seqid# gets updated. nfsrv_lockctrl() will return the value
   2274 	 * of nd_repstat, if it gets that far.
   2275 	 */
   2276 	nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
   2277 		&stateid, exp, nd, p);
   2278 	if (lop)
   2279 		FREE((caddr_t)lop, M_NFSDLOCK);
   2280 	if (stp)
   2281 		FREE((caddr_t)stp, M_NFSDSTATE);
   2282 	if (!nd->nd_repstat) {
   2283 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
   2284 		*tl++ = txdr_unsigned(stateid.seqid);
   2285 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
   2286 	} else if (nd->nd_repstat == NFSERR_DENIED) {
   2287 		NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
   2288 		txdr_hyper(cf.cl_first, tl);
   2289 		tl += 2;
   2290 		if (cf.cl_end == NFS64BITSSET)
   2291 			len = NFS64BITSSET;
   2292 		else
   2293 			len = cf.cl_end - cf.cl_first;
   2294 		txdr_hyper(len, tl);
   2295 		tl += 2;
   2296 		if (cf.cl_flags == NFSLCK_WRITE)
   2297 			*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
   2298 		else
   2299 			*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
   2300 		*tl++ = stateid.other[0];
   2301 		*tl = stateid.other[1];
   2302 		(void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
   2303 	}
   2304 	vput(vp);
   2305 	NFSEXITCODE2(0, nd);
   2306 	return (0);
   2307 nfsmout:
   2308 	vput(vp);
   2309 	if (stp)
   2310 		free((caddr_t)stp, M_NFSDSTATE);
   2311 	NFSEXITCODE2(error, nd);
   2312 	return (error);
   2313 }
   2314 
   2315 /*
   2316  * nfsv4 lock test service
   2317  */
   2318 APPLESTATIC int
   2319 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
   2320     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
   2321 {
   2322 	u_int32_t *tl;
   2323 	int i;
   2324 	struct nfsstate *stp = NULL;
   2325 	struct nfslock lo, *lop = &lo;
   2326 	struct nfslockconflict cf;
   2327 	int error = 0;
   2328 	nfsv4stateid_t stateid;
   2329 	nfsquad_t clientid;
   2330 	u_int64_t len;
   2331 
   2332 	NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
   2333 	i = fxdr_unsigned(int, *(tl + 7));
   2334 	if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
   2335 		nd->nd_repstat = NFSERR_BADXDR;
   2336 		goto nfsmout;
   2337 	}
   2338 	MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
   2339 	    M_NFSDSTATE, M_WAITOK);
   2340 	stp->ls_ownerlen = i;
   2341 	stp->ls_op = NULL;
   2342 	stp->ls_flags = NFSLCK_TEST;
   2343 	stp->ls_uid = nd->nd_cred->cr_uid;
   2344 	i = fxdr_unsigned(int, *tl++);
   2345 	switch (i) {
   2346 	case NFSV4LOCKT_READW:
   2347 		stp->ls_flags |= NFSLCK_BLOCKING;
   2348 	case NFSV4LOCKT_READ:
   2349 		lo.lo_flags = NFSLCK_READ;
   2350 		break;
   2351 	case NFSV4LOCKT_WRITEW:
   2352 		stp->ls_flags |= NFSLCK_BLOCKING;
   2353 	case NFSV4LOCKT_WRITE:
   2354 		lo.lo_flags = NFSLCK_WRITE;
   2355 		break;
   2356 	default:
   2357 		nd->nd_repstat = NFSERR_BADXDR;
   2358 		goto nfsmout;
   2359 	};
   2360 	lo.lo_first = fxdr_hyper(tl);
   2361 	tl += 2;
   2362 	len = fxdr_hyper(tl);
   2363 	if (len == NFS64BITSSET) {
   2364 		lo.lo_end = NFS64BITSSET;
   2365 	} else {
   2366 		lo.lo_end = lo.lo_first + len;
   2367 		if (lo.lo_end <= lo.lo_first)
   2368 			nd->nd_repstat = NFSERR_INVAL;
   2369 	}
   2370 	tl += 2;
   2371 	clientid.lval[0] = *tl++;
   2372 	clientid.lval[1] = *tl;
   2373 	if (nd->nd_flag & ND_IMPLIEDCLID) {
   2374 		if (nd->nd_clientid.qval != clientid.qval)
   2375 			printf("EEK! multiple clids\n");
   2376 	} else {
   2377 		nd->nd_flag |= ND_IMPLIEDCLID;
   2378 		nd->nd_clientid.qval = clientid.qval;
   2379 	}
   2380 	error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
   2381 	if (error)
   2382 		goto nfsmout;
   2383 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
   2384 	    if (vnode_vtype(vp) == VDIR)
   2385 		nd->nd_repstat = NFSERR_ISDIR;
   2386 	    else
   2387 		nd->nd_repstat = NFSERR_INVAL;
   2388 	}
   2389 	if (!nd->nd_repstat)
   2390 	  nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
   2391 	    &stateid, exp, nd, p);
   2392 	if (stp)
   2393 		FREE((caddr_t)stp, M_NFSDSTATE);
   2394 	if (nd->nd_repstat) {
   2395 	    if (nd->nd_repstat == NFSERR_DENIED) {
   2396 		NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
   2397 		txdr_hyper(cf.cl_first, tl);
   2398 		tl += 2;
   2399 		if (cf.cl_end == NFS64BITSSET)
   2400 			len = NFS64BITSSET;
   2401 		else
   2402 			len = cf.cl_end - cf.cl_first;
   2403 		txdr_hyper(len, tl);
   2404 		tl += 2;
   2405 		if (cf.cl_flags == NFSLCK_WRITE)
   2406 			*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
   2407 		else
   2408 			*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
   2409 		*tl++ = stp->ls_stateid.other[0];
   2410 		*tl = stp->ls_stateid.other[1];
   2411 		(void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
   2412 	    }
   2413 	}
   2414 	vput(vp);
   2415 	NFSEXITCODE2(0, nd);
   2416 	return (0);
   2417 nfsmout:
   2418 	vput(vp);
   2419 	if (stp)
   2420 		free((caddr_t)stp, M_NFSDSTATE);
   2421 	NFSEXITCODE2(error, nd);
   2422 	return (error);
   2423 }
   2424 
   2425 /*
   2426  * nfsv4 unlock service
   2427  */
   2428 APPLESTATIC int
   2429 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
   2430     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
   2431 {
   2432 	u_int32_t *tl;
   2433 	int i;
   2434 	struct nfsstate *stp;
   2435 	struct nfslock *lop;
   2436 	int error = 0;
   2437 	nfsv4stateid_t stateid;
   2438 	nfsquad_t clientid;
   2439 	u_int64_t len;
   2440 
   2441 	NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
   2442 	MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
   2443 	    M_NFSDSTATE, M_WAITOK);
   2444 	MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
   2445 	    M_NFSDLOCK, M_WAITOK);
   2446 	stp->ls_flags = NFSLCK_UNLOCK;
   2447 	lop->lo_flags = NFSLCK_UNLOCK;
   2448 	stp->ls_op = nd->nd_rp;
   2449 	i = fxdr_unsigned(int, *tl++);
   2450 	switch (i) {
   2451 	case NFSV4LOCKT_READW:
   2452 		stp->ls_flags |= NFSLCK_BLOCKING;
   2453 	case NFSV4LOCKT_READ:
   2454 		break;
   2455 	case NFSV4LOCKT_WRITEW:
   2456 		stp->ls_flags |= NFSLCK_BLOCKING;
   2457 	case NFSV4LOCKT_WRITE:
   2458 		break;
   2459 	default:
   2460 		nd->nd_repstat = NFSERR_BADXDR;
   2461 		free(stp, M_NFSDSTATE);
   2462 		free(lop, M_NFSDLOCK);
   2463 		goto nfsmout;
   2464 	};
   2465 	stp->ls_ownerlen = 0;
   2466 	stp->ls_uid = nd->nd_cred->cr_uid;
   2467 	stp->ls_seq = fxdr_unsigned(int, *tl++);
   2468 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
   2469 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
   2470 	    NFSX_STATEIDOTHER);
   2471 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
   2472 	lop->lo_first = fxdr_hyper(tl);
   2473 	tl += 2;
   2474 	len = fxdr_hyper(tl);
   2475 	if (len == NFS64BITSSET) {
   2476 		lop->lo_end = NFS64BITSSET;
   2477 	} else {
   2478 		lop->lo_end = lop->lo_first + len;
   2479 		if (lop->lo_end <= lop->lo_first)
   2480 			nd->nd_repstat = NFSERR_INVAL;
   2481 	}
   2482 	clientid.lval[0] = stp->ls_stateid.other[0];
   2483 	clientid.lval[1] = stp->ls_stateid.other[1];
   2484 	if (nd->nd_flag & ND_IMPLIEDCLID) {
   2485 		if (nd->nd_clientid.qval != clientid.qval)
   2486 			printf("EEK! multiple clids\n");
   2487 	} else {
   2488 		nd->nd_flag |= ND_IMPLIEDCLID;
   2489 		nd->nd_clientid.qval = clientid.qval;
   2490 	}
   2491 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
   2492 	    if (vnode_vtype(vp) == VDIR)
   2493 		nd->nd_repstat = NFSERR_ISDIR;
   2494 	    else
   2495 		nd->nd_repstat = NFSERR_INVAL;
   2496 	}
   2497 	/*
   2498 	 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
   2499 	 * seqid# gets incremented. nfsrv_lockctrl() will return the
   2500 	 * value of nd_repstat, if it gets that far.
   2501 	 */
   2502 	nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
   2503 	    &stateid, exp, nd, p);
   2504 	if (stp)
   2505 		FREE((caddr_t)stp, M_NFSDSTATE);
   2506 	if (lop)
   2507 		free((caddr_t)lop, M_NFSDLOCK);
   2508 	if (!nd->nd_repstat) {
   2509 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
   2510 		*tl++ = txdr_unsigned(stateid.seqid);
   2511 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
   2512 	}
   2513 nfsmout:
   2514 	vput(vp);
   2515 	NFSEXITCODE2(error, nd);
   2516 	return (error);
   2517 }
   2518 
   2519 /*
   2520  * nfsv4 open service
   2521  */
   2522 APPLESTATIC int
   2523 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
   2524     vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
   2525     struct nfsexstuff *exp)
   2526 {
   2527 	u_int32_t *tl;
   2528 	int i;
   2529 	struct nfsstate *stp = NULL;
   2530 	int error = 0, create, claim, exclusive_flag = 0;
   2531 	u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
   2532 	int how = NFSCREATE_UNCHECKED;
   2533 	int32_t cverf[2], tverf[2] = { 0, 0 };
   2534 	vnode_t vp = NULL, dirp = NULL;
   2535 	struct nfsvattr nva, dirfor, diraft;
   2536 	struct nameidata named;
   2537 	nfsv4stateid_t stateid, delegstateid;
   2538 	nfsattrbit_t attrbits;
   2539 	nfsquad_t clientid;
   2540 	char *bufp = NULL;
   2541 	u_long *hashp;
   2542 	NFSACL_T *aclp = NULL;
   2543 
   2544 #ifdef NFS4_ACL_EXTATTR_NAME
   2545 	aclp = acl_alloc(M_WAITOK);
   2546 	aclp->acl_cnt = 0;
   2547 #endif
   2548 	NFSZERO_ATTRBIT(&attrbits);
   2549 	named.ni_startdir = NULL;
   2550 	named.ni_cnd.cn_nameiop = 0;
   2551 	NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
   2552 	i = fxdr_unsigned(int, *(tl + 5));
   2553 	if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
   2554 		nd->nd_repstat = NFSERR_BADXDR;
   2555 		goto nfsmout;
   2556 	}
   2557 	MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
   2558 	    M_NFSDSTATE, M_WAITOK);
   2559 	stp->ls_ownerlen = i;
   2560 	stp->ls_op = nd->nd_rp;
   2561 	stp->ls_flags = NFSLCK_OPEN;
   2562 	stp->ls_uid = nd->nd_cred->cr_uid;
   2563 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
   2564 	i = fxdr_unsigned(int, *tl++);
   2565 	switch (i) {
   2566 	case NFSV4OPEN_ACCESSREAD:
   2567 		stp->ls_flags |= NFSLCK_READACCESS;
   2568 		break;
   2569 	case NFSV4OPEN_ACCESSWRITE:
   2570 		stp->ls_flags |= NFSLCK_WRITEACCESS;
   2571 		break;
   2572 	case NFSV4OPEN_ACCESSBOTH:
   2573 		stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
   2574 		break;
   2575 	default:
   2576 		nd->nd_repstat = NFSERR_INVAL;
   2577 	};
   2578 	i = fxdr_unsigned(int, *tl++);
   2579 	switch (i) {
   2580 	case NFSV4OPEN_DENYNONE:
   2581 		break;
   2582 	case NFSV4OPEN_DENYREAD:
   2583 		stp->ls_flags |= NFSLCK_READDENY;
   2584 		break;
   2585 	case NFSV4OPEN_DENYWRITE:
   2586 		stp->ls_flags |= NFSLCK_WRITEDENY;
   2587 		break;
   2588 	case NFSV4OPEN_DENYBOTH:
   2589 		stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
   2590 		break;
   2591 	default:
   2592 		nd->nd_repstat = NFSERR_INVAL;
   2593 	};
   2594 	clientid.lval[0] = *tl++;
   2595 	clientid.lval[1] = *tl;
   2596 	if (nd->nd_flag & ND_IMPLIEDCLID) {
   2597 		if (nd->nd_clientid.qval != clientid.qval)
   2598 			printf("EEK! multiple clids\n");
   2599 	} else {
   2600 		nd->nd_flag |= ND_IMPLIEDCLID;
   2601 		nd->nd_clientid.qval = clientid.qval;
   2602 	}
   2603 	error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
   2604 	if (error)
   2605 		goto nfsmout;
   2606 	NFSVNO_ATTRINIT(&nva);
   2607 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2608 	create = fxdr_unsigned(int, *tl);
   2609 	if (!nd->nd_repstat)
   2610 		nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
   2611 	if (create == NFSV4OPEN_CREATE) {
   2612 		nva.na_type = VREG;
   2613 		nva.na_mode = 0;
   2614 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2615 		how = fxdr_unsigned(int, *tl);
   2616 		switch (how) {
   2617 		case NFSCREATE_UNCHECKED:
   2618 		case NFSCREATE_GUARDED:
   2619 			error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p);
   2620 			if (error)
   2621 				goto nfsmout;
   2622 			/*
   2623 			 * If the na_gid being set is the same as that of
   2624 			 * the directory it is going in, clear it, since
   2625 			 * that is what will be set by default. This allows
   2626 			 * a user that isn't in that group to do the create.
   2627 			 */
   2628 			if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
   2629 			    nva.na_gid == dirfor.na_gid)
   2630 				NFSVNO_UNSET(&nva, gid);
   2631 			if (!nd->nd_repstat)
   2632 				nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
   2633 			break;
   2634 		case NFSCREATE_EXCLUSIVE:
   2635 			NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
   2636 			cverf[0] = *tl++;
   2637 			cverf[1] = *tl;
   2638 			break;
   2639 		default:
   2640 			nd->nd_repstat = NFSERR_BADXDR;
   2641 			goto nfsmout;
   2642 		};
   2643 	} else if (create != NFSV4OPEN_NOCREATE) {
   2644 		nd->nd_repstat = NFSERR_BADXDR;
   2645 		goto nfsmout;
   2646 	}
   2647 
   2648 	/*
   2649 	 * Now, handle the claim, which usually includes looking up a
   2650 	 * name in the directory referenced by dp. The exception is
   2651 	 * NFSV4OPEN_CLAIMPREVIOUS.
   2652 	 */
   2653 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2654 	claim = fxdr_unsigned(int, *tl);
   2655 	if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
   2656 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
   2657 		stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
   2658 		NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
   2659 		stp->ls_flags |= NFSLCK_DELEGCUR;
   2660 	} else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
   2661 		stp->ls_flags |= NFSLCK_DELEGPREV;
   2662 	}
   2663 	if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
   2664 	    || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
   2665 		if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
   2666 		    claim != NFSV4OPEN_CLAIMNULL)
   2667 			nd->nd_repstat = NFSERR_INVAL;
   2668 		if (nd->nd_repstat) {
   2669 			nd->nd_repstat = nfsrv_opencheck(clientid,
   2670 			    &stateid, stp, NULL, nd, p, nd->nd_repstat);
   2671 			goto nfsmout;
   2672 		}
   2673 		if (create == NFSV4OPEN_CREATE)
   2674 		    NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
   2675 			LOCKPARENT | LOCKLEAF | SAVESTART);
   2676 		else
   2677 		    NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
   2678 			LOCKLEAF | SAVESTART);
   2679 		nfsvno_setpathbuf(&named, &bufp, &hashp);
   2680 		error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
   2681 		if (error) {
   2682 			vrele(dp);
   2683 #ifdef NFS4_ACL_EXTATTR_NAME
   2684 			acl_free(aclp);
   2685 #endif
   2686 			FREE((caddr_t)stp, M_NFSDSTATE);
   2687 			nfsvno_relpathbuf(&named);
   2688 			NFSEXITCODE2(error, nd);
   2689 			return (error);
   2690 		}
   2691 		if (!nd->nd_repstat) {
   2692 			nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
   2693 			    p, &dirp);
   2694 		} else {
   2695 			vrele(dp);
   2696 			nfsvno_relpathbuf(&named);
   2697 		}
   2698 		if (create == NFSV4OPEN_CREATE) {
   2699 		    switch (how) {
   2700 		    case NFSCREATE_UNCHECKED:
   2701 			if (named.ni_vp) {
   2702 				/*
   2703 				 * Clear the setable attribute bits, except
   2704 				 * for Size, if it is being truncated.
   2705 				 */
   2706 				NFSZERO_ATTRBIT(&attrbits);
   2707 				if (NFSVNO_ISSETSIZE(&nva))
   2708 					NFSSETBIT_ATTRBIT(&attrbits,
   2709 					    NFSATTRBIT_SIZE);
   2710 			}
   2711 			break;
   2712 		    case NFSCREATE_GUARDED:
   2713 			if (named.ni_vp && !nd->nd_repstat)
   2714 				nd->nd_repstat = EEXIST;
   2715 			break;
   2716 		    case NFSCREATE_EXCLUSIVE:
   2717 			exclusive_flag = 1;
   2718 			if (!named.ni_vp)
   2719 				nva.na_mode = 0;
   2720 		    };
   2721 		}
   2722 		nfsvno_open(nd, &named, clientid, &stateid, stp,
   2723 		    &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
   2724 		    nd->nd_cred, p, exp, &vp);
   2725 	} else if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
   2726 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2727 		i = fxdr_unsigned(int, *tl);
   2728 		switch (i) {
   2729 		case NFSV4OPEN_DELEGATEREAD:
   2730 			stp->ls_flags |= NFSLCK_DELEGREAD;
   2731 			break;
   2732 		case NFSV4OPEN_DELEGATEWRITE:
   2733 			stp->ls_flags |= NFSLCK_DELEGWRITE;
   2734 		case NFSV4OPEN_DELEGATENONE:
   2735 			break;
   2736 		default:
   2737 			nd->nd_repstat = NFSERR_BADXDR;
   2738 			goto nfsmout;
   2739 		};
   2740 		stp->ls_flags |= NFSLCK_RECLAIM;
   2741 		vp = dp;
   2742 		NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
   2743 		if ((vp->v_iflag & VI_DOOMED) == 0)
   2744 			nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
   2745 			    stp, vp, nd, p, nd->nd_repstat);
   2746 		else
   2747 			nd->nd_repstat = NFSERR_PERM;
   2748 	} else {
   2749 		nd->nd_repstat = NFSERR_BADXDR;
   2750 		goto nfsmout;
   2751 	}
   2752 
   2753 	/*
   2754 	 * Do basic access checking.
   2755 	 */
   2756 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
   2757 		/*
   2758 		 * The IETF working group decided that this is the correct
   2759 		 * error return for all non-regular files.
   2760 		 */
   2761 		nd->nd_repstat = NFSERR_SYMLINK;
   2762 	}
   2763 	if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
   2764 	    nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
   2765 	        exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
   2766 	if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
   2767 	    nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
   2768 	        exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
   2769 	    if (nd->nd_repstat)
   2770 		nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
   2771 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
   2772 		    NFSACCCHK_VPISLOCKED, NULL);
   2773 	}
   2774 
   2775 	if (!nd->nd_repstat) {
   2776 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
   2777 		if (!nd->nd_repstat) {
   2778 			tverf[0] = nva.na_atime.tv_sec;
   2779 			tverf[1] = nva.na_atime.tv_nsec;
   2780 		}
   2781 	}
   2782 	if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
   2783 	    cverf[1] != tverf[1]))
   2784 		nd->nd_repstat = EEXIST;
   2785 	/*
   2786 	 * Do the open locking/delegation stuff.
   2787 	 */
   2788 	if (!nd->nd_repstat)
   2789 	    nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
   2790 		&delegstateid, &rflags, exp, p, nva.na_filerev);
   2791 
   2792 	/*
   2793 	 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
   2794 	 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
   2795 	 * (ie: Leave the NFSVOPUNLOCK() about here.)
   2796 	 */
   2797 	if (vp)
   2798 		NFSVOPUNLOCK(vp, 0);
   2799 	if (stp)
   2800 		FREE((caddr_t)stp, M_NFSDSTATE);
   2801 	if (!nd->nd_repstat && dirp)
   2802 		nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p,
   2803 		    0);
   2804 	if (!nd->nd_repstat) {
   2805 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
   2806 		*tl++ = txdr_unsigned(stateid.seqid);
   2807 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
   2808 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
   2809 		if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
   2810 			*tl++ = newnfs_true;
   2811 			*tl++ = 0;
   2812 			*tl++ = 0;
   2813 			*tl++ = 0;
   2814 			*tl++ = 0;
   2815 		} else {
   2816 			*tl++ = newnfs_false;	/* Since dirp is not locked */
   2817 			txdr_hyper(dirfor.na_filerev, tl);
   2818 			tl += 2;
   2819 			txdr_hyper(diraft.na_filerev, tl);
   2820 			tl += 2;
   2821 		}
   2822 		*tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
   2823 		(void) nfsrv_putattrbit(nd, &attrbits);
   2824 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2825 		if (rflags & NFSV4OPEN_READDELEGATE)
   2826 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
   2827 		else if (rflags & NFSV4OPEN_WRITEDELEGATE)
   2828 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
   2829 		else
   2830 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
   2831 		if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
   2832 			NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
   2833 			*tl++ = txdr_unsigned(delegstateid.seqid);
   2834 			NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
   2835 			    NFSX_STATEIDOTHER);
   2836 			tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
   2837 			if (rflags & NFSV4OPEN_RECALL)
   2838 				*tl = newnfs_true;
   2839 			else
   2840 				*tl = newnfs_false;
   2841 			if (rflags & NFSV4OPEN_WRITEDELEGATE) {
   2842 				NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
   2843 				*tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
   2844 				txdr_hyper(nva.na_size, tl);
   2845 			}
   2846 			NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
   2847 			*tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
   2848 			*tl++ = txdr_unsigned(0x0);
   2849 			acemask = NFSV4ACE_ALLFILESMASK;
   2850 			if (nva.na_mode & S_IRUSR)
   2851 			    acemask |= NFSV4ACE_READMASK;
   2852 			if (nva.na_mode & S_IWUSR)
   2853 			    acemask |= NFSV4ACE_WRITEMASK;
   2854 			if (nva.na_mode & S_IXUSR)
   2855 			    acemask |= NFSV4ACE_EXECUTEMASK;
   2856 			*tl = txdr_unsigned(acemask);
   2857 			(void) nfsm_strtom(nd, "OWNER@", 6);
   2858 		}
   2859 		*vpp = vp;
   2860 	} else if (vp) {
   2861 		vrele(vp);
   2862 	}
   2863 	if (dirp)
   2864 		vrele(dirp);
   2865 #ifdef NFS4_ACL_EXTATTR_NAME
   2866 	acl_free(aclp);
   2867 #endif
   2868 	NFSEXITCODE2(0, nd);
   2869 	return (0);
   2870 nfsmout:
   2871 	vrele(dp);
   2872 #ifdef NFS4_ACL_EXTATTR_NAME
   2873 	acl_free(aclp);
   2874 #endif
   2875 	if (stp)
   2876 		FREE((caddr_t)stp, M_NFSDSTATE);
   2877 	NFSEXITCODE2(error, nd);
   2878 	return (error);
   2879 }
   2880 
   2881 /*
   2882  * nfsv4 close service
   2883  */
   2884 APPLESTATIC int
   2885 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
   2886     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   2887 {
   2888 	u_int32_t *tl;
   2889 	struct nfsstate st, *stp = &st;
   2890 	int error = 0;
   2891 	nfsv4stateid_t stateid;
   2892 	nfsquad_t clientid;
   2893 
   2894 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
   2895 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
   2896 	stp->ls_ownerlen = 0;
   2897 	stp->ls_op = nd->nd_rp;
   2898 	stp->ls_uid = nd->nd_cred->cr_uid;
   2899 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
   2900 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
   2901 	    NFSX_STATEIDOTHER);
   2902 	stp->ls_flags = NFSLCK_CLOSE;
   2903 	clientid.lval[0] = stp->ls_stateid.other[0];
   2904 	clientid.lval[1] = stp->ls_stateid.other[1];
   2905 	if (nd->nd_flag & ND_IMPLIEDCLID) {
   2906 		if (nd->nd_clientid.qval != clientid.qval)
   2907 			printf("EEK! multiple clids\n");
   2908 	} else {
   2909 		nd->nd_flag |= ND_IMPLIEDCLID;
   2910 		nd->nd_clientid.qval = clientid.qval;
   2911 	}
   2912 	nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
   2913 	vput(vp);
   2914 	if (!nd->nd_repstat) {
   2915 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
   2916 		*tl++ = txdr_unsigned(stateid.seqid);
   2917 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
   2918 	}
   2919 	NFSEXITCODE2(0, nd);
   2920 	return (0);
   2921 nfsmout:
   2922 	vput(vp);
   2923 	NFSEXITCODE2(error, nd);
   2924 	return (error);
   2925 }
   2926 
   2927 /*
   2928  * nfsv4 delegpurge service
   2929  */
   2930 APPLESTATIC int
   2931 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
   2932     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
   2933 {
   2934 	u_int32_t *tl;
   2935 	int error = 0;
   2936 	nfsquad_t clientid;
   2937 
   2938 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
   2939 		nd->nd_repstat = NFSERR_WRONGSEC;
   2940 		goto nfsmout;
   2941 	}
   2942 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   2943 	clientid.lval[0] = *tl++;
   2944 	clientid.lval[1] = *tl;
   2945 	if (nd->nd_flag & ND_IMPLIEDCLID) {
   2946 		if (nd->nd_clientid.qval != clientid.qval)
   2947 			printf("EEK! multiple clids\n");
   2948 	} else {
   2949 		nd->nd_flag |= ND_IMPLIEDCLID;
   2950 		nd->nd_clientid.qval = clientid.qval;
   2951 	}
   2952 	nd->nd_repstat = nfsrv_delegupdate(clientid, NULL, NULL,
   2953 	    NFSV4OP_DELEGPURGE, nd->nd_cred, p);
   2954 nfsmout:
   2955 	NFSEXITCODE2(error, nd);
   2956 	return (error);
   2957 }
   2958 
   2959 /*
   2960  * nfsv4 delegreturn service
   2961  */
   2962 APPLESTATIC int
   2963 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
   2964     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   2965 {
   2966 	u_int32_t *tl;
   2967 	int error = 0;
   2968 	nfsv4stateid_t stateid;
   2969 	nfsquad_t clientid;
   2970 
   2971 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
   2972 	stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
   2973 	NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
   2974 	clientid.lval[0] = stateid.other[0];
   2975 	clientid.lval[1] = stateid.other[1];
   2976 	if (nd->nd_flag & ND_IMPLIEDCLID) {
   2977 		if (nd->nd_clientid.qval != clientid.qval)
   2978 			printf("EEK! multiple clids\n");
   2979 	} else {
   2980 		nd->nd_flag |= ND_IMPLIEDCLID;
   2981 		nd->nd_clientid.qval = clientid.qval;
   2982 	}
   2983 	nd->nd_repstat = nfsrv_delegupdate(clientid, &stateid, vp,
   2984 	    NFSV4OP_DELEGRETURN, nd->nd_cred, p);
   2985 nfsmout:
   2986 	vput(vp);
   2987 	NFSEXITCODE2(error, nd);
   2988 	return (error);
   2989 }
   2990 
   2991 /*
   2992  * nfsv4 get file handle service
   2993  */
   2994 APPLESTATIC int
   2995 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
   2996     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   2997 {
   2998 	fhandle_t fh;
   2999 
   3000 	nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
   3001 	vput(vp);
   3002 	if (!nd->nd_repstat)
   3003 		(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
   3004 	NFSEXITCODE2(0, nd);
   3005 	return (0);
   3006 }
   3007 
   3008 /*
   3009  * nfsv4 open confirm service
   3010  */
   3011 APPLESTATIC int
   3012 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
   3013     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   3014 {
   3015 	u_int32_t *tl;
   3016 	struct nfsstate st, *stp = &st;
   3017 	int error = 0;
   3018 	nfsv4stateid_t stateid;
   3019 	nfsquad_t clientid;
   3020 
   3021 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
   3022 	stp->ls_ownerlen = 0;
   3023 	stp->ls_op = nd->nd_rp;
   3024 	stp->ls_uid = nd->nd_cred->cr_uid;
   3025 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
   3026 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
   3027 	    NFSX_STATEIDOTHER);
   3028 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
   3029 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
   3030 	stp->ls_flags = NFSLCK_CONFIRM;
   3031 	clientid.lval[0] = stp->ls_stateid.other[0];
   3032 	clientid.lval[1] = stp->ls_stateid.other[1];
   3033 	if (nd->nd_flag & ND_IMPLIEDCLID) {
   3034 		if (nd->nd_clientid.qval != clientid.qval)
   3035 			printf("EEK! multiple clids\n");
   3036 	} else {
   3037 		nd->nd_flag |= ND_IMPLIEDCLID;
   3038 		nd->nd_clientid.qval = clientid.qval;
   3039 	}
   3040 	nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
   3041 	if (!nd->nd_repstat) {
   3042 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
   3043 		*tl++ = txdr_unsigned(stateid.seqid);
   3044 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
   3045 	}
   3046 nfsmout:
   3047 	vput(vp);
   3048 	NFSEXITCODE2(error, nd);
   3049 	return (error);
   3050 }
   3051 
   3052 /*
   3053  * nfsv4 open downgrade service
   3054  */
   3055 APPLESTATIC int
   3056 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
   3057     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   3058 {
   3059 	u_int32_t *tl;
   3060 	int i;
   3061 	struct nfsstate st, *stp = &st;
   3062 	int error = 0;
   3063 	nfsv4stateid_t stateid;
   3064 	nfsquad_t clientid;
   3065 
   3066 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
   3067 	stp->ls_ownerlen = 0;
   3068 	stp->ls_op = nd->nd_rp;
   3069 	stp->ls_uid = nd->nd_cred->cr_uid;
   3070 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
   3071 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
   3072 	    NFSX_STATEIDOTHER);
   3073 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
   3074 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
   3075 	i = fxdr_unsigned(int, *tl++);
   3076 	switch (i) {
   3077 	case NFSV4OPEN_ACCESSREAD:
   3078 		stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
   3079 		break;
   3080 	case NFSV4OPEN_ACCESSWRITE:
   3081 		stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
   3082 		break;
   3083 	case NFSV4OPEN_ACCESSBOTH:
   3084 		stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
   3085 		    NFSLCK_DOWNGRADE);
   3086 		break;
   3087 	default:
   3088 		nd->nd_repstat = NFSERR_BADXDR;
   3089 	};
   3090 	i = fxdr_unsigned(int, *tl);
   3091 	switch (i) {
   3092 	case NFSV4OPEN_DENYNONE:
   3093 		break;
   3094 	case NFSV4OPEN_DENYREAD:
   3095 		stp->ls_flags |= NFSLCK_READDENY;
   3096 		break;
   3097 	case NFSV4OPEN_DENYWRITE:
   3098 		stp->ls_flags |= NFSLCK_WRITEDENY;
   3099 		break;
   3100 	case NFSV4OPEN_DENYBOTH:
   3101 		stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
   3102 		break;
   3103 	default:
   3104 		nd->nd_repstat = NFSERR_BADXDR;
   3105 	};
   3106 
   3107 	clientid.lval[0] = stp->ls_stateid.other[0];
   3108 	clientid.lval[1] = stp->ls_stateid.other[1];
   3109 	if (nd->nd_flag & ND_IMPLIEDCLID) {
   3110 		if (nd->nd_clientid.qval != clientid.qval)
   3111 			printf("EEK! multiple clids\n");
   3112 	} else {
   3113 		nd->nd_flag |= ND_IMPLIEDCLID;
   3114 		nd->nd_clientid.qval = clientid.qval;
   3115 	}
   3116 	if (!nd->nd_repstat)
   3117 		nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
   3118 		    nd, p);
   3119 	if (!nd->nd_repstat) {
   3120 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
   3121 		*tl++ = txdr_unsigned(stateid.seqid);
   3122 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
   3123 	}
   3124 nfsmout:
   3125 	vput(vp);
   3126 	NFSEXITCODE2(error, nd);
   3127 	return (error);
   3128 }
   3129 
   3130 /*
   3131  * nfsv4 renew lease service
   3132  */
   3133 APPLESTATIC int
   3134 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
   3135     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   3136 {
   3137 	u_int32_t *tl;
   3138 	int error = 0;
   3139 	nfsquad_t clientid;
   3140 
   3141 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
   3142 		nd->nd_repstat = NFSERR_WRONGSEC;
   3143 		goto nfsmout;
   3144 	}
   3145 	NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
   3146 	clientid.lval[0] = *tl++;
   3147 	clientid.lval[1] = *tl;
   3148 	if (nd->nd_flag & ND_IMPLIEDCLID) {
   3149 		if (nd->nd_clientid.qval != clientid.qval)
   3150 			printf("EEK! multiple clids\n");
   3151 	} else {
   3152 		nd->nd_flag |= ND_IMPLIEDCLID;
   3153 		nd->nd_clientid.qval = clientid.qval;
   3154 	}
   3155 	nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
   3156 	    NULL, (nfsquad_t)((u_quad_t)0), nd, p);
   3157 nfsmout:
   3158 	NFSEXITCODE2(error, nd);
   3159 	return (error);
   3160 }
   3161 
   3162 /*
   3163  * nfsv4 security info service
   3164  */
   3165 APPLESTATIC int
   3166 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
   3167     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
   3168 {
   3169 	u_int32_t *tl;
   3170 	int len;
   3171 	struct nameidata named;
   3172 	vnode_t dirp = NULL, vp;
   3173 	struct nfsrvfh fh;
   3174 	struct nfsexstuff retnes;
   3175 	u_int32_t *sizp;
   3176 	int error = 0, savflag, i;
   3177 	char *bufp;
   3178 	u_long *hashp;
   3179 
   3180 	/*
   3181 	 * All this just to get the export flags for the name.
   3182 	 */
   3183 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
   3184 	    LOCKLEAF | SAVESTART);
   3185 	nfsvno_setpathbuf(&named, &bufp, &hashp);
   3186 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
   3187 	if (error) {
   3188 		vput(dp);
   3189 		nfsvno_relpathbuf(&named);
   3190 		goto out;
   3191 	}
   3192 	if (!nd->nd_repstat) {
   3193 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
   3194 	} else {
   3195 		vput(dp);
   3196 		nfsvno_relpathbuf(&named);
   3197 	}
   3198 	if (dirp)
   3199 		vrele(dirp);
   3200 	if (nd->nd_repstat)
   3201 		goto out;
   3202 	vrele(named.ni_startdir);
   3203 	nfsvno_relpathbuf(&named);
   3204 	fh.nfsrvfh_len = NFSX_MYFH;
   3205 	vp = named.ni_vp;
   3206 	nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
   3207 	vput(vp);
   3208 	savflag = nd->nd_flag;
   3209 	if (!nd->nd_repstat) {
   3210 		nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p);
   3211 		if (vp)
   3212 			vput(vp);
   3213 	}
   3214 	nd->nd_flag = savflag;
   3215 	if (nd->nd_repstat)
   3216 		goto out;
   3217 
   3218 	/*
   3219 	 * Finally have the export flags for name, so we can create
   3220 	 * the security info.
   3221 	 */
   3222 	len = 0;
   3223 	NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
   3224 	for (i = 0; i < retnes.nes_numsecflavor; i++) {
   3225 		if (retnes.nes_secflavors[i] == AUTH_SYS) {
   3226 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   3227 			*tl = txdr_unsigned(RPCAUTH_UNIX);
   3228 			len++;
   3229 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
   3230 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   3231 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
   3232 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
   3233 			    nfsgss_mechlist[KERBV_MECH].len);
   3234 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   3235 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
   3236 			*tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
   3237 			len++;
   3238 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
   3239 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   3240 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
   3241 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
   3242 			    nfsgss_mechlist[KERBV_MECH].len);
   3243 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   3244 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
   3245 			*tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
   3246 			len++;
   3247 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
   3248 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   3249 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
   3250 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
   3251 			    nfsgss_mechlist[KERBV_MECH].len);
   3252 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   3253 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
   3254 			*tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
   3255 			len++;
   3256 		}
   3257 	}
   3258 	*sizp = txdr_unsigned(len);
   3259 
   3260 out:
   3261 	NFSEXITCODE2(error, nd);
   3262 	return (error);
   3263 }
   3264 
   3265 /*
   3266  * nfsv4 set client id service
   3267  */
   3268 APPLESTATIC int
   3269 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
   3270     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   3271 {
   3272 	u_int32_t *tl;
   3273 	int i;
   3274 	int error = 0, idlen;
   3275 	struct nfsclient *clp = NULL;
   3276 	struct sockaddr_in *rad;
   3277 	u_char *verf, *ucp, *ucp2, addrbuf[24];
   3278 	nfsquad_t clientid, confirm;
   3279 
   3280 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
   3281 		nd->nd_repstat = NFSERR_WRONGSEC;
   3282 		goto out;
   3283 	}
   3284 	NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
   3285 	verf = (u_char *)tl;
   3286 	tl += (NFSX_VERF / NFSX_UNSIGNED);
   3287 	i = fxdr_unsigned(int, *tl);
   3288 	if (i > NFSV4_OPAQUELIMIT || i <= 0) {
   3289 		nd->nd_repstat = NFSERR_BADXDR;
   3290 		goto nfsmout;
   3291 	}
   3292 	idlen = i;
   3293 	if (nd->nd_flag & ND_GSS)
   3294 		i += nd->nd_princlen;
   3295 	MALLOC(clp, struct nfsclient *, sizeof (struct nfsclient) + i,
   3296 	    M_NFSDCLIENT, M_WAITOK);
   3297 	NFSBZERO((caddr_t)clp, sizeof (struct nfsclient) + i);
   3298 	NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
   3299 	NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
   3300 	NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
   3301 	clp->lc_req.nr_cred = NULL;
   3302 	NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
   3303 	clp->lc_idlen = idlen;
   3304 	error = nfsrv_mtostr(nd, clp->lc_id, idlen);
   3305 	if (error)
   3306 		goto nfsmout;
   3307 	if (nd->nd_flag & ND_GSS) {
   3308 		clp->lc_flags = LCL_GSS;
   3309 		if (nd->nd_flag & ND_GSSINTEGRITY)
   3310 			clp->lc_flags |= LCL_GSSINTEGRITY;
   3311 		else if (nd->nd_flag & ND_GSSPRIVACY)
   3312 			clp->lc_flags |= LCL_GSSPRIVACY;
   3313 	} else {
   3314 		clp->lc_flags = 0;
   3315 	}
   3316 	if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
   3317 		clp->lc_flags |= LCL_NAME;
   3318 		clp->lc_namelen = nd->nd_princlen;
   3319 		clp->lc_name = &clp->lc_id[idlen];
   3320 		NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
   3321 	} else {
   3322 		clp->lc_uid = nd->nd_cred->cr_uid;
   3323 		clp->lc_gid = nd->nd_cred->cr_gid;
   3324 	}
   3325 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   3326 	clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
   3327 	error = nfsrv_getclientipaddr(nd, clp);
   3328 	if (error)
   3329 		goto nfsmout;
   3330 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   3331 	clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
   3332 
   3333 	/*
   3334 	 * nfsrv_setclient() does the actual work of adding it to the
   3335 	 * client list. If there is no error, the structure has been
   3336 	 * linked into the client list and clp should no longer be used
   3337 	 * here. When an error is returned, it has not been linked in,
   3338 	 * so it should be free'd.
   3339 	 */
   3340 	nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
   3341 	if (nd->nd_repstat == NFSERR_CLIDINUSE) {
   3342 		if (clp->lc_flags & LCL_TCPCALLBACK)
   3343 			(void) nfsm_strtom(nd, "tcp", 3);
   3344 		else
   3345 			(void) nfsm_strtom(nd, "udp", 3);
   3346 		rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
   3347 		ucp = (u_char *)&rad->sin_addr.s_addr;
   3348 		ucp2 = (u_char *)&rad->sin_port;
   3349 		sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
   3350 		    ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
   3351 		    ucp2[0] & 0xff, ucp2[1] & 0xff);
   3352 		(void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
   3353 	}
   3354 	if (clp) {
   3355 		NFSSOCKADDRFREE(clp->lc_req.nr_nam);
   3356 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
   3357 		free((caddr_t)clp, M_NFSDCLIENT);
   3358 	}
   3359 	if (!nd->nd_repstat) {
   3360 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
   3361 		*tl++ = clientid.lval[0];
   3362 		*tl++ = clientid.lval[1];
   3363 		*tl++ = confirm.lval[0];
   3364 		*tl = confirm.lval[1];
   3365 	}
   3366 
   3367 out:
   3368 	NFSEXITCODE2(0, nd);
   3369 	return (0);
   3370 nfsmout:
   3371 	if (clp) {
   3372 		NFSSOCKADDRFREE(clp->lc_req.nr_nam);
   3373 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
   3374 		free((caddr_t)clp, M_NFSDCLIENT);
   3375 	}
   3376 	NFSEXITCODE2(error, nd);
   3377 	return (error);
   3378 }
   3379 
   3380 /*
   3381  * nfsv4 set client id confirm service
   3382  */
   3383 APPLESTATIC int
   3384 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
   3385     __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
   3386     __unused struct nfsexstuff *exp)
   3387 {
   3388 	u_int32_t *tl;
   3389 	int error = 0;
   3390 	nfsquad_t clientid, confirm;
   3391 
   3392 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
   3393 		nd->nd_repstat = NFSERR_WRONGSEC;
   3394 		goto nfsmout;
   3395 	}
   3396 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
   3397 	clientid.lval[0] = *tl++;
   3398 	clientid.lval[1] = *tl++;
   3399 	confirm.lval[0] = *tl++;
   3400 	confirm.lval[1] = *tl;
   3401 
   3402 	/*
   3403 	 * nfsrv_getclient() searches the client list for a match and
   3404 	 * returns the appropriate NFSERR status.
   3405 	 */
   3406 	nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
   3407 	    NULL, confirm, nd, p);
   3408 nfsmout:
   3409 	NFSEXITCODE2(error, nd);
   3410 	return (error);
   3411 }
   3412 
   3413 /*
   3414  * nfsv4 verify service
   3415  */
   3416 APPLESTATIC int
   3417 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
   3418     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   3419 {
   3420 	int error = 0, ret, fhsize = NFSX_MYFH;
   3421 	struct nfsvattr nva;
   3422 	struct statfs sf;
   3423 	struct nfsfsinfo fs;
   3424 	fhandle_t fh;
   3425 
   3426 	nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
   3427 	if (!nd->nd_repstat)
   3428 		nd->nd_repstat = nfsvno_statfs(vp, &sf);
   3429 	if (!nd->nd_repstat)
   3430 		nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
   3431 	if (!nd->nd_repstat) {
   3432 		nfsvno_getfs(&fs, isdgram);
   3433 		error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
   3434 		    &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
   3435 		if (!error) {
   3436 			if (nd->nd_procnum == NFSV4OP_NVERIFY) {
   3437 				if (ret == 0)
   3438 					nd->nd_repstat = NFSERR_SAME;
   3439 				else if (ret != NFSERR_NOTSAME)
   3440 					nd->nd_repstat = ret;
   3441 			} else if (ret)
   3442 				nd->nd_repstat = ret;
   3443 		}
   3444 	}
   3445 	vput(vp);
   3446 	NFSEXITCODE2(error, nd);
   3447 	return (error);
   3448 }
   3449 
   3450 /*
   3451  * nfs openattr rpc
   3452  */
   3453 APPLESTATIC int
   3454 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
   3455     vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
   3456     __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
   3457 {
   3458 	u_int32_t *tl;
   3459 	int error = 0, createdir;
   3460 
   3461 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   3462 	createdir = fxdr_unsigned(int, *tl);
   3463 	nd->nd_repstat = NFSERR_NOTSUPP;
   3464 nfsmout:
   3465 	vrele(dp);
   3466 	NFSEXITCODE2(error, nd);
   3467 	return (error);
   3468 }
   3469 
   3470 /*
   3471  * nfsv4 release lock owner service
   3472  */
   3473 APPLESTATIC int
   3474 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
   3475     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   3476 {
   3477 	u_int32_t *tl;
   3478 	struct nfsstate *stp = NULL;
   3479 	int error = 0, len;
   3480 	nfsquad_t clientid;
   3481 
   3482 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
   3483 		nd->nd_repstat = NFSERR_WRONGSEC;
   3484 		goto nfsmout;
   3485 	}
   3486 	NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
   3487 	len = fxdr_unsigned(int, *(tl + 2));
   3488 	if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
   3489 		nd->nd_repstat = NFSERR_BADXDR;
   3490 		goto nfsmout;
   3491 	}
   3492 	MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len,
   3493 	    M_NFSDSTATE, M_WAITOK);
   3494 	stp->ls_ownerlen = len;
   3495 	stp->ls_op = NULL;
   3496 	stp->ls_flags = NFSLCK_RELEASE;
   3497 	stp->ls_uid = nd->nd_cred->cr_uid;
   3498 	clientid.lval[0] = *tl++;
   3499 	clientid.lval[1] = *tl;
   3500 	if (nd->nd_flag & ND_IMPLIEDCLID) {
   3501 		if (nd->nd_clientid.qval != clientid.qval)
   3502 			printf("EEK! multiple clids\n");
   3503 	} else {
   3504 		nd->nd_flag |= ND_IMPLIEDCLID;
   3505 		nd->nd_clientid.qval = clientid.qval;
   3506 	}
   3507 	error = nfsrv_mtostr(nd, stp->ls_owner, len);
   3508 	if (error)
   3509 		goto nfsmout;
   3510 	nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
   3511 	FREE((caddr_t)stp, M_NFSDSTATE);
   3512 
   3513 	NFSEXITCODE2(0, nd);
   3514 	return (0);
   3515 nfsmout:
   3516 	if (stp)
   3517 		free((caddr_t)stp, M_NFSDSTATE);
   3518 	NFSEXITCODE2(error, nd);
   3519 	return (error);
   3520 }
   3521