|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
26: /*
27: * Copyright (c) 1989, 1993
28: * The Regents of the University of California. All rights reserved.
29: *
30: * This code is derived from software contributed to Berkeley by
31: * Rick Macklem at The University of Guelph.
32: *
33: * Redistribution and use in source and binary forms, with or without
34: * modification, are permitted provided that the following conditions
35: * are met:
36: * 1. Redistributions of source code must retain the above copyright
37: * notice, this list of conditions and the following disclaimer.
38: * 2. Redistributions in binary form must reproduce the above copyright
39: * notice, this list of conditions and the following disclaimer in the
40: * documentation and/or other materials provided with the distribution.
41: * 3. All advertising materials mentioning features or use of this software
42: * must display the following acknowledgement:
43: * This product includes software developed by the University of
44: * California, Berkeley and its contributors.
45: * 4. Neither the name of the University nor the names of its contributors
46: * may be used to endorse or promote products derived from this software
47: * without specific prior written permission.
48: *
49: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59: * SUCH DAMAGE.
60: *
61: * @(#)nfs_serv.c 8.7 (Berkeley) 5/14/95
62: * FreeBSD-Id: nfs_serv.c,v 1.52 1997/10/28 15:59:05 bde Exp $
63: */
64:
65: /*
66: * nfs version 2 and 3 server calls to vnode ops
67: * - these routines generally have 3 phases
68: * 1 - break down and validate rpc request in mbuf list
69: * 2 - do the vnode ops for the request
70: * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
71: * 3 - build the rpc reply in an mbuf list
72: * nb:
73: * - do not mix the phases, since the nfsm_?? macros can return failures
74: * on a bad rpc or similar and do not do any vrele() or vput()'s
75: *
76: * - the nfsm_reply() macro generates an nfs rpc reply with the nfs
77: * error number iff error != 0 whereas
78: * returning an error from the server function implies a fatal error
79: * such as a badly constructed rpc request that should be dropped without
80: * a reply.
81: * For Version 3, nfsm_reply() does not return for the error case, since
82: * most version 3 rpcs return more than the status for error cases.
83: */
84:
85: #include <mach_nbc.h>
86: #include <sys/param.h>
87: #include <sys/systm.h>
88: #include <sys/proc.h>
89: #include <sys/namei.h>
90: #include <sys/unistd.h>
91: #include <sys/malloc.h>
92: #include <sys/vnode.h>
93: #include <sys/mount.h>
94: #include <sys/socket.h>
95: #include <sys/socketvar.h>
96: #include <sys/mbuf.h>
97: #include <sys/dirent.h>
98: #include <sys/stat.h>
99: #include <sys/kernel.h>
100: #include <sys/sysctl.h>
101: #include <ufs/ufs/dir.h>
102:
103: #include <sys/vm.h>
104: #include <sys/vmparam.h>
105: #include <machine/spl.h>
106:
107: #include <kern/mapfs.h>
108:
109: #include <nfs/nfsproto.h>
110: #include <nfs/rpcv2.h>
111: #include <nfs/nfs.h>
112: #include <nfs/xdr_subs.h>
113: #include <nfs/nfsm_subs.h>
114: #include <nfs/nqnfs.h>
115:
116: nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
117: NFFIFO, NFNON };
118: #ifndef NFS_NOSERVER
119: nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
120: NFCHR, NFNON };
121: /* Global vars */
122: extern u_long nfs_xdrneg1;
123: extern u_long nfs_false, nfs_true;
124: extern enum vtype nv3tov_type[8];
125: extern struct nfsstats nfsstats;
126:
127: int nfsrvw_procrastinate = NFS_GATHERDELAY * 1000;
128: int nfsrvw_procrastinate_v3 = 0;
129:
130: int nfs_async = 0;
131: #ifdef notyet
132: /* XXX CSM 11/25/97 Upgrade sysctl.h someday */
133: SYSCTL_INT(_vfs_nfs, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0, "");
134: #endif
135:
136: static int nfsrv_access __P((struct vnode *,int,struct ucred *,int,
137: struct proc *));
138: static void nfsrvw_coalesce __P((struct nfsrv_descript *,
139: struct nfsrv_descript *));
140:
141: extern int vnode_uncache(struct vnode *vp);
142:
143: /*
144: * nfs v3 access service
145: */
146: int
147: nfsrv3_access(nfsd, slp, procp, mrq)
148: struct nfsrv_descript *nfsd;
149: struct nfssvc_sock *slp;
150: struct proc *procp;
151: struct mbuf **mrq;
152: {
153: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
154: struct mbuf *nam = nfsd->nd_nam;
155: caddr_t dpos = nfsd->nd_dpos;
156: struct ucred *cred = &nfsd->nd_cr;
157: struct vnode *vp;
158: nfsfh_t nfh;
159: fhandle_t *fhp;
160: register u_long *tl;
161: register long t1;
162: caddr_t bpos;
163: int error = 0, rdonly, cache, getret;
164: char *cp2;
165: struct mbuf *mb, *mreq, *mb2;
166: struct vattr vattr, *vap = &vattr;
167: u_long testmode, nfsmode;
168: u_quad_t frev;
169:
170: #ifndef nolint
171: cache = 0;
172: #endif
173: fhp = &nfh.fh_generic;
174: nfsm_srvmtofh(fhp);
175: nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
176: if ((error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
177: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE))) {
178: nfsm_reply(NFSX_UNSIGNED);
179: nfsm_srvpostop_attr(1, (struct vattr *)0);
180: return (0);
181: }
182: nfsmode = fxdr_unsigned(u_long, *tl);
183: if ((nfsmode & NFSV3ACCESS_READ) &&
184: nfsrv_access(vp, VREAD, cred, rdonly, procp))
185: nfsmode &= ~NFSV3ACCESS_READ;
186: if (vp->v_type == VDIR)
187: testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
188: NFSV3ACCESS_DELETE);
189: else
190: testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
191: if ((nfsmode & testmode) &&
192: nfsrv_access(vp, VWRITE, cred, rdonly, procp))
193: nfsmode &= ~testmode;
194: if (vp->v_type == VDIR)
195: testmode = NFSV3ACCESS_LOOKUP;
196: else
197: testmode = NFSV3ACCESS_EXECUTE;
198: if ((nfsmode & testmode) &&
199: nfsrv_access(vp, VEXEC, cred, rdonly, procp))
200: nfsmode &= ~testmode;
201: getret = VOP_GETATTR(vp, vap, cred, procp);
202: vput(vp);
203: nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED);
204: nfsm_srvpostop_attr(getret, vap);
205: nfsm_build(tl, u_long *, NFSX_UNSIGNED);
206: *tl = txdr_unsigned(nfsmode);
207: nfsm_srvdone;
208: }
209:
210: /*
211: * nfs getattr service
212: */
213: int
214: nfsrv_getattr(nfsd, slp, procp, mrq)
215: struct nfsrv_descript *nfsd;
216: struct nfssvc_sock *slp;
217: struct proc *procp;
218: struct mbuf **mrq;
219: {
220: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
221: struct mbuf *nam = nfsd->nd_nam;
222: caddr_t dpos = nfsd->nd_dpos;
223: struct ucred *cred = &nfsd->nd_cr;
224: register struct nfs_fattr *fp;
225: struct vattr va;
226: register struct vattr *vap = &va;
227: struct vnode *vp;
228: nfsfh_t nfh;
229: fhandle_t *fhp;
230: register u_long *tl;
231: register long t1;
232: caddr_t bpos;
233: int error = 0, rdonly, cache;
234: char *cp2;
235: struct mbuf *mb, *mb2, *mreq;
236: u_quad_t frev;
237:
238: fhp = &nfh.fh_generic;
239: nfsm_srvmtofh(fhp);
240: if ((error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
241: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE))) {
242: nfsm_reply(0);
243: return (0);
244: }
245: nqsrv_getl(vp, ND_READ);
246: error = VOP_GETATTR(vp, vap, cred, procp);
247: vput(vp);
248: nfsm_reply(NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
249: if (error)
250: return (0);
251: nfsm_build(fp, struct nfs_fattr *, NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
252: nfsm_srvfillattr(vap, fp);
253: nfsm_srvdone;
254: }
255:
256: /*
257: * nfs setattr service
258: */
259: int
260: nfsrv_setattr(nfsd, slp, procp, mrq)
261: struct nfsrv_descript *nfsd;
262: struct nfssvc_sock *slp;
263: struct proc *procp;
264: struct mbuf **mrq;
265: {
266: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
267: struct mbuf *nam = nfsd->nd_nam;
268: caddr_t dpos = nfsd->nd_dpos;
269: struct ucred *cred = &nfsd->nd_cr;
270: struct vattr va, preat;
271: register struct vattr *vap = &va;
272: register struct nfsv2_sattr *sp;
273: register struct nfs_fattr *fp;
274: struct vnode *vp;
275: nfsfh_t nfh;
276: fhandle_t *fhp;
277: register u_long *tl;
278: register long t1;
279: caddr_t bpos;
280: int error = 0, rdonly, cache, preat_ret = 1, postat_ret = 1;
281: int v3 = (nfsd->nd_flag & ND_NFSV3), gcheck = 0;
282: char *cp2;
283: struct mbuf *mb, *mb2, *mreq;
284: u_quad_t frev;
285: struct timespec guard;
286:
287: fhp = &nfh.fh_generic;
288: nfsm_srvmtofh(fhp);
289: VATTR_NULL(vap);
290: if (v3) {
291: nfsm_srvsattr(vap);
292: nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
293: gcheck = fxdr_unsigned(int, *tl);
294: if (gcheck) {
295: nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
296: fxdr_nfsv3time(tl, &guard);
297: }
298: } else {
299: nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
300: /*
301: * Nah nah nah nah na nah
302: * There is a bug in the Sun client that puts 0xffff in the mode
303: * field of sattr when it should put in 0xffffffff. The u_short
304: * doesn't sign extend.
305: * --> check the low order 2 bytes for 0xffff
306: */
307: if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
308: vap->va_mode = nfstov_mode(sp->sa_mode);
309: if (sp->sa_uid != nfs_xdrneg1)
310: vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
311: if (sp->sa_gid != nfs_xdrneg1)
312: vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
313: if (sp->sa_size != nfs_xdrneg1)
314: vap->va_size = fxdr_unsigned(u_quad_t, sp->sa_size);
315: if (sp->sa_atime.nfsv2_sec != nfs_xdrneg1) {
316: #ifdef notyet
317: fxdr_nfsv2time(&sp->sa_atime, &vap->va_atime);
318: #else
319: vap->va_atime.tv_sec =
320: fxdr_unsigned(long, sp->sa_atime.nfsv2_sec);
321: vap->va_atime.tv_nsec = 0;
322: #endif
323: }
324: if (sp->sa_mtime.nfsv2_sec != nfs_xdrneg1)
325: fxdr_nfsv2time(&sp->sa_mtime, &vap->va_mtime);
326:
327: }
328:
329: /*
330: * Now that we have all the fields, lets do it.
331: */
332: if ((error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
333: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE))) {
334: nfsm_reply(2 * NFSX_UNSIGNED);
335: nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
336: return (0);
337: }
338: nqsrv_getl(vp, ND_WRITE);
339: if (v3) {
340: error = preat_ret = VOP_GETATTR(vp, &preat, cred, procp);
341: if (!error && gcheck &&
342: (preat.va_ctime.tv_sec != guard.tv_sec ||
343: preat.va_ctime.tv_nsec != guard.tv_nsec))
344: error = NFSERR_NOT_SYNC;
345: if (error) {
346: vput(vp);
347: nfsm_reply(NFSX_WCCDATA(v3));
348: nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
349: return (0);
350: }
351: }
352:
353: /*
354: * If the size is being changed write acces is required, otherwise
355: * just check for a read only file system.
356: */
357: if (vap->va_size == ((u_quad_t)((quad_t) -1))) {
358: if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
359: error = EROFS;
360: goto out;
361: }
362: } else {
363: if (vp->v_type == VDIR) {
364: error = EISDIR;
365: goto out;
366: } else if ((error = nfsrv_access(vp, VWRITE, cred, rdonly,
367: procp)))
368: goto out;
369: }
370: error = VOP_SETATTR(vp, vap, cred, procp);
371: postat_ret = VOP_GETATTR(vp, vap, cred, procp);
372: if (!error)
373: error = postat_ret;
374: out:
375: vput(vp);
376: nfsm_reply(NFSX_WCCORFATTR(v3));
377: if (v3) {
378: nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
379: return (0);
380: } else {
381: nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
382: nfsm_srvfillattr(vap, fp);
383: }
384: nfsm_srvdone;
385: }
386:
387: /*
388: * nfs lookup rpc
389: */
390: int
391: nfsrv_lookup(nfsd, slp, procp, mrq)
392: struct nfsrv_descript *nfsd;
393: struct nfssvc_sock *slp;
394: struct proc *procp;
395: struct mbuf **mrq;
396: {
397: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
398: struct mbuf *nam = nfsd->nd_nam;
399: caddr_t dpos = nfsd->nd_dpos;
400: struct ucred *cred = &nfsd->nd_cr;
401: register struct nfs_fattr *fp;
402: struct nameidata nd, *ndp = &nd;
403: #ifdef notdef
404: struct nameidata ind;
405: #endif
406: struct vnode *vp, *dirp;
407: nfsfh_t nfh;
408: fhandle_t *fhp;
409: register caddr_t cp;
410: register u_long *tl;
411: register long t1;
412: caddr_t bpos;
413: int error = 0, cache, len, dirattr_ret = 1;
414: int v3 = (nfsd->nd_flag & ND_NFSV3), pubflag;
415: char *cp2;
416: struct mbuf *mb, *mb2, *mreq;
417: struct vattr va, dirattr, *vap = &va;
418: u_quad_t frev;
419:
420: fhp = &nfh.fh_generic;
421: nfsm_srvmtofh(fhp);
422: nfsm_srvnamesiz(len);
423:
424: pubflag = nfs_ispublicfh(fhp);
425:
426: nd.ni_cnd.cn_cred = cred;
427: nd.ni_cnd.cn_nameiop = LOOKUP;
428: nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART;
429: error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
430: &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), pubflag);
431:
432: /* XXX CSM 12/4/97 Revisit when enabling WebNFS */
433: #ifdef notyet
434: if (!error && pubflag) {
435: if (nd.ni_vp->v_type == VDIR && nfs_pub.np_index != NULL) {
436: /*
437: * Setup call to lookup() to see if we can find
438: * the index file. Arguably, this doesn't belong
439: * in a kernel.. Ugh.
440: */
441: ind = nd;
442: VOP_UNLOCK(nd.ni_vp, 0, procp);
443: ind.ni_pathlen = strlen(nfs_pub.np_index);
444: ind.ni_cnd.cn_nameptr = ind.ni_cnd.cn_pnbuf =
445: nfs_pub.np_index;
446: ind.ni_startdir = nd.ni_vp;
447: VREF(ind.ni_startdir);
448: error = lookup(&ind);
449: if (!error) {
450: /*
451: * Found an index file. Get rid of
452: * the old references.
453: */
454: if (dirp)
455: vrele(dirp);
456: dirp = nd.ni_vp;
457: vrele(nd.ni_startdir);
458: ndp = &ind;
459: } else
460: error = 0;
461: }
462: /*
463: * If the public filehandle was used, check that this lookup
464: * didn't result in a filehandle outside the publicly exported
465: * filesystem.
466: */
467:
468: if (!error && ndp->ni_vp->v_mount != nfs_pub.np_mount) {
469: vput(nd.ni_vp);
470: error = EPERM;
471: }
472: }
473: #endif
474:
475: if (dirp) {
476: if (v3)
477: dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred,
478: procp);
479: vrele(dirp);
480: }
481:
482: if (error) {
483: nfsm_reply(NFSX_POSTOPATTR(v3));
484: nfsm_srvpostop_attr(dirattr_ret, &dirattr);
485: return (0);
486: }
487:
488: nqsrv_getl(ndp->ni_startdir, ND_READ);
489: vrele(ndp->ni_startdir);
490: FREE_ZONE(nd.ni_cnd.cn_pnbuf, nd.ni_cnd.cn_pnlen, M_NAMEI);
491: vp = ndp->ni_vp;
492: bzero((caddr_t)fhp, sizeof(nfh));
493: fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
494: error = VFS_VPTOFH(vp, &fhp->fh_fid);
495: if (!error)
496: error = VOP_GETATTR(vp, vap, cred, procp);
497: vput(vp);
498: nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPORFATTR(v3) + NFSX_POSTOPATTR(v3));
499: if (error) {
500: nfsm_srvpostop_attr(dirattr_ret, &dirattr);
501: return (0);
502: }
503: nfsm_srvfhtom(fhp, v3);
504: if (v3) {
505: nfsm_srvpostop_attr(0, vap);
506: nfsm_srvpostop_attr(dirattr_ret, &dirattr);
507: } else {
508: nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
509: nfsm_srvfillattr(vap, fp);
510: }
511: nfsm_srvdone;
512: }
513:
514: /*
515: * nfs readlink service
516: */
517: int
518: nfsrv_readlink(nfsd, slp, procp, mrq)
519: struct nfsrv_descript *nfsd;
520: struct nfssvc_sock *slp;
521: struct proc *procp;
522: struct mbuf **mrq;
523: {
524: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
525: struct mbuf *nam = nfsd->nd_nam;
526: caddr_t dpos = nfsd->nd_dpos;
527: struct ucred *cred = &nfsd->nd_cr;
528: struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
529: register struct iovec *ivp = iv;
530: register struct mbuf *mp;
531: register u_long *tl;
532: register long t1;
533: caddr_t bpos;
534: int error = 0, rdonly, cache, i, tlen, len, getret;
535: int v3 = (nfsd->nd_flag & ND_NFSV3);
536: char *cp2;
537: struct mbuf *mb, *mb2, *mp2, *mp3, *mreq;
538: struct vnode *vp;
539: struct vattr attr;
540: nfsfh_t nfh;
541: fhandle_t *fhp;
542: struct uio io, *uiop = &io;
543: u_quad_t frev;
544:
545: #ifndef nolint
546: mp2 = mp3 = (struct mbuf *)0;
547: #endif
548: fhp = &nfh.fh_generic;
549: nfsm_srvmtofh(fhp);
550: len = 0;
551: i = 0;
552: while (len < NFS_MAXPATHLEN) {
553: MGET(mp, M_WAIT, MT_DATA);
554: MCLGET(mp, M_WAIT);
555: mp->m_len = NFSMSIZ(mp);
556: if (len == 0)
557: mp3 = mp2 = mp;
558: else {
559: mp2->m_next = mp;
560: mp2 = mp;
561: }
562: if ((len+mp->m_len) > NFS_MAXPATHLEN) {
563: mp->m_len = NFS_MAXPATHLEN-len;
564: len = NFS_MAXPATHLEN;
565: } else
566: len += mp->m_len;
567: ivp->iov_base = mtod(mp, caddr_t);
568: ivp->iov_len = mp->m_len;
569: i++;
570: ivp++;
571: }
572: uiop->uio_iov = iv;
573: uiop->uio_iovcnt = i;
574: uiop->uio_offset = 0;
575: uiop->uio_resid = len;
576: uiop->uio_rw = UIO_READ;
577: uiop->uio_segflg = UIO_SYSSPACE;
578: uiop->uio_procp = (struct proc *)0;
579: if ((error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
580: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE))) {
581: m_freem(mp3);
582: nfsm_reply(2 * NFSX_UNSIGNED);
583: nfsm_srvpostop_attr(1, (struct vattr *)0);
584: return (0);
585: }
586: if (vp->v_type != VLNK) {
587: if (v3)
588: error = EINVAL;
589: else
590: error = ENXIO;
591: goto out;
592: }
593: nqsrv_getl(vp, ND_READ);
594: error = VOP_READLINK(vp, uiop, cred);
595: out:
596: getret = VOP_GETATTR(vp, &attr, cred, procp);
597: vput(vp);
598: if (error)
599: m_freem(mp3);
600: nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_UNSIGNED);
601: if (v3) {
602: nfsm_srvpostop_attr(getret, &attr);
603: if (error)
604: return (0);
605: }
606: if (uiop->uio_resid > 0) {
607: len -= uiop->uio_resid;
608: tlen = nfsm_rndup(len);
609: nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len);
610: }
611: nfsm_build(tl, u_long *, NFSX_UNSIGNED);
612: *tl = txdr_unsigned(len);
613: mb->m_next = mp3;
614: nfsm_srvdone;
615: }
616:
617: /*
618: * nfs read service
619: */
620: int
621: nfsrv_read(nfsd, slp, procp, mrq)
622: struct nfsrv_descript *nfsd;
623: struct nfssvc_sock *slp;
624: struct proc *procp;
625: struct mbuf **mrq;
626: {
627: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
628: struct mbuf *nam = nfsd->nd_nam;
629: caddr_t dpos = nfsd->nd_dpos;
630: struct ucred *cred = &nfsd->nd_cr;
631: register struct iovec *iv;
632: struct iovec *iv2;
633: register struct mbuf *m;
634: register struct nfs_fattr *fp;
635: register u_long *tl;
636: register long t1;
637: register int i;
638: caddr_t bpos;
639: int error = 0, rdonly, cache, cnt, len, left, siz, tlen, getret;
640: int v3 = (nfsd->nd_flag & ND_NFSV3), reqlen;
641: char *cp2;
642: struct mbuf *mb, *mb2, *mreq;
643: struct mbuf *m2;
644: struct vnode *vp;
645: nfsfh_t nfh;
646: fhandle_t *fhp;
647: struct uio io, *uiop = &io;
648: struct vattr va, *vap = &va;
649: off_t off;
650: u_quad_t frev;
651:
652: fhp = &nfh.fh_generic;
653: nfsm_srvmtofh(fhp);
654: if (v3) {
655: nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
656: fxdr_hyper(tl, &off);
657: } else {
658: nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
659: off = (off_t)fxdr_unsigned(u_long, *tl);
660: }
661: nfsm_srvstrsiz(reqlen, NFS_SRVMAXDATA(nfsd));
662: if ((error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
663: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE))) {
664: nfsm_reply(2 * NFSX_UNSIGNED);
665: nfsm_srvpostop_attr(1, (struct vattr *)0);
666: return (0);
667: }
668: if (vp->v_type != VREG) {
669: if (v3)
670: error = EINVAL;
671: else
672: error = (vp->v_type == VDIR) ? EISDIR : EACCES;
673: }
674: if (!error) {
675: nqsrv_getl(vp, ND_READ);
676: if ((error = nfsrv_access(vp, VREAD, cred, rdonly, procp)))
677: error = nfsrv_access(vp, VEXEC, cred, rdonly, procp);
678: }
679: getret = VOP_GETATTR(vp, vap, cred, procp);
680: if (!error)
681: error = getret;
682: if (error) {
683: vput(vp);
684: nfsm_reply(NFSX_POSTOPATTR(v3));
685: nfsm_srvpostop_attr(getret, vap);
686: return (0);
687: }
688: if (off >= vap->va_size)
689: cnt = 0;
690: else if ((off + reqlen) > vap->va_size)
691: cnt = nfsm_rndup(vap->va_size - off);
692: else
693: cnt = reqlen;
694: nfsm_reply(NFSX_POSTOPORFATTR(v3) + 3 * NFSX_UNSIGNED+nfsm_rndup(cnt));
695: if (v3) {
696: nfsm_build(tl, u_long *, NFSX_V3FATTR + 4 * NFSX_UNSIGNED);
697: *tl++ = nfs_true;
698: fp = (struct nfs_fattr *)tl;
699: tl += (NFSX_V3FATTR / sizeof (u_long));
700: } else {
701: nfsm_build(tl, u_long *, NFSX_V2FATTR + NFSX_UNSIGNED);
702: fp = (struct nfs_fattr *)tl;
703: tl += (NFSX_V2FATTR / sizeof (u_long));
704: }
705: len = left = cnt;
706: if (cnt > 0) {
707: /*
708: * Generate the mbuf list with the uio_iov ref. to it.
709: */
710: i = 0;
711: m = m2 = mb;
712: while (left > 0) {
713: siz = min(M_TRAILINGSPACE(m), left);
714: if (siz > 0) {
715: left -= siz;
716: i++;
717: }
718: if (left > 0) {
719: MGET(m, M_WAIT, MT_DATA);
720: MCLGET(m, M_WAIT);
721: m->m_len = 0;
722: m2->m_next = m;
723: m2 = m;
724: }
725: }
726: MALLOC(iv, struct iovec *, i * sizeof (struct iovec),
727: M_TEMP, M_WAITOK);
728: uiop->uio_iov = iv2 = iv;
729: m = mb;
730: left = cnt;
731: i = 0;
732: while (left > 0) {
733: if (m == NULL)
734: panic("nfsrv_read iov");
735: siz = min(M_TRAILINGSPACE(m), left);
736: if (siz > 0) {
737: iv->iov_base = mtod(m, caddr_t) + m->m_len;
738: iv->iov_len = siz;
739: m->m_len += siz;
740: left -= siz;
741: iv++;
742: i++;
743: }
744: m = m->m_next;
745: }
746: uiop->uio_iovcnt = i;
747: uiop->uio_offset = off;
748: uiop->uio_resid = cnt;
749: uiop->uio_rw = UIO_READ;
750: uiop->uio_segflg = UIO_SYSSPACE;
751: #if MACH_NBC
752: if (vp->v_type == VREG) {
753: uiop->uio_procp = procp;
754: map_vnode(vp, procp);
755: error = mapfs_io(vp, uiop, uiop->uio_rw,
756: IO_NODELOCKED, cred);
757: unmap_vnode(vp, procp);
758: } else
759: #endif /* MACH_NBC */
760: error = VOP_READ(vp, uiop, IO_NODELOCKED, cred);
761: off = uiop->uio_offset;
762: FREE((caddr_t)iv2, M_TEMP);
763: if (error || (getret = VOP_GETATTR(vp, vap, cred, procp))) {
764: if (!error)
765: error = getret;
766: m_freem(mreq);
767: vput(vp);
768: nfsm_reply(NFSX_POSTOPATTR(v3));
769: nfsm_srvpostop_attr(getret, vap);
770: return (0);
771: }
772: } else
773: uiop->uio_resid = 0;
774: vput(vp);
775: nfsm_srvfillattr(vap, fp);
776: len -= uiop->uio_resid;
777: tlen = nfsm_rndup(len);
778: if (cnt != tlen || tlen != len)
779: nfsm_adj(mb, cnt - tlen, tlen - len);
780: if (v3) {
781: *tl++ = txdr_unsigned(len);
782: if (len < reqlen)
783: *tl++ = nfs_true;
784: else
785: *tl++ = nfs_false;
786: }
787: *tl = txdr_unsigned(len);
788: nfsm_srvdone;
789: }
790:
791: /*
792: * nfs write service
793: */
794: int
795: nfsrv_write(nfsd, slp, procp, mrq)
796: struct nfsrv_descript *nfsd;
797: struct nfssvc_sock *slp;
798: struct proc *procp;
799: struct mbuf **mrq;
800: {
801: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
802: struct mbuf *nam = nfsd->nd_nam;
803: caddr_t dpos = nfsd->nd_dpos;
804: struct ucred *cred = &nfsd->nd_cr;
805: register struct iovec *ivp;
806: register int i, cnt;
807: register struct mbuf *mp;
808: register struct nfs_fattr *fp;
809: struct iovec *iv;
810: struct vattr va, forat;
811: register struct vattr *vap = &va;
812: register u_long *tl;
813: register long t1;
814: caddr_t bpos;
815: int error = 0, rdonly, cache, len, forat_ret = 1;
816: int ioflags, aftat_ret = 1, retlen, zeroing, adjust;
817: int stable = NFSV3WRITE_FILESYNC;
818: int v3 = (nfsd->nd_flag & ND_NFSV3);
819: char *cp2;
820: struct mbuf *mb, *mb2, *mreq;
821: struct vnode *vp;
822: nfsfh_t nfh;
823: fhandle_t *fhp;
824: struct uio io, *uiop = &io;
825: off_t off;
826: u_quad_t frev;
827:
828: if (mrep == NULL) {
829: *mrq = NULL;
830: return (0);
831: }
832: fhp = &nfh.fh_generic;
833: nfsm_srvmtofh(fhp);
834: if (v3) {
835: nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
836: fxdr_hyper(tl, &off);
837: tl += 3;
838: stable = fxdr_unsigned(int, *tl++);
839: } else {
840: nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
841: off = (off_t)fxdr_unsigned(u_long, *++tl);
842: tl += 2;
843: if (nfs_async)
844: stable = NFSV3WRITE_UNSTABLE;
845: }
846: retlen = len = fxdr_unsigned(long, *tl);
847: cnt = i = 0;
848:
849: /*
850: * For NFS Version 2, it is not obvious what a write of zero length
851: * should do, but I might as well be consistent with Version 3,
852: * which is to return ok so long as there are no permission problems.
853: */
854: if (len > 0) {
855: zeroing = 1;
856: mp = mrep;
857: while (mp) {
858: if (mp == md) {
859: zeroing = 0;
860: adjust = dpos - mtod(mp, caddr_t);
861: mp->m_len -= adjust;
862: if (mp->m_len > 0 && adjust > 0)
863: NFSMADV(mp, adjust);
864: }
865: if (zeroing)
866: mp->m_len = 0;
867: else if (mp->m_len > 0) {
868: i += mp->m_len;
869: if (i > len) {
870: mp->m_len -= (i - len);
871: zeroing = 1;
872: }
873: if (mp->m_len > 0)
874: cnt++;
875: }
876: mp = mp->m_next;
877: }
878: }
879: if (len > NFS_MAXDATA || len < 0 || i < len) {
880: error = EIO;
881: nfsm_reply(2 * NFSX_UNSIGNED);
882: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
883: return (0);
884: }
885: if ((error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
886: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE))) {
887: nfsm_reply(2 * NFSX_UNSIGNED);
888: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
889: return (0);
890: }
891: if (v3)
892: forat_ret = VOP_GETATTR(vp, &forat, cred, procp);
893: if (vp->v_type != VREG) {
894: if (v3)
895: error = EINVAL;
896: else
897: error = (vp->v_type == VDIR) ? EISDIR : EACCES;
898: }
899: if (!error) {
900: nqsrv_getl(vp, ND_WRITE);
901: error = nfsrv_access(vp, VWRITE, cred, rdonly, procp);
902: }
903: if (error) {
904: vput(vp);
905: nfsm_reply(NFSX_WCCDATA(v3));
906: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
907: return (0);
908: }
909:
910: if (len > 0) {
911: MALLOC(ivp, struct iovec *, cnt * sizeof (struct iovec), M_TEMP,
912: M_WAITOK);
913: uiop->uio_iov = iv = ivp;
914: uiop->uio_iovcnt = cnt;
915: mp = mrep;
916: while (mp) {
917: if (mp->m_len > 0) {
918: ivp->iov_base = mtod(mp, caddr_t);
919: ivp->iov_len = mp->m_len;
920: ivp++;
921: }
922: mp = mp->m_next;
923: }
924:
925: /*
926: * XXX
927: * The IO_METASYNC flag indicates that all metadata (and not just
928: * enough to ensure data integrity) mus be written to stable storage
929: * synchronously.
930: * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
931: */
932: if (stable == NFSV3WRITE_UNSTABLE)
933: ioflags = IO_NODELOCKED;
934: else if (stable == NFSV3WRITE_DATASYNC)
935: ioflags = (IO_SYNC | IO_NODELOCKED);
936: else
937: ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
938: uiop->uio_resid = len;
939: uiop->uio_rw = UIO_WRITE;
940: uiop->uio_segflg = UIO_SYSSPACE;
941: uiop->uio_procp = (struct proc *)0;
942: uiop->uio_offset = off;
943: #if MACH_NBC
944: if (vp->v_type == VREG) {
945: map_vnode(vp, procp);
946: error = mapfs_io(vp, uiop, uiop->uio_rw, ioflags, cred);
947: unmap_vnode(vp, procp);
948: } else
949: #endif /* MACH_NBC */
950: error = VOP_WRITE(vp, uiop, ioflags, cred);
951: nfsstats.srvvop_writes++;
952: FREE((caddr_t)iv, M_TEMP);
953: }
954: aftat_ret = VOP_GETATTR(vp, vap, cred, procp);
955: vput(vp);
956: if (!error)
957: error = aftat_ret;
958: nfsm_reply(NFSX_PREOPATTR(v3) + NFSX_POSTOPORFATTR(v3) +
959: 2 * NFSX_UNSIGNED + NFSX_WRITEVERF(v3));
960: if (v3) {
961: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
962: if (error)
963: return (0);
964: nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
965: *tl++ = txdr_unsigned(retlen);
966: /*
967: * If nfs_async is set, then pretend the write was FILESYNC.
968: */
969: if (stable == NFSV3WRITE_UNSTABLE && !nfs_async)
970: *tl++ = txdr_unsigned(stable);
971: else
972: *tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC);
973: /*
974: * Actually, there is no need to txdr these fields,
975: * but it may make the values more human readable,
976: * for debugging purposes.
977: */
978: *tl++ = txdr_unsigned(boottime.tv_sec);
979: *tl = txdr_unsigned(boottime.tv_usec);
980: } else {
981: nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
982: nfsm_srvfillattr(vap, fp);
983: }
984: nfsm_srvdone;
985: }
986:
987: /*
988: * NFS write service with write gathering support. Called when
989: * nfsrvw_procrastinate > 0.
990: * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
991: * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
992: * Jan. 1994.
993: */
994: int
995: nfsrv_writegather(ndp, slp, procp, mrq)
996: struct nfsrv_descript **ndp;
997: struct nfssvc_sock *slp;
998: struct proc *procp;
999: struct mbuf **mrq;
1000: {
1001: register struct iovec *ivp;
1002: register struct mbuf *mp;
1003: register struct nfsrv_descript *wp, *nfsd, *owp, *swp;
1004: register struct nfs_fattr *fp;
1005: register int i;
1006: struct iovec *iov;
1007: struct nfsrvw_delayhash *wpp;
1008: struct ucred *cred;
1009: struct vattr va, forat;
1010: register u_long *tl;
1011: register long t1;
1012: caddr_t bpos, dpos;
1013: int error = 0, rdonly, cache, len, forat_ret = 1;
1014: int ioflags, aftat_ret = 1, s, adjust, v3, zeroing;
1015: char *cp2;
1016: struct mbuf *mb, *mb2, *mreq, *mrep, *md;
1017: struct vnode *vp;
1018: struct uio io, *uiop = &io;
1019: u_quad_t frev, cur_usec;
1020:
1021: #ifndef nolint
1022: i = 0;
1023: len = 0;
1024: #endif
1025: *mrq = NULL;
1026: if (*ndp) {
1027: nfsd = *ndp;
1028: *ndp = NULL;
1029: mrep = nfsd->nd_mrep;
1030: md = nfsd->nd_md;
1031: dpos = nfsd->nd_dpos;
1032: cred = &nfsd->nd_cr;
1033: v3 = (nfsd->nd_flag & ND_NFSV3);
1034: LIST_INIT(&nfsd->nd_coalesce);
1035: nfsd->nd_mreq = NULL;
1036: nfsd->nd_stable = NFSV3WRITE_FILESYNC;
1037: cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec;
1038: nfsd->nd_time = cur_usec +
1039: (v3 ? nfsrvw_procrastinate_v3 : nfsrvw_procrastinate);
1040:
1041: /*
1042: * Now, get the write header..
1043: */
1044: nfsm_srvmtofh(&nfsd->nd_fh);
1045: if (v3) {
1046: nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
1047: fxdr_hyper(tl, &nfsd->nd_off);
1048: tl += 3;
1049: nfsd->nd_stable = fxdr_unsigned(int, *tl++);
1050: } else {
1051: nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
1052: nfsd->nd_off = (off_t)fxdr_unsigned(u_long, *++tl);
1053: tl += 2;
1054: if (nfs_async)
1055: nfsd->nd_stable = NFSV3WRITE_UNSTABLE;
1056: }
1057: len = fxdr_unsigned(long, *tl);
1058: nfsd->nd_len = len;
1059: nfsd->nd_eoff = nfsd->nd_off + len;
1060:
1061: /*
1062: * Trim the header out of the mbuf list and trim off any trailing
1063: * junk so that the mbuf list has only the write data.
1064: */
1065: zeroing = 1;
1066: i = 0;
1067: mp = mrep;
1068: while (mp) {
1069: if (mp == md) {
1070: zeroing = 0;
1071: adjust = dpos - mtod(mp, caddr_t);
1072: mp->m_len -= adjust;
1073: if (mp->m_len > 0 && adjust > 0)
1074: NFSMADV(mp, adjust);
1075: }
1076: if (zeroing)
1077: mp->m_len = 0;
1078: else {
1079: i += mp->m_len;
1080: if (i > len) {
1081: mp->m_len -= (i - len);
1082: zeroing = 1;
1083: }
1084: }
1085: mp = mp->m_next;
1086: }
1087: if (len > NFS_MAXDATA || len < 0 || i < len) {
1088: nfsmout:
1089: m_freem(mrep);
1090: error = EIO;
1091: nfsm_writereply(2 * NFSX_UNSIGNED, v3);
1092: if (v3)
1093: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1094: nfsd->nd_mreq = mreq;
1095: nfsd->nd_mrep = NULL;
1096: nfsd->nd_time = 0;
1097: }
1098:
1099: /*
1100: * Add this entry to the hash and time queues.
1101: */
1102: s = splsoftclock();
1103: owp = NULL;
1104: wp = slp->ns_tq.lh_first;
1105: while (wp && wp->nd_time < nfsd->nd_time) {
1106: owp = wp;
1107: wp = wp->nd_tq.le_next;
1108: }
1109: NFS_DPF(WG, ("Q%03x", nfsd->nd_retxid & 0xfff));
1110: if (owp) {
1111: LIST_INSERT_AFTER(owp, nfsd, nd_tq);
1112: } else {
1113: LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
1114: }
1115: if (nfsd->nd_mrep) {
1116: wpp = NWDELAYHASH(slp, nfsd->nd_fh.fh_fid.fid_data);
1117: owp = NULL;
1118: wp = wpp->lh_first;
1119: while (wp &&
1120: bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) {
1121: owp = wp;
1122: wp = wp->nd_hash.le_next;
1123: }
1124: while (wp && wp->nd_off < nfsd->nd_off &&
1125: !bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) {
1126: owp = wp;
1127: wp = wp->nd_hash.le_next;
1128: }
1129: if (owp) {
1130: LIST_INSERT_AFTER(owp, nfsd, nd_hash);
1131:
1132: /*
1133: * Search the hash list for overlapping entries and
1134: * coalesce.
1135: */
1136: for(; nfsd && NFSW_CONTIG(owp, nfsd); nfsd = wp) {
1137: wp = nfsd->nd_hash.le_next;
1138: if (NFSW_SAMECRED(owp, nfsd))
1139: nfsrvw_coalesce(owp, nfsd);
1140: }
1141: } else {
1142: LIST_INSERT_HEAD(wpp, nfsd, nd_hash);
1143: }
1144: }
1145: splx(s);
1146: }
1147:
1148: /*
1149: * Now, do VOP_WRITE()s for any one(s) that need to be done now
1150: * and generate the associated reply mbuf list(s).
1151: */
1152: loop1:
1153: cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec;
1154: s = splsoftclock();
1155: for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = owp) {
1156: owp = nfsd->nd_tq.le_next;
1157: if (nfsd->nd_time > cur_usec)
1158: break;
1159: if (nfsd->nd_mreq)
1160: continue;
1161: NFS_DPF(WG, ("P%03x", nfsd->nd_retxid & 0xfff));
1162: LIST_REMOVE(nfsd, nd_tq);
1163: LIST_REMOVE(nfsd, nd_hash);
1164: splx(s);
1165: mrep = nfsd->nd_mrep;
1166: nfsd->nd_mrep = NULL;
1167: cred = &nfsd->nd_cr;
1168: v3 = (nfsd->nd_flag & ND_NFSV3);
1169: forat_ret = aftat_ret = 1;
1170: error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &vp, cred, slp,
1171: nfsd->nd_nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
1172: if (!error) {
1173: if (v3)
1174: forat_ret = VOP_GETATTR(vp, &forat, cred, procp);
1175: if (vp->v_type != VREG) {
1176: if (v3)
1177: error = EINVAL;
1178: else
1179: error = (vp->v_type == VDIR) ? EISDIR : EACCES;
1180: }
1181: } else
1182: vp = NULL;
1183: if (!error) {
1184: nqsrv_getl(vp, ND_WRITE);
1185: error = nfsrv_access(vp, VWRITE, cred, rdonly, procp);
1186: }
1187:
1188: if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE)
1189: ioflags = IO_NODELOCKED;
1190: else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC)
1191: ioflags = (IO_SYNC | IO_NODELOCKED);
1192: else
1193: ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
1194: uiop->uio_rw = UIO_WRITE;
1195: uiop->uio_segflg = UIO_SYSSPACE;
1196: uiop->uio_procp = (struct proc *)0;
1197: uiop->uio_offset = nfsd->nd_off;
1198: uiop->uio_resid = nfsd->nd_eoff - nfsd->nd_off;
1199: if (uiop->uio_resid > 0) {
1200: mp = mrep;
1201: i = 0;
1202: while (mp) {
1203: if (mp->m_len > 0)
1204: i++;
1205: mp = mp->m_next;
1206: }
1207: uiop->uio_iovcnt = i;
1208: MALLOC(iov, struct iovec *, i * sizeof (struct iovec),
1209: M_TEMP, M_WAITOK);
1210: uiop->uio_iov = ivp = iov;
1211: mp = mrep;
1212: while (mp) {
1213: if (mp->m_len > 0) {
1214: ivp->iov_base = mtod(mp, caddr_t);
1215: ivp->iov_len = mp->m_len;
1216: ivp++;
1217: }
1218: mp = mp->m_next;
1219: }
1220: if (!error) {
1221: #if MACH_NBC
1222: if (vp->v_type == VREG) {
1223: map_vnode(vp, procp);
1224: error = mapfs_io(vp, uiop, uiop->uio_rw,
1225: ioflags, cred);
1226: unmap_vnode(vp, procp);
1227: } else
1228: #endif /* MACH_NBC */
1229: error = VOP_WRITE(vp, uiop, ioflags, cred);
1230: nfsstats.srvvop_writes++;
1231: }
1232: FREE((caddr_t)iov, M_TEMP);
1233: }
1234: m_freem(mrep);
1235: if (vp) {
1236: aftat_ret = VOP_GETATTR(vp, &va, cred, procp);
1237: vput(vp);
1238: }
1239:
1240: /*
1241: * Loop around generating replies for all write rpcs that have
1242: * now been completed.
1243: */
1244: swp = nfsd;
1245: do {
1246: NFS_DPF(WG, ("R%03x", nfsd->nd_retxid & 0xfff));
1247: if (error) {
1248: nfsm_writereply(NFSX_WCCDATA(v3), v3);
1249: if (v3) {
1250: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1251: }
1252: } else {
1253: nfsm_writereply(NFSX_PREOPATTR(v3) +
1254: NFSX_POSTOPORFATTR(v3) + 2 * NFSX_UNSIGNED +
1255: NFSX_WRITEVERF(v3), v3);
1256: if (v3) {
1257: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1258: nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
1259: *tl++ = txdr_unsigned(nfsd->nd_len);
1260: *tl++ = txdr_unsigned(swp->nd_stable);
1261: /*
1262: * Actually, there is no need to txdr these fields,
1263: * but it may make the values more human readable,
1264: * for debugging purposes.
1265: */
1266: *tl++ = txdr_unsigned(boottime.tv_sec);
1267: *tl = txdr_unsigned(boottime.tv_usec);
1268: } else {
1269: nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
1270: nfsm_srvfillattr(&va, fp);
1271: }
1272: }
1273: nfsd->nd_mreq = mreq;
1274: if (nfsd->nd_mrep)
1275: panic("nfsrv_write: nd_mrep not free");
1276:
1277: /*
1278: * Done. Put it at the head of the timer queue so that
1279: * the final phase can return the reply.
1280: */
1281: s = splsoftclock();
1282: if (nfsd != swp) {
1283: nfsd->nd_time = 0;
1284: LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
1285: }
1286: nfsd = swp->nd_coalesce.lh_first;
1287: if (nfsd) {
1288: LIST_REMOVE(nfsd, nd_tq);
1289: }
1290: splx(s);
1291: } while (nfsd);
1292: s = splsoftclock();
1293: swp->nd_time = 0;
1294: LIST_INSERT_HEAD(&slp->ns_tq, swp, nd_tq);
1295: splx(s);
1296: goto loop1;
1297: }
1298: splx(s);
1299:
1300: /*
1301: * Search for a reply to return.
1302: */
1303: s = splsoftclock();
1304: for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = nfsd->nd_tq.le_next)
1305: if (nfsd->nd_mreq) {
1306: NFS_DPF(WG, ("X%03x", nfsd->nd_retxid & 0xfff));
1307: LIST_REMOVE(nfsd, nd_tq);
1308: *mrq = nfsd->nd_mreq;
1309: *ndp = nfsd;
1310: break;
1311: }
1312: splx(s);
1313: return (0);
1314: }
1315:
1316: /*
1317: * Coalesce the write request nfsd into owp. To do this we must:
1318: * - remove nfsd from the queues
1319: * - merge nfsd->nd_mrep into owp->nd_mrep
1320: * - update the nd_eoff and nd_stable for owp
1321: * - put nfsd on owp's nd_coalesce list
1322: * NB: Must be called at splsoftclock().
1323: */
1324: static void
1325: nfsrvw_coalesce(owp, nfsd)
1326: register struct nfsrv_descript *owp;
1327: register struct nfsrv_descript *nfsd;
1328: {
1329: register int overlap;
1330: register struct mbuf *mp;
1331: struct nfsrv_descript *p;
1332:
1333: NFS_DPF(WG, ("C%03x-%03x",
1334: nfsd->nd_retxid & 0xfff, owp->nd_retxid & 0xfff));
1335: LIST_REMOVE(nfsd, nd_hash);
1336: LIST_REMOVE(nfsd, nd_tq);
1337: if (owp->nd_eoff < nfsd->nd_eoff) {
1338: overlap = owp->nd_eoff - nfsd->nd_off;
1339: if (overlap < 0)
1340: panic("nfsrv_coalesce: bad off");
1341: if (overlap > 0)
1342: m_adj(nfsd->nd_mrep, overlap);
1343: mp = owp->nd_mrep;
1344: while (mp->m_next)
1345: mp = mp->m_next;
1346: mp->m_next = nfsd->nd_mrep;
1347: owp->nd_eoff = nfsd->nd_eoff;
1348: } else
1349: m_freem(nfsd->nd_mrep);
1350: nfsd->nd_mrep = NULL;
1351: if (nfsd->nd_stable == NFSV3WRITE_FILESYNC)
1352: owp->nd_stable = NFSV3WRITE_FILESYNC;
1353: else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC &&
1354: owp->nd_stable == NFSV3WRITE_UNSTABLE)
1355: owp->nd_stable = NFSV3WRITE_DATASYNC;
1356: LIST_INSERT_HEAD(&owp->nd_coalesce, nfsd, nd_tq);
1357:
1358: /*
1359: * If nfsd had anything else coalesced into it, transfer them
1360: * to owp, otherwise their replies will never get sent.
1361: */
1362: for (p = nfsd->nd_coalesce.lh_first; p;
1363: p = nfsd->nd_coalesce.lh_first) {
1364: LIST_REMOVE(p, nd_tq);
1365: LIST_INSERT_HEAD(&owp->nd_coalesce, p, nd_tq);
1366: }
1367: }
1368:
1369: /*
1370: * Sort the group list in increasing numerical order.
1371: * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1372: * that used to be here.)
1373: */
1374: void
1375: nfsrvw_sort(list, num)
1376: register gid_t *list;
1377: register int num;
1378: {
1379: register int i, j;
1380: gid_t v;
1381:
1382: /* Insertion sort. */
1383: for (i = 1; i < num; i++) {
1384: v = list[i];
1385: /* find correct slot for value v, moving others up */
1386: for (j = i; --j >= 0 && v < list[j];)
1387: list[j + 1] = list[j];
1388: list[j + 1] = v;
1389: }
1390: }
1391:
1392: /*
1393: * copy credentials making sure that the result can be compared with bcmp().
1394: */
1395: void
1396: nfsrv_setcred(incred, outcred)
1397: register struct ucred *incred, *outcred;
1398: {
1399: register int i;
1400:
1401: bzero((caddr_t)outcred, sizeof (struct ucred));
1402: outcred->cr_ref = 1;
1403: outcred->cr_uid = incred->cr_uid;
1404: outcred->cr_ngroups = incred->cr_ngroups;
1405: for (i = 0; i < incred->cr_ngroups; i++)
1406: outcred->cr_groups[i] = incred->cr_groups[i];
1407: nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
1408: }
1409:
1410: /*
1411: * nfs create service
1412: * now does a truncate to 0 length via. setattr if it already exists
1413: */
1414: int
1415: nfsrv_create(nfsd, slp, procp, mrq)
1416: struct nfsrv_descript *nfsd;
1417: struct nfssvc_sock *slp;
1418: struct proc *procp;
1419: struct mbuf **mrq;
1420: {
1421: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1422: struct mbuf *nam = nfsd->nd_nam;
1423: caddr_t dpos = nfsd->nd_dpos;
1424: struct ucred *cred = &nfsd->nd_cr;
1425: register struct nfs_fattr *fp;
1426: struct vattr va, dirfor, diraft;
1427: register struct vattr *vap = &va;
1428: register struct nfsv2_sattr *sp;
1429: register u_long *tl;
1430: struct nameidata nd;
1431: register caddr_t cp;
1432: register long t1;
1433: caddr_t bpos;
1434: int error = 0, rdev, cache, len, tsize, dirfor_ret = 1, diraft_ret = 1;
1435: int v3 = (nfsd->nd_flag & ND_NFSV3), how, exclusive_flag = 0;
1436: char *cp2;
1437: struct mbuf *mb, *mb2, *mreq;
1438: struct vnode *vp, *dirp = (struct vnode *)0;
1439: nfsfh_t nfh;
1440: fhandle_t *fhp;
1441: u_quad_t frev, tempsize;
1442: u_char cverf[NFSX_V3CREATEVERF];
1443:
1444: #ifndef nolint
1445: rdev = 0;
1446: #endif
1447: nd.ni_cnd.cn_nameiop = 0;
1448: fhp = &nfh.fh_generic;
1449: nfsm_srvmtofh(fhp);
1450: nfsm_srvnamesiz(len);
1451: nd.ni_cnd.cn_cred = cred;
1452: nd.ni_cnd.cn_nameiop = CREATE;
1453: nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART;
1454: error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1455: &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1456: if (dirp) {
1457: if (v3)
1458: dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
1459: procp);
1460: else {
1461: vrele(dirp);
1462: dirp = (struct vnode *)0;
1463: }
1464: }
1465: if (error) {
1466: nfsm_reply(NFSX_WCCDATA(v3));
1467: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1468: if (dirp)
1469: vrele(dirp);
1470: return (0);
1471: }
1472: VATTR_NULL(vap);
1473: if (v3) {
1474: nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
1475: how = fxdr_unsigned(int, *tl);
1476: switch (how) {
1477: case NFSV3CREATE_GUARDED:
1478: if (nd.ni_vp) {
1479: error = EEXIST;
1480: break;
1481: }
1482: case NFSV3CREATE_UNCHECKED:
1483: nfsm_srvsattr(vap);
1484: break;
1485: case NFSV3CREATE_EXCLUSIVE:
1486: nfsm_dissect(cp, caddr_t, NFSX_V3CREATEVERF);
1487: bcopy(cp, cverf, NFSX_V3CREATEVERF);
1488: exclusive_flag = 1;
1489: if (nd.ni_vp == NULL)
1490: vap->va_mode = 0;
1491: break;
1492: };
1493: vap->va_type = VREG;
1494: } else {
1495: nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1496: vap->va_type = IFTOVT(fxdr_unsigned(u_long, sp->sa_mode));
1497: if (vap->va_type == VNON)
1498: vap->va_type = VREG;
1499: vap->va_mode = nfstov_mode(sp->sa_mode);
1500: switch (vap->va_type) {
1501: case VREG:
1502: tsize = fxdr_unsigned(long, sp->sa_size);
1503: if (tsize != -1)
1504: vap->va_size = (u_quad_t)tsize;
1505: break;
1506: case VCHR:
1507: case VBLK:
1508: case VFIFO:
1509: rdev = fxdr_unsigned(long, sp->sa_size);
1510: break;
1511: };
1512: }
1513:
1514: /*
1515: * Iff doesn't exist, create it
1516: * otherwise just truncate to 0 length
1517: * should I set the mode too ??
1518: */
1519: if (nd.ni_vp == NULL) {
1520: if (vap->va_type == VREG || vap->va_type == VSOCK) {
1521: vrele(nd.ni_startdir);
1522: nqsrv_getl(nd.ni_dvp, ND_WRITE);
1523: error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
1524: if (!error) {
1525: nfsrv_object_create(nd.ni_vp);
1526: FREE_ZONE(nd.ni_cnd.cn_pnbuf,
1527: nd.ni_cnd.cn_pnlen, M_NAMEI);
1528: if (exclusive_flag) {
1529: exclusive_flag = 0;
1530: VATTR_NULL(vap);
1531: bcopy(cverf, (caddr_t)&vap->va_atime,
1532: NFSX_V3CREATEVERF);
1533: error = VOP_SETATTR(nd.ni_vp, vap, cred,
1534: procp);
1535: }
1536: }
1537: } else if (vap->va_type == VCHR || vap->va_type == VBLK ||
1538: vap->va_type == VFIFO) {
1539: if (vap->va_type == VCHR && rdev == 0xffffffff)
1540: vap->va_type = VFIFO;
1541: if (vap->va_type != VFIFO &&
1542: (error = suser(cred, (u_short *)0))) {
1543: vrele(nd.ni_startdir);
1544: _FREE_ZONE(nd.ni_cnd.cn_pnbuf,
1545: nd.ni_cnd.cn_pnlen, M_NAMEI);
1546: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1547: vput(nd.ni_dvp);
1548: nfsm_reply(0);
1549: return (error);
1550: } else
1551: vap->va_rdev = (dev_t)rdev;
1552: nqsrv_getl(nd.ni_dvp, ND_WRITE);
1553: if ((error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap))) {
1554: vrele(nd.ni_startdir);
1555: nfsm_reply(0);
1556: }
1557: nd.ni_cnd.cn_nameiop = LOOKUP;
1558: nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
1559: nd.ni_cnd.cn_proc = procp;
1560: nd.ni_cnd.cn_cred = cred;
1561: if ((error = lookup(&nd))) {
1562: _FREE_ZONE(nd.ni_cnd.cn_pnbuf,
1563: nd.ni_cnd.cn_pnlen, M_NAMEI);
1564: nfsm_reply(0);
1565: }
1566: nfsrv_object_create(nd.ni_vp);
1567: FREE_ZONE(nd.ni_cnd.cn_pnbuf,
1568: nd.ni_cnd.cn_pnlen, M_NAMEI);
1569: if (nd.ni_cnd.cn_flags & ISSYMLINK) {
1570: vrele(nd.ni_dvp);
1571: vput(nd.ni_vp);
1572: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1573: error = EINVAL;
1574: nfsm_reply(0);
1575: }
1576: } else {
1577: vrele(nd.ni_startdir);
1578: _FREE_ZONE(nd.ni_cnd.cn_pnbuf,
1579: nd.ni_cnd.cn_pnlen, M_NAMEI);
1580: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1581: vput(nd.ni_dvp);
1582: error = ENXIO;
1583: }
1584: vp = nd.ni_vp;
1585: } else {
1586: vrele(nd.ni_startdir);
1587: _FREE_ZONE(nd.ni_cnd.cn_pnbuf, nd.ni_cnd.cn_pnlen, M_NAMEI);
1588: vp = nd.ni_vp;
1589: if (nd.ni_dvp == vp)
1590: vrele(nd.ni_dvp);
1591: else
1592: vput(nd.ni_dvp);
1593: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1594: if (vap->va_size != -1) {
1595: error = nfsrv_access(vp, VWRITE, cred,
1596: (nd.ni_cnd.cn_flags & RDONLY), procp);
1597: if (!error) {
1598: nqsrv_getl(vp, ND_WRITE);
1599: tempsize = vap->va_size;
1600: VATTR_NULL(vap);
1601: vap->va_size = tempsize;
1602: error = VOP_SETATTR(vp, vap, cred,
1603: procp);
1604: }
1605: if (error)
1606: vput(vp);
1607: }
1608: }
1609: if (!error) {
1610: bzero((caddr_t)fhp, sizeof(nfh));
1611: fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1612: error = VFS_VPTOFH(vp, &fhp->fh_fid);
1613: if (!error)
1614: error = VOP_GETATTR(vp, vap, cred, procp);
1615: vput(vp);
1616: }
1617: if (v3) {
1618: if (exclusive_flag && !error &&
1619: bcmp(cverf, (caddr_t)&vap->va_atime, NFSX_V3CREATEVERF))
1620: error = EEXIST;
1621: diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1622: vrele(dirp);
1623: }
1624: nfsm_reply(NFSX_SRVFH(v3) + NFSX_FATTR(v3) + NFSX_WCCDATA(v3));
1625: if (v3) {
1626: if (!error) {
1627: nfsm_srvpostop_fh(fhp);
1628: nfsm_srvpostop_attr(0, vap);
1629: }
1630: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1631: } else {
1632: nfsm_srvfhtom(fhp, v3);
1633: nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
1634: nfsm_srvfillattr(vap, fp);
1635: }
1636: return (0);
1637: nfsmout:
1638: if (dirp)
1639: vrele(dirp);
1640: if (nd.ni_cnd.cn_nameiop) {
1641: vrele(nd.ni_startdir);
1642: _FREE_ZONE((caddr_t)nd.ni_cnd.cn_pnbuf,
1643: nd.ni_cnd.cn_pnlen, M_NAMEI);
1644: }
1645: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1646: if (nd.ni_dvp == nd.ni_vp)
1647: vrele(nd.ni_dvp);
1648: else
1649: vput(nd.ni_dvp);
1650: if (nd.ni_vp)
1651: vput(nd.ni_vp);
1652: return (error);
1653: }
1654:
1655: /*
1656: * nfs v3 mknod service
1657: */
1658: int
1659: nfsrv_mknod(nfsd, slp, procp, mrq)
1660: struct nfsrv_descript *nfsd;
1661: struct nfssvc_sock *slp;
1662: struct proc *procp;
1663: struct mbuf **mrq;
1664: {
1665: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1666: struct mbuf *nam = nfsd->nd_nam;
1667: caddr_t dpos = nfsd->nd_dpos;
1668: struct ucred *cred = &nfsd->nd_cr;
1669: struct vattr va, dirfor, diraft;
1670: register struct vattr *vap = &va;
1671: register u_long *tl;
1672: struct nameidata nd;
1673: register long t1;
1674: caddr_t bpos;
1675: int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
1676: u_long major, minor;
1677: enum vtype vtyp;
1678: char *cp2;
1679: struct mbuf *mb, *mb2, *mreq;
1680: struct vnode *vp, *dirp = (struct vnode *)0;
1681: nfsfh_t nfh;
1682: fhandle_t *fhp;
1683: u_quad_t frev;
1684:
1685: nd.ni_cnd.cn_nameiop = 0;
1686: fhp = &nfh.fh_generic;
1687: nfsm_srvmtofh(fhp);
1688: nfsm_srvnamesiz(len);
1689: nd.ni_cnd.cn_cred = cred;
1690: nd.ni_cnd.cn_nameiop = CREATE;
1691: nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART;
1692: error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1693: &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1694: if (dirp)
1695: dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp);
1696: if (error) {
1697: nfsm_reply(NFSX_WCCDATA(1));
1698: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1699: if (dirp)
1700: vrele(dirp);
1701: return (0);
1702: }
1703: nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
1704: vtyp = nfsv3tov_type(*tl);
1705: if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) {
1706: vrele(nd.ni_startdir);
1707: _FREE_ZONE((caddr_t)nd.ni_cnd.cn_pnbuf,
1708: nd.ni_cnd.cn_pnlen, M_NAMEI);
1709: error = NFSERR_BADTYPE;
1710: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1711: vput(nd.ni_dvp);
1712: goto out;
1713: }
1714: VATTR_NULL(vap);
1715: nfsm_srvsattr(vap);
1716: if (vtyp == VCHR || vtyp == VBLK) {
1717: nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
1718: major = fxdr_unsigned(u_long, *tl++);
1719: minor = fxdr_unsigned(u_long, *tl);
1720: vap->va_rdev = makedev(major, minor);
1721: }
1722:
1723: /*
1724: * Iff doesn't exist, create it.
1725: */
1726: if (nd.ni_vp) {
1727: vrele(nd.ni_startdir);
1728: _FREE_ZONE((caddr_t)nd.ni_cnd.cn_pnbuf,
1729: nd.ni_cnd.cn_pnlen, M_NAMEI);
1730: error = EEXIST;
1731: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1732: vput(nd.ni_dvp);
1733: goto out;
1734: }
1735: vap->va_type = vtyp;
1736: if (vtyp == VSOCK) {
1737: vrele(nd.ni_startdir);
1738: nqsrv_getl(nd.ni_dvp, ND_WRITE);
1739: error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
1740: if (!error)
1741: FREE_ZONE(nd.ni_cnd.cn_pnbuf,
1742: nd.ni_cnd.cn_pnlen, M_NAMEI);
1743: } else {
1744: if (vtyp != VFIFO && (error = suser(cred, (u_short *)0))) {
1745: vrele(nd.ni_startdir);
1746: _FREE_ZONE((caddr_t)nd.ni_cnd.cn_pnbuf,
1747: nd.ni_cnd.cn_pnlen, M_NAMEI);
1748: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1749: vput(nd.ni_dvp);
1750: goto out;
1751: }
1752: nqsrv_getl(nd.ni_dvp, ND_WRITE);
1753: if ((error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap))) {
1754: vrele(nd.ni_startdir);
1755: goto out;
1756: }
1757: nd.ni_cnd.cn_nameiop = LOOKUP;
1758: nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
1759: nd.ni_cnd.cn_proc = procp;
1760: nd.ni_cnd.cn_cred = procp->p_ucred;
1761: error = lookup(&nd);
1762: FREE_ZONE(nd.ni_cnd.cn_pnbuf, nd.ni_cnd.cn_pnlen, M_NAMEI);
1763: if (error)
1764: goto out;
1765: if (nd.ni_cnd.cn_flags & ISSYMLINK) {
1766: vrele(nd.ni_dvp);
1767: vput(nd.ni_vp);
1768: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1769: error = EINVAL;
1770: }
1771: }
1772: out:
1773: vp = nd.ni_vp;
1774: if (!error) {
1775: bzero((caddr_t)fhp, sizeof(nfh));
1776: fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1777: error = VFS_VPTOFH(vp, &fhp->fh_fid);
1778: if (!error)
1779: error = VOP_GETATTR(vp, vap, cred, procp);
1780: vput(vp);
1781: }
1782: diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1783: vrele(dirp);
1784: nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1));
1785: if (!error) {
1786: nfsm_srvpostop_fh(fhp);
1787: nfsm_srvpostop_attr(0, vap);
1788: }
1789: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1790: return (0);
1791: nfsmout:
1792: if (dirp)
1793: vrele(dirp);
1794: if (nd.ni_cnd.cn_nameiop) {
1795: vrele(nd.ni_startdir);
1796: _FREE_ZONE((caddr_t)nd.ni_cnd.cn_pnbuf,
1797: nd.ni_cnd.cn_pnlen, M_NAMEI);
1798: }
1799: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1800: if (nd.ni_dvp == nd.ni_vp)
1801: vrele(nd.ni_dvp);
1802: else
1803: vput(nd.ni_dvp);
1804: if (nd.ni_vp)
1805: vput(nd.ni_vp);
1806: return (error);
1807: }
1808:
1809: /*
1810: * nfs remove service
1811: */
1812: int
1813: nfsrv_remove(nfsd, slp, procp, mrq)
1814: struct nfsrv_descript *nfsd;
1815: struct nfssvc_sock *slp;
1816: struct proc *procp;
1817: struct mbuf **mrq;
1818: {
1819: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1820: struct mbuf *nam = nfsd->nd_nam;
1821: caddr_t dpos = nfsd->nd_dpos;
1822: struct ucred *cred = &nfsd->nd_cr;
1823: struct nameidata nd;
1824: register u_long *tl;
1825: register long t1;
1826: caddr_t bpos;
1827: int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
1828: int v3 = (nfsd->nd_flag & ND_NFSV3);
1829: char *cp2;
1830: struct mbuf *mb, *mreq;
1831: struct vnode *vp, *dirp;
1832: struct vattr dirfor, diraft;
1833: nfsfh_t nfh;
1834: fhandle_t *fhp;
1835: u_quad_t frev;
1836:
1837: #ifndef nolint
1838: vp = (struct vnode *)0;
1839: #endif
1840: fhp = &nfh.fh_generic;
1841: nfsm_srvmtofh(fhp);
1842: nfsm_srvnamesiz(len);
1843: nd.ni_cnd.cn_cred = cred;
1844: nd.ni_cnd.cn_nameiop = DELETE;
1845: nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
1846: error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1847: &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1848: if (dirp) {
1849: if (v3)
1850: dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
1851: procp);
1852: else
1853: vrele(dirp);
1854: }
1855: if (!error) {
1856: vp = nd.ni_vp;
1857: if (vp->v_type == VDIR) {
1858: error = EPERM; /* POSIX */
1859: goto out;
1860: }
1861: /*
1862: * The root of a mounted filesystem cannot be deleted.
1863: */
1864: if (vp->v_flag & VROOT) {
1865: error = EBUSY;
1866: goto out;
1867: }
1868: out:
1869: if (!error) {
1870: (void) vnode_uncache(vp);
1871: nqsrv_getl(nd.ni_dvp, ND_WRITE);
1872: nqsrv_getl(vp, ND_WRITE);
1873:
1874: error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1875:
1876: } else {
1877: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1878: if (nd.ni_dvp == vp)
1879: vrele(nd.ni_dvp);
1880: else
1881: vput(nd.ni_dvp);
1882: vput(vp);
1883: }
1884: }
1885: if (dirp && v3) {
1886: diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1887: vrele(dirp);
1888: }
1889: nfsm_reply(NFSX_WCCDATA(v3));
1890: if (v3) {
1891: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1892: return (0);
1893: }
1894: nfsm_srvdone;
1895: }
1896:
1897: /*
1898: * nfs rename service
1899: */
1900: int
1901: nfsrv_rename(nfsd, slp, procp, mrq)
1902: struct nfsrv_descript *nfsd;
1903: struct nfssvc_sock *slp;
1904: struct proc *procp;
1905: struct mbuf **mrq;
1906: {
1907: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1908: struct mbuf *nam = nfsd->nd_nam;
1909: caddr_t dpos = nfsd->nd_dpos;
1910: struct ucred *cred = &nfsd->nd_cr;
1911: register u_long *tl;
1912: register long t1;
1913: caddr_t bpos;
1914: int error = 0, cache, len, len2, fdirfor_ret = 1, fdiraft_ret = 1;
1915: int tdirfor_ret = 1, tdiraft_ret = 1;
1916: int v3 = (nfsd->nd_flag & ND_NFSV3);
1917: char *cp2;
1918: struct mbuf *mb, *mreq;
1919: struct nameidata fromnd, tond;
1920: struct vnode *fvp, *tvp, *tdvp, *fdirp = (struct vnode *)0;
1921: struct vnode *tdirp = (struct vnode *)0;
1922: struct vattr fdirfor, fdiraft, tdirfor, tdiraft;
1923: nfsfh_t fnfh, tnfh;
1924: fhandle_t *ffhp, *tfhp;
1925: u_quad_t frev;
1926: uid_t saved_uid;
1927:
1928: #ifndef nolint
1929: fvp = (struct vnode *)0;
1930: #endif
1931: ffhp = &fnfh.fh_generic;
1932: tfhp = &tnfh.fh_generic;
1933: fromnd.ni_cnd.cn_nameiop = 0;
1934: tond.ni_cnd.cn_nameiop = 0;
1935: nfsm_srvmtofh(ffhp);
1936: nfsm_srvnamesiz(len);
1937: /*
1938: * Remember our original uid so that we can reset cr_uid before
1939: * the second nfs_namei() call, in case it is remapped.
1940: */
1941: saved_uid = cred->cr_uid;
1942: fromnd.ni_cnd.cn_cred = cred;
1943: fromnd.ni_cnd.cn_nameiop = DELETE;
1944: fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART;
1945: error = nfs_namei(&fromnd, ffhp, len, slp, nam, &md,
1946: &dpos, &fdirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1947: if (fdirp) {
1948: if (v3)
1949: fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, cred,
1950: procp);
1951: else {
1952: vrele(fdirp);
1953: fdirp = (struct vnode *)0;
1954: }
1955: }
1956: if (error) {
1957: nfsm_reply(2 * NFSX_WCCDATA(v3));
1958: nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1959: nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1960: if (fdirp)
1961: vrele(fdirp);
1962: return (0);
1963: }
1964: fvp = fromnd.ni_vp;
1965: nfsm_srvmtofh(tfhp);
1966: nfsm_strsiz(len2, NFS_MAXNAMLEN);
1967: cred->cr_uid = saved_uid;
1968: tond.ni_cnd.cn_cred = cred;
1969: tond.ni_cnd.cn_nameiop = RENAME;
1970: tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART;
1971: error = nfs_namei(&tond, tfhp, len2, slp, nam, &md,
1972: &dpos, &tdirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1973: if (tdirp) {
1974: if (v3)
1975: tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, cred,
1976: procp);
1977: else {
1978: vrele(tdirp);
1979: tdirp = (struct vnode *)0;
1980: }
1981: }
1982: if (error) {
1983: VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1984: vrele(fromnd.ni_dvp);
1985: vrele(fvp);
1986: goto out1;
1987: }
1988: tdvp = tond.ni_dvp;
1989: tvp = tond.ni_vp;
1990: if (tvp != NULL) {
1991: if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
1992: if (v3)
1993: error = EEXIST;
1994: else
1995: error = EISDIR;
1996: goto out;
1997: } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
1998: if (v3)
1999: error = EEXIST;
2000: else
2001: error = ENOTDIR;
2002: goto out;
2003: }
2004: if (tvp->v_type == VDIR && tvp->v_mountedhere) {
2005: if (v3)
2006: error = EXDEV;
2007: else
2008: error = ENOTEMPTY;
2009: goto out;
2010: }
2011: }
2012: if (fvp->v_type == VDIR && fvp->v_mountedhere) {
2013: if (v3)
2014: error = EXDEV;
2015: else
2016: error = ENOTEMPTY;
2017: goto out;
2018: }
2019: if (fvp->v_mount != tdvp->v_mount) {
2020: if (v3)
2021: error = EXDEV;
2022: else
2023: error = ENOTEMPTY;
2024: goto out;
2025: }
2026: if (fvp == tdvp)
2027: if (v3)
2028: error = EINVAL;
2029: else
2030: error = ENOTEMPTY;
2031: /*
2032: * If source is the same as the destination (that is the
2033: * same vnode) then there is nothing to do.
2034: * (fixed to have POSIX semantics - CSM 3/2/98)
2035: */
2036: if (fvp == tvp)
2037: error = -1;
2038: out:
2039: if (!error) {
2040: nqsrv_getl(fromnd.ni_dvp, ND_WRITE);
2041: nqsrv_getl(tdvp, ND_WRITE);
2042: if (tvp) {
2043: nqsrv_getl(tvp, ND_WRITE);
2044: (void) vnode_uncache(tvp);
2045: }
2046: error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
2047: tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
2048: } else {
2049: VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
2050: if (tdvp == tvp)
2051: vrele(tdvp);
2052: else
2053: vput(tdvp);
2054: if (tvp)
2055: vput(tvp);
2056: VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2057: vrele(fromnd.ni_dvp);
2058: vrele(fvp);
2059: if (error == -1)
2060: error = 0;
2061: }
2062: vrele(tond.ni_startdir);
2063: FREE_ZONE(tond.ni_cnd.cn_pnbuf, tond.ni_cnd.cn_pnlen, M_NAMEI);
2064: out1:
2065: if (fdirp) {
2066: fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, cred, procp);
2067: vrele(fdirp);
2068: }
2069: if (tdirp) {
2070: tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred, procp);
2071: vrele(tdirp);
2072: }
2073: vrele(fromnd.ni_startdir);
2074: FREE_ZONE(fromnd.ni_cnd.cn_pnbuf, fromnd.ni_cnd.cn_pnlen, M_NAMEI);
2075: nfsm_reply(2 * NFSX_WCCDATA(v3));
2076: if (v3) {
2077: nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
2078: nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
2079: }
2080: return (0);
2081:
2082: nfsmout:
2083: if (fdirp)
2084: vrele(fdirp);
2085: if (tdirp)
2086: vrele(tdirp);
2087: if (tond.ni_cnd.cn_nameiop) {
2088: vrele(tond.ni_startdir);
2089: FREE_ZONE(tond.ni_cnd.cn_pnbuf, tond.ni_cnd.cn_pnlen, M_NAMEI);
2090: }
2091: if (fromnd.ni_cnd.cn_nameiop) {
2092: vrele(fromnd.ni_startdir);
2093: FREE_ZONE(fromnd.ni_cnd.cn_pnbuf,
2094: fromnd.ni_cnd.cn_pnlen, M_NAMEI);
2095: VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2096: vrele(fromnd.ni_dvp);
2097: vrele(fvp);
2098: }
2099: return (error);
2100: }
2101:
2102: /*
2103: * nfs link service
2104: */
2105: int
2106: nfsrv_link(nfsd, slp, procp, mrq)
2107: struct nfsrv_descript *nfsd;
2108: struct nfssvc_sock *slp;
2109: struct proc *procp;
2110: struct mbuf **mrq;
2111: {
2112: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2113: struct mbuf *nam = nfsd->nd_nam;
2114: caddr_t dpos = nfsd->nd_dpos;
2115: struct ucred *cred = &nfsd->nd_cr;
2116: struct nameidata nd;
2117: register u_long *tl;
2118: register long t1;
2119: caddr_t bpos;
2120: int error = 0, rdonly, cache, len, dirfor_ret = 1, diraft_ret = 1;
2121: int getret = 1, v3 = (nfsd->nd_flag & ND_NFSV3);
2122: char *cp2;
2123: struct mbuf *mb, *mreq;
2124: struct vnode *vp, *xp, *dirp = (struct vnode *)0;
2125: struct vattr dirfor, diraft, at;
2126: nfsfh_t nfh, dnfh;
2127: fhandle_t *fhp, *dfhp;
2128: u_quad_t frev;
2129:
2130: fhp = &nfh.fh_generic;
2131: dfhp = &dnfh.fh_generic;
2132: nfsm_srvmtofh(fhp);
2133: nfsm_srvmtofh(dfhp);
2134: nfsm_srvnamesiz(len);
2135: if ((error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, slp, nam,
2136: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE))) {
2137: nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2138: nfsm_srvpostop_attr(getret, &at);
2139: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2140: return (0);
2141: }
2142: if (vp->v_type == VDIR) {
2143: error = EPERM; /* POSIX */
2144: goto out1;
2145: }
2146: nd.ni_cnd.cn_cred = cred;
2147: nd.ni_cnd.cn_nameiop = CREATE;
2148: nd.ni_cnd.cn_flags = LOCKPARENT;
2149: error = nfs_namei(&nd, dfhp, len, slp, nam, &md, &dpos,
2150: &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
2151: if (dirp) {
2152: if (v3)
2153: dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
2154: procp);
2155: else {
2156: vrele(dirp);
2157: dirp = (struct vnode *)0;
2158: }
2159: }
2160: if (error)
2161: goto out1;
2162: xp = nd.ni_vp;
2163: if (xp != NULL) {
2164: error = EEXIST;
2165: goto out;
2166: }
2167: xp = nd.ni_dvp;
2168: if (vp->v_mount != xp->v_mount)
2169: error = EXDEV;
2170: out:
2171: if (!error) {
2172: nqsrv_getl(vp, ND_WRITE);
2173: nqsrv_getl(xp, ND_WRITE);
2174: error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd);
2175: } else {
2176: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2177: if (nd.ni_dvp == nd.ni_vp)
2178: vrele(nd.ni_dvp);
2179: else
2180: vput(nd.ni_dvp);
2181: if (nd.ni_vp)
2182: vrele(nd.ni_vp);
2183: }
2184: out1:
2185: if (v3)
2186: getret = VOP_GETATTR(vp, &at, cred, procp);
2187: if (dirp) {
2188: diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2189: vrele(dirp);
2190: }
2191: vrele(vp);
2192: nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2193: if (v3) {
2194: nfsm_srvpostop_attr(getret, &at);
2195: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2196: return (0);
2197: }
2198: nfsm_srvdone;
2199: }
2200:
2201: /*
2202: * nfs symbolic link service
2203: */
2204: int
2205: nfsrv_symlink(nfsd, slp, procp, mrq)
2206: struct nfsrv_descript *nfsd;
2207: struct nfssvc_sock *slp;
2208: struct proc *procp;
2209: struct mbuf **mrq;
2210: {
2211: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2212: struct mbuf *nam = nfsd->nd_nam;
2213: caddr_t dpos = nfsd->nd_dpos;
2214: struct ucred *cred = &nfsd->nd_cr;
2215: struct vattr va, dirfor, diraft;
2216: struct nameidata nd;
2217: register struct vattr *vap = &va;
2218: register u_long *tl;
2219: register long t1;
2220: struct nfsv2_sattr *sp;
2221: char *bpos, *pathcp = (char *)0, *cp2;
2222: struct uio io;
2223: struct iovec iv;
2224: int error = 0, cache, len, len2, dirfor_ret = 1, diraft_ret = 1;
2225: int v3 = (nfsd->nd_flag & ND_NFSV3);
2226: struct mbuf *mb, *mreq, *mb2;
2227: struct vnode *dirp = (struct vnode *)0;
2228: nfsfh_t nfh;
2229: fhandle_t *fhp;
2230: u_quad_t frev;
2231:
2232: nd.ni_cnd.cn_nameiop = 0;
2233: fhp = &nfh.fh_generic;
2234: nfsm_srvmtofh(fhp);
2235: nfsm_srvnamesiz(len);
2236: nd.ni_cnd.cn_cred = cred;
2237: nd.ni_cnd.cn_nameiop = CREATE;
2238: nd.ni_cnd.cn_flags = LOCKPARENT | SAVESTART;
2239: error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
2240: &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
2241: if (dirp) {
2242: if (v3)
2243: dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
2244: procp);
2245: else {
2246: vrele(dirp);
2247: dirp = (struct vnode *)0;
2248: }
2249: }
2250: if (error)
2251: goto out;
2252: VATTR_NULL(vap);
2253: if (v3)
2254: nfsm_srvsattr(vap);
2255: nfsm_strsiz(len2, NFS_MAXPATHLEN);
2256: MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK);
2257: iv.iov_base = pathcp;
2258: iv.iov_len = len2;
2259: io.uio_resid = len2;
2260: io.uio_offset = 0;
2261: io.uio_iov = &iv;
2262: io.uio_iovcnt = 1;
2263: io.uio_segflg = UIO_SYSSPACE;
2264: io.uio_rw = UIO_READ;
2265: io.uio_procp = (struct proc *)0;
2266: nfsm_mtouio(&io, len2);
2267: if (!v3) {
2268: nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
2269: vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode);
2270: }
2271: *(pathcp + len2) = '\0';
2272: if (nd.ni_vp) {
2273: vrele(nd.ni_startdir);
2274: _FREE_ZONE(nd.ni_cnd.cn_pnbuf, nd.ni_cnd.cn_pnlen, M_NAMEI);
2275: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2276: if (nd.ni_dvp == nd.ni_vp)
2277: vrele(nd.ni_dvp);
2278: else
2279: vput(nd.ni_dvp);
2280: vrele(nd.ni_vp);
2281: error = EEXIST;
2282: goto out;
2283: }
2284: nqsrv_getl(nd.ni_dvp, ND_WRITE);
2285: error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp);
2286: if (error)
2287: vrele(nd.ni_startdir);
2288: else {
2289: if (v3) {
2290: nd.ni_cnd.cn_nameiop = LOOKUP;
2291: nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART | FOLLOW);
2292: nd.ni_cnd.cn_flags |= (NOFOLLOW | LOCKLEAF);
2293: nd.ni_cnd.cn_proc = procp;
2294: nd.ni_cnd.cn_cred = cred;
2295: error = lookup(&nd);
2296: if (!error) {
2297: bzero((caddr_t)fhp, sizeof(nfh));
2298: fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid;
2299: error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid);
2300: if (!error)
2301: error = VOP_GETATTR(nd.ni_vp, vap, cred,
2302: procp);
2303: vput(nd.ni_vp);
2304: }
2305: } else
2306: vrele(nd.ni_startdir);
2307: FREE_ZONE(nd.ni_cnd.cn_pnbuf, nd.ni_cnd.cn_pnlen, M_NAMEI);
2308: }
2309: out:
2310: if (pathcp)
2311: FREE(pathcp, M_TEMP);
2312: if (dirp) {
2313: diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2314: vrele(dirp);
2315: }
2316: nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2317: if (v3) {
2318: if (!error) {
2319: nfsm_srvpostop_fh(fhp);
2320: nfsm_srvpostop_attr(0, vap);
2321: }
2322: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2323: }
2324: return (0);
2325: nfsmout:
2326: if (nd.ni_cnd.cn_nameiop) {
2327: vrele(nd.ni_startdir);
2328: _FREE_ZONE(nd.ni_cnd.cn_pnbuf, nd.ni_cnd.cn_pnlen, M_NAMEI);
2329: }
2330: if (dirp)
2331: vrele(dirp);
2332: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2333: if (nd.ni_dvp == nd.ni_vp)
2334: vrele(nd.ni_dvp);
2335: else
2336: vput(nd.ni_dvp);
2337: if (nd.ni_vp)
2338: vrele(nd.ni_vp);
2339: if (pathcp)
2340: FREE(pathcp, M_TEMP);
2341: return (error);
2342: }
2343:
2344: /*
2345: * nfs mkdir service
2346: */
2347: int
2348: nfsrv_mkdir(nfsd, slp, procp, mrq)
2349: struct nfsrv_descript *nfsd;
2350: struct nfssvc_sock *slp;
2351: struct proc *procp;
2352: struct mbuf **mrq;
2353: {
2354: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2355: struct mbuf *nam = nfsd->nd_nam;
2356: caddr_t dpos = nfsd->nd_dpos;
2357: struct ucred *cred = &nfsd->nd_cr;
2358: struct vattr va, dirfor, diraft;
2359: register struct vattr *vap = &va;
2360: register struct nfs_fattr *fp;
2361: struct nameidata nd;
2362: register caddr_t cp;
2363: register u_long *tl;
2364: register long t1;
2365: caddr_t bpos;
2366: int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
2367: int v3 = (nfsd->nd_flag & ND_NFSV3);
2368: char *cp2;
2369: struct mbuf *mb, *mb2, *mreq;
2370: struct vnode *vp, *dirp = (struct vnode *)0;
2371: nfsfh_t nfh;
2372: fhandle_t *fhp;
2373: u_quad_t frev;
2374:
2375: fhp = &nfh.fh_generic;
2376: nfsm_srvmtofh(fhp);
2377: nfsm_srvnamesiz(len);
2378: nd.ni_cnd.cn_cred = cred;
2379: nd.ni_cnd.cn_nameiop = CREATE;
2380: nd.ni_cnd.cn_flags = LOCKPARENT;
2381: error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
2382: &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
2383: if (dirp) {
2384: if (v3)
2385: dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
2386: procp);
2387: else {
2388: vrele(dirp);
2389: dirp = (struct vnode *)0;
2390: }
2391: }
2392: if (error) {
2393: nfsm_reply(NFSX_WCCDATA(v3));
2394: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2395: if (dirp)
2396: vrele(dirp);
2397: return (0);
2398: }
2399: VATTR_NULL(vap);
2400: if (v3) {
2401: nfsm_srvsattr(vap);
2402: } else {
2403: nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2404: vap->va_mode = nfstov_mode(*tl++);
2405: }
2406: vap->va_type = VDIR;
2407: vp = nd.ni_vp;
2408: if (vp != NULL) {
2409: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2410: if (nd.ni_dvp == vp)
2411: vrele(nd.ni_dvp);
2412: else
2413: vput(nd.ni_dvp);
2414: vrele(vp);
2415: error = EEXIST;
2416: goto out;
2417: }
2418: nqsrv_getl(nd.ni_dvp, ND_WRITE);
2419: error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
2420: if (!error) {
2421: vp = nd.ni_vp;
2422: bzero((caddr_t)fhp, sizeof(nfh));
2423: fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
2424: error = VFS_VPTOFH(vp, &fhp->fh_fid);
2425: if (!error)
2426: error = VOP_GETATTR(vp, vap, cred, procp);
2427: vput(vp);
2428: }
2429: out:
2430: if (dirp) {
2431: diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2432: vrele(dirp);
2433: }
2434: nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2435: if (v3) {
2436: if (!error) {
2437: nfsm_srvpostop_fh(fhp);
2438: nfsm_srvpostop_attr(0, vap);
2439: }
2440: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2441: } else {
2442: nfsm_srvfhtom(fhp, v3);
2443: nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
2444: nfsm_srvfillattr(vap, fp);
2445: }
2446: return (0);
2447: nfsmout:
2448: if (dirp)
2449: vrele(dirp);
2450: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2451: if (nd.ni_dvp == nd.ni_vp)
2452: vrele(nd.ni_dvp);
2453: else
2454: vput(nd.ni_dvp);
2455: if (nd.ni_vp)
2456: vrele(nd.ni_vp);
2457: return (error);
2458: }
2459:
2460: /*
2461: * nfs rmdir service
2462: */
2463: int
2464: nfsrv_rmdir(nfsd, slp, procp, mrq)
2465: struct nfsrv_descript *nfsd;
2466: struct nfssvc_sock *slp;
2467: struct proc *procp;
2468: struct mbuf **mrq;
2469: {
2470: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2471: struct mbuf *nam = nfsd->nd_nam;
2472: caddr_t dpos = nfsd->nd_dpos;
2473: struct ucred *cred = &nfsd->nd_cr;
2474: register u_long *tl;
2475: register long t1;
2476: caddr_t bpos;
2477: int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
2478: int v3 = (nfsd->nd_flag & ND_NFSV3);
2479: char *cp2;
2480: struct mbuf *mb, *mreq;
2481: struct vnode *vp, *dirp = (struct vnode *)0;
2482: struct vattr dirfor, diraft;
2483: nfsfh_t nfh;
2484: fhandle_t *fhp;
2485: struct nameidata nd;
2486: u_quad_t frev;
2487:
2488: fhp = &nfh.fh_generic;
2489: nfsm_srvmtofh(fhp);
2490: nfsm_srvnamesiz(len);
2491: nd.ni_cnd.cn_cred = cred;
2492: nd.ni_cnd.cn_nameiop = DELETE;
2493: nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
2494: error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
2495: &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
2496: if (dirp) {
2497: if (v3)
2498: dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
2499: procp);
2500: else {
2501: vrele(dirp);
2502: dirp = (struct vnode *)0;
2503: }
2504: }
2505: if (error) {
2506: nfsm_reply(NFSX_WCCDATA(v3));
2507: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2508: if (dirp)
2509: vrele(dirp);
2510: return (0);
2511: }
2512: vp = nd.ni_vp;
2513: if (vp->v_type != VDIR) {
2514: error = ENOTDIR;
2515: goto out;
2516: }
2517: /*
2518: * No rmdir "." please.
2519: */
2520: if (nd.ni_dvp == vp) {
2521: error = EINVAL;
2522: goto out;
2523: }
2524: /*
2525: * The root of a mounted filesystem cannot be deleted.
2526: */
2527: if (vp->v_flag & VROOT)
2528: error = EBUSY;
2529: out:
2530: if (!error) {
2531: nqsrv_getl(nd.ni_dvp, ND_WRITE);
2532: nqsrv_getl(vp, ND_WRITE);
2533: error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
2534: } else {
2535: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2536: if (nd.ni_dvp == nd.ni_vp)
2537: vrele(nd.ni_dvp);
2538: else
2539: vput(nd.ni_dvp);
2540: vput(vp);
2541: }
2542: if (dirp) {
2543: diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2544: vrele(dirp);
2545: }
2546: nfsm_reply(NFSX_WCCDATA(v3));
2547: if (v3) {
2548: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2549: return (0);
2550: }
2551: nfsm_srvdone;
2552: }
2553:
2554: /*
2555: * nfs readdir service
2556: * - mallocs what it thinks is enough to read
2557: * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
2558: * - calls VOP_READDIR()
2559: * - loops around building the reply
2560: * if the output generated exceeds count break out of loop
2561: * The nfsm_clget macro is used here so that the reply will be packed
2562: * tightly in mbuf clusters.
2563: * - it only knows that it has encountered eof when the VOP_READDIR()
2564: * reads nothing
2565: * - as such one readdir rpc will return eof false although you are there
2566: * and then the next will return eof
2567: * - it trims out records with d_fileno == 0
2568: * this doesn't matter for Unix clients, but they might confuse clients
2569: * for other os'.
2570: * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
2571: * than requested, but this may not apply to all filesystems. For
2572: * example, client NFS does not { although it is never remote mounted
2573: * anyhow }
2574: * The alternate call nfsrv_readdirplus() does lookups as well.
2575: * PS: The NFS protocol spec. does not clarify what the "count" byte
2576: * argument is a count of.. just name strings and file id's or the
2577: * entire reply rpc or ...
2578: * I tried just file name and id sizes and it confused the Sun client,
2579: * so I am using the full rpc size now. The "paranoia.." comment refers
2580: * to including the status longwords that are not a part of the dir.
2581: * "entry" structures, but are in the rpc.
2582: */
2583: struct flrep {
2584: nfsuint64 fl_off;
2585: u_long fl_postopok;
2586: u_long fl_fattr[NFSX_V3FATTR / sizeof (u_long)];
2587: u_long fl_fhok;
2588: u_long fl_fhsize;
2589: u_long fl_nfh[NFSX_V3FH / sizeof (u_long)];
2590: };
2591:
2592: int
2593: nfsrv_readdir(nfsd, slp, procp, mrq)
2594: struct nfsrv_descript *nfsd;
2595: struct nfssvc_sock *slp;
2596: struct proc *procp;
2597: struct mbuf **mrq;
2598: {
2599: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2600: struct mbuf *nam = nfsd->nd_nam;
2601: caddr_t dpos = nfsd->nd_dpos;
2602: struct ucred *cred = &nfsd->nd_cr;
2603: register char *bp, *be;
2604: register struct mbuf *mp;
2605: register struct dirent *dp;
2606: register caddr_t cp;
2607: register u_long *tl;
2608: register long t1;
2609: caddr_t bpos;
2610: struct mbuf *mb, *mb2, *mreq, *mp2;
2611: char *cpos, *cend, *cp2, *rbuf;
2612: struct vnode *vp;
2613: struct vattr at;
2614: nfsfh_t nfh;
2615: fhandle_t *fhp;
2616: struct uio io;
2617: struct iovec iv;
2618: int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
2619: int siz, cnt, fullsiz, eofflag, rdonly, cache, ncookies;
2620: int v3 = (nfsd->nd_flag & ND_NFSV3);
2621: u_quad_t frev, off, toff, verf;
2622: u_long *cookies = NULL, *cookiep;
2623:
2624: fhp = &nfh.fh_generic;
2625: nfsm_srvmtofh(fhp);
2626: if (v3) {
2627: nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
2628: fxdr_hyper(tl, &toff);
2629: tl += 2;
2630: fxdr_hyper(tl, &verf);
2631: tl += 2;
2632: } else {
2633: nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
2634: toff = fxdr_unsigned(u_quad_t, *tl++);
2635: }
2636: off = toff;
2637: cnt = fxdr_unsigned(int, *tl);
2638: siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
2639: xfer = NFS_SRVMAXDATA(nfsd);
2640: if (siz > xfer)
2641: siz = xfer;
2642: fullsiz = siz;
2643: if ((error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
2644: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE))) {
2645: nfsm_reply(NFSX_UNSIGNED);
2646: nfsm_srvpostop_attr(getret, &at);
2647: return (0);
2648: }
2649: nqsrv_getl(vp, ND_READ);
2650: if (v3) {
2651: error = getret = VOP_GETATTR(vp, &at, cred, procp);
2652: if (!error && toff && verf && verf != at.va_filerev)
2653: error = NFSERR_BAD_COOKIE;
2654: }
2655: if (!error)
2656: error = nfsrv_access(vp, VEXEC, cred, rdonly, procp);
2657: if (error) {
2658: vput(vp);
2659: nfsm_reply(NFSX_POSTOPATTR(v3));
2660: nfsm_srvpostop_attr(getret, &at);
2661: return (0);
2662: }
2663: VOP_UNLOCK(vp, 0, procp);
2664: MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
2665: again:
2666: iv.iov_base = rbuf;
2667: iv.iov_len = fullsiz;
2668: io.uio_iov = &iv;
2669: io.uio_iovcnt = 1;
2670: io.uio_offset = (off_t)off;
2671: io.uio_resid = fullsiz;
2672: io.uio_segflg = UIO_SYSSPACE;
2673: io.uio_rw = UIO_READ;
2674: io.uio_procp = (struct proc *)0;
2675: eofflag = 0;
2676: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, procp);
2677: if (cookies) {
2678: _FREE((caddr_t)cookies, M_TEMP);
2679: cookies = NULL;
2680: }
2681: error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
2682: off = (off_t)io.uio_offset;
2683: if (!cookies && !error)
2684: error = NFSERR_PERM;
2685: if (v3) {
2686: getret = VOP_GETATTR(vp, &at, cred, procp);
2687: if (!error)
2688: error = getret;
2689: }
2690: VOP_UNLOCK(vp, 0, procp);
2691: if (error) {
2692: vrele(vp);
2693: _FREE((caddr_t)rbuf, M_TEMP);
2694: if (cookies)
2695: _FREE((caddr_t)cookies, M_TEMP);
2696: nfsm_reply(NFSX_POSTOPATTR(v3));
2697: nfsm_srvpostop_attr(getret, &at);
2698: return (0);
2699: }
2700: if (io.uio_resid) {
2701: siz -= io.uio_resid;
2702:
2703: /*
2704: * If nothing read, return eof
2705: * rpc reply
2706: */
2707: if (siz == 0) {
2708: vrele(vp);
2709: nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) +
2710: 2 * NFSX_UNSIGNED);
2711: if (v3) {
2712: nfsm_srvpostop_attr(getret, &at);
2713: nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
2714: txdr_hyper(&at.va_filerev, tl);
2715: tl += 2;
2716: } else
2717: nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
2718: *tl++ = nfs_false;
2719: *tl = nfs_true;
2720: FREE((caddr_t)rbuf, M_TEMP);
2721: FREE((caddr_t)cookies, M_TEMP);
2722: return (0);
2723: }
2724: }
2725:
2726: /*
2727: * Check for degenerate cases of nothing useful read.
2728: * If so go try again
2729: */
2730: cpos = rbuf;
2731: cend = rbuf + siz;
2732: dp = (struct dirent *)cpos;
2733: cookiep = cookies;
2734: #ifdef __FreeBSD__
2735: /*
2736: * For some reason FreeBSD's ufs_readdir() chooses to back the
2737: * directory offset up to a block boundary, so it is necessary to
2738: * skip over the records that preceed the requested offset. This
2739: * requires the assumption that file offset cookies monotonically
2740: * increase.
2741: */
2742: while (cpos < cend && ncookies > 0 &&
2743: (dp->d_fileno == 0 || ((u_quad_t)(*cookiep)) <= toff)) {
2744: #else
2745: while (dp->d_fileno == 0 && cpos < cend && ncookies > 0) {
2746: #endif
2747: cpos += dp->d_reclen;
2748: dp = (struct dirent *)cpos;
2749: cookiep++;
2750: ncookies--;
2751: }
2752: if (cpos >= cend || ncookies == 0) {
2753: toff = off;
2754: siz = fullsiz;
2755: goto again;
2756: }
2757:
2758: len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */
2759: nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz);
2760: if (v3) {
2761: nfsm_srvpostop_attr(getret, &at);
2762: nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
2763: txdr_hyper(&at.va_filerev, tl);
2764: }
2765: mp = mp2 = mb;
2766: bp = bpos;
2767: be = bp + M_TRAILINGSPACE(mp);
2768:
2769: /* Loop through the records and build reply */
2770: while (cpos < cend && ncookies > 0) {
2771: if (dp->d_fileno != 0) {
2772: nlen = dp->d_namlen;
2773: rem = nfsm_rndup(nlen)-nlen;
2774: len += (4 * NFSX_UNSIGNED + nlen + rem);
2775: if (v3)
2776: len += 2 * NFSX_UNSIGNED;
2777: if (len > cnt) {
2778: eofflag = 0;
2779: break;
2780: }
2781: /*
2782: * Build the directory record xdr from
2783: * the dirent entry.
2784: */
2785: nfsm_clget;
2786: *tl = nfs_true;
2787: bp += NFSX_UNSIGNED;
2788: if (v3) {
2789: nfsm_clget;
2790: *tl = 0;
2791: bp += NFSX_UNSIGNED;
2792: }
2793: nfsm_clget;
2794: *tl = txdr_unsigned(dp->d_fileno);
2795: bp += NFSX_UNSIGNED;
2796: nfsm_clget;
2797: *tl = txdr_unsigned(nlen);
2798: bp += NFSX_UNSIGNED;
2799:
2800: /* And loop around copying the name */
2801: xfer = nlen;
2802: cp = dp->d_name;
2803: while (xfer > 0) {
2804: nfsm_clget;
2805: if ((bp+xfer) > be)
2806: tsiz = be-bp;
2807: else
2808: tsiz = xfer;
2809: bcopy(cp, bp, tsiz);
2810: bp += tsiz;
2811: xfer -= tsiz;
2812: if (xfer > 0)
2813: cp += tsiz;
2814: }
2815: /* And null pad to a long boundary */
2816: for (i = 0; i < rem; i++)
2817: *bp++ = '\0';
2818: nfsm_clget;
2819:
2820: /* Finish off the record */
2821: if (v3) {
2822: *tl = 0;
2823: bp += NFSX_UNSIGNED;
2824: nfsm_clget;
2825: }
2826: *tl = txdr_unsigned(*cookiep);
2827: bp += NFSX_UNSIGNED;
2828: }
2829: cpos += dp->d_reclen;
2830: dp = (struct dirent *)cpos;
2831: cookiep++;
2832: ncookies--;
2833: }
2834: vrele(vp);
2835: nfsm_clget;
2836: *tl = nfs_false;
2837: bp += NFSX_UNSIGNED;
2838: nfsm_clget;
2839: if (eofflag)
2840: *tl = nfs_true;
2841: else
2842: *tl = nfs_false;
2843: bp += NFSX_UNSIGNED;
2844: if (mp != mb) {
2845: if (bp < be)
2846: mp->m_len = bp - mtod(mp, caddr_t);
2847: } else
2848: mp->m_len += bp - bpos;
2849: FREE((caddr_t)rbuf, M_TEMP);
2850: FREE((caddr_t)cookies, M_TEMP);
2851: nfsm_srvdone;
2852: }
2853:
2854: int
2855: nfsrv_readdirplus(nfsd, slp, procp, mrq)
2856: struct nfsrv_descript *nfsd;
2857: struct nfssvc_sock *slp;
2858: struct proc *procp;
2859: struct mbuf **mrq;
2860: {
2861: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2862: struct mbuf *nam = nfsd->nd_nam;
2863: caddr_t dpos = nfsd->nd_dpos;
2864: struct ucred *cred = &nfsd->nd_cr;
2865: register char *bp, *be;
2866: register struct mbuf *mp;
2867: register struct dirent *dp;
2868: register caddr_t cp;
2869: register u_long *tl;
2870: register long t1;
2871: caddr_t bpos;
2872: struct mbuf *mb, *mb2, *mreq, *mp2;
2873: char *cpos, *cend, *cp2, *rbuf;
2874: struct vnode *vp, *nvp;
2875: struct flrep fl;
2876: nfsfh_t nfh;
2877: fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh;
2878: struct uio io;
2879: struct iovec iv;
2880: struct vattr va, at, *vap = &va;
2881: struct nfs_fattr *fp;
2882: int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
2883: int siz, cnt, fullsiz, eofflag, rdonly, cache, dirlen, ncookies;
2884: u_quad_t frev, off, toff, verf;
2885: u_long *cookies = NULL, *cookiep;
2886:
2887: fhp = &nfh.fh_generic;
2888: nfsm_srvmtofh(fhp);
2889: nfsm_dissect(tl, u_long *, 6 * NFSX_UNSIGNED);
2890: fxdr_hyper(tl, &toff);
2891: tl += 2;
2892: fxdr_hyper(tl, &verf);
2893: tl += 2;
2894: siz = fxdr_unsigned(int, *tl++);
2895: cnt = fxdr_unsigned(int, *tl);
2896: off = toff;
2897: siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
2898: xfer = NFS_SRVMAXDATA(nfsd);
2899: if (siz > xfer)
2900: siz = xfer;
2901: fullsiz = siz;
2902: if ((error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
2903: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE))) {
2904: nfsm_reply(NFSX_UNSIGNED);
2905: nfsm_srvpostop_attr(getret, &at);
2906: return (0);
2907: }
2908: error = getret = VOP_GETATTR(vp, &at, cred, procp);
2909: if (!error && toff && verf && verf != at.va_filerev)
2910: error = NFSERR_BAD_COOKIE;
2911: if (!error) {
2912: nqsrv_getl(vp, ND_READ);
2913: error = nfsrv_access(vp, VEXEC, cred, rdonly, procp);
2914: }
2915: if (error) {
2916: vput(vp);
2917: nfsm_reply(NFSX_V3POSTOPATTR);
2918: nfsm_srvpostop_attr(getret, &at);
2919: return (0);
2920: }
2921: VOP_UNLOCK(vp, 0, procp);
2922: MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
2923: again:
2924: iv.iov_base = rbuf;
2925: iv.iov_len = fullsiz;
2926: io.uio_iov = &iv;
2927: io.uio_iovcnt = 1;
2928: io.uio_offset = (off_t)off;
2929: io.uio_resid = fullsiz;
2930: io.uio_segflg = UIO_SYSSPACE;
2931: io.uio_rw = UIO_READ;
2932: io.uio_procp = (struct proc *)0;
2933: eofflag = 0;
2934: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, procp);
2935: if (cookies) {
2936: _FREE((caddr_t)cookies, M_TEMP);
2937: cookies = NULL;
2938: }
2939: error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
2940: off = (u_quad_t)io.uio_offset;
2941: getret = VOP_GETATTR(vp, &at, cred, procp);
2942: VOP_UNLOCK(vp, 0, procp);
2943: if (!cookies && !error)
2944: error = NFSERR_PERM;
2945: if (!error)
2946: error = getret;
2947: if (error) {
2948: vrele(vp);
2949: if (cookies)
2950: _FREE((caddr_t)cookies, M_TEMP);
2951: _FREE((caddr_t)rbuf, M_TEMP);
2952: nfsm_reply(NFSX_V3POSTOPATTR);
2953: nfsm_srvpostop_attr(getret, &at);
2954: return (0);
2955: }
2956: if (io.uio_resid) {
2957: siz -= io.uio_resid;
2958:
2959: /*
2960: * If nothing read, return eof
2961: * rpc reply
2962: */
2963: if (siz == 0) {
2964: vrele(vp);
2965: nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
2966: 2 * NFSX_UNSIGNED);
2967: nfsm_srvpostop_attr(getret, &at);
2968: nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
2969: txdr_hyper(&at.va_filerev, tl);
2970: tl += 2;
2971: *tl++ = nfs_false;
2972: *tl = nfs_true;
2973: FREE((caddr_t)cookies, M_TEMP);
2974: FREE((caddr_t)rbuf, M_TEMP);
2975: return (0);
2976: }
2977: }
2978:
2979: /*
2980: * Check for degenerate cases of nothing useful read.
2981: * If so go try again
2982: */
2983: cpos = rbuf;
2984: cend = rbuf + siz;
2985: dp = (struct dirent *)cpos;
2986: cookiep = cookies;
2987: #ifdef __FreeBSD__
2988: /*
2989: * For some reason FreeBSD's ufs_readdir() chooses to back the
2990: * directory offset up to a block boundary, so it is necessary to
2991: * skip over the records that preceed the requested offset. This
2992: * requires the assumption that file offset cookies monotonically
2993: * increase.
2994: */
2995: while (cpos < cend && ncookies > 0 &&
2996: (dp->d_fileno == 0 || ((u_quad_t)(*cookiep)) <= toff)) {
2997: #else
2998: while (dp->d_fileno == 0 && cpos < cend && ncookies > 0) {
2999: #endif
3000: cpos += dp->d_reclen;
3001: dp = (struct dirent *)cpos;
3002: cookiep++;
3003: ncookies--;
3004: }
3005: if (cpos >= cend || ncookies == 0) {
3006: toff = off;
3007: siz = fullsiz;
3008: goto again;
3009: }
3010:
3011: /*
3012: * Probe one of the directory entries to see if the filesystem
3013: * supports VGET.
3014: */
3015: if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp) == EOPNOTSUPP) {
3016: error = NFSERR_NOTSUPP;
3017: vrele(vp);
3018: _FREE((caddr_t)cookies, M_TEMP);
3019: _FREE((caddr_t)rbuf, M_TEMP);
3020: nfsm_reply(NFSX_V3POSTOPATTR);
3021: nfsm_srvpostop_attr(getret, &at);
3022: return (0);
3023: }
3024: vput(nvp);
3025:
3026: dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED;
3027: nfsm_reply(cnt);
3028: nfsm_srvpostop_attr(getret, &at);
3029: nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
3030: txdr_hyper(&at.va_filerev, tl);
3031: mp = mp2 = mb;
3032: bp = bpos;
3033: be = bp + M_TRAILINGSPACE(mp);
3034:
3035: /* Loop through the records and build reply */
3036: while (cpos < cend && ncookies > 0) {
3037: if (dp->d_fileno != 0) {
3038: nlen = dp->d_namlen;
3039: rem = nfsm_rndup(nlen)-nlen;
3040:
3041: /*
3042: * For readdir_and_lookup get the vnode using
3043: * the file number.
3044: */
3045: if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp))
3046: goto invalid;
3047: bzero((caddr_t)nfhp, NFSX_V3FH);
3048: nfhp->fh_fsid =
3049: nvp->v_mount->mnt_stat.f_fsid;
3050: if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) {
3051: vput(nvp);
3052: goto invalid;
3053: }
3054: if (VOP_GETATTR(nvp, vap, cred, procp)) {
3055: vput(nvp);
3056: goto invalid;
3057: }
3058: vput(nvp);
3059:
3060: /*
3061: * If either the dircount or maxcount will be
3062: * exceeded, get out now. Both of these lengths
3063: * are calculated conservatively, including all
3064: * XDR overheads.
3065: */
3066: len += (7 * NFSX_UNSIGNED + nlen + rem + NFSX_V3FH +
3067: NFSX_V3POSTOPATTR);
3068: dirlen += (6 * NFSX_UNSIGNED + nlen + rem);
3069: if (len > cnt || dirlen > fullsiz) {
3070: eofflag = 0;
3071: break;
3072: }
3073:
3074: /*
3075: * Build the directory record xdr from
3076: * the dirent entry.
3077: */
3078: fp = (struct nfs_fattr *)&fl.fl_fattr;
3079: nfsm_srvfillattr(vap, fp);
3080: fl.fl_fhsize = txdr_unsigned(NFSX_V3FH);
3081: fl.fl_fhok = nfs_true;
3082: fl.fl_postopok = nfs_true;
3083: fl.fl_off.nfsuquad[0] = 0;
3084: fl.fl_off.nfsuquad[1] = txdr_unsigned(*cookiep);
3085:
3086: nfsm_clget;
3087: *tl = nfs_true;
3088: bp += NFSX_UNSIGNED;
3089: nfsm_clget;
3090: *tl = 0;
3091: bp += NFSX_UNSIGNED;
3092: nfsm_clget;
3093: *tl = txdr_unsigned(dp->d_fileno);
3094: bp += NFSX_UNSIGNED;
3095: nfsm_clget;
3096: *tl = txdr_unsigned(nlen);
3097: bp += NFSX_UNSIGNED;
3098:
3099: /* And loop around copying the name */
3100: xfer = nlen;
3101: cp = dp->d_name;
3102: while (xfer > 0) {
3103: nfsm_clget;
3104: if ((bp + xfer) > be)
3105: tsiz = be - bp;
3106: else
3107: tsiz = xfer;
3108: bcopy(cp, bp, tsiz);
3109: bp += tsiz;
3110: xfer -= tsiz;
3111: if (xfer > 0)
3112: cp += tsiz;
3113: }
3114: /* And null pad to a long boundary */
3115: for (i = 0; i < rem; i++)
3116: *bp++ = '\0';
3117:
3118: /*
3119: * Now copy the flrep structure out.
3120: */
3121: xfer = sizeof (struct flrep);
3122: cp = (caddr_t)&fl;
3123: while (xfer > 0) {
3124: nfsm_clget;
3125: if ((bp + xfer) > be)
3126: tsiz = be - bp;
3127: else
3128: tsiz = xfer;
3129: bcopy(cp, bp, tsiz);
3130: bp += tsiz;
3131: xfer -= tsiz;
3132: if (xfer > 0)
3133: cp += tsiz;
3134: }
3135: }
3136: invalid:
3137: cpos += dp->d_reclen;
3138: dp = (struct dirent *)cpos;
3139: cookiep++;
3140: ncookies--;
3141: }
3142: vrele(vp);
3143: nfsm_clget;
3144: *tl = nfs_false;
3145: bp += NFSX_UNSIGNED;
3146: nfsm_clget;
3147: if (eofflag)
3148: *tl = nfs_true;
3149: else
3150: *tl = nfs_false;
3151: bp += NFSX_UNSIGNED;
3152: if (mp != mb) {
3153: if (bp < be)
3154: mp->m_len = bp - mtod(mp, caddr_t);
3155: } else
3156: mp->m_len += bp - bpos;
3157: FREE((caddr_t)cookies, M_TEMP);
3158: FREE((caddr_t)rbuf, M_TEMP);
3159: nfsm_srvdone;
3160: }
3161:
3162: /*
3163: * nfs commit service
3164: */
3165: int
3166: nfsrv_commit(nfsd, slp, procp, mrq)
3167: struct nfsrv_descript *nfsd;
3168: struct nfssvc_sock *slp;
3169: struct proc *procp;
3170: struct mbuf **mrq;
3171: {
3172: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3173: struct mbuf *nam = nfsd->nd_nam;
3174: caddr_t dpos = nfsd->nd_dpos;
3175: struct ucred *cred = &nfsd->nd_cr;
3176: struct vattr bfor, aft;
3177: struct vnode *vp;
3178: nfsfh_t nfh;
3179: fhandle_t *fhp;
3180: register u_long *tl;
3181: register long t1;
3182: caddr_t bpos;
3183: int error = 0, rdonly, for_ret = 1, aft_ret = 1, cnt, cache;
3184: char *cp2;
3185: struct mbuf *mb, *mb2, *mreq;
3186: u_quad_t frev, off;
3187:
3188: #ifndef nolint
3189: cache = 0;
3190: #endif
3191: fhp = &nfh.fh_generic;
3192: nfsm_srvmtofh(fhp);
3193: nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
3194:
3195: /*
3196: * XXX At this time VOP_FSYNC() does not accept offset and byte
3197: * count parameters, so these arguments are useless (someday maybe).
3198: */
3199: fxdr_hyper(tl, &off);
3200: tl += 2;
3201: cnt = fxdr_unsigned(int, *tl);
3202: if ((error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3203: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE))) {
3204: nfsm_reply(2 * NFSX_UNSIGNED);
3205: nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
3206: return (0);
3207: }
3208: for_ret = VOP_GETATTR(vp, &bfor, cred, procp);
3209: error = VOP_FSYNC(vp, cred, MNT_WAIT, procp);
3210: aft_ret = VOP_GETATTR(vp, &aft, cred, procp);
3211: vput(vp);
3212: nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF);
3213: nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
3214: if (!error) {
3215: nfsm_build(tl, u_long *, NFSX_V3WRITEVERF);
3216: *tl++ = txdr_unsigned(boottime.tv_sec);
3217: *tl = txdr_unsigned(boottime.tv_usec);
3218: } else
3219: return (0);
3220: nfsm_srvdone;
3221: }
3222:
3223: /*
3224: * nfs statfs service
3225: */
3226: int
3227: nfsrv_statfs(nfsd, slp, procp, mrq)
3228: struct nfsrv_descript *nfsd;
3229: struct nfssvc_sock *slp;
3230: struct proc *procp;
3231: struct mbuf **mrq;
3232: {
3233: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3234: struct mbuf *nam = nfsd->nd_nam;
3235: caddr_t dpos = nfsd->nd_dpos;
3236: struct ucred *cred = &nfsd->nd_cr;
3237: register struct statfs *sf;
3238: register struct nfs_statfs *sfp;
3239: register u_long *tl;
3240: register long t1;
3241: caddr_t bpos;
3242: int error = 0, rdonly, cache, getret = 1;
3243: int v3 = (nfsd->nd_flag & ND_NFSV3);
3244: char *cp2;
3245: struct mbuf *mb, *mb2, *mreq;
3246: struct vnode *vp;
3247: struct vattr at;
3248: nfsfh_t nfh;
3249: fhandle_t *fhp;
3250: struct statfs statfs;
3251: u_quad_t frev, tval;
3252:
3253: #ifndef nolint
3254: cache = 0;
3255: #endif
3256: fhp = &nfh.fh_generic;
3257: nfsm_srvmtofh(fhp);
3258: if ((error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3259: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE))) {
3260: nfsm_reply(NFSX_UNSIGNED);
3261: nfsm_srvpostop_attr(getret, &at);
3262: return (0);
3263: }
3264: sf = &statfs;
3265: error = VFS_STATFS(vp->v_mount, sf, procp);
3266: getret = VOP_GETATTR(vp, &at, cred, procp);
3267: vput(vp);
3268: nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3));
3269: if (v3)
3270: nfsm_srvpostop_attr(getret, &at);
3271: if (error)
3272: return (0);
3273: nfsm_build(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
3274: if (v3) {
3275: tval = (u_quad_t)sf->f_blocks;
3276: tval *= (u_quad_t)sf->f_bsize;
3277: txdr_hyper(&tval, &sfp->sf_tbytes);
3278: tval = (u_quad_t)sf->f_bfree;
3279: tval *= (u_quad_t)sf->f_bsize;
3280: txdr_hyper(&tval, &sfp->sf_fbytes);
3281: tval = (u_quad_t)sf->f_bavail;
3282: tval *= (u_quad_t)sf->f_bsize;
3283: txdr_hyper(&tval, &sfp->sf_abytes);
3284: sfp->sf_tfiles.nfsuquad[0] = 0;
3285: sfp->sf_tfiles.nfsuquad[1] = txdr_unsigned(sf->f_files);
3286: sfp->sf_ffiles.nfsuquad[0] = 0;
3287: sfp->sf_ffiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
3288: sfp->sf_afiles.nfsuquad[0] = 0;
3289: sfp->sf_afiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
3290: sfp->sf_invarsec = 0;
3291: } else {
3292: sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
3293: sfp->sf_bsize = txdr_unsigned(sf->f_bsize);
3294: sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
3295: sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
3296: sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
3297: }
3298: nfsm_srvdone;
3299: }
3300:
3301: /*
3302: * nfs fsinfo service
3303: */
3304: int
3305: nfsrv_fsinfo(nfsd, slp, procp, mrq)
3306: struct nfsrv_descript *nfsd;
3307: struct nfssvc_sock *slp;
3308: struct proc *procp;
3309: struct mbuf **mrq;
3310: {
3311: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3312: struct mbuf *nam = nfsd->nd_nam;
3313: caddr_t dpos = nfsd->nd_dpos;
3314: struct ucred *cred = &nfsd->nd_cr;
3315: register u_long *tl;
3316: register struct nfsv3_fsinfo *sip;
3317: register long t1;
3318: caddr_t bpos;
3319: int error = 0, rdonly, cache, getret = 1, pref;
3320: char *cp2;
3321: struct mbuf *mb, *mb2, *mreq;
3322: struct vnode *vp;
3323: struct vattr at;
3324: nfsfh_t nfh;
3325: fhandle_t *fhp;
3326: u_quad_t frev;
3327:
3328: #ifndef nolint
3329: cache = 0;
3330: #endif
3331: fhp = &nfh.fh_generic;
3332: nfsm_srvmtofh(fhp);
3333: if ((error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3334: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE))) {
3335: nfsm_reply(NFSX_UNSIGNED);
3336: nfsm_srvpostop_attr(getret, &at);
3337: return (0);
3338: }
3339: getret = VOP_GETATTR(vp, &at, cred, procp);
3340: vput(vp);
3341: nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO);
3342: nfsm_srvpostop_attr(getret, &at);
3343: nfsm_build(sip, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
3344:
3345: /*
3346: * XXX
3347: * There should be file system VFS OP(s) to get this information.
3348: * For now, assume ufs.
3349: */
3350: if (slp->ns_so->so_type == SOCK_DGRAM)
3351: pref = NFS_MAXDGRAMDATA;
3352: else
3353: pref = NFS_MAXDATA;
3354: sip->fs_rtmax = txdr_unsigned(NFS_MAXDATA);
3355: sip->fs_rtpref = txdr_unsigned(pref);
3356: sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE);
3357: sip->fs_wtmax = txdr_unsigned(NFS_MAXDATA);
3358: sip->fs_wtpref = txdr_unsigned(pref);
3359: sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE);
3360: sip->fs_dtpref = txdr_unsigned(pref);
3361: sip->fs_maxfilesize.nfsuquad[0] = 0xffffffff;
3362: sip->fs_maxfilesize.nfsuquad[1] = 0xffffffff;
3363: sip->fs_timedelta.nfsv3_sec = 0;
3364: sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1);
3365: sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK |
3366: NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS |
3367: NFSV3FSINFO_CANSETTIME);
3368: nfsm_srvdone;
3369: }
3370:
3371: /*
3372: * nfs pathconf service
3373: */
3374: int
3375: nfsrv_pathconf(nfsd, slp, procp, mrq)
3376: struct nfsrv_descript *nfsd;
3377: struct nfssvc_sock *slp;
3378: struct proc *procp;
3379: struct mbuf **mrq;
3380: {
3381: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3382: struct mbuf *nam = nfsd->nd_nam;
3383: caddr_t dpos = nfsd->nd_dpos;
3384: struct ucred *cred = &nfsd->nd_cr;
3385: register u_long *tl;
3386: register struct nfsv3_pathconf *pc;
3387: register long t1;
3388: caddr_t bpos;
3389: int error = 0, rdonly, cache, getret = 1, linkmax, namemax;
3390: int chownres, notrunc;
3391: char *cp2;
3392: struct mbuf *mb, *mb2, *mreq;
3393: struct vnode *vp;
3394: struct vattr at;
3395: nfsfh_t nfh;
3396: fhandle_t *fhp;
3397: u_quad_t frev;
3398:
3399: #ifndef nolint
3400: cache = 0;
3401: #endif
3402: fhp = &nfh.fh_generic;
3403: nfsm_srvmtofh(fhp);
3404: if ((error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3405: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE))) {
3406: nfsm_reply(NFSX_UNSIGNED);
3407: nfsm_srvpostop_attr(getret, &at);
3408: return (0);
3409: }
3410: error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax);
3411: if (!error)
3412: error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax);
3413: if (!error)
3414: error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres);
3415: if (!error)
3416: error = VOP_PATHCONF(vp, _PC_NO_TRUNC, ¬runc);
3417: getret = VOP_GETATTR(vp, &at, cred, procp);
3418: vput(vp);
3419: nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF);
3420: nfsm_srvpostop_attr(getret, &at);
3421: if (error)
3422: return (0);
3423: nfsm_build(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
3424:
3425: pc->pc_linkmax = txdr_unsigned(linkmax);
3426: pc->pc_namemax = txdr_unsigned(namemax);
3427: pc->pc_notrunc = txdr_unsigned(notrunc);
3428: pc->pc_chownrestricted = txdr_unsigned(chownres);
3429:
3430: /*
3431: * These should probably be supported by VOP_PATHCONF(), but
3432: * until msdosfs is exportable (why would you want to?), the
3433: * Unix defaults should be ok.
3434: */
3435: pc->pc_caseinsensitive = nfs_false;
3436: pc->pc_casepreserving = nfs_true;
3437: nfsm_srvdone;
3438: }
3439:
3440: /*
3441: * Null operation, used by clients to ping server
3442: */
3443: /* ARGSUSED */
3444: int
3445: nfsrv_null(nfsd, slp, procp, mrq)
3446: struct nfsrv_descript *nfsd;
3447: struct nfssvc_sock *slp;
3448: struct proc *procp;
3449: struct mbuf **mrq;
3450: {
3451: struct mbuf *mrep = nfsd->nd_mrep;
3452: caddr_t bpos;
3453: int error = NFSERR_RETVOID, cache;
3454: struct mbuf *mb, *mreq;
3455: u_quad_t frev;
3456:
3457: #ifndef nolint
3458: cache = 0;
3459: #endif
3460: nfsm_reply(0);
3461: return (0);
3462: }
3463:
3464: /*
3465: * No operation, used for obsolete procedures
3466: */
3467: /* ARGSUSED */
3468: int
3469: nfsrv_noop(nfsd, slp, procp, mrq)
3470: struct nfsrv_descript *nfsd;
3471: struct nfssvc_sock *slp;
3472: struct proc *procp;
3473: struct mbuf **mrq;
3474: {
3475: struct mbuf *mrep = nfsd->nd_mrep;
3476: caddr_t bpos;
3477: int error, cache;
3478: struct mbuf *mb, *mreq;
3479: u_quad_t frev;
3480:
3481: #ifndef nolint
3482: cache = 0;
3483: #endif
3484: if (nfsd->nd_repstat)
3485: error = nfsd->nd_repstat;
3486: else
3487: error = EPROCUNAVAIL;
3488: nfsm_reply(0);
3489: return (0);
3490: }
3491:
3492: /*
3493: * Perform access checking for vnodes obtained from file handles that would
3494: * refer to files already opened by a Unix client. You cannot just use
3495: * vn_writechk() and VOP_ACCESS() for two reasons.
3496: * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
3497: * 2 - The owner is to be given access irrespective of mode bits so that
3498: * processes that chmod after opening a file don't break. I don't like
3499: * this because it opens a security hole, but since the nfs server opens
3500: * a security hole the size of a barn door anyhow, what the heck.
3501: */
3502: static int
3503: nfsrv_access(vp, flags, cred, rdonly, p)
3504: register struct vnode *vp;
3505: int flags;
3506: register struct ucred *cred;
3507: int rdonly;
3508: struct proc *p;
3509: {
3510: struct vattr vattr;
3511: int error;
3512: if (flags & VWRITE) {
3513: /* Just vn_writechk() changed to check rdonly */
3514: /*
3515: * Disallow write attempts on read-only file systems;
3516: * unless the file is a socket or a block or character
3517: * device resident on the file system.
3518: */
3519: if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
3520: switch (vp->v_type) {
3521: case VREG: case VDIR: case VLNK: case VCPLX:
3522: return (EROFS);
3523: }
3524: }
3525: /*
3526: * If there's shared text associated with
3527: * the inode, we can't allow writing.
3528: */
3529: if (vp->v_flag & VTEXT)
3530: return (ETXTBSY);
3531: }
3532: if ((error = VOP_GETATTR(vp, &vattr, cred, p)))
3533: return (error);
3534: if ((error = VOP_ACCESS(vp, flags, cred, p)) &&
3535: cred->cr_uid != vattr.va_uid)
3536: return (error);
3537: return (0);
3538: }
3539: #endif /* NFS_NOSERVER */
3540:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.