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*55655Smckusick * @(#)nfs_serv.c 7.58 (Berkeley) 07/24/92 1138418Smckusick */ 1238418Smckusick 1338418Smckusick /* 1438418Smckusick * nfs version 2 server calls to vnode ops 1538418Smckusick * - these routines generally have 3 phases 1638418Smckusick * 1 - break down and validate rpc request in mbuf list 1738418Smckusick * 2 - do the vnode ops for the request 1838425Smckusick * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c) 1938418Smckusick * 3 - build the rpc reply in an mbuf list 2038418Smckusick * nb: 2138418Smckusick * - do not mix the phases, since the nfsm_?? macros can return failures 2241899Smckusick * on a bad rpc or similar and do not do any vrele() or vput()'s 2338418Smckusick * 2438425Smckusick * - the nfsm_reply() macro generates an nfs rpc reply with the nfs 2538418Smckusick * error number iff error != 0 whereas 2641899Smckusick * returning an error from the server function implies a fatal error 2741899Smckusick * such as a badly constructed rpc request that should be dropped without 2841899Smckusick * a reply. 2938418Smckusick */ 3038418Smckusick 3153322Smckusick #include <sys/param.h> 3255073Spendry #include <sys/systm.h> 3353322Smckusick #include <sys/proc.h> 3453322Smckusick #include <sys/file.h> 3553322Smckusick #include <sys/namei.h> 3653322Smckusick #include <sys/vnode.h> 3753322Smckusick #include <sys/mount.h> 3853322Smckusick #include <sys/mbuf.h> 3953322Smckusick #include <sys/dirent.h> 4054446Smckusick #include <sys/stat.h> 4147573Skarels 4253322Smckusick #include <vm/vm.h> 4347573Skarels 4453322Smckusick #include <nfs/nfsv2.h> 4553322Smckusick #include <nfs/rpcv2.h> 4653322Smckusick #include <nfs/nfs.h> 4753322Smckusick #include <nfs/xdr_subs.h> 4853322Smckusick #include <nfs/nfsm_subs.h> 4953322Smckusick #include <nfs/nqnfs.h> 5053322Smckusick 5138418Smckusick /* Defs */ 5238425Smckusick #define TRUE 1 5338425Smckusick #define FALSE 0 5438418Smckusick 5538418Smckusick /* Global vars */ 5638418Smckusick extern u_long nfs_procids[NFS_NPROCS]; 5738418Smckusick extern u_long nfs_xdrneg1; 5838418Smckusick extern u_long nfs_false, nfs_true; 5952196Smckusick nfstype nfs_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, 6042242Smckusick NFCHR, NFNON }; 6138418Smckusick 6238418Smckusick /* 6338418Smckusick * nfs getattr service 6438418Smckusick */ 6552196Smckusick nfsrv_getattr(nfsd, mrep, md, dpos, cred, nam, mrq) 6652196Smckusick struct nfsd *nfsd; 6738418Smckusick struct mbuf *mrep, *md; 6838418Smckusick caddr_t dpos; 6938418Smckusick struct ucred *cred; 7052196Smckusick struct mbuf *nam, **mrq; 7138418Smckusick { 7238884Smacklem register struct nfsv2_fattr *fp; 7338418Smckusick struct vattr va; 7438418Smckusick register struct vattr *vap = &va; 7538418Smckusick struct vnode *vp; 7638418Smckusick nfsv2fh_t nfh; 7738418Smckusick fhandle_t *fhp; 7848050Smckusick register u_long *tl; 7939494Smckusick register long t1; 8039494Smckusick caddr_t bpos; 8152196Smckusick int error = 0, rdonly, cache; 8239494Smckusick char *cp2; 8339753Smckusick struct mbuf *mb, *mb2, *mreq; 8452196Smckusick u_quad_t frev; 8538418Smckusick 8638418Smckusick fhp = &nfh.fh_generic; 8738418Smckusick nfsm_srvmtofh(fhp); 8852196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 8938418Smckusick nfsm_reply(0); 9052196Smckusick nqsrv_getl(vp, NQL_READ); 9152196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 9238418Smckusick vput(vp); 9338418Smckusick nfsm_reply(NFSX_FATTR); 9438884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 9539753Smckusick nfsm_srvfillattr; 9638418Smckusick nfsm_srvdone; 9738418Smckusick } 9838418Smckusick 9938418Smckusick /* 10038418Smckusick * nfs setattr service 10138418Smckusick */ 10252196Smckusick nfsrv_setattr(nfsd, mrep, md, dpos, cred, nam, mrq) 10352196Smckusick struct nfsd *nfsd; 10438418Smckusick struct mbuf *mrep, *md; 10538418Smckusick caddr_t dpos; 10638418Smckusick struct ucred *cred; 10752196Smckusick struct mbuf *nam, **mrq; 10838418Smckusick { 10938418Smckusick struct vattr va; 11038418Smckusick register struct vattr *vap = &va; 11138884Smacklem register struct nfsv2_sattr *sp; 11238884Smacklem register struct nfsv2_fattr *fp; 11338418Smckusick struct vnode *vp; 11438418Smckusick nfsv2fh_t nfh; 11538418Smckusick fhandle_t *fhp; 11648050Smckusick register u_long *tl; 11739494Smckusick register long t1; 11839494Smckusick caddr_t bpos; 11952196Smckusick int error = 0, rdonly, cache, duration2, cache2; 12039494Smckusick char *cp2; 12139753Smckusick struct mbuf *mb, *mb2, *mreq; 12252196Smckusick u_quad_t frev, frev2; 12338418Smckusick 12438418Smckusick fhp = &nfh.fh_generic; 12538418Smckusick nfsm_srvmtofh(fhp); 12652196Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR); 12752196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 12838418Smckusick nfsm_reply(0); 12952196Smckusick nqsrv_getl(vp, NQL_WRITE); 13052196Smckusick if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) 13138418Smckusick goto out; 13241361Smckusick VATTR_NULL(vap); 13338418Smckusick /* 13438418Smckusick * Nah nah nah nah na nah 13538418Smckusick * There is a bug in the Sun client that puts 0xffff in the mode 13638418Smckusick * field of sattr when it should put in 0xffffffff. The u_short 13738418Smckusick * doesn't sign extend. 13838418Smckusick * --> check the low order 2 bytes for 0xffff 13938418Smckusick */ 14038884Smacklem if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff) 14138884Smacklem vap->va_mode = nfstov_mode(sp->sa_mode); 14238884Smacklem if (sp->sa_uid != nfs_xdrneg1) 14338884Smacklem vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid); 14438884Smacklem if (sp->sa_gid != nfs_xdrneg1) 14538884Smacklem vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid); 14639753Smckusick if (sp->sa_size != nfs_xdrneg1) 14738884Smacklem vap->va_size = fxdr_unsigned(u_long, sp->sa_size); 14839753Smckusick /* 14939753Smckusick * The usec field of sa_atime is overloaded with the va_flags field 15039753Smckusick * for 4.4BSD clients. Hopefully other clients always set both the 15139753Smckusick * sec and usec fields to -1 when not setting the atime. 15239753Smckusick */ 15339753Smckusick if (sp->sa_atime.tv_sec != nfs_xdrneg1) { 15454106Smckusick vap->va_atime.ts_sec = fxdr_unsigned(long, sp->sa_atime.tv_sec); 15554106Smckusick vap->va_atime.ts_nsec = 0; 15638425Smckusick } 15739753Smckusick if (sp->sa_atime.tv_usec != nfs_xdrneg1) 15839753Smckusick vap->va_flags = fxdr_unsigned(u_long, sp->sa_atime.tv_usec); 15938884Smacklem if (sp->sa_mtime.tv_sec != nfs_xdrneg1) 16038884Smacklem fxdr_time(&sp->sa_mtime, &vap->va_mtime); 16152196Smckusick if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) { 16238418Smckusick vput(vp); 16338418Smckusick nfsm_reply(0); 16438418Smckusick } 16552196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 16638418Smckusick out: 16738418Smckusick vput(vp); 16852196Smckusick nfsm_reply(NFSX_FATTR + 2*NFSX_UNSIGNED); 16938884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 17039753Smckusick nfsm_srvfillattr; 17152196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 17252196Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 17352196Smckusick txdr_hyper(&frev2, tl); 17452196Smckusick } 17538418Smckusick nfsm_srvdone; 17638418Smckusick } 17738418Smckusick 17838418Smckusick /* 17938418Smckusick * nfs lookup rpc 18038418Smckusick */ 18152196Smckusick nfsrv_lookup(nfsd, mrep, md, dpos, cred, nam, mrq) 18252196Smckusick struct nfsd *nfsd; 18338418Smckusick struct mbuf *mrep, *md; 18438418Smckusick caddr_t dpos; 18538418Smckusick struct ucred *cred; 18652196Smckusick struct mbuf *nam, **mrq; 18738418Smckusick { 18838884Smacklem register struct nfsv2_fattr *fp; 18949742Smckusick struct nameidata nd; 19038418Smckusick struct vnode *vp; 19138418Smckusick nfsv2fh_t nfh; 19238418Smckusick fhandle_t *fhp; 19339494Smckusick register caddr_t cp; 19448050Smckusick register u_long *tl; 19539494Smckusick register long t1; 19639494Smckusick caddr_t bpos; 19752196Smckusick int error = 0, lflag = 0, rdonly, cache, duration2, cache2, len; 19839494Smckusick char *cp2; 19939753Smckusick struct mbuf *mb, *mb2, *mreq; 20038418Smckusick struct vattr va, *vap = &va; 20152196Smckusick u_quad_t frev, frev2; 20238418Smckusick 20338418Smckusick fhp = &nfh.fh_generic; 20452196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 20552196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 20652196Smckusick if (*tl) { 20752196Smckusick lflag = fxdr_unsigned(int, *tl); 20852196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 20952196Smckusick duration2 = fxdr_unsigned(int, *tl); 21052196Smckusick } 21152196Smckusick } 21238418Smckusick nfsm_srvmtofh(fhp); 21338418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 21452316Sheideman nd.ni_cnd.cn_cred = cred; 21552316Sheideman nd.ni_cnd.cn_nameiop = LOOKUP; 21652316Sheideman nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART; 21752653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 21852653Smckusick nfsd->nd_procp)) 21938418Smckusick nfsm_reply(0); 22052196Smckusick nqsrv_getl(nd.ni_startdir, NQL_READ); 22152196Smckusick vrele(nd.ni_startdir); 22252653Smckusick FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 22349742Smckusick vp = nd.ni_vp; 22438418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 22541398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 22638418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 22738418Smckusick vput(vp); 22838418Smckusick nfsm_reply(0); 22938418Smckusick } 23052196Smckusick if (lflag) 23152196Smckusick (void) nqsrv_getlease(vp, &duration2, lflag, nfsd, 23252196Smckusick nam, &cache2, &frev2, cred); 23352196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 23438418Smckusick vput(vp); 23552196Smckusick nfsm_reply(NFSX_FH + NFSX_FATTR + 5*NFSX_UNSIGNED); 23652196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 23752196Smckusick if (lflag) { 23852196Smckusick nfsm_build(tl, u_long *, 5*NFSX_UNSIGNED); 23952196Smckusick *tl++ = txdr_unsigned(lflag); 24052196Smckusick *tl++ = txdr_unsigned(cache2); 24152196Smckusick *tl++ = txdr_unsigned(duration2); 24252196Smckusick txdr_hyper(&frev2, tl); 24352196Smckusick } else { 24452196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 24552196Smckusick *tl = 0; 24652196Smckusick } 24752196Smckusick } 24838418Smckusick nfsm_srvfhtom(fhp); 24938884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 25039753Smckusick nfsm_srvfillattr; 25138418Smckusick nfsm_srvdone; 25238418Smckusick } 25338418Smckusick 25438418Smckusick /* 25538418Smckusick * nfs readlink service 25638418Smckusick */ 25752196Smckusick nfsrv_readlink(nfsd, mrep, md, dpos, cred, nam, mrq) 25852196Smckusick struct nfsd *nfsd; 25938418Smckusick struct mbuf *mrep, *md; 26038418Smckusick caddr_t dpos; 26138418Smckusick struct ucred *cred; 26252196Smckusick struct mbuf *nam, **mrq; 26338418Smckusick { 26441899Smckusick struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN]; 26538418Smckusick register struct iovec *ivp = iv; 26638418Smckusick register struct mbuf *mp; 26748050Smckusick register u_long *tl; 26839494Smckusick register long t1; 26939494Smckusick caddr_t bpos; 27052196Smckusick int error = 0, rdonly, cache, i, tlen, len; 27139494Smckusick char *cp2; 27239753Smckusick struct mbuf *mb, *mb2, *mp2, *mp3, *mreq; 27338418Smckusick struct vnode *vp; 27438418Smckusick nfsv2fh_t nfh; 27538418Smckusick fhandle_t *fhp; 27638418Smckusick struct uio io, *uiop = &io; 27752196Smckusick u_quad_t frev; 27838418Smckusick 27938418Smckusick fhp = &nfh.fh_generic; 28038418Smckusick nfsm_srvmtofh(fhp); 28138418Smckusick len = 0; 28238418Smckusick i = 0; 28338418Smckusick while (len < NFS_MAXPATHLEN) { 28438418Smckusick MGET(mp, M_WAIT, MT_DATA); 28541899Smckusick MCLGET(mp, M_WAIT); 28638418Smckusick mp->m_len = NFSMSIZ(mp); 28738418Smckusick if (len == 0) 28838418Smckusick mp3 = mp2 = mp; 28941899Smckusick else { 29038418Smckusick mp2->m_next = mp; 29141899Smckusick mp2 = mp; 29241899Smckusick } 29338418Smckusick if ((len+mp->m_len) > NFS_MAXPATHLEN) { 29438418Smckusick mp->m_len = NFS_MAXPATHLEN-len; 29538418Smckusick len = NFS_MAXPATHLEN; 29638418Smckusick } else 29738418Smckusick len += mp->m_len; 29838418Smckusick ivp->iov_base = mtod(mp, caddr_t); 29938418Smckusick ivp->iov_len = mp->m_len; 30038418Smckusick i++; 30138418Smckusick ivp++; 30238418Smckusick } 30338418Smckusick uiop->uio_iov = iv; 30438418Smckusick uiop->uio_iovcnt = i; 30538418Smckusick uiop->uio_offset = 0; 30638418Smckusick uiop->uio_resid = len; 30738418Smckusick uiop->uio_rw = UIO_READ; 30838418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 30948050Smckusick uiop->uio_procp = (struct proc *)0; 31052196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) { 31138418Smckusick m_freem(mp3); 31238418Smckusick nfsm_reply(0); 31338418Smckusick } 31438418Smckusick if (vp->v_type != VLNK) { 31538418Smckusick error = EINVAL; 31638418Smckusick goto out; 31738418Smckusick } 31852196Smckusick nqsrv_getl(vp, NQL_READ); 31938418Smckusick error = VOP_READLINK(vp, uiop, cred); 32038418Smckusick out: 32138418Smckusick vput(vp); 32238418Smckusick if (error) 32338418Smckusick m_freem(mp3); 32438418Smckusick nfsm_reply(NFSX_UNSIGNED); 32538418Smckusick if (uiop->uio_resid > 0) { 32638418Smckusick len -= uiop->uio_resid; 32738418Smckusick tlen = nfsm_rndup(len); 32838418Smckusick nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len); 32938418Smckusick } 33048050Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 33148050Smckusick *tl = txdr_unsigned(len); 33238418Smckusick mb->m_next = mp3; 33338418Smckusick nfsm_srvdone; 33438418Smckusick } 33538418Smckusick 33638418Smckusick /* 33738418Smckusick * nfs read service 33838418Smckusick */ 33952196Smckusick nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq) 34052196Smckusick struct nfsd *nfsd; 34138418Smckusick struct mbuf *mrep, *md; 34238418Smckusick caddr_t dpos; 34338418Smckusick struct ucred *cred; 34452196Smckusick struct mbuf *nam, **mrq; 34538418Smckusick { 34643350Smckusick register struct iovec *iv; 34743350Smckusick struct iovec *iv2; 34841899Smckusick register struct mbuf *m; 34938884Smacklem register struct nfsv2_fattr *fp; 35048050Smckusick register u_long *tl; 35139494Smckusick register long t1; 35239494Smckusick caddr_t bpos; 35352196Smckusick int error = 0, rdonly, cache, i, cnt, len, left, siz, tlen; 35439494Smckusick char *cp2; 35539753Smckusick struct mbuf *mb, *mb2, *mreq; 35652196Smckusick struct mbuf *m2; 35738418Smckusick struct vnode *vp; 35838418Smckusick nfsv2fh_t nfh; 35938418Smckusick fhandle_t *fhp; 36038418Smckusick struct uio io, *uiop = &io; 36138418Smckusick struct vattr va, *vap = &va; 36238418Smckusick off_t off; 36352196Smckusick u_quad_t frev; 36438418Smckusick 36538418Smckusick fhp = &nfh.fh_generic; 36638418Smckusick nfsm_srvmtofh(fhp); 36752196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 36848050Smckusick off = fxdr_unsigned(off_t, *tl); 36938418Smckusick nfsm_srvstrsiz(cnt, NFS_MAXDATA); 37052196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 37138418Smckusick nfsm_reply(0); 37252196Smckusick nqsrv_getl(vp, NQL_READ); 37352196Smckusick if (error = nfsrv_access(vp, VREAD | VEXEC, cred, rdonly, nfsd->nd_procp)) { 37438418Smckusick vput(vp); 37538418Smckusick nfsm_reply(0); 37638418Smckusick } 37752196Smckusick if (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp)) { 37838418Smckusick vput(vp); 37938418Smckusick nfsm_reply(0); 38038418Smckusick } 38152196Smckusick if (off >= vap->va_size) 38252196Smckusick cnt = 0; 38352196Smckusick else if ((off + cnt) > vap->va_size) 38452196Smckusick cnt = nfsm_rndup(vap->va_size - off); 38552196Smckusick nfsm_reply(NFSX_FATTR+NFSX_UNSIGNED+nfsm_rndup(cnt)); 38652196Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 38752196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 38852196Smckusick len = left = cnt; 38952196Smckusick if (cnt > 0) { 39052196Smckusick /* 39152196Smckusick * Generate the mbuf list with the uio_iov ref. to it. 39252196Smckusick */ 39352196Smckusick i = 0; 39452196Smckusick m = m2 = mb; 39552196Smckusick MALLOC(iv, struct iovec *, 39652196Smckusick ((NFS_MAXDATA+MLEN-1)/MLEN) * sizeof (struct iovec), 39752196Smckusick M_TEMP, M_WAITOK); 39852196Smckusick iv2 = iv; 39952196Smckusick while (left > 0) { 40055057Spendry siz = min(M_TRAILINGSPACE(m), left); 40152196Smckusick if (siz > 0) { 40252196Smckusick m->m_len += siz; 40352196Smckusick iv->iov_base = bpos; 40452196Smckusick iv->iov_len = siz; 40552196Smckusick iv++; 40652196Smckusick i++; 40752196Smckusick left -= siz; 40852196Smckusick } 40952196Smckusick if (left > 0) { 41052196Smckusick MGET(m, M_WAIT, MT_DATA); 41152196Smckusick MCLGET(m, M_WAIT); 41252196Smckusick m->m_len = 0; 41352196Smckusick m2->m_next = m; 41452196Smckusick m2 = m; 41552196Smckusick bpos = mtod(m, caddr_t); 41652196Smckusick } 41752196Smckusick } 41852196Smckusick uiop->uio_iov = iv2; 41952196Smckusick uiop->uio_iovcnt = i; 42052196Smckusick uiop->uio_offset = off; 42152196Smckusick uiop->uio_resid = cnt; 42252196Smckusick uiop->uio_rw = UIO_READ; 42352196Smckusick uiop->uio_segflg = UIO_SYSSPACE; 42452196Smckusick error = VOP_READ(vp, uiop, IO_NODELOCKED, cred); 42552196Smckusick off = uiop->uio_offset; 42652196Smckusick FREE((caddr_t)iv2, M_TEMP); 42752196Smckusick if (error || (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp))) { 42852196Smckusick m_freem(mreq); 42952196Smckusick vput(vp); 43052196Smckusick nfsm_reply(0); 43152196Smckusick } 43252196Smckusick } else 43352196Smckusick uiop->uio_resid = 0; 43438418Smckusick vput(vp); 43539753Smckusick nfsm_srvfillattr; 43645877Smckusick len -= uiop->uio_resid; 43752196Smckusick tlen = nfsm_rndup(len); 43852196Smckusick if (cnt != tlen || tlen != len) 43952196Smckusick nfsm_adj(mb, cnt-tlen, tlen-len); 44048050Smckusick *tl = txdr_unsigned(len); 44138418Smckusick nfsm_srvdone; 44238418Smckusick } 44338418Smckusick 44438418Smckusick /* 44538418Smckusick * nfs write service 44638418Smckusick */ 44752196Smckusick nfsrv_write(nfsd, mrep, md, dpos, cred, nam, mrq) 44852196Smckusick struct nfsd *nfsd; 44952196Smckusick struct mbuf *mrep, *md; 45038418Smckusick caddr_t dpos; 45138418Smckusick struct ucred *cred; 45252196Smckusick struct mbuf *nam, **mrq; 45338418Smckusick { 45438418Smckusick register struct iovec *ivp; 45538418Smckusick register struct mbuf *mp; 45638884Smacklem register struct nfsv2_fattr *fp; 45741899Smckusick struct iovec iv[NFS_MAXIOVEC]; 45838418Smckusick struct vattr va; 45938418Smckusick register struct vattr *vap = &va; 46048050Smckusick register u_long *tl; 46139494Smckusick register long t1; 46239494Smckusick caddr_t bpos; 46352196Smckusick int error = 0, rdonly, cache, siz, len, xfer; 46439494Smckusick char *cp2; 46539753Smckusick struct mbuf *mb, *mb2, *mreq; 46638418Smckusick struct vnode *vp; 46738418Smckusick nfsv2fh_t nfh; 46838418Smckusick fhandle_t *fhp; 46938418Smckusick struct uio io, *uiop = &io; 47038418Smckusick off_t off; 47152196Smckusick u_quad_t frev; 47238418Smckusick 47338418Smckusick fhp = &nfh.fh_generic; 47438418Smckusick nfsm_srvmtofh(fhp); 47552196Smckusick nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); 47648050Smckusick off = fxdr_unsigned(off_t, *++tl); 47748050Smckusick tl += 2; 47848050Smckusick len = fxdr_unsigned(long, *tl); 47938418Smckusick if (len > NFS_MAXDATA || len <= 0) { 48038418Smckusick error = EBADRPC; 48138418Smckusick nfsm_reply(0); 48238418Smckusick } 48338418Smckusick if (dpos == (mtod(md, caddr_t)+md->m_len)) { 48438418Smckusick mp = md->m_next; 48538418Smckusick if (mp == NULL) { 48638418Smckusick error = EBADRPC; 48738418Smckusick nfsm_reply(0); 48838418Smckusick } 48938418Smckusick } else { 49038418Smckusick mp = md; 49138418Smckusick siz = dpos-mtod(mp, caddr_t); 49238418Smckusick mp->m_len -= siz; 49338418Smckusick NFSMADV(mp, siz); 49438418Smckusick } 49552196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 49638418Smckusick nfsm_reply(0); 49752196Smckusick nqsrv_getl(vp, NQL_WRITE); 49852196Smckusick if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) { 49938418Smckusick vput(vp); 50038418Smckusick nfsm_reply(0); 50138418Smckusick } 50238418Smckusick uiop->uio_resid = 0; 50338418Smckusick uiop->uio_rw = UIO_WRITE; 50438418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 50548050Smckusick uiop->uio_procp = (struct proc *)0; 50638418Smckusick /* 50741899Smckusick * Do up to NFS_MAXIOVEC mbufs of write each iteration of the 50838418Smckusick * loop until done. 50938418Smckusick */ 51038418Smckusick while (len > 0 && uiop->uio_resid == 0) { 51138418Smckusick ivp = iv; 51238418Smckusick siz = 0; 51338418Smckusick uiop->uio_iov = ivp; 51438418Smckusick uiop->uio_iovcnt = 0; 51538418Smckusick uiop->uio_offset = off; 51641899Smckusick while (len > 0 && uiop->uio_iovcnt < NFS_MAXIOVEC && mp != NULL) { 51738418Smckusick ivp->iov_base = mtod(mp, caddr_t); 51838418Smckusick if (len < mp->m_len) 51938418Smckusick ivp->iov_len = xfer = len; 52038418Smckusick else 52138418Smckusick ivp->iov_len = xfer = mp->m_len; 52238418Smckusick #ifdef notdef 52338418Smckusick /* Not Yet .. */ 52438418Smckusick if (M_HASCL(mp) && (((u_long)ivp->iov_base) & CLOFSET) == 0) 52538418Smckusick ivp->iov_op = NULL; /* what should it be ?? */ 52638418Smckusick else 52738418Smckusick ivp->iov_op = NULL; 52838418Smckusick #endif 52938418Smckusick uiop->uio_iovcnt++; 53038418Smckusick ivp++; 53138418Smckusick len -= xfer; 53238418Smckusick siz += xfer; 53338418Smckusick mp = mp->m_next; 53438418Smckusick } 53538418Smckusick if (len > 0 && mp == NULL) { 53638418Smckusick error = EBADRPC; 53738418Smckusick vput(vp); 53838418Smckusick nfsm_reply(0); 53938418Smckusick } 54038418Smckusick uiop->uio_resid = siz; 54139586Smckusick if (error = VOP_WRITE(vp, uiop, IO_SYNC | IO_NODELOCKED, 54238418Smckusick cred)) { 54338418Smckusick vput(vp); 54438418Smckusick nfsm_reply(0); 54538418Smckusick } 54639586Smckusick off = uiop->uio_offset; 54738418Smckusick } 54852196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 54938418Smckusick vput(vp); 55038418Smckusick nfsm_reply(NFSX_FATTR); 55138884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 55239753Smckusick nfsm_srvfillattr; 55352442Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 55452442Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 55552442Smckusick txdr_hyper(&vap->va_filerev, tl); 55652442Smckusick } 55738418Smckusick nfsm_srvdone; 55838418Smckusick } 55938418Smckusick 56038418Smckusick /* 56138418Smckusick * nfs create service 56238418Smckusick * now does a truncate to 0 length via. setattr if it already exists 56338418Smckusick */ 56452196Smckusick nfsrv_create(nfsd, mrep, md, dpos, cred, nam, mrq) 56552196Smckusick struct nfsd *nfsd; 56652196Smckusick struct mbuf *mrep, *md; 56738418Smckusick caddr_t dpos; 56838418Smckusick struct ucred *cred; 56952196Smckusick struct mbuf *nam, **mrq; 57038418Smckusick { 57138884Smacklem register struct nfsv2_fattr *fp; 57238418Smckusick struct vattr va; 57338418Smckusick register struct vattr *vap = &va; 57449742Smckusick struct nameidata nd; 57539494Smckusick register caddr_t cp; 57648050Smckusick register u_long *tl; 57739494Smckusick register long t1; 57839494Smckusick caddr_t bpos; 57952196Smckusick int error = 0, rdev, cache, len; 58039494Smckusick char *cp2; 58139753Smckusick struct mbuf *mb, *mb2, *mreq; 58238418Smckusick struct vnode *vp; 58338418Smckusick nfsv2fh_t nfh; 58438418Smckusick fhandle_t *fhp; 58552196Smckusick u_quad_t frev; 58638418Smckusick 58752316Sheideman nd.ni_cnd.cn_nameiop = 0; 58838418Smckusick fhp = &nfh.fh_generic; 58938418Smckusick nfsm_srvmtofh(fhp); 59038418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 59152316Sheideman nd.ni_cnd.cn_cred = cred; 59252316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 59352316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART; 59452653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 59552653Smckusick nfsd->nd_procp)) 59638418Smckusick nfsm_reply(0); 59741361Smckusick VATTR_NULL(vap); 59852196Smckusick nfsm_dissect(tl, u_long *, NFSX_SATTR); 59938418Smckusick /* 60038418Smckusick * Iff doesn't exist, create it 60138418Smckusick * otherwise just truncate to 0 length 60238418Smckusick * should I set the mode too ?? 60338418Smckusick */ 60449742Smckusick if (nd.ni_vp == NULL) { 60548050Smckusick vap->va_type = IFTOVT(fxdr_unsigned(u_long, *tl)); 60642867Smckusick if (vap->va_type == VNON) 60742867Smckusick vap->va_type = VREG; 60848050Smckusick vap->va_mode = nfstov_mode(*tl); 60948050Smckusick rdev = fxdr_unsigned(long, *(tl+3)); 61046988Smckusick if (vap->va_type == VREG || vap->va_type == VSOCK) { 61149742Smckusick vrele(nd.ni_startdir); 61252196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 61352234Sheideman if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) 61442242Smckusick nfsm_reply(0); 61552316Sheideman FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 61642242Smckusick } else if (vap->va_type == VCHR || vap->va_type == VBLK || 61742242Smckusick vap->va_type == VFIFO) { 61842242Smckusick if (vap->va_type == VCHR && rdev == 0xffffffff) 61942242Smckusick vap->va_type = VFIFO; 62042242Smckusick if (vap->va_type == VFIFO) { 62142242Smckusick #ifndef FIFO 62252234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 62349742Smckusick vput(nd.ni_dvp); 62442242Smckusick error = ENXIO; 62549742Smckusick goto out; 62642242Smckusick #endif /* FIFO */ 62752196Smckusick } else if (error = suser(cred, (u_short *)0)) { 62852234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 62949742Smckusick vput(nd.ni_dvp); 63049742Smckusick goto out; 63142242Smckusick } else 63242242Smckusick vap->va_rdev = (dev_t)rdev; 63352196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 63452234Sheideman if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) { 63549742Smckusick vrele(nd.ni_startdir); 63642242Smckusick nfsm_reply(0); 63749742Smckusick } 63852316Sheideman nd.ni_cnd.cn_nameiop = LOOKUP; 63952316Sheideman nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART); 64052316Sheideman nd.ni_cnd.cn_proc = nfsd->nd_procp; 64152316Sheideman nd.ni_cnd.cn_cred = nfsd->nd_procp->p_ucred; 64252316Sheideman if (error = lookup(&nd)) { 64352316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 64442242Smckusick nfsm_reply(0); 64549742Smckusick } 64652316Sheideman FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 64752316Sheideman if (nd.ni_cnd.cn_flags & ISSYMLINK) { 64849742Smckusick vrele(nd.ni_dvp); 64949742Smckusick vput(nd.ni_vp); 65052234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 65149742Smckusick error = EINVAL; 65249742Smckusick nfsm_reply(0); 65349742Smckusick } 65442242Smckusick } else { 65552234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 65649742Smckusick vput(nd.ni_dvp); 65742242Smckusick error = ENXIO; 65849742Smckusick goto out; 65942242Smckusick } 66049742Smckusick vp = nd.ni_vp; 66138418Smckusick } else { 66249742Smckusick vrele(nd.ni_startdir); 66352316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 66449742Smckusick vp = nd.ni_vp; 66549742Smckusick if (nd.ni_dvp == vp) 66649742Smckusick vrele(nd.ni_dvp); 66743359Smckusick else 66849742Smckusick vput(nd.ni_dvp); 66952234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 67038418Smckusick vap->va_size = 0; 67152196Smckusick nqsrv_getl(vp, NQL_WRITE); 67252196Smckusick if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) { 67342506Smckusick vput(vp); 67438418Smckusick nfsm_reply(0); 67542506Smckusick } 67638418Smckusick } 67738418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 67841398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 67938418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 68038418Smckusick vput(vp); 68138418Smckusick nfsm_reply(0); 68238418Smckusick } 68352196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 68438418Smckusick vput(vp); 68538418Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR); 68638418Smckusick nfsm_srvfhtom(fhp); 68738884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 68839753Smckusick nfsm_srvfillattr; 68938418Smckusick return (error); 69038418Smckusick nfsmout: 69152316Sheideman if (nd.ni_cnd.cn_nameiop || nd.ni_cnd.cn_flags) 69251464Sbostic vrele(nd.ni_startdir); 69352234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 69449742Smckusick if (nd.ni_dvp == nd.ni_vp) 69549742Smckusick vrele(nd.ni_dvp); 69643359Smckusick else 69749742Smckusick vput(nd.ni_dvp); 69849742Smckusick if (nd.ni_vp) 69949742Smckusick vput(nd.ni_vp); 70038418Smckusick return (error); 70149742Smckusick 70249742Smckusick out: 70349742Smckusick vrele(nd.ni_startdir); 70452316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 70549742Smckusick nfsm_reply(0); 70638418Smckusick } 70738418Smckusick 70838418Smckusick /* 70938418Smckusick * nfs remove service 71038418Smckusick */ 71152196Smckusick nfsrv_remove(nfsd, mrep, md, dpos, cred, nam, mrq) 71252196Smckusick struct nfsd *nfsd; 71352196Smckusick struct mbuf *mrep, *md; 71438418Smckusick caddr_t dpos; 71538418Smckusick struct ucred *cred; 71652196Smckusick struct mbuf *nam, **mrq; 71738418Smckusick { 71849742Smckusick struct nameidata nd; 71948050Smckusick register u_long *tl; 72039494Smckusick register long t1; 72139494Smckusick caddr_t bpos; 72252196Smckusick int error = 0, cache, len; 72339494Smckusick char *cp2; 72439753Smckusick struct mbuf *mb, *mreq; 72538418Smckusick struct vnode *vp; 72638418Smckusick nfsv2fh_t nfh; 72738418Smckusick fhandle_t *fhp; 72852196Smckusick u_quad_t frev; 72938418Smckusick 73038418Smckusick fhp = &nfh.fh_generic; 73138418Smckusick nfsm_srvmtofh(fhp); 73238418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 73352316Sheideman nd.ni_cnd.cn_cred = cred; 73452316Sheideman nd.ni_cnd.cn_nameiop = DELETE; 73552316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 73652653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 73752653Smckusick nfsd->nd_procp)) 73838418Smckusick nfsm_reply(0); 73949742Smckusick vp = nd.ni_vp; 74038418Smckusick if (vp->v_type == VDIR && 74152196Smckusick (error = suser(cred, (u_short *)0))) 74238418Smckusick goto out; 74338418Smckusick /* 74449454Smckusick * The root of a mounted filesystem cannot be deleted. 74538418Smckusick */ 74638418Smckusick if (vp->v_flag & VROOT) { 74738418Smckusick error = EBUSY; 74838418Smckusick goto out; 74938418Smckusick } 75038418Smckusick if (vp->v_flag & VTEXT) 75145715Smckusick (void) vnode_pager_uncache(vp); 75238418Smckusick out: 75342467Smckusick if (!error) { 75452196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 75552196Smckusick nqsrv_getl(vp, NQL_WRITE); 75652234Sheideman error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 75742467Smckusick } else { 75852234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 75949742Smckusick if (nd.ni_dvp == vp) 76049742Smckusick vrele(nd.ni_dvp); 76143359Smckusick else 76249742Smckusick vput(nd.ni_dvp); 76342467Smckusick vput(vp); 76442467Smckusick } 76538418Smckusick nfsm_reply(0); 76638418Smckusick nfsm_srvdone; 76738418Smckusick } 76838418Smckusick 76938418Smckusick /* 77038418Smckusick * nfs rename service 77138418Smckusick */ 77252196Smckusick nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq) 77352196Smckusick struct nfsd *nfsd; 77452196Smckusick struct mbuf *mrep, *md; 77538418Smckusick caddr_t dpos; 77638418Smckusick struct ucred *cred; 77752196Smckusick struct mbuf *nam, **mrq; 77838418Smckusick { 77948050Smckusick register u_long *tl; 78039494Smckusick register long t1; 78139494Smckusick caddr_t bpos; 78252196Smckusick int error = 0, rdonly, cache, len, len2; 78339494Smckusick char *cp2; 78439753Smckusick struct mbuf *mb, *mreq; 78549742Smckusick struct nameidata fromnd, tond; 78638418Smckusick struct vnode *fvp, *tvp, *tdvp; 78738418Smckusick nfsv2fh_t fnfh, tnfh; 78838418Smckusick fhandle_t *ffhp, *tfhp; 78952196Smckusick u_quad_t frev; 79052196Smckusick uid_t saved_uid; 79138418Smckusick 79238418Smckusick ffhp = &fnfh.fh_generic; 79338418Smckusick tfhp = &tnfh.fh_generic; 79452316Sheideman fromnd.ni_cnd.cn_nameiop = 0; 79552316Sheideman tond.ni_cnd.cn_nameiop = 0; 79638418Smckusick nfsm_srvmtofh(ffhp); 79738418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 79838418Smckusick /* 79952196Smckusick * Remember our original uid so that we can reset cr_uid before 80052196Smckusick * the second nfs_namei() call, in case it is remapped. 80138418Smckusick */ 80252196Smckusick saved_uid = cred->cr_uid; 80352316Sheideman fromnd.ni_cnd.cn_cred = cred; 80452316Sheideman fromnd.ni_cnd.cn_nameiop = DELETE; 80552316Sheideman fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART; 80652653Smckusick if (error = nfs_namei(&fromnd, ffhp, len, nfsd->nd_slp, nam, &md, 80752653Smckusick &dpos, nfsd->nd_procp)) 80838418Smckusick nfsm_reply(0); 80949742Smckusick fvp = fromnd.ni_vp; 81038418Smckusick nfsm_srvmtofh(tfhp); 81141899Smckusick nfsm_strsiz(len2, NFS_MAXNAMLEN); 81252196Smckusick cred->cr_uid = saved_uid; 81352316Sheideman tond.ni_cnd.cn_cred = cred; 81452316Sheideman tond.ni_cnd.cn_nameiop = RENAME; 81552316Sheideman tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; 81652653Smckusick if (error = nfs_namei(&tond, tfhp, len2, nfsd->nd_slp, nam, &md, 81752653Smckusick &dpos, nfsd->nd_procp)) { 81852234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 81949742Smckusick vrele(fromnd.ni_dvp); 82042467Smckusick vrele(fvp); 82142467Smckusick goto out1; 82242467Smckusick } 82338425Smckusick tdvp = tond.ni_dvp; 82438425Smckusick tvp = tond.ni_vp; 82538418Smckusick if (tvp != NULL) { 82638418Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 82738418Smckusick error = EISDIR; 82838418Smckusick goto out; 82938418Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 83038418Smckusick error = ENOTDIR; 83138418Smckusick goto out; 83238418Smckusick } 83352196Smckusick if (tvp->v_type == VDIR && tvp->v_mountedhere) { 83452196Smckusick error = EXDEV; 83552196Smckusick goto out; 83652196Smckusick } 83738418Smckusick } 83852196Smckusick if (fvp->v_type == VDIR && fvp->v_mountedhere) { 83952196Smckusick error = EBUSY; 84052196Smckusick goto out; 84152196Smckusick } 84238418Smckusick if (fvp->v_mount != tdvp->v_mount) { 84338418Smckusick error = EXDEV; 84438418Smckusick goto out; 84538418Smckusick } 84649742Smckusick if (fvp == tdvp) 84738418Smckusick error = EINVAL; 84849742Smckusick /* 84949742Smckusick * If source is the same as the destination (that is the 85049742Smckusick * same vnode with the same name in the same directory), 85149742Smckusick * then there is nothing to do. 85249742Smckusick */ 85349742Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 85452316Sheideman fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 85552316Sheideman !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 85652316Sheideman fromnd.ni_cnd.cn_namelen)) 85749742Smckusick error = -1; 85838418Smckusick out: 85942467Smckusick if (!error) { 86052196Smckusick nqsrv_getl(fromnd.ni_dvp, NQL_WRITE); 86152196Smckusick nqsrv_getl(tdvp, NQL_WRITE); 86252196Smckusick if (tvp) 86352196Smckusick nqsrv_getl(tvp, NQL_WRITE); 86452234Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 86552234Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 86642467Smckusick } else { 86752234Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 86843359Smckusick if (tdvp == tvp) 86943359Smckusick vrele(tdvp); 87043359Smckusick else 87143359Smckusick vput(tdvp); 87242467Smckusick if (tvp) 87342467Smckusick vput(tvp); 87452234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 87549742Smckusick vrele(fromnd.ni_dvp); 87642467Smckusick vrele(fvp); 87738418Smckusick } 87846513Smckusick vrele(tond.ni_startdir); 87952316Sheideman FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 88038418Smckusick out1: 88149742Smckusick vrele(fromnd.ni_startdir); 88252316Sheideman FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 88338418Smckusick nfsm_reply(0); 88438418Smckusick return (error); 88549742Smckusick 88638418Smckusick nfsmout: 88752316Sheideman if (tond.ni_cnd.cn_nameiop || tond.ni_cnd.cn_flags) { 88849742Smckusick vrele(tond.ni_startdir); 88952316Sheideman FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 89049742Smckusick } 89152316Sheideman if (fromnd.ni_cnd.cn_nameiop || fromnd.ni_cnd.cn_flags) { 89249742Smckusick vrele(fromnd.ni_startdir); 89352316Sheideman FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 89452234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 89549742Smckusick vrele(fromnd.ni_dvp); 89649742Smckusick vrele(fvp); 89749742Smckusick } 89838418Smckusick return (error); 89938418Smckusick } 90038418Smckusick 90138418Smckusick /* 90238418Smckusick * nfs link service 90338418Smckusick */ 90452196Smckusick nfsrv_link(nfsd, mrep, md, dpos, cred, nam, mrq) 90552196Smckusick struct nfsd *nfsd; 90652196Smckusick struct mbuf *mrep, *md; 90738418Smckusick caddr_t dpos; 90838418Smckusick struct ucred *cred; 90952196Smckusick struct mbuf *nam, **mrq; 91038418Smckusick { 91149742Smckusick struct nameidata nd; 91248050Smckusick register u_long *tl; 91339494Smckusick register long t1; 91439494Smckusick caddr_t bpos; 91552196Smckusick int error = 0, rdonly, cache, len; 91639494Smckusick char *cp2; 91739753Smckusick struct mbuf *mb, *mreq; 91838418Smckusick struct vnode *vp, *xp; 91938418Smckusick nfsv2fh_t nfh, dnfh; 92038418Smckusick fhandle_t *fhp, *dfhp; 92152196Smckusick u_quad_t frev; 92238418Smckusick 92338418Smckusick fhp = &nfh.fh_generic; 92438418Smckusick dfhp = &dnfh.fh_generic; 92538418Smckusick nfsm_srvmtofh(fhp); 92638418Smckusick nfsm_srvmtofh(dfhp); 92738418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 92852196Smckusick if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 92938418Smckusick nfsm_reply(0); 93052196Smckusick if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0))) 93138418Smckusick goto out1; 93252316Sheideman nd.ni_cnd.cn_cred = cred; 93352316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 93452316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 93552653Smckusick if (error = nfs_namei(&nd, dfhp, len, nfsd->nd_slp, nam, &md, &dpos, 93652653Smckusick nfsd->nd_procp)) 93738418Smckusick goto out1; 93849742Smckusick xp = nd.ni_vp; 93938418Smckusick if (xp != NULL) { 94038418Smckusick error = EEXIST; 94138418Smckusick goto out; 94238418Smckusick } 94349742Smckusick xp = nd.ni_dvp; 94438418Smckusick if (vp->v_mount != xp->v_mount) 94538418Smckusick error = EXDEV; 94638418Smckusick out: 94742467Smckusick if (!error) { 94852196Smckusick nqsrv_getl(vp, NQL_WRITE); 94952196Smckusick nqsrv_getl(xp, NQL_WRITE); 95052933Smckusick error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 95142467Smckusick } else { 95252234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 95349742Smckusick if (nd.ni_dvp == nd.ni_vp) 95449742Smckusick vrele(nd.ni_dvp); 95543359Smckusick else 95649742Smckusick vput(nd.ni_dvp); 95749742Smckusick if (nd.ni_vp) 95849742Smckusick vrele(nd.ni_vp); 95942467Smckusick } 96038418Smckusick out1: 96138418Smckusick vrele(vp); 96238418Smckusick nfsm_reply(0); 96338418Smckusick nfsm_srvdone; 96438418Smckusick } 96538418Smckusick 96638418Smckusick /* 96738418Smckusick * nfs symbolic link service 96838418Smckusick */ 96952196Smckusick nfsrv_symlink(nfsd, mrep, md, dpos, cred, nam, mrq) 97052196Smckusick struct nfsd *nfsd; 97152196Smckusick struct mbuf *mrep, *md; 97238418Smckusick caddr_t dpos; 97338418Smckusick struct ucred *cred; 97452196Smckusick struct mbuf *nam, **mrq; 97538418Smckusick { 97638418Smckusick struct vattr va; 97749742Smckusick struct nameidata nd; 97838418Smckusick register struct vattr *vap = &va; 97948050Smckusick register u_long *tl; 98039494Smckusick register long t1; 98145285Smckusick struct nfsv2_sattr *sp; 98239494Smckusick caddr_t bpos; 98341899Smckusick struct uio io; 98441899Smckusick struct iovec iv; 98552196Smckusick int error = 0, rdonly, cache, len, len2; 98641899Smckusick char *pathcp, *cp2; 98739753Smckusick struct mbuf *mb, *mreq; 98838418Smckusick nfsv2fh_t nfh; 98938418Smckusick fhandle_t *fhp; 99052196Smckusick u_quad_t frev; 99138418Smckusick 99241899Smckusick pathcp = (char *)0; 99338418Smckusick fhp = &nfh.fh_generic; 99438418Smckusick nfsm_srvmtofh(fhp); 99538418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 99652316Sheideman nd.ni_cnd.cn_cred = cred; 99752316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 99852316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 99952653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 100052653Smckusick nfsd->nd_procp)) 100142467Smckusick goto out; 100241899Smckusick nfsm_strsiz(len2, NFS_MAXPATHLEN); 100341899Smckusick MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK); 100441899Smckusick iv.iov_base = pathcp; 100541899Smckusick iv.iov_len = len2; 100641899Smckusick io.uio_resid = len2; 100741899Smckusick io.uio_offset = 0; 100841899Smckusick io.uio_iov = &iv; 100941899Smckusick io.uio_iovcnt = 1; 101041899Smckusick io.uio_segflg = UIO_SYSSPACE; 101141899Smckusick io.uio_rw = UIO_READ; 101248050Smckusick io.uio_procp = (struct proc *)0; 101341899Smckusick nfsm_mtouio(&io, len2); 101452196Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR); 101541899Smckusick *(pathcp + len2) = '\0'; 101649742Smckusick if (nd.ni_vp) { 101752234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 101849742Smckusick if (nd.ni_dvp == nd.ni_vp) 101949742Smckusick vrele(nd.ni_dvp); 102043359Smckusick else 102149742Smckusick vput(nd.ni_dvp); 102249742Smckusick vrele(nd.ni_vp); 102338418Smckusick error = EEXIST; 102438418Smckusick goto out; 102538418Smckusick } 102641361Smckusick VATTR_NULL(vap); 102745285Smckusick vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode); 102852196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 102952234Sheideman error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp); 103038418Smckusick out: 103141899Smckusick if (pathcp) 103241899Smckusick FREE(pathcp, M_TEMP); 103338418Smckusick nfsm_reply(0); 103438418Smckusick return (error); 103538418Smckusick nfsmout: 103652234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 103749742Smckusick if (nd.ni_dvp == nd.ni_vp) 103849742Smckusick vrele(nd.ni_dvp); 103943359Smckusick else 104049742Smckusick vput(nd.ni_dvp); 104149742Smckusick if (nd.ni_vp) 104249742Smckusick vrele(nd.ni_vp); 104341899Smckusick if (pathcp) 104441899Smckusick FREE(pathcp, M_TEMP); 104538418Smckusick return (error); 104638418Smckusick } 104738418Smckusick 104838418Smckusick /* 104938418Smckusick * nfs mkdir service 105038418Smckusick */ 105152196Smckusick nfsrv_mkdir(nfsd, mrep, md, dpos, cred, nam, mrq) 105252196Smckusick struct nfsd *nfsd; 105352196Smckusick struct mbuf *mrep, *md; 105438418Smckusick caddr_t dpos; 105538418Smckusick struct ucred *cred; 105652196Smckusick struct mbuf *nam, **mrq; 105738418Smckusick { 105838418Smckusick struct vattr va; 105938418Smckusick register struct vattr *vap = &va; 106038884Smacklem register struct nfsv2_fattr *fp; 106149742Smckusick struct nameidata nd; 106239494Smckusick register caddr_t cp; 106348050Smckusick register u_long *tl; 106439494Smckusick register long t1; 106539494Smckusick caddr_t bpos; 106652196Smckusick int error = 0, rdonly, cache, len; 106739494Smckusick char *cp2; 106839753Smckusick struct mbuf *mb, *mb2, *mreq; 106938418Smckusick struct vnode *vp; 107038418Smckusick nfsv2fh_t nfh; 107138418Smckusick fhandle_t *fhp; 107252196Smckusick u_quad_t frev; 107338418Smckusick 107438418Smckusick fhp = &nfh.fh_generic; 107538418Smckusick nfsm_srvmtofh(fhp); 107638418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 107752316Sheideman nd.ni_cnd.cn_cred = cred; 107852316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 107952316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 108052653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 108152653Smckusick nfsd->nd_procp)) 108238418Smckusick nfsm_reply(0); 108352196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 108441361Smckusick VATTR_NULL(vap); 108538418Smckusick vap->va_type = VDIR; 108648050Smckusick vap->va_mode = nfstov_mode(*tl++); 108749742Smckusick vp = nd.ni_vp; 108838418Smckusick if (vp != NULL) { 108952234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 109049742Smckusick if (nd.ni_dvp == vp) 109149742Smckusick vrele(nd.ni_dvp); 109243359Smckusick else 109349742Smckusick vput(nd.ni_dvp); 109442467Smckusick vrele(vp); 109538418Smckusick error = EEXIST; 109638418Smckusick nfsm_reply(0); 109738418Smckusick } 109852196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 109952234Sheideman if (error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) 110038418Smckusick nfsm_reply(0); 110149742Smckusick vp = nd.ni_vp; 110238418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 110341398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 110438418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 110538418Smckusick vput(vp); 110638418Smckusick nfsm_reply(0); 110738418Smckusick } 110852196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 110938418Smckusick vput(vp); 111038418Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR); 111138418Smckusick nfsm_srvfhtom(fhp); 111238884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 111339753Smckusick nfsm_srvfillattr; 111438418Smckusick return (error); 111538418Smckusick nfsmout: 111652234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 111749742Smckusick if (nd.ni_dvp == nd.ni_vp) 111849742Smckusick vrele(nd.ni_dvp); 111943359Smckusick else 112049742Smckusick vput(nd.ni_dvp); 112149742Smckusick if (nd.ni_vp) 112249742Smckusick vrele(nd.ni_vp); 112338418Smckusick return (error); 112438418Smckusick } 112538418Smckusick 112638418Smckusick /* 112738418Smckusick * nfs rmdir service 112838418Smckusick */ 112952196Smckusick nfsrv_rmdir(nfsd, mrep, md, dpos, cred, nam, mrq) 113052196Smckusick struct nfsd *nfsd; 113152196Smckusick struct mbuf *mrep, *md; 113238418Smckusick caddr_t dpos; 113338418Smckusick struct ucred *cred; 113452196Smckusick struct mbuf *nam, **mrq; 113538418Smckusick { 113648050Smckusick register u_long *tl; 113739494Smckusick register long t1; 113839494Smckusick caddr_t bpos; 113952196Smckusick int error = 0, rdonly, cache, len; 114039494Smckusick char *cp2; 114139753Smckusick struct mbuf *mb, *mreq; 114238418Smckusick struct vnode *vp; 114338418Smckusick nfsv2fh_t nfh; 114438418Smckusick fhandle_t *fhp; 114549742Smckusick struct nameidata nd; 114652196Smckusick u_quad_t frev; 114738418Smckusick 114838418Smckusick fhp = &nfh.fh_generic; 114938418Smckusick nfsm_srvmtofh(fhp); 115038418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 115152316Sheideman nd.ni_cnd.cn_cred = cred; 115252316Sheideman nd.ni_cnd.cn_nameiop = DELETE; 115352316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 115452653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 115552653Smckusick nfsd->nd_procp)) 115638418Smckusick nfsm_reply(0); 115749742Smckusick vp = nd.ni_vp; 115838418Smckusick if (vp->v_type != VDIR) { 115938418Smckusick error = ENOTDIR; 116038418Smckusick goto out; 116138418Smckusick } 116238418Smckusick /* 116338418Smckusick * No rmdir "." please. 116438418Smckusick */ 116549742Smckusick if (nd.ni_dvp == vp) { 116638418Smckusick error = EINVAL; 116738418Smckusick goto out; 116838418Smckusick } 116938418Smckusick /* 117049454Smckusick * The root of a mounted filesystem cannot be deleted. 117138418Smckusick */ 117238418Smckusick if (vp->v_flag & VROOT) 117338418Smckusick error = EBUSY; 117438418Smckusick out: 117542467Smckusick if (!error) { 117652196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 117752196Smckusick nqsrv_getl(vp, NQL_WRITE); 117852234Sheideman error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 117942467Smckusick } else { 118052234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 118149742Smckusick if (nd.ni_dvp == nd.ni_vp) 118249742Smckusick vrele(nd.ni_dvp); 118343359Smckusick else 118449742Smckusick vput(nd.ni_dvp); 118542467Smckusick vput(vp); 118642467Smckusick } 118738418Smckusick nfsm_reply(0); 118838418Smckusick nfsm_srvdone; 118938418Smckusick } 119038418Smckusick 119138418Smckusick /* 119238418Smckusick * nfs readdir service 119338418Smckusick * - mallocs what it thinks is enough to read 119448050Smckusick * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR 119538418Smckusick * - calls VOP_READDIR() 119640115Smckusick * - loops around building the reply 119738425Smckusick * if the output generated exceeds count break out of loop 119838425Smckusick * The nfsm_clget macro is used here so that the reply will be packed 119938425Smckusick * tightly in mbuf clusters. 120038418Smckusick * - it only knows that it has encountered eof when the VOP_READDIR() 120138425Smckusick * reads nothing 120238418Smckusick * - as such one readdir rpc will return eof false although you are there 120338425Smckusick * and then the next will return eof 120452441Smckusick * - it trims out records with d_fileno == 0 120538425Smckusick * this doesn't matter for Unix clients, but they might confuse clients 120638425Smckusick * for other os'. 120738418Smckusick * NB: It is tempting to set eof to true if the VOP_READDIR() reads less 120838425Smckusick * than requested, but this may not apply to all filesystems. For 120938425Smckusick * example, client NFS does not { although it is never remote mounted 121038425Smckusick * anyhow } 121152196Smckusick * The alternate call nqnfsrv_readdirlook() does lookups as well. 121238418Smckusick * PS: The NFS protocol spec. does not clarify what the "count" byte 121338425Smckusick * argument is a count of.. just name strings and file id's or the 121438425Smckusick * entire reply rpc or ... 121538425Smckusick * I tried just file name and id sizes and it confused the Sun client, 121638425Smckusick * so I am using the full rpc size now. The "paranoia.." comment refers 121738425Smckusick * to including the status longwords that are not a part of the dir. 121838425Smckusick * "entry" structures, but are in the rpc. 121938418Smckusick */ 122052196Smckusick struct flrep { 122152196Smckusick u_long fl_cachable; 122252196Smckusick u_long fl_duration; 122355528Smckusick u_long fl_frev[2]; 122452196Smckusick nfsv2fh_t fl_nfh; 122552196Smckusick struct nfsv2_fattr fl_fattr; 122652196Smckusick }; 122752196Smckusick 122852196Smckusick nfsrv_readdir(nfsd, mrep, md, dpos, cred, nam, mrq) 122952196Smckusick struct nfsd *nfsd; 123038418Smckusick struct mbuf *mrep, *md; 123138418Smckusick caddr_t dpos; 123238418Smckusick struct ucred *cred; 123352196Smckusick struct mbuf *nam, **mrq; 123438418Smckusick { 123538418Smckusick register char *bp, *be; 123638418Smckusick register struct mbuf *mp; 123752441Smckusick register struct dirent *dp; 123839494Smckusick register caddr_t cp; 123948050Smckusick register u_long *tl; 124039494Smckusick register long t1; 124139494Smckusick caddr_t bpos; 124252196Smckusick struct mbuf *mb, *mb2, *mreq, *mp2; 124352196Smckusick char *cpos, *cend, *cp2, *rbuf; 124438418Smckusick struct vnode *vp; 124538418Smckusick nfsv2fh_t nfh; 124638418Smckusick fhandle_t *fhp; 124738418Smckusick struct uio io; 124838418Smckusick struct iovec iv; 124952196Smckusick struct vattr va; 125052196Smckusick int len, nlen, rem, xfer, tsiz, i, error = 0; 125152196Smckusick int siz, cnt, fullsiz, eofflag, rdonly, cache; 125252196Smckusick u_quad_t frev; 125338418Smckusick u_long on; 125438418Smckusick off_t off, toff; 125538418Smckusick 125638418Smckusick fhp = &nfh.fh_generic; 125738418Smckusick nfsm_srvmtofh(fhp); 125852196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 125948050Smckusick toff = fxdr_unsigned(off_t, *tl++); 126048050Smckusick off = (toff & ~(NFS_DIRBLKSIZ-1)); 126148050Smckusick on = (toff & (NFS_DIRBLKSIZ-1)); 126248050Smckusick cnt = fxdr_unsigned(int, *tl); 126348050Smckusick siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); 126441899Smckusick if (cnt > NFS_MAXREADDIR) 126541899Smckusick siz = NFS_MAXREADDIR; 126638418Smckusick fullsiz = siz; 126752196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 126838418Smckusick nfsm_reply(0); 126952196Smckusick nqsrv_getl(vp, NQL_READ); 127052196Smckusick if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { 127138418Smckusick vput(vp); 127238418Smckusick nfsm_reply(0); 127338418Smckusick } 127438418Smckusick VOP_UNLOCK(vp); 127538418Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 127638418Smckusick again: 127738418Smckusick iv.iov_base = rbuf; 127838418Smckusick iv.iov_len = fullsiz; 127938418Smckusick io.uio_iov = &iv; 128038418Smckusick io.uio_iovcnt = 1; 128138418Smckusick io.uio_offset = off; 128238418Smckusick io.uio_resid = fullsiz; 128338418Smckusick io.uio_segflg = UIO_SYSSPACE; 128438418Smckusick io.uio_rw = UIO_READ; 128548050Smckusick io.uio_procp = (struct proc *)0; 128654446Smckusick error = VOP_READDIR(vp, &io, cred); 128739586Smckusick off = io.uio_offset; 128838418Smckusick if (error) { 128938418Smckusick vrele(vp); 129038418Smckusick free((caddr_t)rbuf, M_TEMP); 129138418Smckusick nfsm_reply(0); 129238418Smckusick } 129354446Smckusick if (io.uio_resid < fullsiz) 129454446Smckusick eofflag = 0; 129554446Smckusick else 129654446Smckusick eofflag = 1; 129738418Smckusick if (io.uio_resid) { 129838418Smckusick siz -= io.uio_resid; 129938418Smckusick 130038418Smckusick /* 130138418Smckusick * If nothing read, return eof 130238418Smckusick * rpc reply 130338418Smckusick */ 130438418Smckusick if (siz == 0) { 130538418Smckusick vrele(vp); 130638418Smckusick nfsm_reply(2*NFSX_UNSIGNED); 130748050Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 130848050Smckusick *tl++ = nfs_false; 130948050Smckusick *tl = nfs_true; 131038418Smckusick FREE((caddr_t)rbuf, M_TEMP); 131138418Smckusick return (0); 131238418Smckusick } 131338418Smckusick } 131440115Smckusick 131538418Smckusick /* 131638418Smckusick * Check for degenerate cases of nothing useful read. 131740115Smckusick * If so go try again 131838418Smckusick */ 131940115Smckusick cpos = rbuf + on; 132040115Smckusick cend = rbuf + siz; 132152441Smckusick dp = (struct dirent *)cpos; 132252441Smckusick while (cpos < cend && dp->d_fileno == 0) { 132340115Smckusick cpos += dp->d_reclen; 132452441Smckusick dp = (struct dirent *)cpos; 132540115Smckusick } 132640115Smckusick if (cpos >= cend) { 132738418Smckusick toff = off; 132838418Smckusick siz = fullsiz; 132938418Smckusick on = 0; 133038418Smckusick goto again; 133138418Smckusick } 133240115Smckusick 133340115Smckusick cpos = rbuf + on; 133440115Smckusick cend = rbuf + siz; 133552441Smckusick dp = (struct dirent *)cpos; 133652196Smckusick len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 133752196Smckusick nfsm_reply(siz); 133852196Smckusick mp = mp2 = mb; 133952196Smckusick bp = bpos; 134052196Smckusick be = bp + M_TRAILINGSPACE(mp); 134152196Smckusick 134252196Smckusick /* Loop through the records and build reply */ 134352196Smckusick while (cpos < cend) { 134452441Smckusick if (dp->d_fileno != 0) { 134552196Smckusick nlen = dp->d_namlen; 134652196Smckusick rem = nfsm_rndup(nlen)-nlen; 134752196Smckusick len += (4*NFSX_UNSIGNED + nlen + rem); 134852196Smckusick if (len > cnt) { 134952196Smckusick eofflag = 0; 135052196Smckusick break; 135152196Smckusick } 135252441Smckusick /* 135352441Smckusick * Build the directory record xdr from 135452441Smckusick * the dirent entry. 135552441Smckusick */ 135652196Smckusick nfsm_clget; 135752196Smckusick *tl = nfs_true; 135852196Smckusick bp += NFSX_UNSIGNED; 135952196Smckusick nfsm_clget; 136052441Smckusick *tl = txdr_unsigned(dp->d_fileno); 136152196Smckusick bp += NFSX_UNSIGNED; 136252196Smckusick nfsm_clget; 136352196Smckusick *tl = txdr_unsigned(nlen); 136452196Smckusick bp += NFSX_UNSIGNED; 136552196Smckusick 136652196Smckusick /* And loop around copying the name */ 136752196Smckusick xfer = nlen; 136852196Smckusick cp = dp->d_name; 136952196Smckusick while (xfer > 0) { 137052196Smckusick nfsm_clget; 137152196Smckusick if ((bp+xfer) > be) 137252196Smckusick tsiz = be-bp; 137352196Smckusick else 137452196Smckusick tsiz = xfer; 137552196Smckusick bcopy(cp, bp, tsiz); 137652196Smckusick bp += tsiz; 137752196Smckusick xfer -= tsiz; 137852196Smckusick if (xfer > 0) 137952196Smckusick cp += tsiz; 138052196Smckusick } 138152196Smckusick /* And null pad to a long boundary */ 138252196Smckusick for (i = 0; i < rem; i++) 138352196Smckusick *bp++ = '\0'; 138452196Smckusick nfsm_clget; 138552196Smckusick 138652196Smckusick /* Finish off the record */ 138752196Smckusick toff += dp->d_reclen; 138852196Smckusick *tl = txdr_unsigned(toff); 138952196Smckusick bp += NFSX_UNSIGNED; 139052196Smckusick } else 139152196Smckusick toff += dp->d_reclen; 139252196Smckusick cpos += dp->d_reclen; 139352441Smckusick dp = (struct dirent *)cpos; 139452196Smckusick } 139538418Smckusick vrele(vp); 139652196Smckusick nfsm_clget; 139752196Smckusick *tl = nfs_false; 139852196Smckusick bp += NFSX_UNSIGNED; 139952196Smckusick nfsm_clget; 140052196Smckusick if (eofflag) 140152196Smckusick *tl = nfs_true; 140252196Smckusick else 140352196Smckusick *tl = nfs_false; 140452196Smckusick bp += NFSX_UNSIGNED; 140552196Smckusick if (mp != mb) { 140652196Smckusick if (bp < be) 140752196Smckusick mp->m_len = bp - mtod(mp, caddr_t); 140852196Smckusick } else 140952196Smckusick mp->m_len += bp - bpos; 141052196Smckusick FREE(rbuf, M_TEMP); 141152196Smckusick nfsm_srvdone; 141252196Smckusick } 141352196Smckusick 141452196Smckusick nqnfsrv_readdirlook(nfsd, mrep, md, dpos, cred, nam, mrq) 141552196Smckusick struct nfsd *nfsd; 141652196Smckusick struct mbuf *mrep, *md; 141752196Smckusick caddr_t dpos; 141852196Smckusick struct ucred *cred; 141952196Smckusick struct mbuf *nam, **mrq; 142052196Smckusick { 142152196Smckusick register char *bp, *be; 142252196Smckusick register struct mbuf *mp; 142352441Smckusick register struct dirent *dp; 142452196Smckusick register caddr_t cp; 142552196Smckusick register u_long *tl; 142652196Smckusick register long t1; 142752196Smckusick caddr_t bpos; 142852196Smckusick struct mbuf *mb, *mb2, *mreq, *mp2; 142952196Smckusick char *cpos, *cend, *cp2, *rbuf; 143052196Smckusick struct vnode *vp, *nvp; 143152196Smckusick struct flrep fl; 143252196Smckusick nfsv2fh_t nfh; 143352196Smckusick fhandle_t *fhp; 143452196Smckusick struct uio io; 143552196Smckusick struct iovec iv; 143652196Smckusick struct vattr va, *vap = &va; 143752196Smckusick struct nfsv2_fattr *fp; 143852196Smckusick int len, nlen, rem, xfer, tsiz, i, error = 0, duration2, cache2; 143952196Smckusick int siz, cnt, fullsiz, eofflag, rdonly, cache; 144052196Smckusick u_quad_t frev, frev2; 144152196Smckusick u_long on; 144252196Smckusick off_t off, toff; 144352196Smckusick 144452196Smckusick fhp = &nfh.fh_generic; 144552196Smckusick nfsm_srvmtofh(fhp); 144652196Smckusick nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED); 144752196Smckusick toff = fxdr_unsigned(off_t, *tl++); 144852196Smckusick off = (toff & ~(NFS_DIRBLKSIZ-1)); 144952196Smckusick on = (toff & (NFS_DIRBLKSIZ-1)); 145052196Smckusick cnt = fxdr_unsigned(int, *tl++); 145152196Smckusick duration2 = fxdr_unsigned(int, *tl); 145252196Smckusick siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); 145352196Smckusick if (cnt > NFS_MAXREADDIR) 145452196Smckusick siz = NFS_MAXREADDIR; 145552196Smckusick fullsiz = siz; 145652196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 145752196Smckusick nfsm_reply(0); 145852196Smckusick nqsrv_getl(vp, NQL_READ); 145952196Smckusick if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { 146052196Smckusick vput(vp); 146152196Smckusick nfsm_reply(0); 146252196Smckusick } 146352196Smckusick VOP_UNLOCK(vp); 146452196Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 146552196Smckusick again: 146652196Smckusick iv.iov_base = rbuf; 146752196Smckusick iv.iov_len = fullsiz; 146852196Smckusick io.uio_iov = &iv; 146952196Smckusick io.uio_iovcnt = 1; 147052196Smckusick io.uio_offset = off; 147152196Smckusick io.uio_resid = fullsiz; 147252196Smckusick io.uio_segflg = UIO_SYSSPACE; 147352196Smckusick io.uio_rw = UIO_READ; 147452196Smckusick io.uio_procp = (struct proc *)0; 147554446Smckusick error = VOP_READDIR(vp, &io, cred); 147652196Smckusick off = io.uio_offset; 147752196Smckusick if (error) { 147852196Smckusick vrele(vp); 147952196Smckusick free((caddr_t)rbuf, M_TEMP); 148052196Smckusick nfsm_reply(0); 148152196Smckusick } 148254446Smckusick if (io.uio_resid < fullsiz) 148354446Smckusick eofflag = 0; 148454446Smckusick else 148554446Smckusick eofflag = 1; 148652196Smckusick if (io.uio_resid) { 148752196Smckusick siz -= io.uio_resid; 148852196Smckusick 148952196Smckusick /* 149052196Smckusick * If nothing read, return eof 149152196Smckusick * rpc reply 149252196Smckusick */ 149352196Smckusick if (siz == 0) { 149452196Smckusick vrele(vp); 149552196Smckusick nfsm_reply(2*NFSX_UNSIGNED); 149652196Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 149752196Smckusick *tl++ = nfs_false; 149852196Smckusick *tl = nfs_true; 149952196Smckusick FREE((caddr_t)rbuf, M_TEMP); 150052196Smckusick return (0); 150152196Smckusick } 150252196Smckusick } 150352196Smckusick 150452196Smckusick /* 150552196Smckusick * Check for degenerate cases of nothing useful read. 150652196Smckusick * If so go try again 150752196Smckusick */ 150852196Smckusick cpos = rbuf + on; 150952196Smckusick cend = rbuf + siz; 151052441Smckusick dp = (struct dirent *)cpos; 151152441Smckusick while (cpos < cend && dp->d_fileno == 0) { 151252196Smckusick cpos += dp->d_reclen; 151352441Smckusick dp = (struct dirent *)cpos; 151452196Smckusick } 151552196Smckusick if (cpos >= cend) { 151652196Smckusick toff = off; 151752196Smckusick siz = fullsiz; 151852196Smckusick on = 0; 151952196Smckusick goto again; 152052196Smckusick } 152152196Smckusick 152252196Smckusick cpos = rbuf + on; 152352196Smckusick cend = rbuf + siz; 152452441Smckusick dp = (struct dirent *)cpos; 152538425Smckusick len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 152638418Smckusick nfsm_reply(siz); 152752196Smckusick mp = mp2 = mb; 152852196Smckusick bp = bpos; 152952196Smckusick be = bp + M_TRAILINGSPACE(mp); 153038418Smckusick 153138418Smckusick /* Loop through the records and build reply */ 153238418Smckusick while (cpos < cend) { 153352441Smckusick if (dp->d_fileno != 0) { 153438418Smckusick nlen = dp->d_namlen; 153538418Smckusick rem = nfsm_rndup(nlen)-nlen; 153638425Smckusick 153738418Smckusick /* 153852196Smckusick * For readdir_and_lookup get the vnode using 153952196Smckusick * the file number. 154038418Smckusick */ 154154665Smckusick if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp)) 154252196Smckusick goto invalid; 1543*55655Smckusick bzero((caddr_t)&fl.fl_nfh, sizeof (nfsv2fh_t)); 1544*55655Smckusick fl.fl_nfh.fh_generic.fh_fsid = 1545*55655Smckusick nvp->v_mount->mnt_stat.f_fsid; 1546*55655Smckusick if (VFS_VPTOFH(nvp, &fl.fl_nfh.fh_generic.fh_fid)) { 1547*55655Smckusick vput(nvp); 1548*55655Smckusick goto invalid; 1549*55655Smckusick } 155052196Smckusick (void) nqsrv_getlease(nvp, &duration2, NQL_READ, nfsd, 155152196Smckusick nam, &cache2, &frev2, cred); 155252196Smckusick fl.fl_duration = txdr_unsigned(duration2); 155352196Smckusick fl.fl_cachable = txdr_unsigned(cache2); 155455528Smckusick txdr_hyper(&frev2, fl.fl_frev); 155552196Smckusick if (VOP_GETATTR(nvp, vap, cred, nfsd->nd_procp)) { 155652196Smckusick vput(nvp); 155752196Smckusick goto invalid; 155852196Smckusick } 155952196Smckusick vput(nvp); 156052196Smckusick fp = &fl.fl_fattr; 156152196Smckusick nfsm_srvfillattr; 156252196Smckusick len += (4*NFSX_UNSIGNED + nlen + rem + NFSX_FH 156352196Smckusick + NFSX_FATTR); 156441899Smckusick if (len > cnt) { 156541899Smckusick eofflag = 0; 156638418Smckusick break; 156741899Smckusick } 156852441Smckusick /* 156952441Smckusick * Build the directory record xdr from 157052441Smckusick * the dirent entry. 157152441Smckusick */ 157238418Smckusick nfsm_clget; 157348050Smckusick *tl = nfs_true; 157438418Smckusick bp += NFSX_UNSIGNED; 157552196Smckusick 157652196Smckusick /* 157752196Smckusick * For readdir_and_lookup copy the stuff out. 157852196Smckusick */ 157952196Smckusick xfer = sizeof (struct flrep); 158052196Smckusick cp = (caddr_t)&fl; 158152196Smckusick while (xfer > 0) { 158252196Smckusick nfsm_clget; 158352196Smckusick if ((bp+xfer) > be) 158452196Smckusick tsiz = be-bp; 158552196Smckusick else 158652196Smckusick tsiz = xfer; 158752196Smckusick bcopy(cp, bp, tsiz); 158852196Smckusick bp += tsiz; 158952196Smckusick xfer -= tsiz; 159052196Smckusick if (xfer > 0) 159152196Smckusick cp += tsiz; 159252196Smckusick } 159338418Smckusick nfsm_clget; 159452441Smckusick *tl = txdr_unsigned(dp->d_fileno); 159538418Smckusick bp += NFSX_UNSIGNED; 159638418Smckusick nfsm_clget; 159748050Smckusick *tl = txdr_unsigned(nlen); 159838418Smckusick bp += NFSX_UNSIGNED; 159938425Smckusick 160052196Smckusick /* And loop around copying the name */ 160138418Smckusick xfer = nlen; 160238418Smckusick cp = dp->d_name; 160338418Smckusick while (xfer > 0) { 160438418Smckusick nfsm_clget; 160538418Smckusick if ((bp+xfer) > be) 160638418Smckusick tsiz = be-bp; 160738418Smckusick else 160838418Smckusick tsiz = xfer; 160938418Smckusick bcopy(cp, bp, tsiz); 161038418Smckusick bp += tsiz; 161138418Smckusick xfer -= tsiz; 161238418Smckusick if (xfer > 0) 161338418Smckusick cp += tsiz; 161438418Smckusick } 161538418Smckusick /* And null pad to a long boundary */ 161638418Smckusick for (i = 0; i < rem; i++) 161738418Smckusick *bp++ = '\0'; 161838418Smckusick nfsm_clget; 161938425Smckusick 162038418Smckusick /* Finish off the record */ 162138418Smckusick toff += dp->d_reclen; 162248050Smckusick *tl = txdr_unsigned(toff); 162338418Smckusick bp += NFSX_UNSIGNED; 162438418Smckusick } else 162552196Smckusick invalid: 162638418Smckusick toff += dp->d_reclen; 162738418Smckusick cpos += dp->d_reclen; 162852441Smckusick dp = (struct dirent *)cpos; 162938418Smckusick } 163052196Smckusick vrele(vp); 163138418Smckusick nfsm_clget; 163248050Smckusick *tl = nfs_false; 163338418Smckusick bp += NFSX_UNSIGNED; 163438418Smckusick nfsm_clget; 163540296Smckusick if (eofflag) 163648050Smckusick *tl = nfs_true; 163740296Smckusick else 163848050Smckusick *tl = nfs_false; 163938418Smckusick bp += NFSX_UNSIGNED; 164052196Smckusick if (mp != mb) { 164152196Smckusick if (bp < be) 164252196Smckusick mp->m_len = bp - mtod(mp, caddr_t); 164352196Smckusick } else 164452196Smckusick mp->m_len += bp - bpos; 164538418Smckusick FREE(rbuf, M_TEMP); 164638418Smckusick nfsm_srvdone; 164738418Smckusick } 164838418Smckusick 164938418Smckusick /* 165038418Smckusick * nfs statfs service 165138418Smckusick */ 165252196Smckusick nfsrv_statfs(nfsd, mrep, md, dpos, cred, nam, mrq) 165352196Smckusick struct nfsd *nfsd; 165438418Smckusick struct mbuf *mrep, *md; 165538418Smckusick caddr_t dpos; 165638418Smckusick struct ucred *cred; 165752196Smckusick struct mbuf *nam, **mrq; 165838418Smckusick { 165938418Smckusick register struct statfs *sf; 166038884Smacklem register struct nfsv2_statfs *sfp; 166148050Smckusick register u_long *tl; 166239494Smckusick register long t1; 166339494Smckusick caddr_t bpos; 166452196Smckusick int error = 0, rdonly, cache; 166539494Smckusick char *cp2; 166639753Smckusick struct mbuf *mb, *mb2, *mreq; 166738418Smckusick struct vnode *vp; 166838418Smckusick nfsv2fh_t nfh; 166938418Smckusick fhandle_t *fhp; 167038418Smckusick struct statfs statfs; 167152196Smckusick u_quad_t frev; 167238418Smckusick 167338418Smckusick fhp = &nfh.fh_generic; 167438418Smckusick nfsm_srvmtofh(fhp); 167552196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 167638418Smckusick nfsm_reply(0); 167738418Smckusick sf = &statfs; 167852196Smckusick error = VFS_STATFS(vp->v_mount, sf, nfsd->nd_procp); 167938418Smckusick vput(vp); 168038418Smckusick nfsm_reply(NFSX_STATFS); 168138884Smacklem nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS); 168244993Sbostic sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA); 168351940Smckusick sfp->sf_bsize = txdr_unsigned(sf->f_bsize); 168438884Smacklem sfp->sf_blocks = txdr_unsigned(sf->f_blocks); 168538884Smacklem sfp->sf_bfree = txdr_unsigned(sf->f_bfree); 168638884Smacklem sfp->sf_bavail = txdr_unsigned(sf->f_bavail); 168738418Smckusick nfsm_srvdone; 168838418Smckusick } 168938418Smckusick 169038418Smckusick /* 169138418Smckusick * Null operation, used by clients to ping server 169238418Smckusick */ 169339494Smckusick /* ARGSUSED */ 169452196Smckusick nfsrv_null(nfsd, mrep, md, dpos, cred, nam, mrq) 169552196Smckusick struct nfsd *nfsd; 169638418Smckusick struct mbuf *mrep, *md; 169738418Smckusick caddr_t dpos; 169838418Smckusick struct ucred *cred; 169952196Smckusick struct mbuf *nam, **mrq; 170038418Smckusick { 170139494Smckusick caddr_t bpos; 170252196Smckusick int error = VNOVAL, cache; 170339753Smckusick struct mbuf *mb, *mreq; 170452196Smckusick u_quad_t frev; 170538418Smckusick 170638418Smckusick nfsm_reply(0); 170739494Smckusick return (error); 170838418Smckusick } 170938418Smckusick 171038418Smckusick /* 171138418Smckusick * No operation, used for obsolete procedures 171238418Smckusick */ 171339494Smckusick /* ARGSUSED */ 171452196Smckusick nfsrv_noop(nfsd, mrep, md, dpos, cred, nam, mrq) 171552196Smckusick struct nfsd *nfsd; 171638418Smckusick struct mbuf *mrep, *md; 171738418Smckusick caddr_t dpos; 171838418Smckusick struct ucred *cred; 171952196Smckusick struct mbuf *nam, **mrq; 172038418Smckusick { 172139494Smckusick caddr_t bpos; 172252196Smckusick int error, cache; 172339753Smckusick struct mbuf *mb, *mreq; 172452196Smckusick u_quad_t frev; 172538418Smckusick 172652196Smckusick if (nfsd->nd_repstat) 172752196Smckusick error = nfsd->nd_repstat; 172852196Smckusick else 172952196Smckusick error = EPROCUNAVAIL; 173038418Smckusick nfsm_reply(0); 173139494Smckusick return (error); 173238418Smckusick } 173338425Smckusick 173438450Smckusick /* 173538450Smckusick * Perform access checking for vnodes obtained from file handles that would 173638450Smckusick * refer to files already opened by a Unix client. You cannot just use 173738450Smckusick * vn_writechk() and VOP_ACCESS() for two reasons. 173852196Smckusick * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case 173938450Smckusick * 2 - The owner is to be given access irrespective of mode bits so that 174038450Smckusick * processes that chmod after opening a file don't break. I don't like 174138450Smckusick * this because it opens a security hole, but since the nfs server opens 174238450Smckusick * a security hole the size of a barn door anyhow, what the heck. 174338450Smckusick */ 174452196Smckusick nfsrv_access(vp, flags, cred, rdonly, p) 174538450Smckusick register struct vnode *vp; 174638450Smckusick int flags; 174738450Smckusick register struct ucred *cred; 174852196Smckusick int rdonly; 174948050Smckusick struct proc *p; 175038450Smckusick { 175138450Smckusick struct vattr vattr; 175238450Smckusick int error; 175338450Smckusick if (flags & VWRITE) { 175452196Smckusick /* Just vn_writechk() changed to check rdonly */ 175538450Smckusick /* 175638450Smckusick * Disallow write attempts on read-only file systems; 175738450Smckusick * unless the file is a socket or a block or character 175838450Smckusick * device resident on the file system. 175938450Smckusick */ 176052196Smckusick if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { 176145059Smckusick switch (vp->v_type) { 176245059Smckusick case VREG: case VDIR: case VLNK: 176338450Smckusick return (EROFS); 176445059Smckusick } 176545059Smckusick } 176638450Smckusick /* 176738450Smckusick * If there's shared text associated with 176838450Smckusick * the inode, try to free it up once. If 176938450Smckusick * we fail, we can't allow writing. 177038450Smckusick */ 177145715Smckusick if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) 177238450Smckusick return (ETXTBSY); 177338450Smckusick } 177448050Smckusick if (error = VOP_GETATTR(vp, &vattr, cred, p)) 177545059Smckusick return (error); 177648050Smckusick if ((error = VOP_ACCESS(vp, flags, cred, p)) && 177745059Smckusick cred->cr_uid != vattr.va_uid) 177845059Smckusick return (error); 177945059Smckusick return (0); 178038450Smckusick } 1781