mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 10:04:49 +00:00
- fixed Read/WriteFile(Ex) and 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=15043
This commit is contained in:
parent
c565a223c9
commit
496308ed56
1 changed files with 242 additions and 215 deletions
|
@ -23,78 +23,104 @@
|
||||||
* @implemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
BOOL STDCALL
|
BOOL STDCALL
|
||||||
WriteFile(HANDLE hFile,
|
WriteFile(IN HANDLE hFile,
|
||||||
LPCVOID lpBuffer,
|
IN LPCVOID lpBuffer,
|
||||||
DWORD nNumberOfBytesToWrite,
|
IN DWORD nNumberOfBytesToWrite OPTIONAL,
|
||||||
LPDWORD lpNumberOfBytesWritten,
|
OUT LPDWORD lpNumberOfBytesWritten OPTIONAL,
|
||||||
LPOVERLAPPED lpOverLapped)
|
IN LPOVERLAPPED lpOverlapped OPTIONAL)
|
||||||
{
|
{
|
||||||
HANDLE hEvent = NULL;
|
NTSTATUS Status;
|
||||||
LARGE_INTEGER Offset;
|
|
||||||
NTSTATUS errCode;
|
|
||||||
IO_STATUS_BLOCK IIosb;
|
|
||||||
PIO_STATUS_BLOCK IoStatusBlock;
|
|
||||||
PLARGE_INTEGER ptrOffset;
|
|
||||||
|
|
||||||
DPRINT("WriteFile(hFile %x)\n",hFile);
|
DPRINT("WriteFile(hFile %x)\n", hFile);
|
||||||
|
|
||||||
if (lpOverLapped == NULL && lpNumberOfBytesWritten == NULL)
|
if (lpNumberOfBytesWritten != NULL)
|
||||||
{
|
|
||||||
SetLastError(ERROR_INVALID_PARAMETER);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lpNumberOfBytesWritten)
|
|
||||||
{
|
{
|
||||||
*lpNumberOfBytesWritten = 0;
|
*lpNumberOfBytesWritten = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsConsoleHandle(hFile))
|
if (IsConsoleHandle(hFile))
|
||||||
{
|
{
|
||||||
return(WriteConsoleA(hFile,
|
return WriteConsoleA(hFile,
|
||||||
lpBuffer,
|
lpBuffer,
|
||||||
nNumberOfBytesToWrite,
|
nNumberOfBytesToWrite,
|
||||||
lpNumberOfBytesWritten,
|
lpNumberOfBytesWritten,
|
||||||
NULL));
|
lpOverlapped);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lpOverLapped != NULL)
|
if (lpOverlapped != NULL)
|
||||||
{
|
{
|
||||||
Offset.u.LowPart = lpOverLapped->Offset;
|
LARGE_INTEGER Offset;
|
||||||
Offset.u.HighPart = lpOverLapped->OffsetHigh;
|
PVOID ApcContext;
|
||||||
lpOverLapped->Internal = STATUS_PENDING;
|
|
||||||
hEvent = lpOverLapped->hEvent;
|
|
||||||
IoStatusBlock = (PIO_STATUS_BLOCK)lpOverLapped;
|
|
||||||
ptrOffset = &Offset;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ptrOffset = NULL;
|
|
||||||
IoStatusBlock = &IIosb;
|
|
||||||
}
|
|
||||||
|
|
||||||
errCode = NtWriteFile(hFile,
|
Offset.u.LowPart = lpOverlapped->Offset;
|
||||||
hEvent,
|
Offset.u.HighPart = lpOverlapped->OffsetHigh;
|
||||||
|
lpOverlapped->Internal = STATUS_PENDING;
|
||||||
|
ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
|
||||||
|
|
||||||
|
Status = NtWriteFile(hFile,
|
||||||
|
lpOverlapped->hEvent,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
ApcContext,
|
||||||
IoStatusBlock,
|
(PIO_STATUS_BLOCK)lpOverlapped,
|
||||||
(PVOID)lpBuffer,
|
(PVOID)lpBuffer,
|
||||||
nNumberOfBytesToWrite,
|
nNumberOfBytesToWrite,
|
||||||
ptrOffset,
|
&Offset,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
if (!NT_SUCCESS(errCode) || errCode == STATUS_PENDING)
|
/* return FALSE in case of failure and pending operations! */
|
||||||
|
if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
|
||||||
{
|
{
|
||||||
SetLastErrorByStatus (errCode);
|
SetLastErrorByStatus(Status);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lpNumberOfBytesWritten != NULL )
|
if (lpNumberOfBytesWritten != NULL)
|
||||||
{
|
{
|
||||||
*lpNumberOfBytesWritten = IoStatusBlock->Information;
|
*lpNumberOfBytesWritten = lpOverlapped->InternalHigh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IO_STATUS_BLOCK Iosb;
|
||||||
|
|
||||||
|
Status = NtWriteFile(hFile,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&Iosb,
|
||||||
|
(PVOID)lpBuffer,
|
||||||
|
nNumberOfBytesToWrite,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* wait in case operation is pending */
|
||||||
|
if (Status == STATUS_PENDING)
|
||||||
|
{
|
||||||
|
Status = NtWaitForSingleObject(hFile,
|
||||||
|
FALSE,
|
||||||
|
NULL);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
Status = Iosb.Status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* lpNumberOfBytesWritten must not be NULL here, in fact Win doesn't
|
||||||
|
check that case either and crashes (only after the operation
|
||||||
|
completed) */
|
||||||
|
*lpNumberOfBytesWritten = Iosb.Information;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetLastErrorByStatus(Status);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINT("WriteFile() succeeded\n");
|
DPRINT("WriteFile() succeeded\n");
|
||||||
return(TRUE);
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -102,87 +128,119 @@ WriteFile(HANDLE hFile,
|
||||||
* @implemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
BOOL STDCALL
|
BOOL STDCALL
|
||||||
ReadFile(
|
ReadFile(IN HANDLE hFile,
|
||||||
HANDLE hFile,
|
IN LPVOID lpBuffer,
|
||||||
LPVOID lpBuffer,
|
IN DWORD nNumberOfBytesToRead,
|
||||||
DWORD nNumberOfBytesToRead,
|
OUT LPDWORD lpNumberOfBytesRead OPTIONAL,
|
||||||
LPDWORD lpNumberOfBytesRead,
|
IN LPOVERLAPPED lpOverlapped OPTIONAL)
|
||||||
LPOVERLAPPED lpOverLapped
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
HANDLE hEvent = NULL;
|
NTSTATUS Status;
|
||||||
LARGE_INTEGER Offset;
|
|
||||||
NTSTATUS errCode;
|
|
||||||
IO_STATUS_BLOCK IIosb;
|
|
||||||
PIO_STATUS_BLOCK IoStatusBlock;
|
|
||||||
PLARGE_INTEGER ptrOffset;
|
|
||||||
|
|
||||||
if (lpOverLapped == NULL && lpNumberOfBytesRead == NULL)
|
DPRINT("ReadFile(hFile %x)\n", hFile);
|
||||||
{
|
|
||||||
SetLastError(ERROR_INVALID_PARAMETER);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lpNumberOfBytesRead)
|
if (lpNumberOfBytesRead != NULL)
|
||||||
{
|
{
|
||||||
*lpNumberOfBytesRead = 0;
|
*lpNumberOfBytesRead = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsConsoleHandle(hFile))
|
if (IsConsoleHandle(hFile))
|
||||||
{
|
{
|
||||||
return(ReadConsoleA(hFile,
|
return ReadConsoleA(hFile,
|
||||||
lpBuffer,
|
lpBuffer,
|
||||||
nNumberOfBytesToRead,
|
nNumberOfBytesToRead,
|
||||||
lpNumberOfBytesRead,
|
lpNumberOfBytesRead,
|
||||||
NULL));
|
lpOverlapped);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lpOverLapped)
|
if (lpOverlapped != NULL)
|
||||||
{
|
{
|
||||||
Offset.u.LowPart = lpOverLapped->Offset;
|
LARGE_INTEGER Offset;
|
||||||
Offset.u.HighPart = lpOverLapped->OffsetHigh;
|
PVOID ApcContext;
|
||||||
lpOverLapped->Internal = STATUS_PENDING;
|
|
||||||
hEvent = lpOverLapped->hEvent;
|
|
||||||
IoStatusBlock = (PIO_STATUS_BLOCK)lpOverLapped;
|
|
||||||
ptrOffset = &Offset;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ptrOffset = NULL;
|
|
||||||
IoStatusBlock = &IIosb;
|
|
||||||
}
|
|
||||||
|
|
||||||
errCode = NtReadFile(hFile,
|
Offset.u.LowPart = lpOverlapped->Offset;
|
||||||
hEvent,
|
Offset.u.HighPart = lpOverlapped->OffsetHigh;
|
||||||
|
lpOverlapped->Internal = STATUS_PENDING;
|
||||||
|
ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
|
||||||
|
|
||||||
|
Status = NtReadFile(hFile,
|
||||||
|
lpOverlapped->hEvent,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
ApcContext,
|
||||||
IoStatusBlock,
|
(PIO_STATUS_BLOCK)lpOverlapped,
|
||||||
lpBuffer,
|
lpBuffer,
|
||||||
nNumberOfBytesToRead,
|
nNumberOfBytesToRead,
|
||||||
ptrOffset,
|
&Offset,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
/* for non-overlapped io, a end-of-file error is translated to
|
/* return FALSE in case of failure and pending operations! */
|
||||||
a successful operation with zero bytes read */
|
if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
|
||||||
if (!lpOverLapped && errCode == STATUS_END_OF_FILE)
|
{
|
||||||
|
if (Status == STATUS_END_OF_FILE &&
|
||||||
|
lpNumberOfBytesRead != NULL)
|
||||||
{
|
{
|
||||||
/* IoStatusBlock->Information should contain zero in case of an error, but to be safe,
|
|
||||||
set lpNumberOfBytesRead to zero manually instead of using IoStatusBlock->Information */
|
|
||||||
*lpNumberOfBytesRead = 0;
|
*lpNumberOfBytesRead = 0;
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!NT_SUCCESS(errCode) || errCode == STATUS_PENDING)
|
SetLastErrorByStatus(Status);
|
||||||
{
|
|
||||||
SetLastErrorByStatus (errCode);
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lpNumberOfBytesRead != NULL)
|
if (lpNumberOfBytesRead != NULL)
|
||||||
{
|
{
|
||||||
*lpNumberOfBytesRead = IoStatusBlock->Information;
|
*lpNumberOfBytesRead = lpOverlapped->InternalHigh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IO_STATUS_BLOCK Iosb;
|
||||||
|
|
||||||
|
Status = NtReadFile(hFile,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&Iosb,
|
||||||
|
lpBuffer,
|
||||||
|
nNumberOfBytesToRead,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* wait in case operation is pending */
|
||||||
|
if (Status == STATUS_PENDING)
|
||||||
|
{
|
||||||
|
Status = NtWaitForSingleObject(hFile,
|
||||||
|
FALSE,
|
||||||
|
NULL);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
Status = Iosb.Status;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return(TRUE);
|
if (Status == STATUS_END_OF_FILE)
|
||||||
|
{
|
||||||
|
/* lpNumberOfBytesRead must not be NULL here, in fact Win doesn't
|
||||||
|
check that case either and crashes (only after the operation
|
||||||
|
completed) */
|
||||||
|
*lpNumberOfBytesRead = Iosb.Information;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* lpNumberOfBytesRead must not be NULL here, in fact Win doesn't
|
||||||
|
check that case either and crashes (only after the operation
|
||||||
|
completed) */
|
||||||
|
*lpNumberOfBytesRead = Iosb.Information;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetLastErrorByStatus(Status);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINT("ReadFile() succeeded\n");
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID STDCALL
|
VOID STDCALL
|
||||||
|
@ -205,54 +263,36 @@ ApcRoutine(PVOID ApcContext,
|
||||||
* @implemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
BOOL STDCALL
|
BOOL STDCALL
|
||||||
WriteFileEx (HANDLE hFile,
|
WriteFileEx(IN HANDLE hFile,
|
||||||
LPCVOID lpBuffer,
|
IN LPCVOID lpBuffer,
|
||||||
DWORD nNumberOfBytesToWrite,
|
IN DWORD nNumberOfBytesToWrite OPTIONAL,
|
||||||
LPOVERLAPPED lpOverLapped,
|
IN LPOVERLAPPED lpOverlapped,
|
||||||
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
|
IN LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
|
||||||
{
|
{
|
||||||
|
|
||||||
LARGE_INTEGER Offset;
|
LARGE_INTEGER Offset;
|
||||||
NTSTATUS errCode;
|
NTSTATUS Status;
|
||||||
PIO_STATUS_BLOCK IoStatusBlock;
|
|
||||||
PLARGE_INTEGER ptrOffset;
|
|
||||||
|
|
||||||
DPRINT("WriteFileEx(hFile %x)\n",hFile);
|
Offset.u.LowPart = lpOverlapped->Offset;
|
||||||
|
Offset.u.HighPart = lpOverlapped->OffsetHigh;
|
||||||
|
lpOverlapped->Internal = STATUS_PENDING;
|
||||||
|
|
||||||
Offset.u.LowPart = lpOverLapped->Offset;
|
Status = NtWriteFile(hFile,
|
||||||
Offset.u.HighPart = lpOverLapped->OffsetHigh;
|
|
||||||
lpOverLapped->Internal = STATUS_PENDING;
|
|
||||||
IoStatusBlock = (PIO_STATUS_BLOCK)lpOverLapped;
|
|
||||||
ptrOffset = &Offset;
|
|
||||||
|
|
||||||
errCode = NtWriteFile(hFile,
|
|
||||||
NULL,
|
NULL,
|
||||||
ApcRoutine,
|
ApcRoutine,
|
||||||
lpCompletionRoutine,
|
lpCompletionRoutine,
|
||||||
IoStatusBlock,
|
(PIO_STATUS_BLOCK)lpOverlapped,
|
||||||
(PVOID)lpBuffer,
|
(PVOID)lpBuffer,
|
||||||
nNumberOfBytesToWrite,
|
nNumberOfBytesToWrite,
|
||||||
ptrOffset,
|
&Offset,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
if (NT_ERROR(errCode))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
SetLastErrorByStatus (errCode);
|
SetLastErrorByStatus(Status);
|
||||||
DPRINT("WriteFileEx() failed\n");
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NT_WARNING(errCode))
|
return TRUE;
|
||||||
{
|
|
||||||
SetLastErrorByStatus(errCode);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SetLastError(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
DPRINT("WriteFileEx() succeeded\n");
|
|
||||||
return(TRUE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -260,49 +300,36 @@ WriteFileEx (HANDLE hFile,
|
||||||
* @implemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
BOOL STDCALL
|
BOOL STDCALL
|
||||||
ReadFileEx(HANDLE hFile,
|
ReadFileEx(IN HANDLE hFile,
|
||||||
LPVOID lpBuffer,
|
IN LPVOID lpBuffer,
|
||||||
DWORD nNumberOfBytesToRead,
|
IN DWORD nNumberOfBytesToRead OPTIONAL,
|
||||||
LPOVERLAPPED lpOverLapped,
|
IN LPOVERLAPPED lpOverlapped,
|
||||||
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
|
IN LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
|
||||||
{
|
{
|
||||||
LARGE_INTEGER Offset;
|
LARGE_INTEGER Offset;
|
||||||
NTSTATUS errCode;
|
NTSTATUS Status;
|
||||||
PIO_STATUS_BLOCK IoStatusBlock;
|
|
||||||
PLARGE_INTEGER ptrOffset;
|
|
||||||
|
|
||||||
Offset.u.LowPart = lpOverLapped->Offset;
|
Offset.u.LowPart = lpOverlapped->Offset;
|
||||||
Offset.u.HighPart = lpOverLapped->OffsetHigh;
|
Offset.u.HighPart = lpOverlapped->OffsetHigh;
|
||||||
lpOverLapped->Internal = STATUS_PENDING;
|
lpOverlapped->Internal = STATUS_PENDING;
|
||||||
IoStatusBlock = (PIO_STATUS_BLOCK)lpOverLapped;
|
|
||||||
ptrOffset = &Offset;
|
|
||||||
|
|
||||||
errCode = NtReadFile(hFile,
|
Status = NtReadFile(hFile,
|
||||||
NULL,
|
NULL,
|
||||||
ApcRoutine,
|
ApcRoutine,
|
||||||
lpCompletionRoutine,
|
lpCompletionRoutine,
|
||||||
IoStatusBlock,
|
(PIO_STATUS_BLOCK)lpOverlapped,
|
||||||
lpBuffer,
|
lpBuffer,
|
||||||
nNumberOfBytesToRead,
|
nNumberOfBytesToRead,
|
||||||
ptrOffset,
|
&Offset,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
if (NT_ERROR(errCode))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
SetLastErrorByStatus (errCode);
|
SetLastErrorByStatus(Status);
|
||||||
return(FALSE);
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NT_WARNING(errCode))
|
return TRUE;
|
||||||
{
|
|
||||||
SetLastErrorByStatus(errCode);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SetLastError(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return(TRUE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
Loading…
Reference in a new issue