diff --git a/subsystems/ntvdm/CMakeLists.txt b/subsystems/ntvdm/CMakeLists.txt index 933d4c19df1..95cc9207fa3 100644 --- a/subsystems/ntvdm/CMakeLists.txt +++ b/subsystems/ntvdm/CMakeLists.txt @@ -15,7 +15,8 @@ list(APPEND SOURCE hardware/speaker.c hardware/timer.c hardware/vga.c - dos/dos.c + dos/dos32/dos.c + dos/dem.c bop.c emulator.c int32.c diff --git a/subsystems/ntvdm/bios/bios.c b/subsystems/ntvdm/bios/bios.c index 8eca3d8228a..8c827eee7b7 100644 --- a/subsystems/ntvdm/bios/bios.c +++ b/subsystems/ntvdm/bios/bios.c @@ -53,7 +53,7 @@ static VOID WINAPI BiosMiscService(LPWORD Stack) case 0x86: { /* - * Interval in microseconds CX:DX + * Interval in microseconds in CX:DX * See Ralf Brown: http://www.ctyme.com/intr/rb-1525.htm * for more information. */ diff --git a/subsystems/ntvdm/dos/dem.c b/subsystems/ntvdm/dos/dem.c new file mode 100644 index 00000000000..9ff801aba79 --- /dev/null +++ b/subsystems/ntvdm/dos/dem.c @@ -0,0 +1,178 @@ +/* + * COPYRIGHT: GPL - See COPYING in the top level directory + * PROJECT: ReactOS Virtual DOS Machine + * FILE: dem.c + * PURPOSE: DOS 32-bit Emulation Support Library - + * This library is used by the built-in NTVDM DOS32 and by + * the NT 16-bit DOS in Windows (via BOPs). It also exposes + * exported functions that can be used by VDDs. + * PROGRAMMERS: Aleksandar Andrejevic + * Hermes Belusca-Maito (hermes.belusca@sfr.fr) + */ + +/* INCLUDES *******************************************************************/ + +#define NDEBUG + +#include "dem.h" + +/* Extra PSDK/NDK Headers */ +#include + +/* PRIVATE VARIABLES **********************************************************/ + +#pragma pack(push, 1) + +typedef struct _VDM_FIND_FILE_BLOCK +{ + CHAR DriveLetter; + CHAR Pattern[11]; + UCHAR AttribMask; + DWORD Unused; + HANDLE SearchHandle; + + /* The following part of the structure is documented */ + UCHAR Attributes; + WORD FileTime; + WORD FileDate; + DWORD FileSize; + CHAR FileName[13]; +} VDM_FIND_FILE_BLOCK, *PVDM_FIND_FILE_BLOCK; + +#pragma pack(pop) + +extern BYTE CurrentDrive; + +/* PRIVATE FUNCTIONS **********************************************************/ + +/* PUBLIC FUNCTIONS ***********************************************************/ + +/* PUBLIC EXPORTED APIS *******************************************************/ + +// demLFNCleanup +// demLFNGetCurrentDirectory + +// demGetFileTimeByHandle_WOW +// demWOWLFNAllocateSearchHandle +// demWOWLFNCloseSearchHandle +// demWOWLFNEntry +// demWOWLFNGetSearchHandle +// demWOWLFNInit + +DWORD +WINAPI +demClientErrorEx(IN HANDLE FileHandle, + IN CHAR Unknown, + IN BOOL Flag) +{ + UNIMPLEMENTED; + return GetLastError(); +} + +DWORD +WINAPI +demFileDelete(IN LPCSTR FileName) +{ + if (DeleteFileA(FileName)) SetLastError(ERROR_SUCCESS); + + return GetLastError(); +} + +DWORD +WINAPI +demFileFindFirst(OUT PVOID lpFindFileData, + IN LPCSTR FileName, + IN WORD AttribMask) +{ + BOOLEAN Success = TRUE; + WIN32_FIND_DATAA FindData; + PVDM_FIND_FILE_BLOCK FindFileBlock = (PVDM_FIND_FILE_BLOCK)lpFindFileData; + + /* Fill the block */ + FindFileBlock->DriveLetter = CurrentDrive + 'A'; + FindFileBlock->AttribMask = AttribMask; + FindFileBlock->SearchHandle = FindFirstFileA(FileName, &FindData); + if (FindFileBlock->SearchHandle == INVALID_HANDLE_VALUE) return GetLastError(); + + do + { + /* Check the attributes */ + if (!((FindData.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | + FILE_ATTRIBUTE_SYSTEM | + FILE_ATTRIBUTE_DIRECTORY)) + & ~AttribMask)) + { + break; + } + } + while ((Success = FindNextFileA(FindFileBlock->SearchHandle, &FindData))); + + if (!Success) return GetLastError(); + + FindFileBlock->Attributes = LOBYTE(FindData.dwFileAttributes); + FileTimeToDosDateTime(&FindData.ftLastWriteTime, + &FindFileBlock->FileDate, + &FindFileBlock->FileTime); + FindFileBlock->FileSize = FindData.nFileSizeHigh ? 0xFFFFFFFF + : FindData.nFileSizeLow; + strcpy(FindFileBlock->FileName, FindData.cAlternateFileName); + + return ERROR_SUCCESS; +} + +DWORD +WINAPI +demFileFindNext(OUT PVOID lpFindFileData) +{ + WIN32_FIND_DATAA FindData; + PVDM_FIND_FILE_BLOCK FindFileBlock = (PVDM_FIND_FILE_BLOCK)lpFindFileData; + + do + { + if (!FindNextFileA(FindFileBlock->SearchHandle, &FindData)) + return GetLastError(); + + /* Update the block */ + FindFileBlock->Attributes = LOBYTE(FindData.dwFileAttributes); + FileTimeToDosDateTime(&FindData.ftLastWriteTime, + &FindFileBlock->FileDate, + &FindFileBlock->FileTime); + FindFileBlock->FileSize = FindData.nFileSizeHigh ? 0xFFFFFFFF + : FindData.nFileSizeLow; + strcpy(FindFileBlock->FileName, FindData.cAlternateFileName); + } + while((FindData.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | + FILE_ATTRIBUTE_SYSTEM | + FILE_ATTRIBUTE_DIRECTORY)) + & ~FindFileBlock->AttribMask); + + return ERROR_SUCCESS; +} + +UCHAR +WINAPI +demGetPhysicalDriveType(IN UCHAR DriveNumber) +{ + UNIMPLEMENTED; + return DOSDEVICE_DRIVE_UNKNOWN; +} + +BOOL +WINAPI +demIsShortPathName(IN LPCSTR Path, + IN BOOL Unknown) +{ + UNIMPLEMENTED; + return FALSE; +} + +DWORD +WINAPI +demSetCurrentDirectoryGetDrive(IN LPCSTR CurrentDirectory, + OUT PUCHAR DriveNumber) +{ + UNIMPLEMENTED; + return ERROR_SUCCESS; +} + +/* EOF */ diff --git a/subsystems/ntvdm/dos/dem.h b/subsystems/ntvdm/dos/dem.h new file mode 100644 index 00000000000..907d9137917 --- /dev/null +++ b/subsystems/ntvdm/dos/dem.h @@ -0,0 +1,79 @@ +/* + * COPYRIGHT: GPL - See COPYING in the top level directory + * PROJECT: ReactOS Virtual DOS Machine + * FILE: dem.h + * PURPOSE: DOS 32-bit Emulation Support Library - + * This library is used by the built-in NTVDM DOS32 and by + * the NT 16-bit DOS in Windows (via BOPs). It also exposes + * exported functions that can be used by VDDs. + * PROGRAMMERS: Aleksandar Andrejevic + * Hermes Belusca-Maito (hermes.belusca@sfr.fr) + */ + +#ifndef _DEM_H_ +#define _DEM_H_ + +/* INCLUDES *******************************************************************/ + +#include "ntvdm.h" + +/* FUNCTIONS ******************************************************************/ + +DWORD +WINAPI +demClientErrorEx +( + IN HANDLE FileHandle, + IN CHAR Unknown, + IN BOOL Flag +); + +DWORD +WINAPI +demFileDelete +( + IN LPCSTR FileName +); + +DWORD +WINAPI +demFileFindFirst +( + OUT PVOID lpFindFileData, + IN LPCSTR FileName, + IN WORD AttribMask +); + +DWORD +WINAPI +demFileFindNext +( + OUT PVOID lpFindFileData +); + +UCHAR +WINAPI +demGetPhysicalDriveType +( + IN UCHAR DriveNumber +); + +BOOL +WINAPI +demIsShortPathName +( + IN LPCSTR Path, + IN BOOL Unknown +); + +DWORD +WINAPI +demSetCurrentDirectoryGetDrive +( + IN LPCSTR CurrentDirectory, + OUT PUCHAR DriveNumber +); + +#endif // _DEM_H_ + +/* EOF */ diff --git a/subsystems/ntvdm/dos/dos.c b/subsystems/ntvdm/dos/dos32/dos.c similarity index 95% rename from subsystems/ntvdm/dos/dos.c rename to subsystems/ntvdm/dos/dos32/dos.c index 53223c91a26..c761d7ff947 100644 --- a/subsystems/ntvdm/dos/dos.c +++ b/subsystems/ntvdm/dos/dos32/dos.c @@ -12,6 +12,7 @@ #include "emulator.h" #include "dos.h" +#include "dos/dem.h" #include "bios/bios.h" #include "bop.h" @@ -23,7 +24,7 @@ static WORD CurrentPsp = SYSTEM_PSP; static WORD DosLastError = 0; static DWORD DiskTransferArea; -static BYTE CurrentDrive; +/*static*/ BYTE CurrentDrive; static CHAR LastDrive = 'E'; static CHAR CurrentDirectories[NUM_DRIVES][DOS_DIR_LENGTH]; static HANDLE DosSystemFileTable[DOS_SFT_SIZE]; @@ -38,30 +39,6 @@ static WORD DosErrorLevel = 0x0000; /* 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); -} - static VOID DosCombineFreeBlocks(WORD StartBlock) { PDOS_MCB CurrentMcb = SEGMENT_TO_MCB(StartBlock), NextMcb; @@ -90,6 +67,279 @@ static VOID DosCombineFreeBlocks(WORD StartBlock) } } +static WORD DosAllocateMemory(WORD Size, WORD *MaxAvailable) +{ + WORD Result = 0, Segment = FIRST_MCB_SEGMENT, MaxSize = 0; + PDOS_MCB CurrentMcb, NextMcb; + BOOLEAN SearchUmb = FALSE; + + DPRINT("DosAllocateMemory: Size 0x%04X\n", Size); + + if (DosUmbLinked && (DosAllocStrategy & (DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW))) + { + /* Search UMB first */ + Segment = UMB_START_SEGMENT; + SearchUmb = TRUE; + } + + while (TRUE) + { + /* Get a pointer to the MCB */ + CurrentMcb = SEGMENT_TO_MCB(Segment); + + /* Make sure it's valid */ + if (CurrentMcb->BlockType != 'M' && CurrentMcb->BlockType != 'Z') + { + DPRINT("The DOS memory arena is corrupted!\n"); + DosLastError = ERROR_ARENA_TRASHED; + return 0; + } + + /* Only check free blocks */ + if (CurrentMcb->OwnerPsp != 0) goto Next; + + /* Combine this free block with adjoining free blocks */ + DosCombineFreeBlocks(Segment); + + /* Update the maximum block size */ + if (CurrentMcb->Size > MaxSize) MaxSize = CurrentMcb->Size; + + /* Check if this block is big enough */ + if (CurrentMcb->Size < Size) goto Next; + + switch (DosAllocStrategy & 0x3F) + { + case DOS_ALLOC_FIRST_FIT: + { + /* For first fit, stop immediately */ + Result = Segment; + goto Done; + } + + case DOS_ALLOC_BEST_FIT: + { + /* For best fit, update the smallest block found so far */ + if ((Result == 0) || (CurrentMcb->Size < SEGMENT_TO_MCB(Result)->Size)) + { + Result = Segment; + } + + break; + } + + case DOS_ALLOC_LAST_FIT: + { + /* For last fit, make the current block the result, but keep searching */ + Result = Segment; + break; + } + } + +Next: + /* If this was the last MCB in the chain, quit */ + if (CurrentMcb->BlockType == 'Z') + { + /* Check if nothing was found while searching through UMBs */ + if ((Result == 0) && SearchUmb && (DosAllocStrategy & DOS_ALLOC_HIGH_LOW)) + { + /* Search low memory */ + Segment = FIRST_MCB_SEGMENT; + continue; + } + + break; + } + + /* Otherwise, update the segment and continue */ + Segment += CurrentMcb->Size + 1; + } + +Done: + + /* If we didn't find a free block, return 0 */ + if (Result == 0) + { + DosLastError = ERROR_NOT_ENOUGH_MEMORY; + if (MaxAvailable) *MaxAvailable = MaxSize; + return 0; + } + + /* Get a pointer to the MCB */ + CurrentMcb = SEGMENT_TO_MCB(Result); + + /* Check if the block is larger than requested */ + if (CurrentMcb->Size > Size) + { + /* It is, split it into two blocks */ + NextMcb = SEGMENT_TO_MCB(Result + Size + 1); + + /* Initialize the new MCB structure */ + NextMcb->BlockType = CurrentMcb->BlockType; + NextMcb->Size = CurrentMcb->Size - Size - 1; + NextMcb->OwnerPsp = 0; + + /* Update the current block */ + CurrentMcb->BlockType = 'M'; + CurrentMcb->Size = Size; + } + + /* Take ownership of the block */ + CurrentMcb->OwnerPsp = CurrentPsp; + + /* Return the segment of the data portion of the block */ + return Result + 1; +} + +static BOOLEAN DosResizeMemory(WORD BlockData, WORD NewSize, WORD *MaxAvailable) +{ + BOOLEAN Success = TRUE; + WORD Segment = BlockData - 1, ReturnSize = 0, NextSegment; + PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment), NextMcb; + + DPRINT("DosResizeMemory: BlockData 0x%04X, NewSize 0x%04X\n", + BlockData, + NewSize); + + /* Make sure this is a valid, allocated block */ + if ((Mcb->BlockType != 'M' && Mcb->BlockType != 'Z') || Mcb->OwnerPsp == 0) + { + Success = FALSE; + DosLastError = ERROR_INVALID_HANDLE; + goto Done; + } + + ReturnSize = Mcb->Size; + + /* Check if we need to expand or contract the block */ + if (NewSize > Mcb->Size) + { + /* We can't expand the last block */ + if (Mcb->BlockType != 'M') + { + Success = FALSE; + goto Done; + } + + /* Get the pointer and segment of the next MCB */ + NextSegment = Segment + Mcb->Size + 1; + NextMcb = SEGMENT_TO_MCB(NextSegment); + + /* Make sure the next segment is free */ + if (NextMcb->OwnerPsp != 0) + { + DPRINT("Cannot expand memory block: next segment is not free!\n"); + DosLastError = ERROR_NOT_ENOUGH_MEMORY; + Success = FALSE; + goto Done; + } + + /* Combine this free block with adjoining free blocks */ + DosCombineFreeBlocks(NextSegment); + + /* Set the maximum possible size of the block */ + ReturnSize += NextMcb->Size + 1; + + /* Maximize the current block */ + Mcb->Size = ReturnSize; + Mcb->BlockType = NextMcb->BlockType; + + /* Invalidate the next block */ + NextMcb->BlockType = 'I'; + + /* Check if the block is larger than requested */ + if (Mcb->Size > NewSize) + { + DPRINT("Block too large, reducing size from 0x%04X to 0x%04X\n", + Mcb->Size, + NewSize); + + /* It is, split it into two blocks */ + NextMcb = SEGMENT_TO_MCB(Segment + NewSize + 1); + + /* Initialize the new MCB structure */ + NextMcb->BlockType = Mcb->BlockType; + NextMcb->Size = Mcb->Size - NewSize - 1; + NextMcb->OwnerPsp = 0; + + /* Update the current block */ + Mcb->BlockType = 'M'; + Mcb->Size = NewSize; + } + } + else if (NewSize < Mcb->Size) + { + DPRINT("Shrinking block from 0x%04X to 0x%04X\n", + Mcb->Size, + NewSize); + + /* Just split the block */ + NextMcb = SEGMENT_TO_MCB(Segment + NewSize + 1); + NextMcb->BlockType = Mcb->BlockType; + NextMcb->Size = Mcb->Size - NewSize - 1; + NextMcb->OwnerPsp = 0; + + /* Update the MCB */ + Mcb->BlockType = 'M'; + Mcb->Size = NewSize; + } + +Done: + /* Check if the operation failed */ + if (!Success) + { + DPRINT("DosResizeMemory FAILED. Maximum available: 0x%04X\n", + ReturnSize); + + /* Return the maximum possible size */ + if (MaxAvailable) *MaxAvailable = ReturnSize; + } + + return Success; +} + +static BOOLEAN DosFreeMemory(WORD BlockData) +{ + PDOS_MCB Mcb = SEGMENT_TO_MCB(BlockData - 1); + + DPRINT("DosFreeMemory: BlockData 0x%04X\n", BlockData); + + /* Make sure the MCB is valid */ + if (Mcb->BlockType != 'M' && Mcb->BlockType != 'Z') + { + DPRINT("MCB block type '%c' not valid!\n", Mcb->BlockType); + return FALSE; + } + + /* Mark the block as free */ + Mcb->OwnerPsp = 0; + + return TRUE; +} + +/* 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 WORD DosCopyEnvironmentBlock(WORD SourceSegment, LPCSTR ProgramName) { PCHAR Ptr, SourceBuffer, DestBuffer = NULL; @@ -265,258 +515,83 @@ static VOID DosCopyHandleTable(LPBYTE DestinationTable) } } -/* PUBLIC FUNCTIONS ***********************************************************/ - -WORD DosAllocateMemory(WORD Size, WORD *MaxAvailable) +static BOOLEAN DosCloseHandle(WORD DosHandle) { - WORD Result = 0, Segment = FIRST_MCB_SEGMENT, MaxSize = 0; - PDOS_MCB CurrentMcb, NextMcb; - BOOLEAN SearchUmb = FALSE; + BYTE SftIndex; + PDOS_PSP PspBlock; + LPBYTE HandleTable; - DPRINT("DosAllocateMemory: Size 0x%04X\n", Size); + DPRINT("DosCloseHandle: DosHandle 0x%04X\n", DosHandle); - if (DosUmbLinked && (DosAllocStrategy & (DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW))) + /* 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; + + /* Decrement the reference count of the SFT entry */ + SftIndex = HandleTable[DosHandle]; + DosSftRefCount[SftIndex]--; + + /* Check if the reference count fell to zero */ + if (!DosSftRefCount[SftIndex]) { - /* Search UMB first */ - Segment = UMB_START_SEGMENT; - SearchUmb = TRUE; + /* Close the file, it's no longer needed */ + CloseHandle(DosSystemFileTable[SftIndex]); + + /* Clear the handle */ + DosSystemFileTable[SftIndex] = INVALID_HANDLE_VALUE; } - while (TRUE) - { - /* Get a pointer to the MCB */ - CurrentMcb = SEGMENT_TO_MCB(Segment); - - /* Make sure it's valid */ - if (CurrentMcb->BlockType != 'M' && CurrentMcb->BlockType != 'Z') - { - DPRINT("The DOS memory arena is corrupted!\n"); - DosLastError = ERROR_ARENA_TRASHED; - return 0; - } - - /* Only check free blocks */ - if (CurrentMcb->OwnerPsp != 0) goto Next; - - /* Combine this free block with adjoining free blocks */ - DosCombineFreeBlocks(Segment); - - /* Update the maximum block size */ - if (CurrentMcb->Size > MaxSize) MaxSize = CurrentMcb->Size; - - /* Check if this block is big enough */ - if (CurrentMcb->Size < Size) goto Next; - - switch (DosAllocStrategy & 0x3F) - { - case DOS_ALLOC_FIRST_FIT: - { - /* For first fit, stop immediately */ - Result = Segment; - goto Done; - } - - case DOS_ALLOC_BEST_FIT: - { - /* For best fit, update the smallest block found so far */ - if ((Result == 0) || (CurrentMcb->Size < SEGMENT_TO_MCB(Result)->Size)) - { - Result = Segment; - } - - break; - } - - case DOS_ALLOC_LAST_FIT: - { - /* For last fit, make the current block the result, but keep searching */ - Result = Segment; - break; - } - } - -Next: - /* If this was the last MCB in the chain, quit */ - if (CurrentMcb->BlockType == 'Z') - { - /* Check if nothing was found while searching through UMBs */ - if ((Result == 0) && SearchUmb && (DosAllocStrategy & DOS_ALLOC_HIGH_LOW)) - { - /* Search low memory */ - Segment = FIRST_MCB_SEGMENT; - continue; - } - - break; - } - - /* Otherwise, update the segment and continue */ - Segment += CurrentMcb->Size + 1; - } - -Done: - - /* If we didn't find a free block, return 0 */ - if (Result == 0) - { - DosLastError = ERROR_NOT_ENOUGH_MEMORY; - if (MaxAvailable) *MaxAvailable = MaxSize; - return 0; - } - - /* Get a pointer to the MCB */ - CurrentMcb = SEGMENT_TO_MCB(Result); - - /* Check if the block is larger than requested */ - if (CurrentMcb->Size > Size) - { - /* It is, split it into two blocks */ - NextMcb = SEGMENT_TO_MCB(Result + Size + 1); - - /* Initialize the new MCB structure */ - NextMcb->BlockType = CurrentMcb->BlockType; - NextMcb->Size = CurrentMcb->Size - Size - 1; - NextMcb->OwnerPsp = 0; - - /* Update the current block */ - CurrentMcb->BlockType = 'M'; - CurrentMcb->Size = Size; - } - - /* Take ownership of the block */ - CurrentMcb->OwnerPsp = CurrentPsp; - - /* Return the segment of the data portion of the block */ - return Result + 1; -} - -BOOLEAN DosResizeMemory(WORD BlockData, WORD NewSize, WORD *MaxAvailable) -{ - BOOLEAN Success = TRUE; - WORD Segment = BlockData - 1, ReturnSize = 0, NextSegment; - PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment), NextMcb; - - DPRINT("DosResizeMemory: BlockData 0x%04X, NewSize 0x%04X\n", - BlockData, - NewSize); - - /* Make sure this is a valid, allocated block */ - if ((Mcb->BlockType != 'M' && Mcb->BlockType != 'Z') || Mcb->OwnerPsp == 0) - { - Success = FALSE; - DosLastError = ERROR_INVALID_HANDLE; - goto Done; - } - - ReturnSize = Mcb->Size; - - /* Check if we need to expand or contract the block */ - if (NewSize > Mcb->Size) - { - /* We can't expand the last block */ - if (Mcb->BlockType != 'M') - { - Success = FALSE; - goto Done; - } - - /* Get the pointer and segment of the next MCB */ - NextSegment = Segment + Mcb->Size + 1; - NextMcb = SEGMENT_TO_MCB(NextSegment); - - /* Make sure the next segment is free */ - if (NextMcb->OwnerPsp != 0) - { - DPRINT("Cannot expand memory block: next segment is not free!\n"); - DosLastError = ERROR_NOT_ENOUGH_MEMORY; - Success = FALSE; - goto Done; - } - - /* Combine this free block with adjoining free blocks */ - DosCombineFreeBlocks(NextSegment); - - /* Set the maximum possible size of the block */ - ReturnSize += NextMcb->Size + 1; - - /* Maximize the current block */ - Mcb->Size = ReturnSize; - Mcb->BlockType = NextMcb->BlockType; - - /* Invalidate the next block */ - NextMcb->BlockType = 'I'; - - /* Check if the block is larger than requested */ - if (Mcb->Size > NewSize) - { - DPRINT("Block too large, reducing size from 0x%04X to 0x%04X\n", - Mcb->Size, - NewSize); - - /* It is, split it into two blocks */ - NextMcb = SEGMENT_TO_MCB(Segment + NewSize + 1); - - /* Initialize the new MCB structure */ - NextMcb->BlockType = Mcb->BlockType; - NextMcb->Size = Mcb->Size - NewSize - 1; - NextMcb->OwnerPsp = 0; - - /* Update the current block */ - Mcb->BlockType = 'M'; - Mcb->Size = NewSize; - } - } - else if (NewSize < Mcb->Size) - { - DPRINT("Shrinking block from 0x%04X to 0x%04X\n", - Mcb->Size, - NewSize); - - /* Just split the block */ - NextMcb = SEGMENT_TO_MCB(Segment + NewSize + 1); - NextMcb->BlockType = Mcb->BlockType; - NextMcb->Size = Mcb->Size - NewSize - 1; - NextMcb->OwnerPsp = 0; - - /* Update the MCB */ - Mcb->BlockType = 'M'; - Mcb->Size = NewSize; - } - -Done: - /* Check if the operation failed */ - if (!Success) - { - DPRINT("DosResizeMemory FAILED. Maximum available: 0x%04X\n", - ReturnSize); - - /* Return the maximum possible size */ - if (MaxAvailable) *MaxAvailable = ReturnSize; - } - - return Success; -} - -BOOLEAN DosFreeMemory(WORD BlockData) -{ - PDOS_MCB Mcb = SEGMENT_TO_MCB(BlockData - 1); - - DPRINT("DosFreeMemory: BlockData 0x%04X\n", BlockData); - - /* Make sure the MCB is valid */ - if (Mcb->BlockType != 'M' && Mcb->BlockType != 'Z') - { - DPRINT("MCB block type '%c' not valid!\n", Mcb->BlockType); - return FALSE; - } - - /* Mark the block as free */ - Mcb->OwnerPsp = 0; + /* Clear the entry in the JFT */ + HandleTable[DosHandle] = 0xFF; return TRUE; } -BOOLEAN DosLinkUmb(VOID) +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]; + DosSftRefCount[SftIndex]++; + + /* Make the new handle point to that SFT entry */ + HandleTable[NewHandle] = SftIndex; + + /* Return success */ + return TRUE; +} + +static BOOLEAN DosLinkUmb(VOID) { DWORD Segment = FIRST_MCB_SEGMENT; PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment); @@ -543,7 +618,7 @@ BOOLEAN DosLinkUmb(VOID) return TRUE; } -BOOLEAN DosUnlinkUmb(VOID) +static BOOLEAN DosUnlinkUmb(VOID) { DWORD Segment = FIRST_MCB_SEGMENT; PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment); @@ -574,7 +649,7 @@ BOOLEAN DosUnlinkUmb(VOID) return TRUE; } -WORD DosCreateFile(LPWORD Handle, LPCSTR FilePath, WORD Attributes) +static WORD DosCreateFile(LPWORD Handle, LPCSTR FilePath, WORD Attributes) { HANDLE FileHandle; WORD DosHandle; @@ -615,7 +690,7 @@ WORD DosCreateFile(LPWORD Handle, LPCSTR FilePath, WORD Attributes) return ERROR_SUCCESS; } -WORD DosOpenFile(LPWORD Handle, LPCSTR FilePath, BYTE AccessMode) +static WORD DosOpenFile(LPWORD Handle, LPCSTR FilePath, BYTE AccessMode) { HANDLE FileHandle; ACCESS_MASK Access = 0; @@ -688,7 +763,7 @@ WORD DosOpenFile(LPWORD Handle, LPCSTR FilePath, BYTE AccessMode) return ERROR_SUCCESS; } -WORD DosReadFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesRead) +static WORD DosReadFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesRead) { WORD Result = ERROR_SUCCESS; DWORD BytesRead32 = 0; @@ -713,7 +788,7 @@ WORD DosReadFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesRead) return Result; } -WORD DosWriteFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesWritten) +static WORD DosWriteFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesWritten) { WORD Result = ERROR_SUCCESS; DWORD BytesWritten32 = 0; @@ -753,7 +828,7 @@ WORD DosWriteFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesWritte return Result; } -WORD DosSeekFile(WORD FileHandle, LONG Offset, BYTE Origin, LPDWORD NewOffset) +static WORD DosSeekFile(WORD FileHandle, LONG Offset, BYTE Origin, LPDWORD NewOffset) { WORD Result = ERROR_SUCCESS; DWORD FilePointer; @@ -796,7 +871,7 @@ WORD DosSeekFile(WORD FileHandle, LONG Offset, BYTE Origin, LPDWORD NewOffset) return ERROR_SUCCESS; } -BOOLEAN DosFlushFileBuffers(WORD FileHandle) +static BOOLEAN DosFlushFileBuffers(WORD FileHandle) { HANDLE Handle = DosGetRealHandle(FileHandle); @@ -814,146 +889,7 @@ BOOLEAN DosFlushFileBuffers(WORD FileHandle) return (BOOLEAN)FlushFileBuffers(Handle); } -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; - PDOS_PSP PspBlock; - LPBYTE HandleTable; - - 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; - - /* Decrement the reference count of the SFT entry */ - SftIndex = HandleTable[DosHandle]; - DosSftRefCount[SftIndex]--; - - /* Check if the reference count fell to zero */ - if (!DosSftRefCount[SftIndex]) - { - /* Close the file, it's no longer needed */ - CloseHandle(DosSystemFileTable[SftIndex]); - - /* Clear the handle */ - DosSystemFileTable[SftIndex] = INVALID_HANDLE_VALUE; - } - - /* Clear the entry in the JFT */ - HandleTable[DosHandle] = 0xFF; - - return TRUE; -} - -WORD DosFindFirstFile(LPSTR FileSpec, WORD AttribMask) -{ - BOOLEAN Success = TRUE; - WIN32_FIND_DATAA FindData; - PVDM_FIND_FILE_BLOCK FindFileBlock = (PVDM_FIND_FILE_BLOCK)FAR_POINTER(DiskTransferArea); - - /* Fill the block */ - FindFileBlock->DriveLetter = CurrentDrive + 'A'; - FindFileBlock->AttribMask = AttribMask; - FindFileBlock->SearchHandle = FindFirstFileA(FileSpec, &FindData); - if (FindFileBlock->SearchHandle == INVALID_HANDLE_VALUE) return GetLastError(); - - do - { - /* Check the attributes */ - if (!((FindData.dwFileAttributes - & (FILE_ATTRIBUTE_HIDDEN - | FILE_ATTRIBUTE_SYSTEM - | FILE_ATTRIBUTE_DIRECTORY)) - & ~AttribMask)) break; - } - while ((Success = FindNextFileA(FindFileBlock->SearchHandle, &FindData))); - - if (!Success) return GetLastError(); - - FindFileBlock->Attributes = LOBYTE(FindData.dwFileAttributes); - FileTimeToDosDateTime(&FindData.ftLastWriteTime, - &FindFileBlock->FileDate, - &FindFileBlock->FileTime); - FindFileBlock->FileSize = FindData.nFileSizeHigh ? 0xFFFFFFFF - : FindData.nFileSizeLow; - strcpy(FindFileBlock->FileName, FindData.cAlternateFileName); - - return ERROR_SUCCESS; -} - -WORD DosFindNextFile(VOID) -{ - WIN32_FIND_DATAA FindData; - PVDM_FIND_FILE_BLOCK FindFileBlock = (PVDM_FIND_FILE_BLOCK)FAR_POINTER(DiskTransferArea); - - do - { - if (!FindNextFileA(FindFileBlock->SearchHandle, &FindData)) return GetLastError(); - - /* Update the block */ - FindFileBlock->Attributes = LOBYTE(FindData.dwFileAttributes); - FileTimeToDosDateTime(&FindData.ftLastWriteTime, - &FindFileBlock->FileDate, - &FindFileBlock->FileTime); - FindFileBlock->FileSize = FindData.nFileSizeHigh ? 0xFFFFFFFF - : FindData.nFileSizeLow; - strcpy(FindFileBlock->FileName, FindData.cAlternateFileName); - } - while((FindData.dwFileAttributes - & (FILE_ATTRIBUTE_HIDDEN - | FILE_ATTRIBUTE_SYSTEM - | FILE_ATTRIBUTE_DIRECTORY)) - & ~FindFileBlock->AttribMask); - - return ERROR_SUCCESS; -} - -BOOLEAN DosChangeDrive(BYTE Drive) +static BOOLEAN DosChangeDrive(BYTE Drive) { WCHAR DirectoryPath[DOS_CMDLINE_LENGTH]; @@ -973,7 +909,7 @@ BOOLEAN DosChangeDrive(BYTE Drive) return TRUE; } -BOOLEAN DosChangeDirectory(LPSTR Directory) +static BOOLEAN DosChangeDirectory(LPSTR Directory) { BYTE DriveNumber; DWORD Attributes; @@ -1040,6 +976,8 @@ BOOLEAN DosChangeDirectory(LPSTR Directory) return TRUE; } +/* PUBLIC FUNCTIONS ***********************************************************/ + VOID DosInitializePsp(WORD PspSegment, LPCSTR CommandLine, WORD ProgramSize, WORD Environment) { PDOS_PSP PspBlock = SEGMENT_TO_PSP(PspSegment); @@ -2279,8 +2217,7 @@ VOID WINAPI DosInt21h(LPWORD Stack) { LPSTR FileName = (LPSTR)SEG_OFF_TO_PTR(getDS(), getDX()); - /* Call the API function */ - if (DeleteFileA(FileName)) + if (demFileDelete(FileName) == ERROR_SUCCESS) { Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; /* @@ -2548,7 +2485,9 @@ VOID WINAPI DosInt21h(LPWORD Stack) /* Find First File */ case 0x4E: { - WORD Result = DosFindFirstFile(SEG_OFF_TO_PTR(getDS(), getDX()), getCX()); + WORD Result = (WORD)demFileFindFirst(FAR_POINTER(DiskTransferArea), + SEG_OFF_TO_PTR(getDS(), getDX()), + getCX()); setAX(Result); if (Result == ERROR_SUCCESS) Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; @@ -2560,7 +2499,7 @@ VOID WINAPI DosInt21h(LPWORD Stack) /* Find Next File */ case 0x4F: { - WORD Result = DosFindNextFile(); + WORD Result = (WORD)demFileFindNext(FAR_POINTER(DiskTransferArea)); setAX(Result); if (Result == ERROR_SUCCESS) Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; diff --git a/subsystems/ntvdm/dos/dos.h b/subsystems/ntvdm/dos/dos32/dos.h similarity index 78% rename from subsystems/ntvdm/dos/dos.h rename to subsystems/ntvdm/dos/dos32/dos.h index 2daa17a1727..500bdfdd031 100644 --- a/subsystems/ntvdm/dos/dos.h +++ b/subsystems/ntvdm/dos/dos32/dos.h @@ -118,36 +118,10 @@ typedef struct _DOS_DRIVER_HEADER CHAR DeviceName[8]; } DOS_DRIVER_HEADER, *PDOS_DRIVER_HEADER; -typedef struct _VDM_FIND_FILE_BLOCK -{ - CHAR DriveLetter; - CHAR Pattern[11]; - UCHAR AttribMask; - DWORD Unused; - HANDLE SearchHandle; - - /* The following part of the structure is documented */ - UCHAR Attributes; - WORD FileTime; - WORD FileDate; - DWORD FileSize; - CHAR FileName[13]; -} VDM_FIND_FILE_BLOCK, *PVDM_FIND_FILE_BLOCK; - #pragma pack(pop) /* FUNCTIONS ******************************************************************/ -WORD DosAllocateMemory(WORD Size, WORD *MaxAvailable); -BOOLEAN DosResizeMemory(WORD BlockData, WORD NewSize, WORD *MaxAvailable); -BOOLEAN DosFreeMemory(WORD BlockData); -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); diff --git a/subsystems/ntvdm/ntvdm.c b/subsystems/ntvdm/ntvdm.c index 91bbe55e2e6..e6a33d6e750 100644 --- a/subsystems/ntvdm/ntvdm.c +++ b/subsystems/ntvdm/ntvdm.c @@ -18,7 +18,7 @@ #include "hardware/ps2.h" #include "hardware/timer.h" #include "hardware/vga.h" -#include "dos/dos.h" +#include "dos/dos32/dos.h" /* * Activate this line if you want to be able to test NTVDM with: diff --git a/subsystems/ntvdm/ntvdm.spec b/subsystems/ntvdm/ntvdm.spec index ceca023a33d..8a9d7b3e60c 100644 --- a/subsystems/ntvdm/ntvdm.spec +++ b/subsystems/ntvdm/ntvdm.spec @@ -175,6 +175,24 @@ +@ stdcall demClientErrorEx(long long long) +@ stdcall demFileDelete(ptr) +@ stdcall demFileFindFirst(ptr ptr long) +@ stdcall demFileFindNext(ptr) +;@ stdcall demGetFileTimeByHandle_WOW +@ stdcall demGetPhysicalDriveType(long) +@ stdcall demIsShortPathName(ptr long) +;@ stdcall demLFNCleanup +;@ stdcall demLFNGetCurrentDirectory +@ stdcall demSetCurrentDirectoryGetDrive(ptr ptr) +;@ stdcall demWOWLFNAllocateSearchHandle +;@ stdcall demWOWLFNCloseSearchHandle +;@ stdcall demWOWLFNEntry +;@ stdcall demWOWLFNGetSearchHandle +;@ stdcall demWOWLFNInit + + + @ stdcall MGetVdmPointer(long long long) @ stdcall Sim32pGetVDMPointer(long long)