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