Jamie Reece Wilson
232a136bfe
[+] IOHandle::SetWriteEoSOnClose [+] IOHandle::HandleCreate::bFlushOnClose [+] IOHandle::HandleCreate::bWriteEoSOnClose [*] Unified grug based auto-truncating. Previously we were truncating on the final derefing thread; now, we truncate on the grug thread. [*] Refactor/Cleanup IOHandle
386 lines
12 KiB
C++
386 lines
12 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, bool bFlushOnClose, bool bWriteEoS)
|
|
{
|
|
#if 0
|
|
HANDLE hHandle = (HANDLE)uOSHandle;
|
|
AuWin32CloseHandle(hHandle);
|
|
#else
|
|
Grug::CloseHandle(uOSHandle, bFlushOnClose, bWriteEoS);
|
|
#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->bShouldWriteEoS = create.bWriteEoSOnClose;
|
|
this->bFlushOnClose = create.bFlushOnClose;
|
|
|
|
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;
|
|
}
|
|
} |