|
|
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.