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
SetFileCompletionNotificationModes(IN HANDLE FileHandle,IN UCHAR Flags)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
CreateIoCompletionPort(IN HANDLE FileHandle,IN HANDLE ExistingCompletionPort,IN ULONG_PTR CompletionKey,IN DWORD NumberOfConcurrentThreads)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
GetQueuedCompletionStatus(IN HANDLE CompletionHandle,IN LPDWORD lpNumberOfBytesTransferred,OUT PULONG_PTR lpCompletionKey,OUT LPOVERLAPPED * lpOverlapped,IN DWORD dwMilliseconds)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
PostQueuedCompletionStatus(IN HANDLE CompletionHandle,IN DWORD dwNumberOfBytesTransferred,IN ULONG_PTR dwCompletionKey,IN LPOVERLAPPED lpOverlapped)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
GetOverlappedResult(IN HANDLE hFile,IN LPOVERLAPPED lpOverlapped,OUT LPDWORD lpNumberOfBytesTransferred,IN BOOL bWait)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
BindIoCompletionCallback(IN HANDLE FileHandle,IN LPOVERLAPPED_COMPLETION_ROUTINE Function,IN ULONG Flags)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