mirror of
https://github.com/reactos/reactos.git
synced 2025-05-07 02:41:22 +00:00
[NTVDM]
Implement INT 21h, AH = 52h (Get List of Lists - SYSVARS). Rewrite the SFT code to keep the SFT in guest memory. Implement the NUL device driver. svn path=/trunk/; revision=67444
This commit is contained in:
parent
71a0dd0f0e
commit
12dff944a2
10 changed files with 1126 additions and 926 deletions
|
@ -33,6 +33,7 @@ list(APPEND SOURCE
|
|||
dos/dos32krnl/dos.c
|
||||
dos/dos32krnl/dosfiles.c
|
||||
dos/dos32krnl/emsdrv.c
|
||||
dos/dos32krnl/handle.c
|
||||
dos/dos32krnl/himem.c
|
||||
dos/dos32krnl/memory.c
|
||||
dos/mouse32.c
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "int32.h"
|
||||
|
||||
#include "dos.h"
|
||||
#include "dosfiles.h"
|
||||
#include "memory.h"
|
||||
#include "bios/bios.h"
|
||||
|
||||
|
@ -56,43 +57,33 @@ CHAR DosReadCharacter(WORD FileHandle)
|
|||
|
||||
BOOLEAN DosCheckInput(VOID)
|
||||
{
|
||||
PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(DOS_INPUT_HANDLE);
|
||||
PDOS_FILE_DESCRIPTOR Descriptor = DosGetHandleFileDescriptor(DOS_INPUT_HANDLE);
|
||||
|
||||
if (SftEntry == NULL)
|
||||
if (Descriptor == NULL)
|
||||
{
|
||||
/* Invalid handle */
|
||||
DosLastError = ERROR_INVALID_HANDLE; // ERROR_FILE_NOT_FOUND
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
switch (SftEntry->Type)
|
||||
if (Descriptor->DeviceInfo & (1 << 7))
|
||||
{
|
||||
case DOS_SFT_ENTRY_WIN32:
|
||||
{
|
||||
DWORD FileSizeHigh;
|
||||
DWORD FileSize = GetFileSize(SftEntry->Handle, &FileSizeHigh);
|
||||
LONG LocationHigh = 0;
|
||||
DWORD Location = SetFilePointer(SftEntry->Handle, 0, &LocationHigh, FILE_CURRENT);
|
||||
WORD Result;
|
||||
PDOS_DEVICE_NODE Node = DosGetDriverNode(Descriptor->DevicePointer);
|
||||
|
||||
return ((Location != FileSize) || (LocationHigh != FileSizeHigh));
|
||||
}
|
||||
if (!Node->InputStatusRoutine) return FALSE;
|
||||
|
||||
Result = Node->InputStatusRoutine(Node);
|
||||
return !(Result & DOS_DEVSTAT_BUSY);
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD FileSizeHigh;
|
||||
DWORD FileSize = GetFileSize(Descriptor->Win32Handle, &FileSizeHigh);
|
||||
LONG LocationHigh = 0;
|
||||
DWORD Location = SetFilePointer(Descriptor->Win32Handle, 0, &LocationHigh, FILE_CURRENT);
|
||||
|
||||
case DOS_SFT_ENTRY_DEVICE:
|
||||
{
|
||||
WORD Result;
|
||||
|
||||
if (!SftEntry->DeviceNode->InputStatusRoutine) return FALSE;
|
||||
|
||||
Result = SftEntry->DeviceNode->InputStatusRoutine(SftEntry->DeviceNode);
|
||||
return !(Result & DOS_DEVSTAT_BUSY);
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
/* Invalid handle */
|
||||
DosLastError = ERROR_INVALID_HANDLE;
|
||||
return FALSE;
|
||||
}
|
||||
return ((Location != FileSize) || (LocationHigh != FileSizeHigh));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@ static const BYTE InterruptRoutine[] = {
|
|||
C_ASSERT((sizeof(StrategyRoutine) + sizeof(InterruptRoutine)) == DEVICE_CODE_SIZE);
|
||||
|
||||
static LIST_ENTRY DeviceList = { &DeviceList, &DeviceList };
|
||||
static DWORD FirstDriver = 0xFFFFFFFF;
|
||||
static PDOS_REQUEST_HEADER DeviceRequest;
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
@ -213,17 +212,9 @@ static WORD NTAPI DosDriverDispatchOutputUntilBusy(PDOS_DEVICE_NODE DeviceNode,
|
|||
|
||||
static VOID DosAddDriver(DWORD Driver)
|
||||
{
|
||||
PDOS_DRIVER LastDriver;
|
||||
PDOS_DRIVER LastDriver = &SysVars->NullDevice;
|
||||
|
||||
if (LOWORD(FirstDriver) == 0xFFFF)
|
||||
{
|
||||
/* This is the first driver */
|
||||
FirstDriver = Driver;
|
||||
return;
|
||||
}
|
||||
|
||||
/* The list isn't empty, so find the last driver in it */
|
||||
LastDriver = (PDOS_DRIVER)FAR_POINTER(FirstDriver);
|
||||
/* Find the last driver in the list */
|
||||
while (LOWORD(LastDriver->Link) != 0xFFFF)
|
||||
{
|
||||
LastDriver = (PDOS_DRIVER)FAR_POINTER(LastDriver->Link);
|
||||
|
@ -231,18 +222,25 @@ static VOID DosAddDriver(DWORD Driver)
|
|||
|
||||
/* Add the new driver to the list */
|
||||
LastDriver->Link = Driver;
|
||||
LastDriver = (PDOS_DRIVER)FAR_POINTER(Driver);
|
||||
|
||||
if (LastDriver->DeviceAttributes & DOS_DEVATTR_CLOCK)
|
||||
{
|
||||
/* Update the active CLOCK driver */
|
||||
SysVars->ActiveClock = Driver;
|
||||
}
|
||||
|
||||
if (LastDriver->DeviceAttributes
|
||||
& (DOS_DEVATTR_STDIN | DOS_DEVATTR_STDOUT | DOS_DEVATTR_CON))
|
||||
{
|
||||
/* Update the active CON driver */
|
||||
SysVars->ActiveCon = Driver;
|
||||
}
|
||||
}
|
||||
|
||||
static VOID DosRemoveDriver(DWORD Driver)
|
||||
{
|
||||
DWORD CurrentDriver = FirstDriver;
|
||||
|
||||
if (FirstDriver == Driver)
|
||||
{
|
||||
/* Update the first driver */
|
||||
FirstDriver = ((PDOS_DRIVER)FAR_POINTER(FirstDriver))->Link;
|
||||
return;
|
||||
}
|
||||
DWORD CurrentDriver = MAKELONG(FIELD_OFFSET(DOS_SYSVARS, NullDevice), DOS_DATA_SEGMENT);
|
||||
|
||||
while (LOWORD(CurrentDriver) != 0xFFFF)
|
||||
{
|
||||
|
@ -289,49 +287,55 @@ static PDOS_DEVICE_NODE DosCreateDeviceNode(DWORD Driver)
|
|||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
PDOS_DEVICE_NODE DosGetDevice(LPCSTR DeviceName)
|
||||
PDOS_DEVICE_NODE DosGetDriverNode(DWORD Driver)
|
||||
{
|
||||
PLIST_ENTRY i;
|
||||
DWORD CurrentDriver = FirstDriver;
|
||||
PDOS_DEVICE_NODE Node;
|
||||
|
||||
for (i = DeviceList.Flink; i != &DeviceList; i = i->Flink)
|
||||
{
|
||||
Node = CONTAINING_RECORD(i, DOS_DEVICE_NODE, Entry);
|
||||
if (Node->Driver == Driver) break;
|
||||
}
|
||||
|
||||
if (i == &DeviceList)
|
||||
{
|
||||
DPRINT1("The driver at %04X:%04X has no associated device node. "
|
||||
"Installing automagically.\n",
|
||||
HIWORD(Driver),
|
||||
LOWORD(Driver));
|
||||
|
||||
/* Create the device node */
|
||||
Node = DosCreateDeviceNode(Driver);
|
||||
Node->IoctlReadRoutine = DosDriverDispatchIoctlRead;
|
||||
Node->ReadRoutine = DosDriverDispatchRead;
|
||||
Node->PeekRoutine = DosDriverDispatchPeek;
|
||||
Node->InputStatusRoutine = DosDriverDispatchInputStatus;
|
||||
Node->FlushInputRoutine = DosDriverDispatchFlushInput;
|
||||
Node->IoctlWriteRoutine = DosDriverDispatchIoctlWrite;
|
||||
Node->WriteRoutine = DosDriverDispatchWrite;
|
||||
Node->OutputStatusRoutine = DosDriverDispatchOutputStatus;
|
||||
Node->FlushOutputRoutine = DosDriverDispatchFlushOutput;
|
||||
Node->OpenRoutine = DosDriverDispatchOpen;
|
||||
Node->CloseRoutine = DosDriverDispatchClose;
|
||||
Node->OutputUntilBusyRoutine = DosDriverDispatchOutputUntilBusy;
|
||||
}
|
||||
|
||||
return Node;
|
||||
}
|
||||
|
||||
PDOS_DEVICE_NODE DosGetDevice(LPCSTR DeviceName)
|
||||
{
|
||||
DWORD CurrentDriver = MAKELONG(FIELD_OFFSET(DOS_SYSVARS, NullDevice), DOS_DATA_SEGMENT);
|
||||
ANSI_STRING DeviceNameString;
|
||||
|
||||
RtlInitAnsiString(&DeviceNameString, DeviceName);
|
||||
|
||||
while (LOWORD(CurrentDriver) != 0xFFFF)
|
||||
{
|
||||
PDOS_DEVICE_NODE Node;
|
||||
PDOS_DEVICE_NODE Node = DosGetDriverNode(CurrentDriver);
|
||||
PDOS_DRIVER DriverHeader = (PDOS_DRIVER)FAR_POINTER(CurrentDriver);
|
||||
|
||||
/* Get the device node for this driver */
|
||||
for (i = DeviceList.Flink; i != &DeviceList; i = i->Flink)
|
||||
{
|
||||
Node = CONTAINING_RECORD(i, DOS_DEVICE_NODE, Entry);
|
||||
if (Node->Driver == CurrentDriver) break;
|
||||
}
|
||||
|
||||
if (i == &DeviceList)
|
||||
{
|
||||
DPRINT1("The driver at %04X:%04X has no associated device node. "
|
||||
"Installing automagically.\n",
|
||||
HIWORD(CurrentDriver),
|
||||
LOWORD(CurrentDriver));
|
||||
|
||||
/* Create the device node */
|
||||
Node = DosCreateDeviceNode(CurrentDriver);
|
||||
Node->IoctlReadRoutine = DosDriverDispatchIoctlRead;
|
||||
Node->ReadRoutine = DosDriverDispatchRead;
|
||||
Node->PeekRoutine = DosDriverDispatchPeek;
|
||||
Node->InputStatusRoutine = DosDriverDispatchInputStatus;
|
||||
Node->FlushInputRoutine = DosDriverDispatchFlushInput;
|
||||
Node->IoctlWriteRoutine = DosDriverDispatchIoctlWrite;
|
||||
Node->WriteRoutine = DosDriverDispatchWrite;
|
||||
Node->OutputStatusRoutine = DosDriverDispatchOutputStatus;
|
||||
Node->FlushOutputRoutine = DosDriverDispatchFlushOutput;
|
||||
Node->OpenRoutine = DosDriverDispatchOpen;
|
||||
Node->CloseRoutine = DosDriverDispatchClose;
|
||||
Node->OutputUntilBusyRoutine = DosDriverDispatchOutputUntilBusy;
|
||||
}
|
||||
|
||||
if (RtlEqualString(&Node->Name, &DeviceNameString, TRUE)) return Node;
|
||||
CurrentDriver = DriverHeader->Link;
|
||||
}
|
||||
|
|
|
@ -194,6 +194,7 @@ typedef struct _DOS_OUTPUT_BUSY_REQUEST
|
|||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
PDOS_DEVICE_NODE DosGetDriverNode(DWORD Driver);
|
||||
PDOS_DEVICE_NODE DosGetDevice(LPCSTR DeviceName);
|
||||
PDOS_DEVICE_NODE DosCreateDevice(WORD Attributes, PCHAR DeviceName);
|
||||
PDOS_DEVICE_NODE DosCreateDeviceEx
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#include "dos.h"
|
||||
#include "dos/dem.h"
|
||||
#include "device.h"
|
||||
#include "handle.h"
|
||||
#include "dosfiles.h"
|
||||
#include "memory.h"
|
||||
#include "himem.h"
|
||||
|
||||
|
@ -39,12 +41,13 @@ static DWORD DiskTransferArea;
|
|||
/*static*/ BYTE CurrentDrive;
|
||||
static CHAR LastDrive = 'E';
|
||||
static CHAR CurrentDirectories[NUM_DRIVES][DOS_DIR_LENGTH];
|
||||
static DOS_SFT_ENTRY DosSystemFileTable[DOS_SFT_SIZE];
|
||||
static WORD DosErrorLevel = 0x0000;
|
||||
static PBYTE InDos;
|
||||
|
||||
/* PUBLIC VARIABLES ***********************************************************/
|
||||
|
||||
PDOS_SYSVARS SysVars;
|
||||
|
||||
/* Echo state for INT 21h, AH = 01h and AH = 3Fh */
|
||||
BOOLEAN DoEcho = FALSE;
|
||||
WORD CurrentPsp = SYSTEM_PSP;
|
||||
|
@ -120,456 +123,6 @@ static WORD DosCopyEnvironmentBlock(LPCSTR Environment OPTIONAL,
|
|||
return DestSegment;
|
||||
}
|
||||
|
||||
/* 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 inline PDOS_SFT_ENTRY DosFindFreeSftEntry(VOID)
|
||||
{
|
||||
UINT i;
|
||||
|
||||
for (i = 0; i < DOS_SFT_SIZE; i++)
|
||||
{
|
||||
if (DosSystemFileTable[i].Type == DOS_SFT_ENTRY_NONE)
|
||||
{
|
||||
return &DosSystemFileTable[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline PDOS_SFT_ENTRY DosFindWin32SftEntry(HANDLE Handle)
|
||||
{
|
||||
UINT i;
|
||||
|
||||
for (i = 0; i < DOS_SFT_SIZE; i++)
|
||||
{
|
||||
if (DosSystemFileTable[i].Type == DOS_SFT_ENTRY_WIN32
|
||||
&& DosSystemFileTable[i].Handle == Handle)
|
||||
{
|
||||
return &DosSystemFileTable[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline PDOS_SFT_ENTRY DosFindDeviceSftEntry(PDOS_DEVICE_NODE Device)
|
||||
{
|
||||
UINT i;
|
||||
|
||||
for (i = 0; i < DOS_SFT_SIZE; i++)
|
||||
{
|
||||
if (DosSystemFileTable[i].Type == DOS_SFT_ENTRY_DEVICE
|
||||
&& DosSystemFileTable[i].DeviceNode == Device)
|
||||
{
|
||||
return &DosSystemFileTable[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
WORD DosOpenHandle(HANDLE Handle)
|
||||
{
|
||||
WORD DosHandle;
|
||||
PDOS_PSP PspBlock;
|
||||
LPBYTE HandleTable;
|
||||
PDOS_SFT_ENTRY SftEntry;
|
||||
|
||||
/* The system PSP has no handle table */
|
||||
if (CurrentPsp == SYSTEM_PSP) return INVALID_DOS_HANDLE;
|
||||
|
||||
/* Get a pointer to the handle table */
|
||||
PspBlock = SEGMENT_TO_PSP(CurrentPsp);
|
||||
HandleTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr);
|
||||
|
||||
/* Find a free entry in the JFT */
|
||||
for (DosHandle = 0; DosHandle < PspBlock->HandleTableSize; DosHandle++)
|
||||
{
|
||||
if (HandleTable[DosHandle] == 0xFF) break;
|
||||
}
|
||||
|
||||
/* If there are no free entries, fail */
|
||||
if (DosHandle == PspBlock->HandleTableSize) return INVALID_DOS_HANDLE;
|
||||
|
||||
/* Check if the handle is already in the SFT */
|
||||
SftEntry = DosFindWin32SftEntry(Handle);
|
||||
if (SftEntry != NULL)
|
||||
{
|
||||
/* Already in the table, reference it */
|
||||
SftEntry->RefCount++;
|
||||
goto Finish;
|
||||
}
|
||||
|
||||
/* Find a free SFT entry to use */
|
||||
SftEntry = DosFindFreeSftEntry();
|
||||
if (SftEntry == NULL)
|
||||
{
|
||||
/* The SFT is full */
|
||||
return INVALID_DOS_HANDLE;
|
||||
}
|
||||
|
||||
/* Initialize the empty table entry */
|
||||
SftEntry->Type = DOS_SFT_ENTRY_WIN32;
|
||||
SftEntry->Handle = Handle;
|
||||
SftEntry->RefCount = 1;
|
||||
|
||||
Finish:
|
||||
|
||||
/* Set the JFT entry to that SFT index */
|
||||
HandleTable[DosHandle] = ARRAY_INDEX(SftEntry, DosSystemFileTable);
|
||||
|
||||
/* Return the new handle */
|
||||
return DosHandle;
|
||||
}
|
||||
|
||||
WORD DosOpenDevice(PDOS_DEVICE_NODE Device)
|
||||
{
|
||||
WORD DosHandle;
|
||||
PDOS_PSP PspBlock;
|
||||
LPBYTE HandleTable;
|
||||
PDOS_SFT_ENTRY SftEntry;
|
||||
|
||||
DPRINT("DosOpenDevice(\"%Z\")\n", &Device->Name);
|
||||
|
||||
/* The system PSP has no handle table */
|
||||
if (CurrentPsp == SYSTEM_PSP) return INVALID_DOS_HANDLE;
|
||||
|
||||
/* Get a pointer to the handle table */
|
||||
PspBlock = SEGMENT_TO_PSP(CurrentPsp);
|
||||
HandleTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr);
|
||||
|
||||
/* Find a free entry in the JFT */
|
||||
for (DosHandle = 0; DosHandle < PspBlock->HandleTableSize; DosHandle++)
|
||||
{
|
||||
if (HandleTable[DosHandle] == 0xFF) break;
|
||||
}
|
||||
|
||||
/* If there are no free entries, fail */
|
||||
if (DosHandle == PspBlock->HandleTableSize) return INVALID_DOS_HANDLE;
|
||||
|
||||
/* Check if the device is already in the SFT */
|
||||
SftEntry = DosFindDeviceSftEntry(Device);
|
||||
if (SftEntry != NULL)
|
||||
{
|
||||
/* Already in the table, reference it */
|
||||
SftEntry->RefCount++;
|
||||
goto Finish;
|
||||
}
|
||||
|
||||
/* Find a free SFT entry to use */
|
||||
SftEntry = DosFindFreeSftEntry();
|
||||
if (SftEntry == NULL)
|
||||
{
|
||||
/* The SFT is full */
|
||||
return INVALID_DOS_HANDLE;
|
||||
}
|
||||
|
||||
/* Initialize the empty table entry */
|
||||
SftEntry->Type = DOS_SFT_ENTRY_DEVICE;
|
||||
SftEntry->DeviceNode = Device;
|
||||
SftEntry->RefCount = 1;
|
||||
|
||||
Finish:
|
||||
|
||||
/* Call the open routine, if it exists */
|
||||
if (Device->OpenRoutine) Device->OpenRoutine(Device);
|
||||
|
||||
/* Set the JFT entry to that SFT index */
|
||||
HandleTable[DosHandle] = ARRAY_INDEX(SftEntry, DosSystemFileTable);
|
||||
|
||||
/* Return the new handle */
|
||||
return DosHandle;
|
||||
}
|
||||
|
||||
static VOID DosCopyHandleTable(LPBYTE DestinationTable)
|
||||
{
|
||||
UINT i;
|
||||
PDOS_PSP PspBlock;
|
||||
LPBYTE SourceTable;
|
||||
|
||||
/* Clear the table first */
|
||||
for (i = 0; i < 20; i++) DestinationTable[i] = 0xFF;
|
||||
|
||||
/* Check if this is the initial process */
|
||||
if (CurrentPsp == SYSTEM_PSP)
|
||||
{
|
||||
PDOS_SFT_ENTRY SftEntry;
|
||||
HANDLE StandardHandles[3];
|
||||
PDOS_DEVICE_NODE Con = DosGetDevice("CON");
|
||||
ASSERT(Con != NULL);
|
||||
|
||||
/* Get the native standard handles */
|
||||
StandardHandles[0] = GetStdHandle(STD_INPUT_HANDLE);
|
||||
StandardHandles[1] = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
StandardHandles[2] = GetStdHandle(STD_ERROR_HANDLE);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
/* Find the corresponding SFT entry */
|
||||
if (IsConsoleHandle(StandardHandles[i]))
|
||||
{
|
||||
SftEntry = DosFindDeviceSftEntry(Con);
|
||||
}
|
||||
else
|
||||
{
|
||||
SftEntry = DosFindWin32SftEntry(StandardHandles[i]);
|
||||
}
|
||||
|
||||
if (SftEntry == NULL)
|
||||
{
|
||||
/* Create a new SFT entry for it */
|
||||
SftEntry = DosFindFreeSftEntry();
|
||||
if (SftEntry == NULL)
|
||||
{
|
||||
DPRINT1("Cannot create standard handle %d, the SFT is full!\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
SftEntry->RefCount = 0;
|
||||
|
||||
if (IsConsoleHandle(StandardHandles[i]))
|
||||
{
|
||||
SftEntry->Type = DOS_SFT_ENTRY_DEVICE;
|
||||
SftEntry->DeviceNode = Con;
|
||||
|
||||
/* Call the open routine */
|
||||
if (Con->OpenRoutine) Con->OpenRoutine(Con);
|
||||
}
|
||||
else
|
||||
{
|
||||
SftEntry->Type = DOS_SFT_ENTRY_WIN32;
|
||||
SftEntry->Handle = StandardHandles[i];
|
||||
}
|
||||
}
|
||||
|
||||
SftEntry->RefCount++;
|
||||
DestinationTable[i] = ARRAY_INDEX(SftEntry, DosSystemFileTable);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Get the parent PSP block and handle table */
|
||||
PspBlock = SEGMENT_TO_PSP(CurrentPsp);
|
||||
SourceTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr);
|
||||
|
||||
/* Copy the first 20 handles into the new table */
|
||||
for (i = 0; i < DEFAULT_JFT_SIZE; i++)
|
||||
{
|
||||
DestinationTable[i] = SourceTable[i];
|
||||
|
||||
/* Increase the reference count */
|
||||
DosSystemFileTable[SourceTable[i]].RefCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static BOOLEAN DosResizeHandleTable(WORD NewSize)
|
||||
{
|
||||
PDOS_PSP PspBlock;
|
||||
LPBYTE HandleTable;
|
||||
WORD Segment;
|
||||
|
||||
/* Get the PSP block */
|
||||
PspBlock = SEGMENT_TO_PSP(CurrentPsp);
|
||||
|
||||
if (NewSize == PspBlock->HandleTableSize)
|
||||
{
|
||||
/* No change */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (PspBlock->HandleTableSize > DEFAULT_JFT_SIZE)
|
||||
{
|
||||
/* Get the segment of the current table */
|
||||
Segment = (LOWORD(PspBlock->HandleTablePtr) >> 4) + HIWORD(PspBlock->HandleTablePtr);
|
||||
|
||||
if (NewSize <= DEFAULT_JFT_SIZE)
|
||||
{
|
||||
/* Get the current handle table */
|
||||
HandleTable = FAR_POINTER(PspBlock->HandleTablePtr);
|
||||
|
||||
/* Copy it to the PSP */
|
||||
RtlCopyMemory(PspBlock->HandleTable, HandleTable, NewSize);
|
||||
|
||||
/* Free the memory */
|
||||
DosFreeMemory(Segment);
|
||||
|
||||
/* Update the handle table pointer and size */
|
||||
PspBlock->HandleTableSize = NewSize;
|
||||
PspBlock->HandleTablePtr = MAKELONG(0x18, CurrentPsp);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Resize the memory */
|
||||
if (!DosResizeMemory(Segment, NewSize, NULL))
|
||||
{
|
||||
/* Unable to resize, try allocating it somewhere else */
|
||||
Segment = DosAllocateMemory(NewSize, NULL);
|
||||
if (Segment == 0) return FALSE;
|
||||
|
||||
/* Get the new handle table */
|
||||
HandleTable = SEG_OFF_TO_PTR(Segment, 0);
|
||||
|
||||
/* Copy the handles to the new table */
|
||||
RtlCopyMemory(HandleTable,
|
||||
FAR_POINTER(PspBlock->HandleTablePtr),
|
||||
PspBlock->HandleTableSize);
|
||||
|
||||
/* Update the handle table pointer */
|
||||
PspBlock->HandleTablePtr = MAKELONG(0, Segment);
|
||||
}
|
||||
|
||||
/* Update the handle table size */
|
||||
PspBlock->HandleTableSize = NewSize;
|
||||
}
|
||||
}
|
||||
else if (NewSize > DEFAULT_JFT_SIZE)
|
||||
{
|
||||
Segment = DosAllocateMemory(NewSize, NULL);
|
||||
if (Segment == 0) return FALSE;
|
||||
|
||||
/* Get the new handle table */
|
||||
HandleTable = SEG_OFF_TO_PTR(Segment, 0);
|
||||
|
||||
/* Copy the handles from the PSP to the new table */
|
||||
RtlCopyMemory(HandleTable,
|
||||
FAR_POINTER(PspBlock->HandleTablePtr),
|
||||
PspBlock->HandleTableSize);
|
||||
|
||||
/* Update the handle table pointer and size */
|
||||
PspBlock->HandleTableSize = NewSize;
|
||||
PspBlock->HandleTablePtr = MAKELONG(0, Segment);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOLEAN DosCloseHandle(WORD DosHandle)
|
||||
{
|
||||
PDOS_PSP PspBlock;
|
||||
LPBYTE HandleTable;
|
||||
PDOS_SFT_ENTRY SftEntry;
|
||||
|
||||
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;
|
||||
|
||||
/* Make sure the SFT entry is valid */
|
||||
SftEntry = &DosSystemFileTable[HandleTable[DosHandle]];
|
||||
if (SftEntry->Type == DOS_SFT_ENTRY_NONE) return FALSE;
|
||||
|
||||
/* Decrement the reference count of the SFT entry */
|
||||
SftEntry->RefCount--;
|
||||
|
||||
/* Check if the reference count fell to zero */
|
||||
if (!SftEntry->RefCount)
|
||||
{
|
||||
switch (SftEntry->Type)
|
||||
{
|
||||
case DOS_SFT_ENTRY_WIN32:
|
||||
{
|
||||
/* Close the win32 handle and clear it */
|
||||
CloseHandle(SftEntry->Handle);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case DOS_SFT_ENTRY_DEVICE:
|
||||
{
|
||||
PDOS_DEVICE_NODE Node = SftEntry->DeviceNode;
|
||||
|
||||
/* Call the close routine, if it exists */
|
||||
if (Node->CloseRoutine) SftEntry->DeviceNode->CloseRoutine(SftEntry->DeviceNode);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
/* Shouldn't happen */
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Invalidate the SFT entry */
|
||||
SftEntry->Type = DOS_SFT_ENTRY_NONE;
|
||||
}
|
||||
|
||||
/* Clear the entry in the JFT */
|
||||
HandleTable[DosHandle] = 0xFF;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
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];
|
||||
DosSystemFileTable[SftIndex].RefCount++;
|
||||
|
||||
/* Make the new handle point to that SFT entry */
|
||||
HandleTable[NewHandle] = SftIndex;
|
||||
|
||||
/* Return success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOLEAN DosChangeDrive(BYTE Drive)
|
||||
{
|
||||
WCHAR DirectoryPath[DOS_CMDLINE_LENGTH];
|
||||
|
@ -675,25 +228,6 @@ static BOOLEAN DosControlBreak(VOID)
|
|||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
PDOS_SFT_ENTRY DosGetSftEntry(WORD DosHandle)
|
||||
{
|
||||
PDOS_PSP PspBlock;
|
||||
LPBYTE HandleTable;
|
||||
|
||||
/* The system PSP has no handle table */
|
||||
if (CurrentPsp == SYSTEM_PSP) return NULL;
|
||||
|
||||
/* 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 NULL;
|
||||
|
||||
/* Return a pointer to the SFT entry */
|
||||
return &DosSystemFileTable[HandleTable[DosHandle]];
|
||||
}
|
||||
|
||||
VOID DosInitializePsp(WORD PspSegment,
|
||||
LPCSTR CommandLine,
|
||||
WORD ProgramSize,
|
||||
|
@ -1279,110 +813,6 @@ Done:
|
|||
LOWORD(PspBlock->TerminateAddress));
|
||||
}
|
||||
|
||||
BOOLEAN DosHandleIoctl(BYTE ControlCode, WORD FileHandle)
|
||||
{
|
||||
PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(FileHandle);
|
||||
PDOS_DEVICE_NODE Node = NULL;
|
||||
|
||||
/* Make sure it exists */
|
||||
if (!SftEntry)
|
||||
{
|
||||
DosLastError = ERROR_FILE_NOT_FOUND;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (SftEntry->Type == DOS_SFT_ENTRY_DEVICE) Node = SftEntry->DeviceNode;
|
||||
|
||||
switch (ControlCode)
|
||||
{
|
||||
/* Get Device Information */
|
||||
case 0x00:
|
||||
{
|
||||
WORD InfoWord = 0;
|
||||
|
||||
/*
|
||||
* See Ralf Brown: http://www.ctyme.com/intr/rb-2820.htm
|
||||
* for a list of possible flags.
|
||||
*/
|
||||
|
||||
if (Node)
|
||||
{
|
||||
/* Return the device attributes with bit 7 set */
|
||||
InfoWord = Node->DeviceAttributes | (1 << 7);
|
||||
}
|
||||
|
||||
setDX(InfoWord);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Set Device Information */
|
||||
case 0x01:
|
||||
{
|
||||
// TODO: NOT IMPLEMENTED
|
||||
UNIMPLEMENTED;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Read From Device I/O Control Channel */
|
||||
case 0x02:
|
||||
{
|
||||
WORD Length = getCX();
|
||||
|
||||
if (Node == NULL || !(Node->DeviceAttributes & DOS_DEVATTR_IOCTL))
|
||||
{
|
||||
DosLastError = ERROR_INVALID_FUNCTION;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Do nothing if there is no IOCTL routine */
|
||||
if (!Node->IoctlReadRoutine)
|
||||
{
|
||||
setAX(0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Node->IoctlReadRoutine(Node, MAKELONG(getDX(), getDS()), &Length);
|
||||
|
||||
setAX(Length);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Write To Device I/O Control Channel */
|
||||
case 0x03:
|
||||
{
|
||||
WORD Length = getCX();
|
||||
|
||||
if (Node == NULL || !(Node->DeviceAttributes & DOS_DEVATTR_IOCTL))
|
||||
{
|
||||
DosLastError = ERROR_INVALID_FUNCTION;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Do nothing if there is no IOCTL routine */
|
||||
if (!Node->IoctlWriteRoutine)
|
||||
{
|
||||
setAX(0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Node->IoctlWriteRoutine(Node, MAKELONG(getDX(), getDS()), &Length);
|
||||
|
||||
setAX(Length);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Unsupported control code */
|
||||
default:
|
||||
{
|
||||
DPRINT1("Unsupported IOCTL: 0x%02X\n", ControlCode);
|
||||
|
||||
DosLastError = ERROR_INVALID_PARAMETER;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VOID WINAPI DosInt20h(LPWORD Stack)
|
||||
{
|
||||
/* This is the exit interrupt */
|
||||
|
@ -2196,20 +1626,8 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
|||
case 0x3D:
|
||||
{
|
||||
WORD FileHandle;
|
||||
WORD ErrorCode;
|
||||
LPCSTR FileName = (LPCSTR)SEG_OFF_TO_PTR(getDS(), getDX());
|
||||
PDOS_DEVICE_NODE Device = DosGetDevice(FileName);
|
||||
|
||||
if (Device)
|
||||
{
|
||||
FileHandle = DosOpenDevice(Device);
|
||||
ErrorCode = (FileHandle != INVALID_DOS_HANDLE)
|
||||
? ERROR_SUCCESS : ERROR_TOO_MANY_OPEN_FILES;
|
||||
}
|
||||
else
|
||||
{
|
||||
ErrorCode = DosOpenFile(&FileHandle, FileName, getAL());
|
||||
}
|
||||
WORD ErrorCode = DosOpenFile(&FileHandle, FileName, getAL());
|
||||
|
||||
if (ErrorCode == ERROR_SUCCESS)
|
||||
{
|
||||
|
@ -2391,9 +1809,12 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
|||
/* IOCTL */
|
||||
case 0x44:
|
||||
{
|
||||
if (DosHandleIoctl(getAL(), getBX()))
|
||||
WORD Length = getCX();
|
||||
|
||||
if (DosDeviceIoControl(getBX(), getAL(), MAKELONG(getDX(), getDS()), &Length))
|
||||
{
|
||||
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
|
||||
setAX(Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2407,57 +1828,26 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
|||
/* Duplicate Handle */
|
||||
case 0x45:
|
||||
{
|
||||
WORD NewHandle;
|
||||
PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(getBX());
|
||||
WORD NewHandle = DosDuplicateHandle(getBX());
|
||||
|
||||
if (SftEntry == NULL || SftEntry->Type == DOS_SFT_ENTRY_NONE)
|
||||
if (NewHandle != INVALID_DOS_HANDLE)
|
||||
{
|
||||
setAX(NewHandle);
|
||||
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The handle is invalid */
|
||||
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
|
||||
setAX(ERROR_INVALID_HANDLE);
|
||||
break;
|
||||
setAX(DosLastError);
|
||||
}
|
||||
|
||||
/* Open a new handle to the same entry */
|
||||
switch (SftEntry->Type)
|
||||
{
|
||||
case DOS_SFT_ENTRY_WIN32:
|
||||
{
|
||||
NewHandle = DosOpenHandle(SftEntry->Handle);
|
||||
break;
|
||||
}
|
||||
|
||||
case DOS_SFT_ENTRY_DEVICE:
|
||||
{
|
||||
NewHandle = DosOpenDevice(SftEntry->DeviceNode);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
/* Shouldn't happen */
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
if (NewHandle == INVALID_DOS_HANDLE)
|
||||
{
|
||||
/* Too many files open */
|
||||
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
|
||||
setAX(ERROR_TOO_MANY_OPEN_FILES);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Return the result */
|
||||
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
|
||||
setAX(NewHandle);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Force Duplicate Handle */
|
||||
case 0x46:
|
||||
{
|
||||
if (DosDuplicateHandle(getBX(), getCX()))
|
||||
if (DosForceDuplicateHandle(getBX(), getCX()))
|
||||
{
|
||||
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
|
||||
}
|
||||
|
@ -2686,10 +2076,9 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
|||
*/
|
||||
|
||||
/* Return the DOS "list of lists" in ES:BX */
|
||||
setES(0x0000);
|
||||
setBX(0x0000);
|
||||
setES(DOS_DATA_SEGMENT);
|
||||
setBX(FIELD_OFFSET(DOS_SYSVARS, FirstDpb));
|
||||
|
||||
DPRINT1("INT 21h, AH=52h: This application requires the internal DOS List of lists (SYSVARS). UNIMPLEMENTED\n");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2850,44 +2239,30 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
|||
/* Lock/Unlock Region of File */
|
||||
case 0x5C:
|
||||
{
|
||||
PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(getBX());
|
||||
|
||||
if (SftEntry == NULL || SftEntry->Type != DOS_SFT_ENTRY_WIN32)
|
||||
{
|
||||
/* The handle is invalid */
|
||||
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
|
||||
setAX(ERROR_INVALID_HANDLE);
|
||||
break;
|
||||
}
|
||||
|
||||
if (getAL() == 0x00)
|
||||
{
|
||||
/* Lock region of file */
|
||||
if (LockFile(SftEntry->Handle,
|
||||
MAKELONG(getCX(), getDX()), 0,
|
||||
MAKELONG(getSI(), getDI()), 0))
|
||||
if (DosLockFile(getBX(), MAKELONG(getCX(), getDX()), MAKELONG(getSI(), getDI())))
|
||||
{
|
||||
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
|
||||
}
|
||||
else
|
||||
{
|
||||
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
|
||||
setAX(GetLastError());
|
||||
setAX(DosLastError);
|
||||
}
|
||||
}
|
||||
else if (getAL() == 0x01)
|
||||
{
|
||||
/* Unlock region of file */
|
||||
if (UnlockFile(SftEntry->Handle,
|
||||
MAKELONG(getCX(), getDX()), 0,
|
||||
MAKELONG(getSI(), getDI()), 0))
|
||||
if (DosUnlockFile(getBX(), MAKELONG(getCX(), getDX()), MAKELONG(getSI(), getDI())))
|
||||
{
|
||||
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
|
||||
}
|
||||
else
|
||||
{
|
||||
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
|
||||
setAX(GetLastError());
|
||||
setAX(DosLastError);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -3109,13 +2484,26 @@ VOID WINAPI DosInt2Fh(LPWORD Stack)
|
|||
|
||||
BOOLEAN DosKRNLInitialize(VOID)
|
||||
{
|
||||
|
||||
#if 1
|
||||
|
||||
UCHAR i;
|
||||
CHAR CurrentDirectory[MAX_PATH];
|
||||
CHAR DosDirectory[DOS_DIR_LENGTH];
|
||||
LPSTR Path;
|
||||
PDOS_SFT Sft;
|
||||
|
||||
const BYTE NullDriverRoutine[] = {
|
||||
/* Strategy routine entry */
|
||||
0x26, // mov [Request.Status], DOS_DEVSTAT_DONE
|
||||
0xC7,
|
||||
0x47,
|
||||
FIELD_OFFSET(DOS_REQUEST_HEADER, Status),
|
||||
LOBYTE(DOS_DEVSTAT_DONE),
|
||||
HIBYTE(DOS_DEVSTAT_DONE),
|
||||
|
||||
/* Interrupt routine entry */
|
||||
0xCB, // retf
|
||||
};
|
||||
|
||||
FILE *Stream;
|
||||
WCHAR Buffer[256];
|
||||
|
@ -3169,11 +2557,34 @@ BOOLEAN DosKRNLInitialize(VOID)
|
|||
fclose(Stream);
|
||||
}
|
||||
|
||||
/* Initialize the list of lists */
|
||||
SysVars = (PDOS_SYSVARS)SEG_OFF_TO_PTR(DOS_DATA_SEGMENT, 0);
|
||||
RtlZeroMemory(SysVars, sizeof(DOS_SYSVARS));
|
||||
SysVars->FirstMcb = FIRST_MCB_SEGMENT;
|
||||
SysVars->FirstSft = MAKELONG(MASTER_SFT_OFFSET, DOS_DATA_SEGMENT);
|
||||
|
||||
/* Initialize the NUL device driver */
|
||||
SysVars->NullDevice.Link = 0xFFFFFFFF;
|
||||
SysVars->NullDevice.DeviceAttributes = DOS_DEVATTR_NUL | DOS_DEVATTR_CHARACTER;
|
||||
SysVars->NullDevice.StrategyRoutine = FIELD_OFFSET(DOS_SYSVARS, NullDriverRoutine);
|
||||
SysVars->NullDevice.InterruptRoutine = SysVars->NullDevice.StrategyRoutine + 6;
|
||||
RtlFillMemory(SysVars->NullDevice.DeviceName,
|
||||
sizeof(SysVars->NullDevice.DeviceName),
|
||||
' ');
|
||||
RtlCopyMemory(SysVars->NullDevice.DeviceName, "NUL", strlen("NUL"));
|
||||
RtlCopyMemory(SysVars->NullDriverRoutine,
|
||||
NullDriverRoutine,
|
||||
sizeof(NullDriverRoutine));
|
||||
|
||||
/* Initialize the SFT */
|
||||
for (i = 0; i < DOS_SFT_SIZE; i++)
|
||||
Sft = (PDOS_SFT)FAR_POINTER(SysVars->FirstSft);
|
||||
Sft->Link = 0xFFFFFFFF;
|
||||
Sft->NumDescriptors = DOS_SFT_SIZE;
|
||||
|
||||
for (i = 0; i < Sft->NumDescriptors; i++)
|
||||
{
|
||||
DosSystemFileTable[i].Type = DOS_SFT_ENTRY_NONE;
|
||||
DosSystemFileTable[i].RefCount = 0;
|
||||
/* Clear the file descriptor entry */
|
||||
RtlZeroMemory(&Sft->FileDescriptors[i], sizeof(DOS_FILE_DESCRIPTOR));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
#define USER_MEMORY_SIZE (0x9FFE - FIRST_MCB_SEGMENT)
|
||||
#define SYSTEM_PSP 0x08
|
||||
#define SYSTEM_ENV_BLOCK 0x800
|
||||
#define DOS_DATA_SEGMENT 0xA0
|
||||
#define MASTER_SFT_OFFSET 0x100
|
||||
|
||||
#define INVALID_DOS_HANDLE 0xFFFF
|
||||
#define DOS_INPUT_HANDLE 0
|
||||
|
@ -48,7 +50,6 @@
|
|||
#define NUM_DRIVES ('Z' - 'A' + 1)
|
||||
#define DOS_CHAR_ATTRIBUTE 0x07
|
||||
#define DOS_PROGRAM_NAME_TAG 0x0001
|
||||
#define DEFAULT_JFT_SIZE 20
|
||||
|
||||
/* 16 MB of EMS memory */
|
||||
#define EMS_TOTAL_PAGES 1024
|
||||
|
@ -60,25 +61,6 @@ typedef enum
|
|||
DOS_LOAD_OVERLAY = 0x03
|
||||
} DOS_EXEC_TYPE;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DOS_SFT_ENTRY_NONE,
|
||||
DOS_SFT_ENTRY_WIN32,
|
||||
DOS_SFT_ENTRY_DEVICE
|
||||
} DOS_SFT_ENTRY_TYPE;
|
||||
|
||||
typedef struct _DOS_SFT_ENTRY
|
||||
{
|
||||
DOS_SFT_ENTRY_TYPE Type;
|
||||
WORD RefCount;
|
||||
|
||||
union
|
||||
{
|
||||
HANDLE Handle;
|
||||
PDOS_DEVICE_NODE DeviceNode;
|
||||
};
|
||||
} DOS_SFT_ENTRY, *PDOS_SFT_ENTRY;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef struct _DOS_FCB
|
||||
|
@ -96,6 +78,30 @@ typedef struct _DOS_FCB
|
|||
BYTE RecordNumber[3];
|
||||
} DOS_FCB, *PDOS_FCB;
|
||||
|
||||
typedef struct _DOS_SYSVARS
|
||||
{
|
||||
DWORD OemHandler;
|
||||
WORD Int21hReturn;
|
||||
WORD ShareRetryCount;
|
||||
WORD ShareRetryDelay;
|
||||
DWORD DiskBuffer;
|
||||
WORD UnreadConInput;
|
||||
WORD FirstMcb;
|
||||
|
||||
/* This is where the SYSVARS really start */
|
||||
DWORD FirstDpb;
|
||||
DWORD FirstSft;
|
||||
DWORD ActiveClock;
|
||||
DWORD ActiveCon;
|
||||
BYTE Reserved0[6];
|
||||
DWORD CurrentDirs;
|
||||
BYTE Reserved1[6];
|
||||
BYTE NumBlockDevices;
|
||||
BYTE NumLocalDrives;
|
||||
DOS_DRIVER NullDevice;
|
||||
BYTE NullDriverRoutine[7];
|
||||
} DOS_SYSVARS, *PDOS_SYSVARS;
|
||||
|
||||
typedef struct _DOS_PSP
|
||||
{
|
||||
BYTE Exit[2];
|
||||
|
@ -128,15 +134,6 @@ typedef struct _DOS_INPUT_BUFFER
|
|||
CHAR Buffer[ANYSIZE_ARRAY];
|
||||
} DOS_INPUT_BUFFER, *PDOS_INPUT_BUFFER;
|
||||
|
||||
typedef struct _DOS_DRIVER_HEADER
|
||||
{
|
||||
DWORD NextDriver;
|
||||
WORD Attributes;
|
||||
WORD StrategyEntry;
|
||||
WORD InterruptEntry;
|
||||
CHAR DeviceName[8];
|
||||
} DOS_DRIVER_HEADER, *PDOS_DRIVER_HEADER;
|
||||
|
||||
typedef struct _DOS_FIND_FILE_BLOCK
|
||||
{
|
||||
CHAR DriveLetter;
|
||||
|
@ -181,6 +178,7 @@ typedef struct _DOS_COUNTRY_CODE_BUFFER
|
|||
extern BOOLEAN DoEcho;
|
||||
extern WORD CurrentPsp;
|
||||
extern WORD DosLastError;
|
||||
extern PDOS_SYSVARS SysVars;
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
|
@ -208,35 +206,6 @@ VOID ConDrvCleanup(VOID);
|
|||
* DOS Kernel Functions
|
||||
* See dos.c
|
||||
*/
|
||||
WORD DosOpenHandle(HANDLE Handle);
|
||||
PDOS_SFT_ENTRY DosGetSftEntry(WORD DosHandle);
|
||||
|
||||
WORD DosCreateFileEx(LPWORD Handle,
|
||||
LPWORD CreationStatus,
|
||||
LPCSTR FilePath,
|
||||
BYTE AccessShareModes,
|
||||
WORD CreateActionFlags,
|
||||
WORD Attributes);
|
||||
WORD DosCreateFile(LPWORD Handle,
|
||||
LPCSTR FilePath,
|
||||
DWORD CreationDisposition,
|
||||
WORD Attributes);
|
||||
WORD DosOpenFile(LPWORD Handle,
|
||||
LPCSTR FilePath,
|
||||
BYTE AccessShareModes);
|
||||
WORD DosReadFile(WORD FileHandle,
|
||||
DWORD Buffer,
|
||||
WORD Count,
|
||||
LPWORD BytesRead);
|
||||
WORD DosWriteFile(WORD FileHandle,
|
||||
DWORD Buffer,
|
||||
WORD Count,
|
||||
LPWORD BytesWritten);
|
||||
WORD DosSeekFile(WORD FileHandle,
|
||||
LONG Offset,
|
||||
BYTE Origin,
|
||||
LPDWORD NewOffset);
|
||||
BOOL DosFlushFileBuffers(WORD FileHandle);
|
||||
|
||||
VOID DosInitializePsp(
|
||||
WORD PspSegment,
|
||||
|
|
|
@ -17,11 +17,125 @@
|
|||
|
||||
#include "dos.h"
|
||||
#include "dos/dem.h"
|
||||
#include "dosfiles.h"
|
||||
#include "handle.h"
|
||||
|
||||
#include "bios/bios.h"
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
BYTE DosFindFreeDescriptor(VOID)
|
||||
{
|
||||
UINT i;
|
||||
BYTE Count = 0;
|
||||
DWORD CurrentSft = SysVars->FirstSft;
|
||||
|
||||
while (LOWORD(CurrentSft) != 0xFFFF)
|
||||
{
|
||||
PDOS_SFT Sft = (PDOS_SFT)FAR_POINTER(CurrentSft);
|
||||
|
||||
for (i = 0; i < Sft->NumDescriptors; i++)
|
||||
{
|
||||
if (Sft->FileDescriptors[i].RefCount == 0) return Count;
|
||||
Count++;
|
||||
}
|
||||
|
||||
/* Go to the next table */
|
||||
CurrentSft = Sft->Link;
|
||||
}
|
||||
|
||||
/* Invalid ID */
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
BYTE DosFindWin32Descriptor(HANDLE Win32Handle)
|
||||
{
|
||||
UINT i;
|
||||
BYTE Count = 0;
|
||||
DWORD CurrentSft = SysVars->FirstSft;
|
||||
|
||||
while (LOWORD(CurrentSft) != 0xFFFF)
|
||||
{
|
||||
PDOS_SFT Sft = (PDOS_SFT)FAR_POINTER(CurrentSft);
|
||||
|
||||
for (i = 0; i < Sft->NumDescriptors; i++)
|
||||
{
|
||||
if ((Sft->FileDescriptors[i].RefCount > 0)
|
||||
&& !(Sft->FileDescriptors[i].DeviceInfo & (1 << 7))
|
||||
&& (Sft->FileDescriptors[i].Win32Handle == Win32Handle))
|
||||
{
|
||||
return Count;
|
||||
}
|
||||
|
||||
Count++;
|
||||
}
|
||||
|
||||
/* Go to the next table */
|
||||
CurrentSft = Sft->Link;
|
||||
}
|
||||
|
||||
/* Invalid ID */
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
BYTE DosFindDeviceDescriptor(DWORD DevicePointer)
|
||||
{
|
||||
UINT i;
|
||||
BYTE Count = 0;
|
||||
DWORD CurrentSft = SysVars->FirstSft;
|
||||
|
||||
while (LOWORD(CurrentSft) != 0xFFFF)
|
||||
{
|
||||
PDOS_SFT Sft = (PDOS_SFT)FAR_POINTER(CurrentSft);
|
||||
|
||||
for (i = 0; i < Sft->NumDescriptors; i++)
|
||||
{
|
||||
if ((Sft->FileDescriptors[i].RefCount > 0)
|
||||
&& (Sft->FileDescriptors[i].DeviceInfo & (1 << 7))
|
||||
&& (Sft->FileDescriptors[i].DevicePointer == DevicePointer))
|
||||
{
|
||||
return Count;
|
||||
}
|
||||
|
||||
Count++;
|
||||
}
|
||||
|
||||
/* Go to the next table */
|
||||
CurrentSft = Sft->Link;
|
||||
}
|
||||
|
||||
/* Invalid ID */
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
PDOS_FILE_DESCRIPTOR DosGetFileDescriptor(BYTE Id)
|
||||
{
|
||||
DWORD CurrentSft = SysVars->FirstSft;
|
||||
|
||||
while (LOWORD(CurrentSft) != 0xFFFF)
|
||||
{
|
||||
PDOS_SFT Sft = (PDOS_SFT)FAR_POINTER(CurrentSft);
|
||||
|
||||
/* Return it if it's in this table */
|
||||
if (Id <= Sft->NumDescriptors) return &Sft->FileDescriptors[Id];
|
||||
|
||||
/* Go to the next table */
|
||||
Id -= Sft->NumDescriptors;
|
||||
CurrentSft = Sft->Link;
|
||||
}
|
||||
|
||||
/* Invalid ID */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PDOS_FILE_DESCRIPTOR DosGetHandleFileDescriptor(WORD DosHandle)
|
||||
{
|
||||
BYTE DescriptorId = DosQueryHandle(DosHandle);
|
||||
if (DescriptorId == 0xFF) return NULL;
|
||||
|
||||
return DosGetFileDescriptor(DescriptorId);
|
||||
}
|
||||
|
||||
WORD DosCreateFileEx(LPWORD Handle,
|
||||
LPWORD CreationStatus,
|
||||
LPCSTR FilePath,
|
||||
|
@ -37,6 +151,8 @@ WORD DosCreateFileEx(LPWORD Handle,
|
|||
DWORD CreationDisposition = 0;
|
||||
BOOL InheritableFile = FALSE;
|
||||
SECURITY_ATTRIBUTES SecurityAttributes;
|
||||
BYTE DescriptorId;
|
||||
PDOS_FILE_DESCRIPTOR Descriptor;
|
||||
|
||||
DPRINT1("DosCreateFileEx: FilePath \"%s\", AccessShareModes 0x%04X, CreateActionFlags 0x%04X, Attributes 0x%04X\n",
|
||||
FilePath, AccessShareModes, CreateActionFlags, Attributes);
|
||||
|
@ -228,8 +344,26 @@ WORD DosCreateFileEx(LPWORD Handle,
|
|||
}
|
||||
}
|
||||
|
||||
DescriptorId = DosFindFreeDescriptor();
|
||||
if (DescriptorId == 0xFF)
|
||||
{
|
||||
/* Close the file and return the error code */
|
||||
CloseHandle(FileHandle);
|
||||
return ERROR_TOO_MANY_OPEN_FILES;
|
||||
}
|
||||
|
||||
/* Set up the new descriptor */
|
||||
Descriptor = DosGetFileDescriptor(DescriptorId);
|
||||
RtlZeroMemory(Descriptor, sizeof(*Descriptor));
|
||||
|
||||
Descriptor->OpenMode = AccessShareModes;
|
||||
Descriptor->Attributes = LOBYTE(GetFileAttributesA(FilePath));
|
||||
Descriptor->Size = GetFileSize(FileHandle, NULL);
|
||||
Descriptor->OwnerPsp = CurrentPsp;
|
||||
Descriptor->Win32Handle = FileHandle;
|
||||
|
||||
/* Open the DOS handle */
|
||||
DosHandle = DosOpenHandle(FileHandle);
|
||||
DosHandle = DosOpenHandle(DescriptorId);
|
||||
if (DosHandle == INVALID_DOS_HANDLE)
|
||||
{
|
||||
/* Close the file and return the error code */
|
||||
|
@ -249,6 +383,8 @@ WORD DosCreateFile(LPWORD Handle,
|
|||
{
|
||||
HANDLE FileHandle;
|
||||
WORD DosHandle;
|
||||
BYTE DescriptorId;
|
||||
PDOS_FILE_DESCRIPTOR Descriptor;
|
||||
|
||||
DPRINT("DosCreateFile: FilePath \"%s\", CreationDisposition 0x%04X, Attributes 0x%04X\n",
|
||||
FilePath, CreationDisposition, Attributes);
|
||||
|
@ -267,8 +403,25 @@ WORD DosCreateFile(LPWORD Handle,
|
|||
return (WORD)GetLastError();
|
||||
}
|
||||
|
||||
DescriptorId = DosFindFreeDescriptor();
|
||||
if (DescriptorId == 0xFF)
|
||||
{
|
||||
/* Close the file and return the error code */
|
||||
CloseHandle(FileHandle);
|
||||
return ERROR_TOO_MANY_OPEN_FILES;
|
||||
}
|
||||
|
||||
/* Set up the new descriptor */
|
||||
Descriptor = DosGetFileDescriptor(DescriptorId);
|
||||
RtlZeroMemory(Descriptor, sizeof(*Descriptor));
|
||||
|
||||
Descriptor->Attributes = LOBYTE(GetFileAttributesA(FilePath));
|
||||
Descriptor->Size = GetFileSize(FileHandle, NULL);
|
||||
Descriptor->OwnerPsp = CurrentPsp;
|
||||
Descriptor->Win32Handle = FileHandle;
|
||||
|
||||
/* Open the DOS handle */
|
||||
DosHandle = DosOpenHandle(FileHandle);
|
||||
DosHandle = DosOpenHandle(DescriptorId);
|
||||
if (DosHandle == INVALID_DOS_HANDLE)
|
||||
{
|
||||
/* Close the file and return the error code */
|
||||
|
@ -285,12 +438,11 @@ WORD DosOpenFile(LPWORD Handle,
|
|||
LPCSTR FilePath,
|
||||
BYTE AccessShareModes)
|
||||
{
|
||||
HANDLE FileHandle;
|
||||
ACCESS_MASK AccessMode = 0;
|
||||
DWORD ShareMode = 0;
|
||||
BOOL InheritableFile = FALSE;
|
||||
SECURITY_ATTRIBUTES SecurityAttributes;
|
||||
HANDLE FileHandle = NULL;
|
||||
PDOS_DEVICE_NODE Node;
|
||||
WORD DosHandle;
|
||||
BYTE DescriptorId;
|
||||
PDOS_FILE_DESCRIPTOR Descriptor;
|
||||
|
||||
DPRINT("DosOpenFile: FilePath \"%s\", AccessShareModes 0x%04X\n",
|
||||
FilePath, AccessShareModes);
|
||||
|
@ -300,86 +452,125 @@ WORD DosOpenFile(LPWORD Handle,
|
|||
// explains what those AccessShareModes are (see the uStyle flag).
|
||||
//
|
||||
|
||||
/* Parse the access mode */
|
||||
switch (AccessShareModes & 0x03)
|
||||
Node = DosGetDevice(FilePath);
|
||||
if (Node != NULL)
|
||||
{
|
||||
/* Read-only */
|
||||
case 0:
|
||||
AccessMode = GENERIC_READ;
|
||||
break;
|
||||
if (Node->OpenRoutine) Node->OpenRoutine(Node);
|
||||
}
|
||||
else
|
||||
{
|
||||
ACCESS_MASK AccessMode = 0;
|
||||
DWORD ShareMode = 0;
|
||||
BOOL InheritableFile = FALSE;
|
||||
SECURITY_ATTRIBUTES SecurityAttributes;
|
||||
|
||||
/* Write only */
|
||||
case 1:
|
||||
AccessMode = GENERIC_WRITE;
|
||||
break;
|
||||
/* Parse the access mode */
|
||||
switch (AccessShareModes & 0x03)
|
||||
{
|
||||
/* Read-only */
|
||||
case 0:
|
||||
AccessMode = GENERIC_READ;
|
||||
break;
|
||||
|
||||
/* Read and write */
|
||||
case 2:
|
||||
AccessMode = GENERIC_READ | GENERIC_WRITE;
|
||||
break;
|
||||
/* Write only */
|
||||
case 1:
|
||||
AccessMode = GENERIC_WRITE;
|
||||
break;
|
||||
|
||||
/* Invalid */
|
||||
default:
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
/* Read and write */
|
||||
case 2:
|
||||
AccessMode = GENERIC_READ | GENERIC_WRITE;
|
||||
break;
|
||||
|
||||
/* Invalid */
|
||||
default:
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Parse the share mode */
|
||||
switch ((AccessShareModes >> 4) & 0x07)
|
||||
{
|
||||
/* Compatibility mode */
|
||||
case 0:
|
||||
ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
||||
break;
|
||||
|
||||
/* No sharing "DenyAll" */
|
||||
case 1:
|
||||
ShareMode = 0;
|
||||
break;
|
||||
|
||||
/* No write share "DenyWrite" */
|
||||
case 2:
|
||||
ShareMode = FILE_SHARE_READ;
|
||||
break;
|
||||
|
||||
/* No read share "DenyRead" */
|
||||
case 3:
|
||||
ShareMode = FILE_SHARE_WRITE;
|
||||
break;
|
||||
|
||||
/* Full share "DenyNone" */
|
||||
case 4:
|
||||
ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
||||
break;
|
||||
|
||||
/* Invalid */
|
||||
default:
|
||||
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,
|
||||
AccessMode,
|
||||
ShareMode,
|
||||
&SecurityAttributes,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
if (FileHandle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
/* Return the error code */
|
||||
return (WORD)GetLastError();
|
||||
}
|
||||
}
|
||||
|
||||
DescriptorId = DosFindFreeDescriptor();
|
||||
if (DescriptorId == 0xFF)
|
||||
{
|
||||
/* Close the file and return the error code */
|
||||
CloseHandle(FileHandle);
|
||||
return ERROR_TOO_MANY_OPEN_FILES;
|
||||
}
|
||||
|
||||
/* Parse the share mode */
|
||||
switch ((AccessShareModes >> 4) & 0x07)
|
||||
/* Set up the new descriptor */
|
||||
Descriptor = DosGetFileDescriptor(DescriptorId);
|
||||
RtlZeroMemory(Descriptor, sizeof(*Descriptor));
|
||||
|
||||
if (Node != NULL)
|
||||
{
|
||||
/* Compatibility mode */
|
||||
case 0:
|
||||
ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
||||
break;
|
||||
|
||||
/* No sharing "DenyAll" */
|
||||
case 1:
|
||||
ShareMode = 0;
|
||||
break;
|
||||
|
||||
/* No write share "DenyWrite" */
|
||||
case 2:
|
||||
ShareMode = FILE_SHARE_READ;
|
||||
break;
|
||||
|
||||
/* No read share "DenyRead" */
|
||||
case 3:
|
||||
ShareMode = FILE_SHARE_WRITE;
|
||||
break;
|
||||
|
||||
/* Full share "DenyNone" */
|
||||
case 4:
|
||||
ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
||||
break;
|
||||
|
||||
/* Invalid */
|
||||
default:
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
Descriptor->DevicePointer = Node->Driver;
|
||||
Descriptor->DeviceInfo = Node->DeviceAttributes | (1 << 7);
|
||||
}
|
||||
|
||||
/* 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,
|
||||
AccessMode,
|
||||
ShareMode,
|
||||
&SecurityAttributes,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
if (FileHandle == INVALID_HANDLE_VALUE)
|
||||
else
|
||||
{
|
||||
/* Return the error code */
|
||||
return (WORD)GetLastError();
|
||||
Descriptor->OpenMode = AccessShareModes;
|
||||
Descriptor->Attributes = LOBYTE(GetFileAttributesA(FilePath));
|
||||
Descriptor->Size = GetFileSize(FileHandle, NULL);
|
||||
Descriptor->OwnerPsp = CurrentPsp;
|
||||
Descriptor->Win32Handle = FileHandle;
|
||||
}
|
||||
|
||||
/* Open the DOS handle */
|
||||
DosHandle = DosOpenHandle(FileHandle);
|
||||
DosHandle = DosOpenHandle(DescriptorId);
|
||||
if (DosHandle == INVALID_DOS_HANDLE)
|
||||
{
|
||||
/* Close the file and return the error code */
|
||||
|
@ -398,27 +589,39 @@ WORD DosReadFile(WORD FileHandle,
|
|||
LPWORD BytesRead)
|
||||
{
|
||||
WORD Result = ERROR_SUCCESS;
|
||||
PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(FileHandle);
|
||||
PDOS_FILE_DESCRIPTOR Descriptor = DosGetHandleFileDescriptor(FileHandle);
|
||||
|
||||
DPRINT("DosReadFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle, Count);
|
||||
|
||||
if (SftEntry == NULL)
|
||||
if (Descriptor == NULL)
|
||||
{
|
||||
/* Invalid handle */
|
||||
return ERROR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (SftEntry->Type == DOS_SFT_ENTRY_WIN32)
|
||||
if (Descriptor->DeviceInfo & (1 << 7))
|
||||
{
|
||||
PDOS_DEVICE_NODE Node = DosGetDriverNode(Descriptor->DevicePointer);
|
||||
if (!Node->ReadRoutine) return ERROR_INVALID_FUNCTION;
|
||||
|
||||
/* Read the device */
|
||||
Node->ReadRoutine(Node, Buffer, &Count);
|
||||
*BytesRead = Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD BytesRead32 = 0;
|
||||
LPVOID LocalBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Count);
|
||||
ASSERT(LocalBuffer != NULL);
|
||||
|
||||
/* Read the file */
|
||||
if (ReadFile(SftEntry->Handle, LocalBuffer, Count, &BytesRead32, NULL))
|
||||
if (ReadFile(Descriptor->Win32Handle, LocalBuffer, Count, &BytesRead32, NULL))
|
||||
{
|
||||
/* Write to the memory */
|
||||
MemWrite(TO_LINEAR(HIWORD(Buffer), LOWORD(Buffer)), LocalBuffer, LOWORD(BytesRead32));
|
||||
|
||||
/* Update the position */
|
||||
Descriptor->Position += BytesRead32;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -430,19 +633,6 @@ WORD DosReadFile(WORD FileHandle,
|
|||
*BytesRead = LOWORD(BytesRead32);
|
||||
RtlFreeHeap(RtlGetProcessHeap(), 0, LocalBuffer);
|
||||
}
|
||||
else if (SftEntry->Type == DOS_SFT_ENTRY_DEVICE)
|
||||
{
|
||||
if (!SftEntry->DeviceNode->ReadRoutine) return ERROR_INVALID_FUNCTION;
|
||||
|
||||
/* Read the device */
|
||||
SftEntry->DeviceNode->ReadRoutine(SftEntry->DeviceNode, Buffer, &Count);
|
||||
*BytesRead = Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Invalid handle */
|
||||
return ERROR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
/* Return the error code */
|
||||
return Result;
|
||||
|
@ -454,17 +644,26 @@ WORD DosWriteFile(WORD FileHandle,
|
|||
LPWORD BytesWritten)
|
||||
{
|
||||
WORD Result = ERROR_SUCCESS;
|
||||
PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(FileHandle);
|
||||
PDOS_FILE_DESCRIPTOR Descriptor = DosGetHandleFileDescriptor(FileHandle);
|
||||
|
||||
DPRINT("DosWriteFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle, Count);
|
||||
|
||||
if (SftEntry == NULL)
|
||||
if (Descriptor == NULL)
|
||||
{
|
||||
/* Invalid handle */
|
||||
return ERROR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (SftEntry->Type == DOS_SFT_ENTRY_WIN32)
|
||||
if (Descriptor->DeviceInfo & (1 << 7))
|
||||
{
|
||||
PDOS_DEVICE_NODE Node = DosGetDriverNode(Descriptor->DevicePointer);
|
||||
if (!Node->WriteRoutine) return ERROR_INVALID_FUNCTION;
|
||||
|
||||
/* Read the device */
|
||||
Node->WriteRoutine(Node, Buffer, &Count);
|
||||
*BytesWritten = Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD BytesWritten32 = 0;
|
||||
LPVOID LocalBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Count);
|
||||
|
@ -474,7 +673,13 @@ WORD DosWriteFile(WORD FileHandle,
|
|||
MemRead(TO_LINEAR(HIWORD(Buffer), LOWORD(Buffer)), LocalBuffer, Count);
|
||||
|
||||
/* Write the file */
|
||||
if (!WriteFile(SftEntry->Handle, LocalBuffer, Count, &BytesWritten32, NULL))
|
||||
if (WriteFile(Descriptor->Win32Handle, LocalBuffer, Count, &BytesWritten32, NULL))
|
||||
{
|
||||
/* Update the position and size */
|
||||
Descriptor->Position += BytesWritten32;
|
||||
if (Descriptor->Position > Descriptor->Size) Descriptor->Size = Descriptor->Position;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Store the error code */
|
||||
Result = (WORD)GetLastError();
|
||||
|
@ -484,19 +689,6 @@ WORD DosWriteFile(WORD FileHandle,
|
|||
*BytesWritten = LOWORD(BytesWritten32);
|
||||
RtlFreeHeap(RtlGetProcessHeap(), 0, LocalBuffer);
|
||||
}
|
||||
else if (SftEntry->Type == DOS_SFT_ENTRY_DEVICE)
|
||||
{
|
||||
if (!SftEntry->DeviceNode->WriteRoutine) return ERROR_INVALID_FUNCTION;
|
||||
|
||||
/* Read the device */
|
||||
SftEntry->DeviceNode->WriteRoutine(SftEntry->DeviceNode, Buffer, &Count);
|
||||
*BytesWritten = Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Invalid handle */
|
||||
return ERROR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
/* Return the error code */
|
||||
return Result;
|
||||
|
@ -509,25 +701,20 @@ WORD DosSeekFile(WORD FileHandle,
|
|||
{
|
||||
WORD Result = ERROR_SUCCESS;
|
||||
DWORD FilePointer;
|
||||
PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(FileHandle);
|
||||
PDOS_FILE_DESCRIPTOR Descriptor = DosGetHandleFileDescriptor(FileHandle);
|
||||
|
||||
DPRINT("DosSeekFile: FileHandle 0x%04X, Offset 0x%08X, Origin 0x%02X\n",
|
||||
FileHandle,
|
||||
Offset,
|
||||
Origin);
|
||||
|
||||
if (SftEntry == NULL)
|
||||
if (Descriptor == NULL)
|
||||
{
|
||||
/* Invalid handle */
|
||||
return ERROR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (SftEntry->Type == DOS_SFT_ENTRY_NONE)
|
||||
{
|
||||
/* Invalid handle */
|
||||
return ERROR_INVALID_HANDLE;
|
||||
}
|
||||
else if (SftEntry->Type == DOS_SFT_ENTRY_DEVICE)
|
||||
if (Descriptor->DeviceInfo & (1 << 7))
|
||||
{
|
||||
/* For character devices, always return success */
|
||||
return ERROR_SUCCESS;
|
||||
|
@ -539,7 +726,7 @@ WORD DosSeekFile(WORD FileHandle,
|
|||
return ERROR_INVALID_FUNCTION;
|
||||
}
|
||||
|
||||
FilePointer = SetFilePointer(SftEntry->Handle, Offset, NULL, Origin);
|
||||
FilePointer = SetFilePointer(Descriptor->Win32Handle, Offset, NULL, Origin);
|
||||
|
||||
/* Check if there's a possibility the operation failed */
|
||||
if (FilePointer == INVALID_SET_FILE_POINTER)
|
||||
|
@ -554,6 +741,9 @@ WORD DosSeekFile(WORD FileHandle,
|
|||
return Result;
|
||||
}
|
||||
|
||||
/* Update the descriptor */
|
||||
Descriptor->Position = FilePointer;
|
||||
|
||||
/* Return the file pointer, if requested */
|
||||
if (NewOffset) *NewOffset = FilePointer;
|
||||
|
||||
|
@ -563,38 +753,164 @@ WORD DosSeekFile(WORD FileHandle,
|
|||
|
||||
BOOL DosFlushFileBuffers(WORD FileHandle)
|
||||
{
|
||||
PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(FileHandle);
|
||||
PDOS_FILE_DESCRIPTOR Descriptor = DosGetHandleFileDescriptor(FileHandle);
|
||||
|
||||
if (SftEntry == NULL)
|
||||
if (Descriptor == NULL)
|
||||
{
|
||||
/* Invalid handle */
|
||||
return ERROR_INVALID_HANDLE;
|
||||
DosLastError = ERROR_INVALID_HANDLE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
switch (SftEntry->Type)
|
||||
if (Descriptor->DeviceInfo & (1 << 7))
|
||||
{
|
||||
case DOS_SFT_ENTRY_WIN32:
|
||||
PDOS_DEVICE_NODE Node = DosGetDriverNode(Descriptor->DevicePointer);
|
||||
|
||||
if (Node->FlushInputRoutine) Node->FlushInputRoutine(Node);
|
||||
if (Node->FlushOutputRoutine) Node->FlushOutputRoutine(Node);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FlushFileBuffers(Descriptor->Win32Handle);
|
||||
}
|
||||
}
|
||||
|
||||
BOOLEAN DosLockFile(WORD DosHandle, DWORD Offset, DWORD Size)
|
||||
{
|
||||
PDOS_FILE_DESCRIPTOR Descriptor = DosGetHandleFileDescriptor(DosHandle);
|
||||
|
||||
if (Descriptor == NULL)
|
||||
{
|
||||
/* Invalid handle */
|
||||
DosLastError = ERROR_INVALID_HANDLE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Always succeed for character devices */
|
||||
if (Descriptor->DeviceInfo & (1 << 7)) return TRUE;
|
||||
|
||||
if (!LockFile(Descriptor->Win32Handle, Offset, 0, Size, 0))
|
||||
{
|
||||
DosLastError = GetLastError();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOLEAN DosUnlockFile(WORD DosHandle, DWORD Offset, DWORD Size)
|
||||
{
|
||||
PDOS_FILE_DESCRIPTOR Descriptor = DosGetHandleFileDescriptor(DosHandle);
|
||||
|
||||
if (Descriptor == NULL)
|
||||
{
|
||||
/* Invalid handle */
|
||||
DosLastError = ERROR_INVALID_HANDLE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Always succeed for character devices */
|
||||
if (Descriptor->DeviceInfo & (1 << 7)) return TRUE;
|
||||
|
||||
if (!UnlockFile(Descriptor->Win32Handle, Offset, 0, Size, 0))
|
||||
{
|
||||
DosLastError = GetLastError();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOLEAN DosDeviceIoControl(WORD FileHandle, BYTE ControlCode, DWORD Buffer, PWORD Length)
|
||||
{
|
||||
PDOS_FILE_DESCRIPTOR Descriptor = DosGetHandleFileDescriptor(FileHandle);
|
||||
PDOS_DEVICE_NODE Node = NULL;
|
||||
|
||||
if (!Descriptor)
|
||||
{
|
||||
DosLastError = ERROR_INVALID_HANDLE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Descriptor->DeviceInfo & (1 << 7))
|
||||
{
|
||||
Node = DosGetDriverNode(Descriptor->DevicePointer);
|
||||
}
|
||||
|
||||
switch (ControlCode)
|
||||
{
|
||||
/* Get Device Information */
|
||||
case 0x00:
|
||||
{
|
||||
return FlushFileBuffers(SftEntry->Handle);
|
||||
}
|
||||
|
||||
case DOS_SFT_ENTRY_DEVICE:
|
||||
{
|
||||
if (SftEntry->DeviceNode->FlushInputRoutine)
|
||||
SftEntry->DeviceNode->FlushInputRoutine(SftEntry->DeviceNode);
|
||||
|
||||
if (SftEntry->DeviceNode->FlushOutputRoutine)
|
||||
SftEntry->DeviceNode->FlushOutputRoutine(SftEntry->DeviceNode);
|
||||
|
||||
/*
|
||||
* See Ralf Brown: http://www.ctyme.com/intr/rb-2820.htm
|
||||
* for a list of possible flags.
|
||||
*/
|
||||
setDX(Descriptor->DeviceInfo);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* Set Device Information */
|
||||
case 0x01:
|
||||
{
|
||||
// TODO: NOT IMPLEMENTED
|
||||
UNIMPLEMENTED;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Read From Device I/O Control Channel */
|
||||
case 0x02:
|
||||
{
|
||||
if (Node == NULL || !(Node->DeviceAttributes & DOS_DEVATTR_IOCTL))
|
||||
{
|
||||
DosLastError = ERROR_INVALID_FUNCTION;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Do nothing if there is no IOCTL routine */
|
||||
if (!Node->IoctlReadRoutine)
|
||||
{
|
||||
*Length = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Node->IoctlReadRoutine(Node, Buffer, Length);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Write To Device I/O Control Channel */
|
||||
case 0x03:
|
||||
{
|
||||
if (Node == NULL || !(Node->DeviceAttributes & DOS_DEVATTR_IOCTL))
|
||||
{
|
||||
DosLastError = ERROR_INVALID_FUNCTION;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Do nothing if there is no IOCTL routine */
|
||||
if (!Node->IoctlWriteRoutine)
|
||||
{
|
||||
*Length = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Node->IoctlWriteRoutine(Node, Buffer, Length);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Unsupported control code */
|
||||
default:
|
||||
{
|
||||
/* Invalid handle */
|
||||
DPRINT1("Unsupported IOCTL: 0x%02X\n", ControlCode);
|
||||
|
||||
DosLastError = ERROR_INVALID_PARAMETER;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* EOF */
|
||||
|
|
108
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.h
Normal file
108
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.h
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: dos/dos32krnl/dosfiles.h
|
||||
* PURPOSE: DOS32 Files Support
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*/
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef struct _DOS_FILE_DESCRIPTOR
|
||||
{
|
||||
WORD RefCount;
|
||||
WORD OpenMode;
|
||||
BYTE Attributes;
|
||||
WORD DeviceInfo;
|
||||
DWORD DevicePointer;
|
||||
WORD Time;
|
||||
WORD Date;
|
||||
DWORD Size;
|
||||
DWORD Position;
|
||||
DWORD Reserved;
|
||||
WORD OwnerPsp;
|
||||
HANDLE Win32Handle;
|
||||
BYTE Padding[0x1E - sizeof(HANDLE)];
|
||||
} DOS_FILE_DESCRIPTOR, *PDOS_FILE_DESCRIPTOR;
|
||||
|
||||
C_ASSERT(sizeof(DOS_FILE_DESCRIPTOR) == 0x3B);
|
||||
|
||||
typedef struct _DOS_SFT
|
||||
{
|
||||
DWORD Link;
|
||||
WORD NumDescriptors;
|
||||
DOS_FILE_DESCRIPTOR FileDescriptors[ANYSIZE_ARRAY];
|
||||
} DOS_SFT, *PDOS_SFT;
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
BYTE DosFindFreeDescriptor(VOID);
|
||||
BYTE DosFindWin32Descriptor(HANDLE Win32Handle);
|
||||
BYTE DosFindDeviceDescriptor(DWORD DevicePointer);
|
||||
PDOS_FILE_DESCRIPTOR DosGetFileDescriptor(BYTE Id);
|
||||
PDOS_FILE_DESCRIPTOR DosGetHandleFileDescriptor(WORD DosHandle);
|
||||
|
||||
WORD DosCreateFileEx
|
||||
(
|
||||
LPWORD Handle,
|
||||
LPWORD CreationStatus,
|
||||
LPCSTR FilePath,
|
||||
BYTE AccessShareModes,
|
||||
WORD CreateActionFlags,
|
||||
WORD Attributes
|
||||
);
|
||||
|
||||
WORD DosCreateFile
|
||||
(
|
||||
LPWORD Handle,
|
||||
LPCSTR FilePath,
|
||||
DWORD CreationDisposition,
|
||||
WORD Attributes
|
||||
);
|
||||
|
||||
WORD DosOpenFile
|
||||
(
|
||||
LPWORD Handle,
|
||||
LPCSTR FilePath,
|
||||
BYTE AccessShareModes
|
||||
);
|
||||
|
||||
WORD DosReadFile
|
||||
(
|
||||
WORD FileHandle,
|
||||
DWORD Buffer,
|
||||
WORD Count,
|
||||
LPWORD BytesRead
|
||||
);
|
||||
|
||||
WORD DosWriteFile
|
||||
(
|
||||
WORD FileHandle,
|
||||
DWORD Buffer,
|
||||
WORD Count,
|
||||
LPWORD BytesWritten
|
||||
);
|
||||
|
||||
WORD DosSeekFile
|
||||
(
|
||||
WORD FileHandle,
|
||||
LONG Offset,
|
||||
BYTE Origin,
|
||||
LPDWORD NewOffset
|
||||
);
|
||||
|
||||
BOOL DosFlushFileBuffers(WORD FileHandle);
|
||||
BOOLEAN DosLockFile(WORD DosHandle, DWORD Offset, DWORD Size);
|
||||
BOOLEAN DosUnlockFile(WORD DosHandle, DWORD Offset, DWORD Size);
|
||||
|
||||
BOOLEAN DosDeviceIoControl
|
||||
(
|
||||
WORD FileHandle,
|
||||
BYTE ControlCode,
|
||||
DWORD Buffer,
|
||||
PWORD Length
|
||||
);
|
||||
|
||||
#pragma pack(pop)
|
378
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/handle.c
Normal file
378
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/handle.c
Normal file
|
@ -0,0 +1,378 @@
|
|||
/*
|
||||
* COPYRIGHT: GPLv2+ - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: dos/dos32krnl/handle.c
|
||||
* PURPOSE: DOS32 Handles (Job File Table)
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include "ntvdm.h"
|
||||
#include "emulator.h"
|
||||
|
||||
#include "dos.h"
|
||||
#include "dos/dem.h"
|
||||
#include "dosfiles.h"
|
||||
#include "handle.h"
|
||||
#include "memory.h"
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID DosCopyHandleTable(LPBYTE DestinationTable)
|
||||
{
|
||||
UINT i;
|
||||
PDOS_PSP PspBlock;
|
||||
LPBYTE SourceTable;
|
||||
PDOS_FILE_DESCRIPTOR Descriptor;
|
||||
|
||||
/* Clear the table first */
|
||||
for (i = 0; i < DEFAULT_JFT_SIZE; i++) DestinationTable[i] = 0xFF;
|
||||
|
||||
/* Check if this is the initial process */
|
||||
if (CurrentPsp == SYSTEM_PSP)
|
||||
{
|
||||
BYTE DescriptorId;
|
||||
HANDLE StandardHandles[3];
|
||||
|
||||
/* Get the native standard handles */
|
||||
StandardHandles[0] = GetStdHandle(STD_INPUT_HANDLE);
|
||||
StandardHandles[1] = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
StandardHandles[2] = GetStdHandle(STD_ERROR_HANDLE);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
/* Find the corresponding SFT entry */
|
||||
if (IsConsoleHandle(StandardHandles[i]))
|
||||
{
|
||||
DescriptorId = DosFindDeviceDescriptor(SysVars->ActiveCon);
|
||||
}
|
||||
else
|
||||
{
|
||||
DescriptorId = DosFindWin32Descriptor(StandardHandles[i]);
|
||||
}
|
||||
|
||||
if (DescriptorId != 0xFF)
|
||||
{
|
||||
Descriptor = DosGetFileDescriptor(DescriptorId);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Create a new SFT entry for it */
|
||||
DescriptorId = DosFindFreeDescriptor();
|
||||
if (DescriptorId == 0xFF)
|
||||
{
|
||||
DPRINT1("Cannot create standard handle %d, the SFT is full!\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
Descriptor = DosGetFileDescriptor(DescriptorId);
|
||||
ASSERT(Descriptor != NULL);
|
||||
RtlZeroMemory(Descriptor, sizeof(*Descriptor));
|
||||
|
||||
if (IsConsoleHandle(StandardHandles[i]))
|
||||
{
|
||||
PDOS_DEVICE_NODE Node = DosGetDriverNode(SysVars->ActiveCon);
|
||||
|
||||
Descriptor->DeviceInfo = 1 << 7;
|
||||
Descriptor->DevicePointer = SysVars->ActiveCon;
|
||||
|
||||
/* Call the open routine */
|
||||
if (Node->OpenRoutine) Node->OpenRoutine(Node);
|
||||
}
|
||||
else
|
||||
{
|
||||
Descriptor->Win32Handle = StandardHandles[i];
|
||||
}
|
||||
}
|
||||
|
||||
Descriptor->RefCount++;
|
||||
DestinationTable[i] = DescriptorId;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Get the parent PSP block and handle table */
|
||||
PspBlock = SEGMENT_TO_PSP(CurrentPsp);
|
||||
SourceTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr);
|
||||
|
||||
/* Copy the first 20 handles into the new table */
|
||||
for (i = 0; i < DEFAULT_JFT_SIZE; i++)
|
||||
{
|
||||
Descriptor = DosGetFileDescriptor(SourceTable[i]);
|
||||
DestinationTable[i] = SourceTable[i];
|
||||
|
||||
/* Increase the reference count */
|
||||
Descriptor->RefCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOLEAN DosResizeHandleTable(WORD NewSize)
|
||||
{
|
||||
PDOS_PSP PspBlock;
|
||||
LPBYTE HandleTable;
|
||||
WORD Segment;
|
||||
|
||||
/* Get the PSP block */
|
||||
PspBlock = SEGMENT_TO_PSP(CurrentPsp);
|
||||
|
||||
if (NewSize == PspBlock->HandleTableSize)
|
||||
{
|
||||
/* No change */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (PspBlock->HandleTableSize > DEFAULT_JFT_SIZE)
|
||||
{
|
||||
/* Get the segment of the current table */
|
||||
Segment = (LOWORD(PspBlock->HandleTablePtr) >> 4) + HIWORD(PspBlock->HandleTablePtr);
|
||||
|
||||
if (NewSize <= DEFAULT_JFT_SIZE)
|
||||
{
|
||||
/* Get the current handle table */
|
||||
HandleTable = FAR_POINTER(PspBlock->HandleTablePtr);
|
||||
|
||||
/* Copy it to the PSP */
|
||||
RtlCopyMemory(PspBlock->HandleTable, HandleTable, NewSize);
|
||||
|
||||
/* Free the memory */
|
||||
DosFreeMemory(Segment);
|
||||
|
||||
/* Update the handle table pointer and size */
|
||||
PspBlock->HandleTableSize = NewSize;
|
||||
PspBlock->HandleTablePtr = MAKELONG(0x18, CurrentPsp);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Resize the memory */
|
||||
if (!DosResizeMemory(Segment, NewSize, NULL))
|
||||
{
|
||||
/* Unable to resize, try allocating it somewhere else */
|
||||
Segment = DosAllocateMemory(NewSize, NULL);
|
||||
if (Segment == 0) return FALSE;
|
||||
|
||||
/* Get the new handle table */
|
||||
HandleTable = SEG_OFF_TO_PTR(Segment, 0);
|
||||
|
||||
/* Copy the handles to the new table */
|
||||
RtlCopyMemory(HandleTable,
|
||||
FAR_POINTER(PspBlock->HandleTablePtr),
|
||||
PspBlock->HandleTableSize);
|
||||
|
||||
/* Update the handle table pointer */
|
||||
PspBlock->HandleTablePtr = MAKELONG(0, Segment);
|
||||
}
|
||||
|
||||
/* Update the handle table size */
|
||||
PspBlock->HandleTableSize = NewSize;
|
||||
}
|
||||
}
|
||||
else if (NewSize > DEFAULT_JFT_SIZE)
|
||||
{
|
||||
Segment = DosAllocateMemory(NewSize, NULL);
|
||||
if (Segment == 0) return FALSE;
|
||||
|
||||
/* Get the new handle table */
|
||||
HandleTable = SEG_OFF_TO_PTR(Segment, 0);
|
||||
|
||||
/* Copy the handles from the PSP to the new table */
|
||||
RtlCopyMemory(HandleTable,
|
||||
FAR_POINTER(PspBlock->HandleTablePtr),
|
||||
PspBlock->HandleTableSize);
|
||||
|
||||
/* Update the handle table pointer and size */
|
||||
PspBlock->HandleTableSize = NewSize;
|
||||
PspBlock->HandleTablePtr = MAKELONG(0, Segment);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
WORD DosOpenHandle(BYTE DescriptorId)
|
||||
{
|
||||
WORD DosHandle;
|
||||
PDOS_PSP PspBlock;
|
||||
LPBYTE HandleTable;
|
||||
PDOS_FILE_DESCRIPTOR Descriptor = DosGetFileDescriptor(DescriptorId);
|
||||
|
||||
DPRINT("DosOpenHandle: DescriptorId 0x%02X\n", DescriptorId);
|
||||
|
||||
/* Make sure the descriptor ID is valid */
|
||||
if (Descriptor == NULL) return INVALID_DOS_HANDLE;
|
||||
|
||||
/* The system PSP has no handle table */
|
||||
if (CurrentPsp == SYSTEM_PSP) return INVALID_DOS_HANDLE;
|
||||
|
||||
/* Get a pointer to the handle table */
|
||||
PspBlock = SEGMENT_TO_PSP(CurrentPsp);
|
||||
HandleTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr);
|
||||
|
||||
/* Find a free entry in the JFT */
|
||||
for (DosHandle = 0; DosHandle < PspBlock->HandleTableSize; DosHandle++)
|
||||
{
|
||||
if (HandleTable[DosHandle] == 0xFF) break;
|
||||
}
|
||||
|
||||
/* If there are no free entries, fail */
|
||||
if (DosHandle == PspBlock->HandleTableSize) return INVALID_DOS_HANDLE;
|
||||
|
||||
/* Reference the descriptor */
|
||||
Descriptor->RefCount++;
|
||||
|
||||
/* Set the JFT entry to that descriptor ID */
|
||||
HandleTable[DosHandle] = DescriptorId;
|
||||
|
||||
/* Return the new handle */
|
||||
return DosHandle;
|
||||
}
|
||||
|
||||
BYTE DosQueryHandle(WORD DosHandle)
|
||||
{
|
||||
PDOS_PSP PspBlock;
|
||||
LPBYTE HandleTable;
|
||||
|
||||
DPRINT("DosQueryHandle: DosHandle 0x%04X\n", DosHandle);
|
||||
|
||||
/* The system PSP has no handle table */
|
||||
if (CurrentPsp == SYSTEM_PSP) return 0xFF;
|
||||
|
||||
/* Get a pointer to the handle table */
|
||||
PspBlock = SEGMENT_TO_PSP(CurrentPsp);
|
||||
HandleTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr);
|
||||
|
||||
/* Return the descriptor ID */
|
||||
return HandleTable[DosHandle];
|
||||
}
|
||||
|
||||
WORD DosDuplicateHandle(WORD DosHandle)
|
||||
{
|
||||
BYTE DescriptorId = DosQueryHandle(DosHandle);
|
||||
|
||||
if (DescriptorId == 0xFF)
|
||||
{
|
||||
DosLastError = ERROR_INVALID_HANDLE;
|
||||
return INVALID_DOS_HANDLE;
|
||||
}
|
||||
|
||||
return DosOpenHandle(DescriptorId);
|
||||
}
|
||||
|
||||
BOOLEAN DosForceDuplicateHandle(WORD OldHandle, WORD NewHandle)
|
||||
{
|
||||
BYTE DescriptorId;
|
||||
PDOS_PSP PspBlock;
|
||||
LPBYTE HandleTable;
|
||||
PDOS_FILE_DESCRIPTOR Descriptor;
|
||||
|
||||
DPRINT("DosForceDuplicateHandle: 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);
|
||||
}
|
||||
|
||||
DescriptorId = HandleTable[OldHandle];
|
||||
Descriptor = DosGetFileDescriptor(DescriptorId);
|
||||
if (Descriptor == NULL) return FALSE;
|
||||
|
||||
/* Increment the reference count of the descriptor */
|
||||
Descriptor->RefCount++;
|
||||
|
||||
/* Make the new handle point to that descriptor */
|
||||
HandleTable[NewHandle] = DescriptorId;
|
||||
|
||||
/* Return success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOLEAN DosCloseHandle(WORD DosHandle)
|
||||
{
|
||||
PDOS_PSP PspBlock;
|
||||
LPBYTE HandleTable;
|
||||
PDOS_FILE_DESCRIPTOR Descriptor;
|
||||
|
||||
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;
|
||||
|
||||
/* Make sure the descriptor is valid */
|
||||
Descriptor = DosGetFileDescriptor(HandleTable[DosHandle]);
|
||||
if (Descriptor == NULL) return FALSE;
|
||||
|
||||
/* Decrement the reference count of the descriptor */
|
||||
Descriptor->RefCount--;
|
||||
|
||||
/* Check if the reference count fell to zero */
|
||||
if (!Descriptor->RefCount)
|
||||
{
|
||||
if (Descriptor->DeviceInfo & (1 << 7))
|
||||
{
|
||||
PDOS_DEVICE_NODE Node = DosGetDriverNode(Descriptor->DevicePointer);
|
||||
|
||||
/* Call the close routine, if it exists */
|
||||
if (Node->CloseRoutine) Node->CloseRoutine(Node);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Close the win32 handle */
|
||||
CloseHandle(Descriptor->Win32Handle);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear the entry in the JFT */
|
||||
HandleTable[DosHandle] = 0xFF;
|
||||
|
||||
return TRUE;
|
||||
}
|
21
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/handle.h
Normal file
21
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/handle.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* COPYRIGHT: GPLv2+ - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: dos/dos32krnl/handle.h
|
||||
* PURPOSE: DOS32 Handles (Job File Table)
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*/
|
||||
|
||||
/* DEFINITIONS ****************************************************************/
|
||||
|
||||
#define DEFAULT_JFT_SIZE 20
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
VOID DosCopyHandleTable(LPBYTE DestinationTable);
|
||||
BOOLEAN DosResizeHandleTable(WORD NewSize);
|
||||
WORD DosOpenHandle(BYTE DescriptorId);
|
||||
BYTE DosQueryHandle(WORD DosHandle);
|
||||
WORD DosDuplicateHandle(WORD DosHandle);
|
||||
BOOLEAN DosForceDuplicateHandle(WORD OldHandle, WORD NewHandle);
|
||||
BOOLEAN DosCloseHandle(WORD DosHandle);
|
Loading…
Reference in a new issue