- fixed DeviceIoControl to properly wait on completion for synchronous operations

- prevent completion port notification by not passing an APC context to the kernel when the low-order bit of the event handle is set (for asynchronous operations)

svn path=/trunk/; revision=15045
This commit is contained in:
Thomas Bluemel 2005-05-06 15:55:28 +00:00
parent 496308ed56
commit f16e5b9e1d

View file

@ -20,71 +20,39 @@
*/ */
BOOL BOOL
STDCALL STDCALL
DeviceIoControl( DeviceIoControl(IN HANDLE hDevice,
HANDLE hDevice, IN DWORD dwIoControlCode,
DWORD dwIoControlCode, IN LPVOID lpInBuffer OPTIONAL,
LPVOID lpInBuffer, IN DWORD nInBufferSize OPTIONAL,
DWORD nInBufferSize, OUT LPVOID lpOutBuffer OPTIONAL,
LPVOID lpOutBuffer, IN DWORD nOutBufferSize OPTIONAL,
DWORD nOutBufferSize, OUT LPDWORD lpBytesReturned OPTIONAL,
LPDWORD lpBytesReturned, IN LPOVERLAPPED lpOverlapped OPTIONAL)
LPOVERLAPPED lpOverlapped
)
{ {
NTSTATUS errCode = 0; BOOL FsIoCtl;
HANDLE hEvent = NULL; NTSTATUS Status;
PIO_STATUS_BLOCK IoStatusBlock;
IO_STATUS_BLOCK IIosb;
BOOL bFsIoControlCode = FALSE; FsIoCtl = ((dwIoControlCode >> 16) == FILE_DEVICE_FILE_SYSTEM);
DPRINT("DeviceIoControl(hDevice %x dwIoControlCode %d lpInBuffer %x " if (lpBytesReturned != NULL)
"nInBufferSize %d lpOutBuffer %x nOutBufferSize %d "
"lpBytesReturned %x lpOverlapped %x)\n",
hDevice,dwIoControlCode,lpInBuffer,nInBufferSize,lpOutBuffer,
nOutBufferSize,lpBytesReturned,lpOverlapped);
if (lpBytesReturned == NULL)
{ {
DPRINT("DeviceIoControl() - returning STATUS_INVALID_PARAMETER\n"); *lpBytesReturned = 0;
SetLastErrorByStatus (STATUS_INVALID_PARAMETER);
return FALSE;
}
//
// TODO: Review and approve this change by RobD. IoCtrls for Serial.sys were
// going to NtFsControlFile instead of NtDeviceIoControlFile.
// Don't know at this point if anything else is affected by this change.
//
// if (((dwIoControlCode >> 16) & FILE_DEVICE_FILE_SYSTEM) == FILE_DEVICE_FILE_SYSTEM) {
//
if ((dwIoControlCode >> 16) == FILE_DEVICE_FILE_SYSTEM) {
bFsIoControlCode = TRUE;
DPRINT("DeviceIoControl() - FILE_DEVICE_FILE_SYSTEM == TRUE %x %x\n", dwIoControlCode, dwIoControlCode >> 16);
} else {
bFsIoControlCode = FALSE;
DPRINT("DeviceIoControl() - FILE_DEVICE_FILE_SYSTEM == FALSE %x %x\n", dwIoControlCode, dwIoControlCode >> 16);
} }
if (lpOverlapped != NULL) if (lpOverlapped != NULL)
{ {
hEvent = lpOverlapped->hEvent; PVOID ApcContext;
lpOverlapped->Internal = STATUS_PENDING; lpOverlapped->Internal = STATUS_PENDING;
IoStatusBlock = (PIO_STATUS_BLOCK)lpOverlapped; ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
}
else
{
IoStatusBlock = &IIosb;
}
if (bFsIoControlCode == TRUE) if (FsIoCtl)
{ {
errCode = NtFsControlFile (hDevice, Status = NtFsControlFile(hDevice,
hEvent, lpOverlapped->hEvent,
NULL, NULL,
NULL, ApcContext,
IoStatusBlock, (PIO_STATUS_BLOCK)lpOverlapped,
dwIoControlCode, dwIoControlCode,
lpInBuffer, lpInBuffer,
nInBufferSize, nInBufferSize,
@ -93,11 +61,11 @@ DeviceIoControl(
} }
else else
{ {
errCode = NtDeviceIoControlFile (hDevice, Status = NtDeviceIoControlFile(hDevice,
hEvent, lpOverlapped->hEvent,
NULL, NULL,
NULL, ApcContext,
IoStatusBlock, (PIO_STATUS_BLOCK)lpOverlapped,
dwIoControlCode, dwIoControlCode,
lpInBuffer, lpInBuffer,
nInBufferSize, nInBufferSize,
@ -105,28 +73,74 @@ DeviceIoControl(
nOutBufferSize); nOutBufferSize);
} }
if (errCode == STATUS_PENDING) /* return FALSE in case of failure and pending operations! */
if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
{ {
DPRINT("DeviceIoControl() - STATUS_PENDING\n"); SetLastErrorByStatus(Status);
if (NtWaitForSingleObject(hDevice,FALSE,NULL) < 0)
{
*lpBytesReturned = IoStatusBlock->Information;
SetLastErrorByStatus (errCode);
DPRINT("DeviceIoControl() - STATUS_PENDING wait failed.\n");
return FALSE;
}
}
else if (!NT_SUCCESS(errCode))
{
SetLastErrorByStatus (errCode);
DPRINT("DeviceIoControl() - ERROR: %x\n", errCode);
return FALSE; return FALSE;
} }
if (lpOverlapped) if (lpBytesReturned != NULL)
{
*lpBytesReturned = lpOverlapped->InternalHigh; *lpBytesReturned = lpOverlapped->InternalHigh;
}
}
else else
*lpBytesReturned = IoStatusBlock->Information; {
IO_STATUS_BLOCK Iosb;
if (FsIoCtl)
{
Status = NtFsControlFile(hDevice,
NULL,
NULL,
NULL,
&Iosb,
dwIoControlCode,
lpInBuffer,
nInBufferSize,
lpOutBuffer,
nOutBufferSize);
}
else
{
Status = NtDeviceIoControlFile(hDevice,
NULL,
NULL,
NULL,
&Iosb,
dwIoControlCode,
lpInBuffer,
nInBufferSize,
lpOutBuffer,
nOutBufferSize);
}
/* wait in case operation is pending */
if (Status == STATUS_PENDING)
{
Status = NtWaitForSingleObject(hDevice,
FALSE,
NULL);
if (NT_SUCCESS(Status))
{
Status = Iosb.Status;
}
}
if (NT_SUCCESS(Status))
{
/* lpBytesReturned must not be NULL here, in fact Win doesn't
check that case either and crashes (only after the operation
completed) */
*lpBytesReturned = Iosb.Information;
}
else
{
SetLastErrorByStatus(Status);
return FALSE;
}
}
return TRUE; return TRUE;
} }