diff options
author | Eric Engestrom <[email protected]> | 2019-05-01 11:44:16 +0100 |
---|---|---|
committer | Eric Engestrom <[email protected]> | 2019-05-16 12:56:25 +0100 |
commit | 22c1657d0552be0c558ca805c8d574e92f53c2cc (patch) | |
tree | 73425d7875600734864050615c3e35f24d7a8d51 | |
parent | e04cf0b61269ca60b3260d81d94e625965d39901 (diff) |
util/os_file: always use the 'grow' mechanism
Use fstat() only to pre-allocate a big enough buffer.
This fixes a race where if the file grows between fstat() and read()
we would be missing the end of the file, and if the file slims down
read() would just fail.
Fixes: 316964709e21286c2af5 "util: add os_read_file() helper"
Reported-by: Jason Ekstrand <[email protected]>
Signed-off-by: Eric Engestrom <[email protected]>
Reviewed-by: Jason Ekstrand <[email protected]>
-rw-r--r-- | src/util/os_file.c | 62 |
1 files changed, 20 insertions, 42 deletions
diff --git a/src/util/os_file.c b/src/util/os_file.c index ee34a75a2e0..246fd32fdf6 100644 --- a/src/util/os_file.c +++ b/src/util/os_file.c @@ -38,11 +38,29 @@ readN(int fd, char *buf, size_t len) return total ? total : err; } -static char * -read_grow(int fd) +char * +os_read_file(const char *filename) { + /* Note that this also serves as a slight margin to avoid a 2x grow when + * the file is just a few bytes larger when we read it than when we + * fstat'ed it. + * The string's NULL terminator is also included in here. + */ size_t len = 64; + int fd = open(filename, O_RDONLY); + if (fd == -1) { + /* errno set by open() */ + return NULL; + } + + /* Pre-allocate a buffer at least the size of the file if we can read + * that information. + */ + struct stat stat; + if (fstat(fd, &stat) == 0) + len += stat.st_size; + char *buf = malloc(len); if (!buf) { close(fd); @@ -77,46 +95,6 @@ read_grow(int fd) return buf; } -char * -os_read_file(const char *filename) -{ - size_t len = 0; - - int fd = open(filename, O_RDONLY); - if (fd == -1) { - /* errno set by open() */ - return NULL; - } - - struct stat stat; - if (fstat(fd, &stat) == 0) - len = stat.st_size; - - if (!len) - return read_grow(fd); - - /* add NULL terminator */ - len++; - - char *buf = malloc(len); - if (!buf) { - close(fd); - errno = -ENOMEM; - return NULL; - } - - ssize_t read = readN(fd, buf, len - 1); - - close(fd); - - if (read == -1) - return NULL; - - buf[read] = '\0'; - - return buf; -} - #else char * |