/*** 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() { if (this->uOSWriteHandle.has_value() && this->uOSReadHandle.has_value() && this->uOSReadHandle.value() == this->uOSWriteHandle.value()) { this->CloseHandle(this->uOSReadHandle.value()); AuResetMember(this->uOSReadHandle); AuResetMember(this->uOSWriteHandle); } if (this->uOSReadHandle) { this->CloseHandle(this->uOSReadHandle.value()); AuResetMember(this->uOSReadHandle); } if (this->uOSWriteHandle) { this->CloseHandle(this->uOSWriteHandle.value()); AuResetMember(this->uOSWriteHandle); } } bool AFileHandle::InitFromHandle(AuSPtr pHandle) { 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; return true; } bool AFileHandle::InitFromCopy(AuUInt64 uOSHandle) { if (this->IsValid()) { return false; } if (auto uOSWriteHandle = this->DupHandle(uOSHandle, true)) { this->uOSReadHandle = uOSWriteHandle; this->uOSWriteHandle = uOSWriteHandle; return true; } else { return {}; } } bool AFileHandle::InitFromMove(AuUInt64 uOSHandle) { if (this->IsValid()) { return false; } this->uOSReadHandle = uOSHandle; this->uOSWriteHandle = uOSHandle; return true; } bool AFileHandle::InitFromPair(AuOptionalEx optOSReadHandle, AuOptionalEx optOSWriteHandle) { if (this->IsValid()) { return false; } 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(AuOptionalEx uOSReadHandle, AuOptionalEx uOSWriteHandle) { if (this->IsValid()) { return false; } this->uOSReadHandle = uOSReadHandle; this->uOSWriteHandle = uOSWriteHandle; return true; } bool AFileHandle::InitFromStreamEnum(EStandardStream eStream) { 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::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; } AuOptionalEx AFileHandle::GetOSHandleSafe() const { if (auto write = this->uOSWriteHandle) { return write; } if (auto read = this->uOSReadHandle) { return read; } return {}; } AuUInt64 AFileHandle::GetOSHandle() const { return this->uOSReadHandle.ValueOr(this->uOSWriteHandle.value()); } AuUInt64 AFileHandle::GetOSReadHandle() const { return this->uOSReadHandle.value(); } AuOptionalEx AFileHandle::GetOSReadHandleSafe() const { return this->uOSReadHandle; } AuUInt64 AFileHandle::GetOSWriteHandle() const { return this->uOSWriteHandle.value(); } AuOptionalEx 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; } 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) { 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 return true; } AuString AFileHandle::SharingGetString() { 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((HANDLE)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 } } 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) }