/* * 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 */ /* INCLUDES *******************************************************************/ #include "basesrv.h" #include "vdm.h" #define NDEBUG #include /* 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 */