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:
Aleksandar Andrejevic 2015-04-26 18:09:57 +00:00
parent 71a0dd0f0e
commit 12dff944a2
10 changed files with 1126 additions and 926 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View 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;
}

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