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*52196Smckusick * @(#)nfs_serv.c 7.43 (Berkeley) 01/14/92 1138418Smckusick */ 1238418Smckusick 1338418Smckusick /* 1438418Smckusick * nfs version 2 server calls to vnode ops 1538418Smckusick * - these routines generally have 3 phases 1638418Smckusick * 1 - break down and validate rpc request in mbuf list 1738418Smckusick * 2 - do the vnode ops for the request 1838425Smckusick * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c) 1938418Smckusick * 3 - build the rpc reply in an mbuf list 2038418Smckusick * nb: 2138418Smckusick * - do not mix the phases, since the nfsm_?? macros can return failures 2241899Smckusick * on a bad rpc or similar and do not do any vrele() or vput()'s 2338418Smckusick * 2438425Smckusick * - the nfsm_reply() macro generates an nfs rpc reply with the nfs 2538418Smckusick * error number iff error != 0 whereas 2641899Smckusick * returning an error from the server function implies a fatal error 2741899Smckusick * such as a badly constructed rpc request that should be dropped without 2841899Smckusick * a reply. 2938418Smckusick */ 3038418Smckusick 3138418Smckusick #include "param.h" 3249742Smckusick #include "proc.h" 3340135Smckusick #include "file.h" 3448050Smckusick #include "namei.h" 3540135Smckusick #include "vnode.h" 3638418Smckusick #include "mount.h" 3738418Smckusick #include "mbuf.h" 3847573Skarels 3951464Sbostic #include "ufs/ufs/quota.h" 4051464Sbostic #include "ufs/ufs/inode.h" 4151464Sbostic #include "ufs/ufs/dir.h" 4247573Skarels 4338418Smckusick #include "nfsv2.h" 44*52196Smckusick #include "rpcv2.h" 4538418Smckusick #include "nfs.h" 4638418Smckusick #include "xdr_subs.h" 4738418Smckusick #include "nfsm_subs.h" 48*52196Smckusick #include "nqnfs.h" 4938418Smckusick 5038418Smckusick /* Defs */ 5138425Smckusick #define TRUE 1 5238425Smckusick #define FALSE 0 5338418Smckusick 5438418Smckusick /* Global vars */ 5538418Smckusick extern u_long nfs_procids[NFS_NPROCS]; 5638418Smckusick extern u_long nfs_xdrneg1; 5738418Smckusick extern u_long nfs_false, nfs_true; 58*52196Smckusick nfstype nfs_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, 5942242Smckusick NFCHR, NFNON }; 6038418Smckusick 6138418Smckusick /* 6238418Smckusick * nfs getattr service 6338418Smckusick */ 64*52196Smckusick nfsrv_getattr(nfsd, mrep, md, dpos, cred, nam, mrq) 65*52196Smckusick struct nfsd *nfsd; 6638418Smckusick struct mbuf *mrep, *md; 6738418Smckusick caddr_t dpos; 6838418Smckusick struct ucred *cred; 69*52196Smckusick struct mbuf *nam, **mrq; 7038418Smckusick { 7138884Smacklem register struct nfsv2_fattr *fp; 7238418Smckusick struct vattr va; 7338418Smckusick register struct vattr *vap = &va; 7438418Smckusick struct vnode *vp; 7538418Smckusick nfsv2fh_t nfh; 7638418Smckusick fhandle_t *fhp; 7748050Smckusick register u_long *tl; 7839494Smckusick register long t1; 7939494Smckusick caddr_t bpos; 80*52196Smckusick int error = 0, rdonly, cache; 8139494Smckusick char *cp2; 8239753Smckusick struct mbuf *mb, *mb2, *mreq; 83*52196Smckusick u_quad_t frev; 8438418Smckusick 8538418Smckusick fhp = &nfh.fh_generic; 8638418Smckusick nfsm_srvmtofh(fhp); 87*52196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 8838418Smckusick nfsm_reply(0); 89*52196Smckusick nqsrv_getl(vp, NQL_READ); 90*52196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 9138418Smckusick vput(vp); 9238418Smckusick nfsm_reply(NFSX_FATTR); 9338884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 9439753Smckusick nfsm_srvfillattr; 9538418Smckusick nfsm_srvdone; 9638418Smckusick } 9738418Smckusick 9838418Smckusick /* 9938418Smckusick * nfs setattr service 10038418Smckusick */ 101*52196Smckusick nfsrv_setattr(nfsd, mrep, md, dpos, cred, nam, mrq) 102*52196Smckusick struct nfsd *nfsd; 10338418Smckusick struct mbuf *mrep, *md; 10438418Smckusick caddr_t dpos; 10538418Smckusick struct ucred *cred; 106*52196Smckusick struct mbuf *nam, **mrq; 10738418Smckusick { 10838418Smckusick struct vattr va; 10938418Smckusick register struct vattr *vap = &va; 11038884Smacklem register struct nfsv2_sattr *sp; 11138884Smacklem register struct nfsv2_fattr *fp; 11238418Smckusick struct vnode *vp; 11338418Smckusick nfsv2fh_t nfh; 11438418Smckusick fhandle_t *fhp; 11548050Smckusick register u_long *tl; 11639494Smckusick register long t1; 11739494Smckusick caddr_t bpos; 118*52196Smckusick int error = 0, rdonly, cache, duration2, cache2; 11939494Smckusick char *cp2; 12039753Smckusick struct mbuf *mb, *mb2, *mreq; 121*52196Smckusick u_quad_t frev, frev2; 12238418Smckusick 12338418Smckusick fhp = &nfh.fh_generic; 12438418Smckusick nfsm_srvmtofh(fhp); 125*52196Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR); 126*52196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 12738418Smckusick nfsm_reply(0); 128*52196Smckusick nqsrv_getl(vp, NQL_WRITE); 129*52196Smckusick if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) 13038418Smckusick goto out; 13141361Smckusick VATTR_NULL(vap); 13238418Smckusick /* 13338418Smckusick * Nah nah nah nah na nah 13438418Smckusick * There is a bug in the Sun client that puts 0xffff in the mode 13538418Smckusick * field of sattr when it should put in 0xffffffff. The u_short 13638418Smckusick * doesn't sign extend. 13738418Smckusick * --> check the low order 2 bytes for 0xffff 13838418Smckusick */ 13938884Smacklem if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff) 14038884Smacklem vap->va_mode = nfstov_mode(sp->sa_mode); 14138884Smacklem if (sp->sa_uid != nfs_xdrneg1) 14238884Smacklem vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid); 14338884Smacklem if (sp->sa_gid != nfs_xdrneg1) 14438884Smacklem vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid); 14539753Smckusick if (sp->sa_size != nfs_xdrneg1) 14638884Smacklem vap->va_size = fxdr_unsigned(u_long, sp->sa_size); 14739753Smckusick /* 14839753Smckusick * The usec field of sa_atime is overloaded with the va_flags field 14939753Smckusick * for 4.4BSD clients. Hopefully other clients always set both the 15039753Smckusick * sec and usec fields to -1 when not setting the atime. 15139753Smckusick */ 15239753Smckusick if (sp->sa_atime.tv_sec != nfs_xdrneg1) { 15339753Smckusick vap->va_atime.tv_sec = fxdr_unsigned(long, sp->sa_atime.tv_sec); 15439753Smckusick vap->va_atime.tv_usec = 0; 15538425Smckusick } 15639753Smckusick if (sp->sa_atime.tv_usec != nfs_xdrneg1) 15739753Smckusick vap->va_flags = fxdr_unsigned(u_long, sp->sa_atime.tv_usec); 15838884Smacklem if (sp->sa_mtime.tv_sec != nfs_xdrneg1) 15938884Smacklem fxdr_time(&sp->sa_mtime, &vap->va_mtime); 160*52196Smckusick if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) { 16138418Smckusick vput(vp); 16238418Smckusick nfsm_reply(0); 16338418Smckusick } 164*52196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 16538418Smckusick out: 16638418Smckusick vput(vp); 167*52196Smckusick nfsm_reply(NFSX_FATTR + 2*NFSX_UNSIGNED); 16838884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 16939753Smckusick nfsm_srvfillattr; 170*52196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 171*52196Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 172*52196Smckusick txdr_hyper(&frev2, tl); 173*52196Smckusick } 17438418Smckusick nfsm_srvdone; 17538418Smckusick } 17638418Smckusick 17738418Smckusick /* 17838418Smckusick * nfs lookup rpc 17938418Smckusick */ 180*52196Smckusick nfsrv_lookup(nfsd, mrep, md, dpos, cred, nam, mrq) 181*52196Smckusick struct nfsd *nfsd; 18238418Smckusick struct mbuf *mrep, *md; 18338418Smckusick caddr_t dpos; 18438418Smckusick struct ucred *cred; 185*52196Smckusick struct mbuf *nam, **mrq; 18638418Smckusick { 18738884Smacklem register struct nfsv2_fattr *fp; 18849742Smckusick struct nameidata nd; 18938418Smckusick struct vnode *vp; 19038418Smckusick nfsv2fh_t nfh; 19138418Smckusick fhandle_t *fhp; 19239494Smckusick register caddr_t cp; 19348050Smckusick register u_long *tl; 19439494Smckusick register long t1; 19539494Smckusick caddr_t bpos; 196*52196Smckusick int error = 0, lflag = 0, rdonly, cache, duration2, cache2, len; 19739494Smckusick char *cp2; 19839753Smckusick struct mbuf *mb, *mb2, *mreq; 19938418Smckusick struct vattr va, *vap = &va; 200*52196Smckusick u_quad_t frev, frev2; 20138418Smckusick 20238418Smckusick fhp = &nfh.fh_generic; 203*52196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 204*52196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 205*52196Smckusick if (*tl) { 206*52196Smckusick lflag = fxdr_unsigned(int, *tl); 207*52196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 208*52196Smckusick duration2 = fxdr_unsigned(int, *tl); 209*52196Smckusick } 210*52196Smckusick } 21138418Smckusick nfsm_srvmtofh(fhp); 21238418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 21349742Smckusick nd.ni_cred = cred; 214*52196Smckusick nd.ni_nameiop = LOOKUP | LOCKLEAF | SAVESTART; 215*52196Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp)) 21638418Smckusick nfsm_reply(0); 217*52196Smckusick nqsrv_getl(nd.ni_startdir, NQL_READ); 218*52196Smckusick vrele(nd.ni_startdir); 21949742Smckusick vp = nd.ni_vp; 22038418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 22141398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 22238418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 22338418Smckusick vput(vp); 22438418Smckusick nfsm_reply(0); 22538418Smckusick } 226*52196Smckusick if (lflag) 227*52196Smckusick (void) nqsrv_getlease(vp, &duration2, lflag, nfsd, 228*52196Smckusick nam, &cache2, &frev2, cred); 229*52196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 23038418Smckusick vput(vp); 231*52196Smckusick nfsm_reply(NFSX_FH + NFSX_FATTR + 5*NFSX_UNSIGNED); 232*52196Smckusick if (nfsd->nd_nqlflag != NQL_NOVAL) { 233*52196Smckusick if (lflag) { 234*52196Smckusick nfsm_build(tl, u_long *, 5*NFSX_UNSIGNED); 235*52196Smckusick *tl++ = txdr_unsigned(lflag); 236*52196Smckusick *tl++ = txdr_unsigned(cache2); 237*52196Smckusick *tl++ = txdr_unsigned(duration2); 238*52196Smckusick txdr_hyper(&frev2, tl); 239*52196Smckusick } else { 240*52196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 241*52196Smckusick *tl = 0; 242*52196Smckusick } 243*52196Smckusick } 24438418Smckusick nfsm_srvfhtom(fhp); 24538884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 24639753Smckusick nfsm_srvfillattr; 24738418Smckusick nfsm_srvdone; 24838418Smckusick } 24938418Smckusick 25038418Smckusick /* 25138418Smckusick * nfs readlink service 25238418Smckusick */ 253*52196Smckusick nfsrv_readlink(nfsd, mrep, md, dpos, cred, nam, mrq) 254*52196Smckusick struct nfsd *nfsd; 25538418Smckusick struct mbuf *mrep, *md; 25638418Smckusick caddr_t dpos; 25738418Smckusick struct ucred *cred; 258*52196Smckusick struct mbuf *nam, **mrq; 25938418Smckusick { 26041899Smckusick struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN]; 26138418Smckusick register struct iovec *ivp = iv; 26238418Smckusick register struct mbuf *mp; 26348050Smckusick register u_long *tl; 26439494Smckusick register long t1; 26539494Smckusick caddr_t bpos; 266*52196Smckusick int error = 0, rdonly, cache, i, tlen, len; 26739494Smckusick char *cp2; 26839753Smckusick struct mbuf *mb, *mb2, *mp2, *mp3, *mreq; 26938418Smckusick struct vnode *vp; 27038418Smckusick nfsv2fh_t nfh; 27138418Smckusick fhandle_t *fhp; 27238418Smckusick struct uio io, *uiop = &io; 273*52196Smckusick u_quad_t frev; 27438418Smckusick 27538418Smckusick fhp = &nfh.fh_generic; 27638418Smckusick nfsm_srvmtofh(fhp); 27738418Smckusick len = 0; 27838418Smckusick i = 0; 27938418Smckusick while (len < NFS_MAXPATHLEN) { 28038418Smckusick MGET(mp, M_WAIT, MT_DATA); 28141899Smckusick MCLGET(mp, M_WAIT); 28238418Smckusick mp->m_len = NFSMSIZ(mp); 28338418Smckusick if (len == 0) 28438418Smckusick mp3 = mp2 = mp; 28541899Smckusick else { 28638418Smckusick mp2->m_next = mp; 28741899Smckusick mp2 = mp; 28841899Smckusick } 28938418Smckusick if ((len+mp->m_len) > NFS_MAXPATHLEN) { 29038418Smckusick mp->m_len = NFS_MAXPATHLEN-len; 29138418Smckusick len = NFS_MAXPATHLEN; 29238418Smckusick } else 29338418Smckusick len += mp->m_len; 29438418Smckusick ivp->iov_base = mtod(mp, caddr_t); 29538418Smckusick ivp->iov_len = mp->m_len; 29638418Smckusick i++; 29738418Smckusick ivp++; 29838418Smckusick } 29938418Smckusick uiop->uio_iov = iv; 30038418Smckusick uiop->uio_iovcnt = i; 30138418Smckusick uiop->uio_offset = 0; 30238418Smckusick uiop->uio_resid = len; 30338418Smckusick uiop->uio_rw = UIO_READ; 30438418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 30548050Smckusick uiop->uio_procp = (struct proc *)0; 306*52196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) { 30738418Smckusick m_freem(mp3); 30838418Smckusick nfsm_reply(0); 30938418Smckusick } 31038418Smckusick if (vp->v_type != VLNK) { 31138418Smckusick error = EINVAL; 31238418Smckusick goto out; 31338418Smckusick } 314*52196Smckusick nqsrv_getl(vp, NQL_READ); 31538418Smckusick error = VOP_READLINK(vp, uiop, cred); 31638418Smckusick out: 31738418Smckusick vput(vp); 31838418Smckusick if (error) 31938418Smckusick m_freem(mp3); 32038418Smckusick nfsm_reply(NFSX_UNSIGNED); 32138418Smckusick if (uiop->uio_resid > 0) { 32238418Smckusick len -= uiop->uio_resid; 32338418Smckusick tlen = nfsm_rndup(len); 32438418Smckusick nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len); 32538418Smckusick } 32648050Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 32748050Smckusick *tl = txdr_unsigned(len); 32838418Smckusick mb->m_next = mp3; 32938418Smckusick nfsm_srvdone; 33038418Smckusick } 33138418Smckusick 33238418Smckusick /* 33338418Smckusick * nfs read service 33438418Smckusick */ 335*52196Smckusick nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq) 336*52196Smckusick struct nfsd *nfsd; 33738418Smckusick struct mbuf *mrep, *md; 33838418Smckusick caddr_t dpos; 33938418Smckusick struct ucred *cred; 340*52196Smckusick struct mbuf *nam, **mrq; 34138418Smckusick { 34243350Smckusick register struct iovec *iv; 34343350Smckusick struct iovec *iv2; 34441899Smckusick register struct mbuf *m; 34538884Smacklem register struct nfsv2_fattr *fp; 34648050Smckusick register u_long *tl; 34739494Smckusick register long t1; 34839494Smckusick caddr_t bpos; 349*52196Smckusick int error = 0, rdonly, cache, i, cnt, len, left, siz, tlen; 35039494Smckusick char *cp2; 35139753Smckusick struct mbuf *mb, *mb2, *mreq; 352*52196Smckusick struct mbuf *m2; 35338418Smckusick struct vnode *vp; 35438418Smckusick nfsv2fh_t nfh; 35538418Smckusick fhandle_t *fhp; 35638418Smckusick struct uio io, *uiop = &io; 35738418Smckusick struct vattr va, *vap = &va; 35838418Smckusick off_t off; 359*52196Smckusick u_quad_t frev; 36038418Smckusick 36138418Smckusick fhp = &nfh.fh_generic; 36238418Smckusick nfsm_srvmtofh(fhp); 363*52196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 36448050Smckusick off = fxdr_unsigned(off_t, *tl); 36538418Smckusick nfsm_srvstrsiz(cnt, NFS_MAXDATA); 366*52196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 36738418Smckusick nfsm_reply(0); 368*52196Smckusick nqsrv_getl(vp, NQL_READ); 369*52196Smckusick if (error = nfsrv_access(vp, VREAD | VEXEC, cred, rdonly, nfsd->nd_procp)) { 37038418Smckusick vput(vp); 37138418Smckusick nfsm_reply(0); 37238418Smckusick } 373*52196Smckusick if (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp)) { 37438418Smckusick vput(vp); 37538418Smckusick nfsm_reply(0); 37638418Smckusick } 377*52196Smckusick if (off >= vap->va_size) 378*52196Smckusick cnt = 0; 379*52196Smckusick else if ((off + cnt) > vap->va_size) 380*52196Smckusick cnt = nfsm_rndup(vap->va_size - off); 381*52196Smckusick nfsm_reply(NFSX_FATTR+NFSX_UNSIGNED+nfsm_rndup(cnt)); 382*52196Smckusick nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 383*52196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 384*52196Smckusick len = left = cnt; 385*52196Smckusick if (cnt > 0) { 386*52196Smckusick /* 387*52196Smckusick * Generate the mbuf list with the uio_iov ref. to it. 388*52196Smckusick */ 389*52196Smckusick i = 0; 390*52196Smckusick m = m2 = mb; 391*52196Smckusick MALLOC(iv, struct iovec *, 392*52196Smckusick ((NFS_MAXDATA+MLEN-1)/MLEN) * sizeof (struct iovec), 393*52196Smckusick M_TEMP, M_WAITOK); 394*52196Smckusick iv2 = iv; 395*52196Smckusick while (left > 0) { 396*52196Smckusick siz = MIN(M_TRAILINGSPACE(m), left); 397*52196Smckusick if (siz > 0) { 398*52196Smckusick m->m_len += siz; 399*52196Smckusick iv->iov_base = bpos; 400*52196Smckusick iv->iov_len = siz; 401*52196Smckusick iv++; 402*52196Smckusick i++; 403*52196Smckusick left -= siz; 404*52196Smckusick } 405*52196Smckusick if (left > 0) { 406*52196Smckusick MGET(m, M_WAIT, MT_DATA); 407*52196Smckusick MCLGET(m, M_WAIT); 408*52196Smckusick m->m_len = 0; 409*52196Smckusick m2->m_next = m; 410*52196Smckusick m2 = m; 411*52196Smckusick bpos = mtod(m, caddr_t); 412*52196Smckusick } 413*52196Smckusick } 414*52196Smckusick uiop->uio_iov = iv2; 415*52196Smckusick uiop->uio_iovcnt = i; 416*52196Smckusick uiop->uio_offset = off; 417*52196Smckusick uiop->uio_resid = cnt; 418*52196Smckusick uiop->uio_rw = UIO_READ; 419*52196Smckusick uiop->uio_segflg = UIO_SYSSPACE; 420*52196Smckusick error = VOP_READ(vp, uiop, IO_NODELOCKED, cred); 421*52196Smckusick off = uiop->uio_offset; 422*52196Smckusick FREE((caddr_t)iv2, M_TEMP); 423*52196Smckusick if (error || (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp))) { 424*52196Smckusick m_freem(mreq); 425*52196Smckusick vput(vp); 426*52196Smckusick nfsm_reply(0); 427*52196Smckusick } 428*52196Smckusick } else 429*52196Smckusick uiop->uio_resid = 0; 43038418Smckusick vput(vp); 43139753Smckusick nfsm_srvfillattr; 43245877Smckusick len -= uiop->uio_resid; 433*52196Smckusick tlen = nfsm_rndup(len); 434*52196Smckusick if (cnt != tlen || tlen != len) 435*52196Smckusick nfsm_adj(mb, cnt-tlen, tlen-len); 43648050Smckusick *tl = txdr_unsigned(len); 43738418Smckusick nfsm_srvdone; 43838418Smckusick } 43938418Smckusick 44038418Smckusick /* 44138418Smckusick * nfs write service 44238418Smckusick */ 443*52196Smckusick nfsrv_write(nfsd, mrep, md, dpos, cred, nam, mrq) 444*52196Smckusick struct nfsd *nfsd; 445*52196Smckusick struct mbuf *mrep, *md; 44638418Smckusick caddr_t dpos; 44738418Smckusick struct ucred *cred; 448*52196Smckusick struct mbuf *nam, **mrq; 44938418Smckusick { 45038418Smckusick register struct iovec *ivp; 45138418Smckusick register struct mbuf *mp; 45238884Smacklem register struct nfsv2_fattr *fp; 45341899Smckusick struct iovec iv[NFS_MAXIOVEC]; 45438418Smckusick struct vattr va; 45538418Smckusick register struct vattr *vap = &va; 45648050Smckusick register u_long *tl; 45739494Smckusick register long t1; 45839494Smckusick caddr_t bpos; 459*52196Smckusick int error = 0, rdonly, cache, siz, len, xfer; 46039494Smckusick char *cp2; 46139753Smckusick struct mbuf *mb, *mb2, *mreq; 46238418Smckusick struct vnode *vp; 46338418Smckusick nfsv2fh_t nfh; 46438418Smckusick fhandle_t *fhp; 46538418Smckusick struct uio io, *uiop = &io; 46638418Smckusick off_t off; 467*52196Smckusick u_quad_t frev; 46838418Smckusick 46938418Smckusick fhp = &nfh.fh_generic; 47038418Smckusick nfsm_srvmtofh(fhp); 471*52196Smckusick nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); 47248050Smckusick off = fxdr_unsigned(off_t, *++tl); 47348050Smckusick tl += 2; 47448050Smckusick len = fxdr_unsigned(long, *tl); 47538418Smckusick if (len > NFS_MAXDATA || len <= 0) { 47638418Smckusick error = EBADRPC; 47738418Smckusick nfsm_reply(0); 47838418Smckusick } 47938418Smckusick if (dpos == (mtod(md, caddr_t)+md->m_len)) { 48038418Smckusick mp = md->m_next; 48138418Smckusick if (mp == NULL) { 48238418Smckusick error = EBADRPC; 48338418Smckusick nfsm_reply(0); 48438418Smckusick } 48538418Smckusick } else { 48638418Smckusick mp = md; 48738418Smckusick siz = dpos-mtod(mp, caddr_t); 48838418Smckusick mp->m_len -= siz; 48938418Smckusick NFSMADV(mp, siz); 49038418Smckusick } 491*52196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 49238418Smckusick nfsm_reply(0); 493*52196Smckusick nqsrv_getl(vp, NQL_WRITE); 494*52196Smckusick if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) { 49538418Smckusick vput(vp); 49638418Smckusick nfsm_reply(0); 49738418Smckusick } 49838418Smckusick uiop->uio_resid = 0; 49938418Smckusick uiop->uio_rw = UIO_WRITE; 50038418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 50148050Smckusick uiop->uio_procp = (struct proc *)0; 50238418Smckusick /* 50341899Smckusick * Do up to NFS_MAXIOVEC mbufs of write each iteration of the 50438418Smckusick * loop until done. 50538418Smckusick */ 50638418Smckusick while (len > 0 && uiop->uio_resid == 0) { 50738418Smckusick ivp = iv; 50838418Smckusick siz = 0; 50938418Smckusick uiop->uio_iov = ivp; 51038418Smckusick uiop->uio_iovcnt = 0; 51138418Smckusick uiop->uio_offset = off; 51241899Smckusick while (len > 0 && uiop->uio_iovcnt < NFS_MAXIOVEC && mp != NULL) { 51338418Smckusick ivp->iov_base = mtod(mp, caddr_t); 51438418Smckusick if (len < mp->m_len) 51538418Smckusick ivp->iov_len = xfer = len; 51638418Smckusick else 51738418Smckusick ivp->iov_len = xfer = mp->m_len; 51838418Smckusick #ifdef notdef 51938418Smckusick /* Not Yet .. */ 52038418Smckusick if (M_HASCL(mp) && (((u_long)ivp->iov_base) & CLOFSET) == 0) 52138418Smckusick ivp->iov_op = NULL; /* what should it be ?? */ 52238418Smckusick else 52338418Smckusick ivp->iov_op = NULL; 52438418Smckusick #endif 52538418Smckusick uiop->uio_iovcnt++; 52638418Smckusick ivp++; 52738418Smckusick len -= xfer; 52838418Smckusick siz += xfer; 52938418Smckusick mp = mp->m_next; 53038418Smckusick } 53138418Smckusick if (len > 0 && mp == NULL) { 53238418Smckusick error = EBADRPC; 53338418Smckusick vput(vp); 53438418Smckusick nfsm_reply(0); 53538418Smckusick } 53638418Smckusick uiop->uio_resid = siz; 53739586Smckusick if (error = VOP_WRITE(vp, uiop, IO_SYNC | IO_NODELOCKED, 53838418Smckusick cred)) { 53938418Smckusick vput(vp); 54038418Smckusick nfsm_reply(0); 54138418Smckusick } 54239586Smckusick off = uiop->uio_offset; 54338418Smckusick } 544*52196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 54538418Smckusick vput(vp); 54638418Smckusick nfsm_reply(NFSX_FATTR); 54738884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 54839753Smckusick nfsm_srvfillattr; 54938418Smckusick nfsm_srvdone; 55038418Smckusick } 55138418Smckusick 55238418Smckusick /* 55338418Smckusick * nfs create service 55438418Smckusick * now does a truncate to 0 length via. setattr if it already exists 55538418Smckusick */ 556*52196Smckusick nfsrv_create(nfsd, mrep, md, dpos, cred, nam, mrq) 557*52196Smckusick struct nfsd *nfsd; 558*52196Smckusick struct mbuf *mrep, *md; 55938418Smckusick caddr_t dpos; 56038418Smckusick struct ucred *cred; 561*52196Smckusick struct mbuf *nam, **mrq; 56238418Smckusick { 56338884Smacklem register struct nfsv2_fattr *fp; 56438418Smckusick struct vattr va; 56538418Smckusick register struct vattr *vap = &va; 56649742Smckusick struct nameidata nd; 56739494Smckusick register caddr_t cp; 56848050Smckusick register u_long *tl; 56939494Smckusick register long t1; 57039494Smckusick caddr_t bpos; 571*52196Smckusick int error = 0, rdev, cache, len; 57239494Smckusick char *cp2; 57339753Smckusick struct mbuf *mb, *mb2, *mreq; 57438418Smckusick struct vnode *vp; 57538418Smckusick nfsv2fh_t nfh; 57638418Smckusick fhandle_t *fhp; 577*52196Smckusick u_quad_t frev; 57838418Smckusick 57949742Smckusick nd.ni_nameiop = 0; 58038418Smckusick fhp = &nfh.fh_generic; 58138418Smckusick nfsm_srvmtofh(fhp); 58238418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 58349742Smckusick nd.ni_cred = cred; 58449742Smckusick nd.ni_nameiop = CREATE | LOCKPARENT | LOCKLEAF | SAVESTART; 585*52196Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp)) 58638418Smckusick nfsm_reply(0); 58741361Smckusick VATTR_NULL(vap); 588*52196Smckusick nfsm_dissect(tl, u_long *, NFSX_SATTR); 58938418Smckusick /* 59038418Smckusick * Iff doesn't exist, create it 59138418Smckusick * otherwise just truncate to 0 length 59238418Smckusick * should I set the mode too ?? 59338418Smckusick */ 59449742Smckusick if (nd.ni_vp == NULL) { 59548050Smckusick vap->va_type = IFTOVT(fxdr_unsigned(u_long, *tl)); 59642867Smckusick if (vap->va_type == VNON) 59742867Smckusick vap->va_type = VREG; 59848050Smckusick vap->va_mode = nfstov_mode(*tl); 59948050Smckusick rdev = fxdr_unsigned(long, *(tl+3)); 60046988Smckusick if (vap->va_type == VREG || vap->va_type == VSOCK) { 60149742Smckusick vrele(nd.ni_startdir); 602*52196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 603*52196Smckusick if (error = VOP_CREATE(&nd, vap, nfsd->nd_procp)) 60442242Smckusick nfsm_reply(0); 60549742Smckusick FREE(nd.ni_pnbuf, M_NAMEI); 60642242Smckusick } else if (vap->va_type == VCHR || vap->va_type == VBLK || 60742242Smckusick vap->va_type == VFIFO) { 60842242Smckusick if (vap->va_type == VCHR && rdev == 0xffffffff) 60942242Smckusick vap->va_type = VFIFO; 61042242Smckusick if (vap->va_type == VFIFO) { 61142242Smckusick #ifndef FIFO 61249742Smckusick VOP_ABORTOP(&nd); 61349742Smckusick vput(nd.ni_dvp); 61442242Smckusick error = ENXIO; 61549742Smckusick goto out; 61642242Smckusick #endif /* FIFO */ 617*52196Smckusick } else if (error = suser(cred, (u_short *)0)) { 61849742Smckusick VOP_ABORTOP(&nd); 61949742Smckusick vput(nd.ni_dvp); 62049742Smckusick goto out; 62142242Smckusick } else 62242242Smckusick vap->va_rdev = (dev_t)rdev; 623*52196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 624*52196Smckusick if (error = VOP_MKNOD(&nd, vap, cred, nfsd->nd_procp)) { 62549742Smckusick vrele(nd.ni_startdir); 62642242Smckusick nfsm_reply(0); 62749742Smckusick } 62849742Smckusick nd.ni_nameiop &= ~(OPMASK | LOCKPARENT | SAVESTART); 62949742Smckusick nd.ni_nameiop |= LOOKUP; 630*52196Smckusick if (error = lookup(&nd, nfsd->nd_procp)) { 63149742Smckusick free(nd.ni_pnbuf, M_NAMEI); 63242242Smckusick nfsm_reply(0); 63349742Smckusick } 63449742Smckusick FREE(nd.ni_pnbuf, M_NAMEI); 63549742Smckusick if (nd.ni_more) { 63649742Smckusick vrele(nd.ni_dvp); 63749742Smckusick vput(nd.ni_vp); 63849742Smckusick VOP_ABORTOP(&nd); 63949742Smckusick error = EINVAL; 64049742Smckusick nfsm_reply(0); 64149742Smckusick } 64242242Smckusick } else { 64349742Smckusick VOP_ABORTOP(&nd); 64449742Smckusick vput(nd.ni_dvp); 64542242Smckusick error = ENXIO; 64649742Smckusick goto out; 64742242Smckusick } 64849742Smckusick vp = nd.ni_vp; 64938418Smckusick } else { 65049742Smckusick vrele(nd.ni_startdir); 65149742Smckusick free(nd.ni_pnbuf, M_NAMEI); 65249742Smckusick vp = nd.ni_vp; 65349742Smckusick if (nd.ni_dvp == vp) 65449742Smckusick vrele(nd.ni_dvp); 65543359Smckusick else 65649742Smckusick vput(nd.ni_dvp); 65749742Smckusick VOP_ABORTOP(&nd); 65838418Smckusick vap->va_size = 0; 659*52196Smckusick nqsrv_getl(vp, NQL_WRITE); 660*52196Smckusick if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) { 66142506Smckusick vput(vp); 66238418Smckusick nfsm_reply(0); 66342506Smckusick } 66438418Smckusick } 66538418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 66641398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 66738418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 66838418Smckusick vput(vp); 66938418Smckusick nfsm_reply(0); 67038418Smckusick } 671*52196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 67238418Smckusick vput(vp); 67338418Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR); 67438418Smckusick nfsm_srvfhtom(fhp); 67538884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 67639753Smckusick nfsm_srvfillattr; 67738418Smckusick return (error); 67838418Smckusick nfsmout: 67949742Smckusick if (nd.ni_nameiop) 68051464Sbostic vrele(nd.ni_startdir); 68149742Smckusick VOP_ABORTOP(&nd); 68249742Smckusick if (nd.ni_dvp == nd.ni_vp) 68349742Smckusick vrele(nd.ni_dvp); 68443359Smckusick else 68549742Smckusick vput(nd.ni_dvp); 68649742Smckusick if (nd.ni_vp) 68749742Smckusick vput(nd.ni_vp); 68838418Smckusick return (error); 68949742Smckusick 69049742Smckusick out: 69149742Smckusick vrele(nd.ni_startdir); 69249742Smckusick free(nd.ni_pnbuf, M_NAMEI); 69349742Smckusick nfsm_reply(0); 69438418Smckusick } 69538418Smckusick 69638418Smckusick /* 69738418Smckusick * nfs remove service 69838418Smckusick */ 699*52196Smckusick nfsrv_remove(nfsd, mrep, md, dpos, cred, nam, mrq) 700*52196Smckusick struct nfsd *nfsd; 701*52196Smckusick struct mbuf *mrep, *md; 70238418Smckusick caddr_t dpos; 70338418Smckusick struct ucred *cred; 704*52196Smckusick struct mbuf *nam, **mrq; 70538418Smckusick { 70649742Smckusick struct nameidata nd; 70748050Smckusick register u_long *tl; 70839494Smckusick register long t1; 70939494Smckusick caddr_t bpos; 710*52196Smckusick int error = 0, cache, len; 71139494Smckusick char *cp2; 71239753Smckusick struct mbuf *mb, *mreq; 71338418Smckusick struct vnode *vp; 71438418Smckusick nfsv2fh_t nfh; 71538418Smckusick fhandle_t *fhp; 716*52196Smckusick u_quad_t frev; 71738418Smckusick 71838418Smckusick fhp = &nfh.fh_generic; 71938418Smckusick nfsm_srvmtofh(fhp); 72038418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 72149742Smckusick nd.ni_cred = cred; 72249742Smckusick nd.ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 723*52196Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp)) 72438418Smckusick nfsm_reply(0); 72549742Smckusick vp = nd.ni_vp; 72638418Smckusick if (vp->v_type == VDIR && 727*52196Smckusick (error = suser(cred, (u_short *)0))) 72838418Smckusick goto out; 72938418Smckusick /* 73049454Smckusick * The root of a mounted filesystem cannot be deleted. 73138418Smckusick */ 73238418Smckusick if (vp->v_flag & VROOT) { 73338418Smckusick error = EBUSY; 73438418Smckusick goto out; 73538418Smckusick } 73638418Smckusick if (vp->v_flag & VTEXT) 73745715Smckusick (void) vnode_pager_uncache(vp); 73838418Smckusick out: 73942467Smckusick if (!error) { 740*52196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 741*52196Smckusick nqsrv_getl(vp, NQL_WRITE); 742*52196Smckusick error = VOP_REMOVE(&nd, nfsd->nd_procp); 74342467Smckusick } else { 74449742Smckusick VOP_ABORTOP(&nd); 74549742Smckusick if (nd.ni_dvp == vp) 74649742Smckusick vrele(nd.ni_dvp); 74743359Smckusick else 74849742Smckusick vput(nd.ni_dvp); 74942467Smckusick vput(vp); 75042467Smckusick } 75138418Smckusick nfsm_reply(0); 75238418Smckusick nfsm_srvdone; 75338418Smckusick } 75438418Smckusick 75538418Smckusick /* 75638418Smckusick * nfs rename service 75738418Smckusick */ 758*52196Smckusick nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq) 759*52196Smckusick struct nfsd *nfsd; 760*52196Smckusick struct mbuf *mrep, *md; 76138418Smckusick caddr_t dpos; 76238418Smckusick struct ucred *cred; 763*52196Smckusick struct mbuf *nam, **mrq; 76438418Smckusick { 76548050Smckusick register u_long *tl; 76639494Smckusick register long t1; 76739494Smckusick caddr_t bpos; 768*52196Smckusick int error = 0, rdonly, cache, len, len2; 76939494Smckusick char *cp2; 77039753Smckusick struct mbuf *mb, *mreq; 77149742Smckusick struct nameidata fromnd, tond; 77238418Smckusick struct vnode *fvp, *tvp, *tdvp; 77338418Smckusick nfsv2fh_t fnfh, tnfh; 77438418Smckusick fhandle_t *ffhp, *tfhp; 775*52196Smckusick u_quad_t frev; 776*52196Smckusick uid_t saved_uid; 77738418Smckusick 77838418Smckusick ffhp = &fnfh.fh_generic; 77938418Smckusick tfhp = &tnfh.fh_generic; 78049742Smckusick fromnd.ni_nameiop = 0; 78149742Smckusick tond.ni_nameiop = 0; 78238418Smckusick nfsm_srvmtofh(ffhp); 78338418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 78438418Smckusick /* 785*52196Smckusick * Remember our original uid so that we can reset cr_uid before 786*52196Smckusick * the second nfs_namei() call, in case it is remapped. 78738418Smckusick */ 788*52196Smckusick saved_uid = cred->cr_uid; 78949742Smckusick fromnd.ni_cred = cred; 79049742Smckusick fromnd.ni_nameiop = DELETE | WANTPARENT | SAVESTART; 791*52196Smckusick if (error = nfs_namei(&fromnd, ffhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp)) 79238418Smckusick nfsm_reply(0); 79349742Smckusick fvp = fromnd.ni_vp; 79438418Smckusick nfsm_srvmtofh(tfhp); 79541899Smckusick nfsm_strsiz(len2, NFS_MAXNAMLEN); 796*52196Smckusick cred->cr_uid = saved_uid; 79739343Smckusick tond.ni_cred = cred; 79846513Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE 79949742Smckusick | SAVESTART; 800*52196Smckusick if (error = nfs_namei(&tond, tfhp, len2, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp)) { 80149742Smckusick VOP_ABORTOP(&fromnd); 80249742Smckusick vrele(fromnd.ni_dvp); 80342467Smckusick vrele(fvp); 80442467Smckusick goto out1; 80542467Smckusick } 80638425Smckusick tdvp = tond.ni_dvp; 80738425Smckusick tvp = tond.ni_vp; 80838418Smckusick if (tvp != NULL) { 80938418Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 81038418Smckusick error = EISDIR; 81138418Smckusick goto out; 81238418Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 81338418Smckusick error = ENOTDIR; 81438418Smckusick goto out; 81538418Smckusick } 816*52196Smckusick if (tvp->v_type == VDIR && tvp->v_mountedhere) { 817*52196Smckusick error = EXDEV; 818*52196Smckusick goto out; 819*52196Smckusick } 82038418Smckusick } 821*52196Smckusick if (fvp->v_type == VDIR && fvp->v_mountedhere) { 822*52196Smckusick error = EBUSY; 823*52196Smckusick goto out; 824*52196Smckusick } 82538418Smckusick if (fvp->v_mount != tdvp->v_mount) { 82638418Smckusick error = EXDEV; 82738418Smckusick goto out; 82838418Smckusick } 82949742Smckusick if (fvp == tdvp) 83038418Smckusick error = EINVAL; 83149742Smckusick /* 83249742Smckusick * If source is the same as the destination (that is the 83349742Smckusick * same vnode with the same name in the same directory), 83449742Smckusick * then there is nothing to do. 83549742Smckusick */ 83649742Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 83749742Smckusick fromnd.ni_namelen == tond.ni_namelen && 83849742Smckusick !bcmp(fromnd.ni_ptr, tond.ni_ptr, fromnd.ni_namelen)) 83949742Smckusick error = -1; 84038418Smckusick out: 84142467Smckusick if (!error) { 842*52196Smckusick nqsrv_getl(fromnd.ni_dvp, NQL_WRITE); 843*52196Smckusick nqsrv_getl(tdvp, NQL_WRITE); 844*52196Smckusick if (tvp) 845*52196Smckusick nqsrv_getl(tvp, NQL_WRITE); 846*52196Smckusick error = VOP_RENAME(&fromnd, &tond, nfsd->nd_procp); 84742467Smckusick } else { 84842467Smckusick VOP_ABORTOP(&tond); 84943359Smckusick if (tdvp == tvp) 85043359Smckusick vrele(tdvp); 85143359Smckusick else 85243359Smckusick vput(tdvp); 85342467Smckusick if (tvp) 85442467Smckusick vput(tvp); 85549742Smckusick VOP_ABORTOP(&fromnd); 85649742Smckusick vrele(fromnd.ni_dvp); 85742467Smckusick vrele(fvp); 85838418Smckusick } 85946513Smckusick vrele(tond.ni_startdir); 86049742Smckusick FREE(tond.ni_pnbuf, M_NAMEI); 86138418Smckusick out1: 86249742Smckusick vrele(fromnd.ni_startdir); 86349742Smckusick FREE(fromnd.ni_pnbuf, M_NAMEI); 86438418Smckusick nfsm_reply(0); 86538418Smckusick return (error); 86649742Smckusick 86738418Smckusick nfsmout: 86849742Smckusick if (tond.ni_nameiop) { 86949742Smckusick vrele(tond.ni_startdir); 87049742Smckusick FREE(tond.ni_pnbuf, M_NAMEI); 87149742Smckusick } 87249742Smckusick if (fromnd.ni_nameiop) { 87349742Smckusick vrele(fromnd.ni_startdir); 87449742Smckusick FREE(fromnd.ni_pnbuf, M_NAMEI); 87549742Smckusick VOP_ABORTOP(&fromnd); 87649742Smckusick vrele(fromnd.ni_dvp); 87749742Smckusick vrele(fvp); 87849742Smckusick } 87938418Smckusick return (error); 88038418Smckusick } 88138418Smckusick 88238418Smckusick /* 88338418Smckusick * nfs link service 88438418Smckusick */ 885*52196Smckusick nfsrv_link(nfsd, mrep, md, dpos, cred, nam, mrq) 886*52196Smckusick struct nfsd *nfsd; 887*52196Smckusick struct mbuf *mrep, *md; 88838418Smckusick caddr_t dpos; 88938418Smckusick struct ucred *cred; 890*52196Smckusick struct mbuf *nam, **mrq; 89138418Smckusick { 89249742Smckusick struct nameidata nd; 89348050Smckusick register u_long *tl; 89439494Smckusick register long t1; 89539494Smckusick caddr_t bpos; 896*52196Smckusick int error = 0, rdonly, cache, len; 89739494Smckusick char *cp2; 89839753Smckusick struct mbuf *mb, *mreq; 89938418Smckusick struct vnode *vp, *xp; 90038418Smckusick nfsv2fh_t nfh, dnfh; 90138418Smckusick fhandle_t *fhp, *dfhp; 902*52196Smckusick u_quad_t frev; 90338418Smckusick 90438418Smckusick fhp = &nfh.fh_generic; 90538418Smckusick dfhp = &dnfh.fh_generic; 90638418Smckusick nfsm_srvmtofh(fhp); 90738418Smckusick nfsm_srvmtofh(dfhp); 90838418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 909*52196Smckusick if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 91038418Smckusick nfsm_reply(0); 911*52196Smckusick if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0))) 91238418Smckusick goto out1; 91349742Smckusick nd.ni_cred = cred; 91449742Smckusick nd.ni_nameiop = CREATE | LOCKPARENT; 915*52196Smckusick if (error = nfs_namei(&nd, dfhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp)) 91638418Smckusick goto out1; 91749742Smckusick xp = nd.ni_vp; 91838418Smckusick if (xp != NULL) { 91938418Smckusick error = EEXIST; 92038418Smckusick goto out; 92138418Smckusick } 92249742Smckusick xp = nd.ni_dvp; 92338418Smckusick if (vp->v_mount != xp->v_mount) 92438418Smckusick error = EXDEV; 92538418Smckusick out: 92642467Smckusick if (!error) { 927*52196Smckusick nqsrv_getl(vp, NQL_WRITE); 928*52196Smckusick nqsrv_getl(xp, NQL_WRITE); 929*52196Smckusick error = VOP_LINK(vp, &nd, nfsd->nd_procp); 93042467Smckusick } else { 93149742Smckusick VOP_ABORTOP(&nd); 93249742Smckusick if (nd.ni_dvp == nd.ni_vp) 93349742Smckusick vrele(nd.ni_dvp); 93443359Smckusick else 93549742Smckusick vput(nd.ni_dvp); 93649742Smckusick if (nd.ni_vp) 93749742Smckusick vrele(nd.ni_vp); 93842467Smckusick } 93938418Smckusick out1: 94038418Smckusick vrele(vp); 94138418Smckusick nfsm_reply(0); 94238418Smckusick nfsm_srvdone; 94338418Smckusick } 94438418Smckusick 94538418Smckusick /* 94638418Smckusick * nfs symbolic link service 94738418Smckusick */ 948*52196Smckusick nfsrv_symlink(nfsd, mrep, md, dpos, cred, nam, mrq) 949*52196Smckusick struct nfsd *nfsd; 950*52196Smckusick struct mbuf *mrep, *md; 95138418Smckusick caddr_t dpos; 95238418Smckusick struct ucred *cred; 953*52196Smckusick struct mbuf *nam, **mrq; 95438418Smckusick { 95538418Smckusick struct vattr va; 95649742Smckusick struct nameidata nd; 95738418Smckusick register struct vattr *vap = &va; 95848050Smckusick register u_long *tl; 95939494Smckusick register long t1; 96045285Smckusick struct nfsv2_sattr *sp; 96139494Smckusick caddr_t bpos; 96241899Smckusick struct uio io; 96341899Smckusick struct iovec iv; 964*52196Smckusick int error = 0, rdonly, cache, len, len2; 96541899Smckusick char *pathcp, *cp2; 96639753Smckusick struct mbuf *mb, *mreq; 96738418Smckusick nfsv2fh_t nfh; 96838418Smckusick fhandle_t *fhp; 969*52196Smckusick u_quad_t frev; 97038418Smckusick 97141899Smckusick pathcp = (char *)0; 97238418Smckusick fhp = &nfh.fh_generic; 97338418Smckusick nfsm_srvmtofh(fhp); 97438418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 97549742Smckusick nd.ni_cred = cred; 97649742Smckusick nd.ni_nameiop = CREATE | LOCKPARENT; 977*52196Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp)) 97842467Smckusick goto out; 97941899Smckusick nfsm_strsiz(len2, NFS_MAXPATHLEN); 98041899Smckusick MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK); 98141899Smckusick iv.iov_base = pathcp; 98241899Smckusick iv.iov_len = len2; 98341899Smckusick io.uio_resid = len2; 98441899Smckusick io.uio_offset = 0; 98541899Smckusick io.uio_iov = &iv; 98641899Smckusick io.uio_iovcnt = 1; 98741899Smckusick io.uio_segflg = UIO_SYSSPACE; 98841899Smckusick io.uio_rw = UIO_READ; 98948050Smckusick io.uio_procp = (struct proc *)0; 99041899Smckusick nfsm_mtouio(&io, len2); 991*52196Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR); 99241899Smckusick *(pathcp + len2) = '\0'; 99349742Smckusick if (nd.ni_vp) { 99449742Smckusick VOP_ABORTOP(&nd); 99549742Smckusick if (nd.ni_dvp == nd.ni_vp) 99649742Smckusick vrele(nd.ni_dvp); 99743359Smckusick else 99849742Smckusick vput(nd.ni_dvp); 99949742Smckusick vrele(nd.ni_vp); 100038418Smckusick error = EEXIST; 100138418Smckusick goto out; 100238418Smckusick } 100341361Smckusick VATTR_NULL(vap); 100445285Smckusick vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode); 1005*52196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 1006*52196Smckusick error = VOP_SYMLINK(&nd, vap, pathcp, nfsd->nd_procp); 100738418Smckusick out: 100841899Smckusick if (pathcp) 100941899Smckusick FREE(pathcp, M_TEMP); 101038418Smckusick nfsm_reply(0); 101138418Smckusick return (error); 101238418Smckusick nfsmout: 101349742Smckusick VOP_ABORTOP(&nd); 101449742Smckusick if (nd.ni_dvp == nd.ni_vp) 101549742Smckusick vrele(nd.ni_dvp); 101643359Smckusick else 101749742Smckusick vput(nd.ni_dvp); 101849742Smckusick if (nd.ni_vp) 101949742Smckusick vrele(nd.ni_vp); 102041899Smckusick if (pathcp) 102141899Smckusick FREE(pathcp, M_TEMP); 102238418Smckusick return (error); 102338418Smckusick } 102438418Smckusick 102538418Smckusick /* 102638418Smckusick * nfs mkdir service 102738418Smckusick */ 1028*52196Smckusick nfsrv_mkdir(nfsd, mrep, md, dpos, cred, nam, mrq) 1029*52196Smckusick struct nfsd *nfsd; 1030*52196Smckusick struct mbuf *mrep, *md; 103138418Smckusick caddr_t dpos; 103238418Smckusick struct ucred *cred; 1033*52196Smckusick struct mbuf *nam, **mrq; 103438418Smckusick { 103538418Smckusick struct vattr va; 103638418Smckusick register struct vattr *vap = &va; 103738884Smacklem register struct nfsv2_fattr *fp; 103849742Smckusick struct nameidata nd; 103939494Smckusick register caddr_t cp; 104048050Smckusick register u_long *tl; 104139494Smckusick register long t1; 104239494Smckusick caddr_t bpos; 1043*52196Smckusick int error = 0, rdonly, cache, len; 104439494Smckusick char *cp2; 104539753Smckusick struct mbuf *mb, *mb2, *mreq; 104638418Smckusick struct vnode *vp; 104738418Smckusick nfsv2fh_t nfh; 104838418Smckusick fhandle_t *fhp; 1049*52196Smckusick u_quad_t frev; 105038418Smckusick 105138418Smckusick fhp = &nfh.fh_generic; 105238418Smckusick nfsm_srvmtofh(fhp); 105338418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 105449742Smckusick nd.ni_cred = cred; 105549742Smckusick nd.ni_nameiop = CREATE | LOCKPARENT; 1056*52196Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp)) 105738418Smckusick nfsm_reply(0); 1058*52196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 105941361Smckusick VATTR_NULL(vap); 106038418Smckusick vap->va_type = VDIR; 106148050Smckusick vap->va_mode = nfstov_mode(*tl++); 106249742Smckusick vp = nd.ni_vp; 106338418Smckusick if (vp != NULL) { 106449742Smckusick VOP_ABORTOP(&nd); 106549742Smckusick if (nd.ni_dvp == vp) 106649742Smckusick vrele(nd.ni_dvp); 106743359Smckusick else 106849742Smckusick vput(nd.ni_dvp); 106942467Smckusick vrele(vp); 107038418Smckusick error = EEXIST; 107138418Smckusick nfsm_reply(0); 107238418Smckusick } 1073*52196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 1074*52196Smckusick if (error = VOP_MKDIR(&nd, vap, nfsd->nd_procp)) 107538418Smckusick nfsm_reply(0); 107649742Smckusick vp = nd.ni_vp; 107738418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 107841398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 107938418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 108038418Smckusick vput(vp); 108138418Smckusick nfsm_reply(0); 108238418Smckusick } 1083*52196Smckusick error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 108438418Smckusick vput(vp); 108538418Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR); 108638418Smckusick nfsm_srvfhtom(fhp); 108738884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 108839753Smckusick nfsm_srvfillattr; 108938418Smckusick return (error); 109038418Smckusick nfsmout: 109149742Smckusick VOP_ABORTOP(&nd); 109249742Smckusick if (nd.ni_dvp == nd.ni_vp) 109349742Smckusick vrele(nd.ni_dvp); 109443359Smckusick else 109549742Smckusick vput(nd.ni_dvp); 109649742Smckusick if (nd.ni_vp) 109749742Smckusick vrele(nd.ni_vp); 109838418Smckusick return (error); 109938418Smckusick } 110038418Smckusick 110138418Smckusick /* 110238418Smckusick * nfs rmdir service 110338418Smckusick */ 1104*52196Smckusick nfsrv_rmdir(nfsd, mrep, md, dpos, cred, nam, mrq) 1105*52196Smckusick struct nfsd *nfsd; 1106*52196Smckusick struct mbuf *mrep, *md; 110738418Smckusick caddr_t dpos; 110838418Smckusick struct ucred *cred; 1109*52196Smckusick struct mbuf *nam, **mrq; 111038418Smckusick { 111148050Smckusick register u_long *tl; 111239494Smckusick register long t1; 111339494Smckusick caddr_t bpos; 1114*52196Smckusick int error = 0, rdonly, cache, len; 111539494Smckusick char *cp2; 111639753Smckusick struct mbuf *mb, *mreq; 111738418Smckusick struct vnode *vp; 111838418Smckusick nfsv2fh_t nfh; 111938418Smckusick fhandle_t *fhp; 112049742Smckusick struct nameidata nd; 1121*52196Smckusick u_quad_t frev; 112238418Smckusick 112338418Smckusick fhp = &nfh.fh_generic; 112438418Smckusick nfsm_srvmtofh(fhp); 112538418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 112649742Smckusick nd.ni_cred = cred; 112749742Smckusick nd.ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 1128*52196Smckusick if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp)) 112938418Smckusick nfsm_reply(0); 113049742Smckusick vp = nd.ni_vp; 113138418Smckusick if (vp->v_type != VDIR) { 113238418Smckusick error = ENOTDIR; 113338418Smckusick goto out; 113438418Smckusick } 113538418Smckusick /* 113638418Smckusick * No rmdir "." please. 113738418Smckusick */ 113849742Smckusick if (nd.ni_dvp == vp) { 113938418Smckusick error = EINVAL; 114038418Smckusick goto out; 114138418Smckusick } 114238418Smckusick /* 114349454Smckusick * The root of a mounted filesystem cannot be deleted. 114438418Smckusick */ 114538418Smckusick if (vp->v_flag & VROOT) 114638418Smckusick error = EBUSY; 114738418Smckusick out: 114842467Smckusick if (!error) { 1149*52196Smckusick nqsrv_getl(nd.ni_dvp, NQL_WRITE); 1150*52196Smckusick nqsrv_getl(vp, NQL_WRITE); 1151*52196Smckusick error = VOP_RMDIR(&nd, nfsd->nd_procp); 115242467Smckusick } else { 115349742Smckusick VOP_ABORTOP(&nd); 115449742Smckusick if (nd.ni_dvp == nd.ni_vp) 115549742Smckusick vrele(nd.ni_dvp); 115643359Smckusick else 115749742Smckusick vput(nd.ni_dvp); 115842467Smckusick vput(vp); 115942467Smckusick } 116038418Smckusick nfsm_reply(0); 116138418Smckusick nfsm_srvdone; 116238418Smckusick } 116338418Smckusick 116438418Smckusick /* 116538418Smckusick * nfs readdir service 116638418Smckusick * - mallocs what it thinks is enough to read 116748050Smckusick * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR 116838418Smckusick * - calls VOP_READDIR() 116940115Smckusick * - loops around building the reply 117038425Smckusick * if the output generated exceeds count break out of loop 117138425Smckusick * The nfsm_clget macro is used here so that the reply will be packed 117238425Smckusick * tightly in mbuf clusters. 117338418Smckusick * - it only knows that it has encountered eof when the VOP_READDIR() 117438425Smckusick * reads nothing 117538418Smckusick * - as such one readdir rpc will return eof false although you are there 117638425Smckusick * and then the next will return eof 117738418Smckusick * - it trims out records with d_ino == 0 117838425Smckusick * this doesn't matter for Unix clients, but they might confuse clients 117938425Smckusick * for other os'. 118038418Smckusick * NB: It is tempting to set eof to true if the VOP_READDIR() reads less 118138425Smckusick * than requested, but this may not apply to all filesystems. For 118238425Smckusick * example, client NFS does not { although it is never remote mounted 118338425Smckusick * anyhow } 1184*52196Smckusick * The alternate call nqnfsrv_readdirlook() does lookups as well. 118538418Smckusick * PS: The NFS protocol spec. does not clarify what the "count" byte 118638425Smckusick * argument is a count of.. just name strings and file id's or the 118738425Smckusick * entire reply rpc or ... 118838425Smckusick * I tried just file name and id sizes and it confused the Sun client, 118938425Smckusick * so I am using the full rpc size now. The "paranoia.." comment refers 119038425Smckusick * to including the status longwords that are not a part of the dir. 119138425Smckusick * "entry" structures, but are in the rpc. 119238418Smckusick */ 1193*52196Smckusick struct flrep { 1194*52196Smckusick u_long fl_cachable; 1195*52196Smckusick u_long fl_duration; 1196*52196Smckusick u_quad_t fl_frev; 1197*52196Smckusick nfsv2fh_t fl_nfh; 1198*52196Smckusick struct nfsv2_fattr fl_fattr; 1199*52196Smckusick }; 1200*52196Smckusick 1201*52196Smckusick nfsrv_readdir(nfsd, mrep, md, dpos, cred, nam, mrq) 1202*52196Smckusick struct nfsd *nfsd; 120338418Smckusick struct mbuf *mrep, *md; 120438418Smckusick caddr_t dpos; 120538418Smckusick struct ucred *cred; 1206*52196Smckusick struct mbuf *nam, **mrq; 120738418Smckusick { 120838418Smckusick register char *bp, *be; 120938418Smckusick register struct mbuf *mp; 121038418Smckusick register struct direct *dp; 121139494Smckusick register caddr_t cp; 121248050Smckusick register u_long *tl; 121339494Smckusick register long t1; 121439494Smckusick caddr_t bpos; 1215*52196Smckusick struct mbuf *mb, *mb2, *mreq, *mp2; 1216*52196Smckusick char *cpos, *cend, *cp2, *rbuf; 121738418Smckusick struct vnode *vp; 121838418Smckusick nfsv2fh_t nfh; 121938418Smckusick fhandle_t *fhp; 122038418Smckusick struct uio io; 122138418Smckusick struct iovec iv; 1222*52196Smckusick struct vattr va; 1223*52196Smckusick int len, nlen, rem, xfer, tsiz, i, error = 0; 1224*52196Smckusick int siz, cnt, fullsiz, eofflag, rdonly, cache; 1225*52196Smckusick u_quad_t frev; 122638418Smckusick u_long on; 122738418Smckusick off_t off, toff; 122838418Smckusick 122938418Smckusick fhp = &nfh.fh_generic; 123038418Smckusick nfsm_srvmtofh(fhp); 1231*52196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 123248050Smckusick toff = fxdr_unsigned(off_t, *tl++); 123348050Smckusick off = (toff & ~(NFS_DIRBLKSIZ-1)); 123448050Smckusick on = (toff & (NFS_DIRBLKSIZ-1)); 123548050Smckusick cnt = fxdr_unsigned(int, *tl); 123648050Smckusick siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); 123741899Smckusick if (cnt > NFS_MAXREADDIR) 123841899Smckusick siz = NFS_MAXREADDIR; 123938418Smckusick fullsiz = siz; 1240*52196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 124138418Smckusick nfsm_reply(0); 1242*52196Smckusick nqsrv_getl(vp, NQL_READ); 1243*52196Smckusick if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { 124438418Smckusick vput(vp); 124538418Smckusick nfsm_reply(0); 124638418Smckusick } 124738418Smckusick VOP_UNLOCK(vp); 124838418Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 124938418Smckusick again: 125038418Smckusick iv.iov_base = rbuf; 125138418Smckusick iv.iov_len = fullsiz; 125238418Smckusick io.uio_iov = &iv; 125338418Smckusick io.uio_iovcnt = 1; 125438418Smckusick io.uio_offset = off; 125538418Smckusick io.uio_resid = fullsiz; 125638418Smckusick io.uio_segflg = UIO_SYSSPACE; 125738418Smckusick io.uio_rw = UIO_READ; 125848050Smckusick io.uio_procp = (struct proc *)0; 125940296Smckusick error = VOP_READDIR(vp, &io, cred, &eofflag); 126039586Smckusick off = io.uio_offset; 126138418Smckusick if (error) { 126238418Smckusick vrele(vp); 126338418Smckusick free((caddr_t)rbuf, M_TEMP); 126438418Smckusick nfsm_reply(0); 126538418Smckusick } 126638418Smckusick if (io.uio_resid) { 126738418Smckusick siz -= io.uio_resid; 126838418Smckusick 126938418Smckusick /* 127038418Smckusick * If nothing read, return eof 127138418Smckusick * rpc reply 127238418Smckusick */ 127338418Smckusick if (siz == 0) { 127438418Smckusick vrele(vp); 127538418Smckusick nfsm_reply(2*NFSX_UNSIGNED); 127648050Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 127748050Smckusick *tl++ = nfs_false; 127848050Smckusick *tl = nfs_true; 127938418Smckusick FREE((caddr_t)rbuf, M_TEMP); 128038418Smckusick return (0); 128138418Smckusick } 128238418Smckusick } 128340115Smckusick 128438418Smckusick /* 128538418Smckusick * Check for degenerate cases of nothing useful read. 128640115Smckusick * If so go try again 128738418Smckusick */ 128840115Smckusick cpos = rbuf + on; 128940115Smckusick cend = rbuf + siz; 129040115Smckusick dp = (struct direct *)cpos; 129140115Smckusick while (cpos < cend && dp->d_ino == 0) { 129240115Smckusick cpos += dp->d_reclen; 129340115Smckusick dp = (struct direct *)cpos; 129440115Smckusick } 129540115Smckusick if (cpos >= cend) { 129638418Smckusick toff = off; 129738418Smckusick siz = fullsiz; 129838418Smckusick on = 0; 129938418Smckusick goto again; 130038418Smckusick } 130140115Smckusick 130240115Smckusick cpos = rbuf + on; 130340115Smckusick cend = rbuf + siz; 130440115Smckusick dp = (struct direct *)cpos; 1305*52196Smckusick len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 1306*52196Smckusick nfsm_reply(siz); 1307*52196Smckusick mp = mp2 = mb; 1308*52196Smckusick bp = bpos; 1309*52196Smckusick be = bp + M_TRAILINGSPACE(mp); 1310*52196Smckusick 1311*52196Smckusick /* Loop through the records and build reply */ 1312*52196Smckusick while (cpos < cend) { 1313*52196Smckusick if (dp->d_ino != 0) { 1314*52196Smckusick nlen = dp->d_namlen; 1315*52196Smckusick rem = nfsm_rndup(nlen)-nlen; 1316*52196Smckusick len += (4*NFSX_UNSIGNED + nlen + rem); 1317*52196Smckusick if (len > cnt) { 1318*52196Smckusick eofflag = 0; 1319*52196Smckusick break; 1320*52196Smckusick } 1321*52196Smckusick 1322*52196Smckusick /* Build the directory record xdr from the direct entry */ 1323*52196Smckusick nfsm_clget; 1324*52196Smckusick *tl = nfs_true; 1325*52196Smckusick bp += NFSX_UNSIGNED; 1326*52196Smckusick nfsm_clget; 1327*52196Smckusick *tl = txdr_unsigned(dp->d_ino); 1328*52196Smckusick bp += NFSX_UNSIGNED; 1329*52196Smckusick nfsm_clget; 1330*52196Smckusick *tl = txdr_unsigned(nlen); 1331*52196Smckusick bp += NFSX_UNSIGNED; 1332*52196Smckusick 1333*52196Smckusick /* And loop around copying the name */ 1334*52196Smckusick xfer = nlen; 1335*52196Smckusick cp = dp->d_name; 1336*52196Smckusick while (xfer > 0) { 1337*52196Smckusick nfsm_clget; 1338*52196Smckusick if ((bp+xfer) > be) 1339*52196Smckusick tsiz = be-bp; 1340*52196Smckusick else 1341*52196Smckusick tsiz = xfer; 1342*52196Smckusick bcopy(cp, bp, tsiz); 1343*52196Smckusick bp += tsiz; 1344*52196Smckusick xfer -= tsiz; 1345*52196Smckusick if (xfer > 0) 1346*52196Smckusick cp += tsiz; 1347*52196Smckusick } 1348*52196Smckusick /* And null pad to a long boundary */ 1349*52196Smckusick for (i = 0; i < rem; i++) 1350*52196Smckusick *bp++ = '\0'; 1351*52196Smckusick nfsm_clget; 1352*52196Smckusick 1353*52196Smckusick /* Finish off the record */ 1354*52196Smckusick toff += dp->d_reclen; 1355*52196Smckusick *tl = txdr_unsigned(toff); 1356*52196Smckusick bp += NFSX_UNSIGNED; 1357*52196Smckusick } else 1358*52196Smckusick toff += dp->d_reclen; 1359*52196Smckusick cpos += dp->d_reclen; 1360*52196Smckusick dp = (struct direct *)cpos; 1361*52196Smckusick } 136238418Smckusick vrele(vp); 1363*52196Smckusick nfsm_clget; 1364*52196Smckusick *tl = nfs_false; 1365*52196Smckusick bp += NFSX_UNSIGNED; 1366*52196Smckusick nfsm_clget; 1367*52196Smckusick if (eofflag) 1368*52196Smckusick *tl = nfs_true; 1369*52196Smckusick else 1370*52196Smckusick *tl = nfs_false; 1371*52196Smckusick bp += NFSX_UNSIGNED; 1372*52196Smckusick if (mp != mb) { 1373*52196Smckusick if (bp < be) 1374*52196Smckusick mp->m_len = bp - mtod(mp, caddr_t); 1375*52196Smckusick } else 1376*52196Smckusick mp->m_len += bp - bpos; 1377*52196Smckusick FREE(rbuf, M_TEMP); 1378*52196Smckusick nfsm_srvdone; 1379*52196Smckusick } 1380*52196Smckusick 1381*52196Smckusick nqnfsrv_readdirlook(nfsd, mrep, md, dpos, cred, nam, mrq) 1382*52196Smckusick struct nfsd *nfsd; 1383*52196Smckusick struct mbuf *mrep, *md; 1384*52196Smckusick caddr_t dpos; 1385*52196Smckusick struct ucred *cred; 1386*52196Smckusick struct mbuf *nam, **mrq; 1387*52196Smckusick { 1388*52196Smckusick register char *bp, *be; 1389*52196Smckusick register struct mbuf *mp; 1390*52196Smckusick register struct direct *dp; 1391*52196Smckusick register caddr_t cp; 1392*52196Smckusick register u_long *tl; 1393*52196Smckusick register long t1; 1394*52196Smckusick caddr_t bpos; 1395*52196Smckusick struct mbuf *mb, *mb2, *mreq, *mp2; 1396*52196Smckusick char *cpos, *cend, *cp2, *rbuf; 1397*52196Smckusick struct vnode *vp, *nvp; 1398*52196Smckusick struct flrep fl; 1399*52196Smckusick struct ufid *ufp = (struct ufid *)&fl.fl_nfh.fh_generic.fh_fid; 1400*52196Smckusick struct mount *mntp; 1401*52196Smckusick nfsv2fh_t nfh; 1402*52196Smckusick fhandle_t *fhp; 1403*52196Smckusick struct uio io; 1404*52196Smckusick struct iovec iv; 1405*52196Smckusick struct vattr va, *vap = &va; 1406*52196Smckusick struct nfsv2_fattr *fp; 1407*52196Smckusick int len, nlen, rem, xfer, tsiz, i, error = 0, duration2, cache2; 1408*52196Smckusick int siz, cnt, fullsiz, eofflag, rdonly, cache; 1409*52196Smckusick u_quad_t frev, frev2; 1410*52196Smckusick u_long on; 1411*52196Smckusick off_t off, toff; 1412*52196Smckusick 1413*52196Smckusick fhp = &nfh.fh_generic; 1414*52196Smckusick nfsm_srvmtofh(fhp); 1415*52196Smckusick nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED); 1416*52196Smckusick toff = fxdr_unsigned(off_t, *tl++); 1417*52196Smckusick off = (toff & ~(NFS_DIRBLKSIZ-1)); 1418*52196Smckusick on = (toff & (NFS_DIRBLKSIZ-1)); 1419*52196Smckusick cnt = fxdr_unsigned(int, *tl++); 1420*52196Smckusick duration2 = fxdr_unsigned(int, *tl); 1421*52196Smckusick siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); 1422*52196Smckusick if (cnt > NFS_MAXREADDIR) 1423*52196Smckusick siz = NFS_MAXREADDIR; 1424*52196Smckusick fullsiz = siz; 1425*52196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 1426*52196Smckusick nfsm_reply(0); 1427*52196Smckusick nqsrv_getl(vp, NQL_READ); 1428*52196Smckusick if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { 1429*52196Smckusick vput(vp); 1430*52196Smckusick nfsm_reply(0); 1431*52196Smckusick } 1432*52196Smckusick VOP_UNLOCK(vp); 1433*52196Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 1434*52196Smckusick again: 1435*52196Smckusick iv.iov_base = rbuf; 1436*52196Smckusick iv.iov_len = fullsiz; 1437*52196Smckusick io.uio_iov = &iv; 1438*52196Smckusick io.uio_iovcnt = 1; 1439*52196Smckusick io.uio_offset = off; 1440*52196Smckusick io.uio_resid = fullsiz; 1441*52196Smckusick io.uio_segflg = UIO_SYSSPACE; 1442*52196Smckusick io.uio_rw = UIO_READ; 1443*52196Smckusick io.uio_procp = (struct proc *)0; 1444*52196Smckusick error = VOP_READDIR(vp, &io, cred, &eofflag); 1445*52196Smckusick off = io.uio_offset; 1446*52196Smckusick if (error) { 1447*52196Smckusick vrele(vp); 1448*52196Smckusick free((caddr_t)rbuf, M_TEMP); 1449*52196Smckusick nfsm_reply(0); 1450*52196Smckusick } 1451*52196Smckusick if (io.uio_resid) { 1452*52196Smckusick siz -= io.uio_resid; 1453*52196Smckusick 1454*52196Smckusick /* 1455*52196Smckusick * If nothing read, return eof 1456*52196Smckusick * rpc reply 1457*52196Smckusick */ 1458*52196Smckusick if (siz == 0) { 1459*52196Smckusick vrele(vp); 1460*52196Smckusick nfsm_reply(2*NFSX_UNSIGNED); 1461*52196Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 1462*52196Smckusick *tl++ = nfs_false; 1463*52196Smckusick *tl = nfs_true; 1464*52196Smckusick FREE((caddr_t)rbuf, M_TEMP); 1465*52196Smckusick return (0); 1466*52196Smckusick } 1467*52196Smckusick } 1468*52196Smckusick 1469*52196Smckusick /* 1470*52196Smckusick * Check for degenerate cases of nothing useful read. 1471*52196Smckusick * If so go try again 1472*52196Smckusick */ 1473*52196Smckusick cpos = rbuf + on; 1474*52196Smckusick cend = rbuf + siz; 1475*52196Smckusick dp = (struct direct *)cpos; 1476*52196Smckusick while (cpos < cend && dp->d_ino == 0) { 1477*52196Smckusick cpos += dp->d_reclen; 1478*52196Smckusick dp = (struct direct *)cpos; 1479*52196Smckusick } 1480*52196Smckusick if (cpos >= cend) { 1481*52196Smckusick toff = off; 1482*52196Smckusick siz = fullsiz; 1483*52196Smckusick on = 0; 1484*52196Smckusick goto again; 1485*52196Smckusick } 1486*52196Smckusick 1487*52196Smckusick cpos = rbuf + on; 1488*52196Smckusick cend = rbuf + siz; 1489*52196Smckusick dp = (struct direct *)cpos; 149038425Smckusick len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 149138418Smckusick nfsm_reply(siz); 1492*52196Smckusick mp = mp2 = mb; 1493*52196Smckusick bp = bpos; 1494*52196Smckusick be = bp + M_TRAILINGSPACE(mp); 1495*52196Smckusick mntp = vp->v_mount; 149638418Smckusick 149738418Smckusick /* Loop through the records and build reply */ 149838418Smckusick while (cpos < cend) { 149938418Smckusick if (dp->d_ino != 0) { 150038418Smckusick nlen = dp->d_namlen; 150138418Smckusick rem = nfsm_rndup(nlen)-nlen; 150238425Smckusick 150338418Smckusick /* 1504*52196Smckusick * For readdir_and_lookup get the vnode using 1505*52196Smckusick * the file number. 150638418Smckusick */ 1507*52196Smckusick bzero((caddr_t)&fl.fl_nfh, sizeof (nfsv2fh_t)); 1508*52196Smckusick ufp->ufid_len = sizeof (struct ufid); 1509*52196Smckusick ufp->ufid_ino = dp->d_ino; 1510*52196Smckusick fl.fl_nfh.fh_generic.fh_fsid = mntp->mnt_stat.f_fsid; 1511*52196Smckusick if (VFS_FHTOVP(mntp, (struct fid *)ufp, 1, &nvp)) 1512*52196Smckusick goto invalid; 1513*52196Smckusick (void) nqsrv_getlease(nvp, &duration2, NQL_READ, nfsd, 1514*52196Smckusick nam, &cache2, &frev2, cred); 1515*52196Smckusick fl.fl_duration = txdr_unsigned(duration2); 1516*52196Smckusick fl.fl_cachable = txdr_unsigned(cache2); 1517*52196Smckusick txdr_hyper(&frev2, &fl.fl_frev); 1518*52196Smckusick if (VOP_GETATTR(nvp, vap, cred, nfsd->nd_procp)) { 1519*52196Smckusick vput(nvp); 1520*52196Smckusick goto invalid; 1521*52196Smckusick } 1522*52196Smckusick vput(nvp); 1523*52196Smckusick fp = &fl.fl_fattr; 1524*52196Smckusick nfsm_srvfillattr; 1525*52196Smckusick len += (4*NFSX_UNSIGNED + nlen + rem + NFSX_FH 1526*52196Smckusick + NFSX_FATTR); 152741899Smckusick if (len > cnt) { 152841899Smckusick eofflag = 0; 152938418Smckusick break; 153041899Smckusick } 153138425Smckusick 153238418Smckusick /* Build the directory record xdr from the direct entry */ 153338418Smckusick nfsm_clget; 153448050Smckusick *tl = nfs_true; 153538418Smckusick bp += NFSX_UNSIGNED; 1536*52196Smckusick 1537*52196Smckusick /* 1538*52196Smckusick * For readdir_and_lookup copy the stuff out. 1539*52196Smckusick */ 1540*52196Smckusick xfer = sizeof (struct flrep); 1541*52196Smckusick cp = (caddr_t)&fl; 1542*52196Smckusick while (xfer > 0) { 1543*52196Smckusick nfsm_clget; 1544*52196Smckusick if ((bp+xfer) > be) 1545*52196Smckusick tsiz = be-bp; 1546*52196Smckusick else 1547*52196Smckusick tsiz = xfer; 1548*52196Smckusick bcopy(cp, bp, tsiz); 1549*52196Smckusick bp += tsiz; 1550*52196Smckusick xfer -= tsiz; 1551*52196Smckusick if (xfer > 0) 1552*52196Smckusick cp += tsiz; 1553*52196Smckusick } 155438418Smckusick nfsm_clget; 155548050Smckusick *tl = txdr_unsigned(dp->d_ino); 155638418Smckusick bp += NFSX_UNSIGNED; 155738418Smckusick nfsm_clget; 155848050Smckusick *tl = txdr_unsigned(nlen); 155938418Smckusick bp += NFSX_UNSIGNED; 156038425Smckusick 1561*52196Smckusick /* And loop around copying the name */ 156238418Smckusick xfer = nlen; 156338418Smckusick cp = dp->d_name; 156438418Smckusick while (xfer > 0) { 156538418Smckusick nfsm_clget; 156638418Smckusick if ((bp+xfer) > be) 156738418Smckusick tsiz = be-bp; 156838418Smckusick else 156938418Smckusick tsiz = xfer; 157038418Smckusick bcopy(cp, bp, tsiz); 157138418Smckusick bp += tsiz; 157238418Smckusick xfer -= tsiz; 157338418Smckusick if (xfer > 0) 157438418Smckusick cp += tsiz; 157538418Smckusick } 157638418Smckusick /* And null pad to a long boundary */ 157738418Smckusick for (i = 0; i < rem; i++) 157838418Smckusick *bp++ = '\0'; 157938418Smckusick nfsm_clget; 158038425Smckusick 158138418Smckusick /* Finish off the record */ 158238418Smckusick toff += dp->d_reclen; 158348050Smckusick *tl = txdr_unsigned(toff); 158438418Smckusick bp += NFSX_UNSIGNED; 158538418Smckusick } else 1586*52196Smckusick invalid: 158738418Smckusick toff += dp->d_reclen; 158838418Smckusick cpos += dp->d_reclen; 158938418Smckusick dp = (struct direct *)cpos; 159038418Smckusick } 1591*52196Smckusick vrele(vp); 159238418Smckusick nfsm_clget; 159348050Smckusick *tl = nfs_false; 159438418Smckusick bp += NFSX_UNSIGNED; 159538418Smckusick nfsm_clget; 159640296Smckusick if (eofflag) 159748050Smckusick *tl = nfs_true; 159840296Smckusick else 159948050Smckusick *tl = nfs_false; 160038418Smckusick bp += NFSX_UNSIGNED; 1601*52196Smckusick if (mp != mb) { 1602*52196Smckusick if (bp < be) 1603*52196Smckusick mp->m_len = bp - mtod(mp, caddr_t); 1604*52196Smckusick } else 1605*52196Smckusick mp->m_len += bp - bpos; 160638418Smckusick FREE(rbuf, M_TEMP); 160738418Smckusick nfsm_srvdone; 160838418Smckusick } 160938418Smckusick 161038418Smckusick /* 161138418Smckusick * nfs statfs service 161238418Smckusick */ 1613*52196Smckusick nfsrv_statfs(nfsd, mrep, md, dpos, cred, nam, mrq) 1614*52196Smckusick struct nfsd *nfsd; 161538418Smckusick struct mbuf *mrep, *md; 161638418Smckusick caddr_t dpos; 161738418Smckusick struct ucred *cred; 1618*52196Smckusick struct mbuf *nam, **mrq; 161938418Smckusick { 162038418Smckusick register struct statfs *sf; 162138884Smacklem register struct nfsv2_statfs *sfp; 162248050Smckusick register u_long *tl; 162339494Smckusick register long t1; 162439494Smckusick caddr_t bpos; 1625*52196Smckusick int error = 0, rdonly, cache; 162639494Smckusick char *cp2; 162739753Smckusick struct mbuf *mb, *mb2, *mreq; 162838418Smckusick struct vnode *vp; 162938418Smckusick nfsv2fh_t nfh; 163038418Smckusick fhandle_t *fhp; 163138418Smckusick struct statfs statfs; 1632*52196Smckusick u_quad_t frev; 163338418Smckusick 163438418Smckusick fhp = &nfh.fh_generic; 163538418Smckusick nfsm_srvmtofh(fhp); 1636*52196Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 163738418Smckusick nfsm_reply(0); 163838418Smckusick sf = &statfs; 1639*52196Smckusick error = VFS_STATFS(vp->v_mount, sf, nfsd->nd_procp); 164038418Smckusick vput(vp); 164138418Smckusick nfsm_reply(NFSX_STATFS); 164238884Smacklem nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS); 164344993Sbostic sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA); 164451940Smckusick sfp->sf_bsize = txdr_unsigned(sf->f_bsize); 164538884Smacklem sfp->sf_blocks = txdr_unsigned(sf->f_blocks); 164638884Smacklem sfp->sf_bfree = txdr_unsigned(sf->f_bfree); 164738884Smacklem sfp->sf_bavail = txdr_unsigned(sf->f_bavail); 164838418Smckusick nfsm_srvdone; 164938418Smckusick } 165038418Smckusick 165138418Smckusick /* 165238418Smckusick * Null operation, used by clients to ping server 165338418Smckusick */ 165439494Smckusick /* ARGSUSED */ 1655*52196Smckusick nfsrv_null(nfsd, mrep, md, dpos, cred, nam, mrq) 1656*52196Smckusick struct nfsd *nfsd; 165738418Smckusick struct mbuf *mrep, *md; 165838418Smckusick caddr_t dpos; 165938418Smckusick struct ucred *cred; 1660*52196Smckusick struct mbuf *nam, **mrq; 166138418Smckusick { 166239494Smckusick caddr_t bpos; 1663*52196Smckusick int error = VNOVAL, cache; 166439753Smckusick struct mbuf *mb, *mreq; 1665*52196Smckusick u_quad_t frev; 166638418Smckusick 166738418Smckusick nfsm_reply(0); 166839494Smckusick return (error); 166938418Smckusick } 167038418Smckusick 167138418Smckusick /* 167238418Smckusick * No operation, used for obsolete procedures 167338418Smckusick */ 167439494Smckusick /* ARGSUSED */ 1675*52196Smckusick nfsrv_noop(nfsd, mrep, md, dpos, cred, nam, mrq) 1676*52196Smckusick struct nfsd *nfsd; 167738418Smckusick struct mbuf *mrep, *md; 167838418Smckusick caddr_t dpos; 167938418Smckusick struct ucred *cred; 1680*52196Smckusick struct mbuf *nam, **mrq; 168138418Smckusick { 168239494Smckusick caddr_t bpos; 1683*52196Smckusick int error, cache; 168439753Smckusick struct mbuf *mb, *mreq; 1685*52196Smckusick u_quad_t frev; 168638418Smckusick 1687*52196Smckusick if (nfsd->nd_repstat) 1688*52196Smckusick error = nfsd->nd_repstat; 1689*52196Smckusick else 1690*52196Smckusick error = EPROCUNAVAIL; 169138418Smckusick nfsm_reply(0); 169239494Smckusick return (error); 169338418Smckusick } 169438425Smckusick 169538450Smckusick /* 169638450Smckusick * Perform access checking for vnodes obtained from file handles that would 169738450Smckusick * refer to files already opened by a Unix client. You cannot just use 169838450Smckusick * vn_writechk() and VOP_ACCESS() for two reasons. 1699*52196Smckusick * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case 170038450Smckusick * 2 - The owner is to be given access irrespective of mode bits so that 170138450Smckusick * processes that chmod after opening a file don't break. I don't like 170238450Smckusick * this because it opens a security hole, but since the nfs server opens 170338450Smckusick * a security hole the size of a barn door anyhow, what the heck. 170438450Smckusick */ 1705*52196Smckusick nfsrv_access(vp, flags, cred, rdonly, p) 170638450Smckusick register struct vnode *vp; 170738450Smckusick int flags; 170838450Smckusick register struct ucred *cred; 1709*52196Smckusick int rdonly; 171048050Smckusick struct proc *p; 171138450Smckusick { 171238450Smckusick struct vattr vattr; 171338450Smckusick int error; 171438450Smckusick if (flags & VWRITE) { 1715*52196Smckusick /* Just vn_writechk() changed to check rdonly */ 171638450Smckusick /* 171738450Smckusick * Disallow write attempts on read-only file systems; 171838450Smckusick * unless the file is a socket or a block or character 171938450Smckusick * device resident on the file system. 172038450Smckusick */ 1721*52196Smckusick if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { 172245059Smckusick switch (vp->v_type) { 172345059Smckusick case VREG: case VDIR: case VLNK: 172438450Smckusick return (EROFS); 172545059Smckusick } 172645059Smckusick } 172738450Smckusick /* 172838450Smckusick * If there's shared text associated with 172938450Smckusick * the inode, try to free it up once. If 173038450Smckusick * we fail, we can't allow writing. 173138450Smckusick */ 173245715Smckusick if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) 173338450Smckusick return (ETXTBSY); 173438450Smckusick } 173548050Smckusick if (error = VOP_GETATTR(vp, &vattr, cred, p)) 173645059Smckusick return (error); 173748050Smckusick if ((error = VOP_ACCESS(vp, flags, cred, p)) && 173845059Smckusick cred->cr_uid != vattr.va_uid) 173945059Smckusick return (error); 174045059Smckusick return (0); 174138450Smckusick } 1742