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