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