Author: aandrejevic
Date: Mon Jul 1 02:29:29 2013
New Revision: 59406
URL:
http://svn.reactos.org/svn/reactos?rev=59406&view=rev
Log:
[NTVDM]
Implement file creation, opening, reading and writing.
Modified:
branches/ntvdm/subsystems/ntvdm/dos.c
branches/ntvdm/subsystems/ntvdm/dos.h
branches/ntvdm/subsystems/ntvdm/ntvdm.h
Modified: branches/ntvdm/subsystems/ntvdm/dos.c
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/dos.c?re…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/dos.c [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/dos.c [iso-8859-1] Mon Jul 1 02:29:29 2013
@@ -16,6 +16,8 @@
static WORD CurrentPsp = SYSTEM_PSP;
static DWORD DiskTransferArea;
+static HANDLE DosSystemFileTable[DOS_SFT_SIZE];
+static WORD DosSftRefCount[DOS_SFT_SIZE];
/* PRIVATE FUNCTIONS **********************************************************/
@@ -92,6 +94,125 @@
/* Just set the owner */
Mcb->OwnerPsp = NewOwner;
+}
+
+static WORD DosOpenHandle(HANDLE Handle)
+{
+ BYTE i;
+ WORD DosHandle;
+ PDOS_PSP PspBlock;
+ LPBYTE HandleTable;
+
+ /* 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 */
+ for (i = 0; i < DOS_SFT_SIZE; i++)
+ {
+ /* Check if this is the same handle */
+ if (DosSystemFileTable[i] != Handle) continue;
+
+ /* Already in the table, reference it */
+ DosSftRefCount[i]++;
+
+ /* Set the JFT entry to that SFT index */
+ HandleTable[DosHandle] = i;
+
+ /* Return the new handle */
+ return DosHandle;
+ }
+
+ /* Add the handle to the SFT */
+ for (i = 0; i < DOS_SFT_SIZE; i++)
+ {
+ /* Make sure this is an empty table entry */
+ if (DosSystemFileTable[i] != INVALID_HANDLE_VALUE) continue;
+
+ /* Initialize the empty table entry */
+ DosSystemFileTable[i] = Handle;
+ DosSftRefCount[i] = 1;
+
+ /* Set the JFT entry to that SFT index */
+ HandleTable[DosHandle] = i;
+
+ /* Return the new handle */
+ return DosHandle;
+ }
+
+ /* The SFT is full */
+ return INVALID_DOS_HANDLE;
+}
+
+static HANDLE DosGetRealHandle(WORD DosHandle)
+{
+ PDOS_PSP PspBlock;
+ LPBYTE HandleTable;
+
+ /* The system PSP has no handle table */
+ if (CurrentPsp == SYSTEM_PSP) return INVALID_HANDLE_VALUE;
+
+ /* 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 INVALID_HANDLE_VALUE;
+
+ /* Return the Win32 handle */
+ return DosSystemFileTable[HandleTable[DosHandle]];
+}
+
+static VOID DosCopyHandleTable(LPBYTE DestinationTable)
+{
+ INT 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)
+ {
+ /* Set up the standard I/O devices */
+ for (i = 0; i <= 2; i++)
+ {
+ /* Set the index in the SFT */
+ DestinationTable[i] = i;
+
+ /* Increase the reference count */
+ DosSftRefCount[i]++;
+ }
+
+ /* Done */
+ return;
+ }
+
+ /* 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 < 20; i++)
+ {
+ DestinationTable[i] = SourceTable[i];
+
+ /* Increase the reference count */
+ DosSftRefCount[SourceTable[i]]++;
+ }
}
/* PUBLIC FUNCTIONS ***********************************************************/
@@ -273,21 +394,193 @@
return TRUE;
}
-WORD DosCreateFile(LPCSTR FilePath)
-{
- // TODO: NOT IMPLEMENTED
- return 0;
-}
-
-WORD DosOpenFile(LPCSTR FilePath)
-{
- // TODO: NOT IMPLEMENTED
- return 0;
+WORD DosCreateFile(LPWORD Handle, LPCSTR FilePath, WORD Attributes)
+{
+ HANDLE FileHandle;
+ WORD DosHandle;
+
+ /* Create the file */
+ FileHandle = CreateFileA(FilePath,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ CREATE_ALWAYS,
+ Attributes,
+ NULL);
+
+ if (FileHandle == INVALID_HANDLE_VALUE)
+ {
+ /* Return the error code */
+ return GetLastError();
+ }
+
+ /* Open the DOS handle */
+ DosHandle = DosOpenHandle(FileHandle);
+
+ if (DosHandle == INVALID_DOS_HANDLE)
+ {
+ /* Close the handle */
+ CloseHandle(FileHandle);
+
+ /* Return the error code */
+ return ERROR_TOO_MANY_OPEN_FILES;
+ }
+
+ /* It was successful */
+ *Handle = DosHandle;
+ return ERROR_SUCCESS;
+}
+
+WORD DosOpenFile(LPWORD Handle, LPCSTR FilePath, BYTE AccessMode)
+{
+ HANDLE FileHandle;
+ ACCESS_MASK Access = 0;
+ WORD DosHandle;
+
+ /* Parse the access mode */
+ switch (AccessMode & 3)
+ {
+ case 0:
+ {
+ /* Read-only */
+ Access = GENERIC_READ;
+ break;
+ }
+
+ case 1:
+ {
+ /* Write only */
+ Access = GENERIC_WRITE;
+ break;
+ }
+
+ case 2:
+ {
+ /* Read and write */
+ Access = GENERIC_READ | GENERIC_WRITE;
+ break;
+ }
+
+ default:
+ {
+ /* Invalid */
+ return ERROR_INVALID_PARAMETER;
+ }
+ }
+
+ /* Open the file */
+ FileHandle = CreateFileA(FilePath,
+ Access,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (FileHandle == INVALID_HANDLE_VALUE)
+ {
+ /* Return the error code */
+ return GetLastError();
+ }
+
+ /* Open the DOS handle */
+ DosHandle = DosOpenHandle(FileHandle);
+
+ if (DosHandle == INVALID_DOS_HANDLE)
+ {
+ /* Close the handle */
+ CloseHandle(FileHandle);
+
+ /* Return the error code */
+ return ERROR_TOO_MANY_OPEN_FILES;
+ }
+
+ /* It was successful */
+ *Handle = DosHandle;
+ return ERROR_SUCCESS;
+}
+
+WORD DosReadFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesRead)
+{
+ WORD Result = ERROR_SUCCESS;
+ DWORD BytesRead32 = 0;
+ HANDLE Handle = DosGetRealHandle(FileHandle);
+
+ /* Make sure the handle is valid */
+ if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_PARAMETER;
+
+ /* Read the file */
+ if (!ReadFile(Handle, Buffer, Count, &BytesRead32, NULL))
+ {
+ /* Store the error code */
+ Result = GetLastError();
+ }
+
+ /* The number of bytes read is always 16-bit */
+ *BytesRead = LOWORD(BytesRead32);
+
+ /* Return the error code */
+ return Result;
+}
+
+WORD DosWriteFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesWritten)
+{
+ WORD Result = ERROR_SUCCESS;
+ DWORD BytesWritten32 = 0;
+ HANDLE Handle = DosGetRealHandle(FileHandle);
+
+ /* Make sure the handle is valid */
+ if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_PARAMETER;
+
+ /* Write the file */
+ if (!WriteFile(Handle, Buffer, Count, &BytesWritten32, NULL))
+ {
+ /* Store the error code */
+ Result = GetLastError();
+ }
+
+ /* The number of bytes written is always 16-bit */
+ *BytesWritten = LOWORD(BytesWritten32);
+
+ /* Return the error code */
+ return Result;
+}
+
+BOOLEAN DosCloseHandle(WORD DosHandle)
+{
+ BYTE SftIndex;
+ PDOS_PSP PspBlock;
+ LPBYTE HandleTable;
+
+ /* The system PSP has no handle table */
+ if (CurrentPsp == SYSTEM_PSP) return FALSE;
+
+ /* Get a pointer to the handle table */
+ PspBlock = SEGMENT_TO_PSP(CurrentPsp);
+ HandleTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr);
+
+ /* Make sure the handle is open */
+ if (HandleTable[DosHandle] == 0xFF) return FALSE;
+
+ /* Decrement the reference count of the SFT entry */
+ SftIndex = HandleTable[DosHandle];
+ DosSftRefCount[SftIndex]--;
+
+ /* Check if the reference count fell to zero */
+ if (!DosSftRefCount[SftIndex])
+ {
+ /* Close the file, it's no longer needed */
+ CloseHandle(DosSystemFileTable[SftIndex]);
+
+ /* Clear the handle */
+ DosSystemFileTable[SftIndex] = INVALID_HANDLE_VALUE;
+ }
+
+ return TRUE;
}
VOID DosInitializePsp(WORD PspSegment, LPCSTR CommandLine, WORD ProgramSize, WORD
Environment)
{
- INT i;
PDOS_PSP PspBlock = SEGMENT_TO_PSP(PspSegment);
LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress);
@@ -308,11 +601,10 @@
/* Set the parent PSP */
PspBlock->ParentPsp = CurrentPsp;
- /* Initialize the handle table */
- for (i = 0; i < 20; i++) PspBlock->HandleTable[i] = 0xFF;
-
-
-
+ /* Copy the parent handle table */
+ DosCopyHandleTable(PspBlock->HandleTable);
+
+ /* Set the environment block */
PspBlock->EnvBlock = Environment;
/* Set the handle table pointers to the internal handle table */
@@ -863,6 +1155,152 @@
break;
}
+ /* Create File */
+ case 0x3C:
+ {
+ WORD FileHandle;
+ WORD ErrorCode = DosCreateFile(&FileHandle,
+ (LPCSTR)(ULONG_PTR)BaseAddress
+ + TO_LINEAR(DataSegment, LOWORD(Edx)),
+ LOWORD(Ecx));
+
+ if (ErrorCode == 0)
+ {
+ /* Clear CF */
+ EmulatorClearFlag(EMULATOR_FLAG_CF);
+
+ /* Return the handle in AX */
+ EmulatorSetRegister(EMULATOR_REG_AX,
+ (Eax & 0xFFFF0000) | FileHandle);
+ }
+ else
+ {
+ /* Set CF */
+ EmulatorSetFlag(EMULATOR_FLAG_CF);
+
+ /* Return the error code in AX */
+ EmulatorSetRegister(EMULATOR_REG_AX,
+ (Eax & 0xFFFF0000) | ErrorCode);
+ }
+
+ break;
+ }
+
+ /* Open File */
+ case 0x3D:
+ {
+ WORD FileHandle;
+ WORD ErrorCode = DosCreateFile(&FileHandle,
+ (LPCSTR)(ULONG_PTR)BaseAddress
+ + TO_LINEAR(DataSegment, LOWORD(Edx)),
+ LOBYTE(Eax));
+
+ if (ErrorCode == 0)
+ {
+ /* Clear CF */
+ EmulatorClearFlag(EMULATOR_FLAG_CF);
+
+ /* Return the handle in AX */
+ EmulatorSetRegister(EMULATOR_REG_AX,
+ (Eax & 0xFFFF0000) | FileHandle);
+ }
+ else
+ {
+ /* Set CF */
+ EmulatorSetFlag(EMULATOR_FLAG_CF);
+
+ /* Return the error code in AX */
+ EmulatorSetRegister(EMULATOR_REG_AX,
+ (Eax & 0xFFFF0000) | ErrorCode);
+ }
+
+ break;
+ }
+
+ /* Close File */
+ case 0x3E:
+ {
+ if (DosCloseHandle(LOWORD(Ebx)))
+ {
+ /* Clear CF */
+ EmulatorClearFlag(EMULATOR_FLAG_CF);
+ }
+ else
+ {
+ /* Set CF */
+ EmulatorSetFlag(EMULATOR_FLAG_CF);
+
+ /* Return the error code in AX */
+ EmulatorSetRegister(EMULATOR_REG_AX,
+ (Eax & 0xFFFF0000) | ERROR_INVALID_PARAMETER);
+ }
+
+ break;
+ }
+
+ /* Read File */
+ case 0x3F:
+ {
+ WORD BytesRead = 0;
+ WORD ErrorCode = DosReadFile(LOWORD(Ebx),
+ (LPVOID)((ULONG_PTR)BaseAddress
+ + TO_LINEAR(DataSegment, LOWORD(Edx))),
+ LOWORD(Ecx),
+ &BytesRead);
+
+ if (ErrorCode == 0)
+ {
+ /* Clear CF */
+ EmulatorClearFlag(EMULATOR_FLAG_CF);
+
+ /* Return the number of bytes read in AX */
+ EmulatorSetRegister(EMULATOR_REG_AX,
+ (Eax & 0xFFFF0000) | BytesRead);
+ }
+ else
+ {
+ /* Set CF */
+ EmulatorSetFlag(EMULATOR_FLAG_CF);
+
+ /* Return the error code in AX */
+ EmulatorSetRegister(EMULATOR_REG_AX,
+ (Eax & 0xFFFF0000) | ErrorCode);
+ }
+ break;
+ }
+
+ /* Write File */
+ case 0x40:
+ {
+ WORD BytesWritten = 0;
+ WORD ErrorCode = DosWriteFile(LOWORD(Ebx),
+ (LPVOID)((ULONG_PTR)BaseAddress
+ + TO_LINEAR(DataSegment, LOWORD(Edx))),
+ LOWORD(Ecx),
+ &BytesWritten);
+
+ if (ErrorCode == 0)
+ {
+ /* Clear CF */
+ EmulatorClearFlag(EMULATOR_FLAG_CF);
+
+ /* Return the number of bytes written in AX */
+ EmulatorSetRegister(EMULATOR_REG_AX,
+ (Eax & 0xFFFF0000) | BytesWritten);
+ }
+ else
+ {
+ /* Set CF */
+ EmulatorSetFlag(EMULATOR_FLAG_CF);
+
+ /* Return the error code in AX */
+ EmulatorSetRegister(EMULATOR_REG_AX,
+ (Eax & 0xFFFF0000) | ErrorCode);
+ }
+
+ break;
+ }
+
/* Allocate Memory */
case 0x48:
{
@@ -933,6 +1371,7 @@
BOOLEAN DosInitialize()
{
+ BYTE i;
PDOS_MCB Mcb = SEGMENT_TO_MCB(FIRST_MCB_SEGMENT);
FILE *Stream;
WCHAR Buffer[256];
@@ -1006,6 +1445,18 @@
fclose(Stream);
}
+ /* Initialize the SFT */
+ for (i = 0; i < DOS_SFT_SIZE; i++)
+ {
+ DosSystemFileTable[i] = INVALID_HANDLE_VALUE;
+ DosSftRefCount[i] = 0;
+ }
+
+ /* Get handles to standard I/O devices */
+ DosSystemFileTable[0] = GetStdHandle(STD_INPUT_HANDLE);
+ DosSystemFileTable[1] = GetStdHandle(STD_OUTPUT_HANDLE);
+ DosSystemFileTable[2] = GetStdHandle(STD_ERROR_HANDLE);
+
return TRUE;
}
Modified: branches/ntvdm/subsystems/ntvdm/dos.h
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/dos.h?re…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/dos.h [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/dos.h [iso-8859-1] Mon Jul 1 02:29:29 2013
@@ -22,6 +22,8 @@
#define USER_MEMORY_SIZE 0x8FFFF
#define SYSTEM_PSP 0x08
#define SYSTEM_ENV_BLOCK 0x800
+#define INVALID_DOS_HANDLE 0xFFFF
+#define DOS_SFT_SIZE 255
#define SEGMENT_TO_MCB(seg) ((PDOS_MCB)((ULONG_PTR)BaseAddress + TO_LINEAR((seg), 0)))
#define SEGMENT_TO_PSP(seg) ((PDOS_PSP)((ULONG_PTR)BaseAddress + TO_LINEAR((seg), 0)))
@@ -76,34 +78,6 @@
CHAR CommandLine[127];
} DOS_PSP, *PDOS_PSP;
-typedef struct _DOS_SFT_ENTRY
-{
- WORD ReferenceCount;
- WORD Mode;
- BYTE Attribute;
- WORD DeviceInfo;
- DWORD DriveParamBlock;
- WORD FirstCluster;
- WORD FileTime;
- WORD FileDate;
- DWORD FileSize;
- DWORD CurrentOffset;
- WORD LastClusterAccessed;
- DWORD DirEntSector;
- BYTE DirEntryIndex;
- CHAR FileName[11];
- BYTE Reserved0[6];
- WORD OwnerPsp;
- BYTE Reserved1[8];
-} DOS_SFT_ENTRY, *PDOS_SFT_ENTRY;
-
-typedef struct _DOS_SFT
-{
- DWORD NextTablePtr;
- WORD FileCount;
- DOS_SFT_ENTRY Entry[ANYSIZE_ARRAY];
-} DOS_SFT, *PDOS_SFT;
-
typedef struct _DOS_INPUT_BUFFER
{
BYTE MaxLength, Length;
@@ -117,6 +91,10 @@
WORD DosAllocateMemory(WORD Size, WORD *MaxAvailable);
BOOLEAN DosResizeMemory(WORD BlockData, WORD NewSize, WORD *MaxAvailable);
BOOLEAN DosFreeMemory(WORD BlockData);
+WORD DosCreateFile(LPWORD Handle, LPCSTR FilePath, WORD Attributes);
+WORD DosOpenFile(LPWORD Handle, LPCSTR FilePath, BYTE AccessMode);
+WORD DosReadFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesRead);
+WORD DosWriteFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesWritten);
VOID DosInitializePsp(WORD PspSegment, LPCSTR CommandLine, WORD ProgramSize, WORD
Environment);
BOOLEAN DosCreateProcess(LPCSTR CommandLine, WORD EnvBlock);
VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode);
Modified: branches/ntvdm/subsystems/ntvdm/ntvdm.h
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/ntvdm.h?…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/ntvdm.h [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/ntvdm.h [iso-8859-1] Mon Jul 1 02:29:29 2013
@@ -26,6 +26,7 @@
#define MAX_SEGMENT 0xFFFF
#define MAX_OFFSET 0xFFFF
#define MAX_ADDRESS TO_LINEAR(MAX_SEGMENT, MAX_OFFSET)
+#define FAR_POINTER(x) ((ULONG_PTR)BaseAddress + TO_LINEAR(HIWORD(x), LOWORD(x)))
#define STEPS_PER_CYCLE 256
/* FUNCTIONS ******************************************************************/