Date: Sat, 16 Jul 2011 10:43:04 +0000 From: gk@FreeBSD.org To: svn-soc-all@FreeBSD.org Subject: socsvn commit: r224304 - soc2011/gk/ino64-head/sys/ufs/ufs Message-ID: <20110716104304.0F003106564A@hub.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: gk Date: Sat Jul 16 10:43:03 2011 New Revision: 224304 URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=224304 Log: ufs: Use buffer cache in ufs_readdir Return EINVAL if buffer is too small Skip entries with zero inode number Modified: soc2011/gk/ino64-head/sys/ufs/ufs/ufs_vnops.c Modified: soc2011/gk/ino64-head/sys/ufs/ufs/ufs_vnops.c ============================================================================== --- soc2011/gk/ino64-head/sys/ufs/ufs/ufs_vnops.c Sat Jul 16 10:42:52 2011 (r224303) +++ soc2011/gk/ino64-head/sys/ufs/ufs/ufs_vnops.c Sat Jul 16 10:43:03 2011 (r224304) @@ -2130,90 +2130,106 @@ int *a_eofflag; } */ *ap; { + struct vnode *vp = ap->a_vp; struct uio *uio = ap->a_uio; - off_t offset, startoffset; + struct buf *bp; struct inode *ip; struct direct *dp, *edp; - struct dirent dstdp; - struct uio auio; - struct iovec aiov; - caddr_t dirbuf; - int error; - size_t count, readcnt; + struct dirent *dstdp; + off_t offset, startoffset; + size_t readcnt, skipcnt; + ssize_t startresid; + int error = 0; + + if (uio->uio_offset < 0) + return (EINVAL); - ip = VTOI(ap->a_vp); + ip = VTOI(vp); if (ip->i_effnlink == 0) return (0); - count = uio->uio_resid; - /* - * Avoid complications for partial directory entries by adjusting - * the i/o to end at a block boundary. Don't give up (like the old ufs - * does) if the initial adjustment gives a negative count, since - * many callers don't supply a large enough buffer. The correct - * size is a little larger than DIRBLKSIZ to allow for expansion - * of directory entries, but some callers just use 512. - */ + offset = startoffset = uio->uio_offset; - count -= (uio->uio_offset + count) & (DIRBLKSIZ - 1); - if (count <= 0) - count += DIRBLKSIZ; - else if (count > MAXBSIZE) - count = MAXBSIZE; - - auio = *uio; - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_resid = count; - auio.uio_segflg = UIO_SYSSPACE; - aiov.iov_len = count; - dirbuf = malloc(count, M_TEMP, M_WAITOK); - aiov.iov_base = dirbuf; - error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred); - if (error == 0) { - readcnt = count - auio.uio_resid; - edp = (struct direct *)&dirbuf[readcnt]; - bzero(&dstdp, offsetof(struct dirent, d_name)); - for (dp = (struct direct *)dirbuf; - !error && uio->uio_resid > 0 && dp < edp; ) { - dstdp.d_fileno = dp->d_ino; + startresid = uio->uio_resid; + dstdp = malloc(sizeof(struct dirent), M_TEMP, M_WAITOK); + while (error == 0 && uio->uio_resid > 0 && + uio->uio_offset < ip->i_size) { + error = ffs_blkatoff_ra(vp, uio->uio_offset, + startresid, &bp, 2); + if (error) + break; + if (bp->b_offset + bp->b_bcount > ip->i_size) + readcnt = ip->i_size - bp->b_offset; + else + readcnt = bp->b_bcount; + skipcnt = (size_t)(uio->uio_offset - bp->b_offset) & + ~(size_t)(DIRBLKSIZ - 1); + offset = bp->b_offset + skipcnt; + dp = (struct direct *)&bp->b_data[skipcnt]; + edp = (struct direct *)&bp->b_data[readcnt]; + while (error == 0 && uio->uio_resid > 0 && dp < edp) { + if (dp->d_reclen <= 0 || + (caddr_t)dp + dp->d_reclen > (caddr_t)edp) { + error = EIO; + break; + } + if (offset < startoffset) + goto nextentry; + #if BYTE_ORDER == LITTLE_ENDIAN - if (ap->a_vp->v_mount->mnt_maxsymlinklen <= 0) { - dstdp.d_namlen = dp->d_type; - dstdp.d_type = dp->d_namlen; + if (vp->v_mount->mnt_maxsymlinklen <= 0) { + dstdp->d_namlen = dp->d_type; + dstdp->d_type = dp->d_namlen; } else #endif { - dstdp.d_namlen = dp->d_namlen; - dstdp.d_type = dp->d_type; + dstdp->d_namlen = dp->d_namlen; + dstdp->d_type = dp->d_type; } - if (dp->d_reclen > 0 && dstdp.d_namlen <= MAXNAMLEN) { - dstdp.d_off = offset + dp->d_reclen; - dstdp.d_reclen = GENERIC_DIRSIZ(&dstdp); - bcopy(dp->d_name, dstdp.d_name, dstdp.d_namlen); - dstdp.d_name[dstdp.d_namlen] = '\0'; - if(dstdp.d_reclen > uio->uio_resid) - break; - /* advance dp */ - error = uiomove((caddr_t)&dstdp, - dstdp.d_reclen, uio); - if (error == 0) { - offset += dp->d_reclen; - dp = (struct direct *) - ((char *)dp + dp->d_reclen); - } - } else { + if (__offsetof(struct direct, d_name) + + dstdp->d_namlen > dp->d_reclen) { error = EIO; break; } + + if (dp->d_ino == 0) + goto nextentry; + + dstdp->d_fileno = dp->d_ino; + dstdp->d_off = offset + dp->d_reclen; + dstdp->d_reclen = GENERIC_DIRSIZ(dstdp); + bcopy(dp->d_name, dstdp->d_name, dstdp->d_namlen); + dstdp->d_name[dstdp->d_namlen] = '\0'; + if(dstdp->d_reclen > uio->uio_resid) { + if (uio->uio_resid == startresid) + error = EINVAL; + else + error = -1; + break; + } + /* advance dp */ + error = uiomove((caddr_t)dstdp, dstdp->d_reclen, uio); + if (error) + break; +nextentry: + offset += dp->d_reclen; + dp = (struct direct *)((caddr_t)dp + dp->d_reclen); } - /* we need to correct uio_offset */ - uio->uio_offset = startoffset + (caddr_t)dp - dirbuf; + brelse(bp); + uio->uio_offset = offset; } - free(dirbuf, M_TEMP); - if (ap->a_eofflag) - *ap->a_eofflag = VTOI(ap->a_vp)->i_size <= uio->uio_offset; + /* we need to correct uio_offset */ + if (uio->uio_resid == startresid) + uio->uio_offset = startoffset; + else + uio->uio_offset = offset; + + free(dstdp, M_TEMP); + if (error == -1) + error = 0; + if (error == 0 && ap->a_eofflag) + *ap->a_eofflag = ip->i_size <= uio->uio_offset; return (error); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20110716104304.0F003106564A>