[NTVDM] Missed this file.
[reactos.git] / subsystems / mvdm / ntvdm / dos / dos32krnl / handle.c
1 /*
2 * COPYRIGHT: GPLv2+ - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: subsystems/mvdm/ntvdm/dos/dos32krnl/handle.c
5 * PURPOSE: DOS32 Handles (Job File Table)
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "ntvdm.h"
12
13 #define NDEBUG
14 #include <debug.h>
15
16 #include "emulator.h"
17
18 #include "dos.h"
19 #include "dos/dem.h"
20 #include "dosfiles.h"
21 #include "handle.h"
22 #include "memory.h"
23 #include "process.h"
24
25 /* PUBLIC FUNCTIONS ***********************************************************/
26
27 VOID DosCopyHandleTable(LPBYTE DestinationTable)
28 {
29 UINT i;
30 PDOS_PSP PspBlock;
31 LPBYTE SourceTable;
32 PDOS_FILE_DESCRIPTOR Descriptor;
33
34 /* Clear the table first */
35 for (i = 0; i < DEFAULT_JFT_SIZE; i++) DestinationTable[i] = 0xFF;
36
37 /* Check if this is the initial process */
38 if (Sda->CurrentPsp == SYSTEM_PSP)
39 {
40 BYTE DescriptorId;
41 HANDLE StandardHandles[3];
42
43 /* Get the native standard handles */
44 StandardHandles[0] = GetStdHandle(STD_INPUT_HANDLE);
45 StandardHandles[1] = GetStdHandle(STD_OUTPUT_HANDLE);
46 StandardHandles[2] = GetStdHandle(STD_ERROR_HANDLE);
47
48 for (i = 0; i < 3; i++)
49 {
50 /* Find the corresponding SFT entry */
51 if (IsConsoleHandle(StandardHandles[i]))
52 {
53 DescriptorId = DosFindDeviceDescriptor(SysVars->ActiveCon);
54 }
55 else
56 {
57 DescriptorId = DosFindWin32Descriptor(StandardHandles[i]);
58 }
59
60 if (DescriptorId != 0xFF)
61 {
62 Descriptor = DosGetFileDescriptor(DescriptorId);
63 }
64 else
65 {
66 /* Create a new SFT entry for it */
67 DescriptorId = DosFindFreeDescriptor();
68 if (DescriptorId == 0xFF)
69 {
70 DPRINT1("Cannot create standard handle %d, the SFT is full!\n", i);
71 continue;
72 }
73
74 Descriptor = DosGetFileDescriptor(DescriptorId);
75 ASSERT(Descriptor != NULL);
76 RtlZeroMemory(Descriptor, sizeof(*Descriptor));
77
78 if (IsConsoleHandle(StandardHandles[i]))
79 {
80 PDOS_DEVICE_NODE Node = DosGetDriverNode(SysVars->ActiveCon);
81
82 Descriptor->DeviceInfo = Node->DeviceAttributes | FILE_INFO_DEVICE;
83 Descriptor->DevicePointer = SysVars->ActiveCon;
84 RtlFillMemory(Descriptor->FileName, sizeof(Descriptor->FileName), ' ');
85 RtlCopyMemory(Descriptor->FileName, Node->Name.Buffer, Node->Name.Length);
86
87 /* Call the open routine */
88 if (Node->OpenRoutine) Node->OpenRoutine(Node);
89 }
90 else
91 {
92 Descriptor->Win32Handle = StandardHandles[i];
93 }
94 }
95
96 Descriptor->RefCount++;
97 DestinationTable[i] = DescriptorId;
98 }
99 }
100 else
101 {
102 /* Get the parent PSP block and handle table */
103 PspBlock = SEGMENT_TO_PSP(Sda->CurrentPsp);
104 SourceTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr);
105
106 /* Copy the first 20 handles into the new table */
107 for (i = 0; i < DEFAULT_JFT_SIZE; i++)
108 {
109 Descriptor = DosGetFileDescriptor(SourceTable[i]);
110 DestinationTable[i] = SourceTable[i];
111
112 /* Increase the reference count */
113 Descriptor->RefCount++;
114 }
115 }
116 }
117
118 BOOLEAN DosResizeHandleTable(WORD NewSize)
119 {
120 PDOS_PSP PspBlock;
121 LPBYTE HandleTable;
122 WORD Segment;
123
124 /* Get the PSP block */
125 PspBlock = SEGMENT_TO_PSP(Sda->CurrentPsp);
126
127 if (NewSize == PspBlock->HandleTableSize)
128 {
129 /* No change */
130 return TRUE;
131 }
132
133 if (PspBlock->HandleTableSize > DEFAULT_JFT_SIZE)
134 {
135 /* Get the segment of the current table */
136 Segment = (LOWORD(PspBlock->HandleTablePtr) >> 4) + HIWORD(PspBlock->HandleTablePtr);
137
138 if (NewSize <= DEFAULT_JFT_SIZE)
139 {
140 /* Get the current handle table */
141 HandleTable = FAR_POINTER(PspBlock->HandleTablePtr);
142
143 /* Copy it to the PSP */
144 RtlCopyMemory(PspBlock->HandleTable, HandleTable, NewSize);
145
146 /* Free the memory */
147 DosFreeMemory(Segment);
148
149 /* Update the handle table pointer and size */
150 PspBlock->HandleTableSize = NewSize;
151 PspBlock->HandleTablePtr = MAKELONG(0x18, Sda->CurrentPsp);
152 }
153 else
154 {
155 /* Resize the memory */
156 if (!DosResizeMemory(Segment, NewSize, NULL))
157 {
158 /* Unable to resize, try allocating it somewhere else */
159 Segment = DosAllocateMemory(NewSize, NULL);
160 if (Segment == 0) return FALSE;
161
162 /* Get the new handle table */
163 HandleTable = SEG_OFF_TO_PTR(Segment, 0);
164
165 /* Copy the handles to the new table */
166 RtlCopyMemory(HandleTable,
167 FAR_POINTER(PspBlock->HandleTablePtr),
168 PspBlock->HandleTableSize);
169
170 /* Update the handle table pointer */
171 PspBlock->HandleTablePtr = MAKELONG(0, Segment);
172 }
173
174 /* Update the handle table size */
175 PspBlock->HandleTableSize = NewSize;
176 }
177 }
178 else if (NewSize > DEFAULT_JFT_SIZE)
179 {
180 Segment = DosAllocateMemory(NewSize, NULL);
181 if (Segment == 0) return FALSE;
182
183 /* Get the new handle table */
184 HandleTable = SEG_OFF_TO_PTR(Segment, 0);
185
186 /* Copy the handles from the PSP to the new table */
187 RtlCopyMemory(HandleTable,
188 FAR_POINTER(PspBlock->HandleTablePtr),
189 PspBlock->HandleTableSize);
190
191 /* Update the handle table pointer and size */
192 PspBlock->HandleTableSize = NewSize;
193 PspBlock->HandleTablePtr = MAKELONG(0, Segment);
194 }
195
196 return TRUE;
197 }
198
199
200 WORD DosOpenHandle(BYTE DescriptorId)
201 {
202 WORD DosHandle;
203 PDOS_PSP PspBlock;
204 LPBYTE HandleTable;
205 PDOS_FILE_DESCRIPTOR Descriptor = DosGetFileDescriptor(DescriptorId);
206
207 DPRINT("DosOpenHandle: DescriptorId 0x%02X\n", DescriptorId);
208
209 /* Make sure the descriptor ID is valid */
210 if (Descriptor == NULL) return INVALID_DOS_HANDLE;
211
212 /* The system PSP has no handle table */
213 if (Sda->CurrentPsp == SYSTEM_PSP) return INVALID_DOS_HANDLE;
214
215 /* Get a pointer to the handle table */
216 PspBlock = SEGMENT_TO_PSP(Sda->CurrentPsp);
217 HandleTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr);
218
219 /* Find a free entry in the JFT */
220 for (DosHandle = 0; DosHandle < PspBlock->HandleTableSize; DosHandle++)
221 {
222 if (HandleTable[DosHandle] == 0xFF) break;
223 }
224
225 /* If there are no free entries, fail */
226 if (DosHandle == PspBlock->HandleTableSize) return INVALID_DOS_HANDLE;
227
228 /* Reference the descriptor */
229 Descriptor->RefCount++;
230
231 /* Set the JFT entry to that descriptor ID */
232 HandleTable[DosHandle] = DescriptorId;
233
234 /* Return the new handle */
235 return DosHandle;
236 }
237
238 BYTE DosQueryHandle(WORD DosHandle)
239 {
240 PDOS_PSP PspBlock;
241 LPBYTE HandleTable;
242
243 DPRINT("DosQueryHandle: DosHandle 0x%04X\n", DosHandle);
244
245 /* The system PSP has no handle table */
246 if (Sda->CurrentPsp == SYSTEM_PSP) return 0xFF;
247
248 /* Get a pointer to the handle table */
249 PspBlock = SEGMENT_TO_PSP(Sda->CurrentPsp);
250 HandleTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr);
251
252 /* Return the descriptor ID */
253 return HandleTable[DosHandle];
254 }
255
256 WORD DosDuplicateHandle(WORD DosHandle)
257 {
258 BYTE DescriptorId = DosQueryHandle(DosHandle);
259
260 if (DescriptorId == 0xFF)
261 {
262 Sda->LastErrorCode = ERROR_INVALID_HANDLE;
263 return INVALID_DOS_HANDLE;
264 }
265
266 return DosOpenHandle(DescriptorId);
267 }
268
269 BOOLEAN DosForceDuplicateHandle(WORD OldHandle, WORD NewHandle)
270 {
271 BYTE DescriptorId;
272 PDOS_PSP PspBlock;
273 LPBYTE HandleTable;
274 PDOS_FILE_DESCRIPTOR Descriptor;
275
276 DPRINT("DosForceDuplicateHandle: OldHandle 0x%04X, NewHandle 0x%04X\n",
277 OldHandle,
278 NewHandle);
279
280 /* The system PSP has no handle table */
281 if (Sda->CurrentPsp == SYSTEM_PSP) return FALSE;
282
283 /* Get a pointer to the handle table */
284 PspBlock = SEGMENT_TO_PSP(Sda->CurrentPsp);
285 HandleTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr);
286
287 /* Make sure the old handle is open */
288 if (HandleTable[OldHandle] == 0xFF) return FALSE;
289
290 /* Check if the new handle is open */
291 if (HandleTable[NewHandle] != 0xFF)
292 {
293 /* Close it */
294 DosCloseHandle(NewHandle);
295 }
296
297 DescriptorId = HandleTable[OldHandle];
298 Descriptor = DosGetFileDescriptor(DescriptorId);
299 if (Descriptor == NULL) return FALSE;
300
301 /* Increment the reference count of the descriptor */
302 Descriptor->RefCount++;
303
304 /* Make the new handle point to that descriptor */
305 HandleTable[NewHandle] = DescriptorId;
306
307 /* Return success */
308 return TRUE;
309 }
310
311 BOOLEAN DosCloseHandle(WORD DosHandle)
312 {
313 PDOS_PSP PspBlock;
314 LPBYTE HandleTable;
315 PDOS_FILE_DESCRIPTOR Descriptor;
316
317 DPRINT("DosCloseHandle: DosHandle 0x%04X\n", DosHandle);
318
319 /* The system PSP has no handle table */
320 if (Sda->CurrentPsp == SYSTEM_PSP) return FALSE;
321
322 /* Get a pointer to the handle table */
323 PspBlock = SEGMENT_TO_PSP(Sda->CurrentPsp);
324 HandleTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr);
325
326 /* Make sure the handle is open */
327 if (HandleTable[DosHandle] == 0xFF) return FALSE;
328
329 /* Make sure the descriptor is valid */
330 Descriptor = DosGetFileDescriptor(HandleTable[DosHandle]);
331 if (Descriptor == NULL) return FALSE;
332
333 /* Decrement the reference count of the descriptor */
334 Descriptor->RefCount--;
335
336 /* Check if the reference count fell to zero */
337 if (!Descriptor->RefCount)
338 {
339 if (Descriptor->DeviceInfo & FILE_INFO_DEVICE)
340 {
341 PDOS_DEVICE_NODE Node = DosGetDriverNode(Descriptor->DevicePointer);
342
343 /* Call the close routine, if it exists */
344 if (Node->CloseRoutine) Node->CloseRoutine(Node);
345 }
346 else
347 {
348 /* Close the Win32 handle */
349 CloseHandle(Descriptor->Win32Handle);
350 }
351 }
352
353 /* Clear the entry in the JFT */
354 HandleTable[DosHandle] = 0xFF;
355
356 return TRUE;
357 }