From 3ba7a89cea85d134eacf1e624e011fe6f66146fc Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 7 May 2020 12:34:32 -0700 Subject: 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 Signed-off-by: Jeremy Allison Signed-off-by: Stefan Metzmacher --- lib/util/sys_rw.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/util/sys_rw.h | 1 + 2 files changed, 50 insertions(+) (limited to 'lib') 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 -- cgit v1.2.1