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 /* 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 WORD
DosReadFile(WORD FileHandle
,
677 WORD Result
= ERROR_SUCCESS
;
678 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(FileHandle
);
680 DPRINT("DosReadFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle
, Count
);
682 if (Descriptor
== NULL
)
685 return ERROR_INVALID_HANDLE
;
688 if (Descriptor
->DeviceInfo
& FILE_INFO_DEVICE
)
690 PDOS_DEVICE_NODE Node
= DosGetDriverNode(Descriptor
->DevicePointer
);
691 if (!Node
->ReadRoutine
) return ERROR_INVALID_FUNCTION
;
693 /* Read the device */
694 Node
->ReadRoutine(Node
, Buffer
, &Count
);
699 DWORD BytesRead32
= 0;
700 LPVOID LocalBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Count
);
701 ASSERT(LocalBuffer
!= NULL
);
704 if (ReadFile(Descriptor
->Win32Handle
, LocalBuffer
, Count
, &BytesRead32
, NULL
))
706 /* Write to the memory */
707 EmulatorWriteMemory(&EmulatorContext
,
708 TO_LINEAR(HIWORD(Buffer
), LOWORD(Buffer
)),
710 LOWORD(BytesRead32
));
712 /* Update the position */
713 Descriptor
->Position
+= BytesRead32
;
717 /* Store the error code */
718 Result
= (WORD
)GetLastError();
721 /* The number of bytes read is always 16-bit */
722 *BytesRead
= LOWORD(BytesRead32
);
723 RtlFreeHeap(RtlGetProcessHeap(), 0, LocalBuffer
);
726 /* Return the error code */
730 WORD
DosWriteFile(WORD FileHandle
,
735 WORD Result
= ERROR_SUCCESS
;
736 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(FileHandle
);
738 DPRINT("DosWriteFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle
, Count
);
740 if (Descriptor
== NULL
)
743 return ERROR_INVALID_HANDLE
;
746 if (Descriptor
->DeviceInfo
& FILE_INFO_DEVICE
)
748 PDOS_DEVICE_NODE Node
= DosGetDriverNode(Descriptor
->DevicePointer
);
749 if (!Node
->WriteRoutine
) return ERROR_INVALID_FUNCTION
;
751 /* Read the device */
752 Node
->WriteRoutine(Node
, Buffer
, &Count
);
753 *BytesWritten
= Count
;
757 DWORD BytesWritten32
= 0;
758 LPVOID LocalBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Count
);
759 ASSERT(LocalBuffer
!= NULL
);
761 /* Read from the memory */
762 EmulatorReadMemory(&EmulatorContext
,
763 TO_LINEAR(HIWORD(Buffer
),
769 if (WriteFile(Descriptor
->Win32Handle
, LocalBuffer
, Count
, &BytesWritten32
, NULL
))
771 /* Update the position and size */
772 Descriptor
->Position
+= BytesWritten32
;
773 if (Descriptor
->Position
> Descriptor
->Size
) Descriptor
->Size
= Descriptor
->Position
;
777 /* Store the error code */
778 Result
= (WORD
)GetLastError();
781 /* The number of bytes written is always 16-bit */
782 *BytesWritten
= LOWORD(BytesWritten32
);
783 RtlFreeHeap(RtlGetProcessHeap(), 0, LocalBuffer
);
786 /* Return the error code */
790 WORD
DosSeekFile(WORD FileHandle
,
795 WORD Result
= ERROR_SUCCESS
;
797 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(FileHandle
);
799 DPRINT("DosSeekFile: FileHandle 0x%04X, Offset 0x%08X, Origin 0x%02X\n",
804 if (Descriptor
== NULL
)
807 return ERROR_INVALID_HANDLE
;
810 if (Descriptor
->DeviceInfo
& FILE_INFO_DEVICE
)
812 /* For character devices, always return success */
813 return ERROR_SUCCESS
;
816 /* Check if the origin is valid */
817 if (Origin
!= FILE_BEGIN
&& Origin
!= FILE_CURRENT
&& Origin
!= FILE_END
)
819 return ERROR_INVALID_FUNCTION
;
822 FilePointer
= SetFilePointer(Descriptor
->Win32Handle
, Offset
, NULL
, Origin
);
824 /* Check if there's a possibility the operation failed */
825 if (FilePointer
== INVALID_SET_FILE_POINTER
)
827 /* Get the real error code */
828 Result
= (WORD
)GetLastError();
831 if (Result
!= ERROR_SUCCESS
)
833 /* The operation did fail */
837 /* Update the descriptor */
838 Descriptor
->Position
= FilePointer
;
840 /* Return the file pointer, if requested */
841 if (NewOffset
) *NewOffset
= FilePointer
;
844 return ERROR_SUCCESS
;
847 BOOL
DosFlushFileBuffers(WORD FileHandle
)
849 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(FileHandle
);
851 if (Descriptor
== NULL
)
854 Sda
->LastErrorCode
= ERROR_INVALID_HANDLE
;
858 if (Descriptor
->DeviceInfo
& FILE_INFO_DEVICE
)
860 PDOS_DEVICE_NODE Node
= DosGetDriverNode(Descriptor
->DevicePointer
);
862 if (Node
->FlushInputRoutine
) Node
->FlushInputRoutine(Node
);
863 if (Node
->FlushOutputRoutine
) Node
->FlushOutputRoutine(Node
);
869 return FlushFileBuffers(Descriptor
->Win32Handle
);
873 BOOLEAN
DosLockFile(WORD DosHandle
, DWORD Offset
, DWORD Size
)
875 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(DosHandle
);
877 if (Descriptor
== NULL
)
880 Sda
->LastErrorCode
= ERROR_INVALID_HANDLE
;
884 /* Always succeed for character devices */
885 if (Descriptor
->DeviceInfo
& FILE_INFO_DEVICE
) return TRUE
;
887 if (!LockFile(Descriptor
->Win32Handle
, Offset
, 0, Size
, 0))
889 Sda
->LastErrorCode
= GetLastError();
896 BOOLEAN
DosUnlockFile(WORD DosHandle
, DWORD Offset
, DWORD Size
)
898 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(DosHandle
);
900 if (Descriptor
== NULL
)
903 Sda
->LastErrorCode
= ERROR_INVALID_HANDLE
;
907 /* Always succeed for character devices */
908 if (Descriptor
->DeviceInfo
& FILE_INFO_DEVICE
) return TRUE
;
910 if (!UnlockFile(Descriptor
->Win32Handle
, Offset
, 0, Size
, 0))
912 Sda
->LastErrorCode
= GetLastError();
919 BOOLEAN
DosDeviceIoControl(WORD FileHandle
, BYTE ControlCode
, DWORD Buffer
, PWORD Length
)
921 PDOS_FILE_DESCRIPTOR Descriptor
= DosGetHandleFileDescriptor(FileHandle
);
922 PDOS_DEVICE_NODE Node
= NULL
;
926 Sda
->LastErrorCode
= ERROR_INVALID_HANDLE
;
930 if (Descriptor
->DeviceInfo
& FILE_INFO_DEVICE
)
932 Node
= DosGetDriverNode(Descriptor
->DevicePointer
);
937 /* Get Device Information */
941 * See Ralf Brown: http://www.ctyme.com/intr/rb-2820.htm
942 * for a list of possible flags.
944 setDX(Descriptor
->DeviceInfo
);
948 /* Set Device Information */
951 // TODO: NOT IMPLEMENTED
957 /* Read From Device I/O Control Channel */
960 if (Node
== NULL
|| !(Node
->DeviceAttributes
& DOS_DEVATTR_IOCTL
))
962 Sda
->LastErrorCode
= ERROR_INVALID_FUNCTION
;
966 /* Do nothing if there is no IOCTL routine */
967 if (!Node
->IoctlReadRoutine
)
973 Node
->IoctlReadRoutine(Node
, Buffer
, Length
);
977 /* Write To Device I/O Control Channel */
980 if (Node
== NULL
|| !(Node
->DeviceAttributes
& DOS_DEVATTR_IOCTL
))
982 Sda
->LastErrorCode
= ERROR_INVALID_FUNCTION
;
986 /* Do nothing if there is no IOCTL routine */
987 if (!Node
->IoctlWriteRoutine
)
993 Node
->IoctlWriteRoutine(Node
, Buffer
, Length
);
997 /* Get Input Status */
1000 /* Check if this is a file or a device */
1005 if (!Node
->InputStatusRoutine
|| Node
->InputStatusRoutine(Node
))
1007 /* Set the length to 0xFF to mark that it's ready */
1020 if (Descriptor
->Position
< Descriptor
->Size
)
1022 /* Set the length to 0xFF to mark that it's ready */
1035 /* Get Output Status */
1038 /* Check if this is a file or a device */
1043 if (!Node
->OutputStatusRoutine
|| Node
->OutputStatusRoutine(Node
))
1045 /* Set the length to 0xFF to mark that it's ready */
1056 /* Files are always ready for output */
1063 /* Unsupported control code */
1066 DPRINT1("Unsupported IOCTL: 0x%02X\n", ControlCode
);
1068 Sda
->LastErrorCode
= ERROR_INVALID_PARAMETER
;