Fix Asynchronous File Errors

Robert Shearman rob at codeweavers.com
Wed Aug 18 19:55:22 CDT 2004


Changelog:
- Errors should only be reported to I/O completion routine after NtReadFile has succeeded.
- Test case for this behaviour.


-------------- next part --------------
Index: wine/dlls/ntdll/file.c
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/file.c,v
retrieving revision 1.63
diff -u -p -r1.63 file.c
--- wine/dlls/ntdll/file.c	18 Aug 2004 20:57:30 -0000	1.63
+++ wine/dlls/ntdll/file.c	19 Aug 2004 00:47:41 -0000
@@ -248,6 +248,7 @@ typedef struct async_fileio
     char                             *buffer;
     unsigned int                     count;
     off_t                            offset;
+    int                              queue_apc_on_error;
     BOOL                             avail_mode;
 } async_fileio;
 
@@ -265,7 +266,8 @@ static void CALLBACK fileio_call_complet
     async_fileio *ovp = (async_fileio*) data;
     TRACE("data: %p\n", ovp);
 
-    ovp->apc( ovp->apc_user, ovp->async.iosb, ovp->async.iosb->Information );
+    if ((ovp->async.iosb->u.Status == STATUS_SUCCESS) || ovp->queue_apc_on_error)
+        ovp->apc( ovp->apc_user, ovp->async.iosb, ovp->async.iosb->Information );
 
     fileio_async_cleanup( &ovp->async );
 }
@@ -464,6 +467,7 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile,
         ovp->apc = apc;
         ovp->apc_user = apc_user;
         ovp->buffer = buffer;
+        ovp->queue_apc_on_error = 0;
         ovp->avail_mode = (flags & FD_FLAG_AVAILABLE);
         NtResetEvent(hEvent, NULL);
 
@@ -477,8 +481,10 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile,
         }
         if (flags & FD_FLAG_TIMEOUT)
         {
-            NtWaitForSingleObject(hEvent, TRUE, NULL);
+            ret = NtWaitForSingleObject(hEvent, TRUE, NULL);
             NtClose(hEvent);
+            if (ret != STATUS_USER_APC)
+                ovp->queue_apc_on_error = 1;
         }
         else
         {
@@ -486,7 +492,14 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile,
 
             /* let some APC be run, this will read some already pending data */
             timeout.u.LowPart = timeout.u.HighPart = 0;
-            NtDelayExecution( TRUE, &timeout );
+            ret = NtDelayExecution( TRUE, &timeout );
+            /* the apc didn't run and therefore the completion routine now
+             * needs to be sent errors.
+             * Note that there is no race between setting this flag and
+             * returning errors because apc's are run only during alertable
+             * waits */
+            if (ret != STATUS_USER_APC)
+                ovp->queue_apc_on_error = 1;
             /* if we only have to read the available data, and none is available,
              * simply cancel the request. If data was available, it has been read
              * while in by previous call (NtDelayExecution)
@@ -497,6 +510,7 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile,
                 register_old_async(&ovp->async);
             }
         }
+        TRACE("= 0x%08lx\n", io_status->u.Status);
         return io_status->u.Status;
     }
 
@@ -522,6 +536,7 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile,
 	break;
     }
     wine_server_release_fd( hFile, unix_handle );
+    TRACE("= 0x%08lx\n", io_status->u.Status);
     return io_status->u.Status;
 }
 
@@ -641,6 +656,7 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile
         ovp->apc = apc;
         ovp->apc_user = apc_user;
         ovp->buffer = (void*)buffer;
+        ovp->queue_apc_on_error = 0;
         ovp->avail_mode = (flags & FD_FLAG_AVAILABLE);
         NtResetEvent(hEvent, NULL);
 
@@ -650,8 +666,10 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile
             return ret;
         if (flags & FD_FLAG_TIMEOUT)
         {
-            NtWaitForSingleObject(hEvent, TRUE, NULL);
+            ret = NtWaitForSingleObject(hEvent, TRUE, NULL);
             NtClose(hEvent);
+            if (ret != STATUS_USER_APC)
+                ovp->queue_apc_on_error = 1;
         }
         else
         {
@@ -659,7 +677,14 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile
 
             /* let some APC be run, this will write as much data as possible */
             timeout.u.LowPart = timeout.u.HighPart = 0;
-            NtDelayExecution( TRUE, &timeout );
+            ret = NtDelayExecution( TRUE, &timeout );
+            /* the apc didn't run and therefore the completion routine now
+             * needs to be sent errors.
+             * Note that there is no race between setting this flag and
+             * returning errors because apc's are run only during alertable
+             * waits */
+            if (ret != STATUS_USER_APC)
+                ovp->queue_apc_on_error = 1;
         }
         return io_status->u.Status;
     }


More information about the wine-patches mailing list