- 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:
Thomas Bluemel 2005-05-06 14:02:45 +00:00
parent c565a223c9
commit 496308ed56

View file

@ -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 */