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*56360Smckusick * @(#)nfs_serv.c 7.60 (Berkeley) 09/30/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 /* 63*56360Smckusick * nqnfs access service 64*56360Smckusick */ 65*56360Smckusick nqnfsrv_access(nfsd, mrep, md, dpos, cred, nam, mrq) 66*56360Smckusick struct nfsd *nfsd; 67*56360Smckusick struct mbuf *mrep, *md; 68*56360Smckusick caddr_t dpos; 69*56360Smckusick struct ucred *cred; 70*56360Smckusick struct mbuf *nam, **mrq; 71*56360Smckusick { 72*56360Smckusick struct vnode *vp; 73*56360Smckusick nfsv2fh_t nfh; 74*56360Smckusick fhandle_t *fhp; 75*56360Smckusick register u_long *tl; 76*56360Smckusick register long t1; 77*56360Smckusick caddr_t bpos; 78*56360Smckusick int error = 0, rdonly, cache, mode = 0; 79*56360Smckusick char *cp2; 80*56360Smckusick struct mbuf *mb, *mb2, *mreq; 81*56360Smckusick u_quad_t frev; 82*56360Smckusick 83*56360Smckusick fhp = &nfh.fh_generic; 84*56360Smckusick nfsm_srvmtofh(fhp); 85*56360Smckusick nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED); 86*56360Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 87*56360Smckusick nfsm_reply(0); 88*56360Smckusick if (*tl++ == nfs_true) 89*56360Smckusick mode |= VREAD; 90*56360Smckusick if (*tl++ == nfs_true) 91*56360Smckusick mode |= VWRITE; 92*56360Smckusick if (*tl == nfs_true) 93*56360Smckusick mode |= VEXEC; 94*56360Smckusick error = nfsrv_access(vp, mode, cred, rdonly, nfsd->nd_procp); 95*56360Smckusick vput(vp); 96*56360Smckusick nfsm_reply(0); 97*56360Smckusick nfsm_srvdone; 98*56360Smckusick } 99*56360Smckusick 100*56360Smckusick /* 10138418Smckusick * nfs getattr service 10238418Smckusick */ 10352196Smckusick nfsrv_getattr(nfsd, mrep, md, dpos, cred, nam, mrq) 10452196Smckusick struct nfsd *nfsd; 10538418Smckusick struct mbuf *mrep, *md; 10638418Smckusick caddr_t dpos; 10738418Smckusick struct ucred *cred; 10852196Smckusick struct mbuf *nam, **mrq; 10938418Smckusick { 11038884Smacklem register struct nfsv2_fattr *fp; 11138418Smckusick struct vattr va; 11238418Smckusick register struct vattr *vap = &va; 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; 12039494Smckusick char *cp2; 12139753Smckusick struct mbuf *mb, *mb2, *mreq; 12252196Smckusick u_quad_t frev; 12338418Smckusick 12438418Smckusick fhp = &nfh.fh_generic; 12538418Smckusick nfsm_srvmtofh(fhp); 12652196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 12738418Smckusick nfsm_reply(0); 12852196Smckusick nqsrv_getl(vp, NQL_READ); 12952196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 13038418Smckusick vput(vp); 13156285Smckusick nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 13256285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 13339753Smckusick nfsm_srvfillattr; 13438418Smckusick nfsm_srvdone; 13538418Smckusick } 13638418Smckusick 13738418Smckusick /* 13838418Smckusick * nfs setattr service 13938418Smckusick */ 14052196Smckusick nfsrv_setattr(nfsd, mrep, md, dpos, cred, nam, mrq) 14152196Smckusick struct nfsd *nfsd; 14238418Smckusick struct mbuf *mrep, *md; 14338418Smckusick caddr_t dpos; 14438418Smckusick struct ucred *cred; 14552196Smckusick struct mbuf *nam, **mrq; 14638418Smckusick { 14738418Smckusick struct vattr va; 14838418Smckusick register struct vattr *vap = &va; 14938884Smacklem register struct nfsv2_sattr *sp; 15038884Smacklem register struct nfsv2_fattr *fp; 15138418Smckusick struct vnode *vp; 15238418Smckusick nfsv2fh_t nfh; 15338418Smckusick fhandle_t *fhp; 15448050Smckusick register u_long *tl; 15539494Smckusick register long t1; 15639494Smckusick caddr_t bpos; 15752196Smckusick int error = 0, rdonly, cache, duration2, cache2; 15839494Smckusick char *cp2; 15939753Smckusick struct mbuf *mb, *mb2, *mreq; 16052196Smckusick u_quad_t frev, frev2; 16138418Smckusick 16238418Smckusick fhp = &nfh.fh_generic; 16338418Smckusick nfsm_srvmtofh(fhp); 16456285Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 16552196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 16638418Smckusick nfsm_reply(0); 16752196Smckusick nqsrv_getl(vp, NQL_WRITE); 16852196Smckusick if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) 16938418Smckusick goto out; 17041361Smckusick VATTR_NULL(vap); 17138418Smckusick /* 17238418Smckusick * Nah nah nah nah na nah 17338418Smckusick * There is a bug in the Sun client that puts 0xffff in the mode 17438418Smckusick * field of sattr when it should put in 0xffffffff. The u_short 17538418Smckusick * doesn't sign extend. 17638418Smckusick * --> check the low order 2 bytes for 0xffff 17738418Smckusick */ 17838884Smacklem if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff) 17938884Smacklem vap->va_mode = nfstov_mode(sp->sa_mode); 18038884Smacklem if (sp->sa_uid != nfs_xdrneg1) 18138884Smacklem vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid); 18238884Smacklem if (sp->sa_gid != nfs_xdrneg1) 18338884Smacklem vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid); 18456285Smckusick if (nfsd->nd_nqlflag == NQL_NOVAL) { 18556285Smckusick if (sp->sa_nfssize != nfs_xdrneg1) 18656285Smckusick vap->va_size = fxdr_unsigned(u_quad_t, sp->sa_nfssize); 18756285Smckusick /* 18856285Smckusick * The usec field of sa_atime is overloaded with the va_flags field 18956285Smckusick * for 4.4BSD clients. Hopefully other clients always set both the 19056285Smckusick * sec and usec fields to -1 when not setting the atime. 19156285Smckusick */ 19256285Smckusick if (sp->sa_nfsatime.nfs_sec != nfs_xdrneg1) { 19356285Smckusick vap->va_atime.ts_sec = fxdr_unsigned(long, sp->sa_nfsatime.nfs_sec); 19456285Smckusick vap->va_atime.ts_nsec = 0; 19556285Smckusick } 19656285Smckusick if (sp->sa_nfsatime.nfs_usec != nfs_xdrneg1) 19756285Smckusick vap->va_flags = fxdr_unsigned(u_long, sp->sa_nfsatime.nfs_usec); 19856285Smckusick if (sp->sa_nfsmtime.nfs_sec != nfs_xdrneg1) 19956285Smckusick fxdr_nfstime(&sp->sa_nfsmtime, &vap->va_mtime); 20056285Smckusick } else { 20156285Smckusick fxdr_hyper(&sp->sa_nqsize, &vap->va_size); 20256285Smckusick fxdr_nqtime(&sp->sa_nqatime, &vap->va_atime); 20356285Smckusick fxdr_nqtime(&sp->sa_nqmtime, &vap->va_mtime); 20456285Smckusick vap->va_flags = fxdr_unsigned(u_long, sp->sa_nqflags); 20538425Smckusick } 20652196Smckusick if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) { 20738418Smckusick vput(vp); 20838418Smckusick nfsm_reply(0); 20938418Smckusick } 21052196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 21138418Smckusick out: 21238418Smckusick vput(vp); 21356285Smckusick nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL) + 2*NFSX_UNSIGNED); 21456285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 21539753Smckusick nfsm_srvfillattr; 21652196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 21752196Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 21852196Smckusick txdr_hyper(&frev2, tl); 21952196Smckusick } 22038418Smckusick nfsm_srvdone; 22138418Smckusick } 22238418Smckusick 22338418Smckusick /* 22438418Smckusick * nfs lookup rpc 22538418Smckusick */ 22652196Smckusick nfsrv_lookup(nfsd, mrep, md, dpos, cred, nam, mrq) 22752196Smckusick struct nfsd *nfsd; 22838418Smckusick struct mbuf *mrep, *md; 22938418Smckusick caddr_t dpos; 23038418Smckusick struct ucred *cred; 23152196Smckusick struct mbuf *nam, **mrq; 23238418Smckusick { 23338884Smacklem register struct nfsv2_fattr *fp; 23449742Smckusick struct nameidata nd; 23538418Smckusick struct vnode *vp; 23638418Smckusick nfsv2fh_t nfh; 23738418Smckusick fhandle_t *fhp; 23839494Smckusick register caddr_t cp; 23948050Smckusick register u_long *tl; 24039494Smckusick register long t1; 24139494Smckusick caddr_t bpos; 24256285Smckusick int error = 0, rdonly, cache, duration2, cache2, len; 24339494Smckusick char *cp2; 24439753Smckusick struct mbuf *mb, *mb2, *mreq; 24538418Smckusick struct vattr va, *vap = &va; 24652196Smckusick u_quad_t frev, frev2; 24738418Smckusick 24838418Smckusick fhp = &nfh.fh_generic; 24952196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 25052196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 25156285Smckusick duration2 = fxdr_unsigned(int, *tl); 25252196Smckusick } 25338418Smckusick nfsm_srvmtofh(fhp); 25438418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 25552316Sheideman nd.ni_cnd.cn_cred = cred; 25652316Sheideman nd.ni_cnd.cn_nameiop = LOOKUP; 25752316Sheideman nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART; 25852653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 25952653Smckusick nfsd->nd_procp)) 26038418Smckusick nfsm_reply(0); 26152196Smckusick nqsrv_getl(nd.ni_startdir, NQL_READ); 26252196Smckusick vrele(nd.ni_startdir); 26352653Smckusick FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 26449742Smckusick vp = nd.ni_vp; 26538418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 26641398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 26738418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 26838418Smckusick vput(vp); 26938418Smckusick nfsm_reply(0); 27038418Smckusick } 27156285Smckusick if (duration2) 27256285Smckusick (void) nqsrv_getlease(vp, &duration2, NQL_READ, nfsd, 27352196Smckusick nam, &cache2, &frev2, cred); 27452196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 27538418Smckusick vput(vp); 27656285Smckusick nfsm_reply(NFSX_FH + NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL) + 5*NFSX_UNSIGNED); 27752196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 27856285Smckusick if (duration2) { 27952196Smckusick nfsm_build(tl, u_long *, 5*NFSX_UNSIGNED); 28056285Smckusick *tl++ = txdr_unsigned(NQL_READ); 28152196Smckusick *tl++ = txdr_unsigned(cache2); 28252196Smckusick *tl++ = txdr_unsigned(duration2); 28352196Smckusick txdr_hyper(&frev2, tl); 28452196Smckusick } else { 28552196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 28652196Smckusick *tl = 0; 28752196Smckusick } 28852196Smckusick } 28938418Smckusick nfsm_srvfhtom(fhp); 29056285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 29139753Smckusick nfsm_srvfillattr; 29238418Smckusick nfsm_srvdone; 29338418Smckusick } 29438418Smckusick 29538418Smckusick /* 29638418Smckusick * nfs readlink service 29738418Smckusick */ 29852196Smckusick nfsrv_readlink(nfsd, mrep, md, dpos, cred, nam, mrq) 29952196Smckusick struct nfsd *nfsd; 30038418Smckusick struct mbuf *mrep, *md; 30138418Smckusick caddr_t dpos; 30238418Smckusick struct ucred *cred; 30352196Smckusick struct mbuf *nam, **mrq; 30438418Smckusick { 30541899Smckusick struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN]; 30638418Smckusick register struct iovec *ivp = iv; 30738418Smckusick register struct mbuf *mp; 30848050Smckusick register u_long *tl; 30939494Smckusick register long t1; 31039494Smckusick caddr_t bpos; 31152196Smckusick int error = 0, rdonly, cache, i, tlen, len; 31239494Smckusick char *cp2; 31339753Smckusick struct mbuf *mb, *mb2, *mp2, *mp3, *mreq; 31438418Smckusick struct vnode *vp; 31538418Smckusick nfsv2fh_t nfh; 31638418Smckusick fhandle_t *fhp; 31738418Smckusick struct uio io, *uiop = &io; 31852196Smckusick u_quad_t frev; 31938418Smckusick 32038418Smckusick fhp = &nfh.fh_generic; 32138418Smckusick nfsm_srvmtofh(fhp); 32238418Smckusick len = 0; 32338418Smckusick i = 0; 32438418Smckusick while (len < NFS_MAXPATHLEN) { 32538418Smckusick MGET(mp, M_WAIT, MT_DATA); 32641899Smckusick MCLGET(mp, M_WAIT); 32738418Smckusick mp->m_len = NFSMSIZ(mp); 32838418Smckusick if (len == 0) 32938418Smckusick mp3 = mp2 = mp; 33041899Smckusick else { 33138418Smckusick mp2->m_next = mp; 33241899Smckusick mp2 = mp; 33341899Smckusick } 33438418Smckusick if ((len+mp->m_len) > NFS_MAXPATHLEN) { 33538418Smckusick mp->m_len = NFS_MAXPATHLEN-len; 33638418Smckusick len = NFS_MAXPATHLEN; 33738418Smckusick } else 33838418Smckusick len += mp->m_len; 33938418Smckusick ivp->iov_base = mtod(mp, caddr_t); 34038418Smckusick ivp->iov_len = mp->m_len; 34138418Smckusick i++; 34238418Smckusick ivp++; 34338418Smckusick } 34438418Smckusick uiop->uio_iov = iv; 34538418Smckusick uiop->uio_iovcnt = i; 34638418Smckusick uiop->uio_offset = 0; 34738418Smckusick uiop->uio_resid = len; 34838418Smckusick uiop->uio_rw = UIO_READ; 34938418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 35048050Smckusick uiop->uio_procp = (struct proc *)0; 35152196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) { 35238418Smckusick m_freem(mp3); 35338418Smckusick nfsm_reply(0); 35438418Smckusick } 35538418Smckusick if (vp->v_type != VLNK) { 35638418Smckusick error = EINVAL; 35738418Smckusick goto out; 35838418Smckusick } 35952196Smckusick nqsrv_getl(vp, NQL_READ); 36038418Smckusick error = VOP_READLINK(vp, uiop, cred); 36138418Smckusick out: 36238418Smckusick vput(vp); 36338418Smckusick if (error) 36438418Smckusick m_freem(mp3); 36538418Smckusick nfsm_reply(NFSX_UNSIGNED); 36638418Smckusick if (uiop->uio_resid > 0) { 36738418Smckusick len -= uiop->uio_resid; 36838418Smckusick tlen = nfsm_rndup(len); 36938418Smckusick nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len); 37038418Smckusick } 37148050Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 37248050Smckusick *tl = txdr_unsigned(len); 37338418Smckusick mb->m_next = mp3; 37438418Smckusick nfsm_srvdone; 37538418Smckusick } 37638418Smckusick 37738418Smckusick /* 37838418Smckusick * nfs read service 37938418Smckusick */ 38052196Smckusick nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq) 38152196Smckusick struct nfsd *nfsd; 38238418Smckusick struct mbuf *mrep, *md; 38338418Smckusick caddr_t dpos; 38438418Smckusick struct ucred *cred; 38552196Smckusick struct mbuf *nam, **mrq; 38638418Smckusick { 38743350Smckusick register struct iovec *iv; 38843350Smckusick struct iovec *iv2; 38941899Smckusick register struct mbuf *m; 39038884Smacklem register struct nfsv2_fattr *fp; 39148050Smckusick register u_long *tl; 39239494Smckusick register long t1; 39339494Smckusick caddr_t bpos; 39452196Smckusick int error = 0, rdonly, cache, i, cnt, len, left, siz, tlen; 39539494Smckusick char *cp2; 39639753Smckusick struct mbuf *mb, *mb2, *mreq; 39752196Smckusick struct mbuf *m2; 39838418Smckusick struct vnode *vp; 39938418Smckusick nfsv2fh_t nfh; 40038418Smckusick fhandle_t *fhp; 40138418Smckusick struct uio io, *uiop = &io; 40238418Smckusick struct vattr va, *vap = &va; 40338418Smckusick off_t off; 40452196Smckusick u_quad_t frev; 40538418Smckusick 40638418Smckusick fhp = &nfh.fh_generic; 40738418Smckusick nfsm_srvmtofh(fhp); 40856285Smckusick if (nfsd->nd_nqlflag == NQL_NOVAL) { 40956285Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 41056285Smckusick off = (off_t)fxdr_unsigned(u_long, *tl); 41156285Smckusick } else { 41256285Smckusick nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); 41356285Smckusick fxdr_hyper(tl, &off); 41456285Smckusick } 41538418Smckusick nfsm_srvstrsiz(cnt, NFS_MAXDATA); 41652196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 41738418Smckusick nfsm_reply(0); 41852196Smckusick nqsrv_getl(vp, NQL_READ); 41952196Smckusick if (error = nfsrv_access(vp, VREAD | VEXEC, cred, rdonly, nfsd->nd_procp)) { 42038418Smckusick vput(vp); 42138418Smckusick nfsm_reply(0); 42238418Smckusick } 42352196Smckusick if (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp)) { 42438418Smckusick vput(vp); 42538418Smckusick nfsm_reply(0); 42638418Smckusick } 42752196Smckusick if (off >= vap->va_size) 42852196Smckusick cnt = 0; 42952196Smckusick else if ((off + cnt) > vap->va_size) 43052196Smckusick cnt = nfsm_rndup(vap->va_size - off); 43156285Smckusick nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)+NFSX_UNSIGNED+nfsm_rndup(cnt)); 43256285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 43352196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 43452196Smckusick len = left = cnt; 43552196Smckusick if (cnt > 0) { 43652196Smckusick /* 43752196Smckusick * Generate the mbuf list with the uio_iov ref. to it. 43852196Smckusick */ 43952196Smckusick i = 0; 44052196Smckusick m = m2 = mb; 44152196Smckusick MALLOC(iv, struct iovec *, 44252196Smckusick ((NFS_MAXDATA+MLEN-1)/MLEN) * sizeof (struct iovec), 44352196Smckusick M_TEMP, M_WAITOK); 44452196Smckusick iv2 = iv; 44552196Smckusick while (left > 0) { 44655057Spendry siz = min(M_TRAILINGSPACE(m), left); 44752196Smckusick if (siz > 0) { 44852196Smckusick m->m_len += siz; 44952196Smckusick iv->iov_base = bpos; 45052196Smckusick iv->iov_len = siz; 45152196Smckusick iv++; 45252196Smckusick i++; 45352196Smckusick left -= siz; 45452196Smckusick } 45552196Smckusick if (left > 0) { 45652196Smckusick MGET(m, M_WAIT, MT_DATA); 45752196Smckusick MCLGET(m, M_WAIT); 45852196Smckusick m->m_len = 0; 45952196Smckusick m2->m_next = m; 46052196Smckusick m2 = m; 46152196Smckusick bpos = mtod(m, caddr_t); 46252196Smckusick } 46352196Smckusick } 46452196Smckusick uiop->uio_iov = iv2; 46552196Smckusick uiop->uio_iovcnt = i; 46652196Smckusick uiop->uio_offset = off; 46752196Smckusick uiop->uio_resid = cnt; 46852196Smckusick uiop->uio_rw = UIO_READ; 46952196Smckusick uiop->uio_segflg = UIO_SYSSPACE; 47052196Smckusick error = VOP_READ(vp, uiop, IO_NODELOCKED, cred); 47152196Smckusick off = uiop->uio_offset; 47252196Smckusick FREE((caddr_t)iv2, M_TEMP); 47352196Smckusick if (error || (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp))) { 47452196Smckusick m_freem(mreq); 47552196Smckusick vput(vp); 47652196Smckusick nfsm_reply(0); 47752196Smckusick } 47852196Smckusick } else 47952196Smckusick uiop->uio_resid = 0; 48038418Smckusick vput(vp); 48139753Smckusick nfsm_srvfillattr; 48245877Smckusick len -= uiop->uio_resid; 48352196Smckusick tlen = nfsm_rndup(len); 48452196Smckusick if (cnt != tlen || tlen != len) 48552196Smckusick nfsm_adj(mb, cnt-tlen, tlen-len); 48648050Smckusick *tl = txdr_unsigned(len); 48738418Smckusick nfsm_srvdone; 48838418Smckusick } 48938418Smckusick 49038418Smckusick /* 49138418Smckusick * nfs write service 49238418Smckusick */ 49352196Smckusick nfsrv_write(nfsd, mrep, md, dpos, cred, nam, mrq) 49452196Smckusick struct nfsd *nfsd; 49552196Smckusick struct mbuf *mrep, *md; 49638418Smckusick caddr_t dpos; 49738418Smckusick struct ucred *cred; 49852196Smckusick struct mbuf *nam, **mrq; 49938418Smckusick { 50038418Smckusick register struct iovec *ivp; 50138418Smckusick register struct mbuf *mp; 50238884Smacklem register struct nfsv2_fattr *fp; 50341899Smckusick struct iovec iv[NFS_MAXIOVEC]; 50438418Smckusick struct vattr va; 50538418Smckusick register struct vattr *vap = &va; 50648050Smckusick register u_long *tl; 50739494Smckusick register long t1; 50839494Smckusick caddr_t bpos; 50952196Smckusick int error = 0, rdonly, cache, siz, len, xfer; 51056285Smckusick int ioflags = IO_SYNC | IO_NODELOCKED; 51139494Smckusick char *cp2; 51239753Smckusick struct mbuf *mb, *mb2, *mreq; 51338418Smckusick struct vnode *vp; 51438418Smckusick nfsv2fh_t nfh; 51538418Smckusick fhandle_t *fhp; 51638418Smckusick struct uio io, *uiop = &io; 51738418Smckusick off_t off; 51852196Smckusick u_quad_t frev; 51938418Smckusick 52038418Smckusick fhp = &nfh.fh_generic; 52138418Smckusick nfsm_srvmtofh(fhp); 52256285Smckusick nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED); 52356285Smckusick if (nfsd->nd_nqlflag == NQL_NOVAL) { 52456285Smckusick off = (off_t)fxdr_unsigned(u_long, *++tl); 52556285Smckusick tl += 2; 52656285Smckusick } else { 52756285Smckusick fxdr_hyper(tl, &off); 52856285Smckusick tl += 2; 52956285Smckusick if (fxdr_unsigned(u_long, *tl++)) 53056285Smckusick ioflags |= IO_APPEND; 53156285Smckusick } 53248050Smckusick len = fxdr_unsigned(long, *tl); 53338418Smckusick if (len > NFS_MAXDATA || len <= 0) { 53438418Smckusick error = EBADRPC; 53538418Smckusick nfsm_reply(0); 53638418Smckusick } 53738418Smckusick if (dpos == (mtod(md, caddr_t)+md->m_len)) { 53838418Smckusick mp = md->m_next; 53938418Smckusick if (mp == NULL) { 54038418Smckusick error = EBADRPC; 54138418Smckusick nfsm_reply(0); 54238418Smckusick } 54338418Smckusick } else { 54438418Smckusick mp = md; 54538418Smckusick siz = dpos-mtod(mp, caddr_t); 54638418Smckusick mp->m_len -= siz; 54738418Smckusick NFSMADV(mp, siz); 54838418Smckusick } 54952196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 55038418Smckusick nfsm_reply(0); 55152196Smckusick nqsrv_getl(vp, NQL_WRITE); 55252196Smckusick if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) { 55338418Smckusick vput(vp); 55438418Smckusick nfsm_reply(0); 55538418Smckusick } 55638418Smckusick uiop->uio_resid = 0; 55738418Smckusick uiop->uio_rw = UIO_WRITE; 55838418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 55948050Smckusick uiop->uio_procp = (struct proc *)0; 56038418Smckusick /* 56141899Smckusick * Do up to NFS_MAXIOVEC mbufs of write each iteration of the 56238418Smckusick * loop until done. 56338418Smckusick */ 56438418Smckusick while (len > 0 && uiop->uio_resid == 0) { 56538418Smckusick ivp = iv; 56638418Smckusick siz = 0; 56738418Smckusick uiop->uio_iov = ivp; 56838418Smckusick uiop->uio_iovcnt = 0; 56938418Smckusick uiop->uio_offset = off; 57041899Smckusick while (len > 0 && uiop->uio_iovcnt < NFS_MAXIOVEC && mp != NULL) { 57138418Smckusick ivp->iov_base = mtod(mp, caddr_t); 57238418Smckusick if (len < mp->m_len) 57338418Smckusick ivp->iov_len = xfer = len; 57438418Smckusick else 57538418Smckusick ivp->iov_len = xfer = mp->m_len; 57638418Smckusick #ifdef notdef 57738418Smckusick /* Not Yet .. */ 57838418Smckusick if (M_HASCL(mp) && (((u_long)ivp->iov_base) & CLOFSET) == 0) 57938418Smckusick ivp->iov_op = NULL; /* what should it be ?? */ 58038418Smckusick else 58138418Smckusick ivp->iov_op = NULL; 58238418Smckusick #endif 58338418Smckusick uiop->uio_iovcnt++; 58438418Smckusick ivp++; 58538418Smckusick len -= xfer; 58638418Smckusick siz += xfer; 58738418Smckusick mp = mp->m_next; 58838418Smckusick } 58938418Smckusick if (len > 0 && mp == NULL) { 59038418Smckusick error = EBADRPC; 59138418Smckusick vput(vp); 59238418Smckusick nfsm_reply(0); 59338418Smckusick } 59438418Smckusick uiop->uio_resid = siz; 59556285Smckusick if (error = VOP_WRITE(vp, uiop, ioflags, cred)) { 59638418Smckusick vput(vp); 59738418Smckusick nfsm_reply(0); 59838418Smckusick } 59939586Smckusick off = uiop->uio_offset; 60038418Smckusick } 60152196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 60238418Smckusick vput(vp); 60356285Smckusick nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 60456285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 60539753Smckusick nfsm_srvfillattr; 60652442Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 60752442Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 60852442Smckusick txdr_hyper(&vap->va_filerev, tl); 60952442Smckusick } 61038418Smckusick nfsm_srvdone; 61138418Smckusick } 61238418Smckusick 61338418Smckusick /* 61438418Smckusick * nfs create service 61538418Smckusick * now does a truncate to 0 length via. setattr if it already exists 61638418Smckusick */ 61752196Smckusick nfsrv_create(nfsd, mrep, md, dpos, cred, nam, mrq) 61852196Smckusick struct nfsd *nfsd; 61952196Smckusick struct mbuf *mrep, *md; 62038418Smckusick caddr_t dpos; 62138418Smckusick struct ucred *cred; 62252196Smckusick struct mbuf *nam, **mrq; 62338418Smckusick { 62438884Smacklem register struct nfsv2_fattr *fp; 62538418Smckusick struct vattr va; 62638418Smckusick register struct vattr *vap = &va; 62756285Smckusick register struct nfsv2_sattr *sp; 62856285Smckusick register u_long *tl; 62949742Smckusick struct nameidata nd; 63039494Smckusick register caddr_t cp; 63139494Smckusick register long t1; 63239494Smckusick caddr_t bpos; 63356285Smckusick int error = 0, rdev, cache, len, tsize; 63439494Smckusick char *cp2; 63539753Smckusick struct mbuf *mb, *mb2, *mreq; 63638418Smckusick struct vnode *vp; 63738418Smckusick nfsv2fh_t nfh; 63838418Smckusick fhandle_t *fhp; 63952196Smckusick u_quad_t frev; 64038418Smckusick 64152316Sheideman nd.ni_cnd.cn_nameiop = 0; 64238418Smckusick fhp = &nfh.fh_generic; 64338418Smckusick nfsm_srvmtofh(fhp); 64438418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 64552316Sheideman nd.ni_cnd.cn_cred = cred; 64652316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 64752316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART; 64852653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 64952653Smckusick nfsd->nd_procp)) 65038418Smckusick nfsm_reply(0); 65141361Smckusick VATTR_NULL(vap); 65256285Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 65338418Smckusick /* 65438418Smckusick * Iff doesn't exist, create it 65538418Smckusick * otherwise just truncate to 0 length 65638418Smckusick * should I set the mode too ?? 65738418Smckusick */ 65849742Smckusick if (nd.ni_vp == NULL) { 65956285Smckusick vap->va_type = IFTOVT(fxdr_unsigned(u_long, sp->sa_mode)); 66042867Smckusick if (vap->va_type == VNON) 66142867Smckusick vap->va_type = VREG; 66256285Smckusick vap->va_mode = nfstov_mode(sp->sa_mode); 66356285Smckusick if (nfsd->nd_nqlflag == NQL_NOVAL) 66456285Smckusick rdev = fxdr_unsigned(long, sp->sa_nfssize); 66556285Smckusick else 66656285Smckusick rdev = fxdr_unsigned(long, sp->sa_nqrdev); 66746988Smckusick if (vap->va_type == VREG || vap->va_type == VSOCK) { 66849742Smckusick vrele(nd.ni_startdir); 66952196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 67052234Sheideman if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) 67142242Smckusick nfsm_reply(0); 67252316Sheideman FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 67342242Smckusick } else if (vap->va_type == VCHR || vap->va_type == VBLK || 67442242Smckusick vap->va_type == VFIFO) { 67542242Smckusick if (vap->va_type == VCHR && rdev == 0xffffffff) 67642242Smckusick vap->va_type = VFIFO; 67742242Smckusick if (vap->va_type == VFIFO) { 67842242Smckusick #ifndef FIFO 67952234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 68049742Smckusick vput(nd.ni_dvp); 68142242Smckusick error = ENXIO; 68249742Smckusick goto out; 68342242Smckusick #endif /* FIFO */ 68452196Smckusick } else if (error = suser(cred, (u_short *)0)) { 68552234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 68649742Smckusick vput(nd.ni_dvp); 68749742Smckusick goto out; 68842242Smckusick } else 68942242Smckusick vap->va_rdev = (dev_t)rdev; 69052196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 69152234Sheideman if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) { 69249742Smckusick vrele(nd.ni_startdir); 69342242Smckusick nfsm_reply(0); 69449742Smckusick } 69552316Sheideman nd.ni_cnd.cn_nameiop = LOOKUP; 69652316Sheideman nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART); 69752316Sheideman nd.ni_cnd.cn_proc = nfsd->nd_procp; 69852316Sheideman nd.ni_cnd.cn_cred = nfsd->nd_procp->p_ucred; 69952316Sheideman if (error = lookup(&nd)) { 70052316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 70142242Smckusick nfsm_reply(0); 70249742Smckusick } 70352316Sheideman FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 70452316Sheideman if (nd.ni_cnd.cn_flags & ISSYMLINK) { 70549742Smckusick vrele(nd.ni_dvp); 70649742Smckusick vput(nd.ni_vp); 70752234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 70849742Smckusick error = EINVAL; 70949742Smckusick nfsm_reply(0); 71049742Smckusick } 71142242Smckusick } else { 71252234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 71349742Smckusick vput(nd.ni_dvp); 71442242Smckusick error = ENXIO; 71549742Smckusick goto out; 71642242Smckusick } 71749742Smckusick vp = nd.ni_vp; 71838418Smckusick } else { 71949742Smckusick vrele(nd.ni_startdir); 72052316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 72149742Smckusick vp = nd.ni_vp; 72249742Smckusick if (nd.ni_dvp == vp) 72349742Smckusick vrele(nd.ni_dvp); 72443359Smckusick else 72549742Smckusick vput(nd.ni_dvp); 72652234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 72756285Smckusick if (nfsd->nd_nqlflag == NQL_NOVAL) { 72856285Smckusick tsize = fxdr_unsigned(long, sp->sa_nfssize); 72956285Smckusick if (tsize != -1) 73056285Smckusick vap->va_size = (u_quad_t)tsize; 73156285Smckusick else 73256285Smckusick vap->va_size = -1; 73356285Smckusick } else 73456285Smckusick fxdr_hyper(&sp->sa_nqsize, &vap->va_size); 73556285Smckusick if (vap->va_size != -1) { 73656285Smckusick nqsrv_getl(vp, NQL_WRITE); 73756285Smckusick if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) { 73856285Smckusick vput(vp); 73956285Smckusick nfsm_reply(0); 74056285Smckusick } 74142506Smckusick } 74238418Smckusick } 74338418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 74441398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 74538418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 74638418Smckusick vput(vp); 74738418Smckusick nfsm_reply(0); 74838418Smckusick } 74952196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 75038418Smckusick vput(vp); 75156285Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 75238418Smckusick nfsm_srvfhtom(fhp); 75356285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 75439753Smckusick nfsm_srvfillattr; 75538418Smckusick return (error); 75638418Smckusick nfsmout: 75752316Sheideman if (nd.ni_cnd.cn_nameiop || nd.ni_cnd.cn_flags) 75851464Sbostic vrele(nd.ni_startdir); 75952234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 76049742Smckusick if (nd.ni_dvp == nd.ni_vp) 76149742Smckusick vrele(nd.ni_dvp); 76243359Smckusick else 76349742Smckusick vput(nd.ni_dvp); 76449742Smckusick if (nd.ni_vp) 76549742Smckusick vput(nd.ni_vp); 76638418Smckusick return (error); 76749742Smckusick 76849742Smckusick out: 76949742Smckusick vrele(nd.ni_startdir); 77052316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 77149742Smckusick nfsm_reply(0); 77238418Smckusick } 77338418Smckusick 77438418Smckusick /* 77538418Smckusick * nfs remove service 77638418Smckusick */ 77752196Smckusick nfsrv_remove(nfsd, mrep, md, dpos, cred, nam, mrq) 77852196Smckusick struct nfsd *nfsd; 77952196Smckusick struct mbuf *mrep, *md; 78038418Smckusick caddr_t dpos; 78138418Smckusick struct ucred *cred; 78252196Smckusick struct mbuf *nam, **mrq; 78338418Smckusick { 78449742Smckusick struct nameidata nd; 78548050Smckusick register u_long *tl; 78639494Smckusick register long t1; 78739494Smckusick caddr_t bpos; 78852196Smckusick int error = 0, cache, len; 78939494Smckusick char *cp2; 79039753Smckusick struct mbuf *mb, *mreq; 79138418Smckusick struct vnode *vp; 79238418Smckusick nfsv2fh_t nfh; 79338418Smckusick fhandle_t *fhp; 79452196Smckusick u_quad_t frev; 79538418Smckusick 79638418Smckusick fhp = &nfh.fh_generic; 79738418Smckusick nfsm_srvmtofh(fhp); 79838418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 79952316Sheideman nd.ni_cnd.cn_cred = cred; 80052316Sheideman nd.ni_cnd.cn_nameiop = DELETE; 80152316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 80252653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 80352653Smckusick nfsd->nd_procp)) 80438418Smckusick nfsm_reply(0); 80549742Smckusick vp = nd.ni_vp; 80638418Smckusick if (vp->v_type == VDIR && 80752196Smckusick (error = suser(cred, (u_short *)0))) 80838418Smckusick goto out; 80938418Smckusick /* 81049454Smckusick * The root of a mounted filesystem cannot be deleted. 81138418Smckusick */ 81238418Smckusick if (vp->v_flag & VROOT) { 81338418Smckusick error = EBUSY; 81438418Smckusick goto out; 81538418Smckusick } 81638418Smckusick if (vp->v_flag & VTEXT) 81745715Smckusick (void) vnode_pager_uncache(vp); 81838418Smckusick out: 81942467Smckusick if (!error) { 82052196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 82152196Smckusick nqsrv_getl(vp, NQL_WRITE); 82252234Sheideman error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 82342467Smckusick } else { 82452234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 82549742Smckusick if (nd.ni_dvp == vp) 82649742Smckusick vrele(nd.ni_dvp); 82743359Smckusick else 82849742Smckusick vput(nd.ni_dvp); 82942467Smckusick vput(vp); 83042467Smckusick } 83138418Smckusick nfsm_reply(0); 83238418Smckusick nfsm_srvdone; 83338418Smckusick } 83438418Smckusick 83538418Smckusick /* 83638418Smckusick * nfs rename service 83738418Smckusick */ 83852196Smckusick nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq) 83952196Smckusick struct nfsd *nfsd; 84052196Smckusick struct mbuf *mrep, *md; 84138418Smckusick caddr_t dpos; 84238418Smckusick struct ucred *cred; 84352196Smckusick struct mbuf *nam, **mrq; 84438418Smckusick { 84548050Smckusick register u_long *tl; 84639494Smckusick register long t1; 84739494Smckusick caddr_t bpos; 84852196Smckusick int error = 0, rdonly, cache, len, len2; 84939494Smckusick char *cp2; 85039753Smckusick struct mbuf *mb, *mreq; 85149742Smckusick struct nameidata fromnd, tond; 85238418Smckusick struct vnode *fvp, *tvp, *tdvp; 85338418Smckusick nfsv2fh_t fnfh, tnfh; 85438418Smckusick fhandle_t *ffhp, *tfhp; 85552196Smckusick u_quad_t frev; 85652196Smckusick uid_t saved_uid; 85738418Smckusick 85838418Smckusick ffhp = &fnfh.fh_generic; 85938418Smckusick tfhp = &tnfh.fh_generic; 86052316Sheideman fromnd.ni_cnd.cn_nameiop = 0; 86152316Sheideman tond.ni_cnd.cn_nameiop = 0; 86238418Smckusick nfsm_srvmtofh(ffhp); 86338418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 86438418Smckusick /* 86552196Smckusick * Remember our original uid so that we can reset cr_uid before 86652196Smckusick * the second nfs_namei() call, in case it is remapped. 86738418Smckusick */ 86852196Smckusick saved_uid = cred->cr_uid; 86952316Sheideman fromnd.ni_cnd.cn_cred = cred; 87052316Sheideman fromnd.ni_cnd.cn_nameiop = DELETE; 87152316Sheideman fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART; 87252653Smckusick if (error = nfs_namei(&fromnd, ffhp, len, nfsd->nd_slp, nam, &md, 87352653Smckusick &dpos, nfsd->nd_procp)) 87438418Smckusick nfsm_reply(0); 87549742Smckusick fvp = fromnd.ni_vp; 87638418Smckusick nfsm_srvmtofh(tfhp); 87741899Smckusick nfsm_strsiz(len2, NFS_MAXNAMLEN); 87852196Smckusick cred->cr_uid = saved_uid; 87952316Sheideman tond.ni_cnd.cn_cred = cred; 88052316Sheideman tond.ni_cnd.cn_nameiop = RENAME; 88152316Sheideman tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; 88252653Smckusick if (error = nfs_namei(&tond, tfhp, len2, nfsd->nd_slp, nam, &md, 88352653Smckusick &dpos, nfsd->nd_procp)) { 88452234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 88549742Smckusick vrele(fromnd.ni_dvp); 88642467Smckusick vrele(fvp); 88742467Smckusick goto out1; 88842467Smckusick } 88938425Smckusick tdvp = tond.ni_dvp; 89038425Smckusick tvp = tond.ni_vp; 89138418Smckusick if (tvp != NULL) { 89238418Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 89338418Smckusick error = EISDIR; 89438418Smckusick goto out; 89538418Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 89638418Smckusick error = ENOTDIR; 89738418Smckusick goto out; 89838418Smckusick } 89952196Smckusick if (tvp->v_type == VDIR && tvp->v_mountedhere) { 90052196Smckusick error = EXDEV; 90152196Smckusick goto out; 90252196Smckusick } 90338418Smckusick } 90452196Smckusick if (fvp->v_type == VDIR && fvp->v_mountedhere) { 90552196Smckusick error = EBUSY; 90652196Smckusick goto out; 90752196Smckusick } 90838418Smckusick if (fvp->v_mount != tdvp->v_mount) { 90938418Smckusick error = EXDEV; 91038418Smckusick goto out; 91138418Smckusick } 91249742Smckusick if (fvp == tdvp) 91338418Smckusick error = EINVAL; 91449742Smckusick /* 91549742Smckusick * If source is the same as the destination (that is the 91649742Smckusick * same vnode with the same name in the same directory), 91749742Smckusick * then there is nothing to do. 91849742Smckusick */ 91949742Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 92052316Sheideman fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 92152316Sheideman !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 92252316Sheideman fromnd.ni_cnd.cn_namelen)) 92349742Smckusick error = -1; 92438418Smckusick out: 92542467Smckusick if (!error) { 92652196Smckusick nqsrv_getl(fromnd.ni_dvp, NQL_WRITE); 92752196Smckusick nqsrv_getl(tdvp, NQL_WRITE); 92852196Smckusick if (tvp) 92952196Smckusick nqsrv_getl(tvp, NQL_WRITE); 93052234Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 93152234Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 93242467Smckusick } else { 93352234Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 93443359Smckusick if (tdvp == tvp) 93543359Smckusick vrele(tdvp); 93643359Smckusick else 93743359Smckusick vput(tdvp); 93842467Smckusick if (tvp) 93942467Smckusick vput(tvp); 94052234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 94149742Smckusick vrele(fromnd.ni_dvp); 94242467Smckusick vrele(fvp); 94338418Smckusick } 94446513Smckusick vrele(tond.ni_startdir); 94552316Sheideman FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 94638418Smckusick out1: 94749742Smckusick vrele(fromnd.ni_startdir); 94852316Sheideman FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 94938418Smckusick nfsm_reply(0); 95038418Smckusick return (error); 95149742Smckusick 95238418Smckusick nfsmout: 95352316Sheideman if (tond.ni_cnd.cn_nameiop || tond.ni_cnd.cn_flags) { 95449742Smckusick vrele(tond.ni_startdir); 95552316Sheideman FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 95649742Smckusick } 95752316Sheideman if (fromnd.ni_cnd.cn_nameiop || fromnd.ni_cnd.cn_flags) { 95849742Smckusick vrele(fromnd.ni_startdir); 95952316Sheideman FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 96052234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 96149742Smckusick vrele(fromnd.ni_dvp); 96249742Smckusick vrele(fvp); 96349742Smckusick } 96438418Smckusick return (error); 96538418Smckusick } 96638418Smckusick 96738418Smckusick /* 96838418Smckusick * nfs link service 96938418Smckusick */ 97052196Smckusick nfsrv_link(nfsd, mrep, md, dpos, cred, nam, mrq) 97152196Smckusick struct nfsd *nfsd; 97252196Smckusick struct mbuf *mrep, *md; 97338418Smckusick caddr_t dpos; 97438418Smckusick struct ucred *cred; 97552196Smckusick struct mbuf *nam, **mrq; 97638418Smckusick { 97749742Smckusick struct nameidata nd; 97848050Smckusick register u_long *tl; 97939494Smckusick register long t1; 98039494Smckusick caddr_t bpos; 98152196Smckusick int error = 0, rdonly, cache, len; 98239494Smckusick char *cp2; 98339753Smckusick struct mbuf *mb, *mreq; 98438418Smckusick struct vnode *vp, *xp; 98538418Smckusick nfsv2fh_t nfh, dnfh; 98638418Smckusick fhandle_t *fhp, *dfhp; 98752196Smckusick u_quad_t frev; 98838418Smckusick 98938418Smckusick fhp = &nfh.fh_generic; 99038418Smckusick dfhp = &dnfh.fh_generic; 99138418Smckusick nfsm_srvmtofh(fhp); 99238418Smckusick nfsm_srvmtofh(dfhp); 99338418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 99452196Smckusick if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 99538418Smckusick nfsm_reply(0); 99652196Smckusick if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0))) 99738418Smckusick goto out1; 99852316Sheideman nd.ni_cnd.cn_cred = cred; 99952316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 100052316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 100152653Smckusick if (error = nfs_namei(&nd, dfhp, len, nfsd->nd_slp, nam, &md, &dpos, 100252653Smckusick nfsd->nd_procp)) 100338418Smckusick goto out1; 100449742Smckusick xp = nd.ni_vp; 100538418Smckusick if (xp != NULL) { 100638418Smckusick error = EEXIST; 100738418Smckusick goto out; 100838418Smckusick } 100949742Smckusick xp = nd.ni_dvp; 101038418Smckusick if (vp->v_mount != xp->v_mount) 101138418Smckusick error = EXDEV; 101238418Smckusick out: 101342467Smckusick if (!error) { 101452196Smckusick nqsrv_getl(vp, NQL_WRITE); 101552196Smckusick nqsrv_getl(xp, NQL_WRITE); 101652933Smckusick error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 101742467Smckusick } else { 101852234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 101949742Smckusick if (nd.ni_dvp == nd.ni_vp) 102049742Smckusick vrele(nd.ni_dvp); 102143359Smckusick else 102249742Smckusick vput(nd.ni_dvp); 102349742Smckusick if (nd.ni_vp) 102449742Smckusick vrele(nd.ni_vp); 102542467Smckusick } 102638418Smckusick out1: 102738418Smckusick vrele(vp); 102838418Smckusick nfsm_reply(0); 102938418Smckusick nfsm_srvdone; 103038418Smckusick } 103138418Smckusick 103238418Smckusick /* 103338418Smckusick * nfs symbolic link service 103438418Smckusick */ 103552196Smckusick nfsrv_symlink(nfsd, mrep, md, dpos, cred, nam, mrq) 103652196Smckusick struct nfsd *nfsd; 103752196Smckusick struct mbuf *mrep, *md; 103838418Smckusick caddr_t dpos; 103938418Smckusick struct ucred *cred; 104052196Smckusick struct mbuf *nam, **mrq; 104138418Smckusick { 104238418Smckusick struct vattr va; 104349742Smckusick struct nameidata nd; 104438418Smckusick register struct vattr *vap = &va; 104548050Smckusick register u_long *tl; 104639494Smckusick register long t1; 104745285Smckusick struct nfsv2_sattr *sp; 104839494Smckusick caddr_t bpos; 104941899Smckusick struct uio io; 105041899Smckusick struct iovec iv; 105152196Smckusick int error = 0, rdonly, cache, len, len2; 105241899Smckusick char *pathcp, *cp2; 105339753Smckusick struct mbuf *mb, *mreq; 105438418Smckusick nfsv2fh_t nfh; 105538418Smckusick fhandle_t *fhp; 105652196Smckusick u_quad_t frev; 105738418Smckusick 105841899Smckusick pathcp = (char *)0; 105938418Smckusick fhp = &nfh.fh_generic; 106038418Smckusick nfsm_srvmtofh(fhp); 106138418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 106252316Sheideman nd.ni_cnd.cn_cred = cred; 106352316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 106452316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 106552653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 106652653Smckusick nfsd->nd_procp)) 106742467Smckusick goto out; 106841899Smckusick nfsm_strsiz(len2, NFS_MAXPATHLEN); 106941899Smckusick MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK); 107041899Smckusick iv.iov_base = pathcp; 107141899Smckusick iv.iov_len = len2; 107241899Smckusick io.uio_resid = len2; 107341899Smckusick io.uio_offset = 0; 107441899Smckusick io.uio_iov = &iv; 107541899Smckusick io.uio_iovcnt = 1; 107641899Smckusick io.uio_segflg = UIO_SYSSPACE; 107741899Smckusick io.uio_rw = UIO_READ; 107848050Smckusick io.uio_procp = (struct proc *)0; 107941899Smckusick nfsm_mtouio(&io, len2); 108056285Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 108141899Smckusick *(pathcp + len2) = '\0'; 108249742Smckusick if (nd.ni_vp) { 108352234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 108449742Smckusick if (nd.ni_dvp == nd.ni_vp) 108549742Smckusick vrele(nd.ni_dvp); 108643359Smckusick else 108749742Smckusick vput(nd.ni_dvp); 108849742Smckusick vrele(nd.ni_vp); 108938418Smckusick error = EEXIST; 109038418Smckusick goto out; 109138418Smckusick } 109241361Smckusick VATTR_NULL(vap); 109345285Smckusick vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode); 109452196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 109552234Sheideman error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp); 109638418Smckusick out: 109741899Smckusick if (pathcp) 109841899Smckusick FREE(pathcp, M_TEMP); 109938418Smckusick nfsm_reply(0); 110038418Smckusick return (error); 110138418Smckusick nfsmout: 110252234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 110349742Smckusick if (nd.ni_dvp == nd.ni_vp) 110449742Smckusick vrele(nd.ni_dvp); 110543359Smckusick else 110649742Smckusick vput(nd.ni_dvp); 110749742Smckusick if (nd.ni_vp) 110849742Smckusick vrele(nd.ni_vp); 110941899Smckusick if (pathcp) 111041899Smckusick FREE(pathcp, M_TEMP); 111138418Smckusick return (error); 111238418Smckusick } 111338418Smckusick 111438418Smckusick /* 111538418Smckusick * nfs mkdir service 111638418Smckusick */ 111752196Smckusick nfsrv_mkdir(nfsd, mrep, md, dpos, cred, nam, mrq) 111852196Smckusick struct nfsd *nfsd; 111952196Smckusick struct mbuf *mrep, *md; 112038418Smckusick caddr_t dpos; 112138418Smckusick struct ucred *cred; 112252196Smckusick struct mbuf *nam, **mrq; 112338418Smckusick { 112438418Smckusick struct vattr va; 112538418Smckusick register struct vattr *vap = &va; 112638884Smacklem register struct nfsv2_fattr *fp; 112749742Smckusick struct nameidata nd; 112839494Smckusick register caddr_t cp; 112948050Smckusick register u_long *tl; 113039494Smckusick register long t1; 113139494Smckusick caddr_t bpos; 113252196Smckusick int error = 0, rdonly, cache, len; 113339494Smckusick char *cp2; 113439753Smckusick struct mbuf *mb, *mb2, *mreq; 113538418Smckusick struct vnode *vp; 113638418Smckusick nfsv2fh_t nfh; 113738418Smckusick fhandle_t *fhp; 113852196Smckusick u_quad_t frev; 113938418Smckusick 114038418Smckusick fhp = &nfh.fh_generic; 114138418Smckusick nfsm_srvmtofh(fhp); 114238418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 114352316Sheideman nd.ni_cnd.cn_cred = cred; 114452316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 114552316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 114652653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 114752653Smckusick nfsd->nd_procp)) 114838418Smckusick nfsm_reply(0); 114952196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 115041361Smckusick VATTR_NULL(vap); 115138418Smckusick vap->va_type = VDIR; 115248050Smckusick vap->va_mode = nfstov_mode(*tl++); 115349742Smckusick vp = nd.ni_vp; 115438418Smckusick if (vp != NULL) { 115552234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 115649742Smckusick if (nd.ni_dvp == vp) 115749742Smckusick vrele(nd.ni_dvp); 115843359Smckusick else 115949742Smckusick vput(nd.ni_dvp); 116042467Smckusick vrele(vp); 116138418Smckusick error = EEXIST; 116238418Smckusick nfsm_reply(0); 116338418Smckusick } 116452196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 116552234Sheideman if (error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) 116638418Smckusick nfsm_reply(0); 116749742Smckusick vp = nd.ni_vp; 116838418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 116941398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 117038418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 117138418Smckusick vput(vp); 117238418Smckusick nfsm_reply(0); 117338418Smckusick } 117452196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 117538418Smckusick vput(vp); 117656285Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 117738418Smckusick nfsm_srvfhtom(fhp); 117856285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 117939753Smckusick nfsm_srvfillattr; 118038418Smckusick return (error); 118138418Smckusick nfsmout: 118252234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 118349742Smckusick if (nd.ni_dvp == nd.ni_vp) 118449742Smckusick vrele(nd.ni_dvp); 118543359Smckusick else 118649742Smckusick vput(nd.ni_dvp); 118749742Smckusick if (nd.ni_vp) 118849742Smckusick vrele(nd.ni_vp); 118938418Smckusick return (error); 119038418Smckusick } 119138418Smckusick 119238418Smckusick /* 119338418Smckusick * nfs rmdir service 119438418Smckusick */ 119552196Smckusick nfsrv_rmdir(nfsd, mrep, md, dpos, cred, nam, mrq) 119652196Smckusick struct nfsd *nfsd; 119752196Smckusick struct mbuf *mrep, *md; 119838418Smckusick caddr_t dpos; 119938418Smckusick struct ucred *cred; 120052196Smckusick struct mbuf *nam, **mrq; 120138418Smckusick { 120248050Smckusick register u_long *tl; 120339494Smckusick register long t1; 120439494Smckusick caddr_t bpos; 120552196Smckusick int error = 0, rdonly, cache, len; 120639494Smckusick char *cp2; 120739753Smckusick struct mbuf *mb, *mreq; 120838418Smckusick struct vnode *vp; 120938418Smckusick nfsv2fh_t nfh; 121038418Smckusick fhandle_t *fhp; 121149742Smckusick struct nameidata nd; 121252196Smckusick u_quad_t frev; 121338418Smckusick 121438418Smckusick fhp = &nfh.fh_generic; 121538418Smckusick nfsm_srvmtofh(fhp); 121638418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 121752316Sheideman nd.ni_cnd.cn_cred = cred; 121852316Sheideman nd.ni_cnd.cn_nameiop = DELETE; 121952316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 122052653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 122152653Smckusick nfsd->nd_procp)) 122238418Smckusick nfsm_reply(0); 122349742Smckusick vp = nd.ni_vp; 122438418Smckusick if (vp->v_type != VDIR) { 122538418Smckusick error = ENOTDIR; 122638418Smckusick goto out; 122738418Smckusick } 122838418Smckusick /* 122938418Smckusick * No rmdir "." please. 123038418Smckusick */ 123149742Smckusick if (nd.ni_dvp == vp) { 123238418Smckusick error = EINVAL; 123338418Smckusick goto out; 123438418Smckusick } 123538418Smckusick /* 123649454Smckusick * The root of a mounted filesystem cannot be deleted. 123738418Smckusick */ 123838418Smckusick if (vp->v_flag & VROOT) 123938418Smckusick error = EBUSY; 124038418Smckusick out: 124142467Smckusick if (!error) { 124252196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 124352196Smckusick nqsrv_getl(vp, NQL_WRITE); 124452234Sheideman error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 124542467Smckusick } else { 124652234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 124749742Smckusick if (nd.ni_dvp == nd.ni_vp) 124849742Smckusick vrele(nd.ni_dvp); 124943359Smckusick else 125049742Smckusick vput(nd.ni_dvp); 125142467Smckusick vput(vp); 125242467Smckusick } 125338418Smckusick nfsm_reply(0); 125438418Smckusick nfsm_srvdone; 125538418Smckusick } 125638418Smckusick 125738418Smckusick /* 125838418Smckusick * nfs readdir service 125938418Smckusick * - mallocs what it thinks is enough to read 126048050Smckusick * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR 126138418Smckusick * - calls VOP_READDIR() 126240115Smckusick * - loops around building the reply 126338425Smckusick * if the output generated exceeds count break out of loop 126438425Smckusick * The nfsm_clget macro is used here so that the reply will be packed 126538425Smckusick * tightly in mbuf clusters. 126638418Smckusick * - it only knows that it has encountered eof when the VOP_READDIR() 126738425Smckusick * reads nothing 126838418Smckusick * - as such one readdir rpc will return eof false although you are there 126938425Smckusick * and then the next will return eof 127052441Smckusick * - it trims out records with d_fileno == 0 127138425Smckusick * this doesn't matter for Unix clients, but they might confuse clients 127238425Smckusick * for other os'. 127338418Smckusick * NB: It is tempting to set eof to true if the VOP_READDIR() reads less 127438425Smckusick * than requested, but this may not apply to all filesystems. For 127538425Smckusick * example, client NFS does not { although it is never remote mounted 127638425Smckusick * anyhow } 127752196Smckusick * The alternate call nqnfsrv_readdirlook() does lookups as well. 127838418Smckusick * PS: The NFS protocol spec. does not clarify what the "count" byte 127938425Smckusick * argument is a count of.. just name strings and file id's or the 128038425Smckusick * entire reply rpc or ... 128138425Smckusick * I tried just file name and id sizes and it confused the Sun client, 128238425Smckusick * so I am using the full rpc size now. The "paranoia.." comment refers 128338425Smckusick * to including the status longwords that are not a part of the dir. 128438425Smckusick * "entry" structures, but are in the rpc. 128538418Smckusick */ 128652196Smckusick struct flrep { 128752196Smckusick u_long fl_cachable; 128852196Smckusick u_long fl_duration; 128955528Smckusick u_long fl_frev[2]; 129052196Smckusick nfsv2fh_t fl_nfh; 129156285Smckusick u_long fl_fattr[NFSX_NQFATTR / sizeof (u_long)]; 129252196Smckusick }; 129352196Smckusick 129452196Smckusick nfsrv_readdir(nfsd, mrep, md, dpos, cred, nam, mrq) 129552196Smckusick struct nfsd *nfsd; 129638418Smckusick struct mbuf *mrep, *md; 129738418Smckusick caddr_t dpos; 129838418Smckusick struct ucred *cred; 129952196Smckusick struct mbuf *nam, **mrq; 130038418Smckusick { 130138418Smckusick register char *bp, *be; 130238418Smckusick register struct mbuf *mp; 130352441Smckusick register struct dirent *dp; 130439494Smckusick register caddr_t cp; 130548050Smckusick register u_long *tl; 130639494Smckusick register long t1; 130739494Smckusick caddr_t bpos; 130852196Smckusick struct mbuf *mb, *mb2, *mreq, *mp2; 130952196Smckusick char *cpos, *cend, *cp2, *rbuf; 131038418Smckusick struct vnode *vp; 131138418Smckusick nfsv2fh_t nfh; 131238418Smckusick fhandle_t *fhp; 131338418Smckusick struct uio io; 131438418Smckusick struct iovec iv; 131552196Smckusick struct vattr va; 131652196Smckusick int len, nlen, rem, xfer, tsiz, i, error = 0; 131752196Smckusick int siz, cnt, fullsiz, eofflag, rdonly, cache; 131852196Smckusick u_quad_t frev; 131956285Smckusick u_long on, off, toff; 132038418Smckusick 132138418Smckusick fhp = &nfh.fh_generic; 132238418Smckusick nfsm_srvmtofh(fhp); 132352196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 132456285Smckusick toff = fxdr_unsigned(u_long, *tl++); 132548050Smckusick off = (toff & ~(NFS_DIRBLKSIZ-1)); 132648050Smckusick on = (toff & (NFS_DIRBLKSIZ-1)); 132748050Smckusick cnt = fxdr_unsigned(int, *tl); 132848050Smckusick siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); 132941899Smckusick if (cnt > NFS_MAXREADDIR) 133041899Smckusick siz = NFS_MAXREADDIR; 133138418Smckusick fullsiz = siz; 133252196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 133338418Smckusick nfsm_reply(0); 133452196Smckusick nqsrv_getl(vp, NQL_READ); 133552196Smckusick if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { 133638418Smckusick vput(vp); 133738418Smckusick nfsm_reply(0); 133838418Smckusick } 133938418Smckusick VOP_UNLOCK(vp); 134038418Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 134138418Smckusick again: 134238418Smckusick iv.iov_base = rbuf; 134338418Smckusick iv.iov_len = fullsiz; 134438418Smckusick io.uio_iov = &iv; 134538418Smckusick io.uio_iovcnt = 1; 134656285Smckusick io.uio_offset = (off_t)off; 134738418Smckusick io.uio_resid = fullsiz; 134838418Smckusick io.uio_segflg = UIO_SYSSPACE; 134938418Smckusick io.uio_rw = UIO_READ; 135048050Smckusick io.uio_procp = (struct proc *)0; 135154446Smckusick error = VOP_READDIR(vp, &io, cred); 135256285Smckusick off = (off_t)io.uio_offset; 135338418Smckusick if (error) { 135438418Smckusick vrele(vp); 135538418Smckusick free((caddr_t)rbuf, M_TEMP); 135638418Smckusick nfsm_reply(0); 135738418Smckusick } 135854446Smckusick if (io.uio_resid < fullsiz) 135954446Smckusick eofflag = 0; 136054446Smckusick else 136154446Smckusick eofflag = 1; 136238418Smckusick if (io.uio_resid) { 136338418Smckusick siz -= io.uio_resid; 136438418Smckusick 136538418Smckusick /* 136638418Smckusick * If nothing read, return eof 136738418Smckusick * rpc reply 136838418Smckusick */ 136938418Smckusick if (siz == 0) { 137038418Smckusick vrele(vp); 137138418Smckusick nfsm_reply(2*NFSX_UNSIGNED); 137248050Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 137348050Smckusick *tl++ = nfs_false; 137448050Smckusick *tl = nfs_true; 137538418Smckusick FREE((caddr_t)rbuf, M_TEMP); 137638418Smckusick return (0); 137738418Smckusick } 137838418Smckusick } 137940115Smckusick 138038418Smckusick /* 138138418Smckusick * Check for degenerate cases of nothing useful read. 138240115Smckusick * If so go try again 138338418Smckusick */ 138440115Smckusick cpos = rbuf + on; 138540115Smckusick cend = rbuf + siz; 138652441Smckusick dp = (struct dirent *)cpos; 138752441Smckusick while (cpos < cend && dp->d_fileno == 0) { 138840115Smckusick cpos += dp->d_reclen; 138952441Smckusick dp = (struct dirent *)cpos; 139040115Smckusick } 139140115Smckusick if (cpos >= cend) { 139238418Smckusick toff = off; 139338418Smckusick siz = fullsiz; 139438418Smckusick on = 0; 139538418Smckusick goto again; 139638418Smckusick } 139740115Smckusick 139840115Smckusick cpos = rbuf + on; 139940115Smckusick cend = rbuf + siz; 140052441Smckusick dp = (struct dirent *)cpos; 140152196Smckusick len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 140252196Smckusick nfsm_reply(siz); 140352196Smckusick mp = mp2 = mb; 140452196Smckusick bp = bpos; 140552196Smckusick be = bp + M_TRAILINGSPACE(mp); 140652196Smckusick 140752196Smckusick /* Loop through the records and build reply */ 140852196Smckusick while (cpos < cend) { 140952441Smckusick if (dp->d_fileno != 0) { 141052196Smckusick nlen = dp->d_namlen; 141152196Smckusick rem = nfsm_rndup(nlen)-nlen; 141252196Smckusick len += (4*NFSX_UNSIGNED + nlen + rem); 141352196Smckusick if (len > cnt) { 141452196Smckusick eofflag = 0; 141552196Smckusick break; 141652196Smckusick } 141752441Smckusick /* 141852441Smckusick * Build the directory record xdr from 141952441Smckusick * the dirent entry. 142052441Smckusick */ 142152196Smckusick nfsm_clget; 142252196Smckusick *tl = nfs_true; 142352196Smckusick bp += NFSX_UNSIGNED; 142452196Smckusick nfsm_clget; 142552441Smckusick *tl = txdr_unsigned(dp->d_fileno); 142652196Smckusick bp += NFSX_UNSIGNED; 142752196Smckusick nfsm_clget; 142852196Smckusick *tl = txdr_unsigned(nlen); 142952196Smckusick bp += NFSX_UNSIGNED; 143052196Smckusick 143152196Smckusick /* And loop around copying the name */ 143252196Smckusick xfer = nlen; 143352196Smckusick cp = dp->d_name; 143452196Smckusick while (xfer > 0) { 143552196Smckusick nfsm_clget; 143652196Smckusick if ((bp+xfer) > be) 143752196Smckusick tsiz = be-bp; 143852196Smckusick else 143952196Smckusick tsiz = xfer; 144052196Smckusick bcopy(cp, bp, tsiz); 144152196Smckusick bp += tsiz; 144252196Smckusick xfer -= tsiz; 144352196Smckusick if (xfer > 0) 144452196Smckusick cp += tsiz; 144552196Smckusick } 144652196Smckusick /* And null pad to a long boundary */ 144752196Smckusick for (i = 0; i < rem; i++) 144852196Smckusick *bp++ = '\0'; 144952196Smckusick nfsm_clget; 145052196Smckusick 145152196Smckusick /* Finish off the record */ 145252196Smckusick toff += dp->d_reclen; 145352196Smckusick *tl = txdr_unsigned(toff); 145452196Smckusick bp += NFSX_UNSIGNED; 145552196Smckusick } else 145652196Smckusick toff += dp->d_reclen; 145752196Smckusick cpos += dp->d_reclen; 145852441Smckusick dp = (struct dirent *)cpos; 145952196Smckusick } 146038418Smckusick vrele(vp); 146152196Smckusick nfsm_clget; 146252196Smckusick *tl = nfs_false; 146352196Smckusick bp += NFSX_UNSIGNED; 146452196Smckusick nfsm_clget; 146552196Smckusick if (eofflag) 146652196Smckusick *tl = nfs_true; 146752196Smckusick else 146852196Smckusick *tl = nfs_false; 146952196Smckusick bp += NFSX_UNSIGNED; 147052196Smckusick if (mp != mb) { 147152196Smckusick if (bp < be) 147252196Smckusick mp->m_len = bp - mtod(mp, caddr_t); 147352196Smckusick } else 147452196Smckusick mp->m_len += bp - bpos; 147552196Smckusick FREE(rbuf, M_TEMP); 147652196Smckusick nfsm_srvdone; 147752196Smckusick } 147852196Smckusick 147952196Smckusick nqnfsrv_readdirlook(nfsd, mrep, md, dpos, cred, nam, mrq) 148052196Smckusick struct nfsd *nfsd; 148152196Smckusick struct mbuf *mrep, *md; 148252196Smckusick caddr_t dpos; 148352196Smckusick struct ucred *cred; 148452196Smckusick struct mbuf *nam, **mrq; 148552196Smckusick { 148652196Smckusick register char *bp, *be; 148752196Smckusick register struct mbuf *mp; 148852441Smckusick register struct dirent *dp; 148952196Smckusick register caddr_t cp; 149052196Smckusick register u_long *tl; 149152196Smckusick register long t1; 149252196Smckusick caddr_t bpos; 149352196Smckusick struct mbuf *mb, *mb2, *mreq, *mp2; 149452196Smckusick char *cpos, *cend, *cp2, *rbuf; 149552196Smckusick struct vnode *vp, *nvp; 149652196Smckusick struct flrep fl; 149752196Smckusick nfsv2fh_t nfh; 149852196Smckusick fhandle_t *fhp; 149952196Smckusick struct uio io; 150052196Smckusick struct iovec iv; 150152196Smckusick struct vattr va, *vap = &va; 150252196Smckusick struct nfsv2_fattr *fp; 150352196Smckusick int len, nlen, rem, xfer, tsiz, i, error = 0, duration2, cache2; 150452196Smckusick int siz, cnt, fullsiz, eofflag, rdonly, cache; 150552196Smckusick u_quad_t frev, frev2; 150656285Smckusick u_long on, off, toff; 150752196Smckusick 150852196Smckusick fhp = &nfh.fh_generic; 150952196Smckusick nfsm_srvmtofh(fhp); 151052196Smckusick nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED); 151156285Smckusick toff = fxdr_unsigned(u_long, *tl++); 151252196Smckusick off = (toff & ~(NFS_DIRBLKSIZ-1)); 151352196Smckusick on = (toff & (NFS_DIRBLKSIZ-1)); 151452196Smckusick cnt = fxdr_unsigned(int, *tl++); 151552196Smckusick duration2 = fxdr_unsigned(int, *tl); 151652196Smckusick siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); 151752196Smckusick if (cnt > NFS_MAXREADDIR) 151852196Smckusick siz = NFS_MAXREADDIR; 151952196Smckusick fullsiz = siz; 152052196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 152152196Smckusick nfsm_reply(0); 152252196Smckusick nqsrv_getl(vp, NQL_READ); 152352196Smckusick if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { 152452196Smckusick vput(vp); 152552196Smckusick nfsm_reply(0); 152652196Smckusick } 152752196Smckusick VOP_UNLOCK(vp); 152852196Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 152952196Smckusick again: 153052196Smckusick iv.iov_base = rbuf; 153152196Smckusick iv.iov_len = fullsiz; 153252196Smckusick io.uio_iov = &iv; 153352196Smckusick io.uio_iovcnt = 1; 153456285Smckusick io.uio_offset = (off_t)off; 153552196Smckusick io.uio_resid = fullsiz; 153652196Smckusick io.uio_segflg = UIO_SYSSPACE; 153752196Smckusick io.uio_rw = UIO_READ; 153852196Smckusick io.uio_procp = (struct proc *)0; 153954446Smckusick error = VOP_READDIR(vp, &io, cred); 154056285Smckusick off = (u_long)io.uio_offset; 154152196Smckusick if (error) { 154252196Smckusick vrele(vp); 154352196Smckusick free((caddr_t)rbuf, M_TEMP); 154452196Smckusick nfsm_reply(0); 154552196Smckusick } 154654446Smckusick if (io.uio_resid < fullsiz) 154754446Smckusick eofflag = 0; 154854446Smckusick else 154954446Smckusick eofflag = 1; 155052196Smckusick if (io.uio_resid) { 155152196Smckusick siz -= io.uio_resid; 155252196Smckusick 155352196Smckusick /* 155452196Smckusick * If nothing read, return eof 155552196Smckusick * rpc reply 155652196Smckusick */ 155752196Smckusick if (siz == 0) { 155852196Smckusick vrele(vp); 155956285Smckusick nfsm_reply(2 * NFSX_UNSIGNED); 156056285Smckusick nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); 156152196Smckusick *tl++ = nfs_false; 156252196Smckusick *tl = nfs_true; 156352196Smckusick FREE((caddr_t)rbuf, M_TEMP); 156452196Smckusick return (0); 156552196Smckusick } 156652196Smckusick } 156752196Smckusick 156852196Smckusick /* 156952196Smckusick * Check for degenerate cases of nothing useful read. 157052196Smckusick * If so go try again 157152196Smckusick */ 157252196Smckusick cpos = rbuf + on; 157352196Smckusick cend = rbuf + siz; 157452441Smckusick dp = (struct dirent *)cpos; 157552441Smckusick while (cpos < cend && dp->d_fileno == 0) { 157652196Smckusick cpos += dp->d_reclen; 157752441Smckusick dp = (struct dirent *)cpos; 157852196Smckusick } 157952196Smckusick if (cpos >= cend) { 158052196Smckusick toff = off; 158152196Smckusick siz = fullsiz; 158252196Smckusick on = 0; 158352196Smckusick goto again; 158452196Smckusick } 158552196Smckusick 158652196Smckusick cpos = rbuf + on; 158752196Smckusick cend = rbuf + siz; 158852441Smckusick dp = (struct dirent *)cpos; 158956285Smckusick len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 159038418Smckusick nfsm_reply(siz); 159152196Smckusick mp = mp2 = mb; 159252196Smckusick bp = bpos; 159352196Smckusick be = bp + M_TRAILINGSPACE(mp); 159438418Smckusick 159538418Smckusick /* Loop through the records and build reply */ 159638418Smckusick while (cpos < cend) { 159752441Smckusick if (dp->d_fileno != 0) { 159838418Smckusick nlen = dp->d_namlen; 159938418Smckusick rem = nfsm_rndup(nlen)-nlen; 160038425Smckusick 160138418Smckusick /* 160252196Smckusick * For readdir_and_lookup get the vnode using 160352196Smckusick * the file number. 160438418Smckusick */ 160554665Smckusick if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp)) 160652196Smckusick goto invalid; 160755655Smckusick bzero((caddr_t)&fl.fl_nfh, sizeof (nfsv2fh_t)); 160855655Smckusick fl.fl_nfh.fh_generic.fh_fsid = 160955655Smckusick nvp->v_mount->mnt_stat.f_fsid; 161055655Smckusick if (VFS_VPTOFH(nvp, &fl.fl_nfh.fh_generic.fh_fid)) { 161155655Smckusick vput(nvp); 161255655Smckusick goto invalid; 161355655Smckusick } 161456285Smckusick if (duration2) { 161556285Smckusick (void) nqsrv_getlease(nvp, &duration2, NQL_READ, 161656285Smckusick nfsd, nam, &cache2, &frev2, cred); 161756285Smckusick fl.fl_duration = txdr_unsigned(duration2); 161856285Smckusick fl.fl_cachable = txdr_unsigned(cache2); 161956285Smckusick txdr_hyper(&frev2, fl.fl_frev); 162056285Smckusick } else 162156285Smckusick fl.fl_duration = 0; 162252196Smckusick if (VOP_GETATTR(nvp, vap, cred, nfsd->nd_procp)) { 162352196Smckusick vput(nvp); 162452196Smckusick goto invalid; 162552196Smckusick } 162652196Smckusick vput(nvp); 162756285Smckusick fp = (struct nfsv2_fattr *)&fl.fl_fattr; 162852196Smckusick nfsm_srvfillattr; 162952196Smckusick len += (4*NFSX_UNSIGNED + nlen + rem + NFSX_FH 163056285Smckusick + NFSX_NQFATTR); 163141899Smckusick if (len > cnt) { 163241899Smckusick eofflag = 0; 163338418Smckusick break; 163441899Smckusick } 163552441Smckusick /* 163652441Smckusick * Build the directory record xdr from 163752441Smckusick * the dirent entry. 163852441Smckusick */ 163938418Smckusick nfsm_clget; 164048050Smckusick *tl = nfs_true; 164138418Smckusick bp += NFSX_UNSIGNED; 164252196Smckusick 164352196Smckusick /* 164452196Smckusick * For readdir_and_lookup copy the stuff out. 164552196Smckusick */ 164652196Smckusick xfer = sizeof (struct flrep); 164752196Smckusick cp = (caddr_t)&fl; 164852196Smckusick while (xfer > 0) { 164952196Smckusick nfsm_clget; 165052196Smckusick if ((bp+xfer) > be) 165152196Smckusick tsiz = be-bp; 165252196Smckusick else 165352196Smckusick tsiz = xfer; 165452196Smckusick bcopy(cp, bp, tsiz); 165552196Smckusick bp += tsiz; 165652196Smckusick xfer -= tsiz; 165752196Smckusick if (xfer > 0) 165852196Smckusick cp += tsiz; 165952196Smckusick } 166038418Smckusick nfsm_clget; 166152441Smckusick *tl = txdr_unsigned(dp->d_fileno); 166238418Smckusick bp += NFSX_UNSIGNED; 166338418Smckusick nfsm_clget; 166448050Smckusick *tl = txdr_unsigned(nlen); 166538418Smckusick bp += NFSX_UNSIGNED; 166638425Smckusick 166752196Smckusick /* And loop around copying the name */ 166838418Smckusick xfer = nlen; 166938418Smckusick cp = dp->d_name; 167038418Smckusick while (xfer > 0) { 167138418Smckusick nfsm_clget; 167238418Smckusick if ((bp+xfer) > be) 167338418Smckusick tsiz = be-bp; 167438418Smckusick else 167538418Smckusick tsiz = xfer; 167638418Smckusick bcopy(cp, bp, tsiz); 167738418Smckusick bp += tsiz; 167838418Smckusick xfer -= tsiz; 167938418Smckusick if (xfer > 0) 168038418Smckusick cp += tsiz; 168138418Smckusick } 168238418Smckusick /* And null pad to a long boundary */ 168338418Smckusick for (i = 0; i < rem; i++) 168438418Smckusick *bp++ = '\0'; 168538418Smckusick nfsm_clget; 168638425Smckusick 168738418Smckusick /* Finish off the record */ 168838418Smckusick toff += dp->d_reclen; 168948050Smckusick *tl = txdr_unsigned(toff); 169038418Smckusick bp += NFSX_UNSIGNED; 169138418Smckusick } else 169252196Smckusick invalid: 169338418Smckusick toff += dp->d_reclen; 169438418Smckusick cpos += dp->d_reclen; 169552441Smckusick dp = (struct dirent *)cpos; 169638418Smckusick } 169752196Smckusick vrele(vp); 169838418Smckusick nfsm_clget; 169948050Smckusick *tl = nfs_false; 170038418Smckusick bp += NFSX_UNSIGNED; 170138418Smckusick nfsm_clget; 170240296Smckusick if (eofflag) 170348050Smckusick *tl = nfs_true; 170440296Smckusick else 170548050Smckusick *tl = nfs_false; 170638418Smckusick bp += NFSX_UNSIGNED; 170752196Smckusick if (mp != mb) { 170852196Smckusick if (bp < be) 170952196Smckusick mp->m_len = bp - mtod(mp, caddr_t); 171052196Smckusick } else 171152196Smckusick mp->m_len += bp - bpos; 171238418Smckusick FREE(rbuf, M_TEMP); 171338418Smckusick nfsm_srvdone; 171438418Smckusick } 171538418Smckusick 171638418Smckusick /* 171738418Smckusick * nfs statfs service 171838418Smckusick */ 171952196Smckusick nfsrv_statfs(nfsd, mrep, md, dpos, cred, nam, mrq) 172052196Smckusick struct nfsd *nfsd; 172138418Smckusick struct mbuf *mrep, *md; 172238418Smckusick caddr_t dpos; 172338418Smckusick struct ucred *cred; 172452196Smckusick struct mbuf *nam, **mrq; 172538418Smckusick { 172638418Smckusick register struct statfs *sf; 172738884Smacklem register struct nfsv2_statfs *sfp; 172848050Smckusick register u_long *tl; 172939494Smckusick register long t1; 173039494Smckusick caddr_t bpos; 173156285Smckusick int error = 0, rdonly, cache, isnq; 173239494Smckusick char *cp2; 173339753Smckusick struct mbuf *mb, *mb2, *mreq; 173438418Smckusick struct vnode *vp; 173538418Smckusick nfsv2fh_t nfh; 173638418Smckusick fhandle_t *fhp; 173738418Smckusick struct statfs statfs; 173852196Smckusick u_quad_t frev; 173938418Smckusick 174038418Smckusick fhp = &nfh.fh_generic; 174156285Smckusick isnq = (nfsd->nd_nqlflag != NQL_NOVAL); 174238418Smckusick nfsm_srvmtofh(fhp); 174352196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 174438418Smckusick nfsm_reply(0); 174538418Smckusick sf = &statfs; 174652196Smckusick error = VFS_STATFS(vp->v_mount, sf, nfsd->nd_procp); 174738418Smckusick vput(vp); 174856285Smckusick nfsm_reply(NFSX_STATFS(isnq)); 174956285Smckusick nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS(isnq)); 175044993Sbostic sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA); 175151940Smckusick sfp->sf_bsize = txdr_unsigned(sf->f_bsize); 175238884Smacklem sfp->sf_blocks = txdr_unsigned(sf->f_blocks); 175338884Smacklem sfp->sf_bfree = txdr_unsigned(sf->f_bfree); 175438884Smacklem sfp->sf_bavail = txdr_unsigned(sf->f_bavail); 175556285Smckusick if (isnq) { 175656285Smckusick sfp->sf_files = txdr_unsigned(sf->f_files); 175756285Smckusick sfp->sf_ffree = txdr_unsigned(sf->f_ffree); 175856285Smckusick } 175938418Smckusick nfsm_srvdone; 176038418Smckusick } 176138418Smckusick 176238418Smckusick /* 176338418Smckusick * Null operation, used by clients to ping server 176438418Smckusick */ 176539494Smckusick /* ARGSUSED */ 176652196Smckusick nfsrv_null(nfsd, mrep, md, dpos, cred, nam, mrq) 176752196Smckusick struct nfsd *nfsd; 176838418Smckusick struct mbuf *mrep, *md; 176938418Smckusick caddr_t dpos; 177038418Smckusick struct ucred *cred; 177152196Smckusick struct mbuf *nam, **mrq; 177238418Smckusick { 177339494Smckusick caddr_t bpos; 177452196Smckusick int error = VNOVAL, cache; 177539753Smckusick struct mbuf *mb, *mreq; 177652196Smckusick u_quad_t frev; 177738418Smckusick 177838418Smckusick nfsm_reply(0); 177939494Smckusick return (error); 178038418Smckusick } 178138418Smckusick 178238418Smckusick /* 178338418Smckusick * No operation, used for obsolete procedures 178438418Smckusick */ 178539494Smckusick /* ARGSUSED */ 178652196Smckusick nfsrv_noop(nfsd, mrep, md, dpos, cred, nam, mrq) 178752196Smckusick struct nfsd *nfsd; 178838418Smckusick struct mbuf *mrep, *md; 178938418Smckusick caddr_t dpos; 179038418Smckusick struct ucred *cred; 179152196Smckusick struct mbuf *nam, **mrq; 179238418Smckusick { 179339494Smckusick caddr_t bpos; 179452196Smckusick int error, cache; 179539753Smckusick struct mbuf *mb, *mreq; 179652196Smckusick u_quad_t frev; 179738418Smckusick 179852196Smckusick if (nfsd->nd_repstat) 179952196Smckusick error = nfsd->nd_repstat; 180052196Smckusick else 180152196Smckusick error = EPROCUNAVAIL; 180238418Smckusick nfsm_reply(0); 180339494Smckusick return (error); 180438418Smckusick } 180538425Smckusick 180638450Smckusick /* 180738450Smckusick * Perform access checking for vnodes obtained from file handles that would 180838450Smckusick * refer to files already opened by a Unix client. You cannot just use 180938450Smckusick * vn_writechk() and VOP_ACCESS() for two reasons. 181052196Smckusick * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case 181138450Smckusick * 2 - The owner is to be given access irrespective of mode bits so that 181238450Smckusick * processes that chmod after opening a file don't break. I don't like 181338450Smckusick * this because it opens a security hole, but since the nfs server opens 181438450Smckusick * a security hole the size of a barn door anyhow, what the heck. 181538450Smckusick */ 181652196Smckusick nfsrv_access(vp, flags, cred, rdonly, p) 181738450Smckusick register struct vnode *vp; 181838450Smckusick int flags; 181938450Smckusick register struct ucred *cred; 182052196Smckusick int rdonly; 182148050Smckusick struct proc *p; 182238450Smckusick { 182338450Smckusick struct vattr vattr; 182438450Smckusick int error; 182538450Smckusick if (flags & VWRITE) { 182652196Smckusick /* Just vn_writechk() changed to check rdonly */ 182738450Smckusick /* 182838450Smckusick * Disallow write attempts on read-only file systems; 182938450Smckusick * unless the file is a socket or a block or character 183038450Smckusick * device resident on the file system. 183138450Smckusick */ 183252196Smckusick if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { 183345059Smckusick switch (vp->v_type) { 183445059Smckusick case VREG: case VDIR: case VLNK: 183538450Smckusick return (EROFS); 183645059Smckusick } 183745059Smckusick } 183838450Smckusick /* 183938450Smckusick * If there's shared text associated with 184038450Smckusick * the inode, try to free it up once. If 184138450Smckusick * we fail, we can't allow writing. 184238450Smckusick */ 184345715Smckusick if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) 184438450Smckusick return (ETXTBSY); 184538450Smckusick } 184648050Smckusick if (error = VOP_GETATTR(vp, &vattr, cred, p)) 184745059Smckusick return (error); 184848050Smckusick if ((error = VOP_ACCESS(vp, flags, cred, p)) && 184945059Smckusick cred->cr_uid != vattr.va_uid) 185045059Smckusick return (error); 185145059Smckusick return (0); 185238450Smckusick } 1853