#pragma once #include "bcl_common.h" #ifndef RTL_SXS_KERNEL_MODE #include "nturtl.h" #include "windows.h" #include "bcl_w32unicodeinlinestringbuffer.h" #ifndef NUMBER_OF #define NUMBER_OF(q) (sizeof(q) / sizeof(*q)) #endif class CWin32Environment { public: typedef CWin32Environment CEnv; typedef DWORD StatusCode; typedef BCL::CMutablePointerAndCountPair CByteRegion; typedef BCL::CConstantPointerAndCountPair CConstantByteRegion; typedef BCL::CMutablePointerAndCountPair CUnicodeStringPair; typedef BCL::CConstantPointerAndCountPair CConstantUnicodeStringPair; typedef BCL::CWin32BaseUnicodeInlineStringBuffer<128> CStringBuffer; static const CConstantUnicodeStringPair s_FileSystemSeperator; enum { SuccessCode = ERROR_SUCCESS, InvalidParameter = ERROR_INVALID_PARAMETER, NotEnoughBuffer = ERROR_INSUFFICIENT_BUFFER, OutOfMemory = ERROR_NOT_ENOUGH_MEMORY, NotFound = ERROR_NOT_FOUND, NotImplemented = ERROR_INVALID_FUNCTION }; // // Case-sensitive // static StatusCode CompareStrings(const CConstantUnicodeStringPair &Left, const CConstantUnicodeStringPair &Right, int &iResult) { iResult = 0; int iInternalResult = CompareStringW( GetThreadLocale(), 0, Left.GetPointer(), Left.GetCount(), Right.GetPointer(), Right.GetCount()); switch (iInternalResult) { case CSTR_EQUAL: iResult = 0; break; case CSTR_GREATER_THAN: iResult = 1; break; case CSTR_LESS_THAN: iResult = -1; break; case 0: return ::GetLastError(); } return SuccessCode; } static StatusCode CompareStringsCaseInsensitive(const CConstantUnicodeStringPair &Left, const CConstantUnicodeStringPair &Right, int &iResult) { iResult = 0; int iInternalResult = CompareStringW( GetThreadLocale(), NORM_IGNORECASE, Left.GetPointer(), Left.GetCount(), Right.GetPointer(), Right.GetCount()); switch (iInternalResult) { case CSTR_EQUAL: iResult = 0; break; case CSTR_GREATER_THAN: iResult = 1; break; case CSTR_LESS_THAN: iResult = -1; break; case 0: return ::GetLastError(); } return SuccessCode; } static StatusCode CreateDirectory(SIZE_T ItemCount, const CConstantUnicodeStringPair *Listing) { PWSTR pwszWorkingBuffer = NULL, pwszCursor; SIZE_T i = 0; SIZE_T cchRequired = 0; StatusCode Result; // // Figure out how large the buffer is that we need here // for (i = 0; i < ItemCount; i++) { if (i != 0) cchRequired += s_FileSystemSeperator.GetCount(); cchRequired += Listing[i].GetCount(); } Result = CEnv::AllocateHeap((cchRequired + 1) * sizeof(WCHAR), (PVOID*)&pwszWorkingBuffer, NULL); if (CEnv::DidFail(Result)) return Result; pwszCursor = pwszWorkingBuffer; // // Now for each path segment, start copying it into the // working buffer and creating paths from it. // for (i = 0; i < ItemCount; i++) { const CConstantUnicodeStringPair &Me = Listing[i]; if (i != 0) { memcpy(pwszCursor, s_FileSystemSeperator.GetPointer(), s_FileSystemSeperator.GetCount() * sizeof(WCHAR)); pwszCursor += s_FileSystemSeperator.GetCount(); } memcpy(pwszCursor, Me.GetPointer(), Me.GetCount() * sizeof(WCHAR)); pwszCursor += Me.GetCount(); *pwszCursor = UNICODE_NULL; if (!::CreateDirectoryW(pwszWorkingBuffer, NULL) && (::GetLastError() == ERROR_ALREADY_EXISTS)) { Result = ::GetLastError(); goto Exit; } } Result = CEnv::SuccessCode; Exit: if (pwszWorkingBuffer) CEnv::FreeHeap(pwszWorkingBuffer, NULL); return Result; } static CConstantUnicodeStringPair StringFrom(const UNICODE_STRING *pus) { return CConstantUnicodeStringPair(pus->Buffer, pus->Length); } static CConstantUnicodeStringPair StringFrom(PCWSTR pcwszInput) { return CConstantUnicodeStringPair(pcwszInput, ::wcslen(pcwszInput)); } static CConstantUnicodeStringPair StringFrom(const CConstantUnicodeStringPair& src) { return src; } static StatusCode Compare(const CConstantUnicodeStringPair &Left, const CConstantUnicodeStringPair &Right, int &Result) { if (((Left.GetCount() / sizeof(WCHAR)) > USHRT_MAX) || ((Right.GetCount() / sizeof(WCHAR)) > USHRT_MAX)) return InvalidParameter; // Evil casting is required b/c UNICODE_STRING requires it. const UNICODE_STRING TheLeft = { (USHORT)Left.GetCount(), 0, (PWSTR)Left.GetPointer() }; const UNICODE_STRING TheRight = { (SHORT)Right.GetCount(), 0, (PWSTR)Right.GetPointer() }; Result = RtlCompareUnicodeString(&TheLeft, &TheRight, FALSE); return SuccessCode; } static bool DidFail(StatusCode dwCode) { return (dwCode != SuccessCode); } static StatusCode VirtualAlloc(PVOID pvAddress, SIZE_T cbSize, DWORD flAllocationType, DWORD flProtect, PVOID *ppvRegion) { if (NULL == (*ppvRegion = ::VirtualAlloc(pvAddress, cbSize, flAllocationType, flProtect))) { return ::GetLastError(); } else { return SuccessCode; } } static StatusCode VirtualFree(PVOID pvAddress, SIZE_T cbSize, DWORD dwFreeType) { if (!::VirtualFree(pvAddress, cbSize, dwFreeType)) { return ::GetLastError(); } else { return SuccessCode; } } static NTSTATUS FASTCALL AllocateHeap(SIZE_T cb, CByteRegion &Recipient, PVOID pvContext) { PVOID pvAcquired = NULL; CEnv::StatusCode Result; Recipient.SetPointerAndCount(NULL, 0); if (CEnv::DidFail(Result = CEnv::AllocateHeap(cb, &pvAcquired, pvContext))) return Result; Recipient.SetPointerAndCount((CByteRegion::TMutableArray)pvAcquired, cb); return Result; } static NTSTATUS FASTCALL AllocateHeap(SIZE_T cb, PVOID *ppvTarget, PVOID pvContext) { if (NULL == (*ppvTarget = RtlAllocateHeap(RtlProcessHeap(), 0, cb))) { return STATUS_INVALID_PARAMETER; } else { return SuccessCode; } } static NTSTATUS FASTCALL FreeHeap(PVOID ppvTarget, PVOID pvContext) { if (!RtlFreeHeap(RtlProcessHeap(), 0, ppvTarget)) { return STATUS_INVALID_PARAMETER; } else { return SuccessCode; } } static StatusCode CloseHandle(HANDLE h) { if (!::CloseHandle(h)) { return ::GetLastError(); } else { return SuccessCode; } } static StatusCode GetFileHandle(HANDLE* pHandle, const CConstantUnicodeStringPair &FileName, DWORD dwRights, DWORD dwSharing, DWORD dwCreation) { PCWSTR pcwszTemp = NULL; PCWSTR pcwszInput = NULL; StatusCode dwRetVal = SuccessCode; *pHandle = INVALID_HANDLE_VALUE; pcwszInput = FileName.GetPointer(); if (!pcwszInput || (FileName.GetCount() == 0) || (pcwszInput[FileName.GetCount() - 1] != UNICODE_NULL)) { PWSTR pwszAllocTemp = NULL; dwRetVal = AllocateHeap((FileName.GetCount() + 1) * sizeof(WCHAR), (PVOID*)&pwszAllocTemp, NULL); if (dwRetVal != SuccessCode) { return dwRetVal; } RtlCopyMemory(pwszAllocTemp, pcwszInput, FileName.GetCount() * sizeof(WCHAR)); pwszAllocTemp[FileName.GetCount()] = UNICODE_NULL; pcwszTemp = pwszAllocTemp; } else { pcwszTemp = pcwszInput; } *pHandle = CreateFileW(pcwszTemp, dwRights, dwSharing, NULL, dwCreation, FILE_ATTRIBUTE_NORMAL, NULL); if (*pHandle == INVALID_HANDLE_VALUE) { dwRetVal = ::GetLastError(); } else { dwRetVal = SuccessCode; } if (pcwszTemp != pcwszInput) { FreeHeap((PVOID)pcwszTemp, NULL); } return dwRetVal; } static StatusCode ReadFile(HANDLE hFile, CEnv::CByteRegion &Target, SIZE_T &cbDidRead) { return CEnv::ReadFile(hFile, Target.GetPointer(), Target.GetCount(), cbDidRead); } static StatusCode ReadFile(HANDLE hFile, PVOID pvTarget, SIZE_T cbToRead, SIZE_T &cbDidRead) { DWORD dwToRead, dwDidRead; cbDidRead = 0; if (cbToRead > 0xFFFFFFFF) { return InvalidParameter; } dwToRead = (DWORD)cbToRead; if (!::ReadFile(hFile, pvTarget, dwToRead, &dwDidRead, NULL)) { return ::GetLastError(); } cbDidRead = dwDidRead; return SuccessCode; } static StatusCode WriteFile(HANDLE hFile, const CEnv::CConstantByteRegion &Source, SIZE_T &cbDidWrite) { return CEnv::WriteFile(hFile, (PVOID)Source.GetPointer(), Source.GetCount(), cbDidWrite); } static StatusCode WriteFile(HANDLE hFile, const PVOID pvSource, SIZE_T cbToWrite, SIZE_T &cbDidWrite) { DWORD dwToWrite, dwDidWrite; cbDidWrite = 0; if (cbDidWrite > 0xFFFFFFFF) { return InvalidParameter; } dwToWrite = (DWORD)cbToWrite; if (!::WriteFile(hFile, pvSource, dwToWrite, &dwDidWrite, NULL)) { return GetLastError(); } cbDidWrite = dwDidWrite; return SuccessCode; } static StatusCode GetFileSize(HANDLE hFile, PLARGE_INTEGER pcbFileSize) { if (GetFileSizeEx(hFile, pcbFileSize)) { return SuccessCode; } else { return ::GetLastError(); } } }; __declspec(selectany) const CWin32Environment::CConstantUnicodeStringPair CWin32Environment::s_FileSystemSeperator(L"\\", 1); #endif class CNtEnvironment { public: typedef NTSTATUS StatusCode; enum { SuccessCode = STATUS_SUCCESS, InvalidParameter = STATUS_INVALID_PARAMETER, NotEnoughBuffer = STATUS_BUFFER_TOO_SMALL, }; template static T ConvertStatusToOther(StatusCode src); template <> static CWin32Environment::StatusCode ConvertStatusToOther(StatusCode src) { return RtlNtStatusToDosError(src); } template <> static CNtEnvironment::StatusCode ConvertStatusToOther(StatusCode src) { return src; } static bool DidFail(StatusCode status) { return (status < 0); } }; #ifndef RTLSXS_USE_KERNEL_MODE typedef CWin32Environment CEnv; typedef CNtEnvironment COtherEnv; #else typedef CNtEnvironment CEnv; typedef CWin32Environment COtherEnv; #endif