138418Smckusick /* 238418Smckusick * Copyright (c) 1989 The Regents of the University of California. 338418Smckusick * All rights reserved. 438418Smckusick * 538418Smckusick * This code is derived from software contributed to Berkeley by 638418Smckusick * Rick Macklem at The University of Guelph. 738418Smckusick * 844510Sbostic * %sccs.include.redist.c% 938418Smckusick * 10*56285Smckusick * @(#)nfs_serv.c 7.59 (Berkeley) 09/16/92 1138418Smckusick */ 1238418Smckusick 1338418Smckusick /* 1438418Smckusick * nfs version 2 server calls to vnode ops 1538418Smckusick * - these routines generally have 3 phases 1638418Smckusick * 1 - break down and validate rpc request in mbuf list 1738418Smckusick * 2 - do the vnode ops for the request 1838425Smckusick * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c) 1938418Smckusick * 3 - build the rpc reply in an mbuf list 2038418Smckusick * nb: 2138418Smckusick * - do not mix the phases, since the nfsm_?? macros can return failures 2241899Smckusick * on a bad rpc or similar and do not do any vrele() or vput()'s 2338418Smckusick * 2438425Smckusick * - the nfsm_reply() macro generates an nfs rpc reply with the nfs 2538418Smckusick * error number iff error != 0 whereas 2641899Smckusick * returning an error from the server function implies a fatal error 2741899Smckusick * such as a badly constructed rpc request that should be dropped without 2841899Smckusick * a reply. 2938418Smckusick */ 3038418Smckusick 3153322Smckusick #include <sys/param.h> 3255073Spendry #include <sys/systm.h> 3353322Smckusick #include <sys/proc.h> 3453322Smckusick #include <sys/file.h> 3553322Smckusick #include <sys/namei.h> 3653322Smckusick #include <sys/vnode.h> 3753322Smckusick #include <sys/mount.h> 3853322Smckusick #include <sys/mbuf.h> 3953322Smckusick #include <sys/dirent.h> 4054446Smckusick #include <sys/stat.h> 4147573Skarels 4253322Smckusick #include <vm/vm.h> 4347573Skarels 4453322Smckusick #include <nfs/nfsv2.h> 4553322Smckusick #include <nfs/rpcv2.h> 4653322Smckusick #include <nfs/nfs.h> 4753322Smckusick #include <nfs/xdr_subs.h> 4853322Smckusick #include <nfs/nfsm_subs.h> 4953322Smckusick #include <nfs/nqnfs.h> 5053322Smckusick 5138418Smckusick /* Defs */ 5238425Smckusick #define TRUE 1 5338425Smckusick #define FALSE 0 5438418Smckusick 5538418Smckusick /* Global vars */ 5638418Smckusick extern u_long nfs_procids[NFS_NPROCS]; 5738418Smckusick extern u_long nfs_xdrneg1; 5838418Smckusick extern u_long nfs_false, nfs_true; 5952196Smckusick nfstype nfs_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, 6042242Smckusick NFCHR, NFNON }; 6138418Smckusick 6238418Smckusick /* 6338418Smckusick * nfs getattr service 6438418Smckusick */ 6552196Smckusick nfsrv_getattr(nfsd, mrep, md, dpos, cred, nam, mrq) 6652196Smckusick struct nfsd *nfsd; 6738418Smckusick struct mbuf *mrep, *md; 6838418Smckusick caddr_t dpos; 6938418Smckusick struct ucred *cred; 7052196Smckusick struct mbuf *nam, **mrq; 7138418Smckusick { 7238884Smacklem register struct nfsv2_fattr *fp; 7338418Smckusick struct vattr va; 7438418Smckusick register struct vattr *vap = &va; 7538418Smckusick struct vnode *vp; 7638418Smckusick nfsv2fh_t nfh; 7738418Smckusick fhandle_t *fhp; 7848050Smckusick register u_long *tl; 7939494Smckusick register long t1; 8039494Smckusick caddr_t bpos; 8152196Smckusick int error = 0, rdonly, cache; 8239494Smckusick char *cp2; 8339753Smckusick struct mbuf *mb, *mb2, *mreq; 8452196Smckusick u_quad_t frev; 8538418Smckusick 8638418Smckusick fhp = &nfh.fh_generic; 8738418Smckusick nfsm_srvmtofh(fhp); 8852196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 8938418Smckusick nfsm_reply(0); 9052196Smckusick nqsrv_getl(vp, NQL_READ); 9152196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 9238418Smckusick vput(vp); 93*56285Smckusick nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 94*56285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 9539753Smckusick nfsm_srvfillattr; 9638418Smckusick nfsm_srvdone; 9738418Smckusick } 9838418Smckusick 9938418Smckusick /* 10038418Smckusick * nfs setattr service 10138418Smckusick */ 10252196Smckusick nfsrv_setattr(nfsd, mrep, md, dpos, cred, nam, mrq) 10352196Smckusick struct nfsd *nfsd; 10438418Smckusick struct mbuf *mrep, *md; 10538418Smckusick caddr_t dpos; 10638418Smckusick struct ucred *cred; 10752196Smckusick struct mbuf *nam, **mrq; 10838418Smckusick { 10938418Smckusick struct vattr va; 11038418Smckusick register struct vattr *vap = &va; 11138884Smacklem register struct nfsv2_sattr *sp; 11238884Smacklem register struct nfsv2_fattr *fp; 11338418Smckusick struct vnode *vp; 11438418Smckusick nfsv2fh_t nfh; 11538418Smckusick fhandle_t *fhp; 11648050Smckusick register u_long *tl; 11739494Smckusick register long t1; 11839494Smckusick caddr_t bpos; 11952196Smckusick int error = 0, rdonly, cache, duration2, cache2; 12039494Smckusick char *cp2; 12139753Smckusick struct mbuf *mb, *mb2, *mreq; 12252196Smckusick u_quad_t frev, frev2; 12338418Smckusick 12438418Smckusick fhp = &nfh.fh_generic; 12538418Smckusick nfsm_srvmtofh(fhp); 126*56285Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 12752196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 12838418Smckusick nfsm_reply(0); 12952196Smckusick nqsrv_getl(vp, NQL_WRITE); 13052196Smckusick if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) 13138418Smckusick goto out; 13241361Smckusick VATTR_NULL(vap); 13338418Smckusick /* 13438418Smckusick * Nah nah nah nah na nah 13538418Smckusick * There is a bug in the Sun client that puts 0xffff in the mode 13638418Smckusick * field of sattr when it should put in 0xffffffff. The u_short 13738418Smckusick * doesn't sign extend. 13838418Smckusick * --> check the low order 2 bytes for 0xffff 13938418Smckusick */ 14038884Smacklem if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff) 14138884Smacklem vap->va_mode = nfstov_mode(sp->sa_mode); 14238884Smacklem if (sp->sa_uid != nfs_xdrneg1) 14338884Smacklem vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid); 14438884Smacklem if (sp->sa_gid != nfs_xdrneg1) 14538884Smacklem vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid); 146*56285Smckusick if (nfsd->nd_nqlflag == NQL_NOVAL) { 147*56285Smckusick if (sp->sa_nfssize != nfs_xdrneg1) 148*56285Smckusick vap->va_size = fxdr_unsigned(u_quad_t, sp->sa_nfssize); 149*56285Smckusick /* 150*56285Smckusick * The usec field of sa_atime is overloaded with the va_flags field 151*56285Smckusick * for 4.4BSD clients. Hopefully other clients always set both the 152*56285Smckusick * sec and usec fields to -1 when not setting the atime. 153*56285Smckusick */ 154*56285Smckusick if (sp->sa_nfsatime.nfs_sec != nfs_xdrneg1) { 155*56285Smckusick vap->va_atime.ts_sec = fxdr_unsigned(long, sp->sa_nfsatime.nfs_sec); 156*56285Smckusick vap->va_atime.ts_nsec = 0; 157*56285Smckusick } 158*56285Smckusick if (sp->sa_nfsatime.nfs_usec != nfs_xdrneg1) 159*56285Smckusick vap->va_flags = fxdr_unsigned(u_long, sp->sa_nfsatime.nfs_usec); 160*56285Smckusick if (sp->sa_nfsmtime.nfs_sec != nfs_xdrneg1) 161*56285Smckusick fxdr_nfstime(&sp->sa_nfsmtime, &vap->va_mtime); 162*56285Smckusick } else { 163*56285Smckusick fxdr_hyper(&sp->sa_nqsize, &vap->va_size); 164*56285Smckusick fxdr_nqtime(&sp->sa_nqatime, &vap->va_atime); 165*56285Smckusick fxdr_nqtime(&sp->sa_nqmtime, &vap->va_mtime); 166*56285Smckusick vap->va_flags = fxdr_unsigned(u_long, sp->sa_nqflags); 16738425Smckusick } 16852196Smckusick if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) { 16938418Smckusick vput(vp); 17038418Smckusick nfsm_reply(0); 17138418Smckusick } 17252196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 17338418Smckusick out: 17438418Smckusick vput(vp); 175*56285Smckusick nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL) + 2*NFSX_UNSIGNED); 176*56285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 17739753Smckusick nfsm_srvfillattr; 17852196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 17952196Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 18052196Smckusick txdr_hyper(&frev2, tl); 18152196Smckusick } 18238418Smckusick nfsm_srvdone; 18338418Smckusick } 18438418Smckusick 18538418Smckusick /* 18638418Smckusick * nfs lookup rpc 18738418Smckusick */ 18852196Smckusick nfsrv_lookup(nfsd, mrep, md, dpos, cred, nam, mrq) 18952196Smckusick struct nfsd *nfsd; 19038418Smckusick struct mbuf *mrep, *md; 19138418Smckusick caddr_t dpos; 19238418Smckusick struct ucred *cred; 19352196Smckusick struct mbuf *nam, **mrq; 19438418Smckusick { 19538884Smacklem register struct nfsv2_fattr *fp; 19649742Smckusick struct nameidata nd; 19738418Smckusick struct vnode *vp; 19838418Smckusick nfsv2fh_t nfh; 19938418Smckusick fhandle_t *fhp; 20039494Smckusick register caddr_t cp; 20148050Smckusick register u_long *tl; 20239494Smckusick register long t1; 20339494Smckusick caddr_t bpos; 204*56285Smckusick int error = 0, rdonly, cache, duration2, cache2, len; 20539494Smckusick char *cp2; 20639753Smckusick struct mbuf *mb, *mb2, *mreq; 20738418Smckusick struct vattr va, *vap = &va; 20852196Smckusick u_quad_t frev, frev2; 20938418Smckusick 21038418Smckusick fhp = &nfh.fh_generic; 21152196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 21252196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 213*56285Smckusick duration2 = fxdr_unsigned(int, *tl); 21452196Smckusick } 21538418Smckusick nfsm_srvmtofh(fhp); 21638418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 21752316Sheideman nd.ni_cnd.cn_cred = cred; 21852316Sheideman nd.ni_cnd.cn_nameiop = LOOKUP; 21952316Sheideman nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART; 22052653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 22152653Smckusick nfsd->nd_procp)) 22238418Smckusick nfsm_reply(0); 22352196Smckusick nqsrv_getl(nd.ni_startdir, NQL_READ); 22452196Smckusick vrele(nd.ni_startdir); 22552653Smckusick FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 22649742Smckusick vp = nd.ni_vp; 22738418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 22841398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 22938418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 23038418Smckusick vput(vp); 23138418Smckusick nfsm_reply(0); 23238418Smckusick } 233*56285Smckusick if (duration2) 234*56285Smckusick (void) nqsrv_getlease(vp, &duration2, NQL_READ, nfsd, 23552196Smckusick nam, &cache2, &frev2, cred); 23652196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 23738418Smckusick vput(vp); 238*56285Smckusick nfsm_reply(NFSX_FH + NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL) + 5*NFSX_UNSIGNED); 23952196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 240*56285Smckusick if (duration2) { 24152196Smckusick nfsm_build(tl, u_long *, 5*NFSX_UNSIGNED); 242*56285Smckusick *tl++ = txdr_unsigned(NQL_READ); 24352196Smckusick *tl++ = txdr_unsigned(cache2); 24452196Smckusick *tl++ = txdr_unsigned(duration2); 24552196Smckusick txdr_hyper(&frev2, tl); 24652196Smckusick } else { 24752196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 24852196Smckusick *tl = 0; 24952196Smckusick } 25052196Smckusick } 25138418Smckusick nfsm_srvfhtom(fhp); 252*56285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 25339753Smckusick nfsm_srvfillattr; 25438418Smckusick nfsm_srvdone; 25538418Smckusick } 25638418Smckusick 25738418Smckusick /* 25838418Smckusick * nfs readlink service 25938418Smckusick */ 26052196Smckusick nfsrv_readlink(nfsd, mrep, md, dpos, cred, nam, mrq) 26152196Smckusick struct nfsd *nfsd; 26238418Smckusick struct mbuf *mrep, *md; 26338418Smckusick caddr_t dpos; 26438418Smckusick struct ucred *cred; 26552196Smckusick struct mbuf *nam, **mrq; 26638418Smckusick { 26741899Smckusick struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN]; 26838418Smckusick register struct iovec *ivp = iv; 26938418Smckusick register struct mbuf *mp; 27048050Smckusick register u_long *tl; 27139494Smckusick register long t1; 27239494Smckusick caddr_t bpos; 27352196Smckusick int error = 0, rdonly, cache, i, tlen, len; 27439494Smckusick char *cp2; 27539753Smckusick struct mbuf *mb, *mb2, *mp2, *mp3, *mreq; 27638418Smckusick struct vnode *vp; 27738418Smckusick nfsv2fh_t nfh; 27838418Smckusick fhandle_t *fhp; 27938418Smckusick struct uio io, *uiop = &io; 28052196Smckusick u_quad_t frev; 28138418Smckusick 28238418Smckusick fhp = &nfh.fh_generic; 28338418Smckusick nfsm_srvmtofh(fhp); 28438418Smckusick len = 0; 28538418Smckusick i = 0; 28638418Smckusick while (len < NFS_MAXPATHLEN) { 28738418Smckusick MGET(mp, M_WAIT, MT_DATA); 28841899Smckusick MCLGET(mp, M_WAIT); 28938418Smckusick mp->m_len = NFSMSIZ(mp); 29038418Smckusick if (len == 0) 29138418Smckusick mp3 = mp2 = mp; 29241899Smckusick else { 29338418Smckusick mp2->m_next = mp; 29441899Smckusick mp2 = mp; 29541899Smckusick } 29638418Smckusick if ((len+mp->m_len) > NFS_MAXPATHLEN) { 29738418Smckusick mp->m_len = NFS_MAXPATHLEN-len; 29838418Smckusick len = NFS_MAXPATHLEN; 29938418Smckusick } else 30038418Smckusick len += mp->m_len; 30138418Smckusick ivp->iov_base = mtod(mp, caddr_t); 30238418Smckusick ivp->iov_len = mp->m_len; 30338418Smckusick i++; 30438418Smckusick ivp++; 30538418Smckusick } 30638418Smckusick uiop->uio_iov = iv; 30738418Smckusick uiop->uio_iovcnt = i; 30838418Smckusick uiop->uio_offset = 0; 30938418Smckusick uiop->uio_resid = len; 31038418Smckusick uiop->uio_rw = UIO_READ; 31138418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 31248050Smckusick uiop->uio_procp = (struct proc *)0; 31352196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) { 31438418Smckusick m_freem(mp3); 31538418Smckusick nfsm_reply(0); 31638418Smckusick } 31738418Smckusick if (vp->v_type != VLNK) { 31838418Smckusick error = EINVAL; 31938418Smckusick goto out; 32038418Smckusick } 32152196Smckusick nqsrv_getl(vp, NQL_READ); 32238418Smckusick error = VOP_READLINK(vp, uiop, cred); 32338418Smckusick out: 32438418Smckusick vput(vp); 32538418Smckusick if (error) 32638418Smckusick m_freem(mp3); 32738418Smckusick nfsm_reply(NFSX_UNSIGNED); 32838418Smckusick if (uiop->uio_resid > 0) { 32938418Smckusick len -= uiop->uio_resid; 33038418Smckusick tlen = nfsm_rndup(len); 33138418Smckusick nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len); 33238418Smckusick } 33348050Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 33448050Smckusick *tl = txdr_unsigned(len); 33538418Smckusick mb->m_next = mp3; 33638418Smckusick nfsm_srvdone; 33738418Smckusick } 33838418Smckusick 33938418Smckusick /* 34038418Smckusick * nfs read service 34138418Smckusick */ 34252196Smckusick nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq) 34352196Smckusick struct nfsd *nfsd; 34438418Smckusick struct mbuf *mrep, *md; 34538418Smckusick caddr_t dpos; 34638418Smckusick struct ucred *cred; 34752196Smckusick struct mbuf *nam, **mrq; 34838418Smckusick { 34943350Smckusick register struct iovec *iv; 35043350Smckusick struct iovec *iv2; 35141899Smckusick register struct mbuf *m; 35238884Smacklem register struct nfsv2_fattr *fp; 35348050Smckusick register u_long *tl; 35439494Smckusick register long t1; 35539494Smckusick caddr_t bpos; 35652196Smckusick int error = 0, rdonly, cache, i, cnt, len, left, siz, tlen; 35739494Smckusick char *cp2; 35839753Smckusick struct mbuf *mb, *mb2, *mreq; 35952196Smckusick struct mbuf *m2; 36038418Smckusick struct vnode *vp; 36138418Smckusick nfsv2fh_t nfh; 36238418Smckusick fhandle_t *fhp; 36338418Smckusick struct uio io, *uiop = &io; 36438418Smckusick struct vattr va, *vap = &va; 36538418Smckusick off_t off; 36652196Smckusick u_quad_t frev; 36738418Smckusick 36838418Smckusick fhp = &nfh.fh_generic; 36938418Smckusick nfsm_srvmtofh(fhp); 370*56285Smckusick if (nfsd->nd_nqlflag == NQL_NOVAL) { 371*56285Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 372*56285Smckusick off = (off_t)fxdr_unsigned(u_long, *tl); 373*56285Smckusick } else { 374*56285Smckusick nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); 375*56285Smckusick fxdr_hyper(tl, &off); 376*56285Smckusick } 37738418Smckusick nfsm_srvstrsiz(cnt, NFS_MAXDATA); 37852196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 37938418Smckusick nfsm_reply(0); 38052196Smckusick nqsrv_getl(vp, NQL_READ); 38152196Smckusick if (error = nfsrv_access(vp, VREAD | VEXEC, cred, rdonly, nfsd->nd_procp)) { 38238418Smckusick vput(vp); 38338418Smckusick nfsm_reply(0); 38438418Smckusick } 38552196Smckusick if (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp)) { 38638418Smckusick vput(vp); 38738418Smckusick nfsm_reply(0); 38838418Smckusick } 38952196Smckusick if (off >= vap->va_size) 39052196Smckusick cnt = 0; 39152196Smckusick else if ((off + cnt) > vap->va_size) 39252196Smckusick cnt = nfsm_rndup(vap->va_size - off); 393*56285Smckusick nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)+NFSX_UNSIGNED+nfsm_rndup(cnt)); 394*56285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 39552196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 39652196Smckusick len = left = cnt; 39752196Smckusick if (cnt > 0) { 39852196Smckusick /* 39952196Smckusick * Generate the mbuf list with the uio_iov ref. to it. 40052196Smckusick */ 40152196Smckusick i = 0; 40252196Smckusick m = m2 = mb; 40352196Smckusick MALLOC(iv, struct iovec *, 40452196Smckusick ((NFS_MAXDATA+MLEN-1)/MLEN) * sizeof (struct iovec), 40552196Smckusick M_TEMP, M_WAITOK); 40652196Smckusick iv2 = iv; 40752196Smckusick while (left > 0) { 40855057Spendry siz = min(M_TRAILINGSPACE(m), left); 40952196Smckusick if (siz > 0) { 41052196Smckusick m->m_len += siz; 41152196Smckusick iv->iov_base = bpos; 41252196Smckusick iv->iov_len = siz; 41352196Smckusick iv++; 41452196Smckusick i++; 41552196Smckusick left -= siz; 41652196Smckusick } 41752196Smckusick if (left > 0) { 41852196Smckusick MGET(m, M_WAIT, MT_DATA); 41952196Smckusick MCLGET(m, M_WAIT); 42052196Smckusick m->m_len = 0; 42152196Smckusick m2->m_next = m; 42252196Smckusick m2 = m; 42352196Smckusick bpos = mtod(m, caddr_t); 42452196Smckusick } 42552196Smckusick } 42652196Smckusick uiop->uio_iov = iv2; 42752196Smckusick uiop->uio_iovcnt = i; 42852196Smckusick uiop->uio_offset = off; 42952196Smckusick uiop->uio_resid = cnt; 43052196Smckusick uiop->uio_rw = UIO_READ; 43152196Smckusick uiop->uio_segflg = UIO_SYSSPACE; 43252196Smckusick error = VOP_READ(vp, uiop, IO_NODELOCKED, cred); 43352196Smckusick off = uiop->uio_offset; 43452196Smckusick FREE((caddr_t)iv2, M_TEMP); 43552196Smckusick if (error || (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp))) { 43652196Smckusick m_freem(mreq); 43752196Smckusick vput(vp); 43852196Smckusick nfsm_reply(0); 43952196Smckusick } 44052196Smckusick } else 44152196Smckusick uiop->uio_resid = 0; 44238418Smckusick vput(vp); 44339753Smckusick nfsm_srvfillattr; 44445877Smckusick len -= uiop->uio_resid; 44552196Smckusick tlen = nfsm_rndup(len); 44652196Smckusick if (cnt != tlen || tlen != len) 44752196Smckusick nfsm_adj(mb, cnt-tlen, tlen-len); 44848050Smckusick *tl = txdr_unsigned(len); 44938418Smckusick nfsm_srvdone; 45038418Smckusick } 45138418Smckusick 45238418Smckusick /* 45338418Smckusick * nfs write service 45438418Smckusick */ 45552196Smckusick nfsrv_write(nfsd, mrep, md, dpos, cred, nam, mrq) 45652196Smckusick struct nfsd *nfsd; 45752196Smckusick struct mbuf *mrep, *md; 45838418Smckusick caddr_t dpos; 45938418Smckusick struct ucred *cred; 46052196Smckusick struct mbuf *nam, **mrq; 46138418Smckusick { 46238418Smckusick register struct iovec *ivp; 46338418Smckusick register struct mbuf *mp; 46438884Smacklem register struct nfsv2_fattr *fp; 46541899Smckusick struct iovec iv[NFS_MAXIOVEC]; 46638418Smckusick struct vattr va; 46738418Smckusick register struct vattr *vap = &va; 46848050Smckusick register u_long *tl; 46939494Smckusick register long t1; 47039494Smckusick caddr_t bpos; 47152196Smckusick int error = 0, rdonly, cache, siz, len, xfer; 472*56285Smckusick int ioflags = IO_SYNC | IO_NODELOCKED; 47339494Smckusick char *cp2; 47439753Smckusick struct mbuf *mb, *mb2, *mreq; 47538418Smckusick struct vnode *vp; 47638418Smckusick nfsv2fh_t nfh; 47738418Smckusick fhandle_t *fhp; 47838418Smckusick struct uio io, *uiop = &io; 47938418Smckusick off_t off; 48052196Smckusick u_quad_t frev; 48138418Smckusick 48238418Smckusick fhp = &nfh.fh_generic; 48338418Smckusick nfsm_srvmtofh(fhp); 484*56285Smckusick nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED); 485*56285Smckusick if (nfsd->nd_nqlflag == NQL_NOVAL) { 486*56285Smckusick off = (off_t)fxdr_unsigned(u_long, *++tl); 487*56285Smckusick tl += 2; 488*56285Smckusick } else { 489*56285Smckusick fxdr_hyper(tl, &off); 490*56285Smckusick tl += 2; 491*56285Smckusick if (fxdr_unsigned(u_long, *tl++)) 492*56285Smckusick ioflags |= IO_APPEND; 493*56285Smckusick } 49448050Smckusick len = fxdr_unsigned(long, *tl); 49538418Smckusick if (len > NFS_MAXDATA || len <= 0) { 49638418Smckusick error = EBADRPC; 49738418Smckusick nfsm_reply(0); 49838418Smckusick } 49938418Smckusick if (dpos == (mtod(md, caddr_t)+md->m_len)) { 50038418Smckusick mp = md->m_next; 50138418Smckusick if (mp == NULL) { 50238418Smckusick error = EBADRPC; 50338418Smckusick nfsm_reply(0); 50438418Smckusick } 50538418Smckusick } else { 50638418Smckusick mp = md; 50738418Smckusick siz = dpos-mtod(mp, caddr_t); 50838418Smckusick mp->m_len -= siz; 50938418Smckusick NFSMADV(mp, siz); 51038418Smckusick } 51152196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 51238418Smckusick nfsm_reply(0); 51352196Smckusick nqsrv_getl(vp, NQL_WRITE); 51452196Smckusick if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) { 51538418Smckusick vput(vp); 51638418Smckusick nfsm_reply(0); 51738418Smckusick } 51838418Smckusick uiop->uio_resid = 0; 51938418Smckusick uiop->uio_rw = UIO_WRITE; 52038418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 52148050Smckusick uiop->uio_procp = (struct proc *)0; 52238418Smckusick /* 52341899Smckusick * Do up to NFS_MAXIOVEC mbufs of write each iteration of the 52438418Smckusick * loop until done. 52538418Smckusick */ 52638418Smckusick while (len > 0 && uiop->uio_resid == 0) { 52738418Smckusick ivp = iv; 52838418Smckusick siz = 0; 52938418Smckusick uiop->uio_iov = ivp; 53038418Smckusick uiop->uio_iovcnt = 0; 53138418Smckusick uiop->uio_offset = off; 53241899Smckusick while (len > 0 && uiop->uio_iovcnt < NFS_MAXIOVEC && mp != NULL) { 53338418Smckusick ivp->iov_base = mtod(mp, caddr_t); 53438418Smckusick if (len < mp->m_len) 53538418Smckusick ivp->iov_len = xfer = len; 53638418Smckusick else 53738418Smckusick ivp->iov_len = xfer = mp->m_len; 53838418Smckusick #ifdef notdef 53938418Smckusick /* Not Yet .. */ 54038418Smckusick if (M_HASCL(mp) && (((u_long)ivp->iov_base) & CLOFSET) == 0) 54138418Smckusick ivp->iov_op = NULL; /* what should it be ?? */ 54238418Smckusick else 54338418Smckusick ivp->iov_op = NULL; 54438418Smckusick #endif 54538418Smckusick uiop->uio_iovcnt++; 54638418Smckusick ivp++; 54738418Smckusick len -= xfer; 54838418Smckusick siz += xfer; 54938418Smckusick mp = mp->m_next; 55038418Smckusick } 55138418Smckusick if (len > 0 && mp == NULL) { 55238418Smckusick error = EBADRPC; 55338418Smckusick vput(vp); 55438418Smckusick nfsm_reply(0); 55538418Smckusick } 55638418Smckusick uiop->uio_resid = siz; 557*56285Smckusick if (error = VOP_WRITE(vp, uiop, ioflags, cred)) { 55838418Smckusick vput(vp); 55938418Smckusick nfsm_reply(0); 56038418Smckusick } 56139586Smckusick off = uiop->uio_offset; 56238418Smckusick } 56352196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 56438418Smckusick vput(vp); 565*56285Smckusick nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 566*56285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 56739753Smckusick nfsm_srvfillattr; 56852442Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 56952442Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 57052442Smckusick txdr_hyper(&vap->va_filerev, tl); 57152442Smckusick } 57238418Smckusick nfsm_srvdone; 57338418Smckusick } 57438418Smckusick 57538418Smckusick /* 57638418Smckusick * nfs create service 57738418Smckusick * now does a truncate to 0 length via. setattr if it already exists 57838418Smckusick */ 57952196Smckusick nfsrv_create(nfsd, mrep, md, dpos, cred, nam, mrq) 58052196Smckusick struct nfsd *nfsd; 58152196Smckusick struct mbuf *mrep, *md; 58238418Smckusick caddr_t dpos; 58338418Smckusick struct ucred *cred; 58452196Smckusick struct mbuf *nam, **mrq; 58538418Smckusick { 58638884Smacklem register struct nfsv2_fattr *fp; 58738418Smckusick struct vattr va; 58838418Smckusick register struct vattr *vap = &va; 589*56285Smckusick register struct nfsv2_sattr *sp; 590*56285Smckusick register u_long *tl; 59149742Smckusick struct nameidata nd; 59239494Smckusick register caddr_t cp; 59339494Smckusick register long t1; 59439494Smckusick caddr_t bpos; 595*56285Smckusick int error = 0, rdev, cache, len, tsize; 59639494Smckusick char *cp2; 59739753Smckusick struct mbuf *mb, *mb2, *mreq; 59838418Smckusick struct vnode *vp; 59938418Smckusick nfsv2fh_t nfh; 60038418Smckusick fhandle_t *fhp; 60152196Smckusick u_quad_t frev; 60238418Smckusick 60352316Sheideman nd.ni_cnd.cn_nameiop = 0; 60438418Smckusick fhp = &nfh.fh_generic; 60538418Smckusick nfsm_srvmtofh(fhp); 60638418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 60752316Sheideman nd.ni_cnd.cn_cred = cred; 60852316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 60952316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART; 61052653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 61152653Smckusick nfsd->nd_procp)) 61238418Smckusick nfsm_reply(0); 61341361Smckusick VATTR_NULL(vap); 614*56285Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 61538418Smckusick /* 61638418Smckusick * Iff doesn't exist, create it 61738418Smckusick * otherwise just truncate to 0 length 61838418Smckusick * should I set the mode too ?? 61938418Smckusick */ 62049742Smckusick if (nd.ni_vp == NULL) { 621*56285Smckusick vap->va_type = IFTOVT(fxdr_unsigned(u_long, sp->sa_mode)); 62242867Smckusick if (vap->va_type == VNON) 62342867Smckusick vap->va_type = VREG; 624*56285Smckusick vap->va_mode = nfstov_mode(sp->sa_mode); 625*56285Smckusick if (nfsd->nd_nqlflag == NQL_NOVAL) 626*56285Smckusick rdev = fxdr_unsigned(long, sp->sa_nfssize); 627*56285Smckusick else 628*56285Smckusick rdev = fxdr_unsigned(long, sp->sa_nqrdev); 62946988Smckusick if (vap->va_type == VREG || vap->va_type == VSOCK) { 63049742Smckusick vrele(nd.ni_startdir); 63152196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 63252234Sheideman if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) 63342242Smckusick nfsm_reply(0); 63452316Sheideman FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 63542242Smckusick } else if (vap->va_type == VCHR || vap->va_type == VBLK || 63642242Smckusick vap->va_type == VFIFO) { 63742242Smckusick if (vap->va_type == VCHR && rdev == 0xffffffff) 63842242Smckusick vap->va_type = VFIFO; 63942242Smckusick if (vap->va_type == VFIFO) { 64042242Smckusick #ifndef FIFO 64152234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 64249742Smckusick vput(nd.ni_dvp); 64342242Smckusick error = ENXIO; 64449742Smckusick goto out; 64542242Smckusick #endif /* FIFO */ 64652196Smckusick } else if (error = suser(cred, (u_short *)0)) { 64752234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 64849742Smckusick vput(nd.ni_dvp); 64949742Smckusick goto out; 65042242Smckusick } else 65142242Smckusick vap->va_rdev = (dev_t)rdev; 65252196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 65352234Sheideman if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) { 65449742Smckusick vrele(nd.ni_startdir); 65542242Smckusick nfsm_reply(0); 65649742Smckusick } 65752316Sheideman nd.ni_cnd.cn_nameiop = LOOKUP; 65852316Sheideman nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART); 65952316Sheideman nd.ni_cnd.cn_proc = nfsd->nd_procp; 66052316Sheideman nd.ni_cnd.cn_cred = nfsd->nd_procp->p_ucred; 66152316Sheideman if (error = lookup(&nd)) { 66252316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 66342242Smckusick nfsm_reply(0); 66449742Smckusick } 66552316Sheideman FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 66652316Sheideman if (nd.ni_cnd.cn_flags & ISSYMLINK) { 66749742Smckusick vrele(nd.ni_dvp); 66849742Smckusick vput(nd.ni_vp); 66952234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 67049742Smckusick error = EINVAL; 67149742Smckusick nfsm_reply(0); 67249742Smckusick } 67342242Smckusick } else { 67452234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 67549742Smckusick vput(nd.ni_dvp); 67642242Smckusick error = ENXIO; 67749742Smckusick goto out; 67842242Smckusick } 67949742Smckusick vp = nd.ni_vp; 68038418Smckusick } else { 68149742Smckusick vrele(nd.ni_startdir); 68252316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 68349742Smckusick vp = nd.ni_vp; 68449742Smckusick if (nd.ni_dvp == vp) 68549742Smckusick vrele(nd.ni_dvp); 68643359Smckusick else 68749742Smckusick vput(nd.ni_dvp); 68852234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 689*56285Smckusick if (nfsd->nd_nqlflag == NQL_NOVAL) { 690*56285Smckusick tsize = fxdr_unsigned(long, sp->sa_nfssize); 691*56285Smckusick if (tsize != -1) 692*56285Smckusick vap->va_size = (u_quad_t)tsize; 693*56285Smckusick else 694*56285Smckusick vap->va_size = -1; 695*56285Smckusick } else 696*56285Smckusick fxdr_hyper(&sp->sa_nqsize, &vap->va_size); 697*56285Smckusick if (vap->va_size != -1) { 698*56285Smckusick nqsrv_getl(vp, NQL_WRITE); 699*56285Smckusick if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) { 700*56285Smckusick vput(vp); 701*56285Smckusick nfsm_reply(0); 702*56285Smckusick } 70342506Smckusick } 70438418Smckusick } 70538418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 70641398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 70738418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 70838418Smckusick vput(vp); 70938418Smckusick nfsm_reply(0); 71038418Smckusick } 71152196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 71238418Smckusick vput(vp); 713*56285Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 71438418Smckusick nfsm_srvfhtom(fhp); 715*56285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 71639753Smckusick nfsm_srvfillattr; 71738418Smckusick return (error); 71838418Smckusick nfsmout: 71952316Sheideman if (nd.ni_cnd.cn_nameiop || nd.ni_cnd.cn_flags) 72051464Sbostic vrele(nd.ni_startdir); 72152234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 72249742Smckusick if (nd.ni_dvp == nd.ni_vp) 72349742Smckusick vrele(nd.ni_dvp); 72443359Smckusick else 72549742Smckusick vput(nd.ni_dvp); 72649742Smckusick if (nd.ni_vp) 72749742Smckusick vput(nd.ni_vp); 72838418Smckusick return (error); 72949742Smckusick 73049742Smckusick out: 73149742Smckusick vrele(nd.ni_startdir); 73252316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 73349742Smckusick nfsm_reply(0); 73438418Smckusick } 73538418Smckusick 73638418Smckusick /* 73738418Smckusick * nfs remove service 73838418Smckusick */ 73952196Smckusick nfsrv_remove(nfsd, mrep, md, dpos, cred, nam, mrq) 74052196Smckusick struct nfsd *nfsd; 74152196Smckusick struct mbuf *mrep, *md; 74238418Smckusick caddr_t dpos; 74338418Smckusick struct ucred *cred; 74452196Smckusick struct mbuf *nam, **mrq; 74538418Smckusick { 74649742Smckusick struct nameidata nd; 74748050Smckusick register u_long *tl; 74839494Smckusick register long t1; 74939494Smckusick caddr_t bpos; 75052196Smckusick int error = 0, cache, len; 75139494Smckusick char *cp2; 75239753Smckusick struct mbuf *mb, *mreq; 75338418Smckusick struct vnode *vp; 75438418Smckusick nfsv2fh_t nfh; 75538418Smckusick fhandle_t *fhp; 75652196Smckusick u_quad_t frev; 75738418Smckusick 75838418Smckusick fhp = &nfh.fh_generic; 75938418Smckusick nfsm_srvmtofh(fhp); 76038418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 76152316Sheideman nd.ni_cnd.cn_cred = cred; 76252316Sheideman nd.ni_cnd.cn_nameiop = DELETE; 76352316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 76452653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 76552653Smckusick nfsd->nd_procp)) 76638418Smckusick nfsm_reply(0); 76749742Smckusick vp = nd.ni_vp; 76838418Smckusick if (vp->v_type == VDIR && 76952196Smckusick (error = suser(cred, (u_short *)0))) 77038418Smckusick goto out; 77138418Smckusick /* 77249454Smckusick * The root of a mounted filesystem cannot be deleted. 77338418Smckusick */ 77438418Smckusick if (vp->v_flag & VROOT) { 77538418Smckusick error = EBUSY; 77638418Smckusick goto out; 77738418Smckusick } 77838418Smckusick if (vp->v_flag & VTEXT) 77945715Smckusick (void) vnode_pager_uncache(vp); 78038418Smckusick out: 78142467Smckusick if (!error) { 78252196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 78352196Smckusick nqsrv_getl(vp, NQL_WRITE); 78452234Sheideman error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 78542467Smckusick } else { 78652234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 78749742Smckusick if (nd.ni_dvp == vp) 78849742Smckusick vrele(nd.ni_dvp); 78943359Smckusick else 79049742Smckusick vput(nd.ni_dvp); 79142467Smckusick vput(vp); 79242467Smckusick } 79338418Smckusick nfsm_reply(0); 79438418Smckusick nfsm_srvdone; 79538418Smckusick } 79638418Smckusick 79738418Smckusick /* 79838418Smckusick * nfs rename service 79938418Smckusick */ 80052196Smckusick nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq) 80152196Smckusick struct nfsd *nfsd; 80252196Smckusick struct mbuf *mrep, *md; 80338418Smckusick caddr_t dpos; 80438418Smckusick struct ucred *cred; 80552196Smckusick struct mbuf *nam, **mrq; 80638418Smckusick { 80748050Smckusick register u_long *tl; 80839494Smckusick register long t1; 80939494Smckusick caddr_t bpos; 81052196Smckusick int error = 0, rdonly, cache, len, len2; 81139494Smckusick char *cp2; 81239753Smckusick struct mbuf *mb, *mreq; 81349742Smckusick struct nameidata fromnd, tond; 81438418Smckusick struct vnode *fvp, *tvp, *tdvp; 81538418Smckusick nfsv2fh_t fnfh, tnfh; 81638418Smckusick fhandle_t *ffhp, *tfhp; 81752196Smckusick u_quad_t frev; 81852196Smckusick uid_t saved_uid; 81938418Smckusick 82038418Smckusick ffhp = &fnfh.fh_generic; 82138418Smckusick tfhp = &tnfh.fh_generic; 82252316Sheideman fromnd.ni_cnd.cn_nameiop = 0; 82352316Sheideman tond.ni_cnd.cn_nameiop = 0; 82438418Smckusick nfsm_srvmtofh(ffhp); 82538418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 82638418Smckusick /* 82752196Smckusick * Remember our original uid so that we can reset cr_uid before 82852196Smckusick * the second nfs_namei() call, in case it is remapped. 82938418Smckusick */ 83052196Smckusick saved_uid = cred->cr_uid; 83152316Sheideman fromnd.ni_cnd.cn_cred = cred; 83252316Sheideman fromnd.ni_cnd.cn_nameiop = DELETE; 83352316Sheideman fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART; 83452653Smckusick if (error = nfs_namei(&fromnd, ffhp, len, nfsd->nd_slp, nam, &md, 83552653Smckusick &dpos, nfsd->nd_procp)) 83638418Smckusick nfsm_reply(0); 83749742Smckusick fvp = fromnd.ni_vp; 83838418Smckusick nfsm_srvmtofh(tfhp); 83941899Smckusick nfsm_strsiz(len2, NFS_MAXNAMLEN); 84052196Smckusick cred->cr_uid = saved_uid; 84152316Sheideman tond.ni_cnd.cn_cred = cred; 84252316Sheideman tond.ni_cnd.cn_nameiop = RENAME; 84352316Sheideman tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; 84452653Smckusick if (error = nfs_namei(&tond, tfhp, len2, nfsd->nd_slp, nam, &md, 84552653Smckusick &dpos, nfsd->nd_procp)) { 84652234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 84749742Smckusick vrele(fromnd.ni_dvp); 84842467Smckusick vrele(fvp); 84942467Smckusick goto out1; 85042467Smckusick } 85138425Smckusick tdvp = tond.ni_dvp; 85238425Smckusick tvp = tond.ni_vp; 85338418Smckusick if (tvp != NULL) { 85438418Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 85538418Smckusick error = EISDIR; 85638418Smckusick goto out; 85738418Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 85838418Smckusick error = ENOTDIR; 85938418Smckusick goto out; 86038418Smckusick } 86152196Smckusick if (tvp->v_type == VDIR && tvp->v_mountedhere) { 86252196Smckusick error = EXDEV; 86352196Smckusick goto out; 86452196Smckusick } 86538418Smckusick } 86652196Smckusick if (fvp->v_type == VDIR && fvp->v_mountedhere) { 86752196Smckusick error = EBUSY; 86852196Smckusick goto out; 86952196Smckusick } 87038418Smckusick if (fvp->v_mount != tdvp->v_mount) { 87138418Smckusick error = EXDEV; 87238418Smckusick goto out; 87338418Smckusick } 87449742Smckusick if (fvp == tdvp) 87538418Smckusick error = EINVAL; 87649742Smckusick /* 87749742Smckusick * If source is the same as the destination (that is the 87849742Smckusick * same vnode with the same name in the same directory), 87949742Smckusick * then there is nothing to do. 88049742Smckusick */ 88149742Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 88252316Sheideman fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 88352316Sheideman !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 88452316Sheideman fromnd.ni_cnd.cn_namelen)) 88549742Smckusick error = -1; 88638418Smckusick out: 88742467Smckusick if (!error) { 88852196Smckusick nqsrv_getl(fromnd.ni_dvp, NQL_WRITE); 88952196Smckusick nqsrv_getl(tdvp, NQL_WRITE); 89052196Smckusick if (tvp) 89152196Smckusick nqsrv_getl(tvp, NQL_WRITE); 89252234Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 89352234Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 89442467Smckusick } else { 89552234Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 89643359Smckusick if (tdvp == tvp) 89743359Smckusick vrele(tdvp); 89843359Smckusick else 89943359Smckusick vput(tdvp); 90042467Smckusick if (tvp) 90142467Smckusick vput(tvp); 90252234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 90349742Smckusick vrele(fromnd.ni_dvp); 90442467Smckusick vrele(fvp); 90538418Smckusick } 90646513Smckusick vrele(tond.ni_startdir); 90752316Sheideman FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 90838418Smckusick out1: 90949742Smckusick vrele(fromnd.ni_startdir); 91052316Sheideman FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 91138418Smckusick nfsm_reply(0); 91238418Smckusick return (error); 91349742Smckusick 91438418Smckusick nfsmout: 91552316Sheideman if (tond.ni_cnd.cn_nameiop || tond.ni_cnd.cn_flags) { 91649742Smckusick vrele(tond.ni_startdir); 91752316Sheideman FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 91849742Smckusick } 91952316Sheideman if (fromnd.ni_cnd.cn_nameiop || fromnd.ni_cnd.cn_flags) { 92049742Smckusick vrele(fromnd.ni_startdir); 92152316Sheideman FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 92252234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 92349742Smckusick vrele(fromnd.ni_dvp); 92449742Smckusick vrele(fvp); 92549742Smckusick } 92638418Smckusick return (error); 92738418Smckusick } 92838418Smckusick 92938418Smckusick /* 93038418Smckusick * nfs link service 93138418Smckusick */ 93252196Smckusick nfsrv_link(nfsd, mrep, md, dpos, cred, nam, mrq) 93352196Smckusick struct nfsd *nfsd; 93452196Smckusick struct mbuf *mrep, *md; 93538418Smckusick caddr_t dpos; 93638418Smckusick struct ucred *cred; 93752196Smckusick struct mbuf *nam, **mrq; 93838418Smckusick { 93949742Smckusick struct nameidata nd; 94048050Smckusick register u_long *tl; 94139494Smckusick register long t1; 94239494Smckusick caddr_t bpos; 94352196Smckusick int error = 0, rdonly, cache, len; 94439494Smckusick char *cp2; 94539753Smckusick struct mbuf *mb, *mreq; 94638418Smckusick struct vnode *vp, *xp; 94738418Smckusick nfsv2fh_t nfh, dnfh; 94838418Smckusick fhandle_t *fhp, *dfhp; 94952196Smckusick u_quad_t frev; 95038418Smckusick 95138418Smckusick fhp = &nfh.fh_generic; 95238418Smckusick dfhp = &dnfh.fh_generic; 95338418Smckusick nfsm_srvmtofh(fhp); 95438418Smckusick nfsm_srvmtofh(dfhp); 95538418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 95652196Smckusick if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 95738418Smckusick nfsm_reply(0); 95852196Smckusick if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0))) 95938418Smckusick goto out1; 96052316Sheideman nd.ni_cnd.cn_cred = cred; 96152316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 96252316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 96352653Smckusick if (error = nfs_namei(&nd, dfhp, len, nfsd->nd_slp, nam, &md, &dpos, 96452653Smckusick nfsd->nd_procp)) 96538418Smckusick goto out1; 96649742Smckusick xp = nd.ni_vp; 96738418Smckusick if (xp != NULL) { 96838418Smckusick error = EEXIST; 96938418Smckusick goto out; 97038418Smckusick } 97149742Smckusick xp = nd.ni_dvp; 97238418Smckusick if (vp->v_mount != xp->v_mount) 97338418Smckusick error = EXDEV; 97438418Smckusick out: 97542467Smckusick if (!error) { 97652196Smckusick nqsrv_getl(vp, NQL_WRITE); 97752196Smckusick nqsrv_getl(xp, NQL_WRITE); 97852933Smckusick error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 97942467Smckusick } else { 98052234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 98149742Smckusick if (nd.ni_dvp == nd.ni_vp) 98249742Smckusick vrele(nd.ni_dvp); 98343359Smckusick else 98449742Smckusick vput(nd.ni_dvp); 98549742Smckusick if (nd.ni_vp) 98649742Smckusick vrele(nd.ni_vp); 98742467Smckusick } 98838418Smckusick out1: 98938418Smckusick vrele(vp); 99038418Smckusick nfsm_reply(0); 99138418Smckusick nfsm_srvdone; 99238418Smckusick } 99338418Smckusick 99438418Smckusick /* 99538418Smckusick * nfs symbolic link service 99638418Smckusick */ 99752196Smckusick nfsrv_symlink(nfsd, mrep, md, dpos, cred, nam, mrq) 99852196Smckusick struct nfsd *nfsd; 99952196Smckusick struct mbuf *mrep, *md; 100038418Smckusick caddr_t dpos; 100138418Smckusick struct ucred *cred; 100252196Smckusick struct mbuf *nam, **mrq; 100338418Smckusick { 100438418Smckusick struct vattr va; 100549742Smckusick struct nameidata nd; 100638418Smckusick register struct vattr *vap = &va; 100748050Smckusick register u_long *tl; 100839494Smckusick register long t1; 100945285Smckusick struct nfsv2_sattr *sp; 101039494Smckusick caddr_t bpos; 101141899Smckusick struct uio io; 101241899Smckusick struct iovec iv; 101352196Smckusick int error = 0, rdonly, cache, len, len2; 101441899Smckusick char *pathcp, *cp2; 101539753Smckusick struct mbuf *mb, *mreq; 101638418Smckusick nfsv2fh_t nfh; 101738418Smckusick fhandle_t *fhp; 101852196Smckusick u_quad_t frev; 101938418Smckusick 102041899Smckusick pathcp = (char *)0; 102138418Smckusick fhp = &nfh.fh_generic; 102238418Smckusick nfsm_srvmtofh(fhp); 102338418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 102452316Sheideman nd.ni_cnd.cn_cred = cred; 102552316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 102652316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 102752653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 102852653Smckusick nfsd->nd_procp)) 102942467Smckusick goto out; 103041899Smckusick nfsm_strsiz(len2, NFS_MAXPATHLEN); 103141899Smckusick MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK); 103241899Smckusick iv.iov_base = pathcp; 103341899Smckusick iv.iov_len = len2; 103441899Smckusick io.uio_resid = len2; 103541899Smckusick io.uio_offset = 0; 103641899Smckusick io.uio_iov = &iv; 103741899Smckusick io.uio_iovcnt = 1; 103841899Smckusick io.uio_segflg = UIO_SYSSPACE; 103941899Smckusick io.uio_rw = UIO_READ; 104048050Smckusick io.uio_procp = (struct proc *)0; 104141899Smckusick nfsm_mtouio(&io, len2); 1042*56285Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 104341899Smckusick *(pathcp + len2) = '\0'; 104449742Smckusick if (nd.ni_vp) { 104552234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 104649742Smckusick if (nd.ni_dvp == nd.ni_vp) 104749742Smckusick vrele(nd.ni_dvp); 104843359Smckusick else 104949742Smckusick vput(nd.ni_dvp); 105049742Smckusick vrele(nd.ni_vp); 105138418Smckusick error = EEXIST; 105238418Smckusick goto out; 105338418Smckusick } 105441361Smckusick VATTR_NULL(vap); 105545285Smckusick vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode); 105652196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 105752234Sheideman error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp); 105838418Smckusick out: 105941899Smckusick if (pathcp) 106041899Smckusick FREE(pathcp, M_TEMP); 106138418Smckusick nfsm_reply(0); 106238418Smckusick return (error); 106338418Smckusick nfsmout: 106452234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 106549742Smckusick if (nd.ni_dvp == nd.ni_vp) 106649742Smckusick vrele(nd.ni_dvp); 106743359Smckusick else 106849742Smckusick vput(nd.ni_dvp); 106949742Smckusick if (nd.ni_vp) 107049742Smckusick vrele(nd.ni_vp); 107141899Smckusick if (pathcp) 107241899Smckusick FREE(pathcp, M_TEMP); 107338418Smckusick return (error); 107438418Smckusick } 107538418Smckusick 107638418Smckusick /* 107738418Smckusick * nfs mkdir service 107838418Smckusick */ 107952196Smckusick nfsrv_mkdir(nfsd, mrep, md, dpos, cred, nam, mrq) 108052196Smckusick struct nfsd *nfsd; 108152196Smckusick struct mbuf *mrep, *md; 108238418Smckusick caddr_t dpos; 108338418Smckusick struct ucred *cred; 108452196Smckusick struct mbuf *nam, **mrq; 108538418Smckusick { 108638418Smckusick struct vattr va; 108738418Smckusick register struct vattr *vap = &va; 108838884Smacklem register struct nfsv2_fattr *fp; 108949742Smckusick struct nameidata nd; 109039494Smckusick register caddr_t cp; 109148050Smckusick register u_long *tl; 109239494Smckusick register long t1; 109339494Smckusick caddr_t bpos; 109452196Smckusick int error = 0, rdonly, cache, len; 109539494Smckusick char *cp2; 109639753Smckusick struct mbuf *mb, *mb2, *mreq; 109738418Smckusick struct vnode *vp; 109838418Smckusick nfsv2fh_t nfh; 109938418Smckusick fhandle_t *fhp; 110052196Smckusick u_quad_t frev; 110138418Smckusick 110238418Smckusick fhp = &nfh.fh_generic; 110338418Smckusick nfsm_srvmtofh(fhp); 110438418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 110552316Sheideman nd.ni_cnd.cn_cred = cred; 110652316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 110752316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 110852653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 110952653Smckusick nfsd->nd_procp)) 111038418Smckusick nfsm_reply(0); 111152196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 111241361Smckusick VATTR_NULL(vap); 111338418Smckusick vap->va_type = VDIR; 111448050Smckusick vap->va_mode = nfstov_mode(*tl++); 111549742Smckusick vp = nd.ni_vp; 111638418Smckusick if (vp != NULL) { 111752234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 111849742Smckusick if (nd.ni_dvp == vp) 111949742Smckusick vrele(nd.ni_dvp); 112043359Smckusick else 112149742Smckusick vput(nd.ni_dvp); 112242467Smckusick vrele(vp); 112338418Smckusick error = EEXIST; 112438418Smckusick nfsm_reply(0); 112538418Smckusick } 112652196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 112752234Sheideman if (error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) 112838418Smckusick nfsm_reply(0); 112949742Smckusick vp = nd.ni_vp; 113038418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 113141398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 113238418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 113338418Smckusick vput(vp); 113438418Smckusick nfsm_reply(0); 113538418Smckusick } 113652196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 113738418Smckusick vput(vp); 1138*56285Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 113938418Smckusick nfsm_srvfhtom(fhp); 1140*56285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 114139753Smckusick nfsm_srvfillattr; 114238418Smckusick return (error); 114338418Smckusick nfsmout: 114452234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 114549742Smckusick if (nd.ni_dvp == nd.ni_vp) 114649742Smckusick vrele(nd.ni_dvp); 114743359Smckusick else 114849742Smckusick vput(nd.ni_dvp); 114949742Smckusick if (nd.ni_vp) 115049742Smckusick vrele(nd.ni_vp); 115138418Smckusick return (error); 115238418Smckusick } 115338418Smckusick 115438418Smckusick /* 115538418Smckusick * nfs rmdir service 115638418Smckusick */ 115752196Smckusick nfsrv_rmdir(nfsd, mrep, md, dpos, cred, nam, mrq) 115852196Smckusick struct nfsd *nfsd; 115952196Smckusick struct mbuf *mrep, *md; 116038418Smckusick caddr_t dpos; 116138418Smckusick struct ucred *cred; 116252196Smckusick struct mbuf *nam, **mrq; 116338418Smckusick { 116448050Smckusick register u_long *tl; 116539494Smckusick register long t1; 116639494Smckusick caddr_t bpos; 116752196Smckusick int error = 0, rdonly, cache, len; 116839494Smckusick char *cp2; 116939753Smckusick struct mbuf *mb, *mreq; 117038418Smckusick struct vnode *vp; 117138418Smckusick nfsv2fh_t nfh; 117238418Smckusick fhandle_t *fhp; 117349742Smckusick struct nameidata nd; 117452196Smckusick u_quad_t frev; 117538418Smckusick 117638418Smckusick fhp = &nfh.fh_generic; 117738418Smckusick nfsm_srvmtofh(fhp); 117838418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 117952316Sheideman nd.ni_cnd.cn_cred = cred; 118052316Sheideman nd.ni_cnd.cn_nameiop = DELETE; 118152316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 118252653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 118352653Smckusick nfsd->nd_procp)) 118438418Smckusick nfsm_reply(0); 118549742Smckusick vp = nd.ni_vp; 118638418Smckusick if (vp->v_type != VDIR) { 118738418Smckusick error = ENOTDIR; 118838418Smckusick goto out; 118938418Smckusick } 119038418Smckusick /* 119138418Smckusick * No rmdir "." please. 119238418Smckusick */ 119349742Smckusick if (nd.ni_dvp == vp) { 119438418Smckusick error = EINVAL; 119538418Smckusick goto out; 119638418Smckusick } 119738418Smckusick /* 119849454Smckusick * The root of a mounted filesystem cannot be deleted. 119938418Smckusick */ 120038418Smckusick if (vp->v_flag & VROOT) 120138418Smckusick error = EBUSY; 120238418Smckusick out: 120342467Smckusick if (!error) { 120452196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 120552196Smckusick nqsrv_getl(vp, NQL_WRITE); 120652234Sheideman error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 120742467Smckusick } else { 120852234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 120949742Smckusick if (nd.ni_dvp == nd.ni_vp) 121049742Smckusick vrele(nd.ni_dvp); 121143359Smckusick else 121249742Smckusick vput(nd.ni_dvp); 121342467Smckusick vput(vp); 121442467Smckusick } 121538418Smckusick nfsm_reply(0); 121638418Smckusick nfsm_srvdone; 121738418Smckusick } 121838418Smckusick 121938418Smckusick /* 122038418Smckusick * nfs readdir service 122138418Smckusick * - mallocs what it thinks is enough to read 122248050Smckusick * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR 122338418Smckusick * - calls VOP_READDIR() 122440115Smckusick * - loops around building the reply 122538425Smckusick * if the output generated exceeds count break out of loop 122638425Smckusick * The nfsm_clget macro is used here so that the reply will be packed 122738425Smckusick * tightly in mbuf clusters. 122838418Smckusick * - it only knows that it has encountered eof when the VOP_READDIR() 122938425Smckusick * reads nothing 123038418Smckusick * - as such one readdir rpc will return eof false although you are there 123138425Smckusick * and then the next will return eof 123252441Smckusick * - it trims out records with d_fileno == 0 123338425Smckusick * this doesn't matter for Unix clients, but they might confuse clients 123438425Smckusick * for other os'. 123538418Smckusick * NB: It is tempting to set eof to true if the VOP_READDIR() reads less 123638425Smckusick * than requested, but this may not apply to all filesystems. For 123738425Smckusick * example, client NFS does not { although it is never remote mounted 123838425Smckusick * anyhow } 123952196Smckusick * The alternate call nqnfsrv_readdirlook() does lookups as well. 124038418Smckusick * PS: The NFS protocol spec. does not clarify what the "count" byte 124138425Smckusick * argument is a count of.. just name strings and file id's or the 124238425Smckusick * entire reply rpc or ... 124338425Smckusick * I tried just file name and id sizes and it confused the Sun client, 124438425Smckusick * so I am using the full rpc size now. The "paranoia.." comment refers 124538425Smckusick * to including the status longwords that are not a part of the dir. 124638425Smckusick * "entry" structures, but are in the rpc. 124738418Smckusick */ 124852196Smckusick struct flrep { 124952196Smckusick u_long fl_cachable; 125052196Smckusick u_long fl_duration; 125155528Smckusick u_long fl_frev[2]; 125252196Smckusick nfsv2fh_t fl_nfh; 1253*56285Smckusick u_long fl_fattr[NFSX_NQFATTR / sizeof (u_long)]; 125452196Smckusick }; 125552196Smckusick 125652196Smckusick nfsrv_readdir(nfsd, mrep, md, dpos, cred, nam, mrq) 125752196Smckusick struct nfsd *nfsd; 125838418Smckusick struct mbuf *mrep, *md; 125938418Smckusick caddr_t dpos; 126038418Smckusick struct ucred *cred; 126152196Smckusick struct mbuf *nam, **mrq; 126238418Smckusick { 126338418Smckusick register char *bp, *be; 126438418Smckusick register struct mbuf *mp; 126552441Smckusick register struct dirent *dp; 126639494Smckusick register caddr_t cp; 126748050Smckusick register u_long *tl; 126839494Smckusick register long t1; 126939494Smckusick caddr_t bpos; 127052196Smckusick struct mbuf *mb, *mb2, *mreq, *mp2; 127152196Smckusick char *cpos, *cend, *cp2, *rbuf; 127238418Smckusick struct vnode *vp; 127338418Smckusick nfsv2fh_t nfh; 127438418Smckusick fhandle_t *fhp; 127538418Smckusick struct uio io; 127638418Smckusick struct iovec iv; 127752196Smckusick struct vattr va; 127852196Smckusick int len, nlen, rem, xfer, tsiz, i, error = 0; 127952196Smckusick int siz, cnt, fullsiz, eofflag, rdonly, cache; 128052196Smckusick u_quad_t frev; 1281*56285Smckusick u_long on, off, toff; 128238418Smckusick 128338418Smckusick fhp = &nfh.fh_generic; 128438418Smckusick nfsm_srvmtofh(fhp); 128552196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 1286*56285Smckusick toff = fxdr_unsigned(u_long, *tl++); 128748050Smckusick off = (toff & ~(NFS_DIRBLKSIZ-1)); 128848050Smckusick on = (toff & (NFS_DIRBLKSIZ-1)); 128948050Smckusick cnt = fxdr_unsigned(int, *tl); 129048050Smckusick siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); 129141899Smckusick if (cnt > NFS_MAXREADDIR) 129241899Smckusick siz = NFS_MAXREADDIR; 129338418Smckusick fullsiz = siz; 129452196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 129538418Smckusick nfsm_reply(0); 129652196Smckusick nqsrv_getl(vp, NQL_READ); 129752196Smckusick if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { 129838418Smckusick vput(vp); 129938418Smckusick nfsm_reply(0); 130038418Smckusick } 130138418Smckusick VOP_UNLOCK(vp); 130238418Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 130338418Smckusick again: 130438418Smckusick iv.iov_base = rbuf; 130538418Smckusick iv.iov_len = fullsiz; 130638418Smckusick io.uio_iov = &iv; 130738418Smckusick io.uio_iovcnt = 1; 1308*56285Smckusick io.uio_offset = (off_t)off; 130938418Smckusick io.uio_resid = fullsiz; 131038418Smckusick io.uio_segflg = UIO_SYSSPACE; 131138418Smckusick io.uio_rw = UIO_READ; 131248050Smckusick io.uio_procp = (struct proc *)0; 131354446Smckusick error = VOP_READDIR(vp, &io, cred); 1314*56285Smckusick off = (off_t)io.uio_offset; 131538418Smckusick if (error) { 131638418Smckusick vrele(vp); 131738418Smckusick free((caddr_t)rbuf, M_TEMP); 131838418Smckusick nfsm_reply(0); 131938418Smckusick } 132054446Smckusick if (io.uio_resid < fullsiz) 132154446Smckusick eofflag = 0; 132254446Smckusick else 132354446Smckusick eofflag = 1; 132438418Smckusick if (io.uio_resid) { 132538418Smckusick siz -= io.uio_resid; 132638418Smckusick 132738418Smckusick /* 132838418Smckusick * If nothing read, return eof 132938418Smckusick * rpc reply 133038418Smckusick */ 133138418Smckusick if (siz == 0) { 133238418Smckusick vrele(vp); 133338418Smckusick nfsm_reply(2*NFSX_UNSIGNED); 133448050Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 133548050Smckusick *tl++ = nfs_false; 133648050Smckusick *tl = nfs_true; 133738418Smckusick FREE((caddr_t)rbuf, M_TEMP); 133838418Smckusick return (0); 133938418Smckusick } 134038418Smckusick } 134140115Smckusick 134238418Smckusick /* 134338418Smckusick * Check for degenerate cases of nothing useful read. 134440115Smckusick * If so go try again 134538418Smckusick */ 134640115Smckusick cpos = rbuf + on; 134740115Smckusick cend = rbuf + siz; 134852441Smckusick dp = (struct dirent *)cpos; 134952441Smckusick while (cpos < cend && dp->d_fileno == 0) { 135040115Smckusick cpos += dp->d_reclen; 135152441Smckusick dp = (struct dirent *)cpos; 135240115Smckusick } 135340115Smckusick if (cpos >= cend) { 135438418Smckusick toff = off; 135538418Smckusick siz = fullsiz; 135638418Smckusick on = 0; 135738418Smckusick goto again; 135838418Smckusick } 135940115Smckusick 136040115Smckusick cpos = rbuf + on; 136140115Smckusick cend = rbuf + siz; 136252441Smckusick dp = (struct dirent *)cpos; 136352196Smckusick len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 136452196Smckusick nfsm_reply(siz); 136552196Smckusick mp = mp2 = mb; 136652196Smckusick bp = bpos; 136752196Smckusick be = bp + M_TRAILINGSPACE(mp); 136852196Smckusick 136952196Smckusick /* Loop through the records and build reply */ 137052196Smckusick while (cpos < cend) { 137152441Smckusick if (dp->d_fileno != 0) { 137252196Smckusick nlen = dp->d_namlen; 137352196Smckusick rem = nfsm_rndup(nlen)-nlen; 137452196Smckusick len += (4*NFSX_UNSIGNED + nlen + rem); 137552196Smckusick if (len > cnt) { 137652196Smckusick eofflag = 0; 137752196Smckusick break; 137852196Smckusick } 137952441Smckusick /* 138052441Smckusick * Build the directory record xdr from 138152441Smckusick * the dirent entry. 138252441Smckusick */ 138352196Smckusick nfsm_clget; 138452196Smckusick *tl = nfs_true; 138552196Smckusick bp += NFSX_UNSIGNED; 138652196Smckusick nfsm_clget; 138752441Smckusick *tl = txdr_unsigned(dp->d_fileno); 138852196Smckusick bp += NFSX_UNSIGNED; 138952196Smckusick nfsm_clget; 139052196Smckusick *tl = txdr_unsigned(nlen); 139152196Smckusick bp += NFSX_UNSIGNED; 139252196Smckusick 139352196Smckusick /* And loop around copying the name */ 139452196Smckusick xfer = nlen; 139552196Smckusick cp = dp->d_name; 139652196Smckusick while (xfer > 0) { 139752196Smckusick nfsm_clget; 139852196Smckusick if ((bp+xfer) > be) 139952196Smckusick tsiz = be-bp; 140052196Smckusick else 140152196Smckusick tsiz = xfer; 140252196Smckusick bcopy(cp, bp, tsiz); 140352196Smckusick bp += tsiz; 140452196Smckusick xfer -= tsiz; 140552196Smckusick if (xfer > 0) 140652196Smckusick cp += tsiz; 140752196Smckusick } 140852196Smckusick /* And null pad to a long boundary */ 140952196Smckusick for (i = 0; i < rem; i++) 141052196Smckusick *bp++ = '\0'; 141152196Smckusick nfsm_clget; 141252196Smckusick 141352196Smckusick /* Finish off the record */ 141452196Smckusick toff += dp->d_reclen; 141552196Smckusick *tl = txdr_unsigned(toff); 141652196Smckusick bp += NFSX_UNSIGNED; 141752196Smckusick } else 141852196Smckusick toff += dp->d_reclen; 141952196Smckusick cpos += dp->d_reclen; 142052441Smckusick dp = (struct dirent *)cpos; 142152196Smckusick } 142238418Smckusick vrele(vp); 142352196Smckusick nfsm_clget; 142452196Smckusick *tl = nfs_false; 142552196Smckusick bp += NFSX_UNSIGNED; 142652196Smckusick nfsm_clget; 142752196Smckusick if (eofflag) 142852196Smckusick *tl = nfs_true; 142952196Smckusick else 143052196Smckusick *tl = nfs_false; 143152196Smckusick bp += NFSX_UNSIGNED; 143252196Smckusick if (mp != mb) { 143352196Smckusick if (bp < be) 143452196Smckusick mp->m_len = bp - mtod(mp, caddr_t); 143552196Smckusick } else 143652196Smckusick mp->m_len += bp - bpos; 143752196Smckusick FREE(rbuf, M_TEMP); 143852196Smckusick nfsm_srvdone; 143952196Smckusick } 144052196Smckusick 144152196Smckusick nqnfsrv_readdirlook(nfsd, mrep, md, dpos, cred, nam, mrq) 144252196Smckusick struct nfsd *nfsd; 144352196Smckusick struct mbuf *mrep, *md; 144452196Smckusick caddr_t dpos; 144552196Smckusick struct ucred *cred; 144652196Smckusick struct mbuf *nam, **mrq; 144752196Smckusick { 144852196Smckusick register char *bp, *be; 144952196Smckusick register struct mbuf *mp; 145052441Smckusick register struct dirent *dp; 145152196Smckusick register caddr_t cp; 145252196Smckusick register u_long *tl; 145352196Smckusick register long t1; 145452196Smckusick caddr_t bpos; 145552196Smckusick struct mbuf *mb, *mb2, *mreq, *mp2; 145652196Smckusick char *cpos, *cend, *cp2, *rbuf; 145752196Smckusick struct vnode *vp, *nvp; 145852196Smckusick struct flrep fl; 145952196Smckusick nfsv2fh_t nfh; 146052196Smckusick fhandle_t *fhp; 146152196Smckusick struct uio io; 146252196Smckusick struct iovec iv; 146352196Smckusick struct vattr va, *vap = &va; 146452196Smckusick struct nfsv2_fattr *fp; 146552196Smckusick int len, nlen, rem, xfer, tsiz, i, error = 0, duration2, cache2; 146652196Smckusick int siz, cnt, fullsiz, eofflag, rdonly, cache; 146752196Smckusick u_quad_t frev, frev2; 1468*56285Smckusick u_long on, off, toff; 146952196Smckusick 147052196Smckusick fhp = &nfh.fh_generic; 147152196Smckusick nfsm_srvmtofh(fhp); 147252196Smckusick nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED); 1473*56285Smckusick toff = fxdr_unsigned(u_long, *tl++); 147452196Smckusick off = (toff & ~(NFS_DIRBLKSIZ-1)); 147552196Smckusick on = (toff & (NFS_DIRBLKSIZ-1)); 147652196Smckusick cnt = fxdr_unsigned(int, *tl++); 147752196Smckusick duration2 = fxdr_unsigned(int, *tl); 147852196Smckusick siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); 147952196Smckusick if (cnt > NFS_MAXREADDIR) 148052196Smckusick siz = NFS_MAXREADDIR; 148152196Smckusick fullsiz = siz; 148252196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 148352196Smckusick nfsm_reply(0); 148452196Smckusick nqsrv_getl(vp, NQL_READ); 148552196Smckusick if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { 148652196Smckusick vput(vp); 148752196Smckusick nfsm_reply(0); 148852196Smckusick } 148952196Smckusick VOP_UNLOCK(vp); 149052196Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 149152196Smckusick again: 149252196Smckusick iv.iov_base = rbuf; 149352196Smckusick iv.iov_len = fullsiz; 149452196Smckusick io.uio_iov = &iv; 149552196Smckusick io.uio_iovcnt = 1; 1496*56285Smckusick io.uio_offset = (off_t)off; 149752196Smckusick io.uio_resid = fullsiz; 149852196Smckusick io.uio_segflg = UIO_SYSSPACE; 149952196Smckusick io.uio_rw = UIO_READ; 150052196Smckusick io.uio_procp = (struct proc *)0; 150154446Smckusick error = VOP_READDIR(vp, &io, cred); 1502*56285Smckusick off = (u_long)io.uio_offset; 150352196Smckusick if (error) { 150452196Smckusick vrele(vp); 150552196Smckusick free((caddr_t)rbuf, M_TEMP); 150652196Smckusick nfsm_reply(0); 150752196Smckusick } 150854446Smckusick if (io.uio_resid < fullsiz) 150954446Smckusick eofflag = 0; 151054446Smckusick else 151154446Smckusick eofflag = 1; 151252196Smckusick if (io.uio_resid) { 151352196Smckusick siz -= io.uio_resid; 151452196Smckusick 151552196Smckusick /* 151652196Smckusick * If nothing read, return eof 151752196Smckusick * rpc reply 151852196Smckusick */ 151952196Smckusick if (siz == 0) { 152052196Smckusick vrele(vp); 1521*56285Smckusick nfsm_reply(2 * NFSX_UNSIGNED); 1522*56285Smckusick nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); 152352196Smckusick *tl++ = nfs_false; 152452196Smckusick *tl = nfs_true; 152552196Smckusick FREE((caddr_t)rbuf, M_TEMP); 152652196Smckusick return (0); 152752196Smckusick } 152852196Smckusick } 152952196Smckusick 153052196Smckusick /* 153152196Smckusick * Check for degenerate cases of nothing useful read. 153252196Smckusick * If so go try again 153352196Smckusick */ 153452196Smckusick cpos = rbuf + on; 153552196Smckusick cend = rbuf + siz; 153652441Smckusick dp = (struct dirent *)cpos; 153752441Smckusick while (cpos < cend && dp->d_fileno == 0) { 153852196Smckusick cpos += dp->d_reclen; 153952441Smckusick dp = (struct dirent *)cpos; 154052196Smckusick } 154152196Smckusick if (cpos >= cend) { 154252196Smckusick toff = off; 154352196Smckusick siz = fullsiz; 154452196Smckusick on = 0; 154552196Smckusick goto again; 154652196Smckusick } 154752196Smckusick 154852196Smckusick cpos = rbuf + on; 154952196Smckusick cend = rbuf + siz; 155052441Smckusick dp = (struct dirent *)cpos; 1551*56285Smckusick len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 155238418Smckusick nfsm_reply(siz); 155352196Smckusick mp = mp2 = mb; 155452196Smckusick bp = bpos; 155552196Smckusick be = bp + M_TRAILINGSPACE(mp); 155638418Smckusick 155738418Smckusick /* Loop through the records and build reply */ 155838418Smckusick while (cpos < cend) { 155952441Smckusick if (dp->d_fileno != 0) { 156038418Smckusick nlen = dp->d_namlen; 156138418Smckusick rem = nfsm_rndup(nlen)-nlen; 156238425Smckusick 156338418Smckusick /* 156452196Smckusick * For readdir_and_lookup get the vnode using 156552196Smckusick * the file number. 156638418Smckusick */ 156754665Smckusick if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp)) 156852196Smckusick goto invalid; 156955655Smckusick bzero((caddr_t)&fl.fl_nfh, sizeof (nfsv2fh_t)); 157055655Smckusick fl.fl_nfh.fh_generic.fh_fsid = 157155655Smckusick nvp->v_mount->mnt_stat.f_fsid; 157255655Smckusick if (VFS_VPTOFH(nvp, &fl.fl_nfh.fh_generic.fh_fid)) { 157355655Smckusick vput(nvp); 157455655Smckusick goto invalid; 157555655Smckusick } 1576*56285Smckusick if (duration2) { 1577*56285Smckusick (void) nqsrv_getlease(nvp, &duration2, NQL_READ, 1578*56285Smckusick nfsd, nam, &cache2, &frev2, cred); 1579*56285Smckusick fl.fl_duration = txdr_unsigned(duration2); 1580*56285Smckusick fl.fl_cachable = txdr_unsigned(cache2); 1581*56285Smckusick txdr_hyper(&frev2, fl.fl_frev); 1582*56285Smckusick } else 1583*56285Smckusick fl.fl_duration = 0; 158452196Smckusick if (VOP_GETATTR(nvp, vap, cred, nfsd->nd_procp)) { 158552196Smckusick vput(nvp); 158652196Smckusick goto invalid; 158752196Smckusick } 158852196Smckusick vput(nvp); 1589*56285Smckusick fp = (struct nfsv2_fattr *)&fl.fl_fattr; 159052196Smckusick nfsm_srvfillattr; 159152196Smckusick len += (4*NFSX_UNSIGNED + nlen + rem + NFSX_FH 1592*56285Smckusick + NFSX_NQFATTR); 159341899Smckusick if (len > cnt) { 159441899Smckusick eofflag = 0; 159538418Smckusick break; 159641899Smckusick } 159752441Smckusick /* 159852441Smckusick * Build the directory record xdr from 159952441Smckusick * the dirent entry. 160052441Smckusick */ 160138418Smckusick nfsm_clget; 160248050Smckusick *tl = nfs_true; 160338418Smckusick bp += NFSX_UNSIGNED; 160452196Smckusick 160552196Smckusick /* 160652196Smckusick * For readdir_and_lookup copy the stuff out. 160752196Smckusick */ 160852196Smckusick xfer = sizeof (struct flrep); 160952196Smckusick cp = (caddr_t)&fl; 161052196Smckusick while (xfer > 0) { 161152196Smckusick nfsm_clget; 161252196Smckusick if ((bp+xfer) > be) 161352196Smckusick tsiz = be-bp; 161452196Smckusick else 161552196Smckusick tsiz = xfer; 161652196Smckusick bcopy(cp, bp, tsiz); 161752196Smckusick bp += tsiz; 161852196Smckusick xfer -= tsiz; 161952196Smckusick if (xfer > 0) 162052196Smckusick cp += tsiz; 162152196Smckusick } 162238418Smckusick nfsm_clget; 162352441Smckusick *tl = txdr_unsigned(dp->d_fileno); 162438418Smckusick bp += NFSX_UNSIGNED; 162538418Smckusick nfsm_clget; 162648050Smckusick *tl = txdr_unsigned(nlen); 162738418Smckusick bp += NFSX_UNSIGNED; 162838425Smckusick 162952196Smckusick /* And loop around copying the name */ 163038418Smckusick xfer = nlen; 163138418Smckusick cp = dp->d_name; 163238418Smckusick while (xfer > 0) { 163338418Smckusick nfsm_clget; 163438418Smckusick if ((bp+xfer) > be) 163538418Smckusick tsiz = be-bp; 163638418Smckusick else 163738418Smckusick tsiz = xfer; 163838418Smckusick bcopy(cp, bp, tsiz); 163938418Smckusick bp += tsiz; 164038418Smckusick xfer -= tsiz; 164138418Smckusick if (xfer > 0) 164238418Smckusick cp += tsiz; 164338418Smckusick } 164438418Smckusick /* And null pad to a long boundary */ 164538418Smckusick for (i = 0; i < rem; i++) 164638418Smckusick *bp++ = '\0'; 164738418Smckusick nfsm_clget; 164838425Smckusick 164938418Smckusick /* Finish off the record */ 165038418Smckusick toff += dp->d_reclen; 165148050Smckusick *tl = txdr_unsigned(toff); 165238418Smckusick bp += NFSX_UNSIGNED; 165338418Smckusick } else 165452196Smckusick invalid: 165538418Smckusick toff += dp->d_reclen; 165638418Smckusick cpos += dp->d_reclen; 165752441Smckusick dp = (struct dirent *)cpos; 165838418Smckusick } 165952196Smckusick vrele(vp); 166038418Smckusick nfsm_clget; 166148050Smckusick *tl = nfs_false; 166238418Smckusick bp += NFSX_UNSIGNED; 166338418Smckusick nfsm_clget; 166440296Smckusick if (eofflag) 166548050Smckusick *tl = nfs_true; 166640296Smckusick else 166748050Smckusick *tl = nfs_false; 166838418Smckusick bp += NFSX_UNSIGNED; 166952196Smckusick if (mp != mb) { 167052196Smckusick if (bp < be) 167152196Smckusick mp->m_len = bp - mtod(mp, caddr_t); 167252196Smckusick } else 167352196Smckusick mp->m_len += bp - bpos; 167438418Smckusick FREE(rbuf, M_TEMP); 167538418Smckusick nfsm_srvdone; 167638418Smckusick } 167738418Smckusick 167838418Smckusick /* 167938418Smckusick * nfs statfs service 168038418Smckusick */ 168152196Smckusick nfsrv_statfs(nfsd, mrep, md, dpos, cred, nam, mrq) 168252196Smckusick struct nfsd *nfsd; 168338418Smckusick struct mbuf *mrep, *md; 168438418Smckusick caddr_t dpos; 168538418Smckusick struct ucred *cred; 168652196Smckusick struct mbuf *nam, **mrq; 168738418Smckusick { 168838418Smckusick register struct statfs *sf; 168938884Smacklem register struct nfsv2_statfs *sfp; 169048050Smckusick register u_long *tl; 169139494Smckusick register long t1; 169239494Smckusick caddr_t bpos; 1693*56285Smckusick int error = 0, rdonly, cache, isnq; 169439494Smckusick char *cp2; 169539753Smckusick struct mbuf *mb, *mb2, *mreq; 169638418Smckusick struct vnode *vp; 169738418Smckusick nfsv2fh_t nfh; 169838418Smckusick fhandle_t *fhp; 169938418Smckusick struct statfs statfs; 170052196Smckusick u_quad_t frev; 170138418Smckusick 170238418Smckusick fhp = &nfh.fh_generic; 1703*56285Smckusick isnq = (nfsd->nd_nqlflag != NQL_NOVAL); 170438418Smckusick nfsm_srvmtofh(fhp); 170552196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 170638418Smckusick nfsm_reply(0); 170738418Smckusick sf = &statfs; 170852196Smckusick error = VFS_STATFS(vp->v_mount, sf, nfsd->nd_procp); 170938418Smckusick vput(vp); 1710*56285Smckusick nfsm_reply(NFSX_STATFS(isnq)); 1711*56285Smckusick nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS(isnq)); 171244993Sbostic sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA); 171351940Smckusick sfp->sf_bsize = txdr_unsigned(sf->f_bsize); 171438884Smacklem sfp->sf_blocks = txdr_unsigned(sf->f_blocks); 171538884Smacklem sfp->sf_bfree = txdr_unsigned(sf->f_bfree); 171638884Smacklem sfp->sf_bavail = txdr_unsigned(sf->f_bavail); 1717*56285Smckusick if (isnq) { 1718*56285Smckusick sfp->sf_files = txdr_unsigned(sf->f_files); 1719*56285Smckusick sfp->sf_ffree = txdr_unsigned(sf->f_ffree); 1720*56285Smckusick } 172138418Smckusick nfsm_srvdone; 172238418Smckusick } 172338418Smckusick 172438418Smckusick /* 172538418Smckusick * Null operation, used by clients to ping server 172638418Smckusick */ 172739494Smckusick /* ARGSUSED */ 172852196Smckusick nfsrv_null(nfsd, mrep, md, dpos, cred, nam, mrq) 172952196Smckusick struct nfsd *nfsd; 173038418Smckusick struct mbuf *mrep, *md; 173138418Smckusick caddr_t dpos; 173238418Smckusick struct ucred *cred; 173352196Smckusick struct mbuf *nam, **mrq; 173438418Smckusick { 173539494Smckusick caddr_t bpos; 173652196Smckusick int error = VNOVAL, cache; 173739753Smckusick struct mbuf *mb, *mreq; 173852196Smckusick u_quad_t frev; 173938418Smckusick 174038418Smckusick nfsm_reply(0); 174139494Smckusick return (error); 174238418Smckusick } 174338418Smckusick 174438418Smckusick /* 174538418Smckusick * No operation, used for obsolete procedures 174638418Smckusick */ 174739494Smckusick /* ARGSUSED */ 174852196Smckusick nfsrv_noop(nfsd, mrep, md, dpos, cred, nam, mrq) 174952196Smckusick struct nfsd *nfsd; 175038418Smckusick struct mbuf *mrep, *md; 175138418Smckusick caddr_t dpos; 175238418Smckusick struct ucred *cred; 175352196Smckusick struct mbuf *nam, **mrq; 175438418Smckusick { 175539494Smckusick caddr_t bpos; 175652196Smckusick int error, cache; 175739753Smckusick struct mbuf *mb, *mreq; 175852196Smckusick u_quad_t frev; 175938418Smckusick 176052196Smckusick if (nfsd->nd_repstat) 176152196Smckusick error = nfsd->nd_repstat; 176252196Smckusick else 176352196Smckusick error = EPROCUNAVAIL; 176438418Smckusick nfsm_reply(0); 176539494Smckusick return (error); 176638418Smckusick } 176738425Smckusick 176838450Smckusick /* 176938450Smckusick * Perform access checking for vnodes obtained from file handles that would 177038450Smckusick * refer to files already opened by a Unix client. You cannot just use 177138450Smckusick * vn_writechk() and VOP_ACCESS() for two reasons. 177252196Smckusick * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case 177338450Smckusick * 2 - The owner is to be given access irrespective of mode bits so that 177438450Smckusick * processes that chmod after opening a file don't break. I don't like 177538450Smckusick * this because it opens a security hole, but since the nfs server opens 177638450Smckusick * a security hole the size of a barn door anyhow, what the heck. 177738450Smckusick */ 177852196Smckusick nfsrv_access(vp, flags, cred, rdonly, p) 177938450Smckusick register struct vnode *vp; 178038450Smckusick int flags; 178138450Smckusick register struct ucred *cred; 178252196Smckusick int rdonly; 178348050Smckusick struct proc *p; 178438450Smckusick { 178538450Smckusick struct vattr vattr; 178638450Smckusick int error; 178738450Smckusick if (flags & VWRITE) { 178852196Smckusick /* Just vn_writechk() changed to check rdonly */ 178938450Smckusick /* 179038450Smckusick * Disallow write attempts on read-only file systems; 179138450Smckusick * unless the file is a socket or a block or character 179238450Smckusick * device resident on the file system. 179338450Smckusick */ 179452196Smckusick if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { 179545059Smckusick switch (vp->v_type) { 179645059Smckusick case VREG: case VDIR: case VLNK: 179738450Smckusick return (EROFS); 179845059Smckusick } 179945059Smckusick } 180038450Smckusick /* 180138450Smckusick * If there's shared text associated with 180238450Smckusick * the inode, try to free it up once. If 180338450Smckusick * we fail, we can't allow writing. 180438450Smckusick */ 180545715Smckusick if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) 180638450Smckusick return (ETXTBSY); 180738450Smckusick } 180848050Smckusick if (error = VOP_GETATTR(vp, &vattr, cred, p)) 180945059Smckusick return (error); 181048050Smckusick if ((error = VOP_ACCESS(vp, flags, cred, p)) && 181145059Smckusick cred->cr_uid != vattr.va_uid) 181245059Smckusick return (error); 181345059Smckusick return (0); 181438450Smckusick } 1815