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"
24 #include "bios/bios.h"
26 /* PUBLIC FUNCTIONS ***********************************************************/
28 BYTE
DosFindFreeDescriptor(VOID
)
32 DWORD CurrentSft
= SysVars
->FirstSft
;
34 while (LOWORD(CurrentSft
) != 0xFFFF)
36 PDOS_SFT Sft
= (PDOS_SFT
)FAR_POINTER(CurrentSft
);
38 for (i
= 0; i
< Sft
->NumDescriptors
; i
++)
40 if (Sft
->FileDescriptors
[i
].RefCount
== 0) return Count
;
44 /* Go to the next table */
45 CurrentSft
= Sft
->Link
;
52 BYTE
DosFindWin32Descriptor(HANDLE Win32Handle
)
56 DWORD CurrentSft
= SysVars
->FirstSft
;
58 while (LOWORD(CurrentSft
) != 0xFFFF)
60 PDOS_SFT Sft
= (PDOS_SFT
)FAR_POINTER(CurrentSft
);
62 for (i
= 0; i
< Sft
->NumDescriptors
; i
++)
64 if ((Sft
->FileDescriptors
[i
].RefCount
> 0)
65 && !(Sft
->FileDescriptors
[i
].DeviceInfo
& FILE_INFO_DEVICE
)
66 && (Sft
->FileDescriptors
[i
].Win32Handle
== Win32Handle
))
74 /* Go to the next table */
75 CurrentSft
= Sft
->Link
;
82 BYTE
DosFindDeviceDescriptor(DWORD DevicePointer
)
86 DWORD CurrentSft
= SysVars
->FirstSft
;
88 while (LOWORD(CurrentSft
) != 0xFFFF)
90 PDOS_SFT Sft
= (PDOS_SFT
)FAR_POINTER(CurrentSft
);
92 for (i
= 0; i
< Sft
->NumDescriptors
; i
++)
94 if ((Sft
->FileDescriptors
[i
].RefCount
> 0)
95 && (Sft
->FileDescriptors
[i
].DeviceInfo
& FILE_INFO_DEVICE
)
96 && (Sft
->FileDescriptors
[i
].DevicePointer
== DevicePointer
))
104 /* Go to the next table */
105 CurrentSft
= Sft
->Link
;
112 PDOS_FILE_DESCRIPTOR
DosGetFileDescriptor(BYTE Id
)
114 DWORD CurrentSft
= SysVars
->FirstSft
;
116 while (LOWORD(CurrentSft
) != 0xFFFF)
118 PDOS_SFT Sft
= (PDOS_SFT
)FAR_POINTER(CurrentSft
);
120 /* Return it if it's in this table */
121 if (Id
<= Sft
->NumDescriptors
) return &Sft
->FileDescriptors
[Id
];
123 /* Go to the next table */
124 Id
-= Sft
->NumDescriptors
;
125 CurrentSft
= Sft
->Link
;
132 PDOS_FILE_DESCRIPTOR
DosGetHandleFileDescriptor(WORD DosHandle
)
134 BYTE DescriptorId
= DosQueryHandle(DosHandle
);
135 if (DescriptorId
== 0xFF) return NULL
;
137 return DosGetFileDescriptor(DescriptorId
);
140 WORD
DosCreateFileEx(LPWORD Handle
,
141 LPWORD CreationStatus
,
143 BYTE AccessShareModes
,
144 WORD CreateActionFlags
,
149 PDOS_DEVICE_NODE Node
;
151 ACCESS_MASK AccessMode
= 0;
153 DWORD CreationDisposition
= 0;
154 BOOL InheritableFile
= FALSE
;
155 SECURITY_ATTRIBUTES SecurityAttributes
;
157 PDOS_FILE_DESCRIPTOR Descriptor
;
159 DPRINT1("DosCreateFileEx: FilePath \"%s\", AccessShareModes 0x%04X, CreateActionFlags 0x%04X, Attributes 0x%04X\n",
160 FilePath
, AccessShareModes
, CreateActionFlags
, Attributes
);
163 // The article about OpenFile API: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365430(v=vs.85).aspx
164 // explains what those AccessShareModes are (see the uStyle flag).
167 Node
= DosGetDevice(FilePath
);
170 if (Node
->OpenRoutine
) Node
->OpenRoutine(Node
);
174 /* Parse the access mode */
175 switch (AccessShareModes
& 0x03)
179 AccessMode
= GENERIC_READ
;
184 AccessMode
= GENERIC_WRITE
;
189 AccessMode
= GENERIC_READ
| GENERIC_WRITE
;
194 return ERROR_INVALID_PARAMETER
;
197 /* Parse the share mode */
198 switch ((AccessShareModes
>> 4) & 0x07)
200 /* Compatibility mode */
202 ShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
205 /* No sharing "DenyAll" */
210 /* No write share "DenyWrite" */
212 ShareMode
= FILE_SHARE_READ
;
215 /* No read share "DenyRead" */
217 ShareMode
= FILE_SHARE_WRITE
;
220 /* Full share "DenyNone" */
222 ShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
227 return ERROR_INVALID_PARAMETER
;
231 * Parse the creation action flags:
233 * Bitfields for action:
236 * 7-4 Action if file does not exist.
240 * 3-0 Action if file exists.
245 switch (CreateActionFlags
)
247 /* If the file exists, fail, otherwise, fail also */
249 // A special case is used after the call to CreateFileA if it succeeds,
250 // in order to close the opened handle and return an adequate error.
251 CreationDisposition
= OPEN_EXISTING
;
254 /* If the file exists, open it, otherwise, fail */
256 CreationDisposition
= OPEN_EXISTING
;
259 /* If the file exists, replace it, otherwise, fail */
261 CreationDisposition
= TRUNCATE_EXISTING
;
264 /* If the file exists, fail, otherwise, create it */
266 CreationDisposition
= CREATE_NEW
;
269 /* If the file exists, open it, otherwise, create it */
271 CreationDisposition
= OPEN_ALWAYS
;
274 /* If the file exists, replace it, otherwise, create it */
276 CreationDisposition
= CREATE_ALWAYS
;
281 return ERROR_INVALID_PARAMETER
;
284 /* Check for inheritance */
285 InheritableFile
= ((AccessShareModes
& 0x80) == 0);
287 /* Assign default security attributes to the file, and set the inheritance flag */
288 SecurityAttributes
.nLength
= sizeof(SecurityAttributes
);
289 SecurityAttributes
.lpSecurityDescriptor
= NULL
;
290 SecurityAttributes
.bInheritHandle
= InheritableFile
;
293 FileHandle
= CreateFileA(FilePath
,
301 LastError
= (WORD
)GetLastError();
303 if (FileHandle
== INVALID_HANDLE_VALUE
)
305 /* Return the error code */
310 * Special case: CreateActionFlags == 0, we must fail because
311 * the file exists (if it didn't exist we already failed).
313 if (CreateActionFlags
== 0)
315 /* Close the file and return the error code */
316 CloseHandle(FileHandle
);
317 return ERROR_FILE_EXISTS
;
320 /* Set the creation status */
321 switch (CreateActionFlags
)
324 *CreationStatus
= 0x01; // The file was opened
328 *CreationStatus
= 0x03; // The file was replaced
332 *CreationStatus
= 0x02; // The file was created
337 if (LastError
== ERROR_ALREADY_EXISTS
)
338 *CreationStatus
= 0x01; // The file was opened
340 *CreationStatus
= 0x02; // The file was created
347 if (LastError
== ERROR_ALREADY_EXISTS
)
348 *CreationStatus
= 0x03; // The file was replaced
350 *CreationStatus
= 0x02; // The file was created
357 DescriptorId
= DosFindFreeDescriptor();
358 if (DescriptorId
== 0xFF)
360 /* Close the file and return the error code */
361 CloseHandle(FileHandle
);
362 return ERROR_TOO_MANY_OPEN_FILES
;
365 /* Set up the new descriptor */
366 Descriptor
= DosGetFileDescriptor(DescriptorId
);
367 RtlZeroMemory(Descriptor
, sizeof(*Descriptor
));
371 Descriptor
->DevicePointer
= Node
->Driver
;
372 Descriptor
->DeviceInfo
= Node
->DeviceAttributes
| FILE_INFO_DEVICE
;
376 Descriptor
->OpenMode
= AccessShareModes
;
377 Descriptor
->Attributes
= LOBYTE(GetFileAttributesA(FilePath
));
378 Descriptor
->Size
= GetFileSize(FileHandle
, NULL
);
379 Descriptor
->OwnerPsp
= CurrentPsp
;
380 Descriptor
->Win32Handle
= FileHandle
;
383 /* Open the DOS handle */
384 DosHandle
= DosOpenHandle(DescriptorId
);
385 if (DosHandle
== INVALID_DOS_HANDLE
)
387 /* Close the file and return the error code */
388 CloseHandle(FileHandle
);
389 return ERROR_TOO_MANY_OPEN_FILES
;
392 /* It was successful */
394 return ERROR_SUCCESS
;
397 WORD
DosCreateFile(LPWORD Handle
,
399 DWORD CreationDisposition
,
403 PDOS_DEVICE_NODE Node
;
406 PDOS_FILE_DESCRIPTOR Descriptor
;
408 DPRINT("DosCreateFile: FilePath \"%s\", CreationDisposition 0x%04X, Attributes 0x%04X\n",
409 FilePath
, CreationDisposition
, Attributes
);
411 Node
= DosGetDevice(FilePath
);
414 if (Node
->OpenRoutine
) Node
->OpenRoutine(Node
);
418 /* Create the file */
419 FileHandle
= CreateFileA(FilePath
,
420 GENERIC_READ
| GENERIC_WRITE
,
421 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
426 if (FileHandle
== INVALID_HANDLE_VALUE
)
428 /* Return the error code */
429 return (WORD
)GetLastError();
433 DescriptorId
= DosFindFreeDescriptor();
434 if (DescriptorId
== 0xFF)
436 /* Close the file and return the error code */
437 CloseHandle(FileHandle
);
438 return ERROR_TOO_MANY_OPEN_FILES
;
441 /* Set up the new descriptor */
442 Descriptor
= DosGetFileDescriptor(DescriptorId
);
443 RtlZeroMemory(Descriptor
, sizeof(*Descriptor
));
447 Descriptor
->DevicePointer
= Node
->Driver
;
448 Descriptor
->DeviceInfo
= Node
->DeviceAttributes
| FILE_INFO_DEVICE
;
452 Descriptor
->Attributes
= LOBYTE(GetFileAttributesA(FilePath
));
453 Descriptor
->Size
= GetFileSize(FileHandle
, NULL
);
454 Descriptor
->OwnerPsp
= CurrentPsp
;
455 Descriptor
->Win32Handle
= FileHandle
;
458 /* Open the DOS handle */
459 DosHandle
= DosOpenHandle(DescriptorId
);
460 if (DosHandle
== INVALID_DOS_HANDLE
)
462 /* Close the file and return the error code */
463 CloseHandle(FileHandle
);
464 return ERROR_TOO_MANY_OPEN_FILES
;
467 /* It was successful */
469 return ERROR_SUCCESS
;
472 WORD
DosOpenFile(LPWORD Handle
,
474 BYTE AccessShareModes
)
476 HANDLE FileHandle
= NULL
;
477 PDOS_DEVICE_NODE Node
;
480 PDOS_FILE_DESCRIPTOR Descriptor
;
482 DPRINT("DosOpenFile: FilePath \"%s\", AccessShareModes 0x%04X\n",
483 FilePath
, AccessShareModes
);
486 // The article about OpenFile API: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365430(v=vs.85).aspx
487 // explains what those AccessShareModes are (see the uStyle flag).
490 Node
= DosGetDevice(FilePath
);
493 if (Node
->OpenRoutine
) Node
->OpenRoutine(Node
);
497 ACCESS_MASK AccessMode
= 0;
499 BOOL InheritableFile
= FALSE
;
500 SECURITY_ATTRIBUTES SecurityAttributes
;
502 /* Parse the access mode */
503 switch (AccessShareModes
& 0x03)
507 AccessMode
= GENERIC_READ
;
512 AccessMode
= GENERIC_WRITE
;
517 AccessMode
= GENERIC_READ
| GENERIC_WRITE
;
522 return ERROR_INVALID_PARAMETER
;
525 /* Parse the share mode */
526 switch ((AccessShareModes
>> 4) & 0x07)
528 /* Compatibility mode */
530 ShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
533 /* No sharing "DenyAll" */
538 /* No write share "DenyWrite" */
540 ShareMode
= FILE_SHARE_READ
;
543 /* No read share "DenyRead" */
545 ShareMode
= FILE_SHARE_WRITE
;
548 /* Full share "DenyNone" */
550 ShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
555 return ERROR_INVALID_PARAMETER
;
558 /* Check for inheritance */
559 InheritableFile
= ((AccessShareModes
& 0x80) == 0);
561 /* Assign default security attributes to the file, and set the inheritance flag */
562 SecurityAttributes
.nLength
= sizeof(SecurityAttributes
);
563 SecurityAttributes
.lpSecurityDescriptor
= NULL
;
564 SecurityAttributes
.bInheritHandle
= InheritableFile
;
567 FileHandle
= CreateFileA(FilePath
,
572 FILE_ATTRIBUTE_NORMAL
,
574 if (FileHandle
== INVALID_HANDLE_VALUE
)
576 /* Return the error code */
577 return (WORD
)GetLastError();
581 DescriptorId
= DosFindFreeDescriptor();
582 if (DescriptorId
== 0xFF)
584 /* Close the file and return the error code */
585 CloseHandle(FileHandle
);
586 return ERROR_TOO_MANY_OPEN_FILES
;
589 /* Set up the new descriptor */
590 Descriptor
= DosGetFileDescriptor(DescriptorId
);
591 RtlZeroMemory(Descriptor
, sizeof(*Descriptor
));
595 Descriptor
->DevicePointer
= Node
->Driver
;
596 Descriptor
->DeviceInfo
= Node
->DeviceAttributes
| FILE_INFO_DEVICE
;
600 Descriptor
->OpenMode
= AccessShareModes
;
601 Descriptor
->Attributes
= LOBYTE(GetFileAttributesA(FilePath
));
602 Descriptor
->Size
= GetFileSize(FileHandle
, NULL
);
603 Descriptor
->OwnerPsp
= CurrentPsp
;
604 Descriptor
->Win32Handle
= FileHandle
;
607 /* Open the DOS handle */
608 DosHandle
= DosOpenHandle(DescriptorId
);
609 if (DosHandle
== INVALID_DOS_HANDLE
)
611 /* Close the file and return the error code */
612 CloseHandle(FileHandle
);
613 return ERROR_TOO_MANY_OPEN_FILES
;
616 /* It was successful */
618 return ERROR_SUCCESS
;
621 WORD
DosReadFile(WORD FileHandle
,
626 WORD Result
= ERROR_SUCCESS
;
627 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(FileHandle
);
629 DPRINT("DosReadFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle
, Count
);
631 if (Descriptor
== NULL
)
634 return ERROR_INVALID_HANDLE
;
637 if (Descriptor
->DeviceInfo
& FILE_INFO_DEVICE
)
639 PDOS_DEVICE_NODE Node
= DosGetDriverNode(Descriptor
->DevicePointer
);
640 if (!Node
->ReadRoutine
) return ERROR_INVALID_FUNCTION
;
642 /* Read the device */
643 Node
->ReadRoutine(Node
, Buffer
, &Count
);
648 DWORD BytesRead32
= 0;
649 LPVOID LocalBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Count
);
650 ASSERT(LocalBuffer
!= NULL
);
653 if (ReadFile(Descriptor
->Win32Handle
, LocalBuffer
, Count
, &BytesRead32
, NULL
))
655 /* Write to the memory */
656 MemWrite(TO_LINEAR(HIWORD(Buffer
), LOWORD(Buffer
)), LocalBuffer
, LOWORD(BytesRead32
));
658 /* Update the position */
659 Descriptor
->Position
+= BytesRead32
;
663 /* Store the error code */
664 Result
= (WORD
)GetLastError();
667 /* The number of bytes read is always 16-bit */
668 *BytesRead
= LOWORD(BytesRead32
);
669 RtlFreeHeap(RtlGetProcessHeap(), 0, LocalBuffer
);
672 /* Return the error code */
676 WORD
DosWriteFile(WORD FileHandle
,
681 WORD Result
= ERROR_SUCCESS
;
682 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(FileHandle
);
684 DPRINT("DosWriteFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle
, Count
);
686 if (Descriptor
== NULL
)
689 return ERROR_INVALID_HANDLE
;
692 if (Descriptor
->DeviceInfo
& FILE_INFO_DEVICE
)
694 PDOS_DEVICE_NODE Node
= DosGetDriverNode(Descriptor
->DevicePointer
);
695 if (!Node
->WriteRoutine
) return ERROR_INVALID_FUNCTION
;
697 /* Read the device */
698 Node
->WriteRoutine(Node
, Buffer
, &Count
);
699 *BytesWritten
= Count
;
703 DWORD BytesWritten32
= 0;
704 LPVOID LocalBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Count
);
705 ASSERT(LocalBuffer
!= NULL
);
707 /* Read from the memory */
708 MemRead(TO_LINEAR(HIWORD(Buffer
), LOWORD(Buffer
)), LocalBuffer
, Count
);
711 if (WriteFile(Descriptor
->Win32Handle
, LocalBuffer
, Count
, &BytesWritten32
, NULL
))
713 /* Update the position and size */
714 Descriptor
->Position
+= BytesWritten32
;
715 if (Descriptor
->Position
> Descriptor
->Size
) Descriptor
->Size
= Descriptor
->Position
;
719 /* Store the error code */
720 Result
= (WORD
)GetLastError();
723 /* The number of bytes written is always 16-bit */
724 *BytesWritten
= LOWORD(BytesWritten32
);
725 RtlFreeHeap(RtlGetProcessHeap(), 0, LocalBuffer
);
728 /* Return the error code */
732 WORD
DosSeekFile(WORD FileHandle
,
737 WORD Result
= ERROR_SUCCESS
;
739 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(FileHandle
);
741 DPRINT("DosSeekFile: FileHandle 0x%04X, Offset 0x%08X, Origin 0x%02X\n",
746 if (Descriptor
== NULL
)
749 return ERROR_INVALID_HANDLE
;
752 if (Descriptor
->DeviceInfo
& FILE_INFO_DEVICE
)
754 /* For character devices, always return success */
755 return ERROR_SUCCESS
;
758 /* Check if the origin is valid */
759 if (Origin
!= FILE_BEGIN
&& Origin
!= FILE_CURRENT
&& Origin
!= FILE_END
)
761 return ERROR_INVALID_FUNCTION
;
764 FilePointer
= SetFilePointer(Descriptor
->Win32Handle
, Offset
, NULL
, Origin
);
766 /* Check if there's a possibility the operation failed */
767 if (FilePointer
== INVALID_SET_FILE_POINTER
)
769 /* Get the real error code */
770 Result
= (WORD
)GetLastError();
773 if (Result
!= ERROR_SUCCESS
)
775 /* The operation did fail */
779 /* Update the descriptor */
780 Descriptor
->Position
= FilePointer
;
782 /* Return the file pointer, if requested */
783 if (NewOffset
) *NewOffset
= FilePointer
;
786 return ERROR_SUCCESS
;
789 BOOL
DosFlushFileBuffers(WORD FileHandle
)
791 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(FileHandle
);
793 if (Descriptor
== NULL
)
796 DosLastError
= ERROR_INVALID_HANDLE
;
800 if (Descriptor
->DeviceInfo
& FILE_INFO_DEVICE
)
802 PDOS_DEVICE_NODE Node
= DosGetDriverNode(Descriptor
->DevicePointer
);
804 if (Node
->FlushInputRoutine
) Node
->FlushInputRoutine(Node
);
805 if (Node
->FlushOutputRoutine
) Node
->FlushOutputRoutine(Node
);
811 return FlushFileBuffers(Descriptor
->Win32Handle
);
815 BOOLEAN
DosLockFile(WORD DosHandle
, DWORD Offset
, DWORD Size
)
817 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(DosHandle
);
819 if (Descriptor
== NULL
)
822 DosLastError
= ERROR_INVALID_HANDLE
;
826 /* Always succeed for character devices */
827 if (Descriptor
->DeviceInfo
& FILE_INFO_DEVICE
) return TRUE
;
829 if (!LockFile(Descriptor
->Win32Handle
, Offset
, 0, Size
, 0))
831 DosLastError
= GetLastError();
838 BOOLEAN
DosUnlockFile(WORD DosHandle
, DWORD Offset
, DWORD Size
)
840 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(DosHandle
);
842 if (Descriptor
== NULL
)
845 DosLastError
= ERROR_INVALID_HANDLE
;
849 /* Always succeed for character devices */
850 if (Descriptor
->DeviceInfo
& FILE_INFO_DEVICE
) return TRUE
;
852 if (!UnlockFile(Descriptor
->Win32Handle
, Offset
, 0, Size
, 0))
854 DosLastError
= GetLastError();
861 BOOLEAN
DosDeviceIoControl(WORD FileHandle
, BYTE ControlCode
, DWORD Buffer
, PWORD Length
)
863 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(FileHandle
);
864 PDOS_DEVICE_NODE Node
= NULL
;
868 DosLastError
= ERROR_INVALID_HANDLE
;
872 if (Descriptor
->DeviceInfo
& FILE_INFO_DEVICE
)
874 Node
= DosGetDriverNode(Descriptor
->DevicePointer
);
879 /* Get Device Information */
883 * See Ralf Brown: http://www.ctyme.com/intr/rb-2820.htm
884 * for a list of possible flags.
886 setDX(Descriptor
->DeviceInfo
);
890 /* Set Device Information */
893 // TODO: NOT IMPLEMENTED
899 /* Read From Device I/O Control Channel */
902 if (Node
== NULL
|| !(Node
->DeviceAttributes
& DOS_DEVATTR_IOCTL
))
904 DosLastError
= ERROR_INVALID_FUNCTION
;
908 /* Do nothing if there is no IOCTL routine */
909 if (!Node
->IoctlReadRoutine
)
915 Node
->IoctlReadRoutine(Node
, Buffer
, Length
);
919 /* Write To Device I/O Control Channel */
922 if (Node
== NULL
|| !(Node
->DeviceAttributes
& DOS_DEVATTR_IOCTL
))
924 DosLastError
= ERROR_INVALID_FUNCTION
;
928 /* Do nothing if there is no IOCTL routine */
929 if (!Node
->IoctlWriteRoutine
)
935 Node
->IoctlWriteRoutine(Node
, Buffer
, Length
);
939 /* Unsupported control code */
942 DPRINT1("Unsupported IOCTL: 0x%02X\n", ControlCode
);
944 DosLastError
= ERROR_INVALID_PARAMETER
;