aboutsummaryrefslogtreecommitdiff
path: root/zencore/iobuffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'zencore/iobuffer.cpp')
-rw-r--r--zencore/iobuffer.cpp152
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