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*52442Smckusick * @(#)nfs_serv.c 7.47 (Berkeley) 02/06/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 3138418Smckusick #include "param.h" 3249742Smckusick #include "proc.h" 3340135Smckusick #include "file.h" 3448050Smckusick #include "namei.h" 3540135Smckusick #include "vnode.h" 3638418Smckusick #include "mount.h" 3738418Smckusick #include "mbuf.h" 3852441Smckusick #include "dirent.h" 3947573Skarels 4052441Smckusick #include "ufs/ufs/quota.h" /* XXX - for ufid */ 4152441Smckusick #include "ufs/ufs/inode.h" /* XXX - for ufid */ 4247573Skarels 4338418Smckusick #include "nfsv2.h" 4452196Smckusick #include "rpcv2.h" 4538418Smckusick #include "nfs.h" 4638418Smckusick #include "xdr_subs.h" 4738418Smckusick #include "nfsm_subs.h" 4852196Smckusick #include "nqnfs.h" 4938418Smckusick 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 { 7138884Smacklem register struct nfsv2_fattr *fp; 7238418Smckusick struct vattr va; 7338418Smckusick register struct vattr *vap = &va; 7438418Smckusick struct vnode *vp; 7538418Smckusick nfsv2fh_t nfh; 7638418Smckusick fhandle_t *fhp; 7748050Smckusick register u_long *tl; 7839494Smckusick register long t1; 7939494Smckusick caddr_t bpos; 8052196Smckusick int error = 0, rdonly, cache; 8139494Smckusick char *cp2; 8239753Smckusick struct mbuf *mb, *mb2, *mreq; 8352196Smckusick u_quad_t frev; 8438418Smckusick 8538418Smckusick fhp = &nfh.fh_generic; 8638418Smckusick nfsm_srvmtofh(fhp); 8752196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 8838418Smckusick nfsm_reply(0); 8952196Smckusick nqsrv_getl(vp, NQL_READ); 9052196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 9138418Smckusick vput(vp); 9238418Smckusick nfsm_reply(NFSX_FATTR); 9338884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 9439753Smckusick nfsm_srvfillattr; 9538418Smckusick nfsm_srvdone; 9638418Smckusick } 9738418Smckusick 9838418Smckusick /* 9938418Smckusick * nfs setattr service 10038418Smckusick */ 10152196Smckusick nfsrv_setattr(nfsd, mrep, md, dpos, cred, nam, mrq) 10252196Smckusick struct nfsd *nfsd; 10338418Smckusick struct mbuf *mrep, *md; 10438418Smckusick caddr_t dpos; 10538418Smckusick struct ucred *cred; 10652196Smckusick struct mbuf *nam, **mrq; 10738418Smckusick { 10838418Smckusick struct vattr va; 10938418Smckusick register struct vattr *vap = &va; 11038884Smacklem register struct nfsv2_sattr *sp; 11138884Smacklem register struct nfsv2_fattr *fp; 11238418Smckusick struct vnode *vp; 11338418Smckusick nfsv2fh_t nfh; 11438418Smckusick fhandle_t *fhp; 11548050Smckusick register u_long *tl; 11639494Smckusick register long t1; 11739494Smckusick caddr_t bpos; 11852196Smckusick int error = 0, rdonly, cache, duration2, cache2; 11939494Smckusick char *cp2; 12039753Smckusick struct mbuf *mb, *mb2, *mreq; 12152196Smckusick u_quad_t frev, frev2; 12238418Smckusick 12338418Smckusick fhp = &nfh.fh_generic; 12438418Smckusick nfsm_srvmtofh(fhp); 12552196Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR); 12652196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 12738418Smckusick nfsm_reply(0); 12852196Smckusick nqsrv_getl(vp, NQL_WRITE); 12952196Smckusick if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) 13038418Smckusick goto out; 13141361Smckusick VATTR_NULL(vap); 13238418Smckusick /* 13338418Smckusick * Nah nah nah nah na nah 13438418Smckusick * There is a bug in the Sun client that puts 0xffff in the mode 13538418Smckusick * field of sattr when it should put in 0xffffffff. The u_short 13638418Smckusick * doesn't sign extend. 13738418Smckusick * --> check the low order 2 bytes for 0xffff 13838418Smckusick */ 13938884Smacklem if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff) 14038884Smacklem vap->va_mode = nfstov_mode(sp->sa_mode); 14138884Smacklem if (sp->sa_uid != nfs_xdrneg1) 14238884Smacklem vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid); 14338884Smacklem if (sp->sa_gid != nfs_xdrneg1) 14438884Smacklem vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid); 14539753Smckusick if (sp->sa_size != nfs_xdrneg1) 14638884Smacklem vap->va_size = fxdr_unsigned(u_long, sp->sa_size); 14739753Smckusick /* 14839753Smckusick * The usec field of sa_atime is overloaded with the va_flags field 14939753Smckusick * for 4.4BSD clients. Hopefully other clients always set both the 15039753Smckusick * sec and usec fields to -1 when not setting the atime. 15139753Smckusick */ 15239753Smckusick if (sp->sa_atime.tv_sec != nfs_xdrneg1) { 15339753Smckusick vap->va_atime.tv_sec = fxdr_unsigned(long, sp->sa_atime.tv_sec); 15439753Smckusick vap->va_atime.tv_usec = 0; 15538425Smckusick } 15639753Smckusick if (sp->sa_atime.tv_usec != nfs_xdrneg1) 15739753Smckusick vap->va_flags = fxdr_unsigned(u_long, sp->sa_atime.tv_usec); 15838884Smacklem if (sp->sa_mtime.tv_sec != nfs_xdrneg1) 15938884Smacklem fxdr_time(&sp->sa_mtime, &vap->va_mtime); 16052196Smckusick if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) { 16138418Smckusick vput(vp); 16238418Smckusick nfsm_reply(0); 16338418Smckusick } 16452196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 16538418Smckusick out: 16638418Smckusick vput(vp); 16752196Smckusick nfsm_reply(NFSX_FATTR + 2*NFSX_UNSIGNED); 16838884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 16939753Smckusick nfsm_srvfillattr; 17052196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 17152196Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 17252196Smckusick txdr_hyper(&frev2, tl); 17352196Smckusick } 17438418Smckusick nfsm_srvdone; 17538418Smckusick } 17638418Smckusick 17738418Smckusick /* 17838418Smckusick * nfs lookup rpc 17938418Smckusick */ 18052196Smckusick nfsrv_lookup(nfsd, mrep, md, dpos, cred, nam, mrq) 18152196Smckusick struct nfsd *nfsd; 18238418Smckusick struct mbuf *mrep, *md; 18338418Smckusick caddr_t dpos; 18438418Smckusick struct ucred *cred; 18552196Smckusick struct mbuf *nam, **mrq; 18638418Smckusick { 18738884Smacklem register struct nfsv2_fattr *fp; 18849742Smckusick struct nameidata nd; 18938418Smckusick struct vnode *vp; 19038418Smckusick nfsv2fh_t nfh; 19138418Smckusick fhandle_t *fhp; 19239494Smckusick register caddr_t cp; 19348050Smckusick register u_long *tl; 19439494Smckusick register long t1; 19539494Smckusick caddr_t bpos; 19652196Smckusick int error = 0, lflag = 0, rdonly, cache, duration2, cache2, len; 19739494Smckusick char *cp2; 19839753Smckusick struct mbuf *mb, *mb2, *mreq; 19938418Smckusick struct vattr va, *vap = &va; 20052196Smckusick u_quad_t frev, frev2; 20138418Smckusick 20238418Smckusick fhp = &nfh.fh_generic; 20352196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 20452196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 20552196Smckusick if (*tl) { 20652196Smckusick lflag = fxdr_unsigned(int, *tl); 20752196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 20852196Smckusick duration2 = fxdr_unsigned(int, *tl); 20952196Smckusick } 21052196Smckusick } 21138418Smckusick nfsm_srvmtofh(fhp); 21238418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 21352316Sheideman nd.ni_cnd.cn_cred = cred; 21452316Sheideman nd.ni_cnd.cn_nameiop = LOOKUP; 21552316Sheideman nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART; 21652196Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp)) 21738418Smckusick nfsm_reply(0); 21852196Smckusick nqsrv_getl(nd.ni_startdir, NQL_READ); 21952196Smckusick vrele(nd.ni_startdir); 22049742Smckusick vp = nd.ni_vp; 22138418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 22241398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 22338418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 22438418Smckusick vput(vp); 22538418Smckusick nfsm_reply(0); 22638418Smckusick } 22752196Smckusick if (lflag) 22852196Smckusick (void) nqsrv_getlease(vp, &duration2, lflag, nfsd, 22952196Smckusick nam, &cache2, &frev2, cred); 23052196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 23138418Smckusick vput(vp); 23252196Smckusick nfsm_reply(NFSX_FH + NFSX_FATTR + 5*NFSX_UNSIGNED); 23352196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 23452196Smckusick if (lflag) { 23552196Smckusick nfsm_build(tl, u_long *, 5*NFSX_UNSIGNED); 23652196Smckusick *tl++ = txdr_unsigned(lflag); 23752196Smckusick *tl++ = txdr_unsigned(cache2); 23852196Smckusick *tl++ = txdr_unsigned(duration2); 23952196Smckusick txdr_hyper(&frev2, tl); 24052196Smckusick } else { 24152196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 24252196Smckusick *tl = 0; 24352196Smckusick } 24452196Smckusick } 24538418Smckusick nfsm_srvfhtom(fhp); 24638884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 24739753Smckusick nfsm_srvfillattr; 24838418Smckusick nfsm_srvdone; 24938418Smckusick } 25038418Smckusick 25138418Smckusick /* 25238418Smckusick * nfs readlink service 25338418Smckusick */ 25452196Smckusick nfsrv_readlink(nfsd, mrep, md, dpos, cred, nam, mrq) 25552196Smckusick struct nfsd *nfsd; 25638418Smckusick struct mbuf *mrep, *md; 25738418Smckusick caddr_t dpos; 25838418Smckusick struct ucred *cred; 25952196Smckusick struct mbuf *nam, **mrq; 26038418Smckusick { 26141899Smckusick struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN]; 26238418Smckusick register struct iovec *ivp = iv; 26338418Smckusick register struct mbuf *mp; 26448050Smckusick register u_long *tl; 26539494Smckusick register long t1; 26639494Smckusick caddr_t bpos; 26752196Smckusick int error = 0, rdonly, cache, i, tlen, len; 26839494Smckusick char *cp2; 26939753Smckusick struct mbuf *mb, *mb2, *mp2, *mp3, *mreq; 27038418Smckusick struct vnode *vp; 27138418Smckusick nfsv2fh_t nfh; 27238418Smckusick fhandle_t *fhp; 27338418Smckusick struct uio io, *uiop = &io; 27452196Smckusick u_quad_t frev; 27538418Smckusick 27638418Smckusick fhp = &nfh.fh_generic; 27738418Smckusick nfsm_srvmtofh(fhp); 27838418Smckusick len = 0; 27938418Smckusick i = 0; 28038418Smckusick while (len < NFS_MAXPATHLEN) { 28138418Smckusick MGET(mp, M_WAIT, MT_DATA); 28241899Smckusick MCLGET(mp, M_WAIT); 28338418Smckusick mp->m_len = NFSMSIZ(mp); 28438418Smckusick if (len == 0) 28538418Smckusick mp3 = mp2 = mp; 28641899Smckusick else { 28738418Smckusick mp2->m_next = mp; 28841899Smckusick mp2 = mp; 28941899Smckusick } 29038418Smckusick if ((len+mp->m_len) > NFS_MAXPATHLEN) { 29138418Smckusick mp->m_len = NFS_MAXPATHLEN-len; 29238418Smckusick len = NFS_MAXPATHLEN; 29338418Smckusick } else 29438418Smckusick len += mp->m_len; 29538418Smckusick ivp->iov_base = mtod(mp, caddr_t); 29638418Smckusick ivp->iov_len = mp->m_len; 29738418Smckusick i++; 29838418Smckusick ivp++; 29938418Smckusick } 30038418Smckusick uiop->uio_iov = iv; 30138418Smckusick uiop->uio_iovcnt = i; 30238418Smckusick uiop->uio_offset = 0; 30338418Smckusick uiop->uio_resid = len; 30438418Smckusick uiop->uio_rw = UIO_READ; 30538418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 30648050Smckusick uiop->uio_procp = (struct proc *)0; 30752196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) { 30838418Smckusick m_freem(mp3); 30938418Smckusick nfsm_reply(0); 31038418Smckusick } 31138418Smckusick if (vp->v_type != VLNK) { 31238418Smckusick error = EINVAL; 31338418Smckusick goto out; 31438418Smckusick } 31552196Smckusick nqsrv_getl(vp, NQL_READ); 31638418Smckusick error = VOP_READLINK(vp, uiop, cred); 31738418Smckusick out: 31838418Smckusick vput(vp); 31938418Smckusick if (error) 32038418Smckusick m_freem(mp3); 32138418Smckusick nfsm_reply(NFSX_UNSIGNED); 32238418Smckusick if (uiop->uio_resid > 0) { 32338418Smckusick len -= uiop->uio_resid; 32438418Smckusick tlen = nfsm_rndup(len); 32538418Smckusick nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len); 32638418Smckusick } 32748050Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 32848050Smckusick *tl = txdr_unsigned(len); 32938418Smckusick mb->m_next = mp3; 33038418Smckusick nfsm_srvdone; 33138418Smckusick } 33238418Smckusick 33338418Smckusick /* 33438418Smckusick * nfs read service 33538418Smckusick */ 33652196Smckusick nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq) 33752196Smckusick struct nfsd *nfsd; 33838418Smckusick struct mbuf *mrep, *md; 33938418Smckusick caddr_t dpos; 34038418Smckusick struct ucred *cred; 34152196Smckusick struct mbuf *nam, **mrq; 34238418Smckusick { 34343350Smckusick register struct iovec *iv; 34443350Smckusick struct iovec *iv2; 34541899Smckusick register struct mbuf *m; 34638884Smacklem register struct nfsv2_fattr *fp; 34748050Smckusick register u_long *tl; 34839494Smckusick register long t1; 34939494Smckusick caddr_t bpos; 35052196Smckusick int error = 0, rdonly, cache, i, cnt, len, left, siz, tlen; 35139494Smckusick char *cp2; 35239753Smckusick struct mbuf *mb, *mb2, *mreq; 35352196Smckusick struct mbuf *m2; 35438418Smckusick struct vnode *vp; 35538418Smckusick nfsv2fh_t nfh; 35638418Smckusick fhandle_t *fhp; 35738418Smckusick struct uio io, *uiop = &io; 35838418Smckusick struct vattr va, *vap = &va; 35938418Smckusick off_t off; 36052196Smckusick u_quad_t frev; 36138418Smckusick 36238418Smckusick fhp = &nfh.fh_generic; 36338418Smckusick nfsm_srvmtofh(fhp); 36452196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 36548050Smckusick off = fxdr_unsigned(off_t, *tl); 36638418Smckusick nfsm_srvstrsiz(cnt, NFS_MAXDATA); 36752196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 36838418Smckusick nfsm_reply(0); 36952196Smckusick nqsrv_getl(vp, NQL_READ); 37052196Smckusick if (error = nfsrv_access(vp, VREAD | VEXEC, cred, rdonly, nfsd->nd_procp)) { 37138418Smckusick vput(vp); 37238418Smckusick nfsm_reply(0); 37338418Smckusick } 37452196Smckusick if (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp)) { 37538418Smckusick vput(vp); 37638418Smckusick nfsm_reply(0); 37738418Smckusick } 37852196Smckusick if (off >= vap->va_size) 37952196Smckusick cnt = 0; 38052196Smckusick else if ((off + cnt) > vap->va_size) 38152196Smckusick cnt = nfsm_rndup(vap->va_size - off); 38252196Smckusick nfsm_reply(NFSX_FATTR+NFSX_UNSIGNED+nfsm_rndup(cnt)); 38352196Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 38452196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 38552196Smckusick len = left = cnt; 38652196Smckusick if (cnt > 0) { 38752196Smckusick /* 38852196Smckusick * Generate the mbuf list with the uio_iov ref. to it. 38952196Smckusick */ 39052196Smckusick i = 0; 39152196Smckusick m = m2 = mb; 39252196Smckusick MALLOC(iv, struct iovec *, 39352196Smckusick ((NFS_MAXDATA+MLEN-1)/MLEN) * sizeof (struct iovec), 39452196Smckusick M_TEMP, M_WAITOK); 39552196Smckusick iv2 = iv; 39652196Smckusick while (left > 0) { 39752196Smckusick siz = MIN(M_TRAILINGSPACE(m), left); 39852196Smckusick if (siz > 0) { 39952196Smckusick m->m_len += siz; 40052196Smckusick iv->iov_base = bpos; 40152196Smckusick iv->iov_len = siz; 40252196Smckusick iv++; 40352196Smckusick i++; 40452196Smckusick left -= siz; 40552196Smckusick } 40652196Smckusick if (left > 0) { 40752196Smckusick MGET(m, M_WAIT, MT_DATA); 40852196Smckusick MCLGET(m, M_WAIT); 40952196Smckusick m->m_len = 0; 41052196Smckusick m2->m_next = m; 41152196Smckusick m2 = m; 41252196Smckusick bpos = mtod(m, caddr_t); 41352196Smckusick } 41452196Smckusick } 41552196Smckusick uiop->uio_iov = iv2; 41652196Smckusick uiop->uio_iovcnt = i; 41752196Smckusick uiop->uio_offset = off; 41852196Smckusick uiop->uio_resid = cnt; 41952196Smckusick uiop->uio_rw = UIO_READ; 42052196Smckusick uiop->uio_segflg = UIO_SYSSPACE; 42152196Smckusick error = VOP_READ(vp, uiop, IO_NODELOCKED, cred); 42252196Smckusick off = uiop->uio_offset; 42352196Smckusick FREE((caddr_t)iv2, M_TEMP); 42452196Smckusick if (error || (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp))) { 42552196Smckusick m_freem(mreq); 42652196Smckusick vput(vp); 42752196Smckusick nfsm_reply(0); 42852196Smckusick } 42952196Smckusick } else 43052196Smckusick uiop->uio_resid = 0; 43138418Smckusick vput(vp); 43239753Smckusick nfsm_srvfillattr; 43345877Smckusick len -= uiop->uio_resid; 43452196Smckusick tlen = nfsm_rndup(len); 43552196Smckusick if (cnt != tlen || tlen != len) 43652196Smckusick nfsm_adj(mb, cnt-tlen, tlen-len); 43748050Smckusick *tl = txdr_unsigned(len); 43838418Smckusick nfsm_srvdone; 43938418Smckusick } 44038418Smckusick 44138418Smckusick /* 44238418Smckusick * nfs write service 44338418Smckusick */ 44452196Smckusick nfsrv_write(nfsd, mrep, md, dpos, cred, nam, mrq) 44552196Smckusick struct nfsd *nfsd; 44652196Smckusick struct mbuf *mrep, *md; 44738418Smckusick caddr_t dpos; 44838418Smckusick struct ucred *cred; 44952196Smckusick struct mbuf *nam, **mrq; 45038418Smckusick { 45138418Smckusick register struct iovec *ivp; 45238418Smckusick register struct mbuf *mp; 45338884Smacklem register struct nfsv2_fattr *fp; 45441899Smckusick struct iovec iv[NFS_MAXIOVEC]; 45538418Smckusick struct vattr va; 45638418Smckusick register struct vattr *vap = &va; 45748050Smckusick register u_long *tl; 45839494Smckusick register long t1; 45939494Smckusick caddr_t bpos; 46052196Smckusick int error = 0, rdonly, cache, siz, len, xfer; 46139494Smckusick char *cp2; 46239753Smckusick struct mbuf *mb, *mb2, *mreq; 46338418Smckusick struct vnode *vp; 46438418Smckusick nfsv2fh_t nfh; 46538418Smckusick fhandle_t *fhp; 46638418Smckusick struct uio io, *uiop = &io; 46738418Smckusick off_t off; 46852196Smckusick u_quad_t frev; 46938418Smckusick 47038418Smckusick fhp = &nfh.fh_generic; 47138418Smckusick nfsm_srvmtofh(fhp); 47252196Smckusick nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); 47348050Smckusick off = fxdr_unsigned(off_t, *++tl); 47448050Smckusick tl += 2; 47548050Smckusick len = fxdr_unsigned(long, *tl); 47638418Smckusick if (len > NFS_MAXDATA || len <= 0) { 47738418Smckusick error = EBADRPC; 47838418Smckusick nfsm_reply(0); 47938418Smckusick } 48038418Smckusick if (dpos == (mtod(md, caddr_t)+md->m_len)) { 48138418Smckusick mp = md->m_next; 48238418Smckusick if (mp == NULL) { 48338418Smckusick error = EBADRPC; 48438418Smckusick nfsm_reply(0); 48538418Smckusick } 48638418Smckusick } else { 48738418Smckusick mp = md; 48838418Smckusick siz = dpos-mtod(mp, caddr_t); 48938418Smckusick mp->m_len -= siz; 49038418Smckusick NFSMADV(mp, siz); 49138418Smckusick } 49252196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 49338418Smckusick nfsm_reply(0); 49452196Smckusick nqsrv_getl(vp, NQL_WRITE); 49552196Smckusick if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) { 49638418Smckusick vput(vp); 49738418Smckusick nfsm_reply(0); 49838418Smckusick } 49938418Smckusick uiop->uio_resid = 0; 50038418Smckusick uiop->uio_rw = UIO_WRITE; 50138418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 50248050Smckusick uiop->uio_procp = (struct proc *)0; 50338418Smckusick /* 50441899Smckusick * Do up to NFS_MAXIOVEC mbufs of write each iteration of the 50538418Smckusick * loop until done. 50638418Smckusick */ 50738418Smckusick while (len > 0 && uiop->uio_resid == 0) { 50838418Smckusick ivp = iv; 50938418Smckusick siz = 0; 51038418Smckusick uiop->uio_iov = ivp; 51138418Smckusick uiop->uio_iovcnt = 0; 51238418Smckusick uiop->uio_offset = off; 51341899Smckusick while (len > 0 && uiop->uio_iovcnt < NFS_MAXIOVEC && mp != NULL) { 51438418Smckusick ivp->iov_base = mtod(mp, caddr_t); 51538418Smckusick if (len < mp->m_len) 51638418Smckusick ivp->iov_len = xfer = len; 51738418Smckusick else 51838418Smckusick ivp->iov_len = xfer = mp->m_len; 51938418Smckusick #ifdef notdef 52038418Smckusick /* Not Yet .. */ 52138418Smckusick if (M_HASCL(mp) && (((u_long)ivp->iov_base) & CLOFSET) == 0) 52238418Smckusick ivp->iov_op = NULL; /* what should it be ?? */ 52338418Smckusick else 52438418Smckusick ivp->iov_op = NULL; 52538418Smckusick #endif 52638418Smckusick uiop->uio_iovcnt++; 52738418Smckusick ivp++; 52838418Smckusick len -= xfer; 52938418Smckusick siz += xfer; 53038418Smckusick mp = mp->m_next; 53138418Smckusick } 53238418Smckusick if (len > 0 && mp == NULL) { 53338418Smckusick error = EBADRPC; 53438418Smckusick vput(vp); 53538418Smckusick nfsm_reply(0); 53638418Smckusick } 53738418Smckusick uiop->uio_resid = siz; 53839586Smckusick if (error = VOP_WRITE(vp, uiop, IO_SYNC | IO_NODELOCKED, 53938418Smckusick cred)) { 54038418Smckusick vput(vp); 54138418Smckusick nfsm_reply(0); 54238418Smckusick } 54339586Smckusick off = uiop->uio_offset; 54438418Smckusick } 54552196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 54638418Smckusick vput(vp); 54738418Smckusick nfsm_reply(NFSX_FATTR); 54838884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 54939753Smckusick nfsm_srvfillattr; 550*52442Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 551*52442Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 552*52442Smckusick txdr_hyper(&vap->va_filerev, tl); 553*52442Smckusick } 55438418Smckusick nfsm_srvdone; 55538418Smckusick } 55638418Smckusick 55738418Smckusick /* 55838418Smckusick * nfs create service 55938418Smckusick * now does a truncate to 0 length via. setattr if it already exists 56038418Smckusick */ 56152196Smckusick nfsrv_create(nfsd, mrep, md, dpos, cred, nam, mrq) 56252196Smckusick struct nfsd *nfsd; 56352196Smckusick struct mbuf *mrep, *md; 56438418Smckusick caddr_t dpos; 56538418Smckusick struct ucred *cred; 56652196Smckusick struct mbuf *nam, **mrq; 56738418Smckusick { 56838884Smacklem register struct nfsv2_fattr *fp; 56938418Smckusick struct vattr va; 57038418Smckusick register struct vattr *vap = &va; 57149742Smckusick struct nameidata nd; 57239494Smckusick register caddr_t cp; 57348050Smckusick register u_long *tl; 57439494Smckusick register long t1; 57539494Smckusick caddr_t bpos; 57652196Smckusick int error = 0, rdev, cache, len; 57739494Smckusick char *cp2; 57839753Smckusick struct mbuf *mb, *mb2, *mreq; 57938418Smckusick struct vnode *vp; 58038418Smckusick nfsv2fh_t nfh; 58138418Smckusick fhandle_t *fhp; 58252196Smckusick u_quad_t frev; 58338418Smckusick 58452316Sheideman nd.ni_cnd.cn_nameiop = 0; 58538418Smckusick fhp = &nfh.fh_generic; 58638418Smckusick nfsm_srvmtofh(fhp); 58738418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 58852316Sheideman nd.ni_cnd.cn_cred = cred; 58952316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 59052316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART; 59152196Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp)) 59238418Smckusick nfsm_reply(0); 59341361Smckusick VATTR_NULL(vap); 59452196Smckusick nfsm_dissect(tl, u_long *, NFSX_SATTR); 59538418Smckusick /* 59638418Smckusick * Iff doesn't exist, create it 59738418Smckusick * otherwise just truncate to 0 length 59838418Smckusick * should I set the mode too ?? 59938418Smckusick */ 60049742Smckusick if (nd.ni_vp == NULL) { 60148050Smckusick vap->va_type = IFTOVT(fxdr_unsigned(u_long, *tl)); 60242867Smckusick if (vap->va_type == VNON) 60342867Smckusick vap->va_type = VREG; 60448050Smckusick vap->va_mode = nfstov_mode(*tl); 60548050Smckusick rdev = fxdr_unsigned(long, *(tl+3)); 60646988Smckusick if (vap->va_type == VREG || vap->va_type == VSOCK) { 60749742Smckusick vrele(nd.ni_startdir); 60852196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 60952234Sheideman if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) 61042242Smckusick nfsm_reply(0); 61152316Sheideman FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 61242242Smckusick } else if (vap->va_type == VCHR || vap->va_type == VBLK || 61342242Smckusick vap->va_type == VFIFO) { 61442242Smckusick if (vap->va_type == VCHR && rdev == 0xffffffff) 61542242Smckusick vap->va_type = VFIFO; 61642242Smckusick if (vap->va_type == VFIFO) { 61742242Smckusick #ifndef FIFO 61852234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 61949742Smckusick vput(nd.ni_dvp); 62042242Smckusick error = ENXIO; 62149742Smckusick goto out; 62242242Smckusick #endif /* FIFO */ 62352196Smckusick } else if (error = suser(cred, (u_short *)0)) { 62452234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 62549742Smckusick vput(nd.ni_dvp); 62649742Smckusick goto out; 62742242Smckusick } else 62842242Smckusick vap->va_rdev = (dev_t)rdev; 62952196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 63052234Sheideman if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) { 63149742Smckusick vrele(nd.ni_startdir); 63242242Smckusick nfsm_reply(0); 63349742Smckusick } 63452316Sheideman nd.ni_cnd.cn_nameiop = LOOKUP; 63552316Sheideman nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART); 63652316Sheideman nd.ni_cnd.cn_proc = nfsd->nd_procp; 63752316Sheideman nd.ni_cnd.cn_cred = nfsd->nd_procp->p_ucred; 63852316Sheideman if (error = lookup(&nd)) { 63952316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 64042242Smckusick nfsm_reply(0); 64149742Smckusick } 64252316Sheideman FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 64352316Sheideman if (nd.ni_cnd.cn_flags & ISSYMLINK) { 64449742Smckusick vrele(nd.ni_dvp); 64549742Smckusick vput(nd.ni_vp); 64652234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 64749742Smckusick error = EINVAL; 64849742Smckusick nfsm_reply(0); 64949742Smckusick } 65042242Smckusick } else { 65152234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 65249742Smckusick vput(nd.ni_dvp); 65342242Smckusick error = ENXIO; 65449742Smckusick goto out; 65542242Smckusick } 65649742Smckusick vp = nd.ni_vp; 65738418Smckusick } else { 65849742Smckusick vrele(nd.ni_startdir); 65952316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 66049742Smckusick vp = nd.ni_vp; 66149742Smckusick if (nd.ni_dvp == vp) 66249742Smckusick vrele(nd.ni_dvp); 66343359Smckusick else 66449742Smckusick vput(nd.ni_dvp); 66552234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 66638418Smckusick vap->va_size = 0; 66752196Smckusick nqsrv_getl(vp, NQL_WRITE); 66852196Smckusick if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) { 66942506Smckusick vput(vp); 67038418Smckusick nfsm_reply(0); 67142506Smckusick } 67238418Smckusick } 67338418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 67441398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 67538418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 67638418Smckusick vput(vp); 67738418Smckusick nfsm_reply(0); 67838418Smckusick } 67952196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 68038418Smckusick vput(vp); 68138418Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR); 68238418Smckusick nfsm_srvfhtom(fhp); 68338884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 68439753Smckusick nfsm_srvfillattr; 68538418Smckusick return (error); 68638418Smckusick nfsmout: 68752316Sheideman if (nd.ni_cnd.cn_nameiop || nd.ni_cnd.cn_flags) 68851464Sbostic vrele(nd.ni_startdir); 68952234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 69049742Smckusick if (nd.ni_dvp == nd.ni_vp) 69149742Smckusick vrele(nd.ni_dvp); 69243359Smckusick else 69349742Smckusick vput(nd.ni_dvp); 69449742Smckusick if (nd.ni_vp) 69549742Smckusick vput(nd.ni_vp); 69638418Smckusick return (error); 69749742Smckusick 69849742Smckusick out: 69949742Smckusick vrele(nd.ni_startdir); 70052316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 70149742Smckusick nfsm_reply(0); 70238418Smckusick } 70338418Smckusick 70438418Smckusick /* 70538418Smckusick * nfs remove service 70638418Smckusick */ 70752196Smckusick nfsrv_remove(nfsd, mrep, md, dpos, cred, nam, mrq) 70852196Smckusick struct nfsd *nfsd; 70952196Smckusick struct mbuf *mrep, *md; 71038418Smckusick caddr_t dpos; 71138418Smckusick struct ucred *cred; 71252196Smckusick struct mbuf *nam, **mrq; 71338418Smckusick { 71449742Smckusick struct nameidata nd; 71548050Smckusick register u_long *tl; 71639494Smckusick register long t1; 71739494Smckusick caddr_t bpos; 71852196Smckusick int error = 0, cache, len; 71939494Smckusick char *cp2; 72039753Smckusick struct mbuf *mb, *mreq; 72138418Smckusick struct vnode *vp; 72238418Smckusick nfsv2fh_t nfh; 72338418Smckusick fhandle_t *fhp; 72452196Smckusick u_quad_t frev; 72538418Smckusick 72638418Smckusick fhp = &nfh.fh_generic; 72738418Smckusick nfsm_srvmtofh(fhp); 72838418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 72952316Sheideman nd.ni_cnd.cn_cred = cred; 73052316Sheideman nd.ni_cnd.cn_nameiop = DELETE; 73152316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 73252196Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp)) 73338418Smckusick nfsm_reply(0); 73449742Smckusick vp = nd.ni_vp; 73538418Smckusick if (vp->v_type == VDIR && 73652196Smckusick (error = suser(cred, (u_short *)0))) 73738418Smckusick goto out; 73838418Smckusick /* 73949454Smckusick * The root of a mounted filesystem cannot be deleted. 74038418Smckusick */ 74138418Smckusick if (vp->v_flag & VROOT) { 74238418Smckusick error = EBUSY; 74338418Smckusick goto out; 74438418Smckusick } 74538418Smckusick if (vp->v_flag & VTEXT) 74645715Smckusick (void) vnode_pager_uncache(vp); 74738418Smckusick out: 74842467Smckusick if (!error) { 74952196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 75052196Smckusick nqsrv_getl(vp, NQL_WRITE); 75152234Sheideman error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 75242467Smckusick } else { 75352234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 75449742Smckusick if (nd.ni_dvp == vp) 75549742Smckusick vrele(nd.ni_dvp); 75643359Smckusick else 75749742Smckusick vput(nd.ni_dvp); 75842467Smckusick vput(vp); 75942467Smckusick } 76038418Smckusick nfsm_reply(0); 76138418Smckusick nfsm_srvdone; 76238418Smckusick } 76338418Smckusick 76438418Smckusick /* 76538418Smckusick * nfs rename service 76638418Smckusick */ 76752196Smckusick nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq) 76852196Smckusick struct nfsd *nfsd; 76952196Smckusick struct mbuf *mrep, *md; 77038418Smckusick caddr_t dpos; 77138418Smckusick struct ucred *cred; 77252196Smckusick struct mbuf *nam, **mrq; 77338418Smckusick { 77448050Smckusick register u_long *tl; 77539494Smckusick register long t1; 77639494Smckusick caddr_t bpos; 77752196Smckusick int error = 0, rdonly, cache, len, len2; 77839494Smckusick char *cp2; 77939753Smckusick struct mbuf *mb, *mreq; 78049742Smckusick struct nameidata fromnd, tond; 78138418Smckusick struct vnode *fvp, *tvp, *tdvp; 78238418Smckusick nfsv2fh_t fnfh, tnfh; 78338418Smckusick fhandle_t *ffhp, *tfhp; 78452196Smckusick u_quad_t frev; 78552196Smckusick uid_t saved_uid; 78638418Smckusick 78738418Smckusick ffhp = &fnfh.fh_generic; 78838418Smckusick tfhp = &tnfh.fh_generic; 78952316Sheideman fromnd.ni_cnd.cn_nameiop = 0; 79052316Sheideman tond.ni_cnd.cn_nameiop = 0; 79138418Smckusick nfsm_srvmtofh(ffhp); 79238418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 79338418Smckusick /* 79452196Smckusick * Remember our original uid so that we can reset cr_uid before 79552196Smckusick * the second nfs_namei() call, in case it is remapped. 79638418Smckusick */ 79752196Smckusick saved_uid = cred->cr_uid; 79852316Sheideman fromnd.ni_cnd.cn_cred = cred; 79952316Sheideman fromnd.ni_cnd.cn_nameiop = DELETE; 80052316Sheideman fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART; 80152196Smckusick if (error = nfs_namei(&fromnd, ffhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp)) 80238418Smckusick nfsm_reply(0); 80349742Smckusick fvp = fromnd.ni_vp; 80438418Smckusick nfsm_srvmtofh(tfhp); 80541899Smckusick nfsm_strsiz(len2, NFS_MAXNAMLEN); 80652196Smckusick cred->cr_uid = saved_uid; 80752316Sheideman tond.ni_cnd.cn_cred = cred; 80852316Sheideman tond.ni_cnd.cn_nameiop = RENAME; 80952316Sheideman tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; 81052196Smckusick if (error = nfs_namei(&tond, tfhp, len2, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp)) { 81152234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 81249742Smckusick vrele(fromnd.ni_dvp); 81342467Smckusick vrele(fvp); 81442467Smckusick goto out1; 81542467Smckusick } 81638425Smckusick tdvp = tond.ni_dvp; 81738425Smckusick tvp = tond.ni_vp; 81838418Smckusick if (tvp != NULL) { 81938418Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 82038418Smckusick error = EISDIR; 82138418Smckusick goto out; 82238418Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 82338418Smckusick error = ENOTDIR; 82438418Smckusick goto out; 82538418Smckusick } 82652196Smckusick if (tvp->v_type == VDIR && tvp->v_mountedhere) { 82752196Smckusick error = EXDEV; 82852196Smckusick goto out; 82952196Smckusick } 83038418Smckusick } 83152196Smckusick if (fvp->v_type == VDIR && fvp->v_mountedhere) { 83252196Smckusick error = EBUSY; 83352196Smckusick goto out; 83452196Smckusick } 83538418Smckusick if (fvp->v_mount != tdvp->v_mount) { 83638418Smckusick error = EXDEV; 83738418Smckusick goto out; 83838418Smckusick } 83949742Smckusick if (fvp == tdvp) 84038418Smckusick error = EINVAL; 84149742Smckusick /* 84249742Smckusick * If source is the same as the destination (that is the 84349742Smckusick * same vnode with the same name in the same directory), 84449742Smckusick * then there is nothing to do. 84549742Smckusick */ 84649742Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 84752316Sheideman fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 84852316Sheideman !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 84952316Sheideman fromnd.ni_cnd.cn_namelen)) 85049742Smckusick error = -1; 85138418Smckusick out: 85242467Smckusick if (!error) { 85352196Smckusick nqsrv_getl(fromnd.ni_dvp, NQL_WRITE); 85452196Smckusick nqsrv_getl(tdvp, NQL_WRITE); 85552196Smckusick if (tvp) 85652196Smckusick nqsrv_getl(tvp, NQL_WRITE); 85752234Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 85852234Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 85942467Smckusick } else { 86052234Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 86143359Smckusick if (tdvp == tvp) 86243359Smckusick vrele(tdvp); 86343359Smckusick else 86443359Smckusick vput(tdvp); 86542467Smckusick if (tvp) 86642467Smckusick vput(tvp); 86752234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 86849742Smckusick vrele(fromnd.ni_dvp); 86942467Smckusick vrele(fvp); 87038418Smckusick } 87146513Smckusick vrele(tond.ni_startdir); 87252316Sheideman FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 87338418Smckusick out1: 87449742Smckusick vrele(fromnd.ni_startdir); 87552316Sheideman FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 87638418Smckusick nfsm_reply(0); 87738418Smckusick return (error); 87849742Smckusick 87938418Smckusick nfsmout: 88052316Sheideman if (tond.ni_cnd.cn_nameiop || tond.ni_cnd.cn_flags) { 88149742Smckusick vrele(tond.ni_startdir); 88252316Sheideman FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 88349742Smckusick } 88452316Sheideman if (fromnd.ni_cnd.cn_nameiop || fromnd.ni_cnd.cn_flags) { 88549742Smckusick vrele(fromnd.ni_startdir); 88652316Sheideman FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 88752234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 88849742Smckusick vrele(fromnd.ni_dvp); 88949742Smckusick vrele(fvp); 89049742Smckusick } 89138418Smckusick return (error); 89238418Smckusick } 89338418Smckusick 89438418Smckusick /* 89538418Smckusick * nfs link service 89638418Smckusick */ 89752196Smckusick nfsrv_link(nfsd, mrep, md, dpos, cred, nam, mrq) 89852196Smckusick struct nfsd *nfsd; 89952196Smckusick struct mbuf *mrep, *md; 90038418Smckusick caddr_t dpos; 90138418Smckusick struct ucred *cred; 90252196Smckusick struct mbuf *nam, **mrq; 90338418Smckusick { 90449742Smckusick struct nameidata nd; 90548050Smckusick register u_long *tl; 90639494Smckusick register long t1; 90739494Smckusick caddr_t bpos; 90852196Smckusick int error = 0, rdonly, cache, len; 90939494Smckusick char *cp2; 91039753Smckusick struct mbuf *mb, *mreq; 91138418Smckusick struct vnode *vp, *xp; 91238418Smckusick nfsv2fh_t nfh, dnfh; 91338418Smckusick fhandle_t *fhp, *dfhp; 91452196Smckusick u_quad_t frev; 91538418Smckusick 91638418Smckusick fhp = &nfh.fh_generic; 91738418Smckusick dfhp = &dnfh.fh_generic; 91838418Smckusick nfsm_srvmtofh(fhp); 91938418Smckusick nfsm_srvmtofh(dfhp); 92038418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 92152196Smckusick if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 92238418Smckusick nfsm_reply(0); 92352196Smckusick if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0))) 92438418Smckusick goto out1; 92552316Sheideman nd.ni_cnd.cn_cred = cred; 92652316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 92752316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 92852196Smckusick if (error = nfs_namei(&nd, dfhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp)) 92938418Smckusick goto out1; 93049742Smckusick xp = nd.ni_vp; 93138418Smckusick if (xp != NULL) { 93238418Smckusick error = EEXIST; 93338418Smckusick goto out; 93438418Smckusick } 93549742Smckusick xp = nd.ni_dvp; 93638418Smckusick if (vp->v_mount != xp->v_mount) 93738418Smckusick error = EXDEV; 93838418Smckusick out: 93942467Smckusick if (!error) { 94052196Smckusick nqsrv_getl(vp, NQL_WRITE); 94152196Smckusick nqsrv_getl(xp, NQL_WRITE); 94252234Sheideman error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd); 94342467Smckusick } else { 94452234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 94549742Smckusick if (nd.ni_dvp == nd.ni_vp) 94649742Smckusick vrele(nd.ni_dvp); 94743359Smckusick else 94849742Smckusick vput(nd.ni_dvp); 94949742Smckusick if (nd.ni_vp) 95049742Smckusick vrele(nd.ni_vp); 95142467Smckusick } 95238418Smckusick out1: 95338418Smckusick vrele(vp); 95438418Smckusick nfsm_reply(0); 95538418Smckusick nfsm_srvdone; 95638418Smckusick } 95738418Smckusick 95838418Smckusick /* 95938418Smckusick * nfs symbolic link service 96038418Smckusick */ 96152196Smckusick nfsrv_symlink(nfsd, mrep, md, dpos, cred, nam, mrq) 96252196Smckusick struct nfsd *nfsd; 96352196Smckusick struct mbuf *mrep, *md; 96438418Smckusick caddr_t dpos; 96538418Smckusick struct ucred *cred; 96652196Smckusick struct mbuf *nam, **mrq; 96738418Smckusick { 96838418Smckusick struct vattr va; 96949742Smckusick struct nameidata nd; 97038418Smckusick register struct vattr *vap = &va; 97148050Smckusick register u_long *tl; 97239494Smckusick register long t1; 97345285Smckusick struct nfsv2_sattr *sp; 97439494Smckusick caddr_t bpos; 97541899Smckusick struct uio io; 97641899Smckusick struct iovec iv; 97752196Smckusick int error = 0, rdonly, cache, len, len2; 97841899Smckusick char *pathcp, *cp2; 97939753Smckusick struct mbuf *mb, *mreq; 98038418Smckusick nfsv2fh_t nfh; 98138418Smckusick fhandle_t *fhp; 98252196Smckusick u_quad_t frev; 98338418Smckusick 98441899Smckusick pathcp = (char *)0; 98538418Smckusick fhp = &nfh.fh_generic; 98638418Smckusick nfsm_srvmtofh(fhp); 98738418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 98852316Sheideman nd.ni_cnd.cn_cred = cred; 98952316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 99052316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 99152196Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp)) 99242467Smckusick goto out; 99341899Smckusick nfsm_strsiz(len2, NFS_MAXPATHLEN); 99441899Smckusick MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK); 99541899Smckusick iv.iov_base = pathcp; 99641899Smckusick iv.iov_len = len2; 99741899Smckusick io.uio_resid = len2; 99841899Smckusick io.uio_offset = 0; 99941899Smckusick io.uio_iov = &iv; 100041899Smckusick io.uio_iovcnt = 1; 100141899Smckusick io.uio_segflg = UIO_SYSSPACE; 100241899Smckusick io.uio_rw = UIO_READ; 100348050Smckusick io.uio_procp = (struct proc *)0; 100441899Smckusick nfsm_mtouio(&io, len2); 100552196Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR); 100641899Smckusick *(pathcp + len2) = '\0'; 100749742Smckusick if (nd.ni_vp) { 100852234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 100949742Smckusick if (nd.ni_dvp == nd.ni_vp) 101049742Smckusick vrele(nd.ni_dvp); 101143359Smckusick else 101249742Smckusick vput(nd.ni_dvp); 101349742Smckusick vrele(nd.ni_vp); 101438418Smckusick error = EEXIST; 101538418Smckusick goto out; 101638418Smckusick } 101741361Smckusick VATTR_NULL(vap); 101845285Smckusick vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode); 101952196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 102052234Sheideman error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp); 102138418Smckusick out: 102241899Smckusick if (pathcp) 102341899Smckusick FREE(pathcp, M_TEMP); 102438418Smckusick nfsm_reply(0); 102538418Smckusick return (error); 102638418Smckusick nfsmout: 102752234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 102849742Smckusick if (nd.ni_dvp == nd.ni_vp) 102949742Smckusick vrele(nd.ni_dvp); 103043359Smckusick else 103149742Smckusick vput(nd.ni_dvp); 103249742Smckusick if (nd.ni_vp) 103349742Smckusick vrele(nd.ni_vp); 103441899Smckusick if (pathcp) 103541899Smckusick FREE(pathcp, M_TEMP); 103638418Smckusick return (error); 103738418Smckusick } 103838418Smckusick 103938418Smckusick /* 104038418Smckusick * nfs mkdir service 104138418Smckusick */ 104252196Smckusick nfsrv_mkdir(nfsd, mrep, md, dpos, cred, nam, mrq) 104352196Smckusick struct nfsd *nfsd; 104452196Smckusick struct mbuf *mrep, *md; 104538418Smckusick caddr_t dpos; 104638418Smckusick struct ucred *cred; 104752196Smckusick struct mbuf *nam, **mrq; 104838418Smckusick { 104938418Smckusick struct vattr va; 105038418Smckusick register struct vattr *vap = &va; 105138884Smacklem register struct nfsv2_fattr *fp; 105249742Smckusick struct nameidata nd; 105339494Smckusick register caddr_t cp; 105448050Smckusick register u_long *tl; 105539494Smckusick register long t1; 105639494Smckusick caddr_t bpos; 105752196Smckusick int error = 0, rdonly, cache, len; 105839494Smckusick char *cp2; 105939753Smckusick struct mbuf *mb, *mb2, *mreq; 106038418Smckusick struct vnode *vp; 106138418Smckusick nfsv2fh_t nfh; 106238418Smckusick fhandle_t *fhp; 106352196Smckusick u_quad_t frev; 106438418Smckusick 106538418Smckusick fhp = &nfh.fh_generic; 106638418Smckusick nfsm_srvmtofh(fhp); 106738418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 106852316Sheideman nd.ni_cnd.cn_cred = cred; 106952316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 107052316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 107152196Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp)) 107238418Smckusick nfsm_reply(0); 107352196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 107441361Smckusick VATTR_NULL(vap); 107538418Smckusick vap->va_type = VDIR; 107648050Smckusick vap->va_mode = nfstov_mode(*tl++); 107749742Smckusick vp = nd.ni_vp; 107838418Smckusick if (vp != NULL) { 107952234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 108049742Smckusick if (nd.ni_dvp == vp) 108149742Smckusick vrele(nd.ni_dvp); 108243359Smckusick else 108349742Smckusick vput(nd.ni_dvp); 108442467Smckusick vrele(vp); 108538418Smckusick error = EEXIST; 108638418Smckusick nfsm_reply(0); 108738418Smckusick } 108852196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 108952234Sheideman if (error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) 109038418Smckusick nfsm_reply(0); 109149742Smckusick vp = nd.ni_vp; 109238418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 109341398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 109438418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 109538418Smckusick vput(vp); 109638418Smckusick nfsm_reply(0); 109738418Smckusick } 109852196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 109938418Smckusick vput(vp); 110038418Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR); 110138418Smckusick nfsm_srvfhtom(fhp); 110238884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 110339753Smckusick nfsm_srvfillattr; 110438418Smckusick return (error); 110538418Smckusick nfsmout: 110652234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 110749742Smckusick if (nd.ni_dvp == nd.ni_vp) 110849742Smckusick vrele(nd.ni_dvp); 110943359Smckusick else 111049742Smckusick vput(nd.ni_dvp); 111149742Smckusick if (nd.ni_vp) 111249742Smckusick vrele(nd.ni_vp); 111338418Smckusick return (error); 111438418Smckusick } 111538418Smckusick 111638418Smckusick /* 111738418Smckusick * nfs rmdir service 111838418Smckusick */ 111952196Smckusick nfsrv_rmdir(nfsd, mrep, md, dpos, cred, nam, mrq) 112052196Smckusick struct nfsd *nfsd; 112152196Smckusick struct mbuf *mrep, *md; 112238418Smckusick caddr_t dpos; 112338418Smckusick struct ucred *cred; 112452196Smckusick struct mbuf *nam, **mrq; 112538418Smckusick { 112648050Smckusick register u_long *tl; 112739494Smckusick register long t1; 112839494Smckusick caddr_t bpos; 112952196Smckusick int error = 0, rdonly, cache, len; 113039494Smckusick char *cp2; 113139753Smckusick struct mbuf *mb, *mreq; 113238418Smckusick struct vnode *vp; 113338418Smckusick nfsv2fh_t nfh; 113438418Smckusick fhandle_t *fhp; 113549742Smckusick struct nameidata nd; 113652196Smckusick u_quad_t frev; 113738418Smckusick 113838418Smckusick fhp = &nfh.fh_generic; 113938418Smckusick nfsm_srvmtofh(fhp); 114038418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 114152316Sheideman nd.ni_cnd.cn_cred = cred; 114252316Sheideman nd.ni_cnd.cn_nameiop = DELETE; 114352316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 114452196Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp)) 114538418Smckusick nfsm_reply(0); 114649742Smckusick vp = nd.ni_vp; 114738418Smckusick if (vp->v_type != VDIR) { 114838418Smckusick error = ENOTDIR; 114938418Smckusick goto out; 115038418Smckusick } 115138418Smckusick /* 115238418Smckusick * No rmdir "." please. 115338418Smckusick */ 115449742Smckusick if (nd.ni_dvp == vp) { 115538418Smckusick error = EINVAL; 115638418Smckusick goto out; 115738418Smckusick } 115838418Smckusick /* 115949454Smckusick * The root of a mounted filesystem cannot be deleted. 116038418Smckusick */ 116138418Smckusick if (vp->v_flag & VROOT) 116238418Smckusick error = EBUSY; 116338418Smckusick out: 116442467Smckusick if (!error) { 116552196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 116652196Smckusick nqsrv_getl(vp, NQL_WRITE); 116752234Sheideman error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 116842467Smckusick } else { 116952234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 117049742Smckusick if (nd.ni_dvp == nd.ni_vp) 117149742Smckusick vrele(nd.ni_dvp); 117243359Smckusick else 117349742Smckusick vput(nd.ni_dvp); 117442467Smckusick vput(vp); 117542467Smckusick } 117638418Smckusick nfsm_reply(0); 117738418Smckusick nfsm_srvdone; 117838418Smckusick } 117938418Smckusick 118038418Smckusick /* 118138418Smckusick * nfs readdir service 118238418Smckusick * - mallocs what it thinks is enough to read 118348050Smckusick * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR 118438418Smckusick * - calls VOP_READDIR() 118540115Smckusick * - loops around building the reply 118638425Smckusick * if the output generated exceeds count break out of loop 118738425Smckusick * The nfsm_clget macro is used here so that the reply will be packed 118838425Smckusick * tightly in mbuf clusters. 118938418Smckusick * - it only knows that it has encountered eof when the VOP_READDIR() 119038425Smckusick * reads nothing 119138418Smckusick * - as such one readdir rpc will return eof false although you are there 119238425Smckusick * and then the next will return eof 119352441Smckusick * - it trims out records with d_fileno == 0 119438425Smckusick * this doesn't matter for Unix clients, but they might confuse clients 119538425Smckusick * for other os'. 119638418Smckusick * NB: It is tempting to set eof to true if the VOP_READDIR() reads less 119738425Smckusick * than requested, but this may not apply to all filesystems. For 119838425Smckusick * example, client NFS does not { although it is never remote mounted 119938425Smckusick * anyhow } 120052196Smckusick * The alternate call nqnfsrv_readdirlook() does lookups as well. 120138418Smckusick * PS: The NFS protocol spec. does not clarify what the "count" byte 120238425Smckusick * argument is a count of.. just name strings and file id's or the 120338425Smckusick * entire reply rpc or ... 120438425Smckusick * I tried just file name and id sizes and it confused the Sun client, 120538425Smckusick * so I am using the full rpc size now. The "paranoia.." comment refers 120638425Smckusick * to including the status longwords that are not a part of the dir. 120738425Smckusick * "entry" structures, but are in the rpc. 120838418Smckusick */ 120952196Smckusick struct flrep { 121052196Smckusick u_long fl_cachable; 121152196Smckusick u_long fl_duration; 121252196Smckusick u_quad_t fl_frev; 121352196Smckusick nfsv2fh_t fl_nfh; 121452196Smckusick struct nfsv2_fattr fl_fattr; 121552196Smckusick }; 121652196Smckusick 121752196Smckusick nfsrv_readdir(nfsd, mrep, md, dpos, cred, nam, mrq) 121852196Smckusick struct nfsd *nfsd; 121938418Smckusick struct mbuf *mrep, *md; 122038418Smckusick caddr_t dpos; 122138418Smckusick struct ucred *cred; 122252196Smckusick struct mbuf *nam, **mrq; 122338418Smckusick { 122438418Smckusick register char *bp, *be; 122538418Smckusick register struct mbuf *mp; 122652441Smckusick register struct dirent *dp; 122739494Smckusick register caddr_t cp; 122848050Smckusick register u_long *tl; 122939494Smckusick register long t1; 123039494Smckusick caddr_t bpos; 123152196Smckusick struct mbuf *mb, *mb2, *mreq, *mp2; 123252196Smckusick char *cpos, *cend, *cp2, *rbuf; 123338418Smckusick struct vnode *vp; 123438418Smckusick nfsv2fh_t nfh; 123538418Smckusick fhandle_t *fhp; 123638418Smckusick struct uio io; 123738418Smckusick struct iovec iv; 123852196Smckusick struct vattr va; 123952196Smckusick int len, nlen, rem, xfer, tsiz, i, error = 0; 124052196Smckusick int siz, cnt, fullsiz, eofflag, rdonly, cache; 124152196Smckusick u_quad_t frev; 124238418Smckusick u_long on; 124338418Smckusick off_t off, toff; 124438418Smckusick 124538418Smckusick fhp = &nfh.fh_generic; 124638418Smckusick nfsm_srvmtofh(fhp); 124752196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 124848050Smckusick toff = fxdr_unsigned(off_t, *tl++); 124948050Smckusick off = (toff & ~(NFS_DIRBLKSIZ-1)); 125048050Smckusick on = (toff & (NFS_DIRBLKSIZ-1)); 125148050Smckusick cnt = fxdr_unsigned(int, *tl); 125248050Smckusick siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); 125341899Smckusick if (cnt > NFS_MAXREADDIR) 125441899Smckusick siz = NFS_MAXREADDIR; 125538418Smckusick fullsiz = siz; 125652196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 125738418Smckusick nfsm_reply(0); 125852196Smckusick nqsrv_getl(vp, NQL_READ); 125952196Smckusick if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { 126038418Smckusick vput(vp); 126138418Smckusick nfsm_reply(0); 126238418Smckusick } 126338418Smckusick VOP_UNLOCK(vp); 126438418Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 126538418Smckusick again: 126638418Smckusick iv.iov_base = rbuf; 126738418Smckusick iv.iov_len = fullsiz; 126838418Smckusick io.uio_iov = &iv; 126938418Smckusick io.uio_iovcnt = 1; 127038418Smckusick io.uio_offset = off; 127138418Smckusick io.uio_resid = fullsiz; 127238418Smckusick io.uio_segflg = UIO_SYSSPACE; 127338418Smckusick io.uio_rw = UIO_READ; 127448050Smckusick io.uio_procp = (struct proc *)0; 127540296Smckusick error = VOP_READDIR(vp, &io, cred, &eofflag); 127639586Smckusick off = io.uio_offset; 127738418Smckusick if (error) { 127838418Smckusick vrele(vp); 127938418Smckusick free((caddr_t)rbuf, M_TEMP); 128038418Smckusick nfsm_reply(0); 128138418Smckusick } 128238418Smckusick if (io.uio_resid) { 128338418Smckusick siz -= io.uio_resid; 128438418Smckusick 128538418Smckusick /* 128638418Smckusick * If nothing read, return eof 128738418Smckusick * rpc reply 128838418Smckusick */ 128938418Smckusick if (siz == 0) { 129038418Smckusick vrele(vp); 129138418Smckusick nfsm_reply(2*NFSX_UNSIGNED); 129248050Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 129348050Smckusick *tl++ = nfs_false; 129448050Smckusick *tl = nfs_true; 129538418Smckusick FREE((caddr_t)rbuf, M_TEMP); 129638418Smckusick return (0); 129738418Smckusick } 129838418Smckusick } 129940115Smckusick 130038418Smckusick /* 130138418Smckusick * Check for degenerate cases of nothing useful read. 130240115Smckusick * If so go try again 130338418Smckusick */ 130440115Smckusick cpos = rbuf + on; 130540115Smckusick cend = rbuf + siz; 130652441Smckusick dp = (struct dirent *)cpos; 130752441Smckusick while (cpos < cend && dp->d_fileno == 0) { 130840115Smckusick cpos += dp->d_reclen; 130952441Smckusick dp = (struct dirent *)cpos; 131040115Smckusick } 131140115Smckusick if (cpos >= cend) { 131238418Smckusick toff = off; 131338418Smckusick siz = fullsiz; 131438418Smckusick on = 0; 131538418Smckusick goto again; 131638418Smckusick } 131740115Smckusick 131840115Smckusick cpos = rbuf + on; 131940115Smckusick cend = rbuf + siz; 132052441Smckusick dp = (struct dirent *)cpos; 132152196Smckusick len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 132252196Smckusick nfsm_reply(siz); 132352196Smckusick mp = mp2 = mb; 132452196Smckusick bp = bpos; 132552196Smckusick be = bp + M_TRAILINGSPACE(mp); 132652196Smckusick 132752196Smckusick /* Loop through the records and build reply */ 132852196Smckusick while (cpos < cend) { 132952441Smckusick if (dp->d_fileno != 0) { 133052196Smckusick nlen = dp->d_namlen; 133152196Smckusick rem = nfsm_rndup(nlen)-nlen; 133252196Smckusick len += (4*NFSX_UNSIGNED + nlen + rem); 133352196Smckusick if (len > cnt) { 133452196Smckusick eofflag = 0; 133552196Smckusick break; 133652196Smckusick } 133752441Smckusick /* 133852441Smckusick * Build the directory record xdr from 133952441Smckusick * the dirent entry. 134052441Smckusick */ 134152196Smckusick nfsm_clget; 134252196Smckusick *tl = nfs_true; 134352196Smckusick bp += NFSX_UNSIGNED; 134452196Smckusick nfsm_clget; 134552441Smckusick *tl = txdr_unsigned(dp->d_fileno); 134652196Smckusick bp += NFSX_UNSIGNED; 134752196Smckusick nfsm_clget; 134852196Smckusick *tl = txdr_unsigned(nlen); 134952196Smckusick bp += NFSX_UNSIGNED; 135052196Smckusick 135152196Smckusick /* And loop around copying the name */ 135252196Smckusick xfer = nlen; 135352196Smckusick cp = dp->d_name; 135452196Smckusick while (xfer > 0) { 135552196Smckusick nfsm_clget; 135652196Smckusick if ((bp+xfer) > be) 135752196Smckusick tsiz = be-bp; 135852196Smckusick else 135952196Smckusick tsiz = xfer; 136052196Smckusick bcopy(cp, bp, tsiz); 136152196Smckusick bp += tsiz; 136252196Smckusick xfer -= tsiz; 136352196Smckusick if (xfer > 0) 136452196Smckusick cp += tsiz; 136552196Smckusick } 136652196Smckusick /* And null pad to a long boundary */ 136752196Smckusick for (i = 0; i < rem; i++) 136852196Smckusick *bp++ = '\0'; 136952196Smckusick nfsm_clget; 137052196Smckusick 137152196Smckusick /* Finish off the record */ 137252196Smckusick toff += dp->d_reclen; 137352196Smckusick *tl = txdr_unsigned(toff); 137452196Smckusick bp += NFSX_UNSIGNED; 137552196Smckusick } else 137652196Smckusick toff += dp->d_reclen; 137752196Smckusick cpos += dp->d_reclen; 137852441Smckusick dp = (struct dirent *)cpos; 137952196Smckusick } 138038418Smckusick vrele(vp); 138152196Smckusick nfsm_clget; 138252196Smckusick *tl = nfs_false; 138352196Smckusick bp += NFSX_UNSIGNED; 138452196Smckusick nfsm_clget; 138552196Smckusick if (eofflag) 138652196Smckusick *tl = nfs_true; 138752196Smckusick else 138852196Smckusick *tl = nfs_false; 138952196Smckusick bp += NFSX_UNSIGNED; 139052196Smckusick if (mp != mb) { 139152196Smckusick if (bp < be) 139252196Smckusick mp->m_len = bp - mtod(mp, caddr_t); 139352196Smckusick } else 139452196Smckusick mp->m_len += bp - bpos; 139552196Smckusick FREE(rbuf, M_TEMP); 139652196Smckusick nfsm_srvdone; 139752196Smckusick } 139852196Smckusick 139952196Smckusick nqnfsrv_readdirlook(nfsd, mrep, md, dpos, cred, nam, mrq) 140052196Smckusick struct nfsd *nfsd; 140152196Smckusick struct mbuf *mrep, *md; 140252196Smckusick caddr_t dpos; 140352196Smckusick struct ucred *cred; 140452196Smckusick struct mbuf *nam, **mrq; 140552196Smckusick { 140652196Smckusick register char *bp, *be; 140752196Smckusick register struct mbuf *mp; 140852441Smckusick register struct dirent *dp; 140952196Smckusick register caddr_t cp; 141052196Smckusick register u_long *tl; 141152196Smckusick register long t1; 141252196Smckusick caddr_t bpos; 141352196Smckusick struct mbuf *mb, *mb2, *mreq, *mp2; 141452196Smckusick char *cpos, *cend, *cp2, *rbuf; 141552196Smckusick struct vnode *vp, *nvp; 141652196Smckusick struct flrep fl; 141752196Smckusick struct ufid *ufp = (struct ufid *)&fl.fl_nfh.fh_generic.fh_fid; 141852196Smckusick struct mount *mntp; 141952196Smckusick nfsv2fh_t nfh; 142052196Smckusick fhandle_t *fhp; 142152196Smckusick struct uio io; 142252196Smckusick struct iovec iv; 142352196Smckusick struct vattr va, *vap = &va; 142452196Smckusick struct nfsv2_fattr *fp; 142552196Smckusick int len, nlen, rem, xfer, tsiz, i, error = 0, duration2, cache2; 142652196Smckusick int siz, cnt, fullsiz, eofflag, rdonly, cache; 142752196Smckusick u_quad_t frev, frev2; 142852196Smckusick u_long on; 142952196Smckusick off_t off, toff; 143052196Smckusick 143152196Smckusick fhp = &nfh.fh_generic; 143252196Smckusick nfsm_srvmtofh(fhp); 143352196Smckusick nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED); 143452196Smckusick toff = fxdr_unsigned(off_t, *tl++); 143552196Smckusick off = (toff & ~(NFS_DIRBLKSIZ-1)); 143652196Smckusick on = (toff & (NFS_DIRBLKSIZ-1)); 143752196Smckusick cnt = fxdr_unsigned(int, *tl++); 143852196Smckusick duration2 = fxdr_unsigned(int, *tl); 143952196Smckusick siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); 144052196Smckusick if (cnt > NFS_MAXREADDIR) 144152196Smckusick siz = NFS_MAXREADDIR; 144252196Smckusick fullsiz = siz; 144352196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 144452196Smckusick nfsm_reply(0); 144552196Smckusick nqsrv_getl(vp, NQL_READ); 144652196Smckusick if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { 144752196Smckusick vput(vp); 144852196Smckusick nfsm_reply(0); 144952196Smckusick } 145052196Smckusick VOP_UNLOCK(vp); 145152196Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 145252196Smckusick again: 145352196Smckusick iv.iov_base = rbuf; 145452196Smckusick iv.iov_len = fullsiz; 145552196Smckusick io.uio_iov = &iv; 145652196Smckusick io.uio_iovcnt = 1; 145752196Smckusick io.uio_offset = off; 145852196Smckusick io.uio_resid = fullsiz; 145952196Smckusick io.uio_segflg = UIO_SYSSPACE; 146052196Smckusick io.uio_rw = UIO_READ; 146152196Smckusick io.uio_procp = (struct proc *)0; 146252196Smckusick error = VOP_READDIR(vp, &io, cred, &eofflag); 146352196Smckusick off = io.uio_offset; 146452196Smckusick if (error) { 146552196Smckusick vrele(vp); 146652196Smckusick free((caddr_t)rbuf, M_TEMP); 146752196Smckusick nfsm_reply(0); 146852196Smckusick } 146952196Smckusick if (io.uio_resid) { 147052196Smckusick siz -= io.uio_resid; 147152196Smckusick 147252196Smckusick /* 147352196Smckusick * If nothing read, return eof 147452196Smckusick * rpc reply 147552196Smckusick */ 147652196Smckusick if (siz == 0) { 147752196Smckusick vrele(vp); 147852196Smckusick nfsm_reply(2*NFSX_UNSIGNED); 147952196Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 148052196Smckusick *tl++ = nfs_false; 148152196Smckusick *tl = nfs_true; 148252196Smckusick FREE((caddr_t)rbuf, M_TEMP); 148352196Smckusick return (0); 148452196Smckusick } 148552196Smckusick } 148652196Smckusick 148752196Smckusick /* 148852196Smckusick * Check for degenerate cases of nothing useful read. 148952196Smckusick * If so go try again 149052196Smckusick */ 149152196Smckusick cpos = rbuf + on; 149252196Smckusick cend = rbuf + siz; 149352441Smckusick dp = (struct dirent *)cpos; 149452441Smckusick while (cpos < cend && dp->d_fileno == 0) { 149552196Smckusick cpos += dp->d_reclen; 149652441Smckusick dp = (struct dirent *)cpos; 149752196Smckusick } 149852196Smckusick if (cpos >= cend) { 149952196Smckusick toff = off; 150052196Smckusick siz = fullsiz; 150152196Smckusick on = 0; 150252196Smckusick goto again; 150352196Smckusick } 150452196Smckusick 150552196Smckusick cpos = rbuf + on; 150652196Smckusick cend = rbuf + siz; 150752441Smckusick dp = (struct dirent *)cpos; 150838425Smckusick len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 150938418Smckusick nfsm_reply(siz); 151052196Smckusick mp = mp2 = mb; 151152196Smckusick bp = bpos; 151252196Smckusick be = bp + M_TRAILINGSPACE(mp); 151352196Smckusick mntp = vp->v_mount; 151438418Smckusick 151538418Smckusick /* Loop through the records and build reply */ 151638418Smckusick while (cpos < cend) { 151752441Smckusick if (dp->d_fileno != 0) { 151838418Smckusick nlen = dp->d_namlen; 151938418Smckusick rem = nfsm_rndup(nlen)-nlen; 152038425Smckusick 152138418Smckusick /* 152252196Smckusick * For readdir_and_lookup get the vnode using 152352196Smckusick * the file number. 152438418Smckusick */ 152552196Smckusick bzero((caddr_t)&fl.fl_nfh, sizeof (nfsv2fh_t)); 152652196Smckusick ufp->ufid_len = sizeof (struct ufid); 152752441Smckusick ufp->ufid_ino = dp->d_fileno; 152852196Smckusick fl.fl_nfh.fh_generic.fh_fsid = mntp->mnt_stat.f_fsid; 152952196Smckusick if (VFS_FHTOVP(mntp, (struct fid *)ufp, 1, &nvp)) 153052196Smckusick goto invalid; 153152196Smckusick (void) nqsrv_getlease(nvp, &duration2, NQL_READ, nfsd, 153252196Smckusick nam, &cache2, &frev2, cred); 153352196Smckusick fl.fl_duration = txdr_unsigned(duration2); 153452196Smckusick fl.fl_cachable = txdr_unsigned(cache2); 153552196Smckusick txdr_hyper(&frev2, &fl.fl_frev); 153652196Smckusick if (VOP_GETATTR(nvp, vap, cred, nfsd->nd_procp)) { 153752196Smckusick vput(nvp); 153852196Smckusick goto invalid; 153952196Smckusick } 154052196Smckusick vput(nvp); 154152196Smckusick fp = &fl.fl_fattr; 154252196Smckusick nfsm_srvfillattr; 154352196Smckusick len += (4*NFSX_UNSIGNED + nlen + rem + NFSX_FH 154452196Smckusick + NFSX_FATTR); 154541899Smckusick if (len > cnt) { 154641899Smckusick eofflag = 0; 154738418Smckusick break; 154841899Smckusick } 154952441Smckusick /* 155052441Smckusick * Build the directory record xdr from 155152441Smckusick * the dirent entry. 155252441Smckusick */ 155338418Smckusick nfsm_clget; 155448050Smckusick *tl = nfs_true; 155538418Smckusick bp += NFSX_UNSIGNED; 155652196Smckusick 155752196Smckusick /* 155852196Smckusick * For readdir_and_lookup copy the stuff out. 155952196Smckusick */ 156052196Smckusick xfer = sizeof (struct flrep); 156152196Smckusick cp = (caddr_t)&fl; 156252196Smckusick while (xfer > 0) { 156352196Smckusick nfsm_clget; 156452196Smckusick if ((bp+xfer) > be) 156552196Smckusick tsiz = be-bp; 156652196Smckusick else 156752196Smckusick tsiz = xfer; 156852196Smckusick bcopy(cp, bp, tsiz); 156952196Smckusick bp += tsiz; 157052196Smckusick xfer -= tsiz; 157152196Smckusick if (xfer > 0) 157252196Smckusick cp += tsiz; 157352196Smckusick } 157438418Smckusick nfsm_clget; 157552441Smckusick *tl = txdr_unsigned(dp->d_fileno); 157638418Smckusick bp += NFSX_UNSIGNED; 157738418Smckusick nfsm_clget; 157848050Smckusick *tl = txdr_unsigned(nlen); 157938418Smckusick bp += NFSX_UNSIGNED; 158038425Smckusick 158152196Smckusick /* And loop around copying the name */ 158238418Smckusick xfer = nlen; 158338418Smckusick cp = dp->d_name; 158438418Smckusick while (xfer > 0) { 158538418Smckusick nfsm_clget; 158638418Smckusick if ((bp+xfer) > be) 158738418Smckusick tsiz = be-bp; 158838418Smckusick else 158938418Smckusick tsiz = xfer; 159038418Smckusick bcopy(cp, bp, tsiz); 159138418Smckusick bp += tsiz; 159238418Smckusick xfer -= tsiz; 159338418Smckusick if (xfer > 0) 159438418Smckusick cp += tsiz; 159538418Smckusick } 159638418Smckusick /* And null pad to a long boundary */ 159738418Smckusick for (i = 0; i < rem; i++) 159838418Smckusick *bp++ = '\0'; 159938418Smckusick nfsm_clget; 160038425Smckusick 160138418Smckusick /* Finish off the record */ 160238418Smckusick toff += dp->d_reclen; 160348050Smckusick *tl = txdr_unsigned(toff); 160438418Smckusick bp += NFSX_UNSIGNED; 160538418Smckusick } else 160652196Smckusick invalid: 160738418Smckusick toff += dp->d_reclen; 160838418Smckusick cpos += dp->d_reclen; 160952441Smckusick dp = (struct dirent *)cpos; 161038418Smckusick } 161152196Smckusick vrele(vp); 161238418Smckusick nfsm_clget; 161348050Smckusick *tl = nfs_false; 161438418Smckusick bp += NFSX_UNSIGNED; 161538418Smckusick nfsm_clget; 161640296Smckusick if (eofflag) 161748050Smckusick *tl = nfs_true; 161840296Smckusick else 161948050Smckusick *tl = nfs_false; 162038418Smckusick bp += NFSX_UNSIGNED; 162152196Smckusick if (mp != mb) { 162252196Smckusick if (bp < be) 162352196Smckusick mp->m_len = bp - mtod(mp, caddr_t); 162452196Smckusick } else 162552196Smckusick mp->m_len += bp - bpos; 162638418Smckusick FREE(rbuf, M_TEMP); 162738418Smckusick nfsm_srvdone; 162838418Smckusick } 162938418Smckusick 163038418Smckusick /* 163138418Smckusick * nfs statfs service 163238418Smckusick */ 163352196Smckusick nfsrv_statfs(nfsd, mrep, md, dpos, cred, nam, mrq) 163452196Smckusick struct nfsd *nfsd; 163538418Smckusick struct mbuf *mrep, *md; 163638418Smckusick caddr_t dpos; 163738418Smckusick struct ucred *cred; 163852196Smckusick struct mbuf *nam, **mrq; 163938418Smckusick { 164038418Smckusick register struct statfs *sf; 164138884Smacklem register struct nfsv2_statfs *sfp; 164248050Smckusick register u_long *tl; 164339494Smckusick register long t1; 164439494Smckusick caddr_t bpos; 164552196Smckusick int error = 0, rdonly, cache; 164639494Smckusick char *cp2; 164739753Smckusick struct mbuf *mb, *mb2, *mreq; 164838418Smckusick struct vnode *vp; 164938418Smckusick nfsv2fh_t nfh; 165038418Smckusick fhandle_t *fhp; 165138418Smckusick struct statfs statfs; 165252196Smckusick u_quad_t frev; 165338418Smckusick 165438418Smckusick fhp = &nfh.fh_generic; 165538418Smckusick nfsm_srvmtofh(fhp); 165652196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 165738418Smckusick nfsm_reply(0); 165838418Smckusick sf = &statfs; 165952196Smckusick error = VFS_STATFS(vp->v_mount, sf, nfsd->nd_procp); 166038418Smckusick vput(vp); 166138418Smckusick nfsm_reply(NFSX_STATFS); 166238884Smacklem nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS); 166344993Sbostic sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA); 166451940Smckusick sfp->sf_bsize = txdr_unsigned(sf->f_bsize); 166538884Smacklem sfp->sf_blocks = txdr_unsigned(sf->f_blocks); 166638884Smacklem sfp->sf_bfree = txdr_unsigned(sf->f_bfree); 166738884Smacklem sfp->sf_bavail = txdr_unsigned(sf->f_bavail); 166838418Smckusick nfsm_srvdone; 166938418Smckusick } 167038418Smckusick 167138418Smckusick /* 167238418Smckusick * Null operation, used by clients to ping server 167338418Smckusick */ 167439494Smckusick /* ARGSUSED */ 167552196Smckusick nfsrv_null(nfsd, mrep, md, dpos, cred, nam, mrq) 167652196Smckusick struct nfsd *nfsd; 167738418Smckusick struct mbuf *mrep, *md; 167838418Smckusick caddr_t dpos; 167938418Smckusick struct ucred *cred; 168052196Smckusick struct mbuf *nam, **mrq; 168138418Smckusick { 168239494Smckusick caddr_t bpos; 168352196Smckusick int error = VNOVAL, cache; 168439753Smckusick struct mbuf *mb, *mreq; 168552196Smckusick u_quad_t frev; 168638418Smckusick 168738418Smckusick nfsm_reply(0); 168839494Smckusick return (error); 168938418Smckusick } 169038418Smckusick 169138418Smckusick /* 169238418Smckusick * No operation, used for obsolete procedures 169338418Smckusick */ 169439494Smckusick /* ARGSUSED */ 169552196Smckusick nfsrv_noop(nfsd, mrep, md, dpos, cred, nam, mrq) 169652196Smckusick struct nfsd *nfsd; 169738418Smckusick struct mbuf *mrep, *md; 169838418Smckusick caddr_t dpos; 169938418Smckusick struct ucred *cred; 170052196Smckusick struct mbuf *nam, **mrq; 170138418Smckusick { 170239494Smckusick caddr_t bpos; 170352196Smckusick int error, cache; 170439753Smckusick struct mbuf *mb, *mreq; 170552196Smckusick u_quad_t frev; 170638418Smckusick 170752196Smckusick if (nfsd->nd_repstat) 170852196Smckusick error = nfsd->nd_repstat; 170952196Smckusick else 171052196Smckusick error = EPROCUNAVAIL; 171138418Smckusick nfsm_reply(0); 171239494Smckusick return (error); 171338418Smckusick } 171438425Smckusick 171538450Smckusick /* 171638450Smckusick * Perform access checking for vnodes obtained from file handles that would 171738450Smckusick * refer to files already opened by a Unix client. You cannot just use 171838450Smckusick * vn_writechk() and VOP_ACCESS() for two reasons. 171952196Smckusick * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case 172038450Smckusick * 2 - The owner is to be given access irrespective of mode bits so that 172138450Smckusick * processes that chmod after opening a file don't break. I don't like 172238450Smckusick * this because it opens a security hole, but since the nfs server opens 172338450Smckusick * a security hole the size of a barn door anyhow, what the heck. 172438450Smckusick */ 172552196Smckusick nfsrv_access(vp, flags, cred, rdonly, p) 172638450Smckusick register struct vnode *vp; 172738450Smckusick int flags; 172838450Smckusick register struct ucred *cred; 172952196Smckusick int rdonly; 173048050Smckusick struct proc *p; 173138450Smckusick { 173238450Smckusick struct vattr vattr; 173338450Smckusick int error; 173438450Smckusick if (flags & VWRITE) { 173552196Smckusick /* Just vn_writechk() changed to check rdonly */ 173638450Smckusick /* 173738450Smckusick * Disallow write attempts on read-only file systems; 173838450Smckusick * unless the file is a socket or a block or character 173938450Smckusick * device resident on the file system. 174038450Smckusick */ 174152196Smckusick if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { 174245059Smckusick switch (vp->v_type) { 174345059Smckusick case VREG: case VDIR: case VLNK: 174438450Smckusick return (EROFS); 174545059Smckusick } 174645059Smckusick } 174738450Smckusick /* 174838450Smckusick * If there's shared text associated with 174938450Smckusick * the inode, try to free it up once. If 175038450Smckusick * we fail, we can't allow writing. 175138450Smckusick */ 175245715Smckusick if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) 175338450Smckusick return (ETXTBSY); 175438450Smckusick } 175548050Smckusick if (error = VOP_GETATTR(vp, &vattr, cred, p)) 175645059Smckusick return (error); 175748050Smckusick if ((error = VOP_ACCESS(vp, flags, cred, p)) && 175845059Smckusick cred->cr_uid != vattr.va_uid) 175945059Smckusick return (error); 176045059Smckusick return (0); 176138450Smckusick } 1762