mirror of
https://github.com/reactos/reactos.git
synced 2025-04-25 08:00:24 +00:00
- 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:
parent
f3968e086c
commit
1ec212dc22
1 changed files with 181 additions and 160 deletions
|
@ -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
|
||||
|
@ -21,131 +20,146 @@ BOOL
|
|||
WINAPI
|
||||
DeviceIoControl(IN HANDLE hDevice,
|
||||
IN DWORD dwIoControlCode,
|
||||
IN LPVOID lpInBuffer OPTIONAL,
|
||||
IN DWORD nInBufferSize OPTIONAL,
|
||||
OUT LPVOID lpOutBuffer OPTIONAL,
|
||||
IN DWORD nOutBufferSize OPTIONAL,
|
||||
OUT LPDWORD lpBytesReturned OPTIONAL,
|
||||
IN LPOVERLAPPED lpOverlapped OPTIONAL)
|
||||
IN LPVOID lpInBuffer OPTIONAL,
|
||||
IN DWORD nInBufferSize OPTIONAL,
|
||||
OUT LPVOID lpOutBuffer OPTIONAL,
|
||||
IN DWORD nOutBufferSize OPTIONAL,
|
||||
OUT LPDWORD lpBytesReturned OPTIONAL,
|
||||
IN LPOVERLAPPED lpOverlapped OPTIONAL)
|
||||
{
|
||||
BOOL FsIoCtl;
|
||||
NTSTATUS Status;
|
||||
BOOL FsIoCtl;
|
||||
NTSTATUS Status;
|
||||
PVOID ApcContext;
|
||||
IO_STATUS_BLOCK Iosb;
|
||||
|
||||
FsIoCtl = ((dwIoControlCode >> 16) == FILE_DEVICE_FILE_SYSTEM);
|
||||
|
||||
if (lpBytesReturned != NULL)
|
||||
{
|
||||
*lpBytesReturned = 0;
|
||||
}
|
||||
|
||||
if (lpOverlapped != NULL)
|
||||
{
|
||||
PVOID ApcContext;
|
||||
/* Check what kind of IOCTL to send */
|
||||
FsIoCtl = ((dwIoControlCode >> 16) == FILE_DEVICE_FILE_SYSTEM);
|
||||
|
||||
/* CHeck for async */
|
||||
if (lpOverlapped != NULL)
|
||||
{
|
||||
/* 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)
|
||||
{
|
||||
Status = NtFsControlFile(hDevice,
|
||||
lpOverlapped->hEvent,
|
||||
NULL,
|
||||
ApcContext,
|
||||
(PIO_STATUS_BLOCK)lpOverlapped,
|
||||
dwIoControlCode,
|
||||
lpInBuffer,
|
||||
nInBufferSize,
|
||||
lpOutBuffer,
|
||||
nOutBufferSize);
|
||||
}
|
||||
{
|
||||
/* Send it */
|
||||
Status = NtFsControlFile(hDevice,
|
||||
lpOverlapped->hEvent,
|
||||
NULL,
|
||||
ApcContext,
|
||||
(PIO_STATUS_BLOCK)lpOverlapped,
|
||||
dwIoControlCode,
|
||||
lpInBuffer,
|
||||
nInBufferSize,
|
||||
lpOutBuffer,
|
||||
nOutBufferSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
Status = NtDeviceIoControlFile(hDevice,
|
||||
lpOverlapped->hEvent,
|
||||
NULL,
|
||||
ApcContext,
|
||||
(PIO_STATUS_BLOCK)lpOverlapped,
|
||||
dwIoControlCode,
|
||||
lpInBuffer,
|
||||
nInBufferSize,
|
||||
lpOutBuffer,
|
||||
nOutBufferSize);
|
||||
}
|
||||
{
|
||||
/* Otherwise send a device control */
|
||||
Status = NtDeviceIoControlFile(hDevice,
|
||||
lpOverlapped->hEvent,
|
||||
NULL,
|
||||
ApcContext,
|
||||
(PIO_STATUS_BLOCK)lpOverlapped,
|
||||
dwIoControlCode,
|
||||
lpInBuffer,
|
||||
nInBufferSize,
|
||||
lpOutBuffer,
|
||||
nOutBufferSize);
|
||||
}
|
||||
|
||||
/* return FALSE in case of failure and pending operations! */
|
||||
if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
|
||||
{
|
||||
SetLastErrorByStatus(Status);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
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)
|
||||
/* Check for or information instead of failure */
|
||||
if (!(NT_ERROR(Status)) && (lpBytesReturned))
|
||||
{
|
||||
/* Protect with SEH */
|
||||
_SEH2_TRY
|
||||
{
|
||||
ERR("Bad caller: lpBytesReturned must not be NULL\n");
|
||||
/* Return the bytes */
|
||||
*lpBytesReturned = lpOverlapped->InternalHigh;
|
||||
}
|
||||
*lpBytesReturned = Iosb.Information;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetLastErrorByStatus(Status);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
/* Return zero bytes */
|
||||
*lpBytesReturned = 0;
|
||||
}
|
||||
_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
|
||||
WINAPI
|
||||
GetOverlappedResult (
|
||||
IN HANDLE hFile,
|
||||
IN LPOVERLAPPED lpOverlapped,
|
||||
OUT LPDWORD lpNumberOfBytesTransferred,
|
||||
IN BOOL bWait
|
||||
)
|
||||
GetOverlappedResult(IN HANDLE hFile,
|
||||
IN LPOVERLAPPED lpOverlapped,
|
||||
OUT LPDWORD lpNumberOfBytesTransferred,
|
||||
IN BOOL bWait)
|
||||
{
|
||||
DWORD WaitStatus;
|
||||
HANDLE hObject;
|
||||
DWORD WaitStatus;
|
||||
HANDLE hObject;
|
||||
|
||||
if (lpOverlapped->Internal == STATUS_PENDING)
|
||||
{
|
||||
if (!bWait)
|
||||
|
||||
/* Check for pending operation */
|
||||
if (lpOverlapped->Internal == STATUS_PENDING)
|
||||
{
|
||||
/* can't use SetLastErrorByStatus(STATUS_PENDING) here,
|
||||
since STATUS_PENDING translates to ERROR_IO_PENDING */
|
||||
SetLastError(ERROR_IO_INCOMPLETE);
|
||||
return FALSE;
|
||||
/* 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 */
|
||||
if (WaitStatus != 0) 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);
|
||||
/* Return bytes transferred */
|
||||
*lpNumberOfBytesTransferred = lpOverlapped->InternalHigh;
|
||||
|
||||
if (WaitStatus == WAIT_FAILED)
|
||||
|
||||
/* Check for failure during I/O */
|
||||
if (!NT_SUCCESS(lpOverlapped->Internal))
|
||||
{
|
||||
WARN("Wait failed!\n");
|
||||
/* WaitForSingleObjectEx sets the last error */
|
||||
return FALSE;
|
||||
/* Set the error and fail */
|
||||
SetLastErrorByStatus(lpOverlapped->Internal);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!lpNumberOfBytesTransferred)
|
||||
{
|
||||
ERR("Bad caller: lpNumberOfBytesTransferred must not be NULL\n");
|
||||
}
|
||||
*lpNumberOfBytesTransferred = lpOverlapped->InternalHigh;
|
||||
|
||||
if (!NT_SUCCESS(lpOverlapped->Internal))
|
||||
{
|
||||
SetLastErrorByStatus(lpOverlapped->Internal);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
/* All done */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue