/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: ProcessSectionView.NT.hpp Date: 2022-08-09 Author: Reece ***/ #include #include "ProcessSectionView.NT.hpp" #include "Process.hpp" #include #include "ProcessSectionFileMapView.NT.hpp" #include #include namespace Aurora::Process { AuSPtr ProcessSectionView::Allocate(AuUInt length) { HANDLE hFileMap; if (!length) { SysPushErrorArg("invalid length"); return {}; } hFileMap = ::CreateFileMappingA(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, #if defined(AURORA_IS_64BIT) AuBitsToHigher(length), AuBitsToLower(length), #else 0, length, #endif nullptr); if ((hFileMap == INVALID_HANDLE_VALUE) || (!hFileMap)) { SysPushErrorIO("Couldn't create file map"); return {}; } auto map = ::MapViewOfFile(hFileMap, SECTION_MAP_READ | SECTION_MAP_WRITE, 0, 0, length); if (!map) { SysPushErrorIO("Couldn't create allocation of section"); AuWin32CloseHandle(hFileMap); return {}; } auto newObject = AuMakeShared(AuUInt(map), hFileMap); if (!newObject) { SysPushErrorMem(); AuWin32CloseHandle(hFileMap); return {}; } return newObject; } AuSPtr ProcessSectionView::MapFileByPath(const AuString &str, AuUInt64 offset, AuUInt length, AuFS::EFileOpenMode mode, AuFS::EFileAdvisoryLockLevel sectionLock) { auto file = AuFS::OpenShared(str, mode, AuFS::EFileAdvisoryLockLevel::eNoSafety); return file ? this->MapFileByObject(file, offset, length, mode, sectionLock) : AuSPtr {}; } AuSPtr ProcessSectionView::MapFileByObject(const AuSPtr &stream, AuUInt64 offset, AuUInt length, AuFS::EFileOpenMode mode, AuFS::EFileAdvisoryLockLevel processLockLevel) { HANDLE hFileMap; ULONG desiredAccess {}, pageAttributes {}; if (!stream) { return {}; } if (!length) { SysPushErrorArg("invalid length"); return {}; } auto ok = AuStaticCast(stream); if (processLockLevel != AuFS::EFileAdvisoryLockLevel::eNoSafety) { DWORD dwFlags {}; OVERLAPPED overlapped {}; if (processLockLevel == AuFS::EFileAdvisoryLockLevel::eBlockReadWrite) { dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; } dwFlags |= LOCKFILE_FAIL_IMMEDIATELY; overlapped.Offset = AuBitsToLower(offset); overlapped.OffsetHigh = AuBitsToHigher(offset); if (!::LockFileEx(ok->GetHandle(), dwFlags, 0, AuBitsToLower(length), AuBitsToHigher(length), &overlapped)) { SysPushErrorIO("No Lock"); return {}; } } switch (mode) { case AuFS::EFileOpenMode::eRead: { desiredAccess = SECTION_MAP_READ; pageAttributes = PAGE_READONLY; break; } case AuFS::EFileOpenMode::eWrite: case AuFS::EFileOpenMode::eReadWrite: { desiredAccess = SECTION_MAP_READ | SECTION_MAP_WRITE; pageAttributes = PAGE_READWRITE; break; } default: SysPushErrorGeneric(); return {}; }; hFileMap = ::CreateFileMappingA(ok->GetHandle(), nullptr, pageAttributes, #if defined(AURORA_IS_64BIT) AuBitsToHigher(length), AuBitsToLower(length), #else 0, length, #endif nullptr); if ((hFileMap == INVALID_HANDLE_VALUE) || (!hFileMap)) { SysPushErrorIO("Couldn't create file map. Is the requeted access mode too high for the given object?"); return {}; } auto map = ::MapViewOfFile(hFileMap, desiredAccess, AuBitsToHigher(offset), AuBitsToLower(offset), length); if (!map) { SysPushErrorIO("Couldn't create map of section"); AuWin32CloseHandle(hFileMap); return {}; } auto newObject = AuMakeShared(AuUInt(map), hFileMap); if (!newObject) { SysPushErrorMem(); AuWin32CloseHandle(hFileMap); ::UnmapViewOfFile(map); return {}; } return newObject; } AuSPtr ProcessSectionView::MapIPCMemory(const AuString &handleString, AuUInt64 offset, AuUInt length, AuFS::EFileOpenMode mode) { AuIPC::IPCHandle handle; HANDLE hFileMap; ULONG desiredAccess {}, pageAttributes {}; if (!length) { SysPushErrorArg("invalid length"); return {}; } if (!handle.FromString(handleString)) { SysPushErrorParseError("{}", handleString); return {}; } auto token = handle.GetToken(AuIPC::EIPCHandleType::eIPCMemory, 0); if (!token) { SysPushErrorParseError(); return {}; } auto actualLength = token->token.word; auto path = token->token.ToNTPath(); if (actualLength < offset + length) { SysPushErrorIO("Out of range"); return {}; } switch (mode) { case AuFS::EFileOpenMode::eRead: { desiredAccess = SECTION_MAP_READ; pageAttributes = PAGE_READONLY; break; } case AuFS::EFileOpenMode::eWrite: case AuFS::EFileOpenMode::eReadWrite: { desiredAccess = SECTION_MAP_READ | SECTION_MAP_WRITE; pageAttributes = PAGE_READWRITE; break; } default: SysPushErrorGeneric(); return {}; }; hFileMap = ::OpenFileMappingA(desiredAccess, FALSE, path.c_str()); if ((hFileMap == INVALID_HANDLE_VALUE) || (!hFileMap)) { SysPushErrorIO("Couldn't create IPC map (handle: {})", handleString); return {}; } auto map = ::MapViewOfFile(hFileMap, desiredAccess, AuBitsToHigher(offset), AuBitsToLower(offset), length); if (!map) { SysPushErrorIO("Couldn't create map of IPC section (handle: {})", handleString); AuWin32CloseHandle(hFileMap); return {}; } auto newObject = AuMakeShared(AuUInt(map), hFileMap); if (!newObject) { SysPushErrorMem(); AuWin32CloseHandle(hFileMap); ::UnmapViewOfFile(map); return {}; } return newObject; } AUKN_SYM AuSPtr GetGlobalProcessSpace() { static ProcessSectionView gSingleton; return AuUnsafeRaiiToShared(&gSingleton); } }