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)
|
::pwrite (native (), buf, count, offset)
|
||||||
);
|
);
|
||||||
#else
|
#else
|
||||||
DWORD written;
|
// Ideally we'd to use something like WriteFile with an OVERLAPPED
|
||||||
OVERLAPPED overlapped;
|
// structure applied to the handle extracted with _get_osfhandle (m_fd).
|
||||||
memset (&overlapped, 0, sizeof (overlapped));
|
//
|
||||||
overlapped.Offset = offset & 0xffffffff;
|
// But this modifies the file cursor, and if we need to seek anyway then
|
||||||
overlapped.OffsetHigh = offset >> 32u;
|
// 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))
|
auto const initial = lseek (0, SEEK_CUR);
|
||||||
error::throw_code (EINVAL);
|
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;
|
return written;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user