[FAST486]
authorAleksandar Andrejevic <aandrejevic@reactos.org>
Sun, 3 May 2015 01:45:57 +0000 (01:45 +0000)
committerAleksandar Andrejevic <aandrejevic@reactos.org>
Sun, 3 May 2015 01:45:57 +0000 (01:45 +0000)
Update the copyright year (better late than never).
Push the error code inside Fast486InterruptInternal, to make the size of the
pushed value on the stack correct.
Update the CPL in Fast486TaskSwitch.

svn path=/trunk/; revision=67526

15 files changed:
reactos/include/reactos/libs/fast486/fast486.h
reactos/lib/fast486/common.c
reactos/lib/fast486/common.h
reactos/lib/fast486/common.inl
reactos/lib/fast486/debug.c
reactos/lib/fast486/extraops.c
reactos/lib/fast486/extraops.h
reactos/lib/fast486/fast486.c
reactos/lib/fast486/fpu.c
reactos/lib/fast486/fpu.h
reactos/lib/fast486/opcodes.c
reactos/lib/fast486/opcodes.h
reactos/lib/fast486/opgroups.c
reactos/lib/fast486/opgroups.h
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.c

index 413f7c7..7f0a02f 100644 (file)
@@ -2,7 +2,7 @@
  * Fast486 386/486 CPU Emulation Library
  * fast486.h
  *
- * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ * Copyright (C) 2015 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index a6d2459..4f39e6a 100644 (file)
@@ -2,7 +2,7 @@
  * Fast486 386/486 CPU Emulation Library
  * common.c
  *
- * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ * Copyright (C) 2015 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -264,7 +264,9 @@ Fast486GetIntVector(PFAST486_STATE State,
 static inline BOOLEAN
 FASTCALL
 Fast486InterruptInternal(PFAST486_STATE State,
-                         PFAST486_IDT_ENTRY IdtEntry)
+                         PFAST486_IDT_ENTRY IdtEntry,
+                         BOOLEAN PushErrorCode,
+                         ULONG ErrorCode)
 {
     USHORT SegmentSelector = IdtEntry->Selector;
     ULONG  Offset          = MAKELONG(IdtEntry->Offset, IdtEntry->OffsetHigh);
@@ -400,6 +402,16 @@ Fast486InterruptInternal(PFAST486_STATE State,
     /* Push the instruction pointer */
     if (!Fast486StackPush(State, State->InstPtr.Long)) goto Cleanup;
 
+    if (PushErrorCode)
+    {
+        /* Push the error code */
+        if (!Fast486StackPush(State, ErrorCode))
+        {
+            /* An exception occurred */
+            goto Cleanup;
+        }
+    }
+
     if ((GateType == FAST486_IDT_INT_GATE) || (GateType == FAST486_IDT_INT_GATE_32))
     {
         /* Disable interrupts after a jump to an interrupt gate handler */
@@ -448,7 +460,7 @@ Fast486PerformInterrupt(PFAST486_STATE State,
     }
 
     /* Perform the interrupt */
-    if (!Fast486InterruptInternal(State, &IdtEntry))
+    if (!Fast486InterruptInternal(State, &IdtEntry, FALSE, 0))
     {
         /* Exception occurred */
         return FALSE;
@@ -463,6 +475,8 @@ Fast486ExceptionWithErrorCode(PFAST486_STATE State,
                               FAST486_EXCEPTIONS ExceptionCode,
                               ULONG ErrorCode)
 {
+    FAST486_IDT_ENTRY IdtEntry;
+
     /* Increment the exception count */
     State->ExceptionCount++;
 
@@ -491,8 +505,8 @@ Fast486ExceptionWithErrorCode(PFAST486_STATE State,
     /* Restore the IP to the saved IP */
     State->InstPtr = State->SavedInstPtr;
 
-    /* Perform the interrupt */
-    if (!Fast486PerformInterrupt(State, ExceptionCode))
+    /* Get the interrupt vector */
+    if (!Fast486GetIntVector(State, ExceptionCode, &IdtEntry))
     {
         /*
          * If this function failed, that means Fast486Exception
@@ -501,18 +515,18 @@ Fast486ExceptionWithErrorCode(PFAST486_STATE State,
         return;
     }
 
-    if (EXCEPTION_HAS_ERROR_CODE(ExceptionCode)
-        && (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE))
+    /* Perform the interrupt */
+    if (!Fast486InterruptInternal(State,
+                                  &IdtEntry,
+                                  EXCEPTION_HAS_ERROR_CODE(ExceptionCode)
+                                  && (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE),
+                                  ErrorCode))
     {
-        /* Push the error code */
-        if (!Fast486StackPush(State, ErrorCode))
-        {
-            /*
-             * If this function failed, that means Fast486Exception
-             * was called again, so just return in this case.
-             */
-            return;
-        }
+        /*
+         * If this function failed, that means Fast486Exception
+         * was called again, so just return in this case.
+         */
+        return;
     }
 
     /* Reset the exception count */
@@ -702,11 +716,17 @@ Fast486TaskSwitch(PFAST486_STATE State, FAST486_TASK_SWITCH_TYPE Type, USHORT Se
     /* Flush the TLB */
     if (State->Tlb) RtlZeroMemory(State->Tlb, NUM_TLB_ENTRIES * sizeof(ULONG));
 
+    /* Update the CPL */
+    State->Cpl = GET_SEGMENT_RPL(NewTss.Cs);
+
 #ifndef FAST486_NO_PREFETCH
     /* Context switching invalidates the prefetch */
     State->PrefetchValid = FALSE;
 #endif
 
+    /* Update the CPL */
+    State->Cpl = GET_SEGMENT_RPL(NewTss.Cs);
+
     /* Load the registers */
     State->InstPtr.Long = State->SavedInstPtr.Long = NewTss.Eip;
     State->Flags.Long = NewTss.Eflags;
index d0394c0..07b2102 100644 (file)
@@ -2,7 +2,7 @@
  * Fast486 386/486 CPU Emulation Library
  * common.h
  *
- * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ * Copyright (C) 2015 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 31e80cc..a6b67ad 100644 (file)
@@ -2,7 +2,7 @@
  * Fast486 386/486 CPU Emulation Library
  * common.inl
  *
- * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ * Copyright (C) 2015 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -782,6 +782,9 @@ Fast486ProcessGate(PFAST486_STATE State, USHORT Selector, ULONG Offset, BOOLEAN
         {
             // TODO: NOT IMPLEMENTED
             UNIMPLEMENTED;
+
+            Fast486Exception(State, FAST486_EXCEPTION_UD);
+            return FALSE;
         }
 
         default:
index 974e99b..af362f1 100644 (file)
@@ -2,7 +2,7 @@
  * Fast486 386/486 CPU Emulation Library
  * fast486dbg.c
  *
- * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ * Copyright (C) 2015 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 93fcbae..9ad56b6 100644 (file)
@@ -2,7 +2,7 @@
  * Fast486 386/486 CPU Emulation Library
  * extraops.c
  *
- * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ * Copyright (C) 2015 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 0a8effd..edd5abe 100644 (file)
@@ -2,7 +2,7 @@
  * Fast486 386/486 CPU Emulation Library
  * extraops.h
  *
- * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ * Copyright (C) 2015 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 006bee5..89669e4 100644 (file)
@@ -2,7 +2,7 @@
  * Fast486 386/486 CPU Emulation Library
  * fast486.c
  *
- * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ * Copyright (C) 2015 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 1e4ce78..a990644 100644 (file)
@@ -2,7 +2,7 @@
  * Fast486 386/486 CPU Emulation Library
  * fpu.c
  *
- * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ * Copyright (C) 2015 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index b14b128..41796d2 100644 (file)
@@ -2,7 +2,7 @@
  * Fast486 386/486 CPU Emulation Library
  * fpu.h
  *
- * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ * Copyright (C) 2015 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 87dce03..8f5e0c6 100644 (file)
@@ -2,7 +2,7 @@
  * Fast486 386/486 CPU Emulation Library
  * opcodes.c
  *
- * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ * Copyright (C) 2015 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 193b38f..84c6b2d 100644 (file)
@@ -2,7 +2,7 @@
  * Fast486 386/486 CPU Emulation Library
  * opcodes.h
  *
- * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ * Copyright (C) 2015 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 60e778d..ccaab8b 100644 (file)
@@ -2,7 +2,7 @@
  * Fast486 386/486 CPU Emulation Library
  * opgroups.c
  *
- * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ * Copyright (C) 2015 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 38eed67..40186d4 100644 (file)
@@ -2,7 +2,7 @@
  * Fast486 386/486 CPU Emulation Library
  * opgroups.h
  *
- * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ * Copyright (C) 2015 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index a678b19..7ccb5c9 100644 (file)
@@ -146,6 +146,7 @@ WORD DosCreateFileEx(LPWORD Handle,
 {
     WORD LastError;
     HANDLE FileHandle;
+    PDOS_DEVICE_NODE Node;
     WORD DosHandle;
     ACCESS_MASK AccessMode = 0;
     DWORD ShareMode = 0;
@@ -163,185 +164,193 @@ WORD DosCreateFileEx(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;
+        /* Parse the access mode */
+        switch (AccessShareModes & 0x03)
+        {
+            /* Read-only */
+            case 0:
+                AccessMode = GENERIC_READ;
+                break;
 
-        /* No sharing "DenyAll" */
-        case 1:
-            ShareMode = 0;
-            break;
+            /* Write only */
+            case 1:
+                AccessMode = GENERIC_WRITE;
+                break;
 
-        /* No write share "DenyWrite" */
-        case 2:
-            ShareMode = FILE_SHARE_READ;
-            break;
+            /* Read and write */
+            case 2:
+                AccessMode = GENERIC_READ | GENERIC_WRITE;
+                break;
 
-        /* No read share "DenyRead" */
-        case 3:
-            ShareMode = FILE_SHARE_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;
 
-        /* Invalid */
-        default:
-            return ERROR_INVALID_PARAMETER;
-    }
-
-    /*
-     * Parse the creation action flags:
-     *
-     * Bitfields for action:
-     * Bit(s)  Description
-     *
-     * 7-4     Action if file does not exist.
-     * 0000    Fail
-     * 0001    Create
-     *
-     * 3-0     Action if file exists.
-     * 0000    Fail
-     * 0001    Open
-     * 0010    Replace/open
-     */
-    switch (CreateActionFlags)
-    {
-        /* If the file exists, fail, otherwise, fail also */
-        case 0x00:
-            // A special case is used after the call to CreateFileA if it succeeds,
-            // in order to close the opened handle and return an adequate error.
-            CreationDisposition = OPEN_EXISTING;
-            break;
+            /* No sharing "DenyAll" */
+            case 1:
+                ShareMode = 0;
+                break;
 
-        /* If the file exists, open it, otherwise, fail */
-        case 0x01:
-            CreationDisposition = OPEN_EXISTING;
-            break;
+            /* No write share "DenyWrite" */
+            case 2:
+                ShareMode = FILE_SHARE_READ;
+                break;
 
-        /* If the file exists, replace it, otherwise, fail */
-        case 0x02:
-            CreationDisposition = TRUNCATE_EXISTING;
-            break;
+            /* No read share "DenyRead" */
+            case 3:
+                ShareMode = FILE_SHARE_WRITE;
+                break;
 
-        /* If the file exists, fail, otherwise, create it */
-        case 0x10:
-            CreationDisposition = CREATE_NEW;
-            break;
+            /* Full share "DenyNone" */
+            case 4:
+                ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+                break;
 
-        /* If the file exists, open it, otherwise, create it */
-        case 0x11:
-            CreationDisposition = OPEN_ALWAYS;
-            break;
+            /* Invalid */
+            default:
+                return ERROR_INVALID_PARAMETER;
+        }
 
-        /* If the file exists, replace it, otherwise, create it */
-        case 0x12:
-            CreationDisposition = CREATE_ALWAYS;
-            break;
+        /*
+         * Parse the creation action flags:
+         *
+         * Bitfields for action:
+         * Bit(s)  Description
+         *
+         * 7-4     Action if file does not exist.
+         * 0000    Fail
+         * 0001    Create
+         *
+         * 3-0     Action if file exists.
+         * 0000    Fail
+         * 0001    Open
+         * 0010    Replace/open
+         */
+        switch (CreateActionFlags)
+        {
+            /* If the file exists, fail, otherwise, fail also */
+            case 0x00:
+                // A special case is used after the call to CreateFileA if it succeeds,
+                // in order to close the opened handle and return an adequate error.
+                CreationDisposition = OPEN_EXISTING;
+                break;
 
-        /* Invalid */
-        default:
-            return ERROR_INVALID_PARAMETER;
-    }
+            /* If the file exists, open it, otherwise, fail */
+            case 0x01:
+                CreationDisposition = OPEN_EXISTING;
+                break;
 
-    /* Check for inheritance */
-    InheritableFile = ((AccessShareModes & 0x80) == 0);
+            /* If the file exists, replace it, otherwise, fail */
+            case 0x02:
+                CreationDisposition = TRUNCATE_EXISTING;
+                break;
 
-    /* Assign default security attributes to the file, and set the inheritance flag */
-    SecurityAttributes.nLength = sizeof(SecurityAttributes);
-    SecurityAttributes.lpSecurityDescriptor = NULL;
-    SecurityAttributes.bInheritHandle = InheritableFile;
+            /* If the file exists, fail, otherwise, create it */
+            case 0x10:
+                CreationDisposition = CREATE_NEW;
+                break;
 
-    /* Open the file */
-    FileHandle = CreateFileA(FilePath,
-                             AccessMode,
-                             ShareMode,
-                             &SecurityAttributes,
-                             CreationDisposition,
-                             Attributes,
-                             NULL);
+            /* If the file exists, open it, otherwise, create it */
+            case 0x11:
+                CreationDisposition = OPEN_ALWAYS;
+                break;
 
-    LastError = (WORD)GetLastError();
+            /* If the file exists, replace it, otherwise, create it */
+            case 0x12:
+                CreationDisposition = CREATE_ALWAYS;
+                break;
 
-    if (FileHandle == INVALID_HANDLE_VALUE)
-    {
-        /* Return the error code */
-        return LastError;
-    }
+            /* Invalid */
+            default:
+                return ERROR_INVALID_PARAMETER;
+        }
 
-    /*
-     * Special case: CreateActionFlags == 0, we must fail because
-     * the file exists (if it didn't exist we already failed).
-     */
-    if (CreateActionFlags == 0)
-    {
-        /* Close the file and return the error code */
-        CloseHandle(FileHandle);
-        return ERROR_FILE_EXISTS;
-    }
+        /* Check for inheritance */
+        InheritableFile = ((AccessShareModes & 0x80) == 0);
 
-    /* Set the creation status */
-    switch (CreateActionFlags)
-    {
-        case 0x01:
-            *CreationStatus = 0x01; // The file was opened
-            break;
+        /* Assign default security attributes to the file, and set the inheritance flag */
+        SecurityAttributes.nLength = sizeof(SecurityAttributes);
+        SecurityAttributes.lpSecurityDescriptor = NULL;
+        SecurityAttributes.bInheritHandle = InheritableFile;
 
-        case 0x02:
-            *CreationStatus = 0x03; // The file was replaced
-            break;
+        /* Open the file */
+        FileHandle = CreateFileA(FilePath,
+                                 AccessMode,
+                                 ShareMode,
+                                 &SecurityAttributes,
+                                 CreationDisposition,
+                                 Attributes,
+                                 NULL);
 
-        case 0x10:
-            *CreationStatus = 0x02; // The file was created
-            break;
+        LastError = (WORD)GetLastError();
 
-        case 0x11:
+        if (FileHandle == INVALID_HANDLE_VALUE)
         {
-            if (LastError == ERROR_ALREADY_EXISTS)
-                *CreationStatus = 0x01; // The file was opened
-            else
-                *CreationStatus = 0x02; // The file was created
+            /* Return the error code */
+            return LastError;
+        }
 
-            break;
+        /*
+         * Special case: CreateActionFlags == 0, we must fail because
+         * the file exists (if it didn't exist we already failed).
+         */
+        if (CreateActionFlags == 0)
+        {
+            /* Close the file and return the error code */
+            CloseHandle(FileHandle);
+            return ERROR_FILE_EXISTS;
         }
 
-        case 0x12:
+        /* Set the creation status */
+        switch (CreateActionFlags)
         {
-            if (LastError == ERROR_ALREADY_EXISTS)
+            case 0x01:
+                *CreationStatus = 0x01; // The file was opened
+                break;
+
+            case 0x02:
                 *CreationStatus = 0x03; // The file was replaced
-            else
+                break;
+
+            case 0x10:
                 *CreationStatus = 0x02; // The file was created
+                break;
 
-            break;
+            case 0x11:
+            {
+                if (LastError == ERROR_ALREADY_EXISTS)
+                    *CreationStatus = 0x01; // The file was opened
+                else
+                    *CreationStatus = 0x02; // The file was created
+
+                break;
+            }
+
+            case 0x12:
+            {
+                if (LastError == ERROR_ALREADY_EXISTS)
+                    *CreationStatus = 0x03; // The file was replaced
+                else
+                    *CreationStatus = 0x02; // The file was created
+
+                break;
+            }
         }
     }
 
@@ -357,11 +366,19 @@ WORD DosCreateFileEx(LPWORD Handle,
     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;
+    if (Node != NULL)
+    {
+        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(DescriptorId);
@@ -383,6 +400,7 @@ WORD DosCreateFile(LPWORD Handle,
                    WORD Attributes)
 {
     HANDLE FileHandle;
+    PDOS_DEVICE_NODE Node;
     WORD DosHandle;
     BYTE DescriptorId;
     PDOS_FILE_DESCRIPTOR Descriptor;
@@ -390,18 +408,26 @@ WORD DosCreateFile(LPWORD Handle,
     DPRINT("DosCreateFile: FilePath \"%s\", CreationDisposition 0x%04X, Attributes 0x%04X\n",
            FilePath, CreationDisposition, Attributes);
 
-    /* Create the file */
-    FileHandle = CreateFileA(FilePath,
-                             GENERIC_READ | GENERIC_WRITE,
-                             FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-                             NULL,
-                             CreationDisposition,
-                             Attributes,
-                             NULL);
-    if (FileHandle == INVALID_HANDLE_VALUE)
+    Node = DosGetDevice(FilePath);
+    if (Node != NULL)
+    {
+        if (Node->OpenRoutine) Node->OpenRoutine(Node);
+    }
+    else
     {
-        /* Return the error code */
-        return (WORD)GetLastError();
+        /* Create the file */
+        FileHandle = CreateFileA(FilePath,
+                                 GENERIC_READ | GENERIC_WRITE,
+                                 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                                 NULL,
+                                 CreationDisposition,
+                                 Attributes,
+                                 NULL);
+        if (FileHandle == INVALID_HANDLE_VALUE)
+        {
+            /* Return the error code */
+            return (WORD)GetLastError();
+        }
     }
 
     DescriptorId = DosFindFreeDescriptor();
@@ -416,10 +442,18 @@ WORD DosCreateFile(LPWORD Handle,
     Descriptor = DosGetFileDescriptor(DescriptorId);
     RtlZeroMemory(Descriptor, sizeof(*Descriptor));
 
-    Descriptor->Attributes = LOBYTE(GetFileAttributesA(FilePath));
-    Descriptor->Size = GetFileSize(FileHandle, NULL);
-    Descriptor->OwnerPsp = CurrentPsp;
-    Descriptor->Win32Handle = FileHandle;
+    if (Node != NULL)
+    {
+        Descriptor->DevicePointer = Node->Driver;
+        Descriptor->DeviceInfo = Node->DeviceAttributes | (1 << 7);
+    }
+    else
+    {
+        Descriptor->Attributes = LOBYTE(GetFileAttributesA(FilePath));
+        Descriptor->Size = GetFileSize(FileHandle, NULL);
+        Descriptor->OwnerPsp = CurrentPsp;
+        Descriptor->Win32Handle = FileHandle;
+    }
 
     /* Open the DOS handle */
     DosHandle = DosOpenHandle(DescriptorId);