reactos/dll/win32/kernel32/client/file/iocompl.c

282 lines
7.6 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* FILE: dll/win32/kernel32/client/file/iocompl.c
* PURPOSE: Io Completion functions
* PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
* UPDATE HISTORY:
* Created 01/11/98
*/
#include <k32.h>
#define NDEBUG
#include <debug.h>
/*
* SetFileCompletionNotificationModes is not entirely Vista-exclusive,
* it was actually added to Windows 2003 in SP2. Headers restrict it from
* pre-Vista though so define the flags we need for it.
*/
#if (_WIN32_WINNT < 0x0600)
#define FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 0x1
#define FILE_SKIP_SET_EVENT_ON_HANDLE 0x2
#endif
/*
* @unimplemented
*/
BOOL
WINAPI
SetFileCompletionNotificationModes(IN HANDLE FileHandle,
IN UCHAR Flags)
{
if (Flags & ~(FILE_SKIP_COMPLETION_PORT_ON_SUCCESS | FILE_SKIP_SET_EVENT_ON_HANDLE))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
UNIMPLEMENTED;
return FALSE;
}
/*
* @implemented
*/
HANDLE
WINAPI
CreateIoCompletionPort(IN HANDLE FileHandle,
IN HANDLE ExistingCompletionPort,
IN ULONG_PTR CompletionKey,
IN DWORD NumberOfConcurrentThreads)
{
NTSTATUS Status;
HANDLE NewPort;
FILE_COMPLETION_INFORMATION CompletionInformation;
IO_STATUS_BLOCK IoStatusBlock;
/* Check if this is a new port */
NewPort = ExistingCompletionPort;
if (!ExistingCompletionPort)
{
/* Create it */
Status = NtCreateIoCompletion(&NewPort,
IO_COMPLETION_ALL_ACCESS,
NULL,
NumberOfConcurrentThreads);
if (!NT_SUCCESS(Status))
{
/* Convert error and fail */
BaseSetLastNTError(Status);
return FALSE;
}
}
/* Check if no actual file is being associated with the completion port */
if (FileHandle == INVALID_HANDLE_VALUE)
{
/* Was there a port already associated? */
if (ExistingCompletionPort)
{
/* You are not allowed using an old port and dropping the handle */
NewPort = NULL;
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
}
}
else
{
/* We have a file handle, so associated it with this completion port */
CompletionInformation.Port = NewPort;
CompletionInformation.Key = (PVOID)CompletionKey;
Status = NtSetInformationFile(FileHandle,
&IoStatusBlock,
&CompletionInformation,
sizeof(FILE_COMPLETION_INFORMATION),
FileCompletionInformation);
if (!NT_SUCCESS(Status))
{
/* Convert the error code and close the newly created port, if any */
BaseSetLastNTError(Status);
if (!ExistingCompletionPort) NtClose(NewPort);
return FALSE;
}
}
/* Return the newly created port, if any */
return NewPort;
}
/*
* @implemented
*/
BOOL
WINAPI
GetQueuedCompletionStatus(IN HANDLE CompletionHandle,
IN LPDWORD lpNumberOfBytesTransferred,
OUT PULONG_PTR lpCompletionKey,
OUT LPOVERLAPPED *lpOverlapped,
IN DWORD dwMilliseconds)
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatus;
ULONG_PTR CompletionKey;
LARGE_INTEGER Time;
PLARGE_INTEGER TimePtr;
/* Convert the timeout and then call the native API */
TimePtr = BaseFormatTimeOut(&Time, dwMilliseconds);
Status = NtRemoveIoCompletion(CompletionHandle,
(PVOID*)&CompletionKey,
(PVOID*)lpOverlapped,
&IoStatus,
TimePtr);
if (!(NT_SUCCESS(Status)) || (Status == STATUS_TIMEOUT))
{
/* Clear out the overlapped output */
*lpOverlapped = NULL;
/* Check what kind of error we got */
if (Status == STATUS_TIMEOUT)
{
/* Timeout error is set directly since there's no conversion */
SetLastError(WAIT_TIMEOUT);
}
else
{
/* Any other error gets converted */
BaseSetLastNTError(Status);
}
/* This is a failure case */
return FALSE;
}
/* Write back the output parameters */
*lpCompletionKey = CompletionKey;
*lpNumberOfBytesTransferred = IoStatus.Information;
/* Check for error */
if (!NT_SUCCESS(IoStatus.Status))
{
/* Convert and fail */
BaseSetLastNTError(IoStatus.Status);
return FALSE;
}
/* Return success */
return TRUE;
}
/*
* @implemented
*/
BOOL
WINAPI
PostQueuedCompletionStatus(IN HANDLE CompletionHandle,
IN DWORD dwNumberOfBytesTransferred,
IN ULONG_PTR dwCompletionKey,
IN LPOVERLAPPED lpOverlapped)
{
NTSTATUS Status;
/* Call the native API */
Status = NtSetIoCompletion(CompletionHandle,
(PVOID)dwCompletionKey,
(PVOID)lpOverlapped,
STATUS_SUCCESS,
dwNumberOfBytesTransferred);
if (!NT_SUCCESS(Status))
{
/* Convert the error and fail */
BaseSetLastNTError(Status);
return FALSE;
}
/* Success path */
return TRUE;
}
/*
* @implemented
*/
BOOL
WINAPI
GetOverlappedResult(IN HANDLE hFile,
IN LPOVERLAPPED lpOverlapped,
OUT LPDWORD lpNumberOfBytesTransferred,
IN BOOL bWait)
{
DWORD WaitStatus;
HANDLE hObject;
/* Check for pending operation */
if (lpOverlapped->Internal == STATUS_PENDING)
{
/* Check if the caller is okay with waiting */
if (!bWait)
{
/* Set timeout */
WaitStatus = WAIT_TIMEOUT;
}
else
{
/* Wait for the result */
hObject = lpOverlapped->hEvent ? lpOverlapped->hEvent : hFile;
WaitStatus = WaitForSingleObject(hObject, INFINITE);
}
/* Check for timeout */
if (WaitStatus == WAIT_TIMEOUT)
{
/* We have to override the last error with INCOMPLETE instead */
SetLastError(ERROR_IO_INCOMPLETE);
return FALSE;
}
/* Fail if we had an error -- the last error is already set */
if (WaitStatus) return FALSE;
}
/* Return bytes transferred */
*lpNumberOfBytesTransferred = lpOverlapped->InternalHigh;
/* Check for failure during I/O */
if (!NT_SUCCESS(lpOverlapped->Internal))
{
/* Set the error and fail */
BaseSetLastNTError(lpOverlapped->Internal);
return FALSE;
}
/* All done */
return TRUE;
}
/*
* @implemented
*/
BOOL
WINAPI
BindIoCompletionCallback(IN HANDLE FileHandle,
IN LPOVERLAPPED_COMPLETION_ROUTINE Function,
IN ULONG Flags)
{
NTSTATUS Status;
/* Call RTL */
Status = RtlSetIoCompletionCallback(FileHandle,
(PIO_APC_ROUTINE)Function,
Flags);
if (!NT_SUCCESS(Status))
{
/* Set error and fail */
BaseSetLastNTError(Status);
return FALSE;
}
/* Return success */
return TRUE;
}
/* EOF */