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 * 838418Smckusick * Redistribution and use in source and binary forms are permitted 938418Smckusick * provided that the above copyright notice and this paragraph are 1038418Smckusick * duplicated in all such forms and that any documentation, 1138418Smckusick * advertising materials, and other materials related to such 1238418Smckusick * distribution and use acknowledge that the software was developed 1338418Smckusick * by the University of California, Berkeley. The name of the 1438418Smckusick * University may not be used to endorse or promote products derived 1538418Smckusick * from this software without specific prior written permission. 1638418Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1738418Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1838418Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1938418Smckusick * 20*38451Smckusick * @(#)nfs_serv.c 7.5 (Berkeley) 07/16/89 2138418Smckusick */ 2238418Smckusick 2338418Smckusick /* 2438418Smckusick * nfs version 2 server calls to vnode ops 2538418Smckusick * - these routines generally have 3 phases 2638418Smckusick * 1 - break down and validate rpc request in mbuf list 2738418Smckusick * 2 - do the vnode ops for the request 2838425Smckusick * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c) 2938418Smckusick * 3 - build the rpc reply in an mbuf list 3038418Smckusick * nb: 3138418Smckusick * - do not mix the phases, since the nfsm_?? macros can return failures 3238418Smckusick * on mbuf exhaustion or similar and do not do any vrele() or vput()'s 3338418Smckusick * 3438425Smckusick * - the nfsm_reply() macro generates an nfs rpc reply with the nfs 3538418Smckusick * error number iff error != 0 whereas 3638425Smckusick * nfsm_srverr simply drops the mbufs and gives up 3738425Smckusick * (==> nfsm_srverr implies an error here at the server, usually mbuf 3838418Smckusick * exhaustion) 3938418Smckusick */ 4038418Smckusick 4138418Smckusick #include "strings.h" 4238418Smckusick #include "time.h" 4338418Smckusick #include "param.h" 4438418Smckusick #include "mount.h" 4538418Smckusick #include "malloc.h" 4638418Smckusick #include "mbuf.h" 4738418Smckusick #include "file.h" 4838418Smckusick #include "user.h" 4938418Smckusick #include "../ufs/dir.h" 5038418Smckusick #include "vnode.h" 5138418Smckusick #include "uio.h" 5238418Smckusick #include "ucred.h" 5338418Smckusick #include "namei.h" 5438418Smckusick #include "errno.h" 5538418Smckusick #include "../ufs/inode.h" 5638418Smckusick #include "nfsv2.h" 5738418Smckusick #include "nfs.h" 5838418Smckusick #include "xdr_subs.h" 5938418Smckusick #include "nfsm_subs.h" 6038418Smckusick 6138418Smckusick /* Defs */ 6238425Smckusick #define TRUE 1 6338425Smckusick #define FALSE 0 6438418Smckusick 6538418Smckusick /* Global vars */ 6638418Smckusick extern u_long nfs_procids[NFS_NPROCS]; 6738418Smckusick extern u_long nfs_xdrneg1; 6838418Smckusick extern u_long nfs_false, nfs_true; 6938418Smckusick nfstype nfs_type[VSOCK+1]={ NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, }; 7038418Smckusick 7138418Smckusick /* 7238418Smckusick * nfs getattr service 7338418Smckusick */ 7438418Smckusick nfsrv_getattr(mrep, md, dpos, cred, xid, mrq) 7538418Smckusick struct mbuf **mrq; 7638418Smckusick struct mbuf *mrep, *md; 7738418Smckusick caddr_t dpos; 7838418Smckusick struct ucred *cred; 7938418Smckusick u_long xid; 8038418Smckusick { 8138418Smckusick struct vattr va; 8238418Smckusick register struct vattr *vap = &va; 8338418Smckusick struct vnode *vp; 8438418Smckusick nfsv2fh_t nfh; 8538418Smckusick fhandle_t *fhp; 8638418Smckusick nfsm_srvars; 8738418Smckusick 8838418Smckusick fhp = &nfh.fh_generic; 8938418Smckusick nfsm_srvmtofh(fhp); 9038418Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) 9138418Smckusick nfsm_reply(0); 9238418Smckusick error = VOP_GETATTR(vp, vap, cred); 9338418Smckusick vput(vp); 9438418Smckusick nfsm_reply(NFSX_FATTR); 9538418Smckusick nfsm_build(p, u_long *, NFSX_FATTR); 9638418Smckusick *p++ = vtonfs_type(vap->va_type); 9738418Smckusick *p++ = vtonfs_mode(vap->va_type, vap->va_mode); 9838418Smckusick *p++ = txdr_unsigned(vap->va_nlink); 9938418Smckusick *p++ = txdr_unsigned(vap->va_uid); 10038418Smckusick *p++ = txdr_unsigned(vap->va_gid); 10138418Smckusick *p++ = txdr_unsigned(vap->va_size); 10238418Smckusick *p++ = txdr_unsigned(vap->va_blocksize); 10338418Smckusick *p++ = txdr_unsigned(vap->va_rdev); 10438418Smckusick *p++ = txdr_unsigned(vap->va_bytes); 10538418Smckusick *p++ = txdr_unsigned(vap->va_fsid); 10638418Smckusick *p++ = txdr_unsigned(vap->va_fileid); 10738418Smckusick txdr_time(&(vap->va_atime), p); 10838418Smckusick p += 2; 10938418Smckusick txdr_time(&(vap->va_mtime), p); 11038418Smckusick p += 2; 11138418Smckusick txdr_time(&(vap->va_ctime), p); 11238418Smckusick nfsm_srvdone; 11338418Smckusick } 11438418Smckusick 11538418Smckusick /* 11638418Smckusick * nfs setattr service 11738418Smckusick */ 11838418Smckusick nfsrv_setattr(mrep, md, dpos, cred, xid, mrq) 11938418Smckusick struct mbuf **mrq; 12038418Smckusick struct mbuf *mrep, *md; 12138418Smckusick caddr_t dpos; 12238418Smckusick struct ucred *cred; 12338418Smckusick u_long xid; 12438418Smckusick { 12538418Smckusick struct vattr va; 12638418Smckusick register struct vattr *vap = &va; 12738418Smckusick struct vnode *vp; 12838418Smckusick nfsv2fh_t nfh; 12938418Smckusick fhandle_t *fhp; 13038418Smckusick nfsm_srvars; 13138418Smckusick 13238418Smckusick fhp = &nfh.fh_generic; 13338418Smckusick nfsm_srvmtofh(fhp); 13438418Smckusick nfsm_disect(p, u_long *, NFSX_SATTR); 13538418Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) 13638418Smckusick nfsm_reply(0); 13738450Smckusick if (error = nfsrv_access(vp, VWRITE, cred)) 13838418Smckusick goto out; 13938418Smckusick vattr_null(vap); 14038418Smckusick /* 14138418Smckusick * Nah nah nah nah na nah 14238418Smckusick * There is a bug in the Sun client that puts 0xffff in the mode 14338418Smckusick * field of sattr when it should put in 0xffffffff. The u_short 14438418Smckusick * doesn't sign extend. 14538418Smckusick * --> check the low order 2 bytes for 0xffff 14638418Smckusick */ 14738418Smckusick if ((fxdr_unsigned(int, *p) & 0xffff) != 0xffff) 14838418Smckusick vap->va_mode = nfstov_mode(*p); 14938418Smckusick if (*++p != nfs_xdrneg1) 15038418Smckusick vap->va_uid = fxdr_unsigned(uid_t, *p); 15138418Smckusick if (*++p != nfs_xdrneg1) 15238418Smckusick vap->va_gid = fxdr_unsigned(gid_t, *p); 15338425Smckusick if (*++p != nfs_xdrneg1) { 15438418Smckusick vap->va_size = fxdr_unsigned(u_long, *p); 15538425Smckusick } 15638418Smckusick if (*++p != nfs_xdrneg1) 15738418Smckusick fxdr_time(p, &(vap->va_atime)); 15838418Smckusick p += 2; 15938418Smckusick if (*p != nfs_xdrneg1) 16038418Smckusick fxdr_time(p, &(vap->va_mtime)); 16138418Smckusick if (error = VOP_SETATTR(vp, vap, cred)) { 16238418Smckusick vput(vp); 16338418Smckusick nfsm_reply(0); 16438418Smckusick } 16538418Smckusick error = VOP_GETATTR(vp, vap, cred); 16638418Smckusick out: 16738418Smckusick vput(vp); 16838418Smckusick nfsm_reply(NFSX_FATTR); 16938418Smckusick nfsm_build(p, u_long *, NFSX_FATTR); 17038418Smckusick *p++ = vtonfs_type(vap->va_type); 17138418Smckusick *p++ = vtonfs_mode(vap->va_type, vap->va_mode); 17238418Smckusick *p++ = txdr_unsigned(vap->va_nlink); 17338418Smckusick *p++ = txdr_unsigned(vap->va_uid); 17438418Smckusick *p++ = txdr_unsigned(vap->va_gid); 17538418Smckusick *p++ = txdr_unsigned(vap->va_size); 17638418Smckusick *p++ = txdr_unsigned(vap->va_blocksize); 17738418Smckusick *p++ = txdr_unsigned(vap->va_rdev); 17838418Smckusick *p++ = txdr_unsigned(vap->va_bytes); 17938418Smckusick *p++ = txdr_unsigned(vap->va_fsid); 18038418Smckusick *p++ = txdr_unsigned(vap->va_fileid); 18138418Smckusick txdr_time(&(vap->va_atime), p); 18238418Smckusick p += 2; 18338418Smckusick txdr_time(&(vap->va_mtime), p); 18438418Smckusick p += 2; 18538418Smckusick txdr_time(&(vap->va_ctime), p); 18638418Smckusick nfsm_srvdone; 18738418Smckusick } 18838418Smckusick 18938418Smckusick /* 19038418Smckusick * nfs lookup rpc 19138418Smckusick */ 19238418Smckusick nfsrv_lookup(mrep, md, dpos, cred, xid, mrq) 19338418Smckusick struct mbuf **mrq; 19438418Smckusick struct mbuf *mrep, *md; 19538418Smckusick caddr_t dpos; 19638418Smckusick struct ucred *cred; 19738418Smckusick u_long xid; 19838418Smckusick { 19938418Smckusick register struct nameidata *ndp = &u.u_nd; 20038418Smckusick struct vnode *vp; 20138418Smckusick nfsv2fh_t nfh; 20238418Smckusick fhandle_t *fhp; 20338418Smckusick nfsm_srvars; 20438418Smckusick long len; 20538418Smckusick struct vattr va, *vap = &va; 20638418Smckusick 20738418Smckusick fhp = &nfh.fh_generic; 20838418Smckusick nfsm_srvmtofh(fhp); 20938418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 21038418Smckusick ndp->ni_cred = cred; 21138418Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 21238418Smckusick if (error = nfs_namei(ndp, fhp, len, &md, &dpos)) 21338418Smckusick nfsm_reply(0); 21438418Smckusick vp = ndp->ni_vp; 21538418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 21638418Smckusick fhp->fh_fsid = vp->v_mount->m_fsid; 21738418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 21838418Smckusick vput(vp); 21938418Smckusick nfsm_reply(0); 22038418Smckusick } 22138418Smckusick error = VOP_GETATTR(vp, vap, cred); 22238418Smckusick vput(vp); 22338418Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR); 22438418Smckusick nfsm_srvfhtom(fhp); 22538418Smckusick nfsm_build(p, u_long *, NFSX_FATTR); 22638418Smckusick *p++ = vtonfs_type(vap->va_type); 22738418Smckusick *p++ = vtonfs_mode(vap->va_type, vap->va_mode); 22838418Smckusick *p++ = txdr_unsigned(vap->va_nlink); 22938418Smckusick *p++ = txdr_unsigned(vap->va_uid); 23038418Smckusick *p++ = txdr_unsigned(vap->va_gid); 23138418Smckusick *p++ = txdr_unsigned(vap->va_size); 23238418Smckusick *p++ = txdr_unsigned(vap->va_blocksize); 23338418Smckusick *p++ = txdr_unsigned(vap->va_rdev); 23438418Smckusick *p++ = txdr_unsigned(vap->va_bytes); 23538418Smckusick *p++ = txdr_unsigned(vap->va_fsid); 23638418Smckusick *p++ = txdr_unsigned(vap->va_fileid); 23738418Smckusick txdr_time(&(vap->va_atime), p); 23838418Smckusick p += 2; 23938418Smckusick txdr_time(&(vap->va_mtime), p); 24038418Smckusick p += 2; 24138418Smckusick txdr_time(&(vap->va_ctime), p); 24238418Smckusick nfsm_srvdone; 24338418Smckusick } 24438418Smckusick 24538418Smckusick /* 24638418Smckusick * nfs readlink service 24738418Smckusick */ 24838418Smckusick nfsrv_readlink(mrep, md, dpos, cred, xid, mrq) 24938418Smckusick struct mbuf **mrq; 25038418Smckusick struct mbuf *mrep, *md; 25138418Smckusick caddr_t dpos; 25238418Smckusick struct ucred *cred; 25338418Smckusick long xid; 25438418Smckusick { 25538418Smckusick struct iovec iv[NFS_MAXPATHLEN/MLEN+1]; 25638418Smckusick register struct iovec *ivp = iv; 25738418Smckusick register struct mbuf *mp; 25838418Smckusick nfsm_srvars; 25938418Smckusick struct mbuf *mp2, *mp3; 26038418Smckusick struct vnode *vp; 26138418Smckusick nfsv2fh_t nfh; 26238418Smckusick fhandle_t *fhp; 26338418Smckusick struct uio io, *uiop = &io; 26438418Smckusick int i, tlen, len; 26538418Smckusick 26638418Smckusick fhp = &nfh.fh_generic; 26738418Smckusick nfsm_srvmtofh(fhp); 26838418Smckusick len = 0; 26938418Smckusick i = 0; 27038418Smckusick while (len < NFS_MAXPATHLEN) { 27138418Smckusick MGET(mp, M_WAIT, MT_DATA); 27238418Smckusick NFSMCLGET(mp, M_WAIT); 27338418Smckusick mp->m_len = NFSMSIZ(mp); 27438418Smckusick if (len == 0) 27538418Smckusick mp3 = mp2 = mp; 27638418Smckusick else 27738418Smckusick mp2->m_next = mp; 27838418Smckusick if ((len+mp->m_len) > NFS_MAXPATHLEN) { 27938418Smckusick mp->m_len = NFS_MAXPATHLEN-len; 28038418Smckusick len = NFS_MAXPATHLEN; 28138418Smckusick } else 28238418Smckusick len += mp->m_len; 28338418Smckusick ivp->iov_base = mtod(mp, caddr_t); 28438418Smckusick ivp->iov_len = mp->m_len; 28538418Smckusick i++; 28638418Smckusick ivp++; 28738418Smckusick } 28838418Smckusick uiop->uio_iov = iv; 28938418Smckusick uiop->uio_iovcnt = i; 29038418Smckusick uiop->uio_offset = 0; 29138418Smckusick uiop->uio_resid = len; 29238418Smckusick uiop->uio_rw = UIO_READ; 29338418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 29438418Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) { 29538418Smckusick m_freem(mp3); 29638418Smckusick nfsm_reply(0); 29738418Smckusick } 29838418Smckusick if (vp->v_type != VLNK) { 29938418Smckusick error = EINVAL; 30038418Smckusick goto out; 30138418Smckusick } 30238418Smckusick error = VOP_READLINK(vp, uiop, cred); 30338418Smckusick out: 30438418Smckusick vput(vp); 30538418Smckusick if (error) 30638418Smckusick m_freem(mp3); 30738418Smckusick nfsm_reply(NFSX_UNSIGNED); 30838418Smckusick if (uiop->uio_resid > 0) { 30938418Smckusick len -= uiop->uio_resid; 31038418Smckusick tlen = nfsm_rndup(len); 31138418Smckusick nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len); 31238418Smckusick } 31338418Smckusick nfsm_build(p, u_long *, NFSX_UNSIGNED); 31438418Smckusick *p = txdr_unsigned(len); 31538418Smckusick mb->m_next = mp3; 31638418Smckusick nfsm_srvdone; 31738418Smckusick } 31838418Smckusick 31938418Smckusick /* 32038418Smckusick * nfs read service 32138418Smckusick */ 32238418Smckusick nfsrv_read(mrep, md, dpos, cred, xid, mrq) 32338418Smckusick struct mbuf **mrq; 32438418Smckusick struct mbuf *mrep, *md; 32538418Smckusick caddr_t dpos; 32638418Smckusick struct ucred *cred; 32738418Smckusick u_long xid; 32838418Smckusick { 32938418Smckusick struct iovec iv[NFS_MAXDATA/MCLBYTES+1]; 33038418Smckusick register struct iovec *ivp = iv; 33138418Smckusick register struct mbuf *mp; 33238418Smckusick nfsm_srvars; 33338418Smckusick struct mbuf *mp2, *mp3; 33438418Smckusick struct vnode *vp; 33538418Smckusick nfsv2fh_t nfh; 33638418Smckusick fhandle_t *fhp; 33738418Smckusick struct uio io, *uiop = &io; 33838418Smckusick struct vattr va, *vap = &va; 33938418Smckusick int i, tlen, cnt, len, nio, left; 34038418Smckusick off_t off; 34138418Smckusick 34238418Smckusick fhp = &nfh.fh_generic; 34338418Smckusick nfsm_srvmtofh(fhp); 34438418Smckusick nfsm_disect(p, u_long *, NFSX_UNSIGNED); 34538418Smckusick off = fxdr_unsigned(off_t, *p); 34638418Smckusick nfsm_srvstrsiz(cnt, NFS_MAXDATA); 34738418Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) 34838418Smckusick nfsm_reply(0); 34938450Smckusick if (error = nfsrv_access(vp, VREAD | VEXEC, cred)) { 35038418Smckusick vput(vp); 35138418Smckusick nfsm_reply(0); 35238418Smckusick } 35338418Smckusick len = left = cnt; 35438418Smckusick nio = (cnt+MCLBYTES-1)/MCLBYTES; 35538418Smckusick uiop->uio_iov = ivp; 35638418Smckusick uiop->uio_iovcnt = nio; 35738418Smckusick uiop->uio_offset = off; 35838418Smckusick uiop->uio_resid = cnt; 35938418Smckusick uiop->uio_rw = UIO_READ; 36038418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 36138418Smckusick for (i = 0; i < nio; i++) { 36238418Smckusick MGET(mp, M_WAIT, MT_DATA); 36338418Smckusick if (left > MLEN) 36438418Smckusick NFSMCLGET(mp, M_WAIT); 36538418Smckusick mp->m_len = (M_HASCL(mp)) ? MCLBYTES : MLEN; 36638418Smckusick if (i == 0) { 36738418Smckusick mp3 = mp2 = mp; 36838418Smckusick } else { 36938418Smckusick mp2->m_next = mp; 37038418Smckusick mp2 = mp; 37138418Smckusick } 37238418Smckusick if (left > MLEN && !M_HASCL(mp)) { 37338418Smckusick m_freem(mp3); 37438418Smckusick vput(vp); 37538418Smckusick nfsm_srverr; 37638418Smckusick } 37738418Smckusick ivp->iov_base = mtod(mp, caddr_t); 37838418Smckusick if (left > mp->m_len) { 37938418Smckusick ivp->iov_len = mp->m_len; 38038418Smckusick left -= mp->m_len; 38138418Smckusick } else { 38238418Smckusick ivp->iov_len = mp->m_len = left; 38338418Smckusick left = 0; 38438418Smckusick } 38538418Smckusick ivp++; 38638418Smckusick } 38738418Smckusick error = VOP_READ(vp, uiop, &off, IO_NODELOCKED, cred); 38838418Smckusick if (error) { 38938418Smckusick m_freem(mp3); 39038418Smckusick vput(vp); 39138418Smckusick nfsm_reply(0); 39238418Smckusick } 39338418Smckusick if (error = VOP_GETATTR(vp, vap, cred)) 39438418Smckusick m_freem(mp3); 39538418Smckusick vput(vp); 39638418Smckusick nfsm_reply(NFSX_FATTR+NFSX_UNSIGNED); 39738418Smckusick nfsm_build(p, u_long *, NFSX_FATTR+NFSX_UNSIGNED); 39838418Smckusick *p++ = vtonfs_type(vap->va_type); 39938418Smckusick *p++ = vtonfs_mode(vap->va_type, vap->va_mode); 40038418Smckusick *p++ = txdr_unsigned(vap->va_nlink); 40138418Smckusick *p++ = txdr_unsigned(vap->va_uid); 40238418Smckusick *p++ = txdr_unsigned(vap->va_gid); 40338418Smckusick *p++ = txdr_unsigned(vap->va_size); 40438418Smckusick *p++ = txdr_unsigned(vap->va_blocksize); 40538418Smckusick *p++ = txdr_unsigned(vap->va_rdev); 40638418Smckusick *p++ = txdr_unsigned(vap->va_bytes); 40738418Smckusick *p++ = txdr_unsigned(vap->va_fsid); 40838418Smckusick *p++ = txdr_unsigned(vap->va_fileid); 40938418Smckusick txdr_time(&(vap->va_atime), p); 41038418Smckusick p += 2; 41138418Smckusick txdr_time(&(vap->va_mtime), p); 41238418Smckusick p += 2; 41338418Smckusick txdr_time(&(vap->va_ctime), p); 41438418Smckusick p += 2; 41538418Smckusick if (uiop->uio_resid > 0) { 41638418Smckusick len -= uiop->uio_resid; 41738418Smckusick if (len > 0) { 41838418Smckusick tlen = nfsm_rndup(len); 41938418Smckusick nfsm_adj(mp3, cnt-tlen, tlen-len); 42038418Smckusick } else { 42138418Smckusick m_freem(mp3); 42238418Smckusick mp3 = (struct mbuf *)0; 42338418Smckusick } 42438418Smckusick } 42538418Smckusick *p = txdr_unsigned(len); 42638418Smckusick mb->m_next = mp3; 42738418Smckusick nfsm_srvdone; 42838418Smckusick } 42938418Smckusick 43038418Smckusick /* 43138418Smckusick * nfs write service 43238418Smckusick */ 43338418Smckusick nfsrv_write(mrep, md, dpos, cred, xid, mrq) 43438418Smckusick struct mbuf *mrep, *md, **mrq; 43538418Smckusick caddr_t dpos; 43638418Smckusick struct ucred *cred; 43738418Smckusick long xid; 43838418Smckusick { 43938418Smckusick register struct iovec *ivp; 44038418Smckusick register struct mbuf *mp; 44138418Smckusick struct iovec iv[MAX_IOVEC]; 44238418Smckusick struct vattr va; 44338418Smckusick register struct vattr *vap = &va; 44438418Smckusick nfsm_srvars; 44538418Smckusick struct vnode *vp; 44638418Smckusick nfsv2fh_t nfh; 44738418Smckusick fhandle_t *fhp; 44838418Smckusick struct uio io, *uiop = &io; 44938418Smckusick off_t off; 45038418Smckusick long siz, len, xfer; 45138418Smckusick 45238418Smckusick fhp = &nfh.fh_generic; 45338418Smckusick nfsm_srvmtofh(fhp); 45438418Smckusick nfsm_disect(p, u_long *, 4*NFSX_UNSIGNED); 45538418Smckusick off = fxdr_unsigned(off_t, *++p); 45638418Smckusick p += 2; 45738418Smckusick len = fxdr_unsigned(long, *p); 45838418Smckusick if (len > NFS_MAXDATA || len <= 0) { 45938418Smckusick error = EBADRPC; 46038418Smckusick nfsm_reply(0); 46138418Smckusick } 46238418Smckusick if (dpos == (mtod(md, caddr_t)+md->m_len)) { 46338418Smckusick mp = md->m_next; 46438418Smckusick if (mp == NULL) { 46538418Smckusick error = EBADRPC; 46638418Smckusick nfsm_reply(0); 46738418Smckusick } 46838418Smckusick } else { 46938418Smckusick mp = md; 47038418Smckusick siz = dpos-mtod(mp, caddr_t); 47138418Smckusick mp->m_len -= siz; 47238418Smckusick NFSMADV(mp, siz); 47338418Smckusick } 47438418Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) 47538418Smckusick nfsm_reply(0); 47638450Smckusick if (error = nfsrv_access(vp, VWRITE, cred)) { 47738418Smckusick vput(vp); 47838418Smckusick nfsm_reply(0); 47938418Smckusick } 48038418Smckusick uiop->uio_resid = 0; 48138418Smckusick uiop->uio_rw = UIO_WRITE; 48238418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 48338418Smckusick /* 48438418Smckusick * Do up to MAX_IOVEC mbufs of write each iteration of the 48538418Smckusick * loop until done. 48638418Smckusick */ 48738418Smckusick while (len > 0 && uiop->uio_resid == 0) { 48838418Smckusick ivp = iv; 48938418Smckusick siz = 0; 49038418Smckusick uiop->uio_iov = ivp; 49138418Smckusick uiop->uio_iovcnt = 0; 49238418Smckusick uiop->uio_offset = off; 49338418Smckusick while (len > 0 && uiop->uio_iovcnt < MAX_IOVEC && mp != NULL) { 49438418Smckusick ivp->iov_base = mtod(mp, caddr_t); 49538418Smckusick if (len < mp->m_len) 49638418Smckusick ivp->iov_len = xfer = len; 49738418Smckusick else 49838418Smckusick ivp->iov_len = xfer = mp->m_len; 49938418Smckusick #ifdef notdef 50038418Smckusick /* Not Yet .. */ 50138418Smckusick if (M_HASCL(mp) && (((u_long)ivp->iov_base) & CLOFSET) == 0) 50238418Smckusick ivp->iov_op = NULL; /* what should it be ?? */ 50338418Smckusick else 50438418Smckusick ivp->iov_op = NULL; 50538418Smckusick #endif 50638418Smckusick uiop->uio_iovcnt++; 50738418Smckusick ivp++; 50838418Smckusick len -= xfer; 50938418Smckusick siz += xfer; 51038418Smckusick mp = mp->m_next; 51138418Smckusick } 51238418Smckusick if (len > 0 && mp == NULL) { 51338418Smckusick error = EBADRPC; 51438418Smckusick vput(vp); 51538418Smckusick nfsm_reply(0); 51638418Smckusick } 51738418Smckusick uiop->uio_resid = siz; 51838418Smckusick if (error = VOP_WRITE(vp, uiop, &off, IO_SYNC | IO_NODELOCKED, 51938418Smckusick cred)) { 52038418Smckusick vput(vp); 52138418Smckusick nfsm_reply(0); 52238418Smckusick } 52338418Smckusick } 52438418Smckusick error = VOP_GETATTR(vp, vap, cred); 52538418Smckusick vput(vp); 52638418Smckusick nfsm_reply(NFSX_FATTR); 52738418Smckusick nfsm_build(p, u_long *, NFSX_FATTR); 52838418Smckusick *p++ = vtonfs_type(vap->va_type); 52938418Smckusick *p++ = vtonfs_mode(vap->va_type, vap->va_mode); 53038418Smckusick *p++ = txdr_unsigned(vap->va_nlink); 53138418Smckusick *p++ = txdr_unsigned(vap->va_uid); 53238418Smckusick *p++ = txdr_unsigned(vap->va_gid); 53338418Smckusick *p++ = txdr_unsigned(vap->va_size); 53438418Smckusick *p++ = txdr_unsigned(vap->va_blocksize); 53538418Smckusick *p++ = txdr_unsigned(vap->va_rdev); 53638418Smckusick *p++ = txdr_unsigned(vap->va_bytes); 53738418Smckusick *p++ = txdr_unsigned(vap->va_fsid); 53838418Smckusick *p++ = txdr_unsigned(vap->va_fileid); 53938418Smckusick txdr_time(&(vap->va_atime), p); 54038418Smckusick p += 2; 54138418Smckusick txdr_time(&(vap->va_mtime), p); 54238418Smckusick p += 2; 54338418Smckusick txdr_time(&(vap->va_ctime), p); 54438418Smckusick nfsm_srvdone; 54538418Smckusick } 54638418Smckusick 54738418Smckusick /* 54838418Smckusick * nfs create service 54938418Smckusick * now does a truncate to 0 length via. setattr if it already exists 55038418Smckusick */ 55138418Smckusick nfsrv_create(mrep, md, dpos, cred, xid, mrq) 55238418Smckusick struct mbuf *mrep, *md, **mrq; 55338418Smckusick caddr_t dpos; 55438418Smckusick struct ucred *cred; 55538418Smckusick long xid; 55638418Smckusick { 55738418Smckusick struct vattr va; 55838418Smckusick register struct vattr *vap = &va; 55938418Smckusick register struct nameidata *ndp = &u.u_nd; 56038418Smckusick nfsm_srvars; 56138418Smckusick struct vnode *vp; 56238418Smckusick nfsv2fh_t nfh; 56338418Smckusick fhandle_t *fhp; 56438418Smckusick long len; 56538418Smckusick 56638418Smckusick ndp->ni_vp = ndp->ni_dvp = (struct vnode *)0; 56738418Smckusick fhp = &nfh.fh_generic; 56838418Smckusick nfsm_srvmtofh(fhp); 56938418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 57038418Smckusick ndp->ni_cred = cred; 57138418Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT | LOCKLEAF; 57238418Smckusick if (error = nfs_namei(ndp, fhp, len, &md, &dpos)) 57338418Smckusick nfsm_reply(0); 57438418Smckusick vattr_null(vap); 57538418Smckusick nfsm_disect(p, u_long *, NFSX_UNSIGNED); 57638418Smckusick /* 57738418Smckusick * Iff doesn't exist, create it 57838418Smckusick * otherwise just truncate to 0 length 57938418Smckusick * should I set the mode too ?? 58038418Smckusick */ 58138418Smckusick if (ndp->ni_vp == NULL) { 58238418Smckusick vap->va_type = VREG; 58338418Smckusick vap->va_mode = nfstov_mode(*p++); 58438418Smckusick if (error = VOP_CREATE(ndp, vap)) 58538418Smckusick nfsm_reply(0); 58638425Smckusick vp = ndp->ni_vp; 58738418Smckusick } else { 58838425Smckusick vp = ndp->ni_vp; 58938425Smckusick ndp->ni_vp = (struct vnode *)0; 59038425Smckusick VOP_ABORTOP(ndp); 59138418Smckusick vap->va_size = 0; 59238425Smckusick if (error = VOP_SETATTR(vp, vap, cred)) 59338418Smckusick nfsm_reply(0); 59438418Smckusick } 59538418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 59638418Smckusick fhp->fh_fsid = vp->v_mount->m_fsid; 59738418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 59838418Smckusick vput(vp); 59938418Smckusick nfsm_reply(0); 60038418Smckusick } 60138418Smckusick error = VOP_GETATTR(vp, vap, cred); 60238418Smckusick vput(vp); 60338418Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR); 60438418Smckusick nfsm_srvfhtom(fhp); 60538418Smckusick nfsm_build(p, u_long *, NFSX_FATTR); 60638418Smckusick *p++ = vtonfs_type(vap->va_type); 60738418Smckusick *p++ = vtonfs_mode(vap->va_type, vap->va_mode); 60838418Smckusick *p++ = txdr_unsigned(vap->va_nlink); 60938418Smckusick *p++ = txdr_unsigned(vap->va_uid); 61038418Smckusick *p++ = txdr_unsigned(vap->va_gid); 61138418Smckusick *p++ = txdr_unsigned(vap->va_size); 61238418Smckusick *p++ = txdr_unsigned(vap->va_blocksize); 61338418Smckusick *p++ = txdr_unsigned(vap->va_rdev); 61438418Smckusick *p++ = txdr_unsigned(vap->va_bytes); 61538418Smckusick *p++ = txdr_unsigned(vap->va_fsid); 61638418Smckusick *p++ = txdr_unsigned(vap->va_fileid); 61738418Smckusick txdr_time(&(vap->va_atime), p); 61838418Smckusick p += 2; 61938418Smckusick txdr_time(&(vap->va_mtime), p); 62038418Smckusick p += 2; 62138418Smckusick txdr_time(&(vap->va_ctime), p); 62238418Smckusick return (error); 62338418Smckusick nfsmout: 62438418Smckusick VOP_ABORTOP(ndp); 62538418Smckusick return (error); 62638418Smckusick } 62738418Smckusick 62838418Smckusick /* 62938418Smckusick * nfs remove service 63038418Smckusick */ 63138418Smckusick nfsrv_remove(mrep, md, dpos, cred, xid, mrq) 63238418Smckusick struct mbuf *mrep, *md, **mrq; 63338418Smckusick caddr_t dpos; 63438418Smckusick struct ucred *cred; 63538418Smckusick long xid; 63638418Smckusick { 63738418Smckusick register struct nameidata *ndp = &u.u_nd; 63838418Smckusick nfsm_srvars; 63938418Smckusick struct vnode *vp; 64038418Smckusick nfsv2fh_t nfh; 64138418Smckusick fhandle_t *fhp; 64238418Smckusick long len; 64338418Smckusick 64438418Smckusick fhp = &nfh.fh_generic; 64538418Smckusick nfsm_srvmtofh(fhp); 64638418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 64738418Smckusick ndp->ni_cred = cred; 64838418Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 64938418Smckusick if (error = nfs_namei(ndp, fhp, len, &md, &dpos)) 65038418Smckusick nfsm_reply(0); 65138418Smckusick vp = ndp->ni_vp; 65238418Smckusick if (vp->v_type == VDIR && 65338418Smckusick (error = suser(cred, (short *)0))) 65438418Smckusick goto out; 65538418Smckusick /* 65638418Smckusick * Don't unlink a mounted file. 65738418Smckusick */ 65838418Smckusick if (vp->v_flag & VROOT) { 65938418Smckusick error = EBUSY; 66038418Smckusick goto out; 66138418Smckusick } 66238418Smckusick if (vp->v_flag & VTEXT) 66338418Smckusick xrele(vp); /* try once to free text */ 66438418Smckusick out: 66538418Smckusick if (error) 66638418Smckusick VOP_ABORTOP(ndp); 66738418Smckusick else 66838418Smckusick error = VOP_REMOVE(ndp); 66938418Smckusick nfsm_reply(0); 67038418Smckusick nfsm_srvdone; 67138418Smckusick } 67238418Smckusick 67338418Smckusick /* 67438418Smckusick * nfs rename service 67538418Smckusick */ 67638418Smckusick nfsrv_rename(mrep, md, dpos, cred, xid, mrq) 67738418Smckusick struct mbuf *mrep, *md, **mrq; 67838418Smckusick caddr_t dpos; 67938418Smckusick struct ucred *cred; 68038418Smckusick long xid; 68138418Smckusick { 68238425Smckusick register struct nameidata *ndp; 68338418Smckusick nfsm_srvars; 68438425Smckusick struct nameidata tond; 68538418Smckusick struct vnode *fvp, *tvp, *tdvp; 68638418Smckusick nfsv2fh_t fnfh, tnfh; 68738418Smckusick fhandle_t *ffhp, *tfhp; 68838418Smckusick long len, len2; 68938418Smckusick int rootflg = 0; 69038418Smckusick 69138425Smckusick ndp = &u.u_nd; 69238425Smckusick ndp->ni_vp = ndp->ni_dvp = (struct vnode *)0; 69338418Smckusick ffhp = &fnfh.fh_generic; 69438418Smckusick tfhp = &tnfh.fh_generic; 69538418Smckusick nfsm_srvmtofh(ffhp); 69638418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 69738418Smckusick /* 69838418Smckusick * Remember if we are root so that we can reset cr_uid before 69938418Smckusick * the second nfs_namei() call 70038418Smckusick */ 70138418Smckusick if (cred->cr_uid == 0) 70238418Smckusick rootflg++; 70338425Smckusick ndp->ni_cred = cred; 70438425Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 70538425Smckusick if (error = nfs_namei(ndp, ffhp, len, &md, &dpos)) 70638418Smckusick nfsm_reply(0); 70738425Smckusick fvp = ndp->ni_vp; 70838418Smckusick nfsm_srvmtofh(tfhp); 70938418Smckusick nfsm_srvstrsiz(len2, NFS_MAXNAMLEN); 71038418Smckusick if (rootflg) 71138418Smckusick cred->cr_uid = 0; 71238425Smckusick nddup(ndp, &tond); 71338425Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 71438425Smckusick error = nfs_namei(&tond, tfhp, len2, &md, &dpos); 71538425Smckusick tdvp = tond.ni_dvp; 71638425Smckusick tvp = tond.ni_vp; 71738418Smckusick if (tvp != NULL) { 71838418Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 71938418Smckusick error = EISDIR; 72038418Smckusick goto out; 72138418Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 72238418Smckusick error = ENOTDIR; 72338418Smckusick goto out; 72438418Smckusick } 72538418Smckusick } 72638418Smckusick if (error) { 72738425Smckusick VOP_ABORTOP(ndp); 72838418Smckusick goto out1; 72938418Smckusick } 73038418Smckusick if (fvp->v_mount != tdvp->v_mount) { 73138418Smckusick error = EXDEV; 73238418Smckusick goto out; 73338418Smckusick } 73438418Smckusick if (fvp == tdvp || fvp == tvp) 73538418Smckusick error = EINVAL; 73638418Smckusick out: 73738418Smckusick if (error) { 73838425Smckusick VOP_ABORTOP(&tond); 73938425Smckusick VOP_ABORTOP(ndp); 74038418Smckusick } else { 741*38451Smckusick VREF(tond.ni_cdir); 74238425Smckusick error = VOP_RENAME(ndp, &tond); 743*38451Smckusick vrele(tond.ni_cdir); 74438418Smckusick } 74538418Smckusick out1: 746*38451Smckusick ndrele(ndp); 74738418Smckusick nfsm_reply(0); 74838418Smckusick return (error); 74938418Smckusick nfsmout: 75038425Smckusick VOP_ABORTOP(ndp); 75138418Smckusick return (error); 75238418Smckusick } 75338418Smckusick 75438418Smckusick /* 75538418Smckusick * nfs link service 75638418Smckusick */ 75738418Smckusick nfsrv_link(mrep, md, dpos, cred, xid, mrq) 75838418Smckusick struct mbuf *mrep, *md, **mrq; 75938418Smckusick caddr_t dpos; 76038418Smckusick struct ucred *cred; 76138418Smckusick long xid; 76238418Smckusick { 76338418Smckusick register struct nameidata *ndp = &u.u_nd; 76438418Smckusick nfsm_srvars; 76538418Smckusick struct vnode *vp, *xp; 76638418Smckusick nfsv2fh_t nfh, dnfh; 76738418Smckusick fhandle_t *fhp, *dfhp; 76838418Smckusick long len; 76938418Smckusick 77038418Smckusick fhp = &nfh.fh_generic; 77138418Smckusick dfhp = &dnfh.fh_generic; 77238418Smckusick nfsm_srvmtofh(fhp); 77338418Smckusick nfsm_srvmtofh(dfhp); 77438418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 77538418Smckusick if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred)) 77638418Smckusick nfsm_reply(0); 77738418Smckusick if (vp->v_type == VDIR && (error = suser(cred, NULL))) 77838418Smckusick goto out1; 77938418Smckusick ndp->ni_cred = cred; 78038418Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 78138418Smckusick if (error = nfs_namei(ndp, dfhp, len, &md, &dpos)) 78238418Smckusick goto out1; 78338418Smckusick xp = ndp->ni_vp; 78438418Smckusick if (xp != NULL) { 78538418Smckusick error = EEXIST; 78638418Smckusick goto out; 78738418Smckusick } 78838418Smckusick xp = ndp->ni_dvp; 78938418Smckusick if (vp->v_mount != xp->v_mount) 79038418Smckusick error = EXDEV; 79138418Smckusick out: 79238418Smckusick if (error) 79338418Smckusick VOP_ABORTOP(ndp); 79438418Smckusick else 79538418Smckusick error = VOP_LINK(vp, ndp); 79638418Smckusick out1: 79738418Smckusick vrele(vp); 79838418Smckusick nfsm_reply(0); 79938418Smckusick nfsm_srvdone; 80038418Smckusick } 80138418Smckusick 80238418Smckusick /* 80338418Smckusick * nfs symbolic link service 80438418Smckusick */ 80538418Smckusick nfsrv_symlink(mrep, md, dpos, cred, xid, mrq) 80638418Smckusick struct mbuf *mrep, *md, **mrq; 80738418Smckusick caddr_t dpos; 80838418Smckusick struct ucred *cred; 80938418Smckusick long xid; 81038418Smckusick { 81138418Smckusick struct vattr va; 81238418Smckusick register struct nameidata *ndp = &u.u_nd; 81338418Smckusick register struct vattr *vap = &va; 81438418Smckusick nfsm_srvars; 81538418Smckusick struct vnode *vp; 81638418Smckusick nfsv2fh_t nfh; 81738418Smckusick fhandle_t *fhp; 81838418Smckusick long len, tlen, len2; 81938418Smckusick 82038418Smckusick ndp->ni_vp = ndp->ni_dvp = (struct vnode *)0; 82138418Smckusick fhp = &nfh.fh_generic; 82238418Smckusick nfsm_srvmtofh(fhp); 82338418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 82438418Smckusick ndp->ni_cred = cred; 82538418Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 82638418Smckusick if (error = nfs_namei(ndp, fhp, len, &md, &dpos)) 82738418Smckusick goto out1; 82838418Smckusick nfsm_srvstrsiz(len2, NFS_MAXPATHLEN); 82938418Smckusick tlen = nfsm_rndup(len2); 83038418Smckusick if (len2 == tlen) { 83138418Smckusick nfsm_disect(cp2, caddr_t, tlen+NFSX_UNSIGNED); 83238418Smckusick *(cp2+tlen) = '\0'; 83338418Smckusick } else { 83438418Smckusick nfsm_disect(cp2, caddr_t, tlen); 83538418Smckusick } 83638418Smckusick vp = ndp->ni_vp; 83738418Smckusick if (vp) { 83838418Smckusick error = EEXIST; 83938418Smckusick goto out; 84038418Smckusick } 84138418Smckusick vp = ndp->ni_dvp; 84238418Smckusick vattr_null(vap); 84338418Smckusick vap->va_mode = 0777; 84438418Smckusick out: 84538418Smckusick if (error) 84638418Smckusick VOP_ABORTOP(ndp); 84738418Smckusick else 84838418Smckusick error = VOP_SYMLINK(ndp, vap, cp2); 84938418Smckusick out1: 85038418Smckusick nfsm_reply(0); 85138418Smckusick return (error); 85238418Smckusick nfsmout: 85338418Smckusick VOP_ABORTOP(ndp); 85438418Smckusick return (error); 85538418Smckusick } 85638418Smckusick 85738418Smckusick /* 85838418Smckusick * nfs mkdir service 85938418Smckusick */ 86038418Smckusick nfsrv_mkdir(mrep, md, dpos, cred, xid, mrq) 86138418Smckusick struct mbuf *mrep, *md, **mrq; 86238418Smckusick caddr_t dpos; 86338418Smckusick struct ucred *cred; 86438418Smckusick long xid; 86538418Smckusick { 86638418Smckusick struct vattr va; 86738418Smckusick register struct vattr *vap = &va; 86838418Smckusick register struct nameidata *ndp = &u.u_nd; 86938418Smckusick nfsm_srvars; 87038418Smckusick struct vnode *vp; 87138418Smckusick nfsv2fh_t nfh; 87238418Smckusick fhandle_t *fhp; 87338418Smckusick long len; 87438418Smckusick 87538418Smckusick ndp->ni_vp = ndp->ni_dvp = (struct vnode *)0; 87638418Smckusick fhp = &nfh.fh_generic; 87738418Smckusick nfsm_srvmtofh(fhp); 87838418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 87938418Smckusick ndp->ni_cred = cred; 88038418Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 88138418Smckusick if (error = nfs_namei(ndp, fhp, len, &md, &dpos)) 88238418Smckusick nfsm_reply(0); 88338418Smckusick nfsm_disect(p, u_long *, NFSX_UNSIGNED); 88438418Smckusick vattr_null(vap); 88538418Smckusick vap->va_type = VDIR; 88638418Smckusick vap->va_mode = nfstov_mode(*p++); 88738418Smckusick vp = ndp->ni_vp; 88838418Smckusick if (vp != NULL) { 88938418Smckusick VOP_ABORTOP(ndp); 89038418Smckusick error = EEXIST; 89138418Smckusick nfsm_reply(0); 89238418Smckusick } 89338418Smckusick if (error = VOP_MKDIR(ndp, vap)) 89438418Smckusick nfsm_reply(0); 89538418Smckusick vp = ndp->ni_vp; 89638418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 89738418Smckusick fhp->fh_fsid = vp->v_mount->m_fsid; 89838418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 89938418Smckusick vput(vp); 90038418Smckusick nfsm_reply(0); 90138418Smckusick } 90238418Smckusick error = VOP_GETATTR(vp, vap, cred); 90338418Smckusick vput(vp); 90438418Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR); 90538418Smckusick nfsm_srvfhtom(fhp); 90638418Smckusick nfsm_build(p, u_long *, NFSX_FATTR); 90738418Smckusick *p++ = vtonfs_type(vap->va_type); 90838418Smckusick *p++ = vtonfs_mode(vap->va_type, vap->va_mode); 90938418Smckusick *p++ = txdr_unsigned(vap->va_nlink); 91038418Smckusick *p++ = txdr_unsigned(vap->va_uid); 91138418Smckusick *p++ = txdr_unsigned(vap->va_gid); 91238418Smckusick *p++ = txdr_unsigned(vap->va_size); 91338418Smckusick *p++ = txdr_unsigned(vap->va_blocksize); 91438418Smckusick *p++ = txdr_unsigned(vap->va_rdev); 91538418Smckusick *p++ = txdr_unsigned(vap->va_bytes); 91638418Smckusick *p++ = txdr_unsigned(vap->va_fsid); 91738418Smckusick *p++ = txdr_unsigned(vap->va_fileid); 91838418Smckusick txdr_time(&(vap->va_atime), p); 91938418Smckusick p += 2; 92038418Smckusick txdr_time(&(vap->va_mtime), p); 92138418Smckusick p += 2; 92238418Smckusick txdr_time(&(vap->va_ctime), p); 92338418Smckusick return (error); 92438418Smckusick nfsmout: 92538418Smckusick VOP_ABORTOP(ndp); 92638418Smckusick return (error); 92738418Smckusick } 92838418Smckusick 92938418Smckusick /* 93038418Smckusick * nfs rmdir service 93138418Smckusick */ 93238418Smckusick nfsrv_rmdir(mrep, md, dpos, cred, xid, mrq) 93338418Smckusick struct mbuf *mrep, *md, **mrq; 93438418Smckusick caddr_t dpos; 93538418Smckusick struct ucred *cred; 93638418Smckusick long xid; 93738418Smckusick { 93838418Smckusick register struct nameidata *ndp = &u.u_nd; 93938418Smckusick nfsm_srvars; 94038418Smckusick struct vnode *vp; 94138418Smckusick nfsv2fh_t nfh; 94238418Smckusick fhandle_t *fhp; 94338418Smckusick long len; 94438418Smckusick 94538418Smckusick fhp = &nfh.fh_generic; 94638418Smckusick nfsm_srvmtofh(fhp); 94738418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 94838418Smckusick ndp->ni_cred = cred; 94938418Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 95038418Smckusick if (error = nfs_namei(ndp, fhp, len, &md, &dpos)) 95138418Smckusick nfsm_reply(0); 95238418Smckusick vp = ndp->ni_vp; 95338418Smckusick if (vp->v_type != VDIR) { 95438418Smckusick error = ENOTDIR; 95538418Smckusick goto out; 95638418Smckusick } 95738418Smckusick /* 95838418Smckusick * No rmdir "." please. 95938418Smckusick */ 96038418Smckusick if (ndp->ni_dvp == vp) { 96138418Smckusick error = EINVAL; 96238418Smckusick goto out; 96338418Smckusick } 96438418Smckusick /* 96538418Smckusick * Don't unlink a mounted file. 96638418Smckusick */ 96738418Smckusick if (vp->v_flag & VROOT) 96838418Smckusick error = EBUSY; 96938418Smckusick out: 97038418Smckusick if (error) 97138418Smckusick VOP_ABORTOP(ndp); 97238418Smckusick else 97338418Smckusick error = VOP_RMDIR(ndp); 97438418Smckusick nfsm_reply(0); 97538418Smckusick nfsm_srvdone; 97638418Smckusick } 97738418Smckusick 97838418Smckusick /* 97938418Smckusick * nfs readdir service 98038418Smckusick * - mallocs what it thinks is enough to read 98138425Smckusick * count rounded up to a multiple of DIRBLKSIZ <= MAX_READDIR 98238418Smckusick * - calls VOP_READDIR() 98338418Smckusick * - loops arround building the reply 98438425Smckusick * if the output generated exceeds count break out of loop 98538425Smckusick * The nfsm_clget macro is used here so that the reply will be packed 98638425Smckusick * tightly in mbuf clusters. 98738418Smckusick * - it only knows that it has encountered eof when the VOP_READDIR() 98838425Smckusick * reads nothing 98938418Smckusick * - as such one readdir rpc will return eof false although you are there 99038425Smckusick * and then the next will return eof 99138418Smckusick * - it trims out records with d_ino == 0 99238425Smckusick * this doesn't matter for Unix clients, but they might confuse clients 99338425Smckusick * for other os'. 99438418Smckusick * NB: It is tempting to set eof to true if the VOP_READDIR() reads less 99538425Smckusick * than requested, but this may not apply to all filesystems. For 99638425Smckusick * example, client NFS does not { although it is never remote mounted 99738425Smckusick * anyhow } 99838418Smckusick * PS: The NFS protocol spec. does not clarify what the "count" byte 99938425Smckusick * argument is a count of.. just name strings and file id's or the 100038425Smckusick * entire reply rpc or ... 100138425Smckusick * I tried just file name and id sizes and it confused the Sun client, 100238425Smckusick * so I am using the full rpc size now. The "paranoia.." comment refers 100338425Smckusick * to including the status longwords that are not a part of the dir. 100438425Smckusick * "entry" structures, but are in the rpc. 100538418Smckusick */ 100638418Smckusick nfsrv_readdir(mrep, md, dpos, cred, xid, mrq) 100738418Smckusick struct mbuf **mrq; 100838418Smckusick struct mbuf *mrep, *md; 100938418Smckusick caddr_t dpos; 101038418Smckusick struct ucred *cred; 101138418Smckusick u_long xid; 101238418Smckusick { 101338418Smckusick register char *bp, *be; 101438418Smckusick register struct mbuf *mp; 101538418Smckusick register struct direct *dp; 101638418Smckusick nfsm_srvars; 101738418Smckusick char *cpos, *cend; 101838418Smckusick int len, nlen, rem, xfer, tsiz, i; 101938418Smckusick struct vnode *vp; 102038418Smckusick struct mbuf *mp2, *mp3; 102138418Smckusick nfsv2fh_t nfh; 102238418Smckusick fhandle_t *fhp; 102338418Smckusick struct uio io; 102438418Smckusick struct iovec iv; 102538418Smckusick int siz, cnt, fullsiz; 102638418Smckusick u_long on; 102738418Smckusick char *rbuf; 102838418Smckusick off_t off, toff; 102938418Smckusick 103038418Smckusick fhp = &nfh.fh_generic; 103138418Smckusick nfsm_srvmtofh(fhp); 103238418Smckusick nfsm_disect(p, u_long *, 2*NFSX_UNSIGNED); 103338418Smckusick toff = fxdr_unsigned(off_t, *p++); 103438418Smckusick off = (toff & ~(DIRBLKSIZ-1)); 103538418Smckusick on = (toff & (DIRBLKSIZ-1)); 103638418Smckusick cnt = fxdr_unsigned(int, *p); 103738418Smckusick siz = ((cnt+DIRBLKSIZ) & ~(DIRBLKSIZ-1)); 103838418Smckusick if (cnt > MAX_READDIR) 103938418Smckusick siz = MAX_READDIR; 104038418Smckusick fullsiz = siz; 104138418Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) 104238418Smckusick nfsm_reply(0); 104338450Smckusick if (error = nfsrv_access(vp, VEXEC, cred)) { 104438418Smckusick vput(vp); 104538418Smckusick nfsm_reply(0); 104638418Smckusick } 104738418Smckusick VOP_UNLOCK(vp); 104838418Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 104938418Smckusick again: 105038418Smckusick iv.iov_base = rbuf; 105138418Smckusick iv.iov_len = fullsiz; 105238418Smckusick io.uio_iov = &iv; 105338418Smckusick io.uio_iovcnt = 1; 105438418Smckusick io.uio_offset = off; 105538418Smckusick io.uio_resid = fullsiz; 105638418Smckusick io.uio_segflg = UIO_SYSSPACE; 105738418Smckusick io.uio_rw = UIO_READ; 105838418Smckusick error = VOP_READDIR(vp, &io, &off, cred); 105938418Smckusick if (error) { 106038418Smckusick vrele(vp); 106138418Smckusick free((caddr_t)rbuf, M_TEMP); 106238418Smckusick nfsm_reply(0); 106338418Smckusick } 106438418Smckusick if (io.uio_resid) { 106538418Smckusick siz -= io.uio_resid; 106638418Smckusick 106738418Smckusick /* 106838418Smckusick * If nothing read, return eof 106938418Smckusick * rpc reply 107038418Smckusick */ 107138418Smckusick if (siz == 0) { 107238418Smckusick vrele(vp); 107338418Smckusick nfsm_reply(2*NFSX_UNSIGNED); 107438418Smckusick nfsm_build(p, u_long *, 2*NFSX_UNSIGNED); 107538418Smckusick *p++ = nfs_false; 107638418Smckusick *p = nfs_true; 107738418Smckusick FREE((caddr_t)rbuf, M_TEMP); 107838418Smckusick return (0); 107938418Smckusick } 108038418Smckusick } 108138418Smckusick cpos = rbuf+on; 108238418Smckusick cend = rbuf+siz; 108338418Smckusick dp = (struct direct *)cpos; 108438418Smckusick /* 108538418Smckusick * Check for degenerate cases of nothing useful read. 108638418Smckusick * If so go try again 108738418Smckusick */ 108838418Smckusick if (cpos >= cend || (dp->d_ino == 0 && (cpos+dp->d_reclen) >= cend)) { 108938418Smckusick toff = off; 109038418Smckusick siz = fullsiz; 109138418Smckusick on = 0; 109238418Smckusick goto again; 109338418Smckusick } 109438418Smckusick vrele(vp); 109538425Smckusick len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 109638418Smckusick bp = be = (caddr_t)0; 109738418Smckusick mp3 = (struct mbuf *)0; 109838418Smckusick nfsm_reply(siz); 109938418Smckusick 110038418Smckusick /* Loop through the records and build reply */ 110138418Smckusick while (cpos < cend) { 110238418Smckusick if (dp->d_ino != 0) { 110338418Smckusick nlen = dp->d_namlen; 110438418Smckusick rem = nfsm_rndup(nlen)-nlen; 110538425Smckusick 110638418Smckusick /* 110738418Smckusick * As noted above, the NFS spec. is not clear about what 110838418Smckusick * should be included in "count" as totalled up here in 110938418Smckusick * "len". 111038418Smckusick */ 111138418Smckusick len += (4*NFSX_UNSIGNED+nlen+rem); 111238418Smckusick if (len > cnt) 111338418Smckusick break; 111438425Smckusick 111538418Smckusick /* Build the directory record xdr from the direct entry */ 111638418Smckusick nfsm_clget; 111738418Smckusick *p = nfs_true; 111838418Smckusick bp += NFSX_UNSIGNED; 111938418Smckusick nfsm_clget; 112038418Smckusick *p = txdr_unsigned(dp->d_ino); 112138418Smckusick bp += NFSX_UNSIGNED; 112238418Smckusick nfsm_clget; 112338418Smckusick *p = txdr_unsigned(nlen); 112438418Smckusick bp += NFSX_UNSIGNED; 112538425Smckusick 112638418Smckusick /* And loop arround copying the name */ 112738418Smckusick xfer = nlen; 112838418Smckusick cp = dp->d_name; 112938418Smckusick while (xfer > 0) { 113038418Smckusick nfsm_clget; 113138418Smckusick if ((bp+xfer) > be) 113238418Smckusick tsiz = be-bp; 113338418Smckusick else 113438418Smckusick tsiz = xfer; 113538418Smckusick bcopy(cp, bp, tsiz); 113638418Smckusick bp += tsiz; 113738418Smckusick xfer -= tsiz; 113838418Smckusick if (xfer > 0) 113938418Smckusick cp += tsiz; 114038418Smckusick } 114138418Smckusick /* And null pad to a long boundary */ 114238418Smckusick for (i = 0; i < rem; i++) 114338418Smckusick *bp++ = '\0'; 114438418Smckusick nfsm_clget; 114538425Smckusick 114638418Smckusick /* Finish off the record */ 114738418Smckusick toff += dp->d_reclen; 114838418Smckusick *p = txdr_unsigned(toff); 114938418Smckusick bp += NFSX_UNSIGNED; 115038418Smckusick } else 115138418Smckusick toff += dp->d_reclen; 115238418Smckusick cpos += dp->d_reclen; 115338418Smckusick dp = (struct direct *)cpos; 115438418Smckusick } 115538418Smckusick nfsm_clget; 115638418Smckusick *p = nfs_false; 115738418Smckusick bp += NFSX_UNSIGNED; 115838418Smckusick nfsm_clget; 115938418Smckusick *p = nfs_false; 116038418Smckusick bp += NFSX_UNSIGNED; 116138418Smckusick if (bp < be) 116238418Smckusick mp->m_len = bp-mtod(mp, caddr_t); 116338418Smckusick mb->m_next = mp3; 116438418Smckusick FREE(rbuf, M_TEMP); 116538418Smckusick nfsm_srvdone; 116638418Smckusick } 116738418Smckusick 116838418Smckusick /* 116938418Smckusick * nfs statfs service 117038418Smckusick */ 117138418Smckusick nfsrv_statfs(mrep, md, dpos, cred, xid, mrq) 117238418Smckusick struct mbuf **mrq; 117338418Smckusick struct mbuf *mrep, *md; 117438418Smckusick caddr_t dpos; 117538418Smckusick struct ucred *cred; 117638418Smckusick u_long xid; 117738418Smckusick { 117838418Smckusick register struct statfs *sf; 117938418Smckusick nfsm_srvars; 118038418Smckusick struct vnode *vp; 118138418Smckusick nfsv2fh_t nfh; 118238418Smckusick fhandle_t *fhp; 118338418Smckusick struct statfs statfs; 118438418Smckusick 118538418Smckusick fhp = &nfh.fh_generic; 118638418Smckusick nfsm_srvmtofh(fhp); 118738418Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) 118838418Smckusick nfsm_reply(0); 118938418Smckusick sf = &statfs; 119038418Smckusick error = VFS_STATFS(vp->v_mount, sf); 119138418Smckusick vput(vp); 119238418Smckusick nfsm_reply(NFSX_STATFS); 119338418Smckusick nfsm_build(p, u_long *, NFSX_STATFS); 119438425Smckusick *p++ = txdr_unsigned(NFS_MAXDATA); 119538418Smckusick *p++ = txdr_unsigned(sf->f_fsize); 119638418Smckusick *p++ = txdr_unsigned(sf->f_blocks); 119738418Smckusick *p++ = txdr_unsigned(sf->f_bfree); 119838418Smckusick *p = txdr_unsigned(sf->f_bavail); 119938418Smckusick nfsm_srvdone; 120038418Smckusick } 120138418Smckusick 120238418Smckusick /* 120338418Smckusick * Null operation, used by clients to ping server 120438418Smckusick */ 120538418Smckusick nfsrv_null(mrep, md, dpos, cred, xid, mrq) 120638418Smckusick struct mbuf **mrq; 120738418Smckusick struct mbuf *mrep, *md; 120838418Smckusick caddr_t dpos; 120938418Smckusick struct ucred *cred; 121038418Smckusick u_long xid; 121138418Smckusick { 121238418Smckusick nfsm_srvars; 121338418Smckusick 121438418Smckusick error = VNOVAL; 121538418Smckusick nfsm_reply(0); 121638418Smckusick nfsm_srvdone; 121738418Smckusick } 121838418Smckusick 121938418Smckusick /* 122038418Smckusick * No operation, used for obsolete procedures 122138418Smckusick */ 122238418Smckusick nfsrv_noop(mrep, md, dpos, cred, xid, mrq) 122338418Smckusick struct mbuf **mrq; 122438418Smckusick struct mbuf *mrep, *md; 122538418Smckusick caddr_t dpos; 122638418Smckusick struct ucred *cred; 122738418Smckusick u_long xid; 122838418Smckusick { 122938418Smckusick nfsm_srvars; 123038418Smckusick 123138418Smckusick error = EPROCUNAVAIL; 123238418Smckusick nfsm_reply(0); 123338418Smckusick nfsm_srvdone; 123438418Smckusick } 123538425Smckusick 123638450Smckusick /* 123738450Smckusick * Perform access checking for vnodes obtained from file handles that would 123838450Smckusick * refer to files already opened by a Unix client. You cannot just use 123938450Smckusick * vn_writechk() and VOP_ACCESS() for two reasons. 124038450Smckusick * 1 - You must check for M_EXRDONLY as well as M_RDONLY for the write case 124138450Smckusick * 2 - The owner is to be given access irrespective of mode bits so that 124238450Smckusick * processes that chmod after opening a file don't break. I don't like 124338450Smckusick * this because it opens a security hole, but since the nfs server opens 124438450Smckusick * a security hole the size of a barn door anyhow, what the heck. 124538450Smckusick */ 124638450Smckusick nfsrv_access(vp, flags, cred) 124738450Smckusick register struct vnode *vp; 124838450Smckusick int flags; 124938450Smckusick register struct ucred *cred; 125038450Smckusick { 125138450Smckusick struct vattr vattr; 125238450Smckusick int error; 125338450Smckusick if (flags & VWRITE) { 125438450Smckusick /* Just vn_writechk() changed to check M_EXRDONLY */ 125538450Smckusick /* 125638450Smckusick * Disallow write attempts on read-only file systems; 125738450Smckusick * unless the file is a socket or a block or character 125838450Smckusick * device resident on the file system. 125938450Smckusick */ 126038450Smckusick if ((vp->v_mount->m_flag & (M_RDONLY | M_EXRDONLY)) && 126138450Smckusick vp->v_type != VCHR && 126238450Smckusick vp->v_type != VBLK && 126338450Smckusick vp->v_type != VSOCK) 126438450Smckusick return (EROFS); 126538450Smckusick /* 126638450Smckusick * If there's shared text associated with 126738450Smckusick * the inode, try to free it up once. If 126838450Smckusick * we fail, we can't allow writing. 126938450Smckusick */ 127038450Smckusick if (vp->v_flag & VTEXT) 127138450Smckusick xrele(vp); 127238450Smckusick if (vp->v_flag & VTEXT) 127338450Smckusick return (ETXTBSY); 127438450Smckusick if (error = VOP_GETATTR(vp, &vattr, cred)) 127538450Smckusick return (error); 127638450Smckusick if (cred->cr_uid == vattr.va_uid) 127738450Smckusick return (0); 127838450Smckusick } else { 127938450Smckusick if (error = VOP_GETATTR(vp, &vattr, cred)) 128038450Smckusick return (error); 128138450Smckusick if (cred->cr_uid == vattr.va_uid) 128238450Smckusick return (0); 128338450Smckusick } 128438450Smckusick return (VOP_ACCESS(vp, flags, cred)); 128538450Smckusick } 1286