xref: /openbsd/sys/nfs/nfs_serv.c (revision 564dba15)
1 /*	$OpenBSD: nfs_serv.c,v 1.126 2024/05/01 13:15:59 jsg Exp $	*/
2 /*     $NetBSD: nfs_serv.c,v 1.34 1997/05/12 23:37:12 fvdl Exp $       */
3 
4 /*
5  * Copyright (c) 1989, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Rick Macklem at The University of Guelph.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  *	@(#)nfs_serv.c	8.7 (Berkeley) 5/14/95
36  */
37 
38 /*
39  * nfs version 2 and 3 server calls to vnode ops
40  * - these routines generally have 3 phases
41  *   1 - break down and validate rpc request in mbuf list
42  *   2 - do the vnode ops for the request
43  *       (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
44  *   3 - build the rpc reply in an mbuf list
45  *   nb:
46  *	- do not mix the phases, since use of the nfsm_?? functions can cause
47  *	  us to return failures on a bad rpc or similar without doing any
48  *	  vrele() or vput()'s
49  *      - the nfsm_reply() function generates an nfs rpc reply with the nfs
50  *	  error number iff error != 0 whereas returning an error from the
51  *	  server function implies a fatal error such as a badly constructed rpc
52  *	  request that should be dropped without a reply.
53  *	For Version 3, we do not return after nfsm_reply() for the error case,
54  *	since most version 3 rpcs return more than the status for error cases.
55  */
56 
57 #include <sys/param.h>
58 #include <sys/systm.h>
59 #include <sys/proc.h>
60 #include <sys/namei.h>
61 #include <sys/vnode.h>
62 #include <sys/lock.h>
63 #include <sys/mount.h>
64 #include <sys/socket.h>
65 #include <sys/socketvar.h>
66 #include <sys/mbuf.h>
67 #include <sys/dirent.h>
68 #include <sys/stat.h>
69 #include <sys/pool.h>
70 #include <sys/unistd.h>
71 
72 #include <ufs/ufs/dir.h>
73 
74 #include <nfs/nfsproto.h>
75 #include <nfs/nfs.h>
76 #include <nfs/xdr_subs.h>
77 #include <nfs/nfs_var.h>
78 #include <nfs/nfsm_subs.h>
79 
80 /* Global vars */
81 extern u_int32_t nfs_xdrneg1;
82 extern u_int32_t nfs_false, nfs_true;
83 extern const enum vtype nv3tov_type[8];
84 extern struct nfsstats nfsstats;
85 
86 int nfsrv_access(struct vnode *, int, struct ucred *, int, struct proc *, int);
87 
88 static inline int
nfsm_reply(struct nfsm_info * infop,struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct mbuf ** mrq,int error,int statuslen)89 nfsm_reply(struct nfsm_info *infop, struct nfsrv_descript *nfsd,
90     struct nfssvc_sock *slp, struct mbuf **mrq, int error, int statuslen)
91 {
92 	nfsd->nd_repstat = error;
93 	if (error && !infop->nmi_v3)
94 		statuslen = 0;
95 	(void)nfs_rephead(statuslen, nfsd, slp, error,
96 		&infop->nmi_mreq, &infop->nmi_mb);
97 	if (infop->nmi_mrep != NULL) {
98 		m_freem(infop->nmi_mrep);
99 		infop->nmi_mrep = NULL;
100 	}
101 	*mrq = infop->nmi_mreq;
102 	if (error && (!infop->nmi_v3 || error == EBADRPC))
103 		return error;
104 	return 0;
105 }
106 
107 static inline int
nfsm_srvmtofh1(struct nfsm_info * infop,struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct mbuf ** mrq)108 nfsm_srvmtofh1(struct nfsm_info *infop, struct nfsrv_descript *nfsd,
109     struct nfssvc_sock *slp, struct mbuf **mrq)
110 {
111 	if (infop->nmi_v3) {
112 		uint32_t *tl = (uint32_t *)nfsm_dissect(infop, NFSX_UNSIGNED);
113 		if (tl == NULL)
114 			return 0; /* *infop->nmi_errorp set */
115 		if (fxdr_unsigned(int, *tl) != NFSX_V3FH) {
116 			*infop->nmi_errorp = EBADRPC;
117 			return nfsm_reply(infop, nfsd, slp, mrq,
118 			    *infop->nmi_errorp, 0);
119 		}
120 	}
121 	return 0;
122 }
123 
124 static inline int
nfsm_srvmtofh2(struct nfsm_info * infop,fhandle_t * fhp)125 nfsm_srvmtofh2(struct nfsm_info *infop, fhandle_t *fhp)
126 {
127 	uint32_t *tl = (uint32_t *)nfsm_dissect(infop, NFSX_V3FH);
128 	if (tl == NULL)
129 		return 1;
130 	bcopy(tl, fhp, NFSX_V3FH);
131 	if (infop->nmi_v3 == 0) {
132 		if (nfsm_adv(infop, NFSX_V2FH - NFSX_V3FH) != 0)
133 			return 1;
134 	}
135 	return 0;
136 }
137 
138 /*
139  * nfs v3 access service
140  */
141 int
nfsrv3_access(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)142 nfsrv3_access(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
143     struct proc *procp, struct mbuf **mrq)
144 {
145 	struct mbuf *nam = nfsd->nd_nam;
146 	struct nfsm_info	info;
147 	struct ucred *cred = &nfsd->nd_cr;
148 	struct vnode *vp;
149 	nfsfh_t nfh;
150 	fhandle_t *fhp;
151 	u_int32_t *tl;
152 	int error = 0, rdonly, getret;
153 	struct vattr va;
154 	u_long testmode, nfsmode;
155 
156 	info.nmi_mreq = NULL;
157 	info.nmi_mrep = nfsd->nd_mrep;
158 	info.nmi_md = nfsd->nd_md;
159 	info.nmi_dpos = nfsd->nd_dpos;
160 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
161 	info.nmi_errorp = &error;
162 
163 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
164 		return 0;
165 	else if (error != 0)
166 		goto nfsmout;
167 	fhp = &nfh.fh_generic;
168 	if (nfsm_srvmtofh2(&info, fhp) != 0)
169 		goto nfsmout;
170 	tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
171 	if (tl == NULL)
172 		goto nfsmout;
173 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
174 	if (error) {
175 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
176 		    NFSX_UNSIGNED) != 0)
177 			return 0;
178 		nfsm_srvpostop_attr(nfsd, 1, NULL, &info);
179 		error = 0;
180 		goto nfsmout;
181 	}
182 	nfsmode = fxdr_unsigned(u_int32_t, *tl);
183 	if ((nfsmode & NFSV3ACCESS_READ) &&
184 		nfsrv_access(vp, VREAD, cred, rdonly, procp, 0))
185 		nfsmode &= ~NFSV3ACCESS_READ;
186 	if (vp->v_type == VDIR)
187 		testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
188 			NFSV3ACCESS_DELETE);
189 	else
190 		testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
191 	if ((nfsmode & testmode) &&
192 		nfsrv_access(vp, VWRITE, cred, rdonly, procp, 0))
193 		nfsmode &= ~testmode;
194 	if (vp->v_type == VDIR)
195 		testmode = NFSV3ACCESS_LOOKUP;
196 	else
197 		testmode = NFSV3ACCESS_EXECUTE;
198 	if ((nfsmode & testmode) &&
199 		nfsrv_access(vp, VEXEC, cred, rdonly, procp, 0))
200 		nfsmode &= ~testmode;
201 	getret = VOP_GETATTR(vp, &va, cred, procp);
202 	vput(vp);
203 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
204 	    NFSX_POSTOPATTR(1) + NFSX_UNSIGNED) != 0)
205 		return 0;
206 	nfsm_srvpostop_attr(nfsd, getret, &va, &info);
207 	tl = nfsm_build(&info.nmi_mb, NFSX_UNSIGNED);
208 	*tl = txdr_unsigned(nfsmode);
209 nfsmout:
210 	return(error);
211 }
212 
213 /*
214  * nfs getattr service
215  */
216 int
nfsrv_getattr(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)217 nfsrv_getattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
218     struct proc *procp, struct mbuf **mrq)
219 {
220 	struct mbuf *nam = nfsd->nd_nam;
221 	struct nfsm_info	info;
222 	struct ucred *cred = &nfsd->nd_cr;
223 	struct nfs_fattr *fp;
224 	struct vattr va;
225 	struct vnode *vp;
226 	nfsfh_t nfh;
227 	fhandle_t *fhp;
228 	int error = 0, rdonly;
229 
230 	info.nmi_mreq = NULL;
231 	info.nmi_mrep = nfsd->nd_mrep;
232 	info.nmi_md = nfsd->nd_md;
233 	info.nmi_dpos = nfsd->nd_dpos;
234 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
235 	info.nmi_errorp = &error;
236 
237 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
238 		return 0;
239 	else if (error != 0)
240 		goto nfsmout;
241 	fhp = &nfh.fh_generic;
242 	if (nfsm_srvmtofh2(&info, fhp) != 0)
243 		goto nfsmout;
244 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
245 	if (error) {
246 		if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
247 			return 0;
248 		error = 0;
249 		goto nfsmout;
250 	}
251 	error = VOP_GETATTR(vp, &va, cred, procp);
252 	vput(vp);
253 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
254 	    NFSX_FATTR(nfsd->nd_flag & ND_NFSV3)) != 0)
255 		return 0;
256 	if (error) {
257 		error = 0;
258 		goto nfsmout;
259 	}
260 	fp = nfsm_build(&info.nmi_mb, NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
261 	nfsm_srvfattr(nfsd, &va, fp);
262 nfsmout:
263 	return(error);
264 }
265 
266 /*
267  * nfs setattr service
268  */
269 int
nfsrv_setattr(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)270 nfsrv_setattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
271     struct proc *procp, struct mbuf **mrq)
272 {
273 	struct mbuf *nam = nfsd->nd_nam;
274 	struct nfsm_info	info;
275 	struct ucred *cred = &nfsd->nd_cr;
276 	struct vattr va, preat;
277 	struct nfsv2_sattr *sp;
278 	struct nfs_fattr *fp;
279 	struct vnode *vp;
280 	nfsfh_t nfh;
281 	fhandle_t *fhp;
282 	u_int32_t *tl;
283 	int error = 0, rdonly, preat_ret = 1, postat_ret = 1;
284 	int gcheck = 0;
285 	struct timespec guard;
286 
287 	info.nmi_mreq = NULL;
288 	info.nmi_mrep = nfsd->nd_mrep;
289 	info.nmi_md = nfsd->nd_md;
290 	info.nmi_dpos = nfsd->nd_dpos;
291 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
292 	info.nmi_errorp = &error;
293 
294 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
295 		return 0;
296 	else if (error != 0)
297 		goto nfsmout;
298 	fhp = &nfh.fh_generic;
299 	if (nfsm_srvmtofh2(&info, fhp) != 0)
300 		goto nfsmout;
301 	VATTR_NULL(&va);
302 	if (info.nmi_v3) {
303 		va.va_vaflags |= VA_UTIMES_NULL;
304 		error = nfsm_srvsattr(&info.nmi_md, &va, info.nmi_mrep, &info.nmi_dpos);
305 		if (error)
306 			goto nfsmout;
307 		tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
308 		if (tl == NULL)
309 			goto nfsmout;
310 		gcheck = fxdr_unsigned(int, *tl);
311 		if (gcheck) {
312 			tl = (uint32_t *)nfsm_dissect(&info, 2 * NFSX_UNSIGNED);
313 			if (tl == NULL)
314 				goto nfsmout;
315 			fxdr_nfsv3time(tl, &guard);
316 		}
317 	} else {
318 		sp = (struct nfsv2_sattr *)nfsm_dissect(&info, NFSX_V2SATTR);
319 		if (sp == NULL)
320 			goto nfsmout;
321 		/*
322 		 * Nah nah nah nah na nah
323 		 * There is a bug in the Sun client that puts 0xffff in the mode
324 		 * field of sattr when it should put in 0xffffffff. The u_short
325 		 * doesn't sign extend.
326 		 * --> check the low order 2 bytes for 0xffff
327 		 */
328 		if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
329 			va.va_mode = nfstov_mode(sp->sa_mode);
330 		if (sp->sa_uid != nfs_xdrneg1)
331 			va.va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
332 		if (sp->sa_gid != nfs_xdrneg1)
333 			va.va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
334 		if (sp->sa_size != nfs_xdrneg1)
335 			va.va_size = fxdr_unsigned(u_quad_t, sp->sa_size);
336 		if (sp->sa_atime.nfsv2_sec != nfs_xdrneg1) {
337 #ifdef notyet
338 			fxdr_nfsv2time(&sp->sa_atime, &va.va_atime);
339 #else
340 			va.va_atime.tv_sec =
341 				fxdr_unsigned(u_int32_t,sp->sa_atime.nfsv2_sec);
342 			va.va_atime.tv_nsec = 0;
343 #endif
344 		}
345 		if (sp->sa_mtime.nfsv2_sec != nfs_xdrneg1)
346 			fxdr_nfsv2time(&sp->sa_mtime, &va.va_mtime);
347 
348 	}
349 
350 	/*
351 	 * Now that we have all the fields, lets do it.
352 	 */
353 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
354 	if (error) {
355 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
356 		    2 * NFSX_UNSIGNED) != 0)
357 			return 0;
358 		nfsm_srvwcc(nfsd, preat_ret, &preat, postat_ret, &va, &info);
359 		error = 0;
360 		goto nfsmout;
361 	}
362 	if (info.nmi_v3) {
363 		error = preat_ret = VOP_GETATTR(vp, &preat, cred, procp);
364 		if (!error && gcheck &&
365 			(preat.va_ctime.tv_sec != guard.tv_sec ||
366 			 preat.va_ctime.tv_nsec != guard.tv_nsec))
367 			error = NFSERR_NOT_SYNC;
368 		if (error) {
369 			vput(vp);
370 			if (nfsm_reply(&info, nfsd, slp, mrq, error,
371 			    NFSX_WCCDATA(info.nmi_v3)) != 0)
372 				return 0;
373 			nfsm_srvwcc(nfsd, preat_ret, &preat, postat_ret, &va,
374 			    &info);
375 			error = 0;
376 			goto nfsmout;
377 		}
378 	}
379 
380 	/*
381 	 * If the size is being changed write access is required, otherwise
382 	 * just check for a read only file system.
383 	 */
384 	if (va.va_size == ((u_quad_t)((quad_t) -1))) {
385 		if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
386 			error = EROFS;
387 			goto out;
388 		}
389 	} else {
390 		if (vp->v_type == VDIR) {
391 			error = EISDIR;
392 			goto out;
393 		} else if ((error = nfsrv_access(vp, VWRITE, cred, rdonly,
394 			procp, 1)) != 0)
395 			goto out;
396 	}
397 	error = VOP_SETATTR(vp, &va, cred, procp);
398 	postat_ret = VOP_GETATTR(vp, &va, cred, procp);
399 	if (!error)
400 		error = postat_ret;
401 out:
402 	vput(vp);
403 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
404 	    NFSX_WCCORFATTR(info.nmi_v3)) != 0)
405 		return 0;
406 	if (info.nmi_v3) {
407 		nfsm_srvwcc(nfsd, preat_ret, &preat, postat_ret, &va,
408 		    &info);
409 		error = 0;
410 		goto nfsmout;
411 	} else {
412 		fp = nfsm_build(&info.nmi_mb, NFSX_V2FATTR);
413 		nfsm_srvfattr(nfsd, &va, fp);
414 	}
415 nfsmout:
416 	return(error);
417 }
418 
419 static inline int
nfsm_srvnamesiz(struct nfsm_info * infop,int * lenp)420 nfsm_srvnamesiz(struct nfsm_info *infop, int *lenp)
421 {
422 	int len;
423 	uint32_t *tl = (uint32_t *)nfsm_dissect(infop, NFSX_UNSIGNED);
424 	if (tl == NULL)
425 		return 1;
426 	len = fxdr_unsigned(int32_t, *tl);
427 	if (len > NFS_MAXNAMLEN)
428 		*infop->nmi_errorp = NFSERR_NAMETOL;
429 	else if (len <= 0)
430 		*infop->nmi_errorp = EBADRPC;
431 	else {
432 		*infop->nmi_errorp = 0;
433 		*lenp = len;
434 	}
435 	return 0;
436 }
437 
438 /*
439  * nfs lookup rpc
440  */
441 int
nfsrv_lookup(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)442 nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
443     struct proc *procp, struct mbuf **mrq)
444 {
445 	struct mbuf *nam = nfsd->nd_nam;
446 	struct ucred *cred = &nfsd->nd_cr;
447 	struct nfs_fattr *fp;
448 	struct nameidata nd;
449 	struct vnode *vp, *dirp;
450 	struct nfsm_info	info;
451 	nfsfh_t nfh;
452 	fhandle_t *fhp;
453 	int error = 0, len, dirattr_ret = 1;
454 	int v3 = (nfsd->nd_flag & ND_NFSV3);
455 	struct vattr va, dirattr;
456 
457 	info.nmi_mrep = nfsd->nd_mrep;
458 	info.nmi_mreq = NULL;
459 	info.nmi_md = nfsd->nd_md;
460 	info.nmi_dpos = nfsd->nd_dpos;
461 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
462 	info.nmi_errorp = &error;
463 
464 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
465 		return 0;
466 	else if (error != 0)
467 		goto nfsmout;
468 	fhp = &nfh.fh_generic;
469 	if (nfsm_srvmtofh2(&info, fhp) != 0)
470 		goto nfsmout;
471 	if (nfsm_srvnamesiz(&info, &len) != 0)
472 		goto nfsmout;
473 	if (error) {
474 		if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
475 			return 0;
476 	}
477 
478 	NDINIT(&nd, LOOKUP, LOCKLEAF | SAVESTART, UIO_SYSSPACE, NULL, procp);
479 	nd.ni_cnd.cn_cred = cred;
480 	error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md, &info.nmi_dpos, &dirp, procp);
481 	if (dirp) {
482 		if (info.nmi_v3)
483 			dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred,
484 				procp);
485 		vrele(dirp);
486 	}
487 	if (error) {
488 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
489 		    NFSX_POSTOPATTR(info.nmi_v3)) != 0)
490 			return 0;
491 		nfsm_srvpostop_attr(nfsd, dirattr_ret, &dirattr, &info);
492 		return (0);
493 	}
494 	vrele(nd.ni_startdir);
495 	pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
496 	vp = nd.ni_vp;
497 	memset(fhp, 0, sizeof(nfh));
498 	fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
499 	error = VFS_VPTOFH(vp, &fhp->fh_fid);
500 	if (!error)
501 		error = VOP_GETATTR(vp, &va, cred, procp);
502 	vput(vp);
503 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
504 	    NFSX_SRVFH(info.nmi_v3) + NFSX_POSTOPORFATTR(info.nmi_v3) +
505 	    NFSX_POSTOPATTR(info.nmi_v3)) != 0)
506 		return 0;
507 	if (error) {
508 		nfsm_srvpostop_attr(nfsd, dirattr_ret, &dirattr, &info);
509 		error = 0;
510 		goto nfsmout;
511 	}
512 	nfsm_srvfhtom(&info.nmi_mb, fhp, info.nmi_v3);
513 	if (v3) {
514 		nfsm_srvpostop_attr(nfsd, 0, &va, &info);
515 		nfsm_srvpostop_attr(nfsd, dirattr_ret, &dirattr, &info);
516 	} else {
517 		fp = nfsm_build(&info.nmi_mb, NFSX_V2FATTR);
518 		nfsm_srvfattr(nfsd, &va, fp);
519 	}
520 nfsmout:
521 	return(error);
522 }
523 
524 /*
525  * nfs readlink service
526  */
527 int
nfsrv_readlink(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)528 nfsrv_readlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
529     struct proc *procp, struct mbuf **mrq)
530 {
531 	struct mbuf *nam = nfsd->nd_nam;
532 	struct ucred *cred = &nfsd->nd_cr;
533 	struct iovec iov;
534 	struct mbuf *mp = NULL;
535 	struct nfsm_info	info;
536 	u_int32_t *tl;
537 	int error = 0, rdonly, tlen, len = 0, getret;
538 	struct vnode *vp;
539 	struct vattr attr;
540 	nfsfh_t nfh;
541 	fhandle_t *fhp;
542 	struct uio uio;
543 
544 	info.nmi_mreq = NULL;
545 	info.nmi_mrep = nfsd->nd_mrep;
546 	info.nmi_md = nfsd->nd_md;
547 	info.nmi_dpos = nfsd->nd_dpos;
548 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
549 	info.nmi_errorp = &error;
550 
551 	memset(&uio, 0, sizeof(uio));
552 
553 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
554 		return 0;
555 	else if (error != 0)
556 		goto nfsmout;
557 	fhp = &nfh.fh_generic;
558 	if (nfsm_srvmtofh2(&info, fhp) != 0)
559 		goto nfsmout;
560 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
561 	if (error) {
562 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
563 		    2 * NFSX_UNSIGNED) != 0)
564 			return 0;
565 		nfsm_srvpostop_attr(nfsd, 1, NULL, &info);
566 		error = 0;
567 		goto nfsmout;
568 	}
569 	if (vp->v_type != VLNK) {
570 		if (info.nmi_v3)
571 			error = EINVAL;
572 		else
573 			error = ENXIO;
574 		goto out;
575 	}
576 
577 	MGET(mp, M_WAIT, MT_DATA);
578 	MCLGET(mp, M_WAIT);		/* MLEN < NFS_MAXPATHLEN < MCLBYTES */
579 	mp->m_len = NFS_MAXPATHLEN;
580 	len = NFS_MAXPATHLEN;
581 	iov.iov_base = mtod(mp, caddr_t);
582 	iov.iov_len = mp->m_len;
583 
584 	uio.uio_iov = &iov;
585 	uio.uio_iovcnt = 1;
586 	uio.uio_offset = 0;
587 	uio.uio_resid = NFS_MAXPATHLEN;
588 	uio.uio_rw = UIO_READ;
589 	uio.uio_segflg = UIO_SYSSPACE;
590 	uio.uio_procp = NULL;
591 
592 	error = VOP_READLINK(vp, &uio, cred);
593 out:
594 	getret = VOP_GETATTR(vp, &attr, cred, procp);
595 	vput(vp);
596 	if (error)
597 		m_freem(mp);
598 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
599 	    NFSX_POSTOPATTR(info.nmi_v3) + NFSX_UNSIGNED) != 0)
600 		return 0;
601 	if (info.nmi_v3) {
602 		nfsm_srvpostop_attr(nfsd, getret, &attr, &info);
603 		if (error) {
604 			error = 0;
605 			goto nfsmout;
606 		}
607 	}
608 	if (uio.uio_resid > 0) {
609 		len -= uio.uio_resid;
610 		tlen = nfsm_rndup(len);
611 		nfsm_adj(mp, NFS_MAXPATHLEN-tlen, tlen-len);
612 	}
613 	tl = nfsm_build(&info.nmi_mb, NFSX_UNSIGNED);
614 	*tl = txdr_unsigned(len);
615 	info.nmi_mb->m_next = mp;
616 
617 nfsmout:
618 	return (error);
619 }
620 
621 /*
622  * nfs read service
623  */
624 int
nfsrv_read(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)625 nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
626     struct proc *procp, struct mbuf **mrq)
627 {
628 	struct mbuf *nam = nfsd->nd_nam;
629 	struct ucred *cred = &nfsd->nd_cr;
630 	struct mbuf *m;
631 	struct nfs_fattr *fp;
632 	struct nfsm_info	info;
633 	u_int32_t *tl;
634 	int i, reqlen;
635 	int error = 0, rdonly, cnt, len, left, siz, tlen, getret = 1;
636 	struct mbuf *m2;
637 	struct vnode *vp;
638 	nfsfh_t nfh;
639 	fhandle_t *fhp;
640 	struct uio io, *uiop = &io;
641 	struct vattr va;
642 	off_t off;
643 
644 	info.nmi_mreq = NULL;
645 	info.nmi_mrep = nfsd->nd_mrep;
646 	info.nmi_md = nfsd->nd_md;
647 	info.nmi_dpos = nfsd->nd_dpos;
648 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
649 	info.nmi_errorp = &error;
650 
651 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
652 		return 0;
653 	else if (error != 0)
654 		goto nfsmout;
655 	fhp = &nfh.fh_generic;
656 	if (nfsm_srvmtofh2(&info, fhp) != 0)
657 		goto nfsmout;
658 	if (info.nmi_v3) {
659 		tl = (uint32_t *)nfsm_dissect(&info, 2 * NFSX_UNSIGNED);
660 		if (tl == NULL)
661 			goto nfsmout;
662 		off = fxdr_hyper(tl);
663 	} else {
664 		tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
665 		if (tl == NULL)
666 			goto nfsmout;
667 		off = (off_t)fxdr_unsigned(u_int32_t, *tl);
668 	}
669 
670 	tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
671 	if (tl == NULL)
672 		goto nfsmout;
673 	reqlen = fxdr_unsigned(int32_t, *tl);
674 	if (reqlen > (NFS_SRVMAXDATA(nfsd)) || reqlen <= 0) {
675 		error = EBADRPC;
676 		if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
677 			return 0;
678 	}
679 
680 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
681 	if (error)
682 		goto bad;
683 
684 	if (vp->v_type != VREG) {
685 		if (info.nmi_v3)
686 			error = EINVAL;
687 		else
688 			error = (vp->v_type == VDIR) ? EISDIR : EACCES;
689 	}
690 	if (!error) {
691 	    if ((error = nfsrv_access(vp, VREAD, cred, rdonly, procp, 1)) != 0)
692 		error = nfsrv_access(vp, VEXEC, cred, rdonly, procp, 1);
693 	}
694 	getret = VOP_GETATTR(vp, &va, cred, procp);
695 	if (!error)
696 		error = getret;
697 	if (error)
698 		goto vbad;
699 
700 	if (off >= va.va_size)
701 		cnt = 0;
702 	else if ((off + reqlen) > va.va_size)
703 		cnt = va.va_size - off;
704 	else
705 		cnt = reqlen;
706 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
707 	    NFSX_POSTOPORFATTR(info.nmi_v3) +
708 	    3 * NFSX_UNSIGNED+nfsm_rndup(cnt)) != 0)
709 		return 0;
710 	if (info.nmi_v3) {
711 		tl = nfsm_build(&info.nmi_mb, NFSX_V3FATTR + 4 * NFSX_UNSIGNED);
712 		*tl++ = nfs_true;
713 		fp = (struct nfs_fattr *)tl;
714 		tl += (NFSX_V3FATTR / sizeof (u_int32_t));
715 	} else {
716 		tl = nfsm_build(&info.nmi_mb, NFSX_V2FATTR + NFSX_UNSIGNED);
717 		fp = (struct nfs_fattr *)tl;
718 		tl += (NFSX_V2FATTR / sizeof (u_int32_t));
719 	}
720 	len = left = nfsm_rndup (cnt);
721 	if (cnt > 0) {
722 		struct iovec *iv, *iv2;
723 		size_t ivlen;
724 		/*
725 		 * Generate the mbuf list with the uio_iov ref. to it.
726 		 */
727 		i = 0;
728 		m = m2 = info.nmi_mb;
729 		while (left > 0) {
730 			siz = min(m_trailingspace(m), left);
731 			if (siz > 0) {
732 				left -= siz;
733 				i++;
734 			}
735 			if (left > 0) {
736 				MGET(m, M_WAIT, MT_DATA);
737 				if (left >= MINCLSIZE)
738 					MCLGET(m, M_WAIT);
739 				m->m_len = 0;
740 				m2->m_next = m;
741 				m2 = m;
742 			}
743 		}
744 		iv = mallocarray(i, sizeof(*iv), M_TEMP, M_WAITOK);
745 		ivlen = i * sizeof(*iv);
746 		uiop->uio_iov = iv2 = iv;
747 		m = info.nmi_mb;
748 		left = len;
749 		i = 0;
750 		while (left > 0) {
751 			if (m == NULL)
752 				panic("nfsrv_read iov");
753 			siz = min(m_trailingspace(m), left);
754 			if (siz > 0) {
755 				iv->iov_base = mtod(m, caddr_t) + m->m_len;
756 				iv->iov_len = siz;
757 				m->m_len += siz;
758 				left -= siz;
759 				iv++;
760 				i++;
761 			}
762 			m = m->m_next;
763 		}
764 		uiop->uio_iovcnt = i;
765 		uiop->uio_offset = off;
766 		uiop->uio_resid = len;
767 		uiop->uio_rw = UIO_READ;
768 		uiop->uio_segflg = UIO_SYSSPACE;
769 		error = VOP_READ(vp, uiop, IO_NODELOCKED, cred);
770 		off = uiop->uio_offset;
771 		free(iv2, M_TEMP, ivlen);
772 		if (error || (getret = VOP_GETATTR(vp, &va, cred, procp)) != 0){
773 			if (!error)
774 				error = getret;
775 			m_freem(info.nmi_mreq);
776 			goto vbad;
777 		}
778 	} else
779 		uiop->uio_resid = 0;
780 	vput(vp);
781 	nfsm_srvfattr(nfsd, &va, fp);
782 	tlen = len - uiop->uio_resid;
783 	cnt = cnt < tlen ? cnt : tlen;
784 	tlen = nfsm_rndup (cnt);
785 	if (len != tlen || tlen != cnt)
786 		nfsm_adj(info.nmi_mb, len - tlen, tlen - cnt);
787 	if (info.nmi_v3) {
788 		*tl++ = txdr_unsigned(cnt);
789 		if (len < reqlen)
790 			*tl++ = nfs_true;
791 		else
792 			*tl++ = nfs_false;
793 	}
794 	*tl = txdr_unsigned(cnt);
795 nfsmout:
796 	return(error);
797 
798 vbad:
799 	vput(vp);
800 bad:
801 	if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
802 		return 0;
803 	nfsm_srvpostop_attr(nfsd, getret, &va, &info);
804 	return (0);
805 }
806 
807 /*
808  * nfs write service
809  */
810 int
nfsrv_write(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)811 nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
812     struct proc *procp, struct mbuf **mrq)
813 {
814 	struct mbuf *nam = nfsd->nd_nam;
815 	struct ucred *cred = &nfsd->nd_cr;
816 	struct nfsm_info	info;
817 	int i, cnt;
818 	struct mbuf *mp;
819 	struct nfs_fattr *fp;
820 	struct timeval boottime;
821 	struct vattr va, forat;
822 	u_int32_t *tl;
823 	int error = 0, rdonly, len, forat_ret = 1;
824 	int ioflags, aftat_ret = 1, retlen, zeroing, adjust;
825 	int stable = NFSV3WRITE_FILESYNC;
826 	struct vnode *vp;
827 	nfsfh_t nfh;
828 	fhandle_t *fhp;
829 	struct uio io, *uiop = &io;
830 	off_t off;
831 
832 	info.nmi_mreq = NULL;
833 	info.nmi_mrep = nfsd->nd_mrep;
834 	info.nmi_md = nfsd->nd_md;
835 	info.nmi_dpos = nfsd->nd_dpos;
836 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
837 	info.nmi_errorp = &error;
838 
839 	if (info.nmi_mrep == NULL) {
840 		*mrq = NULL;
841 		return (0);
842 	}
843 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
844 		return 0;
845 	else if (error != 0)
846 		goto nfsmout;
847 	fhp = &nfh.fh_generic;
848 	if (nfsm_srvmtofh2(&info, fhp) != 0)
849 		goto nfsmout;
850 	if (info.nmi_v3) {
851 		tl = (uint32_t *)nfsm_dissect(&info, 5 * NFSX_UNSIGNED);
852 		if (tl == NULL)
853 			goto nfsmout;
854 		off = fxdr_hyper(tl);
855 		tl += 3;
856 		stable = fxdr_unsigned(int, *tl++);
857 	} else {
858 		tl = (uint32_t *)nfsm_dissect(&info, 4 * NFSX_UNSIGNED);
859 		if (tl == NULL)
860 			goto nfsmout;
861 		off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
862 		tl += 2;
863 	}
864 	retlen = len = fxdr_unsigned(int32_t, *tl);
865 	cnt = i = 0;
866 
867 	/*
868 	 * For NFS Version 2, it is not obvious what a write of zero length
869 	 * should do, but I might as well be consistent with Version 3,
870 	 * which is to return ok so long as there are no permission problems.
871 	 */
872 	if (len > 0) {
873 	    zeroing = 1;
874 	    mp = info.nmi_mrep;
875 	    while (mp) {
876 		if (mp == info.nmi_md) {
877 			zeroing = 0;
878 			adjust = info.nmi_dpos - mtod(mp, caddr_t);
879 			mp->m_len -= adjust;
880 			if (mp->m_len > 0 && adjust > 0)
881 				mp->m_data += adjust;
882 		}
883 		if (zeroing)
884 			mp->m_len = 0;
885 		else if (mp->m_len > 0) {
886 			i += mp->m_len;
887 			if (i > len) {
888 				mp->m_len -= (i - len);
889 				zeroing	= 1;
890 			}
891 			if (mp->m_len > 0)
892 				cnt++;
893 		}
894 		mp = mp->m_next;
895 	    }
896 	}
897 	if (len > NFS_MAXDATA || len < 0 || i < len) {
898 		error = EIO;
899 		goto bad;
900 	}
901 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
902 	if (error)
903 		goto bad;
904 	if (info.nmi_v3)
905 		forat_ret = VOP_GETATTR(vp, &forat, cred, procp);
906 	if (vp->v_type != VREG) {
907 		if (info.nmi_v3)
908 			error = EINVAL;
909 		else
910 			error = (vp->v_type == VDIR) ? EISDIR : EACCES;
911 		goto vbad;
912 	}
913 	error = nfsrv_access(vp, VWRITE, cred, rdonly, procp, 1);
914 	if (error)
915 		goto vbad;
916 
917 	if (len > 0) {
918 	    struct iovec *iv, *ivp;
919 	    size_t ivlen;
920 
921 	    ivp = mallocarray(cnt, sizeof(*ivp), M_TEMP, M_WAITOK);
922 	    ivlen = cnt * sizeof(*ivp);
923 	    uiop->uio_iov = iv = ivp;
924 	    uiop->uio_iovcnt = cnt;
925 	    mp = info.nmi_mrep;
926 	    while (mp) {
927 		if (mp->m_len > 0) {
928 			ivp->iov_base = mtod(mp, caddr_t);
929 			ivp->iov_len = mp->m_len;
930 			ivp++;
931 		}
932 		mp = mp->m_next;
933 	    }
934 
935 	    if (stable == NFSV3WRITE_UNSTABLE)
936 		ioflags = IO_NODELOCKED;
937 	    else if (stable == NFSV3WRITE_DATASYNC)
938 		ioflags = (IO_SYNC | IO_NODELOCKED);
939 	    else
940 		ioflags = (IO_SYNC | IO_NODELOCKED);
941 	    uiop->uio_resid = len;
942 	    uiop->uio_rw = UIO_WRITE;
943 	    uiop->uio_segflg = UIO_SYSSPACE;
944 	    uiop->uio_procp = NULL;
945 	    uiop->uio_offset = off;
946 	    error = VOP_WRITE(vp, uiop, ioflags, cred);
947 	    nfsstats.srvvop_writes++;
948 	    free(iv, M_TEMP, ivlen);
949 	}
950 	aftat_ret = VOP_GETATTR(vp, &va, cred, procp);
951 	vput(vp);
952 	if (!error)
953 		error = aftat_ret;
954 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
955 	    NFSX_PREOPATTR(info.nmi_v3) + NFSX_POSTOPORFATTR(info.nmi_v3) +
956 	    2 * NFSX_UNSIGNED + NFSX_WRITEVERF(info.nmi_v3)) != 0)
957 		return 0;
958 	if (info.nmi_v3) {
959 		nfsm_srvwcc(nfsd, forat_ret, &forat, aftat_ret, &va, &info);
960 		if (error) {
961 			error = 0;
962 			goto nfsmout;
963 		}
964 		tl = nfsm_build(&info.nmi_mb, 4 * NFSX_UNSIGNED);
965 		*tl++ = txdr_unsigned(retlen);
966 		if (stable == NFSV3WRITE_UNSTABLE)
967 			*tl++ = txdr_unsigned(stable);
968 		else
969 			*tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC);
970 		/*
971 		 * Actually, there is no need to txdr these fields,
972 		 * but it may make the values more human readable,
973 		 * for debugging purposes.
974 		 */
975 		microboottime(&boottime);
976 		*tl++ = txdr_unsigned(boottime.tv_sec);
977 		*tl = txdr_unsigned(boottime.tv_usec);
978 	} else {
979 		fp = nfsm_build(&info.nmi_mb, NFSX_V2FATTR);
980 		nfsm_srvfattr(nfsd, &va, fp);
981 	}
982 nfsmout:
983 	return(error);
984 
985 vbad:
986 	vput(vp);
987 bad:
988 	if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
989 		return 0;
990 	nfsm_srvwcc(nfsd, forat_ret, &forat, aftat_ret, &va, &info);
991 	return (0);
992 }
993 
994 static inline void
nfsm_srvpostop_fh(struct nfsm_info * infop,fhandle_t * fhp)995 nfsm_srvpostop_fh(struct nfsm_info *infop, fhandle_t *fhp)
996 {
997 	uint32_t *tl;
998 
999 	tl = nfsm_build(&infop->nmi_mb, 2 * NFSX_UNSIGNED + NFSX_V3FH);
1000 	*tl++ = nfs_true;
1001 	*tl++ = txdr_unsigned(NFSX_V3FH);
1002 	bcopy(fhp, tl, NFSX_V3FH);
1003 }
1004 
1005 /*
1006  * nfs create service
1007  * now does a truncate to 0 length via. setattr if it already exists
1008  */
1009 int
nfsrv_create(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)1010 nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
1011     struct proc *procp, struct mbuf **mrq)
1012 {
1013 	struct mbuf *nam = nfsd->nd_nam;
1014 	struct ucred *cred = &nfsd->nd_cr;
1015 	struct nfs_fattr *fp;
1016 	struct vattr va, dirfor, diraft;
1017 	struct nfsv2_sattr *sp;
1018 	struct nfsm_info	info;
1019 	u_int32_t *tl;
1020 	struct nameidata nd;
1021 	caddr_t cp;
1022 	int error = 0, len, tsize, dirfor_ret = 1, diraft_ret = 1;
1023 	dev_t rdev = 0;
1024 	int how, exclusive_flag = 0;
1025 	struct vnode *vp = NULL, *dirp = NULL;
1026 	nfsfh_t nfh;
1027 	fhandle_t *fhp;
1028 	u_quad_t tempsize;
1029 	u_char cverf[NFSX_V3CREATEVERF];
1030 
1031 	info.nmi_mreq = NULL;
1032 	info.nmi_mrep = nfsd->nd_mrep;
1033 	info.nmi_md = nfsd->nd_md;
1034 	info.nmi_dpos = nfsd->nd_dpos;
1035 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
1036 	info.nmi_errorp = &error;
1037 
1038 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
1039 		return 0;
1040 	else if (error != 0)
1041 		goto nfsmout;
1042 	fhp = &nfh.fh_generic;
1043 	if (nfsm_srvmtofh2(&info, fhp) != 0)
1044 		goto nfsmout;
1045 	if (nfsm_srvnamesiz(&info, &len) != 0)
1046 		goto nfsmout;
1047 	if (error) {
1048 		if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
1049 			return 0;
1050 	}
1051 
1052 	NDINIT(&nd, CREATE, LOCKPARENT | LOCKLEAF | SAVESTART, UIO_SYSSPACE,
1053 	    NULL, procp);
1054 	nd.ni_cnd.cn_cred = cred;
1055 	error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md,
1056 	    &info.nmi_dpos, &dirp, procp);
1057 	if (dirp) {
1058 		if (info.nmi_v3)
1059 			dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp);
1060 		else {
1061 			vrele(dirp);
1062 			dirp = NULL;
1063 		}
1064 	}
1065 	if (error) {
1066 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
1067 		    NFSX_WCCDATA(info.nmi_v3)) != 0)
1068 			return 0;
1069 		nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft,
1070 		    &info);
1071 		if (dirp)
1072 			vrele(dirp);
1073 		return (0);
1074 	}
1075 
1076 	VATTR_NULL(&va);
1077 	if (info.nmi_v3) {
1078 		tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
1079 		if (tl == NULL)
1080 			goto nfsmout;
1081 		how = fxdr_unsigned(int, *tl);
1082 		switch (how) {
1083 		case NFSV3CREATE_GUARDED:
1084 			if (nd.ni_vp) {
1085 				error = EEXIST;
1086 				break;
1087 			}
1088 		case NFSV3CREATE_UNCHECKED:
1089 			error = nfsm_srvsattr(&info.nmi_md, &va, info.nmi_mrep,
1090 			    &info.nmi_dpos);
1091 			if (error)
1092 				goto nfsmout;
1093 			break;
1094 		case NFSV3CREATE_EXCLUSIVE:
1095 			cp = (caddr_t)nfsm_dissect(&info, NFSX_V3CREATEVERF);
1096 			if (cp == NULL)
1097 				goto nfsmout;
1098 			bcopy(cp, cverf, NFSX_V3CREATEVERF);
1099 			exclusive_flag = 1;
1100 			if (nd.ni_vp == NULL)
1101 				va.va_mode = 0;
1102 			break;
1103 		};
1104 		va.va_type = VREG;
1105 	} else {
1106 		sp = (struct nfsv2_sattr *)nfsm_dissect(&info, NFSX_V2SATTR);
1107 		if (sp == NULL)
1108 			goto nfsmout;
1109 		va.va_type = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
1110 		if (va.va_type == VNON)
1111 			va.va_type = VREG;
1112 		va.va_mode = nfstov_mode(sp->sa_mode);
1113 		switch (va.va_type) {
1114 		case VREG:
1115 			tsize = fxdr_unsigned(int32_t, sp->sa_size);
1116 			if (tsize != -1)
1117 				va.va_size = (u_quad_t)tsize;
1118 			break;
1119 		case VCHR:
1120 		case VBLK:
1121 		case VFIFO:
1122 			rdev = (dev_t)fxdr_unsigned(int32_t, sp->sa_size);
1123 			break;
1124 		default:
1125 			break;
1126 		};
1127 	}
1128 
1129 	/*
1130 	 * Iff doesn't exist, create it
1131 	 * otherwise just truncate to 0 length
1132 	 *   should I set the mode too ??
1133 	 */
1134 	if (nd.ni_vp == NULL) {
1135 		if (va.va_type == VREG || va.va_type == VSOCK) {
1136 			vrele(nd.ni_startdir);
1137 			error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd,
1138 			    &va);
1139 			vput(nd.ni_dvp);
1140 			if (!error) {
1141 				pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1142 				if (exclusive_flag) {
1143 					exclusive_flag = 0;
1144 					VATTR_NULL(&va);
1145 					bcopy(cverf, (caddr_t)&va.va_atime,
1146 						NFSX_V3CREATEVERF);
1147 					error = VOP_SETATTR(nd.ni_vp, &va, cred,
1148 						procp);
1149 				}
1150 			}
1151 		} else if (va.va_type == VCHR || va.va_type == VBLK ||
1152 			va.va_type == VFIFO) {
1153 			if (va.va_type == VCHR && rdev == 0xffffffff)
1154 				va.va_type = VFIFO;
1155 			if (va.va_type != VFIFO &&
1156 			    (error = suser_ucred(cred))) {
1157 				vrele(nd.ni_startdir);
1158 				if (nd.ni_cnd.cn_flags & HASBUF) {
1159 					pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1160 					nd.ni_cnd.cn_flags &= ~HASBUF;
1161 				}
1162 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1163 				vput(nd.ni_dvp);
1164 				if (nfsm_reply(&info, nfsd, slp, mrq, error,
1165 				    0) != 0)
1166 					return 0;
1167 				error = 0;
1168 				goto nfsmout;
1169 			} else
1170 				va.va_rdev = (dev_t)rdev;
1171 			error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd,
1172 			    &va);
1173 			vput(nd.ni_dvp);
1174 			if (error) {
1175 				vrele(nd.ni_startdir);
1176 				if (nd.ni_cnd.cn_flags & HASBUF) {
1177 					pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1178 					nd.ni_cnd.cn_flags &= ~HASBUF;
1179 				}
1180 				if (nfsm_reply(&info, nfsd, slp, mrq, error,
1181 				    0) != 0)
1182 					return 0;
1183 				error = 0;
1184 				goto nfsmout;
1185 			}
1186 			nd.ni_cnd.cn_nameiop = LOOKUP;
1187 			nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
1188 			nd.ni_cnd.cn_proc = procp;
1189 			nd.ni_cnd.cn_cred = cred;
1190 			if ((error = vfs_lookup(&nd)) != 0) {
1191 				if (nd.ni_cnd.cn_flags & HASBUF) {
1192 					pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1193 					nd.ni_cnd.cn_flags &= ~HASBUF;
1194 				}
1195 				if (nfsm_reply(&info, nfsd, slp, mrq, error,
1196 				    0) != 0)
1197 					return 0;
1198 				error = 0;
1199 				goto nfsmout;
1200 			}
1201 
1202 			pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1203 			if (nd.ni_cnd.cn_flags & ISSYMLINK) {
1204 				vrele(nd.ni_dvp);
1205 				vput(nd.ni_vp);
1206 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1207 				error = EINVAL;
1208 				if (nfsm_reply(&info, nfsd, slp, mrq, error,
1209 				    0) != 0)
1210 					return 0;
1211 				error = 0;
1212 				goto nfsmout;
1213 			}
1214 		} else {
1215 			vrele(nd.ni_startdir);
1216 			pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1217 			nd.ni_cnd.cn_flags &= ~HASBUF;
1218 			VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1219 			vput(nd.ni_dvp);
1220 			error = ENXIO;
1221 		}
1222 		vp = nd.ni_vp;
1223 	} else {
1224 		vrele(nd.ni_startdir);
1225 		pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1226 		nd.ni_cnd.cn_flags &= ~HASBUF;
1227 		vp = nd.ni_vp;
1228 		if (nd.ni_dvp == vp)
1229 			vrele(nd.ni_dvp);
1230 		else
1231 			vput(nd.ni_dvp);
1232 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1233 		if (va.va_size != -1) {
1234 			error = nfsrv_access(vp, VWRITE, cred,
1235 			    (nd.ni_cnd.cn_flags & RDONLY), procp, 0);
1236 			if (!error) {
1237 				tempsize = va.va_size;
1238 				VATTR_NULL(&va);
1239 				va.va_size = tempsize;
1240 				error = VOP_SETATTR(vp, &va, cred,
1241 					 procp);
1242 			}
1243 			if (error)
1244 				vput(vp);
1245 		}
1246 	}
1247 	if (!error) {
1248 		memset(fhp, 0, sizeof(nfh));
1249 		fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1250 		error = VFS_VPTOFH(vp, &fhp->fh_fid);
1251 		if (!error)
1252 			error = VOP_GETATTR(vp, &va, cred, procp);
1253 		vput(vp);
1254 	}
1255 	if (info.nmi_v3) {
1256 		if (exclusive_flag && !error &&
1257 			bcmp(cverf, (caddr_t)&va.va_atime, NFSX_V3CREATEVERF))
1258 			error = EEXIST;
1259 		diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1260 		vrele(dirp);
1261 	}
1262 	if (nfsm_reply(&info, nfsd, slp, mrq, error, NFSX_SRVFH(info.nmi_v3) +
1263 	    NFSX_FATTR(info.nmi_v3) + NFSX_WCCDATA(info.nmi_v3)) != 0)
1264 		return 0;
1265 	if (info.nmi_v3) {
1266 		if (!error) {
1267 			nfsm_srvpostop_fh(&info, fhp);
1268 			nfsm_srvpostop_attr(nfsd, 0, &va, &info);
1269 		}
1270 		nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft,
1271 		    &info);
1272 	} else {
1273 		nfsm_srvfhtom(&info.nmi_mb, fhp, info.nmi_v3);
1274 		fp = nfsm_build(&info.nmi_mb, NFSX_V2FATTR);
1275 		nfsm_srvfattr(nfsd, &va, fp);
1276 	}
1277 	return (0);
1278 nfsmout:
1279 	if (dirp)
1280 		vrele(dirp);
1281 	if (nd.ni_cnd.cn_nameiop != LOOKUP) {
1282 		vrele(nd.ni_startdir);
1283 		if (nd.ni_cnd.cn_flags & HASBUF) {
1284 			pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1285 			nd.ni_cnd.cn_flags &= ~HASBUF;
1286 		}
1287 	}
1288 	VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1289 	if (nd.ni_dvp == nd.ni_vp)
1290 		vrele(nd.ni_dvp);
1291 	else
1292 		vput(nd.ni_dvp);
1293 	if (nd.ni_vp)
1294 		vput(nd.ni_vp);
1295 	return (error);
1296 }
1297 
1298 /*
1299  * nfs v3 mknod service
1300  */
1301 int
nfsrv_mknod(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)1302 nfsrv_mknod(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
1303     struct proc *procp, struct mbuf **mrq)
1304 {
1305 	struct mbuf *nam = nfsd->nd_nam;
1306 	struct ucred *cred = &nfsd->nd_cr;
1307 	struct vattr va, dirfor, diraft;
1308 	struct nfsm_info	info;
1309 	u_int32_t *tl;
1310 	struct nameidata nd;
1311 	int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
1312 	u_int32_t major, minor;
1313 	enum vtype vtyp;
1314 	struct vnode *vp, *dirp = NULL;
1315 	nfsfh_t nfh;
1316 	fhandle_t *fhp;
1317 
1318 	info.nmi_mreq = NULL;
1319 	info.nmi_mrep = nfsd->nd_mrep;
1320 	info.nmi_md = nfsd->nd_md;
1321 	info.nmi_dpos = nfsd->nd_dpos;
1322 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
1323 	info.nmi_errorp = &error;
1324 
1325 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
1326 		return 0;
1327 	else if (error != 0)
1328 		goto nfsmout;
1329 	fhp = &nfh.fh_generic;
1330 	if (nfsm_srvmtofh2(&info, fhp) != 0)
1331 		goto nfsmout;
1332 	if (nfsm_srvnamesiz(&info, &len) != 0)
1333 		goto nfsmout;
1334 	if (error) {
1335 		if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
1336 			return 0;
1337 	}
1338 
1339 	NDINIT(&nd, CREATE, LOCKPARENT | LOCKLEAF | SAVESTART, UIO_SYSSPACE,
1340 	    NULL, procp);
1341 	nd.ni_cnd.cn_cred = cred;
1342 	error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md, &info.nmi_dpos, &dirp, procp);
1343 	if (dirp)
1344 		dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp);
1345 	if (error) {
1346 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
1347 		    NFSX_WCCDATA(1)) != 0)
1348 			return 0;
1349 		nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft,
1350 		    &info);
1351 		if (dirp)
1352 			vrele(dirp);
1353 		return (0);
1354 	}
1355 
1356 	tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
1357 	if (tl == NULL)
1358 		goto nfsmout;
1359 	vtyp = nfsv3tov_type(*tl);
1360 	if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) {
1361 		vrele(nd.ni_startdir);
1362 		pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1363 		error = NFSERR_BADTYPE;
1364 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1365 		if (nd.ni_dvp == nd.ni_vp)
1366 			vrele(nd.ni_dvp);
1367 		else
1368 			vput(nd.ni_dvp);
1369 		if (nd.ni_vp)
1370 			vput(nd.ni_vp);
1371 		goto out;
1372 	}
1373 	VATTR_NULL(&va);
1374 	error = nfsm_srvsattr(&info.nmi_md, &va, info.nmi_mrep, &info.nmi_dpos);
1375 	if (error)
1376 		goto nfsmout;
1377 	if (vtyp == VCHR || vtyp == VBLK) {
1378 		tl = (uint32_t *)nfsm_dissect(&info, 2 * NFSX_UNSIGNED);
1379 		if (tl == NULL)
1380 			goto nfsmout;
1381 		major = fxdr_unsigned(u_int32_t, *tl++);
1382 		minor = fxdr_unsigned(u_int32_t, *tl);
1383 		va.va_rdev = makedev(major, minor);
1384 	}
1385 
1386 	/*
1387 	 * Iff doesn't exist, create it.
1388 	 */
1389 	if (nd.ni_vp) {
1390 		vrele(nd.ni_startdir);
1391 		pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1392 		error = EEXIST;
1393 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1394 		if (nd.ni_dvp == nd.ni_vp)
1395 			vrele(nd.ni_dvp);
1396 		else
1397 			vput(nd.ni_dvp);
1398 		vput(nd.ni_vp);
1399 		goto out;
1400 	}
1401 	va.va_type = vtyp;
1402 	if (vtyp == VSOCK) {
1403 		vrele(nd.ni_startdir);
1404 		error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va);
1405 		vput(nd.ni_dvp);
1406 		if (!error)
1407 			pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1408 	} else {
1409 		if (va.va_type != VFIFO &&
1410 		    (error = suser_ucred(cred))) {
1411 			vrele(nd.ni_startdir);
1412 			pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1413 			VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1414 			vput(nd.ni_dvp);
1415 			goto out;
1416 		}
1417 		error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va);
1418 		vput(nd.ni_dvp);
1419 		if (error) {
1420 			vrele(nd.ni_startdir);
1421 			goto out;
1422 		}
1423 		nd.ni_cnd.cn_nameiop = LOOKUP;
1424 		nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
1425 		nd.ni_cnd.cn_proc = procp;
1426 		nd.ni_cnd.cn_cred = procp->p_ucred;
1427 		error = vfs_lookup(&nd);
1428 		pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1429 		if (error)
1430 			goto out;
1431 		if (nd.ni_cnd.cn_flags & ISSYMLINK) {
1432 			vrele(nd.ni_dvp);
1433 			vput(nd.ni_vp);
1434 			VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1435 			error = EINVAL;
1436 		}
1437 	}
1438 out:
1439 	vp = nd.ni_vp;
1440 	if (!error) {
1441 		memset(fhp, 0, sizeof(nfh));
1442 		fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1443 		error = VFS_VPTOFH(vp, &fhp->fh_fid);
1444 		if (!error)
1445 			error = VOP_GETATTR(vp, &va, cred, procp);
1446 		vput(vp);
1447 	}
1448 	diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1449 	vrele(dirp);
1450 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
1451 	    NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1)) != 0)
1452 		return 0;
1453 	if (!error) {
1454 		nfsm_srvpostop_fh(&info, fhp);
1455 		nfsm_srvpostop_attr(nfsd, 0, &va, &info);
1456 	}
1457 	nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, &info);
1458 	return (0);
1459 nfsmout:
1460 	if (dirp)
1461 		vrele(dirp);
1462 	if (nd.ni_cnd.cn_nameiop) {
1463 		vrele(nd.ni_startdir);
1464 		pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1465 	}
1466 	VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1467 	if (nd.ni_dvp == nd.ni_vp)
1468 		vrele(nd.ni_dvp);
1469 	else
1470 		vput(nd.ni_dvp);
1471 	if (nd.ni_vp)
1472 		vput(nd.ni_vp);
1473 	return (error);
1474 }
1475 
1476 /*
1477  * nfs remove service
1478  */
1479 int
nfsrv_remove(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)1480 nfsrv_remove(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
1481     struct proc *procp, struct mbuf **mrq)
1482 {
1483 	struct mbuf *nam = nfsd->nd_nam;
1484 	struct ucred *cred = &nfsd->nd_cr;
1485 	struct nameidata nd;
1486 	struct nfsm_info	info;
1487 	int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
1488 	struct vnode *vp, *dirp;
1489 	struct vattr dirfor, diraft;
1490 	nfsfh_t nfh;
1491 	fhandle_t *fhp;
1492 
1493 	info.nmi_mreq = NULL;
1494 	info.nmi_mrep = nfsd->nd_mrep;
1495 	info.nmi_md = nfsd->nd_md;
1496 	info.nmi_dpos = nfsd->nd_dpos;
1497 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
1498 	info.nmi_errorp = &error;
1499 
1500 	vp = NULL;
1501 
1502 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
1503 		return 0;
1504 	else if (error != 0)
1505 		goto nfsmout;
1506 	fhp = &nfh.fh_generic;
1507 	if (nfsm_srvmtofh2(&info, fhp) != 0)
1508 		goto nfsmout;
1509 	if (nfsm_srvnamesiz(&info, &len) != 0)
1510 		goto nfsmout;
1511 	if (error) {
1512 		if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
1513 			return 0;
1514 	}
1515 
1516  	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_SYSSPACE, NULL, procp);
1517 	nd.ni_cnd.cn_cred = cred;
1518 	error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md, &info.nmi_dpos, &dirp, procp);
1519 	if (dirp) {
1520 		if (info.nmi_v3)
1521 			dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp);
1522 		else {
1523 			vrele(dirp);
1524 			dirp = NULL;
1525 		}
1526 	}
1527 
1528 	if (!error) {
1529 		vp = nd.ni_vp;
1530 		if (vp->v_type == VDIR &&
1531 		    (error = suser_ucred(cred)) != 0)
1532 			goto out;
1533 		/*
1534 		 * The root of a mounted filesystem cannot be deleted.
1535 		 */
1536 		if (vp->v_flag & VROOT) {
1537 			error = EBUSY;
1538 			goto out;
1539 		}
1540 		if (vp->v_flag & VTEXT)
1541 			uvm_vnp_uncache(vp);
1542 out:
1543 		if (!error) {
1544 			error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1545 		} else {
1546 			VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1547 			if (nd.ni_dvp == vp)
1548 				vrele(nd.ni_dvp);
1549 			else
1550 				vput(nd.ni_dvp);
1551 			vput(vp);
1552 		}
1553 	}
1554 	if (dirp && info.nmi_v3) {
1555 		diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1556 		vrele(dirp);
1557 	}
1558 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
1559 	    NFSX_WCCDATA(info.nmi_v3)) != 0)
1560 		return 0;
1561 	if (info.nmi_v3) {
1562 		nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft,
1563 		    &info);
1564 		return (0);
1565 	}
1566 
1567 nfsmout:
1568 	return(error);
1569 }
1570 
1571 /*
1572  * nfs rename service
1573  */
1574 int
nfsrv_rename(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)1575 nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
1576     struct proc *procp, struct mbuf **mrq)
1577 {
1578 	struct mbuf *nam = nfsd->nd_nam;
1579 	struct ucred *cred = &nfsd->nd_cr;
1580 	struct nfsm_info	info;
1581 	int error = 0, len, len2, fdirfor_ret = 1, fdiraft_ret = 1;
1582 	int tdirfor_ret = 1, tdiraft_ret = 1;
1583 	struct nameidata fromnd, tond;
1584 	struct vnode *fvp = NULL, *tvp, *tdvp, *fdirp = NULL;
1585 	struct vnode *tdirp = NULL;
1586 	struct vattr fdirfor, fdiraft, tdirfor, tdiraft;
1587 	nfsfh_t fnfh, tnfh;
1588 	fhandle_t *ffhp, *tfhp;
1589 	uid_t saved_uid;
1590 
1591 	info.nmi_mreq = NULL;
1592 	info.nmi_mrep = nfsd->nd_mrep;
1593 	info.nmi_md = nfsd->nd_md;
1594 	info.nmi_dpos = nfsd->nd_dpos;
1595 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
1596 	info.nmi_errorp = &error;
1597 
1598 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
1599 		return 0;
1600 	else if (error != 0)
1601 		goto nfsmout;
1602 	ffhp = &fnfh.fh_generic;
1603 	if (nfsm_srvmtofh2(&info, ffhp) != 0)
1604 		goto nfsmout;
1605 	if (nfsm_srvnamesiz(&info, &len) != 0)
1606 		goto nfsmout;
1607 	if (error) {
1608 		if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
1609 			return 0;
1610 	}
1611 
1612 	/*
1613 	 * Remember our original uid so that we can reset cr_uid before
1614 	 * the second nfs_namei() call, in case it is remapped.
1615 	 */
1616 	saved_uid = cred->cr_uid;
1617 
1618 	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_SYSSPACE, NULL,
1619 	    procp);
1620 	fromnd.ni_cnd.cn_cred = cred;
1621 	error = nfs_namei(&fromnd, ffhp, len, slp, nam, &info.nmi_md,
1622 	    &info.nmi_dpos, &fdirp, procp);
1623 	if (fdirp) {
1624 		if (info.nmi_v3)
1625 			fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, cred,
1626 				procp);
1627 		else {
1628 			vrele(fdirp);
1629 			fdirp = NULL;
1630 		}
1631 	}
1632 	if (error) {
1633 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
1634 		    2 * NFSX_WCCDATA(info.nmi_v3)) != 0)
1635 			return 0;
1636 		nfsm_srvwcc(nfsd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft,
1637 		    &info);
1638 		nfsm_srvwcc(nfsd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft,
1639 		    &info);
1640 		if (fdirp)
1641 			vrele(fdirp);
1642 		return (0);
1643 	}
1644 
1645 	fvp = fromnd.ni_vp;
1646 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
1647 		return 0;
1648 	else if (error != 0)
1649 		goto nfsmout;
1650 	tfhp = &tnfh.fh_generic;
1651 	if (nfsm_srvmtofh2(&info, tfhp) != 0)
1652 		goto nfsmout;
1653 	if (nfsm_strsiz(&info, &len2, NFS_MAXNAMLEN) != 0)
1654 		goto nfsmout;
1655 	cred->cr_uid = saved_uid;
1656 
1657 	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF| NOCACHE | SAVESTART,
1658 	    UIO_SYSSPACE, NULL, procp);
1659 	tond.ni_cnd.cn_cred = cred;
1660 	error = nfs_namei(&tond, tfhp, len2, slp, nam, &info.nmi_md,
1661 	    &info.nmi_dpos, &tdirp, procp);
1662 	if (tdirp) {
1663 		if (info.nmi_v3)
1664 			tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, cred,
1665 				procp);
1666 		else {
1667 			vrele(tdirp);
1668 			tdirp = NULL;
1669 		}
1670 	}
1671 	if (error) {
1672 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1673 		vrele(fromnd.ni_dvp);
1674 		vrele(fvp);
1675 		goto out1;
1676 	}
1677 	tdvp = tond.ni_dvp;
1678 	tvp = tond.ni_vp;
1679 	if (tvp != NULL) {
1680 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
1681 			error = info.nmi_v3 ? EEXIST : EISDIR;
1682 			goto out;
1683 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
1684 			error = info.nmi_v3 ? EEXIST : ENOTDIR;
1685 			goto out;
1686 		}
1687 		if (tvp->v_type == VDIR && tvp->v_mountedhere) {
1688 			error = info.nmi_v3 ? EXDEV : ENOTEMPTY;
1689 			goto out;
1690 		}
1691 	}
1692 	if (fvp->v_type == VDIR && fvp->v_mountedhere) {
1693 		error = info.nmi_v3 ? EXDEV : ENOTEMPTY;
1694 		goto out;
1695 	}
1696 	if (fvp->v_mount != tdvp->v_mount) {
1697 		error = info.nmi_v3 ? EXDEV : ENOTEMPTY;
1698 		goto out;
1699 	}
1700 	if (fvp == tdvp)
1701 		error = info.nmi_v3 ? EINVAL : ENOTEMPTY;
1702 	/*
1703 	 * If source is the same as the destination (that is the
1704 	 * same vnode with the same name in the same directory),
1705 	 * then there is nothing to do.
1706 	 */
1707 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
1708 	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
1709 	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
1710 	      fromnd.ni_cnd.cn_namelen))
1711 		error = -1;
1712 out:
1713 	if (!error) {
1714 		if (tvp) {
1715 			(void)uvm_vnp_uncache(tvp);
1716 		}
1717 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
1718 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
1719 	} else {
1720 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
1721 		if (tdvp == tvp)
1722 			vrele(tdvp);
1723 		else
1724 			vput(tdvp);
1725 		if (tvp)
1726 			vput(tvp);
1727 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1728 		vrele(fromnd.ni_dvp);
1729 		vrele(fvp);
1730 		if (error == -1)
1731 			error = 0;
1732 	}
1733 	vrele(tond.ni_startdir);
1734 	pool_put(&namei_pool, tond.ni_cnd.cn_pnbuf);
1735 out1:
1736 	if (fdirp) {
1737 		fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, cred, procp);
1738 		vrele(fdirp);
1739 	}
1740 	if (tdirp) {
1741 		tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred, procp);
1742 		vrele(tdirp);
1743 	}
1744 	vrele(fromnd.ni_startdir);
1745 	pool_put(&namei_pool, fromnd.ni_cnd.cn_pnbuf);
1746 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
1747 	    2 * NFSX_WCCDATA(info.nmi_v3)) != 0)
1748 		return 0;
1749 	if (info.nmi_v3) {
1750 		nfsm_srvwcc(nfsd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft,
1751 		    &info);
1752 		nfsm_srvwcc(nfsd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft,
1753 		    &info);
1754 	}
1755 	return (0);
1756 
1757 nfsmout:
1758 	if (fdirp)
1759 		vrele(fdirp);
1760 	if (tdirp)
1761 		vrele(tdirp);
1762 	if (tond.ni_cnd.cn_nameiop) {
1763 		vrele(tond.ni_startdir);
1764 		pool_put(&namei_pool, tond.ni_cnd.cn_pnbuf);
1765 	}
1766 	if (fromnd.ni_cnd.cn_nameiop) {
1767 		if (fromnd.ni_startdir)
1768 			vrele(fromnd.ni_startdir);
1769 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1770 
1771 		/*
1772 		 * XXX: Workaround the fact that fromnd.ni_dvp can point
1773 		 * to the same vnode as fdirp.
1774 		 */
1775 		if (fromnd.ni_dvp != NULL && fromnd.ni_dvp != fdirp)
1776 			vrele(fromnd.ni_dvp);
1777 		if (fvp)
1778 			vrele(fvp);
1779 	}
1780 	return (error);
1781 }
1782 
1783 /*
1784  * nfs link service
1785  */
1786 int
nfsrv_link(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)1787 nfsrv_link(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
1788     struct proc *procp, struct mbuf **mrq)
1789 {
1790 	struct mbuf *nam = nfsd->nd_nam;
1791 	struct nfsm_info	info;
1792 	struct ucred *cred = &nfsd->nd_cr;
1793 	struct nameidata nd;
1794 	int error = 0, rdonly, len, dirfor_ret = 1, diraft_ret = 1;
1795 	int getret = 1;
1796 	struct vnode *vp, *xp, *dirp = NULL;
1797 	struct vattr dirfor, diraft, at;
1798 	nfsfh_t nfh, dnfh;
1799 	fhandle_t *fhp, *dfhp;
1800 
1801 	info.nmi_mreq = NULL;
1802 	info.nmi_mrep = nfsd->nd_mrep;
1803 	info.nmi_md = nfsd->nd_md;
1804 	info.nmi_dpos = nfsd->nd_dpos;
1805 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
1806 	info.nmi_errorp = &error;
1807 
1808 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
1809 		return 0;
1810 	else if (error != 0)
1811 		goto nfsmout;
1812 	fhp = &nfh.fh_generic;
1813 	if (nfsm_srvmtofh2(&info, fhp) != 0)
1814 		goto nfsmout;
1815 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
1816 		return 0;
1817 	else if (error != 0)
1818 		goto nfsmout;
1819 	dfhp = &dnfh.fh_generic;
1820 	if (nfsm_srvmtofh2(&info, dfhp) != 0)
1821 		goto nfsmout;
1822 	if (nfsm_srvnamesiz(&info, &len) != 0)
1823 		goto nfsmout;
1824 	if (error) {
1825 		if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
1826 			return 0;
1827 	}
1828 
1829 	error = nfsrv_fhtovp(fhp, 0, &vp, cred, slp, nam, &rdonly);
1830 	if (error) {
1831 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
1832 		    NFSX_POSTOPATTR(info.nmi_v3) +
1833 		    NFSX_WCCDATA(info.nmi_v3)) != 0)
1834 			return 0;
1835 		nfsm_srvpostop_attr(nfsd, getret, &at, &info);
1836 		nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft,
1837 		    &info);
1838 		error = 0;
1839 		goto nfsmout;
1840 	}
1841 	if (vp->v_type == VDIR)
1842 		goto out1;
1843 
1844 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, NULL, procp);
1845 	nd.ni_cnd.cn_cred = cred;
1846 	error = nfs_namei(&nd, dfhp, len, slp, nam, &info.nmi_md,
1847 	    &info.nmi_dpos, &dirp, procp);
1848 	if (dirp) {
1849 		if (info.nmi_v3)
1850 			dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
1851 				procp);
1852 		else {
1853 			vrele(dirp);
1854 			dirp = NULL;
1855 		}
1856 	}
1857 	if (error)
1858 		goto out1;
1859 	xp = nd.ni_vp;
1860 	if (xp != NULL) {
1861 		error = EEXIST;
1862 		goto out;
1863 	}
1864 	xp = nd.ni_dvp;
1865 	if (vp->v_mount != xp->v_mount)
1866 		error = EXDEV;
1867 out:
1868 	if (!error) {
1869 		error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
1870 	} else {
1871 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1872 		if (nd.ni_dvp == nd.ni_vp)
1873 			vrele(nd.ni_dvp);
1874 		else
1875 			vput(nd.ni_dvp);
1876 		if (nd.ni_vp)
1877 			vrele(nd.ni_vp);
1878 	}
1879 out1:
1880 	if (info.nmi_v3)
1881 		getret = VOP_GETATTR(vp, &at, cred, procp);
1882 	if (dirp) {
1883 		diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1884 		vrele(dirp);
1885 	}
1886 	vrele(vp);
1887 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
1888 	    NFSX_POSTOPATTR(info.nmi_v3) + NFSX_WCCDATA(info.nmi_v3)) != 0)
1889 		return 0;
1890 	if (info.nmi_v3) {
1891 		nfsm_srvpostop_attr(nfsd, getret, &at, &info);
1892 		nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft,
1893 		     &info);
1894 		error = 0;
1895 	}
1896 nfsmout:
1897 	return(error);
1898 }
1899 
1900 /*
1901  * nfs symbolic link service
1902  */
1903 int
nfsrv_symlink(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)1904 nfsrv_symlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
1905     struct proc *procp, struct mbuf **mrq)
1906 {
1907 	struct mbuf *nam = nfsd->nd_nam;
1908 	struct ucred *cred = &nfsd->nd_cr;
1909 	struct vattr va, dirfor, diraft;
1910 	struct nameidata nd;
1911 	struct nfsm_info	info;
1912 	struct nfsv2_sattr *sp;
1913 	char *pathcp = NULL;
1914 	struct uio io;
1915 	struct iovec iv;
1916 	int error = 0, len, pathlen, len2, dirfor_ret = 1, diraft_ret = 1;
1917 	struct vnode *dirp = NULL;
1918 	nfsfh_t nfh;
1919 	fhandle_t *fhp;
1920 
1921 	info.nmi_mreq = NULL;
1922 	info.nmi_mrep = nfsd->nd_mrep;
1923 	info.nmi_md = nfsd->nd_md;
1924 	info.nmi_dpos = nfsd->nd_dpos;
1925 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
1926 	info.nmi_errorp = &error;
1927 
1928 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
1929 		return 0;
1930 	else if (error != 0)
1931 		goto nfsmout;
1932 	fhp = &nfh.fh_generic;
1933 	if (nfsm_srvmtofh2(&info, fhp) != 0)
1934 		goto nfsmout;
1935 	if (nfsm_srvnamesiz(&info, &len) != 0)
1936 		goto nfsmout;
1937 	if (error) {
1938 		if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
1939 			return 0;
1940 	}
1941 
1942 	NDINIT(&nd, CREATE, LOCKPARENT | SAVESTART, UIO_SYSSPACE, NULL, procp);
1943 	nd.ni_cnd.cn_cred = cred;
1944 	error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md,
1945 	    &info.nmi_dpos, &dirp, procp);
1946 	if (dirp) {
1947 		if (info.nmi_v3)
1948 			dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
1949 				procp);
1950 		else {
1951 			vrele(dirp);
1952 			dirp = NULL;
1953 		}
1954 	}
1955 	if (error)
1956 		goto out;
1957 	VATTR_NULL(&va);
1958 	if (info.nmi_v3) {
1959 		error = nfsm_srvsattr(&info.nmi_md, &va, info.nmi_mrep,
1960 		    &info.nmi_dpos);
1961 		if (error)
1962 			goto nfsmout;
1963 	}
1964 	if (nfsm_strsiz(&info, &len2, NFS_MAXPATHLEN) != 0)
1965 		goto nfsmout;
1966 	pathlen = len2 + 1;
1967 	pathcp = malloc(pathlen, M_TEMP, M_WAITOK);
1968 	iv.iov_base = pathcp;
1969 	iv.iov_len = len2;
1970 	io.uio_resid = len2;
1971 	io.uio_offset = 0;
1972 	io.uio_iov = &iv;
1973 	io.uio_iovcnt = 1;
1974 	io.uio_segflg = UIO_SYSSPACE;
1975 	io.uio_rw = UIO_READ;
1976 	io.uio_procp = NULL;
1977 	if (nfsm_mtouio(&info, &io, len2) != 0)
1978 		goto nfsmout;
1979 	if (!info.nmi_v3) {
1980 		sp = (struct nfsv2_sattr *)nfsm_dissect(&info, NFSX_V2SATTR);
1981 		if (sp == NULL)
1982 			goto nfsmout;
1983 		va.va_mode = nfstov_mode(sp->sa_mode);
1984 	}
1985 	*(pathcp + len2) = '\0';
1986 	if (nd.ni_vp) {
1987 		vrele(nd.ni_startdir);
1988 		pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1989 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1990 		if (nd.ni_dvp == nd.ni_vp)
1991 			vrele(nd.ni_dvp);
1992 		else
1993 			vput(nd.ni_dvp);
1994 		vrele(nd.ni_vp);
1995 		error = EEXIST;
1996 		goto out;
1997 	}
1998 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va, pathcp);
1999 	if (error)
2000 		vrele(nd.ni_startdir);
2001 	else {
2002 		if (info.nmi_v3) {
2003 			nd.ni_cnd.cn_nameiop = LOOKUP;
2004 			nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART |
2005 			    FOLLOW);
2006 			nd.ni_cnd.cn_flags |= (NOFOLLOW | LOCKLEAF);
2007 			nd.ni_cnd.cn_proc = procp;
2008 			nd.ni_cnd.cn_cred = cred;
2009 			error = vfs_lookup(&nd);
2010 			if (!error) {
2011 				memset(fhp, 0, sizeof(nfh));
2012 				fhp->fh_fsid =
2013 				    nd.ni_vp->v_mount->mnt_stat.f_fsid;
2014 				error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid);
2015 				if (!error)
2016 					error = VOP_GETATTR(nd.ni_vp, &va, cred,
2017 					    procp);
2018 				vput(nd.ni_vp);
2019 			}
2020 		} else
2021 			vrele(nd.ni_startdir);
2022 		pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
2023 	}
2024 out:
2025 	if (pathcp)
2026 		free(pathcp, M_TEMP, pathlen);
2027 	if (dirp) {
2028 		diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2029 		vrele(dirp);
2030 	}
2031 	if (nfsm_reply(&info, nfsd, slp, mrq, error, NFSX_SRVFH(info.nmi_v3) +
2032 	    NFSX_POSTOPATTR(info.nmi_v3) + NFSX_WCCDATA(info.nmi_v3)) != 0)
2033 		return 0;
2034 	if (info.nmi_v3) {
2035 		if (!error) {
2036 			nfsm_srvpostop_fh(&info, fhp);
2037 			nfsm_srvpostop_attr(nfsd, 0, &va, &info);
2038 		}
2039 		nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft,
2040 		    &info);
2041 	}
2042 	return (0);
2043 nfsmout:
2044 	if (nd.ni_cnd.cn_nameiop) {
2045 		vrele(nd.ni_startdir);
2046 		pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
2047 	}
2048 	if (dirp)
2049 		vrele(dirp);
2050 	VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2051 	if (nd.ni_dvp == nd.ni_vp)
2052 		vrele(nd.ni_dvp);
2053 	else
2054 		vput(nd.ni_dvp);
2055 	if (nd.ni_vp)
2056 		vrele(nd.ni_vp);
2057 	if (pathcp)
2058 		free(pathcp, M_TEMP, pathlen);
2059 	return (error);
2060 }
2061 
2062 /*
2063  * nfs mkdir service
2064  */
2065 int
nfsrv_mkdir(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)2066 nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2067     struct proc *procp, struct mbuf **mrq)
2068 {
2069 	struct mbuf *nam = nfsd->nd_nam;
2070 	struct ucred *cred = &nfsd->nd_cr;
2071 	struct vattr va, dirfor, diraft;
2072 	struct nfs_fattr *fp;
2073 	struct nameidata nd;
2074 	struct nfsm_info	info;
2075 	u_int32_t *tl;
2076 	int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
2077 	struct vnode *vp, *dirp = NULL;
2078 	nfsfh_t nfh;
2079 	fhandle_t *fhp;
2080 
2081 	info.nmi_mreq = NULL;
2082 	info.nmi_mrep = nfsd->nd_mrep;
2083 	info.nmi_md = nfsd->nd_md;
2084 	info.nmi_dpos = nfsd->nd_dpos;
2085 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
2086 	info.nmi_errorp = &error;
2087 
2088 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
2089 		return 0;
2090 	else if (error != 0)
2091 		goto nfsmout;
2092 	fhp = &nfh.fh_generic;
2093 	if (nfsm_srvmtofh2(&info, fhp) != 0)
2094 		goto nfsmout;
2095 	if (nfsm_srvnamesiz(&info, &len) != 0)
2096 		goto nfsmout;
2097 	if (error) {
2098 		if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
2099 			return 0;
2100 	}
2101 
2102 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, NULL, procp);
2103 	nd.ni_cnd.cn_cred = cred;
2104 	error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md,
2105 	    &info.nmi_dpos, &dirp, procp);
2106 	if (dirp) {
2107 		if (info.nmi_v3)
2108 			dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp);
2109 		else {
2110 			vrele(dirp);
2111 			dirp = NULL;
2112 		}
2113 	}
2114 	if (error) {
2115 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
2116 		    NFSX_WCCDATA(info.nmi_v3)) != 0)
2117 			return 0;
2118 		nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft,
2119 		    &info);
2120 		if (dirp)
2121 			vrele(dirp);
2122 		return (0);
2123 	}
2124 
2125 	VATTR_NULL(&va);
2126 	if (info.nmi_v3) {
2127 		error = nfsm_srvsattr(&info.nmi_md, &va, info.nmi_mrep,
2128 		    &info.nmi_dpos);
2129 		if (error)
2130 			goto nfsmout;
2131 	} else {
2132 		tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
2133 		if (tl == NULL)
2134 			goto nfsmout;
2135 		va.va_mode = nfstov_mode(*tl++);
2136 	}
2137 	va.va_type = VDIR;
2138 	vp = nd.ni_vp;
2139 	if (vp != NULL) {
2140 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2141 		if (nd.ni_dvp == vp)
2142 			vrele(nd.ni_dvp);
2143 		else
2144 			vput(nd.ni_dvp);
2145 		vrele(vp);
2146 		error = EEXIST;
2147 		goto out;
2148 	}
2149 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va);
2150 	if (!error) {
2151 		vp = nd.ni_vp;
2152 		memset(fhp, 0, sizeof(nfh));
2153 		fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
2154 		error = VFS_VPTOFH(vp, &fhp->fh_fid);
2155 		if (!error)
2156 			error = VOP_GETATTR(vp, &va, cred, procp);
2157 		vput(vp);
2158 	}
2159 out:
2160 	if (dirp) {
2161 		diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2162 		vrele(dirp);
2163 	}
2164 	if (nfsm_reply(&info, nfsd, slp, mrq, error, NFSX_SRVFH(info.nmi_v3) +
2165 	    NFSX_POSTOPATTR(info.nmi_v3) + NFSX_WCCDATA(info.nmi_v3)) != 0)
2166 		return 0;
2167 	if (info.nmi_v3) {
2168 		if (!error) {
2169 			nfsm_srvpostop_fh(&info, fhp);
2170 			nfsm_srvpostop_attr(nfsd, 0, &va, &info);
2171 		}
2172 		nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft,
2173 		    &info);
2174 	} else {
2175 		nfsm_srvfhtom(&info.nmi_mb, fhp, info.nmi_v3);
2176 		fp = nfsm_build(&info.nmi_mb, NFSX_V2FATTR);
2177 		nfsm_srvfattr(nfsd, &va, fp);
2178 	}
2179 	return (0);
2180 nfsmout:
2181 	if (dirp)
2182 		vrele(dirp);
2183 	VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2184 	if (nd.ni_dvp == nd.ni_vp)
2185 		vrele(nd.ni_dvp);
2186 	else
2187 		vput(nd.ni_dvp);
2188 	if (nd.ni_vp)
2189 		vrele(nd.ni_vp);
2190 	return (error);
2191 }
2192 
2193 /*
2194  * nfs rmdir service
2195  */
2196 int
nfsrv_rmdir(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)2197 nfsrv_rmdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2198     struct proc *procp, struct mbuf **mrq)
2199 {
2200 	struct mbuf *nam = nfsd->nd_nam;
2201 	struct ucred *cred = &nfsd->nd_cr;
2202 	struct nfsm_info	info;
2203 	int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
2204 	struct vnode *vp, *dirp = NULL;
2205 	struct vattr dirfor, diraft;
2206 	nfsfh_t nfh;
2207 	fhandle_t *fhp;
2208 	struct nameidata nd;
2209 
2210 	info.nmi_mreq = NULL;
2211 	info.nmi_mrep = nfsd->nd_mrep;
2212 	info.nmi_md = nfsd->nd_md;
2213 	info.nmi_dpos = nfsd->nd_dpos;
2214 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
2215 	info.nmi_errorp = &error;
2216 
2217 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
2218 		return 0;
2219 	else if (error != 0)
2220 		goto nfsmout;
2221 	fhp = &nfh.fh_generic;
2222 	if (nfsm_srvmtofh2(&info, fhp) != 0)
2223 		goto nfsmout;
2224 	if (nfsm_srvnamesiz(&info, &len) != 0)
2225 		goto nfsmout;
2226 	if (error) {
2227 		if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
2228 			return 0;
2229 	}
2230 
2231 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_SYSSPACE, NULL, procp);
2232 	nd.ni_cnd.cn_cred = cred;
2233 	error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md,
2234 	    &info.nmi_dpos, &dirp, procp);
2235 	if (dirp) {
2236 		if (info.nmi_v3)
2237 			dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
2238 				procp);
2239 		else {
2240 			vrele(dirp);
2241 			dirp = NULL;
2242 		}
2243 	}
2244 	if (error) {
2245 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
2246 		    NFSX_WCCDATA(info.nmi_v3)) != 0)
2247 			return 0;
2248 		nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft,
2249 		    &info);
2250 		if (dirp)
2251 			vrele(dirp);
2252 		return (0);
2253 	}
2254 	vp = nd.ni_vp;
2255 	if (vp->v_type != VDIR) {
2256 		error = ENOTDIR;
2257 		goto out;
2258 	}
2259 	/*
2260 	 * No rmdir "." please.
2261 	 */
2262 	if (nd.ni_dvp == vp) {
2263 		error = EINVAL;
2264 		goto out;
2265 	}
2266 	/*
2267 	 * A mounted on directory cannot be deleted.
2268 	 */
2269 	if (vp->v_mountedhere != NULL) {
2270 		error = EBUSY;
2271 		goto out;
2272 	}
2273 	/*
2274 	 * The root of a mounted filesystem cannot be deleted.
2275 	 */
2276 	if (vp->v_flag & VROOT)
2277 		error = EBUSY;
2278 out:
2279 	if (!error) {
2280 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
2281 	} else {
2282 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2283 		if (nd.ni_dvp == nd.ni_vp)
2284 			vrele(nd.ni_dvp);
2285 		else
2286 			vput(nd.ni_dvp);
2287 		vput(vp);
2288 	}
2289 	if (dirp) {
2290 		diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2291 		vrele(dirp);
2292 	}
2293 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
2294 	    NFSX_WCCDATA(info.nmi_v3)) != 0)
2295 		return 0;
2296 	if (info.nmi_v3) {
2297 		nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft,
2298 		    &info);
2299 		error = 0;
2300 	}
2301 nfsmout:
2302 	return(error);
2303 }
2304 
2305 /*
2306  * nfs readdir service
2307  * - mallocs what it thinks is enough to read
2308  *	count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
2309  * - calls VOP_READDIR()
2310  * - loops around building the reply
2311  *	if the output generated exceeds count break out of loop
2312  * - it only knows that it has encountered eof when the VOP_READDIR()
2313  *	reads nothing
2314  * - as such one readdir rpc will return eof false although you are there
2315  *	and then the next will return eof
2316  * - it trims out records with d_fileno == 0
2317  *	this doesn't matter for Unix clients, but they might confuse clients
2318  *	for other os'.
2319  * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
2320  *	than requested, but this may not apply to all filesystems. For
2321  *	example, client NFS does not { although it is never remote mounted
2322  *	anyhow }
2323  *     The alternate call nfsrv_readdirplus() does lookups as well.
2324  * PS: The NFS protocol spec. does not clarify what the "count" byte
2325  *	argument is a count of.. just name strings and file id's or the
2326  *	entire reply rpc or ...
2327  *	I tried just file name and id sizes and it confused the Sun client,
2328  *	so I am using the full rpc size now. The "paranoia.." comment refers
2329  *	to including the status longwords that are not a part of the dir.
2330  *	"entry" structures, but are in the rpc.
2331  */
2332 struct flrep {
2333 	nfsuint64 fl_off;
2334 	u_int32_t fl_postopok;
2335 	u_int32_t fl_fattr[NFSX_V3FATTR / sizeof (u_int32_t)];
2336 	u_int32_t fl_fhok;
2337 	u_int32_t fl_fhsize;
2338 	u_int32_t fl_nfh[NFSX_V3FH / sizeof (u_int32_t)];
2339 };
2340 
2341 int
nfsrv_readdir(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)2342 nfsrv_readdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2343     struct proc *procp, struct mbuf **mrq)
2344 {
2345 	struct mbuf *nam = nfsd->nd_nam;
2346 	struct ucred *cred = &nfsd->nd_cr;
2347 	struct dirent *dp;
2348 	struct nfsm_info	info;
2349 	u_int32_t *tl;
2350 	char *cpos, *cend, *rbuf;
2351 	struct vnode *vp;
2352 	struct vattr at;
2353 	nfsfh_t nfh;
2354 	fhandle_t *fhp;
2355 	struct uio io;
2356 	struct iovec iv;
2357 	int len, nlen, pad, xfer, error = 0, getret = 1;
2358 	int siz, cnt, fullsiz, eofflag, rdonly;
2359 	u_quad_t off, toff, verf;
2360 
2361 	info.nmi_mreq = NULL;
2362 	info.nmi_mrep = nfsd->nd_mrep;
2363 	info.nmi_md = nfsd->nd_md;
2364 	info.nmi_dpos = nfsd->nd_dpos;
2365 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
2366 	info.nmi_errorp = &error;
2367 
2368 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
2369 		return 0;
2370 	else if (error != 0)
2371 		goto nfsmout;
2372 	fhp = &nfh.fh_generic;
2373 	if (nfsm_srvmtofh2(&info, fhp) != 0)
2374 		goto nfsmout;
2375 	if (info.nmi_v3) {
2376 		tl = (uint32_t *)nfsm_dissect(&info, 5 * NFSX_UNSIGNED);
2377 		if (tl == NULL)
2378 			goto nfsmout;
2379 		toff = fxdr_hyper(tl);
2380 		tl += 2;
2381 		verf = fxdr_hyper(tl);
2382 		tl += 2;
2383 	} else {
2384 		tl = (uint32_t *)nfsm_dissect(&info, 2 * NFSX_UNSIGNED);
2385 		if (tl == NULL)
2386 			goto nfsmout;
2387 		toff = fxdr_unsigned(u_quad_t, *tl++);
2388 	}
2389 	off = toff;
2390 	cnt = fxdr_unsigned(int, *tl);
2391 	xfer = NFS_SRVMAXDATA(nfsd);
2392 	if (cnt > xfer || cnt < 0)
2393 		cnt = xfer;
2394 	siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
2395 	if (siz > xfer)
2396 		siz = xfer;
2397 	fullsiz = siz;
2398 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
2399 	if (error) {
2400 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
2401 		    NFSX_UNSIGNED) != 0)
2402 			return 0;
2403 		nfsm_srvpostop_attr(nfsd, getret, &at, &info);
2404 		error = 0;
2405 		goto nfsmout;
2406 	}
2407 	if (info.nmi_v3)
2408 		error = getret = VOP_GETATTR(vp, &at, cred, procp);
2409 	if (!error)
2410 		error = nfsrv_access(vp, VEXEC, cred, rdonly, procp, 0);
2411 	if (error) {
2412 		vput(vp);
2413 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
2414 		    NFSX_POSTOPATTR(info.nmi_v3)) != 0)
2415 			return 0;
2416 		nfsm_srvpostop_attr(nfsd, getret, &at, &info);
2417 		error = 0;
2418 		goto nfsmout;
2419 	}
2420 	VOP_UNLOCK(vp);
2421 	rbuf = malloc(fullsiz, M_TEMP, M_WAITOK);
2422 again:
2423 	iv.iov_base = rbuf;
2424 	iv.iov_len = fullsiz;
2425 	io.uio_iov = &iv;
2426 	io.uio_iovcnt = 1;
2427 	io.uio_offset = (off_t)off;
2428 	io.uio_resid = fullsiz;
2429 	io.uio_segflg = UIO_SYSSPACE;
2430 	io.uio_rw = UIO_READ;
2431 	io.uio_procp = NULL;
2432 	eofflag = 0;
2433 
2434 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2435 	error = VOP_READDIR(vp, &io, cred, &eofflag);
2436 
2437 	off = (off_t)io.uio_offset;
2438 	if (info.nmi_v3) {
2439 		getret = VOP_GETATTR(vp, &at, cred, procp);
2440 		if (!error)
2441 			error = getret;
2442 	}
2443 
2444 	VOP_UNLOCK(vp);
2445 	if (error) {
2446 		vrele(vp);
2447 		free(rbuf, M_TEMP, fullsiz);
2448 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
2449 		    NFSX_POSTOPATTR(info.nmi_v3)) != 0)
2450 			return 0;
2451 		nfsm_srvpostop_attr(nfsd, getret, &at, &info);
2452 		error = 0;
2453 		goto nfsmout;
2454 	}
2455 	if (io.uio_resid) {
2456 		siz -= io.uio_resid;
2457 
2458 		/*
2459 		 * If nothing read, return eof
2460 		 * rpc reply
2461 		 */
2462 		if (siz == 0) {
2463 			vrele(vp);
2464 			if (nfsm_reply(&info, nfsd, slp, mrq, error,
2465 			    NFSX_POSTOPATTR(info.nmi_v3) +
2466 			    NFSX_COOKIEVERF(info.nmi_v3) +
2467 			    2 * NFSX_UNSIGNED) != 0)
2468 				return 0;
2469 			if (info.nmi_v3) {
2470 				nfsm_srvpostop_attr(nfsd, getret, &at, &info);
2471 				tl = nfsm_build(&info.nmi_mb, 4 * NFSX_UNSIGNED);
2472 				txdr_hyper(at.va_filerev, tl);
2473 				tl += 2;
2474 			} else
2475 				tl = nfsm_build(&info.nmi_mb, 2 * NFSX_UNSIGNED);
2476 			*tl++ = nfs_false;
2477 			*tl = nfs_true;
2478 			free(rbuf, M_TEMP, fullsiz);
2479 			error = 0;
2480 			goto nfsmout;
2481 		}
2482 	}
2483 
2484 	/*
2485 	 * Check for degenerate cases of nothing useful read.
2486 	 * If so go try again
2487 	 */
2488 	cpos = rbuf;
2489 	cend = rbuf + siz;
2490 	dp = (struct dirent *)cpos;
2491 
2492 	while (cpos < cend && dp->d_fileno == 0) {
2493 		cpos += dp->d_reclen;
2494 		dp = (struct dirent *)cpos;
2495 	}
2496 	if (cpos >= cend) {
2497 		toff = off;
2498 		siz = fullsiz;
2499 		goto again;
2500 	}
2501 
2502 	len = 3 * NFSX_UNSIGNED;	/* paranoia, probably can be 0 */
2503 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
2504 	    NFSX_POSTOPATTR(info.nmi_v3) +
2505 	    NFSX_COOKIEVERF(info.nmi_v3) + siz) != 0)
2506 		return 0;
2507 	if (info.nmi_v3) {
2508 		nfsm_srvpostop_attr(nfsd, getret, &at, &info);
2509 		tl = nfsm_build(&info.nmi_mb, 2 * NFSX_UNSIGNED);
2510 		txdr_hyper(at.va_filerev, tl);
2511 	}
2512 
2513 	/* Loop through the records and build reply */
2514 	while (cpos < cend) {
2515 		if (dp->d_fileno != 0) {
2516 			nlen = dp->d_namlen;
2517 			pad = nfsm_padlen(nlen);
2518 			len += (4 * NFSX_UNSIGNED + nlen + pad);
2519 			if (info.nmi_v3)
2520 				len += 2 * NFSX_UNSIGNED;
2521 			if (len > cnt) {
2522 				eofflag = 0;
2523 				break;
2524 			}
2525 			/*
2526 			 * Build the directory record xdr from
2527 			 * the dirent entry.
2528 			 */
2529 			tl = nfsm_build(&info.nmi_mb,
2530 			    (info.nmi_v3 ? 3 : 2) * NFSX_UNSIGNED);
2531 			*tl++ = nfs_true;
2532 			if (info.nmi_v3)
2533 				txdr_hyper(dp->d_fileno, tl);
2534 			else
2535 				*tl = txdr_unsigned((u_int32_t)dp->d_fileno);
2536 
2537 			/* And copy the name */
2538 			nfsm_strtombuf(&info.nmi_mb, dp->d_name, nlen);
2539 
2540 			/* Finish off the record */
2541 			if (info.nmi_v3) {
2542 				tl = nfsm_build(&info.nmi_mb, 2*NFSX_UNSIGNED);
2543 				txdr_hyper(dp->d_off, tl);
2544 			} else {
2545 				tl = nfsm_build(&info.nmi_mb, NFSX_UNSIGNED);
2546 				*tl = txdr_unsigned((u_int32_t)dp->d_off);
2547 			}
2548 		}
2549 		cpos += dp->d_reclen;
2550 		dp = (struct dirent *)cpos;
2551 	}
2552 	vrele(vp);
2553 	tl = nfsm_build(&info.nmi_mb, 2 * NFSX_UNSIGNED);
2554 	*tl++ = nfs_false;
2555 	if (eofflag)
2556 		*tl = nfs_true;
2557 	else
2558 		*tl = nfs_false;
2559 	free(rbuf, M_TEMP, fullsiz);
2560 nfsmout:
2561 	return(error);
2562 }
2563 
2564 int
nfsrv_readdirplus(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)2565 nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2566     struct proc *procp, struct mbuf **mrq)
2567 {
2568 	struct mbuf *nam = nfsd->nd_nam;
2569 	struct ucred *cred = &nfsd->nd_cr;
2570 	struct dirent *dp;
2571 	struct nfsm_info	info;
2572 	u_int32_t *tl;
2573 	char *cpos, *cend, *rbuf;
2574 	struct vnode *vp, *nvp;
2575 	struct flrep fl;
2576 	nfsfh_t nfh;
2577 	fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh;
2578 	struct uio io;
2579 	struct iovec iv;
2580 	struct vattr va, at, *vap = &va;
2581 	struct nfs_fattr *fp;
2582 	int len, nlen, pad, xfer, error = 0, getret = 1;
2583 	int siz, cnt, fullsiz, eofflag, rdonly, dirlen;
2584 	u_quad_t off, toff, verf;
2585 
2586 	info.nmi_mreq = NULL;
2587 	info.nmi_mrep = nfsd->nd_mrep;
2588 	info.nmi_md = nfsd->nd_md;
2589 	info.nmi_dpos = nfsd->nd_dpos;
2590 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
2591 	info.nmi_errorp = &error;
2592 
2593 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
2594 		return 0;
2595 	else if (error != 0)
2596 		goto nfsmout;
2597 	fhp = &nfh.fh_generic;
2598 	if (nfsm_srvmtofh2(&info, fhp) != 0)
2599 		goto nfsmout;
2600 	tl = (uint32_t *)nfsm_dissect(&info, 6 * NFSX_UNSIGNED);
2601 	if (tl == NULL)
2602 		goto nfsmout;
2603 	off = toff = fxdr_hyper(tl);
2604 	tl += 2;
2605 	verf = fxdr_hyper(tl);
2606 	tl += 2;
2607 	siz = fxdr_unsigned(int, *tl++);
2608 	cnt = fxdr_unsigned(int, *tl);
2609 	xfer = NFS_SRVMAXDATA(nfsd);
2610 	if (cnt > xfer || cnt < 0)
2611 		cnt = xfer;
2612 	siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
2613 	if (siz > xfer)
2614 		siz = xfer;
2615 	fullsiz = siz;
2616 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
2617 	if (error) {
2618 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
2619 		    NFSX_UNSIGNED) != 0)
2620 			return 0;
2621 		nfsm_srvpostop_attr(nfsd, getret, &at, &info);
2622 		error = 0;
2623 		goto nfsmout;
2624 	}
2625 	error = getret = VOP_GETATTR(vp, &at, cred, procp);
2626 	if (!error)
2627 		error = nfsrv_access(vp, VEXEC, cred, rdonly, procp, 0);
2628 	if (error) {
2629 		vput(vp);
2630 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
2631 		    NFSX_V3POSTOPATTR) != 0)
2632 			return 0;
2633 		nfsm_srvpostop_attr(nfsd, getret, &at, &info);
2634 		error = 0;
2635 		goto nfsmout;
2636 	}
2637 	VOP_UNLOCK(vp);
2638 
2639 	rbuf = malloc(fullsiz, M_TEMP, M_WAITOK);
2640 again:
2641 	iv.iov_base = rbuf;
2642 	iv.iov_len = fullsiz;
2643 	io.uio_iov = &iv;
2644 	io.uio_iovcnt = 1;
2645 	io.uio_offset = (off_t)off;
2646 	io.uio_resid = fullsiz;
2647 	io.uio_segflg = UIO_SYSSPACE;
2648 	io.uio_rw = UIO_READ;
2649 	io.uio_procp = NULL;
2650 	eofflag = 0;
2651 
2652 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2653 	error = VOP_READDIR(vp, &io, cred, &eofflag);
2654 
2655 	off = (u_quad_t)io.uio_offset;
2656 	getret = VOP_GETATTR(vp, &at, cred, procp);
2657 
2658 	VOP_UNLOCK(vp);
2659 
2660 	if (!error)
2661 		error = getret;
2662 	if (error) {
2663 		vrele(vp);
2664 		free(rbuf, M_TEMP, fullsiz);
2665 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
2666 		    NFSX_V3POSTOPATTR) != 0)
2667 			return 0;
2668 		nfsm_srvpostop_attr(nfsd, getret, &at, &info);
2669 		error = 0;
2670 		goto nfsmout;
2671 	}
2672 	if (io.uio_resid) {
2673 		siz -= io.uio_resid;
2674 
2675 		/*
2676 		 * If nothing read, return eof
2677 		 * rpc reply
2678 		 */
2679 		if (siz == 0) {
2680 			vrele(vp);
2681 			if (nfsm_reply(&info, nfsd, slp, mrq, error,
2682 			    NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
2683 			    2 * NFSX_UNSIGNED) != 0)
2684 				return 0;
2685 			nfsm_srvpostop_attr(nfsd, getret, &at, &info);
2686 			tl = nfsm_build(&info.nmi_mb, 4 * NFSX_UNSIGNED);
2687 			txdr_hyper(at.va_filerev, tl);
2688 			tl += 2;
2689 			*tl++ = nfs_false;
2690 			*tl = nfs_true;
2691 			free(rbuf, M_TEMP, fullsiz);
2692 			error = 0;
2693 			goto nfsmout;
2694 		}
2695 	}
2696 
2697 	/*
2698 	 * Check for degenerate cases of nothing useful read.
2699 	 * If so go try again
2700 	 */
2701 	cpos = rbuf;
2702 	cend = rbuf + siz;
2703 	dp = (struct dirent *)cpos;
2704 
2705 	while (cpos < cend && dp->d_fileno == 0) {
2706 		cpos += dp->d_reclen;
2707 		dp = (struct dirent *)cpos;
2708 	}
2709 	if (cpos >= cend) {
2710 		toff = off;
2711 		siz = fullsiz;
2712 		goto again;
2713 	}
2714 
2715 	/*
2716 	 * struct READDIRPLUS3resok {
2717 	 *     postop_attr dir_attributes;
2718 	 *     cookieverf3 cookieverf;
2719 	 *     dirlistplus3 reply;
2720 	 * }
2721 	 *
2722 	 * struct dirlistplus3 {
2723 	 *     entryplus3  *entries;
2724 	 *     bool eof;
2725 	 *  }
2726 	 */
2727 	dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED;
2728 	if (nfsm_reply(&info, nfsd, slp, mrq, error, cnt) != 0)
2729 		return 0;
2730 	nfsm_srvpostop_attr(nfsd, getret, &at, &info);
2731 	tl = nfsm_build(&info.nmi_mb, 2 * NFSX_UNSIGNED);
2732 	txdr_hyper(at.va_filerev, tl);
2733 
2734 	/* Loop through the records and build reply */
2735 	while (cpos < cend) {
2736 		if (dp->d_fileno != 0) {
2737 			nlen = dp->d_namlen;
2738 			pad = nfsm_padlen(nlen);
2739 
2740 			/*
2741 			 * For readdir_and_lookup get the vnode using
2742 			 * the file number.
2743 			 */
2744 			if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp))
2745 				goto invalid;
2746 			memset(nfhp, 0, NFSX_V3FH);
2747 			nfhp->fh_fsid =
2748 				nvp->v_mount->mnt_stat.f_fsid;
2749 			if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) {
2750 				vput(nvp);
2751 				goto invalid;
2752 			}
2753 			if (VOP_GETATTR(nvp, vap, cred, procp)) {
2754 				vput(nvp);
2755 				goto invalid;
2756 			}
2757 			vput(nvp);
2758 
2759 			/*
2760 			 * If either the dircount or maxcount will be
2761 			 * exceeded, get out now. Both of these lengths
2762 			 * are calculated conservatively, including all
2763 			 * XDR overheads.
2764 			 *
2765 			 * Each entry:
2766 			 * 2 * NFSX_UNSIGNED for fileid3
2767 			 * 1 * NFSX_UNSIGNED for length of name
2768 			 * nlen + pad == space the name takes up
2769 			 * 2 * NFSX_UNSIGNED for the cookie
2770 			 * 1 * NFSX_UNSIGNED to indicate if file handle present
2771 			 * 1 * NFSX_UNSIGNED for the file handle length
2772 			 * NFSX_V3FH == space our file handle takes up
2773 			 * NFSX_V3POSTOPATTR == space the attributes take up
2774 			 * 1 * NFSX_UNSIGNED for next pointer
2775 			 */
2776 			len += (8 * NFSX_UNSIGNED + nlen + pad + NFSX_V3FH +
2777 				NFSX_V3POSTOPATTR);
2778 			dirlen += (6 * NFSX_UNSIGNED + nlen + pad);
2779 			if (len > cnt || dirlen > fullsiz) {
2780 				eofflag = 0;
2781 				break;
2782 			}
2783 
2784 			tl = nfsm_build(&info.nmi_mb, 3 * NFSX_UNSIGNED);
2785 			*tl++ = nfs_true;
2786 			txdr_hyper(dp->d_fileno, tl);
2787 
2788 			/* And copy the name */
2789 			nfsm_strtombuf(&info.nmi_mb, dp->d_name, nlen);
2790 
2791 			/*
2792 			 * Build the directory record xdr from
2793 			 * the dirent entry.
2794 			 */
2795 			fp = (struct nfs_fattr *)&fl.fl_fattr;
2796 			nfsm_srvfattr(nfsd, vap, fp);
2797 			fl.fl_fhsize = txdr_unsigned(NFSX_V3FH);
2798 			fl.fl_fhok = nfs_true;
2799 			fl.fl_postopok = nfs_true;
2800 			txdr_hyper(dp->d_off, fl.fl_off.nfsuquad);
2801 
2802 			/* Now copy the flrep structure out. */
2803 			nfsm_buftombuf(&info.nmi_mb, &fl, sizeof(struct flrep));
2804 		}
2805 invalid:
2806 		cpos += dp->d_reclen;
2807 		dp = (struct dirent *)cpos;
2808 	}
2809 	vrele(vp);
2810 	tl = nfsm_build(&info.nmi_mb, 2 * NFSX_UNSIGNED);
2811 	*tl++ = nfs_false;
2812 	if (eofflag)
2813 		*tl = nfs_true;
2814 	else
2815 		*tl = nfs_false;
2816 	free(rbuf, M_TEMP, fullsiz);
2817 nfsmout:
2818 	return(error);
2819 }
2820 
2821 /*
2822  * nfs commit service
2823  */
2824 int
nfsrv_commit(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)2825 nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2826     struct proc *procp, struct mbuf **mrq)
2827 {
2828 	struct mbuf *nam = nfsd->nd_nam;
2829 	struct ucred *cred = &nfsd->nd_cr;
2830 	struct vattr bfor, aft;
2831 	struct vnode *vp;
2832 	struct nfsm_info	info;
2833 	struct timeval boottime;
2834 	nfsfh_t nfh;
2835 	fhandle_t *fhp;
2836 	u_int32_t *tl;
2837 	int error = 0, rdonly, for_ret = 1, aft_ret = 1, cnt;
2838 	u_quad_t off;
2839 
2840 	info.nmi_mreq = NULL;
2841 	info.nmi_mrep = nfsd->nd_mrep;
2842 	info.nmi_md = nfsd->nd_md;
2843 	info.nmi_dpos = nfsd->nd_dpos;
2844 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
2845 	info.nmi_errorp = &error;
2846 
2847 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
2848 		return 0;
2849 	else if (error != 0)
2850 		goto nfsmout;
2851 	fhp = &nfh.fh_generic;
2852 	if (nfsm_srvmtofh2(&info, fhp) != 0)
2853 		goto nfsmout;
2854 	tl = (uint32_t *)nfsm_dissect(&info, 3 * NFSX_UNSIGNED);
2855 	if (tl == NULL)
2856 		goto nfsmout;
2857 
2858 	/*
2859 	 * XXX At this time VOP_FSYNC() does not accept offset and byte
2860 	 * count parameters, so these arguments are useless (someday maybe).
2861 	 */
2862 	off = fxdr_hyper(tl);
2863 	tl += 2;
2864 	cnt = fxdr_unsigned(int, *tl);
2865 	if (cnt < 0)
2866 		cnt = 0;
2867 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
2868 	if (error) {
2869 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
2870 		    2 * NFSX_UNSIGNED) != 0)
2871 			return 0;
2872 		nfsm_srvwcc(nfsd, for_ret, &bfor, aft_ret, &aft, &info);
2873 		error = 0;
2874 		goto nfsmout;
2875 	}
2876 	for_ret = VOP_GETATTR(vp, &bfor, cred, procp);
2877 	error = VOP_FSYNC(vp, cred, MNT_WAIT, procp);
2878 	aft_ret = VOP_GETATTR(vp, &aft, cred, procp);
2879 	vput(vp);
2880 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
2881 	    NFSX_V3WCCDATA + NFSX_V3WRITEVERF) != 0)
2882 		return 0;
2883 	nfsm_srvwcc(nfsd, for_ret, &bfor, aft_ret, &aft, &info);
2884 	if (!error) {
2885 		tl = nfsm_build(&info.nmi_mb, NFSX_V3WRITEVERF);
2886 		microboottime(&boottime);
2887 		*tl++ = txdr_unsigned(boottime.tv_sec);
2888 		*tl = txdr_unsigned(boottime.tv_usec);
2889 	} else
2890 		error = 0;
2891 nfsmout:
2892 	return(error);
2893 }
2894 
2895 /*
2896  * nfs statfs service
2897  */
2898 int
nfsrv_statfs(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)2899 nfsrv_statfs(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2900     struct proc *procp, struct mbuf **mrq)
2901 {
2902 	struct mbuf *nam = nfsd->nd_nam;
2903 	struct ucred *cred = &nfsd->nd_cr;
2904 	struct statfs *sf;
2905 	struct nfs_statfs *sfp;
2906 	struct nfsm_info	info;
2907 	int error = 0, rdonly, getret = 1;
2908 	struct vnode *vp;
2909 	struct vattr at;
2910 	nfsfh_t nfh;
2911 	fhandle_t *fhp;
2912 	struct statfs statfs;
2913 	u_quad_t tval;
2914 
2915 	info.nmi_mreq = NULL;
2916 	info.nmi_mrep = nfsd->nd_mrep;
2917 	info.nmi_md = nfsd->nd_md;
2918 	info.nmi_dpos = nfsd->nd_dpos;
2919 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
2920 	info.nmi_errorp = &error;
2921 
2922 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
2923 		return 0;
2924 	else if (error != 0)
2925 		goto nfsmout;
2926 	fhp = &nfh.fh_generic;
2927 	if (nfsm_srvmtofh2(&info, fhp) != 0)
2928 		goto nfsmout;
2929 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
2930 	if (error) {
2931 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
2932 		    NFSX_UNSIGNED) != 0)
2933 			return 0;
2934 		nfsm_srvpostop_attr(nfsd, getret, &at, &info);
2935 		error = 0;
2936 		goto nfsmout;
2937 	}
2938 	sf = &statfs;
2939 	error = VFS_STATFS(vp->v_mount, sf, procp);
2940 	getret = VOP_GETATTR(vp, &at, cred, procp);
2941 	vput(vp);
2942 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
2943 	    NFSX_POSTOPATTR(info.nmi_v3) + NFSX_STATFS(info.nmi_v3)) != 0)
2944 		return 0;
2945 	if (info.nmi_v3)
2946 		nfsm_srvpostop_attr(nfsd, getret, &at, &info);
2947 	if (error) {
2948 		error = 0;
2949 		goto nfsmout;
2950 	}
2951 	sfp = nfsm_build(&info.nmi_mb, NFSX_STATFS(info.nmi_v3));
2952 	if (info.nmi_v3) {
2953 		tval = (u_quad_t)sf->f_blocks;
2954 		tval *= (u_quad_t)sf->f_bsize;
2955 		txdr_hyper(tval, &sfp->sf_tbytes);
2956 		tval = (u_quad_t)sf->f_bfree;
2957 		tval *= (u_quad_t)sf->f_bsize;
2958 		txdr_hyper(tval, &sfp->sf_fbytes);
2959 		tval = (u_quad_t)sf->f_bavail;
2960 		tval *= (u_quad_t)sf->f_bsize;
2961 		txdr_hyper(tval, &sfp->sf_abytes);
2962 		tval = (u_quad_t)sf->f_files;
2963 		txdr_hyper(tval, &sfp->sf_tfiles);
2964 		tval = (u_quad_t)sf->f_ffree;
2965 		txdr_hyper(tval, &sfp->sf_ffiles);
2966 		txdr_hyper(tval, &sfp->sf_afiles);
2967 		sfp->sf_invarsec = 0;
2968 	} else {
2969 		sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
2970 		sfp->sf_bsize = txdr_unsigned(sf->f_bsize);
2971 		sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
2972 		sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
2973 		sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
2974 	}
2975 nfsmout:
2976 	return(error);
2977 }
2978 
2979 /*
2980  * nfs fsinfo service
2981  */
2982 int
nfsrv_fsinfo(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)2983 nfsrv_fsinfo(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2984     struct proc *procp, struct mbuf **mrq)
2985 {
2986 	struct mbuf *nam = nfsd->nd_nam;
2987 	struct ucred *cred = &nfsd->nd_cr;
2988 	struct nfsm_info	info;
2989 	struct nfsv3_fsinfo *sip;
2990 	int error = 0, rdonly, getret = 1, pref;
2991 	struct vnode *vp;
2992 	struct vattr at;
2993 	nfsfh_t nfh;
2994 	fhandle_t *fhp;
2995 
2996 	info.nmi_mreq = NULL;
2997 	info.nmi_mrep = nfsd->nd_mrep;
2998 	info.nmi_md = nfsd->nd_md;
2999 	info.nmi_dpos = nfsd->nd_dpos;
3000 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
3001 	info.nmi_errorp = &error;
3002 
3003 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
3004 		return 0;
3005 	else if (error != 0)
3006 		goto nfsmout;
3007 	fhp = &nfh.fh_generic;
3008 	if (nfsm_srvmtofh2(&info, fhp) != 0)
3009 		goto nfsmout;
3010 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
3011 	if (error) {
3012 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
3013 		    NFSX_UNSIGNED) != 0)
3014 			return 0;
3015 		nfsm_srvpostop_attr(nfsd, getret, &at, &info);
3016 		error = 0;
3017 		goto nfsmout;
3018 	}
3019 	getret = VOP_GETATTR(vp, &at, cred, procp);
3020 	vput(vp);
3021 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
3022 	    NFSX_V3POSTOPATTR + NFSX_V3FSINFO) != 0)
3023 		return 0;
3024 	nfsm_srvpostop_attr(nfsd, getret, &at, &info);
3025 	sip = nfsm_build(&info.nmi_mb, NFSX_V3FSINFO);
3026 
3027 	/*
3028 	 * XXX
3029 	 * There should be file system VFS OP(s) to get this information.
3030 	 * For now, assume ufs.
3031 	 */
3032 	if (slp->ns_so->so_type == SOCK_DGRAM)
3033 		pref = NFS_MAXDGRAMDATA;
3034 	else
3035 		pref = NFS_MAXDATA;
3036 	sip->fs_rtmax = txdr_unsigned(NFS_MAXDATA);
3037 	sip->fs_rtpref = txdr_unsigned(pref);
3038 	sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE);
3039 	sip->fs_wtmax = txdr_unsigned(NFS_MAXDATA);
3040 	sip->fs_wtpref = txdr_unsigned(pref);
3041 	sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE);
3042 	sip->fs_dtpref = txdr_unsigned(pref);
3043 	sip->fs_maxfilesize.nfsuquad[0] = 0xffffffff;
3044 	sip->fs_maxfilesize.nfsuquad[1] = 0xffffffff;
3045 	sip->fs_timedelta.nfsv3_sec = 0;
3046 	sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1);
3047 	sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK |
3048 		NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS |
3049 		NFSV3FSINFO_CANSETTIME);
3050 nfsmout:
3051 	return(error);
3052 }
3053 
3054 /*
3055  * nfs pathconf service
3056  */
3057 int
nfsrv_pathconf(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)3058 nfsrv_pathconf(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
3059     struct proc *procp, struct mbuf **mrq)
3060 {
3061 	struct mbuf *nam = nfsd->nd_nam;
3062 	struct ucred *cred = &nfsd->nd_cr;
3063 	struct nfsm_info	info;
3064 	struct nfsv3_pathconf *pc;
3065 	int error = 0, rdonly, getret = 1;
3066 	register_t linkmax, namemax, chownres, notrunc;
3067 	struct vnode *vp;
3068 	struct vattr at;
3069 	nfsfh_t nfh;
3070 	fhandle_t *fhp;
3071 
3072 	info.nmi_mreq = NULL;
3073 	info.nmi_mrep = nfsd->nd_mrep;
3074 	info.nmi_md = nfsd->nd_md;
3075 	info.nmi_dpos = nfsd->nd_dpos;
3076 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
3077 	info.nmi_errorp = &error;
3078 
3079 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
3080 		return 0;
3081 	else if (error != 0)
3082 		goto nfsmout;
3083 	fhp = &nfh.fh_generic;
3084 	if (nfsm_srvmtofh2(&info, fhp) != 0)
3085 		goto nfsmout;
3086 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
3087 	if (error) {
3088 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
3089 		    NFSX_UNSIGNED) != 0)
3090 			return 0;
3091 		nfsm_srvpostop_attr(nfsd, getret, &at, &info);
3092 		error = 0;
3093 		goto nfsmout;
3094 	}
3095 	error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax);
3096 	if (!error)
3097 		error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax);
3098 	if (!error)
3099 		error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres);
3100 	if (!error)
3101 		error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &notrunc);
3102 	getret = VOP_GETATTR(vp, &at, cred, procp);
3103 	vput(vp);
3104 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
3105 	    NFSX_V3POSTOPATTR + NFSX_V3PATHCONF) != 0)
3106 		return 0;
3107 	nfsm_srvpostop_attr(nfsd, getret, &at, &info);
3108 	if (error) {
3109 		error = 0;
3110 		goto nfsmout;
3111 	}
3112 	pc = nfsm_build(&info.nmi_mb, NFSX_V3PATHCONF);
3113 
3114 	pc->pc_linkmax = txdr_unsigned(linkmax);
3115 	pc->pc_namemax = txdr_unsigned(namemax);
3116 	pc->pc_notrunc = txdr_unsigned(notrunc);
3117 	pc->pc_chownrestricted = txdr_unsigned(chownres);
3118 
3119 	/*
3120 	 * These should probably be supported by VOP_PATHCONF(), but
3121 	 * until msdosfs is exportable (why would you want to?), the
3122 	 * Unix defaults should be ok.
3123 	 */
3124 	pc->pc_caseinsensitive = nfs_false;
3125 	pc->pc_casepreserving = nfs_true;
3126 nfsmout:
3127 	return(error);
3128 }
3129 
3130 /*
3131  * Null operation, used by clients to ping server
3132  */
3133 int
nfsrv_null(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)3134 nfsrv_null(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
3135     struct proc *procp, struct mbuf **mrq)
3136 {
3137 	struct nfsm_info	info;
3138 	int error = NFSERR_RETVOID;
3139 
3140 	info.nmi_mreq = NULL;
3141 	info.nmi_mrep = nfsd->nd_mrep;
3142 	info.nmi_md = nfsd->nd_md;
3143 	info.nmi_dpos = nfsd->nd_dpos;
3144 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
3145 	info.nmi_errorp = &error;
3146 
3147 	if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
3148 		return 0;
3149 	return (0);
3150 }
3151 
3152 /*
3153  * No operation, used for obsolete procedures
3154  */
3155 int
nfsrv_noop(struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct proc * procp,struct mbuf ** mrq)3156 nfsrv_noop(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
3157     struct proc *procp, struct mbuf **mrq)
3158 {
3159 	struct nfsm_info	info;
3160 	int error;
3161 
3162 	info.nmi_mreq = NULL;
3163 	info.nmi_mrep = nfsd->nd_mrep;
3164 	info.nmi_md = nfsd->nd_md;
3165 	info.nmi_dpos = nfsd->nd_dpos;
3166 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
3167 	info.nmi_errorp = &error;
3168 
3169 	if (nfsd->nd_repstat)
3170 		error = nfsd->nd_repstat;
3171 	else
3172 		error = EPROCUNAVAIL;
3173 	if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
3174 		return 0;
3175 	return (0);
3176 }
3177 
3178 /*
3179  * Perform access checking for vnodes obtained from file handles that would
3180  * refer to files already opened by a Unix client.
3181  * You cannot just use vn_writechk() and VOP_ACCESS() for two reasons:
3182  * 1 - You must check for exported rdonly as well as MNT_RDONLY for the
3183  *     write case
3184  * 2 - The owner is to be given access irrespective of mode bits for some
3185  *     operations, so that processes that chmod after opening a file don't
3186  *     break. I don't like this because it opens a security hole, but since
3187  *     the nfs server opens a security hole the size of a barn door anyhow,
3188  *     what the heck. A notable exception to this rule is when VOP_ACCESS()
3189  *     returns EPERM (e.g. when a file is immutable) which is always an
3190  *     error.
3191  */
3192 int
nfsrv_access(struct vnode * vp,int flags,struct ucred * cred,int rdonly,struct proc * p,int override)3193 nfsrv_access(struct vnode *vp, int flags, struct ucred *cred, int rdonly,
3194     struct proc *p, int override)
3195 {
3196 	struct vattr vattr;
3197 	int error;
3198 
3199 	if (flags & VWRITE) {
3200 		/* Just vn_writechk() changed to check rdonly */
3201 		/*
3202 		 * Disallow write attempts on read-only file systems;
3203 		 * unless the file is a socket or a block or character
3204 		 * device resident on the file system.
3205 		 */
3206 		if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
3207 			switch (vp->v_type) {
3208 			case VREG:
3209 			case VDIR:
3210 			case VLNK:
3211 				return (EROFS);
3212 			default:
3213 				break;
3214 			}
3215 		}
3216 		/*
3217 		 * If there's shared text associated with
3218 		 * the inode, try to free it up once.  If
3219 		 * we fail, we can't allow writing.
3220 		 */
3221 		if ((vp->v_flag & VTEXT) && !uvm_vnp_uncache(vp))
3222 			return (ETXTBSY);
3223 	}
3224 	error = VOP_ACCESS(vp, flags, cred, p);
3225 	/*
3226 	 * Allow certain operations for the owner (reads and writes
3227 	 * on files that are already open).
3228 	 */
3229 	if (override && error == EACCES &&
3230 	    VOP_GETATTR(vp, &vattr, cred, p) == 0 &&
3231 	    cred->cr_uid == vattr.va_uid)
3232 		error = 0;
3233 	return error;
3234 }
3235