- Add some diagnostic DPRINTs (they are off by default), and fix few of them.
- Fix/complete few comments.
- Implement INT 21h, AH=56h (rename file), 5Ah (create temporary file), 5Bh (create new file), 68h and 6Ah ("commit" aka. flush file; they are the same function).
- Stubplement INT 21h, AH=60h (canonicalize file name or path) and 6Ch (extended open or create file). For this latest one I will merge DosCreateFile and DosOpenFile into the same function (in fact a wrapper around CreateFileA, that is used both for creating and opening files).
svn path=/trunk/; revision=63309
/*
* COPYRIGHT: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
- * FILE: dos.c
- * PURPOSE: VDM DOS Kernel
+ * FILE: dos/dos32krnl/bios.c
+ * PURPOSE: DOS32 Bios
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*/
CHAR Character = '\0';
WORD BytesRead;
+ DPRINT("DosReadCharacter\n");
+
/* Use the file reading function */
DosReadFile(FileHandle, &Character, 1, &BytesRead);
* COPYRIGHT: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
* FILE: dos/dos32krnl/dos.c
- * PURPOSE: VDM DOS Kernel
+ * PURPOSE: DOS32 Kernel
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
*/
/* INCLUDES *******************************************************************/
/* Read Character from STDIN with Echo */
case 0x01:
{
+ DPRINT("INT 21h, AH = 01h\n");
+
// FIXME: Under DOS 2+, input / output handle may be redirected!!!!
DoEcho = TRUE;
Character = DosReadCharacter(DOS_INPUT_HANDLE);
DoEcho = FALSE;
- // /* Let the BOP repeat if needed */
- // if (getCF()) break;
+ // FIXME: Check whether Ctrl-C / Ctrl-Break is pressed, and call INT 23h if so.
+ // Check also Ctrl-P and set echo-to-printer flag.
+ // Ctrl-Z is not interpreted.
setAL(Character);
break;
case 0x07:
case 0x08:
{
+ DPRINT("Char input without echo\n");
+
// FIXME: Under DOS 2+, input handle may be redirected!!!!
Character = DosReadCharacter(DOS_INPUT_HANDLE);
* See Ralf Brown: http://www.ctyme.com/intr/rb-2562.htm
* for more information.
*/
- setAL('$');
+ setAL('$'); // *String
break;
}
WORD Count = 0;
InputBuffer = (PDOS_INPUT_BUFFER)SEG_OFF_TO_PTR(getDS(), getDX());
- DPRINT1("Read Buffered Input\n");
+ DPRINT("Read Buffered Input\n");
while (Count < InputBuffer->MaxLength)
{
/* Try to read a character (wait) */
Character = DosReadCharacter(DOS_INPUT_HANDLE);
+ // FIXME: Check whether Ctrl-C / Ctrl-Break is pressed, and call INT 23h if so.
+
/* Echo the character and append it to the buffer */
DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
InputBuffer->Buffer[Count] = Character;
+ Count++; /* Carriage returns are also counted */
+
if (Character == '\r') break;
- Count++;
}
/* Update the length */
InputFunction == 0x07 || InputFunction == 0x08 ||
InputFunction == 0x0A)
{
+ /* Call ourselves recursively */
setAH(InputFunction);
- /*
- * Instead of calling ourselves really recursively as in:
- * DosInt21h(Stack);
- * prefer resetting the CF flag to let the BOP repeat.
- */
- setCF(1);
+ DosInt21h(Stack);
}
break;
}
/* Create New PSP */
case 0x26:
{
- DPRINT1("INT 21h, 26h - Create New PSP is UNIMPLEMENTED\n");
+ DPRINT1("INT 21h, AH = 26h - Create New PSP is UNIMPLEMENTED\n");
break;
}
break;
}
- /* Create File */
+ /* Create or Truncate File */
case 0x3C:
{
WORD FileHandle;
WORD ErrorCode = DosCreateFile(&FileHandle,
(LPCSTR)SEG_OFF_TO_PTR(getDS(), getDX()),
+ CREATE_ALWAYS,
getCX());
- if (ErrorCode == 0)
+ if (ErrorCode == ERROR_SUCCESS)
{
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
setAX(FileHandle);
(LPCSTR)SEG_OFF_TO_PTR(getDS(), getDX()),
getAL());
- if (ErrorCode == 0)
+ if (ErrorCode == ERROR_SUCCESS)
{
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
setAX(FileHandle);
WORD BytesRead = 0;
WORD ErrorCode;
+ DPRINT("INT 21h, AH = 3Fh\n");
+
DoEcho = TRUE;
ErrorCode = DosReadFile(getBX(),
SEG_OFF_TO_PTR(getDS(), getDX()),
break;
}
+ /* Rename File */
+ case 0x56:
+ {
+ LPSTR ExistingFileName = (LPSTR)SEG_OFF_TO_PTR(getDS(), getDX());
+ LPSTR NewFileName = (LPSTR)SEG_OFF_TO_PTR(getES(), getDI());
+
+ /*
+ * See Ralf Brown: http://www.ctyme.com/intr/rb-2990.htm
+ * for more information.
+ */
+
+ if (MoveFileA(ExistingFileName, NewFileName))
+ {
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ }
+ else
+ {
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ setAX(GetLastError());
+ }
+
+ break;
+ }
+
/* Get/Set Memory Management Options */
case 0x58:
{
break;
}
+ /* Create Temporary File */
+ case 0x5A:
+ {
+ LPSTR PathName = (LPSTR)SEG_OFF_TO_PTR(getDS(), getDX());
+ LPSTR FileName = PathName; // The buffer for the path and the full file name is the same.
+ UINT uRetVal;
+ WORD FileHandle;
+ WORD ErrorCode;
+
+ /*
+ * See Ralf Brown: http://www.ctyme.com/intr/rb-3014.htm
+ * for more information.
+ */
+
+ // FIXME: Check for buffer validity?
+ // It should be a ASCIZ path ending with a '\' + 13 zero bytes
+ // to receive the generated filename.
+
+ /* First create the temporary file */
+ uRetVal = GetTempFileNameA(PathName, NULL, 0, FileName);
+ if (uRetVal == 0)
+ {
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ setAX(GetLastError());
+ break;
+ }
+
+ /* Now try to open it in read/write access */
+ ErrorCode = DosOpenFile(&FileHandle, FileName, 2);
+ if (ErrorCode == ERROR_SUCCESS)
+ {
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ setAX(FileHandle);
+ }
+ else
+ {
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ setAX(ErrorCode);
+ }
+
+ break;
+ }
+
+ /* Create New File */
+ case 0x5B:
+ {
+ WORD FileHandle;
+ WORD ErrorCode = DosCreateFile(&FileHandle,
+ (LPCSTR)SEG_OFF_TO_PTR(getDS(), getDX()),
+ CREATE_NEW,
+ getCX());
+
+ if (ErrorCode == ERROR_SUCCESS)
+ {
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ setAX(FileHandle);
+ }
+ else
+ {
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ setAX(ErrorCode);
+ }
+
+ break;
+ }
+
+ /* Canonicalize File Name or Path */
+ case 0x60:
+ {
+ // TODO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ break;
+ }
+
/* Set Handle Count */
case 0x67:
{
break;
}
+ /* Commit File */
+ case 0x68:
+ case 0x6A:
+ {
+ /*
+ * Function 6Ah is identical to function 68h,
+ * and sets AH to 68h if success.
+ * See Ralf Brown: http://www.ctyme.com/intr/rb-3176.htm
+ * for more information.
+ */
+ setAH(0x68);
+
+ if (DosFlushFileBuffers(getBX()))
+ {
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ }
+ else
+ {
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ setAX(GetLastError());
+ }
+
+ break;
+ }
+
+ /* Extended Open/Create */
+ case 0x6C:
+ {
+ /* Check for AL == 00 */
+ if (getAL() != 0x00)
+ {
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ setAX(ERROR_INVALID_FUNCTION);
+ break;
+ }
+
+ // TODO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ // FIXME: Extend and merge DosOpenFile and DosCreateFile into
+ // a single wrapper around CreateFileA, which acts as:
+ // http://www.ctyme.com/intr/rb-3179.htm
+
+ break;
+ }
+
/* Unsupported */
default:
{
{
/*
* This is the DOS 2+ Fast Console Output Interrupt.
+ * The default handler under DOS 2.x and 3.x simply calls INT 10h/AH=0Eh.
+ *
* See Ralf Brown: http://www.ctyme.com/intr/rb-4124.htm
* for more information.
*/
USHORT AX = getAX();
USHORT BX = getBX();
- /* Set the parameters (AL = character, already set) */
+ /*
+ * Set the parameters:
+ * AL contains the character to print (already set),
+ * BL contains the character attribute,
+ * BH contains the video page to use.
+ */
setBL(DOS_CHAR_ATTRIBUTE);
setBH(Bda->VideoPage);
/*
* COPYRIGHT: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
- * FILE: dos.h
- * PURPOSE: VDM DOS Kernel
+ * FILE: dos/dos32krnl/dos.h
+ * PURPOSE: DOS32 Kernel
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*/
WORD DosOpenHandle(HANDLE Handle);
HANDLE DosGetRealHandle(WORD DosHandle);
-WORD DosCreateFile(LPWORD Handle, LPCSTR FilePath, WORD Attributes);
-WORD DosOpenFile(LPWORD Handle, LPCSTR FilePath, BYTE AccessMode);
+WORD DosCreateFile(LPWORD Handle, LPCSTR FilePath, WORD CreationFlags, WORD Attributes);
+WORD DosOpenFile(LPWORD Handle, LPCSTR FilePath, BYTE AccessShareModes);
WORD DosReadFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesRead);
WORD DosWriteFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesWritten);
WORD DosSeekFile(WORD FileHandle, LONG Offset, BYTE Origin, LPDWORD NewOffset);
* COPYRIGHT: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
* FILE: dos/dos32krnl/dosfiles.c
- * PURPOSE: DOS Files
+ * PURPOSE: DOS32 Files Support
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
*/
/* INCLUDES *******************************************************************/
/* PUBLIC FUNCTIONS ***********************************************************/
-WORD DosCreateFile(LPWORD Handle, LPCSTR FilePath, WORD Attributes)
+WORD DosCreateFile(LPWORD Handle, LPCSTR FilePath, WORD CreationFlags, WORD Attributes)
{
HANDLE FileHandle;
WORD DosHandle;
- DPRINT("DosCreateFile: FilePath \"%s\", Attributes 0x%04X\n",
+ DPRINT("DosCreateFile: FilePath \"%s\", CreationFlags 0x%04X, Attributes 0x%04X\n",
FilePath,
+ CreationFlags,
Attributes);
/* Create the file */
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
- CREATE_ALWAYS,
+ CreationFlags,
Attributes,
NULL);
return ERROR_SUCCESS;
}
-WORD DosOpenFile(LPWORD Handle, LPCSTR FilePath, BYTE AccessMode)
+WORD DosOpenFile(LPWORD Handle, LPCSTR FilePath, BYTE AccessShareModes)
{
HANDLE FileHandle;
- ACCESS_MASK Access = 0;
+ ACCESS_MASK AccessMode = 0;
+ DWORD ShareMode = 0;
+ BOOL InheritableFile = FALSE;
+ SECURITY_ATTRIBUTES SecurityAttributes;
WORD DosHandle;
- DPRINT("DosOpenFile: FilePath \"%s\", AccessMode 0x%04X\n",
+ DPRINT("DosOpenFile: FilePath \"%s\", AccessShareModes 0x%04X\n",
FilePath,
- AccessMode);
+ AccessShareModes);
/* Parse the access mode */
- switch (AccessMode & 3)
+ switch (AccessShareModes & 0x03)
{
case 0:
{
/* Read-only */
- Access = GENERIC_READ;
+ AccessMode = GENERIC_READ;
break;
}
case 1:
{
/* Write only */
- Access = GENERIC_WRITE;
+ AccessMode = GENERIC_WRITE;
break;
}
case 2:
{
/* Read and write */
- Access = GENERIC_READ | GENERIC_WRITE;
+ AccessMode = GENERIC_READ | GENERIC_WRITE;
break;
}
}
}
+ /* Parse the share mode */
+ switch ((AccessShareModes >> 4) & 0x07)
+ {
+ case 0:
+ {
+ /* Compatibility mode */
+ ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+ break;
+ }
+
+ case 1:
+ {
+ /* No sharing "DenyAll" */
+ ShareMode = 0;
+ break;
+ }
+
+ case 2:
+ {
+ /* No write share "DenyWrite" */
+ ShareMode = FILE_SHARE_READ;
+ break;
+ }
+
+ case 3:
+ {
+ /* No read share "DenyRead" */
+ ShareMode = FILE_SHARE_WRITE;
+ break;
+ }
+
+ case 4:
+ {
+ /* Full share "DenyNone" */
+ ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ break;
+ }
+
+ default:
+ {
+ /* Invalid */
+ 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,
- Access,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL,
+ AccessMode,
+ ShareMode,
+ &SecurityAttributes,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
DWORD BytesRead32 = 0;
HANDLE Handle = DosGetRealHandle(FileHandle);
- DPRINT1("DosReadFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle, Count);
+ DPRINT("DosReadFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle, Count);
/* Make sure the handle is valid */
if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
DWORD BytesWritten32 = 0;
HANDLE Handle = DosGetRealHandle(FileHandle);
- DPRINT1("DosWriteFile: FileHandle 0x%04X, Count 0x%04X\n",
- FileHandle,
- Count);
+ DPRINT("DosWriteFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle, Count);
/* Make sure the handle is valid */
if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
return ERROR_SUCCESS;
}
-// This function is almost exclusively used as a DosFlushInputBuffer
BOOL DosFlushFileBuffers(WORD FileHandle)
{
HANDLE Handle = DosGetRealHandle(FileHandle);
if (Handle == INVALID_HANDLE_VALUE) return FALSE;
/*
- * No need to check whether the handle is a console handle since
- * FlushFileBuffers() automatically does this check and calls
- * FlushConsoleInputBuffer() for us.
+ * This function can either flush files back to disks, or flush
+ * console input buffers, in which case there is no need to check
+ * whether the handle is a console handle. FlushFileBuffers()
+ * automatically does this check and calls FlushConsoleInputBuffer()
+ * if needed.
*/
return FlushFileBuffers(Handle);
}