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