diff options
Diffstat (limited to 'lib/util/sys_rw.c')
-rw-r--r-- | lib/util/sys_rw.c | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/lib/util/sys_rw.c b/lib/util/sys_rw.c index bfeb2e6b466..d74395fc409 100644 --- a/lib/util/sys_rw.c +++ b/lib/util/sys_rw.c @@ -204,3 +204,52 @@ ssize_t sys_pwrite(int fd, const void *buf, size_t count, off_t off) } while (ret == -1 && errno == EINTR); return ret; } + +/******************************************************************* + A pwrite wrapper that will deal with EINTR and never allow a short + write unless the file system returns an error. +********************************************************************/ + +ssize_t sys_pwrite_full(int fd, const void *buf, size_t count, off_t off) +{ + ssize_t total_written = 0; + const uint8_t *curr_buf = (const 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_pwrite(fd, + curr_buf, + curr_count, + curr_off); + + if (ret == -1) { + return -1; + } + if (ret == 0) { + /* Ensure we can never spin. */ + errno = ENOSPC; + return -1; + } + + if (ret > curr_count) { + errno = EIO; + return -1; + } + + curr_buf += ret; + curr_count -= ret; + curr_off += ret; + + total_written += ret; + } + + return total_written; +} |