- 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) Modified: trunk/reactos/lib/kernel32/file/rw.c _____
Modified: trunk/reactos/lib/kernel32/file/rw.c --- trunk/reactos/lib/kernel32/file/rw.c 2005-05-06 13:35:27 UTC (rev 15042) +++ trunk/reactos/lib/kernel32/file/rw.c 2005-05-06 14:02:45 UTC (rev 15043) @@ -23,78 +23,104 @@
* @implemented */ BOOL STDCALL -WriteFile(HANDLE hFile, - LPCVOID lpBuffer, - DWORD nNumberOfBytesToWrite, - LPDWORD lpNumberOfBytesWritten, - LPOVERLAPPED lpOverLapped) +WriteFile(IN HANDLE hFile, + IN LPCVOID lpBuffer, + IN DWORD nNumberOfBytesToWrite OPTIONAL, + OUT LPDWORD lpNumberOfBytesWritten OPTIONAL, + IN LPOVERLAPPED lpOverlapped OPTIONAL) { - HANDLE hEvent = NULL; - LARGE_INTEGER Offset; - NTSTATUS errCode; - IO_STATUS_BLOCK IIosb; - PIO_STATUS_BLOCK IoStatusBlock; - PLARGE_INTEGER ptrOffset; + NTSTATUS Status;
- DPRINT("WriteFile(hFile %x)\n",hFile); + DPRINT("WriteFile(hFile %x)\n", hFile);
- if (lpOverLapped == NULL && lpNumberOfBytesWritten == NULL) - { - SetLastError(ERROR_INVALID_PARAMETER); - } + if (lpNumberOfBytesWritten != NULL) + { + *lpNumberOfBytesWritten = 0; + }
- if (lpNumberOfBytesWritten) - { - *lpNumberOfBytesWritten = 0; - } - if (IsConsoleHandle(hFile)) { - return(WriteConsoleA(hFile, - lpBuffer, - nNumberOfBytesToWrite, - lpNumberOfBytesWritten, - NULL)); + return WriteConsoleA(hFile, + lpBuffer, + nNumberOfBytesToWrite, + lpNumberOfBytesWritten, + lpOverlapped); }
- if (lpOverLapped != NULL) + if (lpOverlapped != NULL) { - Offset.u.LowPart = lpOverLapped->Offset; - Offset.u.HighPart = lpOverLapped->OffsetHigh; - lpOverLapped->Internal = STATUS_PENDING; - hEvent = lpOverLapped->hEvent; - IoStatusBlock = (PIO_STATUS_BLOCK)lpOverLapped; - ptrOffset = &Offset; + LARGE_INTEGER Offset; + PVOID ApcContext; + + Offset.u.LowPart = lpOverlapped->Offset; + Offset.u.HighPart = lpOverlapped->OffsetHigh; + lpOverlapped->Internal = STATUS_PENDING; + ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped); + + Status = NtWriteFile(hFile, + lpOverlapped->hEvent, + NULL, + ApcContext, + (PIO_STATUS_BLOCK)lpOverlapped, + (PVOID)lpBuffer, + nNumberOfBytesToWrite, + &Offset, + NULL); + + /* return FALSE in case of failure and pending operations! */ + if (!NT_SUCCESS(Status) || Status == STATUS_PENDING) + { + SetLastErrorByStatus(Status); + return FALSE; + } + + if (lpNumberOfBytesWritten != NULL) + { + *lpNumberOfBytesWritten = lpOverlapped->InternalHigh; + } } else { - ptrOffset = NULL; - IoStatusBlock = &IIosb; + 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; + } } - - errCode = NtWriteFile(hFile, - hEvent, - NULL, - NULL, - IoStatusBlock, - (PVOID)lpBuffer, - nNumberOfBytesToWrite, - ptrOffset, - NULL); - - if (!NT_SUCCESS(errCode) || errCode == STATUS_PENDING) - { - SetLastErrorByStatus (errCode); - return FALSE; - }
- if (lpNumberOfBytesWritten != NULL ) - { - *lpNumberOfBytesWritten = IoStatusBlock->Information; - } - - DPRINT("WriteFile() succeeded\n"); - return(TRUE); + DPRINT("WriteFile() succeeded\n"); + return TRUE; }
@@ -102,87 +128,119 @@ * @implemented */ BOOL STDCALL -ReadFile( - HANDLE hFile, - LPVOID lpBuffer, - DWORD nNumberOfBytesToRead, - LPDWORD lpNumberOfBytesRead, - LPOVERLAPPED lpOverLapped - ) +ReadFile(IN HANDLE hFile, + IN LPVOID lpBuffer, + IN DWORD nNumberOfBytesToRead, + OUT LPDWORD lpNumberOfBytesRead OPTIONAL, + IN LPOVERLAPPED lpOverlapped OPTIONAL) { - HANDLE hEvent = NULL; - LARGE_INTEGER Offset; - NTSTATUS errCode; - IO_STATUS_BLOCK IIosb; - PIO_STATUS_BLOCK IoStatusBlock; - PLARGE_INTEGER ptrOffset; + NTSTATUS Status;
- if (lpOverLapped == NULL && lpNumberOfBytesRead == NULL) - { - SetLastError(ERROR_INVALID_PARAMETER); - } + DPRINT("ReadFile(hFile %x)\n", hFile);
- if (lpNumberOfBytesRead) - { - *lpNumberOfBytesRead = 0; - } - - if (IsConsoleHandle(hFile)) - { - return(ReadConsoleA(hFile, - lpBuffer, - nNumberOfBytesToRead, - lpNumberOfBytesRead, - NULL)); - } - - if (lpOverLapped) - { - Offset.u.LowPart = lpOverLapped->Offset; - Offset.u.HighPart = lpOverLapped->OffsetHigh; - lpOverLapped->Internal = STATUS_PENDING; - hEvent = lpOverLapped->hEvent; - IoStatusBlock = (PIO_STATUS_BLOCK)lpOverLapped; - ptrOffset = &Offset; - } - else - { - ptrOffset = NULL; - IoStatusBlock = &IIosb; - } - - errCode = NtReadFile(hFile, - hEvent, - NULL, - NULL, - IoStatusBlock, - lpBuffer, - nNumberOfBytesToRead, - ptrOffset, - NULL); + if (lpNumberOfBytesRead != NULL) + { + *lpNumberOfBytesRead = 0; + }
- /* for non-overlapped io, a end-of-file error is translated to - a successful operation with zero bytes read */ - if (!lpOverLapped && errCode == STATUS_END_OF_FILE) - { - /* 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; - return TRUE; - } - - if (!NT_SUCCESS(errCode) || errCode == STATUS_PENDING) - { - SetLastErrorByStatus (errCode); - return FALSE; - } + if (IsConsoleHandle(hFile)) + { + return ReadConsoleA(hFile, + lpBuffer, + nNumberOfBytesToRead, + lpNumberOfBytesRead, + lpOverlapped); + }
- if (lpNumberOfBytesRead != NULL) - { - *lpNumberOfBytesRead = IoStatusBlock->Information; - } - - return(TRUE); + if (lpOverlapped != NULL) + { + LARGE_INTEGER Offset; + PVOID ApcContext; + + Offset.u.LowPart = lpOverlapped->Offset; + Offset.u.HighPart = lpOverlapped->OffsetHigh; + lpOverlapped->Internal = STATUS_PENDING; + ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped); + + Status = NtReadFile(hFile, + lpOverlapped->hEvent, + NULL, + ApcContext, + (PIO_STATUS_BLOCK)lpOverlapped, + lpBuffer, + nNumberOfBytesToRead, + &Offset, + NULL); + + /* return FALSE in case of failure and pending operations! */ + if (!NT_SUCCESS(Status) || Status == STATUS_PENDING) + { + if (Status == STATUS_END_OF_FILE && + lpNumberOfBytesRead != NULL) + { + *lpNumberOfBytesRead = 0; + } + + SetLastErrorByStatus(Status); + return FALSE; + } + + if (lpNumberOfBytesRead != NULL) + { + *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; + } + } + + 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 @@ -191,13 +249,13 @@ ULONG Reserved) { DWORD dwErrorCode; - LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine = + LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine = (LPOVERLAPPED_COMPLETION_ROUTINE)ApcContext;
dwErrorCode = RtlNtStatusToDosError(IoStatusBlock->Status); - lpCompletionRoutine(dwErrorCode, - IoStatusBlock->Information, - (LPOVERLAPPED)IoStatusBlock); + lpCompletionRoutine(dwErrorCode, + IoStatusBlock->Information, + (LPOVERLAPPED)IoStatusBlock); }
@@ -205,54 +263,36 @@ * @implemented */ BOOL STDCALL -WriteFileEx (HANDLE hFile, - LPCVOID lpBuffer, - DWORD nNumberOfBytesToWrite, - LPOVERLAPPED lpOverLapped, - LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) +WriteFileEx(IN HANDLE hFile, + IN LPCVOID lpBuffer, + IN DWORD nNumberOfBytesToWrite OPTIONAL, + IN LPOVERLAPPED lpOverlapped, + IN LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) { - LARGE_INTEGER Offset; - NTSTATUS errCode; - 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; - IoStatusBlock = (PIO_STATUS_BLOCK)lpOverLapped; - ptrOffset = &Offset; + NTSTATUS Status;
- errCode = NtWriteFile(hFile, - NULL, - ApcRoutine, - lpCompletionRoutine, - IoStatusBlock, - (PVOID)lpBuffer, - nNumberOfBytesToWrite, - ptrOffset, - NULL); - - if (NT_ERROR(errCode)) + Offset.u.LowPart = lpOverlapped->Offset; + Offset.u.HighPart = lpOverlapped->OffsetHigh; + lpOverlapped->Internal = STATUS_PENDING; + + Status = NtWriteFile(hFile, + NULL, + ApcRoutine, + lpCompletionRoutine, + (PIO_STATUS_BLOCK)lpOverlapped, + (PVOID)lpBuffer, + nNumberOfBytesToWrite, + &Offset, + NULL); + + if (!NT_SUCCESS(Status)) { - SetLastErrorByStatus (errCode); - DPRINT("WriteFileEx() failed\n"); + SetLastErrorByStatus(Status); return FALSE; } - - if (NT_WARNING(errCode)) - { - SetLastErrorByStatus(errCode); - } - else - { - SetLastError(0); - } - - DPRINT("WriteFileEx() succeeded\n"); - return(TRUE); + + return TRUE; }
@@ -260,49 +300,36 @@ * @implemented */ BOOL STDCALL -ReadFileEx(HANDLE hFile, - LPVOID lpBuffer, - DWORD nNumberOfBytesToRead, - LPOVERLAPPED lpOverLapped, - LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) +ReadFileEx(IN HANDLE hFile, + IN LPVOID lpBuffer, + IN DWORD nNumberOfBytesToRead OPTIONAL, + IN LPOVERLAPPED lpOverlapped, + IN LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) { LARGE_INTEGER Offset; - NTSTATUS errCode; - PIO_STATUS_BLOCK IoStatusBlock; - PLARGE_INTEGER ptrOffset; + NTSTATUS Status;
- Offset.u.LowPart = lpOverLapped->Offset; - Offset.u.HighPart = lpOverLapped->OffsetHigh; - lpOverLapped->Internal = STATUS_PENDING; - IoStatusBlock = (PIO_STATUS_BLOCK)lpOverLapped; - ptrOffset = &Offset; + Offset.u.LowPart = lpOverlapped->Offset; + Offset.u.HighPart = lpOverlapped->OffsetHigh; + lpOverlapped->Internal = STATUS_PENDING;
- errCode = NtReadFile(hFile, - NULL, - ApcRoutine, - lpCompletionRoutine, - IoStatusBlock, - lpBuffer, - nNumberOfBytesToRead, - ptrOffset, - NULL); + Status = NtReadFile(hFile, + NULL, + ApcRoutine, + lpCompletionRoutine, + (PIO_STATUS_BLOCK)lpOverlapped, + lpBuffer, + nNumberOfBytesToRead, + &Offset, + NULL);
- if (NT_ERROR(errCode)) + if (!NT_SUCCESS(Status)) { - SetLastErrorByStatus (errCode); - return(FALSE); + SetLastErrorByStatus(Status); + return FALSE; }
- if (NT_WARNING(errCode)) - { - SetLastErrorByStatus(errCode); - } - else - { - SetLastError(0); - } - - return(TRUE); + return TRUE; }
/* EOF */