📄 nfs_serv.c
字号:
/* * Check for degenerate cases of nothing useful read. * If so go try again */ cpos = rbuf + on; cend = rbuf + siz; dp = (struct dirent *)cpos; while (cpos < cend && dp->d_fileno == 0) { cpos += dp->d_reclen; dp = (struct dirent *)cpos; } if (cpos >= cend) { toff = off; siz = fullsiz; on = 0; goto again; } cpos = rbuf + on; cend = rbuf + siz; dp = (struct dirent *)cpos; len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */ nfsm_reply(siz); mp = mp2 = mb; bp = bpos; be = bp + M_TRAILINGSPACE(mp); /* Loop through the records and build reply */ while (cpos < cend) { if (dp->d_fileno != 0) { nlen = dp->d_namlen; rem = nfsm_rndup(nlen)-nlen; len += (4*NFSX_UNSIGNED + nlen + rem); if (len > cnt) { eofflag = 0; break; } /* * Build the directory record xdr from * the dirent entry. */ nfsm_clget; *tl = nfs_true; bp += NFSX_UNSIGNED; nfsm_clget; *tl = txdr_unsigned(dp->d_fileno); bp += NFSX_UNSIGNED; nfsm_clget; *tl = txdr_unsigned(nlen); bp += NFSX_UNSIGNED; /* And loop around copying the name */ xfer = nlen; cp = dp->d_name; while (xfer > 0) { nfsm_clget; if ((bp+xfer) > be) tsiz = be-bp; else tsiz = xfer; bcopy(cp, bp, tsiz); bp += tsiz; xfer -= tsiz; if (xfer > 0) cp += tsiz; } /* And null pad to a long boundary */ for (i = 0; i < rem; i++) *bp++ = '\0'; nfsm_clget; /* Finish off the record */ toff += dp->d_reclen; *tl = txdr_unsigned(toff); bp += NFSX_UNSIGNED; } else toff += dp->d_reclen; cpos += dp->d_reclen; dp = (struct dirent *)cpos; } vrele(vp); nfsm_clget; *tl = nfs_false; bp += NFSX_UNSIGNED; nfsm_clget; if (eofflag) *tl = nfs_true; else *tl = nfs_false; bp += NFSX_UNSIGNED; if (mp != mb) { if (bp < be) mp->m_len = bp - mtod(mp, caddr_t); } else mp->m_len += bp - bpos; FREE(rbuf, M_TEMP); nfsm_srvdone;}nqnfsrv_readdirlook(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 char *bp, *be; register struct mbuf *mp; register struct dirent *dp; register caddr_t cp; register u_long *tl; register long t1; caddr_t bpos; struct mbuf *mb, *mb2, *mreq, *mp2; char *cpos, *cend, *cp2, *rbuf; struct vnode *vp, *nvp; struct flrep fl; nfsv2fh_t nfh; fhandle_t *fhp; struct uio io; struct iovec iv; struct vattr va, *vap = &va; struct nfsv2_fattr *fp; int len, nlen, rem, xfer, tsiz, i, error = 0, duration2, cache2; int siz, cnt, fullsiz, eofflag, rdonly, cache; u_quad_t frev, frev2; u_long on, off, toff; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED); toff = fxdr_unsigned(u_long, *tl++); off = (toff & ~(NFS_DIRBLKSIZ-1)); on = (toff & (NFS_DIRBLKSIZ-1)); cnt = fxdr_unsigned(int, *tl++); duration2 = fxdr_unsigned(int, *tl); siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); if (cnt > NFS_MAXREADDIR) siz = NFS_MAXREADDIR; fullsiz = siz; if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) nfsm_reply(0); nqsrv_getl(vp, NQL_READ); if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { vput(vp); nfsm_reply(0); } VOP_UNLOCK(vp); MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);again: iv.iov_base = rbuf; iv.iov_len = fullsiz; io.uio_iov = &iv; io.uio_iovcnt = 1; io.uio_offset = (off_t)off; io.uio_resid = fullsiz; io.uio_segflg = UIO_SYSSPACE; io.uio_rw = UIO_READ; io.uio_procp = (struct proc *)0; error = VOP_READDIR(vp, &io, cred); off = (u_long)io.uio_offset; if (error) { vrele(vp); free((caddr_t)rbuf, M_TEMP); nfsm_reply(0); } if (io.uio_resid < fullsiz) eofflag = 0; else eofflag = 1; if (io.uio_resid) { siz -= io.uio_resid; /* * If nothing read, return eof * rpc reply */ if (siz == 0) { vrele(vp); nfsm_reply(2 * NFSX_UNSIGNED); nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); *tl++ = nfs_false; *tl = nfs_true; FREE((caddr_t)rbuf, M_TEMP); return (0); } } /* * Check for degenerate cases of nothing useful read. * If so go try again */ cpos = rbuf + on; cend = rbuf + siz; dp = (struct dirent *)cpos; while (cpos < cend && dp->d_fileno == 0) { cpos += dp->d_reclen; dp = (struct dirent *)cpos; } if (cpos >= cend) { toff = off; siz = fullsiz; on = 0; goto again; } cpos = rbuf + on; cend = rbuf + siz; dp = (struct dirent *)cpos; len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */ nfsm_reply(siz); mp = mp2 = mb; bp = bpos; be = bp + M_TRAILINGSPACE(mp); /* Loop through the records and build reply */ while (cpos < cend) { if (dp->d_fileno != 0) { nlen = dp->d_namlen; rem = nfsm_rndup(nlen)-nlen; /* * For readdir_and_lookup get the vnode using * the file number. */ if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp)) goto invalid; bzero((caddr_t)&fl.fl_nfh, sizeof (nfsv2fh_t)); fl.fl_nfh.fh_generic.fh_fsid = nvp->v_mount->mnt_stat.f_fsid; if (VFS_VPTOFH(nvp, &fl.fl_nfh.fh_generic.fh_fid)) { vput(nvp); goto invalid; } if (duration2) { (void) nqsrv_getlease(nvp, &duration2, NQL_READ, nfsd, nam, &cache2, &frev2, cred); fl.fl_duration = txdr_unsigned(duration2); fl.fl_cachable = txdr_unsigned(cache2); txdr_hyper(&frev2, fl.fl_frev); } else fl.fl_duration = 0; if (VOP_GETATTR(nvp, vap, cred, nfsd->nd_procp)) { vput(nvp); goto invalid; } vput(nvp); fp = (struct nfsv2_fattr *)&fl.fl_fattr; nfsm_srvfillattr; len += (4*NFSX_UNSIGNED + nlen + rem + NFSX_FH + NFSX_NQFATTR); if (len > cnt) { eofflag = 0; break; } /* * Build the directory record xdr from * the dirent entry. */ nfsm_clget; *tl = nfs_true; bp += NFSX_UNSIGNED; /* * For readdir_and_lookup copy the stuff out. */ xfer = sizeof (struct flrep); cp = (caddr_t)&fl; while (xfer > 0) { nfsm_clget; if ((bp+xfer) > be) tsiz = be-bp; else tsiz = xfer; bcopy(cp, bp, tsiz); bp += tsiz; xfer -= tsiz; if (xfer > 0) cp += tsiz; } nfsm_clget; *tl = txdr_unsigned(dp->d_fileno); bp += NFSX_UNSIGNED; nfsm_clget; *tl = txdr_unsigned(nlen); bp += NFSX_UNSIGNED; /* And loop around copying the name */ xfer = nlen; cp = dp->d_name; while (xfer > 0) { nfsm_clget; if ((bp+xfer) > be) tsiz = be-bp; else tsiz = xfer; bcopy(cp, bp, tsiz); bp += tsiz; xfer -= tsiz; if (xfer > 0) cp += tsiz; } /* And null pad to a long boundary */ for (i = 0; i < rem; i++) *bp++ = '\0'; nfsm_clget; /* Finish off the record */ toff += dp->d_reclen; *tl = txdr_unsigned(toff); bp += NFSX_UNSIGNED; } elseinvalid: toff += dp->d_reclen; cpos += dp->d_reclen; dp = (struct dirent *)cpos; } vrele(vp); nfsm_clget; *tl = nfs_false; bp += NFSX_UNSIGNED; nfsm_clget; if (eofflag) *tl = nfs_true; else *tl = nfs_false; bp += NFSX_UNSIGNED; if (mp != mb) { if (bp < be) mp->m_len = bp - mtod(mp, caddr_t); } else mp->m_len += bp - bpos; FREE(rbuf, M_TEMP); nfsm_srvdone;}/* * nfs statfs service */nfsrv_statfs(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 statfs *sf; register struct nfsv2_statfs *sfp; register u_long *tl; register long t1; caddr_t bpos; int error = 0, rdonly, cache, isnq; char *cp2; struct mbuf *mb, *mb2, *mreq; struct vnode *vp; nfsv2fh_t nfh; fhandle_t *fhp; struct statfs statfs; u_quad_t frev; fhp = &nfh.fh_generic; isnq = (nfsd->nd_nqlflag != NQL_NOVAL); nfsm_srvmtofh(fhp); if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) nfsm_reply(0); sf = &statfs; error = VFS_STATFS(vp->v_mount, sf, nfsd->nd_procp); vput(vp); nfsm_reply(NFSX_STATFS(isnq)); nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS(isnq)); sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA); sfp->sf_bsize = txdr_unsigned(sf->f_bsize); sfp->sf_blocks = txdr_unsigned(sf->f_blocks); sfp->sf_bfree = txdr_unsigned(sf->f_bfree); sfp->sf_bavail = txdr_unsigned(sf->f_bavail); if (isnq) { sfp->sf_files = txdr_unsigned(sf->f_files); sfp->sf_ffree = txdr_unsigned(sf->f_ffree); } nfsm_srvdone;}/* * Null operation, used by clients to ping server *//* ARGSUSED */nfsrv_null(nfsd, mrep, md, dpos, cred, nam, mrq) struct nfsd *nfsd; struct mbuf *mrep, *md; caddr_t dpos; struct ucred *cred; struct mbuf *nam, **mrq;{ caddr_t bpos; int error = VNOVAL, cache; struct mbuf *mb, *mreq; u_quad_t frev; nfsm_reply(0); return (error);}/* * No operation, used for obsolete procedures *//* ARGSUSED */nfsrv_noop(nfsd, mrep, md, dpos, cred, nam, mrq) struct nfsd *nfsd; struct mbuf *mrep, *md; caddr_t dpos; struct ucred *cred; struct mbuf *nam, **mrq;{ caddr_t bpos; int error, cache; struct mbuf *mb, *mreq; u_quad_t frev; if (nfsd->nd_repstat) error = nfsd->nd_repstat; else error = EPROCUNAVAIL; nfsm_reply(0); return (error);}/* * Perform access checking for vnodes obtained from file handles that would * refer to files already opened by a Unix client. You cannot just use * vn_writechk() and VOP_ACCESS() for two reasons. * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case * 2 - The owner is to be given access irrespective of mode bits so that * processes that chmod after opening a file don't break. I don't like * this because it opens a security hole, but since the nfs server opens * a security hole the size of a barn door anyhow, what the heck. */nfsrv_access(vp, flags, cred, rdonly, p) register struct vnode *vp; int flags; register struct ucred *cred; int rdonly; struct proc *p;{ struct vattr vattr; int error; if (flags & VWRITE) { /* Just vn_writechk() changed to check rdonly */ /* * Disallow write attempts on read-only file systems; * unless the file is a socket or a block or character * device resident on the file system. */ if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { switch (vp->v_type) { case VREG: case VDIR: case VLNK: return (EROFS); } } /* * If there's shared text associated with * the inode, try to free it up once. If * we fail, we can't allow writing. */ if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) return (ETXTBSY); } if (error = VOP_GETATTR(vp, &vattr, cred, p)) return (error); if ((error = VOP_ACCESS(vp, flags, cred, p)) && cred->cr_uid != vattr.va_uid) return (error); return (0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -