2013-03-16 20:48:10 +00:00
|
|
|
/*
|
1998-12-04 18:28:13 +00:00
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS system libraries
|
2015-11-14 14:57:11 +00:00
|
|
|
* FILE: dll/win32/kernel32/client/file/iocompl.c
|
1998-12-04 18:28:13 +00:00
|
|
|
* PURPOSE: Io Completion functions
|
|
|
|
* PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
|
|
|
|
* UPDATE HISTORY:
|
|
|
|
* Created 01/11/98
|
|
|
|
*/
|
|
|
|
|
2003-01-15 21:24:36 +00:00
|
|
|
#include <k32.h>
|
[KERNEL32]: While working on the CMAKE branch, Amine and myself discovered a rather serious issue in kernel32 (and perhaps other libraries as well). Unlike rbuild, CMake does not allow you to export non-existant DLL functions (try it: add "poopyhead" in kernel32's exports under RBuild, and will it export "poopyhead", God knowing what that will actually link to).
As an additional feature on top of the "allow non-existing functions to be exported" "feature", because rbuild generates and links STDCALL function names without the proper decoration (vs. enforcing decoration at linking, but only removing it at export-time), this allows the definition (as an export) of a STDCALL function that is completely different from the actual function itself.
For example, the 5-parameter Foo function is normally Foo@20, while the 3-parameter Foo function woudl be Foo@12. Linking one against the other would fail (say, 2 parameters were added to Foo in a newer version). However, under RBUILD, both of these would appear as "Foo", and the linker/compiler would happilly connect the caller of Foo@3 (that has pushed 3 parameters) to the receiving side of Foo@5 (that is about to pop 5 parameters).
Even -if- decorations WERE to be applied, Foo@12 would STILL succeed, because of the first feature, which would enable the export of Foo@12 even though no such function exist.
In a further, bizare, twist of fate, the behavior of this RBUILD "feature", when the target function is not found, is to link the exported DLL TO ITSELF.
Therefore, one can see how, previously to this patch, kernel32.dll would import a dozen functions from itself (all the non-existing functions).
To really seal the deal, the behavior of exported functions used by kernel32, but that are actually forwarded to another DLL deserves a special mention.
GetLastError, for example, merely forwards to RtlGetLastWin32Error, so it is normal behavior to use a #define in the C code so that all internal calls to the function are routed correctly.
This did not happen, so instead, kernel32 tried importing/linking/exporting GetLastError, but this symbol is not found in the binary, because it is only a forwarder.
This caused kernel32 to import from itself (the behavior when an exported symbol is not found). When importing from itself, the loader would now find the _forwarded_ for GetLastError, and correctly link with ntdll.
What should be a one-liner of assembly (inline TEB access) thus became a triple-call indirection (GetLastError@0->StubLastError@0->__impGetLastError@0->__impRtlGetLastWin32Error->RtlGetLastWin32Error.
While analyzing these issues, we also realized a strange macro SetLastErrorByStatus that manually tried to perform what there already exists a function for: RtlSetLastNtStatusFromWin32Error.
And, in an exciting coda, we also realized that our Server 2003 Kernel32 exports more than a dozen Windows 95 APIs, through an auto-stub generation mechanism within winebuild, that gets linked as an object behind the scenes.
[KERNEL32]: Removed all Win95 exports, cleaned up exports.
[KERNEL32]: Fixed up set/get error macros by making them inline and/or calling the correct ntdll function.
[KERNEL32]: Removed bizare calls to Wine-internal/specific APIs from our core Win32 DLL.
[KERNEL32]: Wrote stubs for all functions which should be exported, and set the correct number of parameters for them.
[KERNEL32]: Kernel32 is smaller, loads faster, does not export Windows 95 functions, does not export non-existing functions, and does not import from itself anymore.
Note: This is one of the many failings of RBUILD the CMAKE system has helped us discover. I believe these issues are serious enough to warrant an immediate sync with trunk, but rest assured, there are many more completely broken, infinitely-regressing things that we discovered while switching to CMAKE.
svn path=/trunk/; revision=48475
2010-08-07 05:02:58 +00:00
|
|
|
#define NDEBUG
|
|
|
|
#include <debug.h>
|
2002-09-08 10:23:54 +00:00
|
|
|
|
2015-09-09 11:21:02 +00:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
2003-07-10 18:50:51 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
1999-10-07 23:46:27 +00:00
|
|
|
HANDLE
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2012-02-21 21:31:01 +00:00
|
|
|
CreateIoCompletionPort(IN HANDLE FileHandle,
|
|
|
|
IN HANDLE ExistingCompletionPort,
|
|
|
|
IN ULONG_PTR CompletionKey,
|
|
|
|
IN DWORD NumberOfConcurrentThreads)
|
1998-12-04 18:28:13 +00:00
|
|
|
{
|
2012-02-21 21:31:01 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2005-05-09 01:46:57 +00:00
|
|
|
|
2012-02-21 21:31:01 +00:00
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
}
|
2003-03-19 23:17:52 +00:00
|
|
|
|
2012-02-21 21:31:01 +00:00
|
|
|
/* Return the newly created port, if any */
|
|
|
|
return NewPort;
|
1998-12-04 18:28:13 +00:00
|
|
|
}
|
|
|
|
|
2003-07-10 18:50:51 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2004-01-23 16:37:11 +00:00
|
|
|
BOOL
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2012-02-21 21:31:01 +00:00
|
|
|
GetQueuedCompletionStatus(IN HANDLE CompletionHandle,
|
|
|
|
IN LPDWORD lpNumberOfBytesTransferred,
|
|
|
|
OUT PULONG_PTR lpCompletionKey,
|
|
|
|
OUT LPOVERLAPPED *lpOverlapped,
|
|
|
|
IN DWORD dwMilliseconds)
|
1998-12-04 18:28:13 +00:00
|
|
|
{
|
2012-02-21 21:31:01 +00:00
|
|
|
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,
|
2008-12-17 05:50:20 +00:00
|
|
|
(PVOID*)&CompletionKey,
|
|
|
|
(PVOID*)lpOverlapped,
|
2003-03-19 23:17:52 +00:00
|
|
|
&IoStatus,
|
2011-07-23 11:05:00 +00:00
|
|
|
TimePtr);
|
2012-02-21 21:31:01 +00:00
|
|
|
if (!(NT_SUCCESS(Status)) || (Status == STATUS_TIMEOUT))
|
|
|
|
{
|
|
|
|
/* Clear out the overlapped output */
|
|
|
|
*lpOverlapped = NULL;
|
2003-03-19 23:17:52 +00:00
|
|
|
|
2012-02-21 21:31:01 +00:00
|
|
|
/* 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);
|
|
|
|
}
|
2012-02-17 16:11:40 +00:00
|
|
|
|
2012-02-21 21:31:01 +00:00
|
|
|
/* This is a failure case */
|
|
|
|
return FALSE;
|
|
|
|
}
|
2003-03-19 23:17:52 +00:00
|
|
|
|
2012-02-21 21:31:01 +00:00
|
|
|
/* Write back the output parameters */
|
|
|
|
*lpCompletionKey = CompletionKey;
|
|
|
|
*lpNumberOfBytesTransferred = IoStatus.Information;
|
2003-03-19 23:17:52 +00:00
|
|
|
|
2012-02-21 21:31:01 +00:00
|
|
|
/* Check for error */
|
|
|
|
if (!NT_SUCCESS(IoStatus.Status))
|
|
|
|
{
|
|
|
|
/* Convert and fail */
|
|
|
|
BaseSetLastNTError(IoStatus.Status);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2003-03-19 23:17:52 +00:00
|
|
|
|
2012-02-21 21:31:01 +00:00
|
|
|
/* Return success */
|
|
|
|
return TRUE;
|
1998-12-04 18:28:13 +00:00
|
|
|
}
|
|
|
|
|
2003-07-10 18:50:51 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2004-01-23 16:37:11 +00:00
|
|
|
BOOL
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2012-02-21 21:31:01 +00:00
|
|
|
PostQueuedCompletionStatus(IN HANDLE CompletionHandle,
|
|
|
|
IN DWORD dwNumberOfBytesTransferred,
|
|
|
|
IN ULONG_PTR dwCompletionKey,
|
|
|
|
IN LPOVERLAPPED lpOverlapped)
|
1998-12-04 18:28:13 +00:00
|
|
|
{
|
2012-02-21 21:31:01 +00:00
|
|
|
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;
|
|
|
|
}
|
2003-03-19 23:17:52 +00:00
|
|
|
|
2012-02-21 21:31:01 +00:00
|
|
|
/* Success path */
|
|
|
|
return TRUE;
|
1998-12-04 18:28:13 +00:00
|
|
|
}
|
2000-06-03 14:47:33 +00:00
|
|
|
|
2003-07-10 18:50:51 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2011-11-07 00:18:13 +00:00
|
|
|
BOOL
|
|
|
|
WINAPI
|
|
|
|
GetOverlappedResult(IN HANDLE hFile,
|
|
|
|
IN LPOVERLAPPED lpOverlapped,
|
|
|
|
OUT LPDWORD lpNumberOfBytesTransferred,
|
|
|
|
IN BOOL bWait)
|
2003-02-03 14:20:24 +00:00
|
|
|
{
|
2011-11-07 00:18:13 +00:00
|
|
|
DWORD WaitStatus;
|
|
|
|
HANDLE hObject;
|
2003-02-03 14:20:24 +00:00
|
|
|
|
2011-11-07 00:18:13 +00:00
|
|
|
/* Check for pending operation */
|
|
|
|
if (lpOverlapped->Internal == STATUS_PENDING)
|
2003-02-03 14:20:24 +00:00
|
|
|
{
|
2011-11-07 00:18:13 +00:00
|
|
|
/* 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 */
|
2012-02-21 21:31:01 +00:00
|
|
|
if (WaitStatus) return FALSE;
|
2003-02-03 14:20:24 +00:00
|
|
|
}
|
|
|
|
|
2011-11-07 00:18:13 +00:00
|
|
|
/* 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;
|
|
|
|
}
|
2003-02-03 14:20:24 +00:00
|
|
|
|
2011-11-07 00:18:13 +00:00
|
|
|
/* All done */
|
|
|
|
return TRUE;
|
|
|
|
}
|
2006-01-14 22:47:35 +00:00
|
|
|
|
|
|
|
/*
|
2011-07-22 02:13:57 +00:00
|
|
|
* @implemented
|
2006-01-14 22:47:35 +00:00
|
|
|
*/
|
|
|
|
BOOL
|
|
|
|
WINAPI
|
2012-02-21 21:31:01 +00:00
|
|
|
BindIoCompletionCallback(IN HANDLE FileHandle,
|
|
|
|
IN LPOVERLAPPED_COMPLETION_ROUTINE Function,
|
|
|
|
IN ULONG Flags)
|
2006-01-14 22:47:35 +00:00
|
|
|
{
|
2012-02-21 21:31:01 +00:00
|
|
|
NTSTATUS Status;
|
2006-01-14 22:47:35 +00:00
|
|
|
|
2012-02-21 21:31:01 +00:00
|
|
|
/* Call RTL */
|
2011-07-22 02:13:57 +00:00
|
|
|
Status = RtlSetIoCompletionCallback(FileHandle,
|
|
|
|
(PIO_APC_ROUTINE)Function,
|
|
|
|
Flags);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2012-02-21 21:31:01 +00:00
|
|
|
/* Set error and fail */
|
|
|
|
BaseSetLastNTError(Status);
|
2011-07-22 02:13:57 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2012-02-21 21:31:01 +00:00
|
|
|
/* Return success */
|
2011-07-22 02:13:57 +00:00
|
|
|
return TRUE;
|
2006-01-14 22:47:35 +00:00
|
|
|
}
|
|
|
|
|
2000-06-03 14:47:33 +00:00
|
|
|
/* EOF */
|