xref: /reactos/dll/win32/kernel32/client/file/iocompl.c (revision 24cb57fd)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS system libraries
4  * FILE:            dll/win32/kernel32/client/file/iocompl.c
5  * PURPOSE:         Io Completion functions
6  * PROGRAMMERS:     Ariadne (ariadne@xs4all.nl)
7  *                  Oleg Dubinskiy (oleg.dubinskij30@gmail.com)
8  * UPDATE HISTORY:
9  *                  Created 01/11/98
10  */
11 
12 #include <k32.h>
13 #define NDEBUG
14 #include <debug.h>
15 
16 /*
17  * SetFileCompletionNotificationModes is not entirely Vista-exclusive,
18  * it was actually added to Windows 2003 in SP2. Headers restrict it from
19  * pre-Vista though so define the flags we need for it.
20  */
21 #if (_WIN32_WINNT < 0x0600)
22 #define FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 0x1
23 #define FILE_SKIP_SET_EVENT_ON_HANDLE        0x2
24 #endif
25 
26 /*
27  * @implemented
28  */
29 BOOL
30 WINAPI
31 SetFileCompletionNotificationModes(IN HANDLE FileHandle,
32                                    IN UCHAR Flags)
33 {
34     NTSTATUS Status;
35     FILE_IO_COMPLETION_NOTIFICATION_INFORMATION FileInformation;
36     IO_STATUS_BLOCK IoStatusBlock;
37 
38     if (Flags & ~(FILE_SKIP_COMPLETION_PORT_ON_SUCCESS | FILE_SKIP_SET_EVENT_ON_HANDLE))
39     {
40         SetLastError(ERROR_INVALID_PARAMETER);
41         return FALSE;
42     }
43 
44     FileInformation.Flags = Flags;
45 
46     Status = NtSetInformationFile(FileHandle,
47                                   &IoStatusBlock,
48                                   &FileInformation,
49                                   sizeof(FileInformation),
50                                   FileIoCompletionNotificationInformation);
51     if (!NT_SUCCESS(Status))
52     {
53         BaseSetLastNTError(Status);
54         return FALSE;
55     }
56 
57     return TRUE;
58 }
59 
60 /*
61  * @implemented
62  */
63 HANDLE
64 WINAPI
65 CreateIoCompletionPort(IN HANDLE FileHandle,
66                        IN HANDLE ExistingCompletionPort,
67                        IN ULONG_PTR CompletionKey,
68                        IN DWORD NumberOfConcurrentThreads)
69 {
70     NTSTATUS Status;
71     HANDLE NewPort;
72     FILE_COMPLETION_INFORMATION CompletionInformation;
73     IO_STATUS_BLOCK IoStatusBlock;
74 
75     /* Check if this is a new port */
76     NewPort = ExistingCompletionPort;
77     if (!ExistingCompletionPort)
78     {
79         /* Create it */
80         Status = NtCreateIoCompletion(&NewPort,
81                                       IO_COMPLETION_ALL_ACCESS,
82                                       NULL,
83                                       NumberOfConcurrentThreads);
84         if (!NT_SUCCESS(Status))
85         {
86             /* Convert error and fail */
87             BaseSetLastNTError(Status);
88             return FALSE;
89         }
90     }
91 
92     /* Check if no actual file is being associated with the completion port */
93     if (FileHandle == INVALID_HANDLE_VALUE)
94     {
95         /* Was there a port already associated? */
96         if (ExistingCompletionPort)
97         {
98             /* You are not allowed using an old port and dropping the handle */
99             NewPort = NULL;
100             BaseSetLastNTError(STATUS_INVALID_PARAMETER);
101         }
102     }
103     else
104     {
105         /* We have a file handle, so associated it with this completion port */
106         CompletionInformation.Port = NewPort;
107         CompletionInformation.Key = (PVOID)CompletionKey;
108         Status = NtSetInformationFile(FileHandle,
109                                       &IoStatusBlock,
110                                       &CompletionInformation,
111                                       sizeof(FILE_COMPLETION_INFORMATION),
112                                       FileCompletionInformation);
113         if (!NT_SUCCESS(Status))
114         {
115             /* Convert the error code and close the newly created port, if any */
116             BaseSetLastNTError(Status);
117             if (!ExistingCompletionPort) NtClose(NewPort);
118             return FALSE;
119         }
120     }
121 
122     /* Return the newly created port, if any */
123     return NewPort;
124 }
125 
126 /*
127  * @implemented
128  */
129 BOOL
130 WINAPI
131 GetQueuedCompletionStatus(IN HANDLE CompletionHandle,
132                           IN LPDWORD lpNumberOfBytesTransferred,
133                           OUT PULONG_PTR lpCompletionKey,
134                           OUT LPOVERLAPPED *lpOverlapped,
135                           IN DWORD dwMilliseconds)
136 {
137     NTSTATUS Status;
138     IO_STATUS_BLOCK IoStatus;
139     ULONG_PTR CompletionKey;
140     LARGE_INTEGER Time;
141     PLARGE_INTEGER TimePtr;
142 
143     /* Convert the timeout and then call the native API */
144     TimePtr = BaseFormatTimeOut(&Time, dwMilliseconds);
145     Status = NtRemoveIoCompletion(CompletionHandle,
146                                   (PVOID*)&CompletionKey,
147                                   (PVOID*)lpOverlapped,
148                                   &IoStatus,
149                                   TimePtr);
150     if (!(NT_SUCCESS(Status)) || (Status == STATUS_TIMEOUT))
151     {
152         /* Clear out the overlapped output */
153         *lpOverlapped = NULL;
154 
155         /* Check what kind of error we got */
156         if (Status == STATUS_TIMEOUT)
157         {
158             /* Timeout error is set directly since there's no conversion */
159             SetLastError(WAIT_TIMEOUT);
160         }
161         else
162         {
163             /* Any other error gets converted */
164             BaseSetLastNTError(Status);
165         }
166 
167         /* This is a failure case */
168         return FALSE;
169     }
170 
171     /* Write back the output parameters */
172     *lpCompletionKey = CompletionKey;
173     *lpNumberOfBytesTransferred = IoStatus.Information;
174 
175     /* Check for error */
176     if (!NT_SUCCESS(IoStatus.Status))
177     {
178         /* Convert and fail */
179         BaseSetLastNTError(IoStatus.Status);
180         return FALSE;
181     }
182 
183     /* Return success */
184     return TRUE;
185 }
186 
187 /*
188  * @implemented
189  */
190 BOOL
191 WINAPI
192 PostQueuedCompletionStatus(IN HANDLE CompletionHandle,
193                            IN DWORD dwNumberOfBytesTransferred,
194                            IN ULONG_PTR dwCompletionKey,
195                            IN LPOVERLAPPED lpOverlapped)
196 {
197     NTSTATUS Status;
198 
199     /* Call the native API */
200     Status = NtSetIoCompletion(CompletionHandle,
201                                (PVOID)dwCompletionKey,
202                                (PVOID)lpOverlapped,
203                                STATUS_SUCCESS,
204                                dwNumberOfBytesTransferred);
205     if (!NT_SUCCESS(Status))
206     {
207         /* Convert the error and fail */
208         BaseSetLastNTError(Status);
209         return FALSE;
210     }
211 
212     /* Success path */
213     return TRUE;
214 }
215 
216 /*
217  * @implemented
218  */
219 BOOL
220 WINAPI
221 GetOverlappedResult(IN HANDLE hFile,
222                     IN LPOVERLAPPED lpOverlapped,
223                     OUT LPDWORD lpNumberOfBytesTransferred,
224                     IN BOOL bWait)
225 {
226     DWORD WaitStatus;
227     HANDLE hObject;
228 
229     /* Check for pending operation */
230     if (lpOverlapped->Internal == STATUS_PENDING)
231     {
232         /* Check if the caller is okay with waiting */
233         if (!bWait)
234         {
235             /* Set timeout */
236             WaitStatus = WAIT_TIMEOUT;
237         }
238         else
239         {
240             /* Wait for the result */
241             hObject = lpOverlapped->hEvent ? lpOverlapped->hEvent : hFile;
242             WaitStatus = WaitForSingleObject(hObject, INFINITE);
243         }
244 
245         /* Check for timeout */
246         if (WaitStatus == WAIT_TIMEOUT)
247         {
248             /* We have to override the last error with INCOMPLETE instead */
249             SetLastError(ERROR_IO_INCOMPLETE);
250             return FALSE;
251         }
252 
253         /* Fail if we had an error -- the last error is already set */
254         if (WaitStatus) return FALSE;
255     }
256 
257     /* Return bytes transferred */
258     *lpNumberOfBytesTransferred = lpOverlapped->InternalHigh;
259 
260     /* Check for failure during I/O */
261     if (!NT_SUCCESS(lpOverlapped->Internal))
262     {
263         /* Set the error and fail */
264         BaseSetLastNTError(lpOverlapped->Internal);
265         return FALSE;
266     }
267 
268     /* All done */
269     return TRUE;
270 }
271 
272 /*
273  * @implemented
274  */
275 BOOL
276 WINAPI
277 BindIoCompletionCallback(IN HANDLE FileHandle,
278                          IN LPOVERLAPPED_COMPLETION_ROUTINE Function,
279                          IN ULONG Flags)
280 {
281     NTSTATUS Status;
282 
283     /* Call RTL */
284     Status = RtlSetIoCompletionCallback(FileHandle,
285                                         (PIO_APC_ROUTINE)Function,
286                                         Flags);
287     if (!NT_SUCCESS(Status))
288     {
289         /* Set error and fail */
290         BaseSetLastNTError(Status);
291         return FALSE;
292     }
293 
294     /* Return success */
295     return TRUE;
296 }
297 
298 /* EOF */
299