- Fix broken check for storing the number of transferred bytes.

- Fix broken logic in GetOverlappedResult
- Patch by Alex

svn path=/trunk/; revision=44667
This commit is contained in:
Johannes Anderwald 2009-12-20 11:57:21 +00:00
parent f3968e086c
commit 1ec212dc22

View file

@ -1,18 +1,17 @@
/* $Id$ /*
* * PROJECT: ReactOS Kernel
* COPYRIGHT: See COPYING in the top level directory * LICENSE: GPL - See COPYING in the top level directory
* PROJECT: ReactOS system libraries * FILE: kernel32/file/deviceio.c
* FILE: lib/kernel32/file/deviceio.c * PURPOSE: Device I/O Base Client Functionality
* PURPOSE: Device I/O and Overlapped Result functions * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
* PROGRAMMER: Ariadne (ariadne@xs4all.nl)
* UPDATE HISTORY:
* Created 01/11/98
*/ */
/* INCLUDES *******************************************************************/
#include <k32.h> #include <k32.h>
#include <wine/debug.h> #include <wine/debug.h>
WINE_DEFAULT_DEBUG_CHANNEL(kernel32file); /* FUNCTIONS ******************************************************************/
/* /*
* @implemented * @implemented
@ -21,131 +20,146 @@ BOOL
WINAPI WINAPI
DeviceIoControl(IN HANDLE hDevice, DeviceIoControl(IN HANDLE hDevice,
IN DWORD dwIoControlCode, IN DWORD dwIoControlCode,
IN LPVOID lpInBuffer OPTIONAL, IN LPVOID lpInBuffer OPTIONAL,
IN DWORD nInBufferSize OPTIONAL, IN DWORD nInBufferSize OPTIONAL,
OUT LPVOID lpOutBuffer OPTIONAL, OUT LPVOID lpOutBuffer OPTIONAL,
IN DWORD nOutBufferSize OPTIONAL, IN DWORD nOutBufferSize OPTIONAL,
OUT LPDWORD lpBytesReturned OPTIONAL, OUT LPDWORD lpBytesReturned OPTIONAL,
IN LPOVERLAPPED lpOverlapped OPTIONAL) IN LPOVERLAPPED lpOverlapped OPTIONAL)
{ {
BOOL FsIoCtl; BOOL FsIoCtl;
NTSTATUS Status; NTSTATUS Status;
PVOID ApcContext;
IO_STATUS_BLOCK Iosb;
FsIoCtl = ((dwIoControlCode >> 16) == FILE_DEVICE_FILE_SYSTEM); /* Check what kind of IOCTL to send */
FsIoCtl = ((dwIoControlCode >> 16) == FILE_DEVICE_FILE_SYSTEM);
if (lpBytesReturned != NULL)
{
*lpBytesReturned = 0;
}
if (lpOverlapped != NULL)
{
PVOID ApcContext;
/* CHeck for async */
if (lpOverlapped != NULL)
{
/* Set pending status */
lpOverlapped->Internal = STATUS_PENDING; lpOverlapped->Internal = STATUS_PENDING;
/* Check if there's an APC context */
ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped); ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
/* Send file system control? */
if (FsIoCtl) if (FsIoCtl)
{ {
Status = NtFsControlFile(hDevice, /* Send it */
lpOverlapped->hEvent, Status = NtFsControlFile(hDevice,
NULL, lpOverlapped->hEvent,
ApcContext, NULL,
(PIO_STATUS_BLOCK)lpOverlapped, ApcContext,
dwIoControlCode, (PIO_STATUS_BLOCK)lpOverlapped,
lpInBuffer, dwIoControlCode,
nInBufferSize, lpInBuffer,
lpOutBuffer, nInBufferSize,
nOutBufferSize); lpOutBuffer,
} nOutBufferSize);
}
else else
{ {
Status = NtDeviceIoControlFile(hDevice, /* Otherwise send a device control */
lpOverlapped->hEvent, Status = NtDeviceIoControlFile(hDevice,
NULL, lpOverlapped->hEvent,
ApcContext, NULL,
(PIO_STATUS_BLOCK)lpOverlapped, ApcContext,
dwIoControlCode, (PIO_STATUS_BLOCK)lpOverlapped,
lpInBuffer, dwIoControlCode,
nInBufferSize, lpInBuffer,
lpOutBuffer, nInBufferSize,
nOutBufferSize); lpOutBuffer,
} nOutBufferSize);
}
/* return FALSE in case of failure and pending operations! */ /* Check for or information instead of failure */
if (!NT_SUCCESS(Status) || Status == STATUS_PENDING) if (!(NT_ERROR(Status)) && (lpBytesReturned))
{ {
SetLastErrorByStatus(Status); /* Protect with SEH */
return FALSE; _SEH2_TRY
}
if (lpBytesReturned != NULL)
{
*lpBytesReturned = lpOverlapped->InternalHigh;
}
}
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);
}
/* 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) */
if (!lpBytesReturned)
{ {
ERR("Bad caller: lpBytesReturned must not be NULL\n"); /* Return the bytes */
*lpBytesReturned = lpOverlapped->InternalHigh;
} }
*lpBytesReturned = Iosb.Information; _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
} {
else /* Return zero bytes */
{ *lpBytesReturned = 0;
SetLastErrorByStatus(Status); }
return FALSE; _SEH2_END;
} }
}
return TRUE; /* Now check for any kind of failure except pending*/
if (!(NT_SUCCESS(Status)) || (Status == STATUS_PENDING))
{
/* Fail */
SetLastErrorByStatus(Status);
return FALSE;
}
}
else
{
/* Sync case -- send file system code? */
if (FsIoCtl)
{
/* Do it */
Status = NtFsControlFile(hDevice,
NULL,
NULL,
NULL,
&Iosb,
dwIoControlCode,
lpInBuffer,
nInBufferSize,
lpOutBuffer,
nOutBufferSize);
}
else
{
/* Send device code instead */
Status = NtDeviceIoControlFile(hDevice,
NULL,
NULL,
NULL,
&Iosb,
dwIoControlCode,
lpInBuffer,
nInBufferSize,
lpOutBuffer,
nOutBufferSize);
}
/* Now check if the operation isn't done yet */
if (Status == STATUS_PENDING)
{
/* Wait for it and get the final status */
Status = NtWaitForSingleObject(hDevice, FALSE, NULL);
if (NT_SUCCESS(Status)) Status = Iosb.Status;
}
/* Check for success */
if (NT_SUCCESS(Status))
{
/* Return the byte count */
*lpBytesReturned = Iosb.Information;
}
else
{
/* Check for informational or warning failure */
if (!NT_ERROR(Status)) *lpBytesReturned = Iosb.Information;
/* Return a failure */
SetLastErrorByStatus(Status);
return FALSE;
}
}
/* Return success */
return TRUE;
} }
@ -154,55 +168,62 @@ DeviceIoControl(IN HANDLE hDevice,
*/ */
BOOL BOOL
WINAPI WINAPI
GetOverlappedResult ( GetOverlappedResult(IN HANDLE hFile,
IN HANDLE hFile, IN LPOVERLAPPED lpOverlapped,
IN LPOVERLAPPED lpOverlapped, OUT LPDWORD lpNumberOfBytesTransferred,
OUT LPDWORD lpNumberOfBytesTransferred, IN BOOL bWait)
IN BOOL bWait
)
{ {
DWORD WaitStatus; DWORD WaitStatus;
HANDLE hObject; HANDLE hObject;
if (lpOverlapped->Internal == STATUS_PENDING)
{ /* Check for pending operation */
if (!bWait) if (lpOverlapped->Internal == STATUS_PENDING)
{ {
/* can't use SetLastErrorByStatus(STATUS_PENDING) here, /* Check if the caller is okay with waiting */
since STATUS_PENDING translates to ERROR_IO_PENDING */ if (!bWait)
SetLastError(ERROR_IO_INCOMPLETE); {
return FALSE; /* 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 != 0) return FALSE;
} }
hObject = lpOverlapped->hEvent ? lpOverlapped->hEvent : hFile;
/* Wine delivers pending APC's while waiting, but Windows does /* Return bytes transferred */
not, nor do we... */ *lpNumberOfBytesTransferred = lpOverlapped->InternalHigh;
WaitStatus = WaitForSingleObject(hObject, INFINITE);
if (WaitStatus == WAIT_FAILED)
/* Check for failure during I/O */
if (!NT_SUCCESS(lpOverlapped->Internal))
{ {
WARN("Wait failed!\n"); /* Set the error and fail */
/* WaitForSingleObjectEx sets the last error */ SetLastErrorByStatus(lpOverlapped->Internal);
return FALSE; return FALSE;
} }
}
if (!lpNumberOfBytesTransferred)
{
ERR("Bad caller: lpNumberOfBytesTransferred must not be NULL\n");
}
*lpNumberOfBytesTransferred = lpOverlapped->InternalHigh;
if (!NT_SUCCESS(lpOverlapped->Internal)) /* All done */
{ return TRUE;
SetLastErrorByStatus(lpOverlapped->Internal);
return FALSE;
}
return TRUE;
} }
/* EOF */ /* EOF */