From b4d5f4c127b0bcca0f6d6eb39768688d7c1f42c4 Mon Sep 17 00:00:00 2001 From: Jamie Reece Wilson Date: Wed, 13 Sep 2023 02:50:53 +0100 Subject: [PATCH] [+] AuIO::IO::EStandardStream [+] AuIO::IOHandle::InitFromStreamEnum(...) --- Include/Aurora/IO/EStandardStream.hpp | 17 +++++++ Include/Aurora/IO/IO.hpp | 1 + Include/Aurora/IO/IOHandle.hpp | 2 + Source/IO/AuIOHandle.NT.cpp | 49 +++++++++++++++++++ Source/IO/AuIOHandle.Unix.cpp | 46 +++++++++++++++++- Source/IO/AuIOHandle.cpp | 17 +++++++ Source/IO/AuIOHandle.hpp | 5 ++ Source/Processes/AuProcess.NT.cpp | 68 +++++++++------------------ 8 files changed, 157 insertions(+), 48 deletions(-) create mode 100644 Include/Aurora/IO/EStandardStream.hpp diff --git a/Include/Aurora/IO/EStandardStream.hpp b/Include/Aurora/IO/EStandardStream.hpp new file mode 100644 index 00000000..690ad26a --- /dev/null +++ b/Include/Aurora/IO/EStandardStream.hpp @@ -0,0 +1,17 @@ +/*** + Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: EStandardStream.hpp + Date: 2023-9-13 + Author: Reece +***/ +#pragma once + +namespace Aurora::IO +{ + AUE_DEFINE_VA(EStandardStream, + eInputStream, + eOutputStream, + eErrorStream + ); +} \ No newline at end of file diff --git a/Include/Aurora/IO/IO.hpp b/Include/Aurora/IO/IO.hpp index cf93fb7d..cdceedff 100644 --- a/Include/Aurora/IO/IO.hpp +++ b/Include/Aurora/IO/IO.hpp @@ -8,6 +8,7 @@ #pragma once #include "EStreamError.hpp" +#include "EStandardStream.hpp" #include "IStreamReader.hpp" #include "IStreamWriter.hpp" diff --git a/Include/Aurora/IO/IOHandle.hpp b/Include/Aurora/IO/IOHandle.hpp index 1b0997c0..fb2d03c4 100644 --- a/Include/Aurora/IO/IOHandle.hpp +++ b/Include/Aurora/IO/IOHandle.hpp @@ -106,6 +106,8 @@ namespace Aurora::IO virtual bool InitFromPairMove(AuOptionalEx uOSReadHandle, AuOptionalEx uOSWriteHandle) = 0; + virtual bool InitFromStreamEnum(EStandardStream eStream) = 0; + virtual AuUInt64 GetOSHandle() = 0; virtual AuOptionalEx GetOSHandleSafe() = 0; diff --git a/Source/IO/AuIOHandle.NT.cpp b/Source/IO/AuIOHandle.NT.cpp index 412d2eea..56063cc7 100644 --- a/Source/IO/AuIOHandle.NT.cpp +++ b/Source/IO/AuIOHandle.NT.cpp @@ -45,6 +45,55 @@ namespace Aurora::IO AuWin32CloseHandle(hHandle); } + 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, + false, + 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, + false, + 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; + } + } + struct NTIOHandle final : AFileHandle { bool InitFromPath(HandleCreate create) override; diff --git a/Source/IO/AuIOHandle.Unix.cpp b/Source/IO/AuIOHandle.Unix.cpp index 87af041e..5442da1c 100644 --- a/Source/IO/AuIOHandle.Unix.cpp +++ b/Source/IO/AuIOHandle.Unix.cpp @@ -23,17 +23,49 @@ // Yea, I don't give a shit. #endif +#if !defined(FD_CLOEXEC) + #define FD_CLOEXEC 0 +#endif + namespace Aurora::IO { AuUInt64 AFileHandle::DupHandle(AuUInt64 uOSHandle, bool bWriteAccess) { - int fd = dup(uOSHandle); + return DupHandle(uOSHandle, bWriteAccess, false); + } + + AuUInt64 AFileHandle::DupHandle(AuUInt64 uOSHandle, bool bWriteAccess, bool bShareAccess) + { + int fd = ::dup(uOSHandle); if (fd < 0) { return 0; } - + + int flags = ::fcntl(fd, F_GETFL, 0); + if (flags == -1) + { + ::close(fd); + return 0; + } + + if (bShareAccess) + { + flags &= ~FD_CLOEXEC; + } + else + { + flags |= FD_CLOEXEC; + } + + flags = ::fcntl(fd, F_SETFL, flags); + if (flags == -1) + { + ::close(fd); + return 0; + } + return AuUInt64(fd); } @@ -48,6 +80,16 @@ namespace Aurora::IO ::close(fd); } + void AFileHandle::InitStdIn(bool bSharing) + { + this->uOSReadHandle = DupHandle(STDIN_FILENO, false, bSharing); + } + + void AFileHandle::InitStdOut(bool bError, bool bSharing) + { + this->uOSReadHandle = this->uOSWriteHandle = DupHandle(bError ? STDERR_FILENO : STDOUT_FILENO, true, bSharing); + } + struct UnixIOHandle final : AFileHandle { bool InitFromPath(HandleCreate create) override; diff --git a/Source/IO/AuIOHandle.cpp b/Source/IO/AuIOHandle.cpp index 80a72626..cd95e1b3 100644 --- a/Source/IO/AuIOHandle.cpp +++ b/Source/IO/AuIOHandle.cpp @@ -126,6 +126,23 @@ namespace Aurora::IO 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() { bool bIsFile {}; diff --git a/Source/IO/AuIOHandle.hpp b/Source/IO/AuIOHandle.hpp index e28f5ac2..85d4cc3e 100644 --- a/Source/IO/AuIOHandle.hpp +++ b/Source/IO/AuIOHandle.hpp @@ -30,6 +30,8 @@ namespace Aurora::IO bool InitFromPairMove(AuOptionalEx uOSReadHandle, AuOptionalEx uOSWriteHandle) override; + bool InitFromStreamEnum(EStandardStream eStream) override; + AuUInt64 GetOSHandle() override; AuOptionalEx GetOSHandleSafe() override; @@ -54,6 +56,9 @@ namespace Aurora::IO bool IsTTY() override; bool IsPipe() override; + void InitStdIn(bool bSharing = false); + void InitStdOut(bool bError = false, bool bSharing = false); + AuOptionalEx uOSWriteHandle; AuOptionalEx uOSReadHandle; AuSPtr pThat; diff --git a/Source/Processes/AuProcess.NT.cpp b/Source/Processes/AuProcess.NT.cpp index 4120b1b2..445847e6 100644 --- a/Source/Processes/AuProcess.NT.cpp +++ b/Source/Processes/AuProcess.NT.cpp @@ -295,23 +295,15 @@ namespace Aurora::Processes } else if (this->startup_.fwdOut == EStreamForward::eCurrentProcess) { - HANDLE hHandle = GetStdHandle(STD_OUTPUT_HANDLE); - - if (hHandle != INVALID_HANDLE_VALUE) + AuResetMember(this->startup_.handleOutStream); + AuStaticCast(this->startup_.handleOutStream.AsPointer())->InitStdOut(false, true); + auto optHandle = this->startup_.handleOutStream->GetOSHandleSafe(); + if (!optHandle) { - HANDLE hTargetProcess = ::GetCurrentProcess(); - - if (!::DuplicateHandle(hTargetProcess, - hHandle, - hTargetProcess, - &this->pipeStdOutWrite_, - GENERIC_READ | GENERIC_WRITE, - TRUE, - 0)) - { - return false; - } + return false; } + this->pipeStdOutWrite_ = (HANDLE)optHandle.value(); + this->bDontRelOut_ = true; } if (this->startup_.fwdErr == EStreamForward::eAsyncPipe) @@ -355,23 +347,15 @@ namespace Aurora::Processes } else if (this->startup_.fwdErr == EStreamForward::eCurrentProcess) { - HANDLE hHandle = GetStdHandle(STD_ERROR_HANDLE); - - if (hHandle != INVALID_HANDLE_VALUE) + AuResetMember(this->startup_.handleErrorStream); + AuStaticCast(this->startup_.handleErrorStream.AsPointer())->InitStdOut(true, true); + auto optHandle = this->startup_.handleErrorStream->GetOSHandleSafe(); + if (!optHandle) { - HANDLE hTargetProcess = ::GetCurrentProcess(); - - if (!::DuplicateHandle(hTargetProcess, - hHandle, - hTargetProcess, - &this->pipeStdErrWrite_, - GENERIC_READ | GENERIC_WRITE, - TRUE, - 0)) - { - return false; - } + return false; } + this->pipeStdErrWrite_ = (HANDLE)optHandle.value(); + this->bDontRelErr_ = true; } if (this->startup_.fwdIn == EStreamForward::eAsyncPipe) @@ -415,23 +399,15 @@ namespace Aurora::Processes } else if (this->startup_.fwdIn == EStreamForward::eCurrentProcess) { - HANDLE hHandle = GetStdHandle(STD_INPUT_HANDLE); - - if (hHandle != INVALID_HANDLE_VALUE) + AuResetMember(this->startup_.handleInputStream); + AuStaticCast(this->startup_.handleInputStream.AsPointer())->InitStdIn(true); + auto optHandle = this->startup_.handleInputStream->GetOSHandleSafe(); + if (!optHandle) { - HANDLE hTargetProcess = ::GetCurrentProcess(); - - if (!::DuplicateHandle(hTargetProcess, - hHandle, - hTargetProcess, - &this->pipeStdInRead_, - GENERIC_READ, - TRUE, - 0)) - { - return false; - } + return false; } + this->pipeStdInRead_ = (HANDLE)optHandle.value(); + this->bDontRelIn_ = true; } { @@ -439,7 +415,7 @@ namespace Aurora::Processes #define NEW_NULL_HANDLE \ { \ - nulFile = CreateFileA("NUL", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); \ + nulFile = Win32Open(L"NUL", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, false, OPEN_EXISTING, 0, 0); \ SetHandleInformation(nulFile, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); \ }