[NTVDM]
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Thu, 15 May 2014 23:13:06 +0000 (23:13 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Thu, 15 May 2014 23:13:06 +0000 (23:13 +0000)
- Add some diagnostic DPRINTs (they are off by default), and fix few of them.
- Fix/complete few comments.
- Implement INT 21h, AH=56h (rename file), 5Ah (create temporary file), 5Bh (create new file), 68h and 6Ah ("commit" aka. flush file; they are the same function).
- Stubplement INT 21h, AH=60h (canonicalize file name or path) and 6Ch (extended open or create file). For this latest one I will merge DosCreateFile and DosOpenFile into the same function (in fact a wrapper around CreateFileA, that is used both for creating and opening files).

svn path=/trunk/; revision=63309

reactos/subsystems/ntvdm/dos/dos32krnl/bios.c
reactos/subsystems/ntvdm/dos/dos32krnl/dos.c
reactos/subsystems/ntvdm/dos/dos32krnl/dos.h
reactos/subsystems/ntvdm/dos/dos32krnl/dosfiles.c

index 32057e5..b70be3b 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * COPYRIGHT:       GPL - See COPYING in the top level directory
  * PROJECT:         ReactOS Virtual DOS Machine
- * FILE:            dos.c
- * PURPOSE:         VDM DOS Kernel
+ * FILE:            dos/dos32krnl/bios.c
+ * PURPOSE:         DOS32 Bios
  * PROGRAMMERS:     Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
  */
 
@@ -31,6 +31,8 @@ CHAR DosReadCharacter(WORD FileHandle)
     CHAR Character = '\0';
     WORD BytesRead;
 
+    DPRINT("DosReadCharacter\n");
+
     /* Use the file reading function */
     DosReadFile(FileHandle, &Character, 1, &BytesRead);
 
index bfdef07..4928ca4 100644 (file)
@@ -2,8 +2,9 @@
  * COPYRIGHT:       GPL - See COPYING in the top level directory
  * PROJECT:         ReactOS Virtual DOS Machine
  * FILE:            dos/dos32krnl/dos.c
- * PURPOSE:         VDM DOS Kernel
+ * PURPOSE:         DOS32 Kernel
  * PROGRAMMERS:     Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ *                  Hermes Belusca-Maito (hermes.belusca@sfr.fr)
  */
 
 /* INCLUDES *******************************************************************/
@@ -1436,13 +1437,16 @@ VOID WINAPI DosInt21h(LPWORD Stack)
         /* Read Character from STDIN with Echo */
         case 0x01:
         {
+            DPRINT("INT 21h, AH = 01h\n");
+
             // FIXME: Under DOS 2+, input / output handle may be redirected!!!!
             DoEcho = TRUE;
             Character = DosReadCharacter(DOS_INPUT_HANDLE);
             DoEcho = FALSE;
 
-            // /* Let the BOP repeat if needed */
-            // if (getCF()) break;
+            // FIXME: Check whether Ctrl-C / Ctrl-Break is pressed, and call INT 23h if so.
+            // Check also Ctrl-P and set echo-to-printer flag.
+            // Ctrl-Z is not interpreted.
 
             setAL(Character);
             break;
@@ -1536,6 +1540,8 @@ VOID WINAPI DosInt21h(LPWORD Stack)
         case 0x07:
         case 0x08:
         {
+            DPRINT("Char input without echo\n");
+
             // FIXME: Under DOS 2+, input handle may be redirected!!!!
             Character = DosReadCharacter(DOS_INPUT_HANDLE);
 
@@ -1566,7 +1572,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
              * See Ralf Brown: http://www.ctyme.com/intr/rb-2562.htm
              * for more information.
              */
-            setAL('$');
+            setAL('$'); // *String
             break;
         }
 
@@ -1576,7 +1582,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
             WORD Count = 0;
             InputBuffer = (PDOS_INPUT_BUFFER)SEG_OFF_TO_PTR(getDS(), getDX());
 
-            DPRINT1("Read Buffered Input\n");
+            DPRINT("Read Buffered Input\n");
 
             while (Count < InputBuffer->MaxLength)
             {
@@ -1585,12 +1591,15 @@ VOID WINAPI DosInt21h(LPWORD Stack)
                 /* Try to read a character (wait) */
                 Character = DosReadCharacter(DOS_INPUT_HANDLE);
 
+                // FIXME: Check whether Ctrl-C / Ctrl-Break is pressed, and call INT 23h if so.
+
                 /* Echo the character and append it to the buffer */
                 DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
                 InputBuffer->Buffer[Count] = Character;
 
+                Count++; /* Carriage returns are also counted */
+
                 if (Character == '\r') break;
-                Count++;
             }
 
             /* Update the length */
@@ -1623,13 +1632,9 @@ VOID WINAPI DosInt21h(LPWORD Stack)
                 InputFunction == 0x07 || InputFunction == 0x08 ||
                 InputFunction == 0x0A)
             {
+                /* Call ourselves recursively */
                 setAH(InputFunction);
-                /*
-                 * Instead of calling ourselves really recursively as in:
-                 * DosInt21h(Stack);
-                 * prefer resetting the CF flag to let the BOP repeat.
-                 */
-                setCF(1);
+                DosInt21h(Stack);
             }
             break;
         }
@@ -1737,7 +1742,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
         /* Create New PSP */
         case 0x26:
         {
-            DPRINT1("INT 21h, 26h - Create New PSP is UNIMPLEMENTED\n");
+            DPRINT1("INT 21h, AH = 26h - Create New PSP is UNIMPLEMENTED\n");
             break;
         }
 
@@ -1993,15 +1998,16 @@ VOID WINAPI DosInt21h(LPWORD Stack)
             break;
         }
 
-        /* Create File */
+        /* Create or Truncate File */
         case 0x3C:
         {
             WORD FileHandle;
             WORD ErrorCode = DosCreateFile(&FileHandle,
                                            (LPCSTR)SEG_OFF_TO_PTR(getDS(), getDX()),
+                                           CREATE_ALWAYS,
                                            getCX());
 
-            if (ErrorCode == 0)
+            if (ErrorCode == ERROR_SUCCESS)
             {
                 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
                 setAX(FileHandle);
@@ -2023,7 +2029,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
                                          (LPCSTR)SEG_OFF_TO_PTR(getDS(), getDX()),
                                          getAL());
 
-            if (ErrorCode == 0)
+            if (ErrorCode == ERROR_SUCCESS)
             {
                 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
                 setAX(FileHandle);
@@ -2059,6 +2065,8 @@ VOID WINAPI DosInt21h(LPWORD Stack)
             WORD BytesRead = 0;
             WORD ErrorCode;
 
+            DPRINT("INT 21h, AH = 3Fh\n");
+
             DoEcho = TRUE;
             ErrorCode = DosReadFile(getBX(),
                                     SEG_OFF_TO_PTR(getDS(), getDX()),
@@ -2468,6 +2476,30 @@ VOID WINAPI DosInt21h(LPWORD Stack)
             break;
         }
 
+        /* Rename File */
+        case 0x56:
+        {
+            LPSTR ExistingFileName = (LPSTR)SEG_OFF_TO_PTR(getDS(), getDX());
+            LPSTR NewFileName      = (LPSTR)SEG_OFF_TO_PTR(getES(), getDI());
+
+            /*
+             * See Ralf Brown: http://www.ctyme.com/intr/rb-2990.htm
+             * for more information.
+             */
+
+            if (MoveFileA(ExistingFileName, NewFileName))
+            {
+                Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+            }
+            else
+            {
+                Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+                setAX(GetLastError());
+            }
+
+            break;
+        }
+
         /* Get/Set Memory Management Options */
         case 0x58:
         {
@@ -2524,6 +2556,79 @@ VOID WINAPI DosInt21h(LPWORD Stack)
             break;
         }
 
+        /* Create Temporary File */
+        case 0x5A:
+        {
+            LPSTR PathName = (LPSTR)SEG_OFF_TO_PTR(getDS(), getDX());
+            LPSTR FileName = PathName; // The buffer for the path and the full file name is the same.
+            UINT  uRetVal;
+            WORD  FileHandle;
+            WORD  ErrorCode;
+
+            /*
+             * See Ralf Brown: http://www.ctyme.com/intr/rb-3014.htm
+             * for more information.
+             */
+
+            // FIXME: Check for buffer validity?
+            // It should be a ASCIZ path ending with a '\' + 13 zero bytes
+            // to receive the generated filename.
+
+            /* First create the temporary file */
+            uRetVal = GetTempFileNameA(PathName, NULL, 0, FileName);
+            if (uRetVal == 0)
+            {
+                Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+                setAX(GetLastError());
+                break;
+            }
+
+            /* Now try to open it in read/write access */
+            ErrorCode = DosOpenFile(&FileHandle, FileName, 2);
+            if (ErrorCode == ERROR_SUCCESS)
+            {
+                Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+                setAX(FileHandle);
+            }
+            else
+            {
+                Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+                setAX(ErrorCode);
+            }
+
+            break;
+        }
+
+        /* Create New File */
+        case 0x5B:
+        {
+            WORD FileHandle;
+            WORD ErrorCode = DosCreateFile(&FileHandle,
+                                           (LPCSTR)SEG_OFF_TO_PTR(getDS(), getDX()),
+                                           CREATE_NEW,
+                                           getCX());
+
+            if (ErrorCode == ERROR_SUCCESS)
+            {
+                Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+                setAX(FileHandle);
+            }
+            else
+            {
+                Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+                setAX(ErrorCode);
+            }
+
+            break;
+        }
+
+        /* Canonicalize File Name or Path */
+        case 0x60:
+        {
+            // TODO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+            break;
+        }
+
         /* Set Handle Count */
         case 0x67:
         {
@@ -2537,6 +2642,50 @@ VOID WINAPI DosInt21h(LPWORD Stack)
             break;
         }
 
+        /* Commit File */
+        case 0x68:
+        case 0x6A:
+        {
+            /*
+             * Function 6Ah is identical to function 68h,
+             * and sets AH to 68h if success.
+             * See Ralf Brown: http://www.ctyme.com/intr/rb-3176.htm
+             * for more information.
+             */
+            setAH(0x68);
+
+            if (DosFlushFileBuffers(getBX()))
+            {
+                Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+            }
+            else
+            {
+                Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+                setAX(GetLastError());
+            }
+
+            break;
+        }
+
+        /* Extended Open/Create */
+        case 0x6C:
+        {
+            /* Check for AL == 00 */
+            if (getAL() != 0x00)
+            {
+                Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+                setAX(ERROR_INVALID_FUNCTION);
+                break;
+            }
+
+            // TODO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+            // FIXME: Extend and merge DosOpenFile and DosCreateFile into
+            // a single wrapper around CreateFileA, which acts as:
+            // http://www.ctyme.com/intr/rb-3179.htm
+
+            break;
+        }
+
         /* Unsupported */
         default:
         {
@@ -2562,6 +2711,8 @@ VOID WINAPI DosFastConOut(LPWORD Stack)
 {
     /*
      * This is the DOS 2+ Fast Console Output Interrupt.
+     * The default handler under DOS 2.x and 3.x simply calls INT 10h/AH=0Eh.
+     *
      * See Ralf Brown: http://www.ctyme.com/intr/rb-4124.htm
      * for more information.
      */
@@ -2570,7 +2721,12 @@ VOID WINAPI DosFastConOut(LPWORD Stack)
     USHORT AX = getAX();
     USHORT BX = getBX();
 
-    /* Set the parameters (AL = character, already set) */
+    /*
+     * Set the parameters:
+     * AL contains the character to print (already set),
+     * BL contains the character attribute,
+     * BH contains the video page to use.
+     */
     setBL(DOS_CHAR_ATTRIBUTE);
     setBH(Bda->VideoPage);
 
index ead1344..e2f0cef 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * COPYRIGHT:       GPL - See COPYING in the top level directory
  * PROJECT:         ReactOS Virtual DOS Machine
- * FILE:            dos.h
- * PURPOSE:         VDM DOS Kernel
+ * FILE:            dos/dos32krnl/dos.h
+ * PURPOSE:         DOS32 Kernel
  * PROGRAMMERS:     Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
  */
 
@@ -191,8 +191,8 @@ BOOL IsConsoleHandle(HANDLE hHandle);
 WORD DosOpenHandle(HANDLE Handle);
 HANDLE DosGetRealHandle(WORD DosHandle);
 
-WORD DosCreateFile(LPWORD Handle, LPCSTR FilePath, WORD Attributes);
-WORD DosOpenFile(LPWORD Handle, LPCSTR FilePath, BYTE AccessMode);
+WORD DosCreateFile(LPWORD Handle, LPCSTR FilePath, WORD CreationFlags, WORD Attributes);
+WORD DosOpenFile(LPWORD Handle, LPCSTR FilePath, BYTE AccessShareModes);
 WORD DosReadFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesRead);
 WORD DosWriteFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesWritten);
 WORD DosSeekFile(WORD FileHandle, LONG Offset, BYTE Origin, LPDWORD NewOffset);
index 51c57d3..e5560b2 100644 (file)
@@ -2,8 +2,9 @@
  * COPYRIGHT:       GPL - See COPYING in the top level directory
  * PROJECT:         ReactOS Virtual DOS Machine
  * FILE:            dos/dos32krnl/dosfiles.c
- * PURPOSE:         DOS Files
+ * PURPOSE:         DOS32 Files Support
  * PROGRAMMERS:     Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ *                  Hermes Belusca-Maito (hermes.belusca@sfr.fr)
  */
 
 /* INCLUDES *******************************************************************/
 
 /* PUBLIC FUNCTIONS ***********************************************************/
 
-WORD DosCreateFile(LPWORD Handle, LPCSTR FilePath, WORD Attributes)
+WORD DosCreateFile(LPWORD Handle, LPCSTR FilePath, WORD CreationFlags, WORD Attributes)
 {
     HANDLE FileHandle;
     WORD DosHandle;
 
-    DPRINT("DosCreateFile: FilePath \"%s\", Attributes 0x%04X\n",
+    DPRINT("DosCreateFile: FilePath \"%s\", CreationFlags 0x%04X, Attributes 0x%04X\n",
             FilePath,
+            CreationFlags,
             Attributes);
 
     /* Create the file */
@@ -36,7 +38,7 @@ WORD DosCreateFile(LPWORD Handle, LPCSTR FilePath, WORD Attributes)
                              GENERIC_READ | GENERIC_WRITE,
                              FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                              NULL,
-                             CREATE_ALWAYS,
+                             CreationFlags,
                              Attributes,
                              NULL);
 
@@ -63,37 +65,40 @@ WORD DosCreateFile(LPWORD Handle, LPCSTR FilePath, WORD Attributes)
     return ERROR_SUCCESS;
 }
 
-WORD DosOpenFile(LPWORD Handle, LPCSTR FilePath, BYTE AccessMode)
+WORD DosOpenFile(LPWORD Handle, LPCSTR FilePath, BYTE AccessShareModes)
 {
     HANDLE FileHandle;
-    ACCESS_MASK Access = 0;
+    ACCESS_MASK AccessMode = 0;
+    DWORD ShareMode = 0;
+    BOOL InheritableFile = FALSE;
+    SECURITY_ATTRIBUTES SecurityAttributes;
     WORD DosHandle;
 
-    DPRINT("DosOpenFile: FilePath \"%s\", AccessMode 0x%04X\n",
+    DPRINT("DosOpenFile: FilePath \"%s\", AccessShareModes 0x%04X\n",
             FilePath,
-            AccessMode);
+            AccessShareModes);
 
     /* Parse the access mode */
-    switch (AccessMode & 3)
+    switch (AccessShareModes & 0x03)
     {
         case 0:
         {
             /* Read-only */
-            Access = GENERIC_READ;
+            AccessMode = GENERIC_READ;
             break;
         }
 
         case 1:
         {
             /* Write only */
-            Access = GENERIC_WRITE;
+            AccessMode = GENERIC_WRITE;
             break;
         }
 
         case 2:
         {
             /* Read and write */
-            Access = GENERIC_READ | GENERIC_WRITE;
+            AccessMode = GENERIC_READ | GENERIC_WRITE;
             break;
         }
 
@@ -104,11 +109,64 @@ WORD DosOpenFile(LPWORD Handle, LPCSTR FilePath, BYTE AccessMode)
         }
     }
 
+    /* Parse the share mode */
+    switch ((AccessShareModes >> 4) & 0x07)
+    {
+        case 0:
+        {
+            /* Compatibility mode */
+            ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+            break;
+        }
+
+        case 1:
+        {
+            /* No sharing "DenyAll" */
+            ShareMode = 0;
+            break;
+        }
+
+        case 2:
+        {
+            /* No write share "DenyWrite" */
+            ShareMode = FILE_SHARE_READ;
+            break;
+        }
+
+        case 3:
+        {
+            /* No read share "DenyRead" */
+            ShareMode = FILE_SHARE_WRITE;
+            break;
+        }
+
+        case 4:
+        {
+            /* Full share "DenyNone" */
+            ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+            break;
+        }
+
+        default:
+        {
+            /* Invalid */
+            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,
-                             Access,
-                             FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-                             NULL,
+                             AccessMode,
+                             ShareMode,
+                             &SecurityAttributes,
                              OPEN_EXISTING,
                              FILE_ATTRIBUTE_NORMAL,
                              NULL);
@@ -142,7 +200,7 @@ WORD DosReadFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesRead)
     DWORD BytesRead32 = 0;
     HANDLE Handle = DosGetRealHandle(FileHandle);
 
-    DPRINT1("DosReadFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle, Count);
+    DPRINT("DosReadFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle, Count);
 
     /* Make sure the handle is valid */
     if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
@@ -207,9 +265,7 @@ WORD DosWriteFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesWritte
     DWORD BytesWritten32 = 0;
     HANDLE Handle = DosGetRealHandle(FileHandle);
 
-    DPRINT1("DosWriteFile: FileHandle 0x%04X, Count 0x%04X\n",
-           FileHandle,
-           Count);
+    DPRINT("DosWriteFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle, Count);
 
     /* Make sure the handle is valid */
     if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
@@ -313,7 +369,6 @@ WORD DosSeekFile(WORD FileHandle, LONG Offset, BYTE Origin, LPDWORD NewOffset)
     return ERROR_SUCCESS;
 }
 
-// This function is almost exclusively used as a DosFlushInputBuffer
 BOOL DosFlushFileBuffers(WORD FileHandle)
 {
     HANDLE Handle = DosGetRealHandle(FileHandle);
@@ -322,9 +377,11 @@ BOOL DosFlushFileBuffers(WORD FileHandle)
     if (Handle == INVALID_HANDLE_VALUE) return FALSE;
 
     /*
-     * No need to check whether the handle is a console handle since
-     * FlushFileBuffers() automatically does this check and calls
-     * FlushConsoleInputBuffer() for us.
+     * This function can either flush files back to disks, or flush
+     * console input buffers, in which case there is no need to check
+     * whether the handle is a console handle. FlushFileBuffers()
+     * automatically does this check and calls FlushConsoleInputBuffer()
+     * if needed.
      */
     return FlushFileBuffers(Handle);
 }