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>
9 /* INCLUDES *******************************************************************/
25 /* PUBLIC FUNCTIONS ***********************************************************/
27 VOID
DosCopyHandleTable(LPBYTE DestinationTable
)
32 PDOS_FILE_DESCRIPTOR Descriptor
;
34 /* Clear the table first */
35 for (i
= 0; i
< DEFAULT_JFT_SIZE
; i
++) DestinationTable
[i
] = 0xFF;
37 /* Check if this is the initial process */
38 if (Sda
->CurrentPsp
== SYSTEM_PSP
)
41 HANDLE StandardHandles
[3];
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
);
48 for (i
= 0; i
< 3; i
++)
50 /* Find the corresponding SFT entry */
51 if (IsConsoleHandle(StandardHandles
[i
]))
53 DescriptorId
= DosFindDeviceDescriptor(SysVars
->ActiveCon
);
57 DescriptorId
= DosFindWin32Descriptor(StandardHandles
[i
]);
60 if (DescriptorId
!= 0xFF)
62 Descriptor
= DosGetFileDescriptor(DescriptorId
);
66 /* Create a new SFT entry for it */
67 DescriptorId
= DosFindFreeDescriptor();
68 if (DescriptorId
== 0xFF)
70 DPRINT1("Cannot create standard handle %d, the SFT is full!\n", i
);
74 Descriptor
= DosGetFileDescriptor(DescriptorId
);
75 ASSERT(Descriptor
!= NULL
);
76 RtlZeroMemory(Descriptor
, sizeof(*Descriptor
));
78 if (IsConsoleHandle(StandardHandles
[i
]))
80 PDOS_DEVICE_NODE Node
= DosGetDriverNode(SysVars
->ActiveCon
);
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
);
87 /* Call the open routine */
88 if (Node
->OpenRoutine
) Node
->OpenRoutine(Node
);
92 Descriptor
->Win32Handle
= StandardHandles
[i
];
96 Descriptor
->RefCount
++;
97 DestinationTable
[i
] = DescriptorId
;
102 /* Get the parent PSP block and handle table */
103 PspBlock
= SEGMENT_TO_PSP(Sda
->CurrentPsp
);
104 SourceTable
= (LPBYTE
)FAR_POINTER(PspBlock
->HandleTablePtr
);
106 /* Copy the first 20 handles into the new table */
107 for (i
= 0; i
< DEFAULT_JFT_SIZE
; i
++)
109 Descriptor
= DosGetFileDescriptor(SourceTable
[i
]);
110 DestinationTable
[i
] = SourceTable
[i
];
112 /* Increase the reference count */
113 Descriptor
->RefCount
++;
118 BOOLEAN
DosResizeHandleTable(WORD NewSize
)
124 /* Get the PSP block */
125 PspBlock
= SEGMENT_TO_PSP(Sda
->CurrentPsp
);
127 if (NewSize
== PspBlock
->HandleTableSize
)
133 if (PspBlock
->HandleTableSize
> DEFAULT_JFT_SIZE
)
135 /* Get the segment of the current table */
136 Segment
= (LOWORD(PspBlock
->HandleTablePtr
) >> 4) + HIWORD(PspBlock
->HandleTablePtr
);
138 if (NewSize
<= DEFAULT_JFT_SIZE
)
140 /* Get the current handle table */
141 HandleTable
= FAR_POINTER(PspBlock
->HandleTablePtr
);
143 /* Copy it to the PSP */
144 RtlCopyMemory(PspBlock
->HandleTable
, HandleTable
, NewSize
);
146 /* Free the memory */
147 DosFreeMemory(Segment
);
149 /* Update the handle table pointer and size */
150 PspBlock
->HandleTableSize
= NewSize
;
151 PspBlock
->HandleTablePtr
= MAKELONG(0x18, Sda
->CurrentPsp
);
155 /* Resize the memory */
156 if (!DosResizeMemory(Segment
, NewSize
, NULL
))
158 /* Unable to resize, try allocating it somewhere else */
159 Segment
= DosAllocateMemory(NewSize
, NULL
);
160 if (Segment
== 0) return FALSE
;
162 /* Get the new handle table */
163 HandleTable
= SEG_OFF_TO_PTR(Segment
, 0);
165 /* Copy the handles to the new table */
166 RtlCopyMemory(HandleTable
,
167 FAR_POINTER(PspBlock
->HandleTablePtr
),
168 PspBlock
->HandleTableSize
);
170 /* Update the handle table pointer */
171 PspBlock
->HandleTablePtr
= MAKELONG(0, Segment
);
174 /* Update the handle table size */
175 PspBlock
->HandleTableSize
= NewSize
;
178 else if (NewSize
> DEFAULT_JFT_SIZE
)
180 Segment
= DosAllocateMemory(NewSize
, NULL
);
181 if (Segment
== 0) return FALSE
;
183 /* Get the new handle table */
184 HandleTable
= SEG_OFF_TO_PTR(Segment
, 0);
186 /* Copy the handles from the PSP to the new table */
187 RtlCopyMemory(HandleTable
,
188 FAR_POINTER(PspBlock
->HandleTablePtr
),
189 PspBlock
->HandleTableSize
);
191 /* Update the handle table pointer and size */
192 PspBlock
->HandleTableSize
= NewSize
;
193 PspBlock
->HandleTablePtr
= MAKELONG(0, Segment
);
200 WORD
DosOpenHandle(BYTE DescriptorId
)
205 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetFileDescriptor(DescriptorId
);
207 DPRINT("DosOpenHandle: DescriptorId 0x%02X\n", DescriptorId
);
209 /* Make sure the descriptor ID is valid */
210 if (Descriptor
== NULL
) return INVALID_DOS_HANDLE
;
212 /* The system PSP has no handle table */
213 if (Sda
->CurrentPsp
== SYSTEM_PSP
) return INVALID_DOS_HANDLE
;
215 /* Get a pointer to the handle table */
216 PspBlock
= SEGMENT_TO_PSP(Sda
->CurrentPsp
);
217 HandleTable
= (LPBYTE
)FAR_POINTER(PspBlock
->HandleTablePtr
);
219 /* Find a free entry in the JFT */
220 for (DosHandle
= 0; DosHandle
< PspBlock
->HandleTableSize
; DosHandle
++)
222 if (HandleTable
[DosHandle
] == 0xFF) break;
225 /* If there are no free entries, fail */
226 if (DosHandle
== PspBlock
->HandleTableSize
) return INVALID_DOS_HANDLE
;
228 /* Reference the descriptor */
229 Descriptor
->RefCount
++;
231 /* Set the JFT entry to that descriptor ID */
232 HandleTable
[DosHandle
] = DescriptorId
;
234 /* Return the new handle */
238 BYTE
DosQueryHandle(WORD DosHandle
)
243 DPRINT("DosQueryHandle: DosHandle 0x%04X\n", DosHandle
);
245 /* The system PSP has no handle table */
246 if (Sda
->CurrentPsp
== SYSTEM_PSP
) return 0xFF;
248 /* Get a pointer to the handle table */
249 PspBlock
= SEGMENT_TO_PSP(Sda
->CurrentPsp
);
250 HandleTable
= (LPBYTE
)FAR_POINTER(PspBlock
->HandleTablePtr
);
252 /* Return the descriptor ID */
253 return HandleTable
[DosHandle
];
256 WORD
DosDuplicateHandle(WORD DosHandle
)
258 BYTE DescriptorId
= DosQueryHandle(DosHandle
);
260 if (DescriptorId
== 0xFF)
262 Sda
->LastErrorCode
= ERROR_INVALID_HANDLE
;
263 return INVALID_DOS_HANDLE
;
266 return DosOpenHandle(DescriptorId
);
269 BOOLEAN
DosForceDuplicateHandle(WORD OldHandle
, WORD NewHandle
)
274 PDOS_FILE_DESCRIPTOR Descriptor
;
276 DPRINT("DosForceDuplicateHandle: OldHandle 0x%04X, NewHandle 0x%04X\n",
280 /* The system PSP has no handle table */
281 if (Sda
->CurrentPsp
== SYSTEM_PSP
) return FALSE
;
283 /* Get a pointer to the handle table */
284 PspBlock
= SEGMENT_TO_PSP(Sda
->CurrentPsp
);
285 HandleTable
= (LPBYTE
)FAR_POINTER(PspBlock
->HandleTablePtr
);
287 /* Make sure the old handle is open */
288 if (HandleTable
[OldHandle
] == 0xFF) return FALSE
;
290 /* Check if the new handle is open */
291 if (HandleTable
[NewHandle
] != 0xFF)
294 DosCloseHandle(NewHandle
);
297 DescriptorId
= HandleTable
[OldHandle
];
298 Descriptor
= DosGetFileDescriptor(DescriptorId
);
299 if (Descriptor
== NULL
) return FALSE
;
301 /* Increment the reference count of the descriptor */
302 Descriptor
->RefCount
++;
304 /* Make the new handle point to that descriptor */
305 HandleTable
[NewHandle
] = DescriptorId
;
311 BOOLEAN
DosCloseHandle(WORD DosHandle
)
315 PDOS_FILE_DESCRIPTOR Descriptor
;
317 DPRINT("DosCloseHandle: DosHandle 0x%04X\n", DosHandle
);
319 /* The system PSP has no handle table */
320 if (Sda
->CurrentPsp
== SYSTEM_PSP
) return FALSE
;
322 /* Get a pointer to the handle table */
323 PspBlock
= SEGMENT_TO_PSP(Sda
->CurrentPsp
);
324 HandleTable
= (LPBYTE
)FAR_POINTER(PspBlock
->HandleTablePtr
);
326 /* Make sure the handle is open */
327 if (HandleTable
[DosHandle
] == 0xFF) return FALSE
;
329 /* Make sure the descriptor is valid */
330 Descriptor
= DosGetFileDescriptor(HandleTable
[DosHandle
]);
331 if (Descriptor
== NULL
) return FALSE
;
333 /* Decrement the reference count of the descriptor */
334 Descriptor
->RefCount
--;
336 /* Check if the reference count fell to zero */
337 if (!Descriptor
->RefCount
)
339 if (Descriptor
->DeviceInfo
& FILE_INFO_DEVICE
)
341 PDOS_DEVICE_NODE Node
= DosGetDriverNode(Descriptor
->DevicePointer
);
343 /* Call the close routine, if it exists */
344 if (Node
->CloseRoutine
) Node
->CloseRoutine(Node
);
348 /* Close the Win32 handle */
349 CloseHandle(Descriptor
->Win32Handle
);
353 /* Clear the entry in the JFT */
354 HandleTable
[DosHandle
] = 0xFF;