diff options
Diffstat (limited to 'src/zencore/iobuffer.cpp')
| -rw-r--r-- | src/zencore/iobuffer.cpp | 109 |
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; } |