mirror of
https://github.com/reactos/reactos.git
synced 2024-09-06 10:52:52 +00:00
444 lines
14 KiB
C
444 lines
14 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;
|
|
}
|
|
|
|
*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;
|
|
}
|
|
|
|
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;
|
|
|
|
/* 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;
|
|
}
|
|
|
|
/* Initialize the console record */
|
|
ConsoleRecord->ConsoleHandle = CheckVdmRequest->ConsoleHandle;
|
|
ConsoleRecord->CurrentDirs = NULL;
|
|
ConsoleRecord->CurDirsLength = 0;
|
|
ConsoleRecord->SessionId = GetNextDosSesId();
|
|
InitializeListHead(&ConsoleRecord->DosListHead);
|
|
|
|
/* Add the console record */
|
|
InsertTailList(&VDMConsoleListHead, &ConsoleRecord->Entry);
|
|
}
|
|
|
|
// TODO: NOT IMPLEMENTED
|
|
UNIMPLEMENTED;
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
else
|
|
{
|
|
// TODO: NOT IMPLEMENTED
|
|
UNIMPLEMENTED;
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
Cleanup:
|
|
/* Leave the critical section */
|
|
RtlLeaveCriticalSection(CriticalSection);
|
|
|
|
return Status;
|
|
}
|
|
|
|
CSR_API(BaseSrvUpdateVDMEntry)
|
|
{
|
|
DPRINT1("%s not yet implemented\n", __FUNCTION__);
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
CSR_API(BaseSrvGetNextVDMCommand)
|
|
{
|
|
DPRINT1("%s not yet implemented\n", __FUNCTION__);
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
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);
|
|
|
|
/* Remove the DOS entry */
|
|
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;
|
|
}
|
|
|
|
/* Remove the console record */
|
|
RemoveEntryList(&ConsoleRecord->Entry);
|
|
RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
|
|
}
|
|
else
|
|
{
|
|
// TODO: NOT IMPLEMENTED
|
|
UNIMPLEMENTED;
|
|
return 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->ParentProcess == 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 */
|
|
RemoveEntryList(&DosRecord->Entry);
|
|
RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
|
|
|
|
Cleanup:
|
|
/* Leave the critical section */
|
|
RtlLeaveCriticalSection(&DosCriticalSection);
|
|
|
|
return Status;
|
|
}
|
|
|
|
CSR_API(BaseSrvSetReenterCount)
|
|
{
|
|
DPRINT1("%s not yet implemented\n", __FUNCTION__);
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
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 */
|