diff options
Diffstat (limited to 'zencore/iobuffer.cpp')
| -rw-r--r-- | zencore/iobuffer.cpp | 152 |
1 files changed, 113 insertions, 39 deletions
diff --git a/zencore/iobuffer.cpp b/zencore/iobuffer.cpp index dc998d5ea..a730a316f 100644 --- a/zencore/iobuffer.cpp +++ b/zencore/iobuffer.cpp @@ -2,6 +2,7 @@ #include <zencore/iobuffer.h> +#include <zencore/except.h> #include <zencore/filesystem.h> #include <zencore/fmtutils.h> #include <zencore/iohash.h> @@ -13,7 +14,13 @@ #include <memory.h> #include <system_error> -#include <atlfile.h> +#if ZEN_PLATFORM_WINDOWS +# include <atlfile.h> +#else +# include <sys/stat.h> +# include <sys/mman.h> +#endif + #include <gsl/gsl-lite.hpp> namespace zen { @@ -23,12 +30,14 @@ namespace zen { void* IoBufferCore::AllocateBuffer(size_t InSize, size_t Alignment) { +#if ZEN_PLATFORM_WINDOWS if (((InSize & 0xffFF) == 0) && (Alignment == 0x10000)) { m_Flags |= kLowLevelAlloc; return VirtualAlloc(nullptr, InSize, MEM_COMMIT, PAGE_READWRITE); } else +#endif // ZEN_PLATFORM_WINDOWS { return Memory::Alloc(InSize, Alignment); } @@ -37,11 +46,13 @@ IoBufferCore::AllocateBuffer(size_t InSize, size_t Alignment) void IoBufferCore::FreeBuffer() { +#if ZEN_PLATFORM_WINDOWS if (m_Flags & kLowLevelAlloc) { VirtualFree(const_cast<void*>(m_DataPtr), 0, MEM_DECOMMIT); } else +#endif // ZEN_PLATFORM_WINDOWS { return Memory::Free(const_cast<void*>(m_DataPtr)); } @@ -153,17 +164,29 @@ IoBufferExtendedCore::~IoBufferExtendedCore() { if (m_MappedPointer) { +#if ZEN_PLATFORM_WINDOWS UnmapViewOfFile(m_MappedPointer); +#else + uint64_t MapSize = ~uint64_t(uintptr_t(m_MmapHandle)); + munmap(m_MappedPointer, MapSize); +#endif } +#if ZEN_PLATFORM_WINDOWS if (m_Flags & kOwnsMmap) { CloseHandle(m_MmapHandle); } +#endif if (m_Flags & kOwnsFile) { +#if ZEN_PLATFORM_WINDOWS BOOL Success = CloseHandle(m_FileHandle); +#else + int Fd = int(uintptr_t(m_FileHandle)); + bool Success = (close(Fd) == 0); +#endif if (!Success) { @@ -174,7 +197,7 @@ IoBufferExtendedCore::~IoBufferExtendedCore() m_DataPtr = nullptr; } -RwLock g_MappingLock; +static RwLock g_MappingLock; void IoBufferExtendedCore::Materialize() const @@ -193,6 +216,11 @@ IoBufferExtendedCore::Materialize() const if (m_MmapHandle) return; + const uint64_t MapOffset = m_FileOffset & ~0xffffull; + const uint64_t MappedOffsetDisplacement = m_FileOffset - MapOffset; + const uint64_t MapSize = m_DataBytes + MappedOffsetDisplacement; + +#if ZEN_PLATFORM_WINDOWS m_MmapHandle = CreateFileMapping(m_FileHandle, /* lpFileMappingAttributes */ nullptr, /* flProtect */ PAGE_READONLY, @@ -208,20 +236,28 @@ IoBufferExtendedCore::Materialize() const m_Flags |= kOwnsMmap; - const uint64_t MapOffset = m_FileOffset & ~0xffffull; - const uint64_t MappedOffsetDisplacement = m_FileOffset - MapOffset; - const uint64_t MapSize = m_DataBytes + MappedOffsetDisplacement; - void* MappedBase = MapViewOfFile(m_MmapHandle, /* dwDesiredAccess */ FILE_MAP_READ, /* FileOffsetHigh */ uint32_t(MapOffset >> 32), /* FileOffsetLow */ uint32_t(MapOffset & 0xffFFffFFu), /* dwNumberOfBytesToMap */ MapSize); +#else + m_MmapHandle = (void*)uintptr_t(~MapSize); // ~ so it's never null (assuming MapSize >= 0) + m_Flags |= kOwnsMmap; + + void* MappedBase = mmap( + /* addr */ nullptr, + /* length */ MapSize, + /* prot */ PROT_READ, + /* flags */ MAP_SHARED | MAP_NORESERVE, + /* fd */ int(uintptr_t(m_FileHandle)), + /* offset */ MapOffset); +#endif // ZEN_PLATFORM_WINDOWS if (MappedBase == nullptr) { throw std::system_error( - std::error_code(::GetLastError(), std::system_category()), + std::error_code(zen::GetLastError(), std::system_category()), "MapViewOfFile failed (offset {:#x}, size {:#x}) file: '{}'"_format(MapOffset, MapSize, zen::PathFromHandle(m_FileHandle))); } @@ -317,49 +353,72 @@ IoBufferBuilder::MakeFromFileHandle(void* FileHandle, uint64_t Offset, uint64_t } IoBuffer -IoBufferBuilder::MakeFromFile(const wchar_t* FileName, uint64_t Offset, uint64_t Size) +IoBufferBuilder::MakeFromFile(const path_char_t* FileName, uint64_t Offset, uint64_t Size) { + uint64_t FileSize; + +#if ZEN_PLATFORM_WINDOWS CAtlFile DataFile; HRESULT hRes = DataFile.Create(FileName, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING); - if (SUCCEEDED(hRes)) + if (FAILED(hRes)) { - ULONGLONG FileSize; - DataFile.GetSize(FileSize); + return {}; + } + + DataFile.GetSize((ULONGLONG&)FileSize); +#else + int Fd = open(FileName, O_RDONLY); + if (Fd < 0) + { + return {}; + } + + static_assert(sizeof(decltype(stat::st_size)) == sizeof(uint64_t), "fstat() doesn't support large files"); + struct stat Stat; + fstat(Fd, &Stat); + FileSize = Stat.st_size; +#endif // ZEN_PLATFORM_WINDOWS - // TODO: should validate that offset is in range + // TODO: should validate that offset is in range - if (Size == ~0ull) + if (Size == ~0ull) + { + Size = FileSize - Offset; + } + else + { + // Clamp size + if ((Offset + Size) > FileSize) { Size = FileSize - Offset; } - else - { - // Clamp size - if ((Offset + Size) > FileSize) - { - Size = FileSize - Offset; - } - } + } - if (Size) - { - return IoBuffer(IoBuffer::File, DataFile.Detach(), Offset, Size); - } - else - { - // For an empty file, we may as well just return an empty memory IoBuffer - return IoBuffer(IoBuffer::Wrap, "", 0); - } + if (Size) + { +#if ZEN_PLATFORM_WINDOWS + void* Fd = DataFile.Detach(); +#endif + return IoBuffer(IoBuffer::File, (void*)uintptr_t(Fd), Offset, Size); } - return {}; +#if !ZEN_PLATFORM_WINDOWS + close(Fd); +#endif + + // For an empty file, we may as well just return an empty memory IoBuffer + return IoBuffer(IoBuffer::Wrap, "", 0); } IoBuffer -IoBufferBuilder::MakeFromTemporaryFile(const wchar_t* FileName) +IoBufferBuilder::MakeFromTemporaryFile(const path_char_t* FileName) { + uint64_t FileSize; + void* Handle; + +#if ZEN_PLATFORM_WINDOWS CAtlFile DataFile; // We need to open with DELETE since this is used for the case @@ -368,18 +427,33 @@ IoBufferBuilder::MakeFromTemporaryFile(const wchar_t* FileName) HRESULT hRes = DataFile.Create(FileName, GENERIC_READ | DELETE, FILE_SHARE_READ | FILE_SHARE_DELETE, OPEN_EXISTING); - if (SUCCEEDED(hRes)) + if (FAILED(hRes)) { - ULONGLONG FileSize; - DataFile.GetSize(FileSize); + return {}; + } - IoBuffer Iob(IoBuffer::File, DataFile.Detach(), 0, FileSize); - Iob.m_Core->SetIsWholeFile(true); + DataFile.GetSize((ULONGLONG&)FileSize); - return Iob; + Handle = DataFile.Detach(); +#else + int Fd = open(FileName, O_RDONLY); + if (Fd < 0) + { + return {}; } - return {}; + static_assert(sizeof(decltype(stat::st_size)) == sizeof(uint64_t), "fstat() doesn't support large files"); + struct stat Stat; + fstat(Fd, &Stat); + FileSize = Stat.st_size; + + Handle = (void*)uintptr_t(Fd); +#endif // ZEN_PLATFORM_WINDOWS + + IoBuffer Iob(IoBuffer::File, Handle, 0, FileSize); + Iob.m_Core->SetIsWholeFile(true); + + return Iob; } IoHash |