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