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*52933Smckusick * @(#)nfs_serv.c 7.49 (Berkeley) 03/13/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; 21652653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 21752653Smckusick nfsd->nd_procp)) 21838418Smckusick nfsm_reply(0); 21952196Smckusick nqsrv_getl(nd.ni_startdir, NQL_READ); 22052196Smckusick vrele(nd.ni_startdir); 22152653Smckusick FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 22249742Smckusick vp = nd.ni_vp; 22338418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 22441398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 22538418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 22638418Smckusick vput(vp); 22738418Smckusick nfsm_reply(0); 22838418Smckusick } 22952196Smckusick if (lflag) 23052196Smckusick (void) nqsrv_getlease(vp, &duration2, lflag, nfsd, 23152196Smckusick nam, &cache2, &frev2, cred); 23252196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 23338418Smckusick vput(vp); 23452196Smckusick nfsm_reply(NFSX_FH + NFSX_FATTR + 5*NFSX_UNSIGNED); 23552196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 23652196Smckusick if (lflag) { 23752196Smckusick nfsm_build(tl, u_long *, 5*NFSX_UNSIGNED); 23852196Smckusick *tl++ = txdr_unsigned(lflag); 23952196Smckusick *tl++ = txdr_unsigned(cache2); 24052196Smckusick *tl++ = txdr_unsigned(duration2); 24152196Smckusick txdr_hyper(&frev2, tl); 24252196Smckusick } else { 24352196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 24452196Smckusick *tl = 0; 24552196Smckusick } 24652196Smckusick } 24738418Smckusick nfsm_srvfhtom(fhp); 24838884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 24939753Smckusick nfsm_srvfillattr; 25038418Smckusick nfsm_srvdone; 25138418Smckusick } 25238418Smckusick 25338418Smckusick /* 25438418Smckusick * nfs readlink service 25538418Smckusick */ 25652196Smckusick nfsrv_readlink(nfsd, mrep, md, dpos, cred, nam, mrq) 25752196Smckusick struct nfsd *nfsd; 25838418Smckusick struct mbuf *mrep, *md; 25938418Smckusick caddr_t dpos; 26038418Smckusick struct ucred *cred; 26152196Smckusick struct mbuf *nam, **mrq; 26238418Smckusick { 26341899Smckusick struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN]; 26438418Smckusick register struct iovec *ivp = iv; 26538418Smckusick register struct mbuf *mp; 26648050Smckusick register u_long *tl; 26739494Smckusick register long t1; 26839494Smckusick caddr_t bpos; 26952196Smckusick int error = 0, rdonly, cache, i, tlen, len; 27039494Smckusick char *cp2; 27139753Smckusick struct mbuf *mb, *mb2, *mp2, *mp3, *mreq; 27238418Smckusick struct vnode *vp; 27338418Smckusick nfsv2fh_t nfh; 27438418Smckusick fhandle_t *fhp; 27538418Smckusick struct uio io, *uiop = &io; 27652196Smckusick u_quad_t frev; 27738418Smckusick 27838418Smckusick fhp = &nfh.fh_generic; 27938418Smckusick nfsm_srvmtofh(fhp); 28038418Smckusick len = 0; 28138418Smckusick i = 0; 28238418Smckusick while (len < NFS_MAXPATHLEN) { 28338418Smckusick MGET(mp, M_WAIT, MT_DATA); 28441899Smckusick MCLGET(mp, M_WAIT); 28538418Smckusick mp->m_len = NFSMSIZ(mp); 28638418Smckusick if (len == 0) 28738418Smckusick mp3 = mp2 = mp; 28841899Smckusick else { 28938418Smckusick mp2->m_next = mp; 29041899Smckusick mp2 = mp; 29141899Smckusick } 29238418Smckusick if ((len+mp->m_len) > NFS_MAXPATHLEN) { 29338418Smckusick mp->m_len = NFS_MAXPATHLEN-len; 29438418Smckusick len = NFS_MAXPATHLEN; 29538418Smckusick } else 29638418Smckusick len += mp->m_len; 29738418Smckusick ivp->iov_base = mtod(mp, caddr_t); 29838418Smckusick ivp->iov_len = mp->m_len; 29938418Smckusick i++; 30038418Smckusick ivp++; 30138418Smckusick } 30238418Smckusick uiop->uio_iov = iv; 30338418Smckusick uiop->uio_iovcnt = i; 30438418Smckusick uiop->uio_offset = 0; 30538418Smckusick uiop->uio_resid = len; 30638418Smckusick uiop->uio_rw = UIO_READ; 30738418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 30848050Smckusick uiop->uio_procp = (struct proc *)0; 30952196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) { 31038418Smckusick m_freem(mp3); 31138418Smckusick nfsm_reply(0); 31238418Smckusick } 31338418Smckusick if (vp->v_type != VLNK) { 31438418Smckusick error = EINVAL; 31538418Smckusick goto out; 31638418Smckusick } 31752196Smckusick nqsrv_getl(vp, NQL_READ); 31838418Smckusick error = VOP_READLINK(vp, uiop, cred); 31938418Smckusick out: 32038418Smckusick vput(vp); 32138418Smckusick if (error) 32238418Smckusick m_freem(mp3); 32338418Smckusick nfsm_reply(NFSX_UNSIGNED); 32438418Smckusick if (uiop->uio_resid > 0) { 32538418Smckusick len -= uiop->uio_resid; 32638418Smckusick tlen = nfsm_rndup(len); 32738418Smckusick nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len); 32838418Smckusick } 32948050Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 33048050Smckusick *tl = txdr_unsigned(len); 33138418Smckusick mb->m_next = mp3; 33238418Smckusick nfsm_srvdone; 33338418Smckusick } 33438418Smckusick 33538418Smckusick /* 33638418Smckusick * nfs read service 33738418Smckusick */ 33852196Smckusick nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq) 33952196Smckusick struct nfsd *nfsd; 34038418Smckusick struct mbuf *mrep, *md; 34138418Smckusick caddr_t dpos; 34238418Smckusick struct ucred *cred; 34352196Smckusick struct mbuf *nam, **mrq; 34438418Smckusick { 34543350Smckusick register struct iovec *iv; 34643350Smckusick struct iovec *iv2; 34741899Smckusick register struct mbuf *m; 34838884Smacklem register struct nfsv2_fattr *fp; 34948050Smckusick register u_long *tl; 35039494Smckusick register long t1; 35139494Smckusick caddr_t bpos; 35252196Smckusick int error = 0, rdonly, cache, i, cnt, len, left, siz, tlen; 35339494Smckusick char *cp2; 35439753Smckusick struct mbuf *mb, *mb2, *mreq; 35552196Smckusick struct mbuf *m2; 35638418Smckusick struct vnode *vp; 35738418Smckusick nfsv2fh_t nfh; 35838418Smckusick fhandle_t *fhp; 35938418Smckusick struct uio io, *uiop = &io; 36038418Smckusick struct vattr va, *vap = &va; 36138418Smckusick off_t off; 36252196Smckusick u_quad_t frev; 36338418Smckusick 36438418Smckusick fhp = &nfh.fh_generic; 36538418Smckusick nfsm_srvmtofh(fhp); 36652196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 36748050Smckusick off = fxdr_unsigned(off_t, *tl); 36838418Smckusick nfsm_srvstrsiz(cnt, NFS_MAXDATA); 36952196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 37038418Smckusick nfsm_reply(0); 37152196Smckusick nqsrv_getl(vp, NQL_READ); 37252196Smckusick if (error = nfsrv_access(vp, VREAD | VEXEC, cred, rdonly, nfsd->nd_procp)) { 37338418Smckusick vput(vp); 37438418Smckusick nfsm_reply(0); 37538418Smckusick } 37652196Smckusick if (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp)) { 37738418Smckusick vput(vp); 37838418Smckusick nfsm_reply(0); 37938418Smckusick } 38052196Smckusick if (off >= vap->va_size) 38152196Smckusick cnt = 0; 38252196Smckusick else if ((off + cnt) > vap->va_size) 38352196Smckusick cnt = nfsm_rndup(vap->va_size - off); 38452196Smckusick nfsm_reply(NFSX_FATTR+NFSX_UNSIGNED+nfsm_rndup(cnt)); 38552196Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 38652196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 38752196Smckusick len = left = cnt; 38852196Smckusick if (cnt > 0) { 38952196Smckusick /* 39052196Smckusick * Generate the mbuf list with the uio_iov ref. to it. 39152196Smckusick */ 39252196Smckusick i = 0; 39352196Smckusick m = m2 = mb; 39452196Smckusick MALLOC(iv, struct iovec *, 39552196Smckusick ((NFS_MAXDATA+MLEN-1)/MLEN) * sizeof (struct iovec), 39652196Smckusick M_TEMP, M_WAITOK); 39752196Smckusick iv2 = iv; 39852196Smckusick while (left > 0) { 39952196Smckusick siz = MIN(M_TRAILINGSPACE(m), left); 40052196Smckusick if (siz > 0) { 40152196Smckusick m->m_len += siz; 40252196Smckusick iv->iov_base = bpos; 40352196Smckusick iv->iov_len = siz; 40452196Smckusick iv++; 40552196Smckusick i++; 40652196Smckusick left -= siz; 40752196Smckusick } 40852196Smckusick if (left > 0) { 40952196Smckusick MGET(m, M_WAIT, MT_DATA); 41052196Smckusick MCLGET(m, M_WAIT); 41152196Smckusick m->m_len = 0; 41252196Smckusick m2->m_next = m; 41352196Smckusick m2 = m; 41452196Smckusick bpos = mtod(m, caddr_t); 41552196Smckusick } 41652196Smckusick } 41752196Smckusick uiop->uio_iov = iv2; 41852196Smckusick uiop->uio_iovcnt = i; 41952196Smckusick uiop->uio_offset = off; 42052196Smckusick uiop->uio_resid = cnt; 42152196Smckusick uiop->uio_rw = UIO_READ; 42252196Smckusick uiop->uio_segflg = UIO_SYSSPACE; 42352196Smckusick error = VOP_READ(vp, uiop, IO_NODELOCKED, cred); 42452196Smckusick off = uiop->uio_offset; 42552196Smckusick FREE((caddr_t)iv2, M_TEMP); 42652196Smckusick if (error || (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp))) { 42752196Smckusick m_freem(mreq); 42852196Smckusick vput(vp); 42952196Smckusick nfsm_reply(0); 43052196Smckusick } 43152196Smckusick } else 43252196Smckusick uiop->uio_resid = 0; 43338418Smckusick vput(vp); 43439753Smckusick nfsm_srvfillattr; 43545877Smckusick len -= uiop->uio_resid; 43652196Smckusick tlen = nfsm_rndup(len); 43752196Smckusick if (cnt != tlen || tlen != len) 43852196Smckusick nfsm_adj(mb, cnt-tlen, tlen-len); 43948050Smckusick *tl = txdr_unsigned(len); 44038418Smckusick nfsm_srvdone; 44138418Smckusick } 44238418Smckusick 44338418Smckusick /* 44438418Smckusick * nfs write service 44538418Smckusick */ 44652196Smckusick nfsrv_write(nfsd, mrep, md, dpos, cred, nam, mrq) 44752196Smckusick struct nfsd *nfsd; 44852196Smckusick struct mbuf *mrep, *md; 44938418Smckusick caddr_t dpos; 45038418Smckusick struct ucred *cred; 45152196Smckusick struct mbuf *nam, **mrq; 45238418Smckusick { 45338418Smckusick register struct iovec *ivp; 45438418Smckusick register struct mbuf *mp; 45538884Smacklem register struct nfsv2_fattr *fp; 45641899Smckusick struct iovec iv[NFS_MAXIOVEC]; 45738418Smckusick struct vattr va; 45838418Smckusick register struct vattr *vap = &va; 45948050Smckusick register u_long *tl; 46039494Smckusick register long t1; 46139494Smckusick caddr_t bpos; 46252196Smckusick int error = 0, rdonly, cache, siz, len, xfer; 46339494Smckusick char *cp2; 46439753Smckusick struct mbuf *mb, *mb2, *mreq; 46538418Smckusick struct vnode *vp; 46638418Smckusick nfsv2fh_t nfh; 46738418Smckusick fhandle_t *fhp; 46838418Smckusick struct uio io, *uiop = &io; 46938418Smckusick off_t off; 47052196Smckusick u_quad_t frev; 47138418Smckusick 47238418Smckusick fhp = &nfh.fh_generic; 47338418Smckusick nfsm_srvmtofh(fhp); 47452196Smckusick nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); 47548050Smckusick off = fxdr_unsigned(off_t, *++tl); 47648050Smckusick tl += 2; 47748050Smckusick len = fxdr_unsigned(long, *tl); 47838418Smckusick if (len > NFS_MAXDATA || len <= 0) { 47938418Smckusick error = EBADRPC; 48038418Smckusick nfsm_reply(0); 48138418Smckusick } 48238418Smckusick if (dpos == (mtod(md, caddr_t)+md->m_len)) { 48338418Smckusick mp = md->m_next; 48438418Smckusick if (mp == NULL) { 48538418Smckusick error = EBADRPC; 48638418Smckusick nfsm_reply(0); 48738418Smckusick } 48838418Smckusick } else { 48938418Smckusick mp = md; 49038418Smckusick siz = dpos-mtod(mp, caddr_t); 49138418Smckusick mp->m_len -= siz; 49238418Smckusick NFSMADV(mp, siz); 49338418Smckusick } 49452196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 49538418Smckusick nfsm_reply(0); 49652196Smckusick nqsrv_getl(vp, NQL_WRITE); 49752196Smckusick if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) { 49838418Smckusick vput(vp); 49938418Smckusick nfsm_reply(0); 50038418Smckusick } 50138418Smckusick uiop->uio_resid = 0; 50238418Smckusick uiop->uio_rw = UIO_WRITE; 50338418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 50448050Smckusick uiop->uio_procp = (struct proc *)0; 50538418Smckusick /* 50641899Smckusick * Do up to NFS_MAXIOVEC mbufs of write each iteration of the 50738418Smckusick * loop until done. 50838418Smckusick */ 50938418Smckusick while (len > 0 && uiop->uio_resid == 0) { 51038418Smckusick ivp = iv; 51138418Smckusick siz = 0; 51238418Smckusick uiop->uio_iov = ivp; 51338418Smckusick uiop->uio_iovcnt = 0; 51438418Smckusick uiop->uio_offset = off; 51541899Smckusick while (len > 0 && uiop->uio_iovcnt < NFS_MAXIOVEC && mp != NULL) { 51638418Smckusick ivp->iov_base = mtod(mp, caddr_t); 51738418Smckusick if (len < mp->m_len) 51838418Smckusick ivp->iov_len = xfer = len; 51938418Smckusick else 52038418Smckusick ivp->iov_len = xfer = mp->m_len; 52138418Smckusick #ifdef notdef 52238418Smckusick /* Not Yet .. */ 52338418Smckusick if (M_HASCL(mp) && (((u_long)ivp->iov_base) & CLOFSET) == 0) 52438418Smckusick ivp->iov_op = NULL; /* what should it be ?? */ 52538418Smckusick else 52638418Smckusick ivp->iov_op = NULL; 52738418Smckusick #endif 52838418Smckusick uiop->uio_iovcnt++; 52938418Smckusick ivp++; 53038418Smckusick len -= xfer; 53138418Smckusick siz += xfer; 53238418Smckusick mp = mp->m_next; 53338418Smckusick } 53438418Smckusick if (len > 0 && mp == NULL) { 53538418Smckusick error = EBADRPC; 53638418Smckusick vput(vp); 53738418Smckusick nfsm_reply(0); 53838418Smckusick } 53938418Smckusick uiop->uio_resid = siz; 54039586Smckusick if (error = VOP_WRITE(vp, uiop, IO_SYNC | IO_NODELOCKED, 54138418Smckusick cred)) { 54238418Smckusick vput(vp); 54338418Smckusick nfsm_reply(0); 54438418Smckusick } 54539586Smckusick off = uiop->uio_offset; 54638418Smckusick } 54752196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 54838418Smckusick vput(vp); 54938418Smckusick nfsm_reply(NFSX_FATTR); 55038884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 55139753Smckusick nfsm_srvfillattr; 55252442Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 55352442Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 55452442Smckusick txdr_hyper(&vap->va_filerev, tl); 55552442Smckusick } 55638418Smckusick nfsm_srvdone; 55738418Smckusick } 55838418Smckusick 55938418Smckusick /* 56038418Smckusick * nfs create service 56138418Smckusick * now does a truncate to 0 length via. setattr if it already exists 56238418Smckusick */ 56352196Smckusick nfsrv_create(nfsd, mrep, md, dpos, cred, nam, mrq) 56452196Smckusick struct nfsd *nfsd; 56552196Smckusick struct mbuf *mrep, *md; 56638418Smckusick caddr_t dpos; 56738418Smckusick struct ucred *cred; 56852196Smckusick struct mbuf *nam, **mrq; 56938418Smckusick { 57038884Smacklem register struct nfsv2_fattr *fp; 57138418Smckusick struct vattr va; 57238418Smckusick register struct vattr *vap = &va; 57349742Smckusick struct nameidata nd; 57439494Smckusick register caddr_t cp; 57548050Smckusick register u_long *tl; 57639494Smckusick register long t1; 57739494Smckusick caddr_t bpos; 57852196Smckusick int error = 0, rdev, cache, len; 57939494Smckusick char *cp2; 58039753Smckusick struct mbuf *mb, *mb2, *mreq; 58138418Smckusick struct vnode *vp; 58238418Smckusick nfsv2fh_t nfh; 58338418Smckusick fhandle_t *fhp; 58452196Smckusick u_quad_t frev; 58538418Smckusick 58652316Sheideman nd.ni_cnd.cn_nameiop = 0; 58738418Smckusick fhp = &nfh.fh_generic; 58838418Smckusick nfsm_srvmtofh(fhp); 58938418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 59052316Sheideman nd.ni_cnd.cn_cred = cred; 59152316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 59252316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART; 59352653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 59452653Smckusick nfsd->nd_procp)) 59538418Smckusick nfsm_reply(0); 59641361Smckusick VATTR_NULL(vap); 59752196Smckusick nfsm_dissect(tl, u_long *, NFSX_SATTR); 59838418Smckusick /* 59938418Smckusick * Iff doesn't exist, create it 60038418Smckusick * otherwise just truncate to 0 length 60138418Smckusick * should I set the mode too ?? 60238418Smckusick */ 60349742Smckusick if (nd.ni_vp == NULL) { 60448050Smckusick vap->va_type = IFTOVT(fxdr_unsigned(u_long, *tl)); 60542867Smckusick if (vap->va_type == VNON) 60642867Smckusick vap->va_type = VREG; 60748050Smckusick vap->va_mode = nfstov_mode(*tl); 60848050Smckusick rdev = fxdr_unsigned(long, *(tl+3)); 60946988Smckusick if (vap->va_type == VREG || vap->va_type == VSOCK) { 61049742Smckusick vrele(nd.ni_startdir); 61152196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 61252234Sheideman if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) 61342242Smckusick nfsm_reply(0); 61452316Sheideman FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 61542242Smckusick } else if (vap->va_type == VCHR || vap->va_type == VBLK || 61642242Smckusick vap->va_type == VFIFO) { 61742242Smckusick if (vap->va_type == VCHR && rdev == 0xffffffff) 61842242Smckusick vap->va_type = VFIFO; 61942242Smckusick if (vap->va_type == VFIFO) { 62042242Smckusick #ifndef FIFO 62152234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 62249742Smckusick vput(nd.ni_dvp); 62342242Smckusick error = ENXIO; 62449742Smckusick goto out; 62542242Smckusick #endif /* FIFO */ 62652196Smckusick } else if (error = suser(cred, (u_short *)0)) { 62752234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 62849742Smckusick vput(nd.ni_dvp); 62949742Smckusick goto out; 63042242Smckusick } else 63142242Smckusick vap->va_rdev = (dev_t)rdev; 63252196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 63352234Sheideman if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) { 63449742Smckusick vrele(nd.ni_startdir); 63542242Smckusick nfsm_reply(0); 63649742Smckusick } 63752316Sheideman nd.ni_cnd.cn_nameiop = LOOKUP; 63852316Sheideman nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART); 63952316Sheideman nd.ni_cnd.cn_proc = nfsd->nd_procp; 64052316Sheideman nd.ni_cnd.cn_cred = nfsd->nd_procp->p_ucred; 64152316Sheideman if (error = lookup(&nd)) { 64252316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 64342242Smckusick nfsm_reply(0); 64449742Smckusick } 64552316Sheideman FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 64652316Sheideman if (nd.ni_cnd.cn_flags & ISSYMLINK) { 64749742Smckusick vrele(nd.ni_dvp); 64849742Smckusick vput(nd.ni_vp); 64952234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 65049742Smckusick error = EINVAL; 65149742Smckusick nfsm_reply(0); 65249742Smckusick } 65342242Smckusick } else { 65452234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 65549742Smckusick vput(nd.ni_dvp); 65642242Smckusick error = ENXIO; 65749742Smckusick goto out; 65842242Smckusick } 65949742Smckusick vp = nd.ni_vp; 66038418Smckusick } else { 66149742Smckusick vrele(nd.ni_startdir); 66252316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 66349742Smckusick vp = nd.ni_vp; 66449742Smckusick if (nd.ni_dvp == vp) 66549742Smckusick vrele(nd.ni_dvp); 66643359Smckusick else 66749742Smckusick vput(nd.ni_dvp); 66852234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 66938418Smckusick vap->va_size = 0; 67052196Smckusick nqsrv_getl(vp, NQL_WRITE); 67152196Smckusick if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) { 67242506Smckusick vput(vp); 67338418Smckusick nfsm_reply(0); 67442506Smckusick } 67538418Smckusick } 67638418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 67741398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 67838418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 67938418Smckusick vput(vp); 68038418Smckusick nfsm_reply(0); 68138418Smckusick } 68252196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 68338418Smckusick vput(vp); 68438418Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR); 68538418Smckusick nfsm_srvfhtom(fhp); 68638884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 68739753Smckusick nfsm_srvfillattr; 68838418Smckusick return (error); 68938418Smckusick nfsmout: 69052316Sheideman if (nd.ni_cnd.cn_nameiop || nd.ni_cnd.cn_flags) 69151464Sbostic vrele(nd.ni_startdir); 69252234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 69349742Smckusick if (nd.ni_dvp == nd.ni_vp) 69449742Smckusick vrele(nd.ni_dvp); 69543359Smckusick else 69649742Smckusick vput(nd.ni_dvp); 69749742Smckusick if (nd.ni_vp) 69849742Smckusick vput(nd.ni_vp); 69938418Smckusick return (error); 70049742Smckusick 70149742Smckusick out: 70249742Smckusick vrele(nd.ni_startdir); 70352316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 70449742Smckusick nfsm_reply(0); 70538418Smckusick } 70638418Smckusick 70738418Smckusick /* 70838418Smckusick * nfs remove service 70938418Smckusick */ 71052196Smckusick nfsrv_remove(nfsd, mrep, md, dpos, cred, nam, mrq) 71152196Smckusick struct nfsd *nfsd; 71252196Smckusick struct mbuf *mrep, *md; 71338418Smckusick caddr_t dpos; 71438418Smckusick struct ucred *cred; 71552196Smckusick struct mbuf *nam, **mrq; 71638418Smckusick { 71749742Smckusick struct nameidata nd; 71848050Smckusick register u_long *tl; 71939494Smckusick register long t1; 72039494Smckusick caddr_t bpos; 72152196Smckusick int error = 0, cache, len; 72239494Smckusick char *cp2; 72339753Smckusick struct mbuf *mb, *mreq; 72438418Smckusick struct vnode *vp; 72538418Smckusick nfsv2fh_t nfh; 72638418Smckusick fhandle_t *fhp; 72752196Smckusick u_quad_t frev; 72838418Smckusick 72938418Smckusick fhp = &nfh.fh_generic; 73038418Smckusick nfsm_srvmtofh(fhp); 73138418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 73252316Sheideman nd.ni_cnd.cn_cred = cred; 73352316Sheideman nd.ni_cnd.cn_nameiop = DELETE; 73452316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 73552653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 73652653Smckusick nfsd->nd_procp)) 73738418Smckusick nfsm_reply(0); 73849742Smckusick vp = nd.ni_vp; 73938418Smckusick if (vp->v_type == VDIR && 74052196Smckusick (error = suser(cred, (u_short *)0))) 74138418Smckusick goto out; 74238418Smckusick /* 74349454Smckusick * The root of a mounted filesystem cannot be deleted. 74438418Smckusick */ 74538418Smckusick if (vp->v_flag & VROOT) { 74638418Smckusick error = EBUSY; 74738418Smckusick goto out; 74838418Smckusick } 74938418Smckusick if (vp->v_flag & VTEXT) 75045715Smckusick (void) vnode_pager_uncache(vp); 75138418Smckusick out: 75242467Smckusick if (!error) { 75352196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 75452196Smckusick nqsrv_getl(vp, NQL_WRITE); 75552234Sheideman error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 75642467Smckusick } else { 75752234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 75849742Smckusick if (nd.ni_dvp == vp) 75949742Smckusick vrele(nd.ni_dvp); 76043359Smckusick else 76149742Smckusick vput(nd.ni_dvp); 76242467Smckusick vput(vp); 76342467Smckusick } 76438418Smckusick nfsm_reply(0); 76538418Smckusick nfsm_srvdone; 76638418Smckusick } 76738418Smckusick 76838418Smckusick /* 76938418Smckusick * nfs rename service 77038418Smckusick */ 77152196Smckusick nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq) 77252196Smckusick struct nfsd *nfsd; 77352196Smckusick struct mbuf *mrep, *md; 77438418Smckusick caddr_t dpos; 77538418Smckusick struct ucred *cred; 77652196Smckusick struct mbuf *nam, **mrq; 77738418Smckusick { 77848050Smckusick register u_long *tl; 77939494Smckusick register long t1; 78039494Smckusick caddr_t bpos; 78152196Smckusick int error = 0, rdonly, cache, len, len2; 78239494Smckusick char *cp2; 78339753Smckusick struct mbuf *mb, *mreq; 78449742Smckusick struct nameidata fromnd, tond; 78538418Smckusick struct vnode *fvp, *tvp, *tdvp; 78638418Smckusick nfsv2fh_t fnfh, tnfh; 78738418Smckusick fhandle_t *ffhp, *tfhp; 78852196Smckusick u_quad_t frev; 78952196Smckusick uid_t saved_uid; 79038418Smckusick 79138418Smckusick ffhp = &fnfh.fh_generic; 79238418Smckusick tfhp = &tnfh.fh_generic; 79352316Sheideman fromnd.ni_cnd.cn_nameiop = 0; 79452316Sheideman tond.ni_cnd.cn_nameiop = 0; 79538418Smckusick nfsm_srvmtofh(ffhp); 79638418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 79738418Smckusick /* 79852196Smckusick * Remember our original uid so that we can reset cr_uid before 79952196Smckusick * the second nfs_namei() call, in case it is remapped. 80038418Smckusick */ 80152196Smckusick saved_uid = cred->cr_uid; 80252316Sheideman fromnd.ni_cnd.cn_cred = cred; 80352316Sheideman fromnd.ni_cnd.cn_nameiop = DELETE; 80452316Sheideman fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART; 80552653Smckusick if (error = nfs_namei(&fromnd, ffhp, len, nfsd->nd_slp, nam, &md, 80652653Smckusick &dpos, nfsd->nd_procp)) 80738418Smckusick nfsm_reply(0); 80849742Smckusick fvp = fromnd.ni_vp; 80938418Smckusick nfsm_srvmtofh(tfhp); 81041899Smckusick nfsm_strsiz(len2, NFS_MAXNAMLEN); 81152196Smckusick cred->cr_uid = saved_uid; 81252316Sheideman tond.ni_cnd.cn_cred = cred; 81352316Sheideman tond.ni_cnd.cn_nameiop = RENAME; 81452316Sheideman tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; 81552653Smckusick if (error = nfs_namei(&tond, tfhp, len2, nfsd->nd_slp, nam, &md, 81652653Smckusick &dpos, nfsd->nd_procp)) { 81752234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 81849742Smckusick vrele(fromnd.ni_dvp); 81942467Smckusick vrele(fvp); 82042467Smckusick goto out1; 82142467Smckusick } 82238425Smckusick tdvp = tond.ni_dvp; 82338425Smckusick tvp = tond.ni_vp; 82438418Smckusick if (tvp != NULL) { 82538418Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 82638418Smckusick error = EISDIR; 82738418Smckusick goto out; 82838418Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 82938418Smckusick error = ENOTDIR; 83038418Smckusick goto out; 83138418Smckusick } 83252196Smckusick if (tvp->v_type == VDIR && tvp->v_mountedhere) { 83352196Smckusick error = EXDEV; 83452196Smckusick goto out; 83552196Smckusick } 83638418Smckusick } 83752196Smckusick if (fvp->v_type == VDIR && fvp->v_mountedhere) { 83852196Smckusick error = EBUSY; 83952196Smckusick goto out; 84052196Smckusick } 84138418Smckusick if (fvp->v_mount != tdvp->v_mount) { 84238418Smckusick error = EXDEV; 84338418Smckusick goto out; 84438418Smckusick } 84549742Smckusick if (fvp == tdvp) 84638418Smckusick error = EINVAL; 84749742Smckusick /* 84849742Smckusick * If source is the same as the destination (that is the 84949742Smckusick * same vnode with the same name in the same directory), 85049742Smckusick * then there is nothing to do. 85149742Smckusick */ 85249742Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 85352316Sheideman fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 85452316Sheideman !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 85552316Sheideman fromnd.ni_cnd.cn_namelen)) 85649742Smckusick error = -1; 85738418Smckusick out: 85842467Smckusick if (!error) { 85952196Smckusick nqsrv_getl(fromnd.ni_dvp, NQL_WRITE); 86052196Smckusick nqsrv_getl(tdvp, NQL_WRITE); 86152196Smckusick if (tvp) 86252196Smckusick nqsrv_getl(tvp, NQL_WRITE); 86352234Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 86452234Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 86542467Smckusick } else { 86652234Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 86743359Smckusick if (tdvp == tvp) 86843359Smckusick vrele(tdvp); 86943359Smckusick else 87043359Smckusick vput(tdvp); 87142467Smckusick if (tvp) 87242467Smckusick vput(tvp); 87352234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 87449742Smckusick vrele(fromnd.ni_dvp); 87542467Smckusick vrele(fvp); 87638418Smckusick } 87746513Smckusick vrele(tond.ni_startdir); 87852316Sheideman FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 87938418Smckusick out1: 88049742Smckusick vrele(fromnd.ni_startdir); 88152316Sheideman FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 88238418Smckusick nfsm_reply(0); 88338418Smckusick return (error); 88449742Smckusick 88538418Smckusick nfsmout: 88652316Sheideman if (tond.ni_cnd.cn_nameiop || tond.ni_cnd.cn_flags) { 88749742Smckusick vrele(tond.ni_startdir); 88852316Sheideman FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 88949742Smckusick } 89052316Sheideman if (fromnd.ni_cnd.cn_nameiop || fromnd.ni_cnd.cn_flags) { 89149742Smckusick vrele(fromnd.ni_startdir); 89252316Sheideman FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 89352234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 89449742Smckusick vrele(fromnd.ni_dvp); 89549742Smckusick vrele(fvp); 89649742Smckusick } 89738418Smckusick return (error); 89838418Smckusick } 89938418Smckusick 90038418Smckusick /* 90138418Smckusick * nfs link service 90238418Smckusick */ 90352196Smckusick nfsrv_link(nfsd, mrep, md, dpos, cred, nam, mrq) 90452196Smckusick struct nfsd *nfsd; 90552196Smckusick struct mbuf *mrep, *md; 90638418Smckusick caddr_t dpos; 90738418Smckusick struct ucred *cred; 90852196Smckusick struct mbuf *nam, **mrq; 90938418Smckusick { 91049742Smckusick struct nameidata nd; 91148050Smckusick register u_long *tl; 91239494Smckusick register long t1; 91339494Smckusick caddr_t bpos; 91452196Smckusick int error = 0, rdonly, cache, len; 91539494Smckusick char *cp2; 91639753Smckusick struct mbuf *mb, *mreq; 91738418Smckusick struct vnode *vp, *xp; 91838418Smckusick nfsv2fh_t nfh, dnfh; 91938418Smckusick fhandle_t *fhp, *dfhp; 92052196Smckusick u_quad_t frev; 92138418Smckusick 92238418Smckusick fhp = &nfh.fh_generic; 92338418Smckusick dfhp = &dnfh.fh_generic; 92438418Smckusick nfsm_srvmtofh(fhp); 92538418Smckusick nfsm_srvmtofh(dfhp); 92638418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 92752196Smckusick if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 92838418Smckusick nfsm_reply(0); 92952196Smckusick if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0))) 93038418Smckusick goto out1; 93152316Sheideman nd.ni_cnd.cn_cred = cred; 93252316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 93352316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 93452653Smckusick if (error = nfs_namei(&nd, dfhp, len, nfsd->nd_slp, nam, &md, &dpos, 93552653Smckusick nfsd->nd_procp)) 93638418Smckusick goto out1; 93749742Smckusick xp = nd.ni_vp; 93838418Smckusick if (xp != NULL) { 93938418Smckusick error = EEXIST; 94038418Smckusick goto out; 94138418Smckusick } 94249742Smckusick xp = nd.ni_dvp; 94338418Smckusick if (vp->v_mount != xp->v_mount) 94438418Smckusick error = EXDEV; 94538418Smckusick out: 94642467Smckusick if (!error) { 94752196Smckusick nqsrv_getl(vp, NQL_WRITE); 94852196Smckusick nqsrv_getl(xp, NQL_WRITE); 949*52933Smckusick error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 95042467Smckusick } else { 95152234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 95249742Smckusick if (nd.ni_dvp == nd.ni_vp) 95349742Smckusick vrele(nd.ni_dvp); 95443359Smckusick else 95549742Smckusick vput(nd.ni_dvp); 95649742Smckusick if (nd.ni_vp) 95749742Smckusick vrele(nd.ni_vp); 95842467Smckusick } 95938418Smckusick out1: 96038418Smckusick vrele(vp); 96138418Smckusick nfsm_reply(0); 96238418Smckusick nfsm_srvdone; 96338418Smckusick } 96438418Smckusick 96538418Smckusick /* 96638418Smckusick * nfs symbolic link service 96738418Smckusick */ 96852196Smckusick nfsrv_symlink(nfsd, mrep, md, dpos, cred, nam, mrq) 96952196Smckusick struct nfsd *nfsd; 97052196Smckusick struct mbuf *mrep, *md; 97138418Smckusick caddr_t dpos; 97238418Smckusick struct ucred *cred; 97352196Smckusick struct mbuf *nam, **mrq; 97438418Smckusick { 97538418Smckusick struct vattr va; 97649742Smckusick struct nameidata nd; 97738418Smckusick register struct vattr *vap = &va; 97848050Smckusick register u_long *tl; 97939494Smckusick register long t1; 98045285Smckusick struct nfsv2_sattr *sp; 98139494Smckusick caddr_t bpos; 98241899Smckusick struct uio io; 98341899Smckusick struct iovec iv; 98452196Smckusick int error = 0, rdonly, cache, len, len2; 98541899Smckusick char *pathcp, *cp2; 98639753Smckusick struct mbuf *mb, *mreq; 98738418Smckusick nfsv2fh_t nfh; 98838418Smckusick fhandle_t *fhp; 98952196Smckusick u_quad_t frev; 99038418Smckusick 99141899Smckusick pathcp = (char *)0; 99238418Smckusick fhp = &nfh.fh_generic; 99338418Smckusick nfsm_srvmtofh(fhp); 99438418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 99552316Sheideman nd.ni_cnd.cn_cred = cred; 99652316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 99752316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 99852653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 99952653Smckusick nfsd->nd_procp)) 100042467Smckusick goto out; 100141899Smckusick nfsm_strsiz(len2, NFS_MAXPATHLEN); 100241899Smckusick MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK); 100341899Smckusick iv.iov_base = pathcp; 100441899Smckusick iv.iov_len = len2; 100541899Smckusick io.uio_resid = len2; 100641899Smckusick io.uio_offset = 0; 100741899Smckusick io.uio_iov = &iv; 100841899Smckusick io.uio_iovcnt = 1; 100941899Smckusick io.uio_segflg = UIO_SYSSPACE; 101041899Smckusick io.uio_rw = UIO_READ; 101148050Smckusick io.uio_procp = (struct proc *)0; 101241899Smckusick nfsm_mtouio(&io, len2); 101352196Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR); 101441899Smckusick *(pathcp + len2) = '\0'; 101549742Smckusick if (nd.ni_vp) { 101652234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 101749742Smckusick if (nd.ni_dvp == nd.ni_vp) 101849742Smckusick vrele(nd.ni_dvp); 101943359Smckusick else 102049742Smckusick vput(nd.ni_dvp); 102149742Smckusick vrele(nd.ni_vp); 102238418Smckusick error = EEXIST; 102338418Smckusick goto out; 102438418Smckusick } 102541361Smckusick VATTR_NULL(vap); 102645285Smckusick vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode); 102752196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 102852234Sheideman error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp); 102938418Smckusick out: 103041899Smckusick if (pathcp) 103141899Smckusick FREE(pathcp, M_TEMP); 103238418Smckusick nfsm_reply(0); 103338418Smckusick return (error); 103438418Smckusick nfsmout: 103552234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 103649742Smckusick if (nd.ni_dvp == nd.ni_vp) 103749742Smckusick vrele(nd.ni_dvp); 103843359Smckusick else 103949742Smckusick vput(nd.ni_dvp); 104049742Smckusick if (nd.ni_vp) 104149742Smckusick vrele(nd.ni_vp); 104241899Smckusick if (pathcp) 104341899Smckusick FREE(pathcp, M_TEMP); 104438418Smckusick return (error); 104538418Smckusick } 104638418Smckusick 104738418Smckusick /* 104838418Smckusick * nfs mkdir service 104938418Smckusick */ 105052196Smckusick nfsrv_mkdir(nfsd, mrep, md, dpos, cred, nam, mrq) 105152196Smckusick struct nfsd *nfsd; 105252196Smckusick struct mbuf *mrep, *md; 105338418Smckusick caddr_t dpos; 105438418Smckusick struct ucred *cred; 105552196Smckusick struct mbuf *nam, **mrq; 105638418Smckusick { 105738418Smckusick struct vattr va; 105838418Smckusick register struct vattr *vap = &va; 105938884Smacklem register struct nfsv2_fattr *fp; 106049742Smckusick struct nameidata nd; 106139494Smckusick register caddr_t cp; 106248050Smckusick register u_long *tl; 106339494Smckusick register long t1; 106439494Smckusick caddr_t bpos; 106552196Smckusick int error = 0, rdonly, cache, len; 106639494Smckusick char *cp2; 106739753Smckusick struct mbuf *mb, *mb2, *mreq; 106838418Smckusick struct vnode *vp; 106938418Smckusick nfsv2fh_t nfh; 107038418Smckusick fhandle_t *fhp; 107152196Smckusick u_quad_t frev; 107238418Smckusick 107338418Smckusick fhp = &nfh.fh_generic; 107438418Smckusick nfsm_srvmtofh(fhp); 107538418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 107652316Sheideman nd.ni_cnd.cn_cred = cred; 107752316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 107852316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 107952653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 108052653Smckusick nfsd->nd_procp)) 108138418Smckusick nfsm_reply(0); 108252196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 108341361Smckusick VATTR_NULL(vap); 108438418Smckusick vap->va_type = VDIR; 108548050Smckusick vap->va_mode = nfstov_mode(*tl++); 108649742Smckusick vp = nd.ni_vp; 108738418Smckusick if (vp != NULL) { 108852234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 108949742Smckusick if (nd.ni_dvp == vp) 109049742Smckusick vrele(nd.ni_dvp); 109143359Smckusick else 109249742Smckusick vput(nd.ni_dvp); 109342467Smckusick vrele(vp); 109438418Smckusick error = EEXIST; 109538418Smckusick nfsm_reply(0); 109638418Smckusick } 109752196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 109852234Sheideman if (error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) 109938418Smckusick nfsm_reply(0); 110049742Smckusick vp = nd.ni_vp; 110138418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 110241398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 110338418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 110438418Smckusick vput(vp); 110538418Smckusick nfsm_reply(0); 110638418Smckusick } 110752196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 110838418Smckusick vput(vp); 110938418Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR); 111038418Smckusick nfsm_srvfhtom(fhp); 111138884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 111239753Smckusick nfsm_srvfillattr; 111338418Smckusick return (error); 111438418Smckusick nfsmout: 111552234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 111649742Smckusick if (nd.ni_dvp == nd.ni_vp) 111749742Smckusick vrele(nd.ni_dvp); 111843359Smckusick else 111949742Smckusick vput(nd.ni_dvp); 112049742Smckusick if (nd.ni_vp) 112149742Smckusick vrele(nd.ni_vp); 112238418Smckusick return (error); 112338418Smckusick } 112438418Smckusick 112538418Smckusick /* 112638418Smckusick * nfs rmdir service 112738418Smckusick */ 112852196Smckusick nfsrv_rmdir(nfsd, mrep, md, dpos, cred, nam, mrq) 112952196Smckusick struct nfsd *nfsd; 113052196Smckusick struct mbuf *mrep, *md; 113138418Smckusick caddr_t dpos; 113238418Smckusick struct ucred *cred; 113352196Smckusick struct mbuf *nam, **mrq; 113438418Smckusick { 113548050Smckusick register u_long *tl; 113639494Smckusick register long t1; 113739494Smckusick caddr_t bpos; 113852196Smckusick int error = 0, rdonly, cache, len; 113939494Smckusick char *cp2; 114039753Smckusick struct mbuf *mb, *mreq; 114138418Smckusick struct vnode *vp; 114238418Smckusick nfsv2fh_t nfh; 114338418Smckusick fhandle_t *fhp; 114449742Smckusick struct nameidata nd; 114552196Smckusick u_quad_t frev; 114638418Smckusick 114738418Smckusick fhp = &nfh.fh_generic; 114838418Smckusick nfsm_srvmtofh(fhp); 114938418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 115052316Sheideman nd.ni_cnd.cn_cred = cred; 115152316Sheideman nd.ni_cnd.cn_nameiop = DELETE; 115252316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 115352653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 115452653Smckusick nfsd->nd_procp)) 115538418Smckusick nfsm_reply(0); 115649742Smckusick vp = nd.ni_vp; 115738418Smckusick if (vp->v_type != VDIR) { 115838418Smckusick error = ENOTDIR; 115938418Smckusick goto out; 116038418Smckusick } 116138418Smckusick /* 116238418Smckusick * No rmdir "." please. 116338418Smckusick */ 116449742Smckusick if (nd.ni_dvp == vp) { 116538418Smckusick error = EINVAL; 116638418Smckusick goto out; 116738418Smckusick } 116838418Smckusick /* 116949454Smckusick * The root of a mounted filesystem cannot be deleted. 117038418Smckusick */ 117138418Smckusick if (vp->v_flag & VROOT) 117238418Smckusick error = EBUSY; 117338418Smckusick out: 117442467Smckusick if (!error) { 117552196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 117652196Smckusick nqsrv_getl(vp, NQL_WRITE); 117752234Sheideman error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 117842467Smckusick } else { 117952234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 118049742Smckusick if (nd.ni_dvp == nd.ni_vp) 118149742Smckusick vrele(nd.ni_dvp); 118243359Smckusick else 118349742Smckusick vput(nd.ni_dvp); 118442467Smckusick vput(vp); 118542467Smckusick } 118638418Smckusick nfsm_reply(0); 118738418Smckusick nfsm_srvdone; 118838418Smckusick } 118938418Smckusick 119038418Smckusick /* 119138418Smckusick * nfs readdir service 119238418Smckusick * - mallocs what it thinks is enough to read 119348050Smckusick * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR 119438418Smckusick * - calls VOP_READDIR() 119540115Smckusick * - loops around building the reply 119638425Smckusick * if the output generated exceeds count break out of loop 119738425Smckusick * The nfsm_clget macro is used here so that the reply will be packed 119838425Smckusick * tightly in mbuf clusters. 119938418Smckusick * - it only knows that it has encountered eof when the VOP_READDIR() 120038425Smckusick * reads nothing 120138418Smckusick * - as such one readdir rpc will return eof false although you are there 120238425Smckusick * and then the next will return eof 120352441Smckusick * - it trims out records with d_fileno == 0 120438425Smckusick * this doesn't matter for Unix clients, but they might confuse clients 120538425Smckusick * for other os'. 120638418Smckusick * NB: It is tempting to set eof to true if the VOP_READDIR() reads less 120738425Smckusick * than requested, but this may not apply to all filesystems. For 120838425Smckusick * example, client NFS does not { although it is never remote mounted 120938425Smckusick * anyhow } 121052196Smckusick * The alternate call nqnfsrv_readdirlook() does lookups as well. 121138418Smckusick * PS: The NFS protocol spec. does not clarify what the "count" byte 121238425Smckusick * argument is a count of.. just name strings and file id's or the 121338425Smckusick * entire reply rpc or ... 121438425Smckusick * I tried just file name and id sizes and it confused the Sun client, 121538425Smckusick * so I am using the full rpc size now. The "paranoia.." comment refers 121638425Smckusick * to including the status longwords that are not a part of the dir. 121738425Smckusick * "entry" structures, but are in the rpc. 121838418Smckusick */ 121952196Smckusick struct flrep { 122052196Smckusick u_long fl_cachable; 122152196Smckusick u_long fl_duration; 122252196Smckusick u_quad_t fl_frev; 122352196Smckusick nfsv2fh_t fl_nfh; 122452196Smckusick struct nfsv2_fattr fl_fattr; 122552196Smckusick }; 122652196Smckusick 122752196Smckusick nfsrv_readdir(nfsd, mrep, md, dpos, cred, nam, mrq) 122852196Smckusick struct nfsd *nfsd; 122938418Smckusick struct mbuf *mrep, *md; 123038418Smckusick caddr_t dpos; 123138418Smckusick struct ucred *cred; 123252196Smckusick struct mbuf *nam, **mrq; 123338418Smckusick { 123438418Smckusick register char *bp, *be; 123538418Smckusick register struct mbuf *mp; 123652441Smckusick register struct dirent *dp; 123739494Smckusick register caddr_t cp; 123848050Smckusick register u_long *tl; 123939494Smckusick register long t1; 124039494Smckusick caddr_t bpos; 124152196Smckusick struct mbuf *mb, *mb2, *mreq, *mp2; 124252196Smckusick char *cpos, *cend, *cp2, *rbuf; 124338418Smckusick struct vnode *vp; 124438418Smckusick nfsv2fh_t nfh; 124538418Smckusick fhandle_t *fhp; 124638418Smckusick struct uio io; 124738418Smckusick struct iovec iv; 124852196Smckusick struct vattr va; 124952196Smckusick int len, nlen, rem, xfer, tsiz, i, error = 0; 125052196Smckusick int siz, cnt, fullsiz, eofflag, rdonly, cache; 125152196Smckusick u_quad_t frev; 125238418Smckusick u_long on; 125338418Smckusick off_t off, toff; 125438418Smckusick 125538418Smckusick fhp = &nfh.fh_generic; 125638418Smckusick nfsm_srvmtofh(fhp); 125752196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 125848050Smckusick toff = fxdr_unsigned(off_t, *tl++); 125948050Smckusick off = (toff & ~(NFS_DIRBLKSIZ-1)); 126048050Smckusick on = (toff & (NFS_DIRBLKSIZ-1)); 126148050Smckusick cnt = fxdr_unsigned(int, *tl); 126248050Smckusick siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); 126341899Smckusick if (cnt > NFS_MAXREADDIR) 126441899Smckusick siz = NFS_MAXREADDIR; 126538418Smckusick fullsiz = siz; 126652196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 126738418Smckusick nfsm_reply(0); 126852196Smckusick nqsrv_getl(vp, NQL_READ); 126952196Smckusick if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { 127038418Smckusick vput(vp); 127138418Smckusick nfsm_reply(0); 127238418Smckusick } 127338418Smckusick VOP_UNLOCK(vp); 127438418Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 127538418Smckusick again: 127638418Smckusick iv.iov_base = rbuf; 127738418Smckusick iv.iov_len = fullsiz; 127838418Smckusick io.uio_iov = &iv; 127938418Smckusick io.uio_iovcnt = 1; 128038418Smckusick io.uio_offset = off; 128138418Smckusick io.uio_resid = fullsiz; 128238418Smckusick io.uio_segflg = UIO_SYSSPACE; 128338418Smckusick io.uio_rw = UIO_READ; 128448050Smckusick io.uio_procp = (struct proc *)0; 128540296Smckusick error = VOP_READDIR(vp, &io, cred, &eofflag); 128639586Smckusick off = io.uio_offset; 128738418Smckusick if (error) { 128838418Smckusick vrele(vp); 128938418Smckusick free((caddr_t)rbuf, M_TEMP); 129038418Smckusick nfsm_reply(0); 129138418Smckusick } 129238418Smckusick if (io.uio_resid) { 129338418Smckusick siz -= io.uio_resid; 129438418Smckusick 129538418Smckusick /* 129638418Smckusick * If nothing read, return eof 129738418Smckusick * rpc reply 129838418Smckusick */ 129938418Smckusick if (siz == 0) { 130038418Smckusick vrele(vp); 130138418Smckusick nfsm_reply(2*NFSX_UNSIGNED); 130248050Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 130348050Smckusick *tl++ = nfs_false; 130448050Smckusick *tl = nfs_true; 130538418Smckusick FREE((caddr_t)rbuf, M_TEMP); 130638418Smckusick return (0); 130738418Smckusick } 130838418Smckusick } 130940115Smckusick 131038418Smckusick /* 131138418Smckusick * Check for degenerate cases of nothing useful read. 131240115Smckusick * If so go try again 131338418Smckusick */ 131440115Smckusick cpos = rbuf + on; 131540115Smckusick cend = rbuf + siz; 131652441Smckusick dp = (struct dirent *)cpos; 131752441Smckusick while (cpos < cend && dp->d_fileno == 0) { 131840115Smckusick cpos += dp->d_reclen; 131952441Smckusick dp = (struct dirent *)cpos; 132040115Smckusick } 132140115Smckusick if (cpos >= cend) { 132238418Smckusick toff = off; 132338418Smckusick siz = fullsiz; 132438418Smckusick on = 0; 132538418Smckusick goto again; 132638418Smckusick } 132740115Smckusick 132840115Smckusick cpos = rbuf + on; 132940115Smckusick cend = rbuf + siz; 133052441Smckusick dp = (struct dirent *)cpos; 133152196Smckusick len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 133252196Smckusick nfsm_reply(siz); 133352196Smckusick mp = mp2 = mb; 133452196Smckusick bp = bpos; 133552196Smckusick be = bp + M_TRAILINGSPACE(mp); 133652196Smckusick 133752196Smckusick /* Loop through the records and build reply */ 133852196Smckusick while (cpos < cend) { 133952441Smckusick if (dp->d_fileno != 0) { 134052196Smckusick nlen = dp->d_namlen; 134152196Smckusick rem = nfsm_rndup(nlen)-nlen; 134252196Smckusick len += (4*NFSX_UNSIGNED + nlen + rem); 134352196Smckusick if (len > cnt) { 134452196Smckusick eofflag = 0; 134552196Smckusick break; 134652196Smckusick } 134752441Smckusick /* 134852441Smckusick * Build the directory record xdr from 134952441Smckusick * the dirent entry. 135052441Smckusick */ 135152196Smckusick nfsm_clget; 135252196Smckusick *tl = nfs_true; 135352196Smckusick bp += NFSX_UNSIGNED; 135452196Smckusick nfsm_clget; 135552441Smckusick *tl = txdr_unsigned(dp->d_fileno); 135652196Smckusick bp += NFSX_UNSIGNED; 135752196Smckusick nfsm_clget; 135852196Smckusick *tl = txdr_unsigned(nlen); 135952196Smckusick bp += NFSX_UNSIGNED; 136052196Smckusick 136152196Smckusick /* And loop around copying the name */ 136252196Smckusick xfer = nlen; 136352196Smckusick cp = dp->d_name; 136452196Smckusick while (xfer > 0) { 136552196Smckusick nfsm_clget; 136652196Smckusick if ((bp+xfer) > be) 136752196Smckusick tsiz = be-bp; 136852196Smckusick else 136952196Smckusick tsiz = xfer; 137052196Smckusick bcopy(cp, bp, tsiz); 137152196Smckusick bp += tsiz; 137252196Smckusick xfer -= tsiz; 137352196Smckusick if (xfer > 0) 137452196Smckusick cp += tsiz; 137552196Smckusick } 137652196Smckusick /* And null pad to a long boundary */ 137752196Smckusick for (i = 0; i < rem; i++) 137852196Smckusick *bp++ = '\0'; 137952196Smckusick nfsm_clget; 138052196Smckusick 138152196Smckusick /* Finish off the record */ 138252196Smckusick toff += dp->d_reclen; 138352196Smckusick *tl = txdr_unsigned(toff); 138452196Smckusick bp += NFSX_UNSIGNED; 138552196Smckusick } else 138652196Smckusick toff += dp->d_reclen; 138752196Smckusick cpos += dp->d_reclen; 138852441Smckusick dp = (struct dirent *)cpos; 138952196Smckusick } 139038418Smckusick vrele(vp); 139152196Smckusick nfsm_clget; 139252196Smckusick *tl = nfs_false; 139352196Smckusick bp += NFSX_UNSIGNED; 139452196Smckusick nfsm_clget; 139552196Smckusick if (eofflag) 139652196Smckusick *tl = nfs_true; 139752196Smckusick else 139852196Smckusick *tl = nfs_false; 139952196Smckusick bp += NFSX_UNSIGNED; 140052196Smckusick if (mp != mb) { 140152196Smckusick if (bp < be) 140252196Smckusick mp->m_len = bp - mtod(mp, caddr_t); 140352196Smckusick } else 140452196Smckusick mp->m_len += bp - bpos; 140552196Smckusick FREE(rbuf, M_TEMP); 140652196Smckusick nfsm_srvdone; 140752196Smckusick } 140852196Smckusick 140952196Smckusick nqnfsrv_readdirlook(nfsd, mrep, md, dpos, cred, nam, mrq) 141052196Smckusick struct nfsd *nfsd; 141152196Smckusick struct mbuf *mrep, *md; 141252196Smckusick caddr_t dpos; 141352196Smckusick struct ucred *cred; 141452196Smckusick struct mbuf *nam, **mrq; 141552196Smckusick { 141652196Smckusick register char *bp, *be; 141752196Smckusick register struct mbuf *mp; 141852441Smckusick register struct dirent *dp; 141952196Smckusick register caddr_t cp; 142052196Smckusick register u_long *tl; 142152196Smckusick register long t1; 142252196Smckusick caddr_t bpos; 142352196Smckusick struct mbuf *mb, *mb2, *mreq, *mp2; 142452196Smckusick char *cpos, *cend, *cp2, *rbuf; 142552196Smckusick struct vnode *vp, *nvp; 142652196Smckusick struct flrep fl; 142752196Smckusick struct ufid *ufp = (struct ufid *)&fl.fl_nfh.fh_generic.fh_fid; 142852196Smckusick struct mount *mntp; 142952196Smckusick nfsv2fh_t nfh; 143052196Smckusick fhandle_t *fhp; 143152196Smckusick struct uio io; 143252196Smckusick struct iovec iv; 143352196Smckusick struct vattr va, *vap = &va; 143452196Smckusick struct nfsv2_fattr *fp; 143552196Smckusick int len, nlen, rem, xfer, tsiz, i, error = 0, duration2, cache2; 143652196Smckusick int siz, cnt, fullsiz, eofflag, rdonly, cache; 143752196Smckusick u_quad_t frev, frev2; 143852196Smckusick u_long on; 143952196Smckusick off_t off, toff; 144052196Smckusick 144152196Smckusick fhp = &nfh.fh_generic; 144252196Smckusick nfsm_srvmtofh(fhp); 144352196Smckusick nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED); 144452196Smckusick toff = fxdr_unsigned(off_t, *tl++); 144552196Smckusick off = (toff & ~(NFS_DIRBLKSIZ-1)); 144652196Smckusick on = (toff & (NFS_DIRBLKSIZ-1)); 144752196Smckusick cnt = fxdr_unsigned(int, *tl++); 144852196Smckusick duration2 = fxdr_unsigned(int, *tl); 144952196Smckusick siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); 145052196Smckusick if (cnt > NFS_MAXREADDIR) 145152196Smckusick siz = NFS_MAXREADDIR; 145252196Smckusick fullsiz = siz; 145352196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 145452196Smckusick nfsm_reply(0); 145552196Smckusick nqsrv_getl(vp, NQL_READ); 145652196Smckusick if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { 145752196Smckusick vput(vp); 145852196Smckusick nfsm_reply(0); 145952196Smckusick } 146052196Smckusick VOP_UNLOCK(vp); 146152196Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 146252196Smckusick again: 146352196Smckusick iv.iov_base = rbuf; 146452196Smckusick iv.iov_len = fullsiz; 146552196Smckusick io.uio_iov = &iv; 146652196Smckusick io.uio_iovcnt = 1; 146752196Smckusick io.uio_offset = off; 146852196Smckusick io.uio_resid = fullsiz; 146952196Smckusick io.uio_segflg = UIO_SYSSPACE; 147052196Smckusick io.uio_rw = UIO_READ; 147152196Smckusick io.uio_procp = (struct proc *)0; 147252196Smckusick error = VOP_READDIR(vp, &io, cred, &eofflag); 147352196Smckusick off = io.uio_offset; 147452196Smckusick if (error) { 147552196Smckusick vrele(vp); 147652196Smckusick free((caddr_t)rbuf, M_TEMP); 147752196Smckusick nfsm_reply(0); 147852196Smckusick } 147952196Smckusick if (io.uio_resid) { 148052196Smckusick siz -= io.uio_resid; 148152196Smckusick 148252196Smckusick /* 148352196Smckusick * If nothing read, return eof 148452196Smckusick * rpc reply 148552196Smckusick */ 148652196Smckusick if (siz == 0) { 148752196Smckusick vrele(vp); 148852196Smckusick nfsm_reply(2*NFSX_UNSIGNED); 148952196Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 149052196Smckusick *tl++ = nfs_false; 149152196Smckusick *tl = nfs_true; 149252196Smckusick FREE((caddr_t)rbuf, M_TEMP); 149352196Smckusick return (0); 149452196Smckusick } 149552196Smckusick } 149652196Smckusick 149752196Smckusick /* 149852196Smckusick * Check for degenerate cases of nothing useful read. 149952196Smckusick * If so go try again 150052196Smckusick */ 150152196Smckusick cpos = rbuf + on; 150252196Smckusick cend = rbuf + siz; 150352441Smckusick dp = (struct dirent *)cpos; 150452441Smckusick while (cpos < cend && dp->d_fileno == 0) { 150552196Smckusick cpos += dp->d_reclen; 150652441Smckusick dp = (struct dirent *)cpos; 150752196Smckusick } 150852196Smckusick if (cpos >= cend) { 150952196Smckusick toff = off; 151052196Smckusick siz = fullsiz; 151152196Smckusick on = 0; 151252196Smckusick goto again; 151352196Smckusick } 151452196Smckusick 151552196Smckusick cpos = rbuf + on; 151652196Smckusick cend = rbuf + siz; 151752441Smckusick dp = (struct dirent *)cpos; 151838425Smckusick len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 151938418Smckusick nfsm_reply(siz); 152052196Smckusick mp = mp2 = mb; 152152196Smckusick bp = bpos; 152252196Smckusick be = bp + M_TRAILINGSPACE(mp); 152352196Smckusick mntp = vp->v_mount; 152438418Smckusick 152538418Smckusick /* Loop through the records and build reply */ 152638418Smckusick while (cpos < cend) { 152752441Smckusick if (dp->d_fileno != 0) { 152838418Smckusick nlen = dp->d_namlen; 152938418Smckusick rem = nfsm_rndup(nlen)-nlen; 153038425Smckusick 153138418Smckusick /* 153252196Smckusick * For readdir_and_lookup get the vnode using 153352196Smckusick * the file number. 153438418Smckusick */ 153552196Smckusick bzero((caddr_t)&fl.fl_nfh, sizeof (nfsv2fh_t)); 153652196Smckusick ufp->ufid_len = sizeof (struct ufid); 153752441Smckusick ufp->ufid_ino = dp->d_fileno; 153852196Smckusick fl.fl_nfh.fh_generic.fh_fsid = mntp->mnt_stat.f_fsid; 153952196Smckusick if (VFS_FHTOVP(mntp, (struct fid *)ufp, 1, &nvp)) 154052196Smckusick goto invalid; 154152196Smckusick (void) nqsrv_getlease(nvp, &duration2, NQL_READ, nfsd, 154252196Smckusick nam, &cache2, &frev2, cred); 154352196Smckusick fl.fl_duration = txdr_unsigned(duration2); 154452196Smckusick fl.fl_cachable = txdr_unsigned(cache2); 154552196Smckusick txdr_hyper(&frev2, &fl.fl_frev); 154652196Smckusick if (VOP_GETATTR(nvp, vap, cred, nfsd->nd_procp)) { 154752196Smckusick vput(nvp); 154852196Smckusick goto invalid; 154952196Smckusick } 155052196Smckusick vput(nvp); 155152196Smckusick fp = &fl.fl_fattr; 155252196Smckusick nfsm_srvfillattr; 155352196Smckusick len += (4*NFSX_UNSIGNED + nlen + rem + NFSX_FH 155452196Smckusick + NFSX_FATTR); 155541899Smckusick if (len > cnt) { 155641899Smckusick eofflag = 0; 155738418Smckusick break; 155841899Smckusick } 155952441Smckusick /* 156052441Smckusick * Build the directory record xdr from 156152441Smckusick * the dirent entry. 156252441Smckusick */ 156338418Smckusick nfsm_clget; 156448050Smckusick *tl = nfs_true; 156538418Smckusick bp += NFSX_UNSIGNED; 156652196Smckusick 156752196Smckusick /* 156852196Smckusick * For readdir_and_lookup copy the stuff out. 156952196Smckusick */ 157052196Smckusick xfer = sizeof (struct flrep); 157152196Smckusick cp = (caddr_t)&fl; 157252196Smckusick while (xfer > 0) { 157352196Smckusick nfsm_clget; 157452196Smckusick if ((bp+xfer) > be) 157552196Smckusick tsiz = be-bp; 157652196Smckusick else 157752196Smckusick tsiz = xfer; 157852196Smckusick bcopy(cp, bp, tsiz); 157952196Smckusick bp += tsiz; 158052196Smckusick xfer -= tsiz; 158152196Smckusick if (xfer > 0) 158252196Smckusick cp += tsiz; 158352196Smckusick } 158438418Smckusick nfsm_clget; 158552441Smckusick *tl = txdr_unsigned(dp->d_fileno); 158638418Smckusick bp += NFSX_UNSIGNED; 158738418Smckusick nfsm_clget; 158848050Smckusick *tl = txdr_unsigned(nlen); 158938418Smckusick bp += NFSX_UNSIGNED; 159038425Smckusick 159152196Smckusick /* And loop around copying the name */ 159238418Smckusick xfer = nlen; 159338418Smckusick cp = dp->d_name; 159438418Smckusick while (xfer > 0) { 159538418Smckusick nfsm_clget; 159638418Smckusick if ((bp+xfer) > be) 159738418Smckusick tsiz = be-bp; 159838418Smckusick else 159938418Smckusick tsiz = xfer; 160038418Smckusick bcopy(cp, bp, tsiz); 160138418Smckusick bp += tsiz; 160238418Smckusick xfer -= tsiz; 160338418Smckusick if (xfer > 0) 160438418Smckusick cp += tsiz; 160538418Smckusick } 160638418Smckusick /* And null pad to a long boundary */ 160738418Smckusick for (i = 0; i < rem; i++) 160838418Smckusick *bp++ = '\0'; 160938418Smckusick nfsm_clget; 161038425Smckusick 161138418Smckusick /* Finish off the record */ 161238418Smckusick toff += dp->d_reclen; 161348050Smckusick *tl = txdr_unsigned(toff); 161438418Smckusick bp += NFSX_UNSIGNED; 161538418Smckusick } else 161652196Smckusick invalid: 161738418Smckusick toff += dp->d_reclen; 161838418Smckusick cpos += dp->d_reclen; 161952441Smckusick dp = (struct dirent *)cpos; 162038418Smckusick } 162152196Smckusick vrele(vp); 162238418Smckusick nfsm_clget; 162348050Smckusick *tl = nfs_false; 162438418Smckusick bp += NFSX_UNSIGNED; 162538418Smckusick nfsm_clget; 162640296Smckusick if (eofflag) 162748050Smckusick *tl = nfs_true; 162840296Smckusick else 162948050Smckusick *tl = nfs_false; 163038418Smckusick bp += NFSX_UNSIGNED; 163152196Smckusick if (mp != mb) { 163252196Smckusick if (bp < be) 163352196Smckusick mp->m_len = bp - mtod(mp, caddr_t); 163452196Smckusick } else 163552196Smckusick mp->m_len += bp - bpos; 163638418Smckusick FREE(rbuf, M_TEMP); 163738418Smckusick nfsm_srvdone; 163838418Smckusick } 163938418Smckusick 164038418Smckusick /* 164138418Smckusick * nfs statfs service 164238418Smckusick */ 164352196Smckusick nfsrv_statfs(nfsd, mrep, md, dpos, cred, nam, mrq) 164452196Smckusick struct nfsd *nfsd; 164538418Smckusick struct mbuf *mrep, *md; 164638418Smckusick caddr_t dpos; 164738418Smckusick struct ucred *cred; 164852196Smckusick struct mbuf *nam, **mrq; 164938418Smckusick { 165038418Smckusick register struct statfs *sf; 165138884Smacklem register struct nfsv2_statfs *sfp; 165248050Smckusick register u_long *tl; 165339494Smckusick register long t1; 165439494Smckusick caddr_t bpos; 165552196Smckusick int error = 0, rdonly, cache; 165639494Smckusick char *cp2; 165739753Smckusick struct mbuf *mb, *mb2, *mreq; 165838418Smckusick struct vnode *vp; 165938418Smckusick nfsv2fh_t nfh; 166038418Smckusick fhandle_t *fhp; 166138418Smckusick struct statfs statfs; 166252196Smckusick u_quad_t frev; 166338418Smckusick 166438418Smckusick fhp = &nfh.fh_generic; 166538418Smckusick nfsm_srvmtofh(fhp); 166652196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 166738418Smckusick nfsm_reply(0); 166838418Smckusick sf = &statfs; 166952196Smckusick error = VFS_STATFS(vp->v_mount, sf, nfsd->nd_procp); 167038418Smckusick vput(vp); 167138418Smckusick nfsm_reply(NFSX_STATFS); 167238884Smacklem nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS); 167344993Sbostic sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA); 167451940Smckusick sfp->sf_bsize = txdr_unsigned(sf->f_bsize); 167538884Smacklem sfp->sf_blocks = txdr_unsigned(sf->f_blocks); 167638884Smacklem sfp->sf_bfree = txdr_unsigned(sf->f_bfree); 167738884Smacklem sfp->sf_bavail = txdr_unsigned(sf->f_bavail); 167838418Smckusick nfsm_srvdone; 167938418Smckusick } 168038418Smckusick 168138418Smckusick /* 168238418Smckusick * Null operation, used by clients to ping server 168338418Smckusick */ 168439494Smckusick /* ARGSUSED */ 168552196Smckusick nfsrv_null(nfsd, mrep, md, dpos, cred, nam, mrq) 168652196Smckusick struct nfsd *nfsd; 168738418Smckusick struct mbuf *mrep, *md; 168838418Smckusick caddr_t dpos; 168938418Smckusick struct ucred *cred; 169052196Smckusick struct mbuf *nam, **mrq; 169138418Smckusick { 169239494Smckusick caddr_t bpos; 169352196Smckusick int error = VNOVAL, cache; 169439753Smckusick struct mbuf *mb, *mreq; 169552196Smckusick u_quad_t frev; 169638418Smckusick 169738418Smckusick nfsm_reply(0); 169839494Smckusick return (error); 169938418Smckusick } 170038418Smckusick 170138418Smckusick /* 170238418Smckusick * No operation, used for obsolete procedures 170338418Smckusick */ 170439494Smckusick /* ARGSUSED */ 170552196Smckusick nfsrv_noop(nfsd, mrep, md, dpos, cred, nam, mrq) 170652196Smckusick struct nfsd *nfsd; 170738418Smckusick struct mbuf *mrep, *md; 170838418Smckusick caddr_t dpos; 170938418Smckusick struct ucred *cred; 171052196Smckusick struct mbuf *nam, **mrq; 171138418Smckusick { 171239494Smckusick caddr_t bpos; 171352196Smckusick int error, cache; 171439753Smckusick struct mbuf *mb, *mreq; 171552196Smckusick u_quad_t frev; 171638418Smckusick 171752196Smckusick if (nfsd->nd_repstat) 171852196Smckusick error = nfsd->nd_repstat; 171952196Smckusick else 172052196Smckusick error = EPROCUNAVAIL; 172138418Smckusick nfsm_reply(0); 172239494Smckusick return (error); 172338418Smckusick } 172438425Smckusick 172538450Smckusick /* 172638450Smckusick * Perform access checking for vnodes obtained from file handles that would 172738450Smckusick * refer to files already opened by a Unix client. You cannot just use 172838450Smckusick * vn_writechk() and VOP_ACCESS() for two reasons. 172952196Smckusick * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case 173038450Smckusick * 2 - The owner is to be given access irrespective of mode bits so that 173138450Smckusick * processes that chmod after opening a file don't break. I don't like 173238450Smckusick * this because it opens a security hole, but since the nfs server opens 173338450Smckusick * a security hole the size of a barn door anyhow, what the heck. 173438450Smckusick */ 173552196Smckusick nfsrv_access(vp, flags, cred, rdonly, p) 173638450Smckusick register struct vnode *vp; 173738450Smckusick int flags; 173838450Smckusick register struct ucred *cred; 173952196Smckusick int rdonly; 174048050Smckusick struct proc *p; 174138450Smckusick { 174238450Smckusick struct vattr vattr; 174338450Smckusick int error; 174438450Smckusick if (flags & VWRITE) { 174552196Smckusick /* Just vn_writechk() changed to check rdonly */ 174638450Smckusick /* 174738450Smckusick * Disallow write attempts on read-only file systems; 174838450Smckusick * unless the file is a socket or a block or character 174938450Smckusick * device resident on the file system. 175038450Smckusick */ 175152196Smckusick if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { 175245059Smckusick switch (vp->v_type) { 175345059Smckusick case VREG: case VDIR: case VLNK: 175438450Smckusick return (EROFS); 175545059Smckusick } 175645059Smckusick } 175738450Smckusick /* 175838450Smckusick * If there's shared text associated with 175938450Smckusick * the inode, try to free it up once. If 176038450Smckusick * we fail, we can't allow writing. 176138450Smckusick */ 176245715Smckusick if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) 176338450Smckusick return (ETXTBSY); 176438450Smckusick } 176548050Smckusick if (error = VOP_GETATTR(vp, &vattr, cred, p)) 176645059Smckusick return (error); 176748050Smckusick if ((error = VOP_ACCESS(vp, flags, cred, p)) && 176845059Smckusick cred->cr_uid != vattr.va_uid) 176945059Smckusick return (error); 177045059Smckusick return (0); 177138450Smckusick } 1772