diff options
-rw-r--r-- | lib/util/sys_rw.c | 48 | ||||
-rw-r--r-- | lib/util/sys_rw.h | 1 |
2 files changed, 49 insertions, 0 deletions
diff --git a/lib/util/sys_rw.c b/lib/util/sys_rw.c index 6fa7ca57365..bfeb2e6b466 100644 --- a/lib/util/sys_rw.c +++ b/lib/util/sys_rw.c @@ -144,6 +144,54 @@ ssize_t sys_pread(int fd, void *buf, size_t count, off_t off) } /******************************************************************* + A pread wrapper that will deal with EINTR and never return a short + read unless pread returns zero meaning EOF. +********************************************************************/ + +ssize_t sys_pread_full(int fd, void *buf, size_t count, off_t off) +{ + ssize_t total_read = 0; + uint8_t *curr_buf = (uint8_t *)buf; + size_t curr_count = count; + off_t curr_off = off; + bool ok; + + ok = sys_valid_io_range(off, count); + if (!ok) { + errno = EINVAL; + return -1; + } + + while (curr_count != 0) { + ssize_t ret = sys_pread(fd, + curr_buf, + curr_count, + curr_off); + + if (ret == -1) { + return -1; + } + if (ret == 0) { + /* EOF */ + break; + } + + if (ret > curr_count) { + errno = EIO; + return -1; + } + + curr_buf += ret; + curr_count -= ret; + curr_off += ret; + + total_read += ret; + } + + return total_read; +} + +/******************************************************************* A write wrapper that will deal with EINTR ********************************************************************/ diff --git a/lib/util/sys_rw.h b/lib/util/sys_rw.h index 70864cb2b74..1e0dd3730a6 100644 --- a/lib/util/sys_rw.h +++ b/lib/util/sys_rw.h @@ -34,6 +34,7 @@ ssize_t sys_write(int fd, const void *buf, size_t count); void sys_write_v(int fd, const void *buf, size_t count); ssize_t sys_writev(int fd, const struct iovec *iov, int iovcnt); ssize_t sys_pread(int fd, void *buf, size_t count, off_t off); +ssize_t sys_pread_full(int fd, void *buf, size_t count, off_t off); ssize_t sys_pwrite(int fd, const void *buf, size_t count, off_t off); #endif |