362 lines
11 KiB
C++
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)
|
|
} |