2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: 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"
23 #include "bios/bios.h"
25 /* PUBLIC FUNCTIONS ***********************************************************/
27 BYTE
DosFindFreeDescriptor(VOID
)
31 DWORD CurrentSft
= SysVars
->FirstSft
;
33 while (LOWORD(CurrentSft
) != 0xFFFF)
35 PDOS_SFT Sft
= (PDOS_SFT
)FAR_POINTER(CurrentSft
);
37 for (i
= 0; i
< Sft
->NumDescriptors
; i
++)
39 if (Sft
->FileDescriptors
[i
].RefCount
== 0) return Count
;
43 /* Go to the next table */
44 CurrentSft
= Sft
->Link
;
51 BYTE
DosFindWin32Descriptor(HANDLE Win32Handle
)
55 DWORD CurrentSft
= SysVars
->FirstSft
;
57 while (LOWORD(CurrentSft
) != 0xFFFF)
59 PDOS_SFT Sft
= (PDOS_SFT
)FAR_POINTER(CurrentSft
);
61 for (i
= 0; i
< Sft
->NumDescriptors
; i
++)
63 if ((Sft
->FileDescriptors
[i
].RefCount
> 0)
64 && !(Sft
->FileDescriptors
[i
].DeviceInfo
& (1 << 7))
65 && (Sft
->FileDescriptors
[i
].Win32Handle
== Win32Handle
))
73 /* Go to the next table */
74 CurrentSft
= Sft
->Link
;
81 BYTE
DosFindDeviceDescriptor(DWORD DevicePointer
)
85 DWORD CurrentSft
= SysVars
->FirstSft
;
87 while (LOWORD(CurrentSft
) != 0xFFFF)
89 PDOS_SFT Sft
= (PDOS_SFT
)FAR_POINTER(CurrentSft
);
91 for (i
= 0; i
< Sft
->NumDescriptors
; i
++)
93 if ((Sft
->FileDescriptors
[i
].RefCount
> 0)
94 && (Sft
->FileDescriptors
[i
].DeviceInfo
& (1 << 7))
95 && (Sft
->FileDescriptors
[i
].DevicePointer
== DevicePointer
))
103 /* Go to the next table */
104 CurrentSft
= Sft
->Link
;
111 PDOS_FILE_DESCRIPTOR
DosGetFileDescriptor(BYTE Id
)
113 DWORD CurrentSft
= SysVars
->FirstSft
;
115 while (LOWORD(CurrentSft
) != 0xFFFF)
117 PDOS_SFT Sft
= (PDOS_SFT
)FAR_POINTER(CurrentSft
);
119 /* Return it if it's in this table */
120 if (Id
<= Sft
->NumDescriptors
) return &Sft
->FileDescriptors
[Id
];
122 /* Go to the next table */
123 Id
-= Sft
->NumDescriptors
;
124 CurrentSft
= Sft
->Link
;
131 PDOS_FILE_DESCRIPTOR
DosGetHandleFileDescriptor(WORD DosHandle
)
133 BYTE DescriptorId
= DosQueryHandle(DosHandle
);
134 if (DescriptorId
== 0xFF) return NULL
;
136 return DosGetFileDescriptor(DescriptorId
);
139 WORD
DosCreateFileEx(LPWORD Handle
,
140 LPWORD CreationStatus
,
142 BYTE AccessShareModes
,
143 WORD CreateActionFlags
,
149 ACCESS_MASK AccessMode
= 0;
151 DWORD CreationDisposition
= 0;
152 BOOL InheritableFile
= FALSE
;
153 SECURITY_ATTRIBUTES SecurityAttributes
;
155 PDOS_FILE_DESCRIPTOR Descriptor
;
157 DPRINT1("DosCreateFileEx: FilePath \"%s\", AccessShareModes 0x%04X, CreateActionFlags 0x%04X, Attributes 0x%04X\n",
158 FilePath
, AccessShareModes
, CreateActionFlags
, Attributes
);
161 // The article about OpenFile API: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365430(v=vs.85).aspx
162 // explains what those AccessShareModes are (see the uStyle flag).
165 /* Parse the access mode */
166 switch (AccessShareModes
& 0x03)
170 AccessMode
= GENERIC_READ
;
175 AccessMode
= GENERIC_WRITE
;
180 AccessMode
= GENERIC_READ
| GENERIC_WRITE
;
185 return ERROR_INVALID_PARAMETER
;
188 /* Parse the share mode */
189 switch ((AccessShareModes
>> 4) & 0x07)
191 /* Compatibility mode */
193 ShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
196 /* No sharing "DenyAll" */
201 /* No write share "DenyWrite" */
203 ShareMode
= FILE_SHARE_READ
;
206 /* No read share "DenyRead" */
208 ShareMode
= FILE_SHARE_WRITE
;
211 /* Full share "DenyNone" */
213 ShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
218 return ERROR_INVALID_PARAMETER
;
222 * Parse the creation action flags:
224 * Bitfields for action:
227 * 7-4 Action if file does not exist.
231 * 3-0 Action if file exists.
236 switch (CreateActionFlags
)
238 /* If the file exists, fail, otherwise, fail also */
240 // A special case is used after the call to CreateFileA if it succeeds,
241 // in order to close the opened handle and return an adequate error.
242 CreationDisposition
= OPEN_EXISTING
;
245 /* If the file exists, open it, otherwise, fail */
247 CreationDisposition
= OPEN_EXISTING
;
250 /* If the file exists, replace it, otherwise, fail */
252 CreationDisposition
= TRUNCATE_EXISTING
;
255 /* If the file exists, fail, otherwise, create it */
257 CreationDisposition
= CREATE_NEW
;
260 /* If the file exists, open it, otherwise, create it */
262 CreationDisposition
= OPEN_ALWAYS
;
265 /* If the file exists, replace it, otherwise, create it */
267 CreationDisposition
= CREATE_ALWAYS
;
272 return ERROR_INVALID_PARAMETER
;
275 /* Check for inheritance */
276 InheritableFile
= ((AccessShareModes
& 0x80) == 0);
278 /* Assign default security attributes to the file, and set the inheritance flag */
279 SecurityAttributes
.nLength
= sizeof(SecurityAttributes
);
280 SecurityAttributes
.lpSecurityDescriptor
= NULL
;
281 SecurityAttributes
.bInheritHandle
= InheritableFile
;
284 FileHandle
= CreateFileA(FilePath
,
292 LastError
= (WORD
)GetLastError();
294 if (FileHandle
== INVALID_HANDLE_VALUE
)
296 /* Return the error code */
301 * Special case: CreateActionFlags == 0, we must fail because
302 * the file exists (if it didn't exist we already failed).
304 if (CreateActionFlags
== 0)
306 /* Close the file and return the error code */
307 CloseHandle(FileHandle
);
308 return ERROR_FILE_EXISTS
;
311 /* Set the creation status */
312 switch (CreateActionFlags
)
315 *CreationStatus
= 0x01; // The file was opened
319 *CreationStatus
= 0x03; // The file was replaced
323 *CreationStatus
= 0x02; // The file was created
328 if (LastError
== ERROR_ALREADY_EXISTS
)
329 *CreationStatus
= 0x01; // The file was opened
331 *CreationStatus
= 0x02; // The file was created
338 if (LastError
== ERROR_ALREADY_EXISTS
)
339 *CreationStatus
= 0x03; // The file was replaced
341 *CreationStatus
= 0x02; // The file was created
347 DescriptorId
= DosFindFreeDescriptor();
348 if (DescriptorId
== 0xFF)
350 /* Close the file and return the error code */
351 CloseHandle(FileHandle
);
352 return ERROR_TOO_MANY_OPEN_FILES
;
355 /* Set up the new descriptor */
356 Descriptor
= DosGetFileDescriptor(DescriptorId
);
357 RtlZeroMemory(Descriptor
, sizeof(*Descriptor
));
359 Descriptor
->OpenMode
= AccessShareModes
;
360 Descriptor
->Attributes
= LOBYTE(GetFileAttributesA(FilePath
));
361 Descriptor
->Size
= GetFileSize(FileHandle
, NULL
);
362 Descriptor
->OwnerPsp
= CurrentPsp
;
363 Descriptor
->Win32Handle
= FileHandle
;
365 /* Open the DOS handle */
366 DosHandle
= DosOpenHandle(DescriptorId
);
367 if (DosHandle
== INVALID_DOS_HANDLE
)
369 /* Close the file and return the error code */
370 CloseHandle(FileHandle
);
371 return ERROR_TOO_MANY_OPEN_FILES
;
374 /* It was successful */
376 return ERROR_SUCCESS
;
379 WORD
DosCreateFile(LPWORD Handle
,
381 DWORD CreationDisposition
,
387 PDOS_FILE_DESCRIPTOR Descriptor
;
389 DPRINT("DosCreateFile: FilePath \"%s\", CreationDisposition 0x%04X, Attributes 0x%04X\n",
390 FilePath
, CreationDisposition
, Attributes
);
392 /* Create the file */
393 FileHandle
= CreateFileA(FilePath
,
394 GENERIC_READ
| GENERIC_WRITE
,
395 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
400 if (FileHandle
== INVALID_HANDLE_VALUE
)
402 /* Return the error code */
403 return (WORD
)GetLastError();
406 DescriptorId
= DosFindFreeDescriptor();
407 if (DescriptorId
== 0xFF)
409 /* Close the file and return the error code */
410 CloseHandle(FileHandle
);
411 return ERROR_TOO_MANY_OPEN_FILES
;
414 /* Set up the new descriptor */
415 Descriptor
= DosGetFileDescriptor(DescriptorId
);
416 RtlZeroMemory(Descriptor
, sizeof(*Descriptor
));
418 Descriptor
->Attributes
= LOBYTE(GetFileAttributesA(FilePath
));
419 Descriptor
->Size
= GetFileSize(FileHandle
, NULL
);
420 Descriptor
->OwnerPsp
= CurrentPsp
;
421 Descriptor
->Win32Handle
= FileHandle
;
423 /* Open the DOS handle */
424 DosHandle
= DosOpenHandle(DescriptorId
);
425 if (DosHandle
== INVALID_DOS_HANDLE
)
427 /* Close the file and return the error code */
428 CloseHandle(FileHandle
);
429 return ERROR_TOO_MANY_OPEN_FILES
;
432 /* It was successful */
434 return ERROR_SUCCESS
;
437 WORD
DosOpenFile(LPWORD Handle
,
439 BYTE AccessShareModes
)
441 HANDLE FileHandle
= NULL
;
442 PDOS_DEVICE_NODE Node
;
445 PDOS_FILE_DESCRIPTOR Descriptor
;
447 DPRINT("DosOpenFile: FilePath \"%s\", AccessShareModes 0x%04X\n",
448 FilePath
, AccessShareModes
);
451 // The article about OpenFile API: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365430(v=vs.85).aspx
452 // explains what those AccessShareModes are (see the uStyle flag).
455 Node
= DosGetDevice(FilePath
);
458 if (Node
->OpenRoutine
) Node
->OpenRoutine(Node
);
462 ACCESS_MASK AccessMode
= 0;
464 BOOL InheritableFile
= FALSE
;
465 SECURITY_ATTRIBUTES SecurityAttributes
;
467 /* Parse the access mode */
468 switch (AccessShareModes
& 0x03)
472 AccessMode
= GENERIC_READ
;
477 AccessMode
= GENERIC_WRITE
;
482 AccessMode
= GENERIC_READ
| GENERIC_WRITE
;
487 return ERROR_INVALID_PARAMETER
;
490 /* Parse the share mode */
491 switch ((AccessShareModes
>> 4) & 0x07)
493 /* Compatibility mode */
495 ShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
498 /* No sharing "DenyAll" */
503 /* No write share "DenyWrite" */
505 ShareMode
= FILE_SHARE_READ
;
508 /* No read share "DenyRead" */
510 ShareMode
= FILE_SHARE_WRITE
;
513 /* Full share "DenyNone" */
515 ShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
520 return ERROR_INVALID_PARAMETER
;
523 /* Check for inheritance */
524 InheritableFile
= ((AccessShareModes
& 0x80) == 0);
526 /* Assign default security attributes to the file, and set the inheritance flag */
527 SecurityAttributes
.nLength
= sizeof(SecurityAttributes
);
528 SecurityAttributes
.lpSecurityDescriptor
= NULL
;
529 SecurityAttributes
.bInheritHandle
= InheritableFile
;
532 FileHandle
= CreateFileA(FilePath
,
537 FILE_ATTRIBUTE_NORMAL
,
539 if (FileHandle
== INVALID_HANDLE_VALUE
)
541 /* Return the error code */
542 return (WORD
)GetLastError();
546 DescriptorId
= DosFindFreeDescriptor();
547 if (DescriptorId
== 0xFF)
549 /* Close the file and return the error code */
550 CloseHandle(FileHandle
);
551 return ERROR_TOO_MANY_OPEN_FILES
;
554 /* Set up the new descriptor */
555 Descriptor
= DosGetFileDescriptor(DescriptorId
);
556 RtlZeroMemory(Descriptor
, sizeof(*Descriptor
));
560 Descriptor
->DevicePointer
= Node
->Driver
;
561 Descriptor
->DeviceInfo
= Node
->DeviceAttributes
| (1 << 7);
565 Descriptor
->OpenMode
= AccessShareModes
;
566 Descriptor
->Attributes
= LOBYTE(GetFileAttributesA(FilePath
));
567 Descriptor
->Size
= GetFileSize(FileHandle
, NULL
);
568 Descriptor
->OwnerPsp
= CurrentPsp
;
569 Descriptor
->Win32Handle
= FileHandle
;
572 /* Open the DOS handle */
573 DosHandle
= DosOpenHandle(DescriptorId
);
574 if (DosHandle
== INVALID_DOS_HANDLE
)
576 /* Close the file and return the error code */
577 CloseHandle(FileHandle
);
578 return ERROR_TOO_MANY_OPEN_FILES
;
581 /* It was successful */
583 return ERROR_SUCCESS
;
586 WORD
DosReadFile(WORD FileHandle
,
591 WORD Result
= ERROR_SUCCESS
;
592 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(FileHandle
);
594 DPRINT("DosReadFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle
, Count
);
596 if (Descriptor
== NULL
)
599 return ERROR_INVALID_HANDLE
;
602 if (Descriptor
->DeviceInfo
& (1 << 7))
604 PDOS_DEVICE_NODE Node
= DosGetDriverNode(Descriptor
->DevicePointer
);
605 if (!Node
->ReadRoutine
) return ERROR_INVALID_FUNCTION
;
607 /* Read the device */
608 Node
->ReadRoutine(Node
, Buffer
, &Count
);
613 DWORD BytesRead32
= 0;
614 LPVOID LocalBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Count
);
615 ASSERT(LocalBuffer
!= NULL
);
618 if (ReadFile(Descriptor
->Win32Handle
, LocalBuffer
, Count
, &BytesRead32
, NULL
))
620 /* Write to the memory */
621 MemWrite(TO_LINEAR(HIWORD(Buffer
), LOWORD(Buffer
)), LocalBuffer
, LOWORD(BytesRead32
));
623 /* Update the position */
624 Descriptor
->Position
+= BytesRead32
;
628 /* Store the error code */
629 Result
= (WORD
)GetLastError();
632 /* The number of bytes read is always 16-bit */
633 *BytesRead
= LOWORD(BytesRead32
);
634 RtlFreeHeap(RtlGetProcessHeap(), 0, LocalBuffer
);
637 /* Return the error code */
641 WORD
DosWriteFile(WORD FileHandle
,
646 WORD Result
= ERROR_SUCCESS
;
647 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(FileHandle
);
649 DPRINT("DosWriteFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle
, Count
);
651 if (Descriptor
== NULL
)
654 return ERROR_INVALID_HANDLE
;
657 if (Descriptor
->DeviceInfo
& (1 << 7))
659 PDOS_DEVICE_NODE Node
= DosGetDriverNode(Descriptor
->DevicePointer
);
660 if (!Node
->WriteRoutine
) return ERROR_INVALID_FUNCTION
;
662 /* Read the device */
663 Node
->WriteRoutine(Node
, Buffer
, &Count
);
664 *BytesWritten
= Count
;
668 DWORD BytesWritten32
= 0;
669 LPVOID LocalBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Count
);
670 ASSERT(LocalBuffer
!= NULL
);
672 /* Read from the memory */
673 MemRead(TO_LINEAR(HIWORD(Buffer
), LOWORD(Buffer
)), LocalBuffer
, Count
);
676 if (WriteFile(Descriptor
->Win32Handle
, LocalBuffer
, Count
, &BytesWritten32
, NULL
))
678 /* Update the position and size */
679 Descriptor
->Position
+= BytesWritten32
;
680 if (Descriptor
->Position
> Descriptor
->Size
) Descriptor
->Size
= Descriptor
->Position
;
684 /* Store the error code */
685 Result
= (WORD
)GetLastError();
688 /* The number of bytes written is always 16-bit */
689 *BytesWritten
= LOWORD(BytesWritten32
);
690 RtlFreeHeap(RtlGetProcessHeap(), 0, LocalBuffer
);
693 /* Return the error code */
697 WORD
DosSeekFile(WORD FileHandle
,
702 WORD Result
= ERROR_SUCCESS
;
704 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(FileHandle
);
706 DPRINT("DosSeekFile: FileHandle 0x%04X, Offset 0x%08X, Origin 0x%02X\n",
711 if (Descriptor
== NULL
)
714 return ERROR_INVALID_HANDLE
;
717 if (Descriptor
->DeviceInfo
& (1 << 7))
719 /* For character devices, always return success */
720 return ERROR_SUCCESS
;
723 /* Check if the origin is valid */
724 if (Origin
!= FILE_BEGIN
&& Origin
!= FILE_CURRENT
&& Origin
!= FILE_END
)
726 return ERROR_INVALID_FUNCTION
;
729 FilePointer
= SetFilePointer(Descriptor
->Win32Handle
, Offset
, NULL
, Origin
);
731 /* Check if there's a possibility the operation failed */
732 if (FilePointer
== INVALID_SET_FILE_POINTER
)
734 /* Get the real error code */
735 Result
= (WORD
)GetLastError();
738 if (Result
!= ERROR_SUCCESS
)
740 /* The operation did fail */
744 /* Update the descriptor */
745 Descriptor
->Position
= FilePointer
;
747 /* Return the file pointer, if requested */
748 if (NewOffset
) *NewOffset
= FilePointer
;
751 return ERROR_SUCCESS
;
754 BOOL
DosFlushFileBuffers(WORD FileHandle
)
756 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(FileHandle
);
758 if (Descriptor
== NULL
)
761 DosLastError
= ERROR_INVALID_HANDLE
;
765 if (Descriptor
->DeviceInfo
& (1 << 7))
767 PDOS_DEVICE_NODE Node
= DosGetDriverNode(Descriptor
->DevicePointer
);
769 if (Node
->FlushInputRoutine
) Node
->FlushInputRoutine(Node
);
770 if (Node
->FlushOutputRoutine
) Node
->FlushOutputRoutine(Node
);
776 return FlushFileBuffers(Descriptor
->Win32Handle
);
780 BOOLEAN
DosLockFile(WORD DosHandle
, DWORD Offset
, DWORD Size
)
782 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(DosHandle
);
784 if (Descriptor
== NULL
)
787 DosLastError
= ERROR_INVALID_HANDLE
;
791 /* Always succeed for character devices */
792 if (Descriptor
->DeviceInfo
& (1 << 7)) return TRUE
;
794 if (!LockFile(Descriptor
->Win32Handle
, Offset
, 0, Size
, 0))
796 DosLastError
= GetLastError();
803 BOOLEAN
DosUnlockFile(WORD DosHandle
, DWORD Offset
, DWORD Size
)
805 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(DosHandle
);
807 if (Descriptor
== NULL
)
810 DosLastError
= ERROR_INVALID_HANDLE
;
814 /* Always succeed for character devices */
815 if (Descriptor
->DeviceInfo
& (1 << 7)) return TRUE
;
817 if (!UnlockFile(Descriptor
->Win32Handle
, Offset
, 0, Size
, 0))
819 DosLastError
= GetLastError();
826 BOOLEAN
DosDeviceIoControl(WORD FileHandle
, BYTE ControlCode
, DWORD Buffer
, PWORD Length
)
828 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(FileHandle
);
829 PDOS_DEVICE_NODE Node
= NULL
;
833 DosLastError
= ERROR_INVALID_HANDLE
;
837 if (Descriptor
->DeviceInfo
& (1 << 7))
839 Node
= DosGetDriverNode(Descriptor
->DevicePointer
);
844 /* Get Device Information */
848 * See Ralf Brown: http://www.ctyme.com/intr/rb-2820.htm
849 * for a list of possible flags.
851 setDX(Descriptor
->DeviceInfo
);
855 /* Set Device Information */
858 // TODO: NOT IMPLEMENTED
864 /* Read From Device I/O Control Channel */
867 if (Node
== NULL
|| !(Node
->DeviceAttributes
& DOS_DEVATTR_IOCTL
))
869 DosLastError
= ERROR_INVALID_FUNCTION
;
873 /* Do nothing if there is no IOCTL routine */
874 if (!Node
->IoctlReadRoutine
)
880 Node
->IoctlReadRoutine(Node
, Buffer
, Length
);
884 /* Write To Device I/O Control Channel */
887 if (Node
== NULL
|| !(Node
->DeviceAttributes
& DOS_DEVATTR_IOCTL
))
889 DosLastError
= ERROR_INVALID_FUNCTION
;
893 /* Do nothing if there is no IOCTL routine */
894 if (!Node
->IoctlWriteRoutine
)
900 Node
->IoctlWriteRoutine(Node
, Buffer
, Length
);
904 /* Unsupported control code */
907 DPRINT1("Unsupported IOCTL: 0x%02X\n", ControlCode
);
909 DosLastError
= ERROR_INVALID_PARAMETER
;