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*60401Smckusick * @(#)nfs_serv.c 7.66 (Berkeley) 05/25/93 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 /* 6356360Smckusick * nqnfs access service 6456360Smckusick */ 6556360Smckusick nqnfsrv_access(nfsd, mrep, md, dpos, cred, nam, mrq) 6656360Smckusick struct nfsd *nfsd; 6756360Smckusick struct mbuf *mrep, *md; 6856360Smckusick caddr_t dpos; 6956360Smckusick struct ucred *cred; 7056360Smckusick struct mbuf *nam, **mrq; 7156360Smckusick { 7256360Smckusick struct vnode *vp; 7356360Smckusick nfsv2fh_t nfh; 7456360Smckusick fhandle_t *fhp; 7556360Smckusick register u_long *tl; 7656360Smckusick register long t1; 7756360Smckusick caddr_t bpos; 7856360Smckusick int error = 0, rdonly, cache, mode = 0; 7956360Smckusick char *cp2; 8056360Smckusick struct mbuf *mb, *mb2, *mreq; 8156360Smckusick u_quad_t frev; 8256360Smckusick 8356360Smckusick fhp = &nfh.fh_generic; 8456360Smckusick nfsm_srvmtofh(fhp); 8556360Smckusick nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED); 8656360Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 8756360Smckusick nfsm_reply(0); 8856360Smckusick if (*tl++ == nfs_true) 8956360Smckusick mode |= VREAD; 9056360Smckusick if (*tl++ == nfs_true) 9156360Smckusick mode |= VWRITE; 9256360Smckusick if (*tl == nfs_true) 9356360Smckusick mode |= VEXEC; 9456360Smckusick error = nfsrv_access(vp, mode, cred, rdonly, nfsd->nd_procp); 9556360Smckusick vput(vp); 9656360Smckusick nfsm_reply(0); 9756360Smckusick nfsm_srvdone; 9856360Smckusick } 9956360Smckusick 10056360Smckusick /* 10138418Smckusick * nfs getattr service 10238418Smckusick */ 10352196Smckusick nfsrv_getattr(nfsd, mrep, md, dpos, cred, nam, mrq) 10452196Smckusick struct nfsd *nfsd; 10538418Smckusick struct mbuf *mrep, *md; 10638418Smckusick caddr_t dpos; 10738418Smckusick struct ucred *cred; 10852196Smckusick struct mbuf *nam, **mrq; 10938418Smckusick { 11038884Smacklem register struct nfsv2_fattr *fp; 11138418Smckusick struct vattr va; 11238418Smckusick register struct vattr *vap = &va; 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; 12039494Smckusick char *cp2; 12139753Smckusick struct mbuf *mb, *mb2, *mreq; 12252196Smckusick u_quad_t frev; 12338418Smckusick 12438418Smckusick fhp = &nfh.fh_generic; 12538418Smckusick nfsm_srvmtofh(fhp); 12652196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 12738418Smckusick nfsm_reply(0); 12852196Smckusick nqsrv_getl(vp, NQL_READ); 12952196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 13038418Smckusick vput(vp); 13156285Smckusick nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 13256285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 13339753Smckusick nfsm_srvfillattr; 13438418Smckusick nfsm_srvdone; 13538418Smckusick } 13638418Smckusick 13738418Smckusick /* 13838418Smckusick * nfs setattr service 13938418Smckusick */ 14052196Smckusick nfsrv_setattr(nfsd, mrep, md, dpos, cred, nam, mrq) 14152196Smckusick struct nfsd *nfsd; 14238418Smckusick struct mbuf *mrep, *md; 14338418Smckusick caddr_t dpos; 14438418Smckusick struct ucred *cred; 14552196Smckusick struct mbuf *nam, **mrq; 14638418Smckusick { 14738418Smckusick struct vattr va; 14838418Smckusick register struct vattr *vap = &va; 14938884Smacklem register struct nfsv2_sattr *sp; 15038884Smacklem register struct nfsv2_fattr *fp; 15138418Smckusick struct vnode *vp; 15238418Smckusick nfsv2fh_t nfh; 15338418Smckusick fhandle_t *fhp; 15448050Smckusick register u_long *tl; 15539494Smckusick register long t1; 15639494Smckusick caddr_t bpos; 15752196Smckusick int error = 0, rdonly, cache, duration2, cache2; 15839494Smckusick char *cp2; 15939753Smckusick struct mbuf *mb, *mb2, *mreq; 16052196Smckusick u_quad_t frev, frev2; 16138418Smckusick 16238418Smckusick fhp = &nfh.fh_generic; 16338418Smckusick nfsm_srvmtofh(fhp); 16456285Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 16552196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 16638418Smckusick nfsm_reply(0); 16752196Smckusick nqsrv_getl(vp, NQL_WRITE); 16841361Smckusick VATTR_NULL(vap); 16938418Smckusick /* 17038418Smckusick * Nah nah nah nah na nah 17138418Smckusick * There is a bug in the Sun client that puts 0xffff in the mode 17238418Smckusick * field of sattr when it should put in 0xffffffff. The u_short 17338418Smckusick * doesn't sign extend. 17438418Smckusick * --> check the low order 2 bytes for 0xffff 17538418Smckusick */ 17638884Smacklem if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff) 17738884Smacklem vap->va_mode = nfstov_mode(sp->sa_mode); 17838884Smacklem if (sp->sa_uid != nfs_xdrneg1) 17938884Smacklem vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid); 18038884Smacklem if (sp->sa_gid != nfs_xdrneg1) 18138884Smacklem vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid); 18256285Smckusick if (nfsd->nd_nqlflag == NQL_NOVAL) { 18356285Smckusick if (sp->sa_nfssize != nfs_xdrneg1) 18456285Smckusick vap->va_size = fxdr_unsigned(u_quad_t, sp->sa_nfssize); 18556285Smckusick if (sp->sa_nfsatime.nfs_sec != nfs_xdrneg1) { 18658880Smckusick #ifdef notyet 18758880Smckusick fxdr_nfstime(&sp->sa_nfsatime, &vap->va_atime); 18858880Smckusick #else 18958880Smckusick vap->va_atime.ts_sec = 19058880Smckusick fxdr_unsigned(long, sp->sa_nfsatime.nfs_sec); 19156285Smckusick vap->va_atime.ts_nsec = 0; 19258880Smckusick #endif 19356285Smckusick } 19456285Smckusick if (sp->sa_nfsmtime.nfs_sec != nfs_xdrneg1) 19556285Smckusick fxdr_nfstime(&sp->sa_nfsmtime, &vap->va_mtime); 19656285Smckusick } else { 19756285Smckusick fxdr_hyper(&sp->sa_nqsize, &vap->va_size); 19856285Smckusick fxdr_nqtime(&sp->sa_nqatime, &vap->va_atime); 19956285Smckusick fxdr_nqtime(&sp->sa_nqmtime, &vap->va_mtime); 20056285Smckusick vap->va_flags = fxdr_unsigned(u_long, sp->sa_nqflags); 20138425Smckusick } 20259526Smckusick 20359526Smckusick /* 20459526Smckusick * If the size is being changed write acces is required, otherwise 20559526Smckusick * just check for a read only file system. 20659526Smckusick */ 20759526Smckusick if (vap->va_size == ((u_quad_t)((quad_t) -1))) { 20859526Smckusick if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { 20959526Smckusick error = EROFS; 21059526Smckusick goto out; 21159526Smckusick } 21259526Smckusick } else { 21359526Smckusick if (vp->v_type == VDIR) { 21459526Smckusick error = EISDIR; 21559526Smckusick goto out; 21659526Smckusick } else if (error = nfsrv_access(vp, VWRITE, cred, rdonly, 21759526Smckusick nfsd->nd_procp)) 21859526Smckusick goto out; 21959526Smckusick } 22052196Smckusick if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) { 22138418Smckusick vput(vp); 22238418Smckusick nfsm_reply(0); 22338418Smckusick } 22452196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 22538418Smckusick out: 22638418Smckusick vput(vp); 22756285Smckusick nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL) + 2*NFSX_UNSIGNED); 22856285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 22939753Smckusick nfsm_srvfillattr; 23052196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 23152196Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 23252196Smckusick txdr_hyper(&frev2, tl); 23352196Smckusick } 23438418Smckusick nfsm_srvdone; 23538418Smckusick } 23638418Smckusick 23738418Smckusick /* 23838418Smckusick * nfs lookup rpc 23938418Smckusick */ 24052196Smckusick nfsrv_lookup(nfsd, mrep, md, dpos, cred, nam, mrq) 24152196Smckusick struct nfsd *nfsd; 24238418Smckusick struct mbuf *mrep, *md; 24338418Smckusick caddr_t dpos; 24438418Smckusick struct ucred *cred; 24552196Smckusick struct mbuf *nam, **mrq; 24638418Smckusick { 24738884Smacklem register struct nfsv2_fattr *fp; 24849742Smckusick struct nameidata nd; 24938418Smckusick struct vnode *vp; 25038418Smckusick nfsv2fh_t nfh; 25138418Smckusick fhandle_t *fhp; 25239494Smckusick register caddr_t cp; 25348050Smckusick register u_long *tl; 25439494Smckusick register long t1; 25539494Smckusick caddr_t bpos; 25656285Smckusick int error = 0, rdonly, cache, duration2, cache2, len; 25739494Smckusick char *cp2; 25839753Smckusick struct mbuf *mb, *mb2, *mreq; 25938418Smckusick struct vattr va, *vap = &va; 26052196Smckusick u_quad_t frev, frev2; 26138418Smckusick 26238418Smckusick fhp = &nfh.fh_generic; 26356658Smckusick duration2 = 0; 26452196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 26552196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 26656285Smckusick duration2 = fxdr_unsigned(int, *tl); 26752196Smckusick } 26838418Smckusick nfsm_srvmtofh(fhp); 26938418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 27052316Sheideman nd.ni_cnd.cn_cred = cred; 27152316Sheideman nd.ni_cnd.cn_nameiop = LOOKUP; 27252316Sheideman nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART; 27352653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 27452653Smckusick nfsd->nd_procp)) 27538418Smckusick nfsm_reply(0); 27652196Smckusick nqsrv_getl(nd.ni_startdir, NQL_READ); 27752196Smckusick vrele(nd.ni_startdir); 27852653Smckusick FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 27949742Smckusick vp = nd.ni_vp; 28038418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 28141398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 28238418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 28338418Smckusick vput(vp); 28438418Smckusick nfsm_reply(0); 28538418Smckusick } 28656285Smckusick if (duration2) 28756285Smckusick (void) nqsrv_getlease(vp, &duration2, NQL_READ, nfsd, 28852196Smckusick nam, &cache2, &frev2, cred); 28952196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 29038418Smckusick vput(vp); 29156285Smckusick nfsm_reply(NFSX_FH + NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL) + 5*NFSX_UNSIGNED); 29252196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 29356285Smckusick if (duration2) { 29452196Smckusick nfsm_build(tl, u_long *, 5*NFSX_UNSIGNED); 29556285Smckusick *tl++ = txdr_unsigned(NQL_READ); 29652196Smckusick *tl++ = txdr_unsigned(cache2); 29752196Smckusick *tl++ = txdr_unsigned(duration2); 29852196Smckusick txdr_hyper(&frev2, tl); 29952196Smckusick } else { 30052196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 30152196Smckusick *tl = 0; 30252196Smckusick } 30352196Smckusick } 30438418Smckusick nfsm_srvfhtom(fhp); 30556285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 30639753Smckusick nfsm_srvfillattr; 30738418Smckusick nfsm_srvdone; 30838418Smckusick } 30938418Smckusick 31038418Smckusick /* 31138418Smckusick * nfs readlink service 31238418Smckusick */ 31352196Smckusick nfsrv_readlink(nfsd, mrep, md, dpos, cred, nam, mrq) 31452196Smckusick struct nfsd *nfsd; 31538418Smckusick struct mbuf *mrep, *md; 31638418Smckusick caddr_t dpos; 31738418Smckusick struct ucred *cred; 31852196Smckusick struct mbuf *nam, **mrq; 31938418Smckusick { 32041899Smckusick struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN]; 32138418Smckusick register struct iovec *ivp = iv; 32238418Smckusick register struct mbuf *mp; 32348050Smckusick register u_long *tl; 32439494Smckusick register long t1; 32539494Smckusick caddr_t bpos; 32652196Smckusick int error = 0, rdonly, cache, i, tlen, len; 32739494Smckusick char *cp2; 32839753Smckusick struct mbuf *mb, *mb2, *mp2, *mp3, *mreq; 32938418Smckusick struct vnode *vp; 33038418Smckusick nfsv2fh_t nfh; 33138418Smckusick fhandle_t *fhp; 33238418Smckusick struct uio io, *uiop = &io; 33352196Smckusick u_quad_t frev; 33438418Smckusick 33538418Smckusick fhp = &nfh.fh_generic; 33638418Smckusick nfsm_srvmtofh(fhp); 33738418Smckusick len = 0; 33838418Smckusick i = 0; 33938418Smckusick while (len < NFS_MAXPATHLEN) { 34038418Smckusick MGET(mp, M_WAIT, MT_DATA); 34141899Smckusick MCLGET(mp, M_WAIT); 34238418Smckusick mp->m_len = NFSMSIZ(mp); 34338418Smckusick if (len == 0) 34438418Smckusick mp3 = mp2 = mp; 34541899Smckusick else { 34638418Smckusick mp2->m_next = mp; 34741899Smckusick mp2 = mp; 34841899Smckusick } 34938418Smckusick if ((len+mp->m_len) > NFS_MAXPATHLEN) { 35038418Smckusick mp->m_len = NFS_MAXPATHLEN-len; 35138418Smckusick len = NFS_MAXPATHLEN; 35238418Smckusick } else 35338418Smckusick len += mp->m_len; 35438418Smckusick ivp->iov_base = mtod(mp, caddr_t); 35538418Smckusick ivp->iov_len = mp->m_len; 35638418Smckusick i++; 35738418Smckusick ivp++; 35838418Smckusick } 35938418Smckusick uiop->uio_iov = iv; 36038418Smckusick uiop->uio_iovcnt = i; 36138418Smckusick uiop->uio_offset = 0; 36238418Smckusick uiop->uio_resid = len; 36338418Smckusick uiop->uio_rw = UIO_READ; 36438418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 36548050Smckusick uiop->uio_procp = (struct proc *)0; 36652196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) { 36738418Smckusick m_freem(mp3); 36838418Smckusick nfsm_reply(0); 36938418Smckusick } 37038418Smckusick if (vp->v_type != VLNK) { 37138418Smckusick error = EINVAL; 37238418Smckusick goto out; 37338418Smckusick } 37452196Smckusick nqsrv_getl(vp, NQL_READ); 37538418Smckusick error = VOP_READLINK(vp, uiop, cred); 37638418Smckusick out: 37738418Smckusick vput(vp); 37838418Smckusick if (error) 37938418Smckusick m_freem(mp3); 38038418Smckusick nfsm_reply(NFSX_UNSIGNED); 38138418Smckusick if (uiop->uio_resid > 0) { 38238418Smckusick len -= uiop->uio_resid; 38338418Smckusick tlen = nfsm_rndup(len); 38438418Smckusick nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len); 38538418Smckusick } 38648050Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 38748050Smckusick *tl = txdr_unsigned(len); 38838418Smckusick mb->m_next = mp3; 38938418Smckusick nfsm_srvdone; 39038418Smckusick } 39138418Smckusick 39238418Smckusick /* 39338418Smckusick * nfs read service 39438418Smckusick */ 39552196Smckusick nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq) 39652196Smckusick struct nfsd *nfsd; 39738418Smckusick struct mbuf *mrep, *md; 39838418Smckusick caddr_t dpos; 39938418Smckusick struct ucred *cred; 40052196Smckusick struct mbuf *nam, **mrq; 40138418Smckusick { 40243350Smckusick register struct iovec *iv; 40343350Smckusick struct iovec *iv2; 40441899Smckusick register struct mbuf *m; 40538884Smacklem register struct nfsv2_fattr *fp; 40648050Smckusick register u_long *tl; 40739494Smckusick register long t1; 40839494Smckusick caddr_t bpos; 40952196Smckusick int error = 0, rdonly, cache, i, cnt, len, left, siz, tlen; 41039494Smckusick char *cp2; 41139753Smckusick struct mbuf *mb, *mb2, *mreq; 41252196Smckusick struct mbuf *m2; 41338418Smckusick struct vnode *vp; 41438418Smckusick nfsv2fh_t nfh; 41538418Smckusick fhandle_t *fhp; 41638418Smckusick struct uio io, *uiop = &io; 41738418Smckusick struct vattr va, *vap = &va; 41838418Smckusick off_t off; 41952196Smckusick u_quad_t frev; 42038418Smckusick 42138418Smckusick fhp = &nfh.fh_generic; 42238418Smckusick nfsm_srvmtofh(fhp); 42356285Smckusick if (nfsd->nd_nqlflag == NQL_NOVAL) { 42456285Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 42556285Smckusick off = (off_t)fxdr_unsigned(u_long, *tl); 42656285Smckusick } else { 42756285Smckusick nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); 42856285Smckusick fxdr_hyper(tl, &off); 42956285Smckusick } 43038418Smckusick nfsm_srvstrsiz(cnt, NFS_MAXDATA); 43152196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 43238418Smckusick nfsm_reply(0); 43360186Smckusick if (vp->v_type != VREG) { 43460186Smckusick error = (vp->v_type == VDIR) ? EISDIR : EACCES; 43560186Smckusick vput(vp); 43660186Smckusick nfsm_reply(0); 43760186Smckusick } 43852196Smckusick nqsrv_getl(vp, NQL_READ); 43956718Smckusick if ((error = nfsrv_access(vp, VREAD, cred, rdonly, nfsd->nd_procp)) && 44056718Smckusick (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp))) { 44138418Smckusick vput(vp); 44238418Smckusick nfsm_reply(0); 44338418Smckusick } 44452196Smckusick if (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp)) { 44538418Smckusick vput(vp); 44638418Smckusick nfsm_reply(0); 44738418Smckusick } 44852196Smckusick if (off >= vap->va_size) 44952196Smckusick cnt = 0; 45052196Smckusick else if ((off + cnt) > vap->va_size) 45152196Smckusick cnt = nfsm_rndup(vap->va_size - off); 45256285Smckusick nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)+NFSX_UNSIGNED+nfsm_rndup(cnt)); 45356285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 45452196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 45552196Smckusick len = left = cnt; 45652196Smckusick if (cnt > 0) { 45752196Smckusick /* 45852196Smckusick * Generate the mbuf list with the uio_iov ref. to it. 45952196Smckusick */ 46052196Smckusick i = 0; 46152196Smckusick m = m2 = mb; 46252196Smckusick MALLOC(iv, struct iovec *, 46352196Smckusick ((NFS_MAXDATA+MLEN-1)/MLEN) * sizeof (struct iovec), 46452196Smckusick M_TEMP, M_WAITOK); 46552196Smckusick iv2 = iv; 46652196Smckusick while (left > 0) { 46755057Spendry siz = min(M_TRAILINGSPACE(m), left); 46852196Smckusick if (siz > 0) { 46952196Smckusick m->m_len += siz; 47052196Smckusick iv->iov_base = bpos; 47152196Smckusick iv->iov_len = siz; 47252196Smckusick iv++; 47352196Smckusick i++; 47452196Smckusick left -= siz; 47552196Smckusick } 47652196Smckusick if (left > 0) { 47752196Smckusick MGET(m, M_WAIT, MT_DATA); 47852196Smckusick MCLGET(m, M_WAIT); 47952196Smckusick m->m_len = 0; 48052196Smckusick m2->m_next = m; 48152196Smckusick m2 = m; 48252196Smckusick bpos = mtod(m, caddr_t); 48352196Smckusick } 48452196Smckusick } 48552196Smckusick uiop->uio_iov = iv2; 48652196Smckusick uiop->uio_iovcnt = i; 48752196Smckusick uiop->uio_offset = off; 48852196Smckusick uiop->uio_resid = cnt; 48952196Smckusick uiop->uio_rw = UIO_READ; 49052196Smckusick uiop->uio_segflg = UIO_SYSSPACE; 49152196Smckusick error = VOP_READ(vp, uiop, IO_NODELOCKED, cred); 49252196Smckusick off = uiop->uio_offset; 49352196Smckusick FREE((caddr_t)iv2, M_TEMP); 49452196Smckusick if (error || (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp))) { 49552196Smckusick m_freem(mreq); 49652196Smckusick vput(vp); 49752196Smckusick nfsm_reply(0); 49852196Smckusick } 49952196Smckusick } else 50052196Smckusick uiop->uio_resid = 0; 50138418Smckusick vput(vp); 50239753Smckusick nfsm_srvfillattr; 50345877Smckusick len -= uiop->uio_resid; 50452196Smckusick tlen = nfsm_rndup(len); 50552196Smckusick if (cnt != tlen || tlen != len) 50652196Smckusick nfsm_adj(mb, cnt-tlen, tlen-len); 50748050Smckusick *tl = txdr_unsigned(len); 50838418Smckusick nfsm_srvdone; 50938418Smckusick } 51038418Smckusick 51138418Smckusick /* 51238418Smckusick * nfs write service 51338418Smckusick */ 51452196Smckusick nfsrv_write(nfsd, mrep, md, dpos, cred, nam, mrq) 51552196Smckusick struct nfsd *nfsd; 51652196Smckusick struct mbuf *mrep, *md; 51738418Smckusick caddr_t dpos; 51838418Smckusick struct ucred *cred; 51952196Smckusick struct mbuf *nam, **mrq; 52038418Smckusick { 52138418Smckusick register struct iovec *ivp; 52238418Smckusick register struct mbuf *mp; 52338884Smacklem register struct nfsv2_fattr *fp; 52441899Smckusick struct iovec iv[NFS_MAXIOVEC]; 52538418Smckusick struct vattr va; 52638418Smckusick register struct vattr *vap = &va; 52748050Smckusick register u_long *tl; 52839494Smckusick register long t1; 52939494Smckusick caddr_t bpos; 53052196Smckusick int error = 0, rdonly, cache, siz, len, xfer; 53156285Smckusick int ioflags = IO_SYNC | IO_NODELOCKED; 53239494Smckusick char *cp2; 53339753Smckusick struct mbuf *mb, *mb2, *mreq; 53438418Smckusick struct vnode *vp; 53538418Smckusick nfsv2fh_t nfh; 53638418Smckusick fhandle_t *fhp; 53738418Smckusick struct uio io, *uiop = &io; 53838418Smckusick off_t off; 53952196Smckusick u_quad_t frev; 54038418Smckusick 54138418Smckusick fhp = &nfh.fh_generic; 54238418Smckusick nfsm_srvmtofh(fhp); 54356285Smckusick nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED); 54456285Smckusick if (nfsd->nd_nqlflag == NQL_NOVAL) { 54556285Smckusick off = (off_t)fxdr_unsigned(u_long, *++tl); 54656285Smckusick tl += 2; 54756285Smckusick } else { 54856285Smckusick fxdr_hyper(tl, &off); 54956285Smckusick tl += 2; 55056285Smckusick if (fxdr_unsigned(u_long, *tl++)) 55156285Smckusick ioflags |= IO_APPEND; 55256285Smckusick } 55348050Smckusick len = fxdr_unsigned(long, *tl); 55438418Smckusick if (len > NFS_MAXDATA || len <= 0) { 55538418Smckusick error = EBADRPC; 55638418Smckusick nfsm_reply(0); 55738418Smckusick } 55838418Smckusick if (dpos == (mtod(md, caddr_t)+md->m_len)) { 55938418Smckusick mp = md->m_next; 56038418Smckusick if (mp == NULL) { 56138418Smckusick error = EBADRPC; 56238418Smckusick nfsm_reply(0); 56338418Smckusick } 56438418Smckusick } else { 56538418Smckusick mp = md; 56638418Smckusick siz = dpos-mtod(mp, caddr_t); 56738418Smckusick mp->m_len -= siz; 56838418Smckusick NFSMADV(mp, siz); 56938418Smckusick } 57052196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 57138418Smckusick nfsm_reply(0); 57260186Smckusick if (vp->v_type != VREG) { 57360186Smckusick error = (vp->v_type == VDIR) ? EISDIR : EACCES; 57460186Smckusick vput(vp); 57560186Smckusick nfsm_reply(0); 57660186Smckusick } 57752196Smckusick nqsrv_getl(vp, NQL_WRITE); 57852196Smckusick if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) { 57938418Smckusick vput(vp); 58038418Smckusick nfsm_reply(0); 58138418Smckusick } 58238418Smckusick uiop->uio_resid = 0; 58338418Smckusick uiop->uio_rw = UIO_WRITE; 58438418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 58548050Smckusick uiop->uio_procp = (struct proc *)0; 58638418Smckusick /* 58741899Smckusick * Do up to NFS_MAXIOVEC mbufs of write each iteration of the 58838418Smckusick * loop until done. 58938418Smckusick */ 59038418Smckusick while (len > 0 && uiop->uio_resid == 0) { 59138418Smckusick ivp = iv; 59238418Smckusick siz = 0; 59338418Smckusick uiop->uio_iov = ivp; 59438418Smckusick uiop->uio_iovcnt = 0; 59538418Smckusick uiop->uio_offset = off; 59641899Smckusick while (len > 0 && uiop->uio_iovcnt < NFS_MAXIOVEC && mp != NULL) { 59738418Smckusick ivp->iov_base = mtod(mp, caddr_t); 59838418Smckusick if (len < mp->m_len) 59938418Smckusick ivp->iov_len = xfer = len; 60038418Smckusick else 60138418Smckusick ivp->iov_len = xfer = mp->m_len; 60238418Smckusick #ifdef notdef 60338418Smckusick /* Not Yet .. */ 60438418Smckusick if (M_HASCL(mp) && (((u_long)ivp->iov_base) & CLOFSET) == 0) 60538418Smckusick ivp->iov_op = NULL; /* what should it be ?? */ 60638418Smckusick else 60738418Smckusick ivp->iov_op = NULL; 60838418Smckusick #endif 60938418Smckusick uiop->uio_iovcnt++; 61038418Smckusick ivp++; 61138418Smckusick len -= xfer; 61238418Smckusick siz += xfer; 61338418Smckusick mp = mp->m_next; 61438418Smckusick } 61538418Smckusick if (len > 0 && mp == NULL) { 61638418Smckusick error = EBADRPC; 61738418Smckusick vput(vp); 61838418Smckusick nfsm_reply(0); 61938418Smckusick } 62038418Smckusick uiop->uio_resid = siz; 62156285Smckusick if (error = VOP_WRITE(vp, uiop, ioflags, cred)) { 62238418Smckusick vput(vp); 62338418Smckusick nfsm_reply(0); 62438418Smckusick } 62539586Smckusick off = uiop->uio_offset; 62638418Smckusick } 62752196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 62838418Smckusick vput(vp); 62956285Smckusick nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 63056285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 63139753Smckusick nfsm_srvfillattr; 63252442Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 63352442Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 63452442Smckusick txdr_hyper(&vap->va_filerev, tl); 63552442Smckusick } 63638418Smckusick nfsm_srvdone; 63738418Smckusick } 63838418Smckusick 63938418Smckusick /* 64038418Smckusick * nfs create service 64138418Smckusick * now does a truncate to 0 length via. setattr if it already exists 64238418Smckusick */ 64352196Smckusick nfsrv_create(nfsd, mrep, md, dpos, cred, nam, mrq) 64452196Smckusick struct nfsd *nfsd; 64552196Smckusick struct mbuf *mrep, *md; 64638418Smckusick caddr_t dpos; 64738418Smckusick struct ucred *cred; 64852196Smckusick struct mbuf *nam, **mrq; 64938418Smckusick { 65038884Smacklem register struct nfsv2_fattr *fp; 65138418Smckusick struct vattr va; 65238418Smckusick register struct vattr *vap = &va; 65356285Smckusick register struct nfsv2_sattr *sp; 65456285Smckusick register u_long *tl; 65549742Smckusick struct nameidata nd; 65639494Smckusick register caddr_t cp; 65739494Smckusick register long t1; 65839494Smckusick caddr_t bpos; 65956285Smckusick int error = 0, rdev, cache, len, tsize; 66039494Smckusick char *cp2; 66139753Smckusick struct mbuf *mb, *mb2, *mreq; 66238418Smckusick struct vnode *vp; 66338418Smckusick nfsv2fh_t nfh; 66438418Smckusick fhandle_t *fhp; 66552196Smckusick u_quad_t frev; 66638418Smckusick 66752316Sheideman nd.ni_cnd.cn_nameiop = 0; 66838418Smckusick fhp = &nfh.fh_generic; 66938418Smckusick nfsm_srvmtofh(fhp); 67038418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 67152316Sheideman nd.ni_cnd.cn_cred = cred; 67252316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 67352316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART; 67452653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 67552653Smckusick nfsd->nd_procp)) 67638418Smckusick nfsm_reply(0); 67741361Smckusick VATTR_NULL(vap); 67856285Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 67938418Smckusick /* 68038418Smckusick * Iff doesn't exist, create it 68138418Smckusick * otherwise just truncate to 0 length 68238418Smckusick * should I set the mode too ?? 68338418Smckusick */ 68449742Smckusick if (nd.ni_vp == NULL) { 68556285Smckusick vap->va_type = IFTOVT(fxdr_unsigned(u_long, sp->sa_mode)); 68642867Smckusick if (vap->va_type == VNON) 68742867Smckusick vap->va_type = VREG; 68856285Smckusick vap->va_mode = nfstov_mode(sp->sa_mode); 68956285Smckusick if (nfsd->nd_nqlflag == NQL_NOVAL) 69056285Smckusick rdev = fxdr_unsigned(long, sp->sa_nfssize); 69156285Smckusick else 69256285Smckusick rdev = fxdr_unsigned(long, sp->sa_nqrdev); 69346988Smckusick if (vap->va_type == VREG || vap->va_type == VSOCK) { 69449742Smckusick vrele(nd.ni_startdir); 69552196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 69652234Sheideman if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) 69742242Smckusick nfsm_reply(0); 69852316Sheideman FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 69942242Smckusick } else if (vap->va_type == VCHR || vap->va_type == VBLK || 70042242Smckusick vap->va_type == VFIFO) { 70142242Smckusick if (vap->va_type == VCHR && rdev == 0xffffffff) 70242242Smckusick vap->va_type = VFIFO; 70342242Smckusick if (vap->va_type == VFIFO) { 70442242Smckusick #ifndef FIFO 70552234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 70649742Smckusick vput(nd.ni_dvp); 70742242Smckusick error = ENXIO; 70849742Smckusick goto out; 70942242Smckusick #endif /* FIFO */ 71052196Smckusick } else if (error = suser(cred, (u_short *)0)) { 71152234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 71249742Smckusick vput(nd.ni_dvp); 71349742Smckusick goto out; 71442242Smckusick } else 71542242Smckusick vap->va_rdev = (dev_t)rdev; 71652196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 71752234Sheideman if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) { 71849742Smckusick vrele(nd.ni_startdir); 71942242Smckusick nfsm_reply(0); 72049742Smckusick } 72152316Sheideman nd.ni_cnd.cn_nameiop = LOOKUP; 72252316Sheideman nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART); 72352316Sheideman nd.ni_cnd.cn_proc = nfsd->nd_procp; 72452316Sheideman nd.ni_cnd.cn_cred = nfsd->nd_procp->p_ucred; 72552316Sheideman if (error = lookup(&nd)) { 72652316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 72742242Smckusick nfsm_reply(0); 72849742Smckusick } 72952316Sheideman FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 73052316Sheideman if (nd.ni_cnd.cn_flags & ISSYMLINK) { 73149742Smckusick vrele(nd.ni_dvp); 73249742Smckusick vput(nd.ni_vp); 73352234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 73449742Smckusick error = EINVAL; 73549742Smckusick nfsm_reply(0); 73649742Smckusick } 73742242Smckusick } else { 73852234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 73949742Smckusick vput(nd.ni_dvp); 74042242Smckusick error = ENXIO; 74149742Smckusick goto out; 74242242Smckusick } 74349742Smckusick vp = nd.ni_vp; 74438418Smckusick } else { 74549742Smckusick vrele(nd.ni_startdir); 74652316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 74749742Smckusick vp = nd.ni_vp; 74849742Smckusick if (nd.ni_dvp == vp) 74949742Smckusick vrele(nd.ni_dvp); 75043359Smckusick else 75149742Smckusick vput(nd.ni_dvp); 75252234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 75356285Smckusick if (nfsd->nd_nqlflag == NQL_NOVAL) { 75456285Smckusick tsize = fxdr_unsigned(long, sp->sa_nfssize); 75556285Smckusick if (tsize != -1) 75656285Smckusick vap->va_size = (u_quad_t)tsize; 75756285Smckusick else 75856285Smckusick vap->va_size = -1; 75956285Smckusick } else 76056285Smckusick fxdr_hyper(&sp->sa_nqsize, &vap->va_size); 76156285Smckusick if (vap->va_size != -1) { 762*60401Smckusick if (error = nfsrv_access(vp, VWRITE, cred, 763*60401Smckusick (nd.ni_cnd.cn_flags & RDONLY), nfsd->nd_procp)) { 764*60401Smckusick vput(vp); 765*60401Smckusick nfsm_reply(0); 766*60401Smckusick } 76756285Smckusick nqsrv_getl(vp, NQL_WRITE); 76856285Smckusick if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) { 76956285Smckusick vput(vp); 77056285Smckusick nfsm_reply(0); 77156285Smckusick } 77242506Smckusick } 77338418Smckusick } 77438418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 77541398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 77638418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 77738418Smckusick vput(vp); 77838418Smckusick nfsm_reply(0); 77938418Smckusick } 78052196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 78138418Smckusick vput(vp); 78256285Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 78338418Smckusick nfsm_srvfhtom(fhp); 78456285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 78539753Smckusick nfsm_srvfillattr; 78638418Smckusick return (error); 78738418Smckusick nfsmout: 78852316Sheideman if (nd.ni_cnd.cn_nameiop || nd.ni_cnd.cn_flags) 78951464Sbostic vrele(nd.ni_startdir); 79052234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 79149742Smckusick if (nd.ni_dvp == nd.ni_vp) 79249742Smckusick vrele(nd.ni_dvp); 79343359Smckusick else 79449742Smckusick vput(nd.ni_dvp); 79549742Smckusick if (nd.ni_vp) 79649742Smckusick vput(nd.ni_vp); 79738418Smckusick return (error); 79849742Smckusick 79949742Smckusick out: 80049742Smckusick vrele(nd.ni_startdir); 80152316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 80249742Smckusick nfsm_reply(0); 80338418Smckusick } 80438418Smckusick 80538418Smckusick /* 80638418Smckusick * nfs remove service 80738418Smckusick */ 80852196Smckusick nfsrv_remove(nfsd, mrep, md, dpos, cred, nam, mrq) 80952196Smckusick struct nfsd *nfsd; 81052196Smckusick struct mbuf *mrep, *md; 81138418Smckusick caddr_t dpos; 81238418Smckusick struct ucred *cred; 81352196Smckusick struct mbuf *nam, **mrq; 81438418Smckusick { 81549742Smckusick struct nameidata nd; 81648050Smckusick register u_long *tl; 81739494Smckusick register long t1; 81839494Smckusick caddr_t bpos; 81952196Smckusick int error = 0, cache, len; 82039494Smckusick char *cp2; 82139753Smckusick struct mbuf *mb, *mreq; 82238418Smckusick struct vnode *vp; 82338418Smckusick nfsv2fh_t nfh; 82438418Smckusick fhandle_t *fhp; 82552196Smckusick u_quad_t frev; 82638418Smckusick 82738418Smckusick fhp = &nfh.fh_generic; 82838418Smckusick nfsm_srvmtofh(fhp); 82938418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 83052316Sheideman nd.ni_cnd.cn_cred = cred; 83152316Sheideman nd.ni_cnd.cn_nameiop = DELETE; 83252316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 83352653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 83452653Smckusick nfsd->nd_procp)) 83538418Smckusick nfsm_reply(0); 83649742Smckusick vp = nd.ni_vp; 83738418Smckusick if (vp->v_type == VDIR && 83852196Smckusick (error = suser(cred, (u_short *)0))) 83938418Smckusick goto out; 84038418Smckusick /* 84149454Smckusick * The root of a mounted filesystem cannot be deleted. 84238418Smckusick */ 84338418Smckusick if (vp->v_flag & VROOT) { 84438418Smckusick error = EBUSY; 84538418Smckusick goto out; 84638418Smckusick } 84738418Smckusick if (vp->v_flag & VTEXT) 84845715Smckusick (void) vnode_pager_uncache(vp); 84938418Smckusick out: 85042467Smckusick if (!error) { 85152196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 85252196Smckusick nqsrv_getl(vp, NQL_WRITE); 85352234Sheideman error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 85442467Smckusick } else { 85552234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 85649742Smckusick if (nd.ni_dvp == vp) 85749742Smckusick vrele(nd.ni_dvp); 85843359Smckusick else 85949742Smckusick vput(nd.ni_dvp); 86042467Smckusick vput(vp); 86142467Smckusick } 86238418Smckusick nfsm_reply(0); 86338418Smckusick nfsm_srvdone; 86438418Smckusick } 86538418Smckusick 86638418Smckusick /* 86738418Smckusick * nfs rename service 86838418Smckusick */ 86952196Smckusick nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq) 87052196Smckusick struct nfsd *nfsd; 87152196Smckusick struct mbuf *mrep, *md; 87238418Smckusick caddr_t dpos; 87338418Smckusick struct ucred *cred; 87452196Smckusick struct mbuf *nam, **mrq; 87538418Smckusick { 87648050Smckusick register u_long *tl; 87739494Smckusick register long t1; 87839494Smckusick caddr_t bpos; 87952196Smckusick int error = 0, rdonly, cache, len, len2; 88039494Smckusick char *cp2; 88139753Smckusick struct mbuf *mb, *mreq; 88249742Smckusick struct nameidata fromnd, tond; 88338418Smckusick struct vnode *fvp, *tvp, *tdvp; 88438418Smckusick nfsv2fh_t fnfh, tnfh; 88538418Smckusick fhandle_t *ffhp, *tfhp; 88652196Smckusick u_quad_t frev; 88752196Smckusick uid_t saved_uid; 88838418Smckusick 88938418Smckusick ffhp = &fnfh.fh_generic; 89038418Smckusick tfhp = &tnfh.fh_generic; 89152316Sheideman fromnd.ni_cnd.cn_nameiop = 0; 89252316Sheideman tond.ni_cnd.cn_nameiop = 0; 89338418Smckusick nfsm_srvmtofh(ffhp); 89438418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 89538418Smckusick /* 89652196Smckusick * Remember our original uid so that we can reset cr_uid before 89752196Smckusick * the second nfs_namei() call, in case it is remapped. 89838418Smckusick */ 89952196Smckusick saved_uid = cred->cr_uid; 90052316Sheideman fromnd.ni_cnd.cn_cred = cred; 90152316Sheideman fromnd.ni_cnd.cn_nameiop = DELETE; 90252316Sheideman fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART; 90352653Smckusick if (error = nfs_namei(&fromnd, ffhp, len, nfsd->nd_slp, nam, &md, 90452653Smckusick &dpos, nfsd->nd_procp)) 90538418Smckusick nfsm_reply(0); 90649742Smckusick fvp = fromnd.ni_vp; 90738418Smckusick nfsm_srvmtofh(tfhp); 90841899Smckusick nfsm_strsiz(len2, NFS_MAXNAMLEN); 90952196Smckusick cred->cr_uid = saved_uid; 91052316Sheideman tond.ni_cnd.cn_cred = cred; 91152316Sheideman tond.ni_cnd.cn_nameiop = RENAME; 91252316Sheideman tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; 91352653Smckusick if (error = nfs_namei(&tond, tfhp, len2, nfsd->nd_slp, nam, &md, 91452653Smckusick &dpos, nfsd->nd_procp)) { 91552234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 91649742Smckusick vrele(fromnd.ni_dvp); 91742467Smckusick vrele(fvp); 91842467Smckusick goto out1; 91942467Smckusick } 92038425Smckusick tdvp = tond.ni_dvp; 92138425Smckusick tvp = tond.ni_vp; 92238418Smckusick if (tvp != NULL) { 92338418Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 92438418Smckusick error = EISDIR; 92538418Smckusick goto out; 92638418Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 92738418Smckusick error = ENOTDIR; 92838418Smckusick goto out; 92938418Smckusick } 93052196Smckusick if (tvp->v_type == VDIR && tvp->v_mountedhere) { 93152196Smckusick error = EXDEV; 93252196Smckusick goto out; 93352196Smckusick } 93438418Smckusick } 93552196Smckusick if (fvp->v_type == VDIR && fvp->v_mountedhere) { 93652196Smckusick error = EBUSY; 93752196Smckusick goto out; 93852196Smckusick } 93938418Smckusick if (fvp->v_mount != tdvp->v_mount) { 94038418Smckusick error = EXDEV; 94138418Smckusick goto out; 94238418Smckusick } 94349742Smckusick if (fvp == tdvp) 94438418Smckusick error = EINVAL; 94549742Smckusick /* 94649742Smckusick * If source is the same as the destination (that is the 94749742Smckusick * same vnode with the same name in the same directory), 94849742Smckusick * then there is nothing to do. 94949742Smckusick */ 95049742Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 95152316Sheideman fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 95252316Sheideman !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 95352316Sheideman fromnd.ni_cnd.cn_namelen)) 95449742Smckusick error = -1; 95538418Smckusick out: 95642467Smckusick if (!error) { 95752196Smckusick nqsrv_getl(fromnd.ni_dvp, NQL_WRITE); 95852196Smckusick nqsrv_getl(tdvp, NQL_WRITE); 95952196Smckusick if (tvp) 96052196Smckusick nqsrv_getl(tvp, NQL_WRITE); 96152234Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 96252234Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 96342467Smckusick } else { 96452234Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 96543359Smckusick if (tdvp == tvp) 96643359Smckusick vrele(tdvp); 96743359Smckusick else 96843359Smckusick vput(tdvp); 96942467Smckusick if (tvp) 97042467Smckusick vput(tvp); 97152234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 97249742Smckusick vrele(fromnd.ni_dvp); 97342467Smckusick vrele(fvp); 97438418Smckusick } 97546513Smckusick vrele(tond.ni_startdir); 97652316Sheideman FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 97738418Smckusick out1: 97849742Smckusick vrele(fromnd.ni_startdir); 97952316Sheideman FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 98038418Smckusick nfsm_reply(0); 98138418Smckusick return (error); 98249742Smckusick 98338418Smckusick nfsmout: 98452316Sheideman if (tond.ni_cnd.cn_nameiop || tond.ni_cnd.cn_flags) { 98549742Smckusick vrele(tond.ni_startdir); 98652316Sheideman FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 98749742Smckusick } 98852316Sheideman if (fromnd.ni_cnd.cn_nameiop || fromnd.ni_cnd.cn_flags) { 98949742Smckusick vrele(fromnd.ni_startdir); 99052316Sheideman FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 99152234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 99249742Smckusick vrele(fromnd.ni_dvp); 99349742Smckusick vrele(fvp); 99449742Smckusick } 99538418Smckusick return (error); 99638418Smckusick } 99738418Smckusick 99838418Smckusick /* 99938418Smckusick * nfs link service 100038418Smckusick */ 100152196Smckusick nfsrv_link(nfsd, mrep, md, dpos, cred, nam, mrq) 100252196Smckusick struct nfsd *nfsd; 100352196Smckusick struct mbuf *mrep, *md; 100438418Smckusick caddr_t dpos; 100538418Smckusick struct ucred *cred; 100652196Smckusick struct mbuf *nam, **mrq; 100738418Smckusick { 100849742Smckusick struct nameidata nd; 100948050Smckusick register u_long *tl; 101039494Smckusick register long t1; 101139494Smckusick caddr_t bpos; 101252196Smckusick int error = 0, rdonly, cache, len; 101339494Smckusick char *cp2; 101439753Smckusick struct mbuf *mb, *mreq; 101538418Smckusick struct vnode *vp, *xp; 101638418Smckusick nfsv2fh_t nfh, dnfh; 101738418Smckusick fhandle_t *fhp, *dfhp; 101852196Smckusick u_quad_t frev; 101938418Smckusick 102038418Smckusick fhp = &nfh.fh_generic; 102138418Smckusick dfhp = &dnfh.fh_generic; 102238418Smckusick nfsm_srvmtofh(fhp); 102338418Smckusick nfsm_srvmtofh(dfhp); 102438418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 102552196Smckusick if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 102638418Smckusick nfsm_reply(0); 102752196Smckusick if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0))) 102838418Smckusick goto out1; 102952316Sheideman nd.ni_cnd.cn_cred = cred; 103052316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 103152316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 103252653Smckusick if (error = nfs_namei(&nd, dfhp, len, nfsd->nd_slp, nam, &md, &dpos, 103352653Smckusick nfsd->nd_procp)) 103438418Smckusick goto out1; 103549742Smckusick xp = nd.ni_vp; 103638418Smckusick if (xp != NULL) { 103738418Smckusick error = EEXIST; 103838418Smckusick goto out; 103938418Smckusick } 104049742Smckusick xp = nd.ni_dvp; 104138418Smckusick if (vp->v_mount != xp->v_mount) 104238418Smckusick error = EXDEV; 104338418Smckusick out: 104442467Smckusick if (!error) { 104552196Smckusick nqsrv_getl(vp, NQL_WRITE); 104652196Smckusick nqsrv_getl(xp, NQL_WRITE); 104752933Smckusick error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 104842467Smckusick } else { 104952234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 105049742Smckusick if (nd.ni_dvp == nd.ni_vp) 105149742Smckusick vrele(nd.ni_dvp); 105243359Smckusick else 105349742Smckusick vput(nd.ni_dvp); 105449742Smckusick if (nd.ni_vp) 105549742Smckusick vrele(nd.ni_vp); 105642467Smckusick } 105738418Smckusick out1: 105838418Smckusick vrele(vp); 105938418Smckusick nfsm_reply(0); 106038418Smckusick nfsm_srvdone; 106138418Smckusick } 106238418Smckusick 106338418Smckusick /* 106438418Smckusick * nfs symbolic link service 106538418Smckusick */ 106652196Smckusick nfsrv_symlink(nfsd, mrep, md, dpos, cred, nam, mrq) 106752196Smckusick struct nfsd *nfsd; 106852196Smckusick struct mbuf *mrep, *md; 106938418Smckusick caddr_t dpos; 107038418Smckusick struct ucred *cred; 107152196Smckusick struct mbuf *nam, **mrq; 107238418Smckusick { 107338418Smckusick struct vattr va; 107449742Smckusick struct nameidata nd; 107538418Smckusick register struct vattr *vap = &va; 107648050Smckusick register u_long *tl; 107739494Smckusick register long t1; 107845285Smckusick struct nfsv2_sattr *sp; 107939494Smckusick caddr_t bpos; 108041899Smckusick struct uio io; 108141899Smckusick struct iovec iv; 108252196Smckusick int error = 0, rdonly, cache, len, len2; 108341899Smckusick char *pathcp, *cp2; 108439753Smckusick struct mbuf *mb, *mreq; 108538418Smckusick nfsv2fh_t nfh; 108638418Smckusick fhandle_t *fhp; 108752196Smckusick u_quad_t frev; 108838418Smckusick 108941899Smckusick pathcp = (char *)0; 109038418Smckusick fhp = &nfh.fh_generic; 109138418Smckusick nfsm_srvmtofh(fhp); 109238418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 109352316Sheideman nd.ni_cnd.cn_cred = cred; 109452316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 109552316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 109652653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 109752653Smckusick nfsd->nd_procp)) 109842467Smckusick goto out; 109941899Smckusick nfsm_strsiz(len2, NFS_MAXPATHLEN); 110041899Smckusick MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK); 110141899Smckusick iv.iov_base = pathcp; 110241899Smckusick iv.iov_len = len2; 110341899Smckusick io.uio_resid = len2; 110441899Smckusick io.uio_offset = 0; 110541899Smckusick io.uio_iov = &iv; 110641899Smckusick io.uio_iovcnt = 1; 110741899Smckusick io.uio_segflg = UIO_SYSSPACE; 110841899Smckusick io.uio_rw = UIO_READ; 110948050Smckusick io.uio_procp = (struct proc *)0; 111041899Smckusick nfsm_mtouio(&io, len2); 111156285Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 111241899Smckusick *(pathcp + len2) = '\0'; 111349742Smckusick if (nd.ni_vp) { 111452234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 111549742Smckusick if (nd.ni_dvp == nd.ni_vp) 111649742Smckusick vrele(nd.ni_dvp); 111743359Smckusick else 111849742Smckusick vput(nd.ni_dvp); 111949742Smckusick vrele(nd.ni_vp); 112038418Smckusick error = EEXIST; 112138418Smckusick goto out; 112238418Smckusick } 112341361Smckusick VATTR_NULL(vap); 112445285Smckusick vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode); 112552196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 112652234Sheideman error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp); 112738418Smckusick out: 112841899Smckusick if (pathcp) 112941899Smckusick FREE(pathcp, M_TEMP); 113038418Smckusick nfsm_reply(0); 113138418Smckusick return (error); 113238418Smckusick nfsmout: 113352234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 113449742Smckusick if (nd.ni_dvp == nd.ni_vp) 113549742Smckusick vrele(nd.ni_dvp); 113643359Smckusick else 113749742Smckusick vput(nd.ni_dvp); 113849742Smckusick if (nd.ni_vp) 113949742Smckusick vrele(nd.ni_vp); 114041899Smckusick if (pathcp) 114141899Smckusick FREE(pathcp, M_TEMP); 114238418Smckusick return (error); 114338418Smckusick } 114438418Smckusick 114538418Smckusick /* 114638418Smckusick * nfs mkdir service 114738418Smckusick */ 114852196Smckusick nfsrv_mkdir(nfsd, mrep, md, dpos, cred, nam, mrq) 114952196Smckusick struct nfsd *nfsd; 115052196Smckusick struct mbuf *mrep, *md; 115138418Smckusick caddr_t dpos; 115238418Smckusick struct ucred *cred; 115352196Smckusick struct mbuf *nam, **mrq; 115438418Smckusick { 115538418Smckusick struct vattr va; 115638418Smckusick register struct vattr *vap = &va; 115738884Smacklem register struct nfsv2_fattr *fp; 115849742Smckusick struct nameidata nd; 115939494Smckusick register caddr_t cp; 116048050Smckusick register u_long *tl; 116139494Smckusick register long t1; 116239494Smckusick caddr_t bpos; 116352196Smckusick int error = 0, rdonly, cache, len; 116439494Smckusick char *cp2; 116539753Smckusick struct mbuf *mb, *mb2, *mreq; 116638418Smckusick struct vnode *vp; 116738418Smckusick nfsv2fh_t nfh; 116838418Smckusick fhandle_t *fhp; 116952196Smckusick u_quad_t frev; 117038418Smckusick 117138418Smckusick fhp = &nfh.fh_generic; 117238418Smckusick nfsm_srvmtofh(fhp); 117338418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 117452316Sheideman nd.ni_cnd.cn_cred = cred; 117552316Sheideman nd.ni_cnd.cn_nameiop = CREATE; 117652316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT; 117752653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 117852653Smckusick nfsd->nd_procp)) 117938418Smckusick nfsm_reply(0); 118052196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 118141361Smckusick VATTR_NULL(vap); 118238418Smckusick vap->va_type = VDIR; 118348050Smckusick vap->va_mode = nfstov_mode(*tl++); 118449742Smckusick vp = nd.ni_vp; 118538418Smckusick if (vp != NULL) { 118652234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 118749742Smckusick if (nd.ni_dvp == vp) 118849742Smckusick vrele(nd.ni_dvp); 118943359Smckusick else 119049742Smckusick vput(nd.ni_dvp); 119142467Smckusick vrele(vp); 119238418Smckusick error = EEXIST; 119338418Smckusick nfsm_reply(0); 119438418Smckusick } 119552196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 119652234Sheideman if (error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) 119738418Smckusick nfsm_reply(0); 119849742Smckusick vp = nd.ni_vp; 119938418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 120041398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 120138418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 120238418Smckusick vput(vp); 120338418Smckusick nfsm_reply(0); 120438418Smckusick } 120552196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 120638418Smckusick vput(vp); 120756285Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 120838418Smckusick nfsm_srvfhtom(fhp); 120956285Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); 121039753Smckusick nfsm_srvfillattr; 121138418Smckusick return (error); 121238418Smckusick nfsmout: 121352234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 121449742Smckusick if (nd.ni_dvp == nd.ni_vp) 121549742Smckusick vrele(nd.ni_dvp); 121643359Smckusick else 121749742Smckusick vput(nd.ni_dvp); 121849742Smckusick if (nd.ni_vp) 121949742Smckusick vrele(nd.ni_vp); 122038418Smckusick return (error); 122138418Smckusick } 122238418Smckusick 122338418Smckusick /* 122438418Smckusick * nfs rmdir service 122538418Smckusick */ 122652196Smckusick nfsrv_rmdir(nfsd, mrep, md, dpos, cred, nam, mrq) 122752196Smckusick struct nfsd *nfsd; 122852196Smckusick struct mbuf *mrep, *md; 122938418Smckusick caddr_t dpos; 123038418Smckusick struct ucred *cred; 123152196Smckusick struct mbuf *nam, **mrq; 123238418Smckusick { 123348050Smckusick register u_long *tl; 123439494Smckusick register long t1; 123539494Smckusick caddr_t bpos; 123652196Smckusick int error = 0, rdonly, cache, len; 123739494Smckusick char *cp2; 123839753Smckusick struct mbuf *mb, *mreq; 123938418Smckusick struct vnode *vp; 124038418Smckusick nfsv2fh_t nfh; 124138418Smckusick fhandle_t *fhp; 124249742Smckusick struct nameidata nd; 124352196Smckusick u_quad_t frev; 124438418Smckusick 124538418Smckusick fhp = &nfh.fh_generic; 124638418Smckusick nfsm_srvmtofh(fhp); 124738418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 124852316Sheideman nd.ni_cnd.cn_cred = cred; 124952316Sheideman nd.ni_cnd.cn_nameiop = DELETE; 125052316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 125152653Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 125252653Smckusick nfsd->nd_procp)) 125338418Smckusick nfsm_reply(0); 125449742Smckusick vp = nd.ni_vp; 125538418Smckusick if (vp->v_type != VDIR) { 125638418Smckusick error = ENOTDIR; 125738418Smckusick goto out; 125838418Smckusick } 125938418Smckusick /* 126038418Smckusick * No rmdir "." please. 126138418Smckusick */ 126249742Smckusick if (nd.ni_dvp == vp) { 126338418Smckusick error = EINVAL; 126438418Smckusick goto out; 126538418Smckusick } 126638418Smckusick /* 126749454Smckusick * The root of a mounted filesystem cannot be deleted. 126838418Smckusick */ 126938418Smckusick if (vp->v_flag & VROOT) 127038418Smckusick error = EBUSY; 127138418Smckusick out: 127242467Smckusick if (!error) { 127352196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 127452196Smckusick nqsrv_getl(vp, NQL_WRITE); 127552234Sheideman error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 127642467Smckusick } else { 127752234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 127849742Smckusick if (nd.ni_dvp == nd.ni_vp) 127949742Smckusick vrele(nd.ni_dvp); 128043359Smckusick else 128149742Smckusick vput(nd.ni_dvp); 128242467Smckusick vput(vp); 128342467Smckusick } 128438418Smckusick nfsm_reply(0); 128538418Smckusick nfsm_srvdone; 128638418Smckusick } 128738418Smckusick 128838418Smckusick /* 128938418Smckusick * nfs readdir service 129038418Smckusick * - mallocs what it thinks is enough to read 129148050Smckusick * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR 129238418Smckusick * - calls VOP_READDIR() 129340115Smckusick * - loops around building the reply 129438425Smckusick * if the output generated exceeds count break out of loop 129538425Smckusick * The nfsm_clget macro is used here so that the reply will be packed 129638425Smckusick * tightly in mbuf clusters. 129738418Smckusick * - it only knows that it has encountered eof when the VOP_READDIR() 129838425Smckusick * reads nothing 129938418Smckusick * - as such one readdir rpc will return eof false although you are there 130038425Smckusick * and then the next will return eof 130152441Smckusick * - it trims out records with d_fileno == 0 130238425Smckusick * this doesn't matter for Unix clients, but they might confuse clients 130338425Smckusick * for other os'. 130438418Smckusick * NB: It is tempting to set eof to true if the VOP_READDIR() reads less 130538425Smckusick * than requested, but this may not apply to all filesystems. For 130638425Smckusick * example, client NFS does not { although it is never remote mounted 130738425Smckusick * anyhow } 130852196Smckusick * The alternate call nqnfsrv_readdirlook() does lookups as well. 130938418Smckusick * PS: The NFS protocol spec. does not clarify what the "count" byte 131038425Smckusick * argument is a count of.. just name strings and file id's or the 131138425Smckusick * entire reply rpc or ... 131238425Smckusick * I tried just file name and id sizes and it confused the Sun client, 131338425Smckusick * so I am using the full rpc size now. The "paranoia.." comment refers 131438425Smckusick * to including the status longwords that are not a part of the dir. 131538425Smckusick * "entry" structures, but are in the rpc. 131638418Smckusick */ 131752196Smckusick struct flrep { 131852196Smckusick u_long fl_cachable; 131952196Smckusick u_long fl_duration; 132055528Smckusick u_long fl_frev[2]; 132152196Smckusick nfsv2fh_t fl_nfh; 132256285Smckusick u_long fl_fattr[NFSX_NQFATTR / sizeof (u_long)]; 132352196Smckusick }; 132452196Smckusick 132552196Smckusick nfsrv_readdir(nfsd, mrep, md, dpos, cred, nam, mrq) 132652196Smckusick struct nfsd *nfsd; 132738418Smckusick struct mbuf *mrep, *md; 132838418Smckusick caddr_t dpos; 132938418Smckusick struct ucred *cred; 133052196Smckusick struct mbuf *nam, **mrq; 133138418Smckusick { 133238418Smckusick register char *bp, *be; 133338418Smckusick register struct mbuf *mp; 133452441Smckusick register struct dirent *dp; 133539494Smckusick register caddr_t cp; 133648050Smckusick register u_long *tl; 133739494Smckusick register long t1; 133839494Smckusick caddr_t bpos; 133952196Smckusick struct mbuf *mb, *mb2, *mreq, *mp2; 134052196Smckusick char *cpos, *cend, *cp2, *rbuf; 134138418Smckusick struct vnode *vp; 134238418Smckusick nfsv2fh_t nfh; 134338418Smckusick fhandle_t *fhp; 134438418Smckusick struct uio io; 134538418Smckusick struct iovec iv; 134652196Smckusick struct vattr va; 134752196Smckusick int len, nlen, rem, xfer, tsiz, i, error = 0; 134852196Smckusick int siz, cnt, fullsiz, eofflag, rdonly, cache; 134952196Smckusick u_quad_t frev; 135056285Smckusick u_long on, off, toff; 135138418Smckusick 135238418Smckusick fhp = &nfh.fh_generic; 135338418Smckusick nfsm_srvmtofh(fhp); 135452196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 135556285Smckusick toff = fxdr_unsigned(u_long, *tl++); 135648050Smckusick off = (toff & ~(NFS_DIRBLKSIZ-1)); 135748050Smckusick on = (toff & (NFS_DIRBLKSIZ-1)); 135848050Smckusick cnt = fxdr_unsigned(int, *tl); 135948050Smckusick siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); 136041899Smckusick if (cnt > NFS_MAXREADDIR) 136141899Smckusick siz = NFS_MAXREADDIR; 136238418Smckusick fullsiz = siz; 136352196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 136438418Smckusick nfsm_reply(0); 136552196Smckusick nqsrv_getl(vp, NQL_READ); 136652196Smckusick if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { 136738418Smckusick vput(vp); 136838418Smckusick nfsm_reply(0); 136938418Smckusick } 137038418Smckusick VOP_UNLOCK(vp); 137138418Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 137238418Smckusick again: 137338418Smckusick iv.iov_base = rbuf; 137438418Smckusick iv.iov_len = fullsiz; 137538418Smckusick io.uio_iov = &iv; 137638418Smckusick io.uio_iovcnt = 1; 137756285Smckusick io.uio_offset = (off_t)off; 137838418Smckusick io.uio_resid = fullsiz; 137938418Smckusick io.uio_segflg = UIO_SYSSPACE; 138038418Smckusick io.uio_rw = UIO_READ; 138148050Smckusick io.uio_procp = (struct proc *)0; 138254446Smckusick error = VOP_READDIR(vp, &io, cred); 138356285Smckusick off = (off_t)io.uio_offset; 138438418Smckusick if (error) { 138538418Smckusick vrele(vp); 138638418Smckusick free((caddr_t)rbuf, M_TEMP); 138738418Smckusick nfsm_reply(0); 138838418Smckusick } 138954446Smckusick if (io.uio_resid < fullsiz) 139054446Smckusick eofflag = 0; 139154446Smckusick else 139254446Smckusick eofflag = 1; 139338418Smckusick if (io.uio_resid) { 139438418Smckusick siz -= io.uio_resid; 139538418Smckusick 139638418Smckusick /* 139738418Smckusick * If nothing read, return eof 139838418Smckusick * rpc reply 139938418Smckusick */ 140038418Smckusick if (siz == 0) { 140138418Smckusick vrele(vp); 140238418Smckusick nfsm_reply(2*NFSX_UNSIGNED); 140348050Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 140448050Smckusick *tl++ = nfs_false; 140548050Smckusick *tl = nfs_true; 140638418Smckusick FREE((caddr_t)rbuf, M_TEMP); 140738418Smckusick return (0); 140838418Smckusick } 140938418Smckusick } 141040115Smckusick 141138418Smckusick /* 141238418Smckusick * Check for degenerate cases of nothing useful read. 141340115Smckusick * If so go try again 141438418Smckusick */ 141540115Smckusick cpos = rbuf + on; 141640115Smckusick cend = rbuf + siz; 141752441Smckusick dp = (struct dirent *)cpos; 141852441Smckusick while (cpos < cend && dp->d_fileno == 0) { 141940115Smckusick cpos += dp->d_reclen; 142052441Smckusick dp = (struct dirent *)cpos; 142140115Smckusick } 142240115Smckusick if (cpos >= cend) { 142338418Smckusick toff = off; 142438418Smckusick siz = fullsiz; 142538418Smckusick on = 0; 142638418Smckusick goto again; 142738418Smckusick } 142840115Smckusick 142940115Smckusick cpos = rbuf + on; 143040115Smckusick cend = rbuf + siz; 143152441Smckusick dp = (struct dirent *)cpos; 143252196Smckusick len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 143352196Smckusick nfsm_reply(siz); 143452196Smckusick mp = mp2 = mb; 143552196Smckusick bp = bpos; 143652196Smckusick be = bp + M_TRAILINGSPACE(mp); 143752196Smckusick 143852196Smckusick /* Loop through the records and build reply */ 143952196Smckusick while (cpos < cend) { 144052441Smckusick if (dp->d_fileno != 0) { 144152196Smckusick nlen = dp->d_namlen; 144252196Smckusick rem = nfsm_rndup(nlen)-nlen; 144352196Smckusick len += (4*NFSX_UNSIGNED + nlen + rem); 144452196Smckusick if (len > cnt) { 144552196Smckusick eofflag = 0; 144652196Smckusick break; 144752196Smckusick } 144852441Smckusick /* 144952441Smckusick * Build the directory record xdr from 145052441Smckusick * the dirent entry. 145152441Smckusick */ 145252196Smckusick nfsm_clget; 145352196Smckusick *tl = nfs_true; 145452196Smckusick bp += NFSX_UNSIGNED; 145552196Smckusick nfsm_clget; 145652441Smckusick *tl = txdr_unsigned(dp->d_fileno); 145752196Smckusick bp += NFSX_UNSIGNED; 145852196Smckusick nfsm_clget; 145952196Smckusick *tl = txdr_unsigned(nlen); 146052196Smckusick bp += NFSX_UNSIGNED; 146152196Smckusick 146252196Smckusick /* And loop around copying the name */ 146352196Smckusick xfer = nlen; 146452196Smckusick cp = dp->d_name; 146552196Smckusick while (xfer > 0) { 146652196Smckusick nfsm_clget; 146752196Smckusick if ((bp+xfer) > be) 146852196Smckusick tsiz = be-bp; 146952196Smckusick else 147052196Smckusick tsiz = xfer; 147152196Smckusick bcopy(cp, bp, tsiz); 147252196Smckusick bp += tsiz; 147352196Smckusick xfer -= tsiz; 147452196Smckusick if (xfer > 0) 147552196Smckusick cp += tsiz; 147652196Smckusick } 147752196Smckusick /* And null pad to a long boundary */ 147852196Smckusick for (i = 0; i < rem; i++) 147952196Smckusick *bp++ = '\0'; 148052196Smckusick nfsm_clget; 148152196Smckusick 148252196Smckusick /* Finish off the record */ 148352196Smckusick toff += dp->d_reclen; 148452196Smckusick *tl = txdr_unsigned(toff); 148552196Smckusick bp += NFSX_UNSIGNED; 148652196Smckusick } else 148752196Smckusick toff += dp->d_reclen; 148852196Smckusick cpos += dp->d_reclen; 148952441Smckusick dp = (struct dirent *)cpos; 149052196Smckusick } 149138418Smckusick vrele(vp); 149252196Smckusick nfsm_clget; 149352196Smckusick *tl = nfs_false; 149452196Smckusick bp += NFSX_UNSIGNED; 149552196Smckusick nfsm_clget; 149652196Smckusick if (eofflag) 149752196Smckusick *tl = nfs_true; 149852196Smckusick else 149952196Smckusick *tl = nfs_false; 150052196Smckusick bp += NFSX_UNSIGNED; 150152196Smckusick if (mp != mb) { 150252196Smckusick if (bp < be) 150352196Smckusick mp->m_len = bp - mtod(mp, caddr_t); 150452196Smckusick } else 150552196Smckusick mp->m_len += bp - bpos; 150652196Smckusick FREE(rbuf, M_TEMP); 150752196Smckusick nfsm_srvdone; 150852196Smckusick } 150952196Smckusick 151052196Smckusick nqnfsrv_readdirlook(nfsd, mrep, md, dpos, cred, nam, mrq) 151152196Smckusick struct nfsd *nfsd; 151252196Smckusick struct mbuf *mrep, *md; 151352196Smckusick caddr_t dpos; 151452196Smckusick struct ucred *cred; 151552196Smckusick struct mbuf *nam, **mrq; 151652196Smckusick { 151752196Smckusick register char *bp, *be; 151852196Smckusick register struct mbuf *mp; 151952441Smckusick register struct dirent *dp; 152052196Smckusick register caddr_t cp; 152152196Smckusick register u_long *tl; 152252196Smckusick register long t1; 152352196Smckusick caddr_t bpos; 152452196Smckusick struct mbuf *mb, *mb2, *mreq, *mp2; 152552196Smckusick char *cpos, *cend, *cp2, *rbuf; 152652196Smckusick struct vnode *vp, *nvp; 152752196Smckusick struct flrep fl; 152852196Smckusick nfsv2fh_t nfh; 152952196Smckusick fhandle_t *fhp; 153052196Smckusick struct uio io; 153152196Smckusick struct iovec iv; 153252196Smckusick struct vattr va, *vap = &va; 153352196Smckusick struct nfsv2_fattr *fp; 153452196Smckusick int len, nlen, rem, xfer, tsiz, i, error = 0, duration2, cache2; 153552196Smckusick int siz, cnt, fullsiz, eofflag, rdonly, cache; 153652196Smckusick u_quad_t frev, frev2; 153756285Smckusick u_long on, off, toff; 153852196Smckusick 153952196Smckusick fhp = &nfh.fh_generic; 154052196Smckusick nfsm_srvmtofh(fhp); 154152196Smckusick nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED); 154256285Smckusick toff = fxdr_unsigned(u_long, *tl++); 154352196Smckusick off = (toff & ~(NFS_DIRBLKSIZ-1)); 154452196Smckusick on = (toff & (NFS_DIRBLKSIZ-1)); 154552196Smckusick cnt = fxdr_unsigned(int, *tl++); 154652196Smckusick duration2 = fxdr_unsigned(int, *tl); 154752196Smckusick siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); 154852196Smckusick if (cnt > NFS_MAXREADDIR) 154952196Smckusick siz = NFS_MAXREADDIR; 155052196Smckusick fullsiz = siz; 155152196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 155252196Smckusick nfsm_reply(0); 155352196Smckusick nqsrv_getl(vp, NQL_READ); 155452196Smckusick if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { 155552196Smckusick vput(vp); 155652196Smckusick nfsm_reply(0); 155752196Smckusick } 155852196Smckusick VOP_UNLOCK(vp); 155952196Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 156052196Smckusick again: 156152196Smckusick iv.iov_base = rbuf; 156252196Smckusick iv.iov_len = fullsiz; 156352196Smckusick io.uio_iov = &iv; 156452196Smckusick io.uio_iovcnt = 1; 156556285Smckusick io.uio_offset = (off_t)off; 156652196Smckusick io.uio_resid = fullsiz; 156752196Smckusick io.uio_segflg = UIO_SYSSPACE; 156852196Smckusick io.uio_rw = UIO_READ; 156952196Smckusick io.uio_procp = (struct proc *)0; 157054446Smckusick error = VOP_READDIR(vp, &io, cred); 157156285Smckusick off = (u_long)io.uio_offset; 157252196Smckusick if (error) { 157352196Smckusick vrele(vp); 157452196Smckusick free((caddr_t)rbuf, M_TEMP); 157552196Smckusick nfsm_reply(0); 157652196Smckusick } 157754446Smckusick if (io.uio_resid < fullsiz) 157854446Smckusick eofflag = 0; 157954446Smckusick else 158054446Smckusick eofflag = 1; 158152196Smckusick if (io.uio_resid) { 158252196Smckusick siz -= io.uio_resid; 158352196Smckusick 158452196Smckusick /* 158552196Smckusick * If nothing read, return eof 158652196Smckusick * rpc reply 158752196Smckusick */ 158852196Smckusick if (siz == 0) { 158952196Smckusick vrele(vp); 159056285Smckusick nfsm_reply(2 * NFSX_UNSIGNED); 159156285Smckusick nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); 159252196Smckusick *tl++ = nfs_false; 159352196Smckusick *tl = nfs_true; 159452196Smckusick FREE((caddr_t)rbuf, M_TEMP); 159552196Smckusick return (0); 159652196Smckusick } 159752196Smckusick } 159852196Smckusick 159952196Smckusick /* 160052196Smckusick * Check for degenerate cases of nothing useful read. 160152196Smckusick * If so go try again 160252196Smckusick */ 160352196Smckusick cpos = rbuf + on; 160452196Smckusick cend = rbuf + siz; 160552441Smckusick dp = (struct dirent *)cpos; 160652441Smckusick while (cpos < cend && dp->d_fileno == 0) { 160752196Smckusick cpos += dp->d_reclen; 160852441Smckusick dp = (struct dirent *)cpos; 160952196Smckusick } 161052196Smckusick if (cpos >= cend) { 161152196Smckusick toff = off; 161252196Smckusick siz = fullsiz; 161352196Smckusick on = 0; 161452196Smckusick goto again; 161552196Smckusick } 161652196Smckusick 161752196Smckusick cpos = rbuf + on; 161852196Smckusick cend = rbuf + siz; 161952441Smckusick dp = (struct dirent *)cpos; 162056285Smckusick len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 162138418Smckusick nfsm_reply(siz); 162252196Smckusick mp = mp2 = mb; 162352196Smckusick bp = bpos; 162452196Smckusick be = bp + M_TRAILINGSPACE(mp); 162538418Smckusick 162638418Smckusick /* Loop through the records and build reply */ 162738418Smckusick while (cpos < cend) { 162852441Smckusick if (dp->d_fileno != 0) { 162938418Smckusick nlen = dp->d_namlen; 163038418Smckusick rem = nfsm_rndup(nlen)-nlen; 163138425Smckusick 163238418Smckusick /* 163352196Smckusick * For readdir_and_lookup get the vnode using 163452196Smckusick * the file number. 163538418Smckusick */ 163654665Smckusick if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp)) 163752196Smckusick goto invalid; 163855655Smckusick bzero((caddr_t)&fl.fl_nfh, sizeof (nfsv2fh_t)); 163955655Smckusick fl.fl_nfh.fh_generic.fh_fsid = 164055655Smckusick nvp->v_mount->mnt_stat.f_fsid; 164155655Smckusick if (VFS_VPTOFH(nvp, &fl.fl_nfh.fh_generic.fh_fid)) { 164255655Smckusick vput(nvp); 164355655Smckusick goto invalid; 164455655Smckusick } 164556285Smckusick if (duration2) { 164656285Smckusick (void) nqsrv_getlease(nvp, &duration2, NQL_READ, 164756285Smckusick nfsd, nam, &cache2, &frev2, cred); 164856285Smckusick fl.fl_duration = txdr_unsigned(duration2); 164956285Smckusick fl.fl_cachable = txdr_unsigned(cache2); 165056285Smckusick txdr_hyper(&frev2, fl.fl_frev); 165156285Smckusick } else 165256285Smckusick fl.fl_duration = 0; 165352196Smckusick if (VOP_GETATTR(nvp, vap, cred, nfsd->nd_procp)) { 165452196Smckusick vput(nvp); 165552196Smckusick goto invalid; 165652196Smckusick } 165752196Smckusick vput(nvp); 165856285Smckusick fp = (struct nfsv2_fattr *)&fl.fl_fattr; 165952196Smckusick nfsm_srvfillattr; 166052196Smckusick len += (4*NFSX_UNSIGNED + nlen + rem + NFSX_FH 166156285Smckusick + NFSX_NQFATTR); 166241899Smckusick if (len > cnt) { 166341899Smckusick eofflag = 0; 166438418Smckusick break; 166541899Smckusick } 166652441Smckusick /* 166752441Smckusick * Build the directory record xdr from 166852441Smckusick * the dirent entry. 166952441Smckusick */ 167038418Smckusick nfsm_clget; 167148050Smckusick *tl = nfs_true; 167238418Smckusick bp += NFSX_UNSIGNED; 167352196Smckusick 167452196Smckusick /* 167552196Smckusick * For readdir_and_lookup copy the stuff out. 167652196Smckusick */ 167752196Smckusick xfer = sizeof (struct flrep); 167852196Smckusick cp = (caddr_t)&fl; 167952196Smckusick while (xfer > 0) { 168052196Smckusick nfsm_clget; 168152196Smckusick if ((bp+xfer) > be) 168252196Smckusick tsiz = be-bp; 168352196Smckusick else 168452196Smckusick tsiz = xfer; 168552196Smckusick bcopy(cp, bp, tsiz); 168652196Smckusick bp += tsiz; 168752196Smckusick xfer -= tsiz; 168852196Smckusick if (xfer > 0) 168952196Smckusick cp += tsiz; 169052196Smckusick } 169138418Smckusick nfsm_clget; 169252441Smckusick *tl = txdr_unsigned(dp->d_fileno); 169338418Smckusick bp += NFSX_UNSIGNED; 169438418Smckusick nfsm_clget; 169548050Smckusick *tl = txdr_unsigned(nlen); 169638418Smckusick bp += NFSX_UNSIGNED; 169738425Smckusick 169852196Smckusick /* And loop around copying the name */ 169938418Smckusick xfer = nlen; 170038418Smckusick cp = dp->d_name; 170138418Smckusick while (xfer > 0) { 170238418Smckusick nfsm_clget; 170338418Smckusick if ((bp+xfer) > be) 170438418Smckusick tsiz = be-bp; 170538418Smckusick else 170638418Smckusick tsiz = xfer; 170738418Smckusick bcopy(cp, bp, tsiz); 170838418Smckusick bp += tsiz; 170938418Smckusick xfer -= tsiz; 171038418Smckusick if (xfer > 0) 171138418Smckusick cp += tsiz; 171238418Smckusick } 171338418Smckusick /* And null pad to a long boundary */ 171438418Smckusick for (i = 0; i < rem; i++) 171538418Smckusick *bp++ = '\0'; 171638418Smckusick nfsm_clget; 171738425Smckusick 171838418Smckusick /* Finish off the record */ 171938418Smckusick toff += dp->d_reclen; 172048050Smckusick *tl = txdr_unsigned(toff); 172138418Smckusick bp += NFSX_UNSIGNED; 172238418Smckusick } else 172352196Smckusick invalid: 172438418Smckusick toff += dp->d_reclen; 172538418Smckusick cpos += dp->d_reclen; 172652441Smckusick dp = (struct dirent *)cpos; 172738418Smckusick } 172852196Smckusick vrele(vp); 172938418Smckusick nfsm_clget; 173048050Smckusick *tl = nfs_false; 173138418Smckusick bp += NFSX_UNSIGNED; 173238418Smckusick nfsm_clget; 173340296Smckusick if (eofflag) 173448050Smckusick *tl = nfs_true; 173540296Smckusick else 173648050Smckusick *tl = nfs_false; 173738418Smckusick bp += NFSX_UNSIGNED; 173852196Smckusick if (mp != mb) { 173952196Smckusick if (bp < be) 174052196Smckusick mp->m_len = bp - mtod(mp, caddr_t); 174152196Smckusick } else 174252196Smckusick mp->m_len += bp - bpos; 174338418Smckusick FREE(rbuf, M_TEMP); 174438418Smckusick nfsm_srvdone; 174538418Smckusick } 174638418Smckusick 174738418Smckusick /* 174838418Smckusick * nfs statfs service 174938418Smckusick */ 175052196Smckusick nfsrv_statfs(nfsd, mrep, md, dpos, cred, nam, mrq) 175152196Smckusick struct nfsd *nfsd; 175238418Smckusick struct mbuf *mrep, *md; 175338418Smckusick caddr_t dpos; 175438418Smckusick struct ucred *cred; 175552196Smckusick struct mbuf *nam, **mrq; 175638418Smckusick { 175738418Smckusick register struct statfs *sf; 175838884Smacklem register struct nfsv2_statfs *sfp; 175948050Smckusick register u_long *tl; 176039494Smckusick register long t1; 176139494Smckusick caddr_t bpos; 176256285Smckusick int error = 0, rdonly, cache, isnq; 176339494Smckusick char *cp2; 176439753Smckusick struct mbuf *mb, *mb2, *mreq; 176538418Smckusick struct vnode *vp; 176638418Smckusick nfsv2fh_t nfh; 176738418Smckusick fhandle_t *fhp; 176838418Smckusick struct statfs statfs; 176952196Smckusick u_quad_t frev; 177038418Smckusick 177138418Smckusick fhp = &nfh.fh_generic; 177256285Smckusick isnq = (nfsd->nd_nqlflag != NQL_NOVAL); 177338418Smckusick nfsm_srvmtofh(fhp); 177452196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 177538418Smckusick nfsm_reply(0); 177638418Smckusick sf = &statfs; 177752196Smckusick error = VFS_STATFS(vp->v_mount, sf, nfsd->nd_procp); 177838418Smckusick vput(vp); 177956285Smckusick nfsm_reply(NFSX_STATFS(isnq)); 178056285Smckusick nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS(isnq)); 178144993Sbostic sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA); 178251940Smckusick sfp->sf_bsize = txdr_unsigned(sf->f_bsize); 178338884Smacklem sfp->sf_blocks = txdr_unsigned(sf->f_blocks); 178438884Smacklem sfp->sf_bfree = txdr_unsigned(sf->f_bfree); 178538884Smacklem sfp->sf_bavail = txdr_unsigned(sf->f_bavail); 178656285Smckusick if (isnq) { 178756285Smckusick sfp->sf_files = txdr_unsigned(sf->f_files); 178856285Smckusick sfp->sf_ffree = txdr_unsigned(sf->f_ffree); 178956285Smckusick } 179038418Smckusick nfsm_srvdone; 179138418Smckusick } 179238418Smckusick 179338418Smckusick /* 179438418Smckusick * Null operation, used by clients to ping server 179538418Smckusick */ 179639494Smckusick /* ARGSUSED */ 179752196Smckusick nfsrv_null(nfsd, mrep, md, dpos, cred, nam, mrq) 179852196Smckusick struct nfsd *nfsd; 179938418Smckusick struct mbuf *mrep, *md; 180038418Smckusick caddr_t dpos; 180138418Smckusick struct ucred *cred; 180252196Smckusick struct mbuf *nam, **mrq; 180338418Smckusick { 180439494Smckusick caddr_t bpos; 180552196Smckusick int error = VNOVAL, cache; 180639753Smckusick struct mbuf *mb, *mreq; 180752196Smckusick u_quad_t frev; 180838418Smckusick 180938418Smckusick nfsm_reply(0); 181039494Smckusick return (error); 181138418Smckusick } 181238418Smckusick 181338418Smckusick /* 181438418Smckusick * No operation, used for obsolete procedures 181538418Smckusick */ 181639494Smckusick /* ARGSUSED */ 181752196Smckusick nfsrv_noop(nfsd, mrep, md, dpos, cred, nam, mrq) 181852196Smckusick struct nfsd *nfsd; 181938418Smckusick struct mbuf *mrep, *md; 182038418Smckusick caddr_t dpos; 182138418Smckusick struct ucred *cred; 182252196Smckusick struct mbuf *nam, **mrq; 182338418Smckusick { 182439494Smckusick caddr_t bpos; 182552196Smckusick int error, cache; 182639753Smckusick struct mbuf *mb, *mreq; 182752196Smckusick u_quad_t frev; 182838418Smckusick 182952196Smckusick if (nfsd->nd_repstat) 183052196Smckusick error = nfsd->nd_repstat; 183152196Smckusick else 183252196Smckusick error = EPROCUNAVAIL; 183338418Smckusick nfsm_reply(0); 183439494Smckusick return (error); 183538418Smckusick } 183638425Smckusick 183738450Smckusick /* 183838450Smckusick * Perform access checking for vnodes obtained from file handles that would 183938450Smckusick * refer to files already opened by a Unix client. You cannot just use 184038450Smckusick * vn_writechk() and VOP_ACCESS() for two reasons. 184152196Smckusick * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case 184238450Smckusick * 2 - The owner is to be given access irrespective of mode bits so that 184338450Smckusick * processes that chmod after opening a file don't break. I don't like 184438450Smckusick * this because it opens a security hole, but since the nfs server opens 184538450Smckusick * a security hole the size of a barn door anyhow, what the heck. 184638450Smckusick */ 184752196Smckusick nfsrv_access(vp, flags, cred, rdonly, p) 184838450Smckusick register struct vnode *vp; 184938450Smckusick int flags; 185038450Smckusick register struct ucred *cred; 185152196Smckusick int rdonly; 185248050Smckusick struct proc *p; 185338450Smckusick { 185438450Smckusick struct vattr vattr; 185538450Smckusick int error; 185638450Smckusick if (flags & VWRITE) { 185752196Smckusick /* Just vn_writechk() changed to check rdonly */ 185838450Smckusick /* 185938450Smckusick * Disallow write attempts on read-only file systems; 186038450Smckusick * unless the file is a socket or a block or character 186138450Smckusick * device resident on the file system. 186238450Smckusick */ 186352196Smckusick if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { 186445059Smckusick switch (vp->v_type) { 186545059Smckusick case VREG: case VDIR: case VLNK: 186638450Smckusick return (EROFS); 186745059Smckusick } 186845059Smckusick } 186938450Smckusick /* 187038450Smckusick * If there's shared text associated with 187138450Smckusick * the inode, try to free it up once. If 187238450Smckusick * we fail, we can't allow writing. 187338450Smckusick */ 187445715Smckusick if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) 187538450Smckusick return (ETXTBSY); 187638450Smckusick } 187748050Smckusick if (error = VOP_GETATTR(vp, &vattr, cred, p)) 187845059Smckusick return (error); 187948050Smckusick if ((error = VOP_ACCESS(vp, flags, cred, p)) && 188045059Smckusick cred->cr_uid != vattr.va_uid) 188145059Smckusick return (error); 188245059Smckusick return (0); 188338450Smckusick } 1884