AuroraRuntime/Source/Process/AuProcessSectionView.Unix.cpp

336 lines
11 KiB
C++

/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuProcessSectionView.Unix.hpp
Date: 2022-08-10
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "AuProcessSectionView.Unix.hpp"
#include "Process.hpp"
#include <Source/IO/FS/FileStream.Unix.hpp>
#include "AuProcessSectionFileMapView.Unix.hpp"
#include <Source/IO/IPC/AuIPCHandle.hpp>
#include <Source/IO/IPC/AuIPCMemory.Unix.hpp>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
namespace Aurora::Process
{
AuUInt ProcessSectionView::GetStart()
{
return AuNumericLimits<AuUInt>::min();
}
AuUInt ProcessSectionView::GetEnd()
{
return AuNumericLimits<AuUInt>::max();
}
AuSPtr<IProcessSectionMapView> ProcessSectionView::Allocate(AuUInt uLength)
{
if (!uLength)
{
SysPushErrorArg("invalid uLength");
return {};
}
auto map = ::mmap(nullptr, uLength, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
if (map == MAP_FAILED)
{
SysPushErrorIO();
return {};
}
auto newObject = AuMakeShared<ProcessSectionFileMapView>(AuUInt(map),
uLength,
false);
if (!newObject)
{
SysPushErrorMem();
::munmap(map, uLength);
return {};
}
return newObject;
}
AuSPtr<IProcessSectionMapView> ProcessSectionView::MapFileByPath(const AuString &str,
AuUInt64 uOffset,
AuUInt uLength,
AuFS::EFileOpenMode mode,
AuFS::EFileAdvisoryLockLevel sectionLock)
{
return this->MapFileByPathEx(0, str, uOffset, uLength, mode, sectionLock);
}
AuSPtr<IProcessSectionMapView> ProcessSectionView::MapFileByObject(const AuSPtr<IO::IIOHandle> &pIOHandle,
AuUInt64 uOffset,
AuUInt uLength,
AuFS::EFileOpenMode mode,
AuFS::EFileAdvisoryLockLevel processLockLevel)
{
return this->MapFileByObjectEx(0, pIOHandle, uOffset, uLength, mode, processLockLevel);
}
AuSPtr<IProcessSectionMapView> ProcessSectionView::MapIPCMemory(const AuString &handleString,
AuUInt64 uOffset,
AuUInt uLength,
AuFS::EFileOpenMode mode)
{
return this->MapIPCMemoryEx(0, handleString, uOffset, uLength, mode);
}
AuSPtr<IProcessSectionMapView> ProcessSectionView::AllocateEx(AuUInt uLength, AuUInt uOffset)
{
PageTable table {};
table.NX = true;
table.readable = true;
table.writable = true;
return this->AllocateEx2(uLength, uOffset, table);
}
AuSPtr<IProcessSectionMapView> ProcessSectionView::AllocateEx2(AuUInt uLength, AuUInt uOffset, PageTable permissions)
{
if (!uLength)
{
SysPushErrorArg("invalid uLength");
return {};
}
AuUInt32 uProtFlags {};
if (!permissions.NX)
{
uProtFlags |= PROT_EXEC;
}
if (permissions.writable)
{
uProtFlags |= PROT_WRITE;
}
if (permissions.readable)
{
uProtFlags |= PROT_READ;
}
auto map = ::mmap((void *)uOffset, uLength, uProtFlags, MAP_ANONYMOUS | MAP_PRIVATE | (uOffset ? MAP_FIXED : 0), 0, 0);
if (map == MAP_FAILED)
{
SysPushErrorIO();
return {};
}
auto newObject = AuMakeShared<ProcessSectionFileMapView>(AuUInt(map),
uLength,
false);
if (!newObject)
{
SysPushErrorMem();
::munmap(map, uLength);
return {};
}
return newObject;
}
AuSPtr<IProcessSectionMapView> ProcessSectionView::MapFileByPathEx(AuUInt viewOffset,
const AuString &str,
AuUInt64 uOffset,
AuUInt uLength,
Aurora::IO::FS::EFileOpenMode mode,
Aurora::IO::FS::EFileAdvisoryLockLevel processLockLevel)
{
auto pHandle = AuIO::IOHandleShared();
if (!pHandle)
{
SysPushErrorMemory();
return nullptr;
}
AuIO::IIOHandle::HandleCreate createhandle(str);
createhandle.eAdvisoryLevel = AuFS::EFileAdvisoryLockLevel::eNoSafety;
createhandle.eMode = mode;
createhandle.bFailIfNonEmptyFile = false;
createhandle.bDirectIOMode = false;
createhandle.bAsyncHandle = false;
if (!pHandle->InitFromPath(createhandle))
{
return nullptr;
}
return this->MapFileByObjectEx(viewOffset, pHandle, uOffset, uLength, mode, processLockLevel);
}
AuSPtr<IProcessSectionMapView> ProcessSectionView::MapFileByObjectEx(AuUInt viewOffset,
const AuSPtr<IO::IIOHandle> &pIOHandle,
AuUInt64 uOffset,
AuUInt uLength,
Aurora::IO::FS::EFileOpenMode mode,
Aurora::IO::FS::EFileAdvisoryLockLevel processLockLevel)
{
if (!pIOHandle)
{
return {};
}
if (!uLength)
{
SysPushErrorArg("invalid uLength");
return {};
}
int fd = ::dup(pIOHandle->GetOSHandle());
if (fd == -1)
{
SysPushErrorIO();
return {};
}
// TODO (Reece): lock garbage
int prot {};
switch (mode)
{
case AuFS::EFileOpenMode::eRead:
{
prot = PROT_READ;
break;
}
case AuFS::EFileOpenMode::eWrite:
case AuFS::EFileOpenMode::eReadWrite:
{
prot = PROT_READ | PROT_WRITE;
break;
}
default:
SysPushErrorGeneric();
return {};
};
auto map = ::mmap((void *)viewOffset, uLength, prot, MAP_SHARED | (viewOffset ? MAP_FIXED : 0), fd, uOffset);
if (map == MAP_FAILED)
{
SysPushErrorIO();
::close(fd);
return {};
}
auto newObject = AuMakeShared<ProcessSectionFileMapView>(AuUInt(map),
uLength,
true,
fd);
if (!newObject)
{
SysPushErrorMem();
::close(fd);
::munmap(map, uLength);
return {};
}
return newObject;
}
AuSPtr<IProcessSectionMapView> ProcessSectionView::MapIPCMemoryEx(AuUInt viewOffset,
const AuString &handleString,
AuUInt64 uOffset,
AuUInt uLength,
Aurora::IO::FS::EFileOpenMode mode)
{
AuIPC::IPCHandle handle;
if (!uLength)
{
SysPushErrorArg("invalid uLength");
return {};
}
if (!handle.FromString(handleString))
{
SysPushErrorParseError("Invalid handle: {}", handleString);
return {};
}
auto val = handle.GetToken(AuIPC::EIPCHandleType::eIPCMemory, 0);
if (!val)
{
SysPushErrorParseError("Invalid handle: {}", handleString);
return {};
}
auto actualLength = val->token.word;
auto path = AuIPC::GetServerPath(val->token);
if (actualLength < uOffset + uLength)
{
SysPushErrorIO("Out of range");
return {};
}
int fd = ::shm_open(path.c_str(), O_RDWR, S_IRUSR | S_IWUSR);
if (fd == -1)
{
SysPushErrorIO();
return {};
}
// TODO (Reece): lock garbage ( ??? )
int prot {};
switch (mode)
{
case AuFS::EFileOpenMode::eRead:
{
prot = PROT_READ;
break;
}
case AuFS::EFileOpenMode::eWrite:
case AuFS::EFileOpenMode::eReadWrite:
{
prot = PROT_READ | PROT_WRITE;
break;
}
default:
SysPushErrorGeneric();
return {};
};
auto map = ::mmap((void *)viewOffset, uLength, prot, MAP_SHARED | (viewOffset ? MAP_FIXED : 0), fd, uOffset);
if (map == MAP_FAILED)
{
SysPushErrorIO();
::close(fd);
return {};
}
auto newObject = AuMakeShared<ProcessSectionFileMapView>(AuUInt(map),
uLength,
true,
fd);
if (!newObject)
{
SysPushErrorMem();
::close(fd);
::munmap(map, val->token.word);
return {};
}
return newObject;
}
AuList<AuPair<AuUInt, AuUInt>> ProcessSectionView::GetAllocations()
{
AU_LOCK_GUARD(this->spinlock);
return allocations;
}
AUKN_SYM AuSPtr<IProcessSectionView> GetGlobalProcessSpace()
{
static ProcessSectionView gSingleton;
return AuUnsafeRaiiToShared(&gSingleton);
}
}