nfs_serv.c revision 1.15 1 /*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. 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 8.3 (Berkeley) 1/12/94
37 * $Id: nfs_serv.c,v 1.15 1994/06/08 11:36:55 mycroft 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 <sys/param.h>
59 #include <sys/systm.h>
60 #include <sys/proc.h>
61 #include <sys/file.h>
62 #include <sys/namei.h>
63 #include <sys/vnode.h>
64 #include <sys/mount.h>
65 #include <sys/mbuf.h>
66 #include <sys/dirent.h>
67 #include <sys/stat.h>
68
69 #include <vm/vm.h>
70
71 #include <nfs/nfsv2.h>
72 #include <nfs/rpcv2.h>
73 #include <nfs/nfs.h>
74 #include <nfs/xdr_subs.h>
75 #include <nfs/nfsm_subs.h>
76 #include <nfs/nqnfs.h>
77
78 /* Defs */
79 #define TRUE 1
80 #define FALSE 0
81
82 /* Global vars */
83 extern u_long nfs_procids[NFS_NPROCS];
84 extern u_long nfs_xdrneg1;
85 extern u_long nfs_false, nfs_true;
86 nfstype nfs_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
87 NFCHR, NFNON };
88
89 /*
90 * nqnfs access service
91 */
92 nqnfsrv_access(nfsd, mrep, md, dpos, cred, nam, mrq)
93 struct nfsd *nfsd;
94 struct mbuf *mrep, *md;
95 caddr_t dpos;
96 struct ucred *cred;
97 struct mbuf *nam, **mrq;
98 {
99 struct vnode *vp;
100 nfsv2fh_t nfh;
101 fhandle_t *fhp;
102 register u_long *tl;
103 register long t1;
104 caddr_t bpos;
105 int error = 0, rdonly, cache, mode = 0;
106 char *cp2;
107 struct mbuf *mb, *mreq;
108 u_quad_t frev;
109
110 fhp = &nfh.fh_generic;
111 nfsm_srvmtofh(fhp);
112 nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
113 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
114 nfsm_reply(0);
115 if (*tl++ == nfs_true)
116 mode |= VREAD;
117 if (*tl++ == nfs_true)
118 mode |= VWRITE;
119 if (*tl == nfs_true)
120 mode |= VEXEC;
121 error = nfsrv_access(vp, mode, cred, rdonly, nfsd->nd_procp);
122 vput(vp);
123 nfsm_reply(0);
124 nfsm_srvdone;
125 }
126
127 /*
128 * nfs getattr service
129 */
130 nfsrv_getattr(nfsd, mrep, md, dpos, cred, nam, mrq)
131 struct nfsd *nfsd;
132 struct mbuf *mrep, *md;
133 caddr_t dpos;
134 struct ucred *cred;
135 struct mbuf *nam, **mrq;
136 {
137 register struct nfsv2_fattr *fp;
138 struct vattr va;
139 register struct vattr *vap = &va;
140 struct vnode *vp;
141 nfsv2fh_t nfh;
142 fhandle_t *fhp;
143 register u_long *tl;
144 register long t1;
145 caddr_t bpos;
146 int error = 0, rdonly, cache;
147 char *cp2;
148 struct mbuf *mb, *mb2, *mreq;
149 u_quad_t frev;
150
151 fhp = &nfh.fh_generic;
152 nfsm_srvmtofh(fhp);
153 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
154 nfsm_reply(0);
155 nqsrv_getl(vp, NQL_READ);
156 error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
157 vput(vp);
158 nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
159 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
160 nfsm_srvfillattr;
161 nfsm_srvdone;
162 }
163
164 /*
165 * nfs setattr service
166 */
167 nfsrv_setattr(nfsd, mrep, md, dpos, cred, nam, mrq)
168 struct nfsd *nfsd;
169 struct mbuf *mrep, *md;
170 caddr_t dpos;
171 struct ucred *cred;
172 struct mbuf *nam, **mrq;
173 {
174 struct vattr va;
175 register struct vattr *vap = &va;
176 register struct nfsv2_sattr *sp;
177 register struct nfsv2_fattr *fp;
178 struct vnode *vp;
179 nfsv2fh_t nfh;
180 fhandle_t *fhp;
181 register u_long *tl;
182 register long t1;
183 caddr_t bpos;
184 int error = 0, rdonly, cache;
185 char *cp2;
186 struct mbuf *mb, *mb2, *mreq;
187 u_quad_t frev, frev2;
188
189 fhp = &nfh.fh_generic;
190 nfsm_srvmtofh(fhp);
191 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL));
192 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
193 nfsm_reply(0);
194 nqsrv_getl(vp, NQL_WRITE);
195 VATTR_NULL(vap);
196 /*
197 * Nah nah nah nah na nah
198 * There is a bug in the Sun client that puts 0xffff in the mode
199 * field of sattr when it should put in 0xffffffff. The u_short
200 * doesn't sign extend.
201 * --> check the low order 2 bytes for 0xffff
202 */
203 if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
204 vap->va_mode = nfstov_mode(sp->sa_mode);
205 if (sp->sa_uid != nfs_xdrneg1)
206 vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
207 if (sp->sa_gid != nfs_xdrneg1)
208 vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
209 if (nfsd->nd_nqlflag == NQL_NOVAL) {
210 if (sp->sa_nfssize != nfs_xdrneg1)
211 vap->va_size = fxdr_unsigned(u_quad_t, sp->sa_nfssize);
212 if (sp->sa_nfsatime.nfs_sec != nfs_xdrneg1) {
213 #ifdef notyet
214 fxdr_nfstime(&sp->sa_nfsatime, &vap->va_atime);
215 #else
216 vap->va_atime.ts_sec =
217 fxdr_unsigned(long, sp->sa_nfsatime.nfs_sec);
218 vap->va_atime.ts_nsec = 0;
219 #endif
220 }
221 if (sp->sa_nfsmtime.nfs_sec != nfs_xdrneg1)
222 fxdr_nfstime(&sp->sa_nfsmtime, &vap->va_mtime);
223 } else {
224 fxdr_hyper(&sp->sa_nqsize, &vap->va_size);
225 fxdr_nqtime(&sp->sa_nqatime, &vap->va_atime);
226 fxdr_nqtime(&sp->sa_nqmtime, &vap->va_mtime);
227 vap->va_flags = fxdr_unsigned(u_long, sp->sa_nqflags);
228 }
229
230 /*
231 * If the size is being changed write acces is required, otherwise
232 * just check for a read only file system.
233 */
234 if (vap->va_size == ((u_quad_t)((quad_t) -1))) {
235 if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
236 error = EROFS;
237 goto out;
238 }
239 } else {
240 if (vp->v_type == VDIR) {
241 error = EISDIR;
242 goto out;
243 } else if (error = nfsrv_access(vp, VWRITE, cred, rdonly,
244 nfsd->nd_procp))
245 goto out;
246 }
247 if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) {
248 vput(vp);
249 nfsm_reply(0);
250 }
251 error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
252 out:
253 vput(vp);
254 nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL) + 2*NFSX_UNSIGNED);
255 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
256 nfsm_srvfillattr;
257 if (nfsd->nd_nqlflag != NQL_NOVAL) {
258 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
259 txdr_hyper(&frev2, tl);
260 }
261 nfsm_srvdone;
262 }
263
264 /*
265 * nfs lookup rpc
266 */
267 nfsrv_lookup(nfsd, mrep, md, dpos, cred, nam, mrq)
268 struct nfsd *nfsd;
269 struct mbuf *mrep, *md;
270 caddr_t dpos;
271 struct ucred *cred;
272 struct mbuf *nam, **mrq;
273 {
274 register struct nfsv2_fattr *fp;
275 struct nameidata nd;
276 struct vnode *vp;
277 nfsv2fh_t nfh;
278 fhandle_t *fhp;
279 register caddr_t cp;
280 register u_long *tl;
281 register long t1;
282 caddr_t bpos;
283 int error = 0, cache, duration2, cache2, len;
284 char *cp2;
285 struct mbuf *mb, *mb2, *mreq;
286 struct vattr va, *vap = &va;
287 u_quad_t frev, frev2;
288
289 fhp = &nfh.fh_generic;
290 duration2 = 0;
291 if (nfsd->nd_nqlflag != NQL_NOVAL) {
292 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
293 duration2 = fxdr_unsigned(int, *tl);
294 }
295 nfsm_srvmtofh(fhp);
296 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
297 nd.ni_cnd.cn_cred = cred;
298 nd.ni_cnd.cn_nameiop = LOOKUP;
299 nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART;
300 if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
301 nfsd->nd_procp))
302 nfsm_reply(0);
303 nqsrv_getl(nd.ni_startdir, NQL_READ);
304 vrele(nd.ni_startdir);
305 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
306 vp = nd.ni_vp;
307 bzero((caddr_t)fhp, sizeof(nfh));
308 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
309 if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
310 vput(vp);
311 nfsm_reply(0);
312 }
313 if (duration2)
314 (void) nqsrv_getlease(vp, &duration2, NQL_READ, nfsd,
315 nam, &cache2, &frev2, cred);
316 error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
317 vput(vp);
318 nfsm_reply(NFSX_FH + NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL) + 5*NFSX_UNSIGNED);
319 if (nfsd->nd_nqlflag != NQL_NOVAL) {
320 if (duration2) {
321 nfsm_build(tl, u_long *, 5*NFSX_UNSIGNED);
322 *tl++ = txdr_unsigned(NQL_READ);
323 *tl++ = txdr_unsigned(cache2);
324 *tl++ = txdr_unsigned(duration2);
325 txdr_hyper(&frev2, tl);
326 } else {
327 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
328 *tl = 0;
329 }
330 }
331 nfsm_srvfhtom(fhp);
332 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
333 nfsm_srvfillattr;
334 nfsm_srvdone;
335 }
336
337 /*
338 * nfs readlink service
339 */
340 nfsrv_readlink(nfsd, mrep, md, dpos, cred, nam, mrq)
341 struct nfsd *nfsd;
342 struct mbuf *mrep, *md;
343 caddr_t dpos;
344 struct ucred *cred;
345 struct mbuf *nam, **mrq;
346 {
347 struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
348 register struct iovec *ivp = iv;
349 register struct mbuf *mp;
350 register u_long *tl;
351 register long t1;
352 caddr_t bpos;
353 int error = 0, rdonly, cache, i, tlen, len;
354 char *cp2;
355 struct mbuf *mb, *mb2, *mp2, *mp3, *mreq;
356 struct vnode *vp;
357 nfsv2fh_t nfh;
358 fhandle_t *fhp;
359 struct uio io, *uiop = &io;
360 u_quad_t frev;
361
362 fhp = &nfh.fh_generic;
363 nfsm_srvmtofh(fhp);
364 len = 0;
365 i = 0;
366 while (len < NFS_MAXPATHLEN) {
367 MGET(mp, M_WAIT, MT_DATA);
368 MCLGET(mp, M_WAIT);
369 mp->m_len = NFSMSIZ(mp);
370 if (len == 0)
371 mp3 = mp2 = mp;
372 else {
373 mp2->m_next = mp;
374 mp2 = mp;
375 }
376 if ((len+mp->m_len) > NFS_MAXPATHLEN) {
377 mp->m_len = NFS_MAXPATHLEN-len;
378 len = NFS_MAXPATHLEN;
379 } else
380 len += mp->m_len;
381 ivp->iov_base = mtod(mp, caddr_t);
382 ivp->iov_len = mp->m_len;
383 i++;
384 ivp++;
385 }
386 uiop->uio_iov = iv;
387 uiop->uio_iovcnt = i;
388 uiop->uio_offset = 0;
389 uiop->uio_resid = len;
390 uiop->uio_rw = UIO_READ;
391 uiop->uio_segflg = UIO_SYSSPACE;
392 uiop->uio_procp = (struct proc *)0;
393 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) {
394 m_freem(mp3);
395 nfsm_reply(0);
396 }
397 if (vp->v_type != VLNK) {
398 error = EINVAL;
399 goto out;
400 }
401 nqsrv_getl(vp, NQL_READ);
402 error = VOP_READLINK(vp, uiop, cred);
403 out:
404 vput(vp);
405 if (error)
406 m_freem(mp3);
407 nfsm_reply(NFSX_UNSIGNED);
408 if (uiop->uio_resid > 0) {
409 len -= uiop->uio_resid;
410 tlen = nfsm_rndup(len);
411 nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len);
412 }
413 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
414 *tl = txdr_unsigned(len);
415 mb->m_next = mp3;
416 nfsm_srvdone;
417 }
418
419 /*
420 * nfs read service
421 */
422 nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq)
423 struct nfsd *nfsd;
424 struct mbuf *mrep, *md;
425 caddr_t dpos;
426 struct ucred *cred;
427 struct mbuf *nam, **mrq;
428 {
429 register struct iovec *iv;
430 struct iovec *iv2;
431 register struct mbuf *m;
432 register struct nfsv2_fattr *fp;
433 register u_long *tl;
434 register long t1;
435 caddr_t bpos;
436 int error = 0, rdonly, cache, i, cnt, len, left, siz, tlen;
437 char *cp2;
438 struct mbuf *mb, *mb2, *mreq;
439 struct mbuf *m2;
440 struct vnode *vp;
441 nfsv2fh_t nfh;
442 fhandle_t *fhp;
443 struct uio io, *uiop = &io;
444 struct vattr va, *vap = &va;
445 off_t off;
446 u_quad_t frev;
447
448 fhp = &nfh.fh_generic;
449 nfsm_srvmtofh(fhp);
450 if (nfsd->nd_nqlflag == NQL_NOVAL) {
451 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
452 off = (off_t)fxdr_unsigned(u_long, *tl);
453 } else {
454 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
455 fxdr_hyper(tl, &off);
456 }
457 nfsm_srvstrsiz(cnt, NFS_MAXDATA);
458 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
459 nfsm_reply(0);
460 if (vp->v_type != VREG) {
461 error = (vp->v_type == VDIR) ? EISDIR : EACCES;
462 vput(vp);
463 nfsm_reply(0);
464 }
465 nqsrv_getl(vp, NQL_READ);
466 if ((error = nfsrv_access(vp, VREAD, cred, rdonly, nfsd->nd_procp)) &&
467 (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp))) {
468 vput(vp);
469 nfsm_reply(0);
470 }
471 if (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp)) {
472 vput(vp);
473 nfsm_reply(0);
474 }
475 if (off >= vap->va_size)
476 cnt = 0;
477 else if ((off + cnt) > vap->va_size)
478 cnt = nfsm_rndup(vap->va_size - off);
479 nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)+NFSX_UNSIGNED+nfsm_rndup(cnt));
480 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
481 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
482 len = left = cnt;
483 if (cnt > 0) {
484 /*
485 * Generate the mbuf list with the uio_iov ref. to it.
486 */
487 i = 0;
488 m = m2 = mb;
489 MALLOC(iv, struct iovec *,
490 ((NFS_MAXDATA+MLEN-1)/MLEN) * sizeof (struct iovec),
491 M_TEMP, M_WAITOK);
492 iv2 = iv;
493 while (left > 0) {
494 siz = min(M_TRAILINGSPACE(m), left);
495 if (siz > 0) {
496 m->m_len += siz;
497 iv->iov_base = bpos;
498 iv->iov_len = siz;
499 iv++;
500 i++;
501 left -= siz;
502 }
503 if (left > 0) {
504 MGET(m, M_WAIT, MT_DATA);
505 MCLGET(m, M_WAIT);
506 m->m_len = 0;
507 m2->m_next = m;
508 m2 = m;
509 bpos = mtod(m, caddr_t);
510 }
511 }
512 uiop->uio_iov = iv2;
513 uiop->uio_iovcnt = i;
514 uiop->uio_offset = off;
515 uiop->uio_resid = cnt;
516 uiop->uio_rw = UIO_READ;
517 uiop->uio_segflg = UIO_SYSSPACE;
518 error = VOP_READ(vp, uiop, IO_NODELOCKED, cred);
519 off = uiop->uio_offset;
520 FREE((caddr_t)iv2, M_TEMP);
521 if (error || (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp))) {
522 m_freem(mreq);
523 vput(vp);
524 nfsm_reply(0);
525 }
526 } else
527 uiop->uio_resid = 0;
528 vput(vp);
529 nfsm_srvfillattr;
530 len -= uiop->uio_resid;
531 tlen = nfsm_rndup(len);
532 if (cnt != tlen || tlen != len)
533 nfsm_adj(mb, cnt-tlen, tlen-len);
534 *tl = txdr_unsigned(len);
535 nfsm_srvdone;
536 }
537
538 /*
539 * nfs write service
540 */
541 nfsrv_write(nfsd, mrep, md, dpos, cred, nam, mrq)
542 struct nfsd *nfsd;
543 struct mbuf *mrep, *md;
544 caddr_t dpos;
545 struct ucred *cred;
546 struct mbuf *nam, **mrq;
547 {
548 register struct iovec *ivp;
549 register struct mbuf *mp;
550 register struct nfsv2_fattr *fp;
551 struct iovec iv[NFS_MAXIOVEC];
552 struct vattr va;
553 register struct vattr *vap = &va;
554 register u_long *tl;
555 register long t1;
556 caddr_t bpos;
557 int error = 0, rdonly, cache, siz, len, xfer;
558 int ioflags = IO_SYNC | IO_NODELOCKED;
559 char *cp2;
560 struct mbuf *mb, *mb2, *mreq;
561 struct vnode *vp;
562 nfsv2fh_t nfh;
563 fhandle_t *fhp;
564 struct uio io, *uiop = &io;
565 off_t off;
566 u_quad_t frev;
567
568 fhp = &nfh.fh_generic;
569 nfsm_srvmtofh(fhp);
570 nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
571 if (nfsd->nd_nqlflag == NQL_NOVAL) {
572 off = (off_t)fxdr_unsigned(u_long, *++tl);
573 tl += 2;
574 } else {
575 fxdr_hyper(tl, &off);
576 tl += 2;
577 if (fxdr_unsigned(u_long, *tl++))
578 ioflags |= IO_APPEND;
579 }
580 len = fxdr_unsigned(long, *tl);
581 if (len > NFS_MAXDATA || len <= 0) {
582 error = EBADRPC;
583 nfsm_reply(0);
584 }
585 if (dpos == (mtod(md, caddr_t)+md->m_len)) {
586 mp = md->m_next;
587 if (mp == NULL) {
588 error = EBADRPC;
589 nfsm_reply(0);
590 }
591 } else {
592 mp = md;
593 siz = dpos-mtod(mp, caddr_t);
594 mp->m_len -= siz;
595 NFSMADV(mp, siz);
596 }
597 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
598 nfsm_reply(0);
599 if (vp->v_type != VREG) {
600 error = (vp->v_type == VDIR) ? EISDIR : EACCES;
601 vput(vp);
602 nfsm_reply(0);
603 }
604 nqsrv_getl(vp, NQL_WRITE);
605 if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) {
606 vput(vp);
607 nfsm_reply(0);
608 }
609 uiop->uio_resid = 0;
610 uiop->uio_rw = UIO_WRITE;
611 uiop->uio_segflg = UIO_SYSSPACE;
612 uiop->uio_procp = (struct proc *)0;
613 /*
614 * Do up to NFS_MAXIOVEC mbufs of write each iteration of the
615 * loop until done.
616 */
617 while (len > 0 && uiop->uio_resid == 0) {
618 ivp = iv;
619 siz = 0;
620 uiop->uio_iov = ivp;
621 uiop->uio_iovcnt = 0;
622 uiop->uio_offset = off;
623 while (len > 0 && uiop->uio_iovcnt < NFS_MAXIOVEC && mp != NULL) {
624 ivp->iov_base = mtod(mp, caddr_t);
625 if (len < mp->m_len)
626 ivp->iov_len = xfer = len;
627 else
628 ivp->iov_len = xfer = mp->m_len;
629 #ifdef notdef
630 /* Not Yet .. */
631 if (M_HASCL(mp) && (((u_long)ivp->iov_base) & CLOFSET) == 0)
632 ivp->iov_op = NULL; /* what should it be ?? */
633 else
634 ivp->iov_op = NULL;
635 #endif
636 uiop->uio_iovcnt++;
637 ivp++;
638 len -= xfer;
639 siz += xfer;
640 mp = mp->m_next;
641 }
642 if (len > 0 && mp == NULL) {
643 error = EBADRPC;
644 vput(vp);
645 nfsm_reply(0);
646 }
647 uiop->uio_resid = siz;
648 if (error = VOP_WRITE(vp, uiop, ioflags, cred)) {
649 vput(vp);
650 nfsm_reply(0);
651 }
652 off = uiop->uio_offset;
653 }
654 error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
655 vput(vp);
656 nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
657 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
658 nfsm_srvfillattr;
659 if (nfsd->nd_nqlflag != NQL_NOVAL) {
660 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
661 txdr_hyper(&vap->va_filerev, tl);
662 }
663 nfsm_srvdone;
664 }
665
666 /*
667 * nfs create service
668 * now does a truncate to 0 length via. setattr if it already exists
669 */
670 nfsrv_create(nfsd, mrep, md, dpos, cred, nam, mrq)
671 struct nfsd *nfsd;
672 struct mbuf *mrep, *md;
673 caddr_t dpos;
674 struct ucred *cred;
675 struct mbuf *nam, **mrq;
676 {
677 register struct nfsv2_fattr *fp;
678 struct vattr va;
679 register struct vattr *vap = &va;
680 register struct nfsv2_sattr *sp;
681 register u_long *tl;
682 struct nameidata nd;
683 register caddr_t cp;
684 register long t1;
685 caddr_t bpos;
686 int error = 0, rdev, cache, len, tsize;
687 char *cp2;
688 struct mbuf *mb, *mb2, *mreq;
689 struct vnode *vp;
690 nfsv2fh_t nfh;
691 fhandle_t *fhp;
692 u_quad_t frev;
693
694 nd.ni_cnd.cn_nameiop = 0;
695 fhp = &nfh.fh_generic;
696 nfsm_srvmtofh(fhp);
697 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
698 nd.ni_cnd.cn_cred = cred;
699 nd.ni_cnd.cn_nameiop = CREATE;
700 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART;
701 if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
702 nfsd->nd_procp))
703 nfsm_reply(0);
704 VATTR_NULL(vap);
705 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL));
706 /*
707 * Iff doesn't exist, create it
708 * otherwise just truncate to 0 length
709 * should I set the mode too ??
710 */
711 if (nd.ni_vp == NULL) {
712 vap->va_type = IFTOVT(fxdr_unsigned(u_long, sp->sa_mode));
713 if (vap->va_type == VNON)
714 vap->va_type = VREG;
715 vap->va_mode = nfstov_mode(sp->sa_mode);
716 if (nfsd->nd_nqlflag == NQL_NOVAL)
717 rdev = fxdr_unsigned(long, sp->sa_nfssize);
718 else
719 rdev = fxdr_unsigned(long, sp->sa_nqrdev);
720 if (vap->va_type == VREG || vap->va_type == VSOCK) {
721 vrele(nd.ni_startdir);
722 nqsrv_getl(nd.ni_dvp, NQL_WRITE);
723 if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap))
724 nfsm_reply(0);
725 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
726 } else if (vap->va_type == VCHR || vap->va_type == VBLK ||
727 vap->va_type == VFIFO) {
728 if (vap->va_type == VCHR && rdev == 0xffffffff)
729 vap->va_type = VFIFO;
730 if (vap->va_type == VFIFO) {
731 #ifndef FIFO
732 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
733 vput(nd.ni_dvp);
734 error = ENXIO;
735 goto out;
736 #endif /* FIFO */
737 } else if (error = suser(cred, (u_short *)0)) {
738 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
739 vput(nd.ni_dvp);
740 goto out;
741 } else
742 vap->va_rdev = (dev_t)rdev;
743 nqsrv_getl(nd.ni_dvp, NQL_WRITE);
744 if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) {
745 vrele(nd.ni_startdir);
746 nfsm_reply(0);
747 }
748 nd.ni_cnd.cn_nameiop = LOOKUP;
749 nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
750 nd.ni_cnd.cn_proc = nfsd->nd_procp;
751 nd.ni_cnd.cn_cred = nfsd->nd_procp->p_ucred;
752 if (error = lookup(&nd)) {
753 free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
754 nfsm_reply(0);
755 }
756 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
757 if (nd.ni_cnd.cn_flags & ISSYMLINK) {
758 vrele(nd.ni_dvp);
759 vput(nd.ni_vp);
760 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
761 error = EINVAL;
762 nfsm_reply(0);
763 }
764 } else {
765 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
766 vput(nd.ni_dvp);
767 error = ENXIO;
768 goto out;
769 }
770 vp = nd.ni_vp;
771 } else {
772 vrele(nd.ni_startdir);
773 free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
774 vp = nd.ni_vp;
775 if (nd.ni_dvp == vp)
776 vrele(nd.ni_dvp);
777 else
778 vput(nd.ni_dvp);
779 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
780 if (nfsd->nd_nqlflag == NQL_NOVAL) {
781 tsize = fxdr_unsigned(long, sp->sa_nfssize);
782 if (tsize != -1)
783 vap->va_size = (u_quad_t)tsize;
784 else
785 vap->va_size = -1;
786 } else
787 fxdr_hyper(&sp->sa_nqsize, &vap->va_size);
788 if (vap->va_size != -1) {
789 if (error = nfsrv_access(vp, VWRITE, cred,
790 (nd.ni_cnd.cn_flags & RDONLY), nfsd->nd_procp)) {
791 vput(vp);
792 nfsm_reply(0);
793 }
794 nqsrv_getl(vp, NQL_WRITE);
795 if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) {
796 vput(vp);
797 nfsm_reply(0);
798 }
799 }
800 }
801 bzero((caddr_t)fhp, sizeof(nfh));
802 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
803 if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
804 vput(vp);
805 nfsm_reply(0);
806 }
807 error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
808 vput(vp);
809 nfsm_reply(NFSX_FH+NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
810 nfsm_srvfhtom(fhp);
811 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
812 nfsm_srvfillattr;
813 return (error);
814 nfsmout:
815 if (nd.ni_cnd.cn_nameiop || nd.ni_cnd.cn_flags)
816 vrele(nd.ni_startdir);
817 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
818 if (nd.ni_dvp == nd.ni_vp)
819 vrele(nd.ni_dvp);
820 else
821 vput(nd.ni_dvp);
822 if (nd.ni_vp)
823 vput(nd.ni_vp);
824 return (error);
825
826 out:
827 vrele(nd.ni_startdir);
828 free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
829 nfsm_reply(0);
830 }
831
832 /*
833 * nfs remove service
834 */
835 nfsrv_remove(nfsd, mrep, md, dpos, cred, nam, mrq)
836 struct nfsd *nfsd;
837 struct mbuf *mrep, *md;
838 caddr_t dpos;
839 struct ucred *cred;
840 struct mbuf *nam, **mrq;
841 {
842 struct nameidata nd;
843 register u_long *tl;
844 register long t1;
845 caddr_t bpos;
846 int error = 0, cache, len;
847 char *cp2;
848 struct mbuf *mb, *mreq;
849 struct vnode *vp;
850 nfsv2fh_t nfh;
851 fhandle_t *fhp;
852 u_quad_t frev;
853
854 fhp = &nfh.fh_generic;
855 nfsm_srvmtofh(fhp);
856 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
857 nd.ni_cnd.cn_cred = cred;
858 nd.ni_cnd.cn_nameiop = DELETE;
859 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
860 if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
861 nfsd->nd_procp))
862 nfsm_reply(0);
863 vp = nd.ni_vp;
864 if (vp->v_type == VDIR &&
865 (error = suser(cred, (u_short *)0)))
866 goto out;
867 /*
868 * The root of a mounted filesystem cannot be deleted.
869 */
870 if (vp->v_flag & VROOT) {
871 error = EBUSY;
872 goto out;
873 }
874 if (vp->v_flag & VTEXT)
875 (void) vnode_pager_uncache(vp);
876 out:
877 if (!error) {
878 nqsrv_getl(nd.ni_dvp, NQL_WRITE);
879 nqsrv_getl(vp, NQL_WRITE);
880 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
881 } else {
882 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
883 if (nd.ni_dvp == vp)
884 vrele(nd.ni_dvp);
885 else
886 vput(nd.ni_dvp);
887 vput(vp);
888 }
889 nfsm_reply(0);
890 nfsm_srvdone;
891 }
892
893 /*
894 * nfs rename service
895 */
896 nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq)
897 struct nfsd *nfsd;
898 struct mbuf *mrep, *md;
899 caddr_t dpos;
900 struct ucred *cred;
901 struct mbuf *nam, **mrq;
902 {
903 register u_long *tl;
904 register long t1;
905 caddr_t bpos;
906 int error = 0, cache, len, len2;
907 char *cp2;
908 struct mbuf *mb, *mreq;
909 struct nameidata fromnd, tond;
910 struct vnode *fvp, *tvp, *tdvp;
911 nfsv2fh_t fnfh, tnfh;
912 fhandle_t *ffhp, *tfhp;
913 u_quad_t frev;
914 uid_t saved_uid;
915
916 ffhp = &fnfh.fh_generic;
917 tfhp = &tnfh.fh_generic;
918 fromnd.ni_cnd.cn_nameiop = 0;
919 tond.ni_cnd.cn_nameiop = 0;
920 nfsm_srvmtofh(ffhp);
921 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
922 /*
923 * Remember our original uid so that we can reset cr_uid before
924 * the second nfs_namei() call, in case it is remapped.
925 */
926 saved_uid = cred->cr_uid;
927 fromnd.ni_cnd.cn_cred = cred;
928 fromnd.ni_cnd.cn_nameiop = DELETE;
929 fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART;
930 if (error = nfs_namei(&fromnd, ffhp, len, nfsd->nd_slp, nam, &md,
931 &dpos, nfsd->nd_procp))
932 nfsm_reply(0);
933 fvp = fromnd.ni_vp;
934 nfsm_srvmtofh(tfhp);
935 nfsm_strsiz(len2, NFS_MAXNAMLEN);
936 cred->cr_uid = saved_uid;
937 tond.ni_cnd.cn_cred = cred;
938 tond.ni_cnd.cn_nameiop = RENAME;
939 tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART;
940 if (error = nfs_namei(&tond, tfhp, len2, nfsd->nd_slp, nam, &md,
941 &dpos, nfsd->nd_procp)) {
942 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
943 vrele(fromnd.ni_dvp);
944 vrele(fvp);
945 goto out1;
946 }
947 tdvp = tond.ni_dvp;
948 tvp = tond.ni_vp;
949 if (tvp != NULL) {
950 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
951 error = EISDIR;
952 goto out;
953 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
954 error = ENOTDIR;
955 goto out;
956 }
957 if (tvp->v_type == VDIR && tvp->v_mountedhere) {
958 error = EXDEV;
959 goto out;
960 }
961 }
962 if (fvp->v_type == VDIR && fvp->v_mountedhere) {
963 error = EBUSY;
964 goto out;
965 }
966 if (fvp->v_mount != tdvp->v_mount) {
967 error = EXDEV;
968 goto out;
969 }
970 if (fvp == tdvp)
971 error = EINVAL;
972 /*
973 * If source is the same as the destination (that is the
974 * same vnode with the same name in the same directory),
975 * then there is nothing to do.
976 */
977 if (fvp == tvp && fromnd.ni_dvp == tdvp &&
978 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
979 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
980 fromnd.ni_cnd.cn_namelen))
981 error = -1;
982 out:
983 if (!error) {
984 nqsrv_getl(fromnd.ni_dvp, NQL_WRITE);
985 nqsrv_getl(tdvp, NQL_WRITE);
986 if (tvp)
987 nqsrv_getl(tvp, NQL_WRITE);
988 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
989 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
990 } else {
991 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
992 if (tdvp == tvp)
993 vrele(tdvp);
994 else
995 vput(tdvp);
996 if (tvp)
997 vput(tvp);
998 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
999 vrele(fromnd.ni_dvp);
1000 vrele(fvp);
1001 }
1002 vrele(tond.ni_startdir);
1003 FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
1004 out1:
1005 vrele(fromnd.ni_startdir);
1006 FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
1007 nfsm_reply(0);
1008 return (error);
1009
1010 nfsmout:
1011 if (tond.ni_cnd.cn_nameiop || tond.ni_cnd.cn_flags) {
1012 vrele(tond.ni_startdir);
1013 FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
1014 }
1015 if (fromnd.ni_cnd.cn_nameiop || fromnd.ni_cnd.cn_flags) {
1016 vrele(fromnd.ni_startdir);
1017 FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
1018 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1019 vrele(fromnd.ni_dvp);
1020 vrele(fvp);
1021 }
1022 return (error);
1023 }
1024
1025 /*
1026 * nfs link service
1027 */
1028 nfsrv_link(nfsd, mrep, md, dpos, cred, nam, mrq)
1029 struct nfsd *nfsd;
1030 struct mbuf *mrep, *md;
1031 caddr_t dpos;
1032 struct ucred *cred;
1033 struct mbuf *nam, **mrq;
1034 {
1035 struct nameidata nd;
1036 register u_long *tl;
1037 register long t1;
1038 caddr_t bpos;
1039 int error = 0, rdonly, cache, len;
1040 char *cp2;
1041 struct mbuf *mb, *mreq;
1042 struct vnode *vp, *xp;
1043 nfsv2fh_t nfh, dnfh;
1044 fhandle_t *fhp, *dfhp;
1045 u_quad_t frev;
1046
1047 fhp = &nfh.fh_generic;
1048 dfhp = &dnfh.fh_generic;
1049 nfsm_srvmtofh(fhp);
1050 nfsm_srvmtofh(dfhp);
1051 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
1052 if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
1053 nfsm_reply(0);
1054 if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0)))
1055 goto out1;
1056 nd.ni_cnd.cn_cred = cred;
1057 nd.ni_cnd.cn_nameiop = CREATE;
1058 nd.ni_cnd.cn_flags = LOCKPARENT;
1059 if (error = nfs_namei(&nd, dfhp, len, nfsd->nd_slp, nam, &md, &dpos,
1060 nfsd->nd_procp))
1061 goto out1;
1062 xp = nd.ni_vp;
1063 if (xp != NULL) {
1064 error = EEXIST;
1065 goto out;
1066 }
1067 xp = nd.ni_dvp;
1068 if (vp->v_mount != xp->v_mount)
1069 error = EXDEV;
1070 out:
1071 if (!error) {
1072 nqsrv_getl(vp, NQL_WRITE);
1073 nqsrv_getl(xp, NQL_WRITE);
1074 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
1075 } else {
1076 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1077 if (nd.ni_dvp == nd.ni_vp)
1078 vrele(nd.ni_dvp);
1079 else
1080 vput(nd.ni_dvp);
1081 if (nd.ni_vp)
1082 vrele(nd.ni_vp);
1083 }
1084 out1:
1085 vrele(vp);
1086 nfsm_reply(0);
1087 nfsm_srvdone;
1088 }
1089
1090 /*
1091 * nfs symbolic link service
1092 */
1093 nfsrv_symlink(nfsd, mrep, md, dpos, cred, nam, mrq)
1094 struct nfsd *nfsd;
1095 struct mbuf *mrep, *md;
1096 caddr_t dpos;
1097 struct ucred *cred;
1098 struct mbuf *nam, **mrq;
1099 {
1100 struct vattr va;
1101 struct nameidata nd;
1102 register struct vattr *vap = &va;
1103 register u_long *tl;
1104 register long t1;
1105 struct nfsv2_sattr *sp;
1106 caddr_t bpos;
1107 struct uio io;
1108 struct iovec iv;
1109 int error = 0, cache, len, len2;
1110 char *pathcp, *cp2;
1111 struct mbuf *mb, *mreq;
1112 nfsv2fh_t nfh;
1113 fhandle_t *fhp;
1114 u_quad_t frev;
1115
1116 pathcp = (char *)0;
1117 fhp = &nfh.fh_generic;
1118 nfsm_srvmtofh(fhp);
1119 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
1120 nd.ni_cnd.cn_cred = cred;
1121 nd.ni_cnd.cn_nameiop = CREATE;
1122 nd.ni_cnd.cn_flags = LOCKPARENT;
1123 if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
1124 nfsd->nd_procp))
1125 goto out;
1126 nfsm_strsiz(len2, NFS_MAXPATHLEN);
1127 MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK);
1128 iv.iov_base = pathcp;
1129 iv.iov_len = len2;
1130 io.uio_resid = len2;
1131 io.uio_offset = 0;
1132 io.uio_iov = &iv;
1133 io.uio_iovcnt = 1;
1134 io.uio_segflg = UIO_SYSSPACE;
1135 io.uio_rw = UIO_READ;
1136 io.uio_procp = (struct proc *)0;
1137 nfsm_mtouio(&io, len2);
1138 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL));
1139 *(pathcp + len2) = '\0';
1140 if (nd.ni_vp) {
1141 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1142 if (nd.ni_dvp == nd.ni_vp)
1143 vrele(nd.ni_dvp);
1144 else
1145 vput(nd.ni_dvp);
1146 vrele(nd.ni_vp);
1147 error = EEXIST;
1148 goto out;
1149 }
1150 VATTR_NULL(vap);
1151 vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode);
1152 nqsrv_getl(nd.ni_dvp, NQL_WRITE);
1153 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp);
1154 out:
1155 if (pathcp)
1156 FREE(pathcp, M_TEMP);
1157 nfsm_reply(0);
1158 return (error);
1159 nfsmout:
1160 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1161 if (nd.ni_dvp == nd.ni_vp)
1162 vrele(nd.ni_dvp);
1163 else
1164 vput(nd.ni_dvp);
1165 if (nd.ni_vp)
1166 vrele(nd.ni_vp);
1167 if (pathcp)
1168 FREE(pathcp, M_TEMP);
1169 return (error);
1170 }
1171
1172 /*
1173 * nfs mkdir service
1174 */
1175 nfsrv_mkdir(nfsd, mrep, md, dpos, cred, nam, mrq)
1176 struct nfsd *nfsd;
1177 struct mbuf *mrep, *md;
1178 caddr_t dpos;
1179 struct ucred *cred;
1180 struct mbuf *nam, **mrq;
1181 {
1182 struct vattr va;
1183 register struct vattr *vap = &va;
1184 register struct nfsv2_fattr *fp;
1185 struct nameidata nd;
1186 register caddr_t cp;
1187 register u_long *tl;
1188 register long t1;
1189 caddr_t bpos;
1190 int error = 0, cache, len;
1191 char *cp2;
1192 struct mbuf *mb, *mb2, *mreq;
1193 struct vnode *vp;
1194 nfsv2fh_t nfh;
1195 fhandle_t *fhp;
1196 u_quad_t frev;
1197
1198 fhp = &nfh.fh_generic;
1199 nfsm_srvmtofh(fhp);
1200 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
1201 nd.ni_cnd.cn_cred = cred;
1202 nd.ni_cnd.cn_nameiop = CREATE;
1203 nd.ni_cnd.cn_flags = LOCKPARENT;
1204 if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
1205 nfsd->nd_procp))
1206 nfsm_reply(0);
1207 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
1208 VATTR_NULL(vap);
1209 vap->va_type = VDIR;
1210 vap->va_mode = nfstov_mode(*tl++);
1211 vp = nd.ni_vp;
1212 if (vp != NULL) {
1213 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1214 if (nd.ni_dvp == vp)
1215 vrele(nd.ni_dvp);
1216 else
1217 vput(nd.ni_dvp);
1218 vrele(vp);
1219 error = EEXIST;
1220 nfsm_reply(0);
1221 }
1222 nqsrv_getl(nd.ni_dvp, NQL_WRITE);
1223 if (error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap))
1224 nfsm_reply(0);
1225 vp = nd.ni_vp;
1226 bzero((caddr_t)fhp, sizeof(nfh));
1227 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1228 if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
1229 vput(vp);
1230 nfsm_reply(0);
1231 }
1232 error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
1233 vput(vp);
1234 nfsm_reply(NFSX_FH+NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
1235 nfsm_srvfhtom(fhp);
1236 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
1237 nfsm_srvfillattr;
1238 return (error);
1239 nfsmout:
1240 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1241 if (nd.ni_dvp == nd.ni_vp)
1242 vrele(nd.ni_dvp);
1243 else
1244 vput(nd.ni_dvp);
1245 if (nd.ni_vp)
1246 vrele(nd.ni_vp);
1247 return (error);
1248 }
1249
1250 /*
1251 * nfs rmdir service
1252 */
1253 nfsrv_rmdir(nfsd, mrep, md, dpos, cred, nam, mrq)
1254 struct nfsd *nfsd;
1255 struct mbuf *mrep, *md;
1256 caddr_t dpos;
1257 struct ucred *cred;
1258 struct mbuf *nam, **mrq;
1259 {
1260 register u_long *tl;
1261 register long t1;
1262 caddr_t bpos;
1263 int error = 0, cache, len;
1264 char *cp2;
1265 struct mbuf *mb, *mreq;
1266 struct vnode *vp;
1267 nfsv2fh_t nfh;
1268 fhandle_t *fhp;
1269 struct nameidata nd;
1270 u_quad_t frev;
1271
1272 fhp = &nfh.fh_generic;
1273 nfsm_srvmtofh(fhp);
1274 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
1275 nd.ni_cnd.cn_cred = cred;
1276 nd.ni_cnd.cn_nameiop = DELETE;
1277 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
1278 if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
1279 nfsd->nd_procp))
1280 nfsm_reply(0);
1281 vp = nd.ni_vp;
1282 if (vp->v_type != VDIR) {
1283 error = ENOTDIR;
1284 goto out;
1285 }
1286 /*
1287 * No rmdir "." please.
1288 */
1289 if (nd.ni_dvp == vp) {
1290 error = EINVAL;
1291 goto out;
1292 }
1293 /*
1294 * The root of a mounted filesystem cannot be deleted.
1295 */
1296 if (vp->v_flag & VROOT)
1297 error = EBUSY;
1298 out:
1299 if (!error) {
1300 nqsrv_getl(nd.ni_dvp, NQL_WRITE);
1301 nqsrv_getl(vp, NQL_WRITE);
1302 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1303 } else {
1304 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1305 if (nd.ni_dvp == nd.ni_vp)
1306 vrele(nd.ni_dvp);
1307 else
1308 vput(nd.ni_dvp);
1309 vput(vp);
1310 }
1311 nfsm_reply(0);
1312 nfsm_srvdone;
1313 }
1314
1315 /*
1316 * nfs readdir service
1317 * - mallocs what it thinks is enough to read
1318 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
1319 * - calls VOP_READDIR()
1320 * - loops around building the reply
1321 * if the output generated exceeds count break out of loop
1322 * The nfsm_clget macro is used here so that the reply will be packed
1323 * tightly in mbuf clusters.
1324 * - it only knows that it has encountered eof when the VOP_READDIR()
1325 * reads nothing
1326 * - as such one readdir rpc will return eof false although you are there
1327 * and then the next will return eof
1328 * - it trims out records with d_fileno == 0
1329 * this doesn't matter for Unix clients, but they might confuse clients
1330 * for other os'.
1331 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
1332 * than requested, but this may not apply to all filesystems. For
1333 * example, client NFS does not { although it is never remote mounted
1334 * anyhow }
1335 * The alternate call nqnfsrv_readdirlook() does lookups as well.
1336 * PS: The NFS protocol spec. does not clarify what the "count" byte
1337 * argument is a count of.. just name strings and file id's or the
1338 * entire reply rpc or ...
1339 * I tried just file name and id sizes and it confused the Sun client,
1340 * so I am using the full rpc size now. The "paranoia.." comment refers
1341 * to including the status longwords that are not a part of the dir.
1342 * "entry" structures, but are in the rpc.
1343 */
1344 struct flrep {
1345 u_long fl_cachable;
1346 u_long fl_duration;
1347 u_long fl_frev[2];
1348 nfsv2fh_t fl_nfh;
1349 u_long fl_fattr[NFSX_NQFATTR / sizeof (u_long)];
1350 };
1351
1352 nfsrv_readdir(nfsd, mrep, md, dpos, cred, nam, mrq)
1353 struct nfsd *nfsd;
1354 struct mbuf *mrep, *md;
1355 caddr_t dpos;
1356 struct ucred *cred;
1357 struct mbuf *nam, **mrq;
1358 {
1359 register char *bp, *be;
1360 register struct mbuf *mp;
1361 register struct dirent *dp;
1362 register caddr_t cp;
1363 register u_long *tl;
1364 register long t1;
1365 caddr_t bpos;
1366 struct mbuf *mb, *mb2, *mreq, *mp2;
1367 char *cpos, *cend, *cp2, *rbuf;
1368 struct vnode *vp;
1369 nfsv2fh_t nfh;
1370 fhandle_t *fhp;
1371 struct uio io;
1372 struct iovec iv;
1373 int len, nlen, rem, xfer, tsiz, i, error = 0;
1374 int siz, cnt, fullsiz, eofflag, rdonly, cache;
1375 u_quad_t frev;
1376 u_long off, *cookiebuf, *cookie;
1377 int ncookies;
1378
1379 fhp = &nfh.fh_generic;
1380 nfsm_srvmtofh(fhp);
1381 nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
1382 off = fxdr_unsigned(u_long, *tl++);
1383 cnt = fxdr_unsigned(int, *tl);
1384 siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1));
1385 if (cnt > NFS_MAXREADDIR)
1386 siz = NFS_MAXREADDIR;
1387 fullsiz = siz;
1388 ncookies = siz / 16; /* Guess at the number of cookies needed. */
1389 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
1390 nfsm_reply(0);
1391 nqsrv_getl(vp, NQL_READ);
1392 if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) {
1393 vput(vp);
1394 nfsm_reply(0);
1395 }
1396 VOP_UNLOCK(vp);
1397 MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
1398 MALLOC(cookiebuf, u_long *, ncookies * sizeof(*cookiebuf), M_TEMP,
1399 M_WAITOK);
1400 again:
1401 iv.iov_base = rbuf;
1402 iv.iov_len = fullsiz;
1403 io.uio_iov = &iv;
1404 io.uio_iovcnt = 1;
1405 io.uio_offset = (off_t)off;
1406 io.uio_resid = fullsiz;
1407 io.uio_segflg = UIO_SYSSPACE;
1408 io.uio_rw = UIO_READ;
1409 io.uio_procp = (struct proc *)0;
1410 error = VOP_READDIR(vp, &io, cred, &eofflag, cookiebuf, ncookies);
1411 cookie = cookiebuf;
1412 off = (off_t)io.uio_offset;
1413 if (error) {
1414 vrele(vp);
1415 free((caddr_t)cookiebuf, M_TEMP);
1416 free((caddr_t)rbuf, M_TEMP);
1417 nfsm_reply(0);
1418 }
1419 if (io.uio_resid) {
1420 siz -= io.uio_resid;
1421
1422 /*
1423 * If nothing read, return eof
1424 * rpc reply
1425 */
1426 if (siz == 0) {
1427 vrele(vp);
1428 nfsm_reply(2*NFSX_UNSIGNED);
1429 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
1430 *tl++ = nfs_false;
1431 *tl = nfs_true;
1432 FREE((caddr_t)cookiebuf, M_TEMP);
1433 FREE((caddr_t)rbuf, M_TEMP);
1434 return (0);
1435 }
1436 }
1437
1438 /*
1439 * Check for degenerate cases of nothing useful read.
1440 * If so go try again
1441 */
1442 cpos = rbuf;
1443 cend = rbuf + siz;
1444 while (cpos < cend) {
1445 dp = (struct dirent *)cpos;
1446 if (dp->d_fileno == 0) {
1447 cpos += dp->d_reclen;
1448 cookie++;
1449 } else
1450 break;
1451 }
1452 if (cpos >= cend) {
1453 siz = fullsiz;
1454 goto again;
1455 }
1456
1457 len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */
1458 nfsm_reply(siz);
1459 mp = mp2 = mb;
1460 bp = bpos;
1461 be = bp + M_TRAILINGSPACE(mp);
1462
1463 /* Loop through the records and build reply */
1464 while (cpos < cend) {
1465 if (dp->d_fileno != 0) {
1466 nlen = dp->d_namlen;
1467 rem = nfsm_rndup(nlen)-nlen;
1468 len += (4*NFSX_UNSIGNED + nlen + rem);
1469 if (len > cnt) {
1470 eofflag = 0;
1471 break;
1472 }
1473 /*
1474 * Build the directory record xdr from
1475 * the dirent entry.
1476 */
1477 nfsm_clget;
1478 *tl = nfs_true;
1479 bp += NFSX_UNSIGNED;
1480 nfsm_clget;
1481 *tl = txdr_unsigned(dp->d_fileno);
1482 bp += NFSX_UNSIGNED;
1483 nfsm_clget;
1484 *tl = txdr_unsigned(nlen);
1485 bp += NFSX_UNSIGNED;
1486
1487 /* And loop around copying the name */
1488 xfer = nlen;
1489 cp = dp->d_name;
1490 while (xfer > 0) {
1491 nfsm_clget;
1492 if ((bp+xfer) > be)
1493 tsiz = be-bp;
1494 else
1495 tsiz = xfer;
1496 bcopy(cp, bp, tsiz);
1497 bp += tsiz;
1498 xfer -= tsiz;
1499 if (xfer > 0)
1500 cp += tsiz;
1501 }
1502 /* And null pad to a long boundary */
1503 for (i = 0; i < rem; i++)
1504 *bp++ = '\0';
1505 nfsm_clget;
1506
1507 /* Finish off the record */
1508 *tl = txdr_unsigned(*cookie);
1509 bp += NFSX_UNSIGNED;
1510 }
1511 cpos += dp->d_reclen;
1512 dp = (struct dirent *)cpos;
1513 cookie++;
1514 }
1515 vrele(vp);
1516 nfsm_clget;
1517 *tl = nfs_false;
1518 bp += NFSX_UNSIGNED;
1519 nfsm_clget;
1520 if (eofflag)
1521 *tl = nfs_true;
1522 else
1523 *tl = nfs_false;
1524 bp += NFSX_UNSIGNED;
1525 if (mp != mb) {
1526 if (bp < be)
1527 mp->m_len = bp - mtod(mp, caddr_t);
1528 } else
1529 mp->m_len += bp - bpos;
1530 FREE(cookiebuf, M_TEMP);
1531 FREE(rbuf, M_TEMP);
1532 nfsm_srvdone;
1533 }
1534
1535 nqnfsrv_readdirlook(nfsd, mrep, md, dpos, cred, nam, mrq)
1536 struct nfsd *nfsd;
1537 struct mbuf *mrep, *md;
1538 caddr_t dpos;
1539 struct ucred *cred;
1540 struct mbuf *nam, **mrq;
1541 {
1542 register char *bp, *be;
1543 register struct mbuf *mp;
1544 register struct dirent *dp;
1545 register caddr_t cp;
1546 register u_long *tl;
1547 register long t1;
1548 caddr_t bpos;
1549 struct mbuf *mb, *mb2, *mreq, *mp2;
1550 char *cpos, *cend, *cp2, *rbuf;
1551 struct vnode *vp, *nvp;
1552 struct flrep fl;
1553 nfsv2fh_t nfh;
1554 fhandle_t *fhp;
1555 struct uio io;
1556 struct iovec iv;
1557 struct vattr va, *vap = &va;
1558 struct nfsv2_fattr *fp;
1559 int len, nlen, rem, xfer, tsiz, i, error = 0, duration2, cache2;
1560 int siz, cnt, fullsiz, eofflag, rdonly, cache;
1561 u_quad_t frev, frev2;
1562 u_long off, *cookiebuf, *cookie;
1563 int ncookies;
1564
1565 fhp = &nfh.fh_generic;
1566 nfsm_srvmtofh(fhp);
1567 nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED);
1568 off = fxdr_unsigned(u_long, *tl++);
1569 cnt = fxdr_unsigned(int, *tl++);
1570 duration2 = fxdr_unsigned(int, *tl);
1571 siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1));
1572 if (cnt > NFS_MAXREADDIR)
1573 siz = NFS_MAXREADDIR;
1574 fullsiz = siz;
1575 ncookies = siz / 16; /* Guess at the number of cookies needed. */
1576 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
1577 nfsm_reply(0);
1578 nqsrv_getl(vp, NQL_READ);
1579 if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) {
1580 vput(vp);
1581 nfsm_reply(0);
1582 }
1583 VOP_UNLOCK(vp);
1584 MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
1585 MALLOC(cookiebuf, u_long *, ncookies * sizeof(*cookiebuf), M_TEMP,
1586 M_WAITOK);
1587 again:
1588 iv.iov_base = rbuf;
1589 iv.iov_len = fullsiz;
1590 io.uio_iov = &iv;
1591 io.uio_iovcnt = 1;
1592 io.uio_offset = (off_t)off;
1593 io.uio_resid = fullsiz;
1594 io.uio_segflg = UIO_SYSSPACE;
1595 io.uio_rw = UIO_READ;
1596 io.uio_procp = (struct proc *)0;
1597 error = VOP_READDIR(vp, &io, cred, &eofflag, cookiebuf, ncookies);
1598 cookie = cookiebuf;
1599 off = (u_long)io.uio_offset;
1600 if (error) {
1601 vrele(vp);
1602 free((caddr_t)cookiebuf, M_TEMP);
1603 free((caddr_t)rbuf, M_TEMP);
1604 nfsm_reply(0);
1605 }
1606 if (io.uio_resid) {
1607 siz -= io.uio_resid;
1608
1609 /*
1610 * If nothing read, return eof
1611 * rpc reply
1612 */
1613 if (siz == 0) {
1614 vrele(vp);
1615 nfsm_reply(2 * NFSX_UNSIGNED);
1616 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
1617 *tl++ = nfs_false;
1618 *tl = nfs_true;
1619 FREE((caddr_t)cookiebuf, M_TEMP);
1620 FREE((caddr_t)rbuf, M_TEMP);
1621 return (0);
1622 }
1623 }
1624
1625 /*
1626 * Check for degenerate cases of nothing useful read.
1627 * If so go try again
1628 */
1629 cpos = rbuf;
1630 cend = rbuf + siz;
1631 while (cpos < cend) {
1632 dp = (struct dirent *)cpos;
1633 if (dp->d_fileno == 0) {
1634 cpos += dp->d_reclen;
1635 cookie++;
1636 } else
1637 break;
1638 }
1639 if (cpos >= cend) {
1640 siz = fullsiz;
1641 goto again;
1642 }
1643
1644 len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */
1645 nfsm_reply(siz);
1646 mp = mp2 = mb;
1647 bp = bpos;
1648 be = bp + M_TRAILINGSPACE(mp);
1649
1650 /* Loop through the records and build reply */
1651 while (cpos < cend) {
1652 if (dp->d_fileno != 0) {
1653 nlen = dp->d_namlen;
1654 rem = nfsm_rndup(nlen)-nlen;
1655
1656 /*
1657 * For readdir_and_lookup get the vnode using
1658 * the file number.
1659 */
1660 if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp))
1661 goto invalid;
1662 bzero((caddr_t)&fl.fl_nfh, sizeof (nfsv2fh_t));
1663 fl.fl_nfh.fh_generic.fh_fsid =
1664 nvp->v_mount->mnt_stat.f_fsid;
1665 if (VFS_VPTOFH(nvp, &fl.fl_nfh.fh_generic.fh_fid)) {
1666 vput(nvp);
1667 goto invalid;
1668 }
1669 if (duration2) {
1670 (void) nqsrv_getlease(nvp, &duration2, NQL_READ,
1671 nfsd, nam, &cache2, &frev2, cred);
1672 fl.fl_duration = txdr_unsigned(duration2);
1673 fl.fl_cachable = txdr_unsigned(cache2);
1674 txdr_hyper(&frev2, fl.fl_frev);
1675 } else
1676 fl.fl_duration = 0;
1677 if (VOP_GETATTR(nvp, vap, cred, nfsd->nd_procp)) {
1678 vput(nvp);
1679 goto invalid;
1680 }
1681 vput(nvp);
1682 fp = (struct nfsv2_fattr *)&fl.fl_fattr;
1683 nfsm_srvfillattr;
1684 len += (4*NFSX_UNSIGNED + nlen + rem + NFSX_FH
1685 + NFSX_NQFATTR);
1686 if (len > cnt) {
1687 eofflag = 0;
1688 break;
1689 }
1690 /*
1691 * Build the directory record xdr from
1692 * the dirent entry.
1693 */
1694 nfsm_clget;
1695 *tl = nfs_true;
1696 bp += NFSX_UNSIGNED;
1697
1698 /*
1699 * For readdir_and_lookup copy the stuff out.
1700 */
1701 xfer = sizeof (struct flrep);
1702 cp = (caddr_t)&fl;
1703 while (xfer > 0) {
1704 nfsm_clget;
1705 if ((bp+xfer) > be)
1706 tsiz = be-bp;
1707 else
1708 tsiz = xfer;
1709 bcopy(cp, bp, tsiz);
1710 bp += tsiz;
1711 xfer -= tsiz;
1712 if (xfer > 0)
1713 cp += tsiz;
1714 }
1715 nfsm_clget;
1716 *tl = txdr_unsigned(dp->d_fileno);
1717 bp += NFSX_UNSIGNED;
1718 nfsm_clget;
1719 *tl = txdr_unsigned(nlen);
1720 bp += NFSX_UNSIGNED;
1721
1722 /* And loop around copying the name */
1723 xfer = nlen;
1724 cp = dp->d_name;
1725 while (xfer > 0) {
1726 nfsm_clget;
1727 if ((bp+xfer) > be)
1728 tsiz = be-bp;
1729 else
1730 tsiz = xfer;
1731 bcopy(cp, bp, tsiz);
1732 bp += tsiz;
1733 xfer -= tsiz;
1734 if (xfer > 0)
1735 cp += tsiz;
1736 }
1737 /* And null pad to a long boundary */
1738 for (i = 0; i < rem; i++)
1739 *bp++ = '\0';
1740 nfsm_clget;
1741
1742 /* Finish off the record */
1743 *tl = txdr_unsigned(*cookie);
1744 bp += NFSX_UNSIGNED;
1745 }
1746 invalid:
1747 cpos += dp->d_reclen;
1748 dp = (struct dirent *)cpos;
1749 cookie++;
1750 }
1751 vrele(vp);
1752 nfsm_clget;
1753 *tl = nfs_false;
1754 bp += NFSX_UNSIGNED;
1755 nfsm_clget;
1756 if (eofflag)
1757 *tl = nfs_true;
1758 else
1759 *tl = nfs_false;
1760 bp += NFSX_UNSIGNED;
1761 if (mp != mb) {
1762 if (bp < be)
1763 mp->m_len = bp - mtod(mp, caddr_t);
1764 } else
1765 mp->m_len += bp - bpos;
1766 FREE(cookiebuf, M_TEMP);
1767 FREE(rbuf, M_TEMP);
1768 nfsm_srvdone;
1769 }
1770
1771 /*
1772 * nfs statfs service
1773 */
1774 nfsrv_statfs(nfsd, mrep, md, dpos, cred, nam, mrq)
1775 struct nfsd *nfsd;
1776 struct mbuf *mrep, *md;
1777 caddr_t dpos;
1778 struct ucred *cred;
1779 struct mbuf *nam, **mrq;
1780 {
1781 register struct statfs *sf;
1782 register struct nfsv2_statfs *sfp;
1783 register u_long *tl;
1784 register long t1;
1785 caddr_t bpos;
1786 int error = 0, rdonly, cache, isnq;
1787 char *cp2;
1788 struct mbuf *mb, *mb2, *mreq;
1789 struct vnode *vp;
1790 nfsv2fh_t nfh;
1791 fhandle_t *fhp;
1792 struct statfs statfs;
1793 u_quad_t frev;
1794
1795 fhp = &nfh.fh_generic;
1796 isnq = (nfsd->nd_nqlflag != NQL_NOVAL);
1797 nfsm_srvmtofh(fhp);
1798 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
1799 nfsm_reply(0);
1800 sf = &statfs;
1801 error = VFS_STATFS(vp->v_mount, sf, nfsd->nd_procp);
1802 vput(vp);
1803 nfsm_reply(NFSX_STATFS(isnq));
1804 nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS(isnq));
1805 sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
1806 sfp->sf_bsize = txdr_unsigned(sf->f_bsize);
1807 sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
1808 sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
1809 sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
1810 if (isnq) {
1811 sfp->sf_files = txdr_unsigned(sf->f_files);
1812 sfp->sf_ffree = txdr_unsigned(sf->f_ffree);
1813 }
1814 nfsm_srvdone;
1815 }
1816
1817 /*
1818 * Null operation, used by clients to ping server
1819 */
1820 /* ARGSUSED */
1821 nfsrv_null(nfsd, mrep, md, dpos, cred, nam, mrq)
1822 struct nfsd *nfsd;
1823 struct mbuf *mrep, *md;
1824 caddr_t dpos;
1825 struct ucred *cred;
1826 struct mbuf *nam, **mrq;
1827 {
1828 caddr_t bpos;
1829 int error = VNOVAL, cache;
1830 struct mbuf *mb, *mreq;
1831 u_quad_t frev;
1832
1833 nfsm_reply(0);
1834 return (error);
1835 }
1836
1837 /*
1838 * No operation, used for obsolete procedures
1839 */
1840 /* ARGSUSED */
1841 nfsrv_noop(nfsd, mrep, md, dpos, cred, nam, mrq)
1842 struct nfsd *nfsd;
1843 struct mbuf *mrep, *md;
1844 caddr_t dpos;
1845 struct ucred *cred;
1846 struct mbuf *nam, **mrq;
1847 {
1848 caddr_t bpos;
1849 int error, cache;
1850 struct mbuf *mb, *mreq;
1851 u_quad_t frev;
1852
1853 if (nfsd->nd_repstat)
1854 error = nfsd->nd_repstat;
1855 else
1856 error = EPROCUNAVAIL;
1857 nfsm_reply(0);
1858 return (error);
1859 }
1860
1861 /*
1862 * Perform access checking for vnodes obtained from file handles that would
1863 * refer to files already opened by a Unix client. You cannot just use
1864 * vn_writechk() and VOP_ACCESS() for two reasons.
1865 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
1866 * 2 - The owner is to be given access irrespective of mode bits so that
1867 * processes that chmod after opening a file don't break. I don't like
1868 * this because it opens a security hole, but since the nfs server opens
1869 * a security hole the size of a barn door anyhow, what the heck.
1870 */
1871 nfsrv_access(vp, flags, cred, rdonly, p)
1872 register struct vnode *vp;
1873 int flags;
1874 register struct ucred *cred;
1875 int rdonly;
1876 struct proc *p;
1877 {
1878 struct vattr vattr;
1879 int error;
1880 if (flags & VWRITE) {
1881 /* Just vn_writechk() changed to check rdonly */
1882 /*
1883 * Disallow write attempts on read-only file systems;
1884 * unless the file is a socket or a block or character
1885 * device resident on the file system.
1886 */
1887 if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
1888 switch (vp->v_type) {
1889 case VREG: case VDIR: case VLNK:
1890 return (EROFS);
1891 }
1892 }
1893 /*
1894 * If there's shared text associated with
1895 * the inode, try to free it up once. If
1896 * we fail, we can't allow writing.
1897 */
1898 if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp))
1899 return (ETXTBSY);
1900 }
1901 if (error = VOP_GETATTR(vp, &vattr, cred, p))
1902 return (error);
1903 if ((error = VOP_ACCESS(vp, flags, cred, p)) &&
1904 cred->cr_uid != vattr.va_uid)
1905 return (error);
1906 return (0);
1907 }
1908