From 13f77c25388b45946f366c181cda5f8f880b0fbb Mon Sep 17 00:00:00 2001 From: Matthieu Gautier Date: Mon, 10 Jun 2024 17:40:42 +0200 Subject: [PATCH] Fix reading of size >4GiB on Windows. ReadFile take a 32bits size. So we cannot blindly pass a 64bits size. Read by batch of 4MiB. --- src/fs_windows.cpp | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/fs_windows.cpp b/src/fs_windows.cpp index 78d028b9..ab48a767 100644 --- a/src/fs_windows.cpp +++ b/src/fs_windows.cpp @@ -73,22 +73,43 @@ zsize_t FD::readAt(char* dest, zsize_t size, offset_t offset) const EnterCriticalSection(&mp_impl->m_criticalSection); LARGE_INTEGER off; off.QuadPart = offset.v; + std::string errorMsg; + auto size_to_read = size.v; + size_type full_size_read = 0; + if (!SetFilePointerEx(mp_impl->m_handle, off, NULL, FILE_BEGIN)) { + errorMsg = "Seek fail"; goto err; } DWORD size_read; - if (!ReadFile(mp_impl->m_handle, dest, size.v, &size_read, NULL)) { - goto err; + while (size_to_read > 0) { + // Read by batch < 4GiB + // Lets use a batch of 4MiB + auto batch_to_read = std::min(size_to_read, (size_type)4*1024*1024); + if (!ReadFile(mp_impl->m_handle, dest, batch_to_read, &size_read, NULL)) { + errorMsg = "Read fail"; + goto err; + } + + if (size_read == 0) { + errorMsg = "Cannot read past the end of the file"; + goto err; + } + + size_to_read -= size_read; + full_size_read += size_read; + dest += size_read; } - if (size_read != size.v) { + if (full_size_read != size.v) { + errorMsg = "Wrong read size"; goto err; } LeaveCriticalSection(&mp_impl->m_criticalSection); return size; err: LeaveCriticalSection(&mp_impl->m_criticalSection); - throw std::runtime_error("Cannot read"); + throw std::runtime_error(errorMsg); } bool FD::seek(offset_t offset)