Fixes
This commit is contained in:
2
.github/workflows/ci.yaml
vendored
2
.github/workflows/ci.yaml
vendored
@ -22,7 +22,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install OpenSSL v3 (System)
|
||||
run: sudo dnf update && sudo dnf install -y libssl-dev
|
||||
run: sudo dnf install -y openssl-devel
|
||||
|
||||
- name: Configure
|
||||
run: cmake --preset ${{ matrix.target }}
|
||||
|
||||
@ -279,3 +279,239 @@ namespace IACore
|
||||
return result;
|
||||
}
|
||||
} // namespace IACore
|
||||
|
||||
namespace IACore
|
||||
{
|
||||
Expected<NativeFileHandle, String> FileOps::NativeOpenFile(IN CONST FilePath &path, IN EFileAccess access,
|
||||
IN EFileMode mode, IN UINT32 permissions)
|
||||
{
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
DWORD dwAccess = 0;
|
||||
DWORD dwShare = FILE_SHARE_READ;
|
||||
DWORD dwDisposition = 0;
|
||||
DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
|
||||
|
||||
switch (access)
|
||||
{
|
||||
case EFileAccess::READ:
|
||||
dwAccess = GENERIC_READ;
|
||||
break;
|
||||
case EFileAccess::WRITE:
|
||||
dwAccess = GENERIC_WRITE;
|
||||
break;
|
||||
case EFileAccess::READ_WRITE:
|
||||
dwAccess = GENERIC_READ | GENERIC_WRITE;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case EFileMode::OPEN_EXISTING:
|
||||
dwDisposition = OPEN_EXISTING;
|
||||
break;
|
||||
case EFileMode::OPEN_ALWAYS:
|
||||
dwDisposition = OPEN_ALWAYS;
|
||||
break;
|
||||
case EFileMode::CREATE_NEW:
|
||||
dwDisposition = CREATE_NEW;
|
||||
break;
|
||||
case EFileMode::CREATE_ALWAYS:
|
||||
dwDisposition = CREATE_ALWAYS;
|
||||
break;
|
||||
case EFileMode::TRUNCATE_EXISTING:
|
||||
dwDisposition = TRUNCATE_EXISTING;
|
||||
break;
|
||||
}
|
||||
|
||||
HANDLE hFile =
|
||||
CreateFileA(path.string().c_str(), dwAccess, dwShare, NULL, dwDisposition, dwFlagsAndAttributes, NULL);
|
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
return MakeUnexpected(std::format("Failed to open file '{}': {}", path.string(), GetLastError()));
|
||||
|
||||
return hFile;
|
||||
|
||||
#elif IA_PLATFORM_UNIX
|
||||
int flags = 0;
|
||||
|
||||
switch (access)
|
||||
{
|
||||
case EFileAccess::READ:
|
||||
flags = O_RDONLY;
|
||||
break;
|
||||
case EFileAccess::WRITE:
|
||||
flags = O_WRONLY;
|
||||
break;
|
||||
case EFileAccess::READ_WRITE:
|
||||
flags = O_RDWR;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case EFileMode::OPEN_EXISTING:
|
||||
break;
|
||||
case EFileMode::OPEN_ALWAYS:
|
||||
flags |= O_CREAT;
|
||||
break;
|
||||
case EFileMode::CREATE_NEW:
|
||||
flags |= O_CREAT | O_EXCL;
|
||||
break;
|
||||
case EFileMode::CREATE_ALWAYS:
|
||||
flags |= O_CREAT | O_TRUNC;
|
||||
break;
|
||||
case EFileMode::TRUNCATE_EXISTING:
|
||||
flags |= O_TRUNC;
|
||||
break;
|
||||
}
|
||||
|
||||
int fd = open(path.string().c_str(), flags, permissions);
|
||||
|
||||
if (fd == -1)
|
||||
{
|
||||
return MakeUnexpected(std::format("Failed to open file '{}': {}", path.string(), errno));
|
||||
}
|
||||
|
||||
return fd;
|
||||
#endif
|
||||
}
|
||||
|
||||
VOID FileOps::NativeCloseFile(IN NativeFileHandle handle)
|
||||
{
|
||||
if (handle == INVALID_FILE_HANDLE)
|
||||
return;
|
||||
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
CloseHandle(handle);
|
||||
#elif IA_PLATFORM_UNIX
|
||||
close(handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
FileOps::MemoryMappedRegion::~MemoryMappedRegion()
|
||||
{
|
||||
Unmap();
|
||||
}
|
||||
|
||||
FileOps::MemoryMappedRegion::MemoryMappedRegion(MemoryMappedRegion &&other) NOEXCEPT
|
||||
{
|
||||
*this = std::move(other);
|
||||
}
|
||||
|
||||
FileOps::MemoryMappedRegion &FileOps::MemoryMappedRegion::operator=(MemoryMappedRegion &&other) NOEXCEPT
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
Unmap();
|
||||
m_ptr = other.m_ptr;
|
||||
m_size = other.m_size;
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
m_hMap = other.m_hMap;
|
||||
other.m_hMap = NULL;
|
||||
#endif
|
||||
other.m_ptr = nullptr;
|
||||
other.m_size = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Expected<VOID, String> FileOps::MemoryMappedRegion::Map(NativeFileHandle handle, UINT64 offset, SIZE_T size)
|
||||
{
|
||||
Unmap();
|
||||
|
||||
if (handle == INVALID_FILE_HANDLE)
|
||||
return MakeUnexpected("Invalid file handle provided to Map");
|
||||
|
||||
if (size == 0)
|
||||
return MakeUnexpected("Cannot map region of size 0");
|
||||
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
LARGE_INTEGER fileSize;
|
||||
if (!GetFileSizeEx(handle, &fileSize))
|
||||
return MakeUnexpected("Failed to get file size");
|
||||
|
||||
UINT64 endOffset = offset + size;
|
||||
if (static_cast<UINT64>(fileSize.QuadPart) < endOffset)
|
||||
{
|
||||
LARGE_INTEGER newSize;
|
||||
newSize.QuadPart = endOffset;
|
||||
if (!SetFilePointerEx(handle, newSize, NULL, FILE_BEGIN))
|
||||
return MakeUnexpected("Failed to seek to new end of file");
|
||||
|
||||
if (!SetEndOfFile(handle))
|
||||
return MakeUnexpected("Failed to extend file for mapping");
|
||||
}
|
||||
|
||||
m_hMap = CreateFileMappingW(handle, NULL, PAGE_READWRITE, 0, 0, NULL);
|
||||
if (m_hMap == NULL)
|
||||
return MakeUnexpected(std::format("CreateFileMapping failed: {}", GetLastError()));
|
||||
|
||||
DWORD offsetHigh = static_cast<DWORD>(offset >> 32);
|
||||
DWORD offsetLow = static_cast<DWORD>(offset & 0xFFFFFFFF);
|
||||
|
||||
m_ptr = static_cast<PUINT8>(MapViewOfFile(m_hMap, FILE_MAP_WRITE, offsetHigh, offsetLow, size));
|
||||
if (m_ptr == NULL)
|
||||
{
|
||||
CloseHandle(m_hMap);
|
||||
m_hMap = NULL;
|
||||
return MakeUnexpected(
|
||||
std::format("MapViewOfFile failed (Offset: {}, Size: {}): {}", offset, size, GetLastError()));
|
||||
}
|
||||
m_size = size;
|
||||
|
||||
#elif IA_PLATFORM_UNIX
|
||||
struct stat sb;
|
||||
if (fstat(handle, &sb) == -1)
|
||||
return MakeUnexpected("Failed to fstat file");
|
||||
|
||||
UINT64 endOffset = offset + size;
|
||||
if (static_cast<UINT64>(sb.st_size) < endOffset)
|
||||
{
|
||||
if (ftruncate(handle, endOffset) == -1)
|
||||
return MakeUnexpected("Failed to ftruncate (extend) file");
|
||||
}
|
||||
|
||||
void *ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, handle, static_cast<off_t>(offset));
|
||||
if (ptr == MAP_FAILED)
|
||||
return MakeUnexpected(std::format("mmap failed: {}", errno));
|
||||
|
||||
m_ptr = static_cast<PUINT8>(ptr);
|
||||
m_size = size;
|
||||
|
||||
madvise(m_ptr, m_size, MADV_SEQUENTIAL);
|
||||
#endif
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
VOID FileOps::MemoryMappedRegion::Unmap()
|
||||
{
|
||||
if (!m_ptr)
|
||||
return;
|
||||
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
UnmapViewOfFile(m_ptr);
|
||||
if (m_hMap)
|
||||
{
|
||||
CloseHandle(m_hMap);
|
||||
m_hMap = NULL;
|
||||
}
|
||||
#elif IA_PLATFORM_UNIX
|
||||
munmap(m_ptr, m_size);
|
||||
#endif
|
||||
m_ptr = nullptr;
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
VOID FileOps::MemoryMappedRegion::Flush()
|
||||
{
|
||||
if (!m_ptr)
|
||||
return;
|
||||
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
FlushViewOfFile(m_ptr, m_size);
|
||||
#elif IA_PLATFORM_UNIX
|
||||
msync(m_ptr, m_size, MS_SYNC);
|
||||
#endif
|
||||
}
|
||||
} // namespace IACore
|
||||
@ -18,10 +18,41 @@
|
||||
#include <IACore/StreamReader.hpp>
|
||||
#include <IACore/StreamWriter.hpp>
|
||||
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
using NativeFileHandle = HANDLE;
|
||||
STATIC CONSTEXPR NativeFileHandle INVALID_FILE_HANDLE = INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
using NativeFileHandle = int;
|
||||
STATIC CONSTEXPR NativeFileHandle INVALID_FILE_HANDLE = -1;
|
||||
#endif
|
||||
|
||||
namespace IACore
|
||||
{
|
||||
class FileOps
|
||||
{
|
||||
public:
|
||||
class MemoryMappedRegion;
|
||||
|
||||
enum class EFileAccess : UINT8
|
||||
{
|
||||
READ, // Read-only
|
||||
WRITE, // Write-only
|
||||
READ_WRITE // Read and Write
|
||||
};
|
||||
|
||||
enum class EFileMode : UINT8
|
||||
{
|
||||
OPEN_EXISTING, // Fails if file doesn't exist
|
||||
OPEN_ALWAYS, // Opens if exists, creates if not
|
||||
CREATE_NEW, // Fails if file exists
|
||||
CREATE_ALWAYS, // Overwrites existing
|
||||
TRUNCATE_EXISTING // Opens existing and clears it
|
||||
};
|
||||
|
||||
STATIC Expected<NativeFileHandle, String> NativeOpenFile(IN CONST FilePath &path, IN EFileAccess access,
|
||||
IN EFileMode mode, IN UINT32 permissions = 0644);
|
||||
STATIC VOID NativeCloseFile(IN NativeFileHandle handle);
|
||||
|
||||
public:
|
||||
STATIC FilePath NormalizeExecutablePath(IN CONST FilePath &path);
|
||||
|
||||
@ -46,4 +77,45 @@ namespace IACore
|
||||
private:
|
||||
STATIC UnorderedMap<PCUINT8, Tuple<PVOID, PVOID, PVOID>> s_mappedFiles;
|
||||
};
|
||||
|
||||
class FileOps::MemoryMappedRegion
|
||||
{
|
||||
public:
|
||||
MemoryMappedRegion() = default;
|
||||
~MemoryMappedRegion();
|
||||
|
||||
MemoryMappedRegion(CONST MemoryMappedRegion &) = delete;
|
||||
MemoryMappedRegion &operator=(CONST MemoryMappedRegion &) = delete;
|
||||
|
||||
MemoryMappedRegion(MemoryMappedRegion &&other) NOEXCEPT;
|
||||
MemoryMappedRegion &operator=(MemoryMappedRegion &&other) NOEXCEPT;
|
||||
|
||||
Expected<VOID, String> Map(NativeFileHandle handle, UINT64 offset, SIZE_T size);
|
||||
|
||||
VOID Unmap();
|
||||
VOID Flush();
|
||||
|
||||
PUINT8 GetPtr() CONST
|
||||
{
|
||||
return m_ptr;
|
||||
}
|
||||
|
||||
SIZE_T GetSize() CONST
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
BOOL IsValid() CONST
|
||||
{
|
||||
return m_ptr != nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
PUINT8 m_ptr{nullptr};
|
||||
SIZE_T m_size{0};
|
||||
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
HANDLE m_hMap{NULL};
|
||||
#endif
|
||||
};
|
||||
} // namespace IACore
|
||||
Reference in New Issue
Block a user