xref: /original-bsd/sys/nfs/nfs_serv.c (revision 7aab8220)
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 are permitted
9  * provided that the above copyright notice and this paragraph are
10  * duplicated in all such forms and that any documentation,
11  * advertising materials, and other materials related to such
12  * distribution and use acknowledge that the software was developed
13  * by the University of California, Berkeley.  The name of the
14  * University may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  *
20  *	@(#)nfs_serv.c	7.7 (Berkeley) 08/30/89
21  */
22 
23 /*
24  * nfs version 2 server calls to vnode ops
25  * - these routines generally have 3 phases
26  *   1 - break down and validate rpc request in mbuf list
27  *   2 - do the vnode ops for the request
28  *       (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
29  *   3 - build the rpc reply in an mbuf list
30  *   nb:
31  *	- do not mix the phases, since the nfsm_?? macros can return failures
32  *	  on mbuf exhaustion or similar and do not do any vrele() or vput()'s
33  *
34  *      - the nfsm_reply() macro generates an nfs rpc reply with the nfs
35  *	error number iff error != 0 whereas
36  *       nfsm_srverr simply drops the mbufs and gives up
37  *       (==> nfsm_srverr implies an error here at the server, usually mbuf
38  *	  exhaustion)
39  */
40 
41 #include "strings.h"
42 #include "time.h"
43 #include "param.h"
44 #include "mount.h"
45 #include "malloc.h"
46 #include "mbuf.h"
47 #include "file.h"
48 #include "user.h"
49 #include "../ufs/dir.h"
50 #include "vnode.h"
51 #include "uio.h"
52 #include "ucred.h"
53 #include "namei.h"
54 #include "errno.h"
55 #include "../ufs/inode.h"
56 #include "nfsv2.h"
57 #include "nfs.h"
58 #include "xdr_subs.h"
59 #include "nfsm_subs.h"
60 
61 /* Defs */
62 #define	TRUE	1
63 #define	FALSE	0
64 
65 /* Global vars */
66 extern u_long nfs_procids[NFS_NPROCS];
67 extern u_long nfs_xdrneg1;
68 extern u_long nfs_false, nfs_true;
69 nfstype nfs_type[VSOCK+1]={ NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, };
70 
71 /*
72  * nfs getattr service
73  */
74 nfsrv_getattr(mrep, md, dpos, cred, xid, mrq)
75 	struct mbuf **mrq;
76 	struct mbuf *mrep, *md;
77 	caddr_t dpos;
78 	struct ucred *cred;
79 	u_long xid;
80 {
81 	register struct nfsv2_fattr *fp;
82 	struct vattr va;
83 	register struct vattr *vap = &va;
84 	struct vnode *vp;
85 	nfsv2fh_t nfh;
86 	fhandle_t *fhp;
87 	nfsm_srvars;
88 
89 	fhp = &nfh.fh_generic;
90 	nfsm_srvmtofh(fhp);
91 	if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
92 		nfsm_reply(0);
93 	error = VOP_GETATTR(vp, vap, cred);
94 	vput(vp);
95 	nfsm_reply(NFSX_FATTR);
96 	nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
97 	fp->fa_type = vtonfs_type(vap->va_type);
98 	fp->fa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
99 	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
100 	fp->fa_uid = txdr_unsigned(vap->va_uid);
101 	fp->fa_gid = txdr_unsigned(vap->va_gid);
102 	fp->fa_size = txdr_unsigned(vap->va_size);
103 	fp->fa_blocksize = txdr_unsigned(vap->va_blocksize);
104 	fp->fa_rdev = txdr_unsigned(vap->va_rdev);
105 	fp->fa_blocks = txdr_unsigned(vap->va_bytes / vap->va_blocksize);
106 	fp->fa_fsid = txdr_unsigned(vap->va_fsid);
107 	fp->fa_fileid = txdr_unsigned(vap->va_fileid);
108 	txdr_time(&vap->va_atime, &fp->fa_atime);
109 	txdr_time(&vap->va_mtime, &fp->fa_mtime);
110 	txdr_time(&vap->va_ctime, &fp->fa_ctime);
111 	nfsm_srvdone;
112 }
113 
114 /*
115  * nfs setattr service
116  */
117 nfsrv_setattr(mrep, md, dpos, cred, xid, mrq)
118 	struct mbuf **mrq;
119 	struct mbuf *mrep, *md;
120 	caddr_t dpos;
121 	struct ucred *cred;
122 	u_long xid;
123 {
124 	struct vattr va;
125 	register struct vattr *vap = &va;
126 	register struct nfsv2_sattr *sp;
127 	register struct nfsv2_fattr *fp;
128 	struct vnode *vp;
129 	nfsv2fh_t nfh;
130 	fhandle_t *fhp;
131 	nfsm_srvars;
132 
133 	fhp = &nfh.fh_generic;
134 	nfsm_srvmtofh(fhp);
135 	nfsm_disect(sp, struct nfsv2_sattr *, NFSX_SATTR);
136 	if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
137 		nfsm_reply(0);
138 	if (error = nfsrv_access(vp, VWRITE, cred))
139 		goto out;
140 	vattr_null(vap);
141 	/*
142 	 * Nah nah nah nah na nah
143 	 * There is a bug in the Sun client that puts 0xffff in the mode
144 	 * field of sattr when it should put in 0xffffffff. The u_short
145 	 * doesn't sign extend.
146 	 * --> check the low order 2 bytes for 0xffff
147 	 */
148 	if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
149 		vap->va_mode = nfstov_mode(sp->sa_mode);
150 	if (sp->sa_uid != nfs_xdrneg1)
151 		vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
152 	if (sp->sa_gid != nfs_xdrneg1)
153 		vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
154 	if (sp->sa_size != nfs_xdrneg1) {
155 		vap->va_size = fxdr_unsigned(u_long, sp->sa_size);
156 	}
157 	if (sp->sa_atime.tv_sec != nfs_xdrneg1)
158 		fxdr_time(&sp->sa_atime, &vap->va_atime);
159 	if (sp->sa_mtime.tv_sec != nfs_xdrneg1)
160 		fxdr_time(&sp->sa_mtime, &vap->va_mtime);
161 	if (error = VOP_SETATTR(vp, vap, cred)) {
162 		vput(vp);
163 		nfsm_reply(0);
164 	}
165 	error = VOP_GETATTR(vp, vap, cred);
166 out:
167 	vput(vp);
168 	nfsm_reply(NFSX_FATTR);
169 	nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
170 	fp->fa_type = vtonfs_type(vap->va_type);
171 	fp->fa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
172 	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
173 	fp->fa_uid = txdr_unsigned(vap->va_uid);
174 	fp->fa_gid = txdr_unsigned(vap->va_gid);
175 	fp->fa_size = txdr_unsigned(vap->va_size);
176 	fp->fa_blocksize = txdr_unsigned(vap->va_blocksize);
177 	fp->fa_rdev = txdr_unsigned(vap->va_rdev);
178 	fp->fa_blocks = txdr_unsigned(vap->va_bytes / vap->va_blocksize);
179 	fp->fa_fsid = txdr_unsigned(vap->va_fsid);
180 	fp->fa_fileid = txdr_unsigned(vap->va_fileid);
181 	txdr_time(&vap->va_atime, &fp->fa_atime);
182 	txdr_time(&vap->va_mtime, &fp->fa_mtime);
183 	txdr_time(&vap->va_ctime, &fp->fa_ctime);
184 	nfsm_srvdone;
185 }
186 
187 /*
188  * nfs lookup rpc
189  */
190 nfsrv_lookup(mrep, md, dpos, cred, xid, mrq)
191 	struct mbuf **mrq;
192 	struct mbuf *mrep, *md;
193 	caddr_t dpos;
194 	struct ucred *cred;
195 	u_long xid;
196 {
197 	register struct nfsv2_fattr *fp;
198 	register struct nameidata *ndp = &u.u_nd;
199 	struct vnode *vp;
200 	nfsv2fh_t nfh;
201 	fhandle_t *fhp;
202 	nfsm_srvars;
203 	long len;
204 	struct vattr va, *vap = &va;
205 
206 	fhp = &nfh.fh_generic;
207 	nfsm_srvmtofh(fhp);
208 	nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
209 	ndp->ni_cred = cred;
210 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
211 	if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
212 		nfsm_reply(0);
213 	vp = ndp->ni_vp;
214 	bzero((caddr_t)fhp, sizeof(nfh));
215 	fhp->fh_fsid = vp->v_mount->m_fsid;
216 	if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
217 		vput(vp);
218 		nfsm_reply(0);
219 	}
220 	error = VOP_GETATTR(vp, vap, cred);
221 	vput(vp);
222 	nfsm_reply(NFSX_FH+NFSX_FATTR);
223 	nfsm_srvfhtom(fhp);
224 	nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
225 	fp->fa_type = vtonfs_type(vap->va_type);
226 	fp->fa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
227 	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
228 	fp->fa_uid = txdr_unsigned(vap->va_uid);
229 	fp->fa_gid = txdr_unsigned(vap->va_gid);
230 	fp->fa_size = txdr_unsigned(vap->va_size);
231 	fp->fa_blocksize = txdr_unsigned(vap->va_blocksize);
232 	fp->fa_rdev = txdr_unsigned(vap->va_rdev);
233 	fp->fa_blocks = txdr_unsigned(vap->va_bytes / vap->va_blocksize);
234 	fp->fa_fsid = txdr_unsigned(vap->va_fsid);
235 	fp->fa_fileid = txdr_unsigned(vap->va_fileid);
236 	txdr_time(&vap->va_atime, &fp->fa_atime);
237 	txdr_time(&vap->va_mtime, &fp->fa_mtime);
238 	txdr_time(&vap->va_ctime, &fp->fa_ctime);
239 	nfsm_srvdone;
240 }
241 
242 /*
243  * nfs readlink service
244  */
245 nfsrv_readlink(mrep, md, dpos, cred, xid, mrq)
246 	struct mbuf **mrq;
247 	struct mbuf *mrep, *md;
248 	caddr_t dpos;
249 	struct ucred *cred;
250 	long xid;
251 {
252 	struct iovec iv[NFS_MAXPATHLEN/MLEN+1];
253 	register struct iovec *ivp = iv;
254 	register struct mbuf *mp;
255 	nfsm_srvars;
256 	struct mbuf *mp2, *mp3;
257 	struct vnode *vp;
258 	nfsv2fh_t nfh;
259 	fhandle_t *fhp;
260 	struct uio io, *uiop = &io;
261 	int i, tlen, len;
262 
263 	fhp = &nfh.fh_generic;
264 	nfsm_srvmtofh(fhp);
265 	len = 0;
266 	i = 0;
267 	while (len < NFS_MAXPATHLEN) {
268 		MGET(mp, M_WAIT, MT_DATA);
269 		NFSMCLGET(mp, M_WAIT);
270 		mp->m_len = NFSMSIZ(mp);
271 		if (len == 0)
272 			mp3 = mp2 = mp;
273 		else
274 			mp2->m_next = mp;
275 		if ((len+mp->m_len) > NFS_MAXPATHLEN) {
276 			mp->m_len = NFS_MAXPATHLEN-len;
277 			len = NFS_MAXPATHLEN;
278 		} else
279 			len += mp->m_len;
280 		ivp->iov_base = mtod(mp, caddr_t);
281 		ivp->iov_len = mp->m_len;
282 		i++;
283 		ivp++;
284 	}
285 	uiop->uio_iov = iv;
286 	uiop->uio_iovcnt = i;
287 	uiop->uio_offset = 0;
288 	uiop->uio_resid = len;
289 	uiop->uio_rw = UIO_READ;
290 	uiop->uio_segflg = UIO_SYSSPACE;
291 	if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) {
292 		m_freem(mp3);
293 		nfsm_reply(0);
294 	}
295 	if (vp->v_type != VLNK) {
296 		error = EINVAL;
297 		goto out;
298 	}
299 	error = VOP_READLINK(vp, uiop, cred);
300 out:
301 	vput(vp);
302 	if (error)
303 		m_freem(mp3);
304 	nfsm_reply(NFSX_UNSIGNED);
305 	if (uiop->uio_resid > 0) {
306 		len -= uiop->uio_resid;
307 		tlen = nfsm_rndup(len);
308 		nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len);
309 	}
310 	nfsm_build(p, u_long *, NFSX_UNSIGNED);
311 	*p = txdr_unsigned(len);
312 	mb->m_next = mp3;
313 	nfsm_srvdone;
314 }
315 
316 /*
317  * nfs read service
318  */
319 nfsrv_read(mrep, md, dpos, cred, xid, mrq)
320 	struct mbuf **mrq;
321 	struct mbuf *mrep, *md;
322 	caddr_t dpos;
323 	struct ucred *cred;
324 	u_long xid;
325 {
326 	struct iovec iv[NFS_MAXDATA/MCLBYTES+1];
327 	register struct iovec *ivp = iv;
328 	register struct mbuf *mp;
329 	register struct nfsv2_fattr *fp;
330 	nfsm_srvars;
331 	struct mbuf *mp2, *mp3;
332 	struct vnode *vp;
333 	nfsv2fh_t nfh;
334 	fhandle_t *fhp;
335 	struct uio io, *uiop = &io;
336 	struct vattr va, *vap = &va;
337 	int i, tlen, cnt, len, nio, left;
338 	off_t off;
339 
340 	fhp = &nfh.fh_generic;
341 	nfsm_srvmtofh(fhp);
342 	nfsm_disect(p, u_long *, NFSX_UNSIGNED);
343 	off = fxdr_unsigned(off_t, *p);
344 	nfsm_srvstrsiz(cnt, NFS_MAXDATA);
345 	if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
346 		nfsm_reply(0);
347 	if (error = nfsrv_access(vp, VREAD | VEXEC, cred)) {
348 		vput(vp);
349 		nfsm_reply(0);
350 	}
351 	len = left = cnt;
352 	nio = (cnt+MCLBYTES-1)/MCLBYTES;
353 	uiop->uio_iov = ivp;
354 	uiop->uio_iovcnt = nio;
355 	uiop->uio_offset = off;
356 	uiop->uio_resid = cnt;
357 	uiop->uio_rw = UIO_READ;
358 	uiop->uio_segflg = UIO_SYSSPACE;
359 	for (i = 0; i < nio; i++) {
360 		MGET(mp, M_WAIT, MT_DATA);
361 		if (left > MLEN)
362 			NFSMCLGET(mp, M_WAIT);
363 		mp->m_len = (M_HASCL(mp)) ? MCLBYTES : MLEN;
364 		if (i == 0) {
365 			mp3 = mp2 = mp;
366 		} else {
367 			mp2->m_next = mp;
368 			mp2 = mp;
369 		}
370 		if (left > MLEN && !M_HASCL(mp)) {
371 			m_freem(mp3);
372 			vput(vp);
373 			nfsm_srverr;
374 		}
375 		ivp->iov_base = mtod(mp, caddr_t);
376 		if (left > mp->m_len) {
377 			ivp->iov_len = mp->m_len;
378 			left -= mp->m_len;
379 		} else {
380 			ivp->iov_len = mp->m_len = left;
381 			left = 0;
382 		}
383 		ivp++;
384 	}
385 	error = VOP_READ(vp, uiop, &off, IO_NODELOCKED, cred);
386 	if (error) {
387 		m_freem(mp3);
388 		vput(vp);
389 		nfsm_reply(0);
390 	}
391 	if (error = VOP_GETATTR(vp, vap, cred))
392 		m_freem(mp3);
393 	vput(vp);
394 	nfsm_reply(NFSX_FATTR+NFSX_UNSIGNED);
395 	nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
396 	fp->fa_type = vtonfs_type(vap->va_type);
397 	fp->fa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
398 	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
399 	fp->fa_uid = txdr_unsigned(vap->va_uid);
400 	fp->fa_gid = txdr_unsigned(vap->va_gid);
401 	fp->fa_size = txdr_unsigned(vap->va_size);
402 	fp->fa_blocksize = txdr_unsigned(vap->va_blocksize);
403 	fp->fa_rdev = txdr_unsigned(vap->va_rdev);
404 	fp->fa_blocks = txdr_unsigned(vap->va_bytes / vap->va_blocksize);
405 	fp->fa_fsid = txdr_unsigned(vap->va_fsid);
406 	fp->fa_fileid = txdr_unsigned(vap->va_fileid);
407 	txdr_time(&vap->va_atime, &fp->fa_atime);
408 	txdr_time(&vap->va_mtime, &fp->fa_mtime);
409 	txdr_time(&vap->va_ctime, &fp->fa_ctime);
410 	if (uiop->uio_resid > 0) {
411 		len -= uiop->uio_resid;
412 		if (len > 0) {
413 			tlen = nfsm_rndup(len);
414 			nfsm_adj(mp3, cnt-tlen, tlen-len);
415 		} else {
416 			m_freem(mp3);
417 			mp3 = (struct mbuf *)0;
418 		}
419 	}
420 	nfsm_build(p, u_long *, NFSX_UNSIGNED);
421 	*p = txdr_unsigned(len);
422 	mb->m_next = mp3;
423 	nfsm_srvdone;
424 }
425 
426 /*
427  * nfs write service
428  */
429 nfsrv_write(mrep, md, dpos, cred, xid, mrq)
430 	struct mbuf *mrep, *md, **mrq;
431 	caddr_t dpos;
432 	struct ucred *cred;
433 	long xid;
434 {
435 	register struct iovec *ivp;
436 	register struct mbuf *mp;
437 	register struct nfsv2_fattr *fp;
438 	struct iovec iv[MAX_IOVEC];
439 	struct vattr va;
440 	register struct vattr *vap = &va;
441 	nfsm_srvars;
442 	struct vnode *vp;
443 	nfsv2fh_t nfh;
444 	fhandle_t *fhp;
445 	struct uio io, *uiop = &io;
446 	off_t off;
447 	long siz, len, xfer;
448 
449 	fhp = &nfh.fh_generic;
450 	nfsm_srvmtofh(fhp);
451 	nfsm_disect(p, u_long *, 4*NFSX_UNSIGNED);
452 	off = fxdr_unsigned(off_t, *++p);
453 	p += 2;
454 	len = fxdr_unsigned(long, *p);
455 	if (len > NFS_MAXDATA || len <= 0) {
456 		error = EBADRPC;
457 		nfsm_reply(0);
458 	}
459 	if (dpos == (mtod(md, caddr_t)+md->m_len)) {
460 		mp = md->m_next;
461 		if (mp == NULL) {
462 			error = EBADRPC;
463 			nfsm_reply(0);
464 		}
465 	} else {
466 		mp = md;
467 		siz = dpos-mtod(mp, caddr_t);
468 		mp->m_len -= siz;
469 		NFSMADV(mp, siz);
470 	}
471 	if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
472 		nfsm_reply(0);
473 	if (error = nfsrv_access(vp, VWRITE, cred)) {
474 		vput(vp);
475 		nfsm_reply(0);
476 	}
477 	uiop->uio_resid = 0;
478 	uiop->uio_rw = UIO_WRITE;
479 	uiop->uio_segflg = UIO_SYSSPACE;
480 	/*
481 	 * Do up to MAX_IOVEC mbufs of write each iteration of the
482 	 * loop until done.
483 	 */
484 	while (len > 0 && uiop->uio_resid == 0) {
485 		ivp = iv;
486 		siz = 0;
487 		uiop->uio_iov = ivp;
488 		uiop->uio_iovcnt = 0;
489 		uiop->uio_offset = off;
490 		while (len > 0 && uiop->uio_iovcnt < MAX_IOVEC && mp != NULL) {
491 			ivp->iov_base = mtod(mp, caddr_t);
492 			if (len < mp->m_len)
493 				ivp->iov_len = xfer = len;
494 			else
495 				ivp->iov_len = xfer = mp->m_len;
496 #ifdef notdef
497 			/* Not Yet .. */
498 			if (M_HASCL(mp) && (((u_long)ivp->iov_base) & CLOFSET) == 0)
499 				ivp->iov_op = NULL;	/* what should it be ?? */
500 			else
501 				ivp->iov_op = NULL;
502 #endif
503 			uiop->uio_iovcnt++;
504 			ivp++;
505 			len -= xfer;
506 			siz += xfer;
507 			mp = mp->m_next;
508 		}
509 		if (len > 0 && mp == NULL) {
510 			error = EBADRPC;
511 			vput(vp);
512 			nfsm_reply(0);
513 		}
514 		uiop->uio_resid = siz;
515 		if (error = VOP_WRITE(vp, uiop, &off, IO_SYNC | IO_NODELOCKED,
516 			cred)) {
517 			vput(vp);
518 			nfsm_reply(0);
519 		}
520 	}
521 	error = VOP_GETATTR(vp, vap, cred);
522 	vput(vp);
523 	nfsm_reply(NFSX_FATTR);
524 	nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
525 	fp->fa_type = vtonfs_type(vap->va_type);
526 	fp->fa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
527 	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
528 	fp->fa_uid = txdr_unsigned(vap->va_uid);
529 	fp->fa_gid = txdr_unsigned(vap->va_gid);
530 	fp->fa_size = txdr_unsigned(vap->va_size);
531 	fp->fa_blocksize = txdr_unsigned(vap->va_blocksize);
532 	fp->fa_rdev = txdr_unsigned(vap->va_rdev);
533 	fp->fa_blocks = txdr_unsigned(vap->va_bytes / vap->va_blocksize);
534 	fp->fa_fsid = txdr_unsigned(vap->va_fsid);
535 	fp->fa_fileid = txdr_unsigned(vap->va_fileid);
536 	txdr_time(&vap->va_atime, &fp->fa_atime);
537 	txdr_time(&vap->va_mtime, &fp->fa_mtime);
538 	txdr_time(&vap->va_ctime, &fp->fa_ctime);
539 	nfsm_srvdone;
540 }
541 
542 /*
543  * nfs create service
544  * now does a truncate to 0 length via. setattr if it already exists
545  */
546 nfsrv_create(mrep, md, dpos, cred, xid, mrq)
547 	struct mbuf *mrep, *md, **mrq;
548 	caddr_t dpos;
549 	struct ucred *cred;
550 	long xid;
551 {
552 	register struct nfsv2_fattr *fp;
553 	struct vattr va;
554 	register struct vattr *vap = &va;
555 	register struct nameidata *ndp = &u.u_nd;
556 	nfsm_srvars;
557 	struct vnode *vp;
558 	nfsv2fh_t nfh;
559 	fhandle_t *fhp;
560 	long len;
561 
562 	ndp->ni_vp = ndp->ni_dvp = (struct vnode *)0;
563 	fhp = &nfh.fh_generic;
564 	nfsm_srvmtofh(fhp);
565 	nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
566 	ndp->ni_cred = cred;
567 	ndp->ni_nameiop = CREATE | LOCKPARENT | LOCKLEAF;
568 	if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
569 		nfsm_reply(0);
570 	vattr_null(vap);
571 	nfsm_disect(p, u_long *, NFSX_UNSIGNED);
572 	/*
573 	 * Iff doesn't exist, create it
574 	 * otherwise just truncate to 0 length
575 	 *   should I set the mode too ??
576 	 */
577 	if (ndp->ni_vp == NULL) {
578 		vap->va_type = VREG;
579 		vap->va_mode = nfstov_mode(*p++);
580 		if (error = VOP_CREATE(ndp, vap))
581 			nfsm_reply(0);
582 		vp = ndp->ni_vp;
583 	} else {
584 		vp = ndp->ni_vp;
585 		ndp->ni_vp = (struct vnode *)0;
586 		VOP_ABORTOP(ndp);
587 		vap->va_size = 0;
588 		if (error = VOP_SETATTR(vp, vap, cred))
589 			nfsm_reply(0);
590 	}
591 	bzero((caddr_t)fhp, sizeof(nfh));
592 	fhp->fh_fsid = vp->v_mount->m_fsid;
593 	if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
594 		vput(vp);
595 		nfsm_reply(0);
596 	}
597 	error = VOP_GETATTR(vp, vap, cred);
598 	vput(vp);
599 	nfsm_reply(NFSX_FH+NFSX_FATTR);
600 	nfsm_srvfhtom(fhp);
601 	nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
602 	fp->fa_type = vtonfs_type(vap->va_type);
603 	fp->fa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
604 	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
605 	fp->fa_uid = txdr_unsigned(vap->va_uid);
606 	fp->fa_gid = txdr_unsigned(vap->va_gid);
607 	fp->fa_size = txdr_unsigned(vap->va_size);
608 	fp->fa_blocksize = txdr_unsigned(vap->va_blocksize);
609 	fp->fa_rdev = txdr_unsigned(vap->va_rdev);
610 	fp->fa_blocks = txdr_unsigned(vap->va_bytes / vap->va_blocksize);
611 	fp->fa_fsid = txdr_unsigned(vap->va_fsid);
612 	fp->fa_fileid = txdr_unsigned(vap->va_fileid);
613 	txdr_time(&vap->va_atime, &fp->fa_atime);
614 	txdr_time(&vap->va_mtime, &fp->fa_mtime);
615 	txdr_time(&vap->va_ctime, &fp->fa_ctime);
616 	return (error);
617 nfsmout:
618 	VOP_ABORTOP(ndp);
619 	return (error);
620 }
621 
622 /*
623  * nfs remove service
624  */
625 nfsrv_remove(mrep, md, dpos, cred, xid, mrq)
626 	struct mbuf *mrep, *md, **mrq;
627 	caddr_t dpos;
628 	struct ucred *cred;
629 	long xid;
630 {
631 	register struct nameidata *ndp = &u.u_nd;
632 	nfsm_srvars;
633 	struct vnode *vp;
634 	nfsv2fh_t nfh;
635 	fhandle_t *fhp;
636 	long len;
637 
638 	fhp = &nfh.fh_generic;
639 	nfsm_srvmtofh(fhp);
640 	nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
641 	ndp->ni_cred = cred;
642 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
643 	if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
644 		nfsm_reply(0);
645 	vp = ndp->ni_vp;
646 	if (vp->v_type == VDIR &&
647 		(error = suser(cred, (short *)0)))
648 		goto out;
649 	/*
650 	 * Don't unlink a mounted file.
651 	 */
652 	if (vp->v_flag & VROOT) {
653 		error = EBUSY;
654 		goto out;
655 	}
656 	if (vp->v_flag & VTEXT)
657 		xrele(vp);	/* try once to free text */
658 out:
659 	if (error)
660 		VOP_ABORTOP(ndp);
661 	else
662 		error = VOP_REMOVE(ndp);
663 	nfsm_reply(0);
664 	nfsm_srvdone;
665 }
666 
667 /*
668  * nfs rename service
669  */
670 nfsrv_rename(mrep, md, dpos, cred, xid, mrq)
671 	struct mbuf *mrep, *md, **mrq;
672 	caddr_t dpos;
673 	struct ucred *cred;
674 	long xid;
675 {
676 	register struct nameidata *ndp;
677 	nfsm_srvars;
678 	struct nameidata tond;
679 	struct vnode *fvp, *tvp, *tdvp;
680 	nfsv2fh_t fnfh, tnfh;
681 	fhandle_t *ffhp, *tfhp;
682 	long len, len2;
683 	int rootflg = 0;
684 
685 	ndp = &u.u_nd;
686 	ndp->ni_vp = ndp->ni_dvp = (struct vnode *)0;
687 	ffhp = &fnfh.fh_generic;
688 	tfhp = &tnfh.fh_generic;
689 	nfsm_srvmtofh(ffhp);
690 	nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
691 	/*
692 	 * Remember if we are root so that we can reset cr_uid before
693 	 * the second nfs_namei() call
694 	 */
695 	if (cred->cr_uid == 0)
696 		rootflg++;
697 	ndp->ni_cred = cred;
698 	ndp->ni_nameiop = DELETE | WANTPARENT;
699 	if (error = nfs_namei(ndp, ffhp, len, &md, &dpos))
700 		nfsm_reply(0);
701 	fvp = ndp->ni_vp;
702 	nfsm_srvmtofh(tfhp);
703 	nfsm_srvstrsiz(len2, NFS_MAXNAMLEN);
704 	if (rootflg)
705 		cred->cr_uid = 0;
706 	nddup(ndp, &tond);
707 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
708 	error = nfs_namei(&tond, tfhp, len2, &md, &dpos);
709 	tdvp = tond.ni_dvp;
710 	tvp = tond.ni_vp;
711 	if (tvp != NULL) {
712 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
713 			error = EISDIR;
714 			goto out;
715 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
716 			error = ENOTDIR;
717 			goto out;
718 		}
719 	}
720 	if (error) {
721 		VOP_ABORTOP(ndp);
722 		goto out1;
723 	}
724 	if (fvp->v_mount != tdvp->v_mount) {
725 		error = EXDEV;
726 		goto out;
727 	}
728 	if (fvp == tdvp || fvp == tvp)
729 		error = EINVAL;
730 out:
731 	if (error) {
732 		VOP_ABORTOP(&tond);
733 		VOP_ABORTOP(ndp);
734 	} else {
735 		VREF(tond.ni_cdir);
736 		error = VOP_RENAME(ndp, &tond);
737 		vrele(tond.ni_cdir);
738 	}
739 out1:
740 	ndrele(ndp);
741 	nfsm_reply(0);
742 	return (error);
743 nfsmout:
744 	VOP_ABORTOP(ndp);
745 	return (error);
746 }
747 
748 /*
749  * nfs link service
750  */
751 nfsrv_link(mrep, md, dpos, cred, xid, mrq)
752 	struct mbuf *mrep, *md, **mrq;
753 	caddr_t dpos;
754 	struct ucred *cred;
755 	long xid;
756 {
757 	register struct nameidata *ndp = &u.u_nd;
758 	nfsm_srvars;
759 	struct vnode *vp, *xp;
760 	nfsv2fh_t nfh, dnfh;
761 	fhandle_t *fhp, *dfhp;
762 	long len;
763 
764 	fhp = &nfh.fh_generic;
765 	dfhp = &dnfh.fh_generic;
766 	nfsm_srvmtofh(fhp);
767 	nfsm_srvmtofh(dfhp);
768 	nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
769 	if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred))
770 		nfsm_reply(0);
771 	if (vp->v_type == VDIR && (error = suser(cred, NULL)))
772 		goto out1;
773 	ndp->ni_cred = cred;
774 	ndp->ni_nameiop = CREATE | LOCKPARENT;
775 	if (error = nfs_namei(ndp, dfhp, len, &md, &dpos))
776 		goto out1;
777 	xp = ndp->ni_vp;
778 	if (xp != NULL) {
779 		error = EEXIST;
780 		goto out;
781 	}
782 	xp = ndp->ni_dvp;
783 	if (vp->v_mount != xp->v_mount)
784 		error = EXDEV;
785 out:
786 	if (error)
787 		VOP_ABORTOP(ndp);
788 	else
789 		error = VOP_LINK(vp, ndp);
790 out1:
791 	vrele(vp);
792 	nfsm_reply(0);
793 	nfsm_srvdone;
794 }
795 
796 /*
797  * nfs symbolic link service
798  */
799 nfsrv_symlink(mrep, md, dpos, cred, xid, mrq)
800 	struct mbuf *mrep, *md, **mrq;
801 	caddr_t dpos;
802 	struct ucred *cred;
803 	long xid;
804 {
805 	struct vattr va;
806 	register struct nameidata *ndp = &u.u_nd;
807 	register struct vattr *vap = &va;
808 	nfsm_srvars;
809 	struct vnode *vp;
810 	nfsv2fh_t nfh;
811 	fhandle_t *fhp;
812 	long len, tlen, len2;
813 
814 	ndp->ni_vp = ndp->ni_dvp = (struct vnode *)0;
815 	fhp = &nfh.fh_generic;
816 	nfsm_srvmtofh(fhp);
817 	nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
818 	ndp->ni_cred = cred;
819 	ndp->ni_nameiop = CREATE | LOCKPARENT;
820 	if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
821 		goto out1;
822 	nfsm_srvstrsiz(len2, NFS_MAXPATHLEN);
823 	tlen = nfsm_rndup(len2);
824 	if (len2 == tlen) {
825 		nfsm_disect(cp2, caddr_t, tlen+NFSX_UNSIGNED);
826 		*(cp2+tlen) = '\0';
827 	} else {
828 		nfsm_disect(cp2, caddr_t, tlen);
829 	}
830 	vp = ndp->ni_vp;
831 	if (vp) {
832 		error = EEXIST;
833 		goto out;
834 	}
835 	vp = ndp->ni_dvp;
836 	vattr_null(vap);
837 	vap->va_mode = 0777;
838 out:
839 	if (error)
840 		VOP_ABORTOP(ndp);
841 	else
842 		error = VOP_SYMLINK(ndp, vap, cp2);
843 out1:
844 	nfsm_reply(0);
845 	return (error);
846 nfsmout:
847 	VOP_ABORTOP(ndp);
848 	return (error);
849 }
850 
851 /*
852  * nfs mkdir service
853  */
854 nfsrv_mkdir(mrep, md, dpos, cred, xid, mrq)
855 	struct mbuf *mrep, *md, **mrq;
856 	caddr_t dpos;
857 	struct ucred *cred;
858 	long xid;
859 {
860 	struct vattr va;
861 	register struct vattr *vap = &va;
862 	register struct nfsv2_fattr *fp;
863 	register struct nameidata *ndp = &u.u_nd;
864 	nfsm_srvars;
865 	struct vnode *vp;
866 	nfsv2fh_t nfh;
867 	fhandle_t *fhp;
868 	long len;
869 
870 	ndp->ni_vp = ndp->ni_dvp = (struct vnode *)0;
871 	fhp = &nfh.fh_generic;
872 	nfsm_srvmtofh(fhp);
873 	nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
874 	ndp->ni_cred = cred;
875 	ndp->ni_nameiop = CREATE | LOCKPARENT;
876 	if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
877 		nfsm_reply(0);
878 	nfsm_disect(p, u_long *, NFSX_UNSIGNED);
879 	vattr_null(vap);
880 	vap->va_type = VDIR;
881 	vap->va_mode = nfstov_mode(*p++);
882 	vp = ndp->ni_vp;
883 	if (vp != NULL) {
884 		VOP_ABORTOP(ndp);
885 		error = EEXIST;
886 		nfsm_reply(0);
887 	}
888 	if (error = VOP_MKDIR(ndp, vap))
889 		nfsm_reply(0);
890 	vp = ndp->ni_vp;
891 	bzero((caddr_t)fhp, sizeof(nfh));
892 	fhp->fh_fsid = vp->v_mount->m_fsid;
893 	if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
894 		vput(vp);
895 		nfsm_reply(0);
896 	}
897 	error = VOP_GETATTR(vp, vap, cred);
898 	vput(vp);
899 	nfsm_reply(NFSX_FH+NFSX_FATTR);
900 	nfsm_srvfhtom(fhp);
901 	nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR);
902 	fp->fa_type = vtonfs_type(vap->va_type);
903 	fp->fa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
904 	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
905 	fp->fa_uid = txdr_unsigned(vap->va_uid);
906 	fp->fa_gid = txdr_unsigned(vap->va_gid);
907 	fp->fa_size = txdr_unsigned(vap->va_size);
908 	fp->fa_blocksize = txdr_unsigned(vap->va_blocksize);
909 	fp->fa_rdev = txdr_unsigned(vap->va_rdev);
910 	fp->fa_blocks = txdr_unsigned(vap->va_bytes / vap->va_blocksize);
911 	fp->fa_fsid = txdr_unsigned(vap->va_fsid);
912 	fp->fa_fileid = txdr_unsigned(vap->va_fileid);
913 	txdr_time(&vap->va_atime, &fp->fa_atime);
914 	txdr_time(&vap->va_mtime, &fp->fa_mtime);
915 	txdr_time(&vap->va_ctime, &fp->fa_ctime);
916 	return (error);
917 nfsmout:
918 	VOP_ABORTOP(ndp);
919 	return (error);
920 }
921 
922 /*
923  * nfs rmdir service
924  */
925 nfsrv_rmdir(mrep, md, dpos, cred, xid, mrq)
926 	struct mbuf *mrep, *md, **mrq;
927 	caddr_t dpos;
928 	struct ucred *cred;
929 	long xid;
930 {
931 	register struct nameidata *ndp = &u.u_nd;
932 	nfsm_srvars;
933 	struct vnode *vp;
934 	nfsv2fh_t nfh;
935 	fhandle_t *fhp;
936 	long len;
937 
938 	fhp = &nfh.fh_generic;
939 	nfsm_srvmtofh(fhp);
940 	nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
941 	ndp->ni_cred = cred;
942 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
943 	if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
944 		nfsm_reply(0);
945 	vp = ndp->ni_vp;
946 	if (vp->v_type != VDIR) {
947 		error = ENOTDIR;
948 		goto out;
949 	}
950 	/*
951 	 * No rmdir "." please.
952 	 */
953 	if (ndp->ni_dvp == vp) {
954 		error = EINVAL;
955 		goto out;
956 	}
957 	/*
958 	 * Don't unlink a mounted file.
959 	 */
960 	if (vp->v_flag & VROOT)
961 		error = EBUSY;
962 out:
963 	if (error)
964 		VOP_ABORTOP(ndp);
965 	else
966 		error = VOP_RMDIR(ndp);
967 	nfsm_reply(0);
968 	nfsm_srvdone;
969 }
970 
971 /*
972  * nfs readdir service
973  * - mallocs what it thinks is enough to read
974  *	count rounded up to a multiple of DIRBLKSIZ <= MAX_READDIR
975  * - calls VOP_READDIR()
976  * - loops arround building the reply
977  *	if the output generated exceeds count break out of loop
978  *	The nfsm_clget macro is used here so that the reply will be packed
979  *	tightly in mbuf clusters.
980  * - it only knows that it has encountered eof when the VOP_READDIR()
981  *	reads nothing
982  * - as such one readdir rpc will return eof false although you are there
983  *	and then the next will return eof
984  * - it trims out records with d_ino == 0
985  *	this doesn't matter for Unix clients, but they might confuse clients
986  *	for other os'.
987  * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
988  *	than requested, but this may not apply to all filesystems. For
989  *	example, client NFS does not { although it is never remote mounted
990  *	anyhow }
991  * PS: The NFS protocol spec. does not clarify what the "count" byte
992  *	argument is a count of.. just name strings and file id's or the
993  *	entire reply rpc or ...
994  *	I tried just file name and id sizes and it confused the Sun client,
995  *	so I am using the full rpc size now. The "paranoia.." comment refers
996  *	to including the status longwords that are not a part of the dir.
997  *	"entry" structures, but are in the rpc.
998  */
999 nfsrv_readdir(mrep, md, dpos, cred, xid, mrq)
1000 	struct mbuf **mrq;
1001 	struct mbuf *mrep, *md;
1002 	caddr_t dpos;
1003 	struct ucred *cred;
1004 	u_long xid;
1005 {
1006 	register char *bp, *be;
1007 	register struct mbuf *mp;
1008 	register struct direct *dp;
1009 	nfsm_srvars;
1010 	char *cpos, *cend;
1011 	int len, nlen, rem, xfer, tsiz, i;
1012 	struct vnode *vp;
1013 	struct mbuf *mp2, *mp3;
1014 	nfsv2fh_t nfh;
1015 	fhandle_t *fhp;
1016 	struct uio io;
1017 	struct iovec iv;
1018 	int siz, cnt, fullsiz;
1019 	u_long on;
1020 	char *rbuf;
1021 	off_t off, toff;
1022 
1023 	fhp = &nfh.fh_generic;
1024 	nfsm_srvmtofh(fhp);
1025 	nfsm_disect(p, u_long *, 2*NFSX_UNSIGNED);
1026 	toff = fxdr_unsigned(off_t, *p++);
1027 	off = (toff & ~(DIRBLKSIZ-1));
1028 	on = (toff & (DIRBLKSIZ-1));
1029 	cnt = fxdr_unsigned(int, *p);
1030 	siz = ((cnt+DIRBLKSIZ) & ~(DIRBLKSIZ-1));
1031 	if (cnt > MAX_READDIR)
1032 		siz = MAX_READDIR;
1033 	fullsiz = siz;
1034 	if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
1035 		nfsm_reply(0);
1036 	if (error = nfsrv_access(vp, VEXEC, cred)) {
1037 		vput(vp);
1038 		nfsm_reply(0);
1039 	}
1040 	VOP_UNLOCK(vp);
1041 	MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
1042 again:
1043 	iv.iov_base = rbuf;
1044 	iv.iov_len = fullsiz;
1045 	io.uio_iov = &iv;
1046 	io.uio_iovcnt = 1;
1047 	io.uio_offset = off;
1048 	io.uio_resid = fullsiz;
1049 	io.uio_segflg = UIO_SYSSPACE;
1050 	io.uio_rw = UIO_READ;
1051 	error = VOP_READDIR(vp, &io, &off, cred);
1052 	if (error) {
1053 		vrele(vp);
1054 		free((caddr_t)rbuf, M_TEMP);
1055 		nfsm_reply(0);
1056 	}
1057 	if (io.uio_resid) {
1058 		siz -= io.uio_resid;
1059 
1060 		/*
1061 		 * If nothing read, return eof
1062 		 * rpc reply
1063 		 */
1064 		if (siz == 0) {
1065 			vrele(vp);
1066 			nfsm_reply(2*NFSX_UNSIGNED);
1067 			nfsm_build(p, u_long *, 2*NFSX_UNSIGNED);
1068 			*p++ = nfs_false;
1069 			*p = nfs_true;
1070 			FREE((caddr_t)rbuf, M_TEMP);
1071 			return (0);
1072 		}
1073 	}
1074 	cpos = rbuf+on;
1075 	cend = rbuf+siz;
1076 	dp = (struct direct *)cpos;
1077 	/*
1078 	 * Check for degenerate cases of nothing useful read.
1079 	 * If so  go try again
1080 	 */
1081 	if (cpos >= cend || (dp->d_ino == 0 && (cpos+dp->d_reclen) >= cend)) {
1082 		toff = off;
1083 		siz = fullsiz;
1084 		on = 0;
1085 		goto again;
1086 	}
1087 	vrele(vp);
1088 	len = 3*NFSX_UNSIGNED;	/* paranoia, probably can be 0 */
1089 	bp = be = (caddr_t)0;
1090 	mp3 = (struct mbuf *)0;
1091 	nfsm_reply(siz);
1092 
1093 	/* Loop through the records and build reply */
1094 	while (cpos < cend) {
1095 		if (dp->d_ino != 0) {
1096 			nlen = dp->d_namlen;
1097 			rem = nfsm_rndup(nlen)-nlen;
1098 
1099 			/*
1100 			 * As noted above, the NFS spec. is not clear about what
1101 			 * should be included in "count" as totalled up here in
1102 			 * "len".
1103 			 */
1104 			len += (4*NFSX_UNSIGNED+nlen+rem);
1105 			if (len > cnt)
1106 				break;
1107 
1108 			/* Build the directory record xdr from the direct entry */
1109 			nfsm_clget;
1110 			*p = nfs_true;
1111 			bp += NFSX_UNSIGNED;
1112 			nfsm_clget;
1113 			*p = txdr_unsigned(dp->d_ino);
1114 			bp += NFSX_UNSIGNED;
1115 			nfsm_clget;
1116 			*p = txdr_unsigned(nlen);
1117 			bp += NFSX_UNSIGNED;
1118 
1119 			/* And loop arround copying the name */
1120 			xfer = nlen;
1121 			cp = dp->d_name;
1122 			while (xfer > 0) {
1123 				nfsm_clget;
1124 				if ((bp+xfer) > be)
1125 					tsiz = be-bp;
1126 				else
1127 					tsiz = xfer;
1128 				bcopy(cp, bp, tsiz);
1129 				bp += tsiz;
1130 				xfer -= tsiz;
1131 				if (xfer > 0)
1132 					cp += tsiz;
1133 			}
1134 			/* And null pad to a long boundary */
1135 			for (i = 0; i < rem; i++)
1136 				*bp++ = '\0';
1137 			nfsm_clget;
1138 
1139 			/* Finish off the record */
1140 			toff += dp->d_reclen;
1141 			*p = txdr_unsigned(toff);
1142 			bp += NFSX_UNSIGNED;
1143 		} else
1144 			toff += dp->d_reclen;
1145 		cpos += dp->d_reclen;
1146 		dp = (struct direct *)cpos;
1147 	}
1148 	nfsm_clget;
1149 	*p = nfs_false;
1150 	bp += NFSX_UNSIGNED;
1151 	nfsm_clget;
1152 	*p = nfs_false;
1153 	bp += NFSX_UNSIGNED;
1154 	if (bp < be)
1155 		mp->m_len = bp-mtod(mp, caddr_t);
1156 	mb->m_next = mp3;
1157 	FREE(rbuf, M_TEMP);
1158 	nfsm_srvdone;
1159 }
1160 
1161 /*
1162  * nfs statfs service
1163  */
1164 nfsrv_statfs(mrep, md, dpos, cred, xid, mrq)
1165 	struct mbuf **mrq;
1166 	struct mbuf *mrep, *md;
1167 	caddr_t dpos;
1168 	struct ucred *cred;
1169 	u_long xid;
1170 {
1171 	register struct statfs *sf;
1172 	register struct nfsv2_statfs *sfp;
1173 	nfsm_srvars;
1174 	struct vnode *vp;
1175 	nfsv2fh_t nfh;
1176 	fhandle_t *fhp;
1177 	struct statfs statfs;
1178 
1179 	fhp = &nfh.fh_generic;
1180 	nfsm_srvmtofh(fhp);
1181 	if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
1182 		nfsm_reply(0);
1183 	sf = &statfs;
1184 	error = VFS_STATFS(vp->v_mount, sf);
1185 	vput(vp);
1186 	nfsm_reply(NFSX_STATFS);
1187 	nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS);
1188 	sfp->sf_tsize = txdr_unsigned(NFS_MAXDATA);
1189 	sfp->sf_bsize = txdr_unsigned(sf->f_fsize);
1190 	sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
1191 	sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
1192 	sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
1193 	nfsm_srvdone;
1194 }
1195 
1196 /*
1197  * Null operation, used by clients to ping server
1198  */
1199 nfsrv_null(mrep, md, dpos, cred, xid, mrq)
1200 	struct mbuf **mrq;
1201 	struct mbuf *mrep, *md;
1202 	caddr_t dpos;
1203 	struct ucred *cred;
1204 	u_long xid;
1205 {
1206 	nfsm_srvars;
1207 
1208 	error = VNOVAL;
1209 	nfsm_reply(0);
1210 	nfsm_srvdone;
1211 }
1212 
1213 /*
1214  * No operation, used for obsolete procedures
1215  */
1216 nfsrv_noop(mrep, md, dpos, cred, xid, mrq)
1217 	struct mbuf **mrq;
1218 	struct mbuf *mrep, *md;
1219 	caddr_t dpos;
1220 	struct ucred *cred;
1221 	u_long xid;
1222 {
1223 	nfsm_srvars;
1224 
1225 	error = EPROCUNAVAIL;
1226 	nfsm_reply(0);
1227 	nfsm_srvdone;
1228 }
1229 
1230 /*
1231  * Perform access checking for vnodes obtained from file handles that would
1232  * refer to files already opened by a Unix client. You cannot just use
1233  * vn_writechk() and VOP_ACCESS() for two reasons.
1234  * 1 - You must check for M_EXRDONLY as well as M_RDONLY for the write case
1235  * 2 - The owner is to be given access irrespective of mode bits so that
1236  *     processes that chmod after opening a file don't break. I don't like
1237  *     this because it opens a security hole, but since the nfs server opens
1238  *     a security hole the size of a barn door anyhow, what the heck.
1239  */
1240 nfsrv_access(vp, flags, cred)
1241 	register struct vnode *vp;
1242 	int flags;
1243 	register struct ucred *cred;
1244 {
1245 	struct vattr vattr;
1246 	int error;
1247 	if (flags & VWRITE) {
1248 		/* Just vn_writechk() changed to check M_EXRDONLY */
1249 		/*
1250 		 * Disallow write attempts on read-only file systems;
1251 		 * unless the file is a socket or a block or character
1252 		 * device resident on the file system.
1253 		 */
1254 		if ((vp->v_mount->m_flag & (M_RDONLY | M_EXRDONLY)) &&
1255 			vp->v_type != VCHR &&
1256 			vp->v_type != VBLK &&
1257 			vp->v_type != VSOCK)
1258 				return (EROFS);
1259 		/*
1260 		 * If there's shared text associated with
1261 		 * the inode, try to free it up once.  If
1262 		 * we fail, we can't allow writing.
1263 		 */
1264 		if (vp->v_flag & VTEXT)
1265 			xrele(vp);
1266 		if (vp->v_flag & VTEXT)
1267 			return (ETXTBSY);
1268 		if (error = VOP_GETATTR(vp, &vattr, cred))
1269 			return (error);
1270 		if (cred->cr_uid == vattr.va_uid)
1271 			return (0);
1272 	} else {
1273 		if (error = VOP_GETATTR(vp, &vattr, cred))
1274 			return (error);
1275 		if (cred->cr_uid == vattr.va_uid)
1276 			return (0);
1277 	}
1278 	return (VOP_ACCESS(vp, flags, cred));
1279 }
1280