xref: /original-bsd/sys/nfs/nfs_serv.c (revision 2932bec8)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Rick Macklem at The University of Guelph.
7  *
8  * %sccs.include.redist.c%
9  *
10  *	@(#)nfs_serv.c	7.50 (Berkeley) 05/04/92
11  */
12 
13 /*
14  * nfs version 2 server calls to vnode ops
15  * - these routines generally have 3 phases
16  *   1 - break down and validate rpc request in mbuf list
17  *   2 - do the vnode ops for the request
18  *       (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
19  *   3 - build the rpc reply in an mbuf list
20  *   nb:
21  *	- do not mix the phases, since the nfsm_?? macros can return failures
22  *	  on a bad rpc or similar and do not do any vrele() or vput()'s
23  *
24  *      - the nfsm_reply() macro generates an nfs rpc reply with the nfs
25  *	error number iff error != 0 whereas
26  *	returning an error from the server function implies a fatal error
27  *	such as a badly constructed rpc request that should be dropped without
28  *	a reply.
29  */
30 
31 #include <sys/param.h>
32 #include <sys/proc.h>
33 #include <sys/file.h>
34 #include <sys/namei.h>
35 #include <sys/vnode.h>
36 #include <sys/mount.h>
37 #include <sys/mbuf.h>
38 #include <sys/dirent.h>
39 
40 #include <vm/vm.h>
41 
42 #include <ufs/ufs/quota.h>	/* XXX - for ufid */
43 #include <ufs/ufs/inode.h>	/* XXX - for ufid */
44 
45 #include <nfs/nfsv2.h>
46 #include <nfs/rpcv2.h>
47 #include <nfs/nfs.h>
48 #include <nfs/xdr_subs.h>
49 #include <nfs/nfsm_subs.h>
50 #include <nfs/nqnfs.h>
51 
52 /* Defs */
53 #define	TRUE	1
54 #define	FALSE	0
55 
56 /* Global vars */
57 extern u_long nfs_procids[NFS_NPROCS];
58 extern u_long nfs_xdrneg1;
59 extern u_long nfs_false, nfs_true;
60 nfstype nfs_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
61 		      NFCHR, NFNON };
62 
63 /*
64  * nfs getattr service
65  */
66 nfsrv_getattr(nfsd, mrep, md, dpos, cred, nam, mrq)
67 	struct nfsd *nfsd;
68 	struct mbuf *mrep, *md;
69 	caddr_t dpos;
70 	struct ucred *cred;
71 	struct mbuf *nam, **mrq;
72 {
73 	register struct nfsv2_fattr *fp;
74 	struct vattr va;
75 	register struct vattr *vap = &va;
76 	struct vnode *vp;
77 	nfsv2fh_t nfh;
78 	fhandle_t *fhp;
79 	register u_long *tl;
80 	register long t1;
81 	caddr_t bpos;
82 	int error = 0, rdonly, cache;
83 	char *cp2;
84 	struct mbuf *mb, *mb2, *mreq;
85 	u_quad_t frev;
86 
87 	fhp = &nfh.fh_generic;
88 	nfsm_srvmtofh(fhp);
89 	if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
90 		nfsm_reply(0);
91 	nqsrv_getl(vp, NQL_READ);
92 	error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
93 	vput(vp);
94 	nfsm_reply(NFSX_FATTR);
95 	nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
96 	nfsm_srvfillattr;
97 	nfsm_srvdone;
98 }
99 
100 /*
101  * nfs setattr service
102  */
103 nfsrv_setattr(nfsd, mrep, md, dpos, cred, nam, mrq)
104 	struct nfsd *nfsd;
105 	struct mbuf *mrep, *md;
106 	caddr_t dpos;
107 	struct ucred *cred;
108 	struct mbuf *nam, **mrq;
109 {
110 	struct vattr va;
111 	register struct vattr *vap = &va;
112 	register struct nfsv2_sattr *sp;
113 	register struct nfsv2_fattr *fp;
114 	struct vnode *vp;
115 	nfsv2fh_t nfh;
116 	fhandle_t *fhp;
117 	register u_long *tl;
118 	register long t1;
119 	caddr_t bpos;
120 	int error = 0, rdonly, cache, duration2, cache2;
121 	char *cp2;
122 	struct mbuf *mb, *mb2, *mreq;
123 	u_quad_t frev, frev2;
124 
125 	fhp = &nfh.fh_generic;
126 	nfsm_srvmtofh(fhp);
127 	nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR);
128 	if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
129 		nfsm_reply(0);
130 	nqsrv_getl(vp, NQL_WRITE);
131 	if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp))
132 		goto out;
133 	VATTR_NULL(vap);
134 	/*
135 	 * Nah nah nah nah na nah
136 	 * There is a bug in the Sun client that puts 0xffff in the mode
137 	 * field of sattr when it should put in 0xffffffff. The u_short
138 	 * doesn't sign extend.
139 	 * --> check the low order 2 bytes for 0xffff
140 	 */
141 	if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
142 		vap->va_mode = nfstov_mode(sp->sa_mode);
143 	if (sp->sa_uid != nfs_xdrneg1)
144 		vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
145 	if (sp->sa_gid != nfs_xdrneg1)
146 		vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
147 	if (sp->sa_size != nfs_xdrneg1)
148 		vap->va_size = fxdr_unsigned(u_long, sp->sa_size);
149 	/*
150 	 * The usec field of sa_atime is overloaded with the va_flags field
151 	 * for 4.4BSD clients. Hopefully other clients always set both the
152 	 * sec and usec fields to -1 when not setting the atime.
153 	 */
154 	if (sp->sa_atime.tv_sec != nfs_xdrneg1) {
155 		vap->va_atime.tv_sec = fxdr_unsigned(long, sp->sa_atime.tv_sec);
156 		vap->va_atime.tv_usec = 0;
157 	}
158 	if (sp->sa_atime.tv_usec != nfs_xdrneg1)
159 		vap->va_flags = fxdr_unsigned(u_long, sp->sa_atime.tv_usec);
160 	if (sp->sa_mtime.tv_sec != nfs_xdrneg1)
161 		fxdr_time(&sp->sa_mtime, &vap->va_mtime);
162 	if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) {
163 		vput(vp);
164 		nfsm_reply(0);
165 	}
166 	error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
167 out:
168 	vput(vp);
169 	nfsm_reply(NFSX_FATTR + 2*NFSX_UNSIGNED);
170 	nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
171 	nfsm_srvfillattr;
172 	if (nfsd->nd_nqlflag != NQL_NOVAL) {
173 		nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
174 		txdr_hyper(&frev2, tl);
175 	}
176 	nfsm_srvdone;
177 }
178 
179 /*
180  * nfs lookup rpc
181  */
182 nfsrv_lookup(nfsd, mrep, md, dpos, cred, nam, mrq)
183 	struct nfsd *nfsd;
184 	struct mbuf *mrep, *md;
185 	caddr_t dpos;
186 	struct ucred *cred;
187 	struct mbuf *nam, **mrq;
188 {
189 	register struct nfsv2_fattr *fp;
190 	struct nameidata nd;
191 	struct vnode *vp;
192 	nfsv2fh_t nfh;
193 	fhandle_t *fhp;
194 	register caddr_t cp;
195 	register u_long *tl;
196 	register long t1;
197 	caddr_t bpos;
198 	int error = 0, lflag = 0, rdonly, cache, duration2, cache2, len;
199 	char *cp2;
200 	struct mbuf *mb, *mb2, *mreq;
201 	struct vattr va, *vap = &va;
202 	u_quad_t frev, frev2;
203 
204 	fhp = &nfh.fh_generic;
205 	if (nfsd->nd_nqlflag != NQL_NOVAL) {
206 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
207 		if (*tl) {
208 			lflag = fxdr_unsigned(int, *tl);
209 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
210 			duration2 = fxdr_unsigned(int, *tl);
211 		}
212 	}
213 	nfsm_srvmtofh(fhp);
214 	nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
215 	nd.ni_cnd.cn_cred = cred;
216 	nd.ni_cnd.cn_nameiop = LOOKUP;
217 	nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART;
218 	if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
219 	    nfsd->nd_procp))
220 		nfsm_reply(0);
221 	nqsrv_getl(nd.ni_startdir, NQL_READ);
222 	vrele(nd.ni_startdir);
223 	FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
224 	vp = nd.ni_vp;
225 	bzero((caddr_t)fhp, sizeof(nfh));
226 	fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
227 	if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
228 		vput(vp);
229 		nfsm_reply(0);
230 	}
231 	if (lflag)
232 		(void) nqsrv_getlease(vp, &duration2, lflag, nfsd,
233 			nam, &cache2, &frev2, cred);
234 	error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
235 	vput(vp);
236 	nfsm_reply(NFSX_FH + NFSX_FATTR + 5*NFSX_UNSIGNED);
237 	if (nfsd->nd_nqlflag != NQL_NOVAL) {
238 		if (lflag) {
239 			nfsm_build(tl, u_long *, 5*NFSX_UNSIGNED);
240 			*tl++ = txdr_unsigned(lflag);
241 			*tl++ = txdr_unsigned(cache2);
242 			*tl++ = txdr_unsigned(duration2);
243 			txdr_hyper(&frev2, tl);
244 		} else {
245 			nfsm_build(tl, u_long *, NFSX_UNSIGNED);
246 			*tl = 0;
247 		}
248 	}
249 	nfsm_srvfhtom(fhp);
250 	nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
251 	nfsm_srvfillattr;
252 	nfsm_srvdone;
253 }
254 
255 /*
256  * nfs readlink service
257  */
258 nfsrv_readlink(nfsd, mrep, md, dpos, cred, nam, mrq)
259 	struct nfsd *nfsd;
260 	struct mbuf *mrep, *md;
261 	caddr_t dpos;
262 	struct ucred *cred;
263 	struct mbuf *nam, **mrq;
264 {
265 	struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
266 	register struct iovec *ivp = iv;
267 	register struct mbuf *mp;
268 	register u_long *tl;
269 	register long t1;
270 	caddr_t bpos;
271 	int error = 0, rdonly, cache, i, tlen, len;
272 	char *cp2;
273 	struct mbuf *mb, *mb2, *mp2, *mp3, *mreq;
274 	struct vnode *vp;
275 	nfsv2fh_t nfh;
276 	fhandle_t *fhp;
277 	struct uio io, *uiop = &io;
278 	u_quad_t frev;
279 
280 	fhp = &nfh.fh_generic;
281 	nfsm_srvmtofh(fhp);
282 	len = 0;
283 	i = 0;
284 	while (len < NFS_MAXPATHLEN) {
285 		MGET(mp, M_WAIT, MT_DATA);
286 		MCLGET(mp, M_WAIT);
287 		mp->m_len = NFSMSIZ(mp);
288 		if (len == 0)
289 			mp3 = mp2 = mp;
290 		else {
291 			mp2->m_next = mp;
292 			mp2 = mp;
293 		}
294 		if ((len+mp->m_len) > NFS_MAXPATHLEN) {
295 			mp->m_len = NFS_MAXPATHLEN-len;
296 			len = NFS_MAXPATHLEN;
297 		} else
298 			len += mp->m_len;
299 		ivp->iov_base = mtod(mp, caddr_t);
300 		ivp->iov_len = mp->m_len;
301 		i++;
302 		ivp++;
303 	}
304 	uiop->uio_iov = iv;
305 	uiop->uio_iovcnt = i;
306 	uiop->uio_offset = 0;
307 	uiop->uio_resid = len;
308 	uiop->uio_rw = UIO_READ;
309 	uiop->uio_segflg = UIO_SYSSPACE;
310 	uiop->uio_procp = (struct proc *)0;
311 	if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) {
312 		m_freem(mp3);
313 		nfsm_reply(0);
314 	}
315 	if (vp->v_type != VLNK) {
316 		error = EINVAL;
317 		goto out;
318 	}
319 	nqsrv_getl(vp, NQL_READ);
320 	error = VOP_READLINK(vp, uiop, cred);
321 out:
322 	vput(vp);
323 	if (error)
324 		m_freem(mp3);
325 	nfsm_reply(NFSX_UNSIGNED);
326 	if (uiop->uio_resid > 0) {
327 		len -= uiop->uio_resid;
328 		tlen = nfsm_rndup(len);
329 		nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len);
330 	}
331 	nfsm_build(tl, u_long *, NFSX_UNSIGNED);
332 	*tl = txdr_unsigned(len);
333 	mb->m_next = mp3;
334 	nfsm_srvdone;
335 }
336 
337 /*
338  * nfs read service
339  */
340 nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq)
341 	struct nfsd *nfsd;
342 	struct mbuf *mrep, *md;
343 	caddr_t dpos;
344 	struct ucred *cred;
345 	struct mbuf *nam, **mrq;
346 {
347 	register struct iovec *iv;
348 	struct iovec *iv2;
349 	register struct mbuf *m;
350 	register struct nfsv2_fattr *fp;
351 	register u_long *tl;
352 	register long t1;
353 	caddr_t bpos;
354 	int error = 0, rdonly, cache, i, cnt, len, left, siz, tlen;
355 	char *cp2;
356 	struct mbuf *mb, *mb2, *mreq;
357 	struct mbuf *m2;
358 	struct vnode *vp;
359 	nfsv2fh_t nfh;
360 	fhandle_t *fhp;
361 	struct uio io, *uiop = &io;
362 	struct vattr va, *vap = &va;
363 	off_t off;
364 	u_quad_t frev;
365 
366 	fhp = &nfh.fh_generic;
367 	nfsm_srvmtofh(fhp);
368 	nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
369 	off = fxdr_unsigned(off_t, *tl);
370 	nfsm_srvstrsiz(cnt, NFS_MAXDATA);
371 	if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
372 		nfsm_reply(0);
373 	nqsrv_getl(vp, NQL_READ);
374 	if (error = nfsrv_access(vp, VREAD | VEXEC, cred, rdonly, nfsd->nd_procp)) {
375 		vput(vp);
376 		nfsm_reply(0);
377 	}
378 	if (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp)) {
379 		vput(vp);
380 		nfsm_reply(0);
381 	}
382 	if (off >= vap->va_size)
383 		cnt = 0;
384 	else if ((off + cnt) > vap->va_size)
385 		cnt = nfsm_rndup(vap->va_size - off);
386 	nfsm_reply(NFSX_FATTR+NFSX_UNSIGNED+nfsm_rndup(cnt));
387 	nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
388 	nfsm_build(tl, u_long *, NFSX_UNSIGNED);
389 	len = left = cnt;
390 	if (cnt > 0) {
391 		/*
392 		 * Generate the mbuf list with the uio_iov ref. to it.
393 		 */
394 		i = 0;
395 		m = m2 = mb;
396 		MALLOC(iv, struct iovec *,
397 		       ((NFS_MAXDATA+MLEN-1)/MLEN) * sizeof (struct iovec),
398 		       M_TEMP, M_WAITOK);
399 		iv2 = iv;
400 		while (left > 0) {
401 			siz = MIN(M_TRAILINGSPACE(m), left);
402 			if (siz > 0) {
403 				m->m_len += siz;
404 				iv->iov_base = bpos;
405 				iv->iov_len = siz;
406 				iv++;
407 				i++;
408 				left -= siz;
409 			}
410 			if (left > 0) {
411 				MGET(m, M_WAIT, MT_DATA);
412 				MCLGET(m, M_WAIT);
413 				m->m_len = 0;
414 				m2->m_next = m;
415 				m2 = m;
416 				bpos = mtod(m, caddr_t);
417 			}
418 		}
419 		uiop->uio_iov = iv2;
420 		uiop->uio_iovcnt = i;
421 		uiop->uio_offset = off;
422 		uiop->uio_resid = cnt;
423 		uiop->uio_rw = UIO_READ;
424 		uiop->uio_segflg = UIO_SYSSPACE;
425 		error = VOP_READ(vp, uiop, IO_NODELOCKED, cred);
426 		off = uiop->uio_offset;
427 		FREE((caddr_t)iv2, M_TEMP);
428 		if (error || (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp))) {
429 			m_freem(mreq);
430 			vput(vp);
431 			nfsm_reply(0);
432 		}
433 	} else
434 		uiop->uio_resid = 0;
435 	vput(vp);
436 	nfsm_srvfillattr;
437 	len -= uiop->uio_resid;
438 	tlen = nfsm_rndup(len);
439 	if (cnt != tlen || tlen != len)
440 		nfsm_adj(mb, cnt-tlen, tlen-len);
441 	*tl = txdr_unsigned(len);
442 	nfsm_srvdone;
443 }
444 
445 /*
446  * nfs write service
447  */
448 nfsrv_write(nfsd, mrep, md, dpos, cred, nam, mrq)
449 	struct nfsd *nfsd;
450 	struct mbuf *mrep, *md;
451 	caddr_t dpos;
452 	struct ucred *cred;
453 	struct mbuf *nam, **mrq;
454 {
455 	register struct iovec *ivp;
456 	register struct mbuf *mp;
457 	register struct nfsv2_fattr *fp;
458 	struct iovec iv[NFS_MAXIOVEC];
459 	struct vattr va;
460 	register struct vattr *vap = &va;
461 	register u_long *tl;
462 	register long t1;
463 	caddr_t bpos;
464 	int error = 0, rdonly, cache, siz, len, xfer;
465 	char *cp2;
466 	struct mbuf *mb, *mb2, *mreq;
467 	struct vnode *vp;
468 	nfsv2fh_t nfh;
469 	fhandle_t *fhp;
470 	struct uio io, *uiop = &io;
471 	off_t off;
472 	u_quad_t frev;
473 
474 	fhp = &nfh.fh_generic;
475 	nfsm_srvmtofh(fhp);
476 	nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED);
477 	off = fxdr_unsigned(off_t, *++tl);
478 	tl += 2;
479 	len = fxdr_unsigned(long, *tl);
480 	if (len > NFS_MAXDATA || len <= 0) {
481 		error = EBADRPC;
482 		nfsm_reply(0);
483 	}
484 	if (dpos == (mtod(md, caddr_t)+md->m_len)) {
485 		mp = md->m_next;
486 		if (mp == NULL) {
487 			error = EBADRPC;
488 			nfsm_reply(0);
489 		}
490 	} else {
491 		mp = md;
492 		siz = dpos-mtod(mp, caddr_t);
493 		mp->m_len -= siz;
494 		NFSMADV(mp, siz);
495 	}
496 	if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
497 		nfsm_reply(0);
498 	nqsrv_getl(vp, NQL_WRITE);
499 	if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) {
500 		vput(vp);
501 		nfsm_reply(0);
502 	}
503 	uiop->uio_resid = 0;
504 	uiop->uio_rw = UIO_WRITE;
505 	uiop->uio_segflg = UIO_SYSSPACE;
506 	uiop->uio_procp = (struct proc *)0;
507 	/*
508 	 * Do up to NFS_MAXIOVEC mbufs of write each iteration of the
509 	 * loop until done.
510 	 */
511 	while (len > 0 && uiop->uio_resid == 0) {
512 		ivp = iv;
513 		siz = 0;
514 		uiop->uio_iov = ivp;
515 		uiop->uio_iovcnt = 0;
516 		uiop->uio_offset = off;
517 		while (len > 0 && uiop->uio_iovcnt < NFS_MAXIOVEC && mp != NULL) {
518 			ivp->iov_base = mtod(mp, caddr_t);
519 			if (len < mp->m_len)
520 				ivp->iov_len = xfer = len;
521 			else
522 				ivp->iov_len = xfer = mp->m_len;
523 #ifdef notdef
524 			/* Not Yet .. */
525 			if (M_HASCL(mp) && (((u_long)ivp->iov_base) & CLOFSET) == 0)
526 				ivp->iov_op = NULL;	/* what should it be ?? */
527 			else
528 				ivp->iov_op = NULL;
529 #endif
530 			uiop->uio_iovcnt++;
531 			ivp++;
532 			len -= xfer;
533 			siz += xfer;
534 			mp = mp->m_next;
535 		}
536 		if (len > 0 && mp == NULL) {
537 			error = EBADRPC;
538 			vput(vp);
539 			nfsm_reply(0);
540 		}
541 		uiop->uio_resid = siz;
542 		if (error = VOP_WRITE(vp, uiop, IO_SYNC | IO_NODELOCKED,
543 			cred)) {
544 			vput(vp);
545 			nfsm_reply(0);
546 		}
547 		off = uiop->uio_offset;
548 	}
549 	error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
550 	vput(vp);
551 	nfsm_reply(NFSX_FATTR);
552 	nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
553 	nfsm_srvfillattr;
554 	if (nfsd->nd_nqlflag != NQL_NOVAL) {
555 		nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
556 		txdr_hyper(&vap->va_filerev, tl);
557 	}
558 	nfsm_srvdone;
559 }
560 
561 /*
562  * nfs create service
563  * now does a truncate to 0 length via. setattr if it already exists
564  */
565 nfsrv_create(nfsd, mrep, md, dpos, cred, nam, mrq)
566 	struct nfsd *nfsd;
567 	struct mbuf *mrep, *md;
568 	caddr_t dpos;
569 	struct ucred *cred;
570 	struct mbuf *nam, **mrq;
571 {
572 	register struct nfsv2_fattr *fp;
573 	struct vattr va;
574 	register struct vattr *vap = &va;
575 	struct nameidata nd;
576 	register caddr_t cp;
577 	register u_long *tl;
578 	register long t1;
579 	caddr_t bpos;
580 	int error = 0, rdev, cache, len;
581 	char *cp2;
582 	struct mbuf *mb, *mb2, *mreq;
583 	struct vnode *vp;
584 	nfsv2fh_t nfh;
585 	fhandle_t *fhp;
586 	u_quad_t frev;
587 
588 	nd.ni_cnd.cn_nameiop = 0;
589 	fhp = &nfh.fh_generic;
590 	nfsm_srvmtofh(fhp);
591 	nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
592 	nd.ni_cnd.cn_cred = cred;
593 	nd.ni_cnd.cn_nameiop = CREATE;
594 	nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART;
595 	if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
596 	    nfsd->nd_procp))
597 		nfsm_reply(0);
598 	VATTR_NULL(vap);
599 	nfsm_dissect(tl, u_long *, NFSX_SATTR);
600 	/*
601 	 * Iff doesn't exist, create it
602 	 * otherwise just truncate to 0 length
603 	 *   should I set the mode too ??
604 	 */
605 	if (nd.ni_vp == NULL) {
606 		vap->va_type = IFTOVT(fxdr_unsigned(u_long, *tl));
607 		if (vap->va_type == VNON)
608 			vap->va_type = VREG;
609 		vap->va_mode = nfstov_mode(*tl);
610 		rdev = fxdr_unsigned(long, *(tl+3));
611 		if (vap->va_type == VREG || vap->va_type == VSOCK) {
612 			vrele(nd.ni_startdir);
613 			nqsrv_getl(nd.ni_dvp, NQL_WRITE);
614 			if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap))
615 				nfsm_reply(0);
616 			FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
617 		} else if (vap->va_type == VCHR || vap->va_type == VBLK ||
618 			vap->va_type == VFIFO) {
619 			if (vap->va_type == VCHR && rdev == 0xffffffff)
620 				vap->va_type = VFIFO;
621 			if (vap->va_type == VFIFO) {
622 #ifndef FIFO
623 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
624 				vput(nd.ni_dvp);
625 				error = ENXIO;
626 				goto out;
627 #endif /* FIFO */
628 			} else if (error = suser(cred, (u_short *)0)) {
629 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
630 				vput(nd.ni_dvp);
631 				goto out;
632 			} else
633 				vap->va_rdev = (dev_t)rdev;
634 			nqsrv_getl(nd.ni_dvp, NQL_WRITE);
635 			if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) {
636 				vrele(nd.ni_startdir);
637 				nfsm_reply(0);
638 			}
639 			nd.ni_cnd.cn_nameiop = LOOKUP;
640 			nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
641 			nd.ni_cnd.cn_proc = nfsd->nd_procp;
642 			nd.ni_cnd.cn_cred = nfsd->nd_procp->p_ucred;
643 			if (error = lookup(&nd)) {
644 				free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
645 				nfsm_reply(0);
646 			}
647 			FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
648 			if (nd.ni_cnd.cn_flags & ISSYMLINK) {
649 				vrele(nd.ni_dvp);
650 				vput(nd.ni_vp);
651 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
652 				error = EINVAL;
653 				nfsm_reply(0);
654 			}
655 		} else {
656 			VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
657 			vput(nd.ni_dvp);
658 			error = ENXIO;
659 			goto out;
660 		}
661 		vp = nd.ni_vp;
662 	} else {
663 		vrele(nd.ni_startdir);
664 		free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
665 		vp = nd.ni_vp;
666 		if (nd.ni_dvp == vp)
667 			vrele(nd.ni_dvp);
668 		else
669 			vput(nd.ni_dvp);
670 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
671 		vap->va_size = 0;
672 		nqsrv_getl(vp, NQL_WRITE);
673 		if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) {
674 			vput(vp);
675 			nfsm_reply(0);
676 		}
677 	}
678 	bzero((caddr_t)fhp, sizeof(nfh));
679 	fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
680 	if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
681 		vput(vp);
682 		nfsm_reply(0);
683 	}
684 	error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
685 	vput(vp);
686 	nfsm_reply(NFSX_FH+NFSX_FATTR);
687 	nfsm_srvfhtom(fhp);
688 	nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
689 	nfsm_srvfillattr;
690 	return (error);
691 nfsmout:
692 	if (nd.ni_cnd.cn_nameiop || nd.ni_cnd.cn_flags)
693 		vrele(nd.ni_startdir);
694 	VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
695 	if (nd.ni_dvp == nd.ni_vp)
696 		vrele(nd.ni_dvp);
697 	else
698 		vput(nd.ni_dvp);
699 	if (nd.ni_vp)
700 		vput(nd.ni_vp);
701 	return (error);
702 
703 out:
704 	vrele(nd.ni_startdir);
705 	free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
706 	nfsm_reply(0);
707 }
708 
709 /*
710  * nfs remove service
711  */
712 nfsrv_remove(nfsd, mrep, md, dpos, cred, nam, mrq)
713 	struct nfsd *nfsd;
714 	struct mbuf *mrep, *md;
715 	caddr_t dpos;
716 	struct ucred *cred;
717 	struct mbuf *nam, **mrq;
718 {
719 	struct nameidata nd;
720 	register u_long *tl;
721 	register long t1;
722 	caddr_t bpos;
723 	int error = 0, cache, len;
724 	char *cp2;
725 	struct mbuf *mb, *mreq;
726 	struct vnode *vp;
727 	nfsv2fh_t nfh;
728 	fhandle_t *fhp;
729 	u_quad_t frev;
730 
731 	fhp = &nfh.fh_generic;
732 	nfsm_srvmtofh(fhp);
733 	nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
734 	nd.ni_cnd.cn_cred = cred;
735 	nd.ni_cnd.cn_nameiop = DELETE;
736 	nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
737 	if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
738 	    nfsd->nd_procp))
739 		nfsm_reply(0);
740 	vp = nd.ni_vp;
741 	if (vp->v_type == VDIR &&
742 		(error = suser(cred, (u_short *)0)))
743 		goto out;
744 	/*
745 	 * The root of a mounted filesystem cannot be deleted.
746 	 */
747 	if (vp->v_flag & VROOT) {
748 		error = EBUSY;
749 		goto out;
750 	}
751 	if (vp->v_flag & VTEXT)
752 		(void) vnode_pager_uncache(vp);
753 out:
754 	if (!error) {
755 		nqsrv_getl(nd.ni_dvp, NQL_WRITE);
756 		nqsrv_getl(vp, NQL_WRITE);
757 		error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
758 	} else {
759 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
760 		if (nd.ni_dvp == vp)
761 			vrele(nd.ni_dvp);
762 		else
763 			vput(nd.ni_dvp);
764 		vput(vp);
765 	}
766 	nfsm_reply(0);
767 	nfsm_srvdone;
768 }
769 
770 /*
771  * nfs rename service
772  */
773 nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq)
774 	struct nfsd *nfsd;
775 	struct mbuf *mrep, *md;
776 	caddr_t dpos;
777 	struct ucred *cred;
778 	struct mbuf *nam, **mrq;
779 {
780 	register u_long *tl;
781 	register long t1;
782 	caddr_t bpos;
783 	int error = 0, rdonly, cache, len, len2;
784 	char *cp2;
785 	struct mbuf *mb, *mreq;
786 	struct nameidata fromnd, tond;
787 	struct vnode *fvp, *tvp, *tdvp;
788 	nfsv2fh_t fnfh, tnfh;
789 	fhandle_t *ffhp, *tfhp;
790 	u_quad_t frev;
791 	uid_t saved_uid;
792 
793 	ffhp = &fnfh.fh_generic;
794 	tfhp = &tnfh.fh_generic;
795 	fromnd.ni_cnd.cn_nameiop = 0;
796 	tond.ni_cnd.cn_nameiop = 0;
797 	nfsm_srvmtofh(ffhp);
798 	nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
799 	/*
800 	 * Remember our original uid so that we can reset cr_uid before
801 	 * the second nfs_namei() call, in case it is remapped.
802 	 */
803 	saved_uid = cred->cr_uid;
804 	fromnd.ni_cnd.cn_cred = cred;
805 	fromnd.ni_cnd.cn_nameiop = DELETE;
806 	fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART;
807 	if (error = nfs_namei(&fromnd, ffhp, len, nfsd->nd_slp, nam, &md,
808 	    &dpos, nfsd->nd_procp))
809 		nfsm_reply(0);
810 	fvp = fromnd.ni_vp;
811 	nfsm_srvmtofh(tfhp);
812 	nfsm_strsiz(len2, NFS_MAXNAMLEN);
813 	cred->cr_uid = saved_uid;
814 	tond.ni_cnd.cn_cred = cred;
815 	tond.ni_cnd.cn_nameiop = RENAME;
816 	tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART;
817 	if (error = nfs_namei(&tond, tfhp, len2, nfsd->nd_slp, nam, &md,
818 	    &dpos, nfsd->nd_procp)) {
819 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
820 		vrele(fromnd.ni_dvp);
821 		vrele(fvp);
822 		goto out1;
823 	}
824 	tdvp = tond.ni_dvp;
825 	tvp = tond.ni_vp;
826 	if (tvp != NULL) {
827 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
828 			error = EISDIR;
829 			goto out;
830 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
831 			error = ENOTDIR;
832 			goto out;
833 		}
834 		if (tvp->v_type == VDIR && tvp->v_mountedhere) {
835 			error = EXDEV;
836 			goto out;
837 		}
838 	}
839 	if (fvp->v_type == VDIR && fvp->v_mountedhere) {
840 		error = EBUSY;
841 		goto out;
842 	}
843 	if (fvp->v_mount != tdvp->v_mount) {
844 		error = EXDEV;
845 		goto out;
846 	}
847 	if (fvp == tdvp)
848 		error = EINVAL;
849 	/*
850 	 * If source is the same as the destination (that is the
851 	 * same vnode with the same name in the same directory),
852 	 * then there is nothing to do.
853 	 */
854 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
855 	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
856 	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
857 	      fromnd.ni_cnd.cn_namelen))
858 		error = -1;
859 out:
860 	if (!error) {
861 		nqsrv_getl(fromnd.ni_dvp, NQL_WRITE);
862 		nqsrv_getl(tdvp, NQL_WRITE);
863 		if (tvp)
864 			nqsrv_getl(tvp, NQL_WRITE);
865 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
866 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
867 	} else {
868 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
869 		if (tdvp == tvp)
870 			vrele(tdvp);
871 		else
872 			vput(tdvp);
873 		if (tvp)
874 			vput(tvp);
875 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
876 		vrele(fromnd.ni_dvp);
877 		vrele(fvp);
878 	}
879 	vrele(tond.ni_startdir);
880 	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
881 out1:
882 	vrele(fromnd.ni_startdir);
883 	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
884 	nfsm_reply(0);
885 	return (error);
886 
887 nfsmout:
888 	if (tond.ni_cnd.cn_nameiop || tond.ni_cnd.cn_flags) {
889 		vrele(tond.ni_startdir);
890 		FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
891 	}
892 	if (fromnd.ni_cnd.cn_nameiop || fromnd.ni_cnd.cn_flags) {
893 		vrele(fromnd.ni_startdir);
894 		FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
895 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
896 		vrele(fromnd.ni_dvp);
897 		vrele(fvp);
898 	}
899 	return (error);
900 }
901 
902 /*
903  * nfs link service
904  */
905 nfsrv_link(nfsd, mrep, md, dpos, cred, nam, mrq)
906 	struct nfsd *nfsd;
907 	struct mbuf *mrep, *md;
908 	caddr_t dpos;
909 	struct ucred *cred;
910 	struct mbuf *nam, **mrq;
911 {
912 	struct nameidata nd;
913 	register u_long *tl;
914 	register long t1;
915 	caddr_t bpos;
916 	int error = 0, rdonly, cache, len;
917 	char *cp2;
918 	struct mbuf *mb, *mreq;
919 	struct vnode *vp, *xp;
920 	nfsv2fh_t nfh, dnfh;
921 	fhandle_t *fhp, *dfhp;
922 	u_quad_t frev;
923 
924 	fhp = &nfh.fh_generic;
925 	dfhp = &dnfh.fh_generic;
926 	nfsm_srvmtofh(fhp);
927 	nfsm_srvmtofh(dfhp);
928 	nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
929 	if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
930 		nfsm_reply(0);
931 	if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0)))
932 		goto out1;
933 	nd.ni_cnd.cn_cred = cred;
934 	nd.ni_cnd.cn_nameiop = CREATE;
935 	nd.ni_cnd.cn_flags = LOCKPARENT;
936 	if (error = nfs_namei(&nd, dfhp, len, nfsd->nd_slp, nam, &md, &dpos,
937 	    nfsd->nd_procp))
938 		goto out1;
939 	xp = nd.ni_vp;
940 	if (xp != NULL) {
941 		error = EEXIST;
942 		goto out;
943 	}
944 	xp = nd.ni_dvp;
945 	if (vp->v_mount != xp->v_mount)
946 		error = EXDEV;
947 out:
948 	if (!error) {
949 		nqsrv_getl(vp, NQL_WRITE);
950 		nqsrv_getl(xp, NQL_WRITE);
951 		error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
952 	} else {
953 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
954 		if (nd.ni_dvp == nd.ni_vp)
955 			vrele(nd.ni_dvp);
956 		else
957 			vput(nd.ni_dvp);
958 		if (nd.ni_vp)
959 			vrele(nd.ni_vp);
960 	}
961 out1:
962 	vrele(vp);
963 	nfsm_reply(0);
964 	nfsm_srvdone;
965 }
966 
967 /*
968  * nfs symbolic link service
969  */
970 nfsrv_symlink(nfsd, mrep, md, dpos, cred, nam, mrq)
971 	struct nfsd *nfsd;
972 	struct mbuf *mrep, *md;
973 	caddr_t dpos;
974 	struct ucred *cred;
975 	struct mbuf *nam, **mrq;
976 {
977 	struct vattr va;
978 	struct nameidata nd;
979 	register struct vattr *vap = &va;
980 	register u_long *tl;
981 	register long t1;
982 	struct nfsv2_sattr *sp;
983 	caddr_t bpos;
984 	struct uio io;
985 	struct iovec iv;
986 	int error = 0, rdonly, cache, len, len2;
987 	char *pathcp, *cp2;
988 	struct mbuf *mb, *mreq;
989 	nfsv2fh_t nfh;
990 	fhandle_t *fhp;
991 	u_quad_t frev;
992 
993 	pathcp = (char *)0;
994 	fhp = &nfh.fh_generic;
995 	nfsm_srvmtofh(fhp);
996 	nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
997 	nd.ni_cnd.cn_cred = cred;
998 	nd.ni_cnd.cn_nameiop = CREATE;
999 	nd.ni_cnd.cn_flags = LOCKPARENT;
1000 	if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
1001 	    nfsd->nd_procp))
1002 		goto out;
1003 	nfsm_strsiz(len2, NFS_MAXPATHLEN);
1004 	MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK);
1005 	iv.iov_base = pathcp;
1006 	iv.iov_len = len2;
1007 	io.uio_resid = len2;
1008 	io.uio_offset = 0;
1009 	io.uio_iov = &iv;
1010 	io.uio_iovcnt = 1;
1011 	io.uio_segflg = UIO_SYSSPACE;
1012 	io.uio_rw = UIO_READ;
1013 	io.uio_procp = (struct proc *)0;
1014 	nfsm_mtouio(&io, len2);
1015 	nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR);
1016 	*(pathcp + len2) = '\0';
1017 	if (nd.ni_vp) {
1018 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1019 		if (nd.ni_dvp == nd.ni_vp)
1020 			vrele(nd.ni_dvp);
1021 		else
1022 			vput(nd.ni_dvp);
1023 		vrele(nd.ni_vp);
1024 		error = EEXIST;
1025 		goto out;
1026 	}
1027 	VATTR_NULL(vap);
1028 	vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode);
1029 	nqsrv_getl(nd.ni_dvp, NQL_WRITE);
1030 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp);
1031 out:
1032 	if (pathcp)
1033 		FREE(pathcp, M_TEMP);
1034 	nfsm_reply(0);
1035 	return (error);
1036 nfsmout:
1037 	VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1038 	if (nd.ni_dvp == nd.ni_vp)
1039 		vrele(nd.ni_dvp);
1040 	else
1041 		vput(nd.ni_dvp);
1042 	if (nd.ni_vp)
1043 		vrele(nd.ni_vp);
1044 	if (pathcp)
1045 		FREE(pathcp, M_TEMP);
1046 	return (error);
1047 }
1048 
1049 /*
1050  * nfs mkdir service
1051  */
1052 nfsrv_mkdir(nfsd, mrep, md, dpos, cred, nam, mrq)
1053 	struct nfsd *nfsd;
1054 	struct mbuf *mrep, *md;
1055 	caddr_t dpos;
1056 	struct ucred *cred;
1057 	struct mbuf *nam, **mrq;
1058 {
1059 	struct vattr va;
1060 	register struct vattr *vap = &va;
1061 	register struct nfsv2_fattr *fp;
1062 	struct nameidata nd;
1063 	register caddr_t cp;
1064 	register u_long *tl;
1065 	register long t1;
1066 	caddr_t bpos;
1067 	int error = 0, rdonly, cache, len;
1068 	char *cp2;
1069 	struct mbuf *mb, *mb2, *mreq;
1070 	struct vnode *vp;
1071 	nfsv2fh_t nfh;
1072 	fhandle_t *fhp;
1073 	u_quad_t frev;
1074 
1075 	fhp = &nfh.fh_generic;
1076 	nfsm_srvmtofh(fhp);
1077 	nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
1078 	nd.ni_cnd.cn_cred = cred;
1079 	nd.ni_cnd.cn_nameiop = CREATE;
1080 	nd.ni_cnd.cn_flags = LOCKPARENT;
1081 	if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
1082 	    nfsd->nd_procp))
1083 		nfsm_reply(0);
1084 	nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
1085 	VATTR_NULL(vap);
1086 	vap->va_type = VDIR;
1087 	vap->va_mode = nfstov_mode(*tl++);
1088 	vp = nd.ni_vp;
1089 	if (vp != NULL) {
1090 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1091 		if (nd.ni_dvp == vp)
1092 			vrele(nd.ni_dvp);
1093 		else
1094 			vput(nd.ni_dvp);
1095 		vrele(vp);
1096 		error = EEXIST;
1097 		nfsm_reply(0);
1098 	}
1099 	nqsrv_getl(nd.ni_dvp, NQL_WRITE);
1100 	if (error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap))
1101 		nfsm_reply(0);
1102 	vp = nd.ni_vp;
1103 	bzero((caddr_t)fhp, sizeof(nfh));
1104 	fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1105 	if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
1106 		vput(vp);
1107 		nfsm_reply(0);
1108 	}
1109 	error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
1110 	vput(vp);
1111 	nfsm_reply(NFSX_FH+NFSX_FATTR);
1112 	nfsm_srvfhtom(fhp);
1113 	nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
1114 	nfsm_srvfillattr;
1115 	return (error);
1116 nfsmout:
1117 	VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1118 	if (nd.ni_dvp == nd.ni_vp)
1119 		vrele(nd.ni_dvp);
1120 	else
1121 		vput(nd.ni_dvp);
1122 	if (nd.ni_vp)
1123 		vrele(nd.ni_vp);
1124 	return (error);
1125 }
1126 
1127 /*
1128  * nfs rmdir service
1129  */
1130 nfsrv_rmdir(nfsd, mrep, md, dpos, cred, nam, mrq)
1131 	struct nfsd *nfsd;
1132 	struct mbuf *mrep, *md;
1133 	caddr_t dpos;
1134 	struct ucred *cred;
1135 	struct mbuf *nam, **mrq;
1136 {
1137 	register u_long *tl;
1138 	register long t1;
1139 	caddr_t bpos;
1140 	int error = 0, rdonly, cache, len;
1141 	char *cp2;
1142 	struct mbuf *mb, *mreq;
1143 	struct vnode *vp;
1144 	nfsv2fh_t nfh;
1145 	fhandle_t *fhp;
1146 	struct nameidata nd;
1147 	u_quad_t frev;
1148 
1149 	fhp = &nfh.fh_generic;
1150 	nfsm_srvmtofh(fhp);
1151 	nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
1152 	nd.ni_cnd.cn_cred = cred;
1153 	nd.ni_cnd.cn_nameiop = DELETE;
1154 	nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
1155 	if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
1156 	    nfsd->nd_procp))
1157 		nfsm_reply(0);
1158 	vp = nd.ni_vp;
1159 	if (vp->v_type != VDIR) {
1160 		error = ENOTDIR;
1161 		goto out;
1162 	}
1163 	/*
1164 	 * No rmdir "." please.
1165 	 */
1166 	if (nd.ni_dvp == vp) {
1167 		error = EINVAL;
1168 		goto out;
1169 	}
1170 	/*
1171 	 * The root of a mounted filesystem cannot be deleted.
1172 	 */
1173 	if (vp->v_flag & VROOT)
1174 		error = EBUSY;
1175 out:
1176 	if (!error) {
1177 		nqsrv_getl(nd.ni_dvp, NQL_WRITE);
1178 		nqsrv_getl(vp, NQL_WRITE);
1179 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1180 	} else {
1181 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1182 		if (nd.ni_dvp == nd.ni_vp)
1183 			vrele(nd.ni_dvp);
1184 		else
1185 			vput(nd.ni_dvp);
1186 		vput(vp);
1187 	}
1188 	nfsm_reply(0);
1189 	nfsm_srvdone;
1190 }
1191 
1192 /*
1193  * nfs readdir service
1194  * - mallocs what it thinks is enough to read
1195  *	count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
1196  * - calls VOP_READDIR()
1197  * - loops around building the reply
1198  *	if the output generated exceeds count break out of loop
1199  *	The nfsm_clget macro is used here so that the reply will be packed
1200  *	tightly in mbuf clusters.
1201  * - it only knows that it has encountered eof when the VOP_READDIR()
1202  *	reads nothing
1203  * - as such one readdir rpc will return eof false although you are there
1204  *	and then the next will return eof
1205  * - it trims out records with d_fileno == 0
1206  *	this doesn't matter for Unix clients, but they might confuse clients
1207  *	for other os'.
1208  * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
1209  *	than requested, but this may not apply to all filesystems. For
1210  *	example, client NFS does not { although it is never remote mounted
1211  *	anyhow }
1212  *     The alternate call nqnfsrv_readdirlook() does lookups as well.
1213  * PS: The NFS protocol spec. does not clarify what the "count" byte
1214  *	argument is a count of.. just name strings and file id's or the
1215  *	entire reply rpc or ...
1216  *	I tried just file name and id sizes and it confused the Sun client,
1217  *	so I am using the full rpc size now. The "paranoia.." comment refers
1218  *	to including the status longwords that are not a part of the dir.
1219  *	"entry" structures, but are in the rpc.
1220  */
1221 struct flrep {
1222 	u_long fl_cachable;
1223 	u_long fl_duration;
1224 	u_quad_t fl_frev;
1225 	nfsv2fh_t fl_nfh;
1226 	struct nfsv2_fattr fl_fattr;
1227 };
1228 
1229 nfsrv_readdir(nfsd, mrep, md, dpos, cred, nam, mrq)
1230 	struct nfsd *nfsd;
1231 	struct mbuf *mrep, *md;
1232 	caddr_t dpos;
1233 	struct ucred *cred;
1234 	struct mbuf *nam, **mrq;
1235 {
1236 	register char *bp, *be;
1237 	register struct mbuf *mp;
1238 	register struct dirent *dp;
1239 	register caddr_t cp;
1240 	register u_long *tl;
1241 	register long t1;
1242 	caddr_t bpos;
1243 	struct mbuf *mb, *mb2, *mreq, *mp2;
1244 	char *cpos, *cend, *cp2, *rbuf;
1245 	struct vnode *vp;
1246 	nfsv2fh_t nfh;
1247 	fhandle_t *fhp;
1248 	struct uio io;
1249 	struct iovec iv;
1250 	struct vattr va;
1251 	int len, nlen, rem, xfer, tsiz, i, error = 0;
1252 	int siz, cnt, fullsiz, eofflag, rdonly, cache;
1253 	u_quad_t frev;
1254 	u_long on;
1255 	off_t off, toff;
1256 
1257 	fhp = &nfh.fh_generic;
1258 	nfsm_srvmtofh(fhp);
1259 	nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
1260 	toff = fxdr_unsigned(off_t, *tl++);
1261 	off = (toff & ~(NFS_DIRBLKSIZ-1));
1262 	on = (toff & (NFS_DIRBLKSIZ-1));
1263 	cnt = fxdr_unsigned(int, *tl);
1264 	siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1));
1265 	if (cnt > NFS_MAXREADDIR)
1266 		siz = NFS_MAXREADDIR;
1267 	fullsiz = siz;
1268 	if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
1269 		nfsm_reply(0);
1270 	nqsrv_getl(vp, NQL_READ);
1271 	if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) {
1272 		vput(vp);
1273 		nfsm_reply(0);
1274 	}
1275 	VOP_UNLOCK(vp);
1276 	MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
1277 again:
1278 	iv.iov_base = rbuf;
1279 	iv.iov_len = fullsiz;
1280 	io.uio_iov = &iv;
1281 	io.uio_iovcnt = 1;
1282 	io.uio_offset = off;
1283 	io.uio_resid = fullsiz;
1284 	io.uio_segflg = UIO_SYSSPACE;
1285 	io.uio_rw = UIO_READ;
1286 	io.uio_procp = (struct proc *)0;
1287 	error = VOP_READDIR(vp, &io, cred, &eofflag);
1288 	off = io.uio_offset;
1289 	if (error) {
1290 		vrele(vp);
1291 		free((caddr_t)rbuf, M_TEMP);
1292 		nfsm_reply(0);
1293 	}
1294 	if (io.uio_resid) {
1295 		siz -= io.uio_resid;
1296 
1297 		/*
1298 		 * If nothing read, return eof
1299 		 * rpc reply
1300 		 */
1301 		if (siz == 0) {
1302 			vrele(vp);
1303 			nfsm_reply(2*NFSX_UNSIGNED);
1304 			nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
1305 			*tl++ = nfs_false;
1306 			*tl = nfs_true;
1307 			FREE((caddr_t)rbuf, M_TEMP);
1308 			return (0);
1309 		}
1310 	}
1311 
1312 	/*
1313 	 * Check for degenerate cases of nothing useful read.
1314 	 * If so go try again
1315 	 */
1316 	cpos = rbuf + on;
1317 	cend = rbuf + siz;
1318 	dp = (struct dirent *)cpos;
1319 	while (cpos < cend && dp->d_fileno == 0) {
1320 		cpos += dp->d_reclen;
1321 		dp = (struct dirent *)cpos;
1322 	}
1323 	if (cpos >= cend) {
1324 		toff = off;
1325 		siz = fullsiz;
1326 		on = 0;
1327 		goto again;
1328 	}
1329 
1330 	cpos = rbuf + on;
1331 	cend = rbuf + siz;
1332 	dp = (struct dirent *)cpos;
1333 	len = 3*NFSX_UNSIGNED;	/* paranoia, probably can be 0 */
1334 	nfsm_reply(siz);
1335 	mp = mp2 = mb;
1336 	bp = bpos;
1337 	be = bp + M_TRAILINGSPACE(mp);
1338 
1339 	/* Loop through the records and build reply */
1340 	while (cpos < cend) {
1341 		if (dp->d_fileno != 0) {
1342 			nlen = dp->d_namlen;
1343 			rem = nfsm_rndup(nlen)-nlen;
1344 			len += (4*NFSX_UNSIGNED + nlen + rem);
1345 			if (len > cnt) {
1346 				eofflag = 0;
1347 				break;
1348 			}
1349 			/*
1350 			 * Build the directory record xdr from
1351 			 * the dirent entry.
1352 			 */
1353 			nfsm_clget;
1354 			*tl = nfs_true;
1355 			bp += NFSX_UNSIGNED;
1356 			nfsm_clget;
1357 			*tl = txdr_unsigned(dp->d_fileno);
1358 			bp += NFSX_UNSIGNED;
1359 			nfsm_clget;
1360 			*tl = txdr_unsigned(nlen);
1361 			bp += NFSX_UNSIGNED;
1362 
1363 			/* And loop around copying the name */
1364 			xfer = nlen;
1365 			cp = dp->d_name;
1366 			while (xfer > 0) {
1367 				nfsm_clget;
1368 				if ((bp+xfer) > be)
1369 					tsiz = be-bp;
1370 				else
1371 					tsiz = xfer;
1372 				bcopy(cp, bp, tsiz);
1373 				bp += tsiz;
1374 				xfer -= tsiz;
1375 				if (xfer > 0)
1376 					cp += tsiz;
1377 			}
1378 			/* And null pad to a long boundary */
1379 			for (i = 0; i < rem; i++)
1380 				*bp++ = '\0';
1381 			nfsm_clget;
1382 
1383 			/* Finish off the record */
1384 			toff += dp->d_reclen;
1385 			*tl = txdr_unsigned(toff);
1386 			bp += NFSX_UNSIGNED;
1387 		} else
1388 			toff += dp->d_reclen;
1389 		cpos += dp->d_reclen;
1390 		dp = (struct dirent *)cpos;
1391 	}
1392 	vrele(vp);
1393 	nfsm_clget;
1394 	*tl = nfs_false;
1395 	bp += NFSX_UNSIGNED;
1396 	nfsm_clget;
1397 	if (eofflag)
1398 		*tl = nfs_true;
1399 	else
1400 		*tl = nfs_false;
1401 	bp += NFSX_UNSIGNED;
1402 	if (mp != mb) {
1403 		if (bp < be)
1404 			mp->m_len = bp - mtod(mp, caddr_t);
1405 	} else
1406 		mp->m_len += bp - bpos;
1407 	FREE(rbuf, M_TEMP);
1408 	nfsm_srvdone;
1409 }
1410 
1411 nqnfsrv_readdirlook(nfsd, mrep, md, dpos, cred, nam, mrq)
1412 	struct nfsd *nfsd;
1413 	struct mbuf *mrep, *md;
1414 	caddr_t dpos;
1415 	struct ucred *cred;
1416 	struct mbuf *nam, **mrq;
1417 {
1418 	register char *bp, *be;
1419 	register struct mbuf *mp;
1420 	register struct dirent *dp;
1421 	register caddr_t cp;
1422 	register u_long *tl;
1423 	register long t1;
1424 	caddr_t bpos;
1425 	struct mbuf *mb, *mb2, *mreq, *mp2;
1426 	char *cpos, *cend, *cp2, *rbuf;
1427 	struct vnode *vp, *nvp;
1428 	struct flrep fl;
1429 	struct ufid *ufp = (struct ufid *)&fl.fl_nfh.fh_generic.fh_fid;
1430 	struct mount *mntp;
1431 	nfsv2fh_t nfh;
1432 	fhandle_t *fhp;
1433 	struct uio io;
1434 	struct iovec iv;
1435 	struct vattr va, *vap = &va;
1436 	struct nfsv2_fattr *fp;
1437 	int len, nlen, rem, xfer, tsiz, i, error = 0, duration2, cache2;
1438 	int siz, cnt, fullsiz, eofflag, rdonly, cache;
1439 	u_quad_t frev, frev2;
1440 	u_long on;
1441 	off_t off, toff;
1442 
1443 	fhp = &nfh.fh_generic;
1444 	nfsm_srvmtofh(fhp);
1445 	nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED);
1446 	toff = fxdr_unsigned(off_t, *tl++);
1447 	off = (toff & ~(NFS_DIRBLKSIZ-1));
1448 	on = (toff & (NFS_DIRBLKSIZ-1));
1449 	cnt = fxdr_unsigned(int, *tl++);
1450 	duration2 = fxdr_unsigned(int, *tl);
1451 	siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1));
1452 	if (cnt > NFS_MAXREADDIR)
1453 		siz = NFS_MAXREADDIR;
1454 	fullsiz = siz;
1455 	if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
1456 		nfsm_reply(0);
1457 	nqsrv_getl(vp, NQL_READ);
1458 	if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) {
1459 		vput(vp);
1460 		nfsm_reply(0);
1461 	}
1462 	VOP_UNLOCK(vp);
1463 	MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
1464 again:
1465 	iv.iov_base = rbuf;
1466 	iv.iov_len = fullsiz;
1467 	io.uio_iov = &iv;
1468 	io.uio_iovcnt = 1;
1469 	io.uio_offset = off;
1470 	io.uio_resid = fullsiz;
1471 	io.uio_segflg = UIO_SYSSPACE;
1472 	io.uio_rw = UIO_READ;
1473 	io.uio_procp = (struct proc *)0;
1474 	error = VOP_READDIR(vp, &io, cred, &eofflag);
1475 	off = io.uio_offset;
1476 	if (error) {
1477 		vrele(vp);
1478 		free((caddr_t)rbuf, M_TEMP);
1479 		nfsm_reply(0);
1480 	}
1481 	if (io.uio_resid) {
1482 		siz -= io.uio_resid;
1483 
1484 		/*
1485 		 * If nothing read, return eof
1486 		 * rpc reply
1487 		 */
1488 		if (siz == 0) {
1489 			vrele(vp);
1490 			nfsm_reply(2*NFSX_UNSIGNED);
1491 			nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
1492 			*tl++ = nfs_false;
1493 			*tl = nfs_true;
1494 			FREE((caddr_t)rbuf, M_TEMP);
1495 			return (0);
1496 		}
1497 	}
1498 
1499 	/*
1500 	 * Check for degenerate cases of nothing useful read.
1501 	 * If so go try again
1502 	 */
1503 	cpos = rbuf + on;
1504 	cend = rbuf + siz;
1505 	dp = (struct dirent *)cpos;
1506 	while (cpos < cend && dp->d_fileno == 0) {
1507 		cpos += dp->d_reclen;
1508 		dp = (struct dirent *)cpos;
1509 	}
1510 	if (cpos >= cend) {
1511 		toff = off;
1512 		siz = fullsiz;
1513 		on = 0;
1514 		goto again;
1515 	}
1516 
1517 	cpos = rbuf + on;
1518 	cend = rbuf + siz;
1519 	dp = (struct dirent *)cpos;
1520 	len = 3*NFSX_UNSIGNED;	/* paranoia, probably can be 0 */
1521 	nfsm_reply(siz);
1522 	mp = mp2 = mb;
1523 	bp = bpos;
1524 	be = bp + M_TRAILINGSPACE(mp);
1525 	mntp = vp->v_mount;
1526 
1527 	/* Loop through the records and build reply */
1528 	while (cpos < cend) {
1529 		if (dp->d_fileno != 0) {
1530 			nlen = dp->d_namlen;
1531 			rem = nfsm_rndup(nlen)-nlen;
1532 
1533 			/*
1534 			 * For readdir_and_lookup get the vnode using
1535 			 * the file number.
1536 			 */
1537 			bzero((caddr_t)&fl.fl_nfh, sizeof (nfsv2fh_t));
1538 			ufp->ufid_len = sizeof (struct ufid);
1539 			ufp->ufid_ino = dp->d_fileno;
1540 			fl.fl_nfh.fh_generic.fh_fsid = mntp->mnt_stat.f_fsid;
1541 			if (VFS_FHTOVP(mntp, (struct fid *)ufp, 1, &nvp))
1542 				goto invalid;
1543 			(void) nqsrv_getlease(nvp, &duration2, NQL_READ, nfsd,
1544 				nam, &cache2, &frev2, cred);
1545 			fl.fl_duration = txdr_unsigned(duration2);
1546 			fl.fl_cachable = txdr_unsigned(cache2);
1547 			txdr_hyper(&frev2, &fl.fl_frev);
1548 			if (VOP_GETATTR(nvp, vap, cred, nfsd->nd_procp)) {
1549 				vput(nvp);
1550 				goto invalid;
1551 			}
1552 			vput(nvp);
1553 			fp = &fl.fl_fattr;
1554 			nfsm_srvfillattr;
1555 			len += (4*NFSX_UNSIGNED + nlen + rem + NFSX_FH
1556 				+ NFSX_FATTR);
1557 			if (len > cnt) {
1558 				eofflag = 0;
1559 				break;
1560 			}
1561 			/*
1562 			 * Build the directory record xdr from
1563 			 * the dirent entry.
1564 			 */
1565 			nfsm_clget;
1566 			*tl = nfs_true;
1567 			bp += NFSX_UNSIGNED;
1568 
1569 			/*
1570 			 * For readdir_and_lookup copy the stuff out.
1571 			 */
1572 			xfer = sizeof (struct flrep);
1573 			cp = (caddr_t)&fl;
1574 			while (xfer > 0) {
1575 				nfsm_clget;
1576 				if ((bp+xfer) > be)
1577 					tsiz = be-bp;
1578 				else
1579 					tsiz = xfer;
1580 				bcopy(cp, bp, tsiz);
1581 				bp += tsiz;
1582 				xfer -= tsiz;
1583 				if (xfer > 0)
1584 					cp += tsiz;
1585 			}
1586 			nfsm_clget;
1587 			*tl = txdr_unsigned(dp->d_fileno);
1588 			bp += NFSX_UNSIGNED;
1589 			nfsm_clget;
1590 			*tl = txdr_unsigned(nlen);
1591 			bp += NFSX_UNSIGNED;
1592 
1593 			/* And loop around copying the name */
1594 			xfer = nlen;
1595 			cp = dp->d_name;
1596 			while (xfer > 0) {
1597 				nfsm_clget;
1598 				if ((bp+xfer) > be)
1599 					tsiz = be-bp;
1600 				else
1601 					tsiz = xfer;
1602 				bcopy(cp, bp, tsiz);
1603 				bp += tsiz;
1604 				xfer -= tsiz;
1605 				if (xfer > 0)
1606 					cp += tsiz;
1607 			}
1608 			/* And null pad to a long boundary */
1609 			for (i = 0; i < rem; i++)
1610 				*bp++ = '\0';
1611 			nfsm_clget;
1612 
1613 			/* Finish off the record */
1614 			toff += dp->d_reclen;
1615 			*tl = txdr_unsigned(toff);
1616 			bp += NFSX_UNSIGNED;
1617 		} else
1618 invalid:
1619 			toff += dp->d_reclen;
1620 		cpos += dp->d_reclen;
1621 		dp = (struct dirent *)cpos;
1622 	}
1623 	vrele(vp);
1624 	nfsm_clget;
1625 	*tl = nfs_false;
1626 	bp += NFSX_UNSIGNED;
1627 	nfsm_clget;
1628 	if (eofflag)
1629 		*tl = nfs_true;
1630 	else
1631 		*tl = nfs_false;
1632 	bp += NFSX_UNSIGNED;
1633 	if (mp != mb) {
1634 		if (bp < be)
1635 			mp->m_len = bp - mtod(mp, caddr_t);
1636 	} else
1637 		mp->m_len += bp - bpos;
1638 	FREE(rbuf, M_TEMP);
1639 	nfsm_srvdone;
1640 }
1641 
1642 /*
1643  * nfs statfs service
1644  */
1645 nfsrv_statfs(nfsd, mrep, md, dpos, cred, nam, mrq)
1646 	struct nfsd *nfsd;
1647 	struct mbuf *mrep, *md;
1648 	caddr_t dpos;
1649 	struct ucred *cred;
1650 	struct mbuf *nam, **mrq;
1651 {
1652 	register struct statfs *sf;
1653 	register struct nfsv2_statfs *sfp;
1654 	register u_long *tl;
1655 	register long t1;
1656 	caddr_t bpos;
1657 	int error = 0, rdonly, cache;
1658 	char *cp2;
1659 	struct mbuf *mb, *mb2, *mreq;
1660 	struct vnode *vp;
1661 	nfsv2fh_t nfh;
1662 	fhandle_t *fhp;
1663 	struct statfs statfs;
1664 	u_quad_t frev;
1665 
1666 	fhp = &nfh.fh_generic;
1667 	nfsm_srvmtofh(fhp);
1668 	if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
1669 		nfsm_reply(0);
1670 	sf = &statfs;
1671 	error = VFS_STATFS(vp->v_mount, sf, nfsd->nd_procp);
1672 	vput(vp);
1673 	nfsm_reply(NFSX_STATFS);
1674 	nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS);
1675 	sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
1676 	sfp->sf_bsize = txdr_unsigned(sf->f_bsize);
1677 	sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
1678 	sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
1679 	sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
1680 	nfsm_srvdone;
1681 }
1682 
1683 /*
1684  * Null operation, used by clients to ping server
1685  */
1686 /* ARGSUSED */
1687 nfsrv_null(nfsd, mrep, md, dpos, cred, nam, mrq)
1688 	struct nfsd *nfsd;
1689 	struct mbuf *mrep, *md;
1690 	caddr_t dpos;
1691 	struct ucred *cred;
1692 	struct mbuf *nam, **mrq;
1693 {
1694 	caddr_t bpos;
1695 	int error = VNOVAL, cache;
1696 	struct mbuf *mb, *mreq;
1697 	u_quad_t frev;
1698 
1699 	nfsm_reply(0);
1700 	return (error);
1701 }
1702 
1703 /*
1704  * No operation, used for obsolete procedures
1705  */
1706 /* ARGSUSED */
1707 nfsrv_noop(nfsd, mrep, md, dpos, cred, nam, mrq)
1708 	struct nfsd *nfsd;
1709 	struct mbuf *mrep, *md;
1710 	caddr_t dpos;
1711 	struct ucred *cred;
1712 	struct mbuf *nam, **mrq;
1713 {
1714 	caddr_t bpos;
1715 	int error, cache;
1716 	struct mbuf *mb, *mreq;
1717 	u_quad_t frev;
1718 
1719 	if (nfsd->nd_repstat)
1720 		error = nfsd->nd_repstat;
1721 	else
1722 		error = EPROCUNAVAIL;
1723 	nfsm_reply(0);
1724 	return (error);
1725 }
1726 
1727 /*
1728  * Perform access checking for vnodes obtained from file handles that would
1729  * refer to files already opened by a Unix client. You cannot just use
1730  * vn_writechk() and VOP_ACCESS() for two reasons.
1731  * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
1732  * 2 - The owner is to be given access irrespective of mode bits so that
1733  *     processes that chmod after opening a file don't break. I don't like
1734  *     this because it opens a security hole, but since the nfs server opens
1735  *     a security hole the size of a barn door anyhow, what the heck.
1736  */
1737 nfsrv_access(vp, flags, cred, rdonly, p)
1738 	register struct vnode *vp;
1739 	int flags;
1740 	register struct ucred *cred;
1741 	int rdonly;
1742 	struct proc *p;
1743 {
1744 	struct vattr vattr;
1745 	int error;
1746 	if (flags & VWRITE) {
1747 		/* Just vn_writechk() changed to check rdonly */
1748 		/*
1749 		 * Disallow write attempts on read-only file systems;
1750 		 * unless the file is a socket or a block or character
1751 		 * device resident on the file system.
1752 		 */
1753 		if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
1754 			switch (vp->v_type) {
1755 			case VREG: case VDIR: case VLNK:
1756 				return (EROFS);
1757 			}
1758 		}
1759 		/*
1760 		 * If there's shared text associated with
1761 		 * the inode, try to free it up once.  If
1762 		 * we fail, we can't allow writing.
1763 		 */
1764 		if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp))
1765 			return (ETXTBSY);
1766 	}
1767 	if (error = VOP_GETATTR(vp, &vattr, cred, p))
1768 		return (error);
1769 	if ((error = VOP_ACCESS(vp, flags, cred, p)) &&
1770 	    cred->cr_uid != vattr.va_uid)
1771 		return (error);
1772 	return (0);
1773 }
1774