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*54446Smckusick * @(#)nfs_serv.c 7.53 (Berkeley) 06/25/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> 3253322Smckusick #include <sys/proc.h> 3353322Smckusick #include <sys/file.h> 3453322Smckusick #include <sys/namei.h> 3553322Smckusick #include <sys/vnode.h> 3653322Smckusick #include <sys/mount.h> 3753322Smckusick #include <sys/mbuf.h> 3853322Smckusick #include <sys/dirent.h> 39*54446Smckusick #include <sys/stat.h> 4047573Skarels 4153322Smckusick #include <vm/vm.h> 4247573Skarels 4353322Smckusick #include <nfs/nfsv2.h> 4453322Smckusick #include <nfs/rpcv2.h> 4553322Smckusick #include <nfs/nfs.h> 4653322Smckusick #include <nfs/xdr_subs.h> 4753322Smckusick #include <nfs/nfsm_subs.h> 4853322Smckusick #include <nfs/nqnfs.h> 4953322Smckusick 5038418Smckusick /* Defs */ 5138425Smckusick #define TRUE 1 5238425Smckusick #define FALSE 0 5338418Smckusick 5438418Smckusick /* Global vars */ 5538418Smckusick extern u_long nfs_procids[NFS_NPROCS]; 5638418Smckusick extern u_long nfs_xdrneg1; 5738418Smckusick extern u_long nfs_false, nfs_true; 5852196Smckusick nfstype nfs_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, 5942242Smckusick NFCHR, NFNON }; 6038418Smckusick 6138418Smckusick /* 6238418Smckusick * nfs getattr service 6338418Smckusick */ 6452196Smckusick nfsrv_getattr(nfsd, mrep, md, dpos, cred, nam, mrq) 6552196Smckusick struct nfsd *nfsd; 6638418Smckusick struct mbuf *mrep, *md; 6738418Smckusick caddr_t dpos; 6838418Smckusick struct ucred *cred; 6952196Smckusick struct mbuf *nam, **mrq; 7038418Smckusick { 7153552Sheideman USES_VOP_GETATTR; 7238884Smacklem register struct nfsv2_fattr *fp; 7338418Smckusick struct vattr va; 7438418Smckusick register struct vattr *vap = &va; 7538418Smckusick struct vnode *vp; 7638418Smckusick nfsv2fh_t nfh; 7738418Smckusick fhandle_t *fhp; 7848050Smckusick register u_long *tl; 7939494Smckusick register long t1; 8039494Smckusick caddr_t bpos; 8152196Smckusick int error = 0, rdonly, cache; 8239494Smckusick char *cp2; 8339753Smckusick struct mbuf *mb, *mb2, *mreq; 8452196Smckusick u_quad_t frev; 8538418Smckusick 8638418Smckusick fhp = &nfh.fh_generic; 8738418Smckusick nfsm_srvmtofh(fhp); 8852196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 8938418Smckusick nfsm_reply(0); 9052196Smckusick nqsrv_getl(vp, NQL_READ); 9152196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 9238418Smckusick vput(vp); 9338418Smckusick nfsm_reply(NFSX_FATTR); 9438884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 9539753Smckusick nfsm_srvfillattr; 9638418Smckusick nfsm_srvdone; 9738418Smckusick } 9838418Smckusick 9938418Smckusick /* 10038418Smckusick * nfs setattr service 10138418Smckusick */ 10252196Smckusick nfsrv_setattr(nfsd, mrep, md, dpos, cred, nam, mrq) 10352196Smckusick struct nfsd *nfsd; 10438418Smckusick struct mbuf *mrep, *md; 10538418Smckusick caddr_t dpos; 10638418Smckusick struct ucred *cred; 10752196Smckusick struct mbuf *nam, **mrq; 10838418Smckusick { 10953552Sheideman USES_VOP_GETATTR; 11053552Sheideman USES_VOP_SETATTR; 11138418Smckusick struct vattr va; 11238418Smckusick register struct vattr *vap = &va; 11338884Smacklem register struct nfsv2_sattr *sp; 11438884Smacklem register struct nfsv2_fattr *fp; 11538418Smckusick struct vnode *vp; 11638418Smckusick nfsv2fh_t nfh; 11738418Smckusick fhandle_t *fhp; 11848050Smckusick register u_long *tl; 11939494Smckusick register long t1; 12039494Smckusick caddr_t bpos; 12152196Smckusick int error = 0, rdonly, cache, duration2, cache2; 12239494Smckusick char *cp2; 12339753Smckusick struct mbuf *mb, *mb2, *mreq; 12452196Smckusick u_quad_t frev, frev2; 12538418Smckusick 12638418Smckusick fhp = &nfh.fh_generic; 12738418Smckusick nfsm_srvmtofh(fhp); 12852196Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR); 12952196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 13038418Smckusick nfsm_reply(0); 13152196Smckusick nqsrv_getl(vp, NQL_WRITE); 13252196Smckusick if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) 13338418Smckusick goto out; 13441361Smckusick VATTR_NULL(vap); 13538418Smckusick /* 13638418Smckusick * Nah nah nah nah na nah 13738418Smckusick * There is a bug in the Sun client that puts 0xffff in the mode 13838418Smckusick * field of sattr when it should put in 0xffffffff. The u_short 13938418Smckusick * doesn't sign extend. 14038418Smckusick * --> check the low order 2 bytes for 0xffff 14138418Smckusick */ 14238884Smacklem if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff) 14338884Smacklem vap->va_mode = nfstov_mode(sp->sa_mode); 14438884Smacklem if (sp->sa_uid != nfs_xdrneg1) 14538884Smacklem vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid); 14638884Smacklem if (sp->sa_gid != nfs_xdrneg1) 14738884Smacklem vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid); 14839753Smckusick if (sp->sa_size != nfs_xdrneg1) 14938884Smacklem vap->va_size = fxdr_unsigned(u_long, sp->sa_size); 15039753Smckusick /* 15139753Smckusick * The usec field of sa_atime is overloaded with the va_flags field 15239753Smckusick * for 4.4BSD clients. Hopefully other clients always set both the 15339753Smckusick * sec and usec fields to -1 when not setting the atime. 15439753Smckusick */ 15539753Smckusick if (sp->sa_atime.tv_sec != nfs_xdrneg1) { 15654106Smckusick vap->va_atime.ts_sec = fxdr_unsigned(long, sp->sa_atime.tv_sec); 15754106Smckusick vap->va_atime.ts_nsec = 0; 15838425Smckusick } 15939753Smckusick if (sp->sa_atime.tv_usec != nfs_xdrneg1) 16039753Smckusick vap->va_flags = fxdr_unsigned(u_long, sp->sa_atime.tv_usec); 16138884Smacklem if (sp->sa_mtime.tv_sec != nfs_xdrneg1) 16238884Smacklem fxdr_time(&sp->sa_mtime, &vap->va_mtime); 16352196Smckusick if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) { 16438418Smckusick vput(vp); 16538418Smckusick nfsm_reply(0); 16638418Smckusick } 16752196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 16838418Smckusick out: 16938418Smckusick vput(vp); 17052196Smckusick nfsm_reply(NFSX_FATTR + 2*NFSX_UNSIGNED); 17138884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 17239753Smckusick nfsm_srvfillattr; 17352196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 17452196Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 17552196Smckusick txdr_hyper(&frev2, tl); 17652196Smckusick } 17738418Smckusick nfsm_srvdone; 17838418Smckusick } 17938418Smckusick 18038418Smckusick /* 18138418Smckusick * nfs lookup rpc 18238418Smckusick */ 18352196Smckusick nfsrv_lookup(nfsd, mrep, md, dpos, cred, nam, mrq) 18452196Smckusick struct nfsd *nfsd; 18538418Smckusick struct mbuf *mrep, *md; 18638418Smckusick caddr_t dpos; 18738418Smckusick struct ucred *cred; 18852196Smckusick struct mbuf *nam, **mrq; 18938418Smckusick { 19053552Sheideman USES_VOP_GETATTR; 19138884Smacklem register struct nfsv2_fattr *fp; 19249742Smckusick struct nameidata nd; 19338418Smckusick struct vnode *vp; 19438418Smckusick nfsv2fh_t nfh; 19538418Smckusick fhandle_t *fhp; 19639494Smckusick register caddr_t cp; 19748050Smckusick register u_long *tl; 19839494Smckusick register long t1; 19939494Smckusick caddr_t bpos; 20052196Smckusick int error = 0, lflag = 0, rdonly, cache, duration2, cache2, len; 20139494Smckusick char *cp2; 20239753Smckusick struct mbuf *mb, *mb2, *mreq; 20338418Smckusick struct vattr va, *vap = &va; 20452196Smckusick u_quad_t frev, frev2; 20538418Smckusick 20638418Smckusick fhp = &nfh.fh_generic; 20752196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 20852196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 20952196Smckusick if (*tl) { 21052196Smckusick lflag = fxdr_unsigned(int, *tl); 21152196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 21252196Smckusick duration2 = fxdr_unsigned(int, *tl); 21352196Smckusick } 21452196Smckusick } 21538418Smckusick nfsm_srvmtofh(fhp); 21638418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 21752316Sheideman nd.ni_cnd.cn_cred = cred; 21852316Sheideman nd.ni_cnd.cn_nameiop = LOOKUP; 21952316Sheideman nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART; 22052653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 22152653Smckusick nfsd->nd_procp)) 22238418Smckusick nfsm_reply(0); 22352196Smckusick nqsrv_getl(nd.ni_startdir, NQL_READ); 22452196Smckusick vrele(nd.ni_startdir); 22552653Smckusick FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 22649742Smckusick vp = nd.ni_vp; 22738418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 22841398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 22938418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 23038418Smckusick vput(vp); 23138418Smckusick nfsm_reply(0); 23238418Smckusick } 23352196Smckusick if (lflag) 23452196Smckusick (void) nqsrv_getlease(vp, &duration2, lflag, nfsd, 23552196Smckusick nam, &cache2, &frev2, cred); 23652196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 23738418Smckusick vput(vp); 23852196Smckusick nfsm_reply(NFSX_FH + NFSX_FATTR + 5*NFSX_UNSIGNED); 23952196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 24052196Smckusick if (lflag) { 24152196Smckusick nfsm_build(tl, u_long *, 5*NFSX_UNSIGNED); 24252196Smckusick *tl++ = txdr_unsigned(lflag); 24352196Smckusick *tl++ = txdr_unsigned(cache2); 24452196Smckusick *tl++ = txdr_unsigned(duration2); 24552196Smckusick txdr_hyper(&frev2, tl); 24652196Smckusick } else { 24752196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 24852196Smckusick *tl = 0; 24952196Smckusick } 25052196Smckusick } 25138418Smckusick nfsm_srvfhtom(fhp); 25238884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 25339753Smckusick nfsm_srvfillattr; 25438418Smckusick nfsm_srvdone; 25538418Smckusick } 25638418Smckusick 25738418Smckusick /* 25838418Smckusick * nfs readlink service 25938418Smckusick */ 26052196Smckusick nfsrv_readlink(nfsd, mrep, md, dpos, cred, nam, mrq) 26152196Smckusick struct nfsd *nfsd; 26238418Smckusick struct mbuf *mrep, *md; 26338418Smckusick caddr_t dpos; 26438418Smckusick struct ucred *cred; 26552196Smckusick struct mbuf *nam, **mrq; 26638418Smckusick { 26753552Sheideman USES_VOP_READLINK; 26841899Smckusick struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN]; 26938418Smckusick register struct iovec *ivp = iv; 27038418Smckusick register struct mbuf *mp; 27148050Smckusick register u_long *tl; 27239494Smckusick register long t1; 27339494Smckusick caddr_t bpos; 27452196Smckusick int error = 0, rdonly, cache, i, tlen, len; 27539494Smckusick char *cp2; 27639753Smckusick struct mbuf *mb, *mb2, *mp2, *mp3, *mreq; 27738418Smckusick struct vnode *vp; 27838418Smckusick nfsv2fh_t nfh; 27938418Smckusick fhandle_t *fhp; 28038418Smckusick struct uio io, *uiop = &io; 28152196Smckusick u_quad_t frev; 28238418Smckusick 28338418Smckusick fhp = &nfh.fh_generic; 28438418Smckusick nfsm_srvmtofh(fhp); 28538418Smckusick len = 0; 28638418Smckusick i = 0; 28738418Smckusick while (len < NFS_MAXPATHLEN) { 28838418Smckusick MGET(mp, M_WAIT, MT_DATA); 28941899Smckusick MCLGET(mp, M_WAIT); 29038418Smckusick mp->m_len = NFSMSIZ(mp); 29138418Smckusick if (len == 0) 29238418Smckusick mp3 = mp2 = mp; 29341899Smckusick else { 29438418Smckusick mp2->m_next = mp; 29541899Smckusick mp2 = mp; 29641899Smckusick } 29738418Smckusick if ((len+mp->m_len) > NFS_MAXPATHLEN) { 29838418Smckusick mp->m_len = NFS_MAXPATHLEN-len; 29938418Smckusick len = NFS_MAXPATHLEN; 30038418Smckusick } else 30138418Smckusick len += mp->m_len; 30238418Smckusick ivp->iov_base = mtod(mp, caddr_t); 30338418Smckusick ivp->iov_len = mp->m_len; 30438418Smckusick i++; 30538418Smckusick ivp++; 30638418Smckusick } 30738418Smckusick uiop->uio_iov = iv; 30838418Smckusick uiop->uio_iovcnt = i; 30938418Smckusick uiop->uio_offset = 0; 31038418Smckusick uiop->uio_resid = len; 31138418Smckusick uiop->uio_rw = UIO_READ; 31238418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 31348050Smckusick uiop->uio_procp = (struct proc *)0; 31452196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) { 31538418Smckusick m_freem(mp3); 31638418Smckusick nfsm_reply(0); 31738418Smckusick } 31838418Smckusick if (vp->v_type != VLNK) { 31938418Smckusick error = EINVAL; 32038418Smckusick goto out; 32138418Smckusick } 32252196Smckusick nqsrv_getl(vp, NQL_READ); 32338418Smckusick error = VOP_READLINK(vp, uiop, cred); 32438418Smckusick out: 32538418Smckusick vput(vp); 32638418Smckusick if (error) 32738418Smckusick m_freem(mp3); 32838418Smckusick nfsm_reply(NFSX_UNSIGNED); 32938418Smckusick if (uiop->uio_resid > 0) { 33038418Smckusick len -= uiop->uio_resid; 33138418Smckusick tlen = nfsm_rndup(len); 33238418Smckusick nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len); 33338418Smckusick } 33448050Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 33548050Smckusick *tl = txdr_unsigned(len); 33638418Smckusick mb->m_next = mp3; 33738418Smckusick nfsm_srvdone; 33838418Smckusick } 33938418Smckusick 34038418Smckusick /* 34138418Smckusick * nfs read service 34238418Smckusick */ 34352196Smckusick nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq) 34452196Smckusick struct nfsd *nfsd; 34538418Smckusick struct mbuf *mrep, *md; 34638418Smckusick caddr_t dpos; 34738418Smckusick struct ucred *cred; 34852196Smckusick struct mbuf *nam, **mrq; 34938418Smckusick { 35053552Sheideman USES_VOP_GETATTR; 35153552Sheideman USES_VOP_READ; 35243350Smckusick register struct iovec *iv; 35343350Smckusick struct iovec *iv2; 35441899Smckusick register struct mbuf *m; 35538884Smacklem register struct nfsv2_fattr *fp; 35648050Smckusick register u_long *tl; 35739494Smckusick register long t1; 35839494Smckusick caddr_t bpos; 35952196Smckusick int error = 0, rdonly, cache, i, cnt, len, left, siz, tlen; 36039494Smckusick char *cp2; 36139753Smckusick struct mbuf *mb, *mb2, *mreq; 36252196Smckusick struct mbuf *m2; 36338418Smckusick struct vnode *vp; 36438418Smckusick nfsv2fh_t nfh; 36538418Smckusick fhandle_t *fhp; 36638418Smckusick struct uio io, *uiop = &io; 36738418Smckusick struct vattr va, *vap = &va; 36838418Smckusick off_t off; 36952196Smckusick u_quad_t frev; 37038418Smckusick 37138418Smckusick fhp = &nfh.fh_generic; 37238418Smckusick nfsm_srvmtofh(fhp); 37352196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 37448050Smckusick off = fxdr_unsigned(off_t, *tl); 37538418Smckusick nfsm_srvstrsiz(cnt, NFS_MAXDATA); 37652196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 37738418Smckusick nfsm_reply(0); 37852196Smckusick nqsrv_getl(vp, NQL_READ); 37952196Smckusick if (error = nfsrv_access(vp, VREAD | VEXEC, cred, rdonly, nfsd->nd_procp)) { 38038418Smckusick vput(vp); 38138418Smckusick nfsm_reply(0); 38238418Smckusick } 38352196Smckusick if (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp)) { 38438418Smckusick vput(vp); 38538418Smckusick nfsm_reply(0); 38638418Smckusick } 38752196Smckusick if (off >= vap->va_size) 38852196Smckusick cnt = 0; 38952196Smckusick else if ((off + cnt) > vap->va_size) 39052196Smckusick cnt = nfsm_rndup(vap->va_size - off); 39152196Smckusick nfsm_reply(NFSX_FATTR+NFSX_UNSIGNED+nfsm_rndup(cnt)); 39252196Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 39352196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 39452196Smckusick len = left = cnt; 39552196Smckusick if (cnt > 0) { 39652196Smckusick /* 39752196Smckusick * Generate the mbuf list with the uio_iov ref. to it. 39852196Smckusick */ 39952196Smckusick i = 0; 40052196Smckusick m = m2 = mb; 40152196Smckusick MALLOC(iv, struct iovec *, 40252196Smckusick ((NFS_MAXDATA+MLEN-1)/MLEN) * sizeof (struct iovec), 40352196Smckusick M_TEMP, M_WAITOK); 40452196Smckusick iv2 = iv; 40552196Smckusick while (left > 0) { 40652196Smckusick siz = MIN(M_TRAILINGSPACE(m), left); 40752196Smckusick if (siz > 0) { 40852196Smckusick m->m_len += siz; 40952196Smckusick iv->iov_base = bpos; 41052196Smckusick iv->iov_len = siz; 41152196Smckusick iv++; 41252196Smckusick i++; 41352196Smckusick left -= siz; 41452196Smckusick } 41552196Smckusick if (left > 0) { 41652196Smckusick MGET(m, M_WAIT, MT_DATA); 41752196Smckusick MCLGET(m, M_WAIT); 41852196Smckusick m->m_len = 0; 41952196Smckusick m2->m_next = m; 42052196Smckusick m2 = m; 42152196Smckusick bpos = mtod(m, caddr_t); 42252196Smckusick } 42352196Smckusick } 42452196Smckusick uiop->uio_iov = iv2; 42552196Smckusick uiop->uio_iovcnt = i; 42652196Smckusick uiop->uio_offset = off; 42752196Smckusick uiop->uio_resid = cnt; 42852196Smckusick uiop->uio_rw = UIO_READ; 42952196Smckusick uiop->uio_segflg = UIO_SYSSPACE; 43052196Smckusick error = VOP_READ(vp, uiop, IO_NODELOCKED, cred); 43152196Smckusick off = uiop->uio_offset; 43252196Smckusick FREE((caddr_t)iv2, M_TEMP); 43352196Smckusick if (error || (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp))) { 43452196Smckusick m_freem(mreq); 43552196Smckusick vput(vp); 43652196Smckusick nfsm_reply(0); 43752196Smckusick } 43852196Smckusick } else 43952196Smckusick uiop->uio_resid = 0; 44038418Smckusick vput(vp); 44139753Smckusick nfsm_srvfillattr; 44245877Smckusick len -= uiop->uio_resid; 44352196Smckusick tlen = nfsm_rndup(len); 44452196Smckusick if (cnt != tlen || tlen != len) 44552196Smckusick nfsm_adj(mb, cnt-tlen, tlen-len); 44648050Smckusick *tl = txdr_unsigned(len); 44738418Smckusick nfsm_srvdone; 44838418Smckusick } 44938418Smckusick 45038418Smckusick /* 45138418Smckusick * nfs write service 45238418Smckusick */ 45352196Smckusick nfsrv_write(nfsd, mrep, md, dpos, cred, nam, mrq) 45452196Smckusick struct nfsd *nfsd; 45552196Smckusick struct mbuf *mrep, *md; 45638418Smckusick caddr_t dpos; 45738418Smckusick struct ucred *cred; 45852196Smckusick struct mbuf *nam, **mrq; 45938418Smckusick { 46053552Sheideman USES_VOP_GETATTR; 46153552Sheideman USES_VOP_WRITE; 46238418Smckusick register struct iovec *ivp; 46338418Smckusick register struct mbuf *mp; 46438884Smacklem register struct nfsv2_fattr *fp; 46541899Smckusick struct iovec iv[NFS_MAXIOVEC]; 46638418Smckusick struct vattr va; 46738418Smckusick register struct vattr *vap = &va; 46848050Smckusick register u_long *tl; 46939494Smckusick register long t1; 47039494Smckusick caddr_t bpos; 47152196Smckusick int error = 0, rdonly, cache, siz, len, xfer; 47239494Smckusick char *cp2; 47339753Smckusick struct mbuf *mb, *mb2, *mreq; 47438418Smckusick struct vnode *vp; 47538418Smckusick nfsv2fh_t nfh; 47638418Smckusick fhandle_t *fhp; 47738418Smckusick struct uio io, *uiop = &io; 47838418Smckusick off_t off; 47952196Smckusick u_quad_t frev; 48038418Smckusick 48138418Smckusick fhp = &nfh.fh_generic; 48238418Smckusick nfsm_srvmtofh(fhp); 48352196Smckusick nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); 48448050Smckusick off = fxdr_unsigned(off_t, *++tl); 48548050Smckusick tl += 2; 48648050Smckusick len = fxdr_unsigned(long, *tl); 48738418Smckusick if (len > NFS_MAXDATA || len <= 0) { 48838418Smckusick error = EBADRPC; 48938418Smckusick nfsm_reply(0); 49038418Smckusick } 49138418Smckusick if (dpos == (mtod(md, caddr_t)+md->m_len)) { 49238418Smckusick mp = md->m_next; 49338418Smckusick if (mp == NULL) { 49438418Smckusick error = EBADRPC; 49538418Smckusick nfsm_reply(0); 49638418Smckusick } 49738418Smckusick } else { 49838418Smckusick mp = md; 49938418Smckusick siz = dpos-mtod(mp, caddr_t); 50038418Smckusick mp->m_len -= siz; 50138418Smckusick NFSMADV(mp, siz); 50238418Smckusick } 50352196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 50438418Smckusick nfsm_reply(0); 50552196Smckusick nqsrv_getl(vp, NQL_WRITE); 50652196Smckusick if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) { 50738418Smckusick vput(vp); 50838418Smckusick nfsm_reply(0); 50938418Smckusick } 51038418Smckusick uiop->uio_resid = 0; 51138418Smckusick uiop->uio_rw = UIO_WRITE; 51238418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 51348050Smckusick uiop->uio_procp = (struct proc *)0; 51438418Smckusick /* 51541899Smckusick * Do up to NFS_MAXIOVEC mbufs of write each iteration of the 51638418Smckusick * loop until done. 51738418Smckusick */ 51838418Smckusick while (len > 0 && uiop->uio_resid == 0) { 51938418Smckusick ivp = iv; 52038418Smckusick siz = 0; 52138418Smckusick uiop->uio_iov = ivp; 52238418Smckusick uiop->uio_iovcnt = 0; 52338418Smckusick uiop->uio_offset = off; 52441899Smckusick while (len > 0 && uiop->uio_iovcnt < NFS_MAXIOVEC && mp != NULL) { 52538418Smckusick ivp->iov_base = mtod(mp, caddr_t); 52638418Smckusick if (len < mp->m_len) 52738418Smckusick ivp->iov_len = xfer = len; 52838418Smckusick else 52938418Smckusick ivp->iov_len = xfer = mp->m_len; 53038418Smckusick #ifdef notdef 53138418Smckusick /* Not Yet .. */ 53238418Smckusick if (M_HASCL(mp) && (((u_long)ivp->iov_base) & CLOFSET) == 0) 53338418Smckusick ivp->iov_op = NULL; /* what should it be ?? */ 53438418Smckusick else 53538418Smckusick ivp->iov_op = NULL; 53638418Smckusick #endif 53738418Smckusick uiop->uio_iovcnt++; 53838418Smckusick ivp++; 53938418Smckusick len -= xfer; 54038418Smckusick siz += xfer; 54138418Smckusick mp = mp->m_next; 54238418Smckusick } 54338418Smckusick if (len > 0 && mp == NULL) { 54438418Smckusick error = EBADRPC; 54538418Smckusick vput(vp); 54638418Smckusick nfsm_reply(0); 54738418Smckusick } 54838418Smckusick uiop->uio_resid = siz; 54939586Smckusick if (error = VOP_WRITE(vp, uiop, IO_SYNC | IO_NODELOCKED, 55038418Smckusick cred)) { 55138418Smckusick vput(vp); 55238418Smckusick nfsm_reply(0); 55338418Smckusick } 55439586Smckusick off = uiop->uio_offset; 55538418Smckusick } 55652196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 55738418Smckusick vput(vp); 55838418Smckusick nfsm_reply(NFSX_FATTR); 55938884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 56039753Smckusick nfsm_srvfillattr; 56152442Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 56252442Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 56352442Smckusick txdr_hyper(&vap->va_filerev, tl); 56452442Smckusick } 56538418Smckusick nfsm_srvdone; 56638418Smckusick } 56738418Smckusick 56838418Smckusick /* 56938418Smckusick * nfs create service 57038418Smckusick * now does a truncate to 0 length via. setattr if it already exists 57138418Smckusick */ 57252196Smckusick nfsrv_create(nfsd, mrep, md, dpos, cred, nam, mrq) 57352196Smckusick struct nfsd *nfsd; 57452196Smckusick struct mbuf *mrep, *md; 57538418Smckusick caddr_t dpos; 57638418Smckusick struct ucred *cred; 57752196Smckusick struct mbuf *nam, **mrq; 57838418Smckusick { 57953552Sheideman USES_VOP_ABORTOP; 58053552Sheideman USES_VOP_CREATE; 58153552Sheideman USES_VOP_GETATTR; 58253552Sheideman USES_VOP_MKNOD; 58353552Sheideman USES_VOP_SETATTR; 58438884Smacklem register struct nfsv2_fattr *fp; 58538418Smckusick struct vattr va; 58638418Smckusick register struct vattr *vap = &va; 58749742Smckusick struct nameidata nd; 58839494Smckusick register caddr_t cp; 58948050Smckusick register u_long *tl; 59039494Smckusick register long t1; 59139494Smckusick caddr_t bpos; 59252196Smckusick int error = 0, rdev, cache, len; 59339494Smckusick char *cp2; 59439753Smckusick struct mbuf *mb, *mb2, *mreq; 59538418Smckusick struct vnode *vp; 59638418Smckusick nfsv2fh_t nfh; 59738418Smckusick fhandle_t *fhp; 59852196Smckusick u_quad_t frev; 59938418Smckusick 60052316Sheideman nd.ni_cnd.cn_nameiop = 0; 60138418Smckusick fhp = &nfh.fh_generic; 60238418Smckusick nfsm_srvmtofh(fhp); 60338418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 60452316Sheideman nd.ni_cnd.cn_cred = cred; 60552316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 60652316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART; 60752653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 60852653Smckusick nfsd->nd_procp)) 60938418Smckusick nfsm_reply(0); 61041361Smckusick VATTR_NULL(vap); 61152196Smckusick nfsm_dissect(tl, u_long *, NFSX_SATTR); 61238418Smckusick /* 61338418Smckusick * Iff doesn't exist, create it 61438418Smckusick * otherwise just truncate to 0 length 61538418Smckusick * should I set the mode too ?? 61638418Smckusick */ 61749742Smckusick if (nd.ni_vp == NULL) { 61848050Smckusick vap->va_type = IFTOVT(fxdr_unsigned(u_long, *tl)); 61942867Smckusick if (vap->va_type == VNON) 62042867Smckusick vap->va_type = VREG; 62148050Smckusick vap->va_mode = nfstov_mode(*tl); 62248050Smckusick rdev = fxdr_unsigned(long, *(tl+3)); 62346988Smckusick if (vap->va_type == VREG || vap->va_type == VSOCK) { 62449742Smckusick vrele(nd.ni_startdir); 62552196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 62652234Sheideman if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) 62742242Smckusick nfsm_reply(0); 62852316Sheideman FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 62942242Smckusick } else if (vap->va_type == VCHR || vap->va_type == VBLK || 63042242Smckusick vap->va_type == VFIFO) { 63142242Smckusick if (vap->va_type == VCHR && rdev == 0xffffffff) 63242242Smckusick vap->va_type = VFIFO; 63342242Smckusick if (vap->va_type == VFIFO) { 63442242Smckusick #ifndef FIFO 63552234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 63649742Smckusick vput(nd.ni_dvp); 63742242Smckusick error = ENXIO; 63849742Smckusick goto out; 63942242Smckusick #endif /* FIFO */ 64052196Smckusick } else if (error = suser(cred, (u_short *)0)) { 64152234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 64249742Smckusick vput(nd.ni_dvp); 64349742Smckusick goto out; 64442242Smckusick } else 64542242Smckusick vap->va_rdev = (dev_t)rdev; 64652196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 64752234Sheideman if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) { 64849742Smckusick vrele(nd.ni_startdir); 64942242Smckusick nfsm_reply(0); 65049742Smckusick } 65152316Sheideman nd.ni_cnd.cn_nameiop = LOOKUP; 65252316Sheideman nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART); 65352316Sheideman nd.ni_cnd.cn_proc = nfsd->nd_procp; 65452316Sheideman nd.ni_cnd.cn_cred = nfsd->nd_procp->p_ucred; 65552316Sheideman if (error = lookup(&nd)) { 65652316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 65742242Smckusick nfsm_reply(0); 65849742Smckusick } 65952316Sheideman FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 66052316Sheideman if (nd.ni_cnd.cn_flags & ISSYMLINK) { 66149742Smckusick vrele(nd.ni_dvp); 66249742Smckusick vput(nd.ni_vp); 66352234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 66449742Smckusick error = EINVAL; 66549742Smckusick nfsm_reply(0); 66649742Smckusick } 66742242Smckusick } else { 66852234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 66949742Smckusick vput(nd.ni_dvp); 67042242Smckusick error = ENXIO; 67149742Smckusick goto out; 67242242Smckusick } 67349742Smckusick vp = nd.ni_vp; 67438418Smckusick } else { 67549742Smckusick vrele(nd.ni_startdir); 67652316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 67749742Smckusick vp = nd.ni_vp; 67849742Smckusick if (nd.ni_dvp == vp) 67949742Smckusick vrele(nd.ni_dvp); 68043359Smckusick else 68149742Smckusick vput(nd.ni_dvp); 68252234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 68338418Smckusick vap->va_size = 0; 68452196Smckusick nqsrv_getl(vp, NQL_WRITE); 68552196Smckusick if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) { 68642506Smckusick vput(vp); 68738418Smckusick nfsm_reply(0); 68842506Smckusick } 68938418Smckusick } 69038418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 69141398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 69238418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 69338418Smckusick vput(vp); 69438418Smckusick nfsm_reply(0); 69538418Smckusick } 69652196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 69738418Smckusick vput(vp); 69838418Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR); 69938418Smckusick nfsm_srvfhtom(fhp); 70038884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 70139753Smckusick nfsm_srvfillattr; 70238418Smckusick return (error); 70338418Smckusick nfsmout: 70452316Sheideman if (nd.ni_cnd.cn_nameiop || nd.ni_cnd.cn_flags) 70551464Sbostic vrele(nd.ni_startdir); 70652234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 70749742Smckusick if (nd.ni_dvp == nd.ni_vp) 70849742Smckusick vrele(nd.ni_dvp); 70943359Smckusick else 71049742Smckusick vput(nd.ni_dvp); 71149742Smckusick if (nd.ni_vp) 71249742Smckusick vput(nd.ni_vp); 71338418Smckusick return (error); 71449742Smckusick 71549742Smckusick out: 71649742Smckusick vrele(nd.ni_startdir); 71752316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 71849742Smckusick nfsm_reply(0); 71938418Smckusick } 72038418Smckusick 72138418Smckusick /* 72238418Smckusick * nfs remove service 72338418Smckusick */ 72452196Smckusick nfsrv_remove(nfsd, mrep, md, dpos, cred, nam, mrq) 72552196Smckusick struct nfsd *nfsd; 72652196Smckusick struct mbuf *mrep, *md; 72738418Smckusick caddr_t dpos; 72838418Smckusick struct ucred *cred; 72952196Smckusick struct mbuf *nam, **mrq; 73038418Smckusick { 73153552Sheideman USES_VOP_ABORTOP; 73253552Sheideman USES_VOP_REMOVE; 73349742Smckusick struct nameidata nd; 73448050Smckusick register u_long *tl; 73539494Smckusick register long t1; 73639494Smckusick caddr_t bpos; 73752196Smckusick int error = 0, cache, len; 73839494Smckusick char *cp2; 73939753Smckusick struct mbuf *mb, *mreq; 74038418Smckusick struct vnode *vp; 74138418Smckusick nfsv2fh_t nfh; 74238418Smckusick fhandle_t *fhp; 74352196Smckusick u_quad_t frev; 74438418Smckusick 74538418Smckusick fhp = &nfh.fh_generic; 74638418Smckusick nfsm_srvmtofh(fhp); 74738418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 74852316Sheideman nd.ni_cnd.cn_cred = cred; 74952316Sheideman nd.ni_cnd.cn_nameiop = DELETE; 75052316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 75152653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 75252653Smckusick nfsd->nd_procp)) 75338418Smckusick nfsm_reply(0); 75449742Smckusick vp = nd.ni_vp; 75538418Smckusick if (vp->v_type == VDIR && 75652196Smckusick (error = suser(cred, (u_short *)0))) 75738418Smckusick goto out; 75838418Smckusick /* 75949454Smckusick * The root of a mounted filesystem cannot be deleted. 76038418Smckusick */ 76138418Smckusick if (vp->v_flag & VROOT) { 76238418Smckusick error = EBUSY; 76338418Smckusick goto out; 76438418Smckusick } 76538418Smckusick if (vp->v_flag & VTEXT) 76645715Smckusick (void) vnode_pager_uncache(vp); 76738418Smckusick out: 76842467Smckusick if (!error) { 76952196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 77052196Smckusick nqsrv_getl(vp, NQL_WRITE); 77152234Sheideman error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 77242467Smckusick } else { 77352234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 77449742Smckusick if (nd.ni_dvp == vp) 77549742Smckusick vrele(nd.ni_dvp); 77643359Smckusick else 77749742Smckusick vput(nd.ni_dvp); 77842467Smckusick vput(vp); 77942467Smckusick } 78038418Smckusick nfsm_reply(0); 78138418Smckusick nfsm_srvdone; 78238418Smckusick } 78338418Smckusick 78438418Smckusick /* 78538418Smckusick * nfs rename service 78638418Smckusick */ 78752196Smckusick nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq) 78852196Smckusick struct nfsd *nfsd; 78952196Smckusick struct mbuf *mrep, *md; 79038418Smckusick caddr_t dpos; 79138418Smckusick struct ucred *cred; 79252196Smckusick struct mbuf *nam, **mrq; 79338418Smckusick { 79453552Sheideman USES_VOP_ABORTOP; 79553552Sheideman USES_VOP_RENAME; 79648050Smckusick register u_long *tl; 79739494Smckusick register long t1; 79839494Smckusick caddr_t bpos; 79952196Smckusick int error = 0, rdonly, cache, len, len2; 80039494Smckusick char *cp2; 80139753Smckusick struct mbuf *mb, *mreq; 80249742Smckusick struct nameidata fromnd, tond; 80338418Smckusick struct vnode *fvp, *tvp, *tdvp; 80438418Smckusick nfsv2fh_t fnfh, tnfh; 80538418Smckusick fhandle_t *ffhp, *tfhp; 80652196Smckusick u_quad_t frev; 80752196Smckusick uid_t saved_uid; 80838418Smckusick 80938418Smckusick ffhp = &fnfh.fh_generic; 81038418Smckusick tfhp = &tnfh.fh_generic; 81152316Sheideman fromnd.ni_cnd.cn_nameiop = 0; 81252316Sheideman tond.ni_cnd.cn_nameiop = 0; 81338418Smckusick nfsm_srvmtofh(ffhp); 81438418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 81538418Smckusick /* 81652196Smckusick * Remember our original uid so that we can reset cr_uid before 81752196Smckusick * the second nfs_namei() call, in case it is remapped. 81838418Smckusick */ 81952196Smckusick saved_uid = cred->cr_uid; 82052316Sheideman fromnd.ni_cnd.cn_cred = cred; 82152316Sheideman fromnd.ni_cnd.cn_nameiop = DELETE; 82252316Sheideman fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART; 82352653Smckusick if (error = nfs_namei(&fromnd, ffhp, len, nfsd->nd_slp, nam, &md, 82452653Smckusick &dpos, nfsd->nd_procp)) 82538418Smckusick nfsm_reply(0); 82649742Smckusick fvp = fromnd.ni_vp; 82738418Smckusick nfsm_srvmtofh(tfhp); 82841899Smckusick nfsm_strsiz(len2, NFS_MAXNAMLEN); 82952196Smckusick cred->cr_uid = saved_uid; 83052316Sheideman tond.ni_cnd.cn_cred = cred; 83152316Sheideman tond.ni_cnd.cn_nameiop = RENAME; 83252316Sheideman tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; 83352653Smckusick if (error = nfs_namei(&tond, tfhp, len2, nfsd->nd_slp, nam, &md, 83452653Smckusick &dpos, nfsd->nd_procp)) { 83552234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 83649742Smckusick vrele(fromnd.ni_dvp); 83742467Smckusick vrele(fvp); 83842467Smckusick goto out1; 83942467Smckusick } 84038425Smckusick tdvp = tond.ni_dvp; 84138425Smckusick tvp = tond.ni_vp; 84238418Smckusick if (tvp != NULL) { 84338418Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 84438418Smckusick error = EISDIR; 84538418Smckusick goto out; 84638418Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 84738418Smckusick error = ENOTDIR; 84838418Smckusick goto out; 84938418Smckusick } 85052196Smckusick if (tvp->v_type == VDIR && tvp->v_mountedhere) { 85152196Smckusick error = EXDEV; 85252196Smckusick goto out; 85352196Smckusick } 85438418Smckusick } 85552196Smckusick if (fvp->v_type == VDIR && fvp->v_mountedhere) { 85652196Smckusick error = EBUSY; 85752196Smckusick goto out; 85852196Smckusick } 85938418Smckusick if (fvp->v_mount != tdvp->v_mount) { 86038418Smckusick error = EXDEV; 86138418Smckusick goto out; 86238418Smckusick } 86349742Smckusick if (fvp == tdvp) 86438418Smckusick error = EINVAL; 86549742Smckusick /* 86649742Smckusick * If source is the same as the destination (that is the 86749742Smckusick * same vnode with the same name in the same directory), 86849742Smckusick * then there is nothing to do. 86949742Smckusick */ 87049742Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 87152316Sheideman fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 87252316Sheideman !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 87352316Sheideman fromnd.ni_cnd.cn_namelen)) 87449742Smckusick error = -1; 87538418Smckusick out: 87642467Smckusick if (!error) { 87752196Smckusick nqsrv_getl(fromnd.ni_dvp, NQL_WRITE); 87852196Smckusick nqsrv_getl(tdvp, NQL_WRITE); 87952196Smckusick if (tvp) 88052196Smckusick nqsrv_getl(tvp, NQL_WRITE); 88152234Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 88252234Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 88342467Smckusick } else { 88452234Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 88543359Smckusick if (tdvp == tvp) 88643359Smckusick vrele(tdvp); 88743359Smckusick else 88843359Smckusick vput(tdvp); 88942467Smckusick if (tvp) 89042467Smckusick vput(tvp); 89152234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 89249742Smckusick vrele(fromnd.ni_dvp); 89342467Smckusick vrele(fvp); 89438418Smckusick } 89546513Smckusick vrele(tond.ni_startdir); 89652316Sheideman FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 89738418Smckusick out1: 89849742Smckusick vrele(fromnd.ni_startdir); 89952316Sheideman FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 90038418Smckusick nfsm_reply(0); 90138418Smckusick return (error); 90249742Smckusick 90338418Smckusick nfsmout: 90452316Sheideman if (tond.ni_cnd.cn_nameiop || tond.ni_cnd.cn_flags) { 90549742Smckusick vrele(tond.ni_startdir); 90652316Sheideman FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 90749742Smckusick } 90852316Sheideman if (fromnd.ni_cnd.cn_nameiop || fromnd.ni_cnd.cn_flags) { 90949742Smckusick vrele(fromnd.ni_startdir); 91052316Sheideman FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 91152234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 91249742Smckusick vrele(fromnd.ni_dvp); 91349742Smckusick vrele(fvp); 91449742Smckusick } 91538418Smckusick return (error); 91638418Smckusick } 91738418Smckusick 91838418Smckusick /* 91938418Smckusick * nfs link service 92038418Smckusick */ 92152196Smckusick nfsrv_link(nfsd, mrep, md, dpos, cred, nam, mrq) 92252196Smckusick struct nfsd *nfsd; 92352196Smckusick struct mbuf *mrep, *md; 92438418Smckusick caddr_t dpos; 92538418Smckusick struct ucred *cred; 92652196Smckusick struct mbuf *nam, **mrq; 92738418Smckusick { 92853552Sheideman USES_VOP_ABORTOP; 92953552Sheideman USES_VOP_LINK; 93049742Smckusick struct nameidata nd; 93148050Smckusick register u_long *tl; 93239494Smckusick register long t1; 93339494Smckusick caddr_t bpos; 93452196Smckusick int error = 0, rdonly, cache, len; 93539494Smckusick char *cp2; 93639753Smckusick struct mbuf *mb, *mreq; 93738418Smckusick struct vnode *vp, *xp; 93838418Smckusick nfsv2fh_t nfh, dnfh; 93938418Smckusick fhandle_t *fhp, *dfhp; 94052196Smckusick u_quad_t frev; 94138418Smckusick 94238418Smckusick fhp = &nfh.fh_generic; 94338418Smckusick dfhp = &dnfh.fh_generic; 94438418Smckusick nfsm_srvmtofh(fhp); 94538418Smckusick nfsm_srvmtofh(dfhp); 94638418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 94752196Smckusick if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 94838418Smckusick nfsm_reply(0); 94952196Smckusick if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0))) 95038418Smckusick goto out1; 95152316Sheideman nd.ni_cnd.cn_cred = cred; 95252316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 95352316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 95452653Smckusick if (error = nfs_namei(&nd, dfhp, len, nfsd->nd_slp, nam, &md, &dpos, 95552653Smckusick nfsd->nd_procp)) 95638418Smckusick goto out1; 95749742Smckusick xp = nd.ni_vp; 95838418Smckusick if (xp != NULL) { 95938418Smckusick error = EEXIST; 96038418Smckusick goto out; 96138418Smckusick } 96249742Smckusick xp = nd.ni_dvp; 96338418Smckusick if (vp->v_mount != xp->v_mount) 96438418Smckusick error = EXDEV; 96538418Smckusick out: 96642467Smckusick if (!error) { 96752196Smckusick nqsrv_getl(vp, NQL_WRITE); 96852196Smckusick nqsrv_getl(xp, NQL_WRITE); 96952933Smckusick error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 97042467Smckusick } else { 97152234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 97249742Smckusick if (nd.ni_dvp == nd.ni_vp) 97349742Smckusick vrele(nd.ni_dvp); 97443359Smckusick else 97549742Smckusick vput(nd.ni_dvp); 97649742Smckusick if (nd.ni_vp) 97749742Smckusick vrele(nd.ni_vp); 97842467Smckusick } 97938418Smckusick out1: 98038418Smckusick vrele(vp); 98138418Smckusick nfsm_reply(0); 98238418Smckusick nfsm_srvdone; 98338418Smckusick } 98438418Smckusick 98538418Smckusick /* 98638418Smckusick * nfs symbolic link service 98738418Smckusick */ 98852196Smckusick nfsrv_symlink(nfsd, mrep, md, dpos, cred, nam, mrq) 98952196Smckusick struct nfsd *nfsd; 99052196Smckusick struct mbuf *mrep, *md; 99138418Smckusick caddr_t dpos; 99238418Smckusick struct ucred *cred; 99352196Smckusick struct mbuf *nam, **mrq; 99438418Smckusick { 99553552Sheideman USES_VOP_ABORTOP; 99653552Sheideman USES_VOP_SYMLINK; 99738418Smckusick struct vattr va; 99849742Smckusick struct nameidata nd; 99938418Smckusick register struct vattr *vap = &va; 100048050Smckusick register u_long *tl; 100139494Smckusick register long t1; 100245285Smckusick struct nfsv2_sattr *sp; 100339494Smckusick caddr_t bpos; 100441899Smckusick struct uio io; 100541899Smckusick struct iovec iv; 100652196Smckusick int error = 0, rdonly, cache, len, len2; 100741899Smckusick char *pathcp, *cp2; 100839753Smckusick struct mbuf *mb, *mreq; 100938418Smckusick nfsv2fh_t nfh; 101038418Smckusick fhandle_t *fhp; 101152196Smckusick u_quad_t frev; 101238418Smckusick 101341899Smckusick pathcp = (char *)0; 101438418Smckusick fhp = &nfh.fh_generic; 101538418Smckusick nfsm_srvmtofh(fhp); 101638418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 101752316Sheideman nd.ni_cnd.cn_cred = cred; 101852316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 101952316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 102052653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 102152653Smckusick nfsd->nd_procp)) 102242467Smckusick goto out; 102341899Smckusick nfsm_strsiz(len2, NFS_MAXPATHLEN); 102441899Smckusick MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK); 102541899Smckusick iv.iov_base = pathcp; 102641899Smckusick iv.iov_len = len2; 102741899Smckusick io.uio_resid = len2; 102841899Smckusick io.uio_offset = 0; 102941899Smckusick io.uio_iov = &iv; 103041899Smckusick io.uio_iovcnt = 1; 103141899Smckusick io.uio_segflg = UIO_SYSSPACE; 103241899Smckusick io.uio_rw = UIO_READ; 103348050Smckusick io.uio_procp = (struct proc *)0; 103441899Smckusick nfsm_mtouio(&io, len2); 103552196Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR); 103641899Smckusick *(pathcp + len2) = '\0'; 103749742Smckusick if (nd.ni_vp) { 103852234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 103949742Smckusick if (nd.ni_dvp == nd.ni_vp) 104049742Smckusick vrele(nd.ni_dvp); 104143359Smckusick else 104249742Smckusick vput(nd.ni_dvp); 104349742Smckusick vrele(nd.ni_vp); 104438418Smckusick error = EEXIST; 104538418Smckusick goto out; 104638418Smckusick } 104741361Smckusick VATTR_NULL(vap); 104845285Smckusick vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode); 104952196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 105052234Sheideman error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp); 105138418Smckusick out: 105241899Smckusick if (pathcp) 105341899Smckusick FREE(pathcp, M_TEMP); 105438418Smckusick nfsm_reply(0); 105538418Smckusick return (error); 105638418Smckusick nfsmout: 105752234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 105849742Smckusick if (nd.ni_dvp == nd.ni_vp) 105949742Smckusick vrele(nd.ni_dvp); 106043359Smckusick else 106149742Smckusick vput(nd.ni_dvp); 106249742Smckusick if (nd.ni_vp) 106349742Smckusick vrele(nd.ni_vp); 106441899Smckusick if (pathcp) 106541899Smckusick FREE(pathcp, M_TEMP); 106638418Smckusick return (error); 106738418Smckusick } 106838418Smckusick 106938418Smckusick /* 107038418Smckusick * nfs mkdir service 107138418Smckusick */ 107252196Smckusick nfsrv_mkdir(nfsd, mrep, md, dpos, cred, nam, mrq) 107352196Smckusick struct nfsd *nfsd; 107452196Smckusick struct mbuf *mrep, *md; 107538418Smckusick caddr_t dpos; 107638418Smckusick struct ucred *cred; 107752196Smckusick struct mbuf *nam, **mrq; 107838418Smckusick { 107953552Sheideman USES_VOP_ABORTOP; 108053552Sheideman USES_VOP_GETATTR; 108153552Sheideman USES_VOP_MKDIR; 108238418Smckusick struct vattr va; 108338418Smckusick register struct vattr *vap = &va; 108438884Smacklem register struct nfsv2_fattr *fp; 108549742Smckusick struct nameidata nd; 108639494Smckusick register caddr_t cp; 108748050Smckusick register u_long *tl; 108839494Smckusick register long t1; 108939494Smckusick caddr_t bpos; 109052196Smckusick int error = 0, rdonly, cache, len; 109139494Smckusick char *cp2; 109239753Smckusick struct mbuf *mb, *mb2, *mreq; 109338418Smckusick struct vnode *vp; 109438418Smckusick nfsv2fh_t nfh; 109538418Smckusick fhandle_t *fhp; 109652196Smckusick u_quad_t frev; 109738418Smckusick 109838418Smckusick fhp = &nfh.fh_generic; 109938418Smckusick nfsm_srvmtofh(fhp); 110038418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 110152316Sheideman nd.ni_cnd.cn_cred = cred; 110252316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 110352316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 110452653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 110552653Smckusick nfsd->nd_procp)) 110638418Smckusick nfsm_reply(0); 110752196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 110841361Smckusick VATTR_NULL(vap); 110938418Smckusick vap->va_type = VDIR; 111048050Smckusick vap->va_mode = nfstov_mode(*tl++); 111149742Smckusick vp = nd.ni_vp; 111238418Smckusick if (vp != NULL) { 111352234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 111449742Smckusick if (nd.ni_dvp == vp) 111549742Smckusick vrele(nd.ni_dvp); 111643359Smckusick else 111749742Smckusick vput(nd.ni_dvp); 111842467Smckusick vrele(vp); 111938418Smckusick error = EEXIST; 112038418Smckusick nfsm_reply(0); 112138418Smckusick } 112252196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 112352234Sheideman if (error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) 112438418Smckusick nfsm_reply(0); 112549742Smckusick vp = nd.ni_vp; 112638418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 112741398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 112838418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 112938418Smckusick vput(vp); 113038418Smckusick nfsm_reply(0); 113138418Smckusick } 113252196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 113338418Smckusick vput(vp); 113438418Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR); 113538418Smckusick nfsm_srvfhtom(fhp); 113638884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 113739753Smckusick nfsm_srvfillattr; 113838418Smckusick return (error); 113938418Smckusick nfsmout: 114052234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 114149742Smckusick if (nd.ni_dvp == nd.ni_vp) 114249742Smckusick vrele(nd.ni_dvp); 114343359Smckusick else 114449742Smckusick vput(nd.ni_dvp); 114549742Smckusick if (nd.ni_vp) 114649742Smckusick vrele(nd.ni_vp); 114738418Smckusick return (error); 114838418Smckusick } 114938418Smckusick 115038418Smckusick /* 115138418Smckusick * nfs rmdir service 115238418Smckusick */ 115352196Smckusick nfsrv_rmdir(nfsd, mrep, md, dpos, cred, nam, mrq) 115452196Smckusick struct nfsd *nfsd; 115552196Smckusick struct mbuf *mrep, *md; 115638418Smckusick caddr_t dpos; 115738418Smckusick struct ucred *cred; 115852196Smckusick struct mbuf *nam, **mrq; 115938418Smckusick { 116053552Sheideman USES_VOP_ABORTOP; 116153552Sheideman USES_VOP_RMDIR; 116248050Smckusick register u_long *tl; 116339494Smckusick register long t1; 116439494Smckusick caddr_t bpos; 116552196Smckusick int error = 0, rdonly, cache, len; 116639494Smckusick char *cp2; 116739753Smckusick struct mbuf *mb, *mreq; 116838418Smckusick struct vnode *vp; 116938418Smckusick nfsv2fh_t nfh; 117038418Smckusick fhandle_t *fhp; 117149742Smckusick struct nameidata nd; 117252196Smckusick u_quad_t frev; 117338418Smckusick 117438418Smckusick fhp = &nfh.fh_generic; 117538418Smckusick nfsm_srvmtofh(fhp); 117638418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 117752316Sheideman nd.ni_cnd.cn_cred = cred; 117852316Sheideman nd.ni_cnd.cn_nameiop = DELETE; 117952316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 118052653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 118152653Smckusick nfsd->nd_procp)) 118238418Smckusick nfsm_reply(0); 118349742Smckusick vp = nd.ni_vp; 118438418Smckusick if (vp->v_type != VDIR) { 118538418Smckusick error = ENOTDIR; 118638418Smckusick goto out; 118738418Smckusick } 118838418Smckusick /* 118938418Smckusick * No rmdir "." please. 119038418Smckusick */ 119149742Smckusick if (nd.ni_dvp == vp) { 119238418Smckusick error = EINVAL; 119338418Smckusick goto out; 119438418Smckusick } 119538418Smckusick /* 119649454Smckusick * The root of a mounted filesystem cannot be deleted. 119738418Smckusick */ 119838418Smckusick if (vp->v_flag & VROOT) 119938418Smckusick error = EBUSY; 120038418Smckusick out: 120142467Smckusick if (!error) { 120252196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 120352196Smckusick nqsrv_getl(vp, NQL_WRITE); 120452234Sheideman error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 120542467Smckusick } else { 120652234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 120749742Smckusick if (nd.ni_dvp == nd.ni_vp) 120849742Smckusick vrele(nd.ni_dvp); 120943359Smckusick else 121049742Smckusick vput(nd.ni_dvp); 121142467Smckusick vput(vp); 121242467Smckusick } 121338418Smckusick nfsm_reply(0); 121438418Smckusick nfsm_srvdone; 121538418Smckusick } 121638418Smckusick 121738418Smckusick /* 121838418Smckusick * nfs readdir service 121938418Smckusick * - mallocs what it thinks is enough to read 122048050Smckusick * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR 122138418Smckusick * - calls VOP_READDIR() 122240115Smckusick * - loops around building the reply 122338425Smckusick * if the output generated exceeds count break out of loop 122438425Smckusick * The nfsm_clget macro is used here so that the reply will be packed 122538425Smckusick * tightly in mbuf clusters. 122638418Smckusick * - it only knows that it has encountered eof when the VOP_READDIR() 122738425Smckusick * reads nothing 122838418Smckusick * - as such one readdir rpc will return eof false although you are there 122938425Smckusick * and then the next will return eof 123052441Smckusick * - it trims out records with d_fileno == 0 123138425Smckusick * this doesn't matter for Unix clients, but they might confuse clients 123238425Smckusick * for other os'. 123338418Smckusick * NB: It is tempting to set eof to true if the VOP_READDIR() reads less 123438425Smckusick * than requested, but this may not apply to all filesystems. For 123538425Smckusick * example, client NFS does not { although it is never remote mounted 123638425Smckusick * anyhow } 123752196Smckusick * The alternate call nqnfsrv_readdirlook() does lookups as well. 123838418Smckusick * PS: The NFS protocol spec. does not clarify what the "count" byte 123938425Smckusick * argument is a count of.. just name strings and file id's or the 124038425Smckusick * entire reply rpc or ... 124138425Smckusick * I tried just file name and id sizes and it confused the Sun client, 124238425Smckusick * so I am using the full rpc size now. The "paranoia.." comment refers 124338425Smckusick * to including the status longwords that are not a part of the dir. 124438425Smckusick * "entry" structures, but are in the rpc. 124538418Smckusick */ 124652196Smckusick struct flrep { 124752196Smckusick u_long fl_cachable; 124852196Smckusick u_long fl_duration; 124952196Smckusick u_quad_t fl_frev; 125052196Smckusick nfsv2fh_t fl_nfh; 125152196Smckusick struct nfsv2_fattr fl_fattr; 125252196Smckusick }; 125352196Smckusick 125452196Smckusick nfsrv_readdir(nfsd, mrep, md, dpos, cred, nam, mrq) 125552196Smckusick struct nfsd *nfsd; 125638418Smckusick struct mbuf *mrep, *md; 125738418Smckusick caddr_t dpos; 125838418Smckusick struct ucred *cred; 125952196Smckusick struct mbuf *nam, **mrq; 126038418Smckusick { 126153552Sheideman USES_VOP_READDIR; 126253552Sheideman USES_VOP_UNLOCK; 126338418Smckusick register char *bp, *be; 126438418Smckusick register struct mbuf *mp; 126552441Smckusick register struct dirent *dp; 126639494Smckusick register caddr_t cp; 126748050Smckusick register u_long *tl; 126839494Smckusick register long t1; 126939494Smckusick caddr_t bpos; 127052196Smckusick struct mbuf *mb, *mb2, *mreq, *mp2; 127152196Smckusick char *cpos, *cend, *cp2, *rbuf; 127238418Smckusick struct vnode *vp; 127338418Smckusick nfsv2fh_t nfh; 127438418Smckusick fhandle_t *fhp; 127538418Smckusick struct uio io; 127638418Smckusick struct iovec iv; 127752196Smckusick struct vattr va; 127852196Smckusick int len, nlen, rem, xfer, tsiz, i, error = 0; 127952196Smckusick int siz, cnt, fullsiz, eofflag, rdonly, cache; 128052196Smckusick u_quad_t frev; 128138418Smckusick u_long on; 128238418Smckusick off_t off, toff; 128338418Smckusick 128438418Smckusick fhp = &nfh.fh_generic; 128538418Smckusick nfsm_srvmtofh(fhp); 128652196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 128748050Smckusick toff = fxdr_unsigned(off_t, *tl++); 128848050Smckusick off = (toff & ~(NFS_DIRBLKSIZ-1)); 128948050Smckusick on = (toff & (NFS_DIRBLKSIZ-1)); 129048050Smckusick cnt = fxdr_unsigned(int, *tl); 129148050Smckusick siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); 129241899Smckusick if (cnt > NFS_MAXREADDIR) 129341899Smckusick siz = NFS_MAXREADDIR; 129438418Smckusick fullsiz = siz; 129552196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 129638418Smckusick nfsm_reply(0); 129752196Smckusick nqsrv_getl(vp, NQL_READ); 129852196Smckusick if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { 129938418Smckusick vput(vp); 130038418Smckusick nfsm_reply(0); 130138418Smckusick } 130238418Smckusick VOP_UNLOCK(vp); 130338418Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 130438418Smckusick again: 130538418Smckusick iv.iov_base = rbuf; 130638418Smckusick iv.iov_len = fullsiz; 130738418Smckusick io.uio_iov = &iv; 130838418Smckusick io.uio_iovcnt = 1; 130938418Smckusick io.uio_offset = off; 131038418Smckusick io.uio_resid = fullsiz; 131138418Smckusick io.uio_segflg = UIO_SYSSPACE; 131238418Smckusick io.uio_rw = UIO_READ; 131348050Smckusick io.uio_procp = (struct proc *)0; 1314*54446Smckusick error = VOP_READDIR(vp, &io, cred); 131539586Smckusick off = io.uio_offset; 131638418Smckusick if (error) { 131738418Smckusick vrele(vp); 131838418Smckusick free((caddr_t)rbuf, M_TEMP); 131938418Smckusick nfsm_reply(0); 132038418Smckusick } 1321*54446Smckusick if (io.uio_resid < fullsiz) 1322*54446Smckusick eofflag = 0; 1323*54446Smckusick else 1324*54446Smckusick eofflag = 1; 132538418Smckusick if (io.uio_resid) { 132638418Smckusick siz -= io.uio_resid; 132738418Smckusick 132838418Smckusick /* 132938418Smckusick * If nothing read, return eof 133038418Smckusick * rpc reply 133138418Smckusick */ 133238418Smckusick if (siz == 0) { 133338418Smckusick vrele(vp); 133438418Smckusick nfsm_reply(2*NFSX_UNSIGNED); 133548050Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 133648050Smckusick *tl++ = nfs_false; 133748050Smckusick *tl = nfs_true; 133838418Smckusick FREE((caddr_t)rbuf, M_TEMP); 133938418Smckusick return (0); 134038418Smckusick } 134138418Smckusick } 134240115Smckusick 134338418Smckusick /* 134438418Smckusick * Check for degenerate cases of nothing useful read. 134540115Smckusick * If so go try again 134638418Smckusick */ 134740115Smckusick cpos = rbuf + on; 134840115Smckusick cend = rbuf + siz; 134952441Smckusick dp = (struct dirent *)cpos; 135052441Smckusick while (cpos < cend && dp->d_fileno == 0) { 135140115Smckusick cpos += dp->d_reclen; 135252441Smckusick dp = (struct dirent *)cpos; 135340115Smckusick } 135440115Smckusick if (cpos >= cend) { 135538418Smckusick toff = off; 135638418Smckusick siz = fullsiz; 135738418Smckusick on = 0; 135838418Smckusick goto again; 135938418Smckusick } 136040115Smckusick 136140115Smckusick cpos = rbuf + on; 136240115Smckusick cend = rbuf + siz; 136352441Smckusick dp = (struct dirent *)cpos; 136452196Smckusick len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 136552196Smckusick nfsm_reply(siz); 136652196Smckusick mp = mp2 = mb; 136752196Smckusick bp = bpos; 136852196Smckusick be = bp + M_TRAILINGSPACE(mp); 136952196Smckusick 137052196Smckusick /* Loop through the records and build reply */ 137152196Smckusick while (cpos < cend) { 137252441Smckusick if (dp->d_fileno != 0) { 137352196Smckusick nlen = dp->d_namlen; 137452196Smckusick rem = nfsm_rndup(nlen)-nlen; 137552196Smckusick len += (4*NFSX_UNSIGNED + nlen + rem); 137652196Smckusick if (len > cnt) { 137752196Smckusick eofflag = 0; 137852196Smckusick break; 137952196Smckusick } 138052441Smckusick /* 138152441Smckusick * Build the directory record xdr from 138252441Smckusick * the dirent entry. 138352441Smckusick */ 138452196Smckusick nfsm_clget; 138552196Smckusick *tl = nfs_true; 138652196Smckusick bp += NFSX_UNSIGNED; 138752196Smckusick nfsm_clget; 138852441Smckusick *tl = txdr_unsigned(dp->d_fileno); 138952196Smckusick bp += NFSX_UNSIGNED; 139052196Smckusick nfsm_clget; 139152196Smckusick *tl = txdr_unsigned(nlen); 139252196Smckusick bp += NFSX_UNSIGNED; 139352196Smckusick 139452196Smckusick /* And loop around copying the name */ 139552196Smckusick xfer = nlen; 139652196Smckusick cp = dp->d_name; 139752196Smckusick while (xfer > 0) { 139852196Smckusick nfsm_clget; 139952196Smckusick if ((bp+xfer) > be) 140052196Smckusick tsiz = be-bp; 140152196Smckusick else 140252196Smckusick tsiz = xfer; 140352196Smckusick bcopy(cp, bp, tsiz); 140452196Smckusick bp += tsiz; 140552196Smckusick xfer -= tsiz; 140652196Smckusick if (xfer > 0) 140752196Smckusick cp += tsiz; 140852196Smckusick } 140952196Smckusick /* And null pad to a long boundary */ 141052196Smckusick for (i = 0; i < rem; i++) 141152196Smckusick *bp++ = '\0'; 141252196Smckusick nfsm_clget; 141352196Smckusick 141452196Smckusick /* Finish off the record */ 141552196Smckusick toff += dp->d_reclen; 141652196Smckusick *tl = txdr_unsigned(toff); 141752196Smckusick bp += NFSX_UNSIGNED; 141852196Smckusick } else 141952196Smckusick toff += dp->d_reclen; 142052196Smckusick cpos += dp->d_reclen; 142152441Smckusick dp = (struct dirent *)cpos; 142252196Smckusick } 142338418Smckusick vrele(vp); 142452196Smckusick nfsm_clget; 142552196Smckusick *tl = nfs_false; 142652196Smckusick bp += NFSX_UNSIGNED; 142752196Smckusick nfsm_clget; 142852196Smckusick if (eofflag) 142952196Smckusick *tl = nfs_true; 143052196Smckusick else 143152196Smckusick *tl = nfs_false; 143252196Smckusick bp += NFSX_UNSIGNED; 143352196Smckusick if (mp != mb) { 143452196Smckusick if (bp < be) 143552196Smckusick mp->m_len = bp - mtod(mp, caddr_t); 143652196Smckusick } else 143752196Smckusick mp->m_len += bp - bpos; 143852196Smckusick FREE(rbuf, M_TEMP); 143952196Smckusick nfsm_srvdone; 144052196Smckusick } 144152196Smckusick 144252196Smckusick nqnfsrv_readdirlook(nfsd, mrep, md, dpos, cred, nam, mrq) 144352196Smckusick struct nfsd *nfsd; 144452196Smckusick struct mbuf *mrep, *md; 144552196Smckusick caddr_t dpos; 144652196Smckusick struct ucred *cred; 144752196Smckusick struct mbuf *nam, **mrq; 144852196Smckusick { 1449*54446Smckusick USES_VOP_VGET; 145053552Sheideman USES_VOP_GETATTR; 145153552Sheideman USES_VOP_READDIR; 145253552Sheideman USES_VOP_UNLOCK; 145352196Smckusick register char *bp, *be; 145452196Smckusick register struct mbuf *mp; 145552441Smckusick register struct dirent *dp; 145652196Smckusick register caddr_t cp; 145752196Smckusick register u_long *tl; 145852196Smckusick register long t1; 145952196Smckusick caddr_t bpos; 146052196Smckusick struct mbuf *mb, *mb2, *mreq, *mp2; 146152196Smckusick char *cpos, *cend, *cp2, *rbuf; 146252196Smckusick struct vnode *vp, *nvp; 146352196Smckusick struct flrep fl; 146452196Smckusick nfsv2fh_t nfh; 146552196Smckusick fhandle_t *fhp; 146652196Smckusick struct uio io; 146752196Smckusick struct iovec iv; 146852196Smckusick struct vattr va, *vap = &va; 146952196Smckusick struct nfsv2_fattr *fp; 147052196Smckusick int len, nlen, rem, xfer, tsiz, i, error = 0, duration2, cache2; 147152196Smckusick int siz, cnt, fullsiz, eofflag, rdonly, cache; 147252196Smckusick u_quad_t frev, frev2; 147352196Smckusick u_long on; 147452196Smckusick off_t off, toff; 147552196Smckusick 147652196Smckusick fhp = &nfh.fh_generic; 147752196Smckusick nfsm_srvmtofh(fhp); 147852196Smckusick nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED); 147952196Smckusick toff = fxdr_unsigned(off_t, *tl++); 148052196Smckusick off = (toff & ~(NFS_DIRBLKSIZ-1)); 148152196Smckusick on = (toff & (NFS_DIRBLKSIZ-1)); 148252196Smckusick cnt = fxdr_unsigned(int, *tl++); 148352196Smckusick duration2 = fxdr_unsigned(int, *tl); 148452196Smckusick siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); 148552196Smckusick if (cnt > NFS_MAXREADDIR) 148652196Smckusick siz = NFS_MAXREADDIR; 148752196Smckusick fullsiz = siz; 148852196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 148952196Smckusick nfsm_reply(0); 149052196Smckusick nqsrv_getl(vp, NQL_READ); 149152196Smckusick if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { 149252196Smckusick vput(vp); 149352196Smckusick nfsm_reply(0); 149452196Smckusick } 149552196Smckusick VOP_UNLOCK(vp); 149652196Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 149752196Smckusick again: 149852196Smckusick iv.iov_base = rbuf; 149952196Smckusick iv.iov_len = fullsiz; 150052196Smckusick io.uio_iov = &iv; 150152196Smckusick io.uio_iovcnt = 1; 150252196Smckusick io.uio_offset = off; 150352196Smckusick io.uio_resid = fullsiz; 150452196Smckusick io.uio_segflg = UIO_SYSSPACE; 150552196Smckusick io.uio_rw = UIO_READ; 150652196Smckusick io.uio_procp = (struct proc *)0; 1507*54446Smckusick error = VOP_READDIR(vp, &io, cred); 150852196Smckusick off = io.uio_offset; 150952196Smckusick if (error) { 151052196Smckusick vrele(vp); 151152196Smckusick free((caddr_t)rbuf, M_TEMP); 151252196Smckusick nfsm_reply(0); 151352196Smckusick } 1514*54446Smckusick if (io.uio_resid < fullsiz) 1515*54446Smckusick eofflag = 0; 1516*54446Smckusick else 1517*54446Smckusick eofflag = 1; 151852196Smckusick if (io.uio_resid) { 151952196Smckusick siz -= io.uio_resid; 152052196Smckusick 152152196Smckusick /* 152252196Smckusick * If nothing read, return eof 152352196Smckusick * rpc reply 152452196Smckusick */ 152552196Smckusick if (siz == 0) { 152652196Smckusick vrele(vp); 152752196Smckusick nfsm_reply(2*NFSX_UNSIGNED); 152852196Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 152952196Smckusick *tl++ = nfs_false; 153052196Smckusick *tl = nfs_true; 153152196Smckusick FREE((caddr_t)rbuf, M_TEMP); 153252196Smckusick return (0); 153352196Smckusick } 153452196Smckusick } 153552196Smckusick 153652196Smckusick /* 153752196Smckusick * Check for degenerate cases of nothing useful read. 153852196Smckusick * If so go try again 153952196Smckusick */ 154052196Smckusick cpos = rbuf + on; 154152196Smckusick cend = rbuf + siz; 154252441Smckusick dp = (struct dirent *)cpos; 154352441Smckusick while (cpos < cend && dp->d_fileno == 0) { 154452196Smckusick cpos += dp->d_reclen; 154552441Smckusick dp = (struct dirent *)cpos; 154652196Smckusick } 154752196Smckusick if (cpos >= cend) { 154852196Smckusick toff = off; 154952196Smckusick siz = fullsiz; 155052196Smckusick on = 0; 155152196Smckusick goto again; 155252196Smckusick } 155352196Smckusick 155452196Smckusick cpos = rbuf + on; 155552196Smckusick cend = rbuf + siz; 155652441Smckusick dp = (struct dirent *)cpos; 155738425Smckusick len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 155838418Smckusick nfsm_reply(siz); 155952196Smckusick mp = mp2 = mb; 156052196Smckusick bp = bpos; 156152196Smckusick be = bp + M_TRAILINGSPACE(mp); 156238418Smckusick 156338418Smckusick /* Loop through the records and build reply */ 156438418Smckusick while (cpos < cend) { 156552441Smckusick if (dp->d_fileno != 0) { 156638418Smckusick nlen = dp->d_namlen; 156738418Smckusick rem = nfsm_rndup(nlen)-nlen; 156838425Smckusick 156938418Smckusick /* 157052196Smckusick * For readdir_and_lookup get the vnode using 157152196Smckusick * the file number. 157238418Smckusick */ 1573*54446Smckusick if (VOP_VGET(vp, dp->d_fileno, &nvp)) 157452196Smckusick goto invalid; 157552196Smckusick (void) nqsrv_getlease(nvp, &duration2, NQL_READ, nfsd, 157652196Smckusick nam, &cache2, &frev2, cred); 1577*54446Smckusick bzero((caddr_t)&fl.fl_nfh, sizeof (nfsv2fh_t)); 157852196Smckusick fl.fl_duration = txdr_unsigned(duration2); 157952196Smckusick fl.fl_cachable = txdr_unsigned(cache2); 158052196Smckusick txdr_hyper(&frev2, &fl.fl_frev); 158152196Smckusick if (VOP_GETATTR(nvp, vap, cred, nfsd->nd_procp)) { 158252196Smckusick vput(nvp); 158352196Smckusick goto invalid; 158452196Smckusick } 158552196Smckusick vput(nvp); 158652196Smckusick fp = &fl.fl_fattr; 158752196Smckusick nfsm_srvfillattr; 158852196Smckusick len += (4*NFSX_UNSIGNED + nlen + rem + NFSX_FH 158952196Smckusick + NFSX_FATTR); 159041899Smckusick if (len > cnt) { 159141899Smckusick eofflag = 0; 159238418Smckusick break; 159341899Smckusick } 159452441Smckusick /* 159552441Smckusick * Build the directory record xdr from 159652441Smckusick * the dirent entry. 159752441Smckusick */ 159838418Smckusick nfsm_clget; 159948050Smckusick *tl = nfs_true; 160038418Smckusick bp += NFSX_UNSIGNED; 160152196Smckusick 160252196Smckusick /* 160352196Smckusick * For readdir_and_lookup copy the stuff out. 160452196Smckusick */ 160552196Smckusick xfer = sizeof (struct flrep); 160652196Smckusick cp = (caddr_t)&fl; 160752196Smckusick while (xfer > 0) { 160852196Smckusick nfsm_clget; 160952196Smckusick if ((bp+xfer) > be) 161052196Smckusick tsiz = be-bp; 161152196Smckusick else 161252196Smckusick tsiz = xfer; 161352196Smckusick bcopy(cp, bp, tsiz); 161452196Smckusick bp += tsiz; 161552196Smckusick xfer -= tsiz; 161652196Smckusick if (xfer > 0) 161752196Smckusick cp += tsiz; 161852196Smckusick } 161938418Smckusick nfsm_clget; 162052441Smckusick *tl = txdr_unsigned(dp->d_fileno); 162138418Smckusick bp += NFSX_UNSIGNED; 162238418Smckusick nfsm_clget; 162348050Smckusick *tl = txdr_unsigned(nlen); 162438418Smckusick bp += NFSX_UNSIGNED; 162538425Smckusick 162652196Smckusick /* And loop around copying the name */ 162738418Smckusick xfer = nlen; 162838418Smckusick cp = dp->d_name; 162938418Smckusick while (xfer > 0) { 163038418Smckusick nfsm_clget; 163138418Smckusick if ((bp+xfer) > be) 163238418Smckusick tsiz = be-bp; 163338418Smckusick else 163438418Smckusick tsiz = xfer; 163538418Smckusick bcopy(cp, bp, tsiz); 163638418Smckusick bp += tsiz; 163738418Smckusick xfer -= tsiz; 163838418Smckusick if (xfer > 0) 163938418Smckusick cp += tsiz; 164038418Smckusick } 164138418Smckusick /* And null pad to a long boundary */ 164238418Smckusick for (i = 0; i < rem; i++) 164338418Smckusick *bp++ = '\0'; 164438418Smckusick nfsm_clget; 164538425Smckusick 164638418Smckusick /* Finish off the record */ 164738418Smckusick toff += dp->d_reclen; 164848050Smckusick *tl = txdr_unsigned(toff); 164938418Smckusick bp += NFSX_UNSIGNED; 165038418Smckusick } else 165152196Smckusick invalid: 165238418Smckusick toff += dp->d_reclen; 165338418Smckusick cpos += dp->d_reclen; 165452441Smckusick dp = (struct dirent *)cpos; 165538418Smckusick } 165652196Smckusick vrele(vp); 165738418Smckusick nfsm_clget; 165848050Smckusick *tl = nfs_false; 165938418Smckusick bp += NFSX_UNSIGNED; 166038418Smckusick nfsm_clget; 166140296Smckusick if (eofflag) 166248050Smckusick *tl = nfs_true; 166340296Smckusick else 166448050Smckusick *tl = nfs_false; 166538418Smckusick bp += NFSX_UNSIGNED; 166652196Smckusick if (mp != mb) { 166752196Smckusick if (bp < be) 166852196Smckusick mp->m_len = bp - mtod(mp, caddr_t); 166952196Smckusick } else 167052196Smckusick mp->m_len += bp - bpos; 167138418Smckusick FREE(rbuf, M_TEMP); 167238418Smckusick nfsm_srvdone; 167338418Smckusick } 167438418Smckusick 167538418Smckusick /* 167638418Smckusick * nfs statfs service 167738418Smckusick */ 167852196Smckusick nfsrv_statfs(nfsd, mrep, md, dpos, cred, nam, mrq) 167952196Smckusick struct nfsd *nfsd; 168038418Smckusick struct mbuf *mrep, *md; 168138418Smckusick caddr_t dpos; 168238418Smckusick struct ucred *cred; 168352196Smckusick struct mbuf *nam, **mrq; 168438418Smckusick { 168538418Smckusick register struct statfs *sf; 168638884Smacklem register struct nfsv2_statfs *sfp; 168748050Smckusick register u_long *tl; 168839494Smckusick register long t1; 168939494Smckusick caddr_t bpos; 169052196Smckusick int error = 0, rdonly, cache; 169139494Smckusick char *cp2; 169239753Smckusick struct mbuf *mb, *mb2, *mreq; 169338418Smckusick struct vnode *vp; 169438418Smckusick nfsv2fh_t nfh; 169538418Smckusick fhandle_t *fhp; 169638418Smckusick struct statfs statfs; 169752196Smckusick u_quad_t frev; 169838418Smckusick 169938418Smckusick fhp = &nfh.fh_generic; 170038418Smckusick nfsm_srvmtofh(fhp); 170152196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 170238418Smckusick nfsm_reply(0); 170338418Smckusick sf = &statfs; 170452196Smckusick error = VFS_STATFS(vp->v_mount, sf, nfsd->nd_procp); 170538418Smckusick vput(vp); 170638418Smckusick nfsm_reply(NFSX_STATFS); 170738884Smacklem nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS); 170844993Sbostic sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA); 170951940Smckusick sfp->sf_bsize = txdr_unsigned(sf->f_bsize); 171038884Smacklem sfp->sf_blocks = txdr_unsigned(sf->f_blocks); 171138884Smacklem sfp->sf_bfree = txdr_unsigned(sf->f_bfree); 171238884Smacklem sfp->sf_bavail = txdr_unsigned(sf->f_bavail); 171338418Smckusick nfsm_srvdone; 171438418Smckusick } 171538418Smckusick 171638418Smckusick /* 171738418Smckusick * Null operation, used by clients to ping server 171838418Smckusick */ 171939494Smckusick /* ARGSUSED */ 172052196Smckusick nfsrv_null(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 { 172739494Smckusick caddr_t bpos; 172852196Smckusick int error = VNOVAL, cache; 172939753Smckusick struct mbuf *mb, *mreq; 173052196Smckusick u_quad_t frev; 173138418Smckusick 173238418Smckusick nfsm_reply(0); 173339494Smckusick return (error); 173438418Smckusick } 173538418Smckusick 173638418Smckusick /* 173738418Smckusick * No operation, used for obsolete procedures 173838418Smckusick */ 173939494Smckusick /* ARGSUSED */ 174052196Smckusick nfsrv_noop(nfsd, mrep, md, dpos, cred, nam, mrq) 174152196Smckusick struct nfsd *nfsd; 174238418Smckusick struct mbuf *mrep, *md; 174338418Smckusick caddr_t dpos; 174438418Smckusick struct ucred *cred; 174552196Smckusick struct mbuf *nam, **mrq; 174638418Smckusick { 174739494Smckusick caddr_t bpos; 174852196Smckusick int error, cache; 174939753Smckusick struct mbuf *mb, *mreq; 175052196Smckusick u_quad_t frev; 175138418Smckusick 175252196Smckusick if (nfsd->nd_repstat) 175352196Smckusick error = nfsd->nd_repstat; 175452196Smckusick else 175552196Smckusick error = EPROCUNAVAIL; 175638418Smckusick nfsm_reply(0); 175739494Smckusick return (error); 175838418Smckusick } 175938425Smckusick 176038450Smckusick /* 176138450Smckusick * Perform access checking for vnodes obtained from file handles that would 176238450Smckusick * refer to files already opened by a Unix client. You cannot just use 176338450Smckusick * vn_writechk() and VOP_ACCESS() for two reasons. 176452196Smckusick * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case 176538450Smckusick * 2 - The owner is to be given access irrespective of mode bits so that 176638450Smckusick * processes that chmod after opening a file don't break. I don't like 176738450Smckusick * this because it opens a security hole, but since the nfs server opens 176838450Smckusick * a security hole the size of a barn door anyhow, what the heck. 176938450Smckusick */ 177052196Smckusick nfsrv_access(vp, flags, cred, rdonly, p) 177138450Smckusick register struct vnode *vp; 177238450Smckusick int flags; 177338450Smckusick register struct ucred *cred; 177452196Smckusick int rdonly; 177548050Smckusick struct proc *p; 177638450Smckusick { 177753552Sheideman USES_VOP_ACCESS; 177853552Sheideman USES_VOP_GETATTR; 177938450Smckusick struct vattr vattr; 178038450Smckusick int error; 178138450Smckusick if (flags & VWRITE) { 178252196Smckusick /* Just vn_writechk() changed to check rdonly */ 178338450Smckusick /* 178438450Smckusick * Disallow write attempts on read-only file systems; 178538450Smckusick * unless the file is a socket or a block or character 178638450Smckusick * device resident on the file system. 178738450Smckusick */ 178852196Smckusick if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { 178945059Smckusick switch (vp->v_type) { 179045059Smckusick case VREG: case VDIR: case VLNK: 179138450Smckusick return (EROFS); 179245059Smckusick } 179345059Smckusick } 179438450Smckusick /* 179538450Smckusick * If there's shared text associated with 179638450Smckusick * the inode, try to free it up once. If 179738450Smckusick * we fail, we can't allow writing. 179838450Smckusick */ 179945715Smckusick if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) 180038450Smckusick return (ETXTBSY); 180138450Smckusick } 180248050Smckusick if (error = VOP_GETATTR(vp, &vattr, cred, p)) 180345059Smckusick return (error); 180448050Smckusick if ((error = VOP_ACCESS(vp, flags, cred, p)) && 180545059Smckusick cred->cr_uid != vattr.va_uid) 180645059Smckusick return (error); 180745059Smckusick return (0); 180838450Smckusick } 1809