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