/*** Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuIOHandle.cpp Date: 2023-7-28 Author: Reece ***/ #include #include "AuIOHandle.hpp" #include "FS/FileAdvisory.hpp" #if defined(AURORA_IS_MODERNNT_DERIVED) #include #endif #if defined(AURORA_IS_POSIX_DERIVED) #include #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 &pHandle) { SysCheckArgNotNull(pHandle, false); AU_LOCK_GUARD(this); auto pSrc = AuStaticCast(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 optOSReadHandle, AuOptional 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 uOSReadHandle, AuOptional 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 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 AFileHandle::GetOSReadHandleSafe() const { return this->uOSReadHandle; } AuUInt64 AFileHandle::GetOSWriteHandle() const { return this->uOSWriteHandle.Value(); } AuOptional 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 AuROString &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(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(pIOHandle); } AUKN_SYM void IOHandleCopy(IIOHandle *dest, const IIOHandle *source) { AuResetMember(*AuStaticCast(dest)); dest->InitFromPair(source->GetOSReadHandleSafe(), source->GetOSWriteHandleSafe()); } AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, IOHandle, AFileHandle) }