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*56718Smckusick * @(#)nfs_serv.c 7.62 (Berkeley) 11/12/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 /* 6356360Smckusick * nqnfs access service 6456360Smckusick */ 6556360Smckusick nqnfsrv_access(nfsd, mrep, md, dpos, cred, nam, mrq) 6656360Smckusick struct nfsd *nfsd; 6756360Smckusick struct mbuf *mrep, *md; 6856360Smckusick caddr_t dpos; 6956360Smckusick struct ucred *cred; 7056360Smckusick struct mbuf *nam, **mrq; 7156360Smckusick { 7256360Smckusick struct vnode *vp; 7356360Smckusick nfsv2fh_t nfh; 7456360Smckusick fhandle_t *fhp; 7556360Smckusick register u_long *tl; 7656360Smckusick register long t1; 7756360Smckusick caddr_t bpos; 7856360Smckusick int error = 0, rdonly, cache, mode = 0; 7956360Smckusick char *cp2; 8056360Smckusick struct mbuf *mb, *mb2, *mreq; 8156360Smckusick u_quad_t frev; 8256360Smckusick 8356360Smckusick fhp = &nfh.fh_generic; 8456360Smckusick nfsm_srvmtofh(fhp); 8556360Smckusick nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED); 8656360Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 8756360Smckusick nfsm_reply(0); 8856360Smckusick if (*tl++ == nfs_true) 8956360Smckusick mode |= VREAD; 9056360Smckusick if (*tl++ == nfs_true) 9156360Smckusick mode |= VWRITE; 9256360Smckusick if (*tl == nfs_true) 9356360Smckusick mode |= VEXEC; 9456360Smckusick error = nfsrv_access(vp, mode, cred, rdonly, nfsd->nd_procp); 9556360Smckusick vput(vp); 9656360Smckusick nfsm_reply(0); 9756360Smckusick nfsm_srvdone; 9856360Smckusick } 9956360Smckusick 10056360Smckusick /* 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; 24956658Smckusick duration2 = 0; 25052196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 25152196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 25256285Smckusick duration2 = fxdr_unsigned(int, *tl); 25352196Smckusick } 25438418Smckusick nfsm_srvmtofh(fhp); 25538418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 25652316Sheideman nd.ni_cnd.cn_cred = cred; 25752316Sheideman nd.ni_cnd.cn_nameiop = LOOKUP; 25852316Sheideman nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART; 25952653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 26052653Smckusick nfsd->nd_procp)) 26138418Smckusick nfsm_reply(0); 26252196Smckusick nqsrv_getl(nd.ni_startdir, NQL_READ); 26352196Smckusick vrele(nd.ni_startdir); 26452653Smckusick FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 26549742Smckusick vp = nd.ni_vp; 26638418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 26741398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 26838418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 26938418Smckusick vput(vp); 27038418Smckusick nfsm_reply(0); 27138418Smckusick } 27256285Smckusick if (duration2) 27356285Smckusick (void) nqsrv_getlease(vp, &duration2, NQL_READ, nfsd, 27452196Smckusick nam, &cache2, &frev2, cred); 27552196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 27638418Smckusick vput(vp); 27756285Smckusick nfsm_reply(NFSX_FH + NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL) + 5*NFSX_UNSIGNED); 27852196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 27956285Smckusick if (duration2) { 28052196Smckusick nfsm_build(tl, u_long *, 5*NFSX_UNSIGNED); 28156285Smckusick *tl++ = txdr_unsigned(NQL_READ); 28252196Smckusick *tl++ = txdr_unsigned(cache2); 28352196Smckusick *tl++ = txdr_unsigned(duration2); 28452196Smckusick txdr_hyper(&frev2, tl); 28552196Smckusick } else { 28652196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 28752196Smckusick *tl = 0; 28852196Smckusick } 28952196Smckusick } 29038418Smckusick nfsm_srvfhtom(fhp); 29156285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 29239753Smckusick nfsm_srvfillattr; 29338418Smckusick nfsm_srvdone; 29438418Smckusick } 29538418Smckusick 29638418Smckusick /* 29738418Smckusick * nfs readlink service 29838418Smckusick */ 29952196Smckusick nfsrv_readlink(nfsd, mrep, md, dpos, cred, nam, mrq) 30052196Smckusick struct nfsd *nfsd; 30138418Smckusick struct mbuf *mrep, *md; 30238418Smckusick caddr_t dpos; 30338418Smckusick struct ucred *cred; 30452196Smckusick struct mbuf *nam, **mrq; 30538418Smckusick { 30641899Smckusick struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN]; 30738418Smckusick register struct iovec *ivp = iv; 30838418Smckusick register struct mbuf *mp; 30948050Smckusick register u_long *tl; 31039494Smckusick register long t1; 31139494Smckusick caddr_t bpos; 31252196Smckusick int error = 0, rdonly, cache, i, tlen, len; 31339494Smckusick char *cp2; 31439753Smckusick struct mbuf *mb, *mb2, *mp2, *mp3, *mreq; 31538418Smckusick struct vnode *vp; 31638418Smckusick nfsv2fh_t nfh; 31738418Smckusick fhandle_t *fhp; 31838418Smckusick struct uio io, *uiop = &io; 31952196Smckusick u_quad_t frev; 32038418Smckusick 32138418Smckusick fhp = &nfh.fh_generic; 32238418Smckusick nfsm_srvmtofh(fhp); 32338418Smckusick len = 0; 32438418Smckusick i = 0; 32538418Smckusick while (len < NFS_MAXPATHLEN) { 32638418Smckusick MGET(mp, M_WAIT, MT_DATA); 32741899Smckusick MCLGET(mp, M_WAIT); 32838418Smckusick mp->m_len = NFSMSIZ(mp); 32938418Smckusick if (len == 0) 33038418Smckusick mp3 = mp2 = mp; 33141899Smckusick else { 33238418Smckusick mp2->m_next = mp; 33341899Smckusick mp2 = mp; 33441899Smckusick } 33538418Smckusick if ((len+mp->m_len) > NFS_MAXPATHLEN) { 33638418Smckusick mp->m_len = NFS_MAXPATHLEN-len; 33738418Smckusick len = NFS_MAXPATHLEN; 33838418Smckusick } else 33938418Smckusick len += mp->m_len; 34038418Smckusick ivp->iov_base = mtod(mp, caddr_t); 34138418Smckusick ivp->iov_len = mp->m_len; 34238418Smckusick i++; 34338418Smckusick ivp++; 34438418Smckusick } 34538418Smckusick uiop->uio_iov = iv; 34638418Smckusick uiop->uio_iovcnt = i; 34738418Smckusick uiop->uio_offset = 0; 34838418Smckusick uiop->uio_resid = len; 34938418Smckusick uiop->uio_rw = UIO_READ; 35038418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 35148050Smckusick uiop->uio_procp = (struct proc *)0; 35252196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) { 35338418Smckusick m_freem(mp3); 35438418Smckusick nfsm_reply(0); 35538418Smckusick } 35638418Smckusick if (vp->v_type != VLNK) { 35738418Smckusick error = EINVAL; 35838418Smckusick goto out; 35938418Smckusick } 36052196Smckusick nqsrv_getl(vp, NQL_READ); 36138418Smckusick error = VOP_READLINK(vp, uiop, cred); 36238418Smckusick out: 36338418Smckusick vput(vp); 36438418Smckusick if (error) 36538418Smckusick m_freem(mp3); 36638418Smckusick nfsm_reply(NFSX_UNSIGNED); 36738418Smckusick if (uiop->uio_resid > 0) { 36838418Smckusick len -= uiop->uio_resid; 36938418Smckusick tlen = nfsm_rndup(len); 37038418Smckusick nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len); 37138418Smckusick } 37248050Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 37348050Smckusick *tl = txdr_unsigned(len); 37438418Smckusick mb->m_next = mp3; 37538418Smckusick nfsm_srvdone; 37638418Smckusick } 37738418Smckusick 37838418Smckusick /* 37938418Smckusick * nfs read service 38038418Smckusick */ 38152196Smckusick nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq) 38252196Smckusick struct nfsd *nfsd; 38338418Smckusick struct mbuf *mrep, *md; 38438418Smckusick caddr_t dpos; 38538418Smckusick struct ucred *cred; 38652196Smckusick struct mbuf *nam, **mrq; 38738418Smckusick { 38843350Smckusick register struct iovec *iv; 38943350Smckusick struct iovec *iv2; 39041899Smckusick register struct mbuf *m; 39138884Smacklem register struct nfsv2_fattr *fp; 39248050Smckusick register u_long *tl; 39339494Smckusick register long t1; 39439494Smckusick caddr_t bpos; 39552196Smckusick int error = 0, rdonly, cache, i, cnt, len, left, siz, tlen; 39639494Smckusick char *cp2; 39739753Smckusick struct mbuf *mb, *mb2, *mreq; 39852196Smckusick struct mbuf *m2; 39938418Smckusick struct vnode *vp; 40038418Smckusick nfsv2fh_t nfh; 40138418Smckusick fhandle_t *fhp; 40238418Smckusick struct uio io, *uiop = &io; 40338418Smckusick struct vattr va, *vap = &va; 40438418Smckusick off_t off; 40552196Smckusick u_quad_t frev; 40638418Smckusick 40738418Smckusick fhp = &nfh.fh_generic; 40838418Smckusick nfsm_srvmtofh(fhp); 40956285Smckusick if (nfsd->nd_nqlflag == NQL_NOVAL) { 41056285Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 41156285Smckusick off = (off_t)fxdr_unsigned(u_long, *tl); 41256285Smckusick } else { 41356285Smckusick nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); 41456285Smckusick fxdr_hyper(tl, &off); 41556285Smckusick } 41638418Smckusick nfsm_srvstrsiz(cnt, NFS_MAXDATA); 41752196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 41838418Smckusick nfsm_reply(0); 41952196Smckusick nqsrv_getl(vp, NQL_READ); 420*56718Smckusick if ((error = nfsrv_access(vp, VREAD, cred, rdonly, nfsd->nd_procp)) && 421*56718Smckusick (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp))) { 42238418Smckusick vput(vp); 42338418Smckusick nfsm_reply(0); 42438418Smckusick } 42552196Smckusick if (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp)) { 42638418Smckusick vput(vp); 42738418Smckusick nfsm_reply(0); 42838418Smckusick } 42952196Smckusick if (off >= vap->va_size) 43052196Smckusick cnt = 0; 43152196Smckusick else if ((off + cnt) > vap->va_size) 43252196Smckusick cnt = nfsm_rndup(vap->va_size - off); 43356285Smckusick nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)+NFSX_UNSIGNED+nfsm_rndup(cnt)); 43456285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 43552196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 43652196Smckusick len = left = cnt; 43752196Smckusick if (cnt > 0) { 43852196Smckusick /* 43952196Smckusick * Generate the mbuf list with the uio_iov ref. to it. 44052196Smckusick */ 44152196Smckusick i = 0; 44252196Smckusick m = m2 = mb; 44352196Smckusick MALLOC(iv, struct iovec *, 44452196Smckusick ((NFS_MAXDATA+MLEN-1)/MLEN) * sizeof (struct iovec), 44552196Smckusick M_TEMP, M_WAITOK); 44652196Smckusick iv2 = iv; 44752196Smckusick while (left > 0) { 44855057Spendry siz = min(M_TRAILINGSPACE(m), left); 44952196Smckusick if (siz > 0) { 45052196Smckusick m->m_len += siz; 45152196Smckusick iv->iov_base = bpos; 45252196Smckusick iv->iov_len = siz; 45352196Smckusick iv++; 45452196Smckusick i++; 45552196Smckusick left -= siz; 45652196Smckusick } 45752196Smckusick if (left > 0) { 45852196Smckusick MGET(m, M_WAIT, MT_DATA); 45952196Smckusick MCLGET(m, M_WAIT); 46052196Smckusick m->m_len = 0; 46152196Smckusick m2->m_next = m; 46252196Smckusick m2 = m; 46352196Smckusick bpos = mtod(m, caddr_t); 46452196Smckusick } 46552196Smckusick } 46652196Smckusick uiop->uio_iov = iv2; 46752196Smckusick uiop->uio_iovcnt = i; 46852196Smckusick uiop->uio_offset = off; 46952196Smckusick uiop->uio_resid = cnt; 47052196Smckusick uiop->uio_rw = UIO_READ; 47152196Smckusick uiop->uio_segflg = UIO_SYSSPACE; 47252196Smckusick error = VOP_READ(vp, uiop, IO_NODELOCKED, cred); 47352196Smckusick off = uiop->uio_offset; 47452196Smckusick FREE((caddr_t)iv2, M_TEMP); 47552196Smckusick if (error || (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp))) { 47652196Smckusick m_freem(mreq); 47752196Smckusick vput(vp); 47852196Smckusick nfsm_reply(0); 47952196Smckusick } 48052196Smckusick } else 48152196Smckusick uiop->uio_resid = 0; 48238418Smckusick vput(vp); 48339753Smckusick nfsm_srvfillattr; 48445877Smckusick len -= uiop->uio_resid; 48552196Smckusick tlen = nfsm_rndup(len); 48652196Smckusick if (cnt != tlen || tlen != len) 48752196Smckusick nfsm_adj(mb, cnt-tlen, tlen-len); 48848050Smckusick *tl = txdr_unsigned(len); 48938418Smckusick nfsm_srvdone; 49038418Smckusick } 49138418Smckusick 49238418Smckusick /* 49338418Smckusick * nfs write service 49438418Smckusick */ 49552196Smckusick nfsrv_write(nfsd, mrep, md, dpos, cred, nam, mrq) 49652196Smckusick struct nfsd *nfsd; 49752196Smckusick struct mbuf *mrep, *md; 49838418Smckusick caddr_t dpos; 49938418Smckusick struct ucred *cred; 50052196Smckusick struct mbuf *nam, **mrq; 50138418Smckusick { 50238418Smckusick register struct iovec *ivp; 50338418Smckusick register struct mbuf *mp; 50438884Smacklem register struct nfsv2_fattr *fp; 50541899Smckusick struct iovec iv[NFS_MAXIOVEC]; 50638418Smckusick struct vattr va; 50738418Smckusick register struct vattr *vap = &va; 50848050Smckusick register u_long *tl; 50939494Smckusick register long t1; 51039494Smckusick caddr_t bpos; 51152196Smckusick int error = 0, rdonly, cache, siz, len, xfer; 51256285Smckusick int ioflags = IO_SYNC | IO_NODELOCKED; 51339494Smckusick char *cp2; 51439753Smckusick struct mbuf *mb, *mb2, *mreq; 51538418Smckusick struct vnode *vp; 51638418Smckusick nfsv2fh_t nfh; 51738418Smckusick fhandle_t *fhp; 51838418Smckusick struct uio io, *uiop = &io; 51938418Smckusick off_t off; 52052196Smckusick u_quad_t frev; 52138418Smckusick 52238418Smckusick fhp = &nfh.fh_generic; 52338418Smckusick nfsm_srvmtofh(fhp); 52456285Smckusick nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED); 52556285Smckusick if (nfsd->nd_nqlflag == NQL_NOVAL) { 52656285Smckusick off = (off_t)fxdr_unsigned(u_long, *++tl); 52756285Smckusick tl += 2; 52856285Smckusick } else { 52956285Smckusick fxdr_hyper(tl, &off); 53056285Smckusick tl += 2; 53156285Smckusick if (fxdr_unsigned(u_long, *tl++)) 53256285Smckusick ioflags |= IO_APPEND; 53356285Smckusick } 53448050Smckusick len = fxdr_unsigned(long, *tl); 53538418Smckusick if (len > NFS_MAXDATA || len <= 0) { 53638418Smckusick error = EBADRPC; 53738418Smckusick nfsm_reply(0); 53838418Smckusick } 53938418Smckusick if (dpos == (mtod(md, caddr_t)+md->m_len)) { 54038418Smckusick mp = md->m_next; 54138418Smckusick if (mp == NULL) { 54238418Smckusick error = EBADRPC; 54338418Smckusick nfsm_reply(0); 54438418Smckusick } 54538418Smckusick } else { 54638418Smckusick mp = md; 54738418Smckusick siz = dpos-mtod(mp, caddr_t); 54838418Smckusick mp->m_len -= siz; 54938418Smckusick NFSMADV(mp, siz); 55038418Smckusick } 55152196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 55238418Smckusick nfsm_reply(0); 55352196Smckusick nqsrv_getl(vp, NQL_WRITE); 55452196Smckusick if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) { 55538418Smckusick vput(vp); 55638418Smckusick nfsm_reply(0); 55738418Smckusick } 55838418Smckusick uiop->uio_resid = 0; 55938418Smckusick uiop->uio_rw = UIO_WRITE; 56038418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 56148050Smckusick uiop->uio_procp = (struct proc *)0; 56238418Smckusick /* 56341899Smckusick * Do up to NFS_MAXIOVEC mbufs of write each iteration of the 56438418Smckusick * loop until done. 56538418Smckusick */ 56638418Smckusick while (len > 0 && uiop->uio_resid == 0) { 56738418Smckusick ivp = iv; 56838418Smckusick siz = 0; 56938418Smckusick uiop->uio_iov = ivp; 57038418Smckusick uiop->uio_iovcnt = 0; 57138418Smckusick uiop->uio_offset = off; 57241899Smckusick while (len > 0 && uiop->uio_iovcnt < NFS_MAXIOVEC && mp != NULL) { 57338418Smckusick ivp->iov_base = mtod(mp, caddr_t); 57438418Smckusick if (len < mp->m_len) 57538418Smckusick ivp->iov_len = xfer = len; 57638418Smckusick else 57738418Smckusick ivp->iov_len = xfer = mp->m_len; 57838418Smckusick #ifdef notdef 57938418Smckusick /* Not Yet .. */ 58038418Smckusick if (M_HASCL(mp) && (((u_long)ivp->iov_base) & CLOFSET) == 0) 58138418Smckusick ivp->iov_op = NULL; /* what should it be ?? */ 58238418Smckusick else 58338418Smckusick ivp->iov_op = NULL; 58438418Smckusick #endif 58538418Smckusick uiop->uio_iovcnt++; 58638418Smckusick ivp++; 58738418Smckusick len -= xfer; 58838418Smckusick siz += xfer; 58938418Smckusick mp = mp->m_next; 59038418Smckusick } 59138418Smckusick if (len > 0 && mp == NULL) { 59238418Smckusick error = EBADRPC; 59338418Smckusick vput(vp); 59438418Smckusick nfsm_reply(0); 59538418Smckusick } 59638418Smckusick uiop->uio_resid = siz; 59756285Smckusick if (error = VOP_WRITE(vp, uiop, ioflags, cred)) { 59838418Smckusick vput(vp); 59938418Smckusick nfsm_reply(0); 60038418Smckusick } 60139586Smckusick off = uiop->uio_offset; 60238418Smckusick } 60352196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 60438418Smckusick vput(vp); 60556285Smckusick nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 60656285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 60739753Smckusick nfsm_srvfillattr; 60852442Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 60952442Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 61052442Smckusick txdr_hyper(&vap->va_filerev, tl); 61152442Smckusick } 61238418Smckusick nfsm_srvdone; 61338418Smckusick } 61438418Smckusick 61538418Smckusick /* 61638418Smckusick * nfs create service 61738418Smckusick * now does a truncate to 0 length via. setattr if it already exists 61838418Smckusick */ 61952196Smckusick nfsrv_create(nfsd, mrep, md, dpos, cred, nam, mrq) 62052196Smckusick struct nfsd *nfsd; 62152196Smckusick struct mbuf *mrep, *md; 62238418Smckusick caddr_t dpos; 62338418Smckusick struct ucred *cred; 62452196Smckusick struct mbuf *nam, **mrq; 62538418Smckusick { 62638884Smacklem register struct nfsv2_fattr *fp; 62738418Smckusick struct vattr va; 62838418Smckusick register struct vattr *vap = &va; 62956285Smckusick register struct nfsv2_sattr *sp; 63056285Smckusick register u_long *tl; 63149742Smckusick struct nameidata nd; 63239494Smckusick register caddr_t cp; 63339494Smckusick register long t1; 63439494Smckusick caddr_t bpos; 63556285Smckusick int error = 0, rdev, cache, len, tsize; 63639494Smckusick char *cp2; 63739753Smckusick struct mbuf *mb, *mb2, *mreq; 63838418Smckusick struct vnode *vp; 63938418Smckusick nfsv2fh_t nfh; 64038418Smckusick fhandle_t *fhp; 64152196Smckusick u_quad_t frev; 64238418Smckusick 64352316Sheideman nd.ni_cnd.cn_nameiop = 0; 64438418Smckusick fhp = &nfh.fh_generic; 64538418Smckusick nfsm_srvmtofh(fhp); 64638418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 64752316Sheideman nd.ni_cnd.cn_cred = cred; 64852316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 64952316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART; 65052653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 65152653Smckusick nfsd->nd_procp)) 65238418Smckusick nfsm_reply(0); 65341361Smckusick VATTR_NULL(vap); 65456285Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 65538418Smckusick /* 65638418Smckusick * Iff doesn't exist, create it 65738418Smckusick * otherwise just truncate to 0 length 65838418Smckusick * should I set the mode too ?? 65938418Smckusick */ 66049742Smckusick if (nd.ni_vp == NULL) { 66156285Smckusick vap->va_type = IFTOVT(fxdr_unsigned(u_long, sp->sa_mode)); 66242867Smckusick if (vap->va_type == VNON) 66342867Smckusick vap->va_type = VREG; 66456285Smckusick vap->va_mode = nfstov_mode(sp->sa_mode); 66556285Smckusick if (nfsd->nd_nqlflag == NQL_NOVAL) 66656285Smckusick rdev = fxdr_unsigned(long, sp->sa_nfssize); 66756285Smckusick else 66856285Smckusick rdev = fxdr_unsigned(long, sp->sa_nqrdev); 66946988Smckusick if (vap->va_type == VREG || vap->va_type == VSOCK) { 67049742Smckusick vrele(nd.ni_startdir); 67152196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 67252234Sheideman if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) 67342242Smckusick nfsm_reply(0); 67452316Sheideman FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 67542242Smckusick } else if (vap->va_type == VCHR || vap->va_type == VBLK || 67642242Smckusick vap->va_type == VFIFO) { 67742242Smckusick if (vap->va_type == VCHR && rdev == 0xffffffff) 67842242Smckusick vap->va_type = VFIFO; 67942242Smckusick if (vap->va_type == VFIFO) { 68042242Smckusick #ifndef FIFO 68152234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 68249742Smckusick vput(nd.ni_dvp); 68342242Smckusick error = ENXIO; 68449742Smckusick goto out; 68542242Smckusick #endif /* FIFO */ 68652196Smckusick } else if (error = suser(cred, (u_short *)0)) { 68752234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 68849742Smckusick vput(nd.ni_dvp); 68949742Smckusick goto out; 69042242Smckusick } else 69142242Smckusick vap->va_rdev = (dev_t)rdev; 69252196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 69352234Sheideman if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) { 69449742Smckusick vrele(nd.ni_startdir); 69542242Smckusick nfsm_reply(0); 69649742Smckusick } 69752316Sheideman nd.ni_cnd.cn_nameiop = LOOKUP; 69852316Sheideman nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART); 69952316Sheideman nd.ni_cnd.cn_proc = nfsd->nd_procp; 70052316Sheideman nd.ni_cnd.cn_cred = nfsd->nd_procp->p_ucred; 70152316Sheideman if (error = lookup(&nd)) { 70252316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 70342242Smckusick nfsm_reply(0); 70449742Smckusick } 70552316Sheideman FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 70652316Sheideman if (nd.ni_cnd.cn_flags & ISSYMLINK) { 70749742Smckusick vrele(nd.ni_dvp); 70849742Smckusick vput(nd.ni_vp); 70952234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 71049742Smckusick error = EINVAL; 71149742Smckusick nfsm_reply(0); 71249742Smckusick } 71342242Smckusick } else { 71452234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 71549742Smckusick vput(nd.ni_dvp); 71642242Smckusick error = ENXIO; 71749742Smckusick goto out; 71842242Smckusick } 71949742Smckusick vp = nd.ni_vp; 72038418Smckusick } else { 72149742Smckusick vrele(nd.ni_startdir); 72252316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 72349742Smckusick vp = nd.ni_vp; 72449742Smckusick if (nd.ni_dvp == vp) 72549742Smckusick vrele(nd.ni_dvp); 72643359Smckusick else 72749742Smckusick vput(nd.ni_dvp); 72852234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 72956285Smckusick if (nfsd->nd_nqlflag == NQL_NOVAL) { 73056285Smckusick tsize = fxdr_unsigned(long, sp->sa_nfssize); 73156285Smckusick if (tsize != -1) 73256285Smckusick vap->va_size = (u_quad_t)tsize; 73356285Smckusick else 73456285Smckusick vap->va_size = -1; 73556285Smckusick } else 73656285Smckusick fxdr_hyper(&sp->sa_nqsize, &vap->va_size); 73756285Smckusick if (vap->va_size != -1) { 73856285Smckusick nqsrv_getl(vp, NQL_WRITE); 73956285Smckusick if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) { 74056285Smckusick vput(vp); 74156285Smckusick nfsm_reply(0); 74256285Smckusick } 74342506Smckusick } 74438418Smckusick } 74538418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 74641398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 74738418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 74838418Smckusick vput(vp); 74938418Smckusick nfsm_reply(0); 75038418Smckusick } 75152196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 75238418Smckusick vput(vp); 75356285Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 75438418Smckusick nfsm_srvfhtom(fhp); 75556285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 75639753Smckusick nfsm_srvfillattr; 75738418Smckusick return (error); 75838418Smckusick nfsmout: 75952316Sheideman if (nd.ni_cnd.cn_nameiop || nd.ni_cnd.cn_flags) 76051464Sbostic vrele(nd.ni_startdir); 76152234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 76249742Smckusick if (nd.ni_dvp == nd.ni_vp) 76349742Smckusick vrele(nd.ni_dvp); 76443359Smckusick else 76549742Smckusick vput(nd.ni_dvp); 76649742Smckusick if (nd.ni_vp) 76749742Smckusick vput(nd.ni_vp); 76838418Smckusick return (error); 76949742Smckusick 77049742Smckusick out: 77149742Smckusick vrele(nd.ni_startdir); 77252316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 77349742Smckusick nfsm_reply(0); 77438418Smckusick } 77538418Smckusick 77638418Smckusick /* 77738418Smckusick * nfs remove service 77838418Smckusick */ 77952196Smckusick nfsrv_remove(nfsd, mrep, md, dpos, cred, nam, mrq) 78052196Smckusick struct nfsd *nfsd; 78152196Smckusick struct mbuf *mrep, *md; 78238418Smckusick caddr_t dpos; 78338418Smckusick struct ucred *cred; 78452196Smckusick struct mbuf *nam, **mrq; 78538418Smckusick { 78649742Smckusick struct nameidata nd; 78748050Smckusick register u_long *tl; 78839494Smckusick register long t1; 78939494Smckusick caddr_t bpos; 79052196Smckusick int error = 0, cache, len; 79139494Smckusick char *cp2; 79239753Smckusick struct mbuf *mb, *mreq; 79338418Smckusick struct vnode *vp; 79438418Smckusick nfsv2fh_t nfh; 79538418Smckusick fhandle_t *fhp; 79652196Smckusick u_quad_t frev; 79738418Smckusick 79838418Smckusick fhp = &nfh.fh_generic; 79938418Smckusick nfsm_srvmtofh(fhp); 80038418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 80152316Sheideman nd.ni_cnd.cn_cred = cred; 80252316Sheideman nd.ni_cnd.cn_nameiop = DELETE; 80352316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 80452653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 80552653Smckusick nfsd->nd_procp)) 80638418Smckusick nfsm_reply(0); 80749742Smckusick vp = nd.ni_vp; 80838418Smckusick if (vp->v_type == VDIR && 80952196Smckusick (error = suser(cred, (u_short *)0))) 81038418Smckusick goto out; 81138418Smckusick /* 81249454Smckusick * The root of a mounted filesystem cannot be deleted. 81338418Smckusick */ 81438418Smckusick if (vp->v_flag & VROOT) { 81538418Smckusick error = EBUSY; 81638418Smckusick goto out; 81738418Smckusick } 81838418Smckusick if (vp->v_flag & VTEXT) 81945715Smckusick (void) vnode_pager_uncache(vp); 82038418Smckusick out: 82142467Smckusick if (!error) { 82252196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 82352196Smckusick nqsrv_getl(vp, NQL_WRITE); 82452234Sheideman error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 82542467Smckusick } else { 82652234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 82749742Smckusick if (nd.ni_dvp == vp) 82849742Smckusick vrele(nd.ni_dvp); 82943359Smckusick else 83049742Smckusick vput(nd.ni_dvp); 83142467Smckusick vput(vp); 83242467Smckusick } 83338418Smckusick nfsm_reply(0); 83438418Smckusick nfsm_srvdone; 83538418Smckusick } 83638418Smckusick 83738418Smckusick /* 83838418Smckusick * nfs rename service 83938418Smckusick */ 84052196Smckusick nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq) 84152196Smckusick struct nfsd *nfsd; 84252196Smckusick struct mbuf *mrep, *md; 84338418Smckusick caddr_t dpos; 84438418Smckusick struct ucred *cred; 84552196Smckusick struct mbuf *nam, **mrq; 84638418Smckusick { 84748050Smckusick register u_long *tl; 84839494Smckusick register long t1; 84939494Smckusick caddr_t bpos; 85052196Smckusick int error = 0, rdonly, cache, len, len2; 85139494Smckusick char *cp2; 85239753Smckusick struct mbuf *mb, *mreq; 85349742Smckusick struct nameidata fromnd, tond; 85438418Smckusick struct vnode *fvp, *tvp, *tdvp; 85538418Smckusick nfsv2fh_t fnfh, tnfh; 85638418Smckusick fhandle_t *ffhp, *tfhp; 85752196Smckusick u_quad_t frev; 85852196Smckusick uid_t saved_uid; 85938418Smckusick 86038418Smckusick ffhp = &fnfh.fh_generic; 86138418Smckusick tfhp = &tnfh.fh_generic; 86252316Sheideman fromnd.ni_cnd.cn_nameiop = 0; 86352316Sheideman tond.ni_cnd.cn_nameiop = 0; 86438418Smckusick nfsm_srvmtofh(ffhp); 86538418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 86638418Smckusick /* 86752196Smckusick * Remember our original uid so that we can reset cr_uid before 86852196Smckusick * the second nfs_namei() call, in case it is remapped. 86938418Smckusick */ 87052196Smckusick saved_uid = cred->cr_uid; 87152316Sheideman fromnd.ni_cnd.cn_cred = cred; 87252316Sheideman fromnd.ni_cnd.cn_nameiop = DELETE; 87352316Sheideman fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART; 87452653Smckusick if (error = nfs_namei(&fromnd, ffhp, len, nfsd->nd_slp, nam, &md, 87552653Smckusick &dpos, nfsd->nd_procp)) 87638418Smckusick nfsm_reply(0); 87749742Smckusick fvp = fromnd.ni_vp; 87838418Smckusick nfsm_srvmtofh(tfhp); 87941899Smckusick nfsm_strsiz(len2, NFS_MAXNAMLEN); 88052196Smckusick cred->cr_uid = saved_uid; 88152316Sheideman tond.ni_cnd.cn_cred = cred; 88252316Sheideman tond.ni_cnd.cn_nameiop = RENAME; 88352316Sheideman tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; 88452653Smckusick if (error = nfs_namei(&tond, tfhp, len2, nfsd->nd_slp, nam, &md, 88552653Smckusick &dpos, nfsd->nd_procp)) { 88652234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 88749742Smckusick vrele(fromnd.ni_dvp); 88842467Smckusick vrele(fvp); 88942467Smckusick goto out1; 89042467Smckusick } 89138425Smckusick tdvp = tond.ni_dvp; 89238425Smckusick tvp = tond.ni_vp; 89338418Smckusick if (tvp != NULL) { 89438418Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 89538418Smckusick error = EISDIR; 89638418Smckusick goto out; 89738418Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 89838418Smckusick error = ENOTDIR; 89938418Smckusick goto out; 90038418Smckusick } 90152196Smckusick if (tvp->v_type == VDIR && tvp->v_mountedhere) { 90252196Smckusick error = EXDEV; 90352196Smckusick goto out; 90452196Smckusick } 90538418Smckusick } 90652196Smckusick if (fvp->v_type == VDIR && fvp->v_mountedhere) { 90752196Smckusick error = EBUSY; 90852196Smckusick goto out; 90952196Smckusick } 91038418Smckusick if (fvp->v_mount != tdvp->v_mount) { 91138418Smckusick error = EXDEV; 91238418Smckusick goto out; 91338418Smckusick } 91449742Smckusick if (fvp == tdvp) 91538418Smckusick error = EINVAL; 91649742Smckusick /* 91749742Smckusick * If source is the same as the destination (that is the 91849742Smckusick * same vnode with the same name in the same directory), 91949742Smckusick * then there is nothing to do. 92049742Smckusick */ 92149742Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 92252316Sheideman fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 92352316Sheideman !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 92452316Sheideman fromnd.ni_cnd.cn_namelen)) 92549742Smckusick error = -1; 92638418Smckusick out: 92742467Smckusick if (!error) { 92852196Smckusick nqsrv_getl(fromnd.ni_dvp, NQL_WRITE); 92952196Smckusick nqsrv_getl(tdvp, NQL_WRITE); 93052196Smckusick if (tvp) 93152196Smckusick nqsrv_getl(tvp, NQL_WRITE); 93252234Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 93352234Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 93442467Smckusick } else { 93552234Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 93643359Smckusick if (tdvp == tvp) 93743359Smckusick vrele(tdvp); 93843359Smckusick else 93943359Smckusick vput(tdvp); 94042467Smckusick if (tvp) 94142467Smckusick vput(tvp); 94252234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 94349742Smckusick vrele(fromnd.ni_dvp); 94442467Smckusick vrele(fvp); 94538418Smckusick } 94646513Smckusick vrele(tond.ni_startdir); 94752316Sheideman FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 94838418Smckusick out1: 94949742Smckusick vrele(fromnd.ni_startdir); 95052316Sheideman FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 95138418Smckusick nfsm_reply(0); 95238418Smckusick return (error); 95349742Smckusick 95438418Smckusick nfsmout: 95552316Sheideman if (tond.ni_cnd.cn_nameiop || tond.ni_cnd.cn_flags) { 95649742Smckusick vrele(tond.ni_startdir); 95752316Sheideman FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 95849742Smckusick } 95952316Sheideman if (fromnd.ni_cnd.cn_nameiop || fromnd.ni_cnd.cn_flags) { 96049742Smckusick vrele(fromnd.ni_startdir); 96152316Sheideman FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 96252234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 96349742Smckusick vrele(fromnd.ni_dvp); 96449742Smckusick vrele(fvp); 96549742Smckusick } 96638418Smckusick return (error); 96738418Smckusick } 96838418Smckusick 96938418Smckusick /* 97038418Smckusick * nfs link service 97138418Smckusick */ 97252196Smckusick nfsrv_link(nfsd, mrep, md, dpos, cred, nam, mrq) 97352196Smckusick struct nfsd *nfsd; 97452196Smckusick struct mbuf *mrep, *md; 97538418Smckusick caddr_t dpos; 97638418Smckusick struct ucred *cred; 97752196Smckusick struct mbuf *nam, **mrq; 97838418Smckusick { 97949742Smckusick struct nameidata nd; 98048050Smckusick register u_long *tl; 98139494Smckusick register long t1; 98239494Smckusick caddr_t bpos; 98352196Smckusick int error = 0, rdonly, cache, len; 98439494Smckusick char *cp2; 98539753Smckusick struct mbuf *mb, *mreq; 98638418Smckusick struct vnode *vp, *xp; 98738418Smckusick nfsv2fh_t nfh, dnfh; 98838418Smckusick fhandle_t *fhp, *dfhp; 98952196Smckusick u_quad_t frev; 99038418Smckusick 99138418Smckusick fhp = &nfh.fh_generic; 99238418Smckusick dfhp = &dnfh.fh_generic; 99338418Smckusick nfsm_srvmtofh(fhp); 99438418Smckusick nfsm_srvmtofh(dfhp); 99538418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 99652196Smckusick if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 99738418Smckusick nfsm_reply(0); 99852196Smckusick if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0))) 99938418Smckusick goto out1; 100052316Sheideman nd.ni_cnd.cn_cred = cred; 100152316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 100252316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 100352653Smckusick if (error = nfs_namei(&nd, dfhp, len, nfsd->nd_slp, nam, &md, &dpos, 100452653Smckusick nfsd->nd_procp)) 100538418Smckusick goto out1; 100649742Smckusick xp = nd.ni_vp; 100738418Smckusick if (xp != NULL) { 100838418Smckusick error = EEXIST; 100938418Smckusick goto out; 101038418Smckusick } 101149742Smckusick xp = nd.ni_dvp; 101238418Smckusick if (vp->v_mount != xp->v_mount) 101338418Smckusick error = EXDEV; 101438418Smckusick out: 101542467Smckusick if (!error) { 101652196Smckusick nqsrv_getl(vp, NQL_WRITE); 101752196Smckusick nqsrv_getl(xp, NQL_WRITE); 101852933Smckusick error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 101942467Smckusick } else { 102052234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 102149742Smckusick if (nd.ni_dvp == nd.ni_vp) 102249742Smckusick vrele(nd.ni_dvp); 102343359Smckusick else 102449742Smckusick vput(nd.ni_dvp); 102549742Smckusick if (nd.ni_vp) 102649742Smckusick vrele(nd.ni_vp); 102742467Smckusick } 102838418Smckusick out1: 102938418Smckusick vrele(vp); 103038418Smckusick nfsm_reply(0); 103138418Smckusick nfsm_srvdone; 103238418Smckusick } 103338418Smckusick 103438418Smckusick /* 103538418Smckusick * nfs symbolic link service 103638418Smckusick */ 103752196Smckusick nfsrv_symlink(nfsd, mrep, md, dpos, cred, nam, mrq) 103852196Smckusick struct nfsd *nfsd; 103952196Smckusick struct mbuf *mrep, *md; 104038418Smckusick caddr_t dpos; 104138418Smckusick struct ucred *cred; 104252196Smckusick struct mbuf *nam, **mrq; 104338418Smckusick { 104438418Smckusick struct vattr va; 104549742Smckusick struct nameidata nd; 104638418Smckusick register struct vattr *vap = &va; 104748050Smckusick register u_long *tl; 104839494Smckusick register long t1; 104945285Smckusick struct nfsv2_sattr *sp; 105039494Smckusick caddr_t bpos; 105141899Smckusick struct uio io; 105241899Smckusick struct iovec iv; 105352196Smckusick int error = 0, rdonly, cache, len, len2; 105441899Smckusick char *pathcp, *cp2; 105539753Smckusick struct mbuf *mb, *mreq; 105638418Smckusick nfsv2fh_t nfh; 105738418Smckusick fhandle_t *fhp; 105852196Smckusick u_quad_t frev; 105938418Smckusick 106041899Smckusick pathcp = (char *)0; 106138418Smckusick fhp = &nfh.fh_generic; 106238418Smckusick nfsm_srvmtofh(fhp); 106338418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 106452316Sheideman nd.ni_cnd.cn_cred = cred; 106552316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 106652316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 106752653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 106852653Smckusick nfsd->nd_procp)) 106942467Smckusick goto out; 107041899Smckusick nfsm_strsiz(len2, NFS_MAXPATHLEN); 107141899Smckusick MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK); 107241899Smckusick iv.iov_base = pathcp; 107341899Smckusick iv.iov_len = len2; 107441899Smckusick io.uio_resid = len2; 107541899Smckusick io.uio_offset = 0; 107641899Smckusick io.uio_iov = &iv; 107741899Smckusick io.uio_iovcnt = 1; 107841899Smckusick io.uio_segflg = UIO_SYSSPACE; 107941899Smckusick io.uio_rw = UIO_READ; 108048050Smckusick io.uio_procp = (struct proc *)0; 108141899Smckusick nfsm_mtouio(&io, len2); 108256285Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 108341899Smckusick *(pathcp + len2) = '\0'; 108449742Smckusick if (nd.ni_vp) { 108552234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 108649742Smckusick if (nd.ni_dvp == nd.ni_vp) 108749742Smckusick vrele(nd.ni_dvp); 108843359Smckusick else 108949742Smckusick vput(nd.ni_dvp); 109049742Smckusick vrele(nd.ni_vp); 109138418Smckusick error = EEXIST; 109238418Smckusick goto out; 109338418Smckusick } 109441361Smckusick VATTR_NULL(vap); 109545285Smckusick vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode); 109652196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 109752234Sheideman error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp); 109838418Smckusick out: 109941899Smckusick if (pathcp) 110041899Smckusick FREE(pathcp, M_TEMP); 110138418Smckusick nfsm_reply(0); 110238418Smckusick return (error); 110338418Smckusick nfsmout: 110452234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 110549742Smckusick if (nd.ni_dvp == nd.ni_vp) 110649742Smckusick vrele(nd.ni_dvp); 110743359Smckusick else 110849742Smckusick vput(nd.ni_dvp); 110949742Smckusick if (nd.ni_vp) 111049742Smckusick vrele(nd.ni_vp); 111141899Smckusick if (pathcp) 111241899Smckusick FREE(pathcp, M_TEMP); 111338418Smckusick return (error); 111438418Smckusick } 111538418Smckusick 111638418Smckusick /* 111738418Smckusick * nfs mkdir service 111838418Smckusick */ 111952196Smckusick nfsrv_mkdir(nfsd, mrep, md, dpos, cred, nam, mrq) 112052196Smckusick struct nfsd *nfsd; 112152196Smckusick struct mbuf *mrep, *md; 112238418Smckusick caddr_t dpos; 112338418Smckusick struct ucred *cred; 112452196Smckusick struct mbuf *nam, **mrq; 112538418Smckusick { 112638418Smckusick struct vattr va; 112738418Smckusick register struct vattr *vap = &va; 112838884Smacklem register struct nfsv2_fattr *fp; 112949742Smckusick struct nameidata nd; 113039494Smckusick register caddr_t cp; 113148050Smckusick register u_long *tl; 113239494Smckusick register long t1; 113339494Smckusick caddr_t bpos; 113452196Smckusick int error = 0, rdonly, cache, len; 113539494Smckusick char *cp2; 113639753Smckusick struct mbuf *mb, *mb2, *mreq; 113738418Smckusick struct vnode *vp; 113838418Smckusick nfsv2fh_t nfh; 113938418Smckusick fhandle_t *fhp; 114052196Smckusick u_quad_t frev; 114138418Smckusick 114238418Smckusick fhp = &nfh.fh_generic; 114338418Smckusick nfsm_srvmtofh(fhp); 114438418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 114552316Sheideman nd.ni_cnd.cn_cred = cred; 114652316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 114752316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 114852653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 114952653Smckusick nfsd->nd_procp)) 115038418Smckusick nfsm_reply(0); 115152196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 115241361Smckusick VATTR_NULL(vap); 115338418Smckusick vap->va_type = VDIR; 115448050Smckusick vap->va_mode = nfstov_mode(*tl++); 115549742Smckusick vp = nd.ni_vp; 115638418Smckusick if (vp != NULL) { 115752234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 115849742Smckusick if (nd.ni_dvp == vp) 115949742Smckusick vrele(nd.ni_dvp); 116043359Smckusick else 116149742Smckusick vput(nd.ni_dvp); 116242467Smckusick vrele(vp); 116338418Smckusick error = EEXIST; 116438418Smckusick nfsm_reply(0); 116538418Smckusick } 116652196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 116752234Sheideman if (error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) 116838418Smckusick nfsm_reply(0); 116949742Smckusick vp = nd.ni_vp; 117038418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 117141398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 117238418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 117338418Smckusick vput(vp); 117438418Smckusick nfsm_reply(0); 117538418Smckusick } 117652196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 117738418Smckusick vput(vp); 117856285Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 117938418Smckusick nfsm_srvfhtom(fhp); 118056285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 118139753Smckusick nfsm_srvfillattr; 118238418Smckusick return (error); 118338418Smckusick nfsmout: 118452234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 118549742Smckusick if (nd.ni_dvp == nd.ni_vp) 118649742Smckusick vrele(nd.ni_dvp); 118743359Smckusick else 118849742Smckusick vput(nd.ni_dvp); 118949742Smckusick if (nd.ni_vp) 119049742Smckusick vrele(nd.ni_vp); 119138418Smckusick return (error); 119238418Smckusick } 119338418Smckusick 119438418Smckusick /* 119538418Smckusick * nfs rmdir service 119638418Smckusick */ 119752196Smckusick nfsrv_rmdir(nfsd, mrep, md, dpos, cred, nam, mrq) 119852196Smckusick struct nfsd *nfsd; 119952196Smckusick struct mbuf *mrep, *md; 120038418Smckusick caddr_t dpos; 120138418Smckusick struct ucred *cred; 120252196Smckusick struct mbuf *nam, **mrq; 120338418Smckusick { 120448050Smckusick register u_long *tl; 120539494Smckusick register long t1; 120639494Smckusick caddr_t bpos; 120752196Smckusick int error = 0, rdonly, cache, len; 120839494Smckusick char *cp2; 120939753Smckusick struct mbuf *mb, *mreq; 121038418Smckusick struct vnode *vp; 121138418Smckusick nfsv2fh_t nfh; 121238418Smckusick fhandle_t *fhp; 121349742Smckusick struct nameidata nd; 121452196Smckusick u_quad_t frev; 121538418Smckusick 121638418Smckusick fhp = &nfh.fh_generic; 121738418Smckusick nfsm_srvmtofh(fhp); 121838418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 121952316Sheideman nd.ni_cnd.cn_cred = cred; 122052316Sheideman nd.ni_cnd.cn_nameiop = DELETE; 122152316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 122252653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 122352653Smckusick nfsd->nd_procp)) 122438418Smckusick nfsm_reply(0); 122549742Smckusick vp = nd.ni_vp; 122638418Smckusick if (vp->v_type != VDIR) { 122738418Smckusick error = ENOTDIR; 122838418Smckusick goto out; 122938418Smckusick } 123038418Smckusick /* 123138418Smckusick * No rmdir "." please. 123238418Smckusick */ 123349742Smckusick if (nd.ni_dvp == vp) { 123438418Smckusick error = EINVAL; 123538418Smckusick goto out; 123638418Smckusick } 123738418Smckusick /* 123849454Smckusick * The root of a mounted filesystem cannot be deleted. 123938418Smckusick */ 124038418Smckusick if (vp->v_flag & VROOT) 124138418Smckusick error = EBUSY; 124238418Smckusick out: 124342467Smckusick if (!error) { 124452196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 124552196Smckusick nqsrv_getl(vp, NQL_WRITE); 124652234Sheideman error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 124742467Smckusick } else { 124852234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 124949742Smckusick if (nd.ni_dvp == nd.ni_vp) 125049742Smckusick vrele(nd.ni_dvp); 125143359Smckusick else 125249742Smckusick vput(nd.ni_dvp); 125342467Smckusick vput(vp); 125442467Smckusick } 125538418Smckusick nfsm_reply(0); 125638418Smckusick nfsm_srvdone; 125738418Smckusick } 125838418Smckusick 125938418Smckusick /* 126038418Smckusick * nfs readdir service 126138418Smckusick * - mallocs what it thinks is enough to read 126248050Smckusick * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR 126338418Smckusick * - calls VOP_READDIR() 126440115Smckusick * - loops around building the reply 126538425Smckusick * if the output generated exceeds count break out of loop 126638425Smckusick * The nfsm_clget macro is used here so that the reply will be packed 126738425Smckusick * tightly in mbuf clusters. 126838418Smckusick * - it only knows that it has encountered eof when the VOP_READDIR() 126938425Smckusick * reads nothing 127038418Smckusick * - as such one readdir rpc will return eof false although you are there 127138425Smckusick * and then the next will return eof 127252441Smckusick * - it trims out records with d_fileno == 0 127338425Smckusick * this doesn't matter for Unix clients, but they might confuse clients 127438425Smckusick * for other os'. 127538418Smckusick * NB: It is tempting to set eof to true if the VOP_READDIR() reads less 127638425Smckusick * than requested, but this may not apply to all filesystems. For 127738425Smckusick * example, client NFS does not { although it is never remote mounted 127838425Smckusick * anyhow } 127952196Smckusick * The alternate call nqnfsrv_readdirlook() does lookups as well. 128038418Smckusick * PS: The NFS protocol spec. does not clarify what the "count" byte 128138425Smckusick * argument is a count of.. just name strings and file id's or the 128238425Smckusick * entire reply rpc or ... 128338425Smckusick * I tried just file name and id sizes and it confused the Sun client, 128438425Smckusick * so I am using the full rpc size now. The "paranoia.." comment refers 128538425Smckusick * to including the status longwords that are not a part of the dir. 128638425Smckusick * "entry" structures, but are in the rpc. 128738418Smckusick */ 128852196Smckusick struct flrep { 128952196Smckusick u_long fl_cachable; 129052196Smckusick u_long fl_duration; 129155528Smckusick u_long fl_frev[2]; 129252196Smckusick nfsv2fh_t fl_nfh; 129356285Smckusick u_long fl_fattr[NFSX_NQFATTR / sizeof (u_long)]; 129452196Smckusick }; 129552196Smckusick 129652196Smckusick nfsrv_readdir(nfsd, mrep, md, dpos, cred, nam, mrq) 129752196Smckusick struct nfsd *nfsd; 129838418Smckusick struct mbuf *mrep, *md; 129938418Smckusick caddr_t dpos; 130038418Smckusick struct ucred *cred; 130152196Smckusick struct mbuf *nam, **mrq; 130238418Smckusick { 130338418Smckusick register char *bp, *be; 130438418Smckusick register struct mbuf *mp; 130552441Smckusick register struct dirent *dp; 130639494Smckusick register caddr_t cp; 130748050Smckusick register u_long *tl; 130839494Smckusick register long t1; 130939494Smckusick caddr_t bpos; 131052196Smckusick struct mbuf *mb, *mb2, *mreq, *mp2; 131152196Smckusick char *cpos, *cend, *cp2, *rbuf; 131238418Smckusick struct vnode *vp; 131338418Smckusick nfsv2fh_t nfh; 131438418Smckusick fhandle_t *fhp; 131538418Smckusick struct uio io; 131638418Smckusick struct iovec iv; 131752196Smckusick struct vattr va; 131852196Smckusick int len, nlen, rem, xfer, tsiz, i, error = 0; 131952196Smckusick int siz, cnt, fullsiz, eofflag, rdonly, cache; 132052196Smckusick u_quad_t frev; 132156285Smckusick u_long on, off, toff; 132238418Smckusick 132338418Smckusick fhp = &nfh.fh_generic; 132438418Smckusick nfsm_srvmtofh(fhp); 132552196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 132656285Smckusick toff = fxdr_unsigned(u_long, *tl++); 132748050Smckusick off = (toff & ~(NFS_DIRBLKSIZ-1)); 132848050Smckusick on = (toff & (NFS_DIRBLKSIZ-1)); 132948050Smckusick cnt = fxdr_unsigned(int, *tl); 133048050Smckusick siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); 133141899Smckusick if (cnt > NFS_MAXREADDIR) 133241899Smckusick siz = NFS_MAXREADDIR; 133338418Smckusick fullsiz = siz; 133452196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 133538418Smckusick nfsm_reply(0); 133652196Smckusick nqsrv_getl(vp, NQL_READ); 133752196Smckusick if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { 133838418Smckusick vput(vp); 133938418Smckusick nfsm_reply(0); 134038418Smckusick } 134138418Smckusick VOP_UNLOCK(vp); 134238418Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 134338418Smckusick again: 134438418Smckusick iv.iov_base = rbuf; 134538418Smckusick iv.iov_len = fullsiz; 134638418Smckusick io.uio_iov = &iv; 134738418Smckusick io.uio_iovcnt = 1; 134856285Smckusick io.uio_offset = (off_t)off; 134938418Smckusick io.uio_resid = fullsiz; 135038418Smckusick io.uio_segflg = UIO_SYSSPACE; 135138418Smckusick io.uio_rw = UIO_READ; 135248050Smckusick io.uio_procp = (struct proc *)0; 135354446Smckusick error = VOP_READDIR(vp, &io, cred); 135456285Smckusick off = (off_t)io.uio_offset; 135538418Smckusick if (error) { 135638418Smckusick vrele(vp); 135738418Smckusick free((caddr_t)rbuf, M_TEMP); 135838418Smckusick nfsm_reply(0); 135938418Smckusick } 136054446Smckusick if (io.uio_resid < fullsiz) 136154446Smckusick eofflag = 0; 136254446Smckusick else 136354446Smckusick eofflag = 1; 136438418Smckusick if (io.uio_resid) { 136538418Smckusick siz -= io.uio_resid; 136638418Smckusick 136738418Smckusick /* 136838418Smckusick * If nothing read, return eof 136938418Smckusick * rpc reply 137038418Smckusick */ 137138418Smckusick if (siz == 0) { 137238418Smckusick vrele(vp); 137338418Smckusick nfsm_reply(2*NFSX_UNSIGNED); 137448050Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 137548050Smckusick *tl++ = nfs_false; 137648050Smckusick *tl = nfs_true; 137738418Smckusick FREE((caddr_t)rbuf, M_TEMP); 137838418Smckusick return (0); 137938418Smckusick } 138038418Smckusick } 138140115Smckusick 138238418Smckusick /* 138338418Smckusick * Check for degenerate cases of nothing useful read. 138440115Smckusick * If so go try again 138538418Smckusick */ 138640115Smckusick cpos = rbuf + on; 138740115Smckusick cend = rbuf + siz; 138852441Smckusick dp = (struct dirent *)cpos; 138952441Smckusick while (cpos < cend && dp->d_fileno == 0) { 139040115Smckusick cpos += dp->d_reclen; 139152441Smckusick dp = (struct dirent *)cpos; 139240115Smckusick } 139340115Smckusick if (cpos >= cend) { 139438418Smckusick toff = off; 139538418Smckusick siz = fullsiz; 139638418Smckusick on = 0; 139738418Smckusick goto again; 139838418Smckusick } 139940115Smckusick 140040115Smckusick cpos = rbuf + on; 140140115Smckusick cend = rbuf + siz; 140252441Smckusick dp = (struct dirent *)cpos; 140352196Smckusick len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 140452196Smckusick nfsm_reply(siz); 140552196Smckusick mp = mp2 = mb; 140652196Smckusick bp = bpos; 140752196Smckusick be = bp + M_TRAILINGSPACE(mp); 140852196Smckusick 140952196Smckusick /* Loop through the records and build reply */ 141052196Smckusick while (cpos < cend) { 141152441Smckusick if (dp->d_fileno != 0) { 141252196Smckusick nlen = dp->d_namlen; 141352196Smckusick rem = nfsm_rndup(nlen)-nlen; 141452196Smckusick len += (4*NFSX_UNSIGNED + nlen + rem); 141552196Smckusick if (len > cnt) { 141652196Smckusick eofflag = 0; 141752196Smckusick break; 141852196Smckusick } 141952441Smckusick /* 142052441Smckusick * Build the directory record xdr from 142152441Smckusick * the dirent entry. 142252441Smckusick */ 142352196Smckusick nfsm_clget; 142452196Smckusick *tl = nfs_true; 142552196Smckusick bp += NFSX_UNSIGNED; 142652196Smckusick nfsm_clget; 142752441Smckusick *tl = txdr_unsigned(dp->d_fileno); 142852196Smckusick bp += NFSX_UNSIGNED; 142952196Smckusick nfsm_clget; 143052196Smckusick *tl = txdr_unsigned(nlen); 143152196Smckusick bp += NFSX_UNSIGNED; 143252196Smckusick 143352196Smckusick /* And loop around copying the name */ 143452196Smckusick xfer = nlen; 143552196Smckusick cp = dp->d_name; 143652196Smckusick while (xfer > 0) { 143752196Smckusick nfsm_clget; 143852196Smckusick if ((bp+xfer) > be) 143952196Smckusick tsiz = be-bp; 144052196Smckusick else 144152196Smckusick tsiz = xfer; 144252196Smckusick bcopy(cp, bp, tsiz); 144352196Smckusick bp += tsiz; 144452196Smckusick xfer -= tsiz; 144552196Smckusick if (xfer > 0) 144652196Smckusick cp += tsiz; 144752196Smckusick } 144852196Smckusick /* And null pad to a long boundary */ 144952196Smckusick for (i = 0; i < rem; i++) 145052196Smckusick *bp++ = '\0'; 145152196Smckusick nfsm_clget; 145252196Smckusick 145352196Smckusick /* Finish off the record */ 145452196Smckusick toff += dp->d_reclen; 145552196Smckusick *tl = txdr_unsigned(toff); 145652196Smckusick bp += NFSX_UNSIGNED; 145752196Smckusick } else 145852196Smckusick toff += dp->d_reclen; 145952196Smckusick cpos += dp->d_reclen; 146052441Smckusick dp = (struct dirent *)cpos; 146152196Smckusick } 146238418Smckusick vrele(vp); 146352196Smckusick nfsm_clget; 146452196Smckusick *tl = nfs_false; 146552196Smckusick bp += NFSX_UNSIGNED; 146652196Smckusick nfsm_clget; 146752196Smckusick if (eofflag) 146852196Smckusick *tl = nfs_true; 146952196Smckusick else 147052196Smckusick *tl = nfs_false; 147152196Smckusick bp += NFSX_UNSIGNED; 147252196Smckusick if (mp != mb) { 147352196Smckusick if (bp < be) 147452196Smckusick mp->m_len = bp - mtod(mp, caddr_t); 147552196Smckusick } else 147652196Smckusick mp->m_len += bp - bpos; 147752196Smckusick FREE(rbuf, M_TEMP); 147852196Smckusick nfsm_srvdone; 147952196Smckusick } 148052196Smckusick 148152196Smckusick nqnfsrv_readdirlook(nfsd, mrep, md, dpos, cred, nam, mrq) 148252196Smckusick struct nfsd *nfsd; 148352196Smckusick struct mbuf *mrep, *md; 148452196Smckusick caddr_t dpos; 148552196Smckusick struct ucred *cred; 148652196Smckusick struct mbuf *nam, **mrq; 148752196Smckusick { 148852196Smckusick register char *bp, *be; 148952196Smckusick register struct mbuf *mp; 149052441Smckusick register struct dirent *dp; 149152196Smckusick register caddr_t cp; 149252196Smckusick register u_long *tl; 149352196Smckusick register long t1; 149452196Smckusick caddr_t bpos; 149552196Smckusick struct mbuf *mb, *mb2, *mreq, *mp2; 149652196Smckusick char *cpos, *cend, *cp2, *rbuf; 149752196Smckusick struct vnode *vp, *nvp; 149852196Smckusick struct flrep fl; 149952196Smckusick nfsv2fh_t nfh; 150052196Smckusick fhandle_t *fhp; 150152196Smckusick struct uio io; 150252196Smckusick struct iovec iv; 150352196Smckusick struct vattr va, *vap = &va; 150452196Smckusick struct nfsv2_fattr *fp; 150552196Smckusick int len, nlen, rem, xfer, tsiz, i, error = 0, duration2, cache2; 150652196Smckusick int siz, cnt, fullsiz, eofflag, rdonly, cache; 150752196Smckusick u_quad_t frev, frev2; 150856285Smckusick u_long on, off, toff; 150952196Smckusick 151052196Smckusick fhp = &nfh.fh_generic; 151152196Smckusick nfsm_srvmtofh(fhp); 151252196Smckusick nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED); 151356285Smckusick toff = fxdr_unsigned(u_long, *tl++); 151452196Smckusick off = (toff & ~(NFS_DIRBLKSIZ-1)); 151552196Smckusick on = (toff & (NFS_DIRBLKSIZ-1)); 151652196Smckusick cnt = fxdr_unsigned(int, *tl++); 151752196Smckusick duration2 = fxdr_unsigned(int, *tl); 151852196Smckusick siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); 151952196Smckusick if (cnt > NFS_MAXREADDIR) 152052196Smckusick siz = NFS_MAXREADDIR; 152152196Smckusick fullsiz = siz; 152252196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 152352196Smckusick nfsm_reply(0); 152452196Smckusick nqsrv_getl(vp, NQL_READ); 152552196Smckusick if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { 152652196Smckusick vput(vp); 152752196Smckusick nfsm_reply(0); 152852196Smckusick } 152952196Smckusick VOP_UNLOCK(vp); 153052196Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 153152196Smckusick again: 153252196Smckusick iv.iov_base = rbuf; 153352196Smckusick iv.iov_len = fullsiz; 153452196Smckusick io.uio_iov = &iv; 153552196Smckusick io.uio_iovcnt = 1; 153656285Smckusick io.uio_offset = (off_t)off; 153752196Smckusick io.uio_resid = fullsiz; 153852196Smckusick io.uio_segflg = UIO_SYSSPACE; 153952196Smckusick io.uio_rw = UIO_READ; 154052196Smckusick io.uio_procp = (struct proc *)0; 154154446Smckusick error = VOP_READDIR(vp, &io, cred); 154256285Smckusick off = (u_long)io.uio_offset; 154352196Smckusick if (error) { 154452196Smckusick vrele(vp); 154552196Smckusick free((caddr_t)rbuf, M_TEMP); 154652196Smckusick nfsm_reply(0); 154752196Smckusick } 154854446Smckusick if (io.uio_resid < fullsiz) 154954446Smckusick eofflag = 0; 155054446Smckusick else 155154446Smckusick eofflag = 1; 155252196Smckusick if (io.uio_resid) { 155352196Smckusick siz -= io.uio_resid; 155452196Smckusick 155552196Smckusick /* 155652196Smckusick * If nothing read, return eof 155752196Smckusick * rpc reply 155852196Smckusick */ 155952196Smckusick if (siz == 0) { 156052196Smckusick vrele(vp); 156156285Smckusick nfsm_reply(2 * NFSX_UNSIGNED); 156256285Smckusick nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); 156352196Smckusick *tl++ = nfs_false; 156452196Smckusick *tl = nfs_true; 156552196Smckusick FREE((caddr_t)rbuf, M_TEMP); 156652196Smckusick return (0); 156752196Smckusick } 156852196Smckusick } 156952196Smckusick 157052196Smckusick /* 157152196Smckusick * Check for degenerate cases of nothing useful read. 157252196Smckusick * If so go try again 157352196Smckusick */ 157452196Smckusick cpos = rbuf + on; 157552196Smckusick cend = rbuf + siz; 157652441Smckusick dp = (struct dirent *)cpos; 157752441Smckusick while (cpos < cend && dp->d_fileno == 0) { 157852196Smckusick cpos += dp->d_reclen; 157952441Smckusick dp = (struct dirent *)cpos; 158052196Smckusick } 158152196Smckusick if (cpos >= cend) { 158252196Smckusick toff = off; 158352196Smckusick siz = fullsiz; 158452196Smckusick on = 0; 158552196Smckusick goto again; 158652196Smckusick } 158752196Smckusick 158852196Smckusick cpos = rbuf + on; 158952196Smckusick cend = rbuf + siz; 159052441Smckusick dp = (struct dirent *)cpos; 159156285Smckusick len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 159238418Smckusick nfsm_reply(siz); 159352196Smckusick mp = mp2 = mb; 159452196Smckusick bp = bpos; 159552196Smckusick be = bp + M_TRAILINGSPACE(mp); 159638418Smckusick 159738418Smckusick /* Loop through the records and build reply */ 159838418Smckusick while (cpos < cend) { 159952441Smckusick if (dp->d_fileno != 0) { 160038418Smckusick nlen = dp->d_namlen; 160138418Smckusick rem = nfsm_rndup(nlen)-nlen; 160238425Smckusick 160338418Smckusick /* 160452196Smckusick * For readdir_and_lookup get the vnode using 160552196Smckusick * the file number. 160638418Smckusick */ 160754665Smckusick if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp)) 160852196Smckusick goto invalid; 160955655Smckusick bzero((caddr_t)&fl.fl_nfh, sizeof (nfsv2fh_t)); 161055655Smckusick fl.fl_nfh.fh_generic.fh_fsid = 161155655Smckusick nvp->v_mount->mnt_stat.f_fsid; 161255655Smckusick if (VFS_VPTOFH(nvp, &fl.fl_nfh.fh_generic.fh_fid)) { 161355655Smckusick vput(nvp); 161455655Smckusick goto invalid; 161555655Smckusick } 161656285Smckusick if (duration2) { 161756285Smckusick (void) nqsrv_getlease(nvp, &duration2, NQL_READ, 161856285Smckusick nfsd, nam, &cache2, &frev2, cred); 161956285Smckusick fl.fl_duration = txdr_unsigned(duration2); 162056285Smckusick fl.fl_cachable = txdr_unsigned(cache2); 162156285Smckusick txdr_hyper(&frev2, fl.fl_frev); 162256285Smckusick } else 162356285Smckusick fl.fl_duration = 0; 162452196Smckusick if (VOP_GETATTR(nvp, vap, cred, nfsd->nd_procp)) { 162552196Smckusick vput(nvp); 162652196Smckusick goto invalid; 162752196Smckusick } 162852196Smckusick vput(nvp); 162956285Smckusick fp = (struct nfsv2_fattr *)&fl.fl_fattr; 163052196Smckusick nfsm_srvfillattr; 163152196Smckusick len += (4*NFSX_UNSIGNED + nlen + rem + NFSX_FH 163256285Smckusick + NFSX_NQFATTR); 163341899Smckusick if (len > cnt) { 163441899Smckusick eofflag = 0; 163538418Smckusick break; 163641899Smckusick } 163752441Smckusick /* 163852441Smckusick * Build the directory record xdr from 163952441Smckusick * the dirent entry. 164052441Smckusick */ 164138418Smckusick nfsm_clget; 164248050Smckusick *tl = nfs_true; 164338418Smckusick bp += NFSX_UNSIGNED; 164452196Smckusick 164552196Smckusick /* 164652196Smckusick * For readdir_and_lookup copy the stuff out. 164752196Smckusick */ 164852196Smckusick xfer = sizeof (struct flrep); 164952196Smckusick cp = (caddr_t)&fl; 165052196Smckusick while (xfer > 0) { 165152196Smckusick nfsm_clget; 165252196Smckusick if ((bp+xfer) > be) 165352196Smckusick tsiz = be-bp; 165452196Smckusick else 165552196Smckusick tsiz = xfer; 165652196Smckusick bcopy(cp, bp, tsiz); 165752196Smckusick bp += tsiz; 165852196Smckusick xfer -= tsiz; 165952196Smckusick if (xfer > 0) 166052196Smckusick cp += tsiz; 166152196Smckusick } 166238418Smckusick nfsm_clget; 166352441Smckusick *tl = txdr_unsigned(dp->d_fileno); 166438418Smckusick bp += NFSX_UNSIGNED; 166538418Smckusick nfsm_clget; 166648050Smckusick *tl = txdr_unsigned(nlen); 166738418Smckusick bp += NFSX_UNSIGNED; 166838425Smckusick 166952196Smckusick /* And loop around copying the name */ 167038418Smckusick xfer = nlen; 167138418Smckusick cp = dp->d_name; 167238418Smckusick while (xfer > 0) { 167338418Smckusick nfsm_clget; 167438418Smckusick if ((bp+xfer) > be) 167538418Smckusick tsiz = be-bp; 167638418Smckusick else 167738418Smckusick tsiz = xfer; 167838418Smckusick bcopy(cp, bp, tsiz); 167938418Smckusick bp += tsiz; 168038418Smckusick xfer -= tsiz; 168138418Smckusick if (xfer > 0) 168238418Smckusick cp += tsiz; 168338418Smckusick } 168438418Smckusick /* And null pad to a long boundary */ 168538418Smckusick for (i = 0; i < rem; i++) 168638418Smckusick *bp++ = '\0'; 168738418Smckusick nfsm_clget; 168838425Smckusick 168938418Smckusick /* Finish off the record */ 169038418Smckusick toff += dp->d_reclen; 169148050Smckusick *tl = txdr_unsigned(toff); 169238418Smckusick bp += NFSX_UNSIGNED; 169338418Smckusick } else 169452196Smckusick invalid: 169538418Smckusick toff += dp->d_reclen; 169638418Smckusick cpos += dp->d_reclen; 169752441Smckusick dp = (struct dirent *)cpos; 169838418Smckusick } 169952196Smckusick vrele(vp); 170038418Smckusick nfsm_clget; 170148050Smckusick *tl = nfs_false; 170238418Smckusick bp += NFSX_UNSIGNED; 170338418Smckusick nfsm_clget; 170440296Smckusick if (eofflag) 170548050Smckusick *tl = nfs_true; 170640296Smckusick else 170748050Smckusick *tl = nfs_false; 170838418Smckusick bp += NFSX_UNSIGNED; 170952196Smckusick if (mp != mb) { 171052196Smckusick if (bp < be) 171152196Smckusick mp->m_len = bp - mtod(mp, caddr_t); 171252196Smckusick } else 171352196Smckusick mp->m_len += bp - bpos; 171438418Smckusick FREE(rbuf, M_TEMP); 171538418Smckusick nfsm_srvdone; 171638418Smckusick } 171738418Smckusick 171838418Smckusick /* 171938418Smckusick * nfs statfs service 172038418Smckusick */ 172152196Smckusick nfsrv_statfs(nfsd, mrep, md, dpos, cred, nam, mrq) 172252196Smckusick struct nfsd *nfsd; 172338418Smckusick struct mbuf *mrep, *md; 172438418Smckusick caddr_t dpos; 172538418Smckusick struct ucred *cred; 172652196Smckusick struct mbuf *nam, **mrq; 172738418Smckusick { 172838418Smckusick register struct statfs *sf; 172938884Smacklem register struct nfsv2_statfs *sfp; 173048050Smckusick register u_long *tl; 173139494Smckusick register long t1; 173239494Smckusick caddr_t bpos; 173356285Smckusick int error = 0, rdonly, cache, isnq; 173439494Smckusick char *cp2; 173539753Smckusick struct mbuf *mb, *mb2, *mreq; 173638418Smckusick struct vnode *vp; 173738418Smckusick nfsv2fh_t nfh; 173838418Smckusick fhandle_t *fhp; 173938418Smckusick struct statfs statfs; 174052196Smckusick u_quad_t frev; 174138418Smckusick 174238418Smckusick fhp = &nfh.fh_generic; 174356285Smckusick isnq = (nfsd->nd_nqlflag != NQL_NOVAL); 174438418Smckusick nfsm_srvmtofh(fhp); 174552196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 174638418Smckusick nfsm_reply(0); 174738418Smckusick sf = &statfs; 174852196Smckusick error = VFS_STATFS(vp->v_mount, sf, nfsd->nd_procp); 174938418Smckusick vput(vp); 175056285Smckusick nfsm_reply(NFSX_STATFS(isnq)); 175156285Smckusick nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS(isnq)); 175244993Sbostic sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA); 175351940Smckusick sfp->sf_bsize = txdr_unsigned(sf->f_bsize); 175438884Smacklem sfp->sf_blocks = txdr_unsigned(sf->f_blocks); 175538884Smacklem sfp->sf_bfree = txdr_unsigned(sf->f_bfree); 175638884Smacklem sfp->sf_bavail = txdr_unsigned(sf->f_bavail); 175756285Smckusick if (isnq) { 175856285Smckusick sfp->sf_files = txdr_unsigned(sf->f_files); 175956285Smckusick sfp->sf_ffree = txdr_unsigned(sf->f_ffree); 176056285Smckusick } 176138418Smckusick nfsm_srvdone; 176238418Smckusick } 176338418Smckusick 176438418Smckusick /* 176538418Smckusick * Null operation, used by clients to ping server 176638418Smckusick */ 176739494Smckusick /* ARGSUSED */ 176852196Smckusick nfsrv_null(nfsd, mrep, md, dpos, cred, nam, mrq) 176952196Smckusick struct nfsd *nfsd; 177038418Smckusick struct mbuf *mrep, *md; 177138418Smckusick caddr_t dpos; 177238418Smckusick struct ucred *cred; 177352196Smckusick struct mbuf *nam, **mrq; 177438418Smckusick { 177539494Smckusick caddr_t bpos; 177652196Smckusick int error = VNOVAL, cache; 177739753Smckusick struct mbuf *mb, *mreq; 177852196Smckusick u_quad_t frev; 177938418Smckusick 178038418Smckusick nfsm_reply(0); 178139494Smckusick return (error); 178238418Smckusick } 178338418Smckusick 178438418Smckusick /* 178538418Smckusick * No operation, used for obsolete procedures 178638418Smckusick */ 178739494Smckusick /* ARGSUSED */ 178852196Smckusick nfsrv_noop(nfsd, mrep, md, dpos, cred, nam, mrq) 178952196Smckusick struct nfsd *nfsd; 179038418Smckusick struct mbuf *mrep, *md; 179138418Smckusick caddr_t dpos; 179238418Smckusick struct ucred *cred; 179352196Smckusick struct mbuf *nam, **mrq; 179438418Smckusick { 179539494Smckusick caddr_t bpos; 179652196Smckusick int error, cache; 179739753Smckusick struct mbuf *mb, *mreq; 179852196Smckusick u_quad_t frev; 179938418Smckusick 180052196Smckusick if (nfsd->nd_repstat) 180152196Smckusick error = nfsd->nd_repstat; 180252196Smckusick else 180352196Smckusick error = EPROCUNAVAIL; 180438418Smckusick nfsm_reply(0); 180539494Smckusick return (error); 180638418Smckusick } 180738425Smckusick 180838450Smckusick /* 180938450Smckusick * Perform access checking for vnodes obtained from file handles that would 181038450Smckusick * refer to files already opened by a Unix client. You cannot just use 181138450Smckusick * vn_writechk() and VOP_ACCESS() for two reasons. 181252196Smckusick * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case 181338450Smckusick * 2 - The owner is to be given access irrespective of mode bits so that 181438450Smckusick * processes that chmod after opening a file don't break. I don't like 181538450Smckusick * this because it opens a security hole, but since the nfs server opens 181638450Smckusick * a security hole the size of a barn door anyhow, what the heck. 181738450Smckusick */ 181852196Smckusick nfsrv_access(vp, flags, cred, rdonly, p) 181938450Smckusick register struct vnode *vp; 182038450Smckusick int flags; 182138450Smckusick register struct ucred *cred; 182252196Smckusick int rdonly; 182348050Smckusick struct proc *p; 182438450Smckusick { 182538450Smckusick struct vattr vattr; 182638450Smckusick int error; 182738450Smckusick if (flags & VWRITE) { 182852196Smckusick /* Just vn_writechk() changed to check rdonly */ 182938450Smckusick /* 183038450Smckusick * Disallow write attempts on read-only file systems; 183138450Smckusick * unless the file is a socket or a block or character 183238450Smckusick * device resident on the file system. 183338450Smckusick */ 183452196Smckusick if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { 183545059Smckusick switch (vp->v_type) { 183645059Smckusick case VREG: case VDIR: case VLNK: 183738450Smckusick return (EROFS); 183845059Smckusick } 183945059Smckusick } 184038450Smckusick /* 184138450Smckusick * If there's shared text associated with 184238450Smckusick * the inode, try to free it up once. If 184338450Smckusick * we fail, we can't allow writing. 184438450Smckusick */ 184545715Smckusick if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) 184638450Smckusick return (ETXTBSY); 184738450Smckusick } 184848050Smckusick if (error = VOP_GETATTR(vp, &vattr, cred, p)) 184945059Smckusick return (error); 185048050Smckusick if ((error = VOP_ACCESS(vp, flags, cred, p)) && 185145059Smckusick cred->cr_uid != vattr.va_uid) 185245059Smckusick return (error); 185345059Smckusick return (0); 185438450Smckusick } 1855