4227311610445270441f733cd77eaa0af4f6f9c7
[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 DPRINT1("%s not yet implemented\n", __FUNCTION__);
194 return STATUS_NOT_IMPLEMENTED;
195 }
196
197 CSR_API(BaseSrvIsFirstVDM)
198 {
199 PBASE_IS_FIRST_VDM IsFirstVDMRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.IsFirstVDMRequest;
200
201 /* Return the result */
202 IsFirstVDMRequest->FirstVDM = FirstVDM;
203
204 /* Clear the first VDM flag */
205 FirstVDM = FALSE;
206
207 return STATUS_SUCCESS;
208 }
209
210 CSR_API(BaseSrvGetVDMExitCode)
211 {
212 NTSTATUS Status;
213 PBASE_GET_VDM_EXIT_CODE GetVDMExitCodeRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.GetVDMExitCodeRequest;
214 PLIST_ENTRY i = NULL;
215 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
216 PVDM_DOS_RECORD DosRecord = NULL;
217
218 /* Enter the critical section */
219 RtlEnterCriticalSection(&DosCriticalSection);
220
221 /* Get the console record */
222 Status = BaseSrvGetConsoleRecord(GetVDMExitCodeRequest->ConsoleHandle, &ConsoleRecord);
223 if (!NT_SUCCESS(Status)) goto Cleanup;
224
225 /* Search for a DOS record that has the same parent process handle */
226 for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink)
227 {
228 DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry);
229 if (DosRecord->ParentProcess == GetVDMExitCodeRequest->hParent) break;
230 }
231
232 /* Check if no DOS record was found */
233 if (i == &ConsoleRecord->DosListHead)
234 {
235 Status = STATUS_NOT_FOUND;
236 goto Cleanup;
237 }
238
239 /* Check if this task is still running */
240 if (DosRecord->State == VDM_READY)
241 {
242 GetVDMExitCodeRequest->ExitCode = STATUS_PENDING;
243 goto Cleanup;
244 }
245
246 /* Return the exit code */
247 GetVDMExitCodeRequest->ExitCode = DosRecord->ExitCode;
248
249 /* Since this is a zombie task record, remove it */
250 RemoveEntryList(&DosRecord->Entry);
251 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
252
253 Cleanup:
254 /* Leave the critical section */
255 RtlLeaveCriticalSection(&DosCriticalSection);
256
257 return Status;
258 }
259
260 CSR_API(BaseSrvSetReenterCount)
261 {
262 DPRINT1("%s not yet implemented\n", __FUNCTION__);
263 return STATUS_NOT_IMPLEMENTED;
264 }
265
266 CSR_API(BaseSrvSetVDMCurDirs)
267 {
268 NTSTATUS Status;
269 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.VDMCurrentDirsRequest;
270 PVDM_CONSOLE_RECORD ConsoleRecord;
271 PCHAR Buffer = NULL;
272
273 /* Validate the input buffer */
274 if (!CsrValidateMessageBuffer(ApiMessage,
275 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs,
276 VDMCurrentDirsRequest->cchCurDirs,
277 sizeof(*VDMCurrentDirsRequest->lpszzCurDirs)))
278 {
279 return STATUS_INVALID_PARAMETER;
280 }
281
282 /* Enter the critical section */
283 RtlEnterCriticalSection(&DosCriticalSection);
284
285 /* Find the console record */
286 Status = BaseSrvGetConsoleRecord(VDMCurrentDirsRequest->ConsoleHandle, &ConsoleRecord);
287 if (!NT_SUCCESS(Status)) goto Cleanup;
288
289 if (ConsoleRecord->CurrentDirs == NULL)
290 {
291 /* Allocate memory for the current directory information */
292 Buffer = RtlAllocateHeap(BaseSrvHeap,
293 HEAP_ZERO_MEMORY,
294 VDMCurrentDirsRequest->cchCurDirs);
295 }
296 else
297 {
298 /* Resize the amount of allocated memory */
299 Buffer = RtlReAllocateHeap(BaseSrvHeap,
300 HEAP_ZERO_MEMORY,
301 ConsoleRecord->CurrentDirs,
302 VDMCurrentDirsRequest->cchCurDirs);
303 }
304
305 if (Buffer == NULL)
306 {
307 /* Allocation failed */
308 Status = STATUS_NO_MEMORY;
309 goto Cleanup;
310 }
311
312 /* Update the console record */
313 ConsoleRecord->CurrentDirs = Buffer;
314 ConsoleRecord->CurDirsLength = VDMCurrentDirsRequest->cchCurDirs;
315
316 /* Copy the data */
317 RtlMoveMemory(ConsoleRecord->CurrentDirs,
318 VDMCurrentDirsRequest->lpszzCurDirs,
319 VDMCurrentDirsRequest->cchCurDirs);
320
321 Cleanup:
322 /* Leave the critical section */
323 RtlLeaveCriticalSection(&DosCriticalSection);
324
325 return Status;
326 }
327
328 CSR_API(BaseSrvGetVDMCurDirs)
329 {
330 NTSTATUS Status;
331 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.VDMCurrentDirsRequest;
332 PVDM_CONSOLE_RECORD ConsoleRecord;
333
334 /* Validate the output buffer */
335 if (!CsrValidateMessageBuffer(ApiMessage,
336 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs,
337 VDMCurrentDirsRequest->cchCurDirs,
338 sizeof(*VDMCurrentDirsRequest->lpszzCurDirs)))
339 {
340 return STATUS_INVALID_PARAMETER;
341 }
342
343 /* Enter the critical section */
344 RtlEnterCriticalSection(&DosCriticalSection);
345
346 /* Find the console record */
347 Status = BaseSrvGetConsoleRecord(VDMCurrentDirsRequest->ConsoleHandle, &ConsoleRecord);
348 if (!NT_SUCCESS(Status)) goto Cleanup;
349
350 /* Return the actual size of the current directory information */
351 VDMCurrentDirsRequest->cchCurDirs = ConsoleRecord->CurDirsLength;
352
353 /* Check if the buffer is large enough */
354 if (VDMCurrentDirsRequest->cchCurDirs < ConsoleRecord->CurDirsLength)
355 {
356 Status = STATUS_BUFFER_TOO_SMALL;
357 goto Cleanup;
358 }
359
360 /* Copy the data */
361 RtlMoveMemory(VDMCurrentDirsRequest->lpszzCurDirs,
362 ConsoleRecord->CurrentDirs,
363 ConsoleRecord->CurDirsLength);
364
365 Cleanup:
366 /* Leave the critical section */
367 RtlLeaveCriticalSection(&DosCriticalSection);
368
369 return Status;
370 }
371
372 CSR_API(BaseSrvBatNotification)
373 {
374 DPRINT1("%s not yet implemented\n", __FUNCTION__);
375 return STATUS_NOT_IMPLEMENTED;
376 }
377
378 CSR_API(BaseSrvRegisterWowExec)
379 {
380 DPRINT1("%s not yet implemented\n", __FUNCTION__);
381 return STATUS_NOT_IMPLEMENTED;
382 }
383
384 CSR_API(BaseSrvRefreshIniFileMapping)
385 {
386 DPRINT1("%s not yet implemented\n", __FUNCTION__);
387 return STATUS_NOT_IMPLEMENTED;
388 }
389
390 /* EOF */