/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: FileAdvisory.NT.cpp Date: 2022-1-29 Author: Reece ***/ #include #include "FS.hpp" #include "FileAdvisory.hpp" #include "FileAdvisory.NT.hpp" namespace Aurora::IO::FS { DWORD NtLockAdvisoryToShare(EFileAdvisoryLockLevel level) { switch (level) { case EFileAdvisoryLockLevel::eEnumCount: case EFileAdvisoryLockLevel::eNoSafety: return FILE_SHARE_READ | FILE_SHARE_WRITE; case EFileAdvisoryLockLevel::eBlockWrite: return FILE_SHARE_READ; case EFileAdvisoryLockLevel::eBlockReadWrite: return 0; } return 0; } bool ApplyFileSectionLock(AuSPtr pHandle, EFileAdvisoryLockLevel level, AuUInt64 uOffset, AuUInt64 uLength) { DWORD dwFlags {}; OVERLAPPED overlapped {}; HANDLE hEventHandle { INVALID_HANDLE_VALUE }; if (!pHandle) { SysPushErrorUninitialized(); return false; } if (!pHandle->IsFile()) { SysPushErrorIOResourceRejected(); return false; } switch (level) { case EFileAdvisoryLockLevel::eEnumCount: case EFileAdvisoryLockLevel::eNoSafety: return true; case EFileAdvisoryLockLevel::eBlockWrite: break; case EFileAdvisoryLockLevel::eBlockReadWrite: dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; break; } auto hHandle = (HANDLE)pHandle->GetOSHandleSafe().ValueOr((AuUInt)INVALID_HANDLE_VALUE); if (hHandle == INVALID_HANDLE_VALUE) { SysPushErrorIOResourceRejected(); return false; } bool bIsAsync = pHandle->IsAsync(); if (bIsAsync) { hEventHandle = ::CreateEventA(nullptr, false, false, nullptr); if (!hEventHandle) { SysPushErrorGeneric(); return false; } overlapped.hEvent = hEventHandle; } overlapped.Offset = AuBitsToLower(uOffset); overlapped.OffsetHigh = AuBitsToHigher(uOffset); dwFlags |= LOCKFILE_FAIL_IMMEDIATELY; if (!LockFileEx(hHandle, dwFlags, 0, AuBitsToLower(uLength), AuBitsToHigher(uLength), &overlapped)) { if (GetLastError() == ERROR_IO_PENDING) { ::WaitForSingleObject(hEventHandle, 0); DWORD idc {}; if (!::GetOverlappedResult(hHandle, &overlapped, &idc, true)) { AuWin32CloseHandle(hEventHandle); return false; } } else { AuWin32CloseHandle(hEventHandle); return false; } } AuWin32CloseHandle(hEventHandle); return true; } bool UnapplyFileSectionLock(AuSPtr pHandle, AuUInt64 uOffset, AuUInt64 uLength) { DWORD dwFlags {}; OVERLAPPED overlapped {}; HANDLE hEventHandle { INVALID_HANDLE_VALUE }; if (!pHandle) { SysPushErrorUninitialized(); return false; } if (!pHandle->IsFile()) { SysPushErrorIOResourceRejected(); return false; } auto hHandle = (HANDLE)pHandle->GetOSHandleSafe().ValueOr((AuUInt)INVALID_HANDLE_VALUE); if (hHandle == INVALID_HANDLE_VALUE) { SysPushErrorIOResourceRejected(); return false; } bool bIsAsync = pHandle->IsAsync(); if (bIsAsync) { hEventHandle = ::CreateEventA(nullptr, false, false, nullptr); if (!hEventHandle) { SysPushErrorGeneric(); return false; } overlapped.hEvent = hEventHandle; } dwFlags |= LOCKFILE_FAIL_IMMEDIATELY; overlapped.Offset = AuBitsToLower(uOffset); overlapped.OffsetHigh = AuBitsToHigher(uOffset); if (!UnlockFileEx(hHandle, 0, AuBitsToLower(uLength), AuBitsToHigher(uLength), &overlapped)) { if (GetLastError() == ERROR_IO_PENDING) { ::WaitForSingleObject(hEventHandle, 0); DWORD idc {}; if (!::GetOverlappedResult(hHandle, &overlapped, &idc, true)) { AuWin32CloseHandle(hEventHandle); return false; } } else { AuWin32CloseHandle(hEventHandle); return false; } } AuWin32CloseHandle(hEventHandle); return true; } }