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*51940Smckusick * @(#)nfs_serv.c 7.42 (Berkeley) 12/14/91 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" 4438418Smckusick #include "nfs.h" 4538418Smckusick #include "xdr_subs.h" 4638418Smckusick #include "nfsm_subs.h" 4738418Smckusick 4838418Smckusick /* Defs */ 4938425Smckusick #define TRUE 1 5038425Smckusick #define FALSE 0 5138418Smckusick 5238418Smckusick /* Global vars */ 5338418Smckusick extern u_long nfs_procids[NFS_NPROCS]; 5438418Smckusick extern u_long nfs_xdrneg1; 5538418Smckusick extern u_long nfs_false, nfs_true; 5642242Smckusick nfstype nfs_type[9]={ NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, 5742242Smckusick NFCHR, NFNON }; 5838418Smckusick 5938418Smckusick /* 6038418Smckusick * nfs getattr service 6138418Smckusick */ 6248050Smckusick nfsrv_getattr(mrep, md, dpos, cred, xid, mrq, repstat, p) 6338418Smckusick struct mbuf **mrq; 6438418Smckusick struct mbuf *mrep, *md; 6538418Smckusick caddr_t dpos; 6638418Smckusick struct ucred *cred; 6738418Smckusick u_long xid; 6839753Smckusick int *repstat; 6948050Smckusick struct proc *p; 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; 8039494Smckusick int error = 0; 8139494Smckusick char *cp2; 8239753Smckusick struct mbuf *mb, *mb2, *mreq; 8338418Smckusick 8438418Smckusick fhp = &nfh.fh_generic; 8538418Smckusick nfsm_srvmtofh(fhp); 8638418Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) 8738418Smckusick nfsm_reply(0); 8848050Smckusick error = VOP_GETATTR(vp, vap, cred, p); 8938418Smckusick vput(vp); 9038418Smckusick nfsm_reply(NFSX_FATTR); 9138884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 9239753Smckusick nfsm_srvfillattr; 9338418Smckusick nfsm_srvdone; 9438418Smckusick } 9538418Smckusick 9638418Smckusick /* 9738418Smckusick * nfs setattr service 9838418Smckusick */ 9948050Smckusick nfsrv_setattr(mrep, md, dpos, cred, xid, mrq, repstat, p) 10038418Smckusick struct mbuf **mrq; 10138418Smckusick struct mbuf *mrep, *md; 10238418Smckusick caddr_t dpos; 10338418Smckusick struct ucred *cred; 10438418Smckusick u_long xid; 10539753Smckusick int *repstat; 10648050Smckusick struct proc *p; 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; 11839494Smckusick int error = 0; 11939494Smckusick char *cp2; 12039753Smckusick struct mbuf *mb, *mb2, *mreq; 12138418Smckusick 12238418Smckusick fhp = &nfh.fh_generic; 12338418Smckusick nfsm_srvmtofh(fhp); 12438884Smacklem nfsm_disect(sp, struct nfsv2_sattr *, NFSX_SATTR); 12538418Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) 12638418Smckusick nfsm_reply(0); 12748050Smckusick if (error = nfsrv_access(vp, VWRITE, cred, p)) 12838418Smckusick goto out; 12941361Smckusick VATTR_NULL(vap); 13038418Smckusick /* 13138418Smckusick * Nah nah nah nah na nah 13238418Smckusick * There is a bug in the Sun client that puts 0xffff in the mode 13338418Smckusick * field of sattr when it should put in 0xffffffff. The u_short 13438418Smckusick * doesn't sign extend. 13538418Smckusick * --> check the low order 2 bytes for 0xffff 13638418Smckusick */ 13738884Smacklem if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff) 13838884Smacklem vap->va_mode = nfstov_mode(sp->sa_mode); 13938884Smacklem if (sp->sa_uid != nfs_xdrneg1) 14038884Smacklem vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid); 14138884Smacklem if (sp->sa_gid != nfs_xdrneg1) 14238884Smacklem vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid); 14339753Smckusick if (sp->sa_size != nfs_xdrneg1) 14438884Smacklem vap->va_size = fxdr_unsigned(u_long, sp->sa_size); 14539753Smckusick /* 14639753Smckusick * The usec field of sa_atime is overloaded with the va_flags field 14739753Smckusick * for 4.4BSD clients. Hopefully other clients always set both the 14839753Smckusick * sec and usec fields to -1 when not setting the atime. 14939753Smckusick */ 15039753Smckusick if (sp->sa_atime.tv_sec != nfs_xdrneg1) { 15139753Smckusick vap->va_atime.tv_sec = fxdr_unsigned(long, sp->sa_atime.tv_sec); 15239753Smckusick vap->va_atime.tv_usec = 0; 15338425Smckusick } 15439753Smckusick if (sp->sa_atime.tv_usec != nfs_xdrneg1) 15539753Smckusick vap->va_flags = fxdr_unsigned(u_long, sp->sa_atime.tv_usec); 15638884Smacklem if (sp->sa_mtime.tv_sec != nfs_xdrneg1) 15738884Smacklem fxdr_time(&sp->sa_mtime, &vap->va_mtime); 15848050Smckusick if (error = VOP_SETATTR(vp, vap, cred, p)) { 15938418Smckusick vput(vp); 16038418Smckusick nfsm_reply(0); 16138418Smckusick } 16248050Smckusick error = VOP_GETATTR(vp, vap, cred, p); 16338418Smckusick out: 16438418Smckusick vput(vp); 16538418Smckusick nfsm_reply(NFSX_FATTR); 16638884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 16739753Smckusick nfsm_srvfillattr; 16838418Smckusick nfsm_srvdone; 16938418Smckusick } 17038418Smckusick 17138418Smckusick /* 17238418Smckusick * nfs lookup rpc 17338418Smckusick */ 17448050Smckusick nfsrv_lookup(mrep, md, dpos, cred, xid, mrq, repstat, p) 17538418Smckusick struct mbuf **mrq; 17638418Smckusick struct mbuf *mrep, *md; 17738418Smckusick caddr_t dpos; 17838418Smckusick struct ucred *cred; 17938418Smckusick u_long xid; 18039753Smckusick int *repstat; 18148050Smckusick struct proc *p; 18238418Smckusick { 18338884Smacklem register struct nfsv2_fattr *fp; 18449742Smckusick struct nameidata nd; 18538418Smckusick struct vnode *vp; 18638418Smckusick nfsv2fh_t nfh; 18738418Smckusick fhandle_t *fhp; 18839494Smckusick register caddr_t cp; 18948050Smckusick register u_long *tl; 19039494Smckusick register long t1; 19139494Smckusick caddr_t bpos; 19239494Smckusick int error = 0; 19339494Smckusick char *cp2; 19439753Smckusick struct mbuf *mb, *mb2, *mreq; 19538418Smckusick long len; 19638418Smckusick struct vattr va, *vap = &va; 19738418Smckusick 19838418Smckusick fhp = &nfh.fh_generic; 19938418Smckusick nfsm_srvmtofh(fhp); 20038418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 20149742Smckusick nd.ni_cred = cred; 20249742Smckusick nd.ni_nameiop = LOOKUP | LOCKLEAF; 20349742Smckusick if (error = nfs_namei(&nd, fhp, len, &md, &dpos, p)) 20438418Smckusick nfsm_reply(0); 20549742Smckusick vp = nd.ni_vp; 20638418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 20741398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 20838418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 20938418Smckusick vput(vp); 21038418Smckusick nfsm_reply(0); 21138418Smckusick } 21248050Smckusick error = VOP_GETATTR(vp, vap, cred, p); 21338418Smckusick vput(vp); 21438418Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR); 21538418Smckusick nfsm_srvfhtom(fhp); 21638884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 21739753Smckusick nfsm_srvfillattr; 21838418Smckusick nfsm_srvdone; 21938418Smckusick } 22038418Smckusick 22138418Smckusick /* 22238418Smckusick * nfs readlink service 22338418Smckusick */ 22448050Smckusick nfsrv_readlink(mrep, md, dpos, cred, xid, mrq, repstat, p) 22538418Smckusick struct mbuf **mrq; 22638418Smckusick struct mbuf *mrep, *md; 22738418Smckusick caddr_t dpos; 22838418Smckusick struct ucred *cred; 22939753Smckusick u_long xid; 23039753Smckusick int *repstat; 23148050Smckusick struct proc *p; 23238418Smckusick { 23341899Smckusick struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN]; 23438418Smckusick register struct iovec *ivp = iv; 23538418Smckusick register struct mbuf *mp; 23648050Smckusick register u_long *tl; 23739494Smckusick register long t1; 23839494Smckusick caddr_t bpos; 23939494Smckusick int error = 0; 24039494Smckusick char *cp2; 24139753Smckusick struct mbuf *mb, *mb2, *mp2, *mp3, *mreq; 24238418Smckusick struct vnode *vp; 24338418Smckusick nfsv2fh_t nfh; 24438418Smckusick fhandle_t *fhp; 24538418Smckusick struct uio io, *uiop = &io; 24638418Smckusick int i, tlen, len; 24738418Smckusick 24838418Smckusick fhp = &nfh.fh_generic; 24938418Smckusick nfsm_srvmtofh(fhp); 25038418Smckusick len = 0; 25138418Smckusick i = 0; 25238418Smckusick while (len < NFS_MAXPATHLEN) { 25338418Smckusick MGET(mp, M_WAIT, MT_DATA); 25441899Smckusick MCLGET(mp, M_WAIT); 25538418Smckusick mp->m_len = NFSMSIZ(mp); 25638418Smckusick if (len == 0) 25738418Smckusick mp3 = mp2 = mp; 25841899Smckusick else { 25938418Smckusick mp2->m_next = mp; 26041899Smckusick mp2 = mp; 26141899Smckusick } 26238418Smckusick if ((len+mp->m_len) > NFS_MAXPATHLEN) { 26338418Smckusick mp->m_len = NFS_MAXPATHLEN-len; 26438418Smckusick len = NFS_MAXPATHLEN; 26538418Smckusick } else 26638418Smckusick len += mp->m_len; 26738418Smckusick ivp->iov_base = mtod(mp, caddr_t); 26838418Smckusick ivp->iov_len = mp->m_len; 26938418Smckusick i++; 27038418Smckusick ivp++; 27138418Smckusick } 27238418Smckusick uiop->uio_iov = iv; 27338418Smckusick uiop->uio_iovcnt = i; 27438418Smckusick uiop->uio_offset = 0; 27538418Smckusick uiop->uio_resid = len; 27638418Smckusick uiop->uio_rw = UIO_READ; 27738418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 27848050Smckusick uiop->uio_procp = (struct proc *)0; 27938418Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) { 28038418Smckusick m_freem(mp3); 28138418Smckusick nfsm_reply(0); 28238418Smckusick } 28338418Smckusick if (vp->v_type != VLNK) { 28438418Smckusick error = EINVAL; 28538418Smckusick goto out; 28638418Smckusick } 28738418Smckusick error = VOP_READLINK(vp, uiop, cred); 28838418Smckusick out: 28938418Smckusick vput(vp); 29038418Smckusick if (error) 29138418Smckusick m_freem(mp3); 29238418Smckusick nfsm_reply(NFSX_UNSIGNED); 29338418Smckusick if (uiop->uio_resid > 0) { 29438418Smckusick len -= uiop->uio_resid; 29538418Smckusick tlen = nfsm_rndup(len); 29638418Smckusick nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len); 29738418Smckusick } 29848050Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 29948050Smckusick *tl = txdr_unsigned(len); 30038418Smckusick mb->m_next = mp3; 30138418Smckusick nfsm_srvdone; 30238418Smckusick } 30338418Smckusick 30438418Smckusick /* 30538418Smckusick * nfs read service 30638418Smckusick */ 30748050Smckusick nfsrv_read(mrep, md, dpos, cred, xid, mrq, repstat, p) 30838418Smckusick struct mbuf **mrq; 30938418Smckusick struct mbuf *mrep, *md; 31038418Smckusick caddr_t dpos; 31138418Smckusick struct ucred *cred; 31238418Smckusick u_long xid; 31339753Smckusick int *repstat; 31448050Smckusick struct proc *p; 31538418Smckusick { 31643350Smckusick register struct iovec *iv; 31743350Smckusick struct iovec *iv2; 31841899Smckusick register struct mbuf *m; 31938884Smacklem register struct nfsv2_fattr *fp; 32048050Smckusick register u_long *tl; 32139494Smckusick register long t1; 32239494Smckusick caddr_t bpos; 32339494Smckusick int error = 0; 32439494Smckusick char *cp2; 32539753Smckusick struct mbuf *mb, *mb2, *mreq; 32641899Smckusick struct mbuf *m2, *m3; 32738418Smckusick struct vnode *vp; 32838418Smckusick nfsv2fh_t nfh; 32938418Smckusick fhandle_t *fhp; 33038418Smckusick struct uio io, *uiop = &io; 33138418Smckusick struct vattr va, *vap = &va; 33241899Smckusick int i, cnt, len, left, siz, tlen; 33338418Smckusick off_t off; 33438418Smckusick 33538418Smckusick fhp = &nfh.fh_generic; 33638418Smckusick nfsm_srvmtofh(fhp); 33748050Smckusick nfsm_disect(tl, u_long *, NFSX_UNSIGNED); 33848050Smckusick off = fxdr_unsigned(off_t, *tl); 33938418Smckusick nfsm_srvstrsiz(cnt, NFS_MAXDATA); 34038418Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) 34138418Smckusick nfsm_reply(0); 34248050Smckusick if (error = nfsrv_access(vp, VREAD | VEXEC, cred, p)) { 34338418Smckusick vput(vp); 34438418Smckusick nfsm_reply(0); 34538418Smckusick } 34638418Smckusick len = left = cnt; 34741899Smckusick /* 34841899Smckusick * Generate the mbuf list with the uio_iov ref. to it. 34941899Smckusick */ 35041899Smckusick i = 0; 35141899Smckusick m3 = (struct mbuf *)0; 35242242Smckusick #ifdef lint 35342242Smckusick m2 = (struct mbuf *)0; 35442242Smckusick #endif /* lint */ 35543350Smckusick MALLOC(iv, struct iovec *, 35643350Smckusick ((NFS_MAXDATA+MLEN-1)/MLEN) * sizeof (struct iovec), M_TEMP, 35743350Smckusick M_WAITOK); 35843350Smckusick iv2 = iv; 35941899Smckusick while (left > 0) { 36041899Smckusick MGET(m, M_WAIT, MT_DATA); 36141899Smckusick if (left > MINCLSIZE) 36241899Smckusick MCLGET(m, M_WAIT); 36341899Smckusick m->m_len = 0; 36441899Smckusick siz = min(M_TRAILINGSPACE(m), left); 36541899Smckusick m->m_len = siz; 36643350Smckusick iv->iov_base = mtod(m, caddr_t); 36743350Smckusick iv->iov_len = siz; 36843350Smckusick iv++; 36941899Smckusick i++; 37041899Smckusick left -= siz; 37141899Smckusick if (m3) { 37241899Smckusick m2->m_next = m; 37341899Smckusick m2 = m; 37441899Smckusick } else 37541899Smckusick m3 = m2 = m; 37641899Smckusick } 37743350Smckusick uiop->uio_iov = iv2; 37841899Smckusick uiop->uio_iovcnt = i; 37938418Smckusick uiop->uio_offset = off; 38038418Smckusick uiop->uio_resid = cnt; 38138418Smckusick uiop->uio_rw = UIO_READ; 38238418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 38348050Smckusick uiop->uio_procp = (struct proc *)0; 38439586Smckusick error = VOP_READ(vp, uiop, IO_NODELOCKED, cred); 38539586Smckusick off = uiop->uio_offset; 38643350Smckusick FREE((caddr_t)iv2, M_TEMP); 38738418Smckusick if (error) { 38841899Smckusick m_freem(m3); 38938418Smckusick vput(vp); 39038418Smckusick nfsm_reply(0); 39138418Smckusick } 39248050Smckusick if (error = VOP_GETATTR(vp, vap, cred, p)) 39341899Smckusick m_freem(m3); 39438418Smckusick vput(vp); 39538418Smckusick nfsm_reply(NFSX_FATTR+NFSX_UNSIGNED); 39638884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 39739753Smckusick nfsm_srvfillattr; 39845877Smckusick len -= uiop->uio_resid; 39945877Smckusick if (len > 0) { 40045877Smckusick tlen = nfsm_rndup(len); 40145877Smckusick if (cnt != tlen || tlen != len) 40241899Smckusick nfsm_adj(m3, cnt-tlen, tlen-len); 40345877Smckusick } else { 40445877Smckusick m_freem(m3); 40545877Smckusick m3 = (struct mbuf *)0; 40638418Smckusick } 40748050Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 40848050Smckusick *tl = txdr_unsigned(len); 40941899Smckusick mb->m_next = m3; 41038418Smckusick nfsm_srvdone; 41138418Smckusick } 41238418Smckusick 41338418Smckusick /* 41438418Smckusick * nfs write service 41538418Smckusick */ 41648050Smckusick nfsrv_write(mrep, md, dpos, cred, xid, mrq, repstat, p) 41738418Smckusick struct mbuf *mrep, *md, **mrq; 41838418Smckusick caddr_t dpos; 41938418Smckusick struct ucred *cred; 42039753Smckusick u_long xid; 42139753Smckusick int *repstat; 42248050Smckusick struct proc *p; 42338418Smckusick { 42438418Smckusick register struct iovec *ivp; 42538418Smckusick register struct mbuf *mp; 42638884Smacklem register struct nfsv2_fattr *fp; 42741899Smckusick struct iovec iv[NFS_MAXIOVEC]; 42838418Smckusick struct vattr va; 42938418Smckusick register struct vattr *vap = &va; 43048050Smckusick register u_long *tl; 43139494Smckusick register long t1; 43239494Smckusick caddr_t bpos; 43339494Smckusick int error = 0; 43439494Smckusick char *cp2; 43539753Smckusick struct mbuf *mb, *mb2, *mreq; 43638418Smckusick struct vnode *vp; 43738418Smckusick nfsv2fh_t nfh; 43838418Smckusick fhandle_t *fhp; 43938418Smckusick struct uio io, *uiop = &io; 44038418Smckusick off_t off; 44138418Smckusick long siz, len, xfer; 44238418Smckusick 44338418Smckusick fhp = &nfh.fh_generic; 44438418Smckusick nfsm_srvmtofh(fhp); 44548050Smckusick nfsm_disect(tl, u_long *, 4*NFSX_UNSIGNED); 44648050Smckusick off = fxdr_unsigned(off_t, *++tl); 44748050Smckusick tl += 2; 44848050Smckusick len = fxdr_unsigned(long, *tl); 44938418Smckusick if (len > NFS_MAXDATA || len <= 0) { 45038418Smckusick error = EBADRPC; 45138418Smckusick nfsm_reply(0); 45238418Smckusick } 45338418Smckusick if (dpos == (mtod(md, caddr_t)+md->m_len)) { 45438418Smckusick mp = md->m_next; 45538418Smckusick if (mp == NULL) { 45638418Smckusick error = EBADRPC; 45738418Smckusick nfsm_reply(0); 45838418Smckusick } 45938418Smckusick } else { 46038418Smckusick mp = md; 46138418Smckusick siz = dpos-mtod(mp, caddr_t); 46238418Smckusick mp->m_len -= siz; 46338418Smckusick NFSMADV(mp, siz); 46438418Smckusick } 46538418Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) 46638418Smckusick nfsm_reply(0); 46748050Smckusick if (error = nfsrv_access(vp, VWRITE, cred, p)) { 46838418Smckusick vput(vp); 46938418Smckusick nfsm_reply(0); 47038418Smckusick } 47138418Smckusick uiop->uio_resid = 0; 47238418Smckusick uiop->uio_rw = UIO_WRITE; 47338418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 47448050Smckusick uiop->uio_procp = (struct proc *)0; 47538418Smckusick /* 47641899Smckusick * Do up to NFS_MAXIOVEC mbufs of write each iteration of the 47738418Smckusick * loop until done. 47838418Smckusick */ 47938418Smckusick while (len > 0 && uiop->uio_resid == 0) { 48038418Smckusick ivp = iv; 48138418Smckusick siz = 0; 48238418Smckusick uiop->uio_iov = ivp; 48338418Smckusick uiop->uio_iovcnt = 0; 48438418Smckusick uiop->uio_offset = off; 48541899Smckusick while (len > 0 && uiop->uio_iovcnt < NFS_MAXIOVEC && mp != NULL) { 48638418Smckusick ivp->iov_base = mtod(mp, caddr_t); 48738418Smckusick if (len < mp->m_len) 48838418Smckusick ivp->iov_len = xfer = len; 48938418Smckusick else 49038418Smckusick ivp->iov_len = xfer = mp->m_len; 49138418Smckusick #ifdef notdef 49238418Smckusick /* Not Yet .. */ 49338418Smckusick if (M_HASCL(mp) && (((u_long)ivp->iov_base) & CLOFSET) == 0) 49438418Smckusick ivp->iov_op = NULL; /* what should it be ?? */ 49538418Smckusick else 49638418Smckusick ivp->iov_op = NULL; 49738418Smckusick #endif 49838418Smckusick uiop->uio_iovcnt++; 49938418Smckusick ivp++; 50038418Smckusick len -= xfer; 50138418Smckusick siz += xfer; 50238418Smckusick mp = mp->m_next; 50338418Smckusick } 50438418Smckusick if (len > 0 && mp == NULL) { 50538418Smckusick error = EBADRPC; 50638418Smckusick vput(vp); 50738418Smckusick nfsm_reply(0); 50838418Smckusick } 50938418Smckusick uiop->uio_resid = siz; 51039586Smckusick if (error = VOP_WRITE(vp, uiop, IO_SYNC | IO_NODELOCKED, 51138418Smckusick cred)) { 51238418Smckusick vput(vp); 51338418Smckusick nfsm_reply(0); 51438418Smckusick } 51539586Smckusick off = uiop->uio_offset; 51638418Smckusick } 51748050Smckusick error = VOP_GETATTR(vp, vap, cred, p); 51838418Smckusick vput(vp); 51938418Smckusick nfsm_reply(NFSX_FATTR); 52038884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 52139753Smckusick nfsm_srvfillattr; 52238418Smckusick nfsm_srvdone; 52338418Smckusick } 52438418Smckusick 52538418Smckusick /* 52638418Smckusick * nfs create service 52738418Smckusick * now does a truncate to 0 length via. setattr if it already exists 52838418Smckusick */ 52948050Smckusick nfsrv_create(mrep, md, dpos, cred, xid, mrq, repstat, p) 53038418Smckusick struct mbuf *mrep, *md, **mrq; 53138418Smckusick caddr_t dpos; 53238418Smckusick struct ucred *cred; 53339753Smckusick u_long xid; 53439753Smckusick int *repstat; 53548050Smckusick struct proc *p; 53638418Smckusick { 53738884Smacklem register struct nfsv2_fattr *fp; 53838418Smckusick struct vattr va; 53938418Smckusick register struct vattr *vap = &va; 54049742Smckusick struct nameidata nd; 54139494Smckusick register caddr_t cp; 54248050Smckusick register u_long *tl; 54339494Smckusick register long t1; 54439494Smckusick caddr_t bpos; 54542242Smckusick long rdev; 54639494Smckusick int error = 0; 54739494Smckusick char *cp2; 54839753Smckusick struct mbuf *mb, *mb2, *mreq; 54938418Smckusick struct vnode *vp; 55038418Smckusick nfsv2fh_t nfh; 55138418Smckusick fhandle_t *fhp; 55238418Smckusick long len; 55338418Smckusick 55449742Smckusick nd.ni_nameiop = 0; 55538418Smckusick fhp = &nfh.fh_generic; 55638418Smckusick nfsm_srvmtofh(fhp); 55738418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 55849742Smckusick nd.ni_cred = cred; 55949742Smckusick nd.ni_nameiop = CREATE | LOCKPARENT | LOCKLEAF | SAVESTART; 56049742Smckusick if (error = nfs_namei(&nd, fhp, len, &md, &dpos, p)) 56138418Smckusick nfsm_reply(0); 56241361Smckusick VATTR_NULL(vap); 56348050Smckusick nfsm_disect(tl, u_long *, NFSX_SATTR); 56438418Smckusick /* 56538418Smckusick * Iff doesn't exist, create it 56638418Smckusick * otherwise just truncate to 0 length 56738418Smckusick * should I set the mode too ?? 56838418Smckusick */ 56949742Smckusick if (nd.ni_vp == NULL) { 57048050Smckusick vap->va_type = IFTOVT(fxdr_unsigned(u_long, *tl)); 57142867Smckusick if (vap->va_type == VNON) 57242867Smckusick vap->va_type = VREG; 57348050Smckusick vap->va_mode = nfstov_mode(*tl); 57448050Smckusick rdev = fxdr_unsigned(long, *(tl+3)); 57546988Smckusick if (vap->va_type == VREG || vap->va_type == VSOCK) { 57649742Smckusick vrele(nd.ni_startdir); 57749742Smckusick if (error = VOP_CREATE(&nd, vap, p)) 57842242Smckusick nfsm_reply(0); 57949742Smckusick FREE(nd.ni_pnbuf, M_NAMEI); 58042242Smckusick } else if (vap->va_type == VCHR || vap->va_type == VBLK || 58142242Smckusick vap->va_type == VFIFO) { 58242242Smckusick if (vap->va_type == VCHR && rdev == 0xffffffff) 58342242Smckusick vap->va_type = VFIFO; 58442242Smckusick if (vap->va_type == VFIFO) { 58542242Smckusick #ifndef FIFO 58649742Smckusick VOP_ABORTOP(&nd); 58749742Smckusick vput(nd.ni_dvp); 58842242Smckusick error = ENXIO; 58949742Smckusick goto out; 59042242Smckusick #endif /* FIFO */ 59142242Smckusick } else if (error = suser(cred, (short *)0)) { 59249742Smckusick VOP_ABORTOP(&nd); 59349742Smckusick vput(nd.ni_dvp); 59449742Smckusick goto out; 59542242Smckusick } else 59642242Smckusick vap->va_rdev = (dev_t)rdev; 59749742Smckusick if (error = VOP_MKNOD(&nd, vap, cred, p)) { 59849742Smckusick vrele(nd.ni_startdir); 59942242Smckusick nfsm_reply(0); 60049742Smckusick } 60149742Smckusick nd.ni_nameiop &= ~(OPMASK | LOCKPARENT | SAVESTART); 60249742Smckusick nd.ni_nameiop |= LOOKUP; 60349742Smckusick if (error = lookup(&nd, p)) { 60449742Smckusick free(nd.ni_pnbuf, M_NAMEI); 60542242Smckusick nfsm_reply(0); 60649742Smckusick } 60749742Smckusick FREE(nd.ni_pnbuf, M_NAMEI); 60849742Smckusick if (nd.ni_more) { 60949742Smckusick vrele(nd.ni_dvp); 61049742Smckusick vput(nd.ni_vp); 61149742Smckusick VOP_ABORTOP(&nd); 61249742Smckusick error = EINVAL; 61349742Smckusick nfsm_reply(0); 61449742Smckusick } 61542242Smckusick } else { 61649742Smckusick VOP_ABORTOP(&nd); 61749742Smckusick vput(nd.ni_dvp); 61842242Smckusick error = ENXIO; 61949742Smckusick goto out; 62042242Smckusick } 62149742Smckusick vp = nd.ni_vp; 62238418Smckusick } else { 62349742Smckusick vrele(nd.ni_startdir); 62449742Smckusick free(nd.ni_pnbuf, M_NAMEI); 62549742Smckusick vp = nd.ni_vp; 62649742Smckusick if (nd.ni_dvp == vp) 62749742Smckusick vrele(nd.ni_dvp); 62843359Smckusick else 62949742Smckusick vput(nd.ni_dvp); 63049742Smckusick VOP_ABORTOP(&nd); 63138418Smckusick vap->va_size = 0; 63248050Smckusick if (error = VOP_SETATTR(vp, vap, cred, p)) { 63342506Smckusick vput(vp); 63438418Smckusick nfsm_reply(0); 63542506Smckusick } 63638418Smckusick } 63738418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 63841398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 63938418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 64038418Smckusick vput(vp); 64138418Smckusick nfsm_reply(0); 64238418Smckusick } 64348050Smckusick error = VOP_GETATTR(vp, vap, cred, p); 64438418Smckusick vput(vp); 64538418Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR); 64638418Smckusick nfsm_srvfhtom(fhp); 64738884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 64839753Smckusick nfsm_srvfillattr; 64938418Smckusick return (error); 65038418Smckusick nfsmout: 65149742Smckusick if (nd.ni_nameiop) 65251464Sbostic vrele(nd.ni_startdir); 65349742Smckusick VOP_ABORTOP(&nd); 65449742Smckusick if (nd.ni_dvp == nd.ni_vp) 65549742Smckusick vrele(nd.ni_dvp); 65643359Smckusick else 65749742Smckusick vput(nd.ni_dvp); 65849742Smckusick if (nd.ni_vp) 65949742Smckusick vput(nd.ni_vp); 66038418Smckusick return (error); 66149742Smckusick 66249742Smckusick out: 66349742Smckusick vrele(nd.ni_startdir); 66449742Smckusick free(nd.ni_pnbuf, M_NAMEI); 66549742Smckusick nfsm_reply(0); 66638418Smckusick } 66738418Smckusick 66838418Smckusick /* 66938418Smckusick * nfs remove service 67038418Smckusick */ 67148050Smckusick nfsrv_remove(mrep, md, dpos, cred, xid, mrq, repstat, p) 67238418Smckusick struct mbuf *mrep, *md, **mrq; 67338418Smckusick caddr_t dpos; 67438418Smckusick struct ucred *cred; 67539753Smckusick u_long xid; 67639753Smckusick int *repstat; 67748050Smckusick struct proc *p; 67838418Smckusick { 67949742Smckusick struct nameidata nd; 68048050Smckusick register u_long *tl; 68139494Smckusick register long t1; 68239494Smckusick caddr_t bpos; 68339494Smckusick int error = 0; 68439494Smckusick char *cp2; 68539753Smckusick struct mbuf *mb, *mreq; 68638418Smckusick struct vnode *vp; 68738418Smckusick nfsv2fh_t nfh; 68838418Smckusick fhandle_t *fhp; 68938418Smckusick long len; 69038418Smckusick 69138418Smckusick fhp = &nfh.fh_generic; 69238418Smckusick nfsm_srvmtofh(fhp); 69338418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 69449742Smckusick nd.ni_cred = cred; 69549742Smckusick nd.ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 69649742Smckusick if (error = nfs_namei(&nd, fhp, len, &md, &dpos, p)) 69738418Smckusick nfsm_reply(0); 69849742Smckusick vp = nd.ni_vp; 69938418Smckusick if (vp->v_type == VDIR && 70038418Smckusick (error = suser(cred, (short *)0))) 70138418Smckusick goto out; 70238418Smckusick /* 70349454Smckusick * The root of a mounted filesystem cannot be deleted. 70438418Smckusick */ 70538418Smckusick if (vp->v_flag & VROOT) { 70638418Smckusick error = EBUSY; 70738418Smckusick goto out; 70838418Smckusick } 70938418Smckusick if (vp->v_flag & VTEXT) 71045715Smckusick (void) vnode_pager_uncache(vp); 71138418Smckusick out: 71242467Smckusick if (!error) { 71349742Smckusick error = VOP_REMOVE(&nd, p); 71442467Smckusick } else { 71549742Smckusick VOP_ABORTOP(&nd); 71649742Smckusick if (nd.ni_dvp == vp) 71749742Smckusick vrele(nd.ni_dvp); 71843359Smckusick else 71949742Smckusick vput(nd.ni_dvp); 72042467Smckusick vput(vp); 72142467Smckusick } 72238418Smckusick nfsm_reply(0); 72338418Smckusick nfsm_srvdone; 72438418Smckusick } 72538418Smckusick 72638418Smckusick /* 72738418Smckusick * nfs rename service 72838418Smckusick */ 72948050Smckusick nfsrv_rename(mrep, md, dpos, cred, xid, mrq, repstat, p) 73038418Smckusick struct mbuf *mrep, *md, **mrq; 73138418Smckusick caddr_t dpos; 73238418Smckusick struct ucred *cred; 73339753Smckusick u_long xid; 73439753Smckusick int *repstat; 73548050Smckusick struct proc *p; 73638418Smckusick { 73748050Smckusick register u_long *tl; 73839494Smckusick register long t1; 73939494Smckusick caddr_t bpos; 74039494Smckusick int error = 0; 74139494Smckusick char *cp2; 74239753Smckusick struct mbuf *mb, *mreq; 74349742Smckusick struct nameidata fromnd, tond; 74438418Smckusick struct vnode *fvp, *tvp, *tdvp; 74538418Smckusick nfsv2fh_t fnfh, tnfh; 74638418Smckusick fhandle_t *ffhp, *tfhp; 74738418Smckusick long len, len2; 74838418Smckusick int rootflg = 0; 74938418Smckusick 75038418Smckusick ffhp = &fnfh.fh_generic; 75138418Smckusick tfhp = &tnfh.fh_generic; 75249742Smckusick fromnd.ni_nameiop = 0; 75349742Smckusick tond.ni_nameiop = 0; 75438418Smckusick nfsm_srvmtofh(ffhp); 75538418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 75638418Smckusick /* 75738418Smckusick * Remember if we are root so that we can reset cr_uid before 75838418Smckusick * the second nfs_namei() call 75938418Smckusick */ 76038418Smckusick if (cred->cr_uid == 0) 76138418Smckusick rootflg++; 76249742Smckusick fromnd.ni_cred = cred; 76349742Smckusick fromnd.ni_nameiop = DELETE | WANTPARENT | SAVESTART; 76449742Smckusick if (error = nfs_namei(&fromnd, ffhp, len, &md, &dpos, p)) 76538418Smckusick nfsm_reply(0); 76649742Smckusick fvp = fromnd.ni_vp; 76738418Smckusick nfsm_srvmtofh(tfhp); 76841899Smckusick nfsm_strsiz(len2, NFS_MAXNAMLEN); 76938418Smckusick if (rootflg) 77038418Smckusick cred->cr_uid = 0; 77139343Smckusick tond.ni_cred = cred; 77246513Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE 77349742Smckusick | SAVESTART; 77449742Smckusick if (error = nfs_namei(&tond, tfhp, len2, &md, &dpos, p)) { 77549742Smckusick VOP_ABORTOP(&fromnd); 77649742Smckusick vrele(fromnd.ni_dvp); 77742467Smckusick vrele(fvp); 77842467Smckusick goto out1; 77942467Smckusick } 78038425Smckusick tdvp = tond.ni_dvp; 78138425Smckusick tvp = tond.ni_vp; 78238418Smckusick if (tvp != NULL) { 78338418Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 78438418Smckusick error = EISDIR; 78538418Smckusick goto out; 78638418Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 78738418Smckusick error = ENOTDIR; 78838418Smckusick goto out; 78938418Smckusick } 79038418Smckusick } 79138418Smckusick if (fvp->v_mount != tdvp->v_mount) { 79238418Smckusick error = EXDEV; 79338418Smckusick goto out; 79438418Smckusick } 79549742Smckusick if (fvp == tdvp) 79638418Smckusick error = EINVAL; 79749742Smckusick /* 79849742Smckusick * If source is the same as the destination (that is the 79949742Smckusick * same vnode with the same name in the same directory), 80049742Smckusick * then there is nothing to do. 80149742Smckusick */ 80249742Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 80349742Smckusick fromnd.ni_namelen == tond.ni_namelen && 80449742Smckusick !bcmp(fromnd.ni_ptr, tond.ni_ptr, fromnd.ni_namelen)) 80549742Smckusick error = -1; 80638418Smckusick out: 80742467Smckusick if (!error) { 80849742Smckusick error = VOP_RENAME(&fromnd, &tond, p); 80942467Smckusick } else { 81042467Smckusick VOP_ABORTOP(&tond); 81143359Smckusick if (tdvp == tvp) 81243359Smckusick vrele(tdvp); 81343359Smckusick else 81443359Smckusick vput(tdvp); 81542467Smckusick if (tvp) 81642467Smckusick vput(tvp); 81749742Smckusick VOP_ABORTOP(&fromnd); 81849742Smckusick vrele(fromnd.ni_dvp); 81942467Smckusick vrele(fvp); 82038418Smckusick } 82146513Smckusick vrele(tond.ni_startdir); 82249742Smckusick FREE(tond.ni_pnbuf, M_NAMEI); 82338418Smckusick out1: 82449742Smckusick vrele(fromnd.ni_startdir); 82549742Smckusick FREE(fromnd.ni_pnbuf, M_NAMEI); 82638418Smckusick nfsm_reply(0); 82738418Smckusick return (error); 82849742Smckusick 82938418Smckusick nfsmout: 83049742Smckusick if (tond.ni_nameiop) { 83149742Smckusick vrele(tond.ni_startdir); 83249742Smckusick FREE(tond.ni_pnbuf, M_NAMEI); 83349742Smckusick } 83449742Smckusick if (fromnd.ni_nameiop) { 83549742Smckusick vrele(fromnd.ni_startdir); 83649742Smckusick FREE(fromnd.ni_pnbuf, M_NAMEI); 83749742Smckusick VOP_ABORTOP(&fromnd); 83849742Smckusick vrele(fromnd.ni_dvp); 83949742Smckusick vrele(fvp); 84049742Smckusick } 84138418Smckusick return (error); 84238418Smckusick } 84338418Smckusick 84438418Smckusick /* 84538418Smckusick * nfs link service 84638418Smckusick */ 84748050Smckusick nfsrv_link(mrep, md, dpos, cred, xid, mrq, repstat, p) 84838418Smckusick struct mbuf *mrep, *md, **mrq; 84938418Smckusick caddr_t dpos; 85038418Smckusick struct ucred *cred; 85139753Smckusick u_long xid; 85239753Smckusick int *repstat; 85348050Smckusick struct proc *p; 85438418Smckusick { 85549742Smckusick struct nameidata nd; 85648050Smckusick register u_long *tl; 85739494Smckusick register long t1; 85839494Smckusick caddr_t bpos; 85939494Smckusick int error = 0; 86039494Smckusick char *cp2; 86139753Smckusick struct mbuf *mb, *mreq; 86238418Smckusick struct vnode *vp, *xp; 86338418Smckusick nfsv2fh_t nfh, dnfh; 86438418Smckusick fhandle_t *fhp, *dfhp; 86538418Smckusick long len; 86638418Smckusick 86738418Smckusick fhp = &nfh.fh_generic; 86838418Smckusick dfhp = &dnfh.fh_generic; 86938418Smckusick nfsm_srvmtofh(fhp); 87038418Smckusick nfsm_srvmtofh(dfhp); 87138418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 87238418Smckusick if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred)) 87338418Smckusick nfsm_reply(0); 87438418Smckusick if (vp->v_type == VDIR && (error = suser(cred, NULL))) 87538418Smckusick goto out1; 87649742Smckusick nd.ni_cred = cred; 87749742Smckusick nd.ni_nameiop = CREATE | LOCKPARENT; 87849742Smckusick if (error = nfs_namei(&nd, dfhp, len, &md, &dpos, p)) 87938418Smckusick goto out1; 88049742Smckusick xp = nd.ni_vp; 88138418Smckusick if (xp != NULL) { 88238418Smckusick error = EEXIST; 88338418Smckusick goto out; 88438418Smckusick } 88549742Smckusick xp = nd.ni_dvp; 88638418Smckusick if (vp->v_mount != xp->v_mount) 88738418Smckusick error = EXDEV; 88838418Smckusick out: 88942467Smckusick if (!error) { 89049742Smckusick error = VOP_LINK(vp, &nd, p); 89142467Smckusick } else { 89249742Smckusick VOP_ABORTOP(&nd); 89349742Smckusick if (nd.ni_dvp == nd.ni_vp) 89449742Smckusick vrele(nd.ni_dvp); 89543359Smckusick else 89649742Smckusick vput(nd.ni_dvp); 89749742Smckusick if (nd.ni_vp) 89849742Smckusick vrele(nd.ni_vp); 89942467Smckusick } 90038418Smckusick out1: 90138418Smckusick vrele(vp); 90238418Smckusick nfsm_reply(0); 90338418Smckusick nfsm_srvdone; 90438418Smckusick } 90538418Smckusick 90638418Smckusick /* 90738418Smckusick * nfs symbolic link service 90838418Smckusick */ 90948050Smckusick nfsrv_symlink(mrep, md, dpos, cred, xid, mrq, repstat, p) 91038418Smckusick struct mbuf *mrep, *md, **mrq; 91138418Smckusick caddr_t dpos; 91238418Smckusick struct ucred *cred; 91339753Smckusick u_long xid; 91439753Smckusick int *repstat; 91548050Smckusick struct proc *p; 91638418Smckusick { 91738418Smckusick struct vattr va; 91849742Smckusick struct nameidata nd; 91938418Smckusick register struct vattr *vap = &va; 92048050Smckusick register u_long *tl; 92139494Smckusick register long t1; 92245285Smckusick struct nfsv2_sattr *sp; 92339494Smckusick caddr_t bpos; 92441899Smckusick struct uio io; 92541899Smckusick struct iovec iv; 92639494Smckusick int error = 0; 92741899Smckusick char *pathcp, *cp2; 92839753Smckusick struct mbuf *mb, *mreq; 92938418Smckusick nfsv2fh_t nfh; 93038418Smckusick fhandle_t *fhp; 93142242Smckusick long len, len2; 93238418Smckusick 93341899Smckusick pathcp = (char *)0; 93438418Smckusick fhp = &nfh.fh_generic; 93538418Smckusick nfsm_srvmtofh(fhp); 93638418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 93749742Smckusick nd.ni_cred = cred; 93849742Smckusick nd.ni_nameiop = CREATE | LOCKPARENT; 93949742Smckusick if (error = nfs_namei(&nd, fhp, len, &md, &dpos, p)) 94042467Smckusick goto out; 94141899Smckusick nfsm_strsiz(len2, NFS_MAXPATHLEN); 94241899Smckusick MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK); 94341899Smckusick iv.iov_base = pathcp; 94441899Smckusick iv.iov_len = len2; 94541899Smckusick io.uio_resid = len2; 94641899Smckusick io.uio_offset = 0; 94741899Smckusick io.uio_iov = &iv; 94841899Smckusick io.uio_iovcnt = 1; 94941899Smckusick io.uio_segflg = UIO_SYSSPACE; 95041899Smckusick io.uio_rw = UIO_READ; 95148050Smckusick io.uio_procp = (struct proc *)0; 95241899Smckusick nfsm_mtouio(&io, len2); 95345285Smckusick nfsm_disect(sp, struct nfsv2_sattr *, NFSX_SATTR); 95441899Smckusick *(pathcp + len2) = '\0'; 95549742Smckusick if (nd.ni_vp) { 95649742Smckusick VOP_ABORTOP(&nd); 95749742Smckusick if (nd.ni_dvp == nd.ni_vp) 95849742Smckusick vrele(nd.ni_dvp); 95943359Smckusick else 96049742Smckusick vput(nd.ni_dvp); 96149742Smckusick vrele(nd.ni_vp); 96238418Smckusick error = EEXIST; 96338418Smckusick goto out; 96438418Smckusick } 96541361Smckusick VATTR_NULL(vap); 96645285Smckusick vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode); 96749742Smckusick error = VOP_SYMLINK(&nd, vap, pathcp, p); 96838418Smckusick out: 96941899Smckusick if (pathcp) 97041899Smckusick FREE(pathcp, M_TEMP); 97138418Smckusick nfsm_reply(0); 97238418Smckusick return (error); 97338418Smckusick nfsmout: 97449742Smckusick VOP_ABORTOP(&nd); 97549742Smckusick if (nd.ni_dvp == nd.ni_vp) 97649742Smckusick vrele(nd.ni_dvp); 97743359Smckusick else 97849742Smckusick vput(nd.ni_dvp); 97949742Smckusick if (nd.ni_vp) 98049742Smckusick vrele(nd.ni_vp); 98141899Smckusick if (pathcp) 98241899Smckusick FREE(pathcp, M_TEMP); 98338418Smckusick return (error); 98438418Smckusick } 98538418Smckusick 98638418Smckusick /* 98738418Smckusick * nfs mkdir service 98838418Smckusick */ 98948050Smckusick nfsrv_mkdir(mrep, md, dpos, cred, xid, mrq, repstat, p) 99038418Smckusick struct mbuf *mrep, *md, **mrq; 99138418Smckusick caddr_t dpos; 99238418Smckusick struct ucred *cred; 99339753Smckusick u_long xid; 99439753Smckusick int *repstat; 99548050Smckusick struct proc *p; 99638418Smckusick { 99738418Smckusick struct vattr va; 99838418Smckusick register struct vattr *vap = &va; 99938884Smacklem register struct nfsv2_fattr *fp; 100049742Smckusick struct nameidata nd; 100139494Smckusick register caddr_t cp; 100248050Smckusick register u_long *tl; 100339494Smckusick register long t1; 100439494Smckusick caddr_t bpos; 100539494Smckusick int error = 0; 100639494Smckusick char *cp2; 100739753Smckusick struct mbuf *mb, *mb2, *mreq; 100838418Smckusick struct vnode *vp; 100938418Smckusick nfsv2fh_t nfh; 101038418Smckusick fhandle_t *fhp; 101138418Smckusick long len; 101238418Smckusick 101338418Smckusick fhp = &nfh.fh_generic; 101438418Smckusick nfsm_srvmtofh(fhp); 101538418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 101649742Smckusick nd.ni_cred = cred; 101749742Smckusick nd.ni_nameiop = CREATE | LOCKPARENT; 101849742Smckusick if (error = nfs_namei(&nd, fhp, len, &md, &dpos, p)) 101938418Smckusick nfsm_reply(0); 102048050Smckusick nfsm_disect(tl, u_long *, NFSX_UNSIGNED); 102141361Smckusick VATTR_NULL(vap); 102238418Smckusick vap->va_type = VDIR; 102348050Smckusick vap->va_mode = nfstov_mode(*tl++); 102449742Smckusick vp = nd.ni_vp; 102538418Smckusick if (vp != NULL) { 102649742Smckusick VOP_ABORTOP(&nd); 102749742Smckusick if (nd.ni_dvp == vp) 102849742Smckusick vrele(nd.ni_dvp); 102943359Smckusick else 103049742Smckusick vput(nd.ni_dvp); 103142467Smckusick vrele(vp); 103238418Smckusick error = EEXIST; 103338418Smckusick nfsm_reply(0); 103438418Smckusick } 103549742Smckusick if (error = VOP_MKDIR(&nd, vap, p)) 103638418Smckusick nfsm_reply(0); 103749742Smckusick vp = nd.ni_vp; 103838418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 103941398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 104038418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 104138418Smckusick vput(vp); 104238418Smckusick nfsm_reply(0); 104338418Smckusick } 104448050Smckusick error = VOP_GETATTR(vp, vap, cred, p); 104538418Smckusick vput(vp); 104638418Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR); 104738418Smckusick nfsm_srvfhtom(fhp); 104838884Smacklem nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 104939753Smckusick nfsm_srvfillattr; 105038418Smckusick return (error); 105138418Smckusick nfsmout: 105249742Smckusick VOP_ABORTOP(&nd); 105349742Smckusick if (nd.ni_dvp == nd.ni_vp) 105449742Smckusick vrele(nd.ni_dvp); 105543359Smckusick else 105649742Smckusick vput(nd.ni_dvp); 105749742Smckusick if (nd.ni_vp) 105849742Smckusick vrele(nd.ni_vp); 105938418Smckusick return (error); 106038418Smckusick } 106138418Smckusick 106238418Smckusick /* 106338418Smckusick * nfs rmdir service 106438418Smckusick */ 106548050Smckusick nfsrv_rmdir(mrep, md, dpos, cred, xid, mrq, repstat, p) 106638418Smckusick struct mbuf *mrep, *md, **mrq; 106738418Smckusick caddr_t dpos; 106838418Smckusick struct ucred *cred; 106939753Smckusick u_long xid; 107039753Smckusick int *repstat; 107148050Smckusick struct proc *p; 107238418Smckusick { 107348050Smckusick register u_long *tl; 107439494Smckusick register long t1; 107539494Smckusick caddr_t bpos; 107639494Smckusick int error = 0; 107739494Smckusick char *cp2; 107839753Smckusick struct mbuf *mb, *mreq; 107938418Smckusick struct vnode *vp; 108038418Smckusick nfsv2fh_t nfh; 108138418Smckusick fhandle_t *fhp; 108238418Smckusick long len; 108349742Smckusick struct nameidata nd; 108438418Smckusick 108538418Smckusick fhp = &nfh.fh_generic; 108638418Smckusick nfsm_srvmtofh(fhp); 108738418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 108849742Smckusick nd.ni_cred = cred; 108949742Smckusick nd.ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 109049742Smckusick if (error = nfs_namei(&nd, fhp, len, &md, &dpos, p)) 109138418Smckusick nfsm_reply(0); 109249742Smckusick vp = nd.ni_vp; 109338418Smckusick if (vp->v_type != VDIR) { 109438418Smckusick error = ENOTDIR; 109538418Smckusick goto out; 109638418Smckusick } 109738418Smckusick /* 109838418Smckusick * No rmdir "." please. 109938418Smckusick */ 110049742Smckusick if (nd.ni_dvp == vp) { 110138418Smckusick error = EINVAL; 110238418Smckusick goto out; 110338418Smckusick } 110438418Smckusick /* 110549454Smckusick * The root of a mounted filesystem cannot be deleted. 110638418Smckusick */ 110738418Smckusick if (vp->v_flag & VROOT) 110838418Smckusick error = EBUSY; 110938418Smckusick out: 111042467Smckusick if (!error) { 111149742Smckusick error = VOP_RMDIR(&nd, p); 111242467Smckusick } else { 111349742Smckusick VOP_ABORTOP(&nd); 111449742Smckusick if (nd.ni_dvp == nd.ni_vp) 111549742Smckusick vrele(nd.ni_dvp); 111643359Smckusick else 111749742Smckusick vput(nd.ni_dvp); 111842467Smckusick vput(vp); 111942467Smckusick } 112038418Smckusick nfsm_reply(0); 112138418Smckusick nfsm_srvdone; 112238418Smckusick } 112338418Smckusick 112438418Smckusick /* 112538418Smckusick * nfs readdir service 112638418Smckusick * - mallocs what it thinks is enough to read 112748050Smckusick * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR 112838418Smckusick * - calls VOP_READDIR() 112940115Smckusick * - loops around building the reply 113038425Smckusick * if the output generated exceeds count break out of loop 113138425Smckusick * The nfsm_clget macro is used here so that the reply will be packed 113238425Smckusick * tightly in mbuf clusters. 113338418Smckusick * - it only knows that it has encountered eof when the VOP_READDIR() 113438425Smckusick * reads nothing 113538418Smckusick * - as such one readdir rpc will return eof false although you are there 113638425Smckusick * and then the next will return eof 113738418Smckusick * - it trims out records with d_ino == 0 113838425Smckusick * this doesn't matter for Unix clients, but they might confuse clients 113938425Smckusick * for other os'. 114038418Smckusick * NB: It is tempting to set eof to true if the VOP_READDIR() reads less 114138425Smckusick * than requested, but this may not apply to all filesystems. For 114238425Smckusick * example, client NFS does not { although it is never remote mounted 114338425Smckusick * anyhow } 114438418Smckusick * PS: The NFS protocol spec. does not clarify what the "count" byte 114538425Smckusick * argument is a count of.. just name strings and file id's or the 114638425Smckusick * entire reply rpc or ... 114738425Smckusick * I tried just file name and id sizes and it confused the Sun client, 114838425Smckusick * so I am using the full rpc size now. The "paranoia.." comment refers 114938425Smckusick * to including the status longwords that are not a part of the dir. 115038425Smckusick * "entry" structures, but are in the rpc. 115138418Smckusick */ 115248050Smckusick nfsrv_readdir(mrep, md, dpos, cred, xid, mrq, repstat, p) 115338418Smckusick struct mbuf **mrq; 115438418Smckusick struct mbuf *mrep, *md; 115538418Smckusick caddr_t dpos; 115638418Smckusick struct ucred *cred; 115738418Smckusick u_long xid; 115839753Smckusick int *repstat; 115948050Smckusick struct proc *p; 116038418Smckusick { 116138418Smckusick register char *bp, *be; 116238418Smckusick register struct mbuf *mp; 116338418Smckusick register struct direct *dp; 116439494Smckusick register caddr_t cp; 116548050Smckusick register u_long *tl; 116639494Smckusick register long t1; 116739494Smckusick caddr_t bpos; 116839494Smckusick int error = 0; 116939494Smckusick char *cp2; 117039753Smckusick struct mbuf *mb, *mb2, *mreq; 117138418Smckusick char *cpos, *cend; 117238418Smckusick int len, nlen, rem, xfer, tsiz, i; 117338418Smckusick struct vnode *vp; 117438418Smckusick struct mbuf *mp2, *mp3; 117538418Smckusick nfsv2fh_t nfh; 117638418Smckusick fhandle_t *fhp; 117738418Smckusick struct uio io; 117838418Smckusick struct iovec iv; 117940296Smckusick int siz, cnt, fullsiz, eofflag; 118038418Smckusick u_long on; 118138418Smckusick char *rbuf; 118238418Smckusick off_t off, toff; 118338418Smckusick 118438418Smckusick fhp = &nfh.fh_generic; 118538418Smckusick nfsm_srvmtofh(fhp); 118648050Smckusick nfsm_disect(tl, u_long *, 2*NFSX_UNSIGNED); 118748050Smckusick toff = fxdr_unsigned(off_t, *tl++); 118848050Smckusick off = (toff & ~(NFS_DIRBLKSIZ-1)); 118948050Smckusick on = (toff & (NFS_DIRBLKSIZ-1)); 119048050Smckusick cnt = fxdr_unsigned(int, *tl); 119148050Smckusick siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); 119241899Smckusick if (cnt > NFS_MAXREADDIR) 119341899Smckusick siz = NFS_MAXREADDIR; 119438418Smckusick fullsiz = siz; 119538418Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) 119638418Smckusick nfsm_reply(0); 119748050Smckusick if (error = nfsrv_access(vp, VEXEC, cred, p)) { 119838418Smckusick vput(vp); 119938418Smckusick nfsm_reply(0); 120038418Smckusick } 120138418Smckusick VOP_UNLOCK(vp); 120238418Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 120338418Smckusick again: 120438418Smckusick iv.iov_base = rbuf; 120538418Smckusick iv.iov_len = fullsiz; 120638418Smckusick io.uio_iov = &iv; 120738418Smckusick io.uio_iovcnt = 1; 120838418Smckusick io.uio_offset = off; 120938418Smckusick io.uio_resid = fullsiz; 121038418Smckusick io.uio_segflg = UIO_SYSSPACE; 121138418Smckusick io.uio_rw = UIO_READ; 121248050Smckusick io.uio_procp = (struct proc *)0; 121340296Smckusick error = VOP_READDIR(vp, &io, cred, &eofflag); 121439586Smckusick off = io.uio_offset; 121538418Smckusick if (error) { 121638418Smckusick vrele(vp); 121738418Smckusick free((caddr_t)rbuf, M_TEMP); 121838418Smckusick nfsm_reply(0); 121938418Smckusick } 122038418Smckusick if (io.uio_resid) { 122138418Smckusick siz -= io.uio_resid; 122238418Smckusick 122338418Smckusick /* 122438418Smckusick * If nothing read, return eof 122538418Smckusick * rpc reply 122638418Smckusick */ 122738418Smckusick if (siz == 0) { 122838418Smckusick vrele(vp); 122938418Smckusick nfsm_reply(2*NFSX_UNSIGNED); 123048050Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 123148050Smckusick *tl++ = nfs_false; 123248050Smckusick *tl = nfs_true; 123338418Smckusick FREE((caddr_t)rbuf, M_TEMP); 123438418Smckusick return (0); 123538418Smckusick } 123638418Smckusick } 123740115Smckusick 123838418Smckusick /* 123938418Smckusick * Check for degenerate cases of nothing useful read. 124040115Smckusick * If so go try again 124138418Smckusick */ 124240115Smckusick cpos = rbuf + on; 124340115Smckusick cend = rbuf + siz; 124440115Smckusick dp = (struct direct *)cpos; 124540115Smckusick while (cpos < cend && dp->d_ino == 0) { 124640115Smckusick cpos += dp->d_reclen; 124740115Smckusick dp = (struct direct *)cpos; 124840115Smckusick } 124940115Smckusick if (cpos >= cend) { 125038418Smckusick toff = off; 125138418Smckusick siz = fullsiz; 125238418Smckusick on = 0; 125338418Smckusick goto again; 125438418Smckusick } 125540115Smckusick 125640115Smckusick cpos = rbuf + on; 125740115Smckusick cend = rbuf + siz; 125840115Smckusick dp = (struct direct *)cpos; 125938418Smckusick vrele(vp); 126038425Smckusick len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 126138418Smckusick bp = be = (caddr_t)0; 126238418Smckusick mp3 = (struct mbuf *)0; 126338418Smckusick nfsm_reply(siz); 126438418Smckusick 126538418Smckusick /* Loop through the records and build reply */ 126638418Smckusick while (cpos < cend) { 126738418Smckusick if (dp->d_ino != 0) { 126838418Smckusick nlen = dp->d_namlen; 126938418Smckusick rem = nfsm_rndup(nlen)-nlen; 127038425Smckusick 127138418Smckusick /* 127238418Smckusick * As noted above, the NFS spec. is not clear about what 127338418Smckusick * should be included in "count" as totalled up here in 127438418Smckusick * "len". 127538418Smckusick */ 127638418Smckusick len += (4*NFSX_UNSIGNED+nlen+rem); 127741899Smckusick if (len > cnt) { 127841899Smckusick eofflag = 0; 127938418Smckusick break; 128041899Smckusick } 128138425Smckusick 128238418Smckusick /* Build the directory record xdr from the direct entry */ 128338418Smckusick nfsm_clget; 128448050Smckusick *tl = nfs_true; 128538418Smckusick bp += NFSX_UNSIGNED; 128638418Smckusick nfsm_clget; 128748050Smckusick *tl = txdr_unsigned(dp->d_ino); 128838418Smckusick bp += NFSX_UNSIGNED; 128938418Smckusick nfsm_clget; 129048050Smckusick *tl = txdr_unsigned(nlen); 129138418Smckusick bp += NFSX_UNSIGNED; 129238425Smckusick 129338418Smckusick /* And loop arround copying the name */ 129438418Smckusick xfer = nlen; 129538418Smckusick cp = dp->d_name; 129638418Smckusick while (xfer > 0) { 129738418Smckusick nfsm_clget; 129838418Smckusick if ((bp+xfer) > be) 129938418Smckusick tsiz = be-bp; 130038418Smckusick else 130138418Smckusick tsiz = xfer; 130238418Smckusick bcopy(cp, bp, tsiz); 130338418Smckusick bp += tsiz; 130438418Smckusick xfer -= tsiz; 130538418Smckusick if (xfer > 0) 130638418Smckusick cp += tsiz; 130738418Smckusick } 130838418Smckusick /* And null pad to a long boundary */ 130938418Smckusick for (i = 0; i < rem; i++) 131038418Smckusick *bp++ = '\0'; 131138418Smckusick nfsm_clget; 131238425Smckusick 131338418Smckusick /* Finish off the record */ 131438418Smckusick toff += dp->d_reclen; 131548050Smckusick *tl = txdr_unsigned(toff); 131638418Smckusick bp += NFSX_UNSIGNED; 131738418Smckusick } else 131838418Smckusick toff += dp->d_reclen; 131938418Smckusick cpos += dp->d_reclen; 132038418Smckusick dp = (struct direct *)cpos; 132138418Smckusick } 132238418Smckusick nfsm_clget; 132348050Smckusick *tl = nfs_false; 132438418Smckusick bp += NFSX_UNSIGNED; 132538418Smckusick nfsm_clget; 132640296Smckusick if (eofflag) 132748050Smckusick *tl = nfs_true; 132840296Smckusick else 132948050Smckusick *tl = nfs_false; 133038418Smckusick bp += NFSX_UNSIGNED; 133138418Smckusick if (bp < be) 133238418Smckusick mp->m_len = bp-mtod(mp, caddr_t); 133338418Smckusick mb->m_next = mp3; 133438418Smckusick FREE(rbuf, M_TEMP); 133538418Smckusick nfsm_srvdone; 133638418Smckusick } 133738418Smckusick 133838418Smckusick /* 133938418Smckusick * nfs statfs service 134038418Smckusick */ 134148050Smckusick nfsrv_statfs(mrep, md, dpos, cred, xid, mrq, repstat, p) 134238418Smckusick struct mbuf **mrq; 134338418Smckusick struct mbuf *mrep, *md; 134438418Smckusick caddr_t dpos; 134538418Smckusick struct ucred *cred; 134638418Smckusick u_long xid; 134739753Smckusick int *repstat; 134848050Smckusick struct proc *p; 134938418Smckusick { 135038418Smckusick register struct statfs *sf; 135138884Smacklem register struct nfsv2_statfs *sfp; 135248050Smckusick register u_long *tl; 135339494Smckusick register long t1; 135439494Smckusick caddr_t bpos; 135539494Smckusick int error = 0; 135639494Smckusick char *cp2; 135739753Smckusick struct mbuf *mb, *mb2, *mreq; 135838418Smckusick struct vnode *vp; 135938418Smckusick nfsv2fh_t nfh; 136038418Smckusick fhandle_t *fhp; 136138418Smckusick struct statfs statfs; 136238418Smckusick 136338418Smckusick fhp = &nfh.fh_generic; 136438418Smckusick nfsm_srvmtofh(fhp); 136538418Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) 136638418Smckusick nfsm_reply(0); 136738418Smckusick sf = &statfs; 136848050Smckusick error = VFS_STATFS(vp->v_mount, sf, p); 136938418Smckusick vput(vp); 137038418Smckusick nfsm_reply(NFSX_STATFS); 137138884Smacklem nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS); 137244993Sbostic sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA); 1373*51940Smckusick sfp->sf_bsize = txdr_unsigned(sf->f_bsize); 137438884Smacklem sfp->sf_blocks = txdr_unsigned(sf->f_blocks); 137538884Smacklem sfp->sf_bfree = txdr_unsigned(sf->f_bfree); 137638884Smacklem sfp->sf_bavail = txdr_unsigned(sf->f_bavail); 137738418Smckusick nfsm_srvdone; 137838418Smckusick } 137938418Smckusick 138038418Smckusick /* 138138418Smckusick * Null operation, used by clients to ping server 138238418Smckusick */ 138339494Smckusick /* ARGSUSED */ 138448050Smckusick nfsrv_null(mrep, md, dpos, cred, xid, mrq, repstat, p) 138538418Smckusick struct mbuf **mrq; 138638418Smckusick struct mbuf *mrep, *md; 138738418Smckusick caddr_t dpos; 138838418Smckusick struct ucred *cred; 138938418Smckusick u_long xid; 139039753Smckusick int *repstat; 139148050Smckusick struct proc *p; 139238418Smckusick { 139339494Smckusick caddr_t bpos; 139439494Smckusick int error = 0; 139539753Smckusick struct mbuf *mb, *mreq; 139638418Smckusick 139738418Smckusick error = VNOVAL; 139838418Smckusick nfsm_reply(0); 139939494Smckusick return (error); 140038418Smckusick } 140138418Smckusick 140238418Smckusick /* 140338418Smckusick * No operation, used for obsolete procedures 140438418Smckusick */ 140539494Smckusick /* ARGSUSED */ 140648050Smckusick nfsrv_noop(mrep, md, dpos, cred, xid, mrq, repstat, p) 140738418Smckusick struct mbuf **mrq; 140838418Smckusick struct mbuf *mrep, *md; 140938418Smckusick caddr_t dpos; 141038418Smckusick struct ucred *cred; 141138418Smckusick u_long xid; 141239753Smckusick int *repstat; 141348050Smckusick struct proc *p; 141438418Smckusick { 141539494Smckusick caddr_t bpos; 141639494Smckusick int error = 0; 141739753Smckusick struct mbuf *mb, *mreq; 141838418Smckusick 141938418Smckusick error = EPROCUNAVAIL; 142038418Smckusick nfsm_reply(0); 142139494Smckusick return (error); 142238418Smckusick } 142338425Smckusick 142438450Smckusick /* 142538450Smckusick * Perform access checking for vnodes obtained from file handles that would 142638450Smckusick * refer to files already opened by a Unix client. You cannot just use 142738450Smckusick * vn_writechk() and VOP_ACCESS() for two reasons. 142841398Smckusick * 1 - You must check for MNT_EXRDONLY as well as MNT_RDONLY for the write case 142938450Smckusick * 2 - The owner is to be given access irrespective of mode bits so that 143038450Smckusick * processes that chmod after opening a file don't break. I don't like 143138450Smckusick * this because it opens a security hole, but since the nfs server opens 143238450Smckusick * a security hole the size of a barn door anyhow, what the heck. 143338450Smckusick */ 143448050Smckusick nfsrv_access(vp, flags, cred, p) 143538450Smckusick register struct vnode *vp; 143638450Smckusick int flags; 143738450Smckusick register struct ucred *cred; 143848050Smckusick struct proc *p; 143938450Smckusick { 144038450Smckusick struct vattr vattr; 144138450Smckusick int error; 144238450Smckusick if (flags & VWRITE) { 144341398Smckusick /* Just vn_writechk() changed to check MNT_EXRDONLY */ 144438450Smckusick /* 144538450Smckusick * Disallow write attempts on read-only file systems; 144638450Smckusick * unless the file is a socket or a block or character 144738450Smckusick * device resident on the file system. 144838450Smckusick */ 144945059Smckusick if (vp->v_mount->mnt_flag & (MNT_RDONLY | MNT_EXRDONLY)) { 145045059Smckusick switch (vp->v_type) { 145145059Smckusick case VREG: case VDIR: case VLNK: 145238450Smckusick return (EROFS); 145345059Smckusick } 145445059Smckusick } 145538450Smckusick /* 145638450Smckusick * If there's shared text associated with 145738450Smckusick * the inode, try to free it up once. If 145838450Smckusick * we fail, we can't allow writing. 145938450Smckusick */ 146045715Smckusick if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) 146138450Smckusick return (ETXTBSY); 146238450Smckusick } 146348050Smckusick if (error = VOP_GETATTR(vp, &vattr, cred, p)) 146445059Smckusick return (error); 146548050Smckusick if ((error = VOP_ACCESS(vp, flags, cred, p)) && 146645059Smckusick cred->cr_uid != vattr.va_uid) 146745059Smckusick return (error); 146845059Smckusick return (0); 146938450Smckusick } 1470