AuroraRuntime/Source/IO/AuIOHandle.NT.cpp
2023-08-15 14:46:21 +01:00

362 lines
11 KiB
C++

/***
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuIOHandle.NT.cpp
Date: 2023-7-28
Author: Reece
***/
#include <RuntimeInternal.hpp>
#include "AuIOHandle.hpp"
#include "AuIOHandle.NT.hpp"
#include "FS/FS.hpp"
#include "FS/FileAdvisory.NT.hpp"
namespace Aurora::IO
{
AuUInt64 AFileHandle::DupHandle(AuUInt64 uOSHandle, bool bWriteAccess)
{
HANDLE hTargetHandle = (HANDLE)uOSHandle;
HANDLE hTargetProcess = ::GetCurrentProcess();
HANDLE hHandle {};
if (!::DuplicateHandle(hTargetProcess,
hTargetHandle,
hTargetProcess,
&hHandle,
bWriteAccess ? GENERIC_WRITE | GENERIC_READ : GENERIC_READ,
FALSE,
FALSE))
{
return 0;
}
return AuUInt64(hHandle);
}
void AFileHandle::CloseHandle(AuUInt64 uOSHandle)
{
HANDLE hHandle = (HANDLE)uOSHandle;
AuWin32CloseHandle(hHandle);
}
struct NTIOHandle final : AFileHandle
{
bool InitFromPath(HandleCreate create) override
{
HANDLE hFileHandle;
DWORD dwFlags {};
DWORD dwShare {};
if (create.path.empty())
{
SysPushErrorArg("Cannot open an IO handle to the provided empty path");
return false;
}
if (!FS::EFileOpenModeIsValid(create.eMode))
{
SysPushErrorParam("Invalid open mode");
return false;
}
if (!FS::EFileAdvisoryLockLevelIsValid(create.eAdvisoryLevel))
{
SysPushErrorParam("Invalid lock mode");
return false;
}
auto pathex = FS::NormalizePathRet(create.path);
if (pathex.empty())
{
SysPushErrorMemory();
return false;
}
auto win32Path = Locale::ConvertFromUTF8(pathex);
if (win32Path.empty())
{
SysPushErrorMemory();
return false;
}
hFileHandle = INVALID_HANDLE_VALUE;
dwShare = FS::NtLockAdvisoryToShare(create.eAdvisoryLevel);
if (create.bAsyncHandle)
{
dwFlags |= FILE_FLAG_OVERLAPPED;
}
if (create.bDirectIOMode)
{
dwFlags |= FILE_FLAG_NO_BUFFERING;
this->bDirectIO = true;
}
if (!dwFlags)
{
dwFlags |= FILE_ATTRIBUTE_NORMAL;
}
switch (create.eMode)
{
case FS::EFileOpenMode::eRead:
{
hFileHandle = ::CreateFileW(win32Path.c_str(),
GENERIC_READ,
dwShare,
NULL,
OPEN_EXISTING,
dwFlags,
NULL);
if (hFileHandle != INVALID_HANDLE_VALUE)
{
this->uOSReadHandle = AuUInt64(hFileHandle);
}
break;
}
case FS::EFileOpenMode::eReadWrite:
{
if (create.bAlwaysCreateDirTree)
{
FS::CreateDirectories(pathex, true);
}
if (create.bFailIfNonEmptyFile)
{
hFileHandle = ::CreateFileW(win32Path.c_str(),
GENERIC_WRITE | GENERIC_READ | DELETE,
NULL,
NULL,
CREATE_NEW,
dwFlags,
NULL);
if (hFileHandle == INVALID_HANDLE_VALUE)
{
if (AuFS::FileExists(pathex.c_str()))
{
SysPushErrorResourceExists("File {} already exists", create.path);
return false;
}
}
}
else
{
hFileHandle = ::CreateFileW(win32Path.c_str(),
GENERIC_WRITE | GENERIC_READ | DELETE,
dwShare,
NULL,
OPEN_EXISTING,
dwFlags,
NULL);
if (hFileHandle == INVALID_HANDLE_VALUE)
{
hFileHandle = ::CreateFileW(win32Path.c_str(),
GENERIC_WRITE | GENERIC_READ | DELETE,
dwShare,
NULL,
CREATE_NEW,
dwFlags,
NULL);
}
}
if (hFileHandle != INVALID_HANDLE_VALUE)
{
this->uOSReadHandle = AuUInt64(hFileHandle);
this->uOSWriteHandle = AuUInt64(hFileHandle);
}
break;
}
case FS::EFileOpenMode::eWrite:
{
if (create.bAlwaysCreateDirTree)
{
FS::CreateDirectories(pathex, true);
}
if (create.bFailIfNonEmptyFile)
{
hFileHandle = ::CreateFileW(win32Path.c_str(),
GENERIC_WRITE | DELETE,
NULL,
NULL,
CREATE_NEW,
dwFlags,
NULL);
if (hFileHandle == INVALID_HANDLE_VALUE)
{
if (AuFS::FileExists(pathex.c_str()))
{
SysPushErrorResourceExists("File {} already exists", create.path);
return false;
}
}
}
else
{
hFileHandle = ::CreateFileW(win32Path.c_str(),
GENERIC_WRITE | FILE_READ_ATTRIBUTES | DELETE,
dwShare,
NULL,
OPEN_EXISTING,
dwFlags,
NULL);
if (hFileHandle == INVALID_HANDLE_VALUE)
{
hFileHandle = ::CreateFileW(win32Path.c_str(),
GENERIC_WRITE | DELETE,
dwShare,
NULL,
CREATE_NEW,
dwFlags,
NULL);
}
}
if (hFileHandle != INVALID_HANDLE_VALUE)
{
this->uOSWriteHandle = AuUInt64(hFileHandle);
}
break;
}
}
if (hFileHandle == INVALID_HANDLE_VALUE)
{
SysPushErrorIO("Couldn't open: {}", create.path);
return false;
}
this->bIsAsync = create.bAsyncHandle;
this->path = create.path;
return this->IsValid();
}
bool IsFile() override;
bool IsTTY() override;
bool IsPipe() override;
AuOptionalEx<bool> optIsFile {};
AuOptionalEx<bool> optIsPipe {};
AuOptionalEx<bool> optIsTTY {};
};
bool NTIOHandle::IsFile()
{
bool bIsFile {};
DWORD dwType {};
HANDLE hHandle {};
if (auto file = this->optIsFile)
{
return file.value();
}
if (auto optHandle = this->GetOSHandleSafe())
{
hHandle = (HANDLE)optHandle.value();
}
else
{
SysPushErrorUninitialized();
return false;
}
if (!(dwType = GetFileType(hHandle)))
{
return false;
}
bIsFile = dwType == FILE_TYPE_DISK;
this->optIsFile = bIsFile;
return bIsFile;
}
bool NTIOHandle::IsTTY()
{
bool bIsTTY {};
DWORD dwType {};
HANDLE hHandle {};
if (auto file = this->optIsTTY)
{
return file.value();
}
if (auto optHandle = this->GetOSHandleSafe())
{
hHandle = (HANDLE)optHandle.value();
}
else
{
SysPushErrorUninitialized();
return false;
}
if (!(dwType = GetFileType(hHandle)))
{
return false;
}
bIsTTY = dwType == FILE_TYPE_CHAR;
this->optIsTTY = bIsTTY;
return bIsTTY;
}
bool NTIOHandle::IsPipe()
{
bool bIsPipe {};
DWORD dwType {};
HANDLE hHandle {};
if (auto file = this->optIsPipe)
{
return file.value();
}
if (auto optHandle = this->GetOSHandleSafe())
{
hHandle = (HANDLE)optHandle.value();
}
else
{
SysPushErrorUninitialized();
return false;
}
if (!(dwType = GetFileType(hHandle)))
{
return false;
}
bIsPipe = dwType == FILE_TYPE_PIPE;
this->optIsPipe = bIsPipe;
return bIsPipe;
}
AUKN_SYM IIOHandle *IOHandleNew()
{
return _new NTIOHandle();
}
AUKN_SYM void IOHandleRelease(IIOHandle *pIOHandle)
{
AuSafeDelete<NTIOHandle *>(pIOHandle);
}
AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, IOHandle, NTIOHandle)
}