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