fallocate: code optimalizations

Based on Pádraig Brady review:

 * use is_nul() from coreutils rather then memcmp()

 * always call skip_hole() (SEEK_DATA)

 * fix possible overflows

Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
Karel Zak 2014-02-19 10:48:16 +01:00
parent c12eff4ce0
commit c4172cc3bb
1 changed files with 29 additions and 18 deletions

View File

@ -130,6 +130,27 @@ static int skip_hole(int fd, off_t *off)
return -1; /* no hole */
}
static int is_nul(void const *buf, size_t bufsize)
{
typedef uintptr_t word;
void const *vp;
char const *cbuf = buf, *cp;
word const *wp = buf;
/* Find first nonzero *word*, or the word with the sentinel. */
while (*wp++ == 0)
continue;
/* Find the first nonzero *byte*, or the sentinel. */
vp = wp - 1;
cp = vp;
while (*cp++ == 0)
continue;
return cbuf + bufsize < cp;
}
static void dig_holes(int fd, off_t off, off_t len)
{
off_t end = len ? off + len : 0;
@ -137,9 +158,8 @@ static void dig_holes(int fd, off_t off, off_t len)
off_t cache_start = 0;
uintmax_t ct = 0;
size_t bufsz, cachesz;
char *buf, *empty;
char *buf;
struct stat st;
int sparse = 0;
if (fstat(fd, &st) != 0)
err(EXIT_FAILURE, _("stat failed %s"), filename);
@ -156,16 +176,10 @@ static void dig_holes(int fd, off_t off, off_t len)
*/
cachesz = getpagesize() * 256;
if (st.st_blocks * 512 < st.st_size) {
if (verbose)
fprintf(stdout, _("%s: already has holes.\n"), filename);
sparse = 1;
}
if (lseek(fd, off, SEEK_SET) < 0)
err(EXIT_FAILURE, _("seek on %s failed"), filename);
buf = xmalloc(bufsz);
empty = xcalloc(1, bufsz);
cache_start = off;
#if defined(POSIX_FADV_SEQUENTIAL) && defined(HAVE_POSIX_FADVISE)
@ -178,20 +192,18 @@ static void dig_holes(int fd, off_t off, off_t len)
rsz = pread(fd, buf, bufsz, off);
if (rsz < 0 && errno)
err(EXIT_FAILURE, _("%s: read failed"), filename);
if (end && rsz > 0 && off + rsz > end)
if (end && rsz > 0 && off > end - rsz)
rsz = end - off;
if (rsz <= 0)
break;
if (memcmp(buf, empty, rsz) == 0) {
if (is_nul(buf, rsz)) {
if (!hole_sz) { /* new hole detected */
if (sparse) {
int rc = skip_hole(fd, &off);
if (rc == 0)
continue; /* hole skipped */
else if (rc == 1)
break; /* end of file */
}
int rc = skip_hole(fd, &off);
if (rc == 0)
continue; /* hole skipped */
else if (rc == 1)
break; /* end of file */
hole_start = off;
}
hole_sz += rsz;
@ -222,7 +234,6 @@ static void dig_holes(int fd, off_t off, off_t len)
}
free(buf);
free(empty);
if (verbose) {
char *str = size_to_human_string(SIZE_SUFFIX_3LETTER | SIZE_SUFFIX_SPACE, ct);