📄 nfs_serv.c
字号:
nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); nfsm_build(tl, u_long *, NFSX_UNSIGNED); len = left = cnt; if (cnt > 0) { /* * Generate the mbuf list with the uio_iov ref. to it. */ i = 0; m = m2 = mb; MALLOC(iv, struct iovec *, ((NFS_MAXDATA+MLEN-1)/MLEN) * sizeof (struct iovec), M_TEMP, M_WAITOK); iv2 = iv; while (left > 0) { siz = min(M_TRAILINGSPACE(m), left); if (siz > 0) { m->m_len += siz; iv->iov_base = bpos; iv->iov_len = siz; iv++; i++; left -= siz; } if (left > 0) { MGET(m, M_WAIT, MT_DATA); MCLGET(m, M_WAIT); m->m_len = 0; m2->m_next = m; m2 = m; bpos = mtod(m, caddr_t); } } uiop->uio_iov = iv2; uiop->uio_iovcnt = i; uiop->uio_offset = off; uiop->uio_resid = cnt; uiop->uio_rw = UIO_READ; uiop->uio_segflg = UIO_SYSSPACE; error = VOP_READ(vp, uiop, IO_NODELOCKED, cred); off = uiop->uio_offset; FREE((caddr_t)iv2, M_TEMP); if (error || (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp))) { m_freem(mreq); vput(vp); nfsm_reply(0); } } else uiop->uio_resid = 0; vput(vp); nfsm_srvfillattr; len -= uiop->uio_resid; tlen = nfsm_rndup(len); if (cnt != tlen || tlen != len) nfsm_adj(mb, cnt-tlen, tlen-len); *tl = txdr_unsigned(len); nfsm_srvdone;}/* * nfs write service */nfsrv_write(nfsd, mrep, md, dpos, cred, nam, mrq) struct nfsd *nfsd; struct mbuf *mrep, *md; caddr_t dpos; struct ucred *cred; struct mbuf *nam, **mrq;{ register struct iovec *ivp; register struct mbuf *mp; register struct nfsv2_fattr *fp; struct iovec iv[NFS_MAXIOVEC]; struct vattr va; register struct vattr *vap = &va; register u_long *tl; register long t1; caddr_t bpos; int error = 0, rdonly, cache, siz, len, xfer; int ioflags = IO_SYNC | IO_NODELOCKED; char *cp2; struct mbuf *mb, *mb2, *mreq; struct vnode *vp; nfsv2fh_t nfh; fhandle_t *fhp; struct uio io, *uiop = &io; off_t off; u_quad_t frev; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED); if (nfsd->nd_nqlflag == NQL_NOVAL) { off = (off_t)fxdr_unsigned(u_long, *++tl); tl += 2; } else { fxdr_hyper(tl, &off); tl += 2; if (fxdr_unsigned(u_long, *tl++)) ioflags |= IO_APPEND; } len = fxdr_unsigned(long, *tl); if (len > NFS_MAXDATA || len <= 0) { error = EBADRPC; nfsm_reply(0); } if (dpos == (mtod(md, caddr_t)+md->m_len)) { mp = md->m_next; if (mp == NULL) { error = EBADRPC; nfsm_reply(0); } } else { mp = md; siz = dpos-mtod(mp, caddr_t); mp->m_len -= siz; NFSMADV(mp, siz); } if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) nfsm_reply(0); if (vp->v_type != VREG) { error = (vp->v_type == VDIR) ? EISDIR : EACCES; vput(vp); nfsm_reply(0); } nqsrv_getl(vp, NQL_WRITE); if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) { vput(vp); nfsm_reply(0); } uiop->uio_resid = 0; uiop->uio_rw = UIO_WRITE; uiop->uio_segflg = UIO_SYSSPACE; uiop->uio_procp = (struct proc *)0; /* * Do up to NFS_MAXIOVEC mbufs of write each iteration of the * loop until done. */ while (len > 0 && uiop->uio_resid == 0) { ivp = iv; siz = 0; uiop->uio_iov = ivp; uiop->uio_iovcnt = 0; uiop->uio_offset = off; while (len > 0 && uiop->uio_iovcnt < NFS_MAXIOVEC && mp != NULL) { ivp->iov_base = mtod(mp, caddr_t); if (len < mp->m_len) ivp->iov_len = xfer = len; else ivp->iov_len = xfer = mp->m_len;#ifdef notdef /* Not Yet .. */ if (M_HASCL(mp) && (((u_long)ivp->iov_base) & CLOFSET) == 0) ivp->iov_op = NULL; /* what should it be ?? */ else ivp->iov_op = NULL;#endif uiop->uio_iovcnt++; ivp++; len -= xfer; siz += xfer; mp = mp->m_next; } if (len > 0 && mp == NULL) { error = EBADRPC; vput(vp); nfsm_reply(0); } uiop->uio_resid = siz; if (error = VOP_WRITE(vp, uiop, ioflags, cred)) { vput(vp); nfsm_reply(0); } off = uiop->uio_offset; } error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); vput(vp); nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); nfsm_srvfillattr; if (nfsd->nd_nqlflag != NQL_NOVAL) { nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); txdr_hyper(&vap->va_filerev, tl); } nfsm_srvdone;}/* * nfs create service * now does a truncate to 0 length via. setattr if it already exists */nfsrv_create(nfsd, mrep, md, dpos, cred, nam, mrq) struct nfsd *nfsd; struct mbuf *mrep, *md; caddr_t dpos; struct ucred *cred; struct mbuf *nam, **mrq;{ register struct nfsv2_fattr *fp; struct vattr va; register struct vattr *vap = &va; register struct nfsv2_sattr *sp; register u_long *tl; struct nameidata nd; register caddr_t cp; register long t1; caddr_t bpos; int error = 0, rdev, cache, len, tsize; char *cp2; struct mbuf *mb, *mb2, *mreq; struct vnode *vp; nfsv2fh_t nfh; fhandle_t *fhp; u_quad_t frev; nd.ni_cnd.cn_nameiop = 0; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); nfsm_srvstrsiz(len, NFS_MAXNAMLEN); nd.ni_cnd.cn_cred = cred; nd.ni_cnd.cn_nameiop = CREATE; nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART; if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp)) nfsm_reply(0); VATTR_NULL(vap); nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL)); /* * Iff doesn't exist, create it * otherwise just truncate to 0 length * should I set the mode too ?? */ if (nd.ni_vp == NULL) { vap->va_type = IFTOVT(fxdr_unsigned(u_long, sp->sa_mode)); if (vap->va_type == VNON) vap->va_type = VREG; vap->va_mode = nfstov_mode(sp->sa_mode); if (nfsd->nd_nqlflag == NQL_NOVAL) rdev = fxdr_unsigned(long, sp->sa_nfssize); else rdev = fxdr_unsigned(long, sp->sa_nqrdev); if (vap->va_type == VREG || vap->va_type == VSOCK) { vrele(nd.ni_startdir); nqsrv_getl(nd.ni_dvp, NQL_WRITE); if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) nfsm_reply(0); FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); } else if (vap->va_type == VCHR || vap->va_type == VBLK || vap->va_type == VFIFO) { if (vap->va_type == VCHR && rdev == 0xffffffff) vap->va_type = VFIFO; if (vap->va_type == VFIFO) {#ifndef FIFO VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); vput(nd.ni_dvp); error = ENXIO; goto out;#endif /* FIFO */ } else if (error = suser(cred, (u_short *)0)) { VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); vput(nd.ni_dvp); goto out; } else vap->va_rdev = (dev_t)rdev; nqsrv_getl(nd.ni_dvp, NQL_WRITE); if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) { vrele(nd.ni_startdir); nfsm_reply(0); } nd.ni_cnd.cn_nameiop = LOOKUP; nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART); nd.ni_cnd.cn_proc = nfsd->nd_procp; nd.ni_cnd.cn_cred = nfsd->nd_procp->p_ucred; if (error = lookup(&nd)) { free(nd.ni_cnd.cn_pnbuf, M_NAMEI); nfsm_reply(0); } FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); if (nd.ni_cnd.cn_flags & ISSYMLINK) { vrele(nd.ni_dvp); vput(nd.ni_vp); VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); error = EINVAL; nfsm_reply(0); } } else { VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); vput(nd.ni_dvp); error = ENXIO; goto out; } vp = nd.ni_vp; } else { vrele(nd.ni_startdir); free(nd.ni_cnd.cn_pnbuf, M_NAMEI); vp = nd.ni_vp; if (nd.ni_dvp == vp) vrele(nd.ni_dvp); else vput(nd.ni_dvp); VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); if (nfsd->nd_nqlflag == NQL_NOVAL) { tsize = fxdr_unsigned(long, sp->sa_nfssize); if (tsize != -1) vap->va_size = (u_quad_t)tsize; else vap->va_size = -1; } else fxdr_hyper(&sp->sa_nqsize, &vap->va_size); if (vap->va_size != -1) { if (error = nfsrv_access(vp, VWRITE, cred, (nd.ni_cnd.cn_flags & RDONLY), nfsd->nd_procp)) { vput(vp); nfsm_reply(0); } nqsrv_getl(vp, NQL_WRITE); if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) { vput(vp); nfsm_reply(0); } } } bzero((caddr_t)fhp, sizeof(nfh)); fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { vput(vp); nfsm_reply(0); } error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); vput(vp); nfsm_reply(NFSX_FH+NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); nfsm_srvfhtom(fhp); nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); nfsm_srvfillattr; return (error);nfsmout: if (nd.ni_cnd.cn_nameiop || nd.ni_cnd.cn_flags) vrele(nd.ni_startdir); VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); if (nd.ni_dvp == nd.ni_vp) vrele(nd.ni_dvp); else vput(nd.ni_dvp); if (nd.ni_vp) vput(nd.ni_vp); return (error);out: vrele(nd.ni_startdir); free(nd.ni_cnd.cn_pnbuf, M_NAMEI); nfsm_reply(0);}/* * nfs remove service */nfsrv_remove(nfsd, mrep, md, dpos, cred, nam, mrq) struct nfsd *nfsd; struct mbuf *mrep, *md; caddr_t dpos; struct ucred *cred; struct mbuf *nam, **mrq;{ struct nameidata nd; register u_long *tl; register long t1; caddr_t bpos; int error = 0, cache, len; char *cp2; struct mbuf *mb, *mreq; struct vnode *vp; nfsv2fh_t nfh; fhandle_t *fhp; u_quad_t frev; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); nfsm_srvstrsiz(len, NFS_MAXNAMLEN); nd.ni_cnd.cn_cred = cred; nd.ni_cnd.cn_nameiop = DELETE; nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp)) nfsm_reply(0); vp = nd.ni_vp; if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0))) goto out; /* * The root of a mounted filesystem cannot be deleted. */ if (vp->v_flag & VROOT) { error = EBUSY; goto out; } if (vp->v_flag & VTEXT) (void) vnode_pager_uncache(vp);out: if (!error) { nqsrv_getl(nd.ni_dvp, NQL_WRITE); nqsrv_getl(vp, NQL_WRITE); error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); } else { VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); if (nd.ni_dvp == vp) vrele(nd.ni_dvp); else vput(nd.ni_dvp); vput(vp); } nfsm_reply(0); nfsm_srvdone;}/* * nfs rename service */nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq) struct nfsd *nfsd; struct mbuf *mrep, *md; caddr_t dpos; struct ucred *cred; struct mbuf *nam, **mrq;{ register u_long *tl; register long t1; caddr_t bpos; int error = 0, cache, len, len2; char *cp2; struct mbuf *mb, *mreq; struct nameidata fromnd, tond; struct vnode *fvp, *tvp, *tdvp; nfsv2fh_t fnfh, tnfh; fhandle_t *ffhp, *tfhp; u_quad_t frev; uid_t saved_uid; ffhp = &fnfh.fh_generic; tfhp = &tnfh.fh_generic; fromnd.ni_cnd.cn_nameiop = 0; tond.ni_cnd.cn_nameiop = 0; nfsm_srvmtofh(ffhp); nfsm_srvstrsiz(len, NFS_MAXNAMLEN); /* * Remember our original uid so that we can reset cr_uid before * the second nfs_namei() call, in case it is remapped. */ saved_uid = cred->cr_uid; fromnd.ni_cnd.cn_cred = cred; fromnd.ni_cnd.cn_nameiop = DELETE; fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART; if (error = nfs_namei(&fromnd, ffhp, len, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp)) nfsm_reply(0); fvp = fromnd.ni_vp; nfsm_srvmtofh(tfhp); nfsm_strsiz(len2, NFS_MAXNAMLEN); cred->cr_uid = saved_uid; tond.ni_cnd.cn_cred = cred; tond.ni_cnd.cn_nameiop = RENAME; tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; if (error = nfs_namei(&tond, tfhp, len2, nfsd->nd_slp, nam, &md, &dpos, nfsd->nd_procp)) { VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); vrele(fromnd.ni_dvp); vrele(fvp); goto out1; } tdvp = tond.ni_dvp; tvp = tond.ni_vp; if (tvp != NULL) { if (fvp->v_type == VDIR && tvp->v_type != VDIR) { error = EISDIR; goto out; } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { error = ENOTDIR; goto out; } if (tvp->v_type == VDIR && tvp->v_mountedhere) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -