/*** Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuIOHandle.NT.cpp Date: 2023-7-28 Author: Reece ***/ #include #include "AuIOHandle.hpp" #include "AuIOHandle.NT.hpp" #include "FS/FS.hpp" #include "FS/FileAdvisory.NT.hpp" #include 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; } }