Add WriteFullyAtOffset utility method
There's ReadFullyAtOffset, but not a corresponding one for write. Add
pwrite baesd implementation so that writes at a specific offset can
shave off a seek() syscall.
Test: th
Change-Id: I77b9d12caa012918a8abad7bcba8490606e65c88
diff --git a/file.cpp b/file.cpp
index d0cec7d..71683fd 100644
--- a/file.cpp
+++ b/file.cpp
@@ -337,6 +337,21 @@
}
return static_cast<ssize_t>(bytes_read);
}
+
+static ssize_t pwrite(borrowed_fd fd, const void* data, size_t byte_count, off64_t offset) {
+ DWORD bytes_written;
+ OVERLAPPED overlapped;
+ memset(&overlapped, 0, sizeof(OVERLAPPED));
+ overlapped.Offset = static_cast<DWORD>(offset);
+ overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);
+ if (!WriteFile(reinterpret_cast<HANDLE>(_get_osfhandle(fd.get())), data,
+ static_cast<DWORD>(byte_count), &bytes_written, &overlapped)) {
+ // In case someone tries to read errno (since this is masquerading as a POSIX call)
+ errno = EIO;
+ return -1;
+ }
+ return static_cast<ssize_t>(bytes_written);
+}
#endif
bool ReadFullyAtOffset(borrowed_fd fd, void* data, size_t byte_count, off64_t offset) {
@@ -351,6 +366,19 @@
return true;
}
+bool WriteFullyAtOffset(borrowed_fd fd, const void* data, size_t byte_count, off64_t offset) {
+ const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
+ size_t remaining = byte_count;
+ while (remaining > 0) {
+ ssize_t n = TEMP_FAILURE_RETRY(pwrite(fd.get(), p, remaining, offset));
+ if (n == -1) return false;
+ p += n;
+ remaining -= n;
+ offset += n;
+ }
+ return true;
+}
+
bool WriteFully(borrowed_fd fd, const void* data, size_t byte_count) {
const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
size_t remaining = byte_count;