From 12dff944a2dacb82c2caa4118b294abd1ba978a5 Mon Sep 17 00:00:00 2001 From: Aleksandar Andrejevic Date: Sun, 26 Apr 2015 18:09:57 +0000 Subject: [PATCH] [NTVDM] Implement INT 21h, AH = 52h (Get List of Lists - SYSVARS). Rewrite the SFT code to keep the SFT in guest memory. Implement the NUL device driver. svn path=/trunk/; revision=67444 --- reactos/subsystems/mvdm/ntvdm/CMakeLists.txt | 1 + .../mvdm/ntvdm/dos/dos32krnl/bios.c | 45 +- .../mvdm/ntvdm/dos/dos32krnl/device.c | 108 +-- .../mvdm/ntvdm/dos/dos32krnl/device.h | 1 + .../subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c | 713 ++---------------- .../subsystems/mvdm/ntvdm/dos/dos32krnl/dos.h | 85 +-- .../mvdm/ntvdm/dos/dos32krnl/dosfiles.c | 576 ++++++++++---- .../mvdm/ntvdm/dos/dos32krnl/dosfiles.h | 108 +++ .../mvdm/ntvdm/dos/dos32krnl/handle.c | 378 ++++++++++ .../mvdm/ntvdm/dos/dos32krnl/handle.h | 21 + 10 files changed, 1118 insertions(+), 918 deletions(-) create mode 100644 reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.h create mode 100644 reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/handle.c create mode 100644 reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/handle.h diff --git a/reactos/subsystems/mvdm/ntvdm/CMakeLists.txt b/reactos/subsystems/mvdm/ntvdm/CMakeLists.txt index a27845d6b6e..f9ea31caebc 100644 --- a/reactos/subsystems/mvdm/ntvdm/CMakeLists.txt +++ b/reactos/subsystems/mvdm/ntvdm/CMakeLists.txt @@ -33,6 +33,7 @@ list(APPEND SOURCE dos/dos32krnl/dos.c dos/dos32krnl/dosfiles.c dos/dos32krnl/emsdrv.c + dos/dos32krnl/handle.c dos/dos32krnl/himem.c dos/dos32krnl/memory.c dos/mouse32.c diff --git a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/bios.c b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/bios.c index 41b144fc1de..72630559d7d 100644 --- a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/bios.c +++ b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/bios.c @@ -15,6 +15,7 @@ #include "int32.h" #include "dos.h" +#include "dosfiles.h" #include "memory.h" #include "bios/bios.h" @@ -56,43 +57,33 @@ CHAR DosReadCharacter(WORD FileHandle) BOOLEAN DosCheckInput(VOID) { - PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(DOS_INPUT_HANDLE); + PDOS_FILE_DESCRIPTOR Descriptor = DosGetHandleFileDescriptor(DOS_INPUT_HANDLE); - if (SftEntry == NULL) + if (Descriptor == NULL) { /* Invalid handle */ DosLastError = ERROR_INVALID_HANDLE; // ERROR_FILE_NOT_FOUND return FALSE; } - switch (SftEntry->Type) + if (Descriptor->DeviceInfo & (1 << 7)) { - case DOS_SFT_ENTRY_WIN32: - { - DWORD FileSizeHigh; - DWORD FileSize = GetFileSize(SftEntry->Handle, &FileSizeHigh); - LONG LocationHigh = 0; - DWORD Location = SetFilePointer(SftEntry->Handle, 0, &LocationHigh, FILE_CURRENT); - - return ((Location != FileSize) || (LocationHigh != FileSizeHigh)); - } - - case DOS_SFT_ENTRY_DEVICE: - { - WORD Result; + WORD Result; + PDOS_DEVICE_NODE Node = DosGetDriverNode(Descriptor->DevicePointer); - if (!SftEntry->DeviceNode->InputStatusRoutine) return FALSE; - - Result = SftEntry->DeviceNode->InputStatusRoutine(SftEntry->DeviceNode); - return !(Result & DOS_DEVSTAT_BUSY); - } + if (!Node->InputStatusRoutine) return FALSE; + + Result = Node->InputStatusRoutine(Node); + return !(Result & DOS_DEVSTAT_BUSY); + } + else + { + DWORD FileSizeHigh; + DWORD FileSize = GetFileSize(Descriptor->Win32Handle, &FileSizeHigh); + LONG LocationHigh = 0; + DWORD Location = SetFilePointer(Descriptor->Win32Handle, 0, &LocationHigh, FILE_CURRENT); - default: - { - /* Invalid handle */ - DosLastError = ERROR_INVALID_HANDLE; - return FALSE; - } + return ((Location != FileSize) || (LocationHigh != FileSizeHigh)); } } diff --git a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/device.c b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/device.c index 91975e4632f..8b622350ee0 100644 --- a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/device.c +++ b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/device.c @@ -40,7 +40,6 @@ static const BYTE InterruptRoutine[] = { C_ASSERT((sizeof(StrategyRoutine) + sizeof(InterruptRoutine)) == DEVICE_CODE_SIZE); static LIST_ENTRY DeviceList = { &DeviceList, &DeviceList }; -static DWORD FirstDriver = 0xFFFFFFFF; static PDOS_REQUEST_HEADER DeviceRequest; /* PRIVATE FUNCTIONS **********************************************************/ @@ -213,17 +212,9 @@ static WORD NTAPI DosDriverDispatchOutputUntilBusy(PDOS_DEVICE_NODE DeviceNode, static VOID DosAddDriver(DWORD Driver) { - PDOS_DRIVER LastDriver; + PDOS_DRIVER LastDriver = &SysVars->NullDevice; - if (LOWORD(FirstDriver) == 0xFFFF) - { - /* This is the first driver */ - FirstDriver = Driver; - return; - } - - /* The list isn't empty, so find the last driver in it */ - LastDriver = (PDOS_DRIVER)FAR_POINTER(FirstDriver); + /* Find the last driver in the list */ while (LOWORD(LastDriver->Link) != 0xFFFF) { LastDriver = (PDOS_DRIVER)FAR_POINTER(LastDriver->Link); @@ -231,18 +222,25 @@ static VOID DosAddDriver(DWORD Driver) /* Add the new driver to the list */ LastDriver->Link = Driver; -} + LastDriver = (PDOS_DRIVER)FAR_POINTER(Driver); -static VOID DosRemoveDriver(DWORD Driver) -{ - DWORD CurrentDriver = FirstDriver; + if (LastDriver->DeviceAttributes & DOS_DEVATTR_CLOCK) + { + /* Update the active CLOCK driver */ + SysVars->ActiveClock = Driver; + } - if (FirstDriver == Driver) + if (LastDriver->DeviceAttributes + & (DOS_DEVATTR_STDIN | DOS_DEVATTR_STDOUT | DOS_DEVATTR_CON)) { - /* Update the first driver */ - FirstDriver = ((PDOS_DRIVER)FAR_POINTER(FirstDriver))->Link; - return; + /* Update the active CON driver */ + SysVars->ActiveCon = Driver; } +} + +static VOID DosRemoveDriver(DWORD Driver) +{ + DWORD CurrentDriver = MAKELONG(FIELD_OFFSET(DOS_SYSVARS, NullDevice), DOS_DATA_SEGMENT); while (LOWORD(CurrentDriver) != 0xFFFF) { @@ -289,49 +287,55 @@ static PDOS_DEVICE_NODE DosCreateDeviceNode(DWORD Driver) /* PUBLIC FUNCTIONS ***********************************************************/ -PDOS_DEVICE_NODE DosGetDevice(LPCSTR DeviceName) +PDOS_DEVICE_NODE DosGetDriverNode(DWORD Driver) { PLIST_ENTRY i; - DWORD CurrentDriver = FirstDriver; + PDOS_DEVICE_NODE Node; + + for (i = DeviceList.Flink; i != &DeviceList; i = i->Flink) + { + Node = CONTAINING_RECORD(i, DOS_DEVICE_NODE, Entry); + if (Node->Driver == Driver) break; + } + + if (i == &DeviceList) + { + DPRINT1("The driver at %04X:%04X has no associated device node. " + "Installing automagically.\n", + HIWORD(Driver), + LOWORD(Driver)); + + /* Create the device node */ + Node = DosCreateDeviceNode(Driver); + Node->IoctlReadRoutine = DosDriverDispatchIoctlRead; + Node->ReadRoutine = DosDriverDispatchRead; + Node->PeekRoutine = DosDriverDispatchPeek; + Node->InputStatusRoutine = DosDriverDispatchInputStatus; + Node->FlushInputRoutine = DosDriverDispatchFlushInput; + Node->IoctlWriteRoutine = DosDriverDispatchIoctlWrite; + Node->WriteRoutine = DosDriverDispatchWrite; + Node->OutputStatusRoutine = DosDriverDispatchOutputStatus; + Node->FlushOutputRoutine = DosDriverDispatchFlushOutput; + Node->OpenRoutine = DosDriverDispatchOpen; + Node->CloseRoutine = DosDriverDispatchClose; + Node->OutputUntilBusyRoutine = DosDriverDispatchOutputUntilBusy; + } + + return Node; +} + +PDOS_DEVICE_NODE DosGetDevice(LPCSTR DeviceName) +{ + DWORD CurrentDriver = MAKELONG(FIELD_OFFSET(DOS_SYSVARS, NullDevice), DOS_DATA_SEGMENT); ANSI_STRING DeviceNameString; RtlInitAnsiString(&DeviceNameString, DeviceName); while (LOWORD(CurrentDriver) != 0xFFFF) { - PDOS_DEVICE_NODE Node; + PDOS_DEVICE_NODE Node = DosGetDriverNode(CurrentDriver); PDOS_DRIVER DriverHeader = (PDOS_DRIVER)FAR_POINTER(CurrentDriver); - /* Get the device node for this driver */ - for (i = DeviceList.Flink; i != &DeviceList; i = i->Flink) - { - Node = CONTAINING_RECORD(i, DOS_DEVICE_NODE, Entry); - if (Node->Driver == CurrentDriver) break; - } - - if (i == &DeviceList) - { - DPRINT1("The driver at %04X:%04X has no associated device node. " - "Installing automagically.\n", - HIWORD(CurrentDriver), - LOWORD(CurrentDriver)); - - /* Create the device node */ - Node = DosCreateDeviceNode(CurrentDriver); - Node->IoctlReadRoutine = DosDriverDispatchIoctlRead; - Node->ReadRoutine = DosDriverDispatchRead; - Node->PeekRoutine = DosDriverDispatchPeek; - Node->InputStatusRoutine = DosDriverDispatchInputStatus; - Node->FlushInputRoutine = DosDriverDispatchFlushInput; - Node->IoctlWriteRoutine = DosDriverDispatchIoctlWrite; - Node->WriteRoutine = DosDriverDispatchWrite; - Node->OutputStatusRoutine = DosDriverDispatchOutputStatus; - Node->FlushOutputRoutine = DosDriverDispatchFlushOutput; - Node->OpenRoutine = DosDriverDispatchOpen; - Node->CloseRoutine = DosDriverDispatchClose; - Node->OutputUntilBusyRoutine = DosDriverDispatchOutputUntilBusy; - } - if (RtlEqualString(&Node->Name, &DeviceNameString, TRUE)) return Node; CurrentDriver = DriverHeader->Link; } diff --git a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/device.h b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/device.h index 2061f4afd8f..bc3ab6e24dc 100644 --- a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/device.h +++ b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/device.h @@ -194,6 +194,7 @@ typedef struct _DOS_OUTPUT_BUSY_REQUEST /* FUNCTIONS ******************************************************************/ +PDOS_DEVICE_NODE DosGetDriverNode(DWORD Driver); PDOS_DEVICE_NODE DosGetDevice(LPCSTR DeviceName); PDOS_DEVICE_NODE DosCreateDevice(WORD Attributes, PCHAR DeviceName); PDOS_DEVICE_NODE DosCreateDeviceEx diff --git a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c index b8cc55b940f..ae904a20c89 100644 --- a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c +++ b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c @@ -19,6 +19,8 @@ #include "dos.h" #include "dos/dem.h" #include "device.h" +#include "handle.h" +#include "dosfiles.h" #include "memory.h" #include "himem.h" @@ -39,12 +41,13 @@ static DWORD DiskTransferArea; /*static*/ BYTE CurrentDrive; static CHAR LastDrive = 'E'; static CHAR CurrentDirectories[NUM_DRIVES][DOS_DIR_LENGTH]; -static DOS_SFT_ENTRY DosSystemFileTable[DOS_SFT_SIZE]; static WORD DosErrorLevel = 0x0000; static PBYTE InDos; /* PUBLIC VARIABLES ***********************************************************/ +PDOS_SYSVARS SysVars; + /* Echo state for INT 21h, AH = 01h and AH = 3Fh */ BOOLEAN DoEcho = FALSE; WORD CurrentPsp = SYSTEM_PSP; @@ -120,456 +123,6 @@ static WORD DosCopyEnvironmentBlock(LPCSTR Environment OPTIONAL, return DestSegment; } -/* Taken from base/shell/cmd/console.c */ -static BOOL IsConsoleHandle(HANDLE hHandle) -{ - DWORD dwMode; - - /* Check whether the handle may be that of a console... */ - if ((GetFileType(hHandle) & FILE_TYPE_CHAR) == 0) return FALSE; - - /* - * It may be. Perform another test... The idea comes from the - * MSDN description of the WriteConsole API: - * - * "WriteConsole fails if it is used with a standard handle - * that is redirected to a file. If an application processes - * multilingual output that can be redirected, determine whether - * the output handle is a console handle (one method is to call - * the GetConsoleMode function and check whether it succeeds). - * If the handle is a console handle, call WriteConsole. If the - * handle is not a console handle, the output is redirected and - * you should call WriteFile to perform the I/O." - */ - return GetConsoleMode(hHandle, &dwMode); -} - -static inline PDOS_SFT_ENTRY DosFindFreeSftEntry(VOID) -{ - UINT i; - - for (i = 0; i < DOS_SFT_SIZE; i++) - { - if (DosSystemFileTable[i].Type == DOS_SFT_ENTRY_NONE) - { - return &DosSystemFileTable[i]; - } - } - - return NULL; -} - -static inline PDOS_SFT_ENTRY DosFindWin32SftEntry(HANDLE Handle) -{ - UINT i; - - for (i = 0; i < DOS_SFT_SIZE; i++) - { - if (DosSystemFileTable[i].Type == DOS_SFT_ENTRY_WIN32 - && DosSystemFileTable[i].Handle == Handle) - { - return &DosSystemFileTable[i]; - } - } - - return NULL; -} - -static inline PDOS_SFT_ENTRY DosFindDeviceSftEntry(PDOS_DEVICE_NODE Device) -{ - UINT i; - - for (i = 0; i < DOS_SFT_SIZE; i++) - { - if (DosSystemFileTable[i].Type == DOS_SFT_ENTRY_DEVICE - && DosSystemFileTable[i].DeviceNode == Device) - { - return &DosSystemFileTable[i]; - } - } - - return NULL; -} - -WORD DosOpenHandle(HANDLE Handle) -{ - WORD DosHandle; - PDOS_PSP PspBlock; - LPBYTE HandleTable; - PDOS_SFT_ENTRY SftEntry; - - /* The system PSP has no handle table */ - if (CurrentPsp == SYSTEM_PSP) return INVALID_DOS_HANDLE; - - /* Get a pointer to the handle table */ - PspBlock = SEGMENT_TO_PSP(CurrentPsp); - HandleTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr); - - /* Find a free entry in the JFT */ - for (DosHandle = 0; DosHandle < PspBlock->HandleTableSize; DosHandle++) - { - if (HandleTable[DosHandle] == 0xFF) break; - } - - /* If there are no free entries, fail */ - if (DosHandle == PspBlock->HandleTableSize) return INVALID_DOS_HANDLE; - - /* Check if the handle is already in the SFT */ - SftEntry = DosFindWin32SftEntry(Handle); - if (SftEntry != NULL) - { - /* Already in the table, reference it */ - SftEntry->RefCount++; - goto Finish; - } - - /* Find a free SFT entry to use */ - SftEntry = DosFindFreeSftEntry(); - if (SftEntry == NULL) - { - /* The SFT is full */ - return INVALID_DOS_HANDLE; - } - - /* Initialize the empty table entry */ - SftEntry->Type = DOS_SFT_ENTRY_WIN32; - SftEntry->Handle = Handle; - SftEntry->RefCount = 1; - -Finish: - - /* Set the JFT entry to that SFT index */ - HandleTable[DosHandle] = ARRAY_INDEX(SftEntry, DosSystemFileTable); - - /* Return the new handle */ - return DosHandle; -} - -WORD DosOpenDevice(PDOS_DEVICE_NODE Device) -{ - WORD DosHandle; - PDOS_PSP PspBlock; - LPBYTE HandleTable; - PDOS_SFT_ENTRY SftEntry; - - DPRINT("DosOpenDevice(\"%Z\")\n", &Device->Name); - - /* The system PSP has no handle table */ - if (CurrentPsp == SYSTEM_PSP) return INVALID_DOS_HANDLE; - - /* Get a pointer to the handle table */ - PspBlock = SEGMENT_TO_PSP(CurrentPsp); - HandleTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr); - - /* Find a free entry in the JFT */ - for (DosHandle = 0; DosHandle < PspBlock->HandleTableSize; DosHandle++) - { - if (HandleTable[DosHandle] == 0xFF) break; - } - - /* If there are no free entries, fail */ - if (DosHandle == PspBlock->HandleTableSize) return INVALID_DOS_HANDLE; - - /* Check if the device is already in the SFT */ - SftEntry = DosFindDeviceSftEntry(Device); - if (SftEntry != NULL) - { - /* Already in the table, reference it */ - SftEntry->RefCount++; - goto Finish; - } - - /* Find a free SFT entry to use */ - SftEntry = DosFindFreeSftEntry(); - if (SftEntry == NULL) - { - /* The SFT is full */ - return INVALID_DOS_HANDLE; - } - - /* Initialize the empty table entry */ - SftEntry->Type = DOS_SFT_ENTRY_DEVICE; - SftEntry->DeviceNode = Device; - SftEntry->RefCount = 1; - -Finish: - - /* Call the open routine, if it exists */ - if (Device->OpenRoutine) Device->OpenRoutine(Device); - - /* Set the JFT entry to that SFT index */ - HandleTable[DosHandle] = ARRAY_INDEX(SftEntry, DosSystemFileTable); - - /* Return the new handle */ - return DosHandle; -} - -static VOID DosCopyHandleTable(LPBYTE DestinationTable) -{ - UINT i; - PDOS_PSP PspBlock; - LPBYTE SourceTable; - - /* Clear the table first */ - for (i = 0; i < 20; i++) DestinationTable[i] = 0xFF; - - /* Check if this is the initial process */ - if (CurrentPsp == SYSTEM_PSP) - { - PDOS_SFT_ENTRY SftEntry; - HANDLE StandardHandles[3]; - PDOS_DEVICE_NODE Con = DosGetDevice("CON"); - ASSERT(Con != NULL); - - /* Get the native standard handles */ - StandardHandles[0] = GetStdHandle(STD_INPUT_HANDLE); - StandardHandles[1] = GetStdHandle(STD_OUTPUT_HANDLE); - StandardHandles[2] = GetStdHandle(STD_ERROR_HANDLE); - - for (i = 0; i < 3; i++) - { - /* Find the corresponding SFT entry */ - if (IsConsoleHandle(StandardHandles[i])) - { - SftEntry = DosFindDeviceSftEntry(Con); - } - else - { - SftEntry = DosFindWin32SftEntry(StandardHandles[i]); - } - - if (SftEntry == NULL) - { - /* Create a new SFT entry for it */ - SftEntry = DosFindFreeSftEntry(); - if (SftEntry == NULL) - { - DPRINT1("Cannot create standard handle %d, the SFT is full!\n", i); - continue; - } - - SftEntry->RefCount = 0; - - if (IsConsoleHandle(StandardHandles[i])) - { - SftEntry->Type = DOS_SFT_ENTRY_DEVICE; - SftEntry->DeviceNode = Con; - - /* Call the open routine */ - if (Con->OpenRoutine) Con->OpenRoutine(Con); - } - else - { - SftEntry->Type = DOS_SFT_ENTRY_WIN32; - SftEntry->Handle = StandardHandles[i]; - } - } - - SftEntry->RefCount++; - DestinationTable[i] = ARRAY_INDEX(SftEntry, DosSystemFileTable); - } - } - else - { - /* Get the parent PSP block and handle table */ - PspBlock = SEGMENT_TO_PSP(CurrentPsp); - SourceTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr); - - /* Copy the first 20 handles into the new table */ - for (i = 0; i < DEFAULT_JFT_SIZE; i++) - { - DestinationTable[i] = SourceTable[i]; - - /* Increase the reference count */ - DosSystemFileTable[SourceTable[i]].RefCount++; - } - } -} - -static BOOLEAN DosResizeHandleTable(WORD NewSize) -{ - PDOS_PSP PspBlock; - LPBYTE HandleTable; - WORD Segment; - - /* Get the PSP block */ - PspBlock = SEGMENT_TO_PSP(CurrentPsp); - - if (NewSize == PspBlock->HandleTableSize) - { - /* No change */ - return TRUE; - } - - if (PspBlock->HandleTableSize > DEFAULT_JFT_SIZE) - { - /* Get the segment of the current table */ - Segment = (LOWORD(PspBlock->HandleTablePtr) >> 4) + HIWORD(PspBlock->HandleTablePtr); - - if (NewSize <= DEFAULT_JFT_SIZE) - { - /* Get the current handle table */ - HandleTable = FAR_POINTER(PspBlock->HandleTablePtr); - - /* Copy it to the PSP */ - RtlCopyMemory(PspBlock->HandleTable, HandleTable, NewSize); - - /* Free the memory */ - DosFreeMemory(Segment); - - /* Update the handle table pointer and size */ - PspBlock->HandleTableSize = NewSize; - PspBlock->HandleTablePtr = MAKELONG(0x18, CurrentPsp); - } - else - { - /* Resize the memory */ - if (!DosResizeMemory(Segment, NewSize, NULL)) - { - /* Unable to resize, try allocating it somewhere else */ - Segment = DosAllocateMemory(NewSize, NULL); - if (Segment == 0) return FALSE; - - /* Get the new handle table */ - HandleTable = SEG_OFF_TO_PTR(Segment, 0); - - /* Copy the handles to the new table */ - RtlCopyMemory(HandleTable, - FAR_POINTER(PspBlock->HandleTablePtr), - PspBlock->HandleTableSize); - - /* Update the handle table pointer */ - PspBlock->HandleTablePtr = MAKELONG(0, Segment); - } - - /* Update the handle table size */ - PspBlock->HandleTableSize = NewSize; - } - } - else if (NewSize > DEFAULT_JFT_SIZE) - { - Segment = DosAllocateMemory(NewSize, NULL); - if (Segment == 0) return FALSE; - - /* Get the new handle table */ - HandleTable = SEG_OFF_TO_PTR(Segment, 0); - - /* Copy the handles from the PSP to the new table */ - RtlCopyMemory(HandleTable, - FAR_POINTER(PspBlock->HandleTablePtr), - PspBlock->HandleTableSize); - - /* Update the handle table pointer and size */ - PspBlock->HandleTableSize = NewSize; - PspBlock->HandleTablePtr = MAKELONG(0, Segment); - } - - return TRUE; -} - -static BOOLEAN DosCloseHandle(WORD DosHandle) -{ - PDOS_PSP PspBlock; - LPBYTE HandleTable; - PDOS_SFT_ENTRY SftEntry; - - DPRINT("DosCloseHandle: DosHandle 0x%04X\n", DosHandle); - - /* The system PSP has no handle table */ - if (CurrentPsp == SYSTEM_PSP) return FALSE; - - /* Get a pointer to the handle table */ - PspBlock = SEGMENT_TO_PSP(CurrentPsp); - HandleTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr); - - /* Make sure the handle is open */ - if (HandleTable[DosHandle] == 0xFF) return FALSE; - - /* Make sure the SFT entry is valid */ - SftEntry = &DosSystemFileTable[HandleTable[DosHandle]]; - if (SftEntry->Type == DOS_SFT_ENTRY_NONE) return FALSE; - - /* Decrement the reference count of the SFT entry */ - SftEntry->RefCount--; - - /* Check if the reference count fell to zero */ - if (!SftEntry->RefCount) - { - switch (SftEntry->Type) - { - case DOS_SFT_ENTRY_WIN32: - { - /* Close the win32 handle and clear it */ - CloseHandle(SftEntry->Handle); - - break; - } - - case DOS_SFT_ENTRY_DEVICE: - { - PDOS_DEVICE_NODE Node = SftEntry->DeviceNode; - - /* Call the close routine, if it exists */ - if (Node->CloseRoutine) SftEntry->DeviceNode->CloseRoutine(SftEntry->DeviceNode); - - break; - } - - default: - { - /* Shouldn't happen */ - ASSERT(FALSE); - } - } - - /* Invalidate the SFT entry */ - SftEntry->Type = DOS_SFT_ENTRY_NONE; - } - - /* Clear the entry in the JFT */ - HandleTable[DosHandle] = 0xFF; - - return TRUE; -} - -static BOOLEAN DosDuplicateHandle(WORD OldHandle, WORD NewHandle) -{ - BYTE SftIndex; - PDOS_PSP PspBlock; - LPBYTE HandleTable; - - DPRINT("DosDuplicateHandle: OldHandle 0x%04X, NewHandle 0x%04X\n", - OldHandle, - NewHandle); - - /* The system PSP has no handle table */ - if (CurrentPsp == SYSTEM_PSP) return FALSE; - - /* Get a pointer to the handle table */ - PspBlock = SEGMENT_TO_PSP(CurrentPsp); - HandleTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr); - - /* Make sure the old handle is open */ - if (HandleTable[OldHandle] == 0xFF) return FALSE; - - /* Check if the new handle is open */ - if (HandleTable[NewHandle] != 0xFF) - { - /* Close it */ - DosCloseHandle(NewHandle); - } - - /* Increment the reference count of the SFT entry */ - SftIndex = HandleTable[OldHandle]; - DosSystemFileTable[SftIndex].RefCount++; - - /* Make the new handle point to that SFT entry */ - HandleTable[NewHandle] = SftIndex; - - /* Return success */ - return TRUE; -} - static BOOLEAN DosChangeDrive(BYTE Drive) { WCHAR DirectoryPath[DOS_CMDLINE_LENGTH]; @@ -675,25 +228,6 @@ static BOOLEAN DosControlBreak(VOID) /* PUBLIC FUNCTIONS ***********************************************************/ -PDOS_SFT_ENTRY DosGetSftEntry(WORD DosHandle) -{ - PDOS_PSP PspBlock; - LPBYTE HandleTable; - - /* The system PSP has no handle table */ - if (CurrentPsp == SYSTEM_PSP) return NULL; - - /* Get a pointer to the handle table */ - PspBlock = SEGMENT_TO_PSP(CurrentPsp); - HandleTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr); - - /* Make sure the handle is open */ - if (HandleTable[DosHandle] == 0xFF) return NULL; - - /* Return a pointer to the SFT entry */ - return &DosSystemFileTable[HandleTable[DosHandle]]; -} - VOID DosInitializePsp(WORD PspSegment, LPCSTR CommandLine, WORD ProgramSize, @@ -1279,110 +813,6 @@ Done: LOWORD(PspBlock->TerminateAddress)); } -BOOLEAN DosHandleIoctl(BYTE ControlCode, WORD FileHandle) -{ - PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(FileHandle); - PDOS_DEVICE_NODE Node = NULL; - - /* Make sure it exists */ - if (!SftEntry) - { - DosLastError = ERROR_FILE_NOT_FOUND; - return FALSE; - } - - if (SftEntry->Type == DOS_SFT_ENTRY_DEVICE) Node = SftEntry->DeviceNode; - - switch (ControlCode) - { - /* Get Device Information */ - case 0x00: - { - WORD InfoWord = 0; - - /* - * See Ralf Brown: http://www.ctyme.com/intr/rb-2820.htm - * for a list of possible flags. - */ - - if (Node) - { - /* Return the device attributes with bit 7 set */ - InfoWord = Node->DeviceAttributes | (1 << 7); - } - - setDX(InfoWord); - return TRUE; - } - - /* Set Device Information */ - case 0x01: - { - // TODO: NOT IMPLEMENTED - UNIMPLEMENTED; - - return FALSE; - } - - /* Read From Device I/O Control Channel */ - case 0x02: - { - WORD Length = getCX(); - - if (Node == NULL || !(Node->DeviceAttributes & DOS_DEVATTR_IOCTL)) - { - DosLastError = ERROR_INVALID_FUNCTION; - return FALSE; - } - - /* Do nothing if there is no IOCTL routine */ - if (!Node->IoctlReadRoutine) - { - setAX(0); - return TRUE; - } - - Node->IoctlReadRoutine(Node, MAKELONG(getDX(), getDS()), &Length); - - setAX(Length); - return TRUE; - } - - /* Write To Device I/O Control Channel */ - case 0x03: - { - WORD Length = getCX(); - - if (Node == NULL || !(Node->DeviceAttributes & DOS_DEVATTR_IOCTL)) - { - DosLastError = ERROR_INVALID_FUNCTION; - return FALSE; - } - - /* Do nothing if there is no IOCTL routine */ - if (!Node->IoctlWriteRoutine) - { - setAX(0); - return TRUE; - } - - Node->IoctlWriteRoutine(Node, MAKELONG(getDX(), getDS()), &Length); - - setAX(Length); - return TRUE; - } - - /* Unsupported control code */ - default: - { - DPRINT1("Unsupported IOCTL: 0x%02X\n", ControlCode); - - DosLastError = ERROR_INVALID_PARAMETER; - return FALSE; - } - } -} - VOID WINAPI DosInt20h(LPWORD Stack) { /* This is the exit interrupt */ @@ -2196,20 +1626,8 @@ VOID WINAPI DosInt21h(LPWORD Stack) case 0x3D: { WORD FileHandle; - WORD ErrorCode; LPCSTR FileName = (LPCSTR)SEG_OFF_TO_PTR(getDS(), getDX()); - PDOS_DEVICE_NODE Device = DosGetDevice(FileName); - - if (Device) - { - FileHandle = DosOpenDevice(Device); - ErrorCode = (FileHandle != INVALID_DOS_HANDLE) - ? ERROR_SUCCESS : ERROR_TOO_MANY_OPEN_FILES; - } - else - { - ErrorCode = DosOpenFile(&FileHandle, FileName, getAL()); - } + WORD ErrorCode = DosOpenFile(&FileHandle, FileName, getAL()); if (ErrorCode == ERROR_SUCCESS) { @@ -2391,9 +1809,12 @@ VOID WINAPI DosInt21h(LPWORD Stack) /* IOCTL */ case 0x44: { - if (DosHandleIoctl(getAL(), getBX())) + WORD Length = getCX(); + + if (DosDeviceIoControl(getBX(), getAL(), MAKELONG(getDX(), getDS()), &Length)) { Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; + setAX(Length); } else { @@ -2407,57 +1828,26 @@ VOID WINAPI DosInt21h(LPWORD Stack) /* Duplicate Handle */ case 0x45: { - WORD NewHandle; - PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(getBX()); - - if (SftEntry == NULL || SftEntry->Type == DOS_SFT_ENTRY_NONE) - { - /* The handle is invalid */ - Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; - setAX(ERROR_INVALID_HANDLE); - break; - } + WORD NewHandle = DosDuplicateHandle(getBX()); - /* Open a new handle to the same entry */ - switch (SftEntry->Type) + if (NewHandle != INVALID_DOS_HANDLE) { - case DOS_SFT_ENTRY_WIN32: - { - NewHandle = DosOpenHandle(SftEntry->Handle); - break; - } - - case DOS_SFT_ENTRY_DEVICE: - { - NewHandle = DosOpenDevice(SftEntry->DeviceNode); - break; - } - - default: - { - /* Shouldn't happen */ - ASSERT(FALSE); - } + setAX(NewHandle); + Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; } - - if (NewHandle == INVALID_DOS_HANDLE) + else { - /* Too many files open */ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; - setAX(ERROR_TOO_MANY_OPEN_FILES); - break; + setAX(DosLastError); } - /* Return the result */ - Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; - setAX(NewHandle); break; } /* Force Duplicate Handle */ case 0x46: { - if (DosDuplicateHandle(getBX(), getCX())) + if (DosForceDuplicateHandle(getBX(), getCX())) { Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; } @@ -2686,10 +2076,9 @@ VOID WINAPI DosInt21h(LPWORD Stack) */ /* Return the DOS "list of lists" in ES:BX */ - setES(0x0000); - setBX(0x0000); + setES(DOS_DATA_SEGMENT); + setBX(FIELD_OFFSET(DOS_SYSVARS, FirstDpb)); - DPRINT1("INT 21h, AH=52h: This application requires the internal DOS List of lists (SYSVARS). UNIMPLEMENTED\n"); break; } @@ -2850,44 +2239,30 @@ VOID WINAPI DosInt21h(LPWORD Stack) /* Lock/Unlock Region of File */ case 0x5C: { - PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(getBX()); - - if (SftEntry == NULL || SftEntry->Type != DOS_SFT_ENTRY_WIN32) - { - /* The handle is invalid */ - Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; - setAX(ERROR_INVALID_HANDLE); - break; - } - if (getAL() == 0x00) { /* Lock region of file */ - if (LockFile(SftEntry->Handle, - MAKELONG(getCX(), getDX()), 0, - MAKELONG(getSI(), getDI()), 0)) + if (DosLockFile(getBX(), MAKELONG(getCX(), getDX()), MAKELONG(getSI(), getDI()))) { Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; } else { Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; - setAX(GetLastError()); + setAX(DosLastError); } } else if (getAL() == 0x01) { /* Unlock region of file */ - if (UnlockFile(SftEntry->Handle, - MAKELONG(getCX(), getDX()), 0, - MAKELONG(getSI(), getDI()), 0)) + if (DosUnlockFile(getBX(), MAKELONG(getCX(), getDX()), MAKELONG(getSI(), getDI()))) { Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; } else { Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; - setAX(GetLastError()); + setAX(DosLastError); } } else @@ -3109,13 +2484,26 @@ VOID WINAPI DosInt2Fh(LPWORD Stack) BOOLEAN DosKRNLInitialize(VOID) { - #if 1 UCHAR i; CHAR CurrentDirectory[MAX_PATH]; CHAR DosDirectory[DOS_DIR_LENGTH]; LPSTR Path; + PDOS_SFT Sft; + + const BYTE NullDriverRoutine[] = { + /* Strategy routine entry */ + 0x26, // mov [Request.Status], DOS_DEVSTAT_DONE + 0xC7, + 0x47, + FIELD_OFFSET(DOS_REQUEST_HEADER, Status), + LOBYTE(DOS_DEVSTAT_DONE), + HIBYTE(DOS_DEVSTAT_DONE), + + /* Interrupt routine entry */ + 0xCB, // retf + }; FILE *Stream; WCHAR Buffer[256]; @@ -3169,11 +2557,34 @@ BOOLEAN DosKRNLInitialize(VOID) fclose(Stream); } + /* Initialize the list of lists */ + SysVars = (PDOS_SYSVARS)SEG_OFF_TO_PTR(DOS_DATA_SEGMENT, 0); + RtlZeroMemory(SysVars, sizeof(DOS_SYSVARS)); + SysVars->FirstMcb = FIRST_MCB_SEGMENT; + SysVars->FirstSft = MAKELONG(MASTER_SFT_OFFSET, DOS_DATA_SEGMENT); + + /* Initialize the NUL device driver */ + SysVars->NullDevice.Link = 0xFFFFFFFF; + SysVars->NullDevice.DeviceAttributes = DOS_DEVATTR_NUL | DOS_DEVATTR_CHARACTER; + SysVars->NullDevice.StrategyRoutine = FIELD_OFFSET(DOS_SYSVARS, NullDriverRoutine); + SysVars->NullDevice.InterruptRoutine = SysVars->NullDevice.StrategyRoutine + 6; + RtlFillMemory(SysVars->NullDevice.DeviceName, + sizeof(SysVars->NullDevice.DeviceName), + ' '); + RtlCopyMemory(SysVars->NullDevice.DeviceName, "NUL", strlen("NUL")); + RtlCopyMemory(SysVars->NullDriverRoutine, + NullDriverRoutine, + sizeof(NullDriverRoutine)); + /* Initialize the SFT */ - for (i = 0; i < DOS_SFT_SIZE; i++) + Sft = (PDOS_SFT)FAR_POINTER(SysVars->FirstSft); + Sft->Link = 0xFFFFFFFF; + Sft->NumDescriptors = DOS_SFT_SIZE; + + for (i = 0; i < Sft->NumDescriptors; i++) { - DosSystemFileTable[i].Type = DOS_SFT_ENTRY_NONE; - DosSystemFileTable[i].RefCount = 0; + /* Clear the file descriptor entry */ + RtlZeroMemory(&Sft->FileDescriptors[i], sizeof(DOS_FILE_DESCRIPTOR)); } #endif diff --git a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.h b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.h index df7a3af635a..c0d0551778d 100644 --- a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.h +++ b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.h @@ -30,6 +30,8 @@ #define USER_MEMORY_SIZE (0x9FFE - FIRST_MCB_SEGMENT) #define SYSTEM_PSP 0x08 #define SYSTEM_ENV_BLOCK 0x800 +#define DOS_DATA_SEGMENT 0xA0 +#define MASTER_SFT_OFFSET 0x100 #define INVALID_DOS_HANDLE 0xFFFF #define DOS_INPUT_HANDLE 0 @@ -48,7 +50,6 @@ #define NUM_DRIVES ('Z' - 'A' + 1) #define DOS_CHAR_ATTRIBUTE 0x07 #define DOS_PROGRAM_NAME_TAG 0x0001 -#define DEFAULT_JFT_SIZE 20 /* 16 MB of EMS memory */ #define EMS_TOTAL_PAGES 1024 @@ -60,25 +61,6 @@ typedef enum DOS_LOAD_OVERLAY = 0x03 } DOS_EXEC_TYPE; -typedef enum -{ - DOS_SFT_ENTRY_NONE, - DOS_SFT_ENTRY_WIN32, - DOS_SFT_ENTRY_DEVICE -} DOS_SFT_ENTRY_TYPE; - -typedef struct _DOS_SFT_ENTRY -{ - DOS_SFT_ENTRY_TYPE Type; - WORD RefCount; - - union - { - HANDLE Handle; - PDOS_DEVICE_NODE DeviceNode; - }; -} DOS_SFT_ENTRY, *PDOS_SFT_ENTRY; - #pragma pack(push, 1) typedef struct _DOS_FCB @@ -96,6 +78,30 @@ typedef struct _DOS_FCB BYTE RecordNumber[3]; } DOS_FCB, *PDOS_FCB; +typedef struct _DOS_SYSVARS +{ + DWORD OemHandler; + WORD Int21hReturn; + WORD ShareRetryCount; + WORD ShareRetryDelay; + DWORD DiskBuffer; + WORD UnreadConInput; + WORD FirstMcb; + + /* This is where the SYSVARS really start */ + DWORD FirstDpb; + DWORD FirstSft; + DWORD ActiveClock; + DWORD ActiveCon; + BYTE Reserved0[6]; + DWORD CurrentDirs; + BYTE Reserved1[6]; + BYTE NumBlockDevices; + BYTE NumLocalDrives; + DOS_DRIVER NullDevice; + BYTE NullDriverRoutine[7]; +} DOS_SYSVARS, *PDOS_SYSVARS; + typedef struct _DOS_PSP { BYTE Exit[2]; @@ -128,15 +134,6 @@ typedef struct _DOS_INPUT_BUFFER CHAR Buffer[ANYSIZE_ARRAY]; } DOS_INPUT_BUFFER, *PDOS_INPUT_BUFFER; -typedef struct _DOS_DRIVER_HEADER -{ - DWORD NextDriver; - WORD Attributes; - WORD StrategyEntry; - WORD InterruptEntry; - CHAR DeviceName[8]; -} DOS_DRIVER_HEADER, *PDOS_DRIVER_HEADER; - typedef struct _DOS_FIND_FILE_BLOCK { CHAR DriveLetter; @@ -181,6 +178,7 @@ typedef struct _DOS_COUNTRY_CODE_BUFFER extern BOOLEAN DoEcho; extern WORD CurrentPsp; extern WORD DosLastError; +extern PDOS_SYSVARS SysVars; /* FUNCTIONS ******************************************************************/ @@ -208,35 +206,6 @@ VOID ConDrvCleanup(VOID); * DOS Kernel Functions * See dos.c */ -WORD DosOpenHandle(HANDLE Handle); -PDOS_SFT_ENTRY DosGetSftEntry(WORD DosHandle); - -WORD DosCreateFileEx(LPWORD Handle, - LPWORD CreationStatus, - LPCSTR FilePath, - BYTE AccessShareModes, - WORD CreateActionFlags, - WORD Attributes); -WORD DosCreateFile(LPWORD Handle, - LPCSTR FilePath, - DWORD CreationDisposition, - WORD Attributes); -WORD DosOpenFile(LPWORD Handle, - LPCSTR FilePath, - BYTE AccessShareModes); -WORD DosReadFile(WORD FileHandle, - DWORD Buffer, - WORD Count, - LPWORD BytesRead); -WORD DosWriteFile(WORD FileHandle, - DWORD Buffer, - WORD Count, - LPWORD BytesWritten); -WORD DosSeekFile(WORD FileHandle, - LONG Offset, - BYTE Origin, - LPDWORD NewOffset); -BOOL DosFlushFileBuffers(WORD FileHandle); VOID DosInitializePsp( WORD PspSegment, diff --git a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.c b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.c index fd11e855833..13a8df18674 100644 --- a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.c +++ b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.c @@ -17,11 +17,125 @@ #include "dos.h" #include "dos/dem.h" +#include "dosfiles.h" +#include "handle.h" #include "bios/bios.h" /* PUBLIC FUNCTIONS ***********************************************************/ +BYTE DosFindFreeDescriptor(VOID) +{ + UINT i; + BYTE Count = 0; + DWORD CurrentSft = SysVars->FirstSft; + + while (LOWORD(CurrentSft) != 0xFFFF) + { + PDOS_SFT Sft = (PDOS_SFT)FAR_POINTER(CurrentSft); + + for (i = 0; i < Sft->NumDescriptors; i++) + { + if (Sft->FileDescriptors[i].RefCount == 0) return Count; + Count++; + } + + /* Go to the next table */ + CurrentSft = Sft->Link; + } + + /* Invalid ID */ + return 0xFF; +} + +BYTE DosFindWin32Descriptor(HANDLE Win32Handle) +{ + UINT i; + BYTE Count = 0; + DWORD CurrentSft = SysVars->FirstSft; + + while (LOWORD(CurrentSft) != 0xFFFF) + { + PDOS_SFT Sft = (PDOS_SFT)FAR_POINTER(CurrentSft); + + for (i = 0; i < Sft->NumDescriptors; i++) + { + if ((Sft->FileDescriptors[i].RefCount > 0) + && !(Sft->FileDescriptors[i].DeviceInfo & (1 << 7)) + && (Sft->FileDescriptors[i].Win32Handle == Win32Handle)) + { + return Count; + } + + Count++; + } + + /* Go to the next table */ + CurrentSft = Sft->Link; + } + + /* Invalid ID */ + return 0xFF; +} + +BYTE DosFindDeviceDescriptor(DWORD DevicePointer) +{ + UINT i; + BYTE Count = 0; + DWORD CurrentSft = SysVars->FirstSft; + + while (LOWORD(CurrentSft) != 0xFFFF) + { + PDOS_SFT Sft = (PDOS_SFT)FAR_POINTER(CurrentSft); + + for (i = 0; i < Sft->NumDescriptors; i++) + { + if ((Sft->FileDescriptors[i].RefCount > 0) + && (Sft->FileDescriptors[i].DeviceInfo & (1 << 7)) + && (Sft->FileDescriptors[i].DevicePointer == DevicePointer)) + { + return Count; + } + + Count++; + } + + /* Go to the next table */ + CurrentSft = Sft->Link; + } + + /* Invalid ID */ + return 0xFF; +} + +PDOS_FILE_DESCRIPTOR DosGetFileDescriptor(BYTE Id) +{ + DWORD CurrentSft = SysVars->FirstSft; + + while (LOWORD(CurrentSft) != 0xFFFF) + { + PDOS_SFT Sft = (PDOS_SFT)FAR_POINTER(CurrentSft); + + /* Return it if it's in this table */ + if (Id <= Sft->NumDescriptors) return &Sft->FileDescriptors[Id]; + + /* Go to the next table */ + Id -= Sft->NumDescriptors; + CurrentSft = Sft->Link; + } + + /* Invalid ID */ + return NULL; +} + +PDOS_FILE_DESCRIPTOR DosGetHandleFileDescriptor(WORD DosHandle) +{ + BYTE DescriptorId = DosQueryHandle(DosHandle); + if (DescriptorId == 0xFF) return NULL; + + return DosGetFileDescriptor(DescriptorId); +} + WORD DosCreateFileEx(LPWORD Handle, LPWORD CreationStatus, LPCSTR FilePath, @@ -37,6 +151,8 @@ WORD DosCreateFileEx(LPWORD Handle, DWORD CreationDisposition = 0; BOOL InheritableFile = FALSE; SECURITY_ATTRIBUTES SecurityAttributes; + BYTE DescriptorId; + PDOS_FILE_DESCRIPTOR Descriptor; DPRINT1("DosCreateFileEx: FilePath \"%s\", AccessShareModes 0x%04X, CreateActionFlags 0x%04X, Attributes 0x%04X\n", FilePath, AccessShareModes, CreateActionFlags, Attributes); @@ -228,8 +344,26 @@ WORD DosCreateFileEx(LPWORD Handle, } } + DescriptorId = DosFindFreeDescriptor(); + if (DescriptorId == 0xFF) + { + /* Close the file and return the error code */ + CloseHandle(FileHandle); + return ERROR_TOO_MANY_OPEN_FILES; + } + + /* Set up the new descriptor */ + Descriptor = DosGetFileDescriptor(DescriptorId); + RtlZeroMemory(Descriptor, sizeof(*Descriptor)); + + Descriptor->OpenMode = AccessShareModes; + Descriptor->Attributes = LOBYTE(GetFileAttributesA(FilePath)); + Descriptor->Size = GetFileSize(FileHandle, NULL); + Descriptor->OwnerPsp = CurrentPsp; + Descriptor->Win32Handle = FileHandle; + /* Open the DOS handle */ - DosHandle = DosOpenHandle(FileHandle); + DosHandle = DosOpenHandle(DescriptorId); if (DosHandle == INVALID_DOS_HANDLE) { /* Close the file and return the error code */ @@ -249,6 +383,8 @@ WORD DosCreateFile(LPWORD Handle, { HANDLE FileHandle; WORD DosHandle; + BYTE DescriptorId; + PDOS_FILE_DESCRIPTOR Descriptor; DPRINT("DosCreateFile: FilePath \"%s\", CreationDisposition 0x%04X, Attributes 0x%04X\n", FilePath, CreationDisposition, Attributes); @@ -267,8 +403,25 @@ WORD DosCreateFile(LPWORD Handle, return (WORD)GetLastError(); } + DescriptorId = DosFindFreeDescriptor(); + if (DescriptorId == 0xFF) + { + /* Close the file and return the error code */ + CloseHandle(FileHandle); + return ERROR_TOO_MANY_OPEN_FILES; + } + + /* Set up the new descriptor */ + Descriptor = DosGetFileDescriptor(DescriptorId); + RtlZeroMemory(Descriptor, sizeof(*Descriptor)); + + Descriptor->Attributes = LOBYTE(GetFileAttributesA(FilePath)); + Descriptor->Size = GetFileSize(FileHandle, NULL); + Descriptor->OwnerPsp = CurrentPsp; + Descriptor->Win32Handle = FileHandle; + /* Open the DOS handle */ - DosHandle = DosOpenHandle(FileHandle); + DosHandle = DosOpenHandle(DescriptorId); if (DosHandle == INVALID_DOS_HANDLE) { /* Close the file and return the error code */ @@ -285,12 +438,11 @@ WORD DosOpenFile(LPWORD Handle, LPCSTR FilePath, BYTE AccessShareModes) { - HANDLE FileHandle; - ACCESS_MASK AccessMode = 0; - DWORD ShareMode = 0; - BOOL InheritableFile = FALSE; - SECURITY_ATTRIBUTES SecurityAttributes; + HANDLE FileHandle = NULL; + PDOS_DEVICE_NODE Node; WORD DosHandle; + BYTE DescriptorId; + PDOS_FILE_DESCRIPTOR Descriptor; DPRINT("DosOpenFile: FilePath \"%s\", AccessShareModes 0x%04X\n", FilePath, AccessShareModes); @@ -300,86 +452,125 @@ WORD DosOpenFile(LPWORD Handle, // explains what those AccessShareModes are (see the uStyle flag). // - /* Parse the access mode */ - switch (AccessShareModes & 0x03) + Node = DosGetDevice(FilePath); + if (Node != NULL) { - /* Read-only */ - case 0: - AccessMode = GENERIC_READ; - break; - - /* Write only */ - case 1: - AccessMode = GENERIC_WRITE; - break; - - /* Read and write */ - case 2: - AccessMode = GENERIC_READ | GENERIC_WRITE; - break; - - /* Invalid */ - default: - return ERROR_INVALID_PARAMETER; + if (Node->OpenRoutine) Node->OpenRoutine(Node); } - - /* Parse the share mode */ - switch ((AccessShareModes >> 4) & 0x07) + else { - /* Compatibility mode */ - case 0: - ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; - break; - - /* No sharing "DenyAll" */ - case 1: - ShareMode = 0; - break; + ACCESS_MASK AccessMode = 0; + DWORD ShareMode = 0; + BOOL InheritableFile = FALSE; + SECURITY_ATTRIBUTES SecurityAttributes; - /* No write share "DenyWrite" */ - case 2: - ShareMode = FILE_SHARE_READ; - break; - - /* No read share "DenyRead" */ - case 3: - ShareMode = FILE_SHARE_WRITE; - break; + /* Parse the access mode */ + switch (AccessShareModes & 0x03) + { + /* Read-only */ + case 0: + AccessMode = GENERIC_READ; + break; + + /* Write only */ + case 1: + AccessMode = GENERIC_WRITE; + break; + + /* Read and write */ + case 2: + AccessMode = GENERIC_READ | GENERIC_WRITE; + break; + + /* Invalid */ + default: + return ERROR_INVALID_PARAMETER; + } - /* Full share "DenyNone" */ - case 4: - ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; - break; + /* Parse the share mode */ + switch ((AccessShareModes >> 4) & 0x07) + { + /* Compatibility mode */ + case 0: + ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + break; + + /* No sharing "DenyAll" */ + case 1: + ShareMode = 0; + break; + + /* No write share "DenyWrite" */ + case 2: + ShareMode = FILE_SHARE_READ; + break; + + /* No read share "DenyRead" */ + case 3: + ShareMode = FILE_SHARE_WRITE; + break; + + /* Full share "DenyNone" */ + case 4: + ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; + break; + + /* Invalid */ + default: + return ERROR_INVALID_PARAMETER; + } - /* Invalid */ - default: - return ERROR_INVALID_PARAMETER; + /* Check for inheritance */ + InheritableFile = ((AccessShareModes & 0x80) == 0); + + /* Assign default security attributes to the file, and set the inheritance flag */ + SecurityAttributes.nLength = sizeof(SecurityAttributes); + SecurityAttributes.lpSecurityDescriptor = NULL; + SecurityAttributes.bInheritHandle = InheritableFile; + + /* Open the file */ + FileHandle = CreateFileA(FilePath, + AccessMode, + ShareMode, + &SecurityAttributes, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (FileHandle == INVALID_HANDLE_VALUE) + { + /* Return the error code */ + return (WORD)GetLastError(); + } + } + + DescriptorId = DosFindFreeDescriptor(); + if (DescriptorId == 0xFF) + { + /* Close the file and return the error code */ + CloseHandle(FileHandle); + return ERROR_TOO_MANY_OPEN_FILES; } - /* Check for inheritance */ - InheritableFile = ((AccessShareModes & 0x80) == 0); - - /* Assign default security attributes to the file, and set the inheritance flag */ - SecurityAttributes.nLength = sizeof(SecurityAttributes); - SecurityAttributes.lpSecurityDescriptor = NULL; - SecurityAttributes.bInheritHandle = InheritableFile; + /* Set up the new descriptor */ + Descriptor = DosGetFileDescriptor(DescriptorId); + RtlZeroMemory(Descriptor, sizeof(*Descriptor)); - /* Open the file */ - FileHandle = CreateFileA(FilePath, - AccessMode, - ShareMode, - &SecurityAttributes, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); - if (FileHandle == INVALID_HANDLE_VALUE) + if (Node != NULL) { - /* Return the error code */ - return (WORD)GetLastError(); + Descriptor->DevicePointer = Node->Driver; + Descriptor->DeviceInfo = Node->DeviceAttributes | (1 << 7); + } + else + { + Descriptor->OpenMode = AccessShareModes; + Descriptor->Attributes = LOBYTE(GetFileAttributesA(FilePath)); + Descriptor->Size = GetFileSize(FileHandle, NULL); + Descriptor->OwnerPsp = CurrentPsp; + Descriptor->Win32Handle = FileHandle; } /* Open the DOS handle */ - DosHandle = DosOpenHandle(FileHandle); + DosHandle = DosOpenHandle(DescriptorId); if (DosHandle == INVALID_DOS_HANDLE) { /* Close the file and return the error code */ @@ -398,27 +589,39 @@ WORD DosReadFile(WORD FileHandle, LPWORD BytesRead) { WORD Result = ERROR_SUCCESS; - PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(FileHandle); + PDOS_FILE_DESCRIPTOR Descriptor = DosGetHandleFileDescriptor(FileHandle); DPRINT("DosReadFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle, Count); - if (SftEntry == NULL) + if (Descriptor == NULL) { /* Invalid handle */ return ERROR_INVALID_HANDLE; } - if (SftEntry->Type == DOS_SFT_ENTRY_WIN32) + if (Descriptor->DeviceInfo & (1 << 7)) + { + PDOS_DEVICE_NODE Node = DosGetDriverNode(Descriptor->DevicePointer); + if (!Node->ReadRoutine) return ERROR_INVALID_FUNCTION; + + /* Read the device */ + Node->ReadRoutine(Node, Buffer, &Count); + *BytesRead = Count; + } + else { DWORD BytesRead32 = 0; LPVOID LocalBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Count); ASSERT(LocalBuffer != NULL); /* Read the file */ - if (ReadFile(SftEntry->Handle, LocalBuffer, Count, &BytesRead32, NULL)) + if (ReadFile(Descriptor->Win32Handle, LocalBuffer, Count, &BytesRead32, NULL)) { /* Write to the memory */ MemWrite(TO_LINEAR(HIWORD(Buffer), LOWORD(Buffer)), LocalBuffer, LOWORD(BytesRead32)); + + /* Update the position */ + Descriptor->Position += BytesRead32; } else { @@ -430,19 +633,6 @@ WORD DosReadFile(WORD FileHandle, *BytesRead = LOWORD(BytesRead32); RtlFreeHeap(RtlGetProcessHeap(), 0, LocalBuffer); } - else if (SftEntry->Type == DOS_SFT_ENTRY_DEVICE) - { - if (!SftEntry->DeviceNode->ReadRoutine) return ERROR_INVALID_FUNCTION; - - /* Read the device */ - SftEntry->DeviceNode->ReadRoutine(SftEntry->DeviceNode, Buffer, &Count); - *BytesRead = Count; - } - else - { - /* Invalid handle */ - return ERROR_INVALID_HANDLE; - } /* Return the error code */ return Result; @@ -454,17 +644,26 @@ WORD DosWriteFile(WORD FileHandle, LPWORD BytesWritten) { WORD Result = ERROR_SUCCESS; - PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(FileHandle); + PDOS_FILE_DESCRIPTOR Descriptor = DosGetHandleFileDescriptor(FileHandle); DPRINT("DosWriteFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle, Count); - if (SftEntry == NULL) + if (Descriptor == NULL) { /* Invalid handle */ return ERROR_INVALID_HANDLE; } - if (SftEntry->Type == DOS_SFT_ENTRY_WIN32) + if (Descriptor->DeviceInfo & (1 << 7)) + { + PDOS_DEVICE_NODE Node = DosGetDriverNode(Descriptor->DevicePointer); + if (!Node->WriteRoutine) return ERROR_INVALID_FUNCTION; + + /* Read the device */ + Node->WriteRoutine(Node, Buffer, &Count); + *BytesWritten = Count; + } + else { DWORD BytesWritten32 = 0; LPVOID LocalBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Count); @@ -474,7 +673,13 @@ WORD DosWriteFile(WORD FileHandle, MemRead(TO_LINEAR(HIWORD(Buffer), LOWORD(Buffer)), LocalBuffer, Count); /* Write the file */ - if (!WriteFile(SftEntry->Handle, LocalBuffer, Count, &BytesWritten32, NULL)) + if (WriteFile(Descriptor->Win32Handle, LocalBuffer, Count, &BytesWritten32, NULL)) + { + /* Update the position and size */ + Descriptor->Position += BytesWritten32; + if (Descriptor->Position > Descriptor->Size) Descriptor->Size = Descriptor->Position; + } + else { /* Store the error code */ Result = (WORD)GetLastError(); @@ -484,19 +689,6 @@ WORD DosWriteFile(WORD FileHandle, *BytesWritten = LOWORD(BytesWritten32); RtlFreeHeap(RtlGetProcessHeap(), 0, LocalBuffer); } - else if (SftEntry->Type == DOS_SFT_ENTRY_DEVICE) - { - if (!SftEntry->DeviceNode->WriteRoutine) return ERROR_INVALID_FUNCTION; - - /* Read the device */ - SftEntry->DeviceNode->WriteRoutine(SftEntry->DeviceNode, Buffer, &Count); - *BytesWritten = Count; - } - else - { - /* Invalid handle */ - return ERROR_INVALID_HANDLE; - } /* Return the error code */ return Result; @@ -509,25 +701,20 @@ WORD DosSeekFile(WORD FileHandle, { WORD Result = ERROR_SUCCESS; DWORD FilePointer; - PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(FileHandle); + PDOS_FILE_DESCRIPTOR Descriptor = DosGetHandleFileDescriptor(FileHandle); DPRINT("DosSeekFile: FileHandle 0x%04X, Offset 0x%08X, Origin 0x%02X\n", FileHandle, Offset, Origin); - if (SftEntry == NULL) + if (Descriptor == NULL) { /* Invalid handle */ return ERROR_INVALID_HANDLE; } - if (SftEntry->Type == DOS_SFT_ENTRY_NONE) - { - /* Invalid handle */ - return ERROR_INVALID_HANDLE; - } - else if (SftEntry->Type == DOS_SFT_ENTRY_DEVICE) + if (Descriptor->DeviceInfo & (1 << 7)) { /* For character devices, always return success */ return ERROR_SUCCESS; @@ -539,7 +726,7 @@ WORD DosSeekFile(WORD FileHandle, return ERROR_INVALID_FUNCTION; } - FilePointer = SetFilePointer(SftEntry->Handle, Offset, NULL, Origin); + FilePointer = SetFilePointer(Descriptor->Win32Handle, Offset, NULL, Origin); /* Check if there's a possibility the operation failed */ if (FilePointer == INVALID_SET_FILE_POINTER) @@ -554,6 +741,9 @@ WORD DosSeekFile(WORD FileHandle, return Result; } + /* Update the descriptor */ + Descriptor->Position = FilePointer; + /* Return the file pointer, if requested */ if (NewOffset) *NewOffset = FilePointer; @@ -563,38 +753,164 @@ WORD DosSeekFile(WORD FileHandle, BOOL DosFlushFileBuffers(WORD FileHandle) { - PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(FileHandle); + PDOS_FILE_DESCRIPTOR Descriptor = DosGetHandleFileDescriptor(FileHandle); - if (SftEntry == NULL) + if (Descriptor == NULL) { /* Invalid handle */ - return ERROR_INVALID_HANDLE; + DosLastError = ERROR_INVALID_HANDLE; + return FALSE; + } + + if (Descriptor->DeviceInfo & (1 << 7)) + { + PDOS_DEVICE_NODE Node = DosGetDriverNode(Descriptor->DevicePointer); + + if (Node->FlushInputRoutine) Node->FlushInputRoutine(Node); + if (Node->FlushOutputRoutine) Node->FlushOutputRoutine(Node); + + return TRUE; + } + else + { + return FlushFileBuffers(Descriptor->Win32Handle); + } +} + +BOOLEAN DosLockFile(WORD DosHandle, DWORD Offset, DWORD Size) +{ + PDOS_FILE_DESCRIPTOR Descriptor = DosGetHandleFileDescriptor(DosHandle); + + if (Descriptor == NULL) + { + /* Invalid handle */ + DosLastError = ERROR_INVALID_HANDLE; + return FALSE; + } + + /* Always succeed for character devices */ + if (Descriptor->DeviceInfo & (1 << 7)) return TRUE; + + if (!LockFile(Descriptor->Win32Handle, Offset, 0, Size, 0)) + { + DosLastError = GetLastError(); + return FALSE; + } + + return TRUE; +} + +BOOLEAN DosUnlockFile(WORD DosHandle, DWORD Offset, DWORD Size) +{ + PDOS_FILE_DESCRIPTOR Descriptor = DosGetHandleFileDescriptor(DosHandle); + + if (Descriptor == NULL) + { + /* Invalid handle */ + DosLastError = ERROR_INVALID_HANDLE; + return FALSE; + } + + /* Always succeed for character devices */ + if (Descriptor->DeviceInfo & (1 << 7)) return TRUE; + + if (!UnlockFile(Descriptor->Win32Handle, Offset, 0, Size, 0)) + { + DosLastError = GetLastError(); + return FALSE; + } + + return TRUE; +} + +BOOLEAN DosDeviceIoControl(WORD FileHandle, BYTE ControlCode, DWORD Buffer, PWORD Length) +{ + PDOS_FILE_DESCRIPTOR Descriptor = DosGetHandleFileDescriptor(FileHandle); + PDOS_DEVICE_NODE Node = NULL; + + if (!Descriptor) + { + DosLastError = ERROR_INVALID_HANDLE; + return FALSE; + } + + if (Descriptor->DeviceInfo & (1 << 7)) + { + Node = DosGetDriverNode(Descriptor->DevicePointer); } - switch (SftEntry->Type) + switch (ControlCode) { - case DOS_SFT_ENTRY_WIN32: + /* Get Device Information */ + case 0x00: { - return FlushFileBuffers(SftEntry->Handle); + /* + * See Ralf Brown: http://www.ctyme.com/intr/rb-2820.htm + * for a list of possible flags. + */ + setDX(Descriptor->DeviceInfo); + return TRUE; } - case DOS_SFT_ENTRY_DEVICE: + /* Set Device Information */ + case 0x01: { - if (SftEntry->DeviceNode->FlushInputRoutine) - SftEntry->DeviceNode->FlushInputRoutine(SftEntry->DeviceNode); + // TODO: NOT IMPLEMENTED + UNIMPLEMENTED; - if (SftEntry->DeviceNode->FlushOutputRoutine) - SftEntry->DeviceNode->FlushOutputRoutine(SftEntry->DeviceNode); + return FALSE; + } + /* Read From Device I/O Control Channel */ + case 0x02: + { + if (Node == NULL || !(Node->DeviceAttributes & DOS_DEVATTR_IOCTL)) + { + DosLastError = ERROR_INVALID_FUNCTION; + return FALSE; + } + + /* Do nothing if there is no IOCTL routine */ + if (!Node->IoctlReadRoutine) + { + *Length = 0; + return TRUE; + } + + Node->IoctlReadRoutine(Node, Buffer, Length); return TRUE; } - + + /* Write To Device I/O Control Channel */ + case 0x03: + { + if (Node == NULL || !(Node->DeviceAttributes & DOS_DEVATTR_IOCTL)) + { + DosLastError = ERROR_INVALID_FUNCTION; + return FALSE; + } + + /* Do nothing if there is no IOCTL routine */ + if (!Node->IoctlWriteRoutine) + { + *Length = 0; + return TRUE; + } + + Node->IoctlWriteRoutine(Node, Buffer, Length); + return TRUE; + } + + /* Unsupported control code */ default: { - /* Invalid handle */ + DPRINT1("Unsupported IOCTL: 0x%02X\n", ControlCode); + + DosLastError = ERROR_INVALID_PARAMETER; return FALSE; } } } + /* EOF */ diff --git a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.h b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.h new file mode 100644 index 00000000000..6e31cfe5a38 --- /dev/null +++ b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.h @@ -0,0 +1,108 @@ +/* + * COPYRIGHT: GPL - See COPYING in the top level directory + * PROJECT: ReactOS Virtual DOS Machine + * FILE: dos/dos32krnl/dosfiles.h + * PURPOSE: DOS32 Files Support + * PROGRAMMERS: Aleksandar Andrejevic + */ + +/* DEFINES ********************************************************************/ + +#pragma pack(push, 1) + +typedef struct _DOS_FILE_DESCRIPTOR +{ + WORD RefCount; + WORD OpenMode; + BYTE Attributes; + WORD DeviceInfo; + DWORD DevicePointer; + WORD Time; + WORD Date; + DWORD Size; + DWORD Position; + DWORD Reserved; + WORD OwnerPsp; + HANDLE Win32Handle; + BYTE Padding[0x1E - sizeof(HANDLE)]; +} DOS_FILE_DESCRIPTOR, *PDOS_FILE_DESCRIPTOR; + +C_ASSERT(sizeof(DOS_FILE_DESCRIPTOR) == 0x3B); + +typedef struct _DOS_SFT +{ + DWORD Link; + WORD NumDescriptors; + DOS_FILE_DESCRIPTOR FileDescriptors[ANYSIZE_ARRAY]; +} DOS_SFT, *PDOS_SFT; + +/* FUNCTIONS ******************************************************************/ + +BYTE DosFindFreeDescriptor(VOID); +BYTE DosFindWin32Descriptor(HANDLE Win32Handle); +BYTE DosFindDeviceDescriptor(DWORD DevicePointer); +PDOS_FILE_DESCRIPTOR DosGetFileDescriptor(BYTE Id); +PDOS_FILE_DESCRIPTOR DosGetHandleFileDescriptor(WORD DosHandle); + +WORD DosCreateFileEx +( + LPWORD Handle, + LPWORD CreationStatus, + LPCSTR FilePath, + BYTE AccessShareModes, + WORD CreateActionFlags, + WORD Attributes +); + +WORD DosCreateFile +( + LPWORD Handle, + LPCSTR FilePath, + DWORD CreationDisposition, + WORD Attributes +); + +WORD DosOpenFile +( + LPWORD Handle, + LPCSTR FilePath, + BYTE AccessShareModes +); + +WORD DosReadFile +( + WORD FileHandle, + DWORD Buffer, + WORD Count, + LPWORD BytesRead +); + +WORD DosWriteFile +( + WORD FileHandle, + DWORD Buffer, + WORD Count, + LPWORD BytesWritten +); + +WORD DosSeekFile +( + WORD FileHandle, + LONG Offset, + BYTE Origin, + LPDWORD NewOffset +); + +BOOL DosFlushFileBuffers(WORD FileHandle); +BOOLEAN DosLockFile(WORD DosHandle, DWORD Offset, DWORD Size); +BOOLEAN DosUnlockFile(WORD DosHandle, DWORD Offset, DWORD Size); + +BOOLEAN DosDeviceIoControl +( + WORD FileHandle, + BYTE ControlCode, + DWORD Buffer, + PWORD Length +); + +#pragma pack(pop) diff --git a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/handle.c b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/handle.c new file mode 100644 index 00000000000..2f64ca83c01 --- /dev/null +++ b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/handle.c @@ -0,0 +1,378 @@ +/* + * COPYRIGHT: GPLv2+ - See COPYING in the top level directory + * PROJECT: ReactOS Virtual DOS Machine + * FILE: dos/dos32krnl/handle.c + * PURPOSE: DOS32 Handles (Job File Table) + * PROGRAMMERS: Aleksandar Andrejevic + */ + +/* INCLUDES *******************************************************************/ + +#define NDEBUG + +#include "ntvdm.h" +#include "emulator.h" + +#include "dos.h" +#include "dos/dem.h" +#include "dosfiles.h" +#include "handle.h" +#include "memory.h" + +/* PRIVATE FUNCTIONS **********************************************************/ + +/* Taken from base/shell/cmd/console.c */ +static BOOL IsConsoleHandle(HANDLE hHandle) +{ + DWORD dwMode; + + /* Check whether the handle may be that of a console... */ + if ((GetFileType(hHandle) & FILE_TYPE_CHAR) == 0) return FALSE; + + /* + * It may be. Perform another test... The idea comes from the + * MSDN description of the WriteConsole API: + * + * "WriteConsole fails if it is used with a standard handle + * that is redirected to a file. If an application processes + * multilingual output that can be redirected, determine whether + * the output handle is a console handle (one method is to call + * the GetConsoleMode function and check whether it succeeds). + * If the handle is a console handle, call WriteConsole. If the + * handle is not a console handle, the output is redirected and + * you should call WriteFile to perform the I/O." + */ + return GetConsoleMode(hHandle, &dwMode); +} + +/* PUBLIC FUNCTIONS ***********************************************************/ + +VOID DosCopyHandleTable(LPBYTE DestinationTable) +{ + UINT i; + PDOS_PSP PspBlock; + LPBYTE SourceTable; + PDOS_FILE_DESCRIPTOR Descriptor; + + /* Clear the table first */ + for (i = 0; i < DEFAULT_JFT_SIZE; i++) DestinationTable[i] = 0xFF; + + /* Check if this is the initial process */ + if (CurrentPsp == SYSTEM_PSP) + { + BYTE DescriptorId; + HANDLE StandardHandles[3]; + + /* Get the native standard handles */ + StandardHandles[0] = GetStdHandle(STD_INPUT_HANDLE); + StandardHandles[1] = GetStdHandle(STD_OUTPUT_HANDLE); + StandardHandles[2] = GetStdHandle(STD_ERROR_HANDLE); + + for (i = 0; i < 3; i++) + { + /* Find the corresponding SFT entry */ + if (IsConsoleHandle(StandardHandles[i])) + { + DescriptorId = DosFindDeviceDescriptor(SysVars->ActiveCon); + } + else + { + DescriptorId = DosFindWin32Descriptor(StandardHandles[i]); + } + + if (DescriptorId != 0xFF) + { + Descriptor = DosGetFileDescriptor(DescriptorId); + } + else + { + /* Create a new SFT entry for it */ + DescriptorId = DosFindFreeDescriptor(); + if (DescriptorId == 0xFF) + { + DPRINT1("Cannot create standard handle %d, the SFT is full!\n", i); + continue; + } + + Descriptor = DosGetFileDescriptor(DescriptorId); + ASSERT(Descriptor != NULL); + RtlZeroMemory(Descriptor, sizeof(*Descriptor)); + + if (IsConsoleHandle(StandardHandles[i])) + { + PDOS_DEVICE_NODE Node = DosGetDriverNode(SysVars->ActiveCon); + + Descriptor->DeviceInfo = 1 << 7; + Descriptor->DevicePointer = SysVars->ActiveCon; + + /* Call the open routine */ + if (Node->OpenRoutine) Node->OpenRoutine(Node); + } + else + { + Descriptor->Win32Handle = StandardHandles[i]; + } + } + + Descriptor->RefCount++; + DestinationTable[i] = DescriptorId; + } + } + else + { + /* Get the parent PSP block and handle table */ + PspBlock = SEGMENT_TO_PSP(CurrentPsp); + SourceTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr); + + /* Copy the first 20 handles into the new table */ + for (i = 0; i < DEFAULT_JFT_SIZE; i++) + { + Descriptor = DosGetFileDescriptor(SourceTable[i]); + DestinationTable[i] = SourceTable[i]; + + /* Increase the reference count */ + Descriptor->RefCount++; + } + } +} + +BOOLEAN DosResizeHandleTable(WORD NewSize) +{ + PDOS_PSP PspBlock; + LPBYTE HandleTable; + WORD Segment; + + /* Get the PSP block */ + PspBlock = SEGMENT_TO_PSP(CurrentPsp); + + if (NewSize == PspBlock->HandleTableSize) + { + /* No change */ + return TRUE; + } + + if (PspBlock->HandleTableSize > DEFAULT_JFT_SIZE) + { + /* Get the segment of the current table */ + Segment = (LOWORD(PspBlock->HandleTablePtr) >> 4) + HIWORD(PspBlock->HandleTablePtr); + + if (NewSize <= DEFAULT_JFT_SIZE) + { + /* Get the current handle table */ + HandleTable = FAR_POINTER(PspBlock->HandleTablePtr); + + /* Copy it to the PSP */ + RtlCopyMemory(PspBlock->HandleTable, HandleTable, NewSize); + + /* Free the memory */ + DosFreeMemory(Segment); + + /* Update the handle table pointer and size */ + PspBlock->HandleTableSize = NewSize; + PspBlock->HandleTablePtr = MAKELONG(0x18, CurrentPsp); + } + else + { + /* Resize the memory */ + if (!DosResizeMemory(Segment, NewSize, NULL)) + { + /* Unable to resize, try allocating it somewhere else */ + Segment = DosAllocateMemory(NewSize, NULL); + if (Segment == 0) return FALSE; + + /* Get the new handle table */ + HandleTable = SEG_OFF_TO_PTR(Segment, 0); + + /* Copy the handles to the new table */ + RtlCopyMemory(HandleTable, + FAR_POINTER(PspBlock->HandleTablePtr), + PspBlock->HandleTableSize); + + /* Update the handle table pointer */ + PspBlock->HandleTablePtr = MAKELONG(0, Segment); + } + + /* Update the handle table size */ + PspBlock->HandleTableSize = NewSize; + } + } + else if (NewSize > DEFAULT_JFT_SIZE) + { + Segment = DosAllocateMemory(NewSize, NULL); + if (Segment == 0) return FALSE; + + /* Get the new handle table */ + HandleTable = SEG_OFF_TO_PTR(Segment, 0); + + /* Copy the handles from the PSP to the new table */ + RtlCopyMemory(HandleTable, + FAR_POINTER(PspBlock->HandleTablePtr), + PspBlock->HandleTableSize); + + /* Update the handle table pointer and size */ + PspBlock->HandleTableSize = NewSize; + PspBlock->HandleTablePtr = MAKELONG(0, Segment); + } + + return TRUE; +} + + +WORD DosOpenHandle(BYTE DescriptorId) +{ + WORD DosHandle; + PDOS_PSP PspBlock; + LPBYTE HandleTable; + PDOS_FILE_DESCRIPTOR Descriptor = DosGetFileDescriptor(DescriptorId); + + DPRINT("DosOpenHandle: DescriptorId 0x%02X\n", DescriptorId); + + /* Make sure the descriptor ID is valid */ + if (Descriptor == NULL) return INVALID_DOS_HANDLE; + + /* The system PSP has no handle table */ + if (CurrentPsp == SYSTEM_PSP) return INVALID_DOS_HANDLE; + + /* Get a pointer to the handle table */ + PspBlock = SEGMENT_TO_PSP(CurrentPsp); + HandleTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr); + + /* Find a free entry in the JFT */ + for (DosHandle = 0; DosHandle < PspBlock->HandleTableSize; DosHandle++) + { + if (HandleTable[DosHandle] == 0xFF) break; + } + + /* If there are no free entries, fail */ + if (DosHandle == PspBlock->HandleTableSize) return INVALID_DOS_HANDLE; + + /* Reference the descriptor */ + Descriptor->RefCount++; + + /* Set the JFT entry to that descriptor ID */ + HandleTable[DosHandle] = DescriptorId; + + /* Return the new handle */ + return DosHandle; +} + +BYTE DosQueryHandle(WORD DosHandle) +{ + PDOS_PSP PspBlock; + LPBYTE HandleTable; + + DPRINT("DosQueryHandle: DosHandle 0x%04X\n", DosHandle); + + /* The system PSP has no handle table */ + if (CurrentPsp == SYSTEM_PSP) return 0xFF; + + /* Get a pointer to the handle table */ + PspBlock = SEGMENT_TO_PSP(CurrentPsp); + HandleTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr); + + /* Return the descriptor ID */ + return HandleTable[DosHandle]; +} + +WORD DosDuplicateHandle(WORD DosHandle) +{ + BYTE DescriptorId = DosQueryHandle(DosHandle); + + if (DescriptorId == 0xFF) + { + DosLastError = ERROR_INVALID_HANDLE; + return INVALID_DOS_HANDLE; + } + + return DosOpenHandle(DescriptorId); +} + +BOOLEAN DosForceDuplicateHandle(WORD OldHandle, WORD NewHandle) +{ + BYTE DescriptorId; + PDOS_PSP PspBlock; + LPBYTE HandleTable; + PDOS_FILE_DESCRIPTOR Descriptor; + + DPRINT("DosForceDuplicateHandle: OldHandle 0x%04X, NewHandle 0x%04X\n", + OldHandle, + NewHandle); + + /* The system PSP has no handle table */ + if (CurrentPsp == SYSTEM_PSP) return FALSE; + + /* Get a pointer to the handle table */ + PspBlock = SEGMENT_TO_PSP(CurrentPsp); + HandleTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr); + + /* Make sure the old handle is open */ + if (HandleTable[OldHandle] == 0xFF) return FALSE; + + /* Check if the new handle is open */ + if (HandleTable[NewHandle] != 0xFF) + { + /* Close it */ + DosCloseHandle(NewHandle); + } + + DescriptorId = HandleTable[OldHandle]; + Descriptor = DosGetFileDescriptor(DescriptorId); + if (Descriptor == NULL) return FALSE; + + /* Increment the reference count of the descriptor */ + Descriptor->RefCount++; + + /* Make the new handle point to that descriptor */ + HandleTable[NewHandle] = DescriptorId; + + /* Return success */ + return TRUE; +} + +BOOLEAN DosCloseHandle(WORD DosHandle) +{ + PDOS_PSP PspBlock; + LPBYTE HandleTable; + PDOS_FILE_DESCRIPTOR Descriptor; + + DPRINT("DosCloseHandle: DosHandle 0x%04X\n", DosHandle); + + /* The system PSP has no handle table */ + if (CurrentPsp == SYSTEM_PSP) return FALSE; + + /* Get a pointer to the handle table */ + PspBlock = SEGMENT_TO_PSP(CurrentPsp); + HandleTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr); + + /* Make sure the handle is open */ + if (HandleTable[DosHandle] == 0xFF) return FALSE; + + /* Make sure the descriptor is valid */ + Descriptor = DosGetFileDescriptor(HandleTable[DosHandle]); + if (Descriptor == NULL) return FALSE; + + /* Decrement the reference count of the descriptor */ + Descriptor->RefCount--; + + /* Check if the reference count fell to zero */ + if (!Descriptor->RefCount) + { + if (Descriptor->DeviceInfo & (1 << 7)) + { + PDOS_DEVICE_NODE Node = DosGetDriverNode(Descriptor->DevicePointer); + + /* Call the close routine, if it exists */ + if (Node->CloseRoutine) Node->CloseRoutine(Node); + } + else + { + /* Close the win32 handle */ + CloseHandle(Descriptor->Win32Handle); + } + } + + /* Clear the entry in the JFT */ + HandleTable[DosHandle] = 0xFF; + + return TRUE; +} diff --git a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/handle.h b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/handle.h new file mode 100644 index 00000000000..d1e7e539ac6 --- /dev/null +++ b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/handle.h @@ -0,0 +1,21 @@ +/* + * COPYRIGHT: GPLv2+ - See COPYING in the top level directory + * PROJECT: ReactOS Virtual DOS Machine + * FILE: dos/dos32krnl/handle.h + * PURPOSE: DOS32 Handles (Job File Table) + * PROGRAMMERS: Aleksandar Andrejevic + */ + +/* DEFINITIONS ****************************************************************/ + +#define DEFAULT_JFT_SIZE 20 + +/* FUNCTIONS ******************************************************************/ + +VOID DosCopyHandleTable(LPBYTE DestinationTable); +BOOLEAN DosResizeHandleTable(WORD NewSize); +WORD DosOpenHandle(BYTE DescriptorId); +BYTE DosQueryHandle(WORD DosHandle); +WORD DosDuplicateHandle(WORD DosHandle); +BOOLEAN DosForceDuplicateHandle(WORD OldHandle, WORD NewHandle); +BOOLEAN DosCloseHandle(WORD DosHandle); -- 2.17.1