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*54106Smckusick * @(#)nfs_serv.c 7.52 (Berkeley) 06/19/92 1138418Smckusick */ 1238418Smckusick 1338418Smckusick /* 1438418Smckusick * nfs version 2 server calls to vnode ops 1538418Smckusick * - these routines generally have 3 phases 1638418Smckusick * 1 - break down and validate rpc request in mbuf list 1738418Smckusick * 2 - do the vnode ops for the request 1838425Smckusick * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c) 1938418Smckusick * 3 - build the rpc reply in an mbuf list 2038418Smckusick * nb: 2138418Smckusick * - do not mix the phases, since the nfsm_?? macros can return failures 2241899Smckusick * on a bad rpc or similar and do not do any vrele() or vput()'s 2338418Smckusick * 2438425Smckusick * - the nfsm_reply() macro generates an nfs rpc reply with the nfs 2538418Smckusick * error number iff error != 0 whereas 2641899Smckusick * returning an error from the server function implies a fatal error 2741899Smckusick * such as a badly constructed rpc request that should be dropped without 2841899Smckusick * a reply. 2938418Smckusick */ 3038418Smckusick 3153322Smckusick #include <sys/param.h> 3253322Smckusick #include <sys/proc.h> 3353322Smckusick #include <sys/file.h> 3453322Smckusick #include <sys/namei.h> 3553322Smckusick #include <sys/vnode.h> 3653322Smckusick #include <sys/mount.h> 3753322Smckusick #include <sys/mbuf.h> 3853322Smckusick #include <sys/dirent.h> 3947573Skarels 4053322Smckusick #include <vm/vm.h> 4147573Skarels 4253322Smckusick #include <ufs/ufs/quota.h> /* XXX - for ufid */ 4353322Smckusick #include <ufs/ufs/inode.h> /* XXX - for ufid */ 4438418Smckusick 4553322Smckusick #include <nfs/nfsv2.h> 4653322Smckusick #include <nfs/rpcv2.h> 4753322Smckusick #include <nfs/nfs.h> 4853322Smckusick #include <nfs/xdr_subs.h> 4953322Smckusick #include <nfs/nfsm_subs.h> 5053322Smckusick #include <nfs/nqnfs.h> 5153322Smckusick 5238418Smckusick /* Defs */ 5338425Smckusick #define TRUE 1 5438425Smckusick #define FALSE 0 5538418Smckusick 5638418Smckusick /* Global vars */ 5738418Smckusick extern u_long nfs_procids[NFS_NPROCS]; 5838418Smckusick extern u_long nfs_xdrneg1; 5938418Smckusick extern u_long nfs_false, nfs_true; 6052196Smckusick nfstype nfs_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, 6142242Smckusick NFCHR, NFNON }; 6238418Smckusick 6338418Smckusick /* 6438418Smckusick * nfs getattr service 6538418Smckusick */ 6652196Smckusick nfsrv_getattr(nfsd, mrep, md, dpos, cred, nam, mrq) 6752196Smckusick struct nfsd *nfsd; 6838418Smckusick struct mbuf *mrep, *md; 6938418Smckusick caddr_t dpos; 7038418Smckusick struct ucred *cred; 7152196Smckusick struct mbuf *nam, **mrq; 7238418Smckusick { 7353552Sheideman USES_VOP_GETATTR; 7438884Smacklem register struct nfsv2_fattr *fp; 7538418Smckusick struct vattr va; 7638418Smckusick register struct vattr *vap = &va; 7738418Smckusick struct vnode *vp; 7838418Smckusick nfsv2fh_t nfh; 7938418Smckusick fhandle_t *fhp; 8048050Smckusick register u_long *tl; 8139494Smckusick register long t1; 8239494Smckusick caddr_t bpos; 8352196Smckusick int error = 0, rdonly, cache; 8439494Smckusick char *cp2; 8539753Smckusick struct mbuf *mb, *mb2, *mreq; 8652196Smckusick u_quad_t frev; 8738418Smckusick 8838418Smckusick fhp = &nfh.fh_generic; 8938418Smckusick nfsm_srvmtofh(fhp); 9052196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 9138418Smckusick nfsm_reply(0); 9252196Smckusick nqsrv_getl(vp, NQL_READ); 9352196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 9438418Smckusick vput(vp); 9538418Smckusick nfsm_reply(NFSX_FATTR); 9638884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 9739753Smckusick nfsm_srvfillattr; 9838418Smckusick nfsm_srvdone; 9938418Smckusick } 10038418Smckusick 10138418Smckusick /* 10238418Smckusick * nfs setattr service 10338418Smckusick */ 10452196Smckusick nfsrv_setattr(nfsd, mrep, md, dpos, cred, nam, mrq) 10552196Smckusick struct nfsd *nfsd; 10638418Smckusick struct mbuf *mrep, *md; 10738418Smckusick caddr_t dpos; 10838418Smckusick struct ucred *cred; 10952196Smckusick struct mbuf *nam, **mrq; 11038418Smckusick { 11153552Sheideman USES_VOP_GETATTR; 11253552Sheideman USES_VOP_SETATTR; 11338418Smckusick struct vattr va; 11438418Smckusick register struct vattr *vap = &va; 11538884Smacklem register struct nfsv2_sattr *sp; 11638884Smacklem register struct nfsv2_fattr *fp; 11738418Smckusick struct vnode *vp; 11838418Smckusick nfsv2fh_t nfh; 11938418Smckusick fhandle_t *fhp; 12048050Smckusick register u_long *tl; 12139494Smckusick register long t1; 12239494Smckusick caddr_t bpos; 12352196Smckusick int error = 0, rdonly, cache, duration2, cache2; 12439494Smckusick char *cp2; 12539753Smckusick struct mbuf *mb, *mb2, *mreq; 12652196Smckusick u_quad_t frev, frev2; 12738418Smckusick 12838418Smckusick fhp = &nfh.fh_generic; 12938418Smckusick nfsm_srvmtofh(fhp); 13052196Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR); 13152196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 13238418Smckusick nfsm_reply(0); 13352196Smckusick nqsrv_getl(vp, NQL_WRITE); 13452196Smckusick if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) 13538418Smckusick goto out; 13641361Smckusick VATTR_NULL(vap); 13738418Smckusick /* 13838418Smckusick * Nah nah nah nah na nah 13938418Smckusick * There is a bug in the Sun client that puts 0xffff in the mode 14038418Smckusick * field of sattr when it should put in 0xffffffff. The u_short 14138418Smckusick * doesn't sign extend. 14238418Smckusick * --> check the low order 2 bytes for 0xffff 14338418Smckusick */ 14438884Smacklem if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff) 14538884Smacklem vap->va_mode = nfstov_mode(sp->sa_mode); 14638884Smacklem if (sp->sa_uid != nfs_xdrneg1) 14738884Smacklem vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid); 14838884Smacklem if (sp->sa_gid != nfs_xdrneg1) 14938884Smacklem vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid); 15039753Smckusick if (sp->sa_size != nfs_xdrneg1) 15138884Smacklem vap->va_size = fxdr_unsigned(u_long, sp->sa_size); 15239753Smckusick /* 15339753Smckusick * The usec field of sa_atime is overloaded with the va_flags field 15439753Smckusick * for 4.4BSD clients. Hopefully other clients always set both the 15539753Smckusick * sec and usec fields to -1 when not setting the atime. 15639753Smckusick */ 15739753Smckusick if (sp->sa_atime.tv_sec != nfs_xdrneg1) { 158*54106Smckusick vap->va_atime.ts_sec = fxdr_unsigned(long, sp->sa_atime.tv_sec); 159*54106Smckusick vap->va_atime.ts_nsec = 0; 16038425Smckusick } 16139753Smckusick if (sp->sa_atime.tv_usec != nfs_xdrneg1) 16239753Smckusick vap->va_flags = fxdr_unsigned(u_long, sp->sa_atime.tv_usec); 16338884Smacklem if (sp->sa_mtime.tv_sec != nfs_xdrneg1) 16438884Smacklem fxdr_time(&sp->sa_mtime, &vap->va_mtime); 16552196Smckusick if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) { 16638418Smckusick vput(vp); 16738418Smckusick nfsm_reply(0); 16838418Smckusick } 16952196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 17038418Smckusick out: 17138418Smckusick vput(vp); 17252196Smckusick nfsm_reply(NFSX_FATTR + 2*NFSX_UNSIGNED); 17338884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 17439753Smckusick nfsm_srvfillattr; 17552196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 17652196Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 17752196Smckusick txdr_hyper(&frev2, tl); 17852196Smckusick } 17938418Smckusick nfsm_srvdone; 18038418Smckusick } 18138418Smckusick 18238418Smckusick /* 18338418Smckusick * nfs lookup rpc 18438418Smckusick */ 18552196Smckusick nfsrv_lookup(nfsd, mrep, md, dpos, cred, nam, mrq) 18652196Smckusick struct nfsd *nfsd; 18738418Smckusick struct mbuf *mrep, *md; 18838418Smckusick caddr_t dpos; 18938418Smckusick struct ucred *cred; 19052196Smckusick struct mbuf *nam, **mrq; 19138418Smckusick { 19253552Sheideman USES_VOP_GETATTR; 19338884Smacklem register struct nfsv2_fattr *fp; 19449742Smckusick struct nameidata nd; 19538418Smckusick struct vnode *vp; 19638418Smckusick nfsv2fh_t nfh; 19738418Smckusick fhandle_t *fhp; 19839494Smckusick register caddr_t cp; 19948050Smckusick register u_long *tl; 20039494Smckusick register long t1; 20139494Smckusick caddr_t bpos; 20252196Smckusick int error = 0, lflag = 0, rdonly, cache, duration2, cache2, len; 20339494Smckusick char *cp2; 20439753Smckusick struct mbuf *mb, *mb2, *mreq; 20538418Smckusick struct vattr va, *vap = &va; 20652196Smckusick u_quad_t frev, frev2; 20738418Smckusick 20838418Smckusick fhp = &nfh.fh_generic; 20952196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 21052196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 21152196Smckusick if (*tl) { 21252196Smckusick lflag = fxdr_unsigned(int, *tl); 21352196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 21452196Smckusick duration2 = fxdr_unsigned(int, *tl); 21552196Smckusick } 21652196Smckusick } 21738418Smckusick nfsm_srvmtofh(fhp); 21838418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 21952316Sheideman nd.ni_cnd.cn_cred = cred; 22052316Sheideman nd.ni_cnd.cn_nameiop = LOOKUP; 22152316Sheideman nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART; 22252653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 22352653Smckusick nfsd->nd_procp)) 22438418Smckusick nfsm_reply(0); 22552196Smckusick nqsrv_getl(nd.ni_startdir, NQL_READ); 22652196Smckusick vrele(nd.ni_startdir); 22752653Smckusick FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 22849742Smckusick vp = nd.ni_vp; 22938418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 23041398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 23138418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 23238418Smckusick vput(vp); 23338418Smckusick nfsm_reply(0); 23438418Smckusick } 23552196Smckusick if (lflag) 23652196Smckusick (void) nqsrv_getlease(vp, &duration2, lflag, nfsd, 23752196Smckusick nam, &cache2, &frev2, cred); 23852196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 23938418Smckusick vput(vp); 24052196Smckusick nfsm_reply(NFSX_FH + NFSX_FATTR + 5*NFSX_UNSIGNED); 24152196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 24252196Smckusick if (lflag) { 24352196Smckusick nfsm_build(tl, u_long *, 5*NFSX_UNSIGNED); 24452196Smckusick *tl++ = txdr_unsigned(lflag); 24552196Smckusick *tl++ = txdr_unsigned(cache2); 24652196Smckusick *tl++ = txdr_unsigned(duration2); 24752196Smckusick txdr_hyper(&frev2, tl); 24852196Smckusick } else { 24952196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 25052196Smckusick *tl = 0; 25152196Smckusick } 25252196Smckusick } 25338418Smckusick nfsm_srvfhtom(fhp); 25438884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 25539753Smckusick nfsm_srvfillattr; 25638418Smckusick nfsm_srvdone; 25738418Smckusick } 25838418Smckusick 25938418Smckusick /* 26038418Smckusick * nfs readlink service 26138418Smckusick */ 26252196Smckusick nfsrv_readlink(nfsd, mrep, md, dpos, cred, nam, mrq) 26352196Smckusick struct nfsd *nfsd; 26438418Smckusick struct mbuf *mrep, *md; 26538418Smckusick caddr_t dpos; 26638418Smckusick struct ucred *cred; 26752196Smckusick struct mbuf *nam, **mrq; 26838418Smckusick { 26953552Sheideman USES_VOP_READLINK; 27041899Smckusick struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN]; 27138418Smckusick register struct iovec *ivp = iv; 27238418Smckusick register struct mbuf *mp; 27348050Smckusick register u_long *tl; 27439494Smckusick register long t1; 27539494Smckusick caddr_t bpos; 27652196Smckusick int error = 0, rdonly, cache, i, tlen, len; 27739494Smckusick char *cp2; 27839753Smckusick struct mbuf *mb, *mb2, *mp2, *mp3, *mreq; 27938418Smckusick struct vnode *vp; 28038418Smckusick nfsv2fh_t nfh; 28138418Smckusick fhandle_t *fhp; 28238418Smckusick struct uio io, *uiop = &io; 28352196Smckusick u_quad_t frev; 28438418Smckusick 28538418Smckusick fhp = &nfh.fh_generic; 28638418Smckusick nfsm_srvmtofh(fhp); 28738418Smckusick len = 0; 28838418Smckusick i = 0; 28938418Smckusick while (len < NFS_MAXPATHLEN) { 29038418Smckusick MGET(mp, M_WAIT, MT_DATA); 29141899Smckusick MCLGET(mp, M_WAIT); 29238418Smckusick mp->m_len = NFSMSIZ(mp); 29338418Smckusick if (len == 0) 29438418Smckusick mp3 = mp2 = mp; 29541899Smckusick else { 29638418Smckusick mp2->m_next = mp; 29741899Smckusick mp2 = mp; 29841899Smckusick } 29938418Smckusick if ((len+mp->m_len) > NFS_MAXPATHLEN) { 30038418Smckusick mp->m_len = NFS_MAXPATHLEN-len; 30138418Smckusick len = NFS_MAXPATHLEN; 30238418Smckusick } else 30338418Smckusick len += mp->m_len; 30438418Smckusick ivp->iov_base = mtod(mp, caddr_t); 30538418Smckusick ivp->iov_len = mp->m_len; 30638418Smckusick i++; 30738418Smckusick ivp++; 30838418Smckusick } 30938418Smckusick uiop->uio_iov = iv; 31038418Smckusick uiop->uio_iovcnt = i; 31138418Smckusick uiop->uio_offset = 0; 31238418Smckusick uiop->uio_resid = len; 31338418Smckusick uiop->uio_rw = UIO_READ; 31438418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 31548050Smckusick uiop->uio_procp = (struct proc *)0; 31652196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) { 31738418Smckusick m_freem(mp3); 31838418Smckusick nfsm_reply(0); 31938418Smckusick } 32038418Smckusick if (vp->v_type != VLNK) { 32138418Smckusick error = EINVAL; 32238418Smckusick goto out; 32338418Smckusick } 32452196Smckusick nqsrv_getl(vp, NQL_READ); 32538418Smckusick error = VOP_READLINK(vp, uiop, cred); 32638418Smckusick out: 32738418Smckusick vput(vp); 32838418Smckusick if (error) 32938418Smckusick m_freem(mp3); 33038418Smckusick nfsm_reply(NFSX_UNSIGNED); 33138418Smckusick if (uiop->uio_resid > 0) { 33238418Smckusick len -= uiop->uio_resid; 33338418Smckusick tlen = nfsm_rndup(len); 33438418Smckusick nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len); 33538418Smckusick } 33648050Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 33748050Smckusick *tl = txdr_unsigned(len); 33838418Smckusick mb->m_next = mp3; 33938418Smckusick nfsm_srvdone; 34038418Smckusick } 34138418Smckusick 34238418Smckusick /* 34338418Smckusick * nfs read service 34438418Smckusick */ 34552196Smckusick nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq) 34652196Smckusick struct nfsd *nfsd; 34738418Smckusick struct mbuf *mrep, *md; 34838418Smckusick caddr_t dpos; 34938418Smckusick struct ucred *cred; 35052196Smckusick struct mbuf *nam, **mrq; 35138418Smckusick { 35253552Sheideman USES_VOP_GETATTR; 35353552Sheideman USES_VOP_READ; 35443350Smckusick register struct iovec *iv; 35543350Smckusick struct iovec *iv2; 35641899Smckusick register struct mbuf *m; 35738884Smacklem register struct nfsv2_fattr *fp; 35848050Smckusick register u_long *tl; 35939494Smckusick register long t1; 36039494Smckusick caddr_t bpos; 36152196Smckusick int error = 0, rdonly, cache, i, cnt, len, left, siz, tlen; 36239494Smckusick char *cp2; 36339753Smckusick struct mbuf *mb, *mb2, *mreq; 36452196Smckusick struct mbuf *m2; 36538418Smckusick struct vnode *vp; 36638418Smckusick nfsv2fh_t nfh; 36738418Smckusick fhandle_t *fhp; 36838418Smckusick struct uio io, *uiop = &io; 36938418Smckusick struct vattr va, *vap = &va; 37038418Smckusick off_t off; 37152196Smckusick u_quad_t frev; 37238418Smckusick 37338418Smckusick fhp = &nfh.fh_generic; 37438418Smckusick nfsm_srvmtofh(fhp); 37552196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 37648050Smckusick off = fxdr_unsigned(off_t, *tl); 37738418Smckusick nfsm_srvstrsiz(cnt, NFS_MAXDATA); 37852196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 37938418Smckusick nfsm_reply(0); 38052196Smckusick nqsrv_getl(vp, NQL_READ); 38152196Smckusick if (error = nfsrv_access(vp, VREAD | VEXEC, cred, rdonly, nfsd->nd_procp)) { 38238418Smckusick vput(vp); 38338418Smckusick nfsm_reply(0); 38438418Smckusick } 38552196Smckusick if (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp)) { 38638418Smckusick vput(vp); 38738418Smckusick nfsm_reply(0); 38838418Smckusick } 38952196Smckusick if (off >= vap->va_size) 39052196Smckusick cnt = 0; 39152196Smckusick else if ((off + cnt) > vap->va_size) 39252196Smckusick cnt = nfsm_rndup(vap->va_size - off); 39352196Smckusick nfsm_reply(NFSX_FATTR+NFSX_UNSIGNED+nfsm_rndup(cnt)); 39452196Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 39552196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 39652196Smckusick len = left = cnt; 39752196Smckusick if (cnt > 0) { 39852196Smckusick /* 39952196Smckusick * Generate the mbuf list with the uio_iov ref. to it. 40052196Smckusick */ 40152196Smckusick i = 0; 40252196Smckusick m = m2 = mb; 40352196Smckusick MALLOC(iv, struct iovec *, 40452196Smckusick ((NFS_MAXDATA+MLEN-1)/MLEN) * sizeof (struct iovec), 40552196Smckusick M_TEMP, M_WAITOK); 40652196Smckusick iv2 = iv; 40752196Smckusick while (left > 0) { 40852196Smckusick siz = MIN(M_TRAILINGSPACE(m), left); 40952196Smckusick if (siz > 0) { 41052196Smckusick m->m_len += siz; 41152196Smckusick iv->iov_base = bpos; 41252196Smckusick iv->iov_len = siz; 41352196Smckusick iv++; 41452196Smckusick i++; 41552196Smckusick left -= siz; 41652196Smckusick } 41752196Smckusick if (left > 0) { 41852196Smckusick MGET(m, M_WAIT, MT_DATA); 41952196Smckusick MCLGET(m, M_WAIT); 42052196Smckusick m->m_len = 0; 42152196Smckusick m2->m_next = m; 42252196Smckusick m2 = m; 42352196Smckusick bpos = mtod(m, caddr_t); 42452196Smckusick } 42552196Smckusick } 42652196Smckusick uiop->uio_iov = iv2; 42752196Smckusick uiop->uio_iovcnt = i; 42852196Smckusick uiop->uio_offset = off; 42952196Smckusick uiop->uio_resid = cnt; 43052196Smckusick uiop->uio_rw = UIO_READ; 43152196Smckusick uiop->uio_segflg = UIO_SYSSPACE; 43252196Smckusick error = VOP_READ(vp, uiop, IO_NODELOCKED, cred); 43352196Smckusick off = uiop->uio_offset; 43452196Smckusick FREE((caddr_t)iv2, M_TEMP); 43552196Smckusick if (error || (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp))) { 43652196Smckusick m_freem(mreq); 43752196Smckusick vput(vp); 43852196Smckusick nfsm_reply(0); 43952196Smckusick } 44052196Smckusick } else 44152196Smckusick uiop->uio_resid = 0; 44238418Smckusick vput(vp); 44339753Smckusick nfsm_srvfillattr; 44445877Smckusick len -= uiop->uio_resid; 44552196Smckusick tlen = nfsm_rndup(len); 44652196Smckusick if (cnt != tlen || tlen != len) 44752196Smckusick nfsm_adj(mb, cnt-tlen, tlen-len); 44848050Smckusick *tl = txdr_unsigned(len); 44938418Smckusick nfsm_srvdone; 45038418Smckusick } 45138418Smckusick 45238418Smckusick /* 45338418Smckusick * nfs write service 45438418Smckusick */ 45552196Smckusick nfsrv_write(nfsd, mrep, md, dpos, cred, nam, mrq) 45652196Smckusick struct nfsd *nfsd; 45752196Smckusick struct mbuf *mrep, *md; 45838418Smckusick caddr_t dpos; 45938418Smckusick struct ucred *cred; 46052196Smckusick struct mbuf *nam, **mrq; 46138418Smckusick { 46253552Sheideman USES_VOP_GETATTR; 46353552Sheideman USES_VOP_WRITE; 46438418Smckusick register struct iovec *ivp; 46538418Smckusick register struct mbuf *mp; 46638884Smacklem register struct nfsv2_fattr *fp; 46741899Smckusick struct iovec iv[NFS_MAXIOVEC]; 46838418Smckusick struct vattr va; 46938418Smckusick register struct vattr *vap = &va; 47048050Smckusick register u_long *tl; 47139494Smckusick register long t1; 47239494Smckusick caddr_t bpos; 47352196Smckusick int error = 0, rdonly, cache, siz, len, xfer; 47439494Smckusick char *cp2; 47539753Smckusick struct mbuf *mb, *mb2, *mreq; 47638418Smckusick struct vnode *vp; 47738418Smckusick nfsv2fh_t nfh; 47838418Smckusick fhandle_t *fhp; 47938418Smckusick struct uio io, *uiop = &io; 48038418Smckusick off_t off; 48152196Smckusick u_quad_t frev; 48238418Smckusick 48338418Smckusick fhp = &nfh.fh_generic; 48438418Smckusick nfsm_srvmtofh(fhp); 48552196Smckusick nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); 48648050Smckusick off = fxdr_unsigned(off_t, *++tl); 48748050Smckusick tl += 2; 48848050Smckusick len = fxdr_unsigned(long, *tl); 48938418Smckusick if (len > NFS_MAXDATA || len <= 0) { 49038418Smckusick error = EBADRPC; 49138418Smckusick nfsm_reply(0); 49238418Smckusick } 49338418Smckusick if (dpos == (mtod(md, caddr_t)+md->m_len)) { 49438418Smckusick mp = md->m_next; 49538418Smckusick if (mp == NULL) { 49638418Smckusick error = EBADRPC; 49738418Smckusick nfsm_reply(0); 49838418Smckusick } 49938418Smckusick } else { 50038418Smckusick mp = md; 50138418Smckusick siz = dpos-mtod(mp, caddr_t); 50238418Smckusick mp->m_len -= siz; 50338418Smckusick NFSMADV(mp, siz); 50438418Smckusick } 50552196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 50638418Smckusick nfsm_reply(0); 50752196Smckusick nqsrv_getl(vp, NQL_WRITE); 50852196Smckusick if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) { 50938418Smckusick vput(vp); 51038418Smckusick nfsm_reply(0); 51138418Smckusick } 51238418Smckusick uiop->uio_resid = 0; 51338418Smckusick uiop->uio_rw = UIO_WRITE; 51438418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 51548050Smckusick uiop->uio_procp = (struct proc *)0; 51638418Smckusick /* 51741899Smckusick * Do up to NFS_MAXIOVEC mbufs of write each iteration of the 51838418Smckusick * loop until done. 51938418Smckusick */ 52038418Smckusick while (len > 0 && uiop->uio_resid == 0) { 52138418Smckusick ivp = iv; 52238418Smckusick siz = 0; 52338418Smckusick uiop->uio_iov = ivp; 52438418Smckusick uiop->uio_iovcnt = 0; 52538418Smckusick uiop->uio_offset = off; 52641899Smckusick while (len > 0 && uiop->uio_iovcnt < NFS_MAXIOVEC && mp != NULL) { 52738418Smckusick ivp->iov_base = mtod(mp, caddr_t); 52838418Smckusick if (len < mp->m_len) 52938418Smckusick ivp->iov_len = xfer = len; 53038418Smckusick else 53138418Smckusick ivp->iov_len = xfer = mp->m_len; 53238418Smckusick #ifdef notdef 53338418Smckusick /* Not Yet .. */ 53438418Smckusick if (M_HASCL(mp) && (((u_long)ivp->iov_base) & CLOFSET) == 0) 53538418Smckusick ivp->iov_op = NULL; /* what should it be ?? */ 53638418Smckusick else 53738418Smckusick ivp->iov_op = NULL; 53838418Smckusick #endif 53938418Smckusick uiop->uio_iovcnt++; 54038418Smckusick ivp++; 54138418Smckusick len -= xfer; 54238418Smckusick siz += xfer; 54338418Smckusick mp = mp->m_next; 54438418Smckusick } 54538418Smckusick if (len > 0 && mp == NULL) { 54638418Smckusick error = EBADRPC; 54738418Smckusick vput(vp); 54838418Smckusick nfsm_reply(0); 54938418Smckusick } 55038418Smckusick uiop->uio_resid = siz; 55139586Smckusick if (error = VOP_WRITE(vp, uiop, IO_SYNC | IO_NODELOCKED, 55238418Smckusick cred)) { 55338418Smckusick vput(vp); 55438418Smckusick nfsm_reply(0); 55538418Smckusick } 55639586Smckusick off = uiop->uio_offset; 55738418Smckusick } 55852196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 55938418Smckusick vput(vp); 56038418Smckusick nfsm_reply(NFSX_FATTR); 56138884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 56239753Smckusick nfsm_srvfillattr; 56352442Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 56452442Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 56552442Smckusick txdr_hyper(&vap->va_filerev, tl); 56652442Smckusick } 56738418Smckusick nfsm_srvdone; 56838418Smckusick } 56938418Smckusick 57038418Smckusick /* 57138418Smckusick * nfs create service 57238418Smckusick * now does a truncate to 0 length via. setattr if it already exists 57338418Smckusick */ 57452196Smckusick nfsrv_create(nfsd, mrep, md, dpos, cred, nam, mrq) 57552196Smckusick struct nfsd *nfsd; 57652196Smckusick struct mbuf *mrep, *md; 57738418Smckusick caddr_t dpos; 57838418Smckusick struct ucred *cred; 57952196Smckusick struct mbuf *nam, **mrq; 58038418Smckusick { 58153552Sheideman USES_VOP_ABORTOP; 58253552Sheideman USES_VOP_CREATE; 58353552Sheideman USES_VOP_GETATTR; 58453552Sheideman USES_VOP_MKNOD; 58553552Sheideman USES_VOP_SETATTR; 58638884Smacklem register struct nfsv2_fattr *fp; 58738418Smckusick struct vattr va; 58838418Smckusick register struct vattr *vap = &va; 58949742Smckusick struct nameidata nd; 59039494Smckusick register caddr_t cp; 59148050Smckusick register u_long *tl; 59239494Smckusick register long t1; 59339494Smckusick caddr_t bpos; 59452196Smckusick int error = 0, rdev, cache, len; 59539494Smckusick char *cp2; 59639753Smckusick struct mbuf *mb, *mb2, *mreq; 59738418Smckusick struct vnode *vp; 59838418Smckusick nfsv2fh_t nfh; 59938418Smckusick fhandle_t *fhp; 60052196Smckusick u_quad_t frev; 60138418Smckusick 60252316Sheideman nd.ni_cnd.cn_nameiop = 0; 60338418Smckusick fhp = &nfh.fh_generic; 60438418Smckusick nfsm_srvmtofh(fhp); 60538418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 60652316Sheideman nd.ni_cnd.cn_cred = cred; 60752316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 60852316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART; 60952653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 61052653Smckusick nfsd->nd_procp)) 61138418Smckusick nfsm_reply(0); 61241361Smckusick VATTR_NULL(vap); 61352196Smckusick nfsm_dissect(tl, u_long *, NFSX_SATTR); 61438418Smckusick /* 61538418Smckusick * Iff doesn't exist, create it 61638418Smckusick * otherwise just truncate to 0 length 61738418Smckusick * should I set the mode too ?? 61838418Smckusick */ 61949742Smckusick if (nd.ni_vp == NULL) { 62048050Smckusick vap->va_type = IFTOVT(fxdr_unsigned(u_long, *tl)); 62142867Smckusick if (vap->va_type == VNON) 62242867Smckusick vap->va_type = VREG; 62348050Smckusick vap->va_mode = nfstov_mode(*tl); 62448050Smckusick rdev = fxdr_unsigned(long, *(tl+3)); 62546988Smckusick if (vap->va_type == VREG || vap->va_type == VSOCK) { 62649742Smckusick vrele(nd.ni_startdir); 62752196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 62852234Sheideman if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) 62942242Smckusick nfsm_reply(0); 63052316Sheideman FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 63142242Smckusick } else if (vap->va_type == VCHR || vap->va_type == VBLK || 63242242Smckusick vap->va_type == VFIFO) { 63342242Smckusick if (vap->va_type == VCHR && rdev == 0xffffffff) 63442242Smckusick vap->va_type = VFIFO; 63542242Smckusick if (vap->va_type == VFIFO) { 63642242Smckusick #ifndef FIFO 63752234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 63849742Smckusick vput(nd.ni_dvp); 63942242Smckusick error = ENXIO; 64049742Smckusick goto out; 64142242Smckusick #endif /* FIFO */ 64252196Smckusick } else if (error = suser(cred, (u_short *)0)) { 64352234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 64449742Smckusick vput(nd.ni_dvp); 64549742Smckusick goto out; 64642242Smckusick } else 64742242Smckusick vap->va_rdev = (dev_t)rdev; 64852196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 64952234Sheideman if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) { 65049742Smckusick vrele(nd.ni_startdir); 65142242Smckusick nfsm_reply(0); 65249742Smckusick } 65352316Sheideman nd.ni_cnd.cn_nameiop = LOOKUP; 65452316Sheideman nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART); 65552316Sheideman nd.ni_cnd.cn_proc = nfsd->nd_procp; 65652316Sheideman nd.ni_cnd.cn_cred = nfsd->nd_procp->p_ucred; 65752316Sheideman if (error = lookup(&nd)) { 65852316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 65942242Smckusick nfsm_reply(0); 66049742Smckusick } 66152316Sheideman FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 66252316Sheideman if (nd.ni_cnd.cn_flags & ISSYMLINK) { 66349742Smckusick vrele(nd.ni_dvp); 66449742Smckusick vput(nd.ni_vp); 66552234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 66649742Smckusick error = EINVAL; 66749742Smckusick nfsm_reply(0); 66849742Smckusick } 66942242Smckusick } else { 67052234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 67149742Smckusick vput(nd.ni_dvp); 67242242Smckusick error = ENXIO; 67349742Smckusick goto out; 67442242Smckusick } 67549742Smckusick vp = nd.ni_vp; 67638418Smckusick } else { 67749742Smckusick vrele(nd.ni_startdir); 67852316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 67949742Smckusick vp = nd.ni_vp; 68049742Smckusick if (nd.ni_dvp == vp) 68149742Smckusick vrele(nd.ni_dvp); 68243359Smckusick else 68349742Smckusick vput(nd.ni_dvp); 68452234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 68538418Smckusick vap->va_size = 0; 68652196Smckusick nqsrv_getl(vp, NQL_WRITE); 68752196Smckusick if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) { 68842506Smckusick vput(vp); 68938418Smckusick nfsm_reply(0); 69042506Smckusick } 69138418Smckusick } 69238418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 69341398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 69438418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 69538418Smckusick vput(vp); 69638418Smckusick nfsm_reply(0); 69738418Smckusick } 69852196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 69938418Smckusick vput(vp); 70038418Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR); 70138418Smckusick nfsm_srvfhtom(fhp); 70238884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 70339753Smckusick nfsm_srvfillattr; 70438418Smckusick return (error); 70538418Smckusick nfsmout: 70652316Sheideman if (nd.ni_cnd.cn_nameiop || nd.ni_cnd.cn_flags) 70751464Sbostic vrele(nd.ni_startdir); 70852234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 70949742Smckusick if (nd.ni_dvp == nd.ni_vp) 71049742Smckusick vrele(nd.ni_dvp); 71143359Smckusick else 71249742Smckusick vput(nd.ni_dvp); 71349742Smckusick if (nd.ni_vp) 71449742Smckusick vput(nd.ni_vp); 71538418Smckusick return (error); 71649742Smckusick 71749742Smckusick out: 71849742Smckusick vrele(nd.ni_startdir); 71952316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 72049742Smckusick nfsm_reply(0); 72138418Smckusick } 72238418Smckusick 72338418Smckusick /* 72438418Smckusick * nfs remove service 72538418Smckusick */ 72652196Smckusick nfsrv_remove(nfsd, mrep, md, dpos, cred, nam, mrq) 72752196Smckusick struct nfsd *nfsd; 72852196Smckusick struct mbuf *mrep, *md; 72938418Smckusick caddr_t dpos; 73038418Smckusick struct ucred *cred; 73152196Smckusick struct mbuf *nam, **mrq; 73238418Smckusick { 73353552Sheideman USES_VOP_ABORTOP; 73453552Sheideman USES_VOP_REMOVE; 73549742Smckusick struct nameidata nd; 73648050Smckusick register u_long *tl; 73739494Smckusick register long t1; 73839494Smckusick caddr_t bpos; 73952196Smckusick int error = 0, cache, len; 74039494Smckusick char *cp2; 74139753Smckusick struct mbuf *mb, *mreq; 74238418Smckusick struct vnode *vp; 74338418Smckusick nfsv2fh_t nfh; 74438418Smckusick fhandle_t *fhp; 74552196Smckusick u_quad_t frev; 74638418Smckusick 74738418Smckusick fhp = &nfh.fh_generic; 74838418Smckusick nfsm_srvmtofh(fhp); 74938418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 75052316Sheideman nd.ni_cnd.cn_cred = cred; 75152316Sheideman nd.ni_cnd.cn_nameiop = DELETE; 75252316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 75352653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 75452653Smckusick nfsd->nd_procp)) 75538418Smckusick nfsm_reply(0); 75649742Smckusick vp = nd.ni_vp; 75738418Smckusick if (vp->v_type == VDIR && 75852196Smckusick (error = suser(cred, (u_short *)0))) 75938418Smckusick goto out; 76038418Smckusick /* 76149454Smckusick * The root of a mounted filesystem cannot be deleted. 76238418Smckusick */ 76338418Smckusick if (vp->v_flag & VROOT) { 76438418Smckusick error = EBUSY; 76538418Smckusick goto out; 76638418Smckusick } 76738418Smckusick if (vp->v_flag & VTEXT) 76845715Smckusick (void) vnode_pager_uncache(vp); 76938418Smckusick out: 77042467Smckusick if (!error) { 77152196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 77252196Smckusick nqsrv_getl(vp, NQL_WRITE); 77352234Sheideman error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 77442467Smckusick } else { 77552234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 77649742Smckusick if (nd.ni_dvp == vp) 77749742Smckusick vrele(nd.ni_dvp); 77843359Smckusick else 77949742Smckusick vput(nd.ni_dvp); 78042467Smckusick vput(vp); 78142467Smckusick } 78238418Smckusick nfsm_reply(0); 78338418Smckusick nfsm_srvdone; 78438418Smckusick } 78538418Smckusick 78638418Smckusick /* 78738418Smckusick * nfs rename service 78838418Smckusick */ 78952196Smckusick nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq) 79052196Smckusick struct nfsd *nfsd; 79152196Smckusick struct mbuf *mrep, *md; 79238418Smckusick caddr_t dpos; 79338418Smckusick struct ucred *cred; 79452196Smckusick struct mbuf *nam, **mrq; 79538418Smckusick { 79653552Sheideman USES_VOP_ABORTOP; 79753552Sheideman USES_VOP_RENAME; 79848050Smckusick register u_long *tl; 79939494Smckusick register long t1; 80039494Smckusick caddr_t bpos; 80152196Smckusick int error = 0, rdonly, cache, len, len2; 80239494Smckusick char *cp2; 80339753Smckusick struct mbuf *mb, *mreq; 80449742Smckusick struct nameidata fromnd, tond; 80538418Smckusick struct vnode *fvp, *tvp, *tdvp; 80638418Smckusick nfsv2fh_t fnfh, tnfh; 80738418Smckusick fhandle_t *ffhp, *tfhp; 80852196Smckusick u_quad_t frev; 80952196Smckusick uid_t saved_uid; 81038418Smckusick 81138418Smckusick ffhp = &fnfh.fh_generic; 81238418Smckusick tfhp = &tnfh.fh_generic; 81352316Sheideman fromnd.ni_cnd.cn_nameiop = 0; 81452316Sheideman tond.ni_cnd.cn_nameiop = 0; 81538418Smckusick nfsm_srvmtofh(ffhp); 81638418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 81738418Smckusick /* 81852196Smckusick * Remember our original uid so that we can reset cr_uid before 81952196Smckusick * the second nfs_namei() call, in case it is remapped. 82038418Smckusick */ 82152196Smckusick saved_uid = cred->cr_uid; 82252316Sheideman fromnd.ni_cnd.cn_cred = cred; 82352316Sheideman fromnd.ni_cnd.cn_nameiop = DELETE; 82452316Sheideman fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART; 82552653Smckusick if (error = nfs_namei(&fromnd, ffhp, len, nfsd->nd_slp, nam, &md, 82652653Smckusick &dpos, nfsd->nd_procp)) 82738418Smckusick nfsm_reply(0); 82849742Smckusick fvp = fromnd.ni_vp; 82938418Smckusick nfsm_srvmtofh(tfhp); 83041899Smckusick nfsm_strsiz(len2, NFS_MAXNAMLEN); 83152196Smckusick cred->cr_uid = saved_uid; 83252316Sheideman tond.ni_cnd.cn_cred = cred; 83352316Sheideman tond.ni_cnd.cn_nameiop = RENAME; 83452316Sheideman tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; 83552653Smckusick if (error = nfs_namei(&tond, tfhp, len2, nfsd->nd_slp, nam, &md, 83652653Smckusick &dpos, nfsd->nd_procp)) { 83752234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 83849742Smckusick vrele(fromnd.ni_dvp); 83942467Smckusick vrele(fvp); 84042467Smckusick goto out1; 84142467Smckusick } 84238425Smckusick tdvp = tond.ni_dvp; 84338425Smckusick tvp = tond.ni_vp; 84438418Smckusick if (tvp != NULL) { 84538418Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 84638418Smckusick error = EISDIR; 84738418Smckusick goto out; 84838418Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 84938418Smckusick error = ENOTDIR; 85038418Smckusick goto out; 85138418Smckusick } 85252196Smckusick if (tvp->v_type == VDIR && tvp->v_mountedhere) { 85352196Smckusick error = EXDEV; 85452196Smckusick goto out; 85552196Smckusick } 85638418Smckusick } 85752196Smckusick if (fvp->v_type == VDIR && fvp->v_mountedhere) { 85852196Smckusick error = EBUSY; 85952196Smckusick goto out; 86052196Smckusick } 86138418Smckusick if (fvp->v_mount != tdvp->v_mount) { 86238418Smckusick error = EXDEV; 86338418Smckusick goto out; 86438418Smckusick } 86549742Smckusick if (fvp == tdvp) 86638418Smckusick error = EINVAL; 86749742Smckusick /* 86849742Smckusick * If source is the same as the destination (that is the 86949742Smckusick * same vnode with the same name in the same directory), 87049742Smckusick * then there is nothing to do. 87149742Smckusick */ 87249742Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 87352316Sheideman fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 87452316Sheideman !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 87552316Sheideman fromnd.ni_cnd.cn_namelen)) 87649742Smckusick error = -1; 87738418Smckusick out: 87842467Smckusick if (!error) { 87952196Smckusick nqsrv_getl(fromnd.ni_dvp, NQL_WRITE); 88052196Smckusick nqsrv_getl(tdvp, NQL_WRITE); 88152196Smckusick if (tvp) 88252196Smckusick nqsrv_getl(tvp, NQL_WRITE); 88352234Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 88452234Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 88542467Smckusick } else { 88652234Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 88743359Smckusick if (tdvp == tvp) 88843359Smckusick vrele(tdvp); 88943359Smckusick else 89043359Smckusick vput(tdvp); 89142467Smckusick if (tvp) 89242467Smckusick vput(tvp); 89352234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 89449742Smckusick vrele(fromnd.ni_dvp); 89542467Smckusick vrele(fvp); 89638418Smckusick } 89746513Smckusick vrele(tond.ni_startdir); 89852316Sheideman FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 89938418Smckusick out1: 90049742Smckusick vrele(fromnd.ni_startdir); 90152316Sheideman FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 90238418Smckusick nfsm_reply(0); 90338418Smckusick return (error); 90449742Smckusick 90538418Smckusick nfsmout: 90652316Sheideman if (tond.ni_cnd.cn_nameiop || tond.ni_cnd.cn_flags) { 90749742Smckusick vrele(tond.ni_startdir); 90852316Sheideman FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 90949742Smckusick } 91052316Sheideman if (fromnd.ni_cnd.cn_nameiop || fromnd.ni_cnd.cn_flags) { 91149742Smckusick vrele(fromnd.ni_startdir); 91252316Sheideman FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 91352234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 91449742Smckusick vrele(fromnd.ni_dvp); 91549742Smckusick vrele(fvp); 91649742Smckusick } 91738418Smckusick return (error); 91838418Smckusick } 91938418Smckusick 92038418Smckusick /* 92138418Smckusick * nfs link service 92238418Smckusick */ 92352196Smckusick nfsrv_link(nfsd, mrep, md, dpos, cred, nam, mrq) 92452196Smckusick struct nfsd *nfsd; 92552196Smckusick struct mbuf *mrep, *md; 92638418Smckusick caddr_t dpos; 92738418Smckusick struct ucred *cred; 92852196Smckusick struct mbuf *nam, **mrq; 92938418Smckusick { 93053552Sheideman USES_VOP_ABORTOP; 93153552Sheideman USES_VOP_LINK; 93249742Smckusick struct nameidata nd; 93348050Smckusick register u_long *tl; 93439494Smckusick register long t1; 93539494Smckusick caddr_t bpos; 93652196Smckusick int error = 0, rdonly, cache, len; 93739494Smckusick char *cp2; 93839753Smckusick struct mbuf *mb, *mreq; 93938418Smckusick struct vnode *vp, *xp; 94038418Smckusick nfsv2fh_t nfh, dnfh; 94138418Smckusick fhandle_t *fhp, *dfhp; 94252196Smckusick u_quad_t frev; 94338418Smckusick 94438418Smckusick fhp = &nfh.fh_generic; 94538418Smckusick dfhp = &dnfh.fh_generic; 94638418Smckusick nfsm_srvmtofh(fhp); 94738418Smckusick nfsm_srvmtofh(dfhp); 94838418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 94952196Smckusick if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 95038418Smckusick nfsm_reply(0); 95152196Smckusick if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0))) 95238418Smckusick goto out1; 95352316Sheideman nd.ni_cnd.cn_cred = cred; 95452316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 95552316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 95652653Smckusick if (error = nfs_namei(&nd, dfhp, len, nfsd->nd_slp, nam, &md, &dpos, 95752653Smckusick nfsd->nd_procp)) 95838418Smckusick goto out1; 95949742Smckusick xp = nd.ni_vp; 96038418Smckusick if (xp != NULL) { 96138418Smckusick error = EEXIST; 96238418Smckusick goto out; 96338418Smckusick } 96449742Smckusick xp = nd.ni_dvp; 96538418Smckusick if (vp->v_mount != xp->v_mount) 96638418Smckusick error = EXDEV; 96738418Smckusick out: 96842467Smckusick if (!error) { 96952196Smckusick nqsrv_getl(vp, NQL_WRITE); 97052196Smckusick nqsrv_getl(xp, NQL_WRITE); 97152933Smckusick error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 97242467Smckusick } else { 97352234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 97449742Smckusick if (nd.ni_dvp == nd.ni_vp) 97549742Smckusick vrele(nd.ni_dvp); 97643359Smckusick else 97749742Smckusick vput(nd.ni_dvp); 97849742Smckusick if (nd.ni_vp) 97949742Smckusick vrele(nd.ni_vp); 98042467Smckusick } 98138418Smckusick out1: 98238418Smckusick vrele(vp); 98338418Smckusick nfsm_reply(0); 98438418Smckusick nfsm_srvdone; 98538418Smckusick } 98638418Smckusick 98738418Smckusick /* 98838418Smckusick * nfs symbolic link service 98938418Smckusick */ 99052196Smckusick nfsrv_symlink(nfsd, mrep, md, dpos, cred, nam, mrq) 99152196Smckusick struct nfsd *nfsd; 99252196Smckusick struct mbuf *mrep, *md; 99338418Smckusick caddr_t dpos; 99438418Smckusick struct ucred *cred; 99552196Smckusick struct mbuf *nam, **mrq; 99638418Smckusick { 99753552Sheideman USES_VOP_ABORTOP; 99853552Sheideman USES_VOP_SYMLINK; 99938418Smckusick struct vattr va; 100049742Smckusick struct nameidata nd; 100138418Smckusick register struct vattr *vap = &va; 100248050Smckusick register u_long *tl; 100339494Smckusick register long t1; 100445285Smckusick struct nfsv2_sattr *sp; 100539494Smckusick caddr_t bpos; 100641899Smckusick struct uio io; 100741899Smckusick struct iovec iv; 100852196Smckusick int error = 0, rdonly, cache, len, len2; 100941899Smckusick char *pathcp, *cp2; 101039753Smckusick struct mbuf *mb, *mreq; 101138418Smckusick nfsv2fh_t nfh; 101238418Smckusick fhandle_t *fhp; 101352196Smckusick u_quad_t frev; 101438418Smckusick 101541899Smckusick pathcp = (char *)0; 101638418Smckusick fhp = &nfh.fh_generic; 101738418Smckusick nfsm_srvmtofh(fhp); 101838418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 101952316Sheideman nd.ni_cnd.cn_cred = cred; 102052316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 102152316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 102252653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 102352653Smckusick nfsd->nd_procp)) 102442467Smckusick goto out; 102541899Smckusick nfsm_strsiz(len2, NFS_MAXPATHLEN); 102641899Smckusick MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK); 102741899Smckusick iv.iov_base = pathcp; 102841899Smckusick iv.iov_len = len2; 102941899Smckusick io.uio_resid = len2; 103041899Smckusick io.uio_offset = 0; 103141899Smckusick io.uio_iov = &iv; 103241899Smckusick io.uio_iovcnt = 1; 103341899Smckusick io.uio_segflg = UIO_SYSSPACE; 103441899Smckusick io.uio_rw = UIO_READ; 103548050Smckusick io.uio_procp = (struct proc *)0; 103641899Smckusick nfsm_mtouio(&io, len2); 103752196Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR); 103841899Smckusick *(pathcp + len2) = '\0'; 103949742Smckusick if (nd.ni_vp) { 104052234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 104149742Smckusick if (nd.ni_dvp == nd.ni_vp) 104249742Smckusick vrele(nd.ni_dvp); 104343359Smckusick else 104449742Smckusick vput(nd.ni_dvp); 104549742Smckusick vrele(nd.ni_vp); 104638418Smckusick error = EEXIST; 104738418Smckusick goto out; 104838418Smckusick } 104941361Smckusick VATTR_NULL(vap); 105045285Smckusick vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode); 105152196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 105252234Sheideman error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp); 105338418Smckusick out: 105441899Smckusick if (pathcp) 105541899Smckusick FREE(pathcp, M_TEMP); 105638418Smckusick nfsm_reply(0); 105738418Smckusick return (error); 105838418Smckusick nfsmout: 105952234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 106049742Smckusick if (nd.ni_dvp == nd.ni_vp) 106149742Smckusick vrele(nd.ni_dvp); 106243359Smckusick else 106349742Smckusick vput(nd.ni_dvp); 106449742Smckusick if (nd.ni_vp) 106549742Smckusick vrele(nd.ni_vp); 106641899Smckusick if (pathcp) 106741899Smckusick FREE(pathcp, M_TEMP); 106838418Smckusick return (error); 106938418Smckusick } 107038418Smckusick 107138418Smckusick /* 107238418Smckusick * nfs mkdir service 107338418Smckusick */ 107452196Smckusick nfsrv_mkdir(nfsd, mrep, md, dpos, cred, nam, mrq) 107552196Smckusick struct nfsd *nfsd; 107652196Smckusick struct mbuf *mrep, *md; 107738418Smckusick caddr_t dpos; 107838418Smckusick struct ucred *cred; 107952196Smckusick struct mbuf *nam, **mrq; 108038418Smckusick { 108153552Sheideman USES_VOP_ABORTOP; 108253552Sheideman USES_VOP_GETATTR; 108353552Sheideman USES_VOP_MKDIR; 108438418Smckusick struct vattr va; 108538418Smckusick register struct vattr *vap = &va; 108638884Smacklem register struct nfsv2_fattr *fp; 108749742Smckusick struct nameidata nd; 108839494Smckusick register caddr_t cp; 108948050Smckusick register u_long *tl; 109039494Smckusick register long t1; 109139494Smckusick caddr_t bpos; 109252196Smckusick int error = 0, rdonly, cache, len; 109339494Smckusick char *cp2; 109439753Smckusick struct mbuf *mb, *mb2, *mreq; 109538418Smckusick struct vnode *vp; 109638418Smckusick nfsv2fh_t nfh; 109738418Smckusick fhandle_t *fhp; 109852196Smckusick u_quad_t frev; 109938418Smckusick 110038418Smckusick fhp = &nfh.fh_generic; 110138418Smckusick nfsm_srvmtofh(fhp); 110238418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 110352316Sheideman nd.ni_cnd.cn_cred = cred; 110452316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 110552316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 110652653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 110752653Smckusick nfsd->nd_procp)) 110838418Smckusick nfsm_reply(0); 110952196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 111041361Smckusick VATTR_NULL(vap); 111138418Smckusick vap->va_type = VDIR; 111248050Smckusick vap->va_mode = nfstov_mode(*tl++); 111349742Smckusick vp = nd.ni_vp; 111438418Smckusick if (vp != NULL) { 111552234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 111649742Smckusick if (nd.ni_dvp == vp) 111749742Smckusick vrele(nd.ni_dvp); 111843359Smckusick else 111949742Smckusick vput(nd.ni_dvp); 112042467Smckusick vrele(vp); 112138418Smckusick error = EEXIST; 112238418Smckusick nfsm_reply(0); 112338418Smckusick } 112452196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 112552234Sheideman if (error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) 112638418Smckusick nfsm_reply(0); 112749742Smckusick vp = nd.ni_vp; 112838418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 112941398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 113038418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 113138418Smckusick vput(vp); 113238418Smckusick nfsm_reply(0); 113338418Smckusick } 113452196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 113538418Smckusick vput(vp); 113638418Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR); 113738418Smckusick nfsm_srvfhtom(fhp); 113838884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 113939753Smckusick nfsm_srvfillattr; 114038418Smckusick return (error); 114138418Smckusick nfsmout: 114252234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 114349742Smckusick if (nd.ni_dvp == nd.ni_vp) 114449742Smckusick vrele(nd.ni_dvp); 114543359Smckusick else 114649742Smckusick vput(nd.ni_dvp); 114749742Smckusick if (nd.ni_vp) 114849742Smckusick vrele(nd.ni_vp); 114938418Smckusick return (error); 115038418Smckusick } 115138418Smckusick 115238418Smckusick /* 115338418Smckusick * nfs rmdir service 115438418Smckusick */ 115552196Smckusick nfsrv_rmdir(nfsd, mrep, md, dpos, cred, nam, mrq) 115652196Smckusick struct nfsd *nfsd; 115752196Smckusick struct mbuf *mrep, *md; 115838418Smckusick caddr_t dpos; 115938418Smckusick struct ucred *cred; 116052196Smckusick struct mbuf *nam, **mrq; 116138418Smckusick { 116253552Sheideman USES_VOP_ABORTOP; 116353552Sheideman USES_VOP_RMDIR; 116448050Smckusick register u_long *tl; 116539494Smckusick register long t1; 116639494Smckusick caddr_t bpos; 116752196Smckusick int error = 0, rdonly, cache, len; 116839494Smckusick char *cp2; 116939753Smckusick struct mbuf *mb, *mreq; 117038418Smckusick struct vnode *vp; 117138418Smckusick nfsv2fh_t nfh; 117238418Smckusick fhandle_t *fhp; 117349742Smckusick struct nameidata nd; 117452196Smckusick u_quad_t frev; 117538418Smckusick 117638418Smckusick fhp = &nfh.fh_generic; 117738418Smckusick nfsm_srvmtofh(fhp); 117838418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 117952316Sheideman nd.ni_cnd.cn_cred = cred; 118052316Sheideman nd.ni_cnd.cn_nameiop = DELETE; 118152316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 118252653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 118352653Smckusick nfsd->nd_procp)) 118438418Smckusick nfsm_reply(0); 118549742Smckusick vp = nd.ni_vp; 118638418Smckusick if (vp->v_type != VDIR) { 118738418Smckusick error = ENOTDIR; 118838418Smckusick goto out; 118938418Smckusick } 119038418Smckusick /* 119138418Smckusick * No rmdir "." please. 119238418Smckusick */ 119349742Smckusick if (nd.ni_dvp == vp) { 119438418Smckusick error = EINVAL; 119538418Smckusick goto out; 119638418Smckusick } 119738418Smckusick /* 119849454Smckusick * The root of a mounted filesystem cannot be deleted. 119938418Smckusick */ 120038418Smckusick if (vp->v_flag & VROOT) 120138418Smckusick error = EBUSY; 120238418Smckusick out: 120342467Smckusick if (!error) { 120452196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 120552196Smckusick nqsrv_getl(vp, NQL_WRITE); 120652234Sheideman error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 120742467Smckusick } else { 120852234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 120949742Smckusick if (nd.ni_dvp == nd.ni_vp) 121049742Smckusick vrele(nd.ni_dvp); 121143359Smckusick else 121249742Smckusick vput(nd.ni_dvp); 121342467Smckusick vput(vp); 121442467Smckusick } 121538418Smckusick nfsm_reply(0); 121638418Smckusick nfsm_srvdone; 121738418Smckusick } 121838418Smckusick 121938418Smckusick /* 122038418Smckusick * nfs readdir service 122138418Smckusick * - mallocs what it thinks is enough to read 122248050Smckusick * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR 122338418Smckusick * - calls VOP_READDIR() 122440115Smckusick * - loops around building the reply 122538425Smckusick * if the output generated exceeds count break out of loop 122638425Smckusick * The nfsm_clget macro is used here so that the reply will be packed 122738425Smckusick * tightly in mbuf clusters. 122838418Smckusick * - it only knows that it has encountered eof when the VOP_READDIR() 122938425Smckusick * reads nothing 123038418Smckusick * - as such one readdir rpc will return eof false although you are there 123138425Smckusick * and then the next will return eof 123252441Smckusick * - it trims out records with d_fileno == 0 123338425Smckusick * this doesn't matter for Unix clients, but they might confuse clients 123438425Smckusick * for other os'. 123538418Smckusick * NB: It is tempting to set eof to true if the VOP_READDIR() reads less 123638425Smckusick * than requested, but this may not apply to all filesystems. For 123738425Smckusick * example, client NFS does not { although it is never remote mounted 123838425Smckusick * anyhow } 123952196Smckusick * The alternate call nqnfsrv_readdirlook() does lookups as well. 124038418Smckusick * PS: The NFS protocol spec. does not clarify what the "count" byte 124138425Smckusick * argument is a count of.. just name strings and file id's or the 124238425Smckusick * entire reply rpc or ... 124338425Smckusick * I tried just file name and id sizes and it confused the Sun client, 124438425Smckusick * so I am using the full rpc size now. The "paranoia.." comment refers 124538425Smckusick * to including the status longwords that are not a part of the dir. 124638425Smckusick * "entry" structures, but are in the rpc. 124738418Smckusick */ 124852196Smckusick struct flrep { 124952196Smckusick u_long fl_cachable; 125052196Smckusick u_long fl_duration; 125152196Smckusick u_quad_t fl_frev; 125252196Smckusick nfsv2fh_t fl_nfh; 125352196Smckusick struct nfsv2_fattr fl_fattr; 125452196Smckusick }; 125552196Smckusick 125652196Smckusick nfsrv_readdir(nfsd, mrep, md, dpos, cred, nam, mrq) 125752196Smckusick struct nfsd *nfsd; 125838418Smckusick struct mbuf *mrep, *md; 125938418Smckusick caddr_t dpos; 126038418Smckusick struct ucred *cred; 126152196Smckusick struct mbuf *nam, **mrq; 126238418Smckusick { 126353552Sheideman USES_VOP_READDIR; 126453552Sheideman USES_VOP_UNLOCK; 126538418Smckusick register char *bp, *be; 126638418Smckusick register struct mbuf *mp; 126752441Smckusick register struct dirent *dp; 126839494Smckusick register caddr_t cp; 126948050Smckusick register u_long *tl; 127039494Smckusick register long t1; 127139494Smckusick caddr_t bpos; 127252196Smckusick struct mbuf *mb, *mb2, *mreq, *mp2; 127352196Smckusick char *cpos, *cend, *cp2, *rbuf; 127438418Smckusick struct vnode *vp; 127538418Smckusick nfsv2fh_t nfh; 127638418Smckusick fhandle_t *fhp; 127738418Smckusick struct uio io; 127838418Smckusick struct iovec iv; 127952196Smckusick struct vattr va; 128052196Smckusick int len, nlen, rem, xfer, tsiz, i, error = 0; 128152196Smckusick int siz, cnt, fullsiz, eofflag, rdonly, cache; 128252196Smckusick u_quad_t frev; 128338418Smckusick u_long on; 128438418Smckusick off_t off, toff; 128538418Smckusick 128638418Smckusick fhp = &nfh.fh_generic; 128738418Smckusick nfsm_srvmtofh(fhp); 128852196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 128948050Smckusick toff = fxdr_unsigned(off_t, *tl++); 129048050Smckusick off = (toff & ~(NFS_DIRBLKSIZ-1)); 129148050Smckusick on = (toff & (NFS_DIRBLKSIZ-1)); 129248050Smckusick cnt = fxdr_unsigned(int, *tl); 129348050Smckusick siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); 129441899Smckusick if (cnt > NFS_MAXREADDIR) 129541899Smckusick siz = NFS_MAXREADDIR; 129638418Smckusick fullsiz = siz; 129752196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 129838418Smckusick nfsm_reply(0); 129952196Smckusick nqsrv_getl(vp, NQL_READ); 130052196Smckusick if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { 130138418Smckusick vput(vp); 130238418Smckusick nfsm_reply(0); 130338418Smckusick } 130438418Smckusick VOP_UNLOCK(vp); 130538418Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 130638418Smckusick again: 130738418Smckusick iv.iov_base = rbuf; 130838418Smckusick iv.iov_len = fullsiz; 130938418Smckusick io.uio_iov = &iv; 131038418Smckusick io.uio_iovcnt = 1; 131138418Smckusick io.uio_offset = off; 131238418Smckusick io.uio_resid = fullsiz; 131338418Smckusick io.uio_segflg = UIO_SYSSPACE; 131438418Smckusick io.uio_rw = UIO_READ; 131548050Smckusick io.uio_procp = (struct proc *)0; 131640296Smckusick error = VOP_READDIR(vp, &io, cred, &eofflag); 131739586Smckusick off = io.uio_offset; 131838418Smckusick if (error) { 131938418Smckusick vrele(vp); 132038418Smckusick free((caddr_t)rbuf, M_TEMP); 132138418Smckusick nfsm_reply(0); 132238418Smckusick } 132338418Smckusick if (io.uio_resid) { 132438418Smckusick siz -= io.uio_resid; 132538418Smckusick 132638418Smckusick /* 132738418Smckusick * If nothing read, return eof 132838418Smckusick * rpc reply 132938418Smckusick */ 133038418Smckusick if (siz == 0) { 133138418Smckusick vrele(vp); 133238418Smckusick nfsm_reply(2*NFSX_UNSIGNED); 133348050Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 133448050Smckusick *tl++ = nfs_false; 133548050Smckusick *tl = nfs_true; 133638418Smckusick FREE((caddr_t)rbuf, M_TEMP); 133738418Smckusick return (0); 133838418Smckusick } 133938418Smckusick } 134040115Smckusick 134138418Smckusick /* 134238418Smckusick * Check for degenerate cases of nothing useful read. 134340115Smckusick * If so go try again 134438418Smckusick */ 134540115Smckusick cpos = rbuf + on; 134640115Smckusick cend = rbuf + siz; 134752441Smckusick dp = (struct dirent *)cpos; 134852441Smckusick while (cpos < cend && dp->d_fileno == 0) { 134940115Smckusick cpos += dp->d_reclen; 135052441Smckusick dp = (struct dirent *)cpos; 135140115Smckusick } 135240115Smckusick if (cpos >= cend) { 135338418Smckusick toff = off; 135438418Smckusick siz = fullsiz; 135538418Smckusick on = 0; 135638418Smckusick goto again; 135738418Smckusick } 135840115Smckusick 135940115Smckusick cpos = rbuf + on; 136040115Smckusick cend = rbuf + siz; 136152441Smckusick dp = (struct dirent *)cpos; 136252196Smckusick len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 136352196Smckusick nfsm_reply(siz); 136452196Smckusick mp = mp2 = mb; 136552196Smckusick bp = bpos; 136652196Smckusick be = bp + M_TRAILINGSPACE(mp); 136752196Smckusick 136852196Smckusick /* Loop through the records and build reply */ 136952196Smckusick while (cpos < cend) { 137052441Smckusick if (dp->d_fileno != 0) { 137152196Smckusick nlen = dp->d_namlen; 137252196Smckusick rem = nfsm_rndup(nlen)-nlen; 137352196Smckusick len += (4*NFSX_UNSIGNED + nlen + rem); 137452196Smckusick if (len > cnt) { 137552196Smckusick eofflag = 0; 137652196Smckusick break; 137752196Smckusick } 137852441Smckusick /* 137952441Smckusick * Build the directory record xdr from 138052441Smckusick * the dirent entry. 138152441Smckusick */ 138252196Smckusick nfsm_clget; 138352196Smckusick *tl = nfs_true; 138452196Smckusick bp += NFSX_UNSIGNED; 138552196Smckusick nfsm_clget; 138652441Smckusick *tl = txdr_unsigned(dp->d_fileno); 138752196Smckusick bp += NFSX_UNSIGNED; 138852196Smckusick nfsm_clget; 138952196Smckusick *tl = txdr_unsigned(nlen); 139052196Smckusick bp += NFSX_UNSIGNED; 139152196Smckusick 139252196Smckusick /* And loop around copying the name */ 139352196Smckusick xfer = nlen; 139452196Smckusick cp = dp->d_name; 139552196Smckusick while (xfer > 0) { 139652196Smckusick nfsm_clget; 139752196Smckusick if ((bp+xfer) > be) 139852196Smckusick tsiz = be-bp; 139952196Smckusick else 140052196Smckusick tsiz = xfer; 140152196Smckusick bcopy(cp, bp, tsiz); 140252196Smckusick bp += tsiz; 140352196Smckusick xfer -= tsiz; 140452196Smckusick if (xfer > 0) 140552196Smckusick cp += tsiz; 140652196Smckusick } 140752196Smckusick /* And null pad to a long boundary */ 140852196Smckusick for (i = 0; i < rem; i++) 140952196Smckusick *bp++ = '\0'; 141052196Smckusick nfsm_clget; 141152196Smckusick 141252196Smckusick /* Finish off the record */ 141352196Smckusick toff += dp->d_reclen; 141452196Smckusick *tl = txdr_unsigned(toff); 141552196Smckusick bp += NFSX_UNSIGNED; 141652196Smckusick } else 141752196Smckusick toff += dp->d_reclen; 141852196Smckusick cpos += dp->d_reclen; 141952441Smckusick dp = (struct dirent *)cpos; 142052196Smckusick } 142138418Smckusick vrele(vp); 142252196Smckusick nfsm_clget; 142352196Smckusick *tl = nfs_false; 142452196Smckusick bp += NFSX_UNSIGNED; 142552196Smckusick nfsm_clget; 142652196Smckusick if (eofflag) 142752196Smckusick *tl = nfs_true; 142852196Smckusick else 142952196Smckusick *tl = nfs_false; 143052196Smckusick bp += NFSX_UNSIGNED; 143152196Smckusick if (mp != mb) { 143252196Smckusick if (bp < be) 143352196Smckusick mp->m_len = bp - mtod(mp, caddr_t); 143452196Smckusick } else 143552196Smckusick mp->m_len += bp - bpos; 143652196Smckusick FREE(rbuf, M_TEMP); 143752196Smckusick nfsm_srvdone; 143852196Smckusick } 143952196Smckusick 144052196Smckusick nqnfsrv_readdirlook(nfsd, mrep, md, dpos, cred, nam, mrq) 144152196Smckusick struct nfsd *nfsd; 144252196Smckusick struct mbuf *mrep, *md; 144352196Smckusick caddr_t dpos; 144452196Smckusick struct ucred *cred; 144552196Smckusick struct mbuf *nam, **mrq; 144652196Smckusick { 144753552Sheideman USES_VOP_GETATTR; 144853552Sheideman USES_VOP_READDIR; 144953552Sheideman USES_VOP_UNLOCK; 145052196Smckusick register char *bp, *be; 145152196Smckusick register struct mbuf *mp; 145252441Smckusick register struct dirent *dp; 145352196Smckusick register caddr_t cp; 145452196Smckusick register u_long *tl; 145552196Smckusick register long t1; 145652196Smckusick caddr_t bpos; 145752196Smckusick struct mbuf *mb, *mb2, *mreq, *mp2; 145852196Smckusick char *cpos, *cend, *cp2, *rbuf; 145952196Smckusick struct vnode *vp, *nvp; 146052196Smckusick struct flrep fl; 146152196Smckusick struct ufid *ufp = (struct ufid *)&fl.fl_nfh.fh_generic.fh_fid; 146252196Smckusick struct mount *mntp; 146352196Smckusick nfsv2fh_t nfh; 146452196Smckusick fhandle_t *fhp; 146552196Smckusick struct uio io; 146652196Smckusick struct iovec iv; 146752196Smckusick struct vattr va, *vap = &va; 146852196Smckusick struct nfsv2_fattr *fp; 146952196Smckusick int len, nlen, rem, xfer, tsiz, i, error = 0, duration2, cache2; 147052196Smckusick int siz, cnt, fullsiz, eofflag, rdonly, cache; 147152196Smckusick u_quad_t frev, frev2; 147252196Smckusick u_long on; 147352196Smckusick off_t off, toff; 147452196Smckusick 147552196Smckusick fhp = &nfh.fh_generic; 147652196Smckusick nfsm_srvmtofh(fhp); 147752196Smckusick nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED); 147852196Smckusick toff = fxdr_unsigned(off_t, *tl++); 147952196Smckusick off = (toff & ~(NFS_DIRBLKSIZ-1)); 148052196Smckusick on = (toff & (NFS_DIRBLKSIZ-1)); 148152196Smckusick cnt = fxdr_unsigned(int, *tl++); 148252196Smckusick duration2 = fxdr_unsigned(int, *tl); 148352196Smckusick siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); 148452196Smckusick if (cnt > NFS_MAXREADDIR) 148552196Smckusick siz = NFS_MAXREADDIR; 148652196Smckusick fullsiz = siz; 148752196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 148852196Smckusick nfsm_reply(0); 148952196Smckusick nqsrv_getl(vp, NQL_READ); 149052196Smckusick if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { 149152196Smckusick vput(vp); 149252196Smckusick nfsm_reply(0); 149352196Smckusick } 149452196Smckusick VOP_UNLOCK(vp); 149552196Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 149652196Smckusick again: 149752196Smckusick iv.iov_base = rbuf; 149852196Smckusick iv.iov_len = fullsiz; 149952196Smckusick io.uio_iov = &iv; 150052196Smckusick io.uio_iovcnt = 1; 150152196Smckusick io.uio_offset = off; 150252196Smckusick io.uio_resid = fullsiz; 150352196Smckusick io.uio_segflg = UIO_SYSSPACE; 150452196Smckusick io.uio_rw = UIO_READ; 150552196Smckusick io.uio_procp = (struct proc *)0; 150652196Smckusick error = VOP_READDIR(vp, &io, cred, &eofflag); 150752196Smckusick off = io.uio_offset; 150852196Smckusick if (error) { 150952196Smckusick vrele(vp); 151052196Smckusick free((caddr_t)rbuf, M_TEMP); 151152196Smckusick nfsm_reply(0); 151252196Smckusick } 151352196Smckusick if (io.uio_resid) { 151452196Smckusick siz -= io.uio_resid; 151552196Smckusick 151652196Smckusick /* 151752196Smckusick * If nothing read, return eof 151852196Smckusick * rpc reply 151952196Smckusick */ 152052196Smckusick if (siz == 0) { 152152196Smckusick vrele(vp); 152252196Smckusick nfsm_reply(2*NFSX_UNSIGNED); 152352196Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 152452196Smckusick *tl++ = nfs_false; 152552196Smckusick *tl = nfs_true; 152652196Smckusick FREE((caddr_t)rbuf, M_TEMP); 152752196Smckusick return (0); 152852196Smckusick } 152952196Smckusick } 153052196Smckusick 153152196Smckusick /* 153252196Smckusick * Check for degenerate cases of nothing useful read. 153352196Smckusick * If so go try again 153452196Smckusick */ 153552196Smckusick cpos = rbuf + on; 153652196Smckusick cend = rbuf + siz; 153752441Smckusick dp = (struct dirent *)cpos; 153852441Smckusick while (cpos < cend && dp->d_fileno == 0) { 153952196Smckusick cpos += dp->d_reclen; 154052441Smckusick dp = (struct dirent *)cpos; 154152196Smckusick } 154252196Smckusick if (cpos >= cend) { 154352196Smckusick toff = off; 154452196Smckusick siz = fullsiz; 154552196Smckusick on = 0; 154652196Smckusick goto again; 154752196Smckusick } 154852196Smckusick 154952196Smckusick cpos = rbuf + on; 155052196Smckusick cend = rbuf + siz; 155152441Smckusick dp = (struct dirent *)cpos; 155238425Smckusick len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 155338418Smckusick nfsm_reply(siz); 155452196Smckusick mp = mp2 = mb; 155552196Smckusick bp = bpos; 155652196Smckusick be = bp + M_TRAILINGSPACE(mp); 155752196Smckusick mntp = vp->v_mount; 155838418Smckusick 155938418Smckusick /* Loop through the records and build reply */ 156038418Smckusick while (cpos < cend) { 156152441Smckusick if (dp->d_fileno != 0) { 156238418Smckusick nlen = dp->d_namlen; 156338418Smckusick rem = nfsm_rndup(nlen)-nlen; 156438425Smckusick 156538418Smckusick /* 156652196Smckusick * For readdir_and_lookup get the vnode using 156752196Smckusick * the file number. 156838418Smckusick */ 156952196Smckusick bzero((caddr_t)&fl.fl_nfh, sizeof (nfsv2fh_t)); 157052196Smckusick ufp->ufid_len = sizeof (struct ufid); 157152441Smckusick ufp->ufid_ino = dp->d_fileno; 157252196Smckusick fl.fl_nfh.fh_generic.fh_fsid = mntp->mnt_stat.f_fsid; 157352196Smckusick if (VFS_FHTOVP(mntp, (struct fid *)ufp, 1, &nvp)) 157452196Smckusick goto invalid; 157552196Smckusick (void) nqsrv_getlease(nvp, &duration2, NQL_READ, nfsd, 157652196Smckusick nam, &cache2, &frev2, cred); 157752196Smckusick fl.fl_duration = txdr_unsigned(duration2); 157852196Smckusick fl.fl_cachable = txdr_unsigned(cache2); 157952196Smckusick txdr_hyper(&frev2, &fl.fl_frev); 158052196Smckusick if (VOP_GETATTR(nvp, vap, cred, nfsd->nd_procp)) { 158152196Smckusick vput(nvp); 158252196Smckusick goto invalid; 158352196Smckusick } 158452196Smckusick vput(nvp); 158552196Smckusick fp = &fl.fl_fattr; 158652196Smckusick nfsm_srvfillattr; 158752196Smckusick len += (4*NFSX_UNSIGNED + nlen + rem + NFSX_FH 158852196Smckusick + NFSX_FATTR); 158941899Smckusick if (len > cnt) { 159041899Smckusick eofflag = 0; 159138418Smckusick break; 159241899Smckusick } 159352441Smckusick /* 159452441Smckusick * Build the directory record xdr from 159552441Smckusick * the dirent entry. 159652441Smckusick */ 159738418Smckusick nfsm_clget; 159848050Smckusick *tl = nfs_true; 159938418Smckusick bp += NFSX_UNSIGNED; 160052196Smckusick 160152196Smckusick /* 160252196Smckusick * For readdir_and_lookup copy the stuff out. 160352196Smckusick */ 160452196Smckusick xfer = sizeof (struct flrep); 160552196Smckusick cp = (caddr_t)&fl; 160652196Smckusick while (xfer > 0) { 160752196Smckusick nfsm_clget; 160852196Smckusick if ((bp+xfer) > be) 160952196Smckusick tsiz = be-bp; 161052196Smckusick else 161152196Smckusick tsiz = xfer; 161252196Smckusick bcopy(cp, bp, tsiz); 161352196Smckusick bp += tsiz; 161452196Smckusick xfer -= tsiz; 161552196Smckusick if (xfer > 0) 161652196Smckusick cp += tsiz; 161752196Smckusick } 161838418Smckusick nfsm_clget; 161952441Smckusick *tl = txdr_unsigned(dp->d_fileno); 162038418Smckusick bp += NFSX_UNSIGNED; 162138418Smckusick nfsm_clget; 162248050Smckusick *tl = txdr_unsigned(nlen); 162338418Smckusick bp += NFSX_UNSIGNED; 162438425Smckusick 162552196Smckusick /* And loop around copying the name */ 162638418Smckusick xfer = nlen; 162738418Smckusick cp = dp->d_name; 162838418Smckusick while (xfer > 0) { 162938418Smckusick nfsm_clget; 163038418Smckusick if ((bp+xfer) > be) 163138418Smckusick tsiz = be-bp; 163238418Smckusick else 163338418Smckusick tsiz = xfer; 163438418Smckusick bcopy(cp, bp, tsiz); 163538418Smckusick bp += tsiz; 163638418Smckusick xfer -= tsiz; 163738418Smckusick if (xfer > 0) 163838418Smckusick cp += tsiz; 163938418Smckusick } 164038418Smckusick /* And null pad to a long boundary */ 164138418Smckusick for (i = 0; i < rem; i++) 164238418Smckusick *bp++ = '\0'; 164338418Smckusick nfsm_clget; 164438425Smckusick 164538418Smckusick /* Finish off the record */ 164638418Smckusick toff += dp->d_reclen; 164748050Smckusick *tl = txdr_unsigned(toff); 164838418Smckusick bp += NFSX_UNSIGNED; 164938418Smckusick } else 165052196Smckusick invalid: 165138418Smckusick toff += dp->d_reclen; 165238418Smckusick cpos += dp->d_reclen; 165352441Smckusick dp = (struct dirent *)cpos; 165438418Smckusick } 165552196Smckusick vrele(vp); 165638418Smckusick nfsm_clget; 165748050Smckusick *tl = nfs_false; 165838418Smckusick bp += NFSX_UNSIGNED; 165938418Smckusick nfsm_clget; 166040296Smckusick if (eofflag) 166148050Smckusick *tl = nfs_true; 166240296Smckusick else 166348050Smckusick *tl = nfs_false; 166438418Smckusick bp += NFSX_UNSIGNED; 166552196Smckusick if (mp != mb) { 166652196Smckusick if (bp < be) 166752196Smckusick mp->m_len = bp - mtod(mp, caddr_t); 166852196Smckusick } else 166952196Smckusick mp->m_len += bp - bpos; 167038418Smckusick FREE(rbuf, M_TEMP); 167138418Smckusick nfsm_srvdone; 167238418Smckusick } 167338418Smckusick 167438418Smckusick /* 167538418Smckusick * nfs statfs service 167638418Smckusick */ 167752196Smckusick nfsrv_statfs(nfsd, mrep, md, dpos, cred, nam, mrq) 167852196Smckusick struct nfsd *nfsd; 167938418Smckusick struct mbuf *mrep, *md; 168038418Smckusick caddr_t dpos; 168138418Smckusick struct ucred *cred; 168252196Smckusick struct mbuf *nam, **mrq; 168338418Smckusick { 168438418Smckusick register struct statfs *sf; 168538884Smacklem register struct nfsv2_statfs *sfp; 168648050Smckusick register u_long *tl; 168739494Smckusick register long t1; 168839494Smckusick caddr_t bpos; 168952196Smckusick int error = 0, rdonly, cache; 169039494Smckusick char *cp2; 169139753Smckusick struct mbuf *mb, *mb2, *mreq; 169238418Smckusick struct vnode *vp; 169338418Smckusick nfsv2fh_t nfh; 169438418Smckusick fhandle_t *fhp; 169538418Smckusick struct statfs statfs; 169652196Smckusick u_quad_t frev; 169738418Smckusick 169838418Smckusick fhp = &nfh.fh_generic; 169938418Smckusick nfsm_srvmtofh(fhp); 170052196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 170138418Smckusick nfsm_reply(0); 170238418Smckusick sf = &statfs; 170352196Smckusick error = VFS_STATFS(vp->v_mount, sf, nfsd->nd_procp); 170438418Smckusick vput(vp); 170538418Smckusick nfsm_reply(NFSX_STATFS); 170638884Smacklem nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS); 170744993Sbostic sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA); 170851940Smckusick sfp->sf_bsize = txdr_unsigned(sf->f_bsize); 170938884Smacklem sfp->sf_blocks = txdr_unsigned(sf->f_blocks); 171038884Smacklem sfp->sf_bfree = txdr_unsigned(sf->f_bfree); 171138884Smacklem sfp->sf_bavail = txdr_unsigned(sf->f_bavail); 171238418Smckusick nfsm_srvdone; 171338418Smckusick } 171438418Smckusick 171538418Smckusick /* 171638418Smckusick * Null operation, used by clients to ping server 171738418Smckusick */ 171839494Smckusick /* ARGSUSED */ 171952196Smckusick nfsrv_null(nfsd, mrep, md, dpos, cred, nam, mrq) 172052196Smckusick struct nfsd *nfsd; 172138418Smckusick struct mbuf *mrep, *md; 172238418Smckusick caddr_t dpos; 172338418Smckusick struct ucred *cred; 172452196Smckusick struct mbuf *nam, **mrq; 172538418Smckusick { 172639494Smckusick caddr_t bpos; 172752196Smckusick int error = VNOVAL, cache; 172839753Smckusick struct mbuf *mb, *mreq; 172952196Smckusick u_quad_t frev; 173038418Smckusick 173138418Smckusick nfsm_reply(0); 173239494Smckusick return (error); 173338418Smckusick } 173438418Smckusick 173538418Smckusick /* 173638418Smckusick * No operation, used for obsolete procedures 173738418Smckusick */ 173839494Smckusick /* ARGSUSED */ 173952196Smckusick nfsrv_noop(nfsd, mrep, md, dpos, cred, nam, mrq) 174052196Smckusick struct nfsd *nfsd; 174138418Smckusick struct mbuf *mrep, *md; 174238418Smckusick caddr_t dpos; 174338418Smckusick struct ucred *cred; 174452196Smckusick struct mbuf *nam, **mrq; 174538418Smckusick { 174639494Smckusick caddr_t bpos; 174752196Smckusick int error, cache; 174839753Smckusick struct mbuf *mb, *mreq; 174952196Smckusick u_quad_t frev; 175038418Smckusick 175152196Smckusick if (nfsd->nd_repstat) 175252196Smckusick error = nfsd->nd_repstat; 175352196Smckusick else 175452196Smckusick error = EPROCUNAVAIL; 175538418Smckusick nfsm_reply(0); 175639494Smckusick return (error); 175738418Smckusick } 175838425Smckusick 175938450Smckusick /* 176038450Smckusick * Perform access checking for vnodes obtained from file handles that would 176138450Smckusick * refer to files already opened by a Unix client. You cannot just use 176238450Smckusick * vn_writechk() and VOP_ACCESS() for two reasons. 176352196Smckusick * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case 176438450Smckusick * 2 - The owner is to be given access irrespective of mode bits so that 176538450Smckusick * processes that chmod after opening a file don't break. I don't like 176638450Smckusick * this because it opens a security hole, but since the nfs server opens 176738450Smckusick * a security hole the size of a barn door anyhow, what the heck. 176838450Smckusick */ 176952196Smckusick nfsrv_access(vp, flags, cred, rdonly, p) 177038450Smckusick register struct vnode *vp; 177138450Smckusick int flags; 177238450Smckusick register struct ucred *cred; 177352196Smckusick int rdonly; 177448050Smckusick struct proc *p; 177538450Smckusick { 177653552Sheideman USES_VOP_ACCESS; 177753552Sheideman USES_VOP_GETATTR; 177838450Smckusick struct vattr vattr; 177938450Smckusick int error; 178038450Smckusick if (flags & VWRITE) { 178152196Smckusick /* Just vn_writechk() changed to check rdonly */ 178238450Smckusick /* 178338450Smckusick * Disallow write attempts on read-only file systems; 178438450Smckusick * unless the file is a socket or a block or character 178538450Smckusick * device resident on the file system. 178638450Smckusick */ 178752196Smckusick if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { 178845059Smckusick switch (vp->v_type) { 178945059Smckusick case VREG: case VDIR: case VLNK: 179038450Smckusick return (EROFS); 179145059Smckusick } 179245059Smckusick } 179338450Smckusick /* 179438450Smckusick * If there's shared text associated with 179538450Smckusick * the inode, try to free it up once. If 179638450Smckusick * we fail, we can't allow writing. 179738450Smckusick */ 179845715Smckusick if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) 179938450Smckusick return (ETXTBSY); 180038450Smckusick } 180148050Smckusick if (error = VOP_GETATTR(vp, &vattr, cred, p)) 180245059Smckusick return (error); 180348050Smckusick if ((error = VOP_ACCESS(vp, flags, cred, p)) && 180445059Smckusick cred->cr_uid != vattr.va_uid) 180545059Smckusick return (error); 180645059Smckusick return (0); 180738450Smckusick } 1808