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 *******************************************************************/
23 /* PRIVATE FUNCTIONS **********************************************************/
25 /* Taken from base/shell/cmd/console.c */
26 static BOOL
IsConsoleHandle(HANDLE hHandle
)
30 /* Check whether the handle may be that of a console... */
31 if ((GetFileType(hHandle
) & FILE_TYPE_CHAR
) == 0) return FALSE
;
34 * It may be. Perform another test... The idea comes from the
35 * MSDN description of the WriteConsole API:
37 * "WriteConsole fails if it is used with a standard handle
38 * that is redirected to a file. If an application processes
39 * multilingual output that can be redirected, determine whether
40 * the output handle is a console handle (one method is to call
41 * the GetConsoleMode function and check whether it succeeds).
42 * If the handle is a console handle, call WriteConsole. If the
43 * handle is not a console handle, the output is redirected and
44 * you should call WriteFile to perform the I/O."
46 return GetConsoleMode(hHandle
, &dwMode
);
49 /* PUBLIC FUNCTIONS ***********************************************************/
51 VOID
DosCopyHandleTable(LPBYTE DestinationTable
)
56 PDOS_FILE_DESCRIPTOR Descriptor
;
58 /* Clear the table first */
59 for (i
= 0; i
< DEFAULT_JFT_SIZE
; i
++) DestinationTable
[i
] = 0xFF;
61 /* Check if this is the initial process */
62 if (Sda
->CurrentPsp
== SYSTEM_PSP
)
65 HANDLE StandardHandles
[3];
67 /* Get the native standard handles */
68 StandardHandles
[0] = GetStdHandle(STD_INPUT_HANDLE
);
69 StandardHandles
[1] = GetStdHandle(STD_OUTPUT_HANDLE
);
70 StandardHandles
[2] = GetStdHandle(STD_ERROR_HANDLE
);
72 for (i
= 0; i
< 3; i
++)
74 /* Find the corresponding SFT entry */
75 if (IsConsoleHandle(StandardHandles
[i
]))
77 DescriptorId
= DosFindDeviceDescriptor(SysVars
->ActiveCon
);
81 DescriptorId
= DosFindWin32Descriptor(StandardHandles
[i
]);
84 if (DescriptorId
!= 0xFF)
86 Descriptor
= DosGetFileDescriptor(DescriptorId
);
90 /* Create a new SFT entry for it */
91 DescriptorId
= DosFindFreeDescriptor();
92 if (DescriptorId
== 0xFF)
94 DPRINT1("Cannot create standard handle %d, the SFT is full!\n", i
);
98 Descriptor
= DosGetFileDescriptor(DescriptorId
);
99 ASSERT(Descriptor
!= NULL
);
100 RtlZeroMemory(Descriptor
, sizeof(*Descriptor
));
102 if (IsConsoleHandle(StandardHandles
[i
]))
104 PDOS_DEVICE_NODE Node
= DosGetDriverNode(SysVars
->ActiveCon
);
106 Descriptor
->DeviceInfo
= Node
->DeviceAttributes
| FILE_INFO_DEVICE
;
107 Descriptor
->DevicePointer
= SysVars
->ActiveCon
;
108 RtlFillMemory(Descriptor
->FileName
, sizeof(Descriptor
->FileName
), ' ');
109 RtlCopyMemory(Descriptor
->FileName
, Node
->Name
.Buffer
, Node
->Name
.Length
);
111 /* Call the open routine */
112 if (Node
->OpenRoutine
) Node
->OpenRoutine(Node
);
116 Descriptor
->Win32Handle
= StandardHandles
[i
];
120 Descriptor
->RefCount
++;
121 DestinationTable
[i
] = DescriptorId
;
126 /* Get the parent PSP block and handle table */
127 PspBlock
= SEGMENT_TO_PSP(Sda
->CurrentPsp
);
128 SourceTable
= (LPBYTE
)FAR_POINTER(PspBlock
->HandleTablePtr
);
130 /* Copy the first 20 handles into the new table */
131 for (i
= 0; i
< DEFAULT_JFT_SIZE
; i
++)
133 Descriptor
= DosGetFileDescriptor(SourceTable
[i
]);
134 DestinationTable
[i
] = SourceTable
[i
];
136 /* Increase the reference count */
137 Descriptor
->RefCount
++;
142 BOOLEAN
DosResizeHandleTable(WORD NewSize
)
148 /* Get the PSP block */
149 PspBlock
= SEGMENT_TO_PSP(Sda
->CurrentPsp
);
151 if (NewSize
== PspBlock
->HandleTableSize
)
157 if (PspBlock
->HandleTableSize
> DEFAULT_JFT_SIZE
)
159 /* Get the segment of the current table */
160 Segment
= (LOWORD(PspBlock
->HandleTablePtr
) >> 4) + HIWORD(PspBlock
->HandleTablePtr
);
162 if (NewSize
<= DEFAULT_JFT_SIZE
)
164 /* Get the current handle table */
165 HandleTable
= FAR_POINTER(PspBlock
->HandleTablePtr
);
167 /* Copy it to the PSP */
168 RtlCopyMemory(PspBlock
->HandleTable
, HandleTable
, NewSize
);
170 /* Free the memory */
171 DosFreeMemory(Segment
);
173 /* Update the handle table pointer and size */
174 PspBlock
->HandleTableSize
= NewSize
;
175 PspBlock
->HandleTablePtr
= MAKELONG(0x18, Sda
->CurrentPsp
);
179 /* Resize the memory */
180 if (!DosResizeMemory(Segment
, NewSize
, NULL
))
182 /* Unable to resize, try allocating it somewhere else */
183 Segment
= DosAllocateMemory(NewSize
, NULL
);
184 if (Segment
== 0) return FALSE
;
186 /* Get the new handle table */
187 HandleTable
= SEG_OFF_TO_PTR(Segment
, 0);
189 /* Copy the handles to the new table */
190 RtlCopyMemory(HandleTable
,
191 FAR_POINTER(PspBlock
->HandleTablePtr
),
192 PspBlock
->HandleTableSize
);
194 /* Update the handle table pointer */
195 PspBlock
->HandleTablePtr
= MAKELONG(0, Segment
);
198 /* Update the handle table size */
199 PspBlock
->HandleTableSize
= NewSize
;
202 else if (NewSize
> DEFAULT_JFT_SIZE
)
204 Segment
= DosAllocateMemory(NewSize
, NULL
);
205 if (Segment
== 0) return FALSE
;
207 /* Get the new handle table */
208 HandleTable
= SEG_OFF_TO_PTR(Segment
, 0);
210 /* Copy the handles from the PSP to the new table */
211 RtlCopyMemory(HandleTable
,
212 FAR_POINTER(PspBlock
->HandleTablePtr
),
213 PspBlock
->HandleTableSize
);
215 /* Update the handle table pointer and size */
216 PspBlock
->HandleTableSize
= NewSize
;
217 PspBlock
->HandleTablePtr
= MAKELONG(0, Segment
);
224 WORD
DosOpenHandle(BYTE DescriptorId
)
229 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetFileDescriptor(DescriptorId
);
231 DPRINT("DosOpenHandle: DescriptorId 0x%02X\n", DescriptorId
);
233 /* Make sure the descriptor ID is valid */
234 if (Descriptor
== NULL
) return INVALID_DOS_HANDLE
;
236 /* The system PSP has no handle table */
237 if (Sda
->CurrentPsp
== SYSTEM_PSP
) return INVALID_DOS_HANDLE
;
239 /* Get a pointer to the handle table */
240 PspBlock
= SEGMENT_TO_PSP(Sda
->CurrentPsp
);
241 HandleTable
= (LPBYTE
)FAR_POINTER(PspBlock
->HandleTablePtr
);
243 /* Find a free entry in the JFT */
244 for (DosHandle
= 0; DosHandle
< PspBlock
->HandleTableSize
; DosHandle
++)
246 if (HandleTable
[DosHandle
] == 0xFF) break;
249 /* If there are no free entries, fail */
250 if (DosHandle
== PspBlock
->HandleTableSize
) return INVALID_DOS_HANDLE
;
252 /* Reference the descriptor */
253 Descriptor
->RefCount
++;
255 /* Set the JFT entry to that descriptor ID */
256 HandleTable
[DosHandle
] = DescriptorId
;
258 /* Return the new handle */
262 BYTE
DosQueryHandle(WORD DosHandle
)
267 DPRINT("DosQueryHandle: DosHandle 0x%04X\n", DosHandle
);
269 /* The system PSP has no handle table */
270 if (Sda
->CurrentPsp
== SYSTEM_PSP
) return 0xFF;
272 /* Get a pointer to the handle table */
273 PspBlock
= SEGMENT_TO_PSP(Sda
->CurrentPsp
);
274 HandleTable
= (LPBYTE
)FAR_POINTER(PspBlock
->HandleTablePtr
);
276 /* Return the descriptor ID */
277 return HandleTable
[DosHandle
];
280 WORD
DosDuplicateHandle(WORD DosHandle
)
282 BYTE DescriptorId
= DosQueryHandle(DosHandle
);
284 if (DescriptorId
== 0xFF)
286 Sda
->LastErrorCode
= ERROR_INVALID_HANDLE
;
287 return INVALID_DOS_HANDLE
;
290 return DosOpenHandle(DescriptorId
);
293 BOOLEAN
DosForceDuplicateHandle(WORD OldHandle
, WORD NewHandle
)
298 PDOS_FILE_DESCRIPTOR Descriptor
;
300 DPRINT("DosForceDuplicateHandle: OldHandle 0x%04X, NewHandle 0x%04X\n",
304 /* The system PSP has no handle table */
305 if (Sda
->CurrentPsp
== SYSTEM_PSP
) return FALSE
;
307 /* Get a pointer to the handle table */
308 PspBlock
= SEGMENT_TO_PSP(Sda
->CurrentPsp
);
309 HandleTable
= (LPBYTE
)FAR_POINTER(PspBlock
->HandleTablePtr
);
311 /* Make sure the old handle is open */
312 if (HandleTable
[OldHandle
] == 0xFF) return FALSE
;
314 /* Check if the new handle is open */
315 if (HandleTable
[NewHandle
] != 0xFF)
318 DosCloseHandle(NewHandle
);
321 DescriptorId
= HandleTable
[OldHandle
];
322 Descriptor
= DosGetFileDescriptor(DescriptorId
);
323 if (Descriptor
== NULL
) return FALSE
;
325 /* Increment the reference count of the descriptor */
326 Descriptor
->RefCount
++;
328 /* Make the new handle point to that descriptor */
329 HandleTable
[NewHandle
] = DescriptorId
;
335 BOOLEAN
DosCloseHandle(WORD DosHandle
)
339 PDOS_FILE_DESCRIPTOR Descriptor
;
341 DPRINT("DosCloseHandle: DosHandle 0x%04X\n", DosHandle
);
343 /* The system PSP has no handle table */
344 if (Sda
->CurrentPsp
== SYSTEM_PSP
) return FALSE
;
346 /* Get a pointer to the handle table */
347 PspBlock
= SEGMENT_TO_PSP(Sda
->CurrentPsp
);
348 HandleTable
= (LPBYTE
)FAR_POINTER(PspBlock
->HandleTablePtr
);
350 /* Make sure the handle is open */
351 if (HandleTable
[DosHandle
] == 0xFF) return FALSE
;
353 /* Make sure the descriptor is valid */
354 Descriptor
= DosGetFileDescriptor(HandleTable
[DosHandle
]);
355 if (Descriptor
== NULL
) return FALSE
;
357 /* Decrement the reference count of the descriptor */
358 Descriptor
->RefCount
--;
360 /* Check if the reference count fell to zero */
361 if (!Descriptor
->RefCount
)
363 if (Descriptor
->DeviceInfo
& (1 << 7))
365 PDOS_DEVICE_NODE Node
= DosGetDriverNode(Descriptor
->DevicePointer
);
367 /* Call the close routine, if it exists */
368 if (Node
->CloseRoutine
) Node
->CloseRoutine(Node
);
372 /* Close the win32 handle */
373 CloseHandle(Descriptor
->Win32Handle
);
377 /* Clear the entry in the JFT */
378 HandleTable
[DosHandle
] = 0xFF;