2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.c
5 * PURPOSE: DOS32 Files Support
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
10 /* INCLUDES *******************************************************************/
16 #include "../../memory.h"
24 #include "bios/bios.h"
26 /* PRIVATE FUNCTIONS **********************************************************/
28 static VOID
StoreNameInSft(LPCSTR FilePath
, PDOS_FILE_DESCRIPTOR Descriptor
)
30 CHAR ShortPath
[MAX_PATH
];
34 /* Try to get the short path */
35 if (!GetShortPathNameA(FilePath
, ShortPath
, sizeof(ShortPath
)))
37 /* If it failed, just use the uppercase long path */
38 strncpy(ShortPath
, FilePath
, sizeof(ShortPath
) - 1);
42 /* Get the name part */
43 Name
= strrchr(ShortPath
, '\\');
44 if (Name
== NULL
) Name
= ShortPath
;
46 /* Find the extension */
47 Extension
= strchr(Name
, '.');
51 /* Terminate the name string, and move the pointer to after the dot */
55 /* Copy the name into the SFT descriptor */
56 RtlCopyMemory(Descriptor
->FileName
, Name
, min(strlen(Name
), 8));
60 /* Copy the extension too */
61 RtlCopyMemory(&Descriptor
->FileName
[8], Extension
, min(strlen(Extension
), 3));
65 /* PUBLIC FUNCTIONS ***********************************************************/
67 BYTE
DosFindFreeDescriptor(VOID
)
71 DWORD CurrentSft
= SysVars
->FirstSft
;
73 while (LOWORD(CurrentSft
) != 0xFFFF)
75 PDOS_SFT Sft
= (PDOS_SFT
)FAR_POINTER(CurrentSft
);
77 for (i
= 0; i
< Sft
->NumDescriptors
; i
++)
79 if (Sft
->FileDescriptors
[i
].RefCount
== 0) return Count
;
83 /* Go to the next table */
84 CurrentSft
= Sft
->Link
;
91 BYTE
DosFindWin32Descriptor(HANDLE Win32Handle
)
95 DWORD CurrentSft
= SysVars
->FirstSft
;
97 while (LOWORD(CurrentSft
) != 0xFFFF)
99 PDOS_SFT Sft
= (PDOS_SFT
)FAR_POINTER(CurrentSft
);
101 for (i
= 0; i
< Sft
->NumDescriptors
; i
++)
103 if ((Sft
->FileDescriptors
[i
].RefCount
> 0)
104 && !(Sft
->FileDescriptors
[i
].DeviceInfo
& FILE_INFO_DEVICE
)
105 && (Sft
->FileDescriptors
[i
].Win32Handle
== Win32Handle
))
113 /* Go to the next table */
114 CurrentSft
= Sft
->Link
;
121 BYTE
DosFindDeviceDescriptor(DWORD DevicePointer
)
125 DWORD CurrentSft
= SysVars
->FirstSft
;
127 while (LOWORD(CurrentSft
) != 0xFFFF)
129 PDOS_SFT Sft
= (PDOS_SFT
)FAR_POINTER(CurrentSft
);
131 for (i
= 0; i
< Sft
->NumDescriptors
; i
++)
133 if ((Sft
->FileDescriptors
[i
].RefCount
> 0)
134 && (Sft
->FileDescriptors
[i
].DeviceInfo
& FILE_INFO_DEVICE
)
135 && (Sft
->FileDescriptors
[i
].DevicePointer
== DevicePointer
))
143 /* Go to the next table */
144 CurrentSft
= Sft
->Link
;
151 PDOS_FILE_DESCRIPTOR
DosGetFileDescriptor(BYTE Id
)
153 DWORD CurrentSft
= SysVars
->FirstSft
;
155 while (LOWORD(CurrentSft
) != 0xFFFF)
157 PDOS_SFT Sft
= (PDOS_SFT
)FAR_POINTER(CurrentSft
);
159 /* Return it if it's in this table */
160 if (Id
<= Sft
->NumDescriptors
) return &Sft
->FileDescriptors
[Id
];
162 /* Go to the next table */
163 Id
-= Sft
->NumDescriptors
;
164 CurrentSft
= Sft
->Link
;
171 PDOS_FILE_DESCRIPTOR
DosGetHandleFileDescriptor(WORD DosHandle
)
173 BYTE DescriptorId
= DosQueryHandle(DosHandle
);
174 if (DescriptorId
== 0xFF) return NULL
;
176 return DosGetFileDescriptor(DescriptorId
);
179 WORD
DosCreateFileEx(LPWORD Handle
,
180 LPWORD CreationStatus
,
182 BYTE AccessShareModes
,
183 WORD CreateActionFlags
,
188 PDOS_DEVICE_NODE Node
;
190 ACCESS_MASK AccessMode
= 0;
192 DWORD CreationDisposition
= 0;
193 BOOL InheritableFile
= FALSE
;
194 SECURITY_ATTRIBUTES SecurityAttributes
;
196 PDOS_FILE_DESCRIPTOR Descriptor
;
198 DPRINT1("DosCreateFileEx: FilePath \"%s\", AccessShareModes 0x%04X, CreateActionFlags 0x%04X, Attributes 0x%04X\n",
199 FilePath
, AccessShareModes
, CreateActionFlags
, Attributes
);
202 // The article about OpenFile API: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365430(v=vs.85).aspx
203 // explains what those AccessShareModes are (see the uStyle flag).
206 Node
= DosGetDevice(FilePath
);
209 if (Node
->OpenRoutine
) Node
->OpenRoutine(Node
);
213 /* Parse the access mode */
214 switch (AccessShareModes
& 0x03)
218 AccessMode
= GENERIC_READ
;
223 AccessMode
= GENERIC_WRITE
;
228 AccessMode
= GENERIC_READ
| GENERIC_WRITE
;
233 return ERROR_INVALID_PARAMETER
;
236 /* Parse the share mode */
237 switch ((AccessShareModes
>> 4) & 0x07)
239 /* Compatibility mode */
241 ShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
244 /* No sharing "DenyAll" */
249 /* No write share "DenyWrite" */
251 ShareMode
= FILE_SHARE_READ
;
254 /* No read share "DenyRead" */
256 ShareMode
= FILE_SHARE_WRITE
;
259 /* Full share "DenyNone" */
261 ShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
266 return ERROR_INVALID_PARAMETER
;
270 * Parse the creation action flags:
272 * Bitfields for action:
275 * 7-4 Action if file does not exist.
279 * 3-0 Action if file exists.
284 switch (CreateActionFlags
)
286 /* If the file exists, fail, otherwise, fail also */
288 // A special case is used after the call to CreateFileA if it succeeds,
289 // in order to close the opened handle and return an adequate error.
290 CreationDisposition
= OPEN_EXISTING
;
293 /* If the file exists, open it, otherwise, fail */
295 CreationDisposition
= OPEN_EXISTING
;
298 /* If the file exists, replace it, otherwise, fail */
300 CreationDisposition
= TRUNCATE_EXISTING
;
303 /* If the file exists, fail, otherwise, create it */
305 CreationDisposition
= CREATE_NEW
;
308 /* If the file exists, open it, otherwise, create it */
310 CreationDisposition
= OPEN_ALWAYS
;
313 /* If the file exists, replace it, otherwise, create it */
315 CreationDisposition
= CREATE_ALWAYS
;
320 return ERROR_INVALID_PARAMETER
;
323 /* Check for inheritance */
324 InheritableFile
= ((AccessShareModes
& 0x80) == 0);
326 /* Assign default security attributes to the file, and set the inheritance flag */
327 SecurityAttributes
.nLength
= sizeof(SecurityAttributes
);
328 SecurityAttributes
.lpSecurityDescriptor
= NULL
;
329 SecurityAttributes
.bInheritHandle
= InheritableFile
;
332 FileHandle
= CreateFileA(FilePath
,
340 LastError
= (WORD
)GetLastError();
342 if (FileHandle
== INVALID_HANDLE_VALUE
)
344 /* Return the error code */
349 * Special case: CreateActionFlags == 0, we must fail because
350 * the file exists (if it didn't exist we already failed).
352 if (CreateActionFlags
== 0)
354 /* Close the file and return the error code */
355 CloseHandle(FileHandle
);
356 return ERROR_FILE_EXISTS
;
359 /* Set the creation status */
360 switch (CreateActionFlags
)
363 *CreationStatus
= 0x01; // The file was opened
367 *CreationStatus
= 0x03; // The file was replaced
371 *CreationStatus
= 0x02; // The file was created
376 if (LastError
== ERROR_ALREADY_EXISTS
)
377 *CreationStatus
= 0x01; // The file was opened
379 *CreationStatus
= 0x02; // The file was created
386 if (LastError
== ERROR_ALREADY_EXISTS
)
387 *CreationStatus
= 0x03; // The file was replaced
389 *CreationStatus
= 0x02; // The file was created
396 DescriptorId
= DosFindFreeDescriptor();
397 if (DescriptorId
== 0xFF)
399 /* Close the file and return the error code */
400 CloseHandle(FileHandle
);
401 return ERROR_TOO_MANY_OPEN_FILES
;
404 /* Set up the new descriptor */
405 Descriptor
= DosGetFileDescriptor(DescriptorId
);
406 RtlZeroMemory(Descriptor
, sizeof(*Descriptor
));
407 RtlFillMemory(Descriptor
->FileName
, sizeof(Descriptor
->FileName
), ' ');
411 Descriptor
->DevicePointer
= Node
->Driver
;
412 Descriptor
->DeviceInfo
= Node
->DeviceAttributes
| FILE_INFO_DEVICE
;
413 RtlCopyMemory(Descriptor
->FileName
, Node
->Name
.Buffer
, Node
->Name
.Length
);
417 Descriptor
->OpenMode
= AccessShareModes
;
418 Descriptor
->Attributes
= LOBYTE(GetFileAttributesA(FilePath
));
419 Descriptor
->Size
= GetFileSize(FileHandle
, NULL
);
420 Descriptor
->Win32Handle
= FileHandle
;
421 StoreNameInSft(FilePath
, Descriptor
);
424 Descriptor
->OwnerPsp
= Sda
->CurrentPsp
;
426 /* Open the DOS handle */
427 DosHandle
= DosOpenHandle(DescriptorId
);
428 if (DosHandle
== INVALID_DOS_HANDLE
)
430 /* Close the file and return the error code */
431 CloseHandle(FileHandle
);
432 return ERROR_TOO_MANY_OPEN_FILES
;
435 /* It was successful */
437 return ERROR_SUCCESS
;
440 WORD
DosCreateFile(LPWORD Handle
,
442 DWORD CreationDisposition
,
446 PDOS_DEVICE_NODE Node
;
449 PDOS_FILE_DESCRIPTOR Descriptor
;
451 DPRINT("DosCreateFile: FilePath \"%s\", CreationDisposition 0x%04X, Attributes 0x%04X\n",
452 FilePath
, CreationDisposition
, Attributes
);
454 Node
= DosGetDevice(FilePath
);
457 if (Node
->OpenRoutine
) Node
->OpenRoutine(Node
);
461 /* Create the file */
462 FileHandle
= CreateFileA(FilePath
,
463 GENERIC_READ
| GENERIC_WRITE
,
464 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
469 if (FileHandle
== INVALID_HANDLE_VALUE
)
471 /* Return the error code */
472 return (WORD
)GetLastError();
476 DescriptorId
= DosFindFreeDescriptor();
477 if (DescriptorId
== 0xFF)
479 /* Close the file and return the error code */
480 CloseHandle(FileHandle
);
481 return ERROR_TOO_MANY_OPEN_FILES
;
484 /* Set up the new descriptor */
485 Descriptor
= DosGetFileDescriptor(DescriptorId
);
486 RtlZeroMemory(Descriptor
, sizeof(*Descriptor
));
487 RtlFillMemory(Descriptor
->FileName
, sizeof(Descriptor
->FileName
), ' ');
491 Descriptor
->DevicePointer
= Node
->Driver
;
492 Descriptor
->DeviceInfo
= Node
->DeviceAttributes
| FILE_INFO_DEVICE
;
493 RtlCopyMemory(Descriptor
->FileName
, Node
->Name
.Buffer
, Node
->Name
.Length
);
497 Descriptor
->Attributes
= LOBYTE(GetFileAttributesA(FilePath
));
498 Descriptor
->Size
= GetFileSize(FileHandle
, NULL
);
499 Descriptor
->Win32Handle
= FileHandle
;
500 StoreNameInSft(FilePath
, Descriptor
);
503 Descriptor
->OwnerPsp
= Sda
->CurrentPsp
;
505 /* Open the DOS handle */
506 DosHandle
= DosOpenHandle(DescriptorId
);
507 if (DosHandle
== INVALID_DOS_HANDLE
)
509 /* Close the file and return the error code */
510 CloseHandle(FileHandle
);
511 return ERROR_TOO_MANY_OPEN_FILES
;
514 /* It was successful */
516 return ERROR_SUCCESS
;
519 WORD
DosOpenFile(LPWORD Handle
,
521 BYTE AccessShareModes
)
523 HANDLE FileHandle
= NULL
;
524 PDOS_DEVICE_NODE Node
;
527 PDOS_FILE_DESCRIPTOR Descriptor
;
529 DPRINT("DosOpenFile: FilePath \"%s\", AccessShareModes 0x%04X\n",
530 FilePath
, AccessShareModes
);
533 // The article about OpenFile API: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365430(v=vs.85).aspx
534 // explains what those AccessShareModes are (see the uStyle flag).
537 Node
= DosGetDevice(FilePath
);
540 if (Node
->OpenRoutine
) Node
->OpenRoutine(Node
);
544 ACCESS_MASK AccessMode
= 0;
546 BOOL InheritableFile
= FALSE
;
547 SECURITY_ATTRIBUTES SecurityAttributes
;
549 /* Parse the access mode */
550 switch (AccessShareModes
& 0x03)
554 AccessMode
= GENERIC_READ
;
559 AccessMode
= GENERIC_WRITE
;
564 AccessMode
= GENERIC_READ
| GENERIC_WRITE
;
569 return ERROR_INVALID_PARAMETER
;
572 /* Parse the share mode */
573 switch ((AccessShareModes
>> 4) & 0x07)
575 /* Compatibility mode */
577 ShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
580 /* No sharing "DenyAll" */
585 /* No write share "DenyWrite" */
587 ShareMode
= FILE_SHARE_READ
;
590 /* No read share "DenyRead" */
592 ShareMode
= FILE_SHARE_WRITE
;
595 /* Full share "DenyNone" */
597 ShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
602 return ERROR_INVALID_PARAMETER
;
605 /* Check for inheritance */
606 InheritableFile
= ((AccessShareModes
& 0x80) == 0);
608 /* Assign default security attributes to the file, and set the inheritance flag */
609 SecurityAttributes
.nLength
= sizeof(SecurityAttributes
);
610 SecurityAttributes
.lpSecurityDescriptor
= NULL
;
611 SecurityAttributes
.bInheritHandle
= InheritableFile
;
614 FileHandle
= CreateFileA(FilePath
,
619 FILE_ATTRIBUTE_NORMAL
,
621 if (FileHandle
== INVALID_HANDLE_VALUE
)
623 /* Return the error code */
624 return (WORD
)GetLastError();
628 DescriptorId
= DosFindFreeDescriptor();
629 if (DescriptorId
== 0xFF)
631 /* Close the file and return the error code */
632 CloseHandle(FileHandle
);
633 return ERROR_TOO_MANY_OPEN_FILES
;
636 /* Set up the new descriptor */
637 Descriptor
= DosGetFileDescriptor(DescriptorId
);
638 RtlZeroMemory(Descriptor
, sizeof(*Descriptor
));
639 RtlFillMemory(Descriptor
->FileName
, sizeof(Descriptor
->FileName
), ' ');
643 Descriptor
->DevicePointer
= Node
->Driver
;
644 Descriptor
->DeviceInfo
= Node
->DeviceAttributes
| FILE_INFO_DEVICE
;
645 RtlCopyMemory(Descriptor
->FileName
, Node
->Name
.Buffer
, Node
->Name
.Length
);
649 Descriptor
->OpenMode
= AccessShareModes
;
650 Descriptor
->Attributes
= LOBYTE(GetFileAttributesA(FilePath
));
651 Descriptor
->Size
= GetFileSize(FileHandle
, NULL
);
652 Descriptor
->Win32Handle
= FileHandle
;
653 StoreNameInSft(FilePath
, Descriptor
);
656 Descriptor
->OwnerPsp
= Sda
->CurrentPsp
;
658 /* Open the DOS handle */
659 DosHandle
= DosOpenHandle(DescriptorId
);
660 if (DosHandle
== INVALID_DOS_HANDLE
)
662 /* Close the file and return the error code */
663 CloseHandle(FileHandle
);
664 return ERROR_TOO_MANY_OPEN_FILES
;
667 /* It was successful */
669 return ERROR_SUCCESS
;
672 BYTE
DosReadLineBuffered(WORD FileHandle
, DWORD Buffer
, BYTE MaxSize
)
674 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(FileHandle
);
675 PDOS_DEVICE_NODE Node
= DosGetDriverNode(Descriptor
->DevicePointer
);
677 PCHAR Pointer
= FAR_POINTER(Buffer
);
684 /* Read a character from the device */
685 Node
->ReadRoutine(Node
,
686 MAKELONG(DOS_DATA_OFFSET(Sda
.ByteBuffer
),
689 if (Amount
== 0) break;
691 Character
= Sda
->ByteBuffer
;
693 if (LineSize
== MaxSize
- 1 && Character
!= '\r' && Character
!= '\b')
695 /* Line buffer full */
696 // TODO: Should we beep?
702 /* Extended character */
705 /* Read the scancode and discard it */
707 Node
->ReadRoutine(Node
,
708 MAKELONG(DOS_DATA_OFFSET(Sda
.ByteBuffer
),
717 DosEchoCharacter(Character
);
719 if (DosControlBreak())
721 /* Set the character to CR to end the loop */
730 DosEchoCharacter('\r');
731 DosEchoCharacter('\n');
740 DosEchoCharacter(Character
);
742 /* Erase the '^' too */
743 if (Pointer
[LineSize
] > 0x00 && Pointer
[LineSize
] < 0x20)
745 DosEchoCharacter(Character
);
754 /* Store the character in the buffer */
755 Pointer
[LineSize
++] = Character
;
756 DosEchoCharacter(Character
);
760 /* Stop on a carriage return */
761 } while (Character
!= '\r');
766 WORD
DosReadFile(WORD FileHandle
,
771 WORD Result
= ERROR_SUCCESS
;
772 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(FileHandle
);
773 BYTE StaticBuffer
[8192];
775 DPRINT("DosReadFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle
, Count
);
777 if (Descriptor
== NULL
)
780 return ERROR_INVALID_HANDLE
;
783 if (Descriptor
->DeviceInfo
& FILE_INFO_DEVICE
)
785 PDOS_DEVICE_NODE Node
= DosGetDriverNode(Descriptor
->DevicePointer
);
786 if (!Node
->ReadRoutine
) return ERROR_INVALID_FUNCTION
;
788 if (Descriptor
->DeviceInfo
& FILE_INFO_BINARY
)
790 /* Read from the device directly */
791 Node
->ReadRoutine(Node
, Buffer
, &Count
);
794 else if (Descriptor
->DeviceInfo
& FILE_INFO_STDIN
)
796 /* Line-buffered CON input */
797 PCHAR ConBuffer
= NULL
;
798 PCHAR Pointer
= FAR_POINTER(Buffer
);
800 /* Check if the buffer is empty */
801 if (!SysVars
->UnreadConInput
)
803 SysVars
->UnreadConInput
= FIELD_OFFSET(DOS_DATA
, UnreadConInputBuffer
);
805 DosReadLineBuffered(FileHandle
,
806 MAKELONG(SysVars
->UnreadConInput
, DOS_DATA_SEGMENT
),
807 sizeof(DosData
->UnreadConInputBuffer
));
811 ConBuffer
= (PCHAR
)SEG_OFF_TO_PTR(DOS_DATA_SEGMENT
, SysVars
->UnreadConInput
);
813 while (*BytesRead
< Count
)
815 Pointer
[(*BytesRead
)++] = *ConBuffer
;
817 if (*ConBuffer
== '\r')
819 /* A carriage return turns into a line feed */
822 else if (*ConBuffer
== '\n')
824 /* A line feed marks the true end of the line */
825 SysVars
->UnreadConInput
= 0;
827 /* Echo the line feed */
828 DosEchoCharacter('\n');
833 /* Move to the next character */
834 SysVars
->UnreadConInput
++;
841 /* Translated input from a character device that isn't CON */
842 PCHAR Pointer
= FAR_POINTER(Buffer
);
845 while (*BytesRead
< Count
)
849 /* Read a character from the device */
850 Node
->ReadRoutine(Node
,
851 MAKELONG(DOS_DATA_OFFSET(Sda
.ByteBuffer
),
854 if (Amount
== 0) break;
856 Character
= Sda
->ByteBuffer
;
857 // TODO: Process it somehow?
859 /* Store the character in the output buffer */
860 Pointer
[(*BytesRead
)++] = Character
;
863 if (Character
== 0x1A) break;
869 DWORD BytesRead32
= 0;
872 if (Count
<= sizeof(StaticBuffer
))
874 LocalBuffer
= StaticBuffer
;
878 LocalBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Count
);
879 ASSERT(LocalBuffer
!= NULL
);
882 /* Read from the file */
883 if (ReadFile(Descriptor
->Win32Handle
, LocalBuffer
, Count
, &BytesRead32
, NULL
))
885 /* Write to the memory */
886 EmulatorWriteMemory(&EmulatorContext
,
887 TO_LINEAR(HIWORD(Buffer
), LOWORD(Buffer
)),
889 LOWORD(BytesRead32
));
891 /* Update the position */
892 Descriptor
->Position
+= BytesRead32
; // or LOWORD(BytesRead32); ?
896 /* Store the error code */
897 Result
= (WORD
)GetLastError();
900 /* The number of bytes read is always 16-bit */
901 *BytesRead
= LOWORD(BytesRead32
);
903 if (LocalBuffer
!= StaticBuffer
)
904 RtlFreeHeap(RtlGetProcessHeap(), 0, LocalBuffer
);
907 /* Return the error code */
911 WORD
DosWriteFile(WORD FileHandle
,
916 WORD Result
= ERROR_SUCCESS
;
917 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(FileHandle
);
918 BYTE StaticBuffer
[8192];
920 DPRINT("DosWriteFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle
, Count
);
922 if (Descriptor
== NULL
)
925 return ERROR_INVALID_HANDLE
;
928 if (Descriptor
->DeviceInfo
& FILE_INFO_DEVICE
)
930 PDOS_DEVICE_NODE Node
= DosGetDriverNode(Descriptor
->DevicePointer
);
931 if (!Node
->WriteRoutine
) return ERROR_INVALID_FUNCTION
;
933 /* Read the device */
934 Node
->WriteRoutine(Node
, Buffer
, &Count
);
935 *BytesWritten
= Count
;
939 DWORD BytesWritten32
= 0;
943 * Writing zero bytes truncates or extends the file
944 * to the current position of the file pointer.
948 if (!SetEndOfFile(Descriptor
->Win32Handle
))
950 /* Store the error code */
951 Result
= (WORD
)GetLastError();
957 if (Count
<= sizeof(StaticBuffer
))
959 LocalBuffer
= StaticBuffer
;
963 LocalBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Count
);
964 ASSERT(LocalBuffer
!= NULL
);
967 /* Read from the memory */
968 EmulatorReadMemory(&EmulatorContext
,
969 TO_LINEAR(HIWORD(Buffer
), LOWORD(Buffer
)),
973 /* Write to the file */
974 if (WriteFile(Descriptor
->Win32Handle
, LocalBuffer
, Count
, &BytesWritten32
, NULL
))
976 /* Update the position and size */
977 Descriptor
->Position
+= BytesWritten32
; // or LOWORD(BytesWritten32); ?
978 if (Descriptor
->Position
> Descriptor
->Size
) Descriptor
->Size
= Descriptor
->Position
;
982 /* Store the error code */
983 Result
= (WORD
)GetLastError();
986 /* The number of bytes written is always 16-bit */
987 *BytesWritten
= LOWORD(BytesWritten32
);
989 if (LocalBuffer
!= StaticBuffer
)
990 RtlFreeHeap(RtlGetProcessHeap(), 0, LocalBuffer
);
993 /* Return the error code */
997 WORD
DosSeekFile(WORD FileHandle
,
1002 WORD Result
= ERROR_SUCCESS
;
1004 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(FileHandle
);
1006 DPRINT("DosSeekFile: FileHandle 0x%04X, Offset 0x%08X, Origin 0x%02X\n",
1007 FileHandle
, Offset
, Origin
);
1009 if (Descriptor
== NULL
)
1011 /* Invalid handle */
1012 return ERROR_INVALID_HANDLE
;
1015 if (Descriptor
->DeviceInfo
& FILE_INFO_DEVICE
)
1017 /* For character devices, always return success */
1018 return ERROR_SUCCESS
;
1021 /* Check if the origin is valid */
1022 if (Origin
!= FILE_BEGIN
&& Origin
!= FILE_CURRENT
&& Origin
!= FILE_END
)
1024 return ERROR_INVALID_FUNCTION
;
1027 FilePointer
= SetFilePointer(Descriptor
->Win32Handle
, Offset
, NULL
, Origin
);
1029 /* Check if there's a possibility the operation failed */
1030 if (FilePointer
== INVALID_SET_FILE_POINTER
)
1032 /* Get the real error code */
1033 Result
= (WORD
)GetLastError();
1036 if (Result
!= ERROR_SUCCESS
)
1038 /* The operation did fail */
1042 /* Update the position */
1043 Descriptor
->Position
= FilePointer
;
1045 /* Return the file pointer, if requested */
1046 if (NewOffset
) *NewOffset
= FilePointer
;
1048 /* Return success */
1049 return ERROR_SUCCESS
;
1052 BOOL
DosFlushFileBuffers(WORD FileHandle
)
1054 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(FileHandle
);
1056 if (Descriptor
== NULL
)
1058 /* Invalid handle */
1059 Sda
->LastErrorCode
= ERROR_INVALID_HANDLE
;
1063 if (Descriptor
->DeviceInfo
& FILE_INFO_DEVICE
)
1065 PDOS_DEVICE_NODE Node
= DosGetDriverNode(Descriptor
->DevicePointer
);
1067 if (Node
->FlushInputRoutine
) Node
->FlushInputRoutine(Node
);
1068 if (Node
->FlushOutputRoutine
) Node
->FlushOutputRoutine(Node
);
1074 return FlushFileBuffers(Descriptor
->Win32Handle
);
1078 BOOLEAN
DosLockFile(WORD DosHandle
, DWORD Offset
, DWORD Size
)
1080 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(DosHandle
);
1082 if (Descriptor
== NULL
)
1084 /* Invalid handle */
1085 Sda
->LastErrorCode
= ERROR_INVALID_HANDLE
;
1089 /* Always succeed for character devices */
1090 if (Descriptor
->DeviceInfo
& FILE_INFO_DEVICE
) return TRUE
;
1092 if (!LockFile(Descriptor
->Win32Handle
, Offset
, 0, Size
, 0))
1094 Sda
->LastErrorCode
= GetLastError();
1101 BOOLEAN
DosUnlockFile(WORD DosHandle
, DWORD Offset
, DWORD Size
)
1103 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(DosHandle
);
1105 if (Descriptor
== NULL
)
1107 /* Invalid handle */
1108 Sda
->LastErrorCode
= ERROR_INVALID_HANDLE
;
1112 /* Always succeed for character devices */
1113 if (Descriptor
->DeviceInfo
& FILE_INFO_DEVICE
) return TRUE
;
1115 if (!UnlockFile(Descriptor
->Win32Handle
, Offset
, 0, Size
, 0))
1117 Sda
->LastErrorCode
= GetLastError();
1124 BOOLEAN
DosDeviceIoControl(WORD FileHandle
, BYTE ControlCode
, DWORD Buffer
, PWORD Length
)
1126 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(FileHandle
);
1127 PDOS_DEVICE_NODE Node
= NULL
;
1131 Sda
->LastErrorCode
= ERROR_INVALID_HANDLE
;
1135 if (Descriptor
->DeviceInfo
& FILE_INFO_DEVICE
)
1137 Node
= DosGetDriverNode(Descriptor
->DevicePointer
);
1140 switch (ControlCode
)
1142 /* Get Device Information */
1146 * See Ralf Brown: http://www.ctyme.com/intr/rb-2820.htm
1147 * for a list of possible flags.
1149 setDX(Descriptor
->DeviceInfo
);
1153 /* Set Device Information */
1156 // TODO: NOT IMPLEMENTED
1161 /* Read from Device I/O Control Channel */
1164 if (Node
== NULL
|| !(Node
->DeviceAttributes
& DOS_DEVATTR_IOCTL
))
1166 Sda
->LastErrorCode
= ERROR_INVALID_FUNCTION
;
1170 /* Do nothing if there is no IOCTL routine */
1171 if (!Node
->IoctlReadRoutine
)
1177 Node
->IoctlReadRoutine(Node
, Buffer
, Length
);
1181 /* Write to Device I/O Control Channel */
1184 if (Node
== NULL
|| !(Node
->DeviceAttributes
& DOS_DEVATTR_IOCTL
))
1186 Sda
->LastErrorCode
= ERROR_INVALID_FUNCTION
;
1190 /* Do nothing if there is no IOCTL routine */
1191 if (!Node
->IoctlWriteRoutine
)
1197 Node
->IoctlWriteRoutine(Node
, Buffer
, Length
);
1201 /* Get Input Status */
1204 /* Check if this is a file or a device */
1209 if (!Node
->InputStatusRoutine
|| Node
->InputStatusRoutine(Node
))
1211 /* Set the length to 0xFF to mark that it's ready */
1224 if (Descriptor
->Position
< Descriptor
->Size
)
1226 /* Set the length to 0xFF to mark that it's ready */
1239 /* Get Output Status */
1242 /* Check if this is a file or a device */
1247 if (!Node
->OutputStatusRoutine
|| Node
->OutputStatusRoutine(Node
))
1249 /* Set the length to 0xFF to mark that it's ready */
1260 /* Files are always ready for output */
1267 /* Unsupported control code */
1270 DPRINT1("Unsupported IOCTL: 0x%02X\n", ControlCode
);
1272 Sda
->LastErrorCode
= ERROR_INVALID_PARAMETER
;