- Start to refactor the DOS sources:
  Introduce the DEM (DOS Emulation) support library that is used by our built-in DOS, and that is used (via BOPs) by windows NT DOS (files: ntio.sys and ntdos.sys).
- Export some of DEM functions; stub most of them and implement the remaining ones (with existing code that we had in dos.c before).

svn path=/branches/ntvdm/; revision=61838
This commit is contained in:
Hermès Bélusca-Maïto 2014-01-26 18:25:59 +00:00
parent 1608c84d72
commit c98977184f
8 changed files with 637 additions and 448 deletions

View file

@ -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

View file

@ -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.
*/

178
subsystems/ntvdm/dos/dem.c Normal file
View file

@ -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 <theflash AT sdf DOT lonestar DOT org>
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
*/
/* INCLUDES *******************************************************************/
#define NDEBUG
#include "dem.h"
/* Extra PSDK/NDK Headers */
#include <ndk/obtypes.h>
/* 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 */

View file

@ -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 <theflash AT sdf DOT lonestar DOT org>
* 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 */

View file

@ -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;

View file

@ -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);

View file

@ -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:

View file

@ -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)