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