fd11e8558334b59e87f15f99b999e06ac9472f36
[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
21 #include "bios/bios.h"
22
23 /* PUBLIC FUNCTIONS ***********************************************************/
24
25 WORD DosCreateFileEx(LPWORD Handle,
26 LPWORD CreationStatus,
27 LPCSTR FilePath,
28 BYTE AccessShareModes,
29 WORD CreateActionFlags,
30 WORD Attributes)
31 {
32 WORD LastError;
33 HANDLE FileHandle;
34 WORD DosHandle;
35 ACCESS_MASK AccessMode = 0;
36 DWORD ShareMode = 0;
37 DWORD CreationDisposition = 0;
38 BOOL InheritableFile = FALSE;
39 SECURITY_ATTRIBUTES SecurityAttributes;
40
41 DPRINT1("DosCreateFileEx: FilePath \"%s\", AccessShareModes 0x%04X, CreateActionFlags 0x%04X, Attributes 0x%04X\n",
42 FilePath, AccessShareModes, CreateActionFlags, Attributes);
43
44 //
45 // The article about OpenFile API: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365430(v=vs.85).aspx
46 // explains what those AccessShareModes are (see the uStyle flag).
47 //
48
49 /* Parse the access mode */
50 switch (AccessShareModes & 0x03)
51 {
52 /* Read-only */
53 case 0:
54 AccessMode = GENERIC_READ;
55 break;
56
57 /* Write only */
58 case 1:
59 AccessMode = GENERIC_WRITE;
60 break;
61
62 /* Read and write */
63 case 2:
64 AccessMode = GENERIC_READ | GENERIC_WRITE;
65 break;
66
67 /* Invalid */
68 default:
69 return ERROR_INVALID_PARAMETER;
70 }
71
72 /* Parse the share mode */
73 switch ((AccessShareModes >> 4) & 0x07)
74 {
75 /* Compatibility mode */
76 case 0:
77 ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
78 break;
79
80 /* No sharing "DenyAll" */
81 case 1:
82 ShareMode = 0;
83 break;
84
85 /* No write share "DenyWrite" */
86 case 2:
87 ShareMode = FILE_SHARE_READ;
88 break;
89
90 /* No read share "DenyRead" */
91 case 3:
92 ShareMode = FILE_SHARE_WRITE;
93 break;
94
95 /* Full share "DenyNone" */
96 case 4:
97 ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
98 break;
99
100 /* Invalid */
101 default:
102 return ERROR_INVALID_PARAMETER;
103 }
104
105 /*
106 * Parse the creation action flags:
107 *
108 * Bitfields for action:
109 * Bit(s) Description
110 *
111 * 7-4 Action if file does not exist.
112 * 0000 Fail
113 * 0001 Create
114 *
115 * 3-0 Action if file exists.
116 * 0000 Fail
117 * 0001 Open
118 * 0010 Replace/open
119 */
120 switch (CreateActionFlags)
121 {
122 /* If the file exists, fail, otherwise, fail also */
123 case 0x00:
124 // A special case is used after the call to CreateFileA if it succeeds,
125 // in order to close the opened handle and return an adequate error.
126 CreationDisposition = OPEN_EXISTING;
127 break;
128
129 /* If the file exists, open it, otherwise, fail */
130 case 0x01:
131 CreationDisposition = OPEN_EXISTING;
132 break;
133
134 /* If the file exists, replace it, otherwise, fail */
135 case 0x02:
136 CreationDisposition = TRUNCATE_EXISTING;
137 break;
138
139 /* If the file exists, fail, otherwise, create it */
140 case 0x10:
141 CreationDisposition = CREATE_NEW;
142 break;
143
144 /* If the file exists, open it, otherwise, create it */
145 case 0x11:
146 CreationDisposition = OPEN_ALWAYS;
147 break;
148
149 /* If the file exists, replace it, otherwise, create it */
150 case 0x12:
151 CreationDisposition = CREATE_ALWAYS;
152 break;
153
154 /* Invalid */
155 default:
156 return ERROR_INVALID_PARAMETER;
157 }
158
159 /* Check for inheritance */
160 InheritableFile = ((AccessShareModes & 0x80) == 0);
161
162 /* Assign default security attributes to the file, and set the inheritance flag */
163 SecurityAttributes.nLength = sizeof(SecurityAttributes);
164 SecurityAttributes.lpSecurityDescriptor = NULL;
165 SecurityAttributes.bInheritHandle = InheritableFile;
166
167 /* Open the file */
168 FileHandle = CreateFileA(FilePath,
169 AccessMode,
170 ShareMode,
171 &SecurityAttributes,
172 CreationDisposition,
173 Attributes,
174 NULL);
175
176 LastError = (WORD)GetLastError();
177
178 if (FileHandle == INVALID_HANDLE_VALUE)
179 {
180 /* Return the error code */
181 return LastError;
182 }
183
184 /*
185 * Special case: CreateActionFlags == 0, we must fail because
186 * the file exists (if it didn't exist we already failed).
187 */
188 if (CreateActionFlags == 0)
189 {
190 /* Close the file and return the error code */
191 CloseHandle(FileHandle);
192 return ERROR_FILE_EXISTS;
193 }
194
195 /* Set the creation status */
196 switch (CreateActionFlags)
197 {
198 case 0x01:
199 *CreationStatus = 0x01; // The file was opened
200 break;
201
202 case 0x02:
203 *CreationStatus = 0x03; // The file was replaced
204 break;
205
206 case 0x10:
207 *CreationStatus = 0x02; // The file was created
208 break;
209
210 case 0x11:
211 {
212 if (LastError == ERROR_ALREADY_EXISTS)
213 *CreationStatus = 0x01; // The file was opened
214 else
215 *CreationStatus = 0x02; // The file was created
216
217 break;
218 }
219
220 case 0x12:
221 {
222 if (LastError == ERROR_ALREADY_EXISTS)
223 *CreationStatus = 0x03; // The file was replaced
224 else
225 *CreationStatus = 0x02; // The file was created
226
227 break;
228 }
229 }
230
231 /* Open the DOS handle */
232 DosHandle = DosOpenHandle(FileHandle);
233 if (DosHandle == INVALID_DOS_HANDLE)
234 {
235 /* Close the file and return the error code */
236 CloseHandle(FileHandle);
237 return ERROR_TOO_MANY_OPEN_FILES;
238 }
239
240 /* It was successful */
241 *Handle = DosHandle;
242 return ERROR_SUCCESS;
243 }
244
245 WORD DosCreateFile(LPWORD Handle,
246 LPCSTR FilePath,
247 DWORD CreationDisposition,
248 WORD Attributes)
249 {
250 HANDLE FileHandle;
251 WORD DosHandle;
252
253 DPRINT("DosCreateFile: FilePath \"%s\", CreationDisposition 0x%04X, Attributes 0x%04X\n",
254 FilePath, CreationDisposition, Attributes);
255
256 /* Create the file */
257 FileHandle = CreateFileA(FilePath,
258 GENERIC_READ | GENERIC_WRITE,
259 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
260 NULL,
261 CreationDisposition,
262 Attributes,
263 NULL);
264 if (FileHandle == INVALID_HANDLE_VALUE)
265 {
266 /* Return the error code */
267 return (WORD)GetLastError();
268 }
269
270 /* Open the DOS handle */
271 DosHandle = DosOpenHandle(FileHandle);
272 if (DosHandle == INVALID_DOS_HANDLE)
273 {
274 /* Close the file and return the error code */
275 CloseHandle(FileHandle);
276 return ERROR_TOO_MANY_OPEN_FILES;
277 }
278
279 /* It was successful */
280 *Handle = DosHandle;
281 return ERROR_SUCCESS;
282 }
283
284 WORD DosOpenFile(LPWORD Handle,
285 LPCSTR FilePath,
286 BYTE AccessShareModes)
287 {
288 HANDLE FileHandle;
289 ACCESS_MASK AccessMode = 0;
290 DWORD ShareMode = 0;
291 BOOL InheritableFile = FALSE;
292 SECURITY_ATTRIBUTES SecurityAttributes;
293 WORD DosHandle;
294
295 DPRINT("DosOpenFile: FilePath \"%s\", AccessShareModes 0x%04X\n",
296 FilePath, AccessShareModes);
297
298 //
299 // The article about OpenFile API: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365430(v=vs.85).aspx
300 // explains what those AccessShareModes are (see the uStyle flag).
301 //
302
303 /* Parse the access mode */
304 switch (AccessShareModes & 0x03)
305 {
306 /* Read-only */
307 case 0:
308 AccessMode = GENERIC_READ;
309 break;
310
311 /* Write only */
312 case 1:
313 AccessMode = GENERIC_WRITE;
314 break;
315
316 /* Read and write */
317 case 2:
318 AccessMode = GENERIC_READ | GENERIC_WRITE;
319 break;
320
321 /* Invalid */
322 default:
323 return ERROR_INVALID_PARAMETER;
324 }
325
326 /* Parse the share mode */
327 switch ((AccessShareModes >> 4) & 0x07)
328 {
329 /* Compatibility mode */
330 case 0:
331 ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
332 break;
333
334 /* No sharing "DenyAll" */
335 case 1:
336 ShareMode = 0;
337 break;
338
339 /* No write share "DenyWrite" */
340 case 2:
341 ShareMode = FILE_SHARE_READ;
342 break;
343
344 /* No read share "DenyRead" */
345 case 3:
346 ShareMode = FILE_SHARE_WRITE;
347 break;
348
349 /* Full share "DenyNone" */
350 case 4:
351 ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
352 break;
353
354 /* Invalid */
355 default:
356 return ERROR_INVALID_PARAMETER;
357 }
358
359 /* Check for inheritance */
360 InheritableFile = ((AccessShareModes & 0x80) == 0);
361
362 /* Assign default security attributes to the file, and set the inheritance flag */
363 SecurityAttributes.nLength = sizeof(SecurityAttributes);
364 SecurityAttributes.lpSecurityDescriptor = NULL;
365 SecurityAttributes.bInheritHandle = InheritableFile;
366
367 /* Open the file */
368 FileHandle = CreateFileA(FilePath,
369 AccessMode,
370 ShareMode,
371 &SecurityAttributes,
372 OPEN_EXISTING,
373 FILE_ATTRIBUTE_NORMAL,
374 NULL);
375 if (FileHandle == INVALID_HANDLE_VALUE)
376 {
377 /* Return the error code */
378 return (WORD)GetLastError();
379 }
380
381 /* Open the DOS handle */
382 DosHandle = DosOpenHandle(FileHandle);
383 if (DosHandle == INVALID_DOS_HANDLE)
384 {
385 /* Close the file and return the error code */
386 CloseHandle(FileHandle);
387 return ERROR_TOO_MANY_OPEN_FILES;
388 }
389
390 /* It was successful */
391 *Handle = DosHandle;
392 return ERROR_SUCCESS;
393 }
394
395 WORD DosReadFile(WORD FileHandle,
396 DWORD Buffer,
397 WORD Count,
398 LPWORD BytesRead)
399 {
400 WORD Result = ERROR_SUCCESS;
401 PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(FileHandle);
402
403 DPRINT("DosReadFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle, Count);
404
405 if (SftEntry == NULL)
406 {
407 /* Invalid handle */
408 return ERROR_INVALID_HANDLE;
409 }
410
411 if (SftEntry->Type == DOS_SFT_ENTRY_WIN32)
412 {
413 DWORD BytesRead32 = 0;
414 LPVOID LocalBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Count);
415 ASSERT(LocalBuffer != NULL);
416
417 /* Read the file */
418 if (ReadFile(SftEntry->Handle, LocalBuffer, Count, &BytesRead32, NULL))
419 {
420 /* Write to the memory */
421 MemWrite(TO_LINEAR(HIWORD(Buffer), LOWORD(Buffer)), LocalBuffer, LOWORD(BytesRead32));
422 }
423 else
424 {
425 /* Store the error code */
426 Result = (WORD)GetLastError();
427 }
428
429 /* The number of bytes read is always 16-bit */
430 *BytesRead = LOWORD(BytesRead32);
431 RtlFreeHeap(RtlGetProcessHeap(), 0, LocalBuffer);
432 }
433 else if (SftEntry->Type == DOS_SFT_ENTRY_DEVICE)
434 {
435 if (!SftEntry->DeviceNode->ReadRoutine) return ERROR_INVALID_FUNCTION;
436
437 /* Read the device */
438 SftEntry->DeviceNode->ReadRoutine(SftEntry->DeviceNode, Buffer, &Count);
439 *BytesRead = Count;
440 }
441 else
442 {
443 /* Invalid handle */
444 return ERROR_INVALID_HANDLE;
445 }
446
447 /* Return the error code */
448 return Result;
449 }
450
451 WORD DosWriteFile(WORD FileHandle,
452 DWORD Buffer,
453 WORD Count,
454 LPWORD BytesWritten)
455 {
456 WORD Result = ERROR_SUCCESS;
457 PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(FileHandle);
458
459 DPRINT("DosWriteFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle, Count);
460
461 if (SftEntry == NULL)
462 {
463 /* Invalid handle */
464 return ERROR_INVALID_HANDLE;
465 }
466
467 if (SftEntry->Type == DOS_SFT_ENTRY_WIN32)
468 {
469 DWORD BytesWritten32 = 0;
470 LPVOID LocalBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Count);
471 ASSERT(LocalBuffer != NULL);
472
473 /* Read from the memory */
474 MemRead(TO_LINEAR(HIWORD(Buffer), LOWORD(Buffer)), LocalBuffer, Count);
475
476 /* Write the file */
477 if (!WriteFile(SftEntry->Handle, LocalBuffer, Count, &BytesWritten32, NULL))
478 {
479 /* Store the error code */
480 Result = (WORD)GetLastError();
481 }
482
483 /* The number of bytes written is always 16-bit */
484 *BytesWritten = LOWORD(BytesWritten32);
485 RtlFreeHeap(RtlGetProcessHeap(), 0, LocalBuffer);
486 }
487 else if (SftEntry->Type == DOS_SFT_ENTRY_DEVICE)
488 {
489 if (!SftEntry->DeviceNode->WriteRoutine) return ERROR_INVALID_FUNCTION;
490
491 /* Read the device */
492 SftEntry->DeviceNode->WriteRoutine(SftEntry->DeviceNode, Buffer, &Count);
493 *BytesWritten = Count;
494 }
495 else
496 {
497 /* Invalid handle */
498 return ERROR_INVALID_HANDLE;
499 }
500
501 /* Return the error code */
502 return Result;
503 }
504
505 WORD DosSeekFile(WORD FileHandle,
506 LONG Offset,
507 BYTE Origin,
508 LPDWORD NewOffset)
509 {
510 WORD Result = ERROR_SUCCESS;
511 DWORD FilePointer;
512 PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(FileHandle);
513
514 DPRINT("DosSeekFile: FileHandle 0x%04X, Offset 0x%08X, Origin 0x%02X\n",
515 FileHandle,
516 Offset,
517 Origin);
518
519 if (SftEntry == NULL)
520 {
521 /* Invalid handle */
522 return ERROR_INVALID_HANDLE;
523 }
524
525 if (SftEntry->Type == DOS_SFT_ENTRY_NONE)
526 {
527 /* Invalid handle */
528 return ERROR_INVALID_HANDLE;
529 }
530 else if (SftEntry->Type == DOS_SFT_ENTRY_DEVICE)
531 {
532 /* For character devices, always return success */
533 return ERROR_SUCCESS;
534 }
535
536 /* Check if the origin is valid */
537 if (Origin != FILE_BEGIN && Origin != FILE_CURRENT && Origin != FILE_END)
538 {
539 return ERROR_INVALID_FUNCTION;
540 }
541
542 FilePointer = SetFilePointer(SftEntry->Handle, Offset, NULL, Origin);
543
544 /* Check if there's a possibility the operation failed */
545 if (FilePointer == INVALID_SET_FILE_POINTER)
546 {
547 /* Get the real error code */
548 Result = (WORD)GetLastError();
549 }
550
551 if (Result != ERROR_SUCCESS)
552 {
553 /* The operation did fail */
554 return Result;
555 }
556
557 /* Return the file pointer, if requested */
558 if (NewOffset) *NewOffset = FilePointer;
559
560 /* Return success */
561 return ERROR_SUCCESS;
562 }
563
564 BOOL DosFlushFileBuffers(WORD FileHandle)
565 {
566 PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(FileHandle);
567
568 if (SftEntry == NULL)
569 {
570 /* Invalid handle */
571 return ERROR_INVALID_HANDLE;
572 }
573
574 switch (SftEntry->Type)
575 {
576 case DOS_SFT_ENTRY_WIN32:
577 {
578 return FlushFileBuffers(SftEntry->Handle);
579 }
580
581 case DOS_SFT_ENTRY_DEVICE:
582 {
583 if (SftEntry->DeviceNode->FlushInputRoutine)
584 SftEntry->DeviceNode->FlushInputRoutine(SftEntry->DeviceNode);
585
586 if (SftEntry->DeviceNode->FlushOutputRoutine)
587 SftEntry->DeviceNode->FlushOutputRoutine(SftEntry->DeviceNode);
588
589 return TRUE;
590 }
591
592 default:
593 {
594 /* Invalid handle */
595 return FALSE;
596 }
597 }
598 }
599
600 /* EOF */