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>
14 /* PRIVATE FUNCTIONS **********************************************************/
16 /* Taken from base/shell/cmd/console.c */
17 static BOOL
IsConsoleHandle(HANDLE hHandle
)
21 /* Check whether the handle may be that of a console... */
22 if ((GetFileType(hHandle
) & FILE_TYPE_CHAR
) == 0) return FALSE
;
25 * It may be. Perform another test... The idea comes from the
26 * MSDN description of the WriteConsole API:
28 * "WriteConsole fails if it is used with a standard handle
29 * that is redirected to a file. If an application processes
30 * multilingual output that can be redirected, determine whether
31 * the output handle is a console handle (one method is to call
32 * the GetConsoleMode function and check whether it succeeds).
33 * If the handle is a console handle, call WriteConsole. If the
34 * handle is not a console handle, the output is redirected and
35 * you should call WriteFile to perform the I/O."
37 return GetConsoleMode(hHandle
, &dwMode
);
40 /* PUBLIC FUNCTIONS ***********************************************************/
42 VOID
DosCopyHandleTable(LPBYTE DestinationTable
)
47 PDOS_FILE_DESCRIPTOR Descriptor
;
49 /* Clear the table first */
50 for (i
= 0; i
< DEFAULT_JFT_SIZE
; i
++) DestinationTable
[i
] = 0xFF;
52 /* Check if this is the initial process */
53 if (Sda
->CurrentPsp
== SYSTEM_PSP
)
56 HANDLE StandardHandles
[3];
58 /* Get the native standard handles */
59 StandardHandles
[0] = GetStdHandle(STD_INPUT_HANDLE
);
60 StandardHandles
[1] = GetStdHandle(STD_OUTPUT_HANDLE
);
61 StandardHandles
[2] = GetStdHandle(STD_ERROR_HANDLE
);
63 for (i
= 0; i
< 3; i
++)
65 /* Find the corresponding SFT entry */
66 if (IsConsoleHandle(StandardHandles
[i
]))
68 DescriptorId
= DosFindDeviceDescriptor(SysVars
->ActiveCon
);
72 DescriptorId
= DosFindWin32Descriptor(StandardHandles
[i
]);
75 if (DescriptorId
!= 0xFF)
77 Descriptor
= DosGetFileDescriptor(DescriptorId
);
81 /* Create a new SFT entry for it */
82 DescriptorId
= DosFindFreeDescriptor();
83 if (DescriptorId
== 0xFF)
85 DPRINT1("Cannot create standard handle %d, the SFT is full!\n", i
);
89 Descriptor
= DosGetFileDescriptor(DescriptorId
);
90 ASSERT(Descriptor
!= NULL
);
91 RtlZeroMemory(Descriptor
, sizeof(*Descriptor
));
93 if (IsConsoleHandle(StandardHandles
[i
]))
95 PDOS_DEVICE_NODE Node
= DosGetDriverNode(SysVars
->ActiveCon
);
97 Descriptor
->DeviceInfo
= Node
->DeviceAttributes
| FILE_INFO_DEVICE
;
98 Descriptor
->DevicePointer
= SysVars
->ActiveCon
;
99 RtlFillMemory(Descriptor
->FileName
, sizeof(Descriptor
->FileName
), ' ');
100 RtlCopyMemory(Descriptor
->FileName
, Node
->Name
.Buffer
, Node
->Name
.Length
);
102 /* Call the open routine */
103 if (Node
->OpenRoutine
) Node
->OpenRoutine(Node
);
107 Descriptor
->Win32Handle
= StandardHandles
[i
];
111 Descriptor
->RefCount
++;
112 DestinationTable
[i
] = DescriptorId
;
117 /* Get the parent PSP block and handle table */
118 PspBlock
= SEGMENT_TO_PSP(Sda
->CurrentPsp
);
119 SourceTable
= (LPBYTE
)FAR_POINTER(PspBlock
->HandleTablePtr
);
121 /* Copy the first 20 handles into the new table */
122 for (i
= 0; i
< DEFAULT_JFT_SIZE
; i
++)
124 Descriptor
= DosGetFileDescriptor(SourceTable
[i
]);
125 DestinationTable
[i
] = SourceTable
[i
];
127 /* Increase the reference count */
128 Descriptor
->RefCount
++;
133 BOOLEAN
DosResizeHandleTable(WORD NewSize
)
139 /* Get the PSP block */
140 PspBlock
= SEGMENT_TO_PSP(Sda
->CurrentPsp
);
142 if (NewSize
== PspBlock
->HandleTableSize
)
148 if (PspBlock
->HandleTableSize
> DEFAULT_JFT_SIZE
)
150 /* Get the segment of the current table */
151 Segment
= (LOWORD(PspBlock
->HandleTablePtr
) >> 4) + HIWORD(PspBlock
->HandleTablePtr
);
153 if (NewSize
<= DEFAULT_JFT_SIZE
)
155 /* Get the current handle table */
156 HandleTable
= FAR_POINTER(PspBlock
->HandleTablePtr
);
158 /* Copy it to the PSP */
159 RtlCopyMemory(PspBlock
->HandleTable
, HandleTable
, NewSize
);
161 /* Free the memory */
162 DosFreeMemory(Segment
);
164 /* Update the handle table pointer and size */
165 PspBlock
->HandleTableSize
= NewSize
;
166 PspBlock
->HandleTablePtr
= MAKELONG(0x18, Sda
->CurrentPsp
);
170 /* Resize the memory */
171 if (!DosResizeMemory(Segment
, NewSize
, NULL
))
173 /* Unable to resize, try allocating it somewhere else */
174 Segment
= DosAllocateMemory(NewSize
, NULL
);
175 if (Segment
== 0) return FALSE
;
177 /* Get the new handle table */
178 HandleTable
= SEG_OFF_TO_PTR(Segment
, 0);
180 /* Copy the handles to the new table */
181 RtlCopyMemory(HandleTable
,
182 FAR_POINTER(PspBlock
->HandleTablePtr
),
183 PspBlock
->HandleTableSize
);
185 /* Update the handle table pointer */
186 PspBlock
->HandleTablePtr
= MAKELONG(0, Segment
);
189 /* Update the handle table size */
190 PspBlock
->HandleTableSize
= NewSize
;
193 else if (NewSize
> DEFAULT_JFT_SIZE
)
195 Segment
= DosAllocateMemory(NewSize
, NULL
);
196 if (Segment
== 0) return FALSE
;
198 /* Get the new handle table */
199 HandleTable
= SEG_OFF_TO_PTR(Segment
, 0);
201 /* Copy the handles from the PSP to the new table */
202 RtlCopyMemory(HandleTable
,
203 FAR_POINTER(PspBlock
->HandleTablePtr
),
204 PspBlock
->HandleTableSize
);
206 /* Update the handle table pointer and size */
207 PspBlock
->HandleTableSize
= NewSize
;
208 PspBlock
->HandleTablePtr
= MAKELONG(0, Segment
);
215 WORD
DosOpenHandle(BYTE DescriptorId
)
220 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetFileDescriptor(DescriptorId
);
222 DPRINT("DosOpenHandle: DescriptorId 0x%02X\n", DescriptorId
);
224 /* Make sure the descriptor ID is valid */
225 if (Descriptor
== NULL
) return INVALID_DOS_HANDLE
;
227 /* The system PSP has no handle table */
228 if (Sda
->CurrentPsp
== SYSTEM_PSP
) return INVALID_DOS_HANDLE
;
230 /* Get a pointer to the handle table */
231 PspBlock
= SEGMENT_TO_PSP(Sda
->CurrentPsp
);
232 HandleTable
= (LPBYTE
)FAR_POINTER(PspBlock
->HandleTablePtr
);
234 /* Find a free entry in the JFT */
235 for (DosHandle
= 0; DosHandle
< PspBlock
->HandleTableSize
; DosHandle
++)
237 if (HandleTable
[DosHandle
] == 0xFF) break;
240 /* If there are no free entries, fail */
241 if (DosHandle
== PspBlock
->HandleTableSize
) return INVALID_DOS_HANDLE
;
243 /* Reference the descriptor */
244 Descriptor
->RefCount
++;
246 /* Set the JFT entry to that descriptor ID */
247 HandleTable
[DosHandle
] = DescriptorId
;
249 /* Return the new handle */
253 BYTE
DosQueryHandle(WORD DosHandle
)
258 DPRINT("DosQueryHandle: DosHandle 0x%04X\n", DosHandle
);
260 /* The system PSP has no handle table */
261 if (Sda
->CurrentPsp
== SYSTEM_PSP
) return 0xFF;
263 /* Get a pointer to the handle table */
264 PspBlock
= SEGMENT_TO_PSP(Sda
->CurrentPsp
);
265 HandleTable
= (LPBYTE
)FAR_POINTER(PspBlock
->HandleTablePtr
);
267 /* Return the descriptor ID */
268 return HandleTable
[DosHandle
];
271 WORD
DosDuplicateHandle(WORD DosHandle
)
273 BYTE DescriptorId
= DosQueryHandle(DosHandle
);
275 if (DescriptorId
== 0xFF)
277 Sda
->LastErrorCode
= ERROR_INVALID_HANDLE
;
278 return INVALID_DOS_HANDLE
;
281 return DosOpenHandle(DescriptorId
);
284 BOOLEAN
DosForceDuplicateHandle(WORD OldHandle
, WORD NewHandle
)
289 PDOS_FILE_DESCRIPTOR Descriptor
;
291 DPRINT("DosForceDuplicateHandle: OldHandle 0x%04X, NewHandle 0x%04X\n",
295 /* The system PSP has no handle table */
296 if (Sda
->CurrentPsp
== SYSTEM_PSP
) return FALSE
;
298 /* Get a pointer to the handle table */
299 PspBlock
= SEGMENT_TO_PSP(Sda
->CurrentPsp
);
300 HandleTable
= (LPBYTE
)FAR_POINTER(PspBlock
->HandleTablePtr
);
302 /* Make sure the old handle is open */
303 if (HandleTable
[OldHandle
] == 0xFF) return FALSE
;
305 /* Check if the new handle is open */
306 if (HandleTable
[NewHandle
] != 0xFF)
309 DosCloseHandle(NewHandle
);
312 DescriptorId
= HandleTable
[OldHandle
];
313 Descriptor
= DosGetFileDescriptor(DescriptorId
);
314 if (Descriptor
== NULL
) return FALSE
;
316 /* Increment the reference count of the descriptor */
317 Descriptor
->RefCount
++;
319 /* Make the new handle point to that descriptor */
320 HandleTable
[NewHandle
] = DescriptorId
;
326 BOOLEAN
DosCloseHandle(WORD DosHandle
)
330 PDOS_FILE_DESCRIPTOR Descriptor
;
332 DPRINT("DosCloseHandle: DosHandle 0x%04X\n", DosHandle
);
334 /* The system PSP has no handle table */
335 if (Sda
->CurrentPsp
== SYSTEM_PSP
) return FALSE
;
337 /* Get a pointer to the handle table */
338 PspBlock
= SEGMENT_TO_PSP(Sda
->CurrentPsp
);
339 HandleTable
= (LPBYTE
)FAR_POINTER(PspBlock
->HandleTablePtr
);
341 /* Make sure the handle is open */
342 if (HandleTable
[DosHandle
] == 0xFF) return FALSE
;
344 /* Make sure the descriptor is valid */
345 Descriptor
= DosGetFileDescriptor(HandleTable
[DosHandle
]);
346 if (Descriptor
== NULL
) return FALSE
;
348 /* Decrement the reference count of the descriptor */
349 Descriptor
->RefCount
--;
351 /* Check if the reference count fell to zero */
352 if (!Descriptor
->RefCount
)
354 if (Descriptor
->DeviceInfo
& FILE_INFO_DEVICE
)
356 PDOS_DEVICE_NODE Node
= DosGetDriverNode(Descriptor
->DevicePointer
);
358 /* Call the close routine, if it exists */
359 if (Node
->CloseRoutine
) Node
->CloseRoutine(Node
);
363 /* Close the Win32 handle */
364 CloseHandle(Descriptor
->Win32Handle
);
368 /* Clear the entry in the JFT */
369 HandleTable
[DosHandle
] = 0xFF;