Sync with trunk r63343.
[reactos.git] / subsystems / 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 "emulator.h"
15 // #include "callback.h"
16
17 #include "dos.h"
18 #include "dos/dem.h"
19
20 #include "bios/bios.h"
21
22 /* PRIVATE VARIABLES **********************************************************/
23
24 /* PUBLIC FUNCTIONS ***********************************************************/
25
26 WORD DosCreateFile(LPWORD Handle, LPCSTR FilePath, WORD CreationFlags, WORD Attributes)
27 {
28 HANDLE FileHandle;
29 WORD DosHandle;
30
31 DPRINT("DosCreateFile: FilePath \"%s\", CreationFlags 0x%04X, Attributes 0x%04X\n",
32 FilePath,
33 CreationFlags,
34 Attributes);
35
36 /* Create the file */
37 FileHandle = CreateFileA(FilePath,
38 GENERIC_READ | GENERIC_WRITE,
39 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
40 NULL,
41 CreationFlags,
42 Attributes,
43 NULL);
44
45 if (FileHandle == INVALID_HANDLE_VALUE)
46 {
47 /* Return the error code */
48 return (WORD)GetLastError();
49 }
50
51 /* Open the DOS handle */
52 DosHandle = DosOpenHandle(FileHandle);
53
54 if (DosHandle == INVALID_DOS_HANDLE)
55 {
56 /* Close the handle */
57 CloseHandle(FileHandle);
58
59 /* Return the error code */
60 return ERROR_TOO_MANY_OPEN_FILES;
61 }
62
63 /* It was successful */
64 *Handle = DosHandle;
65 return ERROR_SUCCESS;
66 }
67
68 WORD DosOpenFile(LPWORD Handle, LPCSTR FilePath, BYTE AccessShareModes)
69 {
70 HANDLE FileHandle;
71 ACCESS_MASK AccessMode = 0;
72 DWORD ShareMode = 0;
73 BOOL InheritableFile = FALSE;
74 SECURITY_ATTRIBUTES SecurityAttributes;
75 WORD DosHandle;
76
77 DPRINT("DosOpenFile: FilePath \"%s\", AccessShareModes 0x%04X\n",
78 FilePath,
79 AccessShareModes);
80
81 /* Parse the access mode */
82 switch (AccessShareModes & 0x03)
83 {
84 case 0:
85 {
86 /* Read-only */
87 AccessMode = GENERIC_READ;
88 break;
89 }
90
91 case 1:
92 {
93 /* Write only */
94 AccessMode = GENERIC_WRITE;
95 break;
96 }
97
98 case 2:
99 {
100 /* Read and write */
101 AccessMode = GENERIC_READ | GENERIC_WRITE;
102 break;
103 }
104
105 default:
106 {
107 /* Invalid */
108 return ERROR_INVALID_PARAMETER;
109 }
110 }
111
112 /* Parse the share mode */
113 switch ((AccessShareModes >> 4) & 0x07)
114 {
115 case 0:
116 {
117 /* Compatibility mode */
118 ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
119 break;
120 }
121
122 case 1:
123 {
124 /* No sharing "DenyAll" */
125 ShareMode = 0;
126 break;
127 }
128
129 case 2:
130 {
131 /* No write share "DenyWrite" */
132 ShareMode = FILE_SHARE_READ;
133 break;
134 }
135
136 case 3:
137 {
138 /* No read share "DenyRead" */
139 ShareMode = FILE_SHARE_WRITE;
140 break;
141 }
142
143 case 4:
144 {
145 /* Full share "DenyNone" */
146 ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
147 break;
148 }
149
150 default:
151 {
152 /* Invalid */
153 return ERROR_INVALID_PARAMETER;
154 }
155 }
156
157 /* Check for inheritance */
158 InheritableFile = ((AccessShareModes & 0x80) == 0);
159
160 /* Assign default security attributes to the file, and set the inheritance flag */
161 SecurityAttributes.nLength = sizeof(SecurityAttributes);
162 SecurityAttributes.lpSecurityDescriptor = NULL;
163 SecurityAttributes.bInheritHandle = InheritableFile;
164
165 /* Open the file */
166 FileHandle = CreateFileA(FilePath,
167 AccessMode,
168 ShareMode,
169 &SecurityAttributes,
170 OPEN_EXISTING,
171 FILE_ATTRIBUTE_NORMAL,
172 NULL);
173
174 if (FileHandle == INVALID_HANDLE_VALUE)
175 {
176 /* Return the error code */
177 return (WORD)GetLastError();
178 }
179
180 /* Open the DOS handle */
181 DosHandle = DosOpenHandle(FileHandle);
182
183 if (DosHandle == INVALID_DOS_HANDLE)
184 {
185 /* Close the handle */
186 CloseHandle(FileHandle);
187
188 /* Return the error code */
189 return ERROR_TOO_MANY_OPEN_FILES;
190 }
191
192 /* It was successful */
193 *Handle = DosHandle;
194 return ERROR_SUCCESS;
195 }
196
197 WORD DosReadFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesRead)
198 {
199 WORD Result = ERROR_SUCCESS;
200 DWORD BytesRead32 = 0;
201 HANDLE Handle = DosGetRealHandle(FileHandle);
202
203 DPRINT("DosReadFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle, Count);
204
205 /* Make sure the handle is valid */
206 if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
207
208 if (IsConsoleHandle(Handle))
209 {
210 CHAR Character;
211
212 /*
213 * Use BIOS Get Keystroke function
214 */
215
216 /* Save AX */
217 USHORT AX = getAX();
218
219 for (BytesRead32 = 0; BytesRead32 < Count; BytesRead32++)
220 {
221 /* Call the BIOS INT 16h, AH=00h "Get Keystroke" */
222 setAH(0x00);
223 Int32Call(&DosContext, BIOS_KBD_INTERRUPT);
224
225 /* Retrieve the character in AL (scan code is in AH) */
226 Character = getAL();
227
228 if (DoEcho) DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
229
230 ((PCHAR)Buffer)[BytesRead32] = Character;
231
232 /* Stop on first carriage return */
233 if (Character == '\r')
234 {
235 if (DoEcho) DosPrintCharacter(DOS_OUTPUT_HANDLE, '\n');
236 break;
237 }
238
239 // BytesRead32++;
240 }
241
242 /* Restore AX */
243 setAX(AX);
244 }
245 else
246 {
247 /* Read the file */
248 if (!ReadFile(Handle, Buffer, Count /* * sizeof(CHAR) */, &BytesRead32, NULL))
249 {
250 /* Store the error code */
251 Result = (WORD)GetLastError();
252 }
253 }
254
255 /* The number of bytes read is always 16-bit */
256 *BytesRead = LOWORD(BytesRead32);
257
258 /* Return the error code */
259 return Result;
260 }
261
262 WORD DosWriteFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesWritten)
263 {
264 WORD Result = ERROR_SUCCESS;
265 DWORD BytesWritten32 = 0;
266 HANDLE Handle = DosGetRealHandle(FileHandle);
267
268 DPRINT("DosWriteFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle, Count);
269
270 /* Make sure the handle is valid */
271 if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
272
273 if (IsConsoleHandle(Handle))
274 {
275 /*
276 * Use BIOS Teletype function
277 */
278
279 /* Save AX and BX */
280 USHORT AX = getAX();
281 USHORT BX = getBX();
282
283 // FIXME: Use BIOS Write String function INT 10h, AH=13h ??
284
285 for (BytesWritten32 = 0; BytesWritten32 < Count; BytesWritten32++)
286 {
287 /* Set the parameters */
288 setAL(((PCHAR)Buffer)[BytesWritten32]);
289 setBL(DOS_CHAR_ATTRIBUTE);
290 setBH(Bda->VideoPage);
291
292 /* Call the BIOS INT 10h, AH=0Eh "Teletype Output" */
293 setAH(0x0E);
294 Int32Call(&DosContext, BIOS_VIDEO_INTERRUPT);
295
296 // BytesWritten32++;
297 }
298
299 /* Restore AX and BX */
300 setBX(BX);
301 setAX(AX);
302 }
303 else
304 {
305 /* Write the file */
306 if (!WriteFile(Handle, Buffer, Count /* * sizeof(CHAR) */, &BytesWritten32, NULL))
307 {
308 /* Store the error code */
309 Result = (WORD)GetLastError();
310 }
311 }
312
313 /* The number of bytes written is always 16-bit */
314 *BytesWritten = LOWORD(BytesWritten32);
315
316 /* Return the error code */
317 return Result;
318 }
319
320 WORD DosSeekFile(WORD FileHandle, LONG Offset, BYTE Origin, LPDWORD NewOffset)
321 {
322 WORD Result = ERROR_SUCCESS;
323 DWORD FilePointer;
324 HANDLE Handle = DosGetRealHandle(FileHandle);
325
326 DPRINT("DosSeekFile: FileHandle 0x%04X, Offset 0x%08X, Origin 0x%02X\n",
327 FileHandle,
328 Offset,
329 Origin);
330
331 /* Make sure the handle is valid */
332 if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
333
334 /* Check if the origin is valid */
335 if (Origin != FILE_BEGIN && Origin != FILE_CURRENT && Origin != FILE_END)
336 {
337 return ERROR_INVALID_FUNCTION;
338 }
339
340 /* Move the file pointer */
341 if (IsConsoleHandle(Handle))
342 {
343 /* Always succeeds when seeking a console handle */
344 FilePointer = 0;
345 Result = ERROR_SUCCESS;
346 }
347 else
348 {
349 FilePointer = SetFilePointer(Handle, Offset, NULL, Origin);
350 }
351
352 /* Check if there's a possibility the operation failed */
353 if (FilePointer == INVALID_SET_FILE_POINTER)
354 {
355 /* Get the real error code */
356 Result = (WORD)GetLastError();
357 }
358
359 if (Result != ERROR_SUCCESS)
360 {
361 /* The operation did fail */
362 return Result;
363 }
364
365 /* Return the file pointer, if requested */
366 if (NewOffset) *NewOffset = FilePointer;
367
368 /* Return success */
369 return ERROR_SUCCESS;
370 }
371
372 BOOL DosFlushFileBuffers(WORD FileHandle)
373 {
374 HANDLE Handle = DosGetRealHandle(FileHandle);
375
376 /* Make sure the handle is valid */
377 if (Handle == INVALID_HANDLE_VALUE) return FALSE;
378
379 /*
380 * This function can either flush files back to disks, or flush
381 * console input buffers, in which case there is no need to check
382 * whether the handle is a console handle. FlushFileBuffers()
383 * automatically does this check and calls FlushConsoleInputBuffer()
384 * if needed.
385 */
386 return FlushFileBuffers(Handle);
387 }