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