+ while (more_dirs && uiop->uio_resid >= DIRBLKSIZ) {
+ nfsstats.rpccnt[NFSPROC_READDIR]++;
+ nfsm_reqhead(nfs_procids[NFSPROC_READDIR], cred, xid);
+ nfsm_fhtom(vp);
+ nfsm_build(p, u_long *, 2*NFSX_UNSIGNED);
+ *p++ = txdr_unsigned(uiop->uio_offset);
+ *p = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
+ nmp->nm_rsize : uiop->uio_resid) & ~(DIRBLKSIZ-1));
+ nfsm_request(vp, NFSPROC_READDIR, procp, 0);
+ siz = 0;
+ nfsm_disect(p, u_long *, NFSX_UNSIGNED);
+ more_dirs = fxdr_unsigned(int, *p);
+
+ /* Save the position so that we can do nfsm_mtouio() later */
+ dpos2 = dpos;
+ md2 = md;
+
+ /* loop thru the dir entries, doctoring them to 4bsd form */
+ off = uiop->uio_offset;
+#ifdef lint
+ dp = (struct direct *)0;
+#endif /* lint */
+ while (more_dirs && siz < uiop->uio_resid) {
+ savoff = off; /* Hold onto offset and dp */
+ savdp = dp;
+ nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED);
+ dp = (struct direct *)p;
+ dp->d_ino = fxdr_unsigned(u_long, *p++);
+ len = fxdr_unsigned(int, *p);
+ if (len <= 0 || len > NFS_MAXNAMLEN) {
+ error = EBADRPC;
+ m_freem(mrep);
+ goto nfsmout;
+ }
+ dp->d_namlen = (u_short)len;
+ nfsm_adv(len); /* Point past name */
+ tlen = nfsm_rndup(len);
+ /*
+ * This should not be necessary, but some servers have
+ * broken XDR such that these bytes are not null filled.
+ */
+ if (tlen != len) {
+ *dpos = '\0'; /* Null-terminate */
+ nfsm_adv(tlen - len);
+ len = tlen;
+ }
+ nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED);
+ off = fxdr_unsigned(off_t, *p);
+ *p++ = 0; /* Ensures null termination of name */
+ more_dirs = fxdr_unsigned(int, *p);
+ dp->d_reclen = len+4*NFSX_UNSIGNED;
+ siz += dp->d_reclen;
+ }
+ /*
+ * If at end of rpc data, get the eof boolean
+ */
+ if (!more_dirs) {
+ nfsm_disecton(p, u_long *, NFSX_UNSIGNED);
+ more_dirs = (fxdr_unsigned(int, *p) == 0);
+
+ /*
+ * If at EOF, cache directory offset
+ */
+ if (!more_dirs)
+ np->n_direofoffset = off;
+ }
+ /*
+ * If there is too much to fit in the data buffer, use savoff and
+ * savdp to trim off the last record.
+ * --> we are not at eof
+ */
+ if (siz > uiop->uio_resid) {
+ off = savoff;
+ siz -= dp->d_reclen;
+ dp = savdp;
+ more_dirs = 0; /* Paranoia */
+ }
+ if (siz > 0) {
+ lastlen = dp->d_reclen;
+ md = md2;
+ dpos = dpos2;
+ nfsm_mtouio(uiop, siz);
+ uiop->uio_offset = off;
+ } else
+ more_dirs = 0; /* Ugh, never happens, but in case.. */
+ m_freem(mrep);
+ }