/*ARGSUSED*/ int puffs_null_node_readdir(struct puffs_usermount *pu, puffs_cookie_t opc, struct dirent *de, off_t *off, size_t *reslen, const struct puffs_cred *pcred, int *eofflag, off_t *cookies, size_t *ncookies) { struct puffs_node *pn = opc; struct dirent entry, *result; DIR *dp; off_t i; int rv; *ncookies = 0; dp = opendir(PNPATH(pn)); if (dp == NULL) return errno; rv = 0; i = *off; /* * XXX: need to do trickery here, telldir/seekdir would be nice, but * then we'd need to keep state, which I'm too lazy to keep */ while (i--) { rv = readdir_r(dp, &entry, &result); if (rv || !result) goto out; } for (;;) { rv = readdir_r(dp, &entry, &result); if (rv != 0) goto out; if (!result) { *eofflag = 1; goto out; } if (_DIRENT_SIZE(result) > *reslen) goto out; *de = *result; *reslen -= _DIRENT_SIZE(result); de = _DIRENT_NEXT(de); (*off)++; PUFFS_STORE_DCOOKIE(cookies, ncookies, *off); } out: closedir(dp); return 0; }
int puffs_nextdent(struct dirent **dent, const char *name, ino_t id, uint8_t dtype, size_t *reslen) { struct dirent *d = *dent; unsigned int len, reclen; int o; char *cp; /* check if we have enough room for our dent-aligned dirent */ if (_DIRENT_RECLEN(d, strlen(name)) > *reslen) return 0; d->d_ino = id; /* Compute the length of the name */ cp = memchr(name, '\0', NAME_MAX); if (cp == NULL) len = NAME_MAX; else len = cp - (name); /* Compute record length */ reclen = offsetof(struct dirent, d_name) + len + 1; o = (reclen % sizeof(long)); if (o != 0) reclen += sizeof(long) - o; /* FIXME: Set d_off? * dep->d_off = */ d->d_reclen = (unsigned short) reclen; (void)memcpy(d->d_name, name, (size_t)len); d->d_name[len] = '\0'; *reslen -= d->d_reclen; *dent = _DIRENT_NEXT(d); return 1; }
/* * Vnode op for reading directories. * * This routine handles converting from the on-disk directory format * "struct direct" to the in-memory format "struct dirent" as well as * byte swapping the entries if necessary. */ int ufs_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 *ncookies; } */ *ap = v; struct vnode *vp = ap->a_vp; struct direct *cdp, *ecdp; struct dirent *ndp; char *cdbuf, *ndbuf, *endp; struct uio auio, *uio; struct iovec aiov; int error; size_t count, ccount, rcount, cdbufsz, ndbufsz; off_t off, *ccp; off_t startoff; size_t skipbytes; struct ufsmount *ump = VFSTOUFS(vp->v_mount); int nswap = UFS_MPNEEDSWAP(ump); #if BYTE_ORDER == LITTLE_ENDIAN int needswap = ump->um_maxsymlinklen <= 0 && nswap == 0; #else int needswap = ump->um_maxsymlinklen <= 0 && nswap != 0; #endif uio = ap->a_uio; count = uio->uio_resid; rcount = count - ((uio->uio_offset + count) & (ump->um_dirblksiz - 1)); if (rcount < _DIRENT_MINSIZE(cdp) || count < _DIRENT_MINSIZE(ndp)) return EINVAL; startoff = uio->uio_offset & ~(ump->um_dirblksiz - 1); skipbytes = uio->uio_offset - startoff; rcount += skipbytes; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_offset = startoff; auio.uio_resid = rcount; UIO_SETUP_SYSSPACE(&auio); auio.uio_rw = UIO_READ; cdbufsz = rcount; cdbuf = kmem_alloc(cdbufsz, KM_SLEEP); aiov.iov_base = cdbuf; aiov.iov_len = rcount; error = VOP_READ(vp, &auio, 0, ap->a_cred); if (error != 0) { kmem_free(cdbuf, cdbufsz); return error; } rcount -= auio.uio_resid; cdp = (struct direct *)(void *)cdbuf; ecdp = (struct direct *)(void *)&cdbuf[rcount]; ndbufsz = count; ndbuf = kmem_alloc(ndbufsz, KM_SLEEP); ndp = (struct dirent *)(void *)ndbuf; endp = &ndbuf[count]; off = uio->uio_offset; if (ap->a_cookies) { ccount = rcount / _DIRENT_RECLEN(cdp, 1); ccp = *(ap->a_cookies) = malloc(ccount * sizeof(*ccp), M_TEMP, M_WAITOK); } else { /* XXX: GCC */ ccount = 0; ccp = NULL; } while (cdp < ecdp) { cdp->d_reclen = ufs_rw16(cdp->d_reclen, nswap); if (skipbytes > 0) { if (cdp->d_reclen <= skipbytes) { skipbytes -= cdp->d_reclen; cdp = _DIRENT_NEXT(cdp); continue; } /* * invalid cookie. */ error = EINVAL; goto out; } if (cdp->d_reclen == 0) { struct dirent *ondp = ndp; ndp->d_reclen = _DIRENT_MINSIZE(ndp); ndp = _DIRENT_NEXT(ndp); ondp->d_reclen = 0; cdp = ecdp; break; } if (needswap) { ndp->d_type = cdp->d_namlen; ndp->d_namlen = cdp->d_type; } else { ndp->d_type = cdp->d_type; ndp->d_namlen = cdp->d_namlen; } ndp->d_reclen = _DIRENT_RECLEN(ndp, ndp->d_namlen); if ((char *)(void *)ndp + ndp->d_reclen + _DIRENT_MINSIZE(ndp) > endp) break; ndp->d_fileno = ufs_rw32(cdp->d_ino, nswap); (void)memcpy(ndp->d_name, cdp->d_name, ndp->d_namlen); memset(&ndp->d_name[ndp->d_namlen], 0, ndp->d_reclen - _DIRENT_NAMEOFF(ndp) - ndp->d_namlen); off += cdp->d_reclen; if (ap->a_cookies) { KASSERT(ccp - *(ap->a_cookies) < ccount); *(ccp++) = off; } ndp = _DIRENT_NEXT(ndp); cdp = _DIRENT_NEXT(cdp); } count = ((char *)(void *)ndp - ndbuf); error = uiomove(ndbuf, count, uio); out: if (ap->a_cookies) { if (error) { free(*(ap->a_cookies), M_TEMP); *(ap->a_cookies) = NULL; *(ap->a_ncookies) = 0; } else { *ap->a_ncookies = ccp - *(ap->a_cookies); } } uio->uio_offset = off; kmem_free(ndbuf, ndbufsz); kmem_free(cdbuf, cdbufsz); *ap->a_eofflag = VTOI(vp)->i_size <= uio->uio_offset; return error; }
/* * MPALMOSTSAFE */ int sys_ogetdirentries(struct ogetdirentries_args *uap) { int error, bytes_transfered; char *buf, *outbuf; size_t len; struct dirent *ndp; struct odirent *destdp; long base; if (uap->count > 16384) len = 16384; else len = uap->count; buf = kmalloc(len, M_TEMP, M_WAITOK); get_mplock(); error = kern_getdirentries(uap->fd, buf, len, &base, &bytes_transfered, UIO_SYSSPACE); rel_mplock(); if (error) { kfree(buf, M_TEMP); return(error); } ndp = (struct dirent *)buf; outbuf = uap->buf; destdp = kmalloc(PADDED_SIZE(MAX_NAMELEN), M_TEMP, M_WAITOK); for (; (char *)ndp < buf + bytes_transfered; ndp = _DIRENT_NEXT(ndp)) { if ((char *)_DIRENT_NEXT(ndp) > buf + bytes_transfered) break; if (ndp->d_namlen > MAX_NAMELEN) continue; destdp->od_fileno = ndp->d_ino; #if BYTE_ORDER == LITTLE_ENDIAN destdp->od_type = ndp->d_namlen; destdp->od_namlen = ndp->d_type; #else destdp->od_type = ndp->d_type; destdp->od_namlen = ndp->d_namlen; #endif destdp->od_reclen = PADDED_SIZE(destdp->od_namlen); if (destdp->od_reclen > len) break; /* XXX can not happen */ bcopy(ndp->d_name, destdp->od_name, destdp->od_namlen); bzero(destdp->od_name + destdp->od_namlen, PADDED_SIZE(destdp->od_namlen) - sizeof(*destdp) - destdp->od_namlen); error = copyout(destdp, outbuf, PADDED_SIZE(destdp->od_namlen)); if (error) break; outbuf += PADDED_SIZE(destdp->od_namlen); len -= PADDED_SIZE(destdp->od_namlen); } kfree(destdp, M_TEMP); kfree(buf, M_TEMP); uap->sysmsg_iresult = (int)(outbuf - uap->buf); return (0); }
/* * Vnode op for reading directories. * * This routine handles converting from the on-disk directory format * "struct lfs_direct" to the in-memory format "struct dirent" as well as * byte swapping the entries if necessary. */ int ulfs_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 *ncookies; } */ *ap = v; struct vnode *vp = ap->a_vp; LFS_DIRHEADER *cdp, *ecdp; struct dirent *ndp; char *cdbuf, *ndbuf, *endp; struct uio auio, *uio; struct iovec aiov; int error; size_t count, ccount, rcount, cdbufsz, ndbufsz; off_t off, *ccp; off_t startoff; size_t skipbytes; struct ulfsmount *ump = VFSTOULFS(vp->v_mount); struct lfs *fs = ump->um_lfs; uio = ap->a_uio; count = uio->uio_resid; rcount = count - ((uio->uio_offset + count) & (fs->um_dirblksiz - 1)); if (rcount < LFS_DIRECTSIZ(fs, 0) || count < _DIRENT_MINSIZE(ndp)) return EINVAL; startoff = uio->uio_offset & ~(fs->um_dirblksiz - 1); skipbytes = uio->uio_offset - startoff; rcount += skipbytes; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_offset = startoff; auio.uio_resid = rcount; UIO_SETUP_SYSSPACE(&auio); auio.uio_rw = UIO_READ; cdbufsz = rcount; cdbuf = kmem_alloc(cdbufsz, KM_SLEEP); aiov.iov_base = cdbuf; aiov.iov_len = rcount; error = VOP_READ(vp, &auio, 0, ap->a_cred); if (error != 0) { kmem_free(cdbuf, cdbufsz); return error; } rcount -= auio.uio_resid; cdp = (LFS_DIRHEADER *)(void *)cdbuf; ecdp = (LFS_DIRHEADER *)(void *)&cdbuf[rcount]; ndbufsz = count; ndbuf = kmem_alloc(ndbufsz, KM_SLEEP); ndp = (struct dirent *)(void *)ndbuf; endp = &ndbuf[count]; off = uio->uio_offset; if (ap->a_cookies) { ccount = rcount / _DIRENT_RECLEN(ndp, 1); ccp = *(ap->a_cookies) = malloc(ccount * sizeof(*ccp), M_TEMP, M_WAITOK); } else { /* XXX: GCC */ ccount = 0; ccp = NULL; } while (cdp < ecdp) { if (skipbytes > 0) { if (lfs_dir_getreclen(fs, cdp) <= skipbytes) { skipbytes -= lfs_dir_getreclen(fs, cdp); cdp = LFS_NEXTDIR(fs, cdp); continue; } /* * invalid cookie. */ error = EINVAL; goto out; } if (lfs_dir_getreclen(fs, cdp) == 0) { struct dirent *ondp = ndp; ndp->d_reclen = _DIRENT_MINSIZE(ndp); ndp = _DIRENT_NEXT(ndp); ondp->d_reclen = 0; cdp = ecdp; break; } ndp->d_type = lfs_dir_gettype(fs, cdp); ndp->d_namlen = lfs_dir_getnamlen(fs, cdp); ndp->d_reclen = _DIRENT_RECLEN(ndp, ndp->d_namlen); if ((char *)(void *)ndp + ndp->d_reclen + _DIRENT_MINSIZE(ndp) > endp) break; ndp->d_fileno = lfs_dir_getino(fs, cdp); (void)memcpy(ndp->d_name, lfs_dir_nameptr(fs, cdp), ndp->d_namlen); memset(&ndp->d_name[ndp->d_namlen], 0, ndp->d_reclen - _DIRENT_NAMEOFF(ndp) - ndp->d_namlen); off += lfs_dir_getreclen(fs, cdp); if (ap->a_cookies) { KASSERT(ccp - *(ap->a_cookies) < ccount); *(ccp++) = off; } ndp = _DIRENT_NEXT(ndp); cdp = LFS_NEXTDIR(fs, cdp); } count = ((char *)(void *)ndp - ndbuf); error = uiomove(ndbuf, count, uio); out: if (ap->a_cookies) { if (error) { free(*(ap->a_cookies), M_TEMP); *(ap->a_cookies) = NULL; *(ap->a_ncookies) = 0; } else { *ap->a_ncookies = ccp - *(ap->a_cookies); } } uio->uio_offset = off; kmem_free(ndbuf, ndbufsz); kmem_free(cdbuf, cdbufsz); *ap->a_eofflag = VTOI(vp)->i_size <= uio->uio_offset; return error; }