int iso_uiodir(struct isoreaddir *idp, struct dirent *dp, off_t off) { int error; dp->d_name[dp->d_namlen] = 0; dp->d_reclen = _DIRENT_SIZE(dp); if (idp->uio->uio_resid < dp->d_reclen) { idp->eofflag = 0; return (-1); } if (idp->cookies) { if (idp->ncookies <= 0) { idp->eofflag = 0; return (-1); } *idp->cookies++ = off; --idp->ncookies; } if ((error = uiomove(dp, dp->d_reclen, idp->uio)) != 0) return (error); idp->uio_off = off; return (0); }
int iso_shipdir(struct isoreaddir *idp) { struct dirent *dp; int cl, sl, assoc; int error; char *cname, *sname; cl = idp->current.d_namlen; cname = idp->current.d_name; if ((assoc = cl > 1 && *cname == ASSOCCHAR)) { cl--; cname++; } dp = &idp->saveent; sname = dp->d_name; if (!(sl = dp->d_namlen)) { dp = &idp->assocent; sname = dp->d_name + 1; sl = dp->d_namlen - 1; } if (sl > 0) { if (sl != cl || memcmp(sname, cname, sl)) { if (idp->assocent.d_namlen) { error = iso_uiodir(idp, &idp->assocent, idp->assocoff); if (error) return (error); idp->assocent.d_namlen = 0; } if (idp->saveent.d_namlen) { error = iso_uiodir(idp, &idp->saveent, idp->saveoff); if (error) return (error); idp->saveent.d_namlen = 0; } } } idp->current.d_reclen = _DIRENT_SIZE(&idp->current); if (assoc) { idp->assocoff = idp->curroff; memcpy(&idp->assocent, &idp->current, idp->current.d_reclen); } else { idp->saveoff = idp->curroff; memcpy(&idp->saveent, &idp->current, idp->current.d_reclen); } return (0); }
int adosfs_readdir(void *v) { struct vop_readdir_args /* { struct vnode *a_vp; struct uio *a_uio; kauth_cred_t a_cred; int *a_eofflag; off_t **a_cookies; int *a_ncookies; } */ *sp = v; int error, first, useri, chainc, hashi, scanned; u_long nextbn; struct dirent ad, *adp; struct anode *pap, *ap; struct vnode *vp; struct uio *uio = sp->a_uio; off_t uoff = uio->uio_offset; off_t *cookies = NULL; int ncookies = 0; #ifdef ADOSFS_DIAGNOSTIC advopprint(sp); #endif if (sp->a_vp->v_type != VDIR) { error = ENOTDIR; goto reterr; } if (uoff < 0) { error = EINVAL; goto reterr; } pap = VTOA(sp->a_vp); adp = &ad; error = nextbn = hashi = chainc = scanned = 0; first = useri = uoff / sizeof ad; /* * If offset requested is not on a slot boundary */ if (uoff % sizeof ad) { error = EINVAL; goto reterr; } for (;;) { if (hashi == pap->ntabent) { *sp->a_eofflag = 1; break; } if (pap->tab[hashi] == 0) { hashi++; continue; } if (nextbn == 0) nextbn = pap->tab[hashi]; /* * First determine if we can skip this chain */ if (chainc == 0) { int skip; skip = useri - scanned; if (pap->tabi[hashi] > 0 && pap->tabi[hashi] <= skip) { scanned += pap->tabi[hashi]; hashi++; nextbn = 0; continue; } } /* * Now [continue to] walk the chain */ ap = NULL; do { error = VFS_VGET(pap->amp->mp, (ino_t)nextbn, &vp); if (error) goto reterr; ap = VTOA(vp); scanned++; chainc++; nextbn = ap->hashf; /* * check for end of chain. */ if (nextbn == 0) { pap->tabi[hashi] = chainc; hashi++; chainc = 0; } else if (pap->tabi[hashi] <= 0 && -chainc < pap->tabi[hashi]) pap->tabi[hashi] = -chainc; if (useri >= scanned) { vput(vp); ap = NULL; } } while (ap == NULL && nextbn != 0); /* * We left the loop but without a result so do main over. */ if (ap == NULL) continue; /* * Fill in dirent record */ memset(adp, 0, sizeof *adp); adp->d_fileno = ap->block; /* * This deserves a function in kern/vfs_subr.c */ switch (ATOV(ap)->v_type) { case VREG: adp->d_type = DT_REG; break; case VDIR: adp->d_type = DT_DIR; break; case VLNK: adp->d_type = DT_LNK; break; default: adp->d_type = DT_UNKNOWN; break; } adp->d_namlen = strlen(ap->name); memcpy(adp->d_name, ap->name, adp->d_namlen); adp->d_reclen = _DIRENT_SIZE(adp); vput(vp); if (adp->d_reclen > uio->uio_resid) { if (useri == first) /* no room for even one entry */ error = EINVAL; break; } error = uiomove(adp, adp->d_reclen, uio); if (error) break; useri++; } ncookies = useri - first; uio->uio_offset = uoff + ncookies * sizeof ad; reterr: #ifdef ADOSFS_DIAGNOSTIC printf(" %d)", error); #endif if (sp->a_ncookies != NULL) { *sp->a_ncookies = ncookies; if (!error) { *sp->a_cookies = cookies = malloc(ncookies * sizeof *cookies, M_TEMP, M_WAITOK); while (ncookies--) { uoff += sizeof ad; *cookies++ = uoff; } } else *sp->a_cookies = NULL; } return(error); }
/* * Vnode op for readdir */ int filecore_readdir(void *v) { struct vop_readdir_args /* { struct vnode *a_vp; struct uio *a_uio; kauth_cred_t a_cred; int *a_eofflag; off_t **a_cookies; int *a_ncookies; } */ *ap = v; struct uio *uio = ap->a_uio; struct vnode *vdp = ap->a_vp; struct filecore_node *dp; struct filecore_mnt *fcmp; struct buf *bp = NULL; struct dirent *de; struct filecore_direntry *dep = NULL; int error = 0; off_t *cookies = NULL; int ncookies = 0; int i; off_t uiooff; dp = VTOI(vdp); if ((dp->i_dirent.attr & FILECORE_ATTR_DIR) == 0) return (ENOTDIR); if (uio->uio_offset % FILECORE_DIRENT_SIZE != 0) return (EINVAL); i = uio->uio_offset / FILECORE_DIRENT_SIZE; uiooff = uio->uio_offset; *ap->a_eofflag = 0; fcmp = dp->i_mnt; error = filecore_dbread(dp, &bp); if (error) { return error; } if (ap->a_ncookies == NULL) cookies = NULL; else { *ap->a_ncookies = 0; ncookies = uio->uio_resid / _DIRENT_MINSIZE((struct dirent *)0); cookies = malloc(ncookies * sizeof(off_t), M_TEMP, M_WAITOK); } de = kmem_zalloc(sizeof(struct dirent), KM_SLEEP); for (; ; i++) { switch (i) { case 0: /* Fake the '.' entry */ de->d_fileno = dp->i_number; de->d_type = DT_DIR; de->d_namlen = 1; strlcpy(de->d_name, ".", sizeof(de->d_name)); break; case 1: /* Fake the '..' entry */ de->d_fileno = filecore_getparent(dp); de->d_type = DT_DIR; de->d_namlen = 2; strlcpy(de->d_name, "..", sizeof(de->d_name)); break; default: de->d_fileno = dp->i_dirent.addr + ((i - 2) << FILECORE_INO_INDEX); dep = fcdirentry(bp->b_data, i - 2); if (dep->attr & FILECORE_ATTR_DIR) de->d_type = DT_DIR; else de->d_type = DT_REG; if (filecore_fn2unix(dep->name, de->d_name, /*###346 [cc] warning: passing arg 3 of `filecore_fn2unix' from incompatible pointer type%%%*/ &de->d_namlen)) { *ap->a_eofflag = 1; goto out; } break; } de->d_reclen = _DIRENT_SIZE(de); if (uio->uio_resid < de->d_reclen) goto out; error = uiomove(de, de->d_reclen, uio); if (error) goto out; uiooff += FILECORE_DIRENT_SIZE; if (cookies) { *cookies++ = i*FILECORE_DIRENT_SIZE; (*ap->a_ncookies)++; if (--ncookies == 0) goto out; } } out: if (cookies) { *ap->a_cookies = cookies; if (error) { free(cookies, M_TEMP); *ap->a_ncookies = 0; *ap->a_cookies = NULL; } } uio->uio_offset = uiooff; #ifdef FILECORE_DEBUG_BR printf("brelse(%p) vn3\n", bp); #endif brelse (bp, 0); kmem_free(de, sizeof(*de)); return (error); }