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