|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
23: /*
24: * Copyright (c) 1989, 1993
25: * The Regents of the University of California. All rights reserved.
26: *
27: * This code is derived from software contributed to Berkeley by
28: * Rick Macklem at The University of Guelph.
29: *
30: * Redistribution and use in source and binary forms, with or without
31: * modification, are permitted provided that the following conditions
32: * are met:
33: * 1. Redistributions of source code must retain the above copyright
34: * notice, this list of conditions and the following disclaimer.
35: * 2. Redistributions in binary form must reproduce the above copyright
36: * notice, this list of conditions and the following disclaimer in the
37: * documentation and/or other materials provided with the distribution.
38: * 3. All advertising materials mentioning features or use of this software
39: * must display the following acknowledgement:
40: * This product includes software developed by the University of
41: * California, Berkeley and its contributors.
42: * 4. Neither the name of the University nor the names of its contributors
43: * may be used to endorse or promote products derived from this software
44: * without specific prior written permission.
45: *
46: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56: * SUCH DAMAGE.
57: *
58: * @(#)nfs_serv.c 8.7 (Berkeley) 5/14/95
59: * FreeBSD-Id: nfs_serv.c,v 1.52 1997/10/28 15:59:05 bde Exp $
60: */
61:
62: /*
63: * nfs version 2 and 3 server calls to vnode ops
64: * - these routines generally have 3 phases
65: * 1 - break down and validate rpc request in mbuf list
66: * 2 - do the vnode ops for the request
67: * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
68: * 3 - build the rpc reply in an mbuf list
69: * nb:
70: * - do not mix the phases, since the nfsm_?? macros can return failures
71: * on a bad rpc or similar and do not do any vrele() or vput()'s
72: *
73: * - the nfsm_reply() macro generates an nfs rpc reply with the nfs
74: * error number iff error != 0 whereas
75: * returning an error from the server function implies a fatal error
76: * such as a badly constructed rpc request that should be dropped without
77: * a reply.
78: * For Version 3, nfsm_reply() does not return for the error case, since
79: * most version 3 rpcs return more than the status for error cases.
80: */
81:
82: #include <mach_nbc.h>
83: #include <sys/param.h>
84: #include <sys/systm.h>
85: #include <sys/proc.h>
86: #include <sys/namei.h>
87: #include <sys/unistd.h>
88: #include <sys/malloc.h>
89: #include <sys/vnode.h>
90: #include <sys/mount.h>
91: #include <sys/socket.h>
92: #include <sys/socketvar.h>
93: #include <sys/mbuf.h>
94: #include <sys/dirent.h>
95: #include <sys/stat.h>
96: #include <sys/kernel.h>
97: #include <sys/sysctl.h>
98: #include <ufs/ufs/dir.h>
99:
100: #include <sys/vm.h>
101: #include <sys/vmparam.h>
102: #include <machine/spl.h>
103:
104: #include <kern/mapfs.h>
105:
106: #include <nfs/nfsproto.h>
107: #include <nfs/rpcv2.h>
108: #include <nfs/nfs.h>
109: #include <nfs/xdr_subs.h>
110: #include <nfs/nfsm_subs.h>
111: #include <nfs/nqnfs.h>
112:
113: nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
114: NFFIFO, NFNON };
115: #ifndef NFS_NOSERVER
116: nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
117: NFCHR, NFNON };
118: /* Global vars */
119: extern u_long nfs_xdrneg1;
120: extern u_long nfs_false, nfs_true;
121: extern enum vtype nv3tov_type[8];
122: extern struct nfsstats nfsstats;
123:
124: int nfsrvw_procrastinate = NFS_GATHERDELAY * 1000;
125: int nfsrvw_procrastinate_v3 = 0;
126:
127: int nfs_async = 0;
128: #ifdef notyet
129: /* XXX CSM 11/25/97 Upgrade sysctl.h someday */
130: SYSCTL_INT(_vfs_nfs, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0, "");
131: #endif
132:
133: static int nfsrv_access __P((struct vnode *,int,struct ucred *,int,
134: struct proc *));
135: static void nfsrvw_coalesce __P((struct nfsrv_descript *,
136: struct nfsrv_descript *));
137:
138: extern int vnode_uncache(struct vnode *vp);
139:
140: /*
141: * nfs v3 access service
142: */
143: int
144: nfsrv3_access(nfsd, slp, procp, mrq)
145: struct nfsrv_descript *nfsd;
146: struct nfssvc_sock *slp;
147: struct proc *procp;
148: struct mbuf **mrq;
149: {
150: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
151: struct mbuf *nam = nfsd->nd_nam;
152: caddr_t dpos = nfsd->nd_dpos;
153: struct ucred *cred = &nfsd->nd_cr;
154: struct vnode *vp;
155: nfsfh_t nfh;
156: fhandle_t *fhp;
157: register u_long *tl;
158: register long t1;
159: caddr_t bpos;
160: int error = 0, rdonly, cache, getret;
161: char *cp2;
162: struct mbuf *mb, *mreq, *mb2;
163: struct vattr vattr, *vap = &vattr;
164: u_long testmode, nfsmode;
165: u_quad_t frev;
166:
167: #ifndef nolint
168: cache = 0;
169: #endif
170: fhp = &nfh.fh_generic;
171: nfsm_srvmtofh(fhp);
172: nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
173: if ((error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
174: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE))) {
175: nfsm_reply(NFSX_UNSIGNED);
176: nfsm_srvpostop_attr(1, (struct vattr *)0);
177: return (0);
178: }
179: nfsmode = fxdr_unsigned(u_long, *tl);
180: if ((nfsmode & NFSV3ACCESS_READ) &&
181: nfsrv_access(vp, VREAD, cred, rdonly, procp))
182: nfsmode &= ~NFSV3ACCESS_READ;
183: if (vp->v_type == VDIR)
184: testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
185: NFSV3ACCESS_DELETE);
186: else
187: testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
188: if ((nfsmode & testmode) &&
189: nfsrv_access(vp, VWRITE, cred, rdonly, procp))
190: nfsmode &= ~testmode;
191: if (vp->v_type == VDIR)
192: testmode = NFSV3ACCESS_LOOKUP;
193: else
194: testmode = NFSV3ACCESS_EXECUTE;
195: if ((nfsmode & testmode) &&
196: nfsrv_access(vp, VEXEC, cred, rdonly, procp))
197: nfsmode &= ~testmode;
198: getret = VOP_GETATTR(vp, vap, cred, procp);
199: vput(vp);
200: nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED);
201: nfsm_srvpostop_attr(getret, vap);
202: nfsm_build(tl, u_long *, NFSX_UNSIGNED);
203: *tl = txdr_unsigned(nfsmode);
204: nfsm_srvdone;
205: }
206:
207: /*
208: * nfs getattr service
209: */
210: int
211: nfsrv_getattr(nfsd, slp, procp, mrq)
212: struct nfsrv_descript *nfsd;
213: struct nfssvc_sock *slp;
214: struct proc *procp;
215: struct mbuf **mrq;
216: {
217: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
218: struct mbuf *nam = nfsd->nd_nam;
219: caddr_t dpos = nfsd->nd_dpos;
220: struct ucred *cred = &nfsd->nd_cr;
221: register struct nfs_fattr *fp;
222: struct vattr va;
223: register struct vattr *vap = &va;
224: struct vnode *vp;
225: nfsfh_t nfh;
226: fhandle_t *fhp;
227: register u_long *tl;
228: register long t1;
229: caddr_t bpos;
230: int error = 0, rdonly, cache;
231: char *cp2;
232: struct mbuf *mb, *mb2, *mreq;
233: u_quad_t frev;
234:
235: fhp = &nfh.fh_generic;
236: nfsm_srvmtofh(fhp);
237: if ((error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
238: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE))) {
239: nfsm_reply(0);
240: return (0);
241: }
242: nqsrv_getl(vp, ND_READ);
243: error = VOP_GETATTR(vp, vap, cred, procp);
244: vput(vp);
245: nfsm_reply(NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
246: if (error)
247: return (0);
248: nfsm_build(fp, struct nfs_fattr *, NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
249: nfsm_srvfillattr(vap, fp);
250: nfsm_srvdone;
251: }
252:
253: /*
254: * nfs setattr service
255: */
256: int
257: nfsrv_setattr(nfsd, slp, procp, mrq)
258: struct nfsrv_descript *nfsd;
259: struct nfssvc_sock *slp;
260: struct proc *procp;
261: struct mbuf **mrq;
262: {
263: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
264: struct mbuf *nam = nfsd->nd_nam;
265: caddr_t dpos = nfsd->nd_dpos;
266: struct ucred *cred = &nfsd->nd_cr;
267: struct vattr va, preat;
268: register struct vattr *vap = &va;
269: register struct nfsv2_sattr *sp;
270: register struct nfs_fattr *fp;
271: struct vnode *vp;
272: nfsfh_t nfh;
273: fhandle_t *fhp;
274: register u_long *tl;
275: register long t1;
276: caddr_t bpos;
277: int error = 0, rdonly, cache, preat_ret = 1, postat_ret = 1;
278: int v3 = (nfsd->nd_flag & ND_NFSV3), gcheck = 0;
279: char *cp2;
280: struct mbuf *mb, *mb2, *mreq;
281: u_quad_t frev;
282: struct timespec guard;
283:
284: fhp = &nfh.fh_generic;
285: nfsm_srvmtofh(fhp);
286: VATTR_NULL(vap);
287: if (v3) {
288: nfsm_srvsattr(vap);
289: nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
290: gcheck = fxdr_unsigned(int, *tl);
291: if (gcheck) {
292: nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
293: fxdr_nfsv3time(tl, &guard);
294: }
295: } else {
296: nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
297: /*
298: * Nah nah nah nah na nah
299: * There is a bug in the Sun client that puts 0xffff in the mode
300: * field of sattr when it should put in 0xffffffff. The u_short
301: * doesn't sign extend.
302: * --> check the low order 2 bytes for 0xffff
303: */
304: if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
305: vap->va_mode = nfstov_mode(sp->sa_mode);
306: if (sp->sa_uid != nfs_xdrneg1)
307: vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
308: if (sp->sa_gid != nfs_xdrneg1)
309: vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
310: if (sp->sa_size != nfs_xdrneg1)
311: vap->va_size = fxdr_unsigned(u_quad_t, sp->sa_size);
312: if (sp->sa_atime.nfsv2_sec != nfs_xdrneg1) {
313: #ifdef notyet
314: fxdr_nfsv2time(&sp->sa_atime, &vap->va_atime);
315: #else
316: vap->va_atime.tv_sec =
317: fxdr_unsigned(long, sp->sa_atime.nfsv2_sec);
318: vap->va_atime.tv_nsec = 0;
319: #endif
320: }
321: if (sp->sa_mtime.nfsv2_sec != nfs_xdrneg1)
322: fxdr_nfsv2time(&sp->sa_mtime, &vap->va_mtime);
323:
324: }
325:
326: /*
327: * Now that we have all the fields, lets do it.
328: */
329: if ((error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
330: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE))) {
331: nfsm_reply(2 * NFSX_UNSIGNED);
332: nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
333: return (0);
334: }
335: nqsrv_getl(vp, ND_WRITE);
336: if (v3) {
337: error = preat_ret = VOP_GETATTR(vp, &preat, cred, procp);
338: if (!error && gcheck &&
339: (preat.va_ctime.tv_sec != guard.tv_sec ||
340: preat.va_ctime.tv_nsec != guard.tv_nsec))
341: error = NFSERR_NOT_SYNC;
342: if (error) {
343: vput(vp);
344: nfsm_reply(NFSX_WCCDATA(v3));
345: nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
346: return (0);
347: }
348: }
349:
350: /*
351: * If the size is being changed write acces is required, otherwise
352: * just check for a read only file system.
353: */
354: if (vap->va_size == ((u_quad_t)((quad_t) -1))) {
355: if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
356: error = EROFS;
357: goto out;
358: }
359: } else {
360: if (vp->v_type == VDIR) {
361: error = EISDIR;
362: goto out;
363: } else if ((error = nfsrv_access(vp, VWRITE, cred, rdonly,
364: procp)))
365: goto out;
366: }
367: error = VOP_SETATTR(vp, vap, cred, procp);
368: postat_ret = VOP_GETATTR(vp, vap, cred, procp);
369: if (!error)
370: error = postat_ret;
371: out:
372: vput(vp);
373: nfsm_reply(NFSX_WCCORFATTR(v3));
374: if (v3) {
375: nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
376: return (0);
377: } else {
378: nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
379: nfsm_srvfillattr(vap, fp);
380: }
381: nfsm_srvdone;
382: }
383:
384: /*
385: * nfs lookup rpc
386: */
387: int
388: nfsrv_lookup(nfsd, slp, procp, mrq)
389: struct nfsrv_descript *nfsd;
390: struct nfssvc_sock *slp;
391: struct proc *procp;
392: struct mbuf **mrq;
393: {
394: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
395: struct mbuf *nam = nfsd->nd_nam;
396: caddr_t dpos = nfsd->nd_dpos;
397: struct ucred *cred = &nfsd->nd_cr;
398: register struct nfs_fattr *fp;
399: struct nameidata nd, *ndp = &nd;
400: #ifdef notdef
401: struct nameidata ind;
402: #endif
403: struct vnode *vp, *dirp;
404: nfsfh_t nfh;
405: fhandle_t *fhp;
406: register caddr_t cp;
407: register u_long *tl;
408: register long t1;
409: caddr_t bpos;
410: int error = 0, cache, len, dirattr_ret = 1;
411: int v3 = (nfsd->nd_flag & ND_NFSV3), pubflag;
412: char *cp2;
413: struct mbuf *mb, *mb2, *mreq;
414: struct vattr va, dirattr, *vap = &va;
415: u_quad_t frev;
416:
417: fhp = &nfh.fh_generic;
418: nfsm_srvmtofh(fhp);
419: nfsm_srvnamesiz(len);
420:
421: pubflag = nfs_ispublicfh(fhp);
422:
423: nd.ni_cnd.cn_cred = cred;
424: nd.ni_cnd.cn_nameiop = LOOKUP;
425: nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART;
426: error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
427: &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), pubflag);
428:
429: /* XXX CSM 12/4/97 Revisit when enabling WebNFS */
430: #ifdef notyet
431: if (!error && pubflag) {
432: if (nd.ni_vp->v_type == VDIR && nfs_pub.np_index != NULL) {
433: /*
434: * Setup call to lookup() to see if we can find
435: * the index file. Arguably, this doesn't belong
436: * in a kernel.. Ugh.
437: */
438: ind = nd;
439: VOP_UNLOCK(nd.ni_vp, 0, procp);
440: ind.ni_pathlen = strlen(nfs_pub.np_index);
441: ind.ni_cnd.cn_nameptr = ind.ni_cnd.cn_pnbuf =
442: nfs_pub.np_index;
443: ind.ni_startdir = nd.ni_vp;
444: VREF(ind.ni_startdir);
445: error = lookup(&ind);
446: if (!error) {
447: /*
448: * Found an index file. Get rid of
449: * the old references.
450: */
451: if (dirp)
452: vrele(dirp);
453: dirp = nd.ni_vp;
454: vrele(nd.ni_startdir);
455: ndp = &ind;
456: } else
457: error = 0;
458: }
459: /*
460: * If the public filehandle was used, check that this lookup
461: * didn't result in a filehandle outside the publicly exported
462: * filesystem.
463: */
464:
465: if (!error && ndp->ni_vp->v_mount != nfs_pub.np_mount) {
466: vput(nd.ni_vp);
467: error = EPERM;
468: }
469: }
470: #endif
471:
472: if (dirp) {
473: if (v3)
474: dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred,
475: procp);
476: vrele(dirp);
477: }
478:
479: if (error) {
480: nfsm_reply(NFSX_POSTOPATTR(v3));
481: nfsm_srvpostop_attr(dirattr_ret, &dirattr);
482: return (0);
483: }
484:
485: nqsrv_getl(ndp->ni_startdir, ND_READ);
486: vrele(ndp->ni_startdir);
487: FREE_ZONE(nd.ni_cnd.cn_pnbuf, nd.ni_cnd.cn_pnlen, M_NAMEI);
488: vp = ndp->ni_vp;
489: bzero((caddr_t)fhp, sizeof(nfh));
490: fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
491: error = VFS_VPTOFH(vp, &fhp->fh_fid);
492: if (!error)
493: error = VOP_GETATTR(vp, vap, cred, procp);
494: vput(vp);
495: nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPORFATTR(v3) + NFSX_POSTOPATTR(v3));
496: if (error) {
497: nfsm_srvpostop_attr(dirattr_ret, &dirattr);
498: return (0);
499: }
500: nfsm_srvfhtom(fhp, v3);
501: if (v3) {
502: nfsm_srvpostop_attr(0, vap);
503: nfsm_srvpostop_attr(dirattr_ret, &dirattr);
504: } else {
505: nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
506: nfsm_srvfillattr(vap, fp);
507: }
508: nfsm_srvdone;
509: }
510:
511: /*
512: * nfs readlink service
513: */
514: int
515: nfsrv_readlink(nfsd, slp, procp, mrq)
516: struct nfsrv_descript *nfsd;
517: struct nfssvc_sock *slp;
518: struct proc *procp;
519: struct mbuf **mrq;
520: {
521: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
522: struct mbuf *nam = nfsd->nd_nam;
523: caddr_t dpos = nfsd->nd_dpos;
524: struct ucred *cred = &nfsd->nd_cr;
525: struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
526: register struct iovec *ivp = iv;
527: register struct mbuf *mp;
528: register u_long *tl;
529: register long t1;
530: caddr_t bpos;
531: int error = 0, rdonly, cache, i, tlen, len, getret;
532: int v3 = (nfsd->nd_flag & ND_NFSV3);
533: char *cp2;
534: struct mbuf *mb, *mb2, *mp2, *mp3, *mreq;
535: struct vnode *vp;
536: struct vattr attr;
537: nfsfh_t nfh;
538: fhandle_t *fhp;
539: struct uio io, *uiop = &io;
540: u_quad_t frev;
541:
542: #ifndef nolint
543: mp2 = mp3 = (struct mbuf *)0;
544: #endif
545: fhp = &nfh.fh_generic;
546: nfsm_srvmtofh(fhp);
547: len = 0;
548: i = 0;
549: while (len < NFS_MAXPATHLEN) {
550: MGET(mp, M_WAIT, MT_DATA);
551: MCLGET(mp, M_WAIT);
552: mp->m_len = NFSMSIZ(mp);
553: if (len == 0)
554: mp3 = mp2 = mp;
555: else {
556: mp2->m_next = mp;
557: mp2 = mp;
558: }
559: if ((len+mp->m_len) > NFS_MAXPATHLEN) {
560: mp->m_len = NFS_MAXPATHLEN-len;
561: len = NFS_MAXPATHLEN;
562: } else
563: len += mp->m_len;
564: ivp->iov_base = mtod(mp, caddr_t);
565: ivp->iov_len = mp->m_len;
566: i++;
567: ivp++;
568: }
569: uiop->uio_iov = iv;
570: uiop->uio_iovcnt = i;
571: uiop->uio_offset = 0;
572: uiop->uio_resid = len;
573: uiop->uio_rw = UIO_READ;
574: uiop->uio_segflg = UIO_SYSSPACE;
575: uiop->uio_procp = (struct proc *)0;
576: if ((error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
577: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE))) {
578: m_freem(mp3);
579: nfsm_reply(2 * NFSX_UNSIGNED);
580: nfsm_srvpostop_attr(1, (struct vattr *)0);
581: return (0);
582: }
583: if (vp->v_type != VLNK) {
584: if (v3)
585: error = EINVAL;
586: else
587: error = ENXIO;
588: goto out;
589: }
590: nqsrv_getl(vp, ND_READ);
591: error = VOP_READLINK(vp, uiop, cred);
592: out:
593: getret = VOP_GETATTR(vp, &attr, cred, procp);
594: vput(vp);
595: if (error)
596: m_freem(mp3);
597: nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_UNSIGNED);
598: if (v3) {
599: nfsm_srvpostop_attr(getret, &attr);
600: if (error)
601: return (0);
602: }
603: if (uiop->uio_resid > 0) {
604: len -= uiop->uio_resid;
605: tlen = nfsm_rndup(len);
606: nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len);
607: }
608: nfsm_build(tl, u_long *, NFSX_UNSIGNED);
609: *tl = txdr_unsigned(len);
610: mb->m_next = mp3;
611: nfsm_srvdone;
612: }
613:
614: /*
615: * nfs read service
616: */
617: int
618: nfsrv_read(nfsd, slp, procp, mrq)
619: struct nfsrv_descript *nfsd;
620: struct nfssvc_sock *slp;
621: struct proc *procp;
622: struct mbuf **mrq;
623: {
624: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
625: struct mbuf *nam = nfsd->nd_nam;
626: caddr_t dpos = nfsd->nd_dpos;
627: struct ucred *cred = &nfsd->nd_cr;
628: register struct iovec *iv;
629: struct iovec *iv2;
630: register struct mbuf *m;
631: register struct nfs_fattr *fp;
632: register u_long *tl;
633: register long t1;
634: register int i;
635: caddr_t bpos;
636: int error = 0, rdonly, cache, cnt, len, left, siz, tlen, getret;
637: int v3 = (nfsd->nd_flag & ND_NFSV3), reqlen;
638: char *cp2;
639: struct mbuf *mb, *mb2, *mreq;
640: struct mbuf *m2;
641: struct vnode *vp;
642: nfsfh_t nfh;
643: fhandle_t *fhp;
644: struct uio io, *uiop = &io;
645: struct vattr va, *vap = &va;
646: off_t off;
647: u_quad_t frev;
648:
649: fhp = &nfh.fh_generic;
650: nfsm_srvmtofh(fhp);
651: if (v3) {
652: nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
653: fxdr_hyper(tl, &off);
654: } else {
655: nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
656: off = (off_t)fxdr_unsigned(u_long, *tl);
657: }
658: nfsm_srvstrsiz(reqlen, NFS_SRVMAXDATA(nfsd));
659: if ((error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
660: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE))) {
661: nfsm_reply(2 * NFSX_UNSIGNED);
662: nfsm_srvpostop_attr(1, (struct vattr *)0);
663: return (0);
664: }
665: if (vp->v_type != VREG) {
666: if (v3)
667: error = EINVAL;
668: else
669: error = (vp->v_type == VDIR) ? EISDIR : EACCES;
670: }
671: if (!error) {
672: nqsrv_getl(vp, ND_READ);
673: if ((error = nfsrv_access(vp, VREAD, cred, rdonly, procp)))
674: error = nfsrv_access(vp, VEXEC, cred, rdonly, procp);
675: }
676: getret = VOP_GETATTR(vp, vap, cred, procp);
677: if (!error)
678: error = getret;
679: if (error) {
680: vput(vp);
681: nfsm_reply(NFSX_POSTOPATTR(v3));
682: nfsm_srvpostop_attr(getret, vap);
683: return (0);
684: }
685: if (off >= vap->va_size)
686: cnt = 0;
687: else if ((off + reqlen) > vap->va_size)
688: cnt = nfsm_rndup(vap->va_size - off);
689: else
690: cnt = reqlen;
691: nfsm_reply(NFSX_POSTOPORFATTR(v3) + 3 * NFSX_UNSIGNED+nfsm_rndup(cnt));
692: if (v3) {
693: nfsm_build(tl, u_long *, NFSX_V3FATTR + 4 * NFSX_UNSIGNED);
694: *tl++ = nfs_true;
695: fp = (struct nfs_fattr *)tl;
696: tl += (NFSX_V3FATTR / sizeof (u_long));
697: } else {
698: nfsm_build(tl, u_long *, NFSX_V2FATTR + NFSX_UNSIGNED);
699: fp = (struct nfs_fattr *)tl;
700: tl += (NFSX_V2FATTR / sizeof (u_long));
701: }
702: len = left = cnt;
703: if (cnt > 0) {
704: /*
705: * Generate the mbuf list with the uio_iov ref. to it.
706: */
707: i = 0;
708: m = m2 = mb;
709: while (left > 0) {
710: siz = min(M_TRAILINGSPACE(m), left);
711: if (siz > 0) {
712: left -= siz;
713: i++;
714: }
715: if (left > 0) {
716: MGET(m, M_WAIT, MT_DATA);
717: MCLGET(m, M_WAIT);
718: m->m_len = 0;
719: m2->m_next = m;
720: m2 = m;
721: }
722: }
723: MALLOC(iv, struct iovec *, i * sizeof (struct iovec),
724: M_TEMP, M_WAITOK);
725: uiop->uio_iov = iv2 = iv;
726: m = mb;
727: left = cnt;
728: i = 0;
729: while (left > 0) {
730: if (m == NULL)
731: panic("nfsrv_read iov");
732: siz = min(M_TRAILINGSPACE(m), left);
733: if (siz > 0) {
734: iv->iov_base = mtod(m, caddr_t) + m->m_len;
735: iv->iov_len = siz;
736: m->m_len += siz;
737: left -= siz;
738: iv++;
739: i++;
740: }
741: m = m->m_next;
742: }
743: uiop->uio_iovcnt = i;
744: uiop->uio_offset = off;
745: uiop->uio_resid = cnt;
746: uiop->uio_rw = UIO_READ;
747: uiop->uio_segflg = UIO_SYSSPACE;
748: #if MACH_NBC
749: if (vp->v_type == VREG) {
750: uiop->uio_procp = procp;
751: map_vnode(vp, procp);
752: error = mapfs_io(vp, uiop, uiop->uio_rw,
753: IO_NODELOCKED, cred);
754: unmap_vnode(vp, procp);
755: } else
756: #endif /* MACH_NBC */
757: error = VOP_READ(vp, uiop, IO_NODELOCKED, cred);
758: off = uiop->uio_offset;
759: FREE((caddr_t)iv2, M_TEMP);
760: if (error || (getret = VOP_GETATTR(vp, vap, cred, procp))) {
761: if (!error)
762: error = getret;
763: m_freem(mreq);
764: vput(vp);
765: nfsm_reply(NFSX_POSTOPATTR(v3));
766: nfsm_srvpostop_attr(getret, vap);
767: return (0);
768: }
769: } else
770: uiop->uio_resid = 0;
771: vput(vp);
772: nfsm_srvfillattr(vap, fp);
773: len -= uiop->uio_resid;
774: tlen = nfsm_rndup(len);
775: if (cnt != tlen || tlen != len)
776: nfsm_adj(mb, cnt - tlen, tlen - len);
777: if (v3) {
778: *tl++ = txdr_unsigned(len);
779: if (len < reqlen)
780: *tl++ = nfs_true;
781: else
782: *tl++ = nfs_false;
783: }
784: *tl = txdr_unsigned(len);
785: nfsm_srvdone;
786: }
787:
788: /*
789: * nfs write service
790: */
791: int
792: nfsrv_write(nfsd, slp, procp, mrq)
793: struct nfsrv_descript *nfsd;
794: struct nfssvc_sock *slp;
795: struct proc *procp;
796: struct mbuf **mrq;
797: {
798: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
799: struct mbuf *nam = nfsd->nd_nam;
800: caddr_t dpos = nfsd->nd_dpos;
801: struct ucred *cred = &nfsd->nd_cr;
802: register struct iovec *ivp;
803: register int i, cnt;
804: register struct mbuf *mp;
805: register struct nfs_fattr *fp;
806: struct iovec *iv;
807: struct vattr va, forat;
808: register struct vattr *vap = &va;
809: register u_long *tl;
810: register long t1;
811: caddr_t bpos;
812: int error = 0, rdonly, cache, len, forat_ret = 1;
813: int ioflags, aftat_ret = 1, retlen, zeroing, adjust;
814: int stable = NFSV3WRITE_FILESYNC;
815: int v3 = (nfsd->nd_flag & ND_NFSV3);
816: char *cp2;
817: struct mbuf *mb, *mb2, *mreq;
818: struct vnode *vp;
819: nfsfh_t nfh;
820: fhandle_t *fhp;
821: struct uio io, *uiop = &io;
822: off_t off;
823: u_quad_t frev;
824:
825: if (mrep == NULL) {
826: *mrq = NULL;
827: return (0);
828: }
829: fhp = &nfh.fh_generic;
830: nfsm_srvmtofh(fhp);
831: if (v3) {
832: nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
833: fxdr_hyper(tl, &off);
834: tl += 3;
835: stable = fxdr_unsigned(int, *tl++);
836: } else {
837: nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
838: off = (off_t)fxdr_unsigned(u_long, *++tl);
839: tl += 2;
840: if (nfs_async)
841: stable = NFSV3WRITE_UNSTABLE;
842: }
843: retlen = len = fxdr_unsigned(long, *tl);
844: cnt = i = 0;
845:
846: /*
847: * For NFS Version 2, it is not obvious what a write of zero length
848: * should do, but I might as well be consistent with Version 3,
849: * which is to return ok so long as there are no permission problems.
850: */
851: if (len > 0) {
852: zeroing = 1;
853: mp = mrep;
854: while (mp) {
855: if (mp == md) {
856: zeroing = 0;
857: adjust = dpos - mtod(mp, caddr_t);
858: mp->m_len -= adjust;
859: if (mp->m_len > 0 && adjust > 0)
860: NFSMADV(mp, adjust);
861: }
862: if (zeroing)
863: mp->m_len = 0;
864: else if (mp->m_len > 0) {
865: i += mp->m_len;
866: if (i > len) {
867: mp->m_len -= (i - len);
868: zeroing = 1;
869: }
870: if (mp->m_len > 0)
871: cnt++;
872: }
873: mp = mp->m_next;
874: }
875: }
876: if (len > NFS_MAXDATA || len < 0 || i < len) {
877: error = EIO;
878: nfsm_reply(2 * NFSX_UNSIGNED);
879: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
880: return (0);
881: }
882: if ((error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
883: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE))) {
884: nfsm_reply(2 * NFSX_UNSIGNED);
885: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
886: return (0);
887: }
888: if (v3)
889: forat_ret = VOP_GETATTR(vp, &forat, cred, procp);
890: if (vp->v_type != VREG) {
891: if (v3)
892: error = EINVAL;
893: else
894: error = (vp->v_type == VDIR) ? EISDIR : EACCES;
895: }
896: if (!error) {
897: nqsrv_getl(vp, ND_WRITE);
898: error = nfsrv_access(vp, VWRITE, cred, rdonly, procp);
899: }
900: if (error) {
901: vput(vp);
902: nfsm_reply(NFSX_WCCDATA(v3));
903: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
904: return (0);
905: }
906:
907: if (len > 0) {
908: MALLOC(ivp, struct iovec *, cnt * sizeof (struct iovec), M_TEMP,
909: M_WAITOK);
910: uiop->uio_iov = iv = ivp;
911: uiop->uio_iovcnt = cnt;
912: mp = mrep;
913: while (mp) {
914: if (mp->m_len > 0) {
915: ivp->iov_base = mtod(mp, caddr_t);
916: ivp->iov_len = mp->m_len;
917: ivp++;
918: }
919: mp = mp->m_next;
920: }
921:
922: /*
923: * XXX
924: * The IO_METASYNC flag indicates that all metadata (and not just
925: * enough to ensure data integrity) mus be written to stable storage
926: * synchronously.
927: * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
928: */
929: if (stable == NFSV3WRITE_UNSTABLE)
930: ioflags = IO_NODELOCKED;
931: else if (stable == NFSV3WRITE_DATASYNC)
932: ioflags = (IO_SYNC | IO_NODELOCKED);
933: else
934: ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
935: uiop->uio_resid = len;
936: uiop->uio_rw = UIO_WRITE;
937: uiop->uio_segflg = UIO_SYSSPACE;
938: uiop->uio_procp = (struct proc *)0;
939: uiop->uio_offset = off;
940: #if MACH_NBC
941: if (vp->v_type == VREG) {
942: map_vnode(vp, procp);
943: error = mapfs_io(vp, uiop, uiop->uio_rw, ioflags, cred);
944: unmap_vnode(vp, procp);
945: } else
946: #endif /* MACH_NBC */
947: error = VOP_WRITE(vp, uiop, ioflags, cred);
948: nfsstats.srvvop_writes++;
949: FREE((caddr_t)iv, M_TEMP);
950: }
951: aftat_ret = VOP_GETATTR(vp, vap, cred, procp);
952: vput(vp);
953: if (!error)
954: error = aftat_ret;
955: nfsm_reply(NFSX_PREOPATTR(v3) + NFSX_POSTOPORFATTR(v3) +
956: 2 * NFSX_UNSIGNED + NFSX_WRITEVERF(v3));
957: if (v3) {
958: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
959: if (error)
960: return (0);
961: nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
962: *tl++ = txdr_unsigned(retlen);
963: /*
964: * If nfs_async is set, then pretend the write was FILESYNC.
965: */
966: if (stable == NFSV3WRITE_UNSTABLE && !nfs_async)
967: *tl++ = txdr_unsigned(stable);
968: else
969: *tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC);
970: /*
971: * Actually, there is no need to txdr these fields,
972: * but it may make the values more human readable,
973: * for debugging purposes.
974: */
975: *tl++ = txdr_unsigned(boottime.tv_sec);
976: *tl = txdr_unsigned(boottime.tv_usec);
977: } else {
978: nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
979: nfsm_srvfillattr(vap, fp);
980: }
981: nfsm_srvdone;
982: }
983:
984: /*
985: * NFS write service with write gathering support. Called when
986: * nfsrvw_procrastinate > 0.
987: * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
988: * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
989: * Jan. 1994.
990: */
991: int
992: nfsrv_writegather(ndp, slp, procp, mrq)
993: struct nfsrv_descript **ndp;
994: struct nfssvc_sock *slp;
995: struct proc *procp;
996: struct mbuf **mrq;
997: {
998: register struct iovec *ivp;
999: register struct mbuf *mp;
1000: register struct nfsrv_descript *wp, *nfsd, *owp, *swp;
1001: register struct nfs_fattr *fp;
1002: register int i;
1003: struct iovec *iov;
1004: struct nfsrvw_delayhash *wpp;
1005: struct ucred *cred;
1006: struct vattr va, forat;
1007: register u_long *tl;
1008: register long t1;
1009: caddr_t bpos, dpos;
1010: int error = 0, rdonly, cache, len, forat_ret = 1;
1011: int ioflags, aftat_ret = 1, s, adjust, v3, zeroing;
1012: char *cp2;
1013: struct mbuf *mb, *mb2, *mreq, *mrep, *md;
1014: struct vnode *vp;
1015: struct uio io, *uiop = &io;
1016: u_quad_t frev, cur_usec;
1017:
1018: #ifndef nolint
1019: i = 0;
1020: len = 0;
1021: #endif
1022: *mrq = NULL;
1023: if (*ndp) {
1024: nfsd = *ndp;
1025: *ndp = NULL;
1026: mrep = nfsd->nd_mrep;
1027: md = nfsd->nd_md;
1028: dpos = nfsd->nd_dpos;
1029: cred = &nfsd->nd_cr;
1030: v3 = (nfsd->nd_flag & ND_NFSV3);
1031: LIST_INIT(&nfsd->nd_coalesce);
1032: nfsd->nd_mreq = NULL;
1033: nfsd->nd_stable = NFSV3WRITE_FILESYNC;
1034: cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec;
1035: nfsd->nd_time = cur_usec +
1036: (v3 ? nfsrvw_procrastinate_v3 : nfsrvw_procrastinate);
1037:
1038: /*
1039: * Now, get the write header..
1040: */
1041: nfsm_srvmtofh(&nfsd->nd_fh);
1042: if (v3) {
1043: nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
1044: fxdr_hyper(tl, &nfsd->nd_off);
1045: tl += 3;
1046: nfsd->nd_stable = fxdr_unsigned(int, *tl++);
1047: } else {
1048: nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
1049: nfsd->nd_off = (off_t)fxdr_unsigned(u_long, *++tl);
1050: tl += 2;
1051: if (nfs_async)
1052: nfsd->nd_stable = NFSV3WRITE_UNSTABLE;
1053: }
1054: len = fxdr_unsigned(long, *tl);
1055: nfsd->nd_len = len;
1056: nfsd->nd_eoff = nfsd->nd_off + len;
1057:
1058: /*
1059: * Trim the header out of the mbuf list and trim off any trailing
1060: * junk so that the mbuf list has only the write data.
1061: */
1062: zeroing = 1;
1063: i = 0;
1064: mp = mrep;
1065: while (mp) {
1066: if (mp == md) {
1067: zeroing = 0;
1068: adjust = dpos - mtod(mp, caddr_t);
1069: mp->m_len -= adjust;
1070: if (mp->m_len > 0 && adjust > 0)
1071: NFSMADV(mp, adjust);
1072: }
1073: if (zeroing)
1074: mp->m_len = 0;
1075: else {
1076: i += mp->m_len;
1077: if (i > len) {
1078: mp->m_len -= (i - len);
1079: zeroing = 1;
1080: }
1081: }
1082: mp = mp->m_next;
1083: }
1084: if (len > NFS_MAXDATA || len < 0 || i < len) {
1085: nfsmout:
1086: m_freem(mrep);
1087: error = EIO;
1088: nfsm_writereply(2 * NFSX_UNSIGNED, v3);
1089: if (v3)
1090: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1091: nfsd->nd_mreq = mreq;
1092: nfsd->nd_mrep = NULL;
1093: nfsd->nd_time = 0;
1094: }
1095:
1096: /*
1097: * Add this entry to the hash and time queues.
1098: */
1099: s = splsoftclock();
1100: owp = NULL;
1101: wp = slp->ns_tq.lh_first;
1102: while (wp && wp->nd_time < nfsd->nd_time) {
1103: owp = wp;
1104: wp = wp->nd_tq.le_next;
1105: }
1106: NFS_DPF(WG, ("Q%03x", nfsd->nd_retxid & 0xfff));
1107: if (owp) {
1108: LIST_INSERT_AFTER(owp, nfsd, nd_tq);
1109: } else {
1110: LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
1111: }
1112: if (nfsd->nd_mrep) {
1113: wpp = NWDELAYHASH(slp, nfsd->nd_fh.fh_fid.fid_data);
1114: owp = NULL;
1115: wp = wpp->lh_first;
1116: while (wp &&
1117: bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) {
1118: owp = wp;
1119: wp = wp->nd_hash.le_next;
1120: }
1121: while (wp && wp->nd_off < nfsd->nd_off &&
1122: !bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) {
1123: owp = wp;
1124: wp = wp->nd_hash.le_next;
1125: }
1126: if (owp) {
1127: LIST_INSERT_AFTER(owp, nfsd, nd_hash);
1128:
1129: /*
1130: * Search the hash list for overlapping entries and
1131: * coalesce.
1132: */
1133: for(; nfsd && NFSW_CONTIG(owp, nfsd); nfsd = wp) {
1134: wp = nfsd->nd_hash.le_next;
1135: if (NFSW_SAMECRED(owp, nfsd))
1136: nfsrvw_coalesce(owp, nfsd);
1137: }
1138: } else {
1139: LIST_INSERT_HEAD(wpp, nfsd, nd_hash);
1140: }
1141: }
1142: splx(s);
1143: }
1144:
1145: /*
1146: * Now, do VOP_WRITE()s for any one(s) that need to be done now
1147: * and generate the associated reply mbuf list(s).
1148: */
1149: loop1:
1150: cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec;
1151: s = splsoftclock();
1152: for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = owp) {
1153: owp = nfsd->nd_tq.le_next;
1154: if (nfsd->nd_time > cur_usec)
1155: break;
1156: if (nfsd->nd_mreq)
1157: continue;
1158: NFS_DPF(WG, ("P%03x", nfsd->nd_retxid & 0xfff));
1159: LIST_REMOVE(nfsd, nd_tq);
1160: LIST_REMOVE(nfsd, nd_hash);
1161: splx(s);
1162: mrep = nfsd->nd_mrep;
1163: nfsd->nd_mrep = NULL;
1164: cred = &nfsd->nd_cr;
1165: v3 = (nfsd->nd_flag & ND_NFSV3);
1166: forat_ret = aftat_ret = 1;
1167: error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &vp, cred, slp,
1168: nfsd->nd_nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
1169: if (!error) {
1170: if (v3)
1171: forat_ret = VOP_GETATTR(vp, &forat, cred, procp);
1172: if (vp->v_type != VREG) {
1173: if (v3)
1174: error = EINVAL;
1175: else
1176: error = (vp->v_type == VDIR) ? EISDIR : EACCES;
1177: }
1178: } else
1179: vp = NULL;
1180: if (!error) {
1181: nqsrv_getl(vp, ND_WRITE);
1182: error = nfsrv_access(vp, VWRITE, cred, rdonly, procp);
1183: }
1184:
1185: if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE)
1186: ioflags = IO_NODELOCKED;
1187: else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC)
1188: ioflags = (IO_SYNC | IO_NODELOCKED);
1189: else
1190: ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
1191: uiop->uio_rw = UIO_WRITE;
1192: uiop->uio_segflg = UIO_SYSSPACE;
1193: uiop->uio_procp = (struct proc *)0;
1194: uiop->uio_offset = nfsd->nd_off;
1195: uiop->uio_resid = nfsd->nd_eoff - nfsd->nd_off;
1196: if (uiop->uio_resid > 0) {
1197: mp = mrep;
1198: i = 0;
1199: while (mp) {
1200: if (mp->m_len > 0)
1201: i++;
1202: mp = mp->m_next;
1203: }
1204: uiop->uio_iovcnt = i;
1205: MALLOC(iov, struct iovec *, i * sizeof (struct iovec),
1206: M_TEMP, M_WAITOK);
1207: uiop->uio_iov = ivp = iov;
1208: mp = mrep;
1209: while (mp) {
1210: if (mp->m_len > 0) {
1211: ivp->iov_base = mtod(mp, caddr_t);
1212: ivp->iov_len = mp->m_len;
1213: ivp++;
1214: }
1215: mp = mp->m_next;
1216: }
1217: if (!error) {
1218: #if MACH_NBC
1219: if (vp->v_type == VREG) {
1220: map_vnode(vp, procp);
1221: error = mapfs_io(vp, uiop, uiop->uio_rw,
1222: ioflags, cred);
1223: unmap_vnode(vp, procp);
1224: } else
1225: #endif /* MACH_NBC */
1226: error = VOP_WRITE(vp, uiop, ioflags, cred);
1227: nfsstats.srvvop_writes++;
1228: }
1229: FREE((caddr_t)iov, M_TEMP);
1230: }
1231: m_freem(mrep);
1232: if (vp) {
1233: aftat_ret = VOP_GETATTR(vp, &va, cred, procp);
1234: vput(vp);
1235: }
1236:
1237: /*
1238: * Loop around generating replies for all write rpcs that have
1239: * now been completed.
1240: */
1241: swp = nfsd;
1242: do {
1243: NFS_DPF(WG, ("R%03x", nfsd->nd_retxid & 0xfff));
1244: if (error) {
1245: nfsm_writereply(NFSX_WCCDATA(v3), v3);
1246: if (v3) {
1247: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1248: }
1249: } else {
1250: nfsm_writereply(NFSX_PREOPATTR(v3) +
1251: NFSX_POSTOPORFATTR(v3) + 2 * NFSX_UNSIGNED +
1252: NFSX_WRITEVERF(v3), v3);
1253: if (v3) {
1254: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1255: nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
1256: *tl++ = txdr_unsigned(nfsd->nd_len);
1257: *tl++ = txdr_unsigned(swp->nd_stable);
1258: /*
1259: * Actually, there is no need to txdr these fields,
1260: * but it may make the values more human readable,
1261: * for debugging purposes.
1262: */
1263: *tl++ = txdr_unsigned(boottime.tv_sec);
1264: *tl = txdr_unsigned(boottime.tv_usec);
1265: } else {
1266: nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
1267: nfsm_srvfillattr(&va, fp);
1268: }
1269: }
1270: nfsd->nd_mreq = mreq;
1271: if (nfsd->nd_mrep)
1272: panic("nfsrv_write: nd_mrep not free");
1273:
1274: /*
1275: * Done. Put it at the head of the timer queue so that
1276: * the final phase can return the reply.
1277: */
1278: s = splsoftclock();
1279: if (nfsd != swp) {
1280: nfsd->nd_time = 0;
1281: LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
1282: }
1283: nfsd = swp->nd_coalesce.lh_first;
1284: if (nfsd) {
1285: LIST_REMOVE(nfsd, nd_tq);
1286: }
1287: splx(s);
1288: } while (nfsd);
1289: s = splsoftclock();
1290: swp->nd_time = 0;
1291: LIST_INSERT_HEAD(&slp->ns_tq, swp, nd_tq);
1292: splx(s);
1293: goto loop1;
1294: }
1295: splx(s);
1296:
1297: /*
1298: * Search for a reply to return.
1299: */
1300: s = splsoftclock();
1301: for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = nfsd->nd_tq.le_next)
1302: if (nfsd->nd_mreq) {
1303: NFS_DPF(WG, ("X%03x", nfsd->nd_retxid & 0xfff));
1304: LIST_REMOVE(nfsd, nd_tq);
1305: *mrq = nfsd->nd_mreq;
1306: *ndp = nfsd;
1307: break;
1308: }
1309: splx(s);
1310: return (0);
1311: }
1312:
1313: /*
1314: * Coalesce the write request nfsd into owp. To do this we must:
1315: * - remove nfsd from the queues
1316: * - merge nfsd->nd_mrep into owp->nd_mrep
1317: * - update the nd_eoff and nd_stable for owp
1318: * - put nfsd on owp's nd_coalesce list
1319: * NB: Must be called at splsoftclock().
1320: */
1321: static void
1322: nfsrvw_coalesce(owp, nfsd)
1323: register struct nfsrv_descript *owp;
1324: register struct nfsrv_descript *nfsd;
1325: {
1326: register int overlap;
1327: register struct mbuf *mp;
1328: struct nfsrv_descript *p;
1329:
1330: NFS_DPF(WG, ("C%03x-%03x",
1331: nfsd->nd_retxid & 0xfff, owp->nd_retxid & 0xfff));
1332: LIST_REMOVE(nfsd, nd_hash);
1333: LIST_REMOVE(nfsd, nd_tq);
1334: if (owp->nd_eoff < nfsd->nd_eoff) {
1335: overlap = owp->nd_eoff - nfsd->nd_off;
1336: if (overlap < 0)
1337: panic("nfsrv_coalesce: bad off");
1338: if (overlap > 0)
1339: m_adj(nfsd->nd_mrep, overlap);
1340: mp = owp->nd_mrep;
1341: while (mp->m_next)
1342: mp = mp->m_next;
1343: mp->m_next = nfsd->nd_mrep;
1344: owp->nd_eoff = nfsd->nd_eoff;
1345: } else
1346: m_freem(nfsd->nd_mrep);
1347: nfsd->nd_mrep = NULL;
1348: if (nfsd->nd_stable == NFSV3WRITE_FILESYNC)
1349: owp->nd_stable = NFSV3WRITE_FILESYNC;
1350: else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC &&
1351: owp->nd_stable == NFSV3WRITE_UNSTABLE)
1352: owp->nd_stable = NFSV3WRITE_DATASYNC;
1353: LIST_INSERT_HEAD(&owp->nd_coalesce, nfsd, nd_tq);
1354:
1355: /*
1356: * If nfsd had anything else coalesced into it, transfer them
1357: * to owp, otherwise their replies will never get sent.
1358: */
1359: for (p = nfsd->nd_coalesce.lh_first; p;
1360: p = nfsd->nd_coalesce.lh_first) {
1361: LIST_REMOVE(p, nd_tq);
1362: LIST_INSERT_HEAD(&owp->nd_coalesce, p, nd_tq);
1363: }
1364: }
1365:
1366: /*
1367: * Sort the group list in increasing numerical order.
1368: * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1369: * that used to be here.)
1370: */
1371: void
1372: nfsrvw_sort(list, num)
1373: register gid_t *list;
1374: register int num;
1375: {
1376: register int i, j;
1377: gid_t v;
1378:
1379: /* Insertion sort. */
1380: for (i = 1; i < num; i++) {
1381: v = list[i];
1382: /* find correct slot for value v, moving others up */
1383: for (j = i; --j >= 0 && v < list[j];)
1384: list[j + 1] = list[j];
1385: list[j + 1] = v;
1386: }
1387: }
1388:
1389: /*
1390: * copy credentials making sure that the result can be compared with bcmp().
1391: */
1392: void
1393: nfsrv_setcred(incred, outcred)
1394: register struct ucred *incred, *outcred;
1395: {
1396: register int i;
1397:
1398: bzero((caddr_t)outcred, sizeof (struct ucred));
1399: outcred->cr_ref = 1;
1400: outcred->cr_uid = incred->cr_uid;
1401: outcred->cr_ngroups = incred->cr_ngroups;
1402: for (i = 0; i < incred->cr_ngroups; i++)
1403: outcred->cr_groups[i] = incred->cr_groups[i];
1404: nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
1405: }
1406:
1407: /*
1408: * nfs create service
1409: * now does a truncate to 0 length via. setattr if it already exists
1410: */
1411: int
1412: nfsrv_create(nfsd, slp, procp, mrq)
1413: struct nfsrv_descript *nfsd;
1414: struct nfssvc_sock *slp;
1415: struct proc *procp;
1416: struct mbuf **mrq;
1417: {
1418: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1419: struct mbuf *nam = nfsd->nd_nam;
1420: caddr_t dpos = nfsd->nd_dpos;
1421: struct ucred *cred = &nfsd->nd_cr;
1422: register struct nfs_fattr *fp;
1423: struct vattr va, dirfor, diraft;
1424: register struct vattr *vap = &va;
1425: register struct nfsv2_sattr *sp;
1426: register u_long *tl;
1427: struct nameidata nd;
1428: register caddr_t cp;
1429: register long t1;
1430: caddr_t bpos;
1431: int error = 0, rdev, cache, len, tsize, dirfor_ret = 1, diraft_ret = 1;
1432: int v3 = (nfsd->nd_flag & ND_NFSV3), how, exclusive_flag = 0;
1433: char *cp2;
1434: struct mbuf *mb, *mb2, *mreq;
1435: struct vnode *vp, *dirp = (struct vnode *)0;
1436: nfsfh_t nfh;
1437: fhandle_t *fhp;
1438: u_quad_t frev, tempsize;
1439: u_char cverf[NFSX_V3CREATEVERF];
1440:
1441: #ifndef nolint
1442: rdev = 0;
1443: #endif
1444: nd.ni_cnd.cn_nameiop = 0;
1445: fhp = &nfh.fh_generic;
1446: nfsm_srvmtofh(fhp);
1447: nfsm_srvnamesiz(len);
1448: nd.ni_cnd.cn_cred = cred;
1449: nd.ni_cnd.cn_nameiop = CREATE;
1450: nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART;
1451: error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1452: &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1453: if (dirp) {
1454: if (v3)
1455: dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
1456: procp);
1457: else {
1458: vrele(dirp);
1459: dirp = (struct vnode *)0;
1460: }
1461: }
1462: if (error) {
1463: nfsm_reply(NFSX_WCCDATA(v3));
1464: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1465: if (dirp)
1466: vrele(dirp);
1467: return (0);
1468: }
1469: VATTR_NULL(vap);
1470: if (v3) {
1471: nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
1472: how = fxdr_unsigned(int, *tl);
1473: switch (how) {
1474: case NFSV3CREATE_GUARDED:
1475: if (nd.ni_vp) {
1476: error = EEXIST;
1477: break;
1478: }
1479: case NFSV3CREATE_UNCHECKED:
1480: nfsm_srvsattr(vap);
1481: break;
1482: case NFSV3CREATE_EXCLUSIVE:
1483: nfsm_dissect(cp, caddr_t, NFSX_V3CREATEVERF);
1484: bcopy(cp, cverf, NFSX_V3CREATEVERF);
1485: exclusive_flag = 1;
1486: if (nd.ni_vp == NULL)
1487: vap->va_mode = 0;
1488: break;
1489: };
1490: vap->va_type = VREG;
1491: } else {
1492: nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1493: vap->va_type = IFTOVT(fxdr_unsigned(u_long, sp->sa_mode));
1494: if (vap->va_type == VNON)
1495: vap->va_type = VREG;
1496: vap->va_mode = nfstov_mode(sp->sa_mode);
1497: switch (vap->va_type) {
1498: case VREG:
1499: tsize = fxdr_unsigned(long, sp->sa_size);
1500: if (tsize != -1)
1501: vap->va_size = (u_quad_t)tsize;
1502: break;
1503: case VCHR:
1504: case VBLK:
1505: case VFIFO:
1506: rdev = fxdr_unsigned(long, sp->sa_size);
1507: break;
1508: };
1509: }
1510:
1511: /*
1512: * Iff doesn't exist, create it
1513: * otherwise just truncate to 0 length
1514: * should I set the mode too ??
1515: */
1516: if (nd.ni_vp == NULL) {
1517: if (vap->va_type == VREG || vap->va_type == VSOCK) {
1518: vrele(nd.ni_startdir);
1519: nqsrv_getl(nd.ni_dvp, ND_WRITE);
1520: error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
1521: if (!error) {
1522: nfsrv_object_create(nd.ni_vp);
1523: FREE_ZONE(nd.ni_cnd.cn_pnbuf,
1524: nd.ni_cnd.cn_pnlen, M_NAMEI);
1525: if (exclusive_flag) {
1526: exclusive_flag = 0;
1527: VATTR_NULL(vap);
1528: bcopy(cverf, (caddr_t)&vap->va_atime,
1529: NFSX_V3CREATEVERF);
1530: error = VOP_SETATTR(nd.ni_vp, vap, cred,
1531: procp);
1532: }
1533: }
1534: } else if (vap->va_type == VCHR || vap->va_type == VBLK ||
1535: vap->va_type == VFIFO) {
1536: if (vap->va_type == VCHR && rdev == 0xffffffff)
1537: vap->va_type = VFIFO;
1538: if (vap->va_type != VFIFO &&
1539: (error = suser(cred, (u_short *)0))) {
1540: vrele(nd.ni_startdir);
1541: _FREE_ZONE(nd.ni_cnd.cn_pnbuf,
1542: nd.ni_cnd.cn_pnlen, M_NAMEI);
1543: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1544: vput(nd.ni_dvp);
1545: nfsm_reply(0);
1546: return (error);
1547: } else
1548: vap->va_rdev = (dev_t)rdev;
1549: nqsrv_getl(nd.ni_dvp, ND_WRITE);
1550: if ((error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap))) {
1551: vrele(nd.ni_startdir);
1552: nfsm_reply(0);
1553: }
1554: nd.ni_cnd.cn_nameiop = LOOKUP;
1555: nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
1556: nd.ni_cnd.cn_proc = procp;
1557: nd.ni_cnd.cn_cred = cred;
1558: if ((error = lookup(&nd))) {
1559: _FREE_ZONE(nd.ni_cnd.cn_pnbuf,
1560: nd.ni_cnd.cn_pnlen, M_NAMEI);
1561: nfsm_reply(0);
1562: }
1563: nfsrv_object_create(nd.ni_vp);
1564: FREE_ZONE(nd.ni_cnd.cn_pnbuf,
1565: nd.ni_cnd.cn_pnlen, M_NAMEI);
1566: if (nd.ni_cnd.cn_flags & ISSYMLINK) {
1567: vrele(nd.ni_dvp);
1568: vput(nd.ni_vp);
1569: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1570: error = EINVAL;
1571: nfsm_reply(0);
1572: }
1573: } else {
1574: vrele(nd.ni_startdir);
1575: _FREE_ZONE(nd.ni_cnd.cn_pnbuf,
1576: nd.ni_cnd.cn_pnlen, M_NAMEI);
1577: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1578: vput(nd.ni_dvp);
1579: error = ENXIO;
1580: }
1581: vp = nd.ni_vp;
1582: } else {
1583: vrele(nd.ni_startdir);
1584: _FREE_ZONE(nd.ni_cnd.cn_pnbuf, nd.ni_cnd.cn_pnlen, M_NAMEI);
1585: vp = nd.ni_vp;
1586: if (nd.ni_dvp == vp)
1587: vrele(nd.ni_dvp);
1588: else
1589: vput(nd.ni_dvp);
1590: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1591: if (vap->va_size != -1) {
1592: error = nfsrv_access(vp, VWRITE, cred,
1593: (nd.ni_cnd.cn_flags & RDONLY), procp);
1594: if (!error) {
1595: nqsrv_getl(vp, ND_WRITE);
1596: tempsize = vap->va_size;
1597: VATTR_NULL(vap);
1598: vap->va_size = tempsize;
1599: error = VOP_SETATTR(vp, vap, cred,
1600: procp);
1601: }
1602: if (error)
1603: vput(vp);
1604: } else {
1605: if (error)
1606: vput(vp); /* make sure we catch the EEXIST for nfsv3 */
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 (error);
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.