[BASESRV]
[reactos.git] / subsystems / win / basesrv / vdm.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Base API Server DLL
4 * FILE: subsystems/win/basesrv/vdm.c
5 * PURPOSE: Virtual DOS Machines (VDM) Support
6 * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
7 * Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include "basesrv.h"
13 #include "vdm.h"
14
15 #define NDEBUG
16 #include <debug.h>
17
18 /* GLOBALS ********************************************************************/
19
20 BOOLEAN FirstVDM = TRUE;
21 LIST_ENTRY VDMConsoleListHead;
22 RTL_CRITICAL_SECTION DosCriticalSection;
23 RTL_CRITICAL_SECTION WowCriticalSection;
24
25 /* FUNCTIONS ******************************************************************/
26
27 NTSTATUS NTAPI BaseSrvGetConsoleRecord(HANDLE ConsoleHandle, PVDM_CONSOLE_RECORD *Record)
28 {
29 PLIST_ENTRY i;
30 PVDM_CONSOLE_RECORD CurrentRecord = NULL;
31
32 /* Search for a record that has the same console handle */
33 for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink)
34 {
35 CurrentRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry);
36 if (CurrentRecord->ConsoleHandle == ConsoleHandle) break;
37 }
38
39 *Record = CurrentRecord;
40 return CurrentRecord ? STATUS_SUCCESS : STATUS_NOT_FOUND;
41 }
42
43 ULONG NTAPI GetNextDosSesId(VOID)
44 {
45 ULONG SessionId;
46 PLIST_ENTRY i;
47 PVDM_CONSOLE_RECORD CurrentRecord = NULL;
48 BOOLEAN Found;
49
50 /* Search for an available session ID */
51 for (SessionId = 1; SessionId != 0; SessionId++)
52 {
53 Found = FALSE;
54
55 /* Check if the ID is already in use */
56 for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink)
57 {
58 CurrentRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry);
59 if (CurrentRecord->SessionId == SessionId) Found = TRUE;
60 }
61
62 /* If not, we found one */
63 if (!Found) break;
64 }
65
66 ASSERT(SessionId != 0);
67
68 /* Return the session ID */
69 return SessionId;
70 }
71
72 VOID NTAPI BaseInitializeVDM(VOID)
73 {
74 /* Initialize the list head */
75 InitializeListHead(&VDMConsoleListHead);
76
77 /* Initialize the critical section */
78 RtlInitializeCriticalSection(&DosCriticalSection);
79 RtlInitializeCriticalSection(&WowCriticalSection);
80 }
81
82 /* PUBLIC SERVER APIS *********************************************************/
83
84 CSR_API(BaseSrvCheckVDM)
85 {
86 NTSTATUS Status;
87 PBASE_CHECK_VDM CheckVdmRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.CheckVDMRequest;
88 PRTL_CRITICAL_SECTION CriticalSection = NULL;
89 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
90
91 /* Validate the message buffers */
92 if (!CsrValidateMessageBuffer(ApiMessage,
93 (PVOID*)&CheckVdmRequest->CmdLine,
94 CheckVdmRequest->CmdLen,
95 sizeof(*CheckVdmRequest->CmdLine))
96 || !CsrValidateMessageBuffer(ApiMessage,
97 (PVOID*)&CheckVdmRequest->AppName,
98 CheckVdmRequest->AppLen,
99 sizeof(*CheckVdmRequest->AppName))
100 || !CsrValidateMessageBuffer(ApiMessage,
101 (PVOID*)&CheckVdmRequest->PifFile,
102 CheckVdmRequest->PifLen,
103 sizeof(*CheckVdmRequest->PifFile))
104 || !CsrValidateMessageBuffer(ApiMessage,
105 (PVOID*)&CheckVdmRequest->CurDirectory,
106 CheckVdmRequest->CurDirectoryLen,
107 sizeof(*CheckVdmRequest->CurDirectory))
108 || !CsrValidateMessageBuffer(ApiMessage,
109 (PVOID*)&CheckVdmRequest->Desktop,
110 CheckVdmRequest->DesktopLen,
111 sizeof(*CheckVdmRequest->Desktop))
112 || !CsrValidateMessageBuffer(ApiMessage,
113 (PVOID*)&CheckVdmRequest->Title,
114 CheckVdmRequest->TitleLen,
115 sizeof(*CheckVdmRequest->Title))
116 || !CsrValidateMessageBuffer(ApiMessage,
117 (PVOID*)&CheckVdmRequest->Reserved,
118 CheckVdmRequest->ReservedLen,
119 sizeof(*CheckVdmRequest->Reserved)))
120 {
121 return STATUS_INVALID_PARAMETER;
122 }
123
124 CriticalSection = (CheckVdmRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW)
125 ? &DosCriticalSection
126 : &WowCriticalSection;
127
128 /* Enter the critical section */
129 RtlEnterCriticalSection(CriticalSection);
130
131 /* Check if this is a DOS or WOW VDM */
132 if (CheckVdmRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW)
133 {
134 /* Get the console record */
135 Status = BaseSrvGetConsoleRecord(CheckVdmRequest->ConsoleHandle,
136 &ConsoleRecord);
137
138 if (!NT_SUCCESS(Status))
139 {
140 /* Allocate a new console record */
141 ConsoleRecord = (PVDM_CONSOLE_RECORD)RtlAllocateHeap(BaseSrvHeap,
142 HEAP_ZERO_MEMORY,
143 sizeof(VDM_CONSOLE_RECORD));
144 if (ConsoleRecord == NULL)
145 {
146 Status = STATUS_NO_MEMORY;
147 goto Cleanup;
148 }
149
150 /* Initialize the console record */
151 ConsoleRecord->ConsoleHandle = CheckVdmRequest->ConsoleHandle;
152 ConsoleRecord->CurrentDirs = NULL;
153 ConsoleRecord->CurDirsLength = 0;
154 ConsoleRecord->SessionId = GetNextDosSesId();
155 InitializeListHead(&ConsoleRecord->DosListHead);
156
157 /* Add the console record */
158 InsertTailList(&VDMConsoleListHead, &ConsoleRecord->Entry);
159 }
160
161 // TODO: NOT IMPLEMENTED
162 UNIMPLEMENTED;
163 return STATUS_NOT_IMPLEMENTED;
164 }
165 else
166 {
167 // TODO: NOT IMPLEMENTED
168 UNIMPLEMENTED;
169 return STATUS_NOT_IMPLEMENTED;
170 }
171
172 Cleanup:
173 /* Leave the critical section */
174 RtlLeaveCriticalSection(CriticalSection);
175
176 return Status;
177 }
178
179 CSR_API(BaseSrvUpdateVDMEntry)
180 {
181 DPRINT1("%s not yet implemented\n", __FUNCTION__);
182 return STATUS_NOT_IMPLEMENTED;
183 }
184
185 CSR_API(BaseSrvGetNextVDMCommand)
186 {
187 DPRINT1("%s not yet implemented\n", __FUNCTION__);
188 return STATUS_NOT_IMPLEMENTED;
189 }
190
191 CSR_API(BaseSrvExitVDM)
192 {
193 NTSTATUS Status;
194 PBASE_EXIT_VDM ExitVdmRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.ExitVDMRequest;
195 PRTL_CRITICAL_SECTION CriticalSection = NULL;
196 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
197 PVDM_DOS_RECORD DosRecord;
198
199 CriticalSection = (ExitVdmRequest->iWowTask == 0)
200 ? &DosCriticalSection
201 : &WowCriticalSection;
202
203 /* Enter the critical section */
204 RtlEnterCriticalSection(CriticalSection);
205
206 if (ExitVdmRequest->iWowTask == 0)
207 {
208 /* Get the console record */
209 Status = BaseSrvGetConsoleRecord(ExitVdmRequest->ConsoleHandle, &ConsoleRecord);
210 if (!NT_SUCCESS(Status)) goto Cleanup;
211
212 /* Cleanup the DOS records */
213 while (ConsoleRecord->DosListHead.Flink != &ConsoleRecord->DosListHead)
214 {
215 DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink,
216 VDM_DOS_RECORD,
217 Entry);
218
219 /* Remove the DOS entry */
220 RemoveEntryList(&DosRecord->Entry);
221 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
222 }
223
224 if (ConsoleRecord->CurrentDirs != NULL)
225 {
226 /* Free the current directories */
227 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord->CurrentDirs);
228 ConsoleRecord->CurrentDirs = NULL;
229 ConsoleRecord->CurDirsLength = 0;
230 }
231
232 /* Remove the console record */
233 RemoveEntryList(&ConsoleRecord->Entry);
234 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
235 }
236 else
237 {
238 // TODO: NOT IMPLEMENTED
239 UNIMPLEMENTED;
240 return STATUS_NOT_IMPLEMENTED;
241 }
242
243 Cleanup:
244 /* Leave the critical section */
245 RtlLeaveCriticalSection(CriticalSection);
246
247 return Status;
248 }
249
250 CSR_API(BaseSrvIsFirstVDM)
251 {
252 PBASE_IS_FIRST_VDM IsFirstVDMRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.IsFirstVDMRequest;
253
254 /* Return the result */
255 IsFirstVDMRequest->FirstVDM = FirstVDM;
256
257 /* Clear the first VDM flag */
258 FirstVDM = FALSE;
259
260 return STATUS_SUCCESS;
261 }
262
263 CSR_API(BaseSrvGetVDMExitCode)
264 {
265 NTSTATUS Status;
266 PBASE_GET_VDM_EXIT_CODE GetVDMExitCodeRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.GetVDMExitCodeRequest;
267 PLIST_ENTRY i = NULL;
268 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
269 PVDM_DOS_RECORD DosRecord = NULL;
270
271 /* Enter the critical section */
272 RtlEnterCriticalSection(&DosCriticalSection);
273
274 /* Get the console record */
275 Status = BaseSrvGetConsoleRecord(GetVDMExitCodeRequest->ConsoleHandle, &ConsoleRecord);
276 if (!NT_SUCCESS(Status)) goto Cleanup;
277
278 /* Search for a DOS record that has the same parent process handle */
279 for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink)
280 {
281 DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry);
282 if (DosRecord->ParentProcess == GetVDMExitCodeRequest->hParent) break;
283 }
284
285 /* Check if no DOS record was found */
286 if (i == &ConsoleRecord->DosListHead)
287 {
288 Status = STATUS_NOT_FOUND;
289 goto Cleanup;
290 }
291
292 /* Check if this task is still running */
293 if (DosRecord->State == VDM_READY)
294 {
295 GetVDMExitCodeRequest->ExitCode = STATUS_PENDING;
296 goto Cleanup;
297 }
298
299 /* Return the exit code */
300 GetVDMExitCodeRequest->ExitCode = DosRecord->ExitCode;
301
302 /* Since this is a zombie task record, remove it */
303 RemoveEntryList(&DosRecord->Entry);
304 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
305
306 Cleanup:
307 /* Leave the critical section */
308 RtlLeaveCriticalSection(&DosCriticalSection);
309
310 return Status;
311 }
312
313 CSR_API(BaseSrvSetReenterCount)
314 {
315 DPRINT1("%s not yet implemented\n", __FUNCTION__);
316 return STATUS_NOT_IMPLEMENTED;
317 }
318
319 CSR_API(BaseSrvSetVDMCurDirs)
320 {
321 NTSTATUS Status;
322 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.VDMCurrentDirsRequest;
323 PVDM_CONSOLE_RECORD ConsoleRecord;
324 PCHAR Buffer = NULL;
325
326 /* Validate the input buffer */
327 if (!CsrValidateMessageBuffer(ApiMessage,
328 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs,
329 VDMCurrentDirsRequest->cchCurDirs,
330 sizeof(*VDMCurrentDirsRequest->lpszzCurDirs)))
331 {
332 return STATUS_INVALID_PARAMETER;
333 }
334
335 /* Enter the critical section */
336 RtlEnterCriticalSection(&DosCriticalSection);
337
338 /* Find the console record */
339 Status = BaseSrvGetConsoleRecord(VDMCurrentDirsRequest->ConsoleHandle, &ConsoleRecord);
340 if (!NT_SUCCESS(Status)) goto Cleanup;
341
342 if (ConsoleRecord->CurrentDirs == NULL)
343 {
344 /* Allocate memory for the current directory information */
345 Buffer = RtlAllocateHeap(BaseSrvHeap,
346 HEAP_ZERO_MEMORY,
347 VDMCurrentDirsRequest->cchCurDirs);
348 }
349 else
350 {
351 /* Resize the amount of allocated memory */
352 Buffer = RtlReAllocateHeap(BaseSrvHeap,
353 HEAP_ZERO_MEMORY,
354 ConsoleRecord->CurrentDirs,
355 VDMCurrentDirsRequest->cchCurDirs);
356 }
357
358 if (Buffer == NULL)
359 {
360 /* Allocation failed */
361 Status = STATUS_NO_MEMORY;
362 goto Cleanup;
363 }
364
365 /* Update the console record */
366 ConsoleRecord->CurrentDirs = Buffer;
367 ConsoleRecord->CurDirsLength = VDMCurrentDirsRequest->cchCurDirs;
368
369 /* Copy the data */
370 RtlMoveMemory(ConsoleRecord->CurrentDirs,
371 VDMCurrentDirsRequest->lpszzCurDirs,
372 VDMCurrentDirsRequest->cchCurDirs);
373
374 Cleanup:
375 /* Leave the critical section */
376 RtlLeaveCriticalSection(&DosCriticalSection);
377
378 return Status;
379 }
380
381 CSR_API(BaseSrvGetVDMCurDirs)
382 {
383 NTSTATUS Status;
384 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.VDMCurrentDirsRequest;
385 PVDM_CONSOLE_RECORD ConsoleRecord;
386
387 /* Validate the output buffer */
388 if (!CsrValidateMessageBuffer(ApiMessage,
389 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs,
390 VDMCurrentDirsRequest->cchCurDirs,
391 sizeof(*VDMCurrentDirsRequest->lpszzCurDirs)))
392 {
393 return STATUS_INVALID_PARAMETER;
394 }
395
396 /* Enter the critical section */
397 RtlEnterCriticalSection(&DosCriticalSection);
398
399 /* Find the console record */
400 Status = BaseSrvGetConsoleRecord(VDMCurrentDirsRequest->ConsoleHandle, &ConsoleRecord);
401 if (!NT_SUCCESS(Status)) goto Cleanup;
402
403 /* Return the actual size of the current directory information */
404 VDMCurrentDirsRequest->cchCurDirs = ConsoleRecord->CurDirsLength;
405
406 /* Check if the buffer is large enough */
407 if (VDMCurrentDirsRequest->cchCurDirs < ConsoleRecord->CurDirsLength)
408 {
409 Status = STATUS_BUFFER_TOO_SMALL;
410 goto Cleanup;
411 }
412
413 /* Copy the data */
414 RtlMoveMemory(VDMCurrentDirsRequest->lpszzCurDirs,
415 ConsoleRecord->CurrentDirs,
416 ConsoleRecord->CurDirsLength);
417
418 Cleanup:
419 /* Leave the critical section */
420 RtlLeaveCriticalSection(&DosCriticalSection);
421
422 return Status;
423 }
424
425 CSR_API(BaseSrvBatNotification)
426 {
427 DPRINT1("%s not yet implemented\n", __FUNCTION__);
428 return STATUS_NOT_IMPLEMENTED;
429 }
430
431 CSR_API(BaseSrvRegisterWowExec)
432 {
433 DPRINT1("%s not yet implemented\n", __FUNCTION__);
434 return STATUS_NOT_IMPLEMENTED;
435 }
436
437 CSR_API(BaseSrvRefreshIniFileMapping)
438 {
439 DPRINT1("%s not yet implemented\n", __FUNCTION__);
440 return STATUS_NOT_IMPLEMENTED;
441 }
442
443 /* EOF */