2 * COPYRIGHT: GPLv2+ - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: dos/dos32krnl/handle.c
5 * PURPOSE: DOS32 Handles (Job File Table)
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
22 /* PRIVATE FUNCTIONS **********************************************************/
24 /* Taken from base/shell/cmd/console.c */
25 static BOOL
IsConsoleHandle(HANDLE hHandle
)
29 /* Check whether the handle may be that of a console... */
30 if ((GetFileType(hHandle
) & FILE_TYPE_CHAR
) == 0) return FALSE
;
33 * It may be. Perform another test... The idea comes from the
34 * MSDN description of the WriteConsole API:
36 * "WriteConsole fails if it is used with a standard handle
37 * that is redirected to a file. If an application processes
38 * multilingual output that can be redirected, determine whether
39 * the output handle is a console handle (one method is to call
40 * the GetConsoleMode function and check whether it succeeds).
41 * If the handle is a console handle, call WriteConsole. If the
42 * handle is not a console handle, the output is redirected and
43 * you should call WriteFile to perform the I/O."
45 return GetConsoleMode(hHandle
, &dwMode
);
48 /* PUBLIC FUNCTIONS ***********************************************************/
50 VOID
DosCopyHandleTable(LPBYTE DestinationTable
)
55 PDOS_FILE_DESCRIPTOR Descriptor
;
57 /* Clear the table first */
58 for (i
= 0; i
< DEFAULT_JFT_SIZE
; i
++) DestinationTable
[i
] = 0xFF;
60 /* Check if this is the initial process */
61 if (CurrentPsp
== SYSTEM_PSP
)
64 HANDLE StandardHandles
[3];
66 /* Get the native standard handles */
67 StandardHandles
[0] = GetStdHandle(STD_INPUT_HANDLE
);
68 StandardHandles
[1] = GetStdHandle(STD_OUTPUT_HANDLE
);
69 StandardHandles
[2] = GetStdHandle(STD_ERROR_HANDLE
);
71 for (i
= 0; i
< 3; i
++)
73 /* Find the corresponding SFT entry */
74 if (IsConsoleHandle(StandardHandles
[i
]))
76 DescriptorId
= DosFindDeviceDescriptor(SysVars
->ActiveCon
);
80 DescriptorId
= DosFindWin32Descriptor(StandardHandles
[i
]);
83 if (DescriptorId
!= 0xFF)
85 Descriptor
= DosGetFileDescriptor(DescriptorId
);
89 /* Create a new SFT entry for it */
90 DescriptorId
= DosFindFreeDescriptor();
91 if (DescriptorId
== 0xFF)
93 DPRINT1("Cannot create standard handle %d, the SFT is full!\n", i
);
97 Descriptor
= DosGetFileDescriptor(DescriptorId
);
98 ASSERT(Descriptor
!= NULL
);
99 RtlZeroMemory(Descriptor
, sizeof(*Descriptor
));
101 if (IsConsoleHandle(StandardHandles
[i
]))
103 PDOS_DEVICE_NODE Node
= DosGetDriverNode(SysVars
->ActiveCon
);
105 Descriptor
->DeviceInfo
= Node
->DeviceAttributes
| (1 << 7);
106 Descriptor
->DevicePointer
= SysVars
->ActiveCon
;
108 /* Call the open routine */
109 if (Node
->OpenRoutine
) Node
->OpenRoutine(Node
);
113 Descriptor
->Win32Handle
= StandardHandles
[i
];
117 Descriptor
->RefCount
++;
118 DestinationTable
[i
] = DescriptorId
;
123 /* Get the parent PSP block and handle table */
124 PspBlock
= SEGMENT_TO_PSP(CurrentPsp
);
125 SourceTable
= (LPBYTE
)FAR_POINTER(PspBlock
->HandleTablePtr
);
127 /* Copy the first 20 handles into the new table */
128 for (i
= 0; i
< DEFAULT_JFT_SIZE
; i
++)
130 Descriptor
= DosGetFileDescriptor(SourceTable
[i
]);
131 DestinationTable
[i
] = SourceTable
[i
];
133 /* Increase the reference count */
134 Descriptor
->RefCount
++;
139 BOOLEAN
DosResizeHandleTable(WORD NewSize
)
145 /* Get the PSP block */
146 PspBlock
= SEGMENT_TO_PSP(CurrentPsp
);
148 if (NewSize
== PspBlock
->HandleTableSize
)
154 if (PspBlock
->HandleTableSize
> DEFAULT_JFT_SIZE
)
156 /* Get the segment of the current table */
157 Segment
= (LOWORD(PspBlock
->HandleTablePtr
) >> 4) + HIWORD(PspBlock
->HandleTablePtr
);
159 if (NewSize
<= DEFAULT_JFT_SIZE
)
161 /* Get the current handle table */
162 HandleTable
= FAR_POINTER(PspBlock
->HandleTablePtr
);
164 /* Copy it to the PSP */
165 RtlCopyMemory(PspBlock
->HandleTable
, HandleTable
, NewSize
);
167 /* Free the memory */
168 DosFreeMemory(Segment
);
170 /* Update the handle table pointer and size */
171 PspBlock
->HandleTableSize
= NewSize
;
172 PspBlock
->HandleTablePtr
= MAKELONG(0x18, CurrentPsp
);
176 /* Resize the memory */
177 if (!DosResizeMemory(Segment
, NewSize
, NULL
))
179 /* Unable to resize, try allocating it somewhere else */
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 to the new table */
187 RtlCopyMemory(HandleTable
,
188 FAR_POINTER(PspBlock
->HandleTablePtr
),
189 PspBlock
->HandleTableSize
);
191 /* Update the handle table pointer */
192 PspBlock
->HandleTablePtr
= MAKELONG(0, Segment
);
195 /* Update the handle table size */
196 PspBlock
->HandleTableSize
= NewSize
;
199 else if (NewSize
> DEFAULT_JFT_SIZE
)
201 Segment
= DosAllocateMemory(NewSize
, NULL
);
202 if (Segment
== 0) return FALSE
;
204 /* Get the new handle table */
205 HandleTable
= SEG_OFF_TO_PTR(Segment
, 0);
207 /* Copy the handles from the PSP to the new table */
208 RtlCopyMemory(HandleTable
,
209 FAR_POINTER(PspBlock
->HandleTablePtr
),
210 PspBlock
->HandleTableSize
);
212 /* Update the handle table pointer and size */
213 PspBlock
->HandleTableSize
= NewSize
;
214 PspBlock
->HandleTablePtr
= MAKELONG(0, Segment
);
221 WORD
DosOpenHandle(BYTE DescriptorId
)
226 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetFileDescriptor(DescriptorId
);
228 DPRINT("DosOpenHandle: DescriptorId 0x%02X\n", DescriptorId
);
230 /* Make sure the descriptor ID is valid */
231 if (Descriptor
== NULL
) return INVALID_DOS_HANDLE
;
233 /* The system PSP has no handle table */
234 if (CurrentPsp
== SYSTEM_PSP
) return INVALID_DOS_HANDLE
;
236 /* Get a pointer to the handle table */
237 PspBlock
= SEGMENT_TO_PSP(CurrentPsp
);
238 HandleTable
= (LPBYTE
)FAR_POINTER(PspBlock
->HandleTablePtr
);
240 /* Find a free entry in the JFT */
241 for (DosHandle
= 0; DosHandle
< PspBlock
->HandleTableSize
; DosHandle
++)
243 if (HandleTable
[DosHandle
] == 0xFF) break;
246 /* If there are no free entries, fail */
247 if (DosHandle
== PspBlock
->HandleTableSize
) return INVALID_DOS_HANDLE
;
249 /* Reference the descriptor */
250 Descriptor
->RefCount
++;
252 /* Set the JFT entry to that descriptor ID */
253 HandleTable
[DosHandle
] = DescriptorId
;
255 /* Return the new handle */
259 BYTE
DosQueryHandle(WORD DosHandle
)
264 DPRINT("DosQueryHandle: DosHandle 0x%04X\n", DosHandle
);
266 /* The system PSP has no handle table */
267 if (CurrentPsp
== SYSTEM_PSP
) return 0xFF;
269 /* Get a pointer to the handle table */
270 PspBlock
= SEGMENT_TO_PSP(CurrentPsp
);
271 HandleTable
= (LPBYTE
)FAR_POINTER(PspBlock
->HandleTablePtr
);
273 /* Return the descriptor ID */
274 return HandleTable
[DosHandle
];
277 WORD
DosDuplicateHandle(WORD DosHandle
)
279 BYTE DescriptorId
= DosQueryHandle(DosHandle
);
281 if (DescriptorId
== 0xFF)
283 DosLastError
= ERROR_INVALID_HANDLE
;
284 return INVALID_DOS_HANDLE
;
287 return DosOpenHandle(DescriptorId
);
290 BOOLEAN
DosForceDuplicateHandle(WORD OldHandle
, WORD NewHandle
)
295 PDOS_FILE_DESCRIPTOR Descriptor
;
297 DPRINT("DosForceDuplicateHandle: OldHandle 0x%04X, NewHandle 0x%04X\n",
301 /* The system PSP has no handle table */
302 if (CurrentPsp
== SYSTEM_PSP
) return FALSE
;
304 /* Get a pointer to the handle table */
305 PspBlock
= SEGMENT_TO_PSP(CurrentPsp
);
306 HandleTable
= (LPBYTE
)FAR_POINTER(PspBlock
->HandleTablePtr
);
308 /* Make sure the old handle is open */
309 if (HandleTable
[OldHandle
] == 0xFF) return FALSE
;
311 /* Check if the new handle is open */
312 if (HandleTable
[NewHandle
] != 0xFF)
315 DosCloseHandle(NewHandle
);
318 DescriptorId
= HandleTable
[OldHandle
];
319 Descriptor
= DosGetFileDescriptor(DescriptorId
);
320 if (Descriptor
== NULL
) return FALSE
;
322 /* Increment the reference count of the descriptor */
323 Descriptor
->RefCount
++;
325 /* Make the new handle point to that descriptor */
326 HandleTable
[NewHandle
] = DescriptorId
;
332 BOOLEAN
DosCloseHandle(WORD DosHandle
)
336 PDOS_FILE_DESCRIPTOR Descriptor
;
338 DPRINT("DosCloseHandle: DosHandle 0x%04X\n", DosHandle
);
340 /* The system PSP has no handle table */
341 if (CurrentPsp
== SYSTEM_PSP
) return FALSE
;
343 /* Get a pointer to the handle table */
344 PspBlock
= SEGMENT_TO_PSP(CurrentPsp
);
345 HandleTable
= (LPBYTE
)FAR_POINTER(PspBlock
->HandleTablePtr
);
347 /* Make sure the handle is open */
348 if (HandleTable
[DosHandle
] == 0xFF) return FALSE
;
350 /* Make sure the descriptor is valid */
351 Descriptor
= DosGetFileDescriptor(HandleTable
[DosHandle
]);
352 if (Descriptor
== NULL
) return FALSE
;
354 /* Decrement the reference count of the descriptor */
355 Descriptor
->RefCount
--;
357 /* Check if the reference count fell to zero */
358 if (!Descriptor
->RefCount
)
360 if (Descriptor
->DeviceInfo
& (1 << 7))
362 PDOS_DEVICE_NODE Node
= DosGetDriverNode(Descriptor
->DevicePointer
);
364 /* Call the close routine, if it exists */
365 if (Node
->CloseRoutine
) Node
->CloseRoutine(Node
);
369 /* Close the win32 handle */
370 CloseHandle(Descriptor
->Win32Handle
);
374 /* Clear the entry in the JFT */
375 HandleTable
[DosHandle
] = 0xFF;