]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
lib: util: Add sys_pwrite_full().
authorJeremy Allison <jra@samba.org>
Thu, 7 May 2020 19:34:32 +0000 (12:34 -0700)
committerJeremy Allison <jra@samba.org>
Tue, 12 May 2020 19:53:43 +0000 (19:53 +0000)
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>
lib/util/sys_rw.c
lib/util/sys_rw.h

index bfeb2e6b4661177171e3fa5cdbcd046bf1e0ac7f..d74395fc409143fbc5a2cc3e2d0bb4e6a1100d3f 100644 (file)
@@ -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;
+}
index 1e0dd3730a60d9d8ee84711942f776b20dcbca3c..b224ecb30ac7ca949f61fbc80c0d42db5264eace 100644 (file)
@@ -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