[NTVDM]
authorAleksandar Andrejevic <aandrejevic@reactos.org>
Sun, 26 Apr 2015 18:09:57 +0000 (18:09 +0000)
committerAleksandar Andrejevic <aandrejevic@reactos.org>
Sun, 26 Apr 2015 18:09:57 +0000 (18:09 +0000)
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
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/bios.c
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/device.c
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/device.h
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.h
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.c
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.h [new file with mode: 0644]
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/handle.c [new file with mode: 0644]
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/handle.h [new file with mode: 0644]

index a27845d..f9ea31c 100644 (file)
@@ -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
index 41b144f..7263055 100644 (file)
@@ -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));
     }
 }
 
index 91975e4..8b62235 100644 (file)
@@ -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;
     }
index 2061f4a..bc3ab6e 100644 (file)
@@ -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
index b8cc55b..ae904a2 100644 (file)
@@ -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
index df7a3af..c0d0551 100644 (file)
@@ -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,
index fd11e85..13a8df1 100644 (file)
 
 #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 (file)
index 0000000..6e31cfe
--- /dev/null
@@ -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 <theflash AT sdf DOT lonestar DOT org>
+ */
+
+/* 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 (file)
index 0000000..2f64ca8
--- /dev/null
@@ -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 <theflash AT sdf DOT lonestar DOT org>
+ */
+
+/* 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 (file)
index 0000000..d1e7e53
--- /dev/null
@@ -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 <theflash AT sdf DOT lonestar DOT org>
+ */
+
+/* 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);