+ struct nfsnode *np, *tp;
+ struct vnode *newvp;
+ nfsv2fh_t *fhp;
+ u_quad_t frev;
+ int error = 0, tlen, more_dirs = 1, tresid, doit, bigenough, i;
+ int cachable;
+
+ if (uiop->uio_iovcnt != 1)
+ panic("nfs rdirlook");
+ nmp = VFSTONFS(vp->v_mount);
+ tresid = uiop->uio_resid;
+ ndp->ni_dvp = vp;
+ newvp = NULLVP;
+ /*
+ * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
+ * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
+ * The stopping criteria is EOF or buffer full.
+ */
+ while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
+ nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]++;
+ nfsm_reqhead(vp, NQNFSPROC_READDIRLOOK,
+ NFSX_FH + 3 * NFSX_UNSIGNED);
+ nfsm_fhtom(vp);
+ nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
+ off = (u_long)uiop->uio_offset;
+ *tl++ = txdr_unsigned(off);
+ *tl++ = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
+ nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
+ if (nmp->nm_flag & NFSMNT_NQLOOKLEASE)
+ *tl = txdr_unsigned(nmp->nm_leaseterm);
+ else
+ *tl = 0;
+ reqtime = time.tv_sec;
+ nfsm_request(vp, NQNFSPROC_READDIRLOOK, uiop->uio_procp, cred);
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
+ more_dirs = fxdr_unsigned(int, *tl);
+
+ /* loop thru the dir entries, doctoring them to 4bsd form */
+ bigenough = 1;
+ while (more_dirs && bigenough) {
+ doit = 1;
+ nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
+ if (nmp->nm_flag & NFSMNT_NQLOOKLEASE) {
+ cachable = fxdr_unsigned(int, *tl++);
+ ltime = reqtime + fxdr_unsigned(int, *tl++);
+ fxdr_hyper(tl, &frev);
+ }
+ nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
+ if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
+ VREF(vp);
+ newvp = vp;
+ np = VTONFS(vp);
+ } else {
+ if (error = nfs_nget(vp->v_mount, fhp, &np))
+ doit = 0;
+ newvp = NFSTOV(np);
+ }
+ if (error = nfs_loadattrcache(&newvp, &md, &dpos,
+ (struct vattr *)0))
+ doit = 0;
+ nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
+ fileno = fxdr_unsigned(u_long, *tl++);
+ len = fxdr_unsigned(int, *tl);
+ if (len <= 0 || len > NFS_MAXNAMLEN) {
+ error = EBADRPC;
+ m_freem(mrep);
+ goto nfsmout;
+ }
+ tlen = (len + 4) & ~0x3;
+ if ((tlen + DIRHDSIZ) > uiop->uio_resid)
+ bigenough = 0;
+ if (bigenough && doit) {
+ dp = (struct dirent *)uiop->uio_iov->iov_base;
+ dp->d_fileno = fileno;
+ dp->d_namlen = len;
+ dp->d_reclen = tlen + DIRHDSIZ;
+ dp->d_type =
+ IFTODT(VTTOIF(np->n_vattr.va_type));
+ uiop->uio_resid -= DIRHDSIZ;
+ uiop->uio_iov->iov_base += DIRHDSIZ;
+ uiop->uio_iov->iov_len -= DIRHDSIZ;
+ cnp->cn_nameptr = uiop->uio_iov->iov_base;
+ cnp->cn_namelen = len;
+ ndp->ni_vp = newvp;
+ nfsm_mtouio(uiop, len);
+ cp = uiop->uio_iov->iov_base;
+ tlen -= len;
+ for (i = 0; i < tlen; i++)
+ *cp++ = '\0';
+ uiop->uio_iov->iov_base += tlen;
+ uiop->uio_iov->iov_len -= tlen;
+ uiop->uio_resid -= tlen;
+ cnp->cn_hash = 0;
+ for (cp = cnp->cn_nameptr, i = 1; i <= len; i++, cp++)
+ cnp->cn_hash += (unsigned char)*cp * i;
+ if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) &&
+ ltime > time.tv_sec)
+ nqnfs_clientlease(nmp, np, NQL_READ,
+ cachable, ltime, frev);
+ if (cnp->cn_namelen <= NCHNAMLEN)
+ cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);
+ } else {
+ nfsm_adv(nfsm_rndup(len));
+ }
+ if (newvp != NULLVP) {
+ vrele(newvp);
+ newvp = NULLVP;
+ }
+ nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
+ if (bigenough)
+ endoff = off = fxdr_unsigned(u_long, *tl++);
+ else
+ endoff = fxdr_unsigned(u_long, *tl++);
+ more_dirs = fxdr_unsigned(int, *tl);
+ }
+ /*
+ * If at end of rpc data, get the eof boolean
+ */
+ if (!more_dirs) {
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
+ more_dirs = (fxdr_unsigned(int, *tl) == 0);