From 4167e5d55f3c6b67ae51824bd8b21b5b3766c315 Mon Sep 17 00:00:00 2001 From: dev0 Date: Fri, 26 Dec 2025 11:25:37 +0530 Subject: [PATCH] Fixes --- .github/workflows/ci.yaml | 2 +- Src/IACore/imp/cpp/FileOps.cpp | 236 ++++++++++++++++++++++++++++++ Src/IACore/inc/IACore/FileOps.hpp | 72 +++++++++ 3 files changed, 309 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index ba98551..3b1a226 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -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 }} diff --git a/Src/IACore/imp/cpp/FileOps.cpp b/Src/IACore/imp/cpp/FileOps.cpp index 9922dbb..6279f97 100644 --- a/Src/IACore/imp/cpp/FileOps.cpp +++ b/Src/IACore/imp/cpp/FileOps.cpp @@ -278,4 +278,240 @@ namespace IACore #endif return result; } +} // namespace IACore + +namespace IACore +{ + Expected 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 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(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(offset >> 32); + DWORD offsetLow = static_cast(offset & 0xFFFFFFFF); + + m_ptr = static_cast(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(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(offset)); + if (ptr == MAP_FAILED) + return MakeUnexpected(std::format("mmap failed: {}", errno)); + + m_ptr = static_cast(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 \ No newline at end of file diff --git a/Src/IACore/inc/IACore/FileOps.hpp b/Src/IACore/inc/IACore/FileOps.hpp index 030d774..b302d0b 100644 --- a/Src/IACore/inc/IACore/FileOps.hpp +++ b/Src/IACore/inc/IACore/FileOps.hpp @@ -18,10 +18,41 @@ #include #include +#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 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> 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 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 \ No newline at end of file