AuroraRuntime/Source/IO/AuIOHandle.NT.cpp

384 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"
#include <Source/Grug/AuGrug.hpp>
namespace Aurora::IO
{
AuUInt64 AFileHandle::DupHandle(AuUInt64 uOSHandle, bool bWriteAccess)
{
return DupHandle(uOSHandle, bWriteAccess, false);
}
AuUInt64 AFileHandle::DupHandle(AuUInt64 uOSHandle, bool bWriteAccess, bool bShareAccess)
{
HANDLE hTargetHandle = (HANDLE)uOSHandle;
HANDLE hTargetProcess = ::GetCurrentProcess();
HANDLE hHandle {};
if (!::DuplicateHandle(hTargetProcess,
hTargetHandle,
hTargetProcess,
&hHandle,
bWriteAccess ? GENERIC_WRITE | GENERIC_READ : GENERIC_READ,
bShareAccess ? TRUE : FALSE,
0))
{
return 0;
}
return AuUInt64(hHandle);
}
void AFileHandle::CloseHandle(AuUInt64 uOSHandle)
{
#if 0
HANDLE hHandle = (HANDLE)uOSHandle;
AuWin32CloseHandle(hHandle);
#else
Grug::CloseHandle(uOSHandle);
#endif
}
void AFileHandle::InitStdIn(bool bSharing)
{
HANDLE hHandle =
#if defined(AURORA_PLATFORM_WIN32)
GetStdHandle(STD_INPUT_HANDLE);
#else
Win32Open(L"CONIN$",
GENERIC_READ,
FILE_SHARE_READ,
bSharing,
OPEN_EXISTING,
0,
0);
#endif
if (hHandle != INVALID_HANDLE_VALUE)
{
auto uHandle = AuBuild::kCurrentPlatform == AuBuild::EPlatform::ePlatformWin32 ?
DupHandle((AuUInt64)hHandle, false, bSharing) :
(AuUInt64)hHandle;
this->uOSReadHandle = uHandle;
}
}
void AFileHandle::InitStdOut(bool bError, bool bSharing)
{
HANDLE hHandle =
#if defined(AURORA_PLATFORM_WIN32)
GetStdHandle(bError ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE);
#else
Win32Open(bError ? L"CONERR$" : L"CONOUT$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
bSharing,
OPEN_EXISTING,
0,
0);
#endif
if (hHandle != INVALID_HANDLE_VALUE)
{
auto uHandle = AuBuild::kCurrentPlatform == AuBuild::EPlatform::ePlatformWin32 ?
DupHandle((AuUInt64)hHandle, true, bSharing) :
(AuUInt64)hHandle;
this->uOSWriteHandle = this->uOSReadHandle = uHandle;
}
}
bool AFileHandle::InitFromPath(HandleCreate create)
{
HANDLE hFileHandle;
DWORD dwFlags {};
DWORD dwAttrs {};
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)
{
dwAttrs |= FILE_ATTRIBUTE_NORMAL;
}
for (AU_ITERATE_N(i, 2))
{
switch (create.eMode)
{
case FS::EFileOpenMode::eRead:
{
hFileHandle = Win32Open(win32Path.c_str(),
GENERIC_READ,
dwShare,
false,
OPEN_EXISTING,
dwFlags,
dwAttrs);
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 = Win32Open(win32Path.c_str(),
GENERIC_WRITE | GENERIC_READ | DELETE,
false,
false,
CREATE_NEW,
dwFlags,
dwAttrs);
if (hFileHandle == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_FILE_EXISTS ||
AuFS::FileExists(pathex.c_str()))
{
SysPushErrorResourceExists("File {} already exists", create.path);
return false;
}
}
}
else
{
hFileHandle = Win32Open(win32Path.c_str(),
GENERIC_WRITE | GENERIC_READ | DELETE,
dwShare,
false,
OPEN_EXISTING,
dwFlags,
dwAttrs);
if (hFileHandle == INVALID_HANDLE_VALUE)
{
hFileHandle = Win32Open(win32Path.c_str(),
GENERIC_WRITE | GENERIC_READ | DELETE,
dwShare,
false,
CREATE_NEW,
dwFlags,
dwAttrs);
}
}
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 = Win32Open(win32Path.c_str(),
GENERIC_WRITE | DELETE,
NULL,
false,
CREATE_NEW,
dwFlags,
dwAttrs);
if (hFileHandle == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_FILE_EXISTS ||
AuFS::FileExists(pathex.c_str()))
{
SysPushErrorResourceExists("File {} already exists", create.path);
return false;
}
}
}
else
{
hFileHandle = Win32Open(win32Path.c_str(),
GENERIC_WRITE | FILE_READ_ATTRIBUTES | DELETE,
dwShare,
false,
OPEN_EXISTING,
dwFlags,
dwAttrs);
if (hFileHandle == INVALID_HANDLE_VALUE)
{
hFileHandle = Win32Open(win32Path.c_str(),
GENERIC_WRITE | DELETE,
dwShare,
false,
CREATE_NEW,
dwFlags,
dwAttrs);
}
}
if (hFileHandle != INVALID_HANDLE_VALUE)
{
this->uOSWriteHandle = AuUInt64(hFileHandle);
}
break;
}
}
if (hFileHandle == INVALID_HANDLE_VALUE)
{
if (i == 0)
{
RuntimeWaitForSecondaryTick();
}
else
{
SysPushErrorIO("Couldn't open: {}", create.path);
return false;
}
}
else
{
break;
}
}
this->bIsAsync = create.bAsyncHandle;
this->path = create.path;
return this->IsValid();
}
AUKN_SYM bool IsHandleTTY(AuUInt uHandle)
{
bool bIsPipe {};
DWORD dwType {};
if (!uHandle ||
uHandle == (AuUInt)INVALID_HANDLE_VALUE)
{
SysPushErrorArg();
return false;
}
if (!(dwType = ::GetFileType((HANDLE)uHandle)))
{
SysPushErrorGeneric();
return {};
}
return dwType == FILE_TYPE_CHAR;
}
AUKN_SYM bool IsHandlePipe(AuUInt uHandle)
{
bool bIsPipe {};
DWORD dwType {};
if (!uHandle ||
uHandle == (AuUInt)INVALID_HANDLE_VALUE)
{
SysPushErrorArg();
return false;
}
if (!(dwType = ::GetFileType((HANDLE)uHandle)))
{
SysPushErrorGeneric();
return {};
}
return dwType == FILE_TYPE_PIPE;
}
AUKN_SYM bool IsHandleFile(AuUInt uHandle)
{
bool bIsPipe {};
DWORD dwType {};
if (!uHandle ||
uHandle == (AuUInt)INVALID_HANDLE_VALUE)
{
SysPushErrorArg();
return false;
}
if (!(dwType = ::GetFileType((HANDLE)uHandle)))
{
SysPushErrorGeneric();
return {};
}
return dwType == FILE_TYPE_DISK;
}
}