diff options
author | Jeremy Allison <jra@samba.org> | 2020-05-07 12:34:32 -0700 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2020-05-12 19:53:43 +0000 |
commit | 3ba7a89cea85d134eacf1e624e011fe6f66146fc (patch) | |
tree | ab36d19206d2c25fdb7d6c526231183ec6207b94 /lib | |
parent | 36af33bf9fcdf93fce5ef1520fcb7ddbb07b355e (diff) | |
download | samba-3ba7a89cea85d134eacf1e624e011fe6f66146fc.tar.gz |
lib: util: Add sys_pwrite_full().
A pwrite wrapper that will deal with EINTR and never return a short
write unless the file system returns an error. Copes with the
unspecified edge condition of pwrite returning zero by changing
the return to -1, errno = ENOSPC.
Thread-safe so may be used as a replacement for pwrite
inside pwrite_do() thread functions.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14361
Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>
Signed-off-by: Jeremy Allison <jra@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/util/sys_rw.c | 49 | ||||
-rw-r--r-- | lib/util/sys_rw.h | 1 |
2 files changed, 50 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; +} diff --git a/lib/util/sys_rw.h b/lib/util/sys_rw.h index 1e0dd3730a6..b224ecb30ac 100644 --- a/lib/util/sys_rw.h +++ b/lib/util/sys_rw.h @@ -36,5 +36,6 @@ 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); +ssize_t sys_pwrite_full(int fd, const void *buf, size_t count, off_t off); #endif |