diff options
author | Rob Landley <rob@landley.net> | 2013-08-08 02:46:45 -0500 |
---|---|---|
committer | Rob Landley <rob@landley.net> | 2013-08-08 02:46:45 -0500 |
commit | 035f27ae4df2b973b8974730bb1b23a25f6160e8 (patch) | |
tree | 12d1520dec29c404882fe915ea94ce76df8e4467 /lib/lib.c | |
parent | 1aa75118c46c8fbe0eeead18974d25e5f13274d5 (diff) | |
download | toybox-035f27ae4df2b973b8974730bb1b23a25f6160e8.tar.gz |
Achille Fouilleul pointed out that fdlength wasn't returning the right length in the binary search case.
(This code was originally written for mke2fs, and applies to block devices. The regular file case should just return the length from stat. The ioctl is left commented out in case I want to add back code to check the size of CDROMs without spinning them up again; not sure the sector size is always right these days.)
Diffstat (limited to 'lib/lib.c')
-rw-r--r-- | lib/lib.c | 36 |
1 files changed, 18 insertions, 18 deletions
@@ -277,42 +277,42 @@ int stridx(char *haystack, char needle) // Return how long the file at fd is, if there's any way to determine it. off_t fdlength(int fd) { - off_t bottom = 0, top = 0, pos, old; - int size; + struct stat st; + off_t base = 0, range = 1, expand = 1, old; - // If the ioctl works for this, return it. + if (!fstat(fd, &st) && S_ISREG(st.st_mode)) return st.st_size; - if (ioctl(fd, BLKGETSIZE, &size) >= 0) return size*512L; + // If the ioctl works for this, return it. + // TODO: is blocksize still always 512, or do we stat for it? + // unsigned int size; + // if (ioctl(fd, BLKGETSIZE, &size) >= 0) return size*512L; // If not, do a binary search for the last location we can read. (Some // block devices don't do BLKGETSIZE right.) This should probably have // a CONFIG option... + // If not, do a binary search for the last location we can read. + old = lseek(fd, 0, SEEK_CUR); do { char temp; - - pos = bottom + (top - bottom) / 2; - - // If we can read from the current location, it's bigger. + off_t pos = base + range / 2; if (lseek(fd, pos, 0)>=0 && read(fd, &temp, 1)==1) { - if (bottom == top) bottom = top = (top+1) * 2; - else bottom = pos; - - // If we can't, it's smaller. + off_t delta = (pos + 1) - base; + base += delta; + if (expand) range = (expand <<= 1) - base; + else range -= delta; } else { - if (bottom == top) { - if (!top) return 0; - bottom = top/2; - } else top = pos; + expand = 0; + range = pos - base; } - } while (bottom + 1 != top); + } while (range > 0); lseek(fd, old, SEEK_SET); - return pos + 1; + return base; } // Read contents of file as a single freshly allocated nul-terminated string. |