You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
372 lines
12 KiB
372 lines
12 KiB
#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<BYTE, SIZE_T> CByteRegion;
|
|
typedef BCL::CConstantPointerAndCountPair<BYTE, SIZE_T> CConstantByteRegion;
|
|
typedef BCL::CMutablePointerAndCountPair<WCHAR, SIZE_T> CUnicodeStringPair;
|
|
typedef BCL::CConstantPointerAndCountPair<WCHAR, SIZE_T> 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 <typename T> 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
|