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