1*38418Smckusick /* 2*38418Smckusick * Copyright (c) 1989 The Regents of the University of California. 3*38418Smckusick * All rights reserved. 4*38418Smckusick * 5*38418Smckusick * This code is derived from software contributed to Berkeley by 6*38418Smckusick * Rick Macklem at The University of Guelph. 7*38418Smckusick * 8*38418Smckusick * Redistribution and use in source and binary forms are permitted 9*38418Smckusick * provided that the above copyright notice and this paragraph are 10*38418Smckusick * duplicated in all such forms and that any documentation, 11*38418Smckusick * advertising materials, and other materials related to such 12*38418Smckusick * distribution and use acknowledge that the software was developed 13*38418Smckusick * by the University of California, Berkeley. The name of the 14*38418Smckusick * University may not be used to endorse or promote products derived 15*38418Smckusick * from this software without specific prior written permission. 16*38418Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17*38418Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18*38418Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19*38418Smckusick * 20*38418Smckusick * @(#)nfs_serv.c 7.1 (Berkeley) 07/05/89 21*38418Smckusick */ 22*38418Smckusick 23*38418Smckusick /* 24*38418Smckusick * nfs version 2 server calls to vnode ops 25*38418Smckusick * - these routines generally have 3 phases 26*38418Smckusick * 1 - break down and validate rpc request in mbuf list 27*38418Smckusick * 2 - do the vnode ops for the request 28*38418Smckusick * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c) 29*38418Smckusick * 3 - build the rpc reply in an mbuf list 30*38418Smckusick * nb: 31*38418Smckusick * - do not mix the phases, since the nfsm_?? macros can return failures 32*38418Smckusick * on mbuf exhaustion or similar and do not do any vrele() or vput()'s 33*38418Smckusick * 34*38418Smckusick * - the nfsm_reply() macro generates an nfs rpc reply with the nfs 35*38418Smckusick * error number iff error != 0 whereas 36*38418Smckusick * nfsm_srverr simply drops the mbufs and gives up 37*38418Smckusick * (==> nfsm_srverr implies an error here at the server, usually mbuf 38*38418Smckusick * exhaustion) 39*38418Smckusick */ 40*38418Smckusick 41*38418Smckusick #include "strings.h" 42*38418Smckusick #include "time.h" 43*38418Smckusick #include "param.h" 44*38418Smckusick #include "mount.h" 45*38418Smckusick #include "malloc.h" 46*38418Smckusick #include "mbuf.h" 47*38418Smckusick #include "file.h" 48*38418Smckusick #include "user.h" 49*38418Smckusick #include "../ufs/dir.h" 50*38418Smckusick #include "vnode.h" 51*38418Smckusick #include "uio.h" 52*38418Smckusick #include "ucred.h" 53*38418Smckusick #include "namei.h" 54*38418Smckusick #include "errno.h" 55*38418Smckusick #include "../ufs/inode.h" 56*38418Smckusick #include "nfsv2.h" 57*38418Smckusick #include "nfs.h" 58*38418Smckusick #include "xdr_subs.h" 59*38418Smckusick #include "nfsm_subs.h" 60*38418Smckusick 61*38418Smckusick /* Defs */ 62*38418Smckusick #define TRUE 1 63*38418Smckusick #define FALSE 0 64*38418Smckusick 65*38418Smckusick /* Global vars */ 66*38418Smckusick extern u_long nfs_procids[NFS_NPROCS]; 67*38418Smckusick extern u_long nfs_xdrneg1; 68*38418Smckusick extern u_long nfs_false, nfs_true; 69*38418Smckusick nfstype nfs_type[VSOCK+1]={ NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, }; 70*38418Smckusick 71*38418Smckusick /* 72*38418Smckusick * nfs getattr service 73*38418Smckusick */ 74*38418Smckusick nfsrv_getattr(mrep, md, dpos, cred, xid, mrq) 75*38418Smckusick struct mbuf **mrq; 76*38418Smckusick struct mbuf *mrep, *md; 77*38418Smckusick caddr_t dpos; 78*38418Smckusick struct ucred *cred; 79*38418Smckusick u_long xid; 80*38418Smckusick { 81*38418Smckusick struct vattr va; 82*38418Smckusick register struct vattr *vap = &va; 83*38418Smckusick struct vnode *vp; 84*38418Smckusick nfsv2fh_t nfh; 85*38418Smckusick fhandle_t *fhp; 86*38418Smckusick nfsm_srvars; 87*38418Smckusick 88*38418Smckusick fhp = &nfh.fh_generic; 89*38418Smckusick nfsm_srvmtofh(fhp); 90*38418Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) 91*38418Smckusick nfsm_reply(0); 92*38418Smckusick error = VOP_GETATTR(vp, vap, cred); 93*38418Smckusick vput(vp); 94*38418Smckusick nfsm_reply(NFSX_FATTR); 95*38418Smckusick nfsm_build(p, u_long *, NFSX_FATTR); 96*38418Smckusick *p++ = vtonfs_type(vap->va_type); 97*38418Smckusick *p++ = vtonfs_mode(vap->va_type, vap->va_mode); 98*38418Smckusick *p++ = txdr_unsigned(vap->va_nlink); 99*38418Smckusick *p++ = txdr_unsigned(vap->va_uid); 100*38418Smckusick *p++ = txdr_unsigned(vap->va_gid); 101*38418Smckusick *p++ = txdr_unsigned(vap->va_size); 102*38418Smckusick *p++ = txdr_unsigned(vap->va_blocksize); 103*38418Smckusick *p++ = txdr_unsigned(vap->va_rdev); 104*38418Smckusick *p++ = txdr_unsigned(vap->va_bytes); 105*38418Smckusick *p++ = txdr_unsigned(vap->va_fsid); 106*38418Smckusick *p++ = txdr_unsigned(vap->va_fileid); 107*38418Smckusick txdr_time(&(vap->va_atime), p); 108*38418Smckusick p += 2; 109*38418Smckusick txdr_time(&(vap->va_mtime), p); 110*38418Smckusick p += 2; 111*38418Smckusick txdr_time(&(vap->va_ctime), p); 112*38418Smckusick nfsm_srvdone; 113*38418Smckusick } 114*38418Smckusick 115*38418Smckusick /* 116*38418Smckusick * nfs setattr service 117*38418Smckusick */ 118*38418Smckusick nfsrv_setattr(mrep, md, dpos, cred, xid, mrq) 119*38418Smckusick struct mbuf **mrq; 120*38418Smckusick struct mbuf *mrep, *md; 121*38418Smckusick caddr_t dpos; 122*38418Smckusick struct ucred *cred; 123*38418Smckusick u_long xid; 124*38418Smckusick { 125*38418Smckusick struct vattr va; 126*38418Smckusick register struct vattr *vap = &va; 127*38418Smckusick struct vnode *vp; 128*38418Smckusick nfsv2fh_t nfh; 129*38418Smckusick fhandle_t *fhp; 130*38418Smckusick nfsm_srvars; 131*38418Smckusick 132*38418Smckusick fhp = &nfh.fh_generic; 133*38418Smckusick nfsm_srvmtofh(fhp); 134*38418Smckusick nfsm_disect(p, u_long *, NFSX_SATTR); 135*38418Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) 136*38418Smckusick nfsm_reply(0); 137*38418Smckusick if (vp->v_mount->m_flag & (M_RDONLY | M_EXRDONLY)) { 138*38418Smckusick error = EROFS; 139*38418Smckusick goto out; 140*38418Smckusick } 141*38418Smckusick vattr_null(vap); 142*38418Smckusick /* 143*38418Smckusick * Nah nah nah nah na nah 144*38418Smckusick * There is a bug in the Sun client that puts 0xffff in the mode 145*38418Smckusick * field of sattr when it should put in 0xffffffff. The u_short 146*38418Smckusick * doesn't sign extend. 147*38418Smckusick * --> check the low order 2 bytes for 0xffff 148*38418Smckusick */ 149*38418Smckusick if ((fxdr_unsigned(int, *p) & 0xffff) != 0xffff) 150*38418Smckusick vap->va_mode = nfstov_mode(*p); 151*38418Smckusick if (*++p != nfs_xdrneg1) 152*38418Smckusick vap->va_uid = fxdr_unsigned(uid_t, *p); 153*38418Smckusick if (*++p != nfs_xdrneg1) 154*38418Smckusick vap->va_gid = fxdr_unsigned(gid_t, *p); 155*38418Smckusick if (*++p != nfs_xdrneg1) 156*38418Smckusick vap->va_size = fxdr_unsigned(u_long, *p); 157*38418Smckusick if (*++p != nfs_xdrneg1) 158*38418Smckusick fxdr_time(p, &(vap->va_atime)); 159*38418Smckusick p += 2; 160*38418Smckusick if (*p != nfs_xdrneg1) 161*38418Smckusick fxdr_time(p, &(vap->va_mtime)); 162*38418Smckusick if (error = VOP_SETATTR(vp, vap, cred)) { 163*38418Smckusick vput(vp); 164*38418Smckusick nfsm_reply(0); 165*38418Smckusick } 166*38418Smckusick error = VOP_GETATTR(vp, vap, cred); 167*38418Smckusick out: 168*38418Smckusick vput(vp); 169*38418Smckusick nfsm_reply(NFSX_FATTR); 170*38418Smckusick nfsm_build(p, u_long *, NFSX_FATTR); 171*38418Smckusick *p++ = vtonfs_type(vap->va_type); 172*38418Smckusick *p++ = vtonfs_mode(vap->va_type, vap->va_mode); 173*38418Smckusick *p++ = txdr_unsigned(vap->va_nlink); 174*38418Smckusick *p++ = txdr_unsigned(vap->va_uid); 175*38418Smckusick *p++ = txdr_unsigned(vap->va_gid); 176*38418Smckusick *p++ = txdr_unsigned(vap->va_size); 177*38418Smckusick *p++ = txdr_unsigned(vap->va_blocksize); 178*38418Smckusick *p++ = txdr_unsigned(vap->va_rdev); 179*38418Smckusick *p++ = txdr_unsigned(vap->va_bytes); 180*38418Smckusick *p++ = txdr_unsigned(vap->va_fsid); 181*38418Smckusick *p++ = txdr_unsigned(vap->va_fileid); 182*38418Smckusick txdr_time(&(vap->va_atime), p); 183*38418Smckusick p += 2; 184*38418Smckusick txdr_time(&(vap->va_mtime), p); 185*38418Smckusick p += 2; 186*38418Smckusick txdr_time(&(vap->va_ctime), p); 187*38418Smckusick nfsm_srvdone; 188*38418Smckusick } 189*38418Smckusick 190*38418Smckusick /* 191*38418Smckusick * nfs lookup rpc 192*38418Smckusick */ 193*38418Smckusick nfsrv_lookup(mrep, md, dpos, cred, xid, mrq) 194*38418Smckusick struct mbuf **mrq; 195*38418Smckusick struct mbuf *mrep, *md; 196*38418Smckusick caddr_t dpos; 197*38418Smckusick struct ucred *cred; 198*38418Smckusick u_long xid; 199*38418Smckusick { 200*38418Smckusick register struct nameidata *ndp = &u.u_nd; 201*38418Smckusick struct vnode *vp; 202*38418Smckusick nfsv2fh_t nfh; 203*38418Smckusick fhandle_t *fhp; 204*38418Smckusick nfsm_srvars; 205*38418Smckusick long len; 206*38418Smckusick struct vattr va, *vap = &va; 207*38418Smckusick 208*38418Smckusick fhp = &nfh.fh_generic; 209*38418Smckusick nfsm_srvmtofh(fhp); 210*38418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 211*38418Smckusick ndp->ni_cred = cred; 212*38418Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 213*38418Smckusick ndp->ni_segflg = UIO_SYSSPACE; 214*38418Smckusick if (error = nfs_namei(ndp, fhp, len, &md, &dpos)) 215*38418Smckusick nfsm_reply(0); 216*38418Smckusick vp = ndp->ni_vp; 217*38418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 218*38418Smckusick fhp->fh_fsid = vp->v_mount->m_fsid; 219*38418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 220*38418Smckusick vput(vp); 221*38418Smckusick nfsm_reply(0); 222*38418Smckusick } 223*38418Smckusick error = VOP_GETATTR(vp, vap, cred); 224*38418Smckusick vput(vp); 225*38418Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR); 226*38418Smckusick nfsm_srvfhtom(fhp); 227*38418Smckusick nfsm_build(p, u_long *, NFSX_FATTR); 228*38418Smckusick *p++ = vtonfs_type(vap->va_type); 229*38418Smckusick *p++ = vtonfs_mode(vap->va_type, vap->va_mode); 230*38418Smckusick *p++ = txdr_unsigned(vap->va_nlink); 231*38418Smckusick *p++ = txdr_unsigned(vap->va_uid); 232*38418Smckusick *p++ = txdr_unsigned(vap->va_gid); 233*38418Smckusick *p++ = txdr_unsigned(vap->va_size); 234*38418Smckusick *p++ = txdr_unsigned(vap->va_blocksize); 235*38418Smckusick *p++ = txdr_unsigned(vap->va_rdev); 236*38418Smckusick *p++ = txdr_unsigned(vap->va_bytes); 237*38418Smckusick *p++ = txdr_unsigned(vap->va_fsid); 238*38418Smckusick *p++ = txdr_unsigned(vap->va_fileid); 239*38418Smckusick txdr_time(&(vap->va_atime), p); 240*38418Smckusick p += 2; 241*38418Smckusick txdr_time(&(vap->va_mtime), p); 242*38418Smckusick p += 2; 243*38418Smckusick txdr_time(&(vap->va_ctime), p); 244*38418Smckusick nfsm_srvdone; 245*38418Smckusick } 246*38418Smckusick 247*38418Smckusick /* 248*38418Smckusick * nfs readlink service 249*38418Smckusick */ 250*38418Smckusick nfsrv_readlink(mrep, md, dpos, cred, xid, mrq) 251*38418Smckusick struct mbuf **mrq; 252*38418Smckusick struct mbuf *mrep, *md; 253*38418Smckusick caddr_t dpos; 254*38418Smckusick struct ucred *cred; 255*38418Smckusick long xid; 256*38418Smckusick { 257*38418Smckusick struct iovec iv[NFS_MAXPATHLEN/MLEN+1]; 258*38418Smckusick register struct iovec *ivp = iv; 259*38418Smckusick register struct mbuf *mp; 260*38418Smckusick nfsm_srvars; 261*38418Smckusick struct mbuf *mp2, *mp3; 262*38418Smckusick struct vnode *vp; 263*38418Smckusick nfsv2fh_t nfh; 264*38418Smckusick fhandle_t *fhp; 265*38418Smckusick struct uio io, *uiop = &io; 266*38418Smckusick int i, tlen, len; 267*38418Smckusick 268*38418Smckusick fhp = &nfh.fh_generic; 269*38418Smckusick nfsm_srvmtofh(fhp); 270*38418Smckusick len = 0; 271*38418Smckusick i = 0; 272*38418Smckusick while (len < NFS_MAXPATHLEN) { 273*38418Smckusick MGET(mp, M_WAIT, MT_DATA); 274*38418Smckusick NFSMCLGET(mp, M_WAIT); 275*38418Smckusick mp->m_len = NFSMSIZ(mp); 276*38418Smckusick if (len == 0) 277*38418Smckusick mp3 = mp2 = mp; 278*38418Smckusick else 279*38418Smckusick mp2->m_next = mp; 280*38418Smckusick if ((len+mp->m_len) > NFS_MAXPATHLEN) { 281*38418Smckusick mp->m_len = NFS_MAXPATHLEN-len; 282*38418Smckusick len = NFS_MAXPATHLEN; 283*38418Smckusick } else 284*38418Smckusick len += mp->m_len; 285*38418Smckusick ivp->iov_base = mtod(mp, caddr_t); 286*38418Smckusick ivp->iov_len = mp->m_len; 287*38418Smckusick i++; 288*38418Smckusick ivp++; 289*38418Smckusick } 290*38418Smckusick uiop->uio_iov = iv; 291*38418Smckusick uiop->uio_iovcnt = i; 292*38418Smckusick uiop->uio_offset = 0; 293*38418Smckusick uiop->uio_resid = len; 294*38418Smckusick uiop->uio_rw = UIO_READ; 295*38418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 296*38418Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) { 297*38418Smckusick m_freem(mp3); 298*38418Smckusick nfsm_reply(0); 299*38418Smckusick } 300*38418Smckusick if (vp->v_type != VLNK) { 301*38418Smckusick error = EINVAL; 302*38418Smckusick goto out; 303*38418Smckusick } 304*38418Smckusick error = VOP_READLINK(vp, uiop, cred); 305*38418Smckusick out: 306*38418Smckusick vput(vp); 307*38418Smckusick if (error) 308*38418Smckusick m_freem(mp3); 309*38418Smckusick nfsm_reply(NFSX_UNSIGNED); 310*38418Smckusick if (uiop->uio_resid > 0) { 311*38418Smckusick len -= uiop->uio_resid; 312*38418Smckusick tlen = nfsm_rndup(len); 313*38418Smckusick nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len); 314*38418Smckusick } 315*38418Smckusick nfsm_build(p, u_long *, NFSX_UNSIGNED); 316*38418Smckusick *p = txdr_unsigned(len); 317*38418Smckusick mb->m_next = mp3; 318*38418Smckusick nfsm_srvdone; 319*38418Smckusick } 320*38418Smckusick 321*38418Smckusick /* 322*38418Smckusick * nfs read service 323*38418Smckusick */ 324*38418Smckusick nfsrv_read(mrep, md, dpos, cred, xid, mrq) 325*38418Smckusick struct mbuf **mrq; 326*38418Smckusick struct mbuf *mrep, *md; 327*38418Smckusick caddr_t dpos; 328*38418Smckusick struct ucred *cred; 329*38418Smckusick u_long xid; 330*38418Smckusick { 331*38418Smckusick struct iovec iv[NFS_MAXDATA/MCLBYTES+1]; 332*38418Smckusick register struct iovec *ivp = iv; 333*38418Smckusick register struct mbuf *mp; 334*38418Smckusick nfsm_srvars; 335*38418Smckusick struct mbuf *mp2, *mp3; 336*38418Smckusick struct vnode *vp; 337*38418Smckusick nfsv2fh_t nfh; 338*38418Smckusick fhandle_t *fhp; 339*38418Smckusick struct uio io, *uiop = &io; 340*38418Smckusick struct vattr va, *vap = &va; 341*38418Smckusick int i, tlen, cnt, len, nio, left; 342*38418Smckusick off_t off; 343*38418Smckusick 344*38418Smckusick fhp = &nfh.fh_generic; 345*38418Smckusick nfsm_srvmtofh(fhp); 346*38418Smckusick nfsm_disect(p, u_long *, NFSX_UNSIGNED); 347*38418Smckusick off = fxdr_unsigned(off_t, *p); 348*38418Smckusick nfsm_srvstrsiz(cnt, NFS_MAXDATA); 349*38418Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) 350*38418Smckusick nfsm_reply(0); 351*38418Smckusick if (error = vn_access(vp, VREAD | VEXEC, cred)) { 352*38418Smckusick vput(vp); 353*38418Smckusick nfsm_reply(0); 354*38418Smckusick } 355*38418Smckusick len = left = cnt; 356*38418Smckusick nio = (cnt+MCLBYTES-1)/MCLBYTES; 357*38418Smckusick uiop->uio_iov = ivp; 358*38418Smckusick uiop->uio_iovcnt = nio; 359*38418Smckusick uiop->uio_offset = off; 360*38418Smckusick uiop->uio_resid = cnt; 361*38418Smckusick uiop->uio_rw = UIO_READ; 362*38418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 363*38418Smckusick for (i = 0; i < nio; i++) { 364*38418Smckusick MGET(mp, M_WAIT, MT_DATA); 365*38418Smckusick if (left > MLEN) 366*38418Smckusick NFSMCLGET(mp, M_WAIT); 367*38418Smckusick mp->m_len = (M_HASCL(mp)) ? MCLBYTES : MLEN; 368*38418Smckusick if (i == 0) { 369*38418Smckusick mp3 = mp2 = mp; 370*38418Smckusick } else { 371*38418Smckusick mp2->m_next = mp; 372*38418Smckusick mp2 = mp; 373*38418Smckusick } 374*38418Smckusick if (left > MLEN && !M_HASCL(mp)) { 375*38418Smckusick m_freem(mp3); 376*38418Smckusick vput(vp); 377*38418Smckusick nfsm_srverr; 378*38418Smckusick } 379*38418Smckusick ivp->iov_base = mtod(mp, caddr_t); 380*38418Smckusick if (left > mp->m_len) { 381*38418Smckusick ivp->iov_len = mp->m_len; 382*38418Smckusick left -= mp->m_len; 383*38418Smckusick } else { 384*38418Smckusick ivp->iov_len = mp->m_len = left; 385*38418Smckusick left = 0; 386*38418Smckusick } 387*38418Smckusick ivp++; 388*38418Smckusick } 389*38418Smckusick error = VOP_READ(vp, uiop, &off, IO_NODELOCKED, cred); 390*38418Smckusick if (error) { 391*38418Smckusick m_freem(mp3); 392*38418Smckusick vput(vp); 393*38418Smckusick nfsm_reply(0); 394*38418Smckusick } 395*38418Smckusick if (error = VOP_GETATTR(vp, vap, cred)) 396*38418Smckusick m_freem(mp3); 397*38418Smckusick vput(vp); 398*38418Smckusick nfsm_reply(NFSX_FATTR+NFSX_UNSIGNED); 399*38418Smckusick nfsm_build(p, u_long *, NFSX_FATTR+NFSX_UNSIGNED); 400*38418Smckusick *p++ = vtonfs_type(vap->va_type); 401*38418Smckusick *p++ = vtonfs_mode(vap->va_type, vap->va_mode); 402*38418Smckusick *p++ = txdr_unsigned(vap->va_nlink); 403*38418Smckusick *p++ = txdr_unsigned(vap->va_uid); 404*38418Smckusick *p++ = txdr_unsigned(vap->va_gid); 405*38418Smckusick *p++ = txdr_unsigned(vap->va_size); 406*38418Smckusick *p++ = txdr_unsigned(vap->va_blocksize); 407*38418Smckusick *p++ = txdr_unsigned(vap->va_rdev); 408*38418Smckusick *p++ = txdr_unsigned(vap->va_bytes); 409*38418Smckusick *p++ = txdr_unsigned(vap->va_fsid); 410*38418Smckusick *p++ = txdr_unsigned(vap->va_fileid); 411*38418Smckusick txdr_time(&(vap->va_atime), p); 412*38418Smckusick p += 2; 413*38418Smckusick txdr_time(&(vap->va_mtime), p); 414*38418Smckusick p += 2; 415*38418Smckusick txdr_time(&(vap->va_ctime), p); 416*38418Smckusick p += 2; 417*38418Smckusick if (uiop->uio_resid > 0) { 418*38418Smckusick len -= uiop->uio_resid; 419*38418Smckusick if (len > 0) { 420*38418Smckusick tlen = nfsm_rndup(len); 421*38418Smckusick nfsm_adj(mp3, cnt-tlen, tlen-len); 422*38418Smckusick } else { 423*38418Smckusick m_freem(mp3); 424*38418Smckusick mp3 = (struct mbuf *)0; 425*38418Smckusick } 426*38418Smckusick } 427*38418Smckusick *p = txdr_unsigned(len); 428*38418Smckusick mb->m_next = mp3; 429*38418Smckusick nfsm_srvdone; 430*38418Smckusick } 431*38418Smckusick 432*38418Smckusick /* 433*38418Smckusick * nfs write service 434*38418Smckusick */ 435*38418Smckusick nfsrv_write(mrep, md, dpos, cred, xid, mrq) 436*38418Smckusick struct mbuf *mrep, *md, **mrq; 437*38418Smckusick caddr_t dpos; 438*38418Smckusick struct ucred *cred; 439*38418Smckusick long xid; 440*38418Smckusick { 441*38418Smckusick register struct iovec *ivp; 442*38418Smckusick register struct mbuf *mp; 443*38418Smckusick struct iovec iv[MAX_IOVEC]; 444*38418Smckusick struct vattr va; 445*38418Smckusick register struct vattr *vap = &va; 446*38418Smckusick nfsm_srvars; 447*38418Smckusick struct vnode *vp; 448*38418Smckusick nfsv2fh_t nfh; 449*38418Smckusick fhandle_t *fhp; 450*38418Smckusick struct uio io, *uiop = &io; 451*38418Smckusick off_t off; 452*38418Smckusick long siz, len, xfer; 453*38418Smckusick 454*38418Smckusick fhp = &nfh.fh_generic; 455*38418Smckusick nfsm_srvmtofh(fhp); 456*38418Smckusick nfsm_disect(p, u_long *, 4*NFSX_UNSIGNED); 457*38418Smckusick off = fxdr_unsigned(off_t, *++p); 458*38418Smckusick p += 2; 459*38418Smckusick len = fxdr_unsigned(long, *p); 460*38418Smckusick if (len > NFS_MAXDATA || len <= 0) { 461*38418Smckusick error = EBADRPC; 462*38418Smckusick nfsm_reply(0); 463*38418Smckusick } 464*38418Smckusick if (dpos == (mtod(md, caddr_t)+md->m_len)) { 465*38418Smckusick mp = md->m_next; 466*38418Smckusick if (mp == NULL) { 467*38418Smckusick error = EBADRPC; 468*38418Smckusick nfsm_reply(0); 469*38418Smckusick } 470*38418Smckusick } else { 471*38418Smckusick mp = md; 472*38418Smckusick siz = dpos-mtod(mp, caddr_t); 473*38418Smckusick mp->m_len -= siz; 474*38418Smckusick NFSMADV(mp, siz); 475*38418Smckusick } 476*38418Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) 477*38418Smckusick nfsm_reply(0); 478*38418Smckusick if (error = vn_access(vp, VWRITE, cred)) { 479*38418Smckusick vput(vp); 480*38418Smckusick nfsm_reply(0); 481*38418Smckusick } 482*38418Smckusick uiop->uio_resid = 0; 483*38418Smckusick uiop->uio_rw = UIO_WRITE; 484*38418Smckusick uiop->uio_segflg = UIO_SYSSPACE; 485*38418Smckusick /* 486*38418Smckusick * Do up to MAX_IOVEC mbufs of write each iteration of the 487*38418Smckusick * loop until done. 488*38418Smckusick */ 489*38418Smckusick while (len > 0 && uiop->uio_resid == 0) { 490*38418Smckusick ivp = iv; 491*38418Smckusick siz = 0; 492*38418Smckusick uiop->uio_iov = ivp; 493*38418Smckusick uiop->uio_iovcnt = 0; 494*38418Smckusick uiop->uio_offset = off; 495*38418Smckusick while (len > 0 && uiop->uio_iovcnt < MAX_IOVEC && mp != NULL) { 496*38418Smckusick ivp->iov_base = mtod(mp, caddr_t); 497*38418Smckusick if (len < mp->m_len) 498*38418Smckusick ivp->iov_len = xfer = len; 499*38418Smckusick else 500*38418Smckusick ivp->iov_len = xfer = mp->m_len; 501*38418Smckusick #ifdef notdef 502*38418Smckusick /* Not Yet .. */ 503*38418Smckusick if (M_HASCL(mp) && (((u_long)ivp->iov_base) & CLOFSET) == 0) 504*38418Smckusick ivp->iov_op = NULL; /* what should it be ?? */ 505*38418Smckusick else 506*38418Smckusick ivp->iov_op = NULL; 507*38418Smckusick #endif 508*38418Smckusick uiop->uio_iovcnt++; 509*38418Smckusick ivp++; 510*38418Smckusick len -= xfer; 511*38418Smckusick siz += xfer; 512*38418Smckusick mp = mp->m_next; 513*38418Smckusick } 514*38418Smckusick if (len > 0 && mp == NULL) { 515*38418Smckusick error = EBADRPC; 516*38418Smckusick vput(vp); 517*38418Smckusick nfsm_reply(0); 518*38418Smckusick } 519*38418Smckusick uiop->uio_resid = siz; 520*38418Smckusick if (error = VOP_WRITE(vp, uiop, &off, IO_SYNC | IO_NODELOCKED, 521*38418Smckusick cred)) { 522*38418Smckusick vput(vp); 523*38418Smckusick nfsm_reply(0); 524*38418Smckusick } 525*38418Smckusick } 526*38418Smckusick error = VOP_GETATTR(vp, vap, cred); 527*38418Smckusick vput(vp); 528*38418Smckusick nfsm_reply(NFSX_FATTR); 529*38418Smckusick nfsm_build(p, u_long *, NFSX_FATTR); 530*38418Smckusick *p++ = vtonfs_type(vap->va_type); 531*38418Smckusick *p++ = vtonfs_mode(vap->va_type, vap->va_mode); 532*38418Smckusick *p++ = txdr_unsigned(vap->va_nlink); 533*38418Smckusick *p++ = txdr_unsigned(vap->va_uid); 534*38418Smckusick *p++ = txdr_unsigned(vap->va_gid); 535*38418Smckusick *p++ = txdr_unsigned(vap->va_size); 536*38418Smckusick *p++ = txdr_unsigned(vap->va_blocksize); 537*38418Smckusick *p++ = txdr_unsigned(vap->va_rdev); 538*38418Smckusick *p++ = txdr_unsigned(vap->va_bytes); 539*38418Smckusick *p++ = txdr_unsigned(vap->va_fsid); 540*38418Smckusick *p++ = txdr_unsigned(vap->va_fileid); 541*38418Smckusick txdr_time(&(vap->va_atime), p); 542*38418Smckusick p += 2; 543*38418Smckusick txdr_time(&(vap->va_mtime), p); 544*38418Smckusick p += 2; 545*38418Smckusick txdr_time(&(vap->va_ctime), p); 546*38418Smckusick nfsm_srvdone; 547*38418Smckusick } 548*38418Smckusick 549*38418Smckusick /* 550*38418Smckusick * nfs create service 551*38418Smckusick * now does a truncate to 0 length via. setattr if it already exists 552*38418Smckusick */ 553*38418Smckusick nfsrv_create(mrep, md, dpos, cred, xid, mrq) 554*38418Smckusick struct mbuf *mrep, *md, **mrq; 555*38418Smckusick caddr_t dpos; 556*38418Smckusick struct ucred *cred; 557*38418Smckusick long xid; 558*38418Smckusick { 559*38418Smckusick struct vattr va; 560*38418Smckusick register struct vattr *vap = &va; 561*38418Smckusick register struct nameidata *ndp = &u.u_nd; 562*38418Smckusick nfsm_srvars; 563*38418Smckusick struct vnode *vp; 564*38418Smckusick nfsv2fh_t nfh; 565*38418Smckusick fhandle_t *fhp; 566*38418Smckusick long len; 567*38418Smckusick 568*38418Smckusick ndp->ni_vp = ndp->ni_dvp = (struct vnode *)0; 569*38418Smckusick fhp = &nfh.fh_generic; 570*38418Smckusick nfsm_srvmtofh(fhp); 571*38418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 572*38418Smckusick ndp->ni_cred = cred; 573*38418Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT | LOCKLEAF; 574*38418Smckusick ndp->ni_segflg = UIO_SYSSPACE; 575*38418Smckusick if (error = nfs_namei(ndp, fhp, len, &md, &dpos)) 576*38418Smckusick nfsm_reply(0); 577*38418Smckusick vattr_null(vap); 578*38418Smckusick nfsm_disect(p, u_long *, NFSX_UNSIGNED); 579*38418Smckusick /* 580*38418Smckusick * Iff doesn't exist, create it 581*38418Smckusick * otherwise just truncate to 0 length 582*38418Smckusick * should I set the mode too ?? 583*38418Smckusick */ 584*38418Smckusick if (ndp->ni_vp == NULL) { 585*38418Smckusick vap->va_type = VREG; 586*38418Smckusick vap->va_mode = nfstov_mode(*p++); 587*38418Smckusick if (error = VOP_CREATE(ndp, vap)) 588*38418Smckusick nfsm_reply(0); 589*38418Smckusick } else { 590*38418Smckusick vap->va_size = 0; 591*38418Smckusick if (error = VOP_SETATTR(ndp->ni_vp, vap, cred)) { 592*38418Smckusick VOP_ABORTOP(ndp); 593*38418Smckusick nfsm_reply(0); 594*38418Smckusick } 595*38418Smckusick vput(ndp->ni_dvp); 596*38418Smckusick } 597*38418Smckusick vp = ndp->ni_vp; 598*38418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 599*38418Smckusick fhp->fh_fsid = vp->v_mount->m_fsid; 600*38418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 601*38418Smckusick vput(vp); 602*38418Smckusick nfsm_reply(0); 603*38418Smckusick } 604*38418Smckusick error = VOP_GETATTR(vp, vap, cred); 605*38418Smckusick vput(vp); 606*38418Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR); 607*38418Smckusick nfsm_srvfhtom(fhp); 608*38418Smckusick nfsm_build(p, u_long *, NFSX_FATTR); 609*38418Smckusick *p++ = vtonfs_type(vap->va_type); 610*38418Smckusick *p++ = vtonfs_mode(vap->va_type, vap->va_mode); 611*38418Smckusick *p++ = txdr_unsigned(vap->va_nlink); 612*38418Smckusick *p++ = txdr_unsigned(vap->va_uid); 613*38418Smckusick *p++ = txdr_unsigned(vap->va_gid); 614*38418Smckusick *p++ = txdr_unsigned(vap->va_size); 615*38418Smckusick *p++ = txdr_unsigned(vap->va_blocksize); 616*38418Smckusick *p++ = txdr_unsigned(vap->va_rdev); 617*38418Smckusick *p++ = txdr_unsigned(vap->va_bytes); 618*38418Smckusick *p++ = txdr_unsigned(vap->va_fsid); 619*38418Smckusick *p++ = txdr_unsigned(vap->va_fileid); 620*38418Smckusick txdr_time(&(vap->va_atime), p); 621*38418Smckusick p += 2; 622*38418Smckusick txdr_time(&(vap->va_mtime), p); 623*38418Smckusick p += 2; 624*38418Smckusick txdr_time(&(vap->va_ctime), p); 625*38418Smckusick return (error); 626*38418Smckusick nfsmout: 627*38418Smckusick VOP_ABORTOP(ndp); 628*38418Smckusick return (error); 629*38418Smckusick } 630*38418Smckusick 631*38418Smckusick /* 632*38418Smckusick * nfs remove service 633*38418Smckusick */ 634*38418Smckusick nfsrv_remove(mrep, md, dpos, cred, xid, mrq) 635*38418Smckusick struct mbuf *mrep, *md, **mrq; 636*38418Smckusick caddr_t dpos; 637*38418Smckusick struct ucred *cred; 638*38418Smckusick long xid; 639*38418Smckusick { 640*38418Smckusick register struct nameidata *ndp = &u.u_nd; 641*38418Smckusick nfsm_srvars; 642*38418Smckusick struct vnode *vp; 643*38418Smckusick nfsv2fh_t nfh; 644*38418Smckusick fhandle_t *fhp; 645*38418Smckusick long len; 646*38418Smckusick 647*38418Smckusick fhp = &nfh.fh_generic; 648*38418Smckusick nfsm_srvmtofh(fhp); 649*38418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 650*38418Smckusick ndp->ni_cred = cred; 651*38418Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 652*38418Smckusick ndp->ni_segflg = UIO_SYSSPACE; 653*38418Smckusick if (error = nfs_namei(ndp, fhp, len, &md, &dpos)) 654*38418Smckusick nfsm_reply(0); 655*38418Smckusick vp = ndp->ni_vp; 656*38418Smckusick if (vp->v_type == VDIR && 657*38418Smckusick (error = suser(cred, (short *)0))) 658*38418Smckusick goto out; 659*38418Smckusick /* 660*38418Smckusick * Don't unlink a mounted file. 661*38418Smckusick */ 662*38418Smckusick if (vp->v_flag & VROOT) { 663*38418Smckusick error = EBUSY; 664*38418Smckusick goto out; 665*38418Smckusick } 666*38418Smckusick if (vp->v_flag & VTEXT) 667*38418Smckusick xrele(vp); /* try once to free text */ 668*38418Smckusick out: 669*38418Smckusick if (error) 670*38418Smckusick VOP_ABORTOP(ndp); 671*38418Smckusick else 672*38418Smckusick error = VOP_REMOVE(ndp); 673*38418Smckusick nfsm_reply(0); 674*38418Smckusick nfsm_srvdone; 675*38418Smckusick } 676*38418Smckusick 677*38418Smckusick /* 678*38418Smckusick * nfs rename service 679*38418Smckusick * malloc() the tond structure to avoid blowing the kernel stack 680*38418Smckusick */ 681*38418Smckusick nfsrv_rename(mrep, md, dpos, cred, xid, mrq) 682*38418Smckusick struct mbuf *mrep, *md, **mrq; 683*38418Smckusick caddr_t dpos; 684*38418Smckusick struct ucred *cred; 685*38418Smckusick long xid; 686*38418Smckusick { 687*38418Smckusick struct nameidata *nam, *tond; 688*38418Smckusick nfsm_srvars; 689*38418Smckusick struct vnode *fvp, *tvp, *tdvp; 690*38418Smckusick nfsv2fh_t fnfh, tnfh; 691*38418Smckusick fhandle_t *ffhp, *tfhp; 692*38418Smckusick long len, len2; 693*38418Smckusick int rootflg = 0; 694*38418Smckusick 695*38418Smckusick nam = &u.u_nd; 696*38418Smckusick MALLOC(tond, struct nameidata *, sizeof(*tond), M_TEMP, M_WAITOK); 697*38418Smckusick ndinit(tond); 698*38418Smckusick nam->ni_vp = nam->ni_dvp = (struct vnode *)0; 699*38418Smckusick ffhp = &fnfh.fh_generic; 700*38418Smckusick tfhp = &tnfh.fh_generic; 701*38418Smckusick nfsm_srvmtofh(ffhp); 702*38418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 703*38418Smckusick /* 704*38418Smckusick * Remember if we are root so that we can reset cr_uid before 705*38418Smckusick * the second nfs_namei() call 706*38418Smckusick */ 707*38418Smckusick if (cred->cr_uid == 0) 708*38418Smckusick rootflg++; 709*38418Smckusick nam->ni_cred = cred; 710*38418Smckusick nam->ni_nameiop = DELETE | WANTPARENT; 711*38418Smckusick nam->ni_segflg = UIO_SYSSPACE; 712*38418Smckusick if (error = nfs_namei(nam, ffhp, len, &md, &dpos)) 713*38418Smckusick nfsm_reply(0); 714*38418Smckusick nfsm_srvmtofh(tfhp); 715*38418Smckusick nfsm_srvstrsiz(len2, NFS_MAXNAMLEN); 716*38418Smckusick if (rootflg) 717*38418Smckusick cred->cr_uid = 0; 718*38418Smckusick tond->ni_cred = cred; 719*38418Smckusick crhold(cred); 720*38418Smckusick tond->ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 721*38418Smckusick tond->ni_segflg = UIO_SYSSPACE; 722*38418Smckusick error = nfs_namei(tond, tfhp, len2, &md, &dpos); 723*38418Smckusick fvp = nam->ni_vp; 724*38418Smckusick tdvp = tond->ni_dvp; 725*38418Smckusick tvp = tond->ni_vp; 726*38418Smckusick if (tvp != NULL) { 727*38418Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 728*38418Smckusick error = EISDIR; 729*38418Smckusick goto out; 730*38418Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 731*38418Smckusick error = ENOTDIR; 732*38418Smckusick goto out; 733*38418Smckusick } 734*38418Smckusick } 735*38418Smckusick if (error) { 736*38418Smckusick VOP_ABORTOP(nam); 737*38418Smckusick goto out1; 738*38418Smckusick } 739*38418Smckusick if (fvp->v_mount != tdvp->v_mount) { 740*38418Smckusick error = EXDEV; 741*38418Smckusick goto out; 742*38418Smckusick } 743*38418Smckusick if (fvp == tdvp || fvp == tvp) 744*38418Smckusick error = EINVAL; 745*38418Smckusick out: 746*38418Smckusick if (error) { 747*38418Smckusick VOP_ABORTOP(tond); 748*38418Smckusick VOP_ABORTOP(nam); 749*38418Smckusick } else { 750*38418Smckusick error = VOP_RENAME(nam, tond); 751*38418Smckusick } 752*38418Smckusick out1: 753*38418Smckusick crfree(tond->ni_cred); 754*38418Smckusick FREE((caddr_t)tond, M_TEMP); 755*38418Smckusick nfsm_reply(0); 756*38418Smckusick return (error); 757*38418Smckusick nfsmout: 758*38418Smckusick VOP_ABORTOP(nam); 759*38418Smckusick free((caddr_t)tond, M_TEMP); 760*38418Smckusick return (error); 761*38418Smckusick } 762*38418Smckusick 763*38418Smckusick /* 764*38418Smckusick * nfs link service 765*38418Smckusick */ 766*38418Smckusick nfsrv_link(mrep, md, dpos, cred, xid, mrq) 767*38418Smckusick struct mbuf *mrep, *md, **mrq; 768*38418Smckusick caddr_t dpos; 769*38418Smckusick struct ucred *cred; 770*38418Smckusick long xid; 771*38418Smckusick { 772*38418Smckusick register struct nameidata *ndp = &u.u_nd; 773*38418Smckusick nfsm_srvars; 774*38418Smckusick struct vnode *vp, *xp; 775*38418Smckusick nfsv2fh_t nfh, dnfh; 776*38418Smckusick fhandle_t *fhp, *dfhp; 777*38418Smckusick long len; 778*38418Smckusick 779*38418Smckusick fhp = &nfh.fh_generic; 780*38418Smckusick dfhp = &dnfh.fh_generic; 781*38418Smckusick nfsm_srvmtofh(fhp); 782*38418Smckusick nfsm_srvmtofh(dfhp); 783*38418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 784*38418Smckusick if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred)) 785*38418Smckusick nfsm_reply(0); 786*38418Smckusick if (vp->v_type == VDIR && (error = suser(cred, NULL))) 787*38418Smckusick goto out1; 788*38418Smckusick ndp->ni_cred = cred; 789*38418Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 790*38418Smckusick ndp->ni_segflg = UIO_SYSSPACE; 791*38418Smckusick if (error = nfs_namei(ndp, dfhp, len, &md, &dpos)) 792*38418Smckusick goto out1; 793*38418Smckusick xp = ndp->ni_vp; 794*38418Smckusick if (xp != NULL) { 795*38418Smckusick error = EEXIST; 796*38418Smckusick goto out; 797*38418Smckusick } 798*38418Smckusick xp = ndp->ni_dvp; 799*38418Smckusick if (vp->v_mount != xp->v_mount) 800*38418Smckusick error = EXDEV; 801*38418Smckusick out: 802*38418Smckusick if (error) 803*38418Smckusick VOP_ABORTOP(ndp); 804*38418Smckusick else 805*38418Smckusick error = VOP_LINK(vp, ndp); 806*38418Smckusick out1: 807*38418Smckusick vrele(vp); 808*38418Smckusick nfsm_reply(0); 809*38418Smckusick nfsm_srvdone; 810*38418Smckusick } 811*38418Smckusick 812*38418Smckusick /* 813*38418Smckusick * nfs symbolic link service 814*38418Smckusick */ 815*38418Smckusick nfsrv_symlink(mrep, md, dpos, cred, xid, mrq) 816*38418Smckusick struct mbuf *mrep, *md, **mrq; 817*38418Smckusick caddr_t dpos; 818*38418Smckusick struct ucred *cred; 819*38418Smckusick long xid; 820*38418Smckusick { 821*38418Smckusick struct vattr va; 822*38418Smckusick register struct nameidata *ndp = &u.u_nd; 823*38418Smckusick register struct vattr *vap = &va; 824*38418Smckusick nfsm_srvars; 825*38418Smckusick struct vnode *vp; 826*38418Smckusick nfsv2fh_t nfh; 827*38418Smckusick fhandle_t *fhp; 828*38418Smckusick long len, tlen, len2; 829*38418Smckusick 830*38418Smckusick ndp->ni_vp = ndp->ni_dvp = (struct vnode *)0; 831*38418Smckusick fhp = &nfh.fh_generic; 832*38418Smckusick nfsm_srvmtofh(fhp); 833*38418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 834*38418Smckusick ndp->ni_cred = cred; 835*38418Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 836*38418Smckusick ndp->ni_segflg = UIO_SYSSPACE; 837*38418Smckusick if (error = nfs_namei(ndp, fhp, len, &md, &dpos)) 838*38418Smckusick goto out1; 839*38418Smckusick nfsm_srvstrsiz(len2, NFS_MAXPATHLEN); 840*38418Smckusick tlen = nfsm_rndup(len2); 841*38418Smckusick if (len2 == tlen) { 842*38418Smckusick nfsm_disect(cp2, caddr_t, tlen+NFSX_UNSIGNED); 843*38418Smckusick *(cp2+tlen) = '\0'; 844*38418Smckusick } else { 845*38418Smckusick nfsm_disect(cp2, caddr_t, tlen); 846*38418Smckusick } 847*38418Smckusick vp = ndp->ni_vp; 848*38418Smckusick if (vp) { 849*38418Smckusick error = EEXIST; 850*38418Smckusick goto out; 851*38418Smckusick } 852*38418Smckusick vp = ndp->ni_dvp; 853*38418Smckusick vattr_null(vap); 854*38418Smckusick vap->va_mode = 0777; 855*38418Smckusick out: 856*38418Smckusick if (error) 857*38418Smckusick VOP_ABORTOP(ndp); 858*38418Smckusick else 859*38418Smckusick error = VOP_SYMLINK(ndp, vap, cp2); 860*38418Smckusick out1: 861*38418Smckusick nfsm_reply(0); 862*38418Smckusick return (error); 863*38418Smckusick nfsmout: 864*38418Smckusick VOP_ABORTOP(ndp); 865*38418Smckusick return (error); 866*38418Smckusick } 867*38418Smckusick 868*38418Smckusick /* 869*38418Smckusick * nfs mkdir service 870*38418Smckusick */ 871*38418Smckusick nfsrv_mkdir(mrep, md, dpos, cred, xid, mrq) 872*38418Smckusick struct mbuf *mrep, *md, **mrq; 873*38418Smckusick caddr_t dpos; 874*38418Smckusick struct ucred *cred; 875*38418Smckusick long xid; 876*38418Smckusick { 877*38418Smckusick struct vattr va; 878*38418Smckusick register struct vattr *vap = &va; 879*38418Smckusick register struct nameidata *ndp = &u.u_nd; 880*38418Smckusick nfsm_srvars; 881*38418Smckusick struct vnode *vp; 882*38418Smckusick nfsv2fh_t nfh; 883*38418Smckusick fhandle_t *fhp; 884*38418Smckusick long len; 885*38418Smckusick 886*38418Smckusick ndp->ni_vp = ndp->ni_dvp = (struct vnode *)0; 887*38418Smckusick fhp = &nfh.fh_generic; 888*38418Smckusick nfsm_srvmtofh(fhp); 889*38418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 890*38418Smckusick ndp->ni_cred = cred; 891*38418Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 892*38418Smckusick ndp->ni_segflg = UIO_SYSSPACE; 893*38418Smckusick if (error = nfs_namei(ndp, fhp, len, &md, &dpos)) 894*38418Smckusick nfsm_reply(0); 895*38418Smckusick nfsm_disect(p, u_long *, NFSX_UNSIGNED); 896*38418Smckusick vattr_null(vap); 897*38418Smckusick vap->va_type = VDIR; 898*38418Smckusick vap->va_mode = nfstov_mode(*p++); 899*38418Smckusick vp = ndp->ni_vp; 900*38418Smckusick if (vp != NULL) { 901*38418Smckusick VOP_ABORTOP(ndp); 902*38418Smckusick error = EEXIST; 903*38418Smckusick nfsm_reply(0); 904*38418Smckusick } 905*38418Smckusick if (error = VOP_MKDIR(ndp, vap)) 906*38418Smckusick nfsm_reply(0); 907*38418Smckusick vp = ndp->ni_vp; 908*38418Smckusick bzero((caddr_t)fhp, sizeof(nfh)); 909*38418Smckusick fhp->fh_fsid = vp->v_mount->m_fsid; 910*38418Smckusick if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 911*38418Smckusick vput(vp); 912*38418Smckusick nfsm_reply(0); 913*38418Smckusick } 914*38418Smckusick error = VOP_GETATTR(vp, vap, cred); 915*38418Smckusick vput(vp); 916*38418Smckusick nfsm_reply(NFSX_FH+NFSX_FATTR); 917*38418Smckusick nfsm_srvfhtom(fhp); 918*38418Smckusick nfsm_build(p, u_long *, NFSX_FATTR); 919*38418Smckusick *p++ = vtonfs_type(vap->va_type); 920*38418Smckusick *p++ = vtonfs_mode(vap->va_type, vap->va_mode); 921*38418Smckusick *p++ = txdr_unsigned(vap->va_nlink); 922*38418Smckusick *p++ = txdr_unsigned(vap->va_uid); 923*38418Smckusick *p++ = txdr_unsigned(vap->va_gid); 924*38418Smckusick *p++ = txdr_unsigned(vap->va_size); 925*38418Smckusick *p++ = txdr_unsigned(vap->va_blocksize); 926*38418Smckusick *p++ = txdr_unsigned(vap->va_rdev); 927*38418Smckusick *p++ = txdr_unsigned(vap->va_bytes); 928*38418Smckusick *p++ = txdr_unsigned(vap->va_fsid); 929*38418Smckusick *p++ = txdr_unsigned(vap->va_fileid); 930*38418Smckusick txdr_time(&(vap->va_atime), p); 931*38418Smckusick p += 2; 932*38418Smckusick txdr_time(&(vap->va_mtime), p); 933*38418Smckusick p += 2; 934*38418Smckusick txdr_time(&(vap->va_ctime), p); 935*38418Smckusick return (error); 936*38418Smckusick nfsmout: 937*38418Smckusick VOP_ABORTOP(ndp); 938*38418Smckusick return (error); 939*38418Smckusick } 940*38418Smckusick 941*38418Smckusick /* 942*38418Smckusick * nfs rmdir service 943*38418Smckusick */ 944*38418Smckusick nfsrv_rmdir(mrep, md, dpos, cred, xid, mrq) 945*38418Smckusick struct mbuf *mrep, *md, **mrq; 946*38418Smckusick caddr_t dpos; 947*38418Smckusick struct ucred *cred; 948*38418Smckusick long xid; 949*38418Smckusick { 950*38418Smckusick register struct nameidata *ndp = &u.u_nd; 951*38418Smckusick nfsm_srvars; 952*38418Smckusick struct vnode *vp; 953*38418Smckusick nfsv2fh_t nfh; 954*38418Smckusick fhandle_t *fhp; 955*38418Smckusick long len; 956*38418Smckusick 957*38418Smckusick fhp = &nfh.fh_generic; 958*38418Smckusick nfsm_srvmtofh(fhp); 959*38418Smckusick nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 960*38418Smckusick ndp->ni_cred = cred; 961*38418Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 962*38418Smckusick ndp->ni_segflg = UIO_SYSSPACE; 963*38418Smckusick if (error = nfs_namei(ndp, fhp, len, &md, &dpos)) 964*38418Smckusick nfsm_reply(0); 965*38418Smckusick vp = ndp->ni_vp; 966*38418Smckusick if (vp->v_type != VDIR) { 967*38418Smckusick error = ENOTDIR; 968*38418Smckusick goto out; 969*38418Smckusick } 970*38418Smckusick /* 971*38418Smckusick * No rmdir "." please. 972*38418Smckusick */ 973*38418Smckusick if (ndp->ni_dvp == vp) { 974*38418Smckusick error = EINVAL; 975*38418Smckusick goto out; 976*38418Smckusick } 977*38418Smckusick /* 978*38418Smckusick * Don't unlink a mounted file. 979*38418Smckusick */ 980*38418Smckusick if (vp->v_flag & VROOT) 981*38418Smckusick error = EBUSY; 982*38418Smckusick out: 983*38418Smckusick if (error) 984*38418Smckusick VOP_ABORTOP(ndp); 985*38418Smckusick else 986*38418Smckusick error = VOP_RMDIR(ndp); 987*38418Smckusick nfsm_reply(0); 988*38418Smckusick nfsm_srvdone; 989*38418Smckusick } 990*38418Smckusick 991*38418Smckusick /* 992*38418Smckusick * nfs readdir service 993*38418Smckusick * - mallocs what it thinks is enough to read 994*38418Smckusick * count rounded up to a multiple of DIRBLKSIZ <= MAX_READDIR 995*38418Smckusick * - calls VOP_READDIR() 996*38418Smckusick * - loops arround building the reply 997*38418Smckusick * if the output generated exceeds count break out of loop 998*38418Smckusick * The nfsm_clget macro is used here so that the reply will be packed 999*38418Smckusick * tightly in mbuf clusters. 1000*38418Smckusick * - it only knows that it has encountered eof when the VOP_READDIR() 1001*38418Smckusick * reads nothing 1002*38418Smckusick * - as such one readdir rpc will return eof false although you are there 1003*38418Smckusick * and then the next will return eof 1004*38418Smckusick * - it trims out records with d_ino == 0 1005*38418Smckusick * this doesn't matter for Unix clients, but they might confuse clients 1006*38418Smckusick * for other os'. 1007*38418Smckusick * NB: It is tempting to set eof to true if the VOP_READDIR() reads less 1008*38418Smckusick * than requested, but this may not apply to all filesystems. For 1009*38418Smckusick * example, client NFS does not { although it is never remote mounted 1010*38418Smckusick * anyhow } 1011*38418Smckusick * PS: The NFS protocol spec. does not clarify what the "count" byte 1012*38418Smckusick * argument is a count of.. just name strings and file id's or the 1013*38418Smckusick * entire reply rpc or ... 1014*38418Smckusick * I tried just file name and id sizes and it confused the Sun client, 1015*38418Smckusick * so I am using the full rpc size now. The "paranoia.." comment refers 1016*38418Smckusick * to including the status longwords that are not a part of the dir. 1017*38418Smckusick * "entry" structures, but are in the rpc. 1018*38418Smckusick */ 1019*38418Smckusick nfsrv_readdir(mrep, md, dpos, cred, xid, mrq) 1020*38418Smckusick struct mbuf **mrq; 1021*38418Smckusick struct mbuf *mrep, *md; 1022*38418Smckusick caddr_t dpos; 1023*38418Smckusick struct ucred *cred; 1024*38418Smckusick u_long xid; 1025*38418Smckusick { 1026*38418Smckusick register char *bp, *be; 1027*38418Smckusick register struct mbuf *mp; 1028*38418Smckusick register struct direct *dp; 1029*38418Smckusick nfsm_srvars; 1030*38418Smckusick char *cpos, *cend; 1031*38418Smckusick int len, nlen, rem, xfer, tsiz, i; 1032*38418Smckusick struct vnode *vp; 1033*38418Smckusick struct mbuf *mp2, *mp3; 1034*38418Smckusick nfsv2fh_t nfh; 1035*38418Smckusick fhandle_t *fhp; 1036*38418Smckusick struct uio io; 1037*38418Smckusick struct iovec iv; 1038*38418Smckusick int siz, cnt, fullsiz; 1039*38418Smckusick u_long on; 1040*38418Smckusick char *rbuf; 1041*38418Smckusick off_t off, toff; 1042*38418Smckusick 1043*38418Smckusick fhp = &nfh.fh_generic; 1044*38418Smckusick nfsm_srvmtofh(fhp); 1045*38418Smckusick nfsm_disect(p, u_long *, 2*NFSX_UNSIGNED); 1046*38418Smckusick toff = fxdr_unsigned(off_t, *p++); 1047*38418Smckusick off = (toff & ~(DIRBLKSIZ-1)); 1048*38418Smckusick on = (toff & (DIRBLKSIZ-1)); 1049*38418Smckusick cnt = fxdr_unsigned(int, *p); 1050*38418Smckusick siz = ((cnt+DIRBLKSIZ) & ~(DIRBLKSIZ-1)); 1051*38418Smckusick if (cnt > MAX_READDIR) 1052*38418Smckusick siz = MAX_READDIR; 1053*38418Smckusick fullsiz = siz; 1054*38418Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) 1055*38418Smckusick nfsm_reply(0); 1056*38418Smckusick if (error = vn_access(vp, VEXEC, cred)) { 1057*38418Smckusick vput(vp); 1058*38418Smckusick nfsm_reply(0); 1059*38418Smckusick } 1060*38418Smckusick VOP_UNLOCK(vp); 1061*38418Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 1062*38418Smckusick again: 1063*38418Smckusick iv.iov_base = rbuf; 1064*38418Smckusick iv.iov_len = fullsiz; 1065*38418Smckusick io.uio_iov = &iv; 1066*38418Smckusick io.uio_iovcnt = 1; 1067*38418Smckusick io.uio_offset = off; 1068*38418Smckusick io.uio_resid = fullsiz; 1069*38418Smckusick io.uio_segflg = UIO_SYSSPACE; 1070*38418Smckusick io.uio_rw = UIO_READ; 1071*38418Smckusick error = VOP_READDIR(vp, &io, &off, cred); 1072*38418Smckusick if (error) { 1073*38418Smckusick vrele(vp); 1074*38418Smckusick free((caddr_t)rbuf, M_TEMP); 1075*38418Smckusick nfsm_reply(0); 1076*38418Smckusick } 1077*38418Smckusick if (io.uio_resid) { 1078*38418Smckusick siz -= io.uio_resid; 1079*38418Smckusick 1080*38418Smckusick /* 1081*38418Smckusick * If nothing read, return eof 1082*38418Smckusick * rpc reply 1083*38418Smckusick */ 1084*38418Smckusick if (siz == 0) { 1085*38418Smckusick vrele(vp); 1086*38418Smckusick nfsm_reply(2*NFSX_UNSIGNED); 1087*38418Smckusick nfsm_build(p, u_long *, 2*NFSX_UNSIGNED); 1088*38418Smckusick *p++ = nfs_false; 1089*38418Smckusick *p = nfs_true; 1090*38418Smckusick FREE((caddr_t)rbuf, M_TEMP); 1091*38418Smckusick return (0); 1092*38418Smckusick } 1093*38418Smckusick } 1094*38418Smckusick cpos = rbuf+on; 1095*38418Smckusick cend = rbuf+siz; 1096*38418Smckusick dp = (struct direct *)cpos; 1097*38418Smckusick /* 1098*38418Smckusick * Check for degenerate cases of nothing useful read. 1099*38418Smckusick * If so go try again 1100*38418Smckusick */ 1101*38418Smckusick if (cpos >= cend || (dp->d_ino == 0 && (cpos+dp->d_reclen) >= cend)) { 1102*38418Smckusick toff = off; 1103*38418Smckusick siz = fullsiz; 1104*38418Smckusick on = 0; 1105*38418Smckusick goto again; 1106*38418Smckusick } 1107*38418Smckusick vrele(vp); 1108*38418Smckusick len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 1109*38418Smckusick bp = be = (caddr_t)0; 1110*38418Smckusick mp3 = (struct mbuf *)0; 1111*38418Smckusick nfsm_reply(siz); 1112*38418Smckusick 1113*38418Smckusick /* Loop through the records and build reply */ 1114*38418Smckusick while (cpos < cend) { 1115*38418Smckusick if (dp->d_ino != 0) { 1116*38418Smckusick nlen = dp->d_namlen; 1117*38418Smckusick rem = nfsm_rndup(nlen)-nlen; 1118*38418Smckusick 1119*38418Smckusick /* 1120*38418Smckusick * As noted above, the NFS spec. is not clear about what 1121*38418Smckusick * should be included in "count" as totalled up here in 1122*38418Smckusick * "len". 1123*38418Smckusick */ 1124*38418Smckusick len += (4*NFSX_UNSIGNED+nlen+rem); 1125*38418Smckusick if (len > cnt) 1126*38418Smckusick break; 1127*38418Smckusick 1128*38418Smckusick /* Build the directory record xdr from the direct entry */ 1129*38418Smckusick nfsm_clget; 1130*38418Smckusick *p = nfs_true; 1131*38418Smckusick bp += NFSX_UNSIGNED; 1132*38418Smckusick nfsm_clget; 1133*38418Smckusick *p = txdr_unsigned(dp->d_ino); 1134*38418Smckusick bp += NFSX_UNSIGNED; 1135*38418Smckusick nfsm_clget; 1136*38418Smckusick *p = txdr_unsigned(nlen); 1137*38418Smckusick bp += NFSX_UNSIGNED; 1138*38418Smckusick 1139*38418Smckusick /* And loop arround copying the name */ 1140*38418Smckusick xfer = nlen; 1141*38418Smckusick cp = dp->d_name; 1142*38418Smckusick while (xfer > 0) { 1143*38418Smckusick nfsm_clget; 1144*38418Smckusick if ((bp+xfer) > be) 1145*38418Smckusick tsiz = be-bp; 1146*38418Smckusick else 1147*38418Smckusick tsiz = xfer; 1148*38418Smckusick bcopy(cp, bp, tsiz); 1149*38418Smckusick bp += tsiz; 1150*38418Smckusick xfer -= tsiz; 1151*38418Smckusick if (xfer > 0) 1152*38418Smckusick cp += tsiz; 1153*38418Smckusick } 1154*38418Smckusick /* And null pad to a long boundary */ 1155*38418Smckusick for (i = 0; i < rem; i++) 1156*38418Smckusick *bp++ = '\0'; 1157*38418Smckusick nfsm_clget; 1158*38418Smckusick 1159*38418Smckusick /* Finish off the record */ 1160*38418Smckusick toff += dp->d_reclen; 1161*38418Smckusick *p = txdr_unsigned(toff); 1162*38418Smckusick bp += NFSX_UNSIGNED; 1163*38418Smckusick } else 1164*38418Smckusick toff += dp->d_reclen; 1165*38418Smckusick cpos += dp->d_reclen; 1166*38418Smckusick dp = (struct direct *)cpos; 1167*38418Smckusick } 1168*38418Smckusick nfsm_clget; 1169*38418Smckusick *p = nfs_false; 1170*38418Smckusick bp += NFSX_UNSIGNED; 1171*38418Smckusick nfsm_clget; 1172*38418Smckusick *p = nfs_false; 1173*38418Smckusick bp += NFSX_UNSIGNED; 1174*38418Smckusick if (bp < be) 1175*38418Smckusick mp->m_len = bp-mtod(mp, caddr_t); 1176*38418Smckusick mb->m_next = mp3; 1177*38418Smckusick FREE(rbuf, M_TEMP); 1178*38418Smckusick nfsm_srvdone; 1179*38418Smckusick } 1180*38418Smckusick 1181*38418Smckusick /* 1182*38418Smckusick * nfs statfs service 1183*38418Smckusick */ 1184*38418Smckusick nfsrv_statfs(mrep, md, dpos, cred, xid, mrq) 1185*38418Smckusick struct mbuf **mrq; 1186*38418Smckusick struct mbuf *mrep, *md; 1187*38418Smckusick caddr_t dpos; 1188*38418Smckusick struct ucred *cred; 1189*38418Smckusick u_long xid; 1190*38418Smckusick { 1191*38418Smckusick register struct statfs *sf; 1192*38418Smckusick nfsm_srvars; 1193*38418Smckusick struct vnode *vp; 1194*38418Smckusick nfsv2fh_t nfh; 1195*38418Smckusick fhandle_t *fhp; 1196*38418Smckusick struct statfs statfs; 1197*38418Smckusick 1198*38418Smckusick fhp = &nfh.fh_generic; 1199*38418Smckusick nfsm_srvmtofh(fhp); 1200*38418Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) 1201*38418Smckusick nfsm_reply(0); 1202*38418Smckusick sf = &statfs; 1203*38418Smckusick error = VFS_STATFS(vp->v_mount, sf); 1204*38418Smckusick vput(vp); 1205*38418Smckusick nfsm_reply(NFSX_STATFS); 1206*38418Smckusick nfsm_build(p, u_long *, NFSX_STATFS); 1207*38418Smckusick *p++ = txdr_unsigned(sf->f_bsize); 1208*38418Smckusick *p++ = txdr_unsigned(sf->f_fsize); 1209*38418Smckusick *p++ = txdr_unsigned(sf->f_blocks); 1210*38418Smckusick *p++ = txdr_unsigned(sf->f_bfree); 1211*38418Smckusick *p = txdr_unsigned(sf->f_bavail); 1212*38418Smckusick nfsm_srvdone; 1213*38418Smckusick } 1214*38418Smckusick 1215*38418Smckusick /* 1216*38418Smckusick * Null operation, used by clients to ping server 1217*38418Smckusick */ 1218*38418Smckusick nfsrv_null(mrep, md, dpos, cred, xid, mrq) 1219*38418Smckusick struct mbuf **mrq; 1220*38418Smckusick struct mbuf *mrep, *md; 1221*38418Smckusick caddr_t dpos; 1222*38418Smckusick struct ucred *cred; 1223*38418Smckusick u_long xid; 1224*38418Smckusick { 1225*38418Smckusick nfsm_srvars; 1226*38418Smckusick 1227*38418Smckusick error = VNOVAL; 1228*38418Smckusick nfsm_reply(0); 1229*38418Smckusick nfsm_srvdone; 1230*38418Smckusick } 1231*38418Smckusick 1232*38418Smckusick /* 1233*38418Smckusick * No operation, used for obsolete procedures 1234*38418Smckusick */ 1235*38418Smckusick nfsrv_noop(mrep, md, dpos, cred, xid, mrq) 1236*38418Smckusick struct mbuf **mrq; 1237*38418Smckusick struct mbuf *mrep, *md; 1238*38418Smckusick caddr_t dpos; 1239*38418Smckusick struct ucred *cred; 1240*38418Smckusick u_long xid; 1241*38418Smckusick { 1242*38418Smckusick nfsm_srvars; 1243*38418Smckusick 1244*38418Smckusick error = EPROCUNAVAIL; 1245*38418Smckusick nfsm_reply(0); 1246*38418Smckusick nfsm_srvdone; 1247*38418Smckusick } 1248