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 } 358