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