aboutsummaryrefslogtreecommitdiff
path: root/src/zencore/iobuffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/zencore/iobuffer.cpp')
-rw-r--r--src/zencore/iobuffer.cpp109
1 files changed, 80 insertions, 29 deletions
diff --git a/src/zencore/iobuffer.cpp b/src/zencore/iobuffer.cpp
index 529afe341..d1aa0bb9e 100644
--- a/src/zencore/iobuffer.cpp
+++ b/src/zencore/iobuffer.cpp
@@ -10,6 +10,7 @@
#include <zencore/memory/llm.h>
#include <zencore/memory/memory.h>
#include <zencore/memoryview.h>
+#include <zencore/scopeguard.h>
#include <zencore/testing.h>
#include <zencore/thread.h>
#include <zencore/trace.h>
@@ -375,7 +376,14 @@ IoBufferExtendedCore::Materialize() const
/* offset */ MapOffset);
#endif // ZEN_PLATFORM_WINDOWS
- if (MappedBase == nullptr)
+#if ZEN_PLATFORM_WINDOWS
+ const bool MapFailed = (MappedBase == nullptr);
+#else
+ // mmap returns MAP_FAILED (not nullptr) on failure
+ const bool MapFailed = (MappedBase == MAP_FAILED);
+#endif
+
+ if (MapFailed)
{
int32_t Error = zen::GetLastError();
#if ZEN_PLATFORM_WINDOWS
@@ -540,32 +548,54 @@ IoBufferBuilder::ReadFromFileMaybe(const IoBuffer& InBuffer)
const uint64_t NumberOfBytesToRead = FileRef.FileChunkSize;
const uint64_t FileOffset = FileRef.FileChunkOffset;
+ uint8_t* const Dst = reinterpret_cast<uint8_t*>(OutBuffer.MutableData());
+
#if ZEN_PLATFORM_WINDOWS
- OVERLAPPED Ovl{};
+ while (BytesRead < NumberOfBytesToRead)
+ {
+ const uint64_t Remaining = NumberOfBytesToRead - BytesRead;
+ const uint64_t ChunkStart = FileOffset + BytesRead;
+ const DWORD ChunkSize = DWORD(Min<uint64_t>(Remaining, 0xffff'ffffu));
- Ovl.Offset = DWORD(FileOffset & 0xffff'ffffu);
- Ovl.OffsetHigh = DWORD(FileOffset >> 32);
+ OVERLAPPED Ovl{};
+ Ovl.Offset = DWORD(ChunkStart & 0xffff'ffffu);
+ Ovl.OffsetHigh = DWORD(ChunkStart >> 32);
- DWORD dwNumberOfBytesRead = 0;
- BOOL Success = ::ReadFile(FileRef.FileHandle, OutBuffer.MutableData(), DWORD(NumberOfBytesToRead), &dwNumberOfBytesRead, &Ovl);
- if (Success)
- {
- BytesRead = size_t(dwNumberOfBytesRead);
- }
- else
- {
- Error = zen::GetLastError();
+ DWORD dwBytesRead = 0;
+ if (!::ReadFile(FileRef.FileHandle, Dst + BytesRead, ChunkSize, &dwBytesRead, &Ovl))
+ {
+ Error = zen::GetLastError();
+ break;
+ }
+ if (dwBytesRead == 0)
+ {
+ // Hit EOF before we got everything we asked for
+ break;
+ }
+ BytesRead += size_t(dwBytesRead);
}
#else
int Fd = int(intptr_t(FileRef.FileHandle));
- ssize_t ReadResult = pread(Fd, OutBuffer.MutableData(), size_t(NumberOfBytesToRead), off_t(FileOffset));
- if (ReadResult != -1)
+ while (BytesRead < NumberOfBytesToRead)
{
- BytesRead = size_t(ReadResult);
- }
- else
- {
- Error = zen::GetLastError();
+ const size_t Remaining = size_t(NumberOfBytesToRead - BytesRead);
+ const off_t ChunkStart = off_t(FileOffset + BytesRead);
+ const ssize_t ReadResult = pread(Fd, Dst + BytesRead, Remaining, ChunkStart);
+ if (ReadResult < 0)
+ {
+ if (errno == EINTR)
+ {
+ continue;
+ }
+ Error = zen::GetLastError();
+ break;
+ }
+ if (ReadResult == 0)
+ {
+ // Hit EOF before we got everything we asked for
+ break;
+ }
+ BytesRead += size_t(ReadResult);
}
#endif
@@ -632,10 +662,19 @@ IoBufferBuilder::MakeFromFile(const std::filesystem::path& FileName, uint64_t Of
{
return {};
}
+ auto FdGuard = MakeGuard([&Fd] {
+ if (Fd >= 0)
+ {
+ close(Fd);
+ }
+ });
static_assert(sizeof(decltype(stat::st_size)) == sizeof(uint64_t), "fstat() doesn't support large files");
struct stat Stat;
- fstat(Fd, &Stat);
+ if (fstat(Fd, &Stat) != 0)
+ {
+ return {};
+ }
FileSize = Stat.st_size;
#endif // ZEN_PLATFORM_WINDOWS
@@ -655,18 +694,20 @@ IoBufferBuilder::MakeFromFile(const std::filesystem::path& FileName, uint64_t Of
if (Size)
{
#if ZEN_PLATFORM_WINDOWS
- void* Fd = DataFile.Detach();
-#endif
+ void* Fd = DataFile.Detach();
+ auto HandleGuard = MakeGuard([Fd] { CloseHandle((HANDLE)Fd); });
+ IoBuffer NewBuffer(IoBuffer::File, Fd, Offset, Size, Offset == 0 && Size == FileSize);
+ HandleGuard.Dismiss();
+#else
IoBuffer NewBuffer(IoBuffer::File, (void*)uintptr_t(Fd), Offset, Size, Offset == 0 && Size == FileSize);
+ FdGuard.Dismiss();
+#endif
NewBuffer.SetContentType(ContentType);
return NewBuffer;
}
-#if !ZEN_PLATFORM_WINDOWS
- close(Fd);
-#endif
-
// For an empty file, we may as well just return an empty memory IoBuffer
+ // (FdGuard on non-Windows closes Fd automatically; DataFile destructor closes the HANDLE on Windows)
return IoBuffer(IoBuffer::Wrap, "", 0);
}
@@ -694,23 +735,33 @@ IoBufferBuilder::MakeFromTemporaryFile(const std::filesystem::path& FileName, Ze
DataFile.GetSize((ULONGLONG&)FileSize);
- Handle = DataFile.Detach();
+ Handle = DataFile.Detach();
+ auto HandleGuard = MakeGuard([Handle] { CloseHandle((HANDLE)Handle); });
#else
int Fd = open(FileName.native().c_str(), O_RDONLY);
if (Fd < 0)
{
return {};
}
+ auto FdGuard = MakeGuard([Fd] { close(Fd); });
static_assert(sizeof(decltype(stat::st_size)) == sizeof(uint64_t), "fstat() doesn't support large files");
struct stat Stat;
- fstat(Fd, &Stat);
+ if (fstat(Fd, &Stat) != 0)
+ {
+ return {};
+ }
FileSize = Stat.st_size;
Handle = (void*)uintptr_t(Fd);
#endif // ZEN_PLATFORM_WINDOWS
IoBuffer NewBuffer(IoBuffer::File, Handle, 0, FileSize, /*IsWholeFile*/ true);
+#if ZEN_PLATFORM_WINDOWS
+ HandleGuard.Dismiss();
+#else
+ FdGuard.Dismiss();
+#endif
NewBuffer.SetContentType(ContentType);
return NewBuffer;
}