[NTVDM]
authorAleksandar Andrejevic <aandrejevic@reactos.org>
Tue, 23 Jul 2013 14:43:03 +0000 (14:43 +0000)
committerAleksandar Andrejevic <aandrejevic@reactos.org>
Tue, 23 Jul 2013 14:43:03 +0000 (14:43 +0000)
Implement several INT 21h functions.

svn path=/branches/ntvdm/; revision=59563

subsystems/ntvdm/dos.c
subsystems/ntvdm/dos.h

index 37b0de4..a999421 100644 (file)
@@ -704,6 +704,87 @@ WORD DosWriteFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesWritte
     return Result;
 }
 
+WORD DosSeekFile(WORD FileHandle, LONG Offset, BYTE Origin, LPDWORD NewOffset)
+{
+    WORD Result = ERROR_SUCCESS;
+    DWORD FilePointer;
+    HANDLE Handle = DosGetRealHandle(FileHandle);
+
+    DPRINT("DosSeekFile: FileHandle 0x%04X, Offset 0x%08X, Origin 0x%02X\n",
+           FileHandle,
+           Offset,
+           Origin);
+
+    /* Make sure the handle is valid */
+    if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
+
+    /* Check if the origin is valid */
+    if (Origin != FILE_BEGIN && Origin != FILE_CURRENT && Origin != FILE_END)
+    {
+        return ERROR_INVALID_FUNCTION;
+    }
+
+    /* Move the file pointer */
+    FilePointer = SetFilePointer(Handle, Offset, NULL, Origin);
+
+    /* Check if there's a possibility the operation failed */
+    if (FilePointer == INVALID_SET_FILE_POINTER)
+    {
+        /* Get the real error code */
+        Result = GetLastError();
+    }
+
+    if (Result != ERROR_SUCCESS)
+    {
+        /* The operation did fail */
+        return Result;
+    }
+
+    /* Return the file pointer, if requested */
+    if (NewOffset) *NewOffset = FilePointer;
+
+    /* Return success */
+    return ERROR_SUCCESS;
+}
+
+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];
+    DosSftRefCount[SftIndex]++;
+
+    /* Make the new handle point to that SFT entry */
+    HandleTable[NewHandle] = SftIndex;
+
+    /* Return success */
+    return TRUE;
+}
+
 BOOLEAN DosCloseHandle(WORD DosHandle)
 {
     BYTE SftIndex;
@@ -736,6 +817,9 @@ BOOLEAN DosCloseHandle(WORD DosHandle)
         DosSystemFileTable[SftIndex] = INVALID_HANDLE_VALUE;
     }
 
+    /* Clear the entry in the JFT */
+    HandleTable[DosHandle] = 0xFF;
+
     return TRUE;
 }
 
@@ -1547,6 +1631,102 @@ VOID DosInt21h(WORD CodeSegment)
             break;
         }
 
+        /* Delete File */
+        case 0x41:
+        {
+            LPSTR FileName = (LPSTR)((ULONG_PTR)BaseAddress + TO_LINEAR(DataSegment, Edx));
+
+            /* Call the API function */
+            if (DeleteFileA(FileName)) EmulatorClearFlag(EMULATOR_FLAG_CF);
+            else
+            {
+                EmulatorSetFlag(EMULATOR_FLAG_CF);
+                EmulatorSetRegister(EMULATOR_REG_AX, GetLastError());
+            }
+
+            break;
+        }
+
+        /* Seek File */
+        case 0x42:
+        {
+            DWORD NewLocation;
+            WORD ErrorCode = DosSeekFile(LOWORD(Ebx),
+                                         MAKELONG(LOWORD(Edx), LOWORD(Ecx)),
+                                         LOBYTE(Eax),
+                                         &NewLocation);
+
+            if (ErrorCode == 0)
+            {
+                /* Clear CF */
+                EmulatorClearFlag(EMULATOR_FLAG_CF);
+
+                /* Return the new offset in DX:AX */
+                EmulatorSetRegister(EMULATOR_REG_DX,
+                                    (Edx & 0xFFFF0000) | HIWORD(NewLocation));
+                EmulatorSetRegister(EMULATOR_REG_AX,
+                                    (Eax & 0xFFFF0000) | LOWORD(NewLocation));
+            }
+            else
+            {
+                /* Set CF */
+                EmulatorSetFlag(EMULATOR_FLAG_CF);
+
+                /* Return the error code in AX */
+                EmulatorSetRegister(EMULATOR_REG_AX,
+                                    (Eax & 0xFFFF0000) | ErrorCode);
+            }
+
+            break;
+        }
+
+        /* Get/Set File Attributes */
+        case 0x43:
+        {
+            DWORD Attributes;
+            LPSTR FileName = (LPSTR)((ULONG_PTR)BaseAddress + TO_LINEAR(DataSegment, Edx));
+
+            if (LOBYTE(Eax) == 0x00)
+            {
+                /* Get the attributes */
+                Attributes = GetFileAttributesA(FileName);
+
+                /* Check if it failed */
+                if (Attributes == INVALID_FILE_ATTRIBUTES)
+                {
+                    EmulatorSetFlag(EMULATOR_FLAG_CF);
+                    EmulatorSetRegister(EMULATOR_REG_AX, GetLastError());
+
+                    break;
+                }
+
+                /* Return the attributes that DOS can understand */
+                EmulatorClearFlag(EMULATOR_FLAG_CF);
+                EmulatorSetRegister(EMULATOR_REG_CX,
+                                    (Ecx & 0xFFFFFF00) | LOBYTE(Attributes));
+            }
+            else if (LOBYTE(Eax) == 0x01)
+            {
+                /* Try to set the attributes */
+                if (SetFileAttributesA(FileName, LOBYTE(Ecx)))
+                {
+                    EmulatorClearFlag(EMULATOR_FLAG_CF);
+                }
+                else
+                {
+                    EmulatorSetFlag(EMULATOR_FLAG_CF);
+                    EmulatorSetRegister(EMULATOR_REG_AX, GetLastError());
+                }
+            }
+            else
+            {
+                EmulatorSetFlag(EMULATOR_FLAG_CF);
+                EmulatorSetRegister(EMULATOR_REG_AX, ERROR_INVALID_FUNCTION);
+            }
+
+            break;
+        }
+
         /* IOCTL */
         case 0x44:
         {
@@ -1555,6 +1735,56 @@ VOID DosInt21h(WORD CodeSegment)
             break;
         }
 
+        /* Duplicate Handle */
+        case 0x45:
+        {
+            WORD NewHandle;
+            HANDLE Handle = DosGetRealHandle(LOWORD(Ebx));
+
+            if (Handle != INVALID_HANDLE_VALUE)
+            {
+                /* The handle is invalid */
+                EmulatorSetFlag(EMULATOR_FLAG_CF);
+                EmulatorSetRegister(EMULATOR_REG_AX, ERROR_INVALID_HANDLE);
+
+                break;
+            }
+
+            /* Open a new handle to the same entry */
+            NewHandle = DosOpenHandle(Handle);
+
+            if (NewHandle == INVALID_DOS_HANDLE)
+            {
+                /* Too many files open */
+                EmulatorSetFlag(EMULATOR_FLAG_CF);
+                EmulatorSetRegister(EMULATOR_REG_AX, ERROR_TOO_MANY_OPEN_FILES);
+
+                break;
+            }
+
+            /* Return the result */
+            EmulatorClearFlag(EMULATOR_FLAG_CF);
+            EmulatorSetRegister(EMULATOR_REG_AX, NewHandle);
+
+            break;
+        }
+
+        /* Force Duplicate Handle */
+        case 0x46:
+        {
+            if (DosDuplicateHandle(LOWORD(Ebx), LOWORD(Ecx)))
+            {
+                EmulatorClearFlag(EMULATOR_FLAG_CF);
+            }
+            else
+            {
+                EmulatorSetFlag(EMULATOR_FLAG_CF);
+                EmulatorSetRegister(EMULATOR_REG_AX, ERROR_INVALID_HANDLE);
+            }
+
+            break;
+        }
+
         /* Allocate Memory */
         case 0x48:
         {
@@ -1618,6 +1848,14 @@ VOID DosInt21h(WORD CodeSegment)
             break;
         }
 
+        /* Get Current Process */
+        case 0x51:
+        {
+            EmulatorSetRegister(EMULATOR_REG_BX, CurrentPsp);
+
+            break;
+        }
+
         /* Get/Set Memory Management Options */
         case 0x58:
         {
index f5b4d1d..5e9d331 100644 (file)
@@ -109,6 +109,9 @@ WORD DosCreateFile(LPWORD Handle, LPCSTR FilePath, WORD Attributes);
 WORD DosOpenFile(LPWORD Handle, LPCSTR FilePath, BYTE AccessMode);
 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);
+BOOLEAN DosDuplicateHandle(WORD OldHandle, WORD NewHandle);
+BOOLEAN DosCloseHandle(WORD DosHandle);
 VOID DosInitializePsp(WORD PspSegment, LPCSTR CommandLine, WORD ProgramSize, WORD Environment);
 BOOLEAN DosCreateProcess(LPCSTR CommandLine, WORD EnvBlock);
 VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode);