/*** 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" namespace Aurora::IO { AuUInt64 AFileHandle::DupHandle(AuUInt64 uOSHandle, bool bWriteAccess) { HANDLE hTargetHandle = (HANDLE)uOSHandle; HANDLE hTargetProcess = ::GetCurrentProcess(); HANDLE hHandle {}; if (!::DuplicateHandle(hTargetProcess, hTargetHandle, hTargetProcess, &hHandle, bWriteAccess ? GENERIC_WRITE | GENERIC_READ : GENERIC_READ, FALSE, FALSE)) { return 0; } return AuUInt64(hHandle); } void AFileHandle::CloseHandle(AuUInt64 uOSHandle) { HANDLE hHandle = (HANDLE)uOSHandle; AuWin32CloseHandle(hHandle); } struct NTIOHandle final : AFileHandle { bool InitFromPath(HandleCreate create) override; }; bool NTIOHandle::InitFromPath(HandleCreate create) { HANDLE hFileHandle; DWORD dwFlags {}; 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) { dwFlags |= FILE_ATTRIBUTE_NORMAL; } switch (create.eMode) { case FS::EFileOpenMode::eRead: { hFileHandle = ::CreateFileW(win32Path.c_str(), GENERIC_READ, dwShare, NULL, OPEN_EXISTING, dwFlags, NULL); 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 = ::CreateFileW(win32Path.c_str(), GENERIC_WRITE | GENERIC_READ | DELETE, NULL, NULL, CREATE_NEW, dwFlags, NULL); if (hFileHandle == INVALID_HANDLE_VALUE) { if (AuFS::FileExists(pathex.c_str())) { SysPushErrorResourceExists("File {} already exists", create.path); return false; } } } else { hFileHandle = ::CreateFileW(win32Path.c_str(), GENERIC_WRITE | GENERIC_READ | DELETE, dwShare, NULL, OPEN_EXISTING, dwFlags, NULL); if (hFileHandle == INVALID_HANDLE_VALUE) { hFileHandle = ::CreateFileW(win32Path.c_str(), GENERIC_WRITE | GENERIC_READ | DELETE, dwShare, NULL, CREATE_NEW, dwFlags, NULL); } } 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 = ::CreateFileW(win32Path.c_str(), GENERIC_WRITE | DELETE, NULL, NULL, CREATE_NEW, dwFlags, NULL); if (hFileHandle == INVALID_HANDLE_VALUE) { if (AuFS::FileExists(pathex.c_str())) { SysPushErrorResourceExists("File {} already exists", create.path); return false; } } } else { hFileHandle = ::CreateFileW(win32Path.c_str(), GENERIC_WRITE | FILE_READ_ATTRIBUTES | DELETE, dwShare, NULL, OPEN_EXISTING, dwFlags, NULL); if (hFileHandle == INVALID_HANDLE_VALUE) { hFileHandle = ::CreateFileW(win32Path.c_str(), GENERIC_WRITE | DELETE, dwShare, NULL, CREATE_NEW, dwFlags, NULL); } } if (hFileHandle != INVALID_HANDLE_VALUE) { this->uOSWriteHandle = AuUInt64(hFileHandle); } break; } } if (hFileHandle == INVALID_HANDLE_VALUE) { SysPushErrorIO("Couldn't open: {}", create.path); return false; } this->bIsAsync = create.bAsyncHandle; 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; } AUKN_SYM IIOHandle *IOHandleNew() { return _new NTIOHandle(); } AUKN_SYM void IOHandleRelease(IIOHandle *pIOHandle) { AuSafeDelete(pIOHandle); } AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, IOHandle, NTIOHandle) }