[NTVDM]
[reactos.git] / reactos / subsystems / mvdm / ntvdm / dos / dos32krnl / dosfiles.c
1 /*
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)
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #define NDEBUG
13
14 #include "ntvdm.h"
15 #include "emulator.h"
16 #include "../../memory.h"
17
18 #include "dos.h"
19 #include "dos/dem.h"
20 #include "dosfiles.h"
21 #include "handle.h"
22 #include "process.h"
23
24 #include "bios/bios.h"
25
26 /* PUBLIC FUNCTIONS ***********************************************************/
27
28 BYTE DosFindFreeDescriptor(VOID)
29 {
30 UINT i;
31 BYTE Count = 0;
32 DWORD CurrentSft = SysVars->FirstSft;
33
34 while (LOWORD(CurrentSft) != 0xFFFF)
35 {
36 PDOS_SFT Sft = (PDOS_SFT)FAR_POINTER(CurrentSft);
37
38 for (i = 0; i < Sft->NumDescriptors; i++)
39 {
40 if (Sft->FileDescriptors[i].RefCount == 0) return Count;
41 Count++;
42 }
43
44 /* Go to the next table */
45 CurrentSft = Sft->Link;
46 }
47
48 /* Invalid ID */
49 return 0xFF;
50 }
51
52 BYTE DosFindWin32Descriptor(HANDLE Win32Handle)
53 {
54 UINT i;
55 BYTE Count = 0;
56 DWORD CurrentSft = SysVars->FirstSft;
57
58 while (LOWORD(CurrentSft) != 0xFFFF)
59 {
60 PDOS_SFT Sft = (PDOS_SFT)FAR_POINTER(CurrentSft);
61
62 for (i = 0; i < Sft->NumDescriptors; i++)
63 {
64 if ((Sft->FileDescriptors[i].RefCount > 0)
65 && !(Sft->FileDescriptors[i].DeviceInfo & (1 << 7))
66 && (Sft->FileDescriptors[i].Win32Handle == Win32Handle))
67 {
68 return Count;
69 }
70
71 Count++;
72 }
73
74 /* Go to the next table */
75 CurrentSft = Sft->Link;
76 }
77
78 /* Invalid ID */
79 return 0xFF;
80 }
81
82 BYTE DosFindDeviceDescriptor(DWORD DevicePointer)
83 {
84 UINT i;
85 BYTE Count = 0;
86 DWORD CurrentSft = SysVars->FirstSft;
87
88 while (LOWORD(CurrentSft) != 0xFFFF)
89 {
90 PDOS_SFT Sft = (PDOS_SFT)FAR_POINTER(CurrentSft);
91
92 for (i = 0; i < Sft->NumDescriptors; i++)
93 {
94 if ((Sft->FileDescriptors[i].RefCount > 0)
95 && (Sft->FileDescriptors[i].DeviceInfo & (1 << 7))
96 && (Sft->FileDescriptors[i].DevicePointer == DevicePointer))
97 {
98 return Count;
99 }
100
101 Count++;
102 }
103
104 /* Go to the next table */
105 CurrentSft = Sft->Link;
106 }
107
108 /* Invalid ID */
109 return 0xFF;
110 }
111
112 PDOS_FILE_DESCRIPTOR DosGetFileDescriptor(BYTE Id)
113 {
114 DWORD CurrentSft = SysVars->FirstSft;
115
116 while (LOWORD(CurrentSft) != 0xFFFF)
117 {
118 PDOS_SFT Sft = (PDOS_SFT)FAR_POINTER(CurrentSft);
119
120 /* Return it if it's in this table */
121 if (Id <= Sft->NumDescriptors) return &Sft->FileDescriptors[Id];
122
123 /* Go to the next table */
124 Id -= Sft->NumDescriptors;
125 CurrentSft = Sft->Link;
126 }
127
128 /* Invalid ID */
129 return NULL;
130 }
131
132 PDOS_FILE_DESCRIPTOR DosGetHandleFileDescriptor(WORD DosHandle)
133 {
134 BYTE DescriptorId = DosQueryHandle(DosHandle);
135 if (DescriptorId == 0xFF) return NULL;
136
137 return DosGetFileDescriptor(DescriptorId);
138 }
139
140 WORD DosCreateFileEx(LPWORD Handle,
141 LPWORD CreationStatus,
142 LPCSTR FilePath,
143 BYTE AccessShareModes,
144 WORD CreateActionFlags,
145 WORD Attributes)
146 {
147 WORD LastError;
148 HANDLE FileHandle;
149 WORD DosHandle;
150 ACCESS_MASK AccessMode = 0;
151 DWORD ShareMode = 0;
152 DWORD CreationDisposition = 0;
153 BOOL InheritableFile = FALSE;
154 SECURITY_ATTRIBUTES SecurityAttributes;
155 BYTE DescriptorId;
156 PDOS_FILE_DESCRIPTOR Descriptor;
157
158 DPRINT1("DosCreateFileEx: FilePath \"%s\", AccessShareModes 0x%04X, CreateActionFlags 0x%04X, Attributes 0x%04X\n",
159 FilePath, AccessShareModes, CreateActionFlags, Attributes);
160
161 //
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).
164 //
165
166 /* Parse the access mode */
167 switch (AccessShareModes & 0x03)
168 {
169 /* Read-only */
170 case 0:
171 AccessMode = GENERIC_READ;
172 break;
173
174 /* Write only */
175 case 1:
176 AccessMode = GENERIC_WRITE;
177 break;
178
179 /* Read and write */
180 case 2:
181 AccessMode = GENERIC_READ | GENERIC_WRITE;
182 break;
183
184 /* Invalid */
185 default:
186 return ERROR_INVALID_PARAMETER;
187 }
188
189 /* Parse the share mode */
190 switch ((AccessShareModes >> 4) & 0x07)
191 {
192 /* Compatibility mode */
193 case 0:
194 ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
195 break;
196
197 /* No sharing "DenyAll" */
198 case 1:
199 ShareMode = 0;
200 break;
201
202 /* No write share "DenyWrite" */
203 case 2:
204 ShareMode = FILE_SHARE_READ;
205 break;
206
207 /* No read share "DenyRead" */
208 case 3:
209 ShareMode = FILE_SHARE_WRITE;
210 break;
211
212 /* Full share "DenyNone" */
213 case 4:
214 ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
215 break;
216
217 /* Invalid */
218 default:
219 return ERROR_INVALID_PARAMETER;
220 }
221
222 /*
223 * Parse the creation action flags:
224 *
225 * Bitfields for action:
226 * Bit(s) Description
227 *
228 * 7-4 Action if file does not exist.
229 * 0000 Fail
230 * 0001 Create
231 *
232 * 3-0 Action if file exists.
233 * 0000 Fail
234 * 0001 Open
235 * 0010 Replace/open
236 */
237 switch (CreateActionFlags)
238 {
239 /* If the file exists, fail, otherwise, fail also */
240 case 0x00:
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;
244 break;
245
246 /* If the file exists, open it, otherwise, fail */
247 case 0x01:
248 CreationDisposition = OPEN_EXISTING;
249 break;
250
251 /* If the file exists, replace it, otherwise, fail */
252 case 0x02:
253 CreationDisposition = TRUNCATE_EXISTING;
254 break;
255
256 /* If the file exists, fail, otherwise, create it */
257 case 0x10:
258 CreationDisposition = CREATE_NEW;
259 break;
260
261 /* If the file exists, open it, otherwise, create it */
262 case 0x11:
263 CreationDisposition = OPEN_ALWAYS;
264 break;
265
266 /* If the file exists, replace it, otherwise, create it */
267 case 0x12:
268 CreationDisposition = CREATE_ALWAYS;
269 break;
270
271 /* Invalid */
272 default:
273 return ERROR_INVALID_PARAMETER;
274 }
275
276 /* Check for inheritance */
277 InheritableFile = ((AccessShareModes & 0x80) == 0);
278
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;
283
284 /* Open the file */
285 FileHandle = CreateFileA(FilePath,
286 AccessMode,
287 ShareMode,
288 &SecurityAttributes,
289 CreationDisposition,
290 Attributes,
291 NULL);
292
293 LastError = (WORD)GetLastError();
294
295 if (FileHandle == INVALID_HANDLE_VALUE)
296 {
297 /* Return the error code */
298 return LastError;
299 }
300
301 /*
302 * Special case: CreateActionFlags == 0, we must fail because
303 * the file exists (if it didn't exist we already failed).
304 */
305 if (CreateActionFlags == 0)
306 {
307 /* Close the file and return the error code */
308 CloseHandle(FileHandle);
309 return ERROR_FILE_EXISTS;
310 }
311
312 /* Set the creation status */
313 switch (CreateActionFlags)
314 {
315 case 0x01:
316 *CreationStatus = 0x01; // The file was opened
317 break;
318
319 case 0x02:
320 *CreationStatus = 0x03; // The file was replaced
321 break;
322
323 case 0x10:
324 *CreationStatus = 0x02; // The file was created
325 break;
326
327 case 0x11:
328 {
329 if (LastError == ERROR_ALREADY_EXISTS)
330 *CreationStatus = 0x01; // The file was opened
331 else
332 *CreationStatus = 0x02; // The file was created
333
334 break;
335 }
336
337 case 0x12:
338 {
339 if (LastError == ERROR_ALREADY_EXISTS)
340 *CreationStatus = 0x03; // The file was replaced
341 else
342 *CreationStatus = 0x02; // The file was created
343
344 break;
345 }
346 }
347
348 DescriptorId = DosFindFreeDescriptor();
349 if (DescriptorId == 0xFF)
350 {
351 /* Close the file and return the error code */
352 CloseHandle(FileHandle);
353 return ERROR_TOO_MANY_OPEN_FILES;
354 }
355
356 /* Set up the new descriptor */
357 Descriptor = DosGetFileDescriptor(DescriptorId);
358 RtlZeroMemory(Descriptor, sizeof(*Descriptor));
359
360 Descriptor->OpenMode = AccessShareModes;
361 Descriptor->Attributes = LOBYTE(GetFileAttributesA(FilePath));
362 Descriptor->Size = GetFileSize(FileHandle, NULL);
363 Descriptor->OwnerPsp = CurrentPsp;
364 Descriptor->Win32Handle = FileHandle;
365
366 /* Open the DOS handle */
367 DosHandle = DosOpenHandle(DescriptorId);
368 if (DosHandle == INVALID_DOS_HANDLE)
369 {
370 /* Close the file and return the error code */
371 CloseHandle(FileHandle);
372 return ERROR_TOO_MANY_OPEN_FILES;
373 }
374
375 /* It was successful */
376 *Handle = DosHandle;
377 return ERROR_SUCCESS;
378 }
379
380 WORD DosCreateFile(LPWORD Handle,
381 LPCSTR FilePath,
382 DWORD CreationDisposition,
383 WORD Attributes)
384 {
385 HANDLE FileHandle;
386 WORD DosHandle;
387 BYTE DescriptorId;
388 PDOS_FILE_DESCRIPTOR Descriptor;
389
390 DPRINT("DosCreateFile: FilePath \"%s\", CreationDisposition 0x%04X, Attributes 0x%04X\n",
391 FilePath, CreationDisposition, Attributes);
392
393 /* Create the file */
394 FileHandle = CreateFileA(FilePath,
395 GENERIC_READ | GENERIC_WRITE,
396 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
397 NULL,
398 CreationDisposition,
399 Attributes,
400 NULL);
401 if (FileHandle == INVALID_HANDLE_VALUE)
402 {
403 /* Return the error code */
404 return (WORD)GetLastError();
405 }
406
407 DescriptorId = DosFindFreeDescriptor();
408 if (DescriptorId == 0xFF)
409 {
410 /* Close the file and return the error code */
411 CloseHandle(FileHandle);
412 return ERROR_TOO_MANY_OPEN_FILES;
413 }
414
415 /* Set up the new descriptor */
416 Descriptor = DosGetFileDescriptor(DescriptorId);
417 RtlZeroMemory(Descriptor, sizeof(*Descriptor));
418
419 Descriptor->Attributes = LOBYTE(GetFileAttributesA(FilePath));
420 Descriptor->Size = GetFileSize(FileHandle, NULL);
421 Descriptor->OwnerPsp = CurrentPsp;
422 Descriptor->Win32Handle = FileHandle;
423
424 /* Open the DOS handle */
425 DosHandle = DosOpenHandle(DescriptorId);
426 if (DosHandle == INVALID_DOS_HANDLE)
427 {
428 /* Close the file and return the error code */
429 CloseHandle(FileHandle);
430 return ERROR_TOO_MANY_OPEN_FILES;
431 }
432
433 /* It was successful */
434 *Handle = DosHandle;
435 return ERROR_SUCCESS;
436 }
437
438 WORD DosOpenFile(LPWORD Handle,
439 LPCSTR FilePath,
440 BYTE AccessShareModes)
441 {
442 HANDLE FileHandle = NULL;
443 PDOS_DEVICE_NODE Node;
444 WORD DosHandle;
445 BYTE DescriptorId;
446 PDOS_FILE_DESCRIPTOR Descriptor;
447
448 DPRINT("DosOpenFile: FilePath \"%s\", AccessShareModes 0x%04X\n",
449 FilePath, AccessShareModes);
450
451 //
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).
454 //
455
456 Node = DosGetDevice(FilePath);
457 if (Node != NULL)
458 {
459 if (Node->OpenRoutine) Node->OpenRoutine(Node);
460 }
461 else
462 {
463 ACCESS_MASK AccessMode = 0;
464 DWORD ShareMode = 0;
465 BOOL InheritableFile = FALSE;
466 SECURITY_ATTRIBUTES SecurityAttributes;
467
468 /* Parse the access mode */
469 switch (AccessShareModes & 0x03)
470 {
471 /* Read-only */
472 case 0:
473 AccessMode = GENERIC_READ;
474 break;
475
476 /* Write only */
477 case 1:
478 AccessMode = GENERIC_WRITE;
479 break;
480
481 /* Read and write */
482 case 2:
483 AccessMode = GENERIC_READ | GENERIC_WRITE;
484 break;
485
486 /* Invalid */
487 default:
488 return ERROR_INVALID_PARAMETER;
489 }
490
491 /* Parse the share mode */
492 switch ((AccessShareModes >> 4) & 0x07)
493 {
494 /* Compatibility mode */
495 case 0:
496 ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
497 break;
498
499 /* No sharing "DenyAll" */
500 case 1:
501 ShareMode = 0;
502 break;
503
504 /* No write share "DenyWrite" */
505 case 2:
506 ShareMode = FILE_SHARE_READ;
507 break;
508
509 /* No read share "DenyRead" */
510 case 3:
511 ShareMode = FILE_SHARE_WRITE;
512 break;
513
514 /* Full share "DenyNone" */
515 case 4:
516 ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
517 break;
518
519 /* Invalid */
520 default:
521 return ERROR_INVALID_PARAMETER;
522 }
523
524 /* Check for inheritance */
525 InheritableFile = ((AccessShareModes & 0x80) == 0);
526
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;
531
532 /* Open the file */
533 FileHandle = CreateFileA(FilePath,
534 AccessMode,
535 ShareMode,
536 &SecurityAttributes,
537 OPEN_EXISTING,
538 FILE_ATTRIBUTE_NORMAL,
539 NULL);
540 if (FileHandle == INVALID_HANDLE_VALUE)
541 {
542 /* Return the error code */
543 return (WORD)GetLastError();
544 }
545 }
546
547 DescriptorId = DosFindFreeDescriptor();
548 if (DescriptorId == 0xFF)
549 {
550 /* Close the file and return the error code */
551 CloseHandle(FileHandle);
552 return ERROR_TOO_MANY_OPEN_FILES;
553 }
554
555 /* Set up the new descriptor */
556 Descriptor = DosGetFileDescriptor(DescriptorId);
557 RtlZeroMemory(Descriptor, sizeof(*Descriptor));
558
559 if (Node != NULL)
560 {
561 Descriptor->DevicePointer = Node->Driver;
562 Descriptor->DeviceInfo = Node->DeviceAttributes | (1 << 7);
563 }
564 else
565 {
566 Descriptor->OpenMode = AccessShareModes;
567 Descriptor->Attributes = LOBYTE(GetFileAttributesA(FilePath));
568 Descriptor->Size = GetFileSize(FileHandle, NULL);
569 Descriptor->OwnerPsp = CurrentPsp;
570 Descriptor->Win32Handle = FileHandle;
571 }
572
573 /* Open the DOS handle */
574 DosHandle = DosOpenHandle(DescriptorId);
575 if (DosHandle == INVALID_DOS_HANDLE)
576 {
577 /* Close the file and return the error code */
578 CloseHandle(FileHandle);
579 return ERROR_TOO_MANY_OPEN_FILES;
580 }
581
582 /* It was successful */
583 *Handle = DosHandle;
584 return ERROR_SUCCESS;
585 }
586
587 WORD DosReadFile(WORD FileHandle,
588 DWORD Buffer,
589 WORD Count,
590 LPWORD BytesRead)
591 {
592 WORD Result = ERROR_SUCCESS;
593 PDOS_FILE_DESCRIPTOR Descriptor = DosGetHandleFileDescriptor(FileHandle);
594
595 DPRINT("DosReadFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle, Count);
596
597 if (Descriptor == NULL)
598 {
599 /* Invalid handle */
600 return ERROR_INVALID_HANDLE;
601 }
602
603 if (Descriptor->DeviceInfo & (1 << 7))
604 {
605 PDOS_DEVICE_NODE Node = DosGetDriverNode(Descriptor->DevicePointer);
606 if (!Node->ReadRoutine) return ERROR_INVALID_FUNCTION;
607
608 /* Read the device */
609 Node->ReadRoutine(Node, Buffer, &Count);
610 *BytesRead = Count;
611 }
612 else
613 {
614 DWORD BytesRead32 = 0;
615 LPVOID LocalBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Count);
616 ASSERT(LocalBuffer != NULL);
617
618 /* Read the file */
619 if (ReadFile(Descriptor->Win32Handle, LocalBuffer, Count, &BytesRead32, NULL))
620 {
621 /* Write to the memory */
622 MemWrite(TO_LINEAR(HIWORD(Buffer), LOWORD(Buffer)), LocalBuffer, LOWORD(BytesRead32));
623
624 /* Update the position */
625 Descriptor->Position += BytesRead32;
626 }
627 else
628 {
629 /* Store the error code */
630 Result = (WORD)GetLastError();
631 }
632
633 /* The number of bytes read is always 16-bit */
634 *BytesRead = LOWORD(BytesRead32);
635 RtlFreeHeap(RtlGetProcessHeap(), 0, LocalBuffer);
636 }
637
638 /* Return the error code */
639 return Result;
640 }
641
642 WORD DosWriteFile(WORD FileHandle,
643 DWORD Buffer,
644 WORD Count,
645 LPWORD BytesWritten)
646 {
647 WORD Result = ERROR_SUCCESS;
648 PDOS_FILE_DESCRIPTOR Descriptor = DosGetHandleFileDescriptor(FileHandle);
649
650 DPRINT("DosWriteFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle, Count);
651
652 if (Descriptor == NULL)
653 {
654 /* Invalid handle */
655 return ERROR_INVALID_HANDLE;
656 }
657
658 if (Descriptor->DeviceInfo & (1 << 7))
659 {
660 PDOS_DEVICE_NODE Node = DosGetDriverNode(Descriptor->DevicePointer);
661 if (!Node->WriteRoutine) return ERROR_INVALID_FUNCTION;
662
663 /* Read the device */
664 Node->WriteRoutine(Node, Buffer, &Count);
665 *BytesWritten = Count;
666 }
667 else
668 {
669 DWORD BytesWritten32 = 0;
670 LPVOID LocalBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Count);
671 ASSERT(LocalBuffer != NULL);
672
673 /* Read from the memory */
674 MemRead(TO_LINEAR(HIWORD(Buffer), LOWORD(Buffer)), LocalBuffer, Count);
675
676 /* Write the file */
677 if (WriteFile(Descriptor->Win32Handle, LocalBuffer, Count, &BytesWritten32, NULL))
678 {
679 /* Update the position and size */
680 Descriptor->Position += BytesWritten32;
681 if (Descriptor->Position > Descriptor->Size) Descriptor->Size = Descriptor->Position;
682 }
683 else
684 {
685 /* Store the error code */
686 Result = (WORD)GetLastError();
687 }
688
689 /* The number of bytes written is always 16-bit */
690 *BytesWritten = LOWORD(BytesWritten32);
691 RtlFreeHeap(RtlGetProcessHeap(), 0, LocalBuffer);
692 }
693
694 /* Return the error code */
695 return Result;
696 }
697
698 WORD DosSeekFile(WORD FileHandle,
699 LONG Offset,
700 BYTE Origin,
701 LPDWORD NewOffset)
702 {
703 WORD Result = ERROR_SUCCESS;
704 DWORD FilePointer;
705 PDOS_FILE_DESCRIPTOR Descriptor = DosGetHandleFileDescriptor(FileHandle);
706
707 DPRINT("DosSeekFile: FileHandle 0x%04X, Offset 0x%08X, Origin 0x%02X\n",
708 FileHandle,
709 Offset,
710 Origin);
711
712 if (Descriptor == NULL)
713 {
714 /* Invalid handle */
715 return ERROR_INVALID_HANDLE;
716 }
717
718 if (Descriptor->DeviceInfo & (1 << 7))
719 {
720 /* For character devices, always return success */
721 return ERROR_SUCCESS;
722 }
723
724 /* Check if the origin is valid */
725 if (Origin != FILE_BEGIN && Origin != FILE_CURRENT && Origin != FILE_END)
726 {
727 return ERROR_INVALID_FUNCTION;
728 }
729
730 FilePointer = SetFilePointer(Descriptor->Win32Handle, Offset, NULL, Origin);
731
732 /* Check if there's a possibility the operation failed */
733 if (FilePointer == INVALID_SET_FILE_POINTER)
734 {
735 /* Get the real error code */
736 Result = (WORD)GetLastError();
737 }
738
739 if (Result != ERROR_SUCCESS)
740 {
741 /* The operation did fail */
742 return Result;
743 }
744
745 /* Update the descriptor */
746 Descriptor->Position = FilePointer;
747
748 /* Return the file pointer, if requested */
749 if (NewOffset) *NewOffset = FilePointer;
750
751 /* Return success */
752 return ERROR_SUCCESS;
753 }
754
755 BOOL DosFlushFileBuffers(WORD FileHandle)
756 {
757 PDOS_FILE_DESCRIPTOR Descriptor = DosGetHandleFileDescriptor(FileHandle);
758
759 if (Descriptor == NULL)
760 {
761 /* Invalid handle */
762 DosLastError = ERROR_INVALID_HANDLE;
763 return FALSE;
764 }
765
766 if (Descriptor->DeviceInfo & (1 << 7))
767 {
768 PDOS_DEVICE_NODE Node = DosGetDriverNode(Descriptor->DevicePointer);
769
770 if (Node->FlushInputRoutine) Node->FlushInputRoutine(Node);
771 if (Node->FlushOutputRoutine) Node->FlushOutputRoutine(Node);
772
773 return TRUE;
774 }
775 else
776 {
777 return FlushFileBuffers(Descriptor->Win32Handle);
778 }
779 }
780
781 BOOLEAN DosLockFile(WORD DosHandle, DWORD Offset, DWORD Size)
782 {
783 PDOS_FILE_DESCRIPTOR Descriptor = DosGetHandleFileDescriptor(DosHandle);
784
785 if (Descriptor == NULL)
786 {
787 /* Invalid handle */
788 DosLastError = ERROR_INVALID_HANDLE;
789 return FALSE;
790 }
791
792 /* Always succeed for character devices */
793 if (Descriptor->DeviceInfo & (1 << 7)) return TRUE;
794
795 if (!LockFile(Descriptor->Win32Handle, Offset, 0, Size, 0))
796 {
797 DosLastError = GetLastError();
798 return FALSE;
799 }
800
801 return TRUE;
802 }
803
804 BOOLEAN DosUnlockFile(WORD DosHandle, DWORD Offset, DWORD Size)
805 {
806 PDOS_FILE_DESCRIPTOR Descriptor = DosGetHandleFileDescriptor(DosHandle);
807
808 if (Descriptor == NULL)
809 {
810 /* Invalid handle */
811 DosLastError = ERROR_INVALID_HANDLE;
812 return FALSE;
813 }
814
815 /* Always succeed for character devices */
816 if (Descriptor->DeviceInfo & (1 << 7)) return TRUE;
817
818 if (!UnlockFile(Descriptor->Win32Handle, Offset, 0, Size, 0))
819 {
820 DosLastError = GetLastError();
821 return FALSE;
822 }
823
824 return TRUE;
825 }
826
827 BOOLEAN DosDeviceIoControl(WORD FileHandle, BYTE ControlCode, DWORD Buffer, PWORD Length)
828 {
829 PDOS_FILE_DESCRIPTOR Descriptor = DosGetHandleFileDescriptor(FileHandle);
830 PDOS_DEVICE_NODE Node = NULL;
831
832 if (!Descriptor)
833 {
834 DosLastError = ERROR_INVALID_HANDLE;
835 return FALSE;
836 }
837
838 if (Descriptor->DeviceInfo & (1 << 7))
839 {
840 Node = DosGetDriverNode(Descriptor->DevicePointer);
841 }
842
843 switch (ControlCode)
844 {
845 /* Get Device Information */
846 case 0x00:
847 {
848 /*
849 * See Ralf Brown: http://www.ctyme.com/intr/rb-2820.htm
850 * for a list of possible flags.
851 */
852 setDX(Descriptor->DeviceInfo);
853 return TRUE;
854 }
855
856 /* Set Device Information */
857 case 0x01:
858 {
859 // TODO: NOT IMPLEMENTED
860 UNIMPLEMENTED;
861
862 return FALSE;
863 }
864
865 /* Read From Device I/O Control Channel */
866 case 0x02:
867 {
868 if (Node == NULL || !(Node->DeviceAttributes & DOS_DEVATTR_IOCTL))
869 {
870 DosLastError = ERROR_INVALID_FUNCTION;
871 return FALSE;
872 }
873
874 /* Do nothing if there is no IOCTL routine */
875 if (!Node->IoctlReadRoutine)
876 {
877 *Length = 0;
878 return TRUE;
879 }
880
881 Node->IoctlReadRoutine(Node, Buffer, Length);
882 return TRUE;
883 }
884
885 /* Write To Device I/O Control Channel */
886 case 0x03:
887 {
888 if (Node == NULL || !(Node->DeviceAttributes & DOS_DEVATTR_IOCTL))
889 {
890 DosLastError = ERROR_INVALID_FUNCTION;
891 return FALSE;
892 }
893
894 /* Do nothing if there is no IOCTL routine */
895 if (!Node->IoctlWriteRoutine)
896 {
897 *Length = 0;
898 return TRUE;
899 }
900
901 Node->IoctlWriteRoutine(Node, Buffer, Length);
902 return TRUE;
903 }
904
905 /* Unsupported control code */
906 default:
907 {
908 DPRINT1("Unsupported IOCTL: 0x%02X\n", ControlCode);
909
910 DosLastError = ERROR_INVALID_PARAMETER;
911 return FALSE;
912 }
913 }
914 }
915
916
917 /* EOF */