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