diff options
Diffstat (limited to 'sys/ufs')
-rw-r--r-- | sys/ufs/ext2fs/ext2fs_lookup.c | 24 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_vnops.c | 149 |
2 files changed, 93 insertions, 80 deletions
diff --git a/sys/ufs/ext2fs/ext2fs_lookup.c b/sys/ufs/ext2fs/ext2fs_lookup.c index 79c3729fc72..b8c9837a902 100644 --- a/sys/ufs/ext2fs/ext2fs_lookup.c +++ b/sys/ufs/ext2fs/ext2fs_lookup.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ext2fs_lookup.c,v 1.28 2013/05/30 19:19:09 guenther Exp $ */ +/* $OpenBSD: ext2fs_lookup.c,v 1.29 2013/08/13 05:52:27 guenther Exp $ */ /* $NetBSD: ext2fs_lookup.c,v 1.16 2000/08/03 20:29:26 thorpej Exp $ */ /* @@ -139,8 +139,6 @@ ext2fs_readdir(void *v) struct iovec aiov; caddr_t dirbuf; off_t off = uio->uio_offset; - u_long *cookies = NULL; - int nc = 0, ncookies = 0; int e2d_reclen; if (vp->v_type != VDIR) @@ -161,11 +159,6 @@ ext2fs_readdir(void *v) aiov.iov_len = e2fs_count; auio.uio_resid = e2fs_count; dirbuf = malloc(e2fs_count, M_TEMP, M_WAITOK | M_ZERO); - if (ap->a_ncookies) { - nc = ncookies = e2fs_count / 16; - cookies = malloc(sizeof(*cookies) * ncookies, M_TEMP, M_WAITOK); - *ap->a_cookies = cookies; - } aiov.iov_base = dirbuf; error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred); @@ -182,16 +175,11 @@ ext2fs_readdir(void *v) if(dstd.d_reclen > uio->uio_resid) { break; } + dstd.d_off = off + e2d_reclen; if ((error = uiomove((caddr_t)&dstd, dstd.d_reclen, uio)) != 0) { break; } off = off + e2d_reclen; - if (cookies != NULL) { - *cookies++ = off; - if (--ncookies <= 0){ - break; /* out of cookies */ - } - } /* advance dp */ dp = (struct ext2fs_direct *) ((char *)dp + e2d_reclen); } @@ -200,14 +188,6 @@ ext2fs_readdir(void *v) } free(dirbuf, M_TEMP); *ap->a_eofflag = ext2fs_size(VTOI(ap->a_vp)) <= uio->uio_offset; - if (ap->a_ncookies) { - if (error) { - free(*ap->a_cookies, M_TEMP); - *ap->a_ncookies = 0; - *ap->a_cookies = NULL; - } else - *ap->a_ncookies = nc - ncookies; - } return (error); } diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c index a007fec5c0e..54eefc3135c 100644 --- a/sys/ufs/ufs/ufs_vnops.c +++ b/sys/ufs/ufs/ufs_vnops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ufs_vnops.c,v 1.107 2013/06/11 16:42:19 deraadt Exp $ */ +/* $OpenBSD: ufs_vnops.c,v 1.108 2013/08/13 05:52:27 guenther Exp $ */ /* $NetBSD: ufs_vnops.c,v 1.18 1996/05/11 18:28:04 mycroft Exp $ */ /* @@ -1365,20 +1365,34 @@ ufs_symlink(void *v) /* * Vnode op for reading directories. * - * The routine below assumes that the on-disk format of a directory - * is the same as that defined by <sys/dirent.h>. If the on-disk - * format changes, then it will be necessary to do a conversion - * from the on-disk format that read returns to the format defined - * by <sys/dirent.h>. + * If the 0x10 bit in uio_segflg is set then this routine will assume + * that the caller wants the on-disk format of the directory, which + * 'happens' to be the same as that defined by struct direct32 in + * <sys/dirent.h>. + * Otherwise, this routine will convert struct direct entries to struct + * dirent entries. */ int ufs_readdir(void *v) { struct vop_readdir_args *ap = v; - struct uio *uio = ap->a_uio; - int error; - size_t count, lost, entries; + struct uio auio, *uio = ap->a_uio; + struct iovec aiov; + union { + struct dirent dn; + char __pad[roundup(sizeof(struct dirent), 8)]; + } u; off_t off = uio->uio_offset; + struct direct *dp, *edp; + caddr_t diskbuf; + size_t count, entries; + int readcnt, error; +#if (BYTE_ORDER == LITTLE_ENDIAN) + int ofmt = ap->a_vp->v_mount->mnt_maxsymlinklen <= 0; +#endif + + if (uio->uio_rw != UIO_READ) + return (EINVAL); count = uio->uio_resid; entries = (uio->uio_offset + count) & (DIRBLKSIZ - 1); @@ -1387,19 +1401,19 @@ ufs_readdir(void *v) if (count <= entries) return (EINVAL); - count -= entries; - lost = uio->uio_resid - count; - uio->uio_resid = count; - uio->uio_iov->iov_len = count; +#if T32 + if (uio->uio_segflg & 0x10) { + uio->uio_segflg &= ~0x10; + + count -= entries; + uio->uio_resid = count; + uio->uio_iov->iov_len = count; + # if (BYTE_ORDER == LITTLE_ENDIAN) - if (ap->a_vp->v_mount->mnt_maxsymlinklen > 0) { + if (! ofmt) error = VOP_READ(ap->a_vp, uio, 0, ap->a_cred); - } else { - struct dirent *dp, *edp; - struct uio auio; - struct iovec aiov; + else { caddr_t dirbuf; - int readcnt; u_char tmp; auio = *uio; @@ -1412,13 +1426,13 @@ ufs_readdir(void *v) error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred); if (error == 0) { readcnt = count - auio.uio_resid; - edp = (struct dirent *)&dirbuf[readcnt]; - for (dp = (struct dirent *)dirbuf; dp < edp; ) { + edp = (struct direct *)&dirbuf[readcnt]; + for (dp = (struct direct *)dirbuf; dp < edp; ) { tmp = dp->d_namlen; dp->d_namlen = dp->d_type; dp->d_type = tmp; if (dp->d_reclen > 0) { - dp = (struct dirent *) + dp = (struct direct *) ((char *)dp + dp->d_reclen); } else { error = EIO; @@ -1433,46 +1447,65 @@ ufs_readdir(void *v) # else error = VOP_READ(ap->a_vp, uio, 0, ap->a_cred); # endif - if (!error && ap->a_ncookies) { - struct dirent *dp, *dpstart; - off_t offstart; - u_long *cookies; - int ncookies; - /* - * Only the NFS server and emulations use cookies, and they - * load the directory block into system space, so we can - * just look at it directly. - */ - if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1) - panic("ufs_readdir: lost in space"); - - dpstart = (struct dirent *) - ((char *)uio->uio_iov->iov_base - - (uio->uio_offset - off)); - offstart = off; - for (dp = dpstart, ncookies = 0; off < uio->uio_offset; ) { - if (dp->d_reclen == 0) - break; - off += dp->d_reclen; - ncookies++; - dp = (struct dirent *)((caddr_t)dp + dp->d_reclen); - } - lost += uio->uio_offset - off; - uio->uio_offset = off; - cookies = malloc(ncookies * sizeof(u_long), M_TEMP, M_WAITOK); - *ap->a_ncookies = ncookies; - *ap->a_cookies = cookies; - for (off = offstart, dp = dpstart; off < uio->uio_offset; ) { - off += dp->d_reclen; - *cookies = off; - cookies++; - dp = (struct dirent *)((caddr_t)dp + dp->d_reclen); + *ap->a_eofflag = DIP(VTOI(ap->a_vp), size) <= uio->uio_offset; + return error; + } +#endif /* T32 */ + + /* + * Convert and copy back the on-disk struct direct format to + * the user-space struct dirent format, one entry at a time + */ + + /* read from disk, stopping on a block boundary, max 64kB */ + readcnt = max(count, 64*1024) - entries; + + auio = *uio; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_resid = readcnt; + auio.uio_segflg = UIO_SYSSPACE; + aiov.iov_len = readcnt; + diskbuf = malloc(readcnt, M_TEMP, M_WAITOK); + aiov.iov_base = diskbuf; + error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred); + readcnt -= auio.uio_resid; + dp = (struct direct *)diskbuf; + edp = (struct direct *)&diskbuf[readcnt]; + while (error == 0 && dp < edp) { + if (dp->d_reclen <= offsetof(struct direct, d_name)) { + error = EIO; + break; } + u.dn.d_reclen = roundup(dp->d_namlen+1 + + offsetof(struct dirent, d_name), 8); + if (u.dn.d_reclen > uio->uio_resid) + break; + off += dp->d_reclen; + u.dn.d_off = off; + u.dn.d_fileno = dp->d_ino; +#if (BYTE_ORDER == LITTLE_ENDIAN) + if (ofmt) { + u.dn.d_type = dp->d_namlen; + u.dn.d_namlen = dp->d_type; + } else +#endif + { + u.dn.d_type = dp->d_type; + u.dn.d_namlen = dp->d_namlen; + } + memcpy(u.dn.d_name, dp->d_name, u.dn.d_namlen); + bzero(u.dn.d_name + u.dn.d_namlen, u.dn.d_reclen + - u.dn.d_namlen - offsetof(struct dirent, d_name)); + + error = uiomove(&u.dn, u.dn.d_reclen, uio); + dp = (struct direct *)((char *)dp + dp->d_reclen); } + free(diskbuf, M_TEMP); - uio->uio_resid += lost; - *ap->a_eofflag = DIP(VTOI(ap->a_vp), size) <= uio->uio_offset; + uio->uio_offset = off; + *ap->a_eofflag = DIP(VTOI(ap->a_vp), size) <= off; return (error); } |