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