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