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