Hello, fdlength in lib.c does not seem to work properly, I noticed this when toybox's insmod sometimes failed mysteriously. I have attached a patch that should fix the issue, along with a test case that evidences the issue (use -std=c99).
Regards, Achille
patch-fix-fdlength.diff
Description: Binary data
#include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <errno.h> #include <fcntl.h> #include <assert.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> // Return how long the file at fd is, if there's any way to determine it. off_t fdlength_old(int fd) { off_t bottom = 0, top = 0, pos, old; int size; // 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. 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. } else { if (bottom == top) { if (!top) return 0; bottom = top/2; } else top = pos; } } while (bottom + 1 != top); lseek(fd, old, SEEK_SET); return pos + 1; } static bool testread(int fd, int pos) { char temp; return lseek(fd, pos, SEEK_SET) >= 0 && read(fd, &temp, 1) == 1; } int fdlength_new(int fd) { int old = lseek(fd, 0, SEEK_CUR); #ifdef CHEAT int n = lseek(fd, 0, SEEK_END); if (n >= 0) { lseek(fd, old, SEEK_SET); return n; } #endif int bottom = 0, top = 0; // ensure top is not readable while (testread(fd, top)) { top = (top + 1) * 2; // XXX: might overflow } if (top == 0) return 0; for (;;) { int pos = bottom + (top - bottom) / 2; if (testread(fd, pos)) { if (pos + 1 == top) { lseek(fd, old, SEEK_SET); return top; } bottom = pos; } else { top = pos; } } } static const char zero_path[] = "/tmp/zero"; static int zero_create(int size) { int fd = open(zero_path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); if (fd < 0) return fd; char block[4096]; memset(block, 0, sizeof(block)); while (size > 0) { int n = size <= (int)sizeof(block) ? size : (int)sizeof(block); write(fd, block, n); size -= n; } close(fd); return open(zero_path, O_RDONLY); } static void zero_delete() { unlink(zero_path); } int main() { for (int i = 0; i < 1024; ++i) { int fd = zero_create(i); if (fd < 0) return 1; int n_old = fdlength_old(fd); int n_new = fdlength_new(fd); assert(n_new == i); if (n_old != i) printf("length = %d, n_old = %d, n_new = %d\n", i, n_old, n_new); close(fd); zero_delete(); } return 0; }
_______________________________________________ Toybox mailing list Toybox@lists.landley.net http://lists.landley.net/listinfo.cgi/toybox-landley.net