return Status;
}
-VOID BaseSrvFreeVDMInfo(PVDM_COMMAND_INFO CommandInfo)
+VOID NTAPI BaseSrvFreeVDMInfo(PVDM_COMMAND_INFO CommandInfo)
{
/* Free the allocated structure members */
if (CommandInfo->CmdLine != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->CmdLine);
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;
}
NTSTATUS NTAPI BaseSrvFillCommandInfo(PVDM_COMMAND_INFO CommandInfo,
- PBASE_GET_NEXT_VDM_COMMAND Message)
+ PBASE_GET_NEXT_VDM_COMMAND Message)
{
/* Copy the data */
Message->iTask = CommandInfo->TaskId;
&ConsoleRecord);
}
+ /* Make sure we found the console record */
+ if (!NT_SUCCESS(Status))
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
/* Return the session ID */
GetNextVdmCommandRequest->iTask = ConsoleRecord->SessionId;
GetNextVdmCommandRequest->WaitObjectForVDM = NULL;
- // HACK: I'm not sure if this should happen...
- for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink)
+ if (GetNextVdmCommandRequest->VDMState & VDM_GET_FIRST_COMMAND)
{
- DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry);
- if (DosRecord->State == VDM_NOT_READY)
+ /* Check if the DOS record list is empty */
+ if (ConsoleRecord->DosListHead.Flink == &ConsoleRecord->DosListHead)
{
- /* If NTVDM is asking for a new command, it means these are done */
- DosRecord->State = VDM_READY;
+ Status = STATUS_INVALID_PARAMETER;
+ goto Cleanup;
+ }
- NtSetEvent(DosRecord->ServerEvent, NULL);
- NtClose(DosRecord->ServerEvent);
- DosRecord->ServerEvent = NULL;
+ /* 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 */
if (i != &ConsoleRecord->DosListHead)
{
- /* Fill the command information */
- Status = BaseSrvFillCommandInfo(DosRecord->CommandInfo, GetNextVdmCommandRequest);
- if (!NT_SUCCESS(Status)) goto Cleanup;
+ /* DOS tasks which haven't been loaded yet should have a command info structure */
+ ASSERT(DosRecord->CommandInfo != NULL);
- /* Free the command information, it's no longer needed */
- BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
- 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;
+ }
- /* Update the VDM state */
- DosRecord->State = VDM_NOT_READY;
+ /* 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;
}
/* There is no command yet */
- if (ConsoleRecord->ServerEvent)
- {
- /* Reset the event */
- NtResetEvent(ConsoleRecord->ServerEvent, NULL);
- }
- else
+ if ((GetNextVdmCommandRequest->VDMState & (VDM_FLAG_DONT_WAIT | VDM_FLAG_RETRY))
+ != (VDM_FLAG_DONT_WAIT | VDM_FLAG_RETRY))
{
- /* Create a pair of wait handles */
- Status = BaseSrvCreatePairWaitHandles(&ConsoleRecord->ServerEvent,
- &ConsoleRecord->ClientEvent);
- if (!NT_SUCCESS(Status)) goto Cleanup;
- }
+ 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;
+ /* Return the client event handle */
+ GetNextVdmCommandRequest->WaitObjectForVDM = ConsoleRecord->ClientEvent;
+ }
Cleanup:
/* Leave the critical section */