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*56658Smckusick * @(#)nfs_serv.c 7.61 (Berkeley) 11/01/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; 249*56658Smckusick 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); 42052196Smckusick if (error = nfsrv_access(vp, VREAD | VEXEC, cred, rdonly, nfsd->nd_procp)) { 42138418Smckusick vput(vp); 42238418Smckusick nfsm_reply(0); 42338418Smckusick } 42452196Smckusick if (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp)) { 42538418Smckusick vput(vp); 42638418Smckusick nfsm_reply(0); 42738418Smckusick } 42852196Smckusick if (off >= vap->va_size) 42952196Smckusick cnt = 0; 43052196Smckusick else if ((off + cnt) > vap->va_size) 43152196Smckusick cnt = nfsm_rndup(vap->va_size - off); 43256285Smckusick nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)+NFSX_UNSIGNED+nfsm_rndup(cnt)); 43356285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 43452196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 43552196Smckusick len = left = cnt; 43652196Smckusick if (cnt > 0) { 43752196Smckusick /* 43852196Smckusick * Generate the mbuf list with the uio_iov ref. to it. 43952196Smckusick */ 44052196Smckusick i = 0; 44152196Smckusick m = m2 = mb; 44252196Smckusick MALLOC(iv, struct iovec *, 44352196Smckusick ((NFS_MAXDATA+MLEN-1)/MLEN) * sizeof (struct iovec), 44452196Smckusick M_TEMP, M_WAITOK); 44552196Smckusick iv2 = iv; 44652196Smckusick while (left > 0) { 44755057Spendry siz = min(M_TRAILINGSPACE(m), left); 44852196Smckusick if (siz > 0) { 44952196Smckusick m->m_len += siz; 45052196Smckusick iv->iov_base = bpos; 45152196Smckusick iv->iov_len = siz; 45252196Smckusick iv++; 45352196Smckusick i++; 45452196Smckusick left -= siz; 45552196Smckusick } 45652196Smckusick if (left > 0) { 45752196Smckusick MGET(m, M_WAIT, MT_DATA); 45852196Smckusick MCLGET(m, M_WAIT); 45952196Smckusick m->m_len = 0; 46052196Smckusick m2->m_next = m; 46152196Smckusick m2 = m; 46252196Smckusick bpos = mtod(m, caddr_t); 46352196Smckusick } 46452196Smckusick } 46552196Smckusick uiop->uio_iov = iv2; 46652196Smckusick uiop->uio_iovcnt = i; 46752196Smckusick uiop->uio_offset = off; 46852196Smckusick uiop->uio_resid = cnt; 46952196Smckusick uiop->uio_rw = UIO_READ; 47052196Smckusick uiop->uio_segflg = UIO_SYSSPACE; 47152196Smckusick error = VOP_READ(vp, uiop, IO_NODELOCKED, cred); 47252196Smckusick off = uiop->uio_offset; 47352196Smckusick FREE((caddr_t)iv2, M_TEMP); 47452196Smckusick if (error || (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp))) { 47552196Smckusick m_freem(mreq); 47652196Smckusick vput(vp); 47752196Smckusick nfsm_reply(0); 47852196Smckusick } 47952196Smckusick } else 48052196Smckusick uiop->uio_resid = 0; 48138418Smckusick vput(vp); 48239753Smckusick nfsm_srvfillattr; 48345877Smckusick len -= uiop->uio_resid; 48452196Smckusick tlen = nfsm_rndup(len); 48552196Smckusick if (cnt != tlen || tlen != len) 48652196Smckusick nfsm_adj(mb, cnt-tlen, tlen-len); 48748050Smckusick *tl = txdr_unsigned(len); 48838418Smckusick nfsm_srvdone; 48938418Smckusick } 49038418Smckusick 49138418Smckusick /* 49238418Smckusick * nfs write service 49338418Smckusick */ 49452196Smckusick nfsrv_write(nfsd, mrep, md, dpos, cred, nam, mrq) 49552196Smckusick struct nfsd *nfsd; 49652196Smckusick struct mbuf *mrep, *md; 49738418Smckusick caddr_t dpos; 49838418Smckusick struct ucred *cred; 49952196Smckusick struct mbuf *nam, **mrq; 50038418Smckusick { 50138418Smckusick register struct iovec *ivp; 50238418Smckusick register struct mbuf *mp; 50338884Smacklem register struct nfsv2_fattr *fp; 50441899Smckusick struct iovec iv[NFS_MAXIOVEC]; 50538418Smckusick struct vattr va; 50638418Smckusick register struct vattr *vap = &va; 50748050Smckusick register u_long *tl; 50839494Smckusick register long t1; 50939494Smckusick caddr_t bpos; 51052196Smckusick int error = 0, rdonly, cache, siz, len, xfer; 51156285Smckusick int ioflags = IO_SYNC | IO_NODELOCKED; 51239494Smckusick char *cp2; 51339753Smckusick struct mbuf *mb, *mb2, *mreq; 51438418Smckusick struct vnode *vp; 51538418Smckusick nfsv2fh_t nfh; 51638418Smckusick fhandle_t *fhp; 51738418Smckusick struct uio io, *uiop = &io; 51838418Smckusick off_t off; 51952196Smckusick u_quad_t frev; 52038418Smckusick 52138418Smckusick fhp = &nfh.fh_generic; 52238418Smckusick nfsm_srvmtofh(fhp); 52356285Smckusick nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED); 52456285Smckusick if (nfsd->nd_nqlflag == NQL_NOVAL) { 52556285Smckusick off = (off_t)fxdr_unsigned(u_long, *++tl); 52656285Smckusick tl += 2; 52756285Smckusick } else { 52856285Smckusick fxdr_hyper(tl, &off); 52956285Smckusick tl += 2; 53056285Smckusick if (fxdr_unsigned(u_long, *tl++)) 53156285Smckusick ioflags |= IO_APPEND; 53256285Smckusick } 53348050Smckusick len = fxdr_unsigned(long, *tl); 53438418Smckusick if (len > NFS_MAXDATA || len <= 0) { 53538418Smckusick error = EBADRPC; 53638418Smckusick nfsm_reply(0); 53738418Smckusick } 53838418Smckusick if (dpos == (mtod(md, caddr_t)+md->m_len)) { 53938418Smckusick mp = md->m_next; 54038418Smckusick if (mp == NULL) { 54138418Smckusick error = EBADRPC; 54238418Smckusick nfsm_reply(0); 54338418Smckusick } 54438418Smckusick } else { 54538418Smckusick mp = md; 54638418Smckusick siz = dpos-mtod(mp, caddr_t); 54738418Smckusick mp->m_len -= siz; 54838418Smckusick NFSMADV(mp, siz); 54938418Smckusick } 55052196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 55138418Smckusick nfsm_reply(0); 55252196Smckusick nqsrv_getl(vp, NQL_WRITE); 55352196Smckusick if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) { 55438418Smckusick vput(vp); 55538418Smckusick nfsm_reply(0); 55638418Smckusick } 55738418Smckusick uiop->uio_resid = 0; 55838418Smckusick uiop->uio_rw = UIO_WRITE; 55938418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 56048050Smckusick uiop->uio_procp = (struct proc *)0; 56138418Smckusick /* 56241899Smckusick * Do up to NFS_MAXIOVEC mbufs of write each iteration of the 56338418Smckusick * loop until done. 56438418Smckusick */ 56538418Smckusick while (len > 0 && uiop->uio_resid == 0) { 56638418Smckusick ivp = iv; 56738418Smckusick siz = 0; 56838418Smckusick uiop->uio_iov = ivp; 56938418Smckusick uiop->uio_iovcnt = 0; 57038418Smckusick uiop->uio_offset = off; 57141899Smckusick while (len > 0 && uiop->uio_iovcnt < NFS_MAXIOVEC && mp != NULL) { 57238418Smckusick ivp->iov_base = mtod(mp, caddr_t); 57338418Smckusick if (len < mp->m_len) 57438418Smckusick ivp->iov_len = xfer = len; 57538418Smckusick else 57638418Smckusick ivp->iov_len = xfer = mp->m_len; 57738418Smckusick #ifdef notdef 57838418Smckusick /* Not Yet .. */ 57938418Smckusick if (M_HASCL(mp) && (((u_long)ivp->iov_base) & CLOFSET) == 0) 58038418Smckusick ivp->iov_op = NULL; /* what should it be ?? */ 58138418Smckusick else 58238418Smckusick ivp->iov_op = NULL; 58338418Smckusick #endif 58438418Smckusick uiop->uio_iovcnt++; 58538418Smckusick ivp++; 58638418Smckusick len -= xfer; 58738418Smckusick siz += xfer; 58838418Smckusick mp = mp->m_next; 58938418Smckusick } 59038418Smckusick if (len > 0 && mp == NULL) { 59138418Smckusick error = EBADRPC; 59238418Smckusick vput(vp); 59338418Smckusick nfsm_reply(0); 59438418Smckusick } 59538418Smckusick uiop->uio_resid = siz; 59656285Smckusick if (error = VOP_WRITE(vp, uiop, ioflags, cred)) { 59738418Smckusick vput(vp); 59838418Smckusick nfsm_reply(0); 59938418Smckusick } 60039586Smckusick off = uiop->uio_offset; 60138418Smckusick } 60252196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 60338418Smckusick vput(vp); 60456285Smckusick nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 60556285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 60639753Smckusick nfsm_srvfillattr; 60752442Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 60852442Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 60952442Smckusick txdr_hyper(&vap->va_filerev, tl); 61052442Smckusick } 61138418Smckusick nfsm_srvdone; 61238418Smckusick } 61338418Smckusick 61438418Smckusick /* 61538418Smckusick * nfs create service 61638418Smckusick * now does a truncate to 0 length via. setattr if it already exists 61738418Smckusick */ 61852196Smckusick nfsrv_create(nfsd, mrep, md, dpos, cred, nam, mrq) 61952196Smckusick struct nfsd *nfsd; 62052196Smckusick struct mbuf *mrep, *md; 62138418Smckusick caddr_t dpos; 62238418Smckusick struct ucred *cred; 62352196Smckusick struct mbuf *nam, **mrq; 62438418Smckusick { 62538884Smacklem register struct nfsv2_fattr *fp; 62638418Smckusick struct vattr va; 62738418Smckusick register struct vattr *vap = &va; 62856285Smckusick register struct nfsv2_sattr *sp; 62956285Smckusick register u_long *tl; 63049742Smckusick struct nameidata nd; 63139494Smckusick register caddr_t cp; 63239494Smckusick register long t1; 63339494Smckusick caddr_t bpos; 63456285Smckusick int error = 0, rdev, cache, len, tsize; 63539494Smckusick char *cp2; 63639753Smckusick struct mbuf *mb, *mb2, *mreq; 63738418Smckusick struct vnode *vp; 63838418Smckusick nfsv2fh_t nfh; 63938418Smckusick fhandle_t *fhp; 64052196Smckusick u_quad_t frev; 64138418Smckusick 64252316Sheideman nd.ni_cnd.cn_nameiop = 0; 64338418Smckusick fhp = &nfh.fh_generic; 64438418Smckusick nfsm_srvmtofh(fhp); 64538418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 64652316Sheideman nd.ni_cnd.cn_cred = cred; 64752316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 64852316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART; 64952653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 65052653Smckusick nfsd->nd_procp)) 65138418Smckusick nfsm_reply(0); 65241361Smckusick VATTR_NULL(vap); 65356285Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 65438418Smckusick /* 65538418Smckusick * Iff doesn't exist, create it 65638418Smckusick * otherwise just truncate to 0 length 65738418Smckusick * should I set the mode too ?? 65838418Smckusick */ 65949742Smckusick if (nd.ni_vp == NULL) { 66056285Smckusick vap->va_type = IFTOVT(fxdr_unsigned(u_long, sp->sa_mode)); 66142867Smckusick if (vap->va_type == VNON) 66242867Smckusick vap->va_type = VREG; 66356285Smckusick vap->va_mode = nfstov_mode(sp->sa_mode); 66456285Smckusick if (nfsd->nd_nqlflag == NQL_NOVAL) 66556285Smckusick rdev = fxdr_unsigned(long, sp->sa_nfssize); 66656285Smckusick else 66756285Smckusick rdev = fxdr_unsigned(long, sp->sa_nqrdev); 66846988Smckusick if (vap->va_type == VREG || vap->va_type == VSOCK) { 66949742Smckusick vrele(nd.ni_startdir); 67052196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 67152234Sheideman if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) 67242242Smckusick nfsm_reply(0); 67352316Sheideman FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 67442242Smckusick } else if (vap->va_type == VCHR || vap->va_type == VBLK || 67542242Smckusick vap->va_type == VFIFO) { 67642242Smckusick if (vap->va_type == VCHR && rdev == 0xffffffff) 67742242Smckusick vap->va_type = VFIFO; 67842242Smckusick if (vap->va_type == VFIFO) { 67942242Smckusick #ifndef FIFO 68052234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 68149742Smckusick vput(nd.ni_dvp); 68242242Smckusick error = ENXIO; 68349742Smckusick goto out; 68442242Smckusick #endif /* FIFO */ 68552196Smckusick } else if (error = suser(cred, (u_short *)0)) { 68652234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 68749742Smckusick vput(nd.ni_dvp); 68849742Smckusick goto out; 68942242Smckusick } else 69042242Smckusick vap->va_rdev = (dev_t)rdev; 69152196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 69252234Sheideman if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) { 69349742Smckusick vrele(nd.ni_startdir); 69442242Smckusick nfsm_reply(0); 69549742Smckusick } 69652316Sheideman nd.ni_cnd.cn_nameiop = LOOKUP; 69752316Sheideman nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART); 69852316Sheideman nd.ni_cnd.cn_proc = nfsd->nd_procp; 69952316Sheideman nd.ni_cnd.cn_cred = nfsd->nd_procp->p_ucred; 70052316Sheideman if (error = lookup(&nd)) { 70152316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 70242242Smckusick nfsm_reply(0); 70349742Smckusick } 70452316Sheideman FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 70552316Sheideman if (nd.ni_cnd.cn_flags & ISSYMLINK) { 70649742Smckusick vrele(nd.ni_dvp); 70749742Smckusick vput(nd.ni_vp); 70852234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 70949742Smckusick error = EINVAL; 71049742Smckusick nfsm_reply(0); 71149742Smckusick } 71242242Smckusick } else { 71352234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 71449742Smckusick vput(nd.ni_dvp); 71542242Smckusick error = ENXIO; 71649742Smckusick goto out; 71742242Smckusick } 71849742Smckusick vp = nd.ni_vp; 71938418Smckusick } else { 72049742Smckusick vrele(nd.ni_startdir); 72152316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 72249742Smckusick vp = nd.ni_vp; 72349742Smckusick if (nd.ni_dvp == vp) 72449742Smckusick vrele(nd.ni_dvp); 72543359Smckusick else 72649742Smckusick vput(nd.ni_dvp); 72752234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 72856285Smckusick if (nfsd->nd_nqlflag == NQL_NOVAL) { 72956285Smckusick tsize = fxdr_unsigned(long, sp->sa_nfssize); 73056285Smckusick if (tsize != -1) 73156285Smckusick vap->va_size = (u_quad_t)tsize; 73256285Smckusick else 73356285Smckusick vap->va_size = -1; 73456285Smckusick } else 73556285Smckusick fxdr_hyper(&sp->sa_nqsize, &vap->va_size); 73656285Smckusick if (vap->va_size != -1) { 73756285Smckusick nqsrv_getl(vp, NQL_WRITE); 73856285Smckusick if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) { 73956285Smckusick vput(vp); 74056285Smckusick nfsm_reply(0); 74156285Smckusick } 74242506Smckusick } 74338418Smckusick } 74438418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 74541398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 74638418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 74738418Smckusick vput(vp); 74838418Smckusick nfsm_reply(0); 74938418Smckusick } 75052196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 75138418Smckusick vput(vp); 75256285Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 75338418Smckusick nfsm_srvfhtom(fhp); 75456285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 75539753Smckusick nfsm_srvfillattr; 75638418Smckusick return (error); 75738418Smckusick nfsmout: 75852316Sheideman if (nd.ni_cnd.cn_nameiop || nd.ni_cnd.cn_flags) 75951464Sbostic vrele(nd.ni_startdir); 76052234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 76149742Smckusick if (nd.ni_dvp == nd.ni_vp) 76249742Smckusick vrele(nd.ni_dvp); 76343359Smckusick else 76449742Smckusick vput(nd.ni_dvp); 76549742Smckusick if (nd.ni_vp) 76649742Smckusick vput(nd.ni_vp); 76738418Smckusick return (error); 76849742Smckusick 76949742Smckusick out: 77049742Smckusick vrele(nd.ni_startdir); 77152316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 77249742Smckusick nfsm_reply(0); 77338418Smckusick } 77438418Smckusick 77538418Smckusick /* 77638418Smckusick * nfs remove service 77738418Smckusick */ 77852196Smckusick nfsrv_remove(nfsd, mrep, md, dpos, cred, nam, mrq) 77952196Smckusick struct nfsd *nfsd; 78052196Smckusick struct mbuf *mrep, *md; 78138418Smckusick caddr_t dpos; 78238418Smckusick struct ucred *cred; 78352196Smckusick struct mbuf *nam, **mrq; 78438418Smckusick { 78549742Smckusick struct nameidata nd; 78648050Smckusick register u_long *tl; 78739494Smckusick register long t1; 78839494Smckusick caddr_t bpos; 78952196Smckusick int error = 0, cache, len; 79039494Smckusick char *cp2; 79139753Smckusick struct mbuf *mb, *mreq; 79238418Smckusick struct vnode *vp; 79338418Smckusick nfsv2fh_t nfh; 79438418Smckusick fhandle_t *fhp; 79552196Smckusick u_quad_t frev; 79638418Smckusick 79738418Smckusick fhp = &nfh.fh_generic; 79838418Smckusick nfsm_srvmtofh(fhp); 79938418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 80052316Sheideman nd.ni_cnd.cn_cred = cred; 80152316Sheideman nd.ni_cnd.cn_nameiop = DELETE; 80252316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 80352653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 80452653Smckusick nfsd->nd_procp)) 80538418Smckusick nfsm_reply(0); 80649742Smckusick vp = nd.ni_vp; 80738418Smckusick if (vp->v_type == VDIR && 80852196Smckusick (error = suser(cred, (u_short *)0))) 80938418Smckusick goto out; 81038418Smckusick /* 81149454Smckusick * The root of a mounted filesystem cannot be deleted. 81238418Smckusick */ 81338418Smckusick if (vp->v_flag & VROOT) { 81438418Smckusick error = EBUSY; 81538418Smckusick goto out; 81638418Smckusick } 81738418Smckusick if (vp->v_flag & VTEXT) 81845715Smckusick (void) vnode_pager_uncache(vp); 81938418Smckusick out: 82042467Smckusick if (!error) { 82152196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 82252196Smckusick nqsrv_getl(vp, NQL_WRITE); 82352234Sheideman error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 82442467Smckusick } else { 82552234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 82649742Smckusick if (nd.ni_dvp == vp) 82749742Smckusick vrele(nd.ni_dvp); 82843359Smckusick else 82949742Smckusick vput(nd.ni_dvp); 83042467Smckusick vput(vp); 83142467Smckusick } 83238418Smckusick nfsm_reply(0); 83338418Smckusick nfsm_srvdone; 83438418Smckusick } 83538418Smckusick 83638418Smckusick /* 83738418Smckusick * nfs rename service 83838418Smckusick */ 83952196Smckusick nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq) 84052196Smckusick struct nfsd *nfsd; 84152196Smckusick struct mbuf *mrep, *md; 84238418Smckusick caddr_t dpos; 84338418Smckusick struct ucred *cred; 84452196Smckusick struct mbuf *nam, **mrq; 84538418Smckusick { 84648050Smckusick register u_long *tl; 84739494Smckusick register long t1; 84839494Smckusick caddr_t bpos; 84952196Smckusick int error = 0, rdonly, cache, len, len2; 85039494Smckusick char *cp2; 85139753Smckusick struct mbuf *mb, *mreq; 85249742Smckusick struct nameidata fromnd, tond; 85338418Smckusick struct vnode *fvp, *tvp, *tdvp; 85438418Smckusick nfsv2fh_t fnfh, tnfh; 85538418Smckusick fhandle_t *ffhp, *tfhp; 85652196Smckusick u_quad_t frev; 85752196Smckusick uid_t saved_uid; 85838418Smckusick 85938418Smckusick ffhp = &fnfh.fh_generic; 86038418Smckusick tfhp = &tnfh.fh_generic; 86152316Sheideman fromnd.ni_cnd.cn_nameiop = 0; 86252316Sheideman tond.ni_cnd.cn_nameiop = 0; 86338418Smckusick nfsm_srvmtofh(ffhp); 86438418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 86538418Smckusick /* 86652196Smckusick * Remember our original uid so that we can reset cr_uid before 86752196Smckusick * the second nfs_namei() call, in case it is remapped. 86838418Smckusick */ 86952196Smckusick saved_uid = cred->cr_uid; 87052316Sheideman fromnd.ni_cnd.cn_cred = cred; 87152316Sheideman fromnd.ni_cnd.cn_nameiop = DELETE; 87252316Sheideman fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART; 87352653Smckusick if (error = nfs_namei(&fromnd, ffhp, len, nfsd->nd_slp, nam, &md, 87452653Smckusick &dpos, nfsd->nd_procp)) 87538418Smckusick nfsm_reply(0); 87649742Smckusick fvp = fromnd.ni_vp; 87738418Smckusick nfsm_srvmtofh(tfhp); 87841899Smckusick nfsm_strsiz(len2, NFS_MAXNAMLEN); 87952196Smckusick cred->cr_uid = saved_uid; 88052316Sheideman tond.ni_cnd.cn_cred = cred; 88152316Sheideman tond.ni_cnd.cn_nameiop = RENAME; 88252316Sheideman tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; 88352653Smckusick if (error = nfs_namei(&tond, tfhp, len2, nfsd->nd_slp, nam, &md, 88452653Smckusick &dpos, nfsd->nd_procp)) { 88552234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 88649742Smckusick vrele(fromnd.ni_dvp); 88742467Smckusick vrele(fvp); 88842467Smckusick goto out1; 88942467Smckusick } 89038425Smckusick tdvp = tond.ni_dvp; 89138425Smckusick tvp = tond.ni_vp; 89238418Smckusick if (tvp != NULL) { 89338418Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 89438418Smckusick error = EISDIR; 89538418Smckusick goto out; 89638418Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 89738418Smckusick error = ENOTDIR; 89838418Smckusick goto out; 89938418Smckusick } 90052196Smckusick if (tvp->v_type == VDIR && tvp->v_mountedhere) { 90152196Smckusick error = EXDEV; 90252196Smckusick goto out; 90352196Smckusick } 90438418Smckusick } 90552196Smckusick if (fvp->v_type == VDIR && fvp->v_mountedhere) { 90652196Smckusick error = EBUSY; 90752196Smckusick goto out; 90852196Smckusick } 90938418Smckusick if (fvp->v_mount != tdvp->v_mount) { 91038418Smckusick error = EXDEV; 91138418Smckusick goto out; 91238418Smckusick } 91349742Smckusick if (fvp == tdvp) 91438418Smckusick error = EINVAL; 91549742Smckusick /* 91649742Smckusick * If source is the same as the destination (that is the 91749742Smckusick * same vnode with the same name in the same directory), 91849742Smckusick * then there is nothing to do. 91949742Smckusick */ 92049742Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 92152316Sheideman fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 92252316Sheideman !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 92352316Sheideman fromnd.ni_cnd.cn_namelen)) 92449742Smckusick error = -1; 92538418Smckusick out: 92642467Smckusick if (!error) { 92752196Smckusick nqsrv_getl(fromnd.ni_dvp, NQL_WRITE); 92852196Smckusick nqsrv_getl(tdvp, NQL_WRITE); 92952196Smckusick if (tvp) 93052196Smckusick nqsrv_getl(tvp, NQL_WRITE); 93152234Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 93252234Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 93342467Smckusick } else { 93452234Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 93543359Smckusick if (tdvp == tvp) 93643359Smckusick vrele(tdvp); 93743359Smckusick else 93843359Smckusick vput(tdvp); 93942467Smckusick if (tvp) 94042467Smckusick vput(tvp); 94152234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 94249742Smckusick vrele(fromnd.ni_dvp); 94342467Smckusick vrele(fvp); 94438418Smckusick } 94546513Smckusick vrele(tond.ni_startdir); 94652316Sheideman FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 94738418Smckusick out1: 94849742Smckusick vrele(fromnd.ni_startdir); 94952316Sheideman FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 95038418Smckusick nfsm_reply(0); 95138418Smckusick return (error); 95249742Smckusick 95338418Smckusick nfsmout: 95452316Sheideman if (tond.ni_cnd.cn_nameiop || tond.ni_cnd.cn_flags) { 95549742Smckusick vrele(tond.ni_startdir); 95652316Sheideman FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 95749742Smckusick } 95852316Sheideman if (fromnd.ni_cnd.cn_nameiop || fromnd.ni_cnd.cn_flags) { 95949742Smckusick vrele(fromnd.ni_startdir); 96052316Sheideman FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 96152234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 96249742Smckusick vrele(fromnd.ni_dvp); 96349742Smckusick vrele(fvp); 96449742Smckusick } 96538418Smckusick return (error); 96638418Smckusick } 96738418Smckusick 96838418Smckusick /* 96938418Smckusick * nfs link service 97038418Smckusick */ 97152196Smckusick nfsrv_link(nfsd, mrep, md, dpos, cred, nam, mrq) 97252196Smckusick struct nfsd *nfsd; 97352196Smckusick struct mbuf *mrep, *md; 97438418Smckusick caddr_t dpos; 97538418Smckusick struct ucred *cred; 97652196Smckusick struct mbuf *nam, **mrq; 97738418Smckusick { 97849742Smckusick struct nameidata nd; 97948050Smckusick register u_long *tl; 98039494Smckusick register long t1; 98139494Smckusick caddr_t bpos; 98252196Smckusick int error = 0, rdonly, cache, len; 98339494Smckusick char *cp2; 98439753Smckusick struct mbuf *mb, *mreq; 98538418Smckusick struct vnode *vp, *xp; 98638418Smckusick nfsv2fh_t nfh, dnfh; 98738418Smckusick fhandle_t *fhp, *dfhp; 98852196Smckusick u_quad_t frev; 98938418Smckusick 99038418Smckusick fhp = &nfh.fh_generic; 99138418Smckusick dfhp = &dnfh.fh_generic; 99238418Smckusick nfsm_srvmtofh(fhp); 99338418Smckusick nfsm_srvmtofh(dfhp); 99438418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 99552196Smckusick if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 99638418Smckusick nfsm_reply(0); 99752196Smckusick if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0))) 99838418Smckusick goto out1; 99952316Sheideman nd.ni_cnd.cn_cred = cred; 100052316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 100152316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 100252653Smckusick if (error = nfs_namei(&nd, dfhp, len, nfsd->nd_slp, nam, &md, &dpos, 100352653Smckusick nfsd->nd_procp)) 100438418Smckusick goto out1; 100549742Smckusick xp = nd.ni_vp; 100638418Smckusick if (xp != NULL) { 100738418Smckusick error = EEXIST; 100838418Smckusick goto out; 100938418Smckusick } 101049742Smckusick xp = nd.ni_dvp; 101138418Smckusick if (vp->v_mount != xp->v_mount) 101238418Smckusick error = EXDEV; 101338418Smckusick out: 101442467Smckusick if (!error) { 101552196Smckusick nqsrv_getl(vp, NQL_WRITE); 101652196Smckusick nqsrv_getl(xp, NQL_WRITE); 101752933Smckusick error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 101842467Smckusick } else { 101952234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 102049742Smckusick if (nd.ni_dvp == nd.ni_vp) 102149742Smckusick vrele(nd.ni_dvp); 102243359Smckusick else 102349742Smckusick vput(nd.ni_dvp); 102449742Smckusick if (nd.ni_vp) 102549742Smckusick vrele(nd.ni_vp); 102642467Smckusick } 102738418Smckusick out1: 102838418Smckusick vrele(vp); 102938418Smckusick nfsm_reply(0); 103038418Smckusick nfsm_srvdone; 103138418Smckusick } 103238418Smckusick 103338418Smckusick /* 103438418Smckusick * nfs symbolic link service 103538418Smckusick */ 103652196Smckusick nfsrv_symlink(nfsd, mrep, md, dpos, cred, nam, mrq) 103752196Smckusick struct nfsd *nfsd; 103852196Smckusick struct mbuf *mrep, *md; 103938418Smckusick caddr_t dpos; 104038418Smckusick struct ucred *cred; 104152196Smckusick struct mbuf *nam, **mrq; 104238418Smckusick { 104338418Smckusick struct vattr va; 104449742Smckusick struct nameidata nd; 104538418Smckusick register struct vattr *vap = &va; 104648050Smckusick register u_long *tl; 104739494Smckusick register long t1; 104845285Smckusick struct nfsv2_sattr *sp; 104939494Smckusick caddr_t bpos; 105041899Smckusick struct uio io; 105141899Smckusick struct iovec iv; 105252196Smckusick int error = 0, rdonly, cache, len, len2; 105341899Smckusick char *pathcp, *cp2; 105439753Smckusick struct mbuf *mb, *mreq; 105538418Smckusick nfsv2fh_t nfh; 105638418Smckusick fhandle_t *fhp; 105752196Smckusick u_quad_t frev; 105838418Smckusick 105941899Smckusick pathcp = (char *)0; 106038418Smckusick fhp = &nfh.fh_generic; 106138418Smckusick nfsm_srvmtofh(fhp); 106238418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 106352316Sheideman nd.ni_cnd.cn_cred = cred; 106452316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 106552316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 106652653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 106752653Smckusick nfsd->nd_procp)) 106842467Smckusick goto out; 106941899Smckusick nfsm_strsiz(len2, NFS_MAXPATHLEN); 107041899Smckusick MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK); 107141899Smckusick iv.iov_base = pathcp; 107241899Smckusick iv.iov_len = len2; 107341899Smckusick io.uio_resid = len2; 107441899Smckusick io.uio_offset = 0; 107541899Smckusick io.uio_iov = &iv; 107641899Smckusick io.uio_iovcnt = 1; 107741899Smckusick io.uio_segflg = UIO_SYSSPACE; 107841899Smckusick io.uio_rw = UIO_READ; 107948050Smckusick io.uio_procp = (struct proc *)0; 108041899Smckusick nfsm_mtouio(&io, len2); 108156285Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 108241899Smckusick *(pathcp + len2) = '\0'; 108349742Smckusick if (nd.ni_vp) { 108452234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 108549742Smckusick if (nd.ni_dvp == nd.ni_vp) 108649742Smckusick vrele(nd.ni_dvp); 108743359Smckusick else 108849742Smckusick vput(nd.ni_dvp); 108949742Smckusick vrele(nd.ni_vp); 109038418Smckusick error = EEXIST; 109138418Smckusick goto out; 109238418Smckusick } 109341361Smckusick VATTR_NULL(vap); 109445285Smckusick vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode); 109552196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 109652234Sheideman error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp); 109738418Smckusick out: 109841899Smckusick if (pathcp) 109941899Smckusick FREE(pathcp, M_TEMP); 110038418Smckusick nfsm_reply(0); 110138418Smckusick return (error); 110238418Smckusick nfsmout: 110352234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 110449742Smckusick if (nd.ni_dvp == nd.ni_vp) 110549742Smckusick vrele(nd.ni_dvp); 110643359Smckusick else 110749742Smckusick vput(nd.ni_dvp); 110849742Smckusick if (nd.ni_vp) 110949742Smckusick vrele(nd.ni_vp); 111041899Smckusick if (pathcp) 111141899Smckusick FREE(pathcp, M_TEMP); 111238418Smckusick return (error); 111338418Smckusick } 111438418Smckusick 111538418Smckusick /* 111638418Smckusick * nfs mkdir service 111738418Smckusick */ 111852196Smckusick nfsrv_mkdir(nfsd, mrep, md, dpos, cred, nam, mrq) 111952196Smckusick struct nfsd *nfsd; 112052196Smckusick struct mbuf *mrep, *md; 112138418Smckusick caddr_t dpos; 112238418Smckusick struct ucred *cred; 112352196Smckusick struct mbuf *nam, **mrq; 112438418Smckusick { 112538418Smckusick struct vattr va; 112638418Smckusick register struct vattr *vap = &va; 112738884Smacklem register struct nfsv2_fattr *fp; 112849742Smckusick struct nameidata nd; 112939494Smckusick register caddr_t cp; 113048050Smckusick register u_long *tl; 113139494Smckusick register long t1; 113239494Smckusick caddr_t bpos; 113352196Smckusick int error = 0, rdonly, cache, len; 113439494Smckusick char *cp2; 113539753Smckusick struct mbuf *mb, *mb2, *mreq; 113638418Smckusick struct vnode *vp; 113738418Smckusick nfsv2fh_t nfh; 113838418Smckusick fhandle_t *fhp; 113952196Smckusick u_quad_t frev; 114038418Smckusick 114138418Smckusick fhp = &nfh.fh_generic; 114238418Smckusick nfsm_srvmtofh(fhp); 114338418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 114452316Sheideman nd.ni_cnd.cn_cred = cred; 114552316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 114652316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 114752653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 114852653Smckusick nfsd->nd_procp)) 114938418Smckusick nfsm_reply(0); 115052196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 115141361Smckusick VATTR_NULL(vap); 115238418Smckusick vap->va_type = VDIR; 115348050Smckusick vap->va_mode = nfstov_mode(*tl++); 115449742Smckusick vp = nd.ni_vp; 115538418Smckusick if (vp != NULL) { 115652234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 115749742Smckusick if (nd.ni_dvp == vp) 115849742Smckusick vrele(nd.ni_dvp); 115943359Smckusick else 116049742Smckusick vput(nd.ni_dvp); 116142467Smckusick vrele(vp); 116238418Smckusick error = EEXIST; 116338418Smckusick nfsm_reply(0); 116438418Smckusick } 116552196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 116652234Sheideman if (error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) 116738418Smckusick nfsm_reply(0); 116849742Smckusick vp = nd.ni_vp; 116938418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 117041398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 117138418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 117238418Smckusick vput(vp); 117338418Smckusick nfsm_reply(0); 117438418Smckusick } 117552196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 117638418Smckusick vput(vp); 117756285Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 117838418Smckusick nfsm_srvfhtom(fhp); 117956285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 118039753Smckusick nfsm_srvfillattr; 118138418Smckusick return (error); 118238418Smckusick nfsmout: 118352234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 118449742Smckusick if (nd.ni_dvp == nd.ni_vp) 118549742Smckusick vrele(nd.ni_dvp); 118643359Smckusick else 118749742Smckusick vput(nd.ni_dvp); 118849742Smckusick if (nd.ni_vp) 118949742Smckusick vrele(nd.ni_vp); 119038418Smckusick return (error); 119138418Smckusick } 119238418Smckusick 119338418Smckusick /* 119438418Smckusick * nfs rmdir service 119538418Smckusick */ 119652196Smckusick nfsrv_rmdir(nfsd, mrep, md, dpos, cred, nam, mrq) 119752196Smckusick struct nfsd *nfsd; 119852196Smckusick struct mbuf *mrep, *md; 119938418Smckusick caddr_t dpos; 120038418Smckusick struct ucred *cred; 120152196Smckusick struct mbuf *nam, **mrq; 120238418Smckusick { 120348050Smckusick register u_long *tl; 120439494Smckusick register long t1; 120539494Smckusick caddr_t bpos; 120652196Smckusick int error = 0, rdonly, cache, len; 120739494Smckusick char *cp2; 120839753Smckusick struct mbuf *mb, *mreq; 120938418Smckusick struct vnode *vp; 121038418Smckusick nfsv2fh_t nfh; 121138418Smckusick fhandle_t *fhp; 121249742Smckusick struct nameidata nd; 121352196Smckusick u_quad_t frev; 121438418Smckusick 121538418Smckusick fhp = &nfh.fh_generic; 121638418Smckusick nfsm_srvmtofh(fhp); 121738418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 121852316Sheideman nd.ni_cnd.cn_cred = cred; 121952316Sheideman nd.ni_cnd.cn_nameiop = DELETE; 122052316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 122152653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 122252653Smckusick nfsd->nd_procp)) 122338418Smckusick nfsm_reply(0); 122449742Smckusick vp = nd.ni_vp; 122538418Smckusick if (vp->v_type != VDIR) { 122638418Smckusick error = ENOTDIR; 122738418Smckusick goto out; 122838418Smckusick } 122938418Smckusick /* 123038418Smckusick * No rmdir "." please. 123138418Smckusick */ 123249742Smckusick if (nd.ni_dvp == vp) { 123338418Smckusick error = EINVAL; 123438418Smckusick goto out; 123538418Smckusick } 123638418Smckusick /* 123749454Smckusick * The root of a mounted filesystem cannot be deleted. 123838418Smckusick */ 123938418Smckusick if (vp->v_flag & VROOT) 124038418Smckusick error = EBUSY; 124138418Smckusick out: 124242467Smckusick if (!error) { 124352196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 124452196Smckusick nqsrv_getl(vp, NQL_WRITE); 124552234Sheideman error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 124642467Smckusick } else { 124752234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 124849742Smckusick if (nd.ni_dvp == nd.ni_vp) 124949742Smckusick vrele(nd.ni_dvp); 125043359Smckusick else 125149742Smckusick vput(nd.ni_dvp); 125242467Smckusick vput(vp); 125342467Smckusick } 125438418Smckusick nfsm_reply(0); 125538418Smckusick nfsm_srvdone; 125638418Smckusick } 125738418Smckusick 125838418Smckusick /* 125938418Smckusick * nfs readdir service 126038418Smckusick * - mallocs what it thinks is enough to read 126148050Smckusick * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR 126238418Smckusick * - calls VOP_READDIR() 126340115Smckusick * - loops around building the reply 126438425Smckusick * if the output generated exceeds count break out of loop 126538425Smckusick * The nfsm_clget macro is used here so that the reply will be packed 126638425Smckusick * tightly in mbuf clusters. 126738418Smckusick * - it only knows that it has encountered eof when the VOP_READDIR() 126838425Smckusick * reads nothing 126938418Smckusick * - as such one readdir rpc will return eof false although you are there 127038425Smckusick * and then the next will return eof 127152441Smckusick * - it trims out records with d_fileno == 0 127238425Smckusick * this doesn't matter for Unix clients, but they might confuse clients 127338425Smckusick * for other os'. 127438418Smckusick * NB: It is tempting to set eof to true if the VOP_READDIR() reads less 127538425Smckusick * than requested, but this may not apply to all filesystems. For 127638425Smckusick * example, client NFS does not { although it is never remote mounted 127738425Smckusick * anyhow } 127852196Smckusick * The alternate call nqnfsrv_readdirlook() does lookups as well. 127938418Smckusick * PS: The NFS protocol spec. does not clarify what the "count" byte 128038425Smckusick * argument is a count of.. just name strings and file id's or the 128138425Smckusick * entire reply rpc or ... 128238425Smckusick * I tried just file name and id sizes and it confused the Sun client, 128338425Smckusick * so I am using the full rpc size now. The "paranoia.." comment refers 128438425Smckusick * to including the status longwords that are not a part of the dir. 128538425Smckusick * "entry" structures, but are in the rpc. 128638418Smckusick */ 128752196Smckusick struct flrep { 128852196Smckusick u_long fl_cachable; 128952196Smckusick u_long fl_duration; 129055528Smckusick u_long fl_frev[2]; 129152196Smckusick nfsv2fh_t fl_nfh; 129256285Smckusick u_long fl_fattr[NFSX_NQFATTR / sizeof (u_long)]; 129352196Smckusick }; 129452196Smckusick 129552196Smckusick nfsrv_readdir(nfsd, mrep, md, dpos, cred, nam, mrq) 129652196Smckusick struct nfsd *nfsd; 129738418Smckusick struct mbuf *mrep, *md; 129838418Smckusick caddr_t dpos; 129938418Smckusick struct ucred *cred; 130052196Smckusick struct mbuf *nam, **mrq; 130138418Smckusick { 130238418Smckusick register char *bp, *be; 130338418Smckusick register struct mbuf *mp; 130452441Smckusick register struct dirent *dp; 130539494Smckusick register caddr_t cp; 130648050Smckusick register u_long *tl; 130739494Smckusick register long t1; 130839494Smckusick caddr_t bpos; 130952196Smckusick struct mbuf *mb, *mb2, *mreq, *mp2; 131052196Smckusick char *cpos, *cend, *cp2, *rbuf; 131138418Smckusick struct vnode *vp; 131238418Smckusick nfsv2fh_t nfh; 131338418Smckusick fhandle_t *fhp; 131438418Smckusick struct uio io; 131538418Smckusick struct iovec iv; 131652196Smckusick struct vattr va; 131752196Smckusick int len, nlen, rem, xfer, tsiz, i, error = 0; 131852196Smckusick int siz, cnt, fullsiz, eofflag, rdonly, cache; 131952196Smckusick u_quad_t frev; 132056285Smckusick u_long on, off, toff; 132138418Smckusick 132238418Smckusick fhp = &nfh.fh_generic; 132338418Smckusick nfsm_srvmtofh(fhp); 132452196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 132556285Smckusick toff = fxdr_unsigned(u_long, *tl++); 132648050Smckusick off = (toff & ~(NFS_DIRBLKSIZ-1)); 132748050Smckusick on = (toff & (NFS_DIRBLKSIZ-1)); 132848050Smckusick cnt = fxdr_unsigned(int, *tl); 132948050Smckusick siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); 133041899Smckusick if (cnt > NFS_MAXREADDIR) 133141899Smckusick siz = NFS_MAXREADDIR; 133238418Smckusick fullsiz = siz; 133352196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 133438418Smckusick nfsm_reply(0); 133552196Smckusick nqsrv_getl(vp, NQL_READ); 133652196Smckusick if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { 133738418Smckusick vput(vp); 133838418Smckusick nfsm_reply(0); 133938418Smckusick } 134038418Smckusick VOP_UNLOCK(vp); 134138418Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 134238418Smckusick again: 134338418Smckusick iv.iov_base = rbuf; 134438418Smckusick iv.iov_len = fullsiz; 134538418Smckusick io.uio_iov = &iv; 134638418Smckusick io.uio_iovcnt = 1; 134756285Smckusick io.uio_offset = (off_t)off; 134838418Smckusick io.uio_resid = fullsiz; 134938418Smckusick io.uio_segflg = UIO_SYSSPACE; 135038418Smckusick io.uio_rw = UIO_READ; 135148050Smckusick io.uio_procp = (struct proc *)0; 135254446Smckusick error = VOP_READDIR(vp, &io, cred); 135356285Smckusick off = (off_t)io.uio_offset; 135438418Smckusick if (error) { 135538418Smckusick vrele(vp); 135638418Smckusick free((caddr_t)rbuf, M_TEMP); 135738418Smckusick nfsm_reply(0); 135838418Smckusick } 135954446Smckusick if (io.uio_resid < fullsiz) 136054446Smckusick eofflag = 0; 136154446Smckusick else 136254446Smckusick eofflag = 1; 136338418Smckusick if (io.uio_resid) { 136438418Smckusick siz -= io.uio_resid; 136538418Smckusick 136638418Smckusick /* 136738418Smckusick * If nothing read, return eof 136838418Smckusick * rpc reply 136938418Smckusick */ 137038418Smckusick if (siz == 0) { 137138418Smckusick vrele(vp); 137238418Smckusick nfsm_reply(2*NFSX_UNSIGNED); 137348050Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 137448050Smckusick *tl++ = nfs_false; 137548050Smckusick *tl = nfs_true; 137638418Smckusick FREE((caddr_t)rbuf, M_TEMP); 137738418Smckusick return (0); 137838418Smckusick } 137938418Smckusick } 138040115Smckusick 138138418Smckusick /* 138238418Smckusick * Check for degenerate cases of nothing useful read. 138340115Smckusick * If so go try again 138438418Smckusick */ 138540115Smckusick cpos = rbuf + on; 138640115Smckusick cend = rbuf + siz; 138752441Smckusick dp = (struct dirent *)cpos; 138852441Smckusick while (cpos < cend && dp->d_fileno == 0) { 138940115Smckusick cpos += dp->d_reclen; 139052441Smckusick dp = (struct dirent *)cpos; 139140115Smckusick } 139240115Smckusick if (cpos >= cend) { 139338418Smckusick toff = off; 139438418Smckusick siz = fullsiz; 139538418Smckusick on = 0; 139638418Smckusick goto again; 139738418Smckusick } 139840115Smckusick 139940115Smckusick cpos = rbuf + on; 140040115Smckusick cend = rbuf + siz; 140152441Smckusick dp = (struct dirent *)cpos; 140252196Smckusick len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 140352196Smckusick nfsm_reply(siz); 140452196Smckusick mp = mp2 = mb; 140552196Smckusick bp = bpos; 140652196Smckusick be = bp + M_TRAILINGSPACE(mp); 140752196Smckusick 140852196Smckusick /* Loop through the records and build reply */ 140952196Smckusick while (cpos < cend) { 141052441Smckusick if (dp->d_fileno != 0) { 141152196Smckusick nlen = dp->d_namlen; 141252196Smckusick rem = nfsm_rndup(nlen)-nlen; 141352196Smckusick len += (4*NFSX_UNSIGNED + nlen + rem); 141452196Smckusick if (len > cnt) { 141552196Smckusick eofflag = 0; 141652196Smckusick break; 141752196Smckusick } 141852441Smckusick /* 141952441Smckusick * Build the directory record xdr from 142052441Smckusick * the dirent entry. 142152441Smckusick */ 142252196Smckusick nfsm_clget; 142352196Smckusick *tl = nfs_true; 142452196Smckusick bp += NFSX_UNSIGNED; 142552196Smckusick nfsm_clget; 142652441Smckusick *tl = txdr_unsigned(dp->d_fileno); 142752196Smckusick bp += NFSX_UNSIGNED; 142852196Smckusick nfsm_clget; 142952196Smckusick *tl = txdr_unsigned(nlen); 143052196Smckusick bp += NFSX_UNSIGNED; 143152196Smckusick 143252196Smckusick /* And loop around copying the name */ 143352196Smckusick xfer = nlen; 143452196Smckusick cp = dp->d_name; 143552196Smckusick while (xfer > 0) { 143652196Smckusick nfsm_clget; 143752196Smckusick if ((bp+xfer) > be) 143852196Smckusick tsiz = be-bp; 143952196Smckusick else 144052196Smckusick tsiz = xfer; 144152196Smckusick bcopy(cp, bp, tsiz); 144252196Smckusick bp += tsiz; 144352196Smckusick xfer -= tsiz; 144452196Smckusick if (xfer > 0) 144552196Smckusick cp += tsiz; 144652196Smckusick } 144752196Smckusick /* And null pad to a long boundary */ 144852196Smckusick for (i = 0; i < rem; i++) 144952196Smckusick *bp++ = '\0'; 145052196Smckusick nfsm_clget; 145152196Smckusick 145252196Smckusick /* Finish off the record */ 145352196Smckusick toff += dp->d_reclen; 145452196Smckusick *tl = txdr_unsigned(toff); 145552196Smckusick bp += NFSX_UNSIGNED; 145652196Smckusick } else 145752196Smckusick toff += dp->d_reclen; 145852196Smckusick cpos += dp->d_reclen; 145952441Smckusick dp = (struct dirent *)cpos; 146052196Smckusick } 146138418Smckusick vrele(vp); 146252196Smckusick nfsm_clget; 146352196Smckusick *tl = nfs_false; 146452196Smckusick bp += NFSX_UNSIGNED; 146552196Smckusick nfsm_clget; 146652196Smckusick if (eofflag) 146752196Smckusick *tl = nfs_true; 146852196Smckusick else 146952196Smckusick *tl = nfs_false; 147052196Smckusick bp += NFSX_UNSIGNED; 147152196Smckusick if (mp != mb) { 147252196Smckusick if (bp < be) 147352196Smckusick mp->m_len = bp - mtod(mp, caddr_t); 147452196Smckusick } else 147552196Smckusick mp->m_len += bp - bpos; 147652196Smckusick FREE(rbuf, M_TEMP); 147752196Smckusick nfsm_srvdone; 147852196Smckusick } 147952196Smckusick 148052196Smckusick nqnfsrv_readdirlook(nfsd, mrep, md, dpos, cred, nam, mrq) 148152196Smckusick struct nfsd *nfsd; 148252196Smckusick struct mbuf *mrep, *md; 148352196Smckusick caddr_t dpos; 148452196Smckusick struct ucred *cred; 148552196Smckusick struct mbuf *nam, **mrq; 148652196Smckusick { 148752196Smckusick register char *bp, *be; 148852196Smckusick register struct mbuf *mp; 148952441Smckusick register struct dirent *dp; 149052196Smckusick register caddr_t cp; 149152196Smckusick register u_long *tl; 149252196Smckusick register long t1; 149352196Smckusick caddr_t bpos; 149452196Smckusick struct mbuf *mb, *mb2, *mreq, *mp2; 149552196Smckusick char *cpos, *cend, *cp2, *rbuf; 149652196Smckusick struct vnode *vp, *nvp; 149752196Smckusick struct flrep fl; 149852196Smckusick nfsv2fh_t nfh; 149952196Smckusick fhandle_t *fhp; 150052196Smckusick struct uio io; 150152196Smckusick struct iovec iv; 150252196Smckusick struct vattr va, *vap = &va; 150352196Smckusick struct nfsv2_fattr *fp; 150452196Smckusick int len, nlen, rem, xfer, tsiz, i, error = 0, duration2, cache2; 150552196Smckusick int siz, cnt, fullsiz, eofflag, rdonly, cache; 150652196Smckusick u_quad_t frev, frev2; 150756285Smckusick u_long on, off, toff; 150852196Smckusick 150952196Smckusick fhp = &nfh.fh_generic; 151052196Smckusick nfsm_srvmtofh(fhp); 151152196Smckusick nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED); 151256285Smckusick toff = fxdr_unsigned(u_long, *tl++); 151352196Smckusick off = (toff & ~(NFS_DIRBLKSIZ-1)); 151452196Smckusick on = (toff & (NFS_DIRBLKSIZ-1)); 151552196Smckusick cnt = fxdr_unsigned(int, *tl++); 151652196Smckusick duration2 = fxdr_unsigned(int, *tl); 151752196Smckusick siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); 151852196Smckusick if (cnt > NFS_MAXREADDIR) 151952196Smckusick siz = NFS_MAXREADDIR; 152052196Smckusick fullsiz = siz; 152152196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 152252196Smckusick nfsm_reply(0); 152352196Smckusick nqsrv_getl(vp, NQL_READ); 152452196Smckusick if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { 152552196Smckusick vput(vp); 152652196Smckusick nfsm_reply(0); 152752196Smckusick } 152852196Smckusick VOP_UNLOCK(vp); 152952196Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 153052196Smckusick again: 153152196Smckusick iv.iov_base = rbuf; 153252196Smckusick iv.iov_len = fullsiz; 153352196Smckusick io.uio_iov = &iv; 153452196Smckusick io.uio_iovcnt = 1; 153556285Smckusick io.uio_offset = (off_t)off; 153652196Smckusick io.uio_resid = fullsiz; 153752196Smckusick io.uio_segflg = UIO_SYSSPACE; 153852196Smckusick io.uio_rw = UIO_READ; 153952196Smckusick io.uio_procp = (struct proc *)0; 154054446Smckusick error = VOP_READDIR(vp, &io, cred); 154156285Smckusick off = (u_long)io.uio_offset; 154252196Smckusick if (error) { 154352196Smckusick vrele(vp); 154452196Smckusick free((caddr_t)rbuf, M_TEMP); 154552196Smckusick nfsm_reply(0); 154652196Smckusick } 154754446Smckusick if (io.uio_resid < fullsiz) 154854446Smckusick eofflag = 0; 154954446Smckusick else 155054446Smckusick eofflag = 1; 155152196Smckusick if (io.uio_resid) { 155252196Smckusick siz -= io.uio_resid; 155352196Smckusick 155452196Smckusick /* 155552196Smckusick * If nothing read, return eof 155652196Smckusick * rpc reply 155752196Smckusick */ 155852196Smckusick if (siz == 0) { 155952196Smckusick vrele(vp); 156056285Smckusick nfsm_reply(2 * NFSX_UNSIGNED); 156156285Smckusick nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); 156252196Smckusick *tl++ = nfs_false; 156352196Smckusick *tl = nfs_true; 156452196Smckusick FREE((caddr_t)rbuf, M_TEMP); 156552196Smckusick return (0); 156652196Smckusick } 156752196Smckusick } 156852196Smckusick 156952196Smckusick /* 157052196Smckusick * Check for degenerate cases of nothing useful read. 157152196Smckusick * If so go try again 157252196Smckusick */ 157352196Smckusick cpos = rbuf + on; 157452196Smckusick cend = rbuf + siz; 157552441Smckusick dp = (struct dirent *)cpos; 157652441Smckusick while (cpos < cend && dp->d_fileno == 0) { 157752196Smckusick cpos += dp->d_reclen; 157852441Smckusick dp = (struct dirent *)cpos; 157952196Smckusick } 158052196Smckusick if (cpos >= cend) { 158152196Smckusick toff = off; 158252196Smckusick siz = fullsiz; 158352196Smckusick on = 0; 158452196Smckusick goto again; 158552196Smckusick } 158652196Smckusick 158752196Smckusick cpos = rbuf + on; 158852196Smckusick cend = rbuf + siz; 158952441Smckusick dp = (struct dirent *)cpos; 159056285Smckusick len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 159138418Smckusick nfsm_reply(siz); 159252196Smckusick mp = mp2 = mb; 159352196Smckusick bp = bpos; 159452196Smckusick be = bp + M_TRAILINGSPACE(mp); 159538418Smckusick 159638418Smckusick /* Loop through the records and build reply */ 159738418Smckusick while (cpos < cend) { 159852441Smckusick if (dp->d_fileno != 0) { 159938418Smckusick nlen = dp->d_namlen; 160038418Smckusick rem = nfsm_rndup(nlen)-nlen; 160138425Smckusick 160238418Smckusick /* 160352196Smckusick * For readdir_and_lookup get the vnode using 160452196Smckusick * the file number. 160538418Smckusick */ 160654665Smckusick if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp)) 160752196Smckusick goto invalid; 160855655Smckusick bzero((caddr_t)&fl.fl_nfh, sizeof (nfsv2fh_t)); 160955655Smckusick fl.fl_nfh.fh_generic.fh_fsid = 161055655Smckusick nvp->v_mount->mnt_stat.f_fsid; 161155655Smckusick if (VFS_VPTOFH(nvp, &fl.fl_nfh.fh_generic.fh_fid)) { 161255655Smckusick vput(nvp); 161355655Smckusick goto invalid; 161455655Smckusick } 161556285Smckusick if (duration2) { 161656285Smckusick (void) nqsrv_getlease(nvp, &duration2, NQL_READ, 161756285Smckusick nfsd, nam, &cache2, &frev2, cred); 161856285Smckusick fl.fl_duration = txdr_unsigned(duration2); 161956285Smckusick fl.fl_cachable = txdr_unsigned(cache2); 162056285Smckusick txdr_hyper(&frev2, fl.fl_frev); 162156285Smckusick } else 162256285Smckusick fl.fl_duration = 0; 162352196Smckusick if (VOP_GETATTR(nvp, vap, cred, nfsd->nd_procp)) { 162452196Smckusick vput(nvp); 162552196Smckusick goto invalid; 162652196Smckusick } 162752196Smckusick vput(nvp); 162856285Smckusick fp = (struct nfsv2_fattr *)&fl.fl_fattr; 162952196Smckusick nfsm_srvfillattr; 163052196Smckusick len += (4*NFSX_UNSIGNED + nlen + rem + NFSX_FH 163156285Smckusick + NFSX_NQFATTR); 163241899Smckusick if (len > cnt) { 163341899Smckusick eofflag = 0; 163438418Smckusick break; 163541899Smckusick } 163652441Smckusick /* 163752441Smckusick * Build the directory record xdr from 163852441Smckusick * the dirent entry. 163952441Smckusick */ 164038418Smckusick nfsm_clget; 164148050Smckusick *tl = nfs_true; 164238418Smckusick bp += NFSX_UNSIGNED; 164352196Smckusick 164452196Smckusick /* 164552196Smckusick * For readdir_and_lookup copy the stuff out. 164652196Smckusick */ 164752196Smckusick xfer = sizeof (struct flrep); 164852196Smckusick cp = (caddr_t)&fl; 164952196Smckusick while (xfer > 0) { 165052196Smckusick nfsm_clget; 165152196Smckusick if ((bp+xfer) > be) 165252196Smckusick tsiz = be-bp; 165352196Smckusick else 165452196Smckusick tsiz = xfer; 165552196Smckusick bcopy(cp, bp, tsiz); 165652196Smckusick bp += tsiz; 165752196Smckusick xfer -= tsiz; 165852196Smckusick if (xfer > 0) 165952196Smckusick cp += tsiz; 166052196Smckusick } 166138418Smckusick nfsm_clget; 166252441Smckusick *tl = txdr_unsigned(dp->d_fileno); 166338418Smckusick bp += NFSX_UNSIGNED; 166438418Smckusick nfsm_clget; 166548050Smckusick *tl = txdr_unsigned(nlen); 166638418Smckusick bp += NFSX_UNSIGNED; 166738425Smckusick 166852196Smckusick /* And loop around copying the name */ 166938418Smckusick xfer = nlen; 167038418Smckusick cp = dp->d_name; 167138418Smckusick while (xfer > 0) { 167238418Smckusick nfsm_clget; 167338418Smckusick if ((bp+xfer) > be) 167438418Smckusick tsiz = be-bp; 167538418Smckusick else 167638418Smckusick tsiz = xfer; 167738418Smckusick bcopy(cp, bp, tsiz); 167838418Smckusick bp += tsiz; 167938418Smckusick xfer -= tsiz; 168038418Smckusick if (xfer > 0) 168138418Smckusick cp += tsiz; 168238418Smckusick } 168338418Smckusick /* And null pad to a long boundary */ 168438418Smckusick for (i = 0; i < rem; i++) 168538418Smckusick *bp++ = '\0'; 168638418Smckusick nfsm_clget; 168738425Smckusick 168838418Smckusick /* Finish off the record */ 168938418Smckusick toff += dp->d_reclen; 169048050Smckusick *tl = txdr_unsigned(toff); 169138418Smckusick bp += NFSX_UNSIGNED; 169238418Smckusick } else 169352196Smckusick invalid: 169438418Smckusick toff += dp->d_reclen; 169538418Smckusick cpos += dp->d_reclen; 169652441Smckusick dp = (struct dirent *)cpos; 169738418Smckusick } 169852196Smckusick vrele(vp); 169938418Smckusick nfsm_clget; 170048050Smckusick *tl = nfs_false; 170138418Smckusick bp += NFSX_UNSIGNED; 170238418Smckusick nfsm_clget; 170340296Smckusick if (eofflag) 170448050Smckusick *tl = nfs_true; 170540296Smckusick else 170648050Smckusick *tl = nfs_false; 170738418Smckusick bp += NFSX_UNSIGNED; 170852196Smckusick if (mp != mb) { 170952196Smckusick if (bp < be) 171052196Smckusick mp->m_len = bp - mtod(mp, caddr_t); 171152196Smckusick } else 171252196Smckusick mp->m_len += bp - bpos; 171338418Smckusick FREE(rbuf, M_TEMP); 171438418Smckusick nfsm_srvdone; 171538418Smckusick } 171638418Smckusick 171738418Smckusick /* 171838418Smckusick * nfs statfs service 171938418Smckusick */ 172052196Smckusick nfsrv_statfs(nfsd, mrep, md, dpos, cred, nam, mrq) 172152196Smckusick struct nfsd *nfsd; 172238418Smckusick struct mbuf *mrep, *md; 172338418Smckusick caddr_t dpos; 172438418Smckusick struct ucred *cred; 172552196Smckusick struct mbuf *nam, **mrq; 172638418Smckusick { 172738418Smckusick register struct statfs *sf; 172838884Smacklem register struct nfsv2_statfs *sfp; 172948050Smckusick register u_long *tl; 173039494Smckusick register long t1; 173139494Smckusick caddr_t bpos; 173256285Smckusick int error = 0, rdonly, cache, isnq; 173339494Smckusick char *cp2; 173439753Smckusick struct mbuf *mb, *mb2, *mreq; 173538418Smckusick struct vnode *vp; 173638418Smckusick nfsv2fh_t nfh; 173738418Smckusick fhandle_t *fhp; 173838418Smckusick struct statfs statfs; 173952196Smckusick u_quad_t frev; 174038418Smckusick 174138418Smckusick fhp = &nfh.fh_generic; 174256285Smckusick isnq = (nfsd->nd_nqlflag != NQL_NOVAL); 174338418Smckusick nfsm_srvmtofh(fhp); 174452196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 174538418Smckusick nfsm_reply(0); 174638418Smckusick sf = &statfs; 174752196Smckusick error = VFS_STATFS(vp->v_mount, sf, nfsd->nd_procp); 174838418Smckusick vput(vp); 174956285Smckusick nfsm_reply(NFSX_STATFS(isnq)); 175056285Smckusick nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS(isnq)); 175144993Sbostic sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA); 175251940Smckusick sfp->sf_bsize = txdr_unsigned(sf->f_bsize); 175338884Smacklem sfp->sf_blocks = txdr_unsigned(sf->f_blocks); 175438884Smacklem sfp->sf_bfree = txdr_unsigned(sf->f_bfree); 175538884Smacklem sfp->sf_bavail = txdr_unsigned(sf->f_bavail); 175656285Smckusick if (isnq) { 175756285Smckusick sfp->sf_files = txdr_unsigned(sf->f_files); 175856285Smckusick sfp->sf_ffree = txdr_unsigned(sf->f_ffree); 175956285Smckusick } 176038418Smckusick nfsm_srvdone; 176138418Smckusick } 176238418Smckusick 176338418Smckusick /* 176438418Smckusick * Null operation, used by clients to ping server 176538418Smckusick */ 176639494Smckusick /* ARGSUSED */ 176752196Smckusick nfsrv_null(nfsd, mrep, md, dpos, cred, nam, mrq) 176852196Smckusick struct nfsd *nfsd; 176938418Smckusick struct mbuf *mrep, *md; 177038418Smckusick caddr_t dpos; 177138418Smckusick struct ucred *cred; 177252196Smckusick struct mbuf *nam, **mrq; 177338418Smckusick { 177439494Smckusick caddr_t bpos; 177552196Smckusick int error = VNOVAL, cache; 177639753Smckusick struct mbuf *mb, *mreq; 177752196Smckusick u_quad_t frev; 177838418Smckusick 177938418Smckusick nfsm_reply(0); 178039494Smckusick return (error); 178138418Smckusick } 178238418Smckusick 178338418Smckusick /* 178438418Smckusick * No operation, used for obsolete procedures 178538418Smckusick */ 178639494Smckusick /* ARGSUSED */ 178752196Smckusick nfsrv_noop(nfsd, mrep, md, dpos, cred, nam, mrq) 178852196Smckusick struct nfsd *nfsd; 178938418Smckusick struct mbuf *mrep, *md; 179038418Smckusick caddr_t dpos; 179138418Smckusick struct ucred *cred; 179252196Smckusick struct mbuf *nam, **mrq; 179338418Smckusick { 179439494Smckusick caddr_t bpos; 179552196Smckusick int error, cache; 179639753Smckusick struct mbuf *mb, *mreq; 179752196Smckusick u_quad_t frev; 179838418Smckusick 179952196Smckusick if (nfsd->nd_repstat) 180052196Smckusick error = nfsd->nd_repstat; 180152196Smckusick else 180252196Smckusick error = EPROCUNAVAIL; 180338418Smckusick nfsm_reply(0); 180439494Smckusick return (error); 180538418Smckusick } 180638425Smckusick 180738450Smckusick /* 180838450Smckusick * Perform access checking for vnodes obtained from file handles that would 180938450Smckusick * refer to files already opened by a Unix client. You cannot just use 181038450Smckusick * vn_writechk() and VOP_ACCESS() for two reasons. 181152196Smckusick * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case 181238450Smckusick * 2 - The owner is to be given access irrespective of mode bits so that 181338450Smckusick * processes that chmod after opening a file don't break. I don't like 181438450Smckusick * this because it opens a security hole, but since the nfs server opens 181538450Smckusick * a security hole the size of a barn door anyhow, what the heck. 181638450Smckusick */ 181752196Smckusick nfsrv_access(vp, flags, cred, rdonly, p) 181838450Smckusick register struct vnode *vp; 181938450Smckusick int flags; 182038450Smckusick register struct ucred *cred; 182152196Smckusick int rdonly; 182248050Smckusick struct proc *p; 182338450Smckusick { 182438450Smckusick struct vattr vattr; 182538450Smckusick int error; 182638450Smckusick if (flags & VWRITE) { 182752196Smckusick /* Just vn_writechk() changed to check rdonly */ 182838450Smckusick /* 182938450Smckusick * Disallow write attempts on read-only file systems; 183038450Smckusick * unless the file is a socket or a block or character 183138450Smckusick * device resident on the file system. 183238450Smckusick */ 183352196Smckusick if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { 183445059Smckusick switch (vp->v_type) { 183545059Smckusick case VREG: case VDIR: case VLNK: 183638450Smckusick return (EROFS); 183745059Smckusick } 183845059Smckusick } 183938450Smckusick /* 184038450Smckusick * If there's shared text associated with 184138450Smckusick * the inode, try to free it up once. If 184238450Smckusick * we fail, we can't allow writing. 184338450Smckusick */ 184445715Smckusick if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) 184538450Smckusick return (ETXTBSY); 184638450Smckusick } 184748050Smckusick if (error = VOP_GETATTR(vp, &vattr, cred, p)) 184845059Smckusick return (error); 184948050Smckusick if ((error = VOP_ACCESS(vp, flags, cred, p)) && 185045059Smckusick cred->cr_uid != vattr.va_uid) 185145059Smckusick return (error); 185245059Smckusick return (0); 185338450Smckusick } 1854