From 7bcfe7b2a8504a4c738cec37ec490ff5de9d57f8 Mon Sep 17 00:00:00 2001 From: Aleksandar Andrejevic Date: Tue, 23 Jul 2013 14:43:03 +0000 Subject: [PATCH] [NTVDM] Implement several INT 21h functions. svn path=/branches/ntvdm/; revision=59563 --- subsystems/ntvdm/dos.c | 238 +++++++++++++++++++++++++++++++++++++++++ subsystems/ntvdm/dos.h | 3 + 2 files changed, 241 insertions(+) diff --git a/subsystems/ntvdm/dos.c b/subsystems/ntvdm/dos.c index 37b0de4ac58..a999421203b 100644 --- a/subsystems/ntvdm/dos.c +++ b/subsystems/ntvdm/dos.c @@ -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: { diff --git a/subsystems/ntvdm/dos.h b/subsystems/ntvdm/dos.h index f5b4d1d883f..5e9d3310724 100644 --- a/subsystems/ntvdm/dos.h +++ b/subsystems/ntvdm/dos.h @@ -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);