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
& (1 << 7))
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
& (1 << 7))
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
,
150 ACCESS_MASK AccessMode
= 0;
152 DWORD CreationDisposition
= 0;
153 BOOL InheritableFile
= FALSE
;
154 SECURITY_ATTRIBUTES SecurityAttributes
;
156 PDOS_FILE_DESCRIPTOR Descriptor
;
158 DPRINT1("DosCreateFileEx: FilePath \"%s\", AccessShareModes 0x%04X, CreateActionFlags 0x%04X, Attributes 0x%04X\n",
159 FilePath
, AccessShareModes
, CreateActionFlags
, Attributes
);
162 // The article about OpenFile API: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365430(v=vs.85).aspx
163 // explains what those AccessShareModes are (see the uStyle flag).
166 /* Parse the access mode */
167 switch (AccessShareModes
& 0x03)
171 AccessMode
= GENERIC_READ
;
176 AccessMode
= GENERIC_WRITE
;
181 AccessMode
= GENERIC_READ
| GENERIC_WRITE
;
186 return ERROR_INVALID_PARAMETER
;
189 /* Parse the share mode */
190 switch ((AccessShareModes
>> 4) & 0x07)
192 /* Compatibility mode */
194 ShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
197 /* No sharing "DenyAll" */
202 /* No write share "DenyWrite" */
204 ShareMode
= FILE_SHARE_READ
;
207 /* No read share "DenyRead" */
209 ShareMode
= FILE_SHARE_WRITE
;
212 /* Full share "DenyNone" */
214 ShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
219 return ERROR_INVALID_PARAMETER
;
223 * Parse the creation action flags:
225 * Bitfields for action:
228 * 7-4 Action if file does not exist.
232 * 3-0 Action if file exists.
237 switch (CreateActionFlags
)
239 /* If the file exists, fail, otherwise, fail also */
241 // A special case is used after the call to CreateFileA if it succeeds,
242 // in order to close the opened handle and return an adequate error.
243 CreationDisposition
= OPEN_EXISTING
;
246 /* If the file exists, open it, otherwise, fail */
248 CreationDisposition
= OPEN_EXISTING
;
251 /* If the file exists, replace it, otherwise, fail */
253 CreationDisposition
= TRUNCATE_EXISTING
;
256 /* If the file exists, fail, otherwise, create it */
258 CreationDisposition
= CREATE_NEW
;
261 /* If the file exists, open it, otherwise, create it */
263 CreationDisposition
= OPEN_ALWAYS
;
266 /* If the file exists, replace it, otherwise, create it */
268 CreationDisposition
= CREATE_ALWAYS
;
273 return ERROR_INVALID_PARAMETER
;
276 /* Check for inheritance */
277 InheritableFile
= ((AccessShareModes
& 0x80) == 0);
279 /* Assign default security attributes to the file, and set the inheritance flag */
280 SecurityAttributes
.nLength
= sizeof(SecurityAttributes
);
281 SecurityAttributes
.lpSecurityDescriptor
= NULL
;
282 SecurityAttributes
.bInheritHandle
= InheritableFile
;
285 FileHandle
= CreateFileA(FilePath
,
293 LastError
= (WORD
)GetLastError();
295 if (FileHandle
== INVALID_HANDLE_VALUE
)
297 /* Return the error code */
302 * Special case: CreateActionFlags == 0, we must fail because
303 * the file exists (if it didn't exist we already failed).
305 if (CreateActionFlags
== 0)
307 /* Close the file and return the error code */
308 CloseHandle(FileHandle
);
309 return ERROR_FILE_EXISTS
;
312 /* Set the creation status */
313 switch (CreateActionFlags
)
316 *CreationStatus
= 0x01; // The file was opened
320 *CreationStatus
= 0x03; // The file was replaced
324 *CreationStatus
= 0x02; // The file was created
329 if (LastError
== ERROR_ALREADY_EXISTS
)
330 *CreationStatus
= 0x01; // The file was opened
332 *CreationStatus
= 0x02; // The file was created
339 if (LastError
== ERROR_ALREADY_EXISTS
)
340 *CreationStatus
= 0x03; // The file was replaced
342 *CreationStatus
= 0x02; // The file was created
348 DescriptorId
= DosFindFreeDescriptor();
349 if (DescriptorId
== 0xFF)
351 /* Close the file and return the error code */
352 CloseHandle(FileHandle
);
353 return ERROR_TOO_MANY_OPEN_FILES
;
356 /* Set up the new descriptor */
357 Descriptor
= DosGetFileDescriptor(DescriptorId
);
358 RtlZeroMemory(Descriptor
, sizeof(*Descriptor
));
360 Descriptor
->OpenMode
= AccessShareModes
;
361 Descriptor
->Attributes
= LOBYTE(GetFileAttributesA(FilePath
));
362 Descriptor
->Size
= GetFileSize(FileHandle
, NULL
);
363 Descriptor
->OwnerPsp
= CurrentPsp
;
364 Descriptor
->Win32Handle
= FileHandle
;
366 /* Open the DOS handle */
367 DosHandle
= DosOpenHandle(DescriptorId
);
368 if (DosHandle
== INVALID_DOS_HANDLE
)
370 /* Close the file and return the error code */
371 CloseHandle(FileHandle
);
372 return ERROR_TOO_MANY_OPEN_FILES
;
375 /* It was successful */
377 return ERROR_SUCCESS
;
380 WORD
DosCreateFile(LPWORD Handle
,
382 DWORD CreationDisposition
,
388 PDOS_FILE_DESCRIPTOR Descriptor
;
390 DPRINT("DosCreateFile: FilePath \"%s\", CreationDisposition 0x%04X, Attributes 0x%04X\n",
391 FilePath
, CreationDisposition
, Attributes
);
393 /* Create the file */
394 FileHandle
= CreateFileA(FilePath
,
395 GENERIC_READ
| GENERIC_WRITE
,
396 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
401 if (FileHandle
== INVALID_HANDLE_VALUE
)
403 /* Return the error code */
404 return (WORD
)GetLastError();
407 DescriptorId
= DosFindFreeDescriptor();
408 if (DescriptorId
== 0xFF)
410 /* Close the file and return the error code */
411 CloseHandle(FileHandle
);
412 return ERROR_TOO_MANY_OPEN_FILES
;
415 /* Set up the new descriptor */
416 Descriptor
= DosGetFileDescriptor(DescriptorId
);
417 RtlZeroMemory(Descriptor
, sizeof(*Descriptor
));
419 Descriptor
->Attributes
= LOBYTE(GetFileAttributesA(FilePath
));
420 Descriptor
->Size
= GetFileSize(FileHandle
, NULL
);
421 Descriptor
->OwnerPsp
= CurrentPsp
;
422 Descriptor
->Win32Handle
= FileHandle
;
424 /* Open the DOS handle */
425 DosHandle
= DosOpenHandle(DescriptorId
);
426 if (DosHandle
== INVALID_DOS_HANDLE
)
428 /* Close the file and return the error code */
429 CloseHandle(FileHandle
);
430 return ERROR_TOO_MANY_OPEN_FILES
;
433 /* It was successful */
435 return ERROR_SUCCESS
;
438 WORD
DosOpenFile(LPWORD Handle
,
440 BYTE AccessShareModes
)
442 HANDLE FileHandle
= NULL
;
443 PDOS_DEVICE_NODE Node
;
446 PDOS_FILE_DESCRIPTOR Descriptor
;
448 DPRINT("DosOpenFile: FilePath \"%s\", AccessShareModes 0x%04X\n",
449 FilePath
, AccessShareModes
);
452 // The article about OpenFile API: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365430(v=vs.85).aspx
453 // explains what those AccessShareModes are (see the uStyle flag).
456 Node
= DosGetDevice(FilePath
);
459 if (Node
->OpenRoutine
) Node
->OpenRoutine(Node
);
463 ACCESS_MASK AccessMode
= 0;
465 BOOL InheritableFile
= FALSE
;
466 SECURITY_ATTRIBUTES SecurityAttributes
;
468 /* Parse the access mode */
469 switch (AccessShareModes
& 0x03)
473 AccessMode
= GENERIC_READ
;
478 AccessMode
= GENERIC_WRITE
;
483 AccessMode
= GENERIC_READ
| GENERIC_WRITE
;
488 return ERROR_INVALID_PARAMETER
;
491 /* Parse the share mode */
492 switch ((AccessShareModes
>> 4) & 0x07)
494 /* Compatibility mode */
496 ShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
499 /* No sharing "DenyAll" */
504 /* No write share "DenyWrite" */
506 ShareMode
= FILE_SHARE_READ
;
509 /* No read share "DenyRead" */
511 ShareMode
= FILE_SHARE_WRITE
;
514 /* Full share "DenyNone" */
516 ShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
521 return ERROR_INVALID_PARAMETER
;
524 /* Check for inheritance */
525 InheritableFile
= ((AccessShareModes
& 0x80) == 0);
527 /* Assign default security attributes to the file, and set the inheritance flag */
528 SecurityAttributes
.nLength
= sizeof(SecurityAttributes
);
529 SecurityAttributes
.lpSecurityDescriptor
= NULL
;
530 SecurityAttributes
.bInheritHandle
= InheritableFile
;
533 FileHandle
= CreateFileA(FilePath
,
538 FILE_ATTRIBUTE_NORMAL
,
540 if (FileHandle
== INVALID_HANDLE_VALUE
)
542 /* Return the error code */
543 return (WORD
)GetLastError();
547 DescriptorId
= DosFindFreeDescriptor();
548 if (DescriptorId
== 0xFF)
550 /* Close the file and return the error code */
551 CloseHandle(FileHandle
);
552 return ERROR_TOO_MANY_OPEN_FILES
;
555 /* Set up the new descriptor */
556 Descriptor
= DosGetFileDescriptor(DescriptorId
);
557 RtlZeroMemory(Descriptor
, sizeof(*Descriptor
));
561 Descriptor
->DevicePointer
= Node
->Driver
;
562 Descriptor
->DeviceInfo
= Node
->DeviceAttributes
| (1 << 7);
566 Descriptor
->OpenMode
= AccessShareModes
;
567 Descriptor
->Attributes
= LOBYTE(GetFileAttributesA(FilePath
));
568 Descriptor
->Size
= GetFileSize(FileHandle
, NULL
);
569 Descriptor
->OwnerPsp
= CurrentPsp
;
570 Descriptor
->Win32Handle
= FileHandle
;
573 /* Open the DOS handle */
574 DosHandle
= DosOpenHandle(DescriptorId
);
575 if (DosHandle
== INVALID_DOS_HANDLE
)
577 /* Close the file and return the error code */
578 CloseHandle(FileHandle
);
579 return ERROR_TOO_MANY_OPEN_FILES
;
582 /* It was successful */
584 return ERROR_SUCCESS
;
587 WORD
DosReadFile(WORD FileHandle
,
592 WORD Result
= ERROR_SUCCESS
;
593 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(FileHandle
);
595 DPRINT("DosReadFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle
, Count
);
597 if (Descriptor
== NULL
)
600 return ERROR_INVALID_HANDLE
;
603 if (Descriptor
->DeviceInfo
& (1 << 7))
605 PDOS_DEVICE_NODE Node
= DosGetDriverNode(Descriptor
->DevicePointer
);
606 if (!Node
->ReadRoutine
) return ERROR_INVALID_FUNCTION
;
608 /* Read the device */
609 Node
->ReadRoutine(Node
, Buffer
, &Count
);
614 DWORD BytesRead32
= 0;
615 LPVOID LocalBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Count
);
616 ASSERT(LocalBuffer
!= NULL
);
619 if (ReadFile(Descriptor
->Win32Handle
, LocalBuffer
, Count
, &BytesRead32
, NULL
))
621 /* Write to the memory */
622 MemWrite(TO_LINEAR(HIWORD(Buffer
), LOWORD(Buffer
)), LocalBuffer
, LOWORD(BytesRead32
));
624 /* Update the position */
625 Descriptor
->Position
+= BytesRead32
;
629 /* Store the error code */
630 Result
= (WORD
)GetLastError();
633 /* The number of bytes read is always 16-bit */
634 *BytesRead
= LOWORD(BytesRead32
);
635 RtlFreeHeap(RtlGetProcessHeap(), 0, LocalBuffer
);
638 /* Return the error code */
642 WORD
DosWriteFile(WORD FileHandle
,
647 WORD Result
= ERROR_SUCCESS
;
648 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(FileHandle
);
650 DPRINT("DosWriteFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle
, Count
);
652 if (Descriptor
== NULL
)
655 return ERROR_INVALID_HANDLE
;
658 if (Descriptor
->DeviceInfo
& (1 << 7))
660 PDOS_DEVICE_NODE Node
= DosGetDriverNode(Descriptor
->DevicePointer
);
661 if (!Node
->WriteRoutine
) return ERROR_INVALID_FUNCTION
;
663 /* Read the device */
664 Node
->WriteRoutine(Node
, Buffer
, &Count
);
665 *BytesWritten
= Count
;
669 DWORD BytesWritten32
= 0;
670 LPVOID LocalBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Count
);
671 ASSERT(LocalBuffer
!= NULL
);
673 /* Read from the memory */
674 MemRead(TO_LINEAR(HIWORD(Buffer
), LOWORD(Buffer
)), LocalBuffer
, Count
);
677 if (WriteFile(Descriptor
->Win32Handle
, LocalBuffer
, Count
, &BytesWritten32
, NULL
))
679 /* Update the position and size */
680 Descriptor
->Position
+= BytesWritten32
;
681 if (Descriptor
->Position
> Descriptor
->Size
) Descriptor
->Size
= Descriptor
->Position
;
685 /* Store the error code */
686 Result
= (WORD
)GetLastError();
689 /* The number of bytes written is always 16-bit */
690 *BytesWritten
= LOWORD(BytesWritten32
);
691 RtlFreeHeap(RtlGetProcessHeap(), 0, LocalBuffer
);
694 /* Return the error code */
698 WORD
DosSeekFile(WORD FileHandle
,
703 WORD Result
= ERROR_SUCCESS
;
705 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(FileHandle
);
707 DPRINT("DosSeekFile: FileHandle 0x%04X, Offset 0x%08X, Origin 0x%02X\n",
712 if (Descriptor
== NULL
)
715 return ERROR_INVALID_HANDLE
;
718 if (Descriptor
->DeviceInfo
& (1 << 7))
720 /* For character devices, always return success */
721 return ERROR_SUCCESS
;
724 /* Check if the origin is valid */
725 if (Origin
!= FILE_BEGIN
&& Origin
!= FILE_CURRENT
&& Origin
!= FILE_END
)
727 return ERROR_INVALID_FUNCTION
;
730 FilePointer
= SetFilePointer(Descriptor
->Win32Handle
, Offset
, NULL
, Origin
);
732 /* Check if there's a possibility the operation failed */
733 if (FilePointer
== INVALID_SET_FILE_POINTER
)
735 /* Get the real error code */
736 Result
= (WORD
)GetLastError();
739 if (Result
!= ERROR_SUCCESS
)
741 /* The operation did fail */
745 /* Update the descriptor */
746 Descriptor
->Position
= FilePointer
;
748 /* Return the file pointer, if requested */
749 if (NewOffset
) *NewOffset
= FilePointer
;
752 return ERROR_SUCCESS
;
755 BOOL
DosFlushFileBuffers(WORD FileHandle
)
757 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(FileHandle
);
759 if (Descriptor
== NULL
)
762 DosLastError
= ERROR_INVALID_HANDLE
;
766 if (Descriptor
->DeviceInfo
& (1 << 7))
768 PDOS_DEVICE_NODE Node
= DosGetDriverNode(Descriptor
->DevicePointer
);
770 if (Node
->FlushInputRoutine
) Node
->FlushInputRoutine(Node
);
771 if (Node
->FlushOutputRoutine
) Node
->FlushOutputRoutine(Node
);
777 return FlushFileBuffers(Descriptor
->Win32Handle
);
781 BOOLEAN
DosLockFile(WORD DosHandle
, DWORD Offset
, DWORD Size
)
783 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(DosHandle
);
785 if (Descriptor
== NULL
)
788 DosLastError
= ERROR_INVALID_HANDLE
;
792 /* Always succeed for character devices */
793 if (Descriptor
->DeviceInfo
& (1 << 7)) return TRUE
;
795 if (!LockFile(Descriptor
->Win32Handle
, Offset
, 0, Size
, 0))
797 DosLastError
= GetLastError();
804 BOOLEAN
DosUnlockFile(WORD DosHandle
, DWORD Offset
, DWORD Size
)
806 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(DosHandle
);
808 if (Descriptor
== NULL
)
811 DosLastError
= ERROR_INVALID_HANDLE
;
815 /* Always succeed for character devices */
816 if (Descriptor
->DeviceInfo
& (1 << 7)) return TRUE
;
818 if (!UnlockFile(Descriptor
->Win32Handle
, Offset
, 0, Size
, 0))
820 DosLastError
= GetLastError();
827 BOOLEAN
DosDeviceIoControl(WORD FileHandle
, BYTE ControlCode
, DWORD Buffer
, PWORD Length
)
829 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(FileHandle
);
830 PDOS_DEVICE_NODE Node
= NULL
;
834 DosLastError
= ERROR_INVALID_HANDLE
;
838 if (Descriptor
->DeviceInfo
& (1 << 7))
840 Node
= DosGetDriverNode(Descriptor
->DevicePointer
);
845 /* Get Device Information */
849 * See Ralf Brown: http://www.ctyme.com/intr/rb-2820.htm
850 * for a list of possible flags.
852 setDX(Descriptor
->DeviceInfo
);
856 /* Set Device Information */
859 // TODO: NOT IMPLEMENTED
865 /* Read From Device I/O Control Channel */
868 if (Node
== NULL
|| !(Node
->DeviceAttributes
& DOS_DEVATTR_IOCTL
))
870 DosLastError
= ERROR_INVALID_FUNCTION
;
874 /* Do nothing if there is no IOCTL routine */
875 if (!Node
->IoctlReadRoutine
)
881 Node
->IoctlReadRoutine(Node
, Buffer
, Length
);
885 /* Write To Device I/O Control Channel */
888 if (Node
== NULL
|| !(Node
->DeviceAttributes
& DOS_DEVATTR_IOCTL
))
890 DosLastError
= ERROR_INVALID_FUNCTION
;
894 /* Do nothing if there is no IOCTL routine */
895 if (!Node
->IoctlWriteRoutine
)
901 Node
->IoctlWriteRoutine(Node
, Buffer
, Length
);
905 /* Unsupported control code */
908 DPRINT1("Unsupported IOCTL: 0x%02X\n", ControlCode
);
910 DosLastError
= ERROR_INVALID_PARAMETER
;