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
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install OpenSSL v3 (System)
|
- name: Install OpenSSL v3 (System)
|
||||||
run: sudo dnf update && sudo dnf install -y libssl-dev
|
run: sudo dnf install -y openssl-devel
|
||||||
|
|
||||||
- name: Configure
|
- name: Configure
|
||||||
run: cmake --preset ${{ matrix.target }}
|
run: cmake --preset ${{ matrix.target }}
|
||||||
|
|||||||
@ -278,4 +278,240 @@ namespace IACore
|
|||||||
#endif
|
#endif
|
||||||
return result;
|
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
|
} // namespace IACore
|
||||||
@ -18,10 +18,41 @@
|
|||||||
#include <IACore/StreamReader.hpp>
|
#include <IACore/StreamReader.hpp>
|
||||||
#include <IACore/StreamWriter.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
|
namespace IACore
|
||||||
{
|
{
|
||||||
class FileOps
|
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:
|
public:
|
||||||
STATIC FilePath NormalizeExecutablePath(IN CONST FilePath &path);
|
STATIC FilePath NormalizeExecutablePath(IN CONST FilePath &path);
|
||||||
|
|
||||||
@ -46,4 +77,45 @@ namespace IACore
|
|||||||
private:
|
private:
|
||||||
STATIC UnorderedMap<PCUINT8, Tuple<PVOID, PVOID, PVOID>> s_mappedFiles;
|
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
|
} // namespace IACore
|
||||||
Reference in New Issue
Block a user