reactos/subsystems/win/basesrv/vdm.c
Aleksandar Andrejevic 9c142126d3 [BASESRV]
In BaseSrvGetConsoleRecord and GetConsoleRecordBySessionId, check if the console record was not found instead
of returning the last one in the list.
In BaseSrvCheckVDM, return the session ID to the caller.


svn path=/branches/ntvdm/; revision=63120
2014-05-02 21:45:16 +00:00

1339 lines
48 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Base API Server DLL
* FILE: subsystems/win/basesrv/vdm.c
* PURPOSE: Virtual DOS Machines (VDM) Support
* PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
* Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*/
/* INCLUDES *******************************************************************/
#include "basesrv.h"
#include "vdm.h"
#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
BOOLEAN FirstVDM = TRUE;
LIST_ENTRY VDMConsoleListHead;
RTL_CRITICAL_SECTION DosCriticalSection;
RTL_CRITICAL_SECTION WowCriticalSection;
/* FUNCTIONS ******************************************************************/
NTSTATUS NTAPI BaseSrvGetConsoleRecord(HANDLE ConsoleHandle, PVDM_CONSOLE_RECORD *Record)
{
PLIST_ENTRY i;
PVDM_CONSOLE_RECORD CurrentRecord = NULL;
/* Search for a record that has the same console handle */
for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink)
{
CurrentRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry);
if (CurrentRecord->ConsoleHandle == ConsoleHandle) break;
}
/* Check if nothing was found */
if (i == &VDMConsoleListHead) CurrentRecord = NULL;
*Record = CurrentRecord;
return CurrentRecord ? STATUS_SUCCESS : STATUS_NOT_FOUND;
}
NTSTATUS NTAPI GetConsoleRecordBySessionId(ULONG TaskId, PVDM_CONSOLE_RECORD *Record)
{
PLIST_ENTRY i;
PVDM_CONSOLE_RECORD CurrentRecord = NULL;
/* Search for a record that has the same console handle */
for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink)
{
CurrentRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry);
if (CurrentRecord->SessionId == TaskId) break;
}
/* Check if nothing was found */
if (i == &VDMConsoleListHead) CurrentRecord = NULL;
*Record = CurrentRecord;
return CurrentRecord ? STATUS_SUCCESS : STATUS_NOT_FOUND;
}
ULONG NTAPI GetNextDosSesId(VOID)
{
ULONG SessionId;
PLIST_ENTRY i;
PVDM_CONSOLE_RECORD CurrentRecord = NULL;
BOOLEAN Found;
/* Search for an available session ID */
for (SessionId = 1; SessionId != 0; SessionId++)
{
Found = FALSE;
/* Check if the ID is already in use */
for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink)
{
CurrentRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry);
if (CurrentRecord->SessionId == SessionId) Found = TRUE;
}
/* If not, we found one */
if (!Found) break;
}
ASSERT(SessionId != 0);
/* Return the session ID */
return SessionId;
}
BOOLEAN NTAPI BaseSrvIsVdmAllowed(VOID)
{
NTSTATUS Status;
BOOLEAN VdmAllowed = TRUE;
HANDLE RootKey, KeyHandle;
UNICODE_STRING KeyName, ValueName, MachineKeyName;
OBJECT_ATTRIBUTES Attributes;
UCHAR ValueBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
PKEY_VALUE_PARTIAL_INFORMATION ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
ULONG ActualSize;
/* Initialize the unicode strings */
RtlInitUnicodeString(&MachineKeyName, L"\\Registry\\Machine");
RtlInitUnicodeString(&KeyName, VDM_POLICY_KEY_NAME);
RtlInitUnicodeString(&ValueName, VDM_DISALLOWED_VALUE_NAME);
InitializeObjectAttributes(&Attributes,
&MachineKeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
/* Open the local machine key */
Status = NtOpenKey(&RootKey, KEY_READ, &Attributes);
if (!NT_SUCCESS(Status)) return FALSE;
InitializeObjectAttributes(&Attributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
RootKey,
NULL);
/* Open the policy key in the local machine hive, if it exists */
if (NT_SUCCESS(NtOpenKey(&KeyHandle, KEY_READ, &Attributes)))
{
/* Read the value, if it's set */
if (NT_SUCCESS(NtQueryValueKey(KeyHandle,
&ValueName,
KeyValuePartialInformation,
ValueInfo,
sizeof(ValueBuffer),
&ActualSize)))
{
if (*((PULONG)ValueInfo->Data))
{
/* The VDM has been disabled in the registry */
VdmAllowed = FALSE;
}
}
NtClose(KeyHandle);
}
/* Close the local machine key */
NtClose(RootKey);
/* If it's disabled system-wide, there's no need to check the user key */
if (!VdmAllowed) return FALSE;
/* Open the current user key of the client */
if (!CsrImpersonateClient(NULL)) return VdmAllowed;
Status = RtlOpenCurrentUser(KEY_READ, &RootKey);
CsrRevertToSelf();
/* If that fails, return the system-wide setting */
if (!NT_SUCCESS(Status)) return VdmAllowed;
InitializeObjectAttributes(&Attributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
RootKey,
NULL);
/* Open the policy key in the current user hive, if it exists */
if (NT_SUCCESS(NtOpenKey(&KeyHandle, KEY_READ, &Attributes)))
{
/* Read the value, if it's set */
if (NT_SUCCESS(NtQueryValueKey(KeyHandle,
&ValueName,
KeyValuePartialInformation,
ValueInfo,
sizeof(ValueBuffer),
&ActualSize)))
{
if (*((PULONG)ValueInfo->Data))
{
/* The VDM has been disabled in the registry */
VdmAllowed = FALSE;
}
}
NtClose(KeyHandle);
}
return VdmAllowed;
}
NTSTATUS NTAPI BaseSrvCreatePairWaitHandles(PHANDLE ServerEvent, PHANDLE ClientEvent)
{
NTSTATUS Status;
/* Create the event */
Status = NtCreateEvent(ServerEvent, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE);
if (!NT_SUCCESS(Status)) return Status;
/* Duplicate the event into the client process */
Status = NtDuplicateObject(NtCurrentProcess(),
*ServerEvent,
CsrGetClientThread()->Process->ProcessHandle,
ClientEvent,
0,
0,
DUPLICATE_SAME_ATTRIBUTES | DUPLICATE_SAME_ACCESS);
if (!NT_SUCCESS(Status)) NtClose(*ServerEvent);
return Status;
}
VOID NTAPI BaseSrvFreeVDMInfo(PVDM_COMMAND_INFO CommandInfo)
{
/* Free the allocated structure members */
if (CommandInfo->CmdLine != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->CmdLine);
if (CommandInfo->AppName != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->AppName);
if (CommandInfo->PifFile != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->PifFile);
if (CommandInfo->CurDirectory != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->CurDirectory);
if (CommandInfo->Env != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Env);
if (CommandInfo->Desktop != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Desktop);
if (CommandInfo->Title != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Title);
if (CommandInfo->Reserved != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Reserved);
/* Free the structure itself */
RtlFreeHeap(BaseSrvHeap, 0, CommandInfo);
}
VOID NTAPI BaseSrvCleanupVdmRecords(ULONG ProcessId)
{
PLIST_ENTRY i;
PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
PVDM_DOS_RECORD DosRecord;
/* Enter the critical section */
RtlEnterCriticalSection(&DosCriticalSection);
/* Search for a record that has the same process handle */
for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink)
{
ConsoleRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry);
if (ConsoleRecord->ProcessId == ProcessId)
{
/* Cleanup the DOS records */
while (ConsoleRecord->DosListHead.Flink != &ConsoleRecord->DosListHead)
{
DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink,
VDM_DOS_RECORD,
Entry);
/* Set the event and close it */
NtSetEvent(DosRecord->ServerEvent, NULL);
NtClose(DosRecord->ServerEvent);
/* Remove the DOS entry */
if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
RemoveEntryList(&DosRecord->Entry);
RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
}
if (ConsoleRecord->CurrentDirs != NULL)
{
/* Free the current directories */
RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord->CurrentDirs);
ConsoleRecord->CurrentDirs = NULL;
ConsoleRecord->CurDirsLength = 0;
}
/* Close the event handle */
if (ConsoleRecord->ServerEvent) NtClose(ConsoleRecord->ServerEvent);
/* Remove the console record */
i = i->Blink;
RemoveEntryList(&ConsoleRecord->Entry);
RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
}
}
/* Leave the critical section */
RtlLeaveCriticalSection(&DosCriticalSection);
}
BOOLEAN NTAPI BaseSrvCopyCommand(PBASE_CHECK_VDM CheckVdmRequest, PVDM_DOS_RECORD DosRecord)
{
BOOLEAN Success = FALSE;
PVDM_COMMAND_INFO CommandInfo = NULL;
/* Allocate the command information structure */
CommandInfo = (PVDM_COMMAND_INFO)RtlAllocateHeap(BaseSrvHeap,
HEAP_ZERO_MEMORY,
sizeof(VDM_COMMAND_INFO));
if (CommandInfo == NULL) return FALSE;
/* Fill the structure */
CommandInfo->TaskId = CheckVdmRequest->iTask;
CommandInfo->ExitCode = DosRecord->ExitCode;
CommandInfo->CodePage = CheckVdmRequest->CodePage;
CommandInfo->StdIn = CheckVdmRequest->StdIn;
CommandInfo->StdOut = CheckVdmRequest->StdOut;
CommandInfo->StdErr = CheckVdmRequest->StdErr;
/* Allocate memory for the command line */
CommandInfo->CmdLine = RtlAllocateHeap(BaseSrvHeap,
HEAP_ZERO_MEMORY,
CheckVdmRequest->CmdLen);
if (CommandInfo->CmdLine == NULL) goto Cleanup;
/* Copy the command line */
RtlMoveMemory(CommandInfo->CmdLine, CheckVdmRequest->CmdLine, CheckVdmRequest->CmdLen);
/* Allocate memory for the application name */
CommandInfo->AppName = RtlAllocateHeap(BaseSrvHeap,
HEAP_ZERO_MEMORY,
CheckVdmRequest->AppLen);
if (CommandInfo->AppName == NULL) goto Cleanup;
/* Copy the application name */
RtlMoveMemory(CommandInfo->AppName, CheckVdmRequest->AppName, CheckVdmRequest->AppLen);
/* Allocate memory for the PIF file name */
if (CheckVdmRequest->PifLen != 0)
{
CommandInfo->PifFile = RtlAllocateHeap(BaseSrvHeap,
HEAP_ZERO_MEMORY,
CheckVdmRequest->PifLen);
if (CommandInfo->PifFile == NULL) goto Cleanup;
/* Copy the PIF file name */
RtlMoveMemory(CommandInfo->PifFile, CheckVdmRequest->PifFile, CheckVdmRequest->PifLen);
}
else CommandInfo->PifFile = NULL;
/* Allocate memory for the current directory */
if (CheckVdmRequest->CurDirectoryLen != 0)
{
CommandInfo->CurDirectory = RtlAllocateHeap(BaseSrvHeap,
HEAP_ZERO_MEMORY,
CheckVdmRequest->CurDirectoryLen);
if (CommandInfo->CurDirectory == NULL) goto Cleanup;
/* Copy the current directory */
RtlMoveMemory(CommandInfo->CurDirectory,
CheckVdmRequest->CurDirectory,
CheckVdmRequest->CurDirectoryLen);
}
else CommandInfo->CurDirectory = NULL;
/* Allocate memory for the environment block */
CommandInfo->Env = RtlAllocateHeap(BaseSrvHeap,
HEAP_ZERO_MEMORY,
CheckVdmRequest->EnvLen);
if (CommandInfo->Env == NULL) goto Cleanup;
/* Copy the environment block */
RtlMoveMemory(CommandInfo->Env, CheckVdmRequest->Env, CheckVdmRequest->EnvLen);
CommandInfo->EnvLen = CheckVdmRequest->EnvLen;
RtlMoveMemory(&CommandInfo->StartupInfo,
CheckVdmRequest->StartupInfo,
sizeof(STARTUPINFOA));
/* Allocate memory for the desktop */
if (CheckVdmRequest->DesktopLen != 0)
{
CommandInfo->Desktop = RtlAllocateHeap(BaseSrvHeap,
HEAP_ZERO_MEMORY,
CheckVdmRequest->DesktopLen);
if (CommandInfo->Desktop == NULL) goto Cleanup;
/* Copy the desktop name */
RtlMoveMemory(CommandInfo->Desktop, CheckVdmRequest->Desktop, CheckVdmRequest->DesktopLen);
}
else CommandInfo->Desktop = NULL;
CommandInfo->DesktopLen = CheckVdmRequest->DesktopLen;
/* Allocate memory for the title */
if (CheckVdmRequest->TitleLen != 0)
{
CommandInfo->Title = RtlAllocateHeap(BaseSrvHeap,
HEAP_ZERO_MEMORY,
CheckVdmRequest->TitleLen);
if (CommandInfo->Title == NULL) goto Cleanup;
/* Copy the title */
RtlMoveMemory(CommandInfo->Title, CheckVdmRequest->Title, CheckVdmRequest->TitleLen);
}
else CommandInfo->Title = NULL;
CommandInfo->TitleLen = CheckVdmRequest->TitleLen;
/* Allocate memory for the reserved field */
if (CheckVdmRequest->ReservedLen != 0)
{
CommandInfo->Reserved = RtlAllocateHeap(BaseSrvHeap,
HEAP_ZERO_MEMORY,
CheckVdmRequest->ReservedLen);
if (CommandInfo->Reserved == NULL) goto Cleanup;
/* Copy the reserved field */
RtlMoveMemory(CommandInfo->Reserved,
CheckVdmRequest->Reserved,
CheckVdmRequest->ReservedLen);
}
else CommandInfo->Reserved = NULL;
CommandInfo->ReservedLen = CheckVdmRequest->ReservedLen;
CommandInfo->CmdLen = CheckVdmRequest->CmdLen;
CommandInfo->AppLen = CheckVdmRequest->AppLen;
CommandInfo->PifLen = CheckVdmRequest->PifLen;
CommandInfo->CurDirectoryLen = CheckVdmRequest->CurDirectoryLen;
CommandInfo->VDMState = DosRecord->State;
// TODO: Set CommandInfo->CurrentDrive
// TODO: Set CommandInfo->ComingFromBat
/* Set the DOS record's command structure */
DosRecord->CommandInfo = CommandInfo;
/* The operation was successful */
Success = TRUE;
Cleanup:
/* If it wasn't successful, free the memory */
if (!Success) BaseSrvFreeVDMInfo(CommandInfo);
return Success;
}
NTSTATUS NTAPI BaseSrvFillCommandInfo(PVDM_COMMAND_INFO CommandInfo,
PBASE_GET_NEXT_VDM_COMMAND Message)
{
/* Copy the data */
Message->iTask = CommandInfo->TaskId;
Message->StdIn = CommandInfo->StdIn;
Message->StdOut = CommandInfo->StdOut;
Message->StdErr = CommandInfo->StdErr;
Message->CodePage = CommandInfo->CodePage;
Message->dwCreationFlags = CommandInfo->CreationFlags;
Message->ExitCode = CommandInfo->ExitCode;
Message->CurrentDrive = CommandInfo->CurrentDrive;
Message->VDMState = CommandInfo->VDMState;
Message->fComingFromBat = CommandInfo->ComingFromBat;
if (CommandInfo->CmdLen && Message->CmdLen)
{
if (Message->CmdLen < CommandInfo->CmdLen) return STATUS_BUFFER_TOO_SMALL;
/* Copy the command line */
RtlMoveMemory(Message->CmdLine, CommandInfo->CmdLine, CommandInfo->CmdLen);
Message->CmdLen = CommandInfo->CmdLen;
}
if (CommandInfo->AppLen && Message->AppLen)
{
if (Message->AppLen < CommandInfo->CmdLen) return STATUS_BUFFER_TOO_SMALL;
/* Copy the application name */
RtlMoveMemory(Message->AppName, CommandInfo->AppName, CommandInfo->AppLen);
Message->AppLen = CommandInfo->AppLen;
}
if (CommandInfo->PifLen && Message->PifLen)
{
if (Message->PifLen < CommandInfo->PifLen) return STATUS_BUFFER_TOO_SMALL;
/* Copy the PIF file name */
RtlMoveMemory(Message->PifFile, CommandInfo->PifFile, CommandInfo->PifLen);
Message->PifLen = CommandInfo->PifLen;
}
if (CommandInfo->CurDirectoryLen && Message->CurDirectoryLen)
{
if (Message->CurDirectoryLen < CommandInfo->CurDirectoryLen) return STATUS_BUFFER_TOO_SMALL;
/* Copy the current directory */
RtlMoveMemory(Message->CurDirectory, CommandInfo->CurDirectory, CommandInfo->CurDirectoryLen);
Message->CurDirectoryLen = CommandInfo->CurDirectoryLen;
}
if (CommandInfo->EnvLen && Message->EnvLen)
{
if (Message->EnvLen < CommandInfo->EnvLen) return STATUS_BUFFER_TOO_SMALL;
/* Copy the environment */
RtlMoveMemory(Message->Env, CommandInfo->Env, CommandInfo->EnvLen);
Message->EnvLen = CommandInfo->EnvLen;
}
/* Copy the startup info */
RtlMoveMemory(Message->StartupInfo,
&CommandInfo->StartupInfo,
sizeof(STARTUPINFOA));
if (CommandInfo->DesktopLen && Message->DesktopLen)
{
if (Message->DesktopLen < CommandInfo->DesktopLen) return STATUS_BUFFER_TOO_SMALL;
/* Copy the desktop name */
RtlMoveMemory(Message->Desktop, CommandInfo->Desktop, CommandInfo->DesktopLen);
Message->DesktopLen = CommandInfo->DesktopLen;
}
if (CommandInfo->TitleLen && Message->TitleLen)
{
if (Message->TitleLen < CommandInfo->TitleLen) return STATUS_BUFFER_TOO_SMALL;
/* Copy the title */
RtlMoveMemory(Message->Title, CommandInfo->Title, CommandInfo->TitleLen);
Message->TitleLen = CommandInfo->TitleLen;
}
if (CommandInfo->ReservedLen && Message->ReservedLen)
{
if (Message->ReservedLen < CommandInfo->ReservedLen) return STATUS_BUFFER_TOO_SMALL;
/* Copy the reserved parameter */
RtlMoveMemory(Message->Reserved, CommandInfo->Reserved, CommandInfo->ReservedLen);
Message->ReservedLen = CommandInfo->ReservedLen;
}
return STATUS_SUCCESS;
}
VOID NTAPI BaseInitializeVDM(VOID)
{
/* Initialize the list head */
InitializeListHead(&VDMConsoleListHead);
/* Initialize the critical section */
RtlInitializeCriticalSection(&DosCriticalSection);
RtlInitializeCriticalSection(&WowCriticalSection);
}
/* PUBLIC SERVER APIS *********************************************************/
CSR_API(BaseSrvCheckVDM)
{
NTSTATUS Status;
PBASE_CHECK_VDM CheckVdmRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.CheckVDMRequest;
PRTL_CRITICAL_SECTION CriticalSection = NULL;
PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
PVDM_DOS_RECORD DosRecord = NULL;
BOOLEAN NewConsoleRecord = FALSE;
/* Don't do anything if the VDM has been disabled in the registry */
if (!BaseSrvIsVdmAllowed()) return STATUS_ACCESS_DENIED;
/* Validate the message buffers */
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&CheckVdmRequest->CmdLine,
CheckVdmRequest->CmdLen,
sizeof(*CheckVdmRequest->CmdLine))
|| !CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&CheckVdmRequest->AppName,
CheckVdmRequest->AppLen,
sizeof(*CheckVdmRequest->AppName))
|| !CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&CheckVdmRequest->PifFile,
CheckVdmRequest->PifLen,
sizeof(*CheckVdmRequest->PifFile))
|| !CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&CheckVdmRequest->CurDirectory,
CheckVdmRequest->CurDirectoryLen,
sizeof(*CheckVdmRequest->CurDirectory))
|| !CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&CheckVdmRequest->Desktop,
CheckVdmRequest->DesktopLen,
sizeof(*CheckVdmRequest->Desktop))
|| !CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&CheckVdmRequest->Title,
CheckVdmRequest->TitleLen,
sizeof(*CheckVdmRequest->Title))
|| !CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&CheckVdmRequest->Reserved,
CheckVdmRequest->ReservedLen,
sizeof(*CheckVdmRequest->Reserved)))
{
return STATUS_INVALID_PARAMETER;
}
CriticalSection = (CheckVdmRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW)
? &DosCriticalSection
: &WowCriticalSection;
/* Enter the critical section */
RtlEnterCriticalSection(CriticalSection);
/* Check if this is a DOS or WOW VDM */
if (CheckVdmRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW)
{
/* Get the console record */
Status = BaseSrvGetConsoleRecord(CheckVdmRequest->ConsoleHandle,
&ConsoleRecord);
if (!NT_SUCCESS(Status))
{
/* Allocate a new console record */
ConsoleRecord = (PVDM_CONSOLE_RECORD)RtlAllocateHeap(BaseSrvHeap,
HEAP_ZERO_MEMORY,
sizeof(VDM_CONSOLE_RECORD));
if (ConsoleRecord == NULL)
{
Status = STATUS_NO_MEMORY;
goto Cleanup;
}
/* Remember that the console record was allocated here */
NewConsoleRecord = TRUE;
/* Initialize the console record */
ConsoleRecord->ConsoleHandle = CheckVdmRequest->ConsoleHandle;
ConsoleRecord->ProcessHandle = CsrGetClientThread()->Process->ProcessHandle;
ConsoleRecord->ServerEvent = ConsoleRecord->ClientEvent = NULL;
ConsoleRecord->ReenterCount = 0;
ConsoleRecord->CurrentDirs = NULL;
ConsoleRecord->CurDirsLength = 0;
ConsoleRecord->SessionId = GetNextDosSesId();
InitializeListHead(&ConsoleRecord->DosListHead);
}
/* Allocate a new DOS record */
DosRecord = (PVDM_DOS_RECORD)RtlAllocateHeap(BaseSrvHeap,
HEAP_ZERO_MEMORY,
sizeof(VDM_DOS_RECORD));
if (DosRecord == NULL)
{
Status = STATUS_NO_MEMORY;
goto Cleanup;
}
/* Initialize the DOS record */
DosRecord->State = VDM_NOT_LOADED;
DosRecord->ExitCode = 0;
Status = BaseSrvCreatePairWaitHandles(&DosRecord->ServerEvent, &DosRecord->ClientEvent);
if (!NT_SUCCESS(Status)) goto Cleanup;
/* Return the client event handle */
CheckVdmRequest->WaitObjectForParent = DosRecord->ClientEvent;
/* Translate the input structure into a VDM command structure and set it in the DOS record */
if (!BaseSrvCopyCommand(CheckVdmRequest, DosRecord))
{
/* The only possibility is that an allocation failure occurred */
Status = STATUS_NO_MEMORY;
goto Cleanup;
}
/* Add the DOS record */
InsertHeadList(&ConsoleRecord->DosListHead, &DosRecord->Entry);
if (ConsoleRecord->ServerEvent)
{
/* Signal the session event */
NtSetEvent(ConsoleRecord->ServerEvent, NULL);
}
if (NewConsoleRecord)
{
/* Add the console record */
InsertTailList(&VDMConsoleListHead, &ConsoleRecord->Entry);
}
CheckVdmRequest->iTask = ConsoleRecord->SessionId;
CheckVdmRequest->VDMState = NewConsoleRecord ? VDM_NOT_LOADED : VDM_READY;
Status = STATUS_SUCCESS;
}
else
{
// TODO: NOT IMPLEMENTED
UNIMPLEMENTED;
Status = STATUS_NOT_IMPLEMENTED;
}
Cleanup:
/* Check if it failed */
if (!NT_SUCCESS(Status))
{
/* Free the DOS record */
if (DosRecord != NULL)
{
if (DosRecord->ServerEvent) NtClose(DosRecord->ServerEvent);
if (DosRecord->ClientEvent)
{
/* Close the remote handle */
NtDuplicateObject(CsrGetClientThread()->Process->ProcessHandle,
DosRecord->ClientEvent,
NULL,
NULL,
0,
0,
DUPLICATE_CLOSE_SOURCE);
}
RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
DosRecord = NULL;
}
/* Free the console record if it was allocated here */
if (NewConsoleRecord)
{
RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
ConsoleRecord = NULL;
}
}
/* Leave the critical section */
RtlLeaveCriticalSection(CriticalSection);
return Status;
}
CSR_API(BaseSrvUpdateVDMEntry)
{
NTSTATUS Status;
PBASE_UPDATE_VDM_ENTRY UpdateVdmEntryRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.UpdateVDMEntryRequest;
PRTL_CRITICAL_SECTION CriticalSection = NULL;
PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
PVDM_DOS_RECORD DosRecord = NULL;
CriticalSection = (UpdateVdmEntryRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW)
? &DosCriticalSection
: &WowCriticalSection;
/* Enter the critical section */
RtlEnterCriticalSection(CriticalSection);
/* Check if this is a DOS or WOW VDM */
if (UpdateVdmEntryRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW)
{
if (UpdateVdmEntryRequest->iTask != 0)
{
/* Get the console record using the task ID */
Status = GetConsoleRecordBySessionId(UpdateVdmEntryRequest->iTask,
&ConsoleRecord);
}
else
{
/* Get the console record using the console handle */
Status = BaseSrvGetConsoleRecord(UpdateVdmEntryRequest->ConsoleHandle,
&ConsoleRecord);
}
if (!NT_SUCCESS(Status)) goto Cleanup;
/* Get the primary DOS record */
DosRecord = (PVDM_DOS_RECORD)CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink,
VDM_DOS_RECORD,
Entry);
switch (UpdateVdmEntryRequest->EntryIndex)
{
case VdmEntryUndo:
{
/* Close the server event handle, the client will close the client handle */
NtClose(DosRecord->ServerEvent);
DosRecord->ServerEvent = DosRecord->ClientEvent = NULL;
if (UpdateVdmEntryRequest->VDMCreationState & (VDM_UNDO_PARTIAL | VDM_UNDO_FULL))
{
/* Remove the DOS record */
if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
RemoveEntryList(&DosRecord->Entry);
RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
/*
* Since this is an undo, if that was the only DOS record the VDM
* won't even start, so the console record should be removed too.
*/
if (ConsoleRecord->DosListHead.Flink == &ConsoleRecord->DosListHead)
{
if (ConsoleRecord->ServerEvent) NtClose(ConsoleRecord->ServerEvent);
RemoveEntryList(&ConsoleRecord->Entry);
RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
}
}
/* It was successful */
Status = STATUS_SUCCESS;
break;
}
case VdmEntryUpdateProcess:
{
/* Duplicate the VDM process handle */
Status = NtDuplicateObject(CsrGetClientThread()->Process->ProcessHandle,
UpdateVdmEntryRequest->VDMProcessHandle,
NtCurrentProcess(),
&ConsoleRecord->ProcessHandle,
0,
0,
DUPLICATE_SAME_ATTRIBUTES | DUPLICATE_SAME_ACCESS);
if (!NT_SUCCESS(Status)) goto Cleanup;
/* Create a pair of handles to one event object */
Status = BaseSrvCreatePairWaitHandles(&DosRecord->ServerEvent,
&DosRecord->ClientEvent);
if (!NT_SUCCESS(Status)) goto Cleanup;
/* Return the client event handle */
UpdateVdmEntryRequest->WaitObjectForParent = DosRecord->ClientEvent;
break;
}
case VdmEntryUpdateControlCHandler:
{
// TODO: NOT IMPLEMENTED
DPRINT1("BaseSrvUpdateVDMEntry: VdmEntryUpdateControlCHandler not implemented!");
Status = STATUS_NOT_IMPLEMENTED;
break;
}
default:
{
/* Invalid */
Status = STATUS_INVALID_PARAMETER;
}
}
}
else
{
// TODO: NOT IMPLEMENTED
UNIMPLEMENTED;
Status = STATUS_NOT_IMPLEMENTED;
}
Cleanup:
/* Leave the critical section */
RtlLeaveCriticalSection(CriticalSection);
return Status;
}
CSR_API(BaseSrvGetNextVDMCommand)
{
NTSTATUS Status;
PBASE_GET_NEXT_VDM_COMMAND GetNextVdmCommandRequest =
&((PBASE_API_MESSAGE)ApiMessage)->Data.GetNextVDMCommandRequest;
PRTL_CRITICAL_SECTION CriticalSection;
PLIST_ENTRY i = NULL;
PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
PVDM_DOS_RECORD DosRecord = NULL;
/* Validate the message buffers */
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&GetNextVdmCommandRequest->CmdLine,
GetNextVdmCommandRequest->CmdLen,
sizeof(*GetNextVdmCommandRequest->CmdLine))
|| !CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&GetNextVdmCommandRequest->AppName,
GetNextVdmCommandRequest->AppLen,
sizeof(*GetNextVdmCommandRequest->AppName))
|| !CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&GetNextVdmCommandRequest->PifFile,
GetNextVdmCommandRequest->PifLen,
sizeof(*GetNextVdmCommandRequest->PifFile))
|| !CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&GetNextVdmCommandRequest->CurDirectory,
GetNextVdmCommandRequest->CurDirectoryLen,
sizeof(*GetNextVdmCommandRequest->CurDirectory))
|| !CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&GetNextVdmCommandRequest->Env,
GetNextVdmCommandRequest->EnvLen,
sizeof(*GetNextVdmCommandRequest->Env))
|| !CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&GetNextVdmCommandRequest->Desktop,
GetNextVdmCommandRequest->DesktopLen,
sizeof(*GetNextVdmCommandRequest->Desktop))
|| !CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&GetNextVdmCommandRequest->Title,
GetNextVdmCommandRequest->TitleLen,
sizeof(*GetNextVdmCommandRequest->Title))
|| !CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&GetNextVdmCommandRequest->Reserved,
GetNextVdmCommandRequest->ReservedLen,
sizeof(*GetNextVdmCommandRequest->Reserved))
|| !CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&GetNextVdmCommandRequest->StartupInfo,
1,
sizeof(STARTUPINFOA)))
{
return STATUS_INVALID_PARAMETER;
}
CriticalSection = (GetNextVdmCommandRequest->VDMState & VDM_FLAG_WOW)
? &WowCriticalSection
: &DosCriticalSection;
/* Enter the critical section */
RtlEnterCriticalSection(CriticalSection);
if (!(GetNextVdmCommandRequest->VDMState & VDM_FLAG_WOW))
{
if (GetNextVdmCommandRequest->iTask != 0)
{
/* Get the console record using the task ID */
Status = GetConsoleRecordBySessionId(GetNextVdmCommandRequest->iTask,
&ConsoleRecord);
}
else
{
/* Get the console record using the console handle */
Status = BaseSrvGetConsoleRecord(GetNextVdmCommandRequest->ConsoleHandle,
&ConsoleRecord);
}
/* Make sure we found the console record */
if (!NT_SUCCESS(Status)) goto Cleanup;
/* Return the session ID */
GetNextVdmCommandRequest->iTask = ConsoleRecord->SessionId;
GetNextVdmCommandRequest->WaitObjectForVDM = NULL;
if (GetNextVdmCommandRequest->VDMState & VDM_GET_FIRST_COMMAND)
{
/* Check if the DOS record list is empty */
if (ConsoleRecord->DosListHead.Flink == &ConsoleRecord->DosListHead)
{
Status = STATUS_INVALID_PARAMETER;
goto Cleanup;
}
/* Get the first DOS record */
DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink, VDM_DOS_RECORD, Entry);
/* Make sure its command information is still there */
if (DosRecord->CommandInfo == NULL)
{
Status = STATUS_INVALID_PARAMETER;
goto Cleanup;
}
/* Fill the command information */
Status = BaseSrvFillCommandInfo(DosRecord->CommandInfo, GetNextVdmCommandRequest);
goto Cleanup;
}
/* Check if we should set the state of a running DOS record to ready */
if (!(GetNextVdmCommandRequest->VDMState
& (VDM_FLAG_FIRST_TASK | VDM_FLAG_RETRY | VDM_FLAG_NESTED_TASK)))
{
/* Search for a DOS record that is currently running */
for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink)
{
DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry);
if (DosRecord->State == VDM_NOT_READY) break;
}
/* Check if we found any */
if (i == &ConsoleRecord->DosListHead)
{
Status = STATUS_INVALID_PARAMETER;
goto Cleanup;
}
/* Set the exit code */
DosRecord->ExitCode = GetNextVdmCommandRequest->ExitCode;
/* Update the VDM state */
DosRecord->State = VDM_READY;
/* Notify all waiting threads that the task is finished */
NtSetEvent(DosRecord->ServerEvent, NULL);
NtClose(DosRecord->ServerEvent);
DosRecord->ServerEvent = NULL;
}
/* Search for a DOS record that isn't loaded yet */
for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink)
{
DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry);
if (DosRecord->State == VDM_NOT_LOADED) break;
}
if (i != &ConsoleRecord->DosListHead)
{
/* DOS tasks which haven't been loaded yet should have a command info structure */
ASSERT(DosRecord->CommandInfo != NULL);
/* Check if the caller only wants environment data */
if (GetNextVdmCommandRequest->VDMState & VDM_GET_ENVIRONMENT)
{
if (GetNextVdmCommandRequest->EnvLen < DosRecord->CommandInfo->EnvLen)
{
/* Not enough space was reserved */
GetNextVdmCommandRequest->EnvLen = DosRecord->CommandInfo->EnvLen;
Status = STATUS_BUFFER_OVERFLOW;
goto Cleanup;
}
/* Copy the environment data */
RtlMoveMemory(GetNextVdmCommandRequest->Env,
DosRecord->CommandInfo->Env,
DosRecord->CommandInfo->EnvLen);
/* Return the actual size to the caller */
GetNextVdmCommandRequest->EnvLen = DosRecord->CommandInfo->EnvLen;
}
else
{
/* Fill the command information */
Status = BaseSrvFillCommandInfo(DosRecord->CommandInfo, GetNextVdmCommandRequest);
/* Free the command information, it's no longer needed */
BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
DosRecord->CommandInfo = NULL;
/* Update the VDM state */
GetNextVdmCommandRequest->VDMState = DosRecord->State = VDM_NOT_READY;
}
Status = STATUS_SUCCESS;
goto Cleanup;
}
}
else
{
// TODO: WOW SUPPORT NOT IMPLEMENTED
Status = STATUS_NOT_IMPLEMENTED;
goto Cleanup;
}
/* There is no command yet */
if ((GetNextVdmCommandRequest->VDMState & (VDM_FLAG_DONT_WAIT | VDM_FLAG_RETRY))
!= (VDM_FLAG_DONT_WAIT | VDM_FLAG_RETRY))
{
if (ConsoleRecord->ServerEvent)
{
/* Reset the event */
NtResetEvent(ConsoleRecord->ServerEvent, NULL);
}
else
{
/* Create a pair of wait handles */
Status = BaseSrvCreatePairWaitHandles(&ConsoleRecord->ServerEvent,
&ConsoleRecord->ClientEvent);
if (!NT_SUCCESS(Status)) goto Cleanup;
}
/* Return the client event handle */
GetNextVdmCommandRequest->WaitObjectForVDM = ConsoleRecord->ClientEvent;
}
Cleanup:
/* Leave the critical section */
RtlLeaveCriticalSection(CriticalSection);
return Status;
}
CSR_API(BaseSrvExitVDM)
{
NTSTATUS Status;
PBASE_EXIT_VDM ExitVdmRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.ExitVDMRequest;
PRTL_CRITICAL_SECTION CriticalSection = NULL;
PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
PVDM_DOS_RECORD DosRecord;
CriticalSection = (ExitVdmRequest->iWowTask == 0)
? &DosCriticalSection
: &WowCriticalSection;
/* Enter the critical section */
RtlEnterCriticalSection(CriticalSection);
if (ExitVdmRequest->iWowTask == 0)
{
/* Get the console record */
Status = BaseSrvGetConsoleRecord(ExitVdmRequest->ConsoleHandle, &ConsoleRecord);
if (!NT_SUCCESS(Status)) goto Cleanup;
/* Cleanup the DOS records */
while (ConsoleRecord->DosListHead.Flink != &ConsoleRecord->DosListHead)
{
DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink,
VDM_DOS_RECORD,
Entry);
/* Set the event and close it */
NtSetEvent(DosRecord->ServerEvent, NULL);
NtClose(DosRecord->ServerEvent);
/* Remove the DOS entry */
if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
RemoveEntryList(&DosRecord->Entry);
RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
}
if (ConsoleRecord->CurrentDirs != NULL)
{
/* Free the current directories */
RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord->CurrentDirs);
ConsoleRecord->CurrentDirs = NULL;
ConsoleRecord->CurDirsLength = 0;
}
/* Close the event handle */
if (ConsoleRecord->ServerEvent) NtClose(ConsoleRecord->ServerEvent);
/* Remove the console record */
RemoveEntryList(&ConsoleRecord->Entry);
RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
}
else
{
// TODO: NOT IMPLEMENTED
UNIMPLEMENTED;
Status = STATUS_NOT_IMPLEMENTED;
}
Cleanup:
/* Leave the critical section */
RtlLeaveCriticalSection(CriticalSection);
return Status;
}
CSR_API(BaseSrvIsFirstVDM)
{
PBASE_IS_FIRST_VDM IsFirstVDMRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.IsFirstVDMRequest;
/* Return the result */
IsFirstVDMRequest->FirstVDM = FirstVDM;
/* Clear the first VDM flag */
FirstVDM = FALSE;
return STATUS_SUCCESS;
}
CSR_API(BaseSrvGetVDMExitCode)
{
NTSTATUS Status;
PBASE_GET_VDM_EXIT_CODE GetVDMExitCodeRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.GetVDMExitCodeRequest;
PLIST_ENTRY i = NULL;
PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
PVDM_DOS_RECORD DosRecord = NULL;
/* Enter the critical section */
RtlEnterCriticalSection(&DosCriticalSection);
/* Get the console record */
Status = BaseSrvGetConsoleRecord(GetVDMExitCodeRequest->ConsoleHandle, &ConsoleRecord);
if (!NT_SUCCESS(Status)) goto Cleanup;
/* Search for a DOS record that has the same parent process handle */
for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink)
{
DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry);
if (DosRecord->ClientEvent == GetVDMExitCodeRequest->hParent) break;
}
/* Check if no DOS record was found */
if (i == &ConsoleRecord->DosListHead)
{
Status = STATUS_NOT_FOUND;
goto Cleanup;
}
/* Check if this task is still running */
if (DosRecord->State == VDM_READY)
{
GetVDMExitCodeRequest->ExitCode = STATUS_PENDING;
goto Cleanup;
}
/* Return the exit code */
GetVDMExitCodeRequest->ExitCode = DosRecord->ExitCode;
/* Since this is a zombie task record, remove it */
if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
RemoveEntryList(&DosRecord->Entry);
RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
Cleanup:
/* Leave the critical section */
RtlLeaveCriticalSection(&DosCriticalSection);
return Status;
}
CSR_API(BaseSrvSetReenterCount)
{
NTSTATUS Status = STATUS_SUCCESS;
PBASE_SET_REENTER_COUNT SetReenterCountRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.SetReenterCountRequest;
PVDM_CONSOLE_RECORD ConsoleRecord;
/* Enter the critical section */
RtlEnterCriticalSection(&DosCriticalSection);
/* Get the console record */
Status = BaseSrvGetConsoleRecord(SetReenterCountRequest->ConsoleHandle, &ConsoleRecord);
if (!NT_SUCCESS(Status)) goto Cleanup;
if (SetReenterCountRequest->fIncDec == VDM_INC_REENTER_COUNT) ConsoleRecord->ReenterCount++;
else if (SetReenterCountRequest->fIncDec == VDM_DEC_REENTER_COUNT)
{
ConsoleRecord->ReenterCount--;
if (ConsoleRecord->ServerEvent != NULL) NtSetEvent(ConsoleRecord->ServerEvent, NULL);
}
else Status = STATUS_INVALID_PARAMETER;
Cleanup:
/* Leave the critical section */
RtlLeaveCriticalSection(&DosCriticalSection);
return Status;
}
CSR_API(BaseSrvSetVDMCurDirs)
{
NTSTATUS Status;
PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.VDMCurrentDirsRequest;
PVDM_CONSOLE_RECORD ConsoleRecord;
PCHAR Buffer = NULL;
/* Validate the input buffer */
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs,
VDMCurrentDirsRequest->cchCurDirs,
sizeof(*VDMCurrentDirsRequest->lpszzCurDirs)))
{
return STATUS_INVALID_PARAMETER;
}
/* Enter the critical section */
RtlEnterCriticalSection(&DosCriticalSection);
/* Find the console record */
Status = BaseSrvGetConsoleRecord(VDMCurrentDirsRequest->ConsoleHandle, &ConsoleRecord);
if (!NT_SUCCESS(Status)) goto Cleanup;
if (ConsoleRecord->CurrentDirs == NULL)
{
/* Allocate memory for the current directory information */
Buffer = RtlAllocateHeap(BaseSrvHeap,
HEAP_ZERO_MEMORY,
VDMCurrentDirsRequest->cchCurDirs);
}
else
{
/* Resize the amount of allocated memory */
Buffer = RtlReAllocateHeap(BaseSrvHeap,
HEAP_ZERO_MEMORY,
ConsoleRecord->CurrentDirs,
VDMCurrentDirsRequest->cchCurDirs);
}
if (Buffer == NULL)
{
/* Allocation failed */
Status = STATUS_NO_MEMORY;
goto Cleanup;
}
/* Update the console record */
ConsoleRecord->CurrentDirs = Buffer;
ConsoleRecord->CurDirsLength = VDMCurrentDirsRequest->cchCurDirs;
/* Copy the data */
RtlMoveMemory(ConsoleRecord->CurrentDirs,
VDMCurrentDirsRequest->lpszzCurDirs,
VDMCurrentDirsRequest->cchCurDirs);
Cleanup:
/* Leave the critical section */
RtlLeaveCriticalSection(&DosCriticalSection);
return Status;
}
CSR_API(BaseSrvGetVDMCurDirs)
{
NTSTATUS Status;
PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.VDMCurrentDirsRequest;
PVDM_CONSOLE_RECORD ConsoleRecord;
/* Validate the output buffer */
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs,
VDMCurrentDirsRequest->cchCurDirs,
sizeof(*VDMCurrentDirsRequest->lpszzCurDirs)))
{
return STATUS_INVALID_PARAMETER;
}
/* Enter the critical section */
RtlEnterCriticalSection(&DosCriticalSection);
/* Find the console record */
Status = BaseSrvGetConsoleRecord(VDMCurrentDirsRequest->ConsoleHandle, &ConsoleRecord);
if (!NT_SUCCESS(Status)) goto Cleanup;
/* Return the actual size of the current directory information */
VDMCurrentDirsRequest->cchCurDirs = ConsoleRecord->CurDirsLength;
/* Check if the buffer is large enough */
if (VDMCurrentDirsRequest->cchCurDirs < ConsoleRecord->CurDirsLength)
{
Status = STATUS_BUFFER_TOO_SMALL;
goto Cleanup;
}
/* Copy the data */
RtlMoveMemory(VDMCurrentDirsRequest->lpszzCurDirs,
ConsoleRecord->CurrentDirs,
ConsoleRecord->CurDirsLength);
Cleanup:
/* Leave the critical section */
RtlLeaveCriticalSection(&DosCriticalSection);
return Status;
}
CSR_API(BaseSrvBatNotification)
{
DPRINT1("%s not yet implemented\n", __FUNCTION__);
return STATUS_NOT_IMPLEMENTED;
}
CSR_API(BaseSrvRegisterWowExec)
{
DPRINT1("%s not yet implemented\n", __FUNCTION__);
return STATUS_NOT_IMPLEMENTED;
}
CSR_API(BaseSrvRefreshIniFileMapping)
{
DPRINT1("%s not yet implemented\n", __FUNCTION__);
return STATUS_NOT_IMPLEMENTED;
}
/* EOF */