diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c index 68919490097..981d2a1d380 100644 --- a/dlls/ntdll/directory.c +++ b/dlls/ntdll/directory.c @@ -2324,6 +2324,7 @@ NtNotifyChangeDirectoryFile( HANDLE FileHandle, HANDLE Event, { struct read_changes_info *info; NTSTATUS status; + ULONG_PTR cvalue = ApcRoutine ? 0 : (ULONG_PTR)ApcContext; TRACE("%p %p %p %p %p %p %u %u %d\n", FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, @@ -2356,7 +2357,7 @@ NtNotifyChangeDirectoryFile( HANDLE FileHandle, HANDLE Event, req->async.arg = info; req->async.apc = read_changes_user_apc; req->async.event = Event; - req->async.cvalue = 0; + req->async.cvalue = cvalue; status = wine_server_call( req ); } SERVER_END_REQ; diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index a3a4af16be0..e84bc3d3afd 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -560,6 +560,7 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent, NTSTATUS status; ULONG total = 0; enum server_fd_type type; + ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user; TRACE("(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p),partial stub!\n", hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key); @@ -620,7 +621,7 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent, BOOL avail_mode; if ((status = get_io_avail_mode( hFile, type, &avail_mode ))) - goto done; + goto err; if (total && avail_mode) { status = STATUS_SUCCESS; @@ -630,7 +631,7 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent, if (!(fileio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*fileio)))) { status = STATUS_NO_MEMORY; - goto done; + goto err; } fileio->io.handle = hFile; fileio->io.apc = apc; @@ -650,13 +651,13 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent, req->async.arg = fileio; req->async.apc = fileio_apc; req->async.event = hEvent; - req->async.cvalue = 0; + req->async.cvalue = cvalue; status = wine_server_call( req ); } SERVER_END_REQ; if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, fileio ); - goto done; + goto err; } else /* synchronous read, wait for the fd to become ready */ { @@ -667,7 +668,7 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent, { timeout_init_done = 1; if ((status = get_io_timeouts( hFile, type, length, TRUE, &timeouts ))) - goto done; + goto err; if (hEvent) NtResetEvent( hEvent, NULL ); } timeout = get_next_io_timeout( &timeouts, total ); @@ -693,6 +694,9 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent, } done: + if (cvalue) NTDLL_AddCompletion( hFile, cvalue, status, total ); + +err: if (needs_close) close( unix_handle ); if (status == STATUS_SUCCESS) { @@ -794,6 +798,7 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent, NTSTATUS status; ULONG total = 0; enum server_fd_type type; + ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user; TRACE("(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p)!\n", hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key); @@ -848,8 +853,12 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent, if (errno == EINTR) continue; if (errno != EAGAIN) { - if (errno == EFAULT) status = STATUS_INVALID_USER_BUFFER; - else status = FILE_GetNtStatus(); + if (errno == EFAULT) + { + status = STATUS_INVALID_USER_BUFFER; + goto err; + } + status = FILE_GetNtStatus(); goto done; } } @@ -861,7 +870,7 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent, if (!(fileio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*fileio)))) { status = STATUS_NO_MEMORY; - goto done; + goto err; } fileio->io.handle = hFile; fileio->io.apc = apc; @@ -880,13 +889,13 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent, req->async.arg = fileio; req->async.apc = fileio_apc; req->async.event = hEvent; - req->async.cvalue = 0; + req->async.cvalue = cvalue; status = wine_server_call( req ); } SERVER_END_REQ; if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, fileio ); - goto done; + goto err; } else /* synchronous write, wait for the fd to become ready */ { @@ -897,7 +906,7 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent, { timeout_init_done = 1; if ((status = get_io_timeouts( hFile, type, length, FALSE, &timeouts ))) - goto done; + goto err; if (hEvent) NtResetEvent( hEvent, NULL ); } timeout = get_next_io_timeout( &timeouts, total ); @@ -921,6 +930,9 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent, } done: + if (cvalue) NTDLL_AddCompletion( hFile, cvalue, status, total ); + +err: if (needs_close) close( unix_handle ); if (status == STATUS_SUCCESS) { @@ -989,6 +1001,7 @@ static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event, NTSTATUS status; HANDLE wait_handle; ULONG options; + ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_context; if (!(async = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*async) ))) return STATUS_NO_MEMORY; @@ -1007,7 +1020,7 @@ static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event, req->async.arg = async; req->async.apc = (apc || event) ? ioctl_apc : NULL; req->async.event = event; - req->async.cvalue = 0; + req->async.cvalue = cvalue; wine_server_add_data( req, in_buffer, in_size ); wine_server_set_reply( req, out_buffer, out_size ); if (!(status = wine_server_call( req ))) @@ -2127,6 +2140,8 @@ NTSTATUS WINAPI NtLockFile( HANDLE hFile, HANDLE lock_granted_event, return STATUS_NOT_IMPLEMENTED; } + if (apc_user) FIXME("I/O completion on lock not implemented yet\n"); + for (;;) { SERVER_START_REQ( lock_file ) diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index 405f348139f..c283e1e0437 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -198,4 +198,7 @@ static inline struct ntdll_thread_regs *ntdll_get_thread_regs(void) return (struct ntdll_thread_regs *)NtCurrentTeb()->SpareBytes1; } +/* Completion */ +extern NTSTATUS NTDLL_AddCompletion( HANDLE hFile, ULONG_PTR CompletionValue, NTSTATUS CompletionStatus, ULONG_PTR Information ); + #endif diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index 47c846108a9..ec8aa590328 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -1310,3 +1310,19 @@ NTSTATUS WINAPI NtQueryIoCompletion( HANDLE CompletionPort, IO_COMPLETION_INFORM } return status; } + +NTSTATUS NTDLL_AddCompletion( HANDLE hFile, ULONG_PTR CompletionValue, NTSTATUS CompletionStatus, ULONG_PTR Information ) +{ + NTSTATUS status; + + SERVER_START_REQ( add_fd_completion ) + { + req->handle = hFile; + req->cvalue = CompletionValue; + req->status = CompletionStatus; + req->information = Information; + status = wine_server_call( req ); + } + SERVER_END_REQ; + return status; +} diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index eb3bc8c9919..55927116b93 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -521,15 +521,15 @@ static void test_iocp_fileio(HANDLE h) ok( !count, "Unexpected msg count: %ld\n", count ); WriteFile( hPipeClt, buf, 3, &read, NULL ); - todo_wine { if (get_msg(h)) { ok( completionKey == CKEY_SECOND, "Invalid completion key: %lx\n", completionKey ); + todo_wine { ok( ioSb.Information == 3, "Invalid ioSb.Information: %ld\n", ioSb.Information ); + } ok( U(ioSb).Status == STATUS_SUCCESS, "Invalid ioSb.Status: %x\n", U(ioSb).Status); ok( completionValue == (ULONG_PTR)&o, "Invalid completion value: %lx\n", completionValue ); } - } count = get_pending_msgs(h); ok( !count, "Unexpected msg count: %ld\n", count ); @@ -538,10 +538,7 @@ static void test_iocp_fileio(HANDLE h) ok( !count, "Unexpected msg count: %ld\n", count ); ReadFile( hPipeSrv, buf, 2, &read, &o); count = get_pending_msgs(h); - todo_wine { ok( count == 1, "Unexpected msg count: %ld\n", count ); - } - todo_wine { if (get_msg(h)) { ok( completionKey == CKEY_SECOND, "Invalid completion key: %lx\n", completionKey ); @@ -549,7 +546,6 @@ static void test_iocp_fileio(HANDLE h) ok( U(ioSb).Status == STATUS_SUCCESS, "Invalid ioSb.Status: %x\n", U(ioSb).Status); ok( completionValue == (ULONG_PTR)&o, "Invalid completion value: %lx\n", completionValue ); } - } } CloseHandle( hPipeSrv );