xref: /reactos/dll/win32/kernel32/client/file/rw.c (revision 139a3d66)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS system libraries
4  * FILE:            dll/win32/kernel32/client/file/rw.c
5  * PURPOSE:         Read/write functions
6  * PROGRAMMER:      Ariadne (ariadne@xs4all.nl)
7  * UPDATE HISTORY:
8  *                  Created 01/11/98
9  */
10 
11 /* INCLUDES ****************************************************************/
12 
13 #include <k32.h>
14 #define NDEBUG
15 #include <debug.h>
16 DEBUG_CHANNEL(kernel32file);
17 
18 /* FUNCTIONS ****************************************************************/
19 
20 /*
21  * @implemented
22  */
23 BOOL WINAPI
24 WriteFile(IN HANDLE hFile,
25           IN LPCVOID lpBuffer,
26           IN DWORD nNumberOfBytesToWrite OPTIONAL,
27           OUT LPDWORD lpNumberOfBytesWritten,
28           IN LPOVERLAPPED lpOverlapped OPTIONAL)
29 {
30     NTSTATUS Status;
31 
32     TRACE("WriteFile(hFile %p)\n", hFile);
33 
34     if (lpNumberOfBytesWritten != NULL) *lpNumberOfBytesWritten = 0;
35 
36     hFile = TranslateStdHandle(hFile);
37 
38     if (IsConsoleHandle(hFile))
39     {
40         return WriteConsoleA(hFile,
41                              lpBuffer,
42                              nNumberOfBytesToWrite,
43                              lpNumberOfBytesWritten,
44                              lpOverlapped);
45     }
46 
47     if (lpOverlapped != NULL)
48     {
49         LARGE_INTEGER Offset;
50         PVOID ApcContext;
51 
52         Offset.u.LowPart = lpOverlapped->Offset;
53         Offset.u.HighPart = lpOverlapped->OffsetHigh;
54         lpOverlapped->Internal = STATUS_PENDING;
55         ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
56 
57         Status = NtWriteFile(hFile,
58                              lpOverlapped->hEvent,
59                              NULL,
60                              ApcContext,
61                              (PIO_STATUS_BLOCK)lpOverlapped,
62                              (PVOID)lpBuffer,
63                              nNumberOfBytesToWrite,
64                              &Offset,
65                              NULL);
66 
67         /* return FALSE in case of failure and pending operations! */
68         if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
69         {
70             BaseSetLastNTError(Status);
71             return FALSE;
72         }
73 
74         if (lpNumberOfBytesWritten != NULL)
75             *lpNumberOfBytesWritten = lpOverlapped->InternalHigh;
76     }
77     else
78     {
79         IO_STATUS_BLOCK Iosb;
80 
81         Status = NtWriteFile(hFile,
82                              NULL,
83                              NULL,
84                              NULL,
85                              &Iosb,
86                              (PVOID)lpBuffer,
87                              nNumberOfBytesToWrite,
88                              NULL,
89                              NULL);
90 
91         /* Wait in case operation is pending */
92         if (Status == STATUS_PENDING)
93         {
94             Status = NtWaitForSingleObject(hFile, FALSE, NULL);
95             if (NT_SUCCESS(Status)) Status = Iosb.Status;
96         }
97 
98         if (NT_SUCCESS(Status))
99         {
100             /*
101              * lpNumberOfBytesWritten must not be NULL here, in fact Win doesn't
102              * check that case either and crashes (only after the operation
103              * completed).
104              */
105             *lpNumberOfBytesWritten = Iosb.Information;
106         }
107         else
108         {
109             BaseSetLastNTError(Status);
110             return FALSE;
111         }
112     }
113 
114     TRACE("WriteFile() succeeded\n");
115     return TRUE;
116 }
117 
118 
119 /*
120  * @implemented
121  */
122 BOOL WINAPI
123 ReadFile(IN HANDLE hFile,
124          IN LPVOID lpBuffer,
125          IN DWORD nNumberOfBytesToRead,
126          OUT LPDWORD lpNumberOfBytesRead OPTIONAL,
127          IN LPOVERLAPPED lpOverlapped OPTIONAL)
128 {
129     NTSTATUS Status;
130 
131     TRACE("ReadFile(hFile %p)\n", hFile);
132 
133     if (lpNumberOfBytesRead != NULL) *lpNumberOfBytesRead = 0;
134 
135     hFile = TranslateStdHandle(hFile);
136 
137     if (IsConsoleHandle(hFile))
138     {
139         if (ReadConsoleA(hFile,
140                          lpBuffer,
141                          nNumberOfBytesToRead,
142                          lpNumberOfBytesRead,
143                          NULL))
144         {
145             DWORD dwMode;
146             GetConsoleMode(hFile, &dwMode);
147             if ((dwMode & ENABLE_PROCESSED_INPUT) && *(PCHAR)lpBuffer == 0x1a)
148             {
149                 /* EOF character entered; simulate end-of-file */
150                 *lpNumberOfBytesRead = 0;
151             }
152             return TRUE;
153         }
154         return FALSE;
155     }
156 
157     if (lpOverlapped != NULL)
158     {
159         LARGE_INTEGER Offset;
160         PVOID ApcContext;
161 
162         Offset.u.LowPart = lpOverlapped->Offset;
163         Offset.u.HighPart = lpOverlapped->OffsetHigh;
164         lpOverlapped->Internal = STATUS_PENDING;
165         ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
166 
167         Status = NtReadFile(hFile,
168                             lpOverlapped->hEvent,
169                             NULL,
170                             ApcContext,
171                             (PIO_STATUS_BLOCK)lpOverlapped,
172                             lpBuffer,
173                             nNumberOfBytesToRead,
174                             &Offset,
175                             NULL);
176 
177         /* return FALSE in case of failure and pending operations! */
178         if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
179         {
180             if (Status == STATUS_END_OF_FILE && lpNumberOfBytesRead != NULL)
181                 *lpNumberOfBytesRead = 0;
182 
183             BaseSetLastNTError(Status);
184             return FALSE;
185         }
186 
187         if (lpNumberOfBytesRead != NULL)
188             *lpNumberOfBytesRead = lpOverlapped->InternalHigh;
189     }
190     else
191     {
192         IO_STATUS_BLOCK Iosb;
193 
194         Status = NtReadFile(hFile,
195                             NULL,
196                             NULL,
197                             NULL,
198                             &Iosb,
199                             lpBuffer,
200                             nNumberOfBytesToRead,
201                             NULL,
202                             NULL);
203 
204         /* Wait in case operation is pending */
205         if (Status == STATUS_PENDING)
206         {
207             Status = NtWaitForSingleObject(hFile, FALSE, NULL);
208             if (NT_SUCCESS(Status)) Status = Iosb.Status;
209         }
210 
211         if (Status == STATUS_END_OF_FILE)
212         {
213             /*
214              * lpNumberOfBytesRead must not be NULL here, in fact Win doesn't
215              * check that case either and crashes (only after the operation
216              * completed).
217              */
218             *lpNumberOfBytesRead = 0;
219             return TRUE;
220         }
221 
222         if (NT_SUCCESS(Status))
223         {
224             /*
225              * lpNumberOfBytesRead must not be NULL here, in fact Win doesn't
226              * check that case either and crashes (only after the operation
227              * completed).
228              */
229             *lpNumberOfBytesRead = Iosb.Information;
230         }
231         else
232         {
233             BaseSetLastNTError(Status);
234             return FALSE;
235         }
236     }
237 
238     TRACE("ReadFile() succeeded\n");
239     return TRUE;
240 }
241 
242 VOID WINAPI
243 ApcRoutine(PVOID ApcContext,
244            PIO_STATUS_BLOCK IoStatusBlock,
245            ULONG Reserved)
246 {
247     DWORD dwErrorCode;
248     LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine =
249         (LPOVERLAPPED_COMPLETION_ROUTINE)ApcContext;
250 
251     dwErrorCode = RtlNtStatusToDosError(IoStatusBlock->Status);
252     lpCompletionRoutine(dwErrorCode,
253                         IoStatusBlock->Information,
254                         (LPOVERLAPPED)IoStatusBlock);
255 }
256 
257 
258 /*
259  * @implemented
260  */
261 BOOL WINAPI
262 WriteFileEx(IN HANDLE hFile,
263             IN LPCVOID lpBuffer,
264             IN DWORD nNumberOfBytesToWrite OPTIONAL,
265             IN LPOVERLAPPED lpOverlapped,
266             IN LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
267 {
268     LARGE_INTEGER Offset;
269     NTSTATUS Status;
270 
271     Offset.u.LowPart = lpOverlapped->Offset;
272     Offset.u.HighPart = lpOverlapped->OffsetHigh;
273     lpOverlapped->Internal = STATUS_PENDING;
274 
275     Status = NtWriteFile(hFile,
276                          NULL,
277                          ApcRoutine,
278                          lpCompletionRoutine,
279                          (PIO_STATUS_BLOCK)lpOverlapped,
280                          (PVOID)lpBuffer,
281                          nNumberOfBytesToWrite,
282                          &Offset,
283                          NULL);
284 
285     if (!NT_SUCCESS(Status))
286     {
287         BaseSetLastNTError(Status);
288         return FALSE;
289     }
290 
291     return TRUE;
292 }
293 
294 
295 /*
296  * @implemented
297  */
298 BOOL WINAPI
299 ReadFileEx(IN HANDLE hFile,
300            IN LPVOID lpBuffer,
301            IN DWORD nNumberOfBytesToRead OPTIONAL,
302            IN LPOVERLAPPED lpOverlapped,
303            IN LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
304 {
305     LARGE_INTEGER Offset;
306     NTSTATUS Status;
307 
308     Offset.u.LowPart = lpOverlapped->Offset;
309     Offset.u.HighPart = lpOverlapped->OffsetHigh;
310     lpOverlapped->Internal = STATUS_PENDING;
311 
312     Status = NtReadFile(hFile,
313                         NULL,
314                         ApcRoutine,
315                         lpCompletionRoutine,
316                         (PIO_STATUS_BLOCK)lpOverlapped,
317                         lpBuffer,
318                         nNumberOfBytesToRead,
319                         &Offset,
320                         NULL);
321 
322     if (!NT_SUCCESS(Status))
323     {
324         BaseSetLastNTError(Status);
325         return FALSE;
326     }
327 
328     return TRUE;
329 }
330 
331 
332 /*
333  * @implemented
334  */
335 BOOL
336 WINAPI
337 ReadFileScatter(HANDLE hFile,
338                 FILE_SEGMENT_ELEMENT aSegmentArray[],
339                 DWORD nNumberOfBytesToRead,
340                 LPDWORD lpReserved,
341                 LPOVERLAPPED lpOverlapped)
342 {
343     PIO_STATUS_BLOCK pIOStatus;
344     LARGE_INTEGER Offset;
345     NTSTATUS Status;
346 
347     DPRINT("(%p %p %u %p)\n", hFile, aSegmentArray, nNumberOfBytesToRead, lpOverlapped);
348 
349     Offset.LowPart  = lpOverlapped->Offset;
350     Offset.HighPart = lpOverlapped->OffsetHigh;
351     pIOStatus = (PIO_STATUS_BLOCK) lpOverlapped;
352     pIOStatus->Status = STATUS_PENDING;
353     pIOStatus->Information = 0;
354 
355     Status = NtReadFileScatter(hFile,
356                                NULL,
357                                NULL,
358                                NULL,
359                                pIOStatus,
360                                aSegmentArray,
361                                nNumberOfBytesToRead,
362                                &Offset,
363                                NULL);
364 
365     if (!NT_SUCCESS(Status))
366     {
367         SetLastError(RtlNtStatusToDosError(Status));
368         return FALSE;
369     }
370 
371     return TRUE;
372 }
373 
374 /*
375  * @implemented
376  */
377 BOOL
378 WINAPI
379 WriteFileGather(HANDLE hFile,
380                 FILE_SEGMENT_ELEMENT aSegmentArray[],
381                 DWORD nNumberOfBytesToWrite,
382                 LPDWORD lpReserved,
383                 LPOVERLAPPED lpOverlapped)
384 {
385     PIO_STATUS_BLOCK IOStatus;
386     LARGE_INTEGER Offset;
387     NTSTATUS Status;
388 
389     DPRINT("%p %p %u %p\n", hFile, aSegmentArray, nNumberOfBytesToWrite, lpOverlapped);
390 
391     Offset.LowPart = lpOverlapped->Offset;
392     Offset.HighPart = lpOverlapped->OffsetHigh;
393     IOStatus = (PIO_STATUS_BLOCK) lpOverlapped;
394     IOStatus->Status = STATUS_PENDING;
395     IOStatus->Information = 0;
396 
397     Status = NtWriteFileGather(hFile,
398                                NULL,
399                                NULL,
400                                NULL,
401                                IOStatus,
402                                aSegmentArray,
403                                nNumberOfBytesToWrite,
404                                &Offset,
405                                NULL);
406 
407     if (!NT_SUCCESS(Status))
408     {
409         SetLastError(RtlNtStatusToDosError(Status));
410         return FALSE;
411     }
412 
413     return TRUE;
414 }
415 
416 /* EOF */
417