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