AuroraRuntime/Source/IO/AuIOHandle.cpp

488 lines
12 KiB
C++

/***
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuIOHandle.cpp
Date: 2023-7-28
Author: Reece
***/
#include <RuntimeInternal.hpp>
#include "AuIOHandle.hpp"
#include "FS/FileAdvisory.hpp"
#if defined(AURORA_IS_MODERNNT_DERIVED)
#include <Aurora/IO/NT/HANDLEPipeServer.hpp>
#endif
#if defined(AURORA_IS_POSIX_DERIVED)
#include <Aurora/IO/UNIX/UNIX.hpp>
#endif
namespace Aurora::IO
{
AFileHandle::AFileHandle()
{
this->uThreadId = AuUInt(AuThreads::GetThreadId());
}
AFileHandle::~AFileHandle()
{
if (this->SharingIsShared())
{
this->SharingStop();
}
if (this->pThat)
{
return;
}
if (this->uOSWriteHandle.HasValue() && this->uOSReadHandle.HasValue() &&
this->uOSReadHandle.Value() == this->uOSWriteHandle.Value())
{
this->CloseHandle(this->uOSReadHandle.Value(), this->bFlushOnClose, this->bShouldWriteEoS);
AuResetMember(this->uOSReadHandle);
AuResetMember(this->uOSWriteHandle);
}
if (this->uOSReadHandle)
{
this->CloseHandle(this->uOSReadHandle.Value(), false, false);
AuResetMember(this->uOSReadHandle);
}
if (this->uOSWriteHandle)
{
AFileHandle::CloseHandle(this->uOSWriteHandle.Value(), this->bFlushOnClose, this->bShouldWriteEoS);
AuResetMember(this->uOSWriteHandle);
}
}
bool AFileHandle::InitFromHandle(const AuSPtr<IIOHandle> &pHandle)
{
SysCheckArgNotNull(pHandle, false);
AU_LOCK_GUARD(this);
auto pSrc = AuStaticCast<AFileHandle>(pHandle);
auto pDest = this;
if (this->IsValid())
{
return false;
}
pDest->pThat = pHandle;
pDest->uOSReadHandle = pSrc->uOSReadHandle;
pDest->uOSWriteHandle = pSrc->uOSWriteHandle;
pDest->bIsAsync = pSrc->bIsAsync;
pDest->uThreadId = pSrc->uThreadId;
return true;
}
bool AFileHandle::InitFromCopy(AuUInt64 uOSHandle)
{
AU_LOCK_GUARD(this);
if (this->IsValid())
{
return false;
}
if (auto uOSWriteHandle = this->DupHandle(uOSHandle, true))
{
this->uOSReadHandle = uOSWriteHandle;
this->uOSWriteHandle = uOSWriteHandle;
this->uThreadId = AuUInt(AuThreads::GetThreadId());
return true;
}
else
{
return {};
}
}
bool AFileHandle::InitFromMove(AuUInt64 uOSHandle)
{
AU_LOCK_GUARD(this);
if (this->IsValid())
{
return false;
}
this->uOSReadHandle = uOSHandle;
this->uOSWriteHandle = uOSHandle;
this->uThreadId = AuUInt(AuThreads::GetThreadId());
return true;
}
bool AFileHandle::InitFromPair(AuOptional<AuUInt64> optOSReadHandle,
AuOptional<AuUInt64> optOSWriteHandle)
{
AU_LOCK_GUARD(this);
if (this->IsValid())
{
return false;
}
this->uThreadId = AuUInt(AuThreads::GetThreadId());
if (optOSReadHandle)
{
if (auto uOSReadHandle2 = this->DupHandle(optOSReadHandle.Value(), false))
{
this->uOSReadHandle = uOSReadHandle2;
}
else
{
return {};
}
}
if (optOSWriteHandle)
{
if (auto uOSWriteHandle2 = this->DupHandle(optOSWriteHandle.Value(), true))
{
this->uOSWriteHandle = uOSWriteHandle2;
}
else
{
this->CloseHandle(this->uOSReadHandle.Value());
AuResetMember(this->uOSReadHandle);
return {};
}
}
return true;
}
bool AFileHandle::InitFromPairMove(AuOptional<AuUInt64> uOSReadHandle,
AuOptional<AuUInt64> uOSWriteHandle)
{
AU_LOCK_GUARD(this);
if (this->IsValid())
{
return false;
}
this->uOSReadHandle = uOSReadHandle;
this->uOSWriteHandle = uOSWriteHandle;
this->uThreadId = AuUInt(AuThreads::GetThreadId());
return true;
}
bool AFileHandle::InitFromStreamEnum(EStandardStream eStream)
{
AU_LOCK_GUARD(this);
switch (eStream)
{
case EStandardStream::eInputStream:
this->InitStdIn();
return this->IsValid();
case EStandardStream::eErrorStream:
case EStandardStream::eOutputStream:
this->InitStdOut(eStream == EStandardStream::eErrorStream);
return this->IsValid();
default:
SysPushErrorArg();
return false;
}
}
bool AFileHandle::IsFile() const
{
bool bIsFile {};
if (auto optFile = this->optIsFile)
{
return optFile.Value();
}
if (auto optHandle = this->GetOSHandleSafe())
{
bIsFile = IsHandleFile(optHandle.Value());
}
else
{
SysPushErrorUninitialized();
return false;
}
this->optIsFile = bIsFile;
return bIsFile;
}
bool AFileHandle::IsTTY() const
{
bool bIsTTY {};
if (auto optTTY = this->optIsTTY)
{
return optTTY.Value();
}
if (auto optHandle = this->GetOSHandleSafe())
{
bIsTTY = IsHandleTTY(optHandle.Value());
}
else
{
SysPushErrorUninitialized();
return false;
}
this->optIsTTY = bIsTTY;
return bIsTTY;
}
bool AFileHandle::IsFlushOnClose() const
{
return this->bFlushOnClose;
}
void AFileHandle::SetFlushOnClose(bool bFlushOnClose)
{
this->bFlushOnClose = bFlushOnClose;
}
bool AFileHandle::IsWriteEoSOnClose() const
{
return this->bShouldWriteEoS;
}
void AFileHandle::SetWriteEoSOnClose(bool bShouldWriteEoS)
{
this->bShouldWriteEoS = bShouldWriteEoS;
}
bool AFileHandle::IsPipe() const
{
bool bIsPipe {};
if (auto optPipe = this->optIsPipe)
{
return optPipe.Value();
}
if (auto optHandle = this->GetOSHandleSafe())
{
bIsPipe = IsHandlePipe(optHandle.Value());
}
else
{
SysPushErrorUninitialized();
return false;
}
this->optIsPipe = bIsPipe;
return bIsPipe;
}
AuOptional<AuUInt64> AFileHandle::GetOSHandleSafe() const
{
if (auto write = this->uOSWriteHandle)
{
return write;
}
if (auto read = this->uOSReadHandle)
{
return read;
}
return {};
}
AuUInt64 AFileHandle::GetOSHandle() const
{
return this->uOSWriteHandle.OrElse(AuMove([=]()
{
return this->uOSReadHandle;
})).Value();
}
AuUInt64 AFileHandle::GetOSReadHandle() const
{
return this->uOSReadHandle.Value();
}
AuOptional<AuUInt64> AFileHandle::GetOSReadHandleSafe() const
{
return this->uOSReadHandle;
}
AuUInt64 AFileHandle::GetOSWriteHandle() const
{
return this->uOSWriteHandle.Value();
}
AuOptional<AuUInt64> AFileHandle::GetOSWriteHandleSafe() const
{
return this->uOSWriteHandle;
}
bool AFileHandle::IsValid() const
{
return this->uOSReadHandle ||
this->uOSWriteHandle;
}
bool AFileHandle::HasUniqueWriteHandle() const
{
return bool(this->uOSWriteHandle);
}
bool AFileHandle::IsAsync() const
{
return this->bIsAsync;
}
const AuString &AFileHandle::GetPath() const
{
return this->path;
}
bool AFileHandle::SectionLock(AuUInt64 uOffset,
AuUInt64 uLength,
FS::EFileAdvisoryLockLevel level)
{
return FS::ApplyFileSectionLock(AuUnsafeRaiiToShared(this), level, uOffset, uLength);
}
bool AFileHandle::SectionUnlock(AuUInt64 uOffset,
AuUInt64 uLength)
{
return FS::UnapplyFileSectionLock(AuUnsafeRaiiToShared(this), uOffset, uLength);
}
bool AFileHandle::InitFromSharing(const AuString &handle)
{
AU_LOCK_GUARD(this);
if (this->uOSReadHandle ||
this->uOSWriteHandle)
{
return false;
}
#if defined(AURORA_IS_MODERNNT_DERIVED)
auto hHandle = NT::ShareFileDescriptorAccept(handle);
if (hHandle == INVALID_HANDLE_VALUE)
{
return false;
}
auto uOSWriteHandle = AuUInt(hHandle);
this->uOSReadHandle = uOSWriteHandle;
this->uOSWriteHandle = uOSWriteHandle;
#endif
#if defined(AURORA_IS_POSIX_DERIVED)
auto iHandle = UNIX::ShareFileDescriptorAccept(handle);
if (iHandle == -1 ||
iHandle == 0)
{
return false;
}
auto uOSWriteHandle = AuUInt(iHandle);
this->uOSReadHandle = uOSWriteHandle;
this->uOSWriteHandle = uOSWriteHandle;
#endif
this->uThreadId = AuUInt(AuThreads::GetThreadId());
return true;
}
bool AFileHandle::InitFromHandleCopy(const IIOHandle *pHandle)
{
SysCheckArgNotNull(pHandle, false);
return this->InitFromPair(pHandle->GetOSReadHandleSafe(), pHandle->GetOSWriteHandleSafe());
}
AuString AFileHandle::SharingGetString()
{
AU_LOCK_GUARD(this);
AuString handle;
if (this->pIPCString)
{
return *this->pIPCString;
}
#if defined(AURORA_IS_MODERNNT_DERIVED)
handle = NT::ShareFileDescriptor((HANDLE)this->GetOSHandleSafe().ValueOr(-1));
#endif
#if defined(AURORA_IS_POSIX_DERIVED)
handle = UNIX::ShareFileDescriptor(this->GetOSHandleSafe().ValueOr(-1));
#endif
if (handle.empty())
{
return {};
}
this->pIPCString = AuMakeSharedPanic<AuString>(handle);
return *this->pIPCString;
}
bool AFileHandle::SharingIsShared()
{
return bool(this->pIPCString);
}
void AFileHandle::SharingStop()
{
if (auto pString = AuExchange(this->pIPCString, {}))
{
#if defined(AURORA_IS_MODERNNT_DERIVED)
NT::ShareFileDescriptorStop(*pString);
#endif
#if defined(AURORA_IS_POSIX_DERIVED)
UNIX::ShareFileDescriptorStop(*pString);
#endif
}
}
AuUInt64 AFileHandle::GetFileLength()
{
if (this->uOSReadHandle)
{
return SysGetFileLength(this->uOSReadHandle.Value());
}
SysPushErrorResourceInvalid();
return 0;
}
bool AFileHandle::ShouldClone()
{
return this->uThreadId != AuUInt(AuThreads::GetThreadId());
}
AUKN_SYM IIOHandle *IOHandleNew()
{
return _new AFileHandle();
}
AUKN_SYM void IOHandleRelease(IIOHandle *pIOHandle)
{
AuSafeDelete<AFileHandle *>(pIOHandle);
}
AUKN_SYM void IOHandleCopy(IIOHandle *dest, const IIOHandle *source)
{
AuResetMember(*AuStaticCast<AFileHandle>(dest));
dest->InitFromPair(source->GetOSReadHandleSafe(), source->GetOSWriteHandleSafe());
}
AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, IOHandle, AFileHandle)
}