mirror of
https://github.com/reactos/reactos.git
synced 2025-01-11 16:51:06 +00:00
c424146e2c
svn path=/branches/cmake-bringup/; revision=48236
508 lines
14 KiB
C
508 lines
14 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS system libraries
|
|
* FILE: lib/kernel32/misc/utils.c
|
|
* PURPOSE: Utility and Support Functions
|
|
* PROGRAMMER: Alex Ionescu (alex@relsoft.net)
|
|
*/
|
|
|
|
/* INCLUDES ****************************************************************/
|
|
|
|
#include <k32.h>
|
|
#ifdef _M_IX86
|
|
#include "i386/ketypes.h"
|
|
#elif defined _M_AMD64
|
|
#include "amd64/ketypes.h"
|
|
#endif
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* GLOBALS ******************************************************************/
|
|
|
|
PRTL_CONVERT_STRING Basep8BitStringToUnicodeString;
|
|
|
|
/* FUNCTIONS ****************************************************************/
|
|
|
|
/*
|
|
* Converts an ANSI or OEM String to the specified Unicode String
|
|
*/
|
|
NTSTATUS
|
|
WINAPI
|
|
Basep8BitStringToLiveUnicodeString(OUT PUNICODE_STRING UnicodeString,
|
|
IN LPCSTR String)
|
|
{
|
|
ANSI_STRING AnsiString;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("Basep8BitStringToLiveUnicodeString\n");
|
|
|
|
/* Create the ANSI String */
|
|
RtlInitAnsiString(&AnsiString, String);
|
|
|
|
/* Convert from OEM or ANSI */
|
|
Status = Basep8BitStringToUnicodeString(UnicodeString, &AnsiString, FALSE);
|
|
|
|
/* Return Status */
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
SetLastErrorByStatus(Status);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
/*
|
|
* Converts an ANSI or OEM String to the TEB StaticUnicodeString
|
|
*/
|
|
PUNICODE_STRING
|
|
WINAPI
|
|
Basep8BitStringToCachedUnicodeString(IN LPCSTR String)
|
|
{
|
|
PUNICODE_STRING StaticString = &NtCurrentTeb()->StaticUnicodeString;
|
|
ANSI_STRING AnsiString;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("Basep8BitStringToCachedUnicodeString\n");
|
|
|
|
/* Initialize an ANSI String */
|
|
RtlInitAnsiString(&AnsiString, String);
|
|
|
|
/* Convert it */
|
|
Status = Basep8BitStringToUnicodeString(StaticString, &AnsiString, FALSE);
|
|
|
|
/* Handle failure */
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
SetLastErrorByStatus(Status);
|
|
return NULL;
|
|
}
|
|
|
|
/* Return pointer to the string */
|
|
return StaticString;
|
|
}
|
|
|
|
NTSTATUS
|
|
WINAPI
|
|
Basep8BitStringToHeapUnicodeString(OUT PUNICODE_STRING UnicodeString,
|
|
IN LPCSTR String)
|
|
{
|
|
ANSI_STRING AnsiString;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("Basep8BitStringToCachedUnicodeString\n");
|
|
|
|
/* Initialize an ANSI String */
|
|
RtlInitAnsiString(&AnsiString, String);
|
|
|
|
/* Convert it */
|
|
Status = Basep8BitStringToUnicodeString(UnicodeString, &AnsiString, TRUE);
|
|
|
|
/* Handle failure */
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
SetLastErrorByStatus(Status);
|
|
}
|
|
/* Return Status */
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* Allocates space from the Heap and converts an Ansi String into it
|
|
*/
|
|
VOID
|
|
WINAPI
|
|
BasepAnsiStringToHeapUnicodeString(IN LPCSTR AnsiString,
|
|
OUT LPWSTR* UnicodeString)
|
|
{
|
|
ANSI_STRING AnsiTemp;
|
|
UNICODE_STRING UnicodeTemp;
|
|
|
|
DPRINT("BasepAnsiStringToHeapUnicodeString\n");
|
|
|
|
/* First create the ANSI_STRING */
|
|
RtlInitAnsiString(&AnsiTemp, AnsiString);
|
|
|
|
if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeTemp,
|
|
&AnsiTemp,
|
|
TRUE)))
|
|
{
|
|
*UnicodeString = UnicodeTemp.Buffer;
|
|
}
|
|
else
|
|
{
|
|
*UnicodeString = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Converts lpSecurityAttributes + Object Name into ObjectAttributes.
|
|
*/
|
|
POBJECT_ATTRIBUTES
|
|
WINAPI
|
|
BasepConvertObjectAttributes(OUT POBJECT_ATTRIBUTES ObjectAttributes,
|
|
IN PSECURITY_ATTRIBUTES SecurityAttributes OPTIONAL,
|
|
IN PUNICODE_STRING ObjectName)
|
|
{
|
|
ULONG Attributes = 0;
|
|
HANDLE RootDirectory = 0;
|
|
PVOID SecurityDescriptor = NULL;
|
|
BOOLEAN NeedOba = FALSE;
|
|
|
|
DPRINT("BasepConvertObjectAttributes. Security: %p, Name: %p\n",
|
|
SecurityAttributes, ObjectName);
|
|
|
|
/* Get the attributes if present */
|
|
if (SecurityAttributes)
|
|
{
|
|
Attributes = SecurityAttributes->bInheritHandle ? OBJ_INHERIT : 0;
|
|
SecurityDescriptor = SecurityAttributes->lpSecurityDescriptor;
|
|
NeedOba = TRUE;
|
|
}
|
|
|
|
if (ObjectName)
|
|
{
|
|
Attributes |= OBJ_OPENIF;
|
|
RootDirectory = hBaseDir;
|
|
NeedOba = TRUE;
|
|
}
|
|
|
|
DPRINT("Attributes: %lx, RootDirectory: %lx, SecurityDescriptor: %p\n",
|
|
Attributes, RootDirectory, SecurityDescriptor);
|
|
|
|
/* Create the Object Attributes */
|
|
if (NeedOba)
|
|
{
|
|
InitializeObjectAttributes(ObjectAttributes,
|
|
ObjectName,
|
|
Attributes,
|
|
RootDirectory,
|
|
SecurityDescriptor);
|
|
return ObjectAttributes;
|
|
}
|
|
|
|
/* Nothing to return */
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Creates a stack for a thread or fiber
|
|
*/
|
|
NTSTATUS
|
|
WINAPI
|
|
BasepCreateStack(HANDLE hProcess,
|
|
SIZE_T StackReserve,
|
|
SIZE_T StackCommit,
|
|
PINITIAL_TEB InitialTeb)
|
|
{
|
|
NTSTATUS Status;
|
|
SYSTEM_BASIC_INFORMATION SystemBasicInfo;
|
|
PIMAGE_NT_HEADERS Headers;
|
|
ULONG_PTR Stack = 0;
|
|
BOOLEAN UseGuard = FALSE;
|
|
|
|
DPRINT("BasepCreateStack (hProcess: %lx, Max: %lx, Current: %lx)\n",
|
|
hProcess, StackReserve, StackCommit);
|
|
|
|
/* Get some memory information */
|
|
Status = NtQuerySystemInformation(SystemBasicInformation,
|
|
&SystemBasicInfo,
|
|
sizeof(SYSTEM_BASIC_INFORMATION),
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failure to query system info\n");
|
|
return Status;
|
|
}
|
|
|
|
/* Use the Image Settings if we are dealing with the current Process */
|
|
if (hProcess == NtCurrentProcess())
|
|
{
|
|
/* Get the Image Headers */
|
|
Headers = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
|
|
|
|
/* If we didn't get the parameters, find them ourselves */
|
|
StackReserve = (StackReserve) ?
|
|
StackReserve : Headers->OptionalHeader.SizeOfStackReserve;
|
|
StackCommit = (StackCommit) ?
|
|
StackCommit : Headers->OptionalHeader.SizeOfStackCommit;
|
|
}
|
|
else
|
|
{
|
|
/* Use the System Settings if needed */
|
|
StackReserve = (StackReserve) ? StackReserve :
|
|
SystemBasicInfo.AllocationGranularity;
|
|
StackCommit = (StackCommit) ? StackCommit : SystemBasicInfo.PageSize;
|
|
}
|
|
|
|
/* Align everything to Page Size */
|
|
StackReserve = ROUND_UP(StackReserve, SystemBasicInfo.AllocationGranularity);
|
|
StackCommit = ROUND_UP(StackCommit, SystemBasicInfo.PageSize);
|
|
#if 1 // FIXME: Remove once Guard Page support is here
|
|
StackCommit = StackReserve;
|
|
#endif
|
|
DPRINT("StackReserve: %lx, StackCommit: %lx\n", StackReserve, StackCommit);
|
|
|
|
/* Reserve memory for the stack */
|
|
Status = ZwAllocateVirtualMemory(hProcess,
|
|
(PVOID*)&Stack,
|
|
0,
|
|
&StackReserve,
|
|
MEM_RESERVE,
|
|
PAGE_READWRITE);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failure to reserve stack\n");
|
|
return Status;
|
|
}
|
|
|
|
/* Now set up some basic Initial TEB Parameters */
|
|
InitialTeb->AllocatedStackBase = (PVOID)Stack;
|
|
InitialTeb->StackBase = (PVOID)(Stack + StackReserve);
|
|
InitialTeb->PreviousStackBase = NULL;
|
|
InitialTeb->PreviousStackLimit = NULL;
|
|
|
|
/* Update the Stack Position */
|
|
Stack += StackReserve - StackCommit;
|
|
|
|
/* Check if we will need a guard page */
|
|
if (StackReserve > StackCommit)
|
|
{
|
|
Stack -= SystemBasicInfo.PageSize;
|
|
StackCommit += SystemBasicInfo.PageSize;
|
|
UseGuard = TRUE;
|
|
}
|
|
|
|
/* Allocate memory for the stack */
|
|
Status = ZwAllocateVirtualMemory(hProcess,
|
|
(PVOID*)&Stack,
|
|
0,
|
|
&StackCommit,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failure to allocate stack\n");
|
|
return Status;
|
|
}
|
|
|
|
/* Now set the current Stack Limit */
|
|
InitialTeb->StackLimit = (PVOID)Stack;
|
|
|
|
/* Create a guard page */
|
|
if (UseGuard)
|
|
{
|
|
SIZE_T GuardPageSize = SystemBasicInfo.PageSize;
|
|
ULONG Dummy;
|
|
|
|
/* Attempt maximum space possible */
|
|
Status = ZwProtectVirtualMemory(hProcess,
|
|
(PVOID*)&Stack,
|
|
&GuardPageSize,
|
|
PAGE_GUARD | PAGE_READWRITE,
|
|
&Dummy);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failure to create guard page\n");
|
|
return Status;
|
|
}
|
|
|
|
/* Update the Stack Limit keeping in mind the Guard Page */
|
|
InitialTeb->StackLimit = (PVOID)((ULONG_PTR)InitialTeb->StackLimit - GuardPageSize);
|
|
}
|
|
|
|
/* We are done! */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
WINAPI
|
|
BasepFreeStack(HANDLE hProcess,
|
|
PINITIAL_TEB InitialTeb)
|
|
{
|
|
SIZE_T Dummy = 0;
|
|
|
|
/* Free the Stack */
|
|
NtFreeVirtualMemory(hProcess,
|
|
&InitialTeb->AllocatedStackBase,
|
|
&Dummy,
|
|
MEM_RELEASE);
|
|
}
|
|
|
|
/*
|
|
* Creates the Initial Context for a Thread or Fiber
|
|
*/
|
|
VOID
|
|
WINAPI
|
|
BasepInitializeContext(IN PCONTEXT Context,
|
|
IN PVOID Parameter,
|
|
IN PVOID StartAddress,
|
|
IN PVOID StackAddress,
|
|
IN ULONG ContextType)
|
|
{
|
|
#ifdef _M_IX86
|
|
DPRINT("BasepInitializeContext: %p\n", Context);
|
|
|
|
/* Setup the Initial Win32 Thread Context */
|
|
Context->Eax = (ULONG)StartAddress;
|
|
Context->Ebx = (ULONG)Parameter;
|
|
Context->Esp = (ULONG)StackAddress;
|
|
/* The other registers are undefined */
|
|
|
|
/* Setup the Segments */
|
|
Context->SegFs = KGDT_R3_TEB | RPL_MASK;
|
|
Context->SegEs = KGDT_R3_DATA | RPL_MASK;
|
|
Context->SegDs = KGDT_R3_DATA | RPL_MASK;
|
|
Context->SegCs = KGDT_R3_CODE | RPL_MASK;
|
|
Context->SegSs = KGDT_R3_DATA | RPL_MASK;
|
|
Context->SegGs = 0;
|
|
|
|
/* Set the EFLAGS */
|
|
Context->EFlags = 0x3000; /* IOPL 3 */
|
|
|
|
if (ContextType == 1) /* For Threads */
|
|
{
|
|
Context->Eip = (ULONG)BaseThreadStartupThunk;
|
|
}
|
|
else if (ContextType == 2) /* For Fibers */
|
|
{
|
|
Context->Eip = (ULONG)BaseFiberStartup;
|
|
}
|
|
else /* For first thread in a Process */
|
|
{
|
|
Context->Eip = (ULONG)BaseProcessStartThunk;
|
|
}
|
|
|
|
/* Set the Context Flags */
|
|
Context->ContextFlags = CONTEXT_FULL;
|
|
|
|
/* Give it some room for the Parameter */
|
|
Context->Esp -= sizeof(PVOID);
|
|
#elif defined(_M_AMD64)
|
|
DPRINT("BasepInitializeContext: %p\n", Context);
|
|
|
|
/* Setup the Initial Win32 Thread Context */
|
|
Context->Rax = (ULONG_PTR)StartAddress;
|
|
Context->Rbx = (ULONG_PTR)Parameter;
|
|
Context->Rsp = (ULONG_PTR)StackAddress;
|
|
/* The other registers are undefined */
|
|
|
|
/* Setup the Segments */
|
|
Context->SegGs = KGDT64_R3_DATA | RPL_MASK;
|
|
Context->SegEs = KGDT64_R3_DATA | RPL_MASK;
|
|
Context->SegDs = KGDT64_R3_DATA | RPL_MASK;
|
|
Context->SegCs = KGDT64_R3_CODE | RPL_MASK;
|
|
Context->SegSs = KGDT64_R3_DATA | RPL_MASK;
|
|
Context->SegFs = KGDT64_R3_CMTEB | RPL_MASK;
|
|
|
|
/* Set the EFLAGS */
|
|
Context->EFlags = 0x3000; /* IOPL 3 */
|
|
|
|
if (ContextType == 1) /* For Threads */
|
|
{
|
|
Context->Rip = (ULONG_PTR)BaseThreadStartupThunk;
|
|
}
|
|
else if (ContextType == 2) /* For Fibers */
|
|
{
|
|
Context->Rip = (ULONG_PTR)BaseFiberStartup;
|
|
}
|
|
else /* For first thread in a Process */
|
|
{
|
|
Context->Rip = (ULONG_PTR)BaseProcessStartThunk;
|
|
}
|
|
|
|
/* Set the Context Flags */
|
|
Context->ContextFlags = CONTEXT_FULL;
|
|
|
|
/* Give it some room for the Parameter */
|
|
Context->Rsp -= sizeof(PVOID);
|
|
#else
|
|
#warning Unknown architecture
|
|
UNIMPLEMENTED;
|
|
DbgBreakPoint();
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Checks if the privilege for Real-Time Priority is there
|
|
*/
|
|
BOOLEAN
|
|
WINAPI
|
|
BasepCheckRealTimePrivilege(VOID)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Maps an image file into a section
|
|
*/
|
|
NTSTATUS
|
|
WINAPI
|
|
BasepMapFile(IN LPCWSTR lpApplicationName,
|
|
OUT PHANDLE hSection,
|
|
IN PUNICODE_STRING ApplicationName)
|
|
{
|
|
CURDIR RelativeName;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
NTSTATUS Status;
|
|
HANDLE hFile = NULL;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
DPRINT("BasepMapFile\n");
|
|
|
|
/* Zero out the Relative Directory */
|
|
RelativeName.Handle = NULL;
|
|
|
|
/* Find the application name */
|
|
if (!RtlDosPathNameToNtPathName_U(lpApplicationName,
|
|
ApplicationName,
|
|
NULL,
|
|
&RelativeName))
|
|
{
|
|
return STATUS_OBJECT_PATH_NOT_FOUND;
|
|
}
|
|
|
|
DPRINT("ApplicationName %wZ\n", ApplicationName);
|
|
DPRINT("RelativeName %wZ\n", &RelativeName.DosPath);
|
|
|
|
/* Did we get a relative name? */
|
|
if (RelativeName.DosPath.Length)
|
|
{
|
|
ApplicationName = &RelativeName.DosPath;
|
|
}
|
|
|
|
/* Initialize the Object Attributes */
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
ApplicationName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
RelativeName.Handle,
|
|
NULL);
|
|
|
|
/* Try to open the executable */
|
|
Status = NtOpenFile(&hFile,
|
|
SYNCHRONIZE | FILE_EXECUTE | FILE_READ_DATA,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_DELETE | FILE_SHARE_READ,
|
|
FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failed to open file\n");
|
|
SetLastErrorByStatus(Status);
|
|
return Status;
|
|
}
|
|
|
|
/* Create a section for this file */
|
|
Status = NtCreateSection(hSection,
|
|
SECTION_ALL_ACCESS,
|
|
NULL,
|
|
NULL,
|
|
PAGE_EXECUTE,
|
|
SEC_IMAGE,
|
|
hFile);
|
|
NtClose(hFile);
|
|
|
|
/* Return status */
|
|
DPRINT("Section: %lx for file: %lx\n", *hSection, hFile);
|
|
return Status;
|
|
}
|