posix/fd: fix the win32 pwrite emulation
We had assumed that WriteFile/OVERLAPPED operations didn't modify the file cursor. This was wrong. We emulate the POSIX behaviour using a few explicit seek calls. This introduces an incorrect transient state, but isn't a huge problem for our use cases.
This commit is contained in:
parent
0db1d54a93
commit
d0950a97fa
26
posix/fd.cpp
26
posix/fd.cpp
@ -180,14 +180,26 @@ fd::pwrite (const void *buf, size_t count, size_t offset)
|
||||
::pwrite (native (), buf, count, offset)
|
||||
);
|
||||
#else
|
||||
DWORD written;
|
||||
OVERLAPPED overlapped;
|
||||
memset (&overlapped, 0, sizeof (overlapped));
|
||||
overlapped.Offset = offset & 0xffffffff;
|
||||
overlapped.OffsetHigh = offset >> 32u;
|
||||
// Ideally we'd to use something like WriteFile with an OVERLAPPED
|
||||
// structure applied to the handle extracted with _get_osfhandle (m_fd).
|
||||
//
|
||||
// But this modifies the file cursor, and if we need to seek anyway then
|
||||
// we may as well just emulate the entire with a query and two seeks.
|
||||
//
|
||||
// NOTE: It is thus possible to observe the fd with an 'incorrect' file
|
||||
// pointer. Do not rely on POSIX behaviour across multiple threads.
|
||||
|
||||
if (!WriteFile (reinterpret_cast<HANDLE> (_get_osfhandle (m_fd)), buf, count, &written, &overlapped))
|
||||
error::throw_code (EINVAL);
|
||||
auto const initial = lseek (0, SEEK_CUR);
|
||||
ssize_t written = -1;
|
||||
try {
|
||||
(void)lseek (offset, SEEK_SET);
|
||||
written = write (buf, count);
|
||||
} catch (...) {
|
||||
(void)lseek (initial, SEEK_SET);
|
||||
throw;
|
||||
}
|
||||
|
||||
(void)lseek (initial, SEEK_SET);
|
||||
return written;
|
||||
#endif
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user