Signed-off-by: Daniel Lehman dlehman25@gmail.com
-- v5: kernelbase: Call NtCancelSynchronousIoFile in CancelSynchronousIo. ntdll: Implement NtCancelSynchronousIoFile. ntdll: Add NtCancelSynchronousIoFile stub. kernel32/tests: Add tests for CancelSynchronousIo.
From: Daniel Lehman dlehman25@gmail.com
Signed-off-by: Daniel Lehman dlehman25@gmail.com --- dlls/kernel32/tests/pipe.c | 105 +++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+)
diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c index 7fa3c313d47..55890cc9172 100644 --- a/dlls/kernel32/tests/pipe.c +++ b/dlls/kernel32/tests/pipe.c @@ -37,6 +37,7 @@ static HANDLE alarm_event; static BOOL (WINAPI *pDuplicateTokenEx)(HANDLE,DWORD,LPSECURITY_ATTRIBUTES, SECURITY_IMPERSONATION_LEVEL,TOKEN_TYPE,PHANDLE); static BOOL (WINAPI *pCancelIoEx)(HANDLE handle, LPOVERLAPPED lpOverlapped); +static BOOL (WINAPI *pCancelSynchronousIo)(HANDLE handle); static BOOL (WINAPI *pGetNamedPipeClientProcessId)(HANDLE,ULONG*); static BOOL (WINAPI *pGetNamedPipeServerProcessId)(HANDLE,ULONG*); static BOOL (WINAPI *pGetNamedPipeClientSessionId)(HANDLE,ULONG*); @@ -4202,6 +4203,108 @@ static void test_exit_process_async(void) CloseHandle(server); }
+static DWORD CALLBACK synchronousIoThreadMain(void *arg) +{ + HANDLE pipe; + BOOL ret; + + pipe = arg; + SetLastError(0xdeadbeef); + ret = ConnectNamedPipe(pipe, NULL); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_OPERATION_ABORTED, "got error %lu\n", GetLastError()); + return 0; +} + +static DWORD CALLBACK synchronousIoThreadMain2(void *arg) +{ + OVERLAPPED ov; + HANDLE pipe; + BOOL ret; + + pipe = arg; + memset(&ov, 0, sizeof(ov)); + ov.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + SetLastError(0xdeadbeef); + ret = ConnectNamedPipe(pipe, &ov); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_IO_PENDING, "got error %lu\n", GetLastError()); + ret = WaitForSingleObject(ov.hEvent, 1000); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", ret); + CloseHandle(ov.hEvent); + return 0; +} + +static void test_CancelSynchronousIo(void) +{ + BOOL res; + DWORD wait; + HANDLE file; + HANDLE pipe; + HANDLE thread; + + /* bogus values */ + SetLastError(0xdeadbeef); + res = pCancelSynchronousIo((HANDLE)0xdeadbeef); + ok(!res, "CancelSynchronousIo succeeded unexpectedly\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_HANDLE, + "In CancelSynchronousIo failure, expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError()); + + SetLastError(0xdeadbeef); + res = pCancelSynchronousIo(GetCurrentThread()); + ok(!res, "CancelSynchronousIo succeeded unexpectedly\n"); + todo_wine + ok(GetLastError() == ERROR_NOT_FOUND, + "In CancelSynchronousIo failure, expected ERROR_NOT_FOUND, got %ld\n", GetLastError()); + + /* synchronous i/o */ + pipe = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + 1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL); + ok(pipe != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with %lu\n", GetLastError()); + thread = CreateThread(NULL, 0, synchronousIoThreadMain, pipe, 0, NULL); + /* wait for I/O to start, which transitions the pipe handle from signaled to nonsignaled state. */ + while ((wait = WaitForSingleObject(pipe, 0)) == WAIT_OBJECT_0) Sleep(1); + ok(wait == WAIT_TIMEOUT, "WaitForSingleObject returned %lu (error %lu)\n", wait, GetLastError()); + SetLastError(0xdeadbeef); + res = pCancelSynchronousIo(thread); + todo_wine + { + ok(res, "CancelSynchronousIo failed with error %ld\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, + "In CancelSynchronousIo failure, expected 0xdeadbeef got %ld\n", GetLastError()); + } + if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + CancelIoEx(pipe, NULL); + wait = WaitForSingleObject(thread, 1000); + ok(wait == WAIT_OBJECT_0, "WaitForSingleObject returned %lx\n", wait); + CloseHandle(thread); + CloseHandle(pipe); + + /* asynchronous i/o */ + pipe = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + 1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL); + ok(pipe != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with %lu\n", GetLastError()); + thread = CreateThread(NULL, 0, synchronousIoThreadMain2, pipe, 0, NULL); + /* wait for I/O to start, which transitions the pipe handle from signaled to nonsignaled state. */ + while ((wait = WaitForSingleObject(pipe, 0)) == WAIT_OBJECT_0) Sleep(1); + ok(wait == WAIT_TIMEOUT, "WaitForSingleObject returned %lu (error %lu)\n", wait, GetLastError()); + SetLastError(0xdeadbeef); + res = pCancelSynchronousIo(thread); + ok(!res, "CancelSynchronousIo succeeded unexpectedly\n"); + todo_wine + ok(GetLastError() == ERROR_NOT_FOUND, + "In CancelSynchronousIo failure, expected ERROR_NOT_FOUND, got %ld\n", GetLastError()); + file = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "CreateFile failed (%ld)\n", GetLastError()); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + CloseHandle(file); + CloseHandle(pipe); +} + START_TEST(pipe) { char **argv; @@ -4212,6 +4315,7 @@ START_TEST(pipe) pDuplicateTokenEx = (void *) GetProcAddress(hmod, "DuplicateTokenEx"); hmod = GetModuleHandleA("kernel32.dll"); pCancelIoEx = (void *) GetProcAddress(hmod, "CancelIoEx"); + pCancelSynchronousIo = (void *) GetProcAddress(hmod, "CancelSynchronousIo"); pGetNamedPipeClientProcessId = (void *) GetProcAddress(hmod, "GetNamedPipeClientProcessId"); pGetNamedPipeServerProcessId = (void *) GetProcAddress(hmod, "GetNamedPipeServerProcessId"); pGetNamedPipeClientSessionId = (void *) GetProcAddress(hmod, "GetNamedPipeClientSessionId"); @@ -4282,4 +4386,5 @@ START_TEST(pipe) test_nowait(PIPE_TYPE_MESSAGE); test_GetOverlappedResultEx(); test_exit_process_async(); + test_CancelSynchronousIo(); }
From: Daniel Lehman dlehman25@gmail.com
Signed-off-by: Daniel Lehman dlehman25@gmail.com --- dlls/ntdll/ntdll.spec | 2 + dlls/ntdll/tests/pipe.c | 154 +++++++++++++++++++++++++++++++++++++++ dlls/ntdll/unix/file.c | 9 +++ dlls/ntdll/unix/loader.c | 1 + dlls/wow64/file.c | 18 +++++ dlls/wow64/syscall.h | 1 + include/winternl.h | 1 + 7 files changed, 186 insertions(+)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 244f9acd2ab..2432307e686 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -153,6 +153,7 @@ # @ stub NtCancelDeviceWakeupRequest @ stdcall -syscall NtCancelIoFile(long ptr) @ stdcall -syscall NtCancelIoFileEx(long ptr ptr) +@ stdcall -syscall NtCancelSynchronousIoFile(long ptr ptr) @ stdcall -syscall NtCancelTimer(long ptr) @ stdcall -syscall NtClearEvent(long) @ stdcall -syscall NtClose(long) @@ -1186,6 +1187,7 @@ # @ stub ZwCancelDeviceWakeupRequest @ stdcall -private -syscall ZwCancelIoFile(long ptr) NtCancelIoFile @ stdcall -private -syscall ZwCancelIoFileEx(long ptr ptr) NtCancelIoFileEx +@ stdcall -private -syscall ZwCancelSynchronousIoFile(long ptr ptr) NtCancelSynchronousIoFile @ stdcall -private -syscall ZwCancelTimer(long ptr) NtCancelTimer @ stdcall -private -syscall ZwClearEvent(long) NtClearEvent @ stdcall -private -syscall ZwClose(long) NtClose diff --git a/dlls/ntdll/tests/pipe.c b/dlls/ntdll/tests/pipe.c index 0ad09daaa82..2a044f6acea 100644 --- a/dlls/ntdll/tests/pipe.c +++ b/dlls/ntdll/tests/pipe.c @@ -75,6 +75,9 @@ typedef struct _FILE_PIPE_WAIT_FOR_BUFFER { #endif #endif
+static BOOL is_wow64; +static BOOL (WINAPI *pIsWow64Process)(HANDLE, BOOL *); + static NTSTATUS (WINAPI *pNtFsControlFile) (HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, PVOID apc_context, PIO_STATUS_BLOCK io, ULONG code, PVOID in_buffer, ULONG in_size, PVOID out_buffer, ULONG out_size); static NTSTATUS (WINAPI *pNtCreateDirectoryObject)(HANDLE *, ACCESS_MASK, OBJECT_ATTRIBUTES *); static NTSTATUS (WINAPI *pNtCreateNamedPipeFile) (PHANDLE handle, ULONG access, @@ -90,6 +93,7 @@ static NTSTATUS (WINAPI *pNtQueryVolumeInformationFile)(HANDLE handle, PIO_STATU static NTSTATUS (WINAPI *pNtSetInformationFile) (HANDLE handle, PIO_STATUS_BLOCK io, PVOID ptr, ULONG len, FILE_INFORMATION_CLASS class); static NTSTATUS (WINAPI *pNtCancelIoFile) (HANDLE hFile, PIO_STATUS_BLOCK io_status); static NTSTATUS (WINAPI *pNtCancelIoFileEx) (HANDLE hFile, IO_STATUS_BLOCK *iosb, IO_STATUS_BLOCK *io_status); +static NTSTATUS (WINAPI *pNtCancelSynchronousIoFile) (HANDLE hFile, IO_STATUS_BLOCK *iosb, IO_STATUS_BLOCK *io_status); static NTSTATUS (WINAPI *pNtRemoveIoCompletion)(HANDLE, PULONG_PTR, PULONG_PTR, PIO_STATUS_BLOCK, PLARGE_INTEGER); static void (WINAPI *pRtlInitUnicodeString) (PUNICODE_STRING target, PCWSTR source);
@@ -114,6 +118,7 @@ static BOOL init_func_ptrs(void) loadfunc(NtQueryVolumeInformationFile) loadfunc(NtSetInformationFile) loadfunc(NtCancelIoFile) + loadfunc(NtCancelSynchronousIoFile) loadfunc(RtlInitUnicodeString) loadfunc(NtRemoveIoCompletion)
@@ -122,6 +127,7 @@ static BOOL init_func_ptrs(void) module = GetModuleHandleA("kernel32.dll"); pOpenThread = (void *)GetProcAddress(module, "OpenThread"); pQueueUserAPC = (void *)GetProcAddress(module, "QueueUserAPC"); + pIsWow64Process = (void *)GetProcAddress(module, "IsWow64Process"); return TRUE; }
@@ -615,6 +621,149 @@ static void test_cancelio(void) CloseHandle(hEvent); }
+struct synchronousio_thread_args +{ + HANDLE pipe; + IO_STATUS_BLOCK iosb; +}; + +static DWORD WINAPI synchronousio_thread(void *arg) +{ + struct synchronousio_thread_args *ctx = arg; + NTSTATUS res; + + res = listen_pipe(ctx->pipe, NULL, &ctx->iosb, FALSE); + ok(res == STATUS_CANCELLED, "NtFsControlFile returned %lx\n", res); + return 0; +} + +static void test_cancelsynchronousio(void) +{ + DWORD ret; + NTSTATUS res; + HANDLE event; + HANDLE thread; + HANDLE client; + IO_STATUS_BLOCK iosb; + struct synchronousio_thread_args ctx; + + /* bogus values */ + todo_wine { + res = pNtCancelSynchronousIoFile((HANDLE)0xdeadbeef, NULL, &iosb); + ok(res == STATUS_INVALID_HANDLE, "NtCancelSynchronousIoFile returned %lx\n", res); + res = pNtCancelSynchronousIoFile(GetCurrentThread(), NULL, NULL); + ok(res == STATUS_ACCESS_VIOLATION, "NtCancelSynchronousIoFile returned %lx\n", res); + res = pNtCancelSynchronousIoFile(GetCurrentThread(), NULL, (IO_STATUS_BLOCK*)0xdeadbeef); + ok(res == STATUS_ACCESS_VIOLATION, "NtCancelSynchronousIoFile returned %lx\n", res); + memset(&iosb, 0x55, sizeof(iosb)); + res = pNtCancelSynchronousIoFile(GetCurrentThread(), (IO_STATUS_BLOCK*)0xdeadbeef, &iosb); + ok(res == STATUS_NOT_FOUND || broken(is_wow64 && res == STATUS_ACCESS_VIOLATION), + "NtCancelSynchronousIoFile returned %lx\n", res); + if (res != STATUS_ACCESS_VIOLATION) + { + ok(U(iosb).Status == STATUS_NOT_FOUND, "iosb.Status got changed to %lx\n", U(iosb).Status); + ok(U(iosb).Information == 0, "iosb.Information got changed to %Iu\n", U(iosb).Information); + } + } + + /* synchronous i/o */ + res = create_pipe(&ctx.pipe, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT); + ok(!res, "NtCreateNamedPipeFile returned %lx\n", res); + + /* NULL io */ + U(ctx.iosb).Status = 0xdeadbabe; + ctx.iosb.Information = 0xdeadbeef; + thread = CreateThread(NULL, 0, synchronousio_thread, &ctx, 0, 0); + /* wait for I/O to start, which transitions the pipe handle from signaled to nonsignaled state. */ + while ((ret = WaitForSingleObject(ctx.pipe, 0)) == WAIT_OBJECT_0) Sleep(1); + ok(ret == WAIT_TIMEOUT, "WaitForSingleObject returned %lu (error %lu)\n", ret, GetLastError()); + memset(&iosb, 0x55, sizeof(iosb)); + res = pNtCancelSynchronousIoFile(thread, NULL, &iosb); + todo_wine { + ok(res == STATUS_SUCCESS, "Failed to cancel I/O\n"); + ok(U(iosb).Status == STATUS_SUCCESS, "iosb.Status got changed to %lx\n", U(iosb).Status); + ok(U(iosb).Information == 0, "iosb.Information got changed to %Iu\n", U(iosb).Information); + } + if (res == STATUS_NOT_IMPLEMENTED) + pNtCancelIoFileEx(ctx.pipe, NULL, &iosb); + ret = WaitForSingleObject(thread, 1000); + ok(ret == WAIT_OBJECT_0, "wait returned %lx\n", ret); + CloseHandle(thread); + CloseHandle(ctx.pipe); + ok(U(ctx.iosb).Status == 0xdeadbabe, "wrong status %lx\n", U(ctx.iosb).Status); + ok(ctx.iosb.Information == 0xdeadbeef, "wrong info %Iu\n", ctx.iosb.Information); + + /* specified io */ + res = create_pipe(&ctx.pipe, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT); + ok(!res, "NtCreateNamedPipeFile returned %lx\n", res); + + U(ctx.iosb).Status = 0xdeadbabe; + ctx.iosb.Information = 0xdeadbeef; + thread = CreateThread(NULL, 0, synchronousio_thread, &ctx, 0, 0); + /* wait for I/O to start, which transitions the pipe handle from signaled to nonsignaled state. */ + while ((ret = WaitForSingleObject(ctx.pipe, 0)) == WAIT_OBJECT_0) Sleep(1); + ok(ret == WAIT_TIMEOUT, "WaitForSingleObject returned %lu (error %lu)\n", ret, GetLastError()); + memset(&iosb, 0x55, sizeof(iosb)); + res = pNtCancelSynchronousIoFile(thread, &iosb, &iosb); + todo_wine { + ok(res == STATUS_NOT_FOUND, "NtCancelSynchronousIoFile returned %lx\n", res); + res = pNtCancelSynchronousIoFile(NULL, &ctx.iosb, &iosb); + ok(res == STATUS_INVALID_HANDLE, "NtCancelSynchronousIoFile returned %lx\n", res); + res = pNtCancelSynchronousIoFile(thread, &ctx.iosb, &iosb); + ok(res == STATUS_SUCCESS || broken(is_wow64 && res == STATUS_NOT_FOUND), + "Failed to cancel I/O\n"); + ok(U(iosb).Status == STATUS_SUCCESS || broken(is_wow64 && U(iosb).Status == STATUS_NOT_FOUND), + "iosb.Status got changed to %lx\n", U(iosb).Status); + ok(U(iosb).Information == 0, "iosb.Information got changed to %Iu\n", U(iosb).Information); + } + if (res == STATUS_NOT_FOUND) + { + res = pNtCancelSynchronousIoFile(thread, NULL, &iosb); + ok(res == STATUS_SUCCESS, "Failed to cancel I/O\n"); + ok(U(iosb).Status == STATUS_SUCCESS, "iosb.Status got changed to %lx\n", U(iosb).Status); + } + if (res == STATUS_NOT_IMPLEMENTED) + pNtCancelIoFileEx(ctx.pipe, NULL, &iosb); + ret = WaitForSingleObject(thread, 1000); + ok(ret == WAIT_OBJECT_0, "wait returned %lx\n", ret); + CloseHandle(thread); + CloseHandle(ctx.pipe); + ok(U(ctx.iosb).Status == 0xdeadbabe, "wrong status %lx\n", U(ctx.iosb).Status); + ok(ctx.iosb.Information == 0xdeadbeef, "wrong info %Iu\n", ctx.iosb.Information); + + /* asynchronous i/o */ + U(ctx.iosb).Status = 0xdeadbabe; + ctx.iosb.Information = 0xdeadbeef; + res = create_pipe(&ctx.pipe, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */); + ok(!res, "NtCreateNamedPipeFile returned %lx\n", res); + event = CreateEventW(NULL, TRUE, FALSE, NULL); + ok(event != INVALID_HANDLE_VALUE, "Can't create event, GetLastError: %lx\n", GetLastError()); + res = listen_pipe(ctx.pipe, event, &ctx.iosb, FALSE); + ok(res == STATUS_PENDING, "NtFsControlFile returned %lx\n", res); + memset(&iosb, 0x55, sizeof(iosb)); + res = pNtCancelSynchronousIoFile(GetCurrentThread(), NULL, &iosb); + todo_wine { + ok(res == STATUS_NOT_FOUND, "NtCancelSynchronousIoFile returned %lx\n", res); + ok(U(iosb).Status == STATUS_NOT_FOUND, "iosb.Status got changed to %lx\n", U(iosb).Status); + ok(U(iosb).Information == 0, "iosb.Information got changed to %Iu\n", U(iosb).Information); + memset(&iosb, 0x55, sizeof(iosb)); + res = pNtCancelSynchronousIoFile(GetCurrentThread(), &ctx.iosb, &iosb); + ok(res == STATUS_NOT_FOUND, "NtCancelSynchronousIoFile returned %lx\n", res); + ok(U(iosb).Status == STATUS_NOT_FOUND, "iosb.Status got changed to %lx\n", U(iosb).Status); + ok(U(iosb).Information == 0, "iosb.Information got changed to %Iu\n", U(iosb).Information); + } + ret = WaitForSingleObject(event, 0); + ok(ret == WAIT_TIMEOUT, "wait returned %lx\n", ret); + client = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, 0); + ok(client != INVALID_HANDLE_VALUE, "can't open pipe: %lu\n", GetLastError()); + ret = WaitForSingleObject(event, 0); + ok(ret == WAIT_OBJECT_0, "wait returned %lx\n", ret); + CloseHandle(ctx.pipe); + CloseHandle(event); + CloseHandle(client); +} + static void _check_pipe_handle_state(int line, HANDLE handle, ULONG read, ULONG completion) { IO_STATUS_BLOCK iosb; @@ -2663,6 +2812,8 @@ START_TEST(pipe) if (!init_func_ptrs()) return;
+ if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE; + trace("starting invalid create tests\n"); test_create_invalid();
@@ -2694,6 +2845,9 @@ START_TEST(pipe) trace("starting cancelio tests\n"); test_cancelio();
+ trace("starting cancelsynchronousio tests\n"); + test_cancelsynchronousio(); + trace("starting byte read in byte mode client -> server\n"); read_pipe_test(PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE); trace("starting byte read in message mode client -> server\n"); diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 7eb8dbe7ad4..269f96c6ea8 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -6028,6 +6028,15 @@ NTSTATUS WINAPI NtCancelIoFileEx( HANDLE handle, IO_STATUS_BLOCK *io, IO_STATUS_ }
+/************************************************************************** + * NtCancelSynchronousIoFile (NTDLL.@) + */ +NTSTATUS WINAPI NtCancelSynchronousIoFile( HANDLE handle, IO_STATUS_BLOCK *io, IO_STATUS_BLOCK *io_status ) +{ + FIXME( "(%p,%p,%p) stub\n", handle, io, io_status ); + return STATUS_NOT_IMPLEMENTED; +} + /****************************************************************** * NtLockFile (NTDLL.@) */ diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index b78efddee1f..c21d32ea811 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -139,6 +139,7 @@ static void * const syscalls[] = NtCallbackReturn, NtCancelIoFile, NtCancelIoFileEx, + NtCancelSynchronousIoFile, NtCancelTimer, NtClearEvent, NtClose, diff --git a/dlls/wow64/file.c b/dlls/wow64/file.c index 7d1c736e48c..ebe0e9b3a77 100644 --- a/dlls/wow64/file.c +++ b/dlls/wow64/file.c @@ -227,6 +227,24 @@ NTSTATUS WINAPI wow64_NtCancelIoFileEx( UINT *args ) }
+/********************************************************************** + * wow64_NtCancelSynchronousIoFile + */ +NTSTATUS WINAPI wow64_NtCancelSynchronousIoFile( UINT *args ) +{ + HANDLE handle = get_handle( &args ); + IO_STATUS_BLOCK32 *io_ptr = get_ptr( &args ); + IO_STATUS_BLOCK32 *io32 = get_ptr( &args ); + + IO_STATUS_BLOCK io; + NTSTATUS status; + + status = NtCancelSynchronousIoFile( handle, (IO_STATUS_BLOCK *)io_ptr, iosb_32to64( &io, io32 )); + put_iosb( io32, &io ); + return status; +} + + /********************************************************************** * wow64_NtCreateFile */ diff --git a/dlls/wow64/syscall.h b/dlls/wow64/syscall.h index b2b1ad6c2a8..935d2bc7fce 100644 --- a/dlls/wow64/syscall.h +++ b/dlls/wow64/syscall.h @@ -40,6 +40,7 @@ SYSCALL_ENTRY( NtCallbackReturn ) \ SYSCALL_ENTRY( NtCancelIoFile ) \ SYSCALL_ENTRY( NtCancelIoFileEx ) \ + SYSCALL_ENTRY( NtCancelSynchronousIoFile ) \ SYSCALL_ENTRY( NtCancelTimer ) \ SYSCALL_ENTRY( NtClearEvent ) \ SYSCALL_ENTRY( NtClose ) \ diff --git a/include/winternl.h b/include/winternl.h index beb0cb7aa05..fea26bf26c6 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -3948,6 +3948,7 @@ NTSYSAPI NTSTATUS WINAPI NtAssignProcessToJobObject(HANDLE,HANDLE); NTSYSAPI NTSTATUS WINAPI NtCallbackReturn(PVOID,ULONG,NTSTATUS); NTSYSAPI NTSTATUS WINAPI NtCancelIoFile(HANDLE,PIO_STATUS_BLOCK); NTSYSAPI NTSTATUS WINAPI NtCancelIoFileEx(HANDLE,PIO_STATUS_BLOCK,PIO_STATUS_BLOCK); +NTSYSAPI NTSTATUS WINAPI NtCancelSynchronousIoFile(HANDLE,PIO_STATUS_BLOCK,PIO_STATUS_BLOCK); NTSYSAPI NTSTATUS WINAPI NtCancelTimer(HANDLE, BOOLEAN*); NTSYSAPI NTSTATUS WINAPI NtClearEvent(HANDLE); NTSYSAPI NTSTATUS WINAPI NtClose(HANDLE);
From: Daniel Lehman dlehman25@gmail.com
Signed-off-by: Daniel Lehman dlehman25@gmail.com --- dlls/ntdll/tests/pipe.c | 12 ------------ dlls/ntdll/unix/file.c | 17 +++++++++++++++-- server/async.c | 34 ++++++++++++++++++++++++++++++++++ server/protocol.def | 5 +++++ 4 files changed, 54 insertions(+), 14 deletions(-)
diff --git a/dlls/ntdll/tests/pipe.c b/dlls/ntdll/tests/pipe.c index 2a044f6acea..569de22b013 100644 --- a/dlls/ntdll/tests/pipe.c +++ b/dlls/ntdll/tests/pipe.c @@ -648,7 +648,6 @@ static void test_cancelsynchronousio(void) struct synchronousio_thread_args ctx;
/* bogus values */ - todo_wine { res = pNtCancelSynchronousIoFile((HANDLE)0xdeadbeef, NULL, &iosb); ok(res == STATUS_INVALID_HANDLE, "NtCancelSynchronousIoFile returned %lx\n", res); res = pNtCancelSynchronousIoFile(GetCurrentThread(), NULL, NULL); @@ -664,7 +663,6 @@ static void test_cancelsynchronousio(void) ok(U(iosb).Status == STATUS_NOT_FOUND, "iosb.Status got changed to %lx\n", U(iosb).Status); ok(U(iosb).Information == 0, "iosb.Information got changed to %Iu\n", U(iosb).Information); } - }
/* synchronous i/o */ res = create_pipe(&ctx.pipe, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT); @@ -679,13 +677,9 @@ static void test_cancelsynchronousio(void) ok(ret == WAIT_TIMEOUT, "WaitForSingleObject returned %lu (error %lu)\n", ret, GetLastError()); memset(&iosb, 0x55, sizeof(iosb)); res = pNtCancelSynchronousIoFile(thread, NULL, &iosb); - todo_wine { ok(res == STATUS_SUCCESS, "Failed to cancel I/O\n"); ok(U(iosb).Status == STATUS_SUCCESS, "iosb.Status got changed to %lx\n", U(iosb).Status); ok(U(iosb).Information == 0, "iosb.Information got changed to %Iu\n", U(iosb).Information); - } - if (res == STATUS_NOT_IMPLEMENTED) - pNtCancelIoFileEx(ctx.pipe, NULL, &iosb); ret = WaitForSingleObject(thread, 1000); ok(ret == WAIT_OBJECT_0, "wait returned %lx\n", ret); CloseHandle(thread); @@ -705,7 +699,6 @@ static void test_cancelsynchronousio(void) ok(ret == WAIT_TIMEOUT, "WaitForSingleObject returned %lu (error %lu)\n", ret, GetLastError()); memset(&iosb, 0x55, sizeof(iosb)); res = pNtCancelSynchronousIoFile(thread, &iosb, &iosb); - todo_wine { ok(res == STATUS_NOT_FOUND, "NtCancelSynchronousIoFile returned %lx\n", res); res = pNtCancelSynchronousIoFile(NULL, &ctx.iosb, &iosb); ok(res == STATUS_INVALID_HANDLE, "NtCancelSynchronousIoFile returned %lx\n", res); @@ -715,15 +708,12 @@ static void test_cancelsynchronousio(void) ok(U(iosb).Status == STATUS_SUCCESS || broken(is_wow64 && U(iosb).Status == STATUS_NOT_FOUND), "iosb.Status got changed to %lx\n", U(iosb).Status); ok(U(iosb).Information == 0, "iosb.Information got changed to %Iu\n", U(iosb).Information); - } if (res == STATUS_NOT_FOUND) { res = pNtCancelSynchronousIoFile(thread, NULL, &iosb); ok(res == STATUS_SUCCESS, "Failed to cancel I/O\n"); ok(U(iosb).Status == STATUS_SUCCESS, "iosb.Status got changed to %lx\n", U(iosb).Status); } - if (res == STATUS_NOT_IMPLEMENTED) - pNtCancelIoFileEx(ctx.pipe, NULL, &iosb); ret = WaitForSingleObject(thread, 1000); ok(ret == WAIT_OBJECT_0, "wait returned %lx\n", ret); CloseHandle(thread); @@ -742,7 +732,6 @@ static void test_cancelsynchronousio(void) ok(res == STATUS_PENDING, "NtFsControlFile returned %lx\n", res); memset(&iosb, 0x55, sizeof(iosb)); res = pNtCancelSynchronousIoFile(GetCurrentThread(), NULL, &iosb); - todo_wine { ok(res == STATUS_NOT_FOUND, "NtCancelSynchronousIoFile returned %lx\n", res); ok(U(iosb).Status == STATUS_NOT_FOUND, "iosb.Status got changed to %lx\n", U(iosb).Status); ok(U(iosb).Information == 0, "iosb.Information got changed to %Iu\n", U(iosb).Information); @@ -751,7 +740,6 @@ static void test_cancelsynchronousio(void) ok(res == STATUS_NOT_FOUND, "NtCancelSynchronousIoFile returned %lx\n", res); ok(U(iosb).Status == STATUS_NOT_FOUND, "iosb.Status got changed to %lx\n", U(iosb).Status); ok(U(iosb).Information == 0, "iosb.Information got changed to %Iu\n", U(iosb).Information); - } ret = WaitForSingleObject(event, 0); ok(ret == WAIT_TIMEOUT, "wait returned %lx\n", ret); client = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 269f96c6ea8..e499c27c067 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -6033,8 +6033,21 @@ NTSTATUS WINAPI NtCancelIoFileEx( HANDLE handle, IO_STATUS_BLOCK *io, IO_STATUS_ */ NTSTATUS WINAPI NtCancelSynchronousIoFile( HANDLE handle, IO_STATUS_BLOCK *io, IO_STATUS_BLOCK *io_status ) { - FIXME( "(%p,%p,%p) stub\n", handle, io, io_status ); - return STATUS_NOT_IMPLEMENTED; + NTSTATUS status; + + TRACE( "(%p %p %p)\n", handle, io, io_status ); + + SERVER_START_REQ( cancel_sync ) + { + req->handle = wine_server_obj_handle( handle ); + req->iosb = wine_server_client_ptr( io ); + status = wine_server_call( req ); + } + SERVER_END_REQ; + + io_status->u.Status = status; + io_status->Information = 0; + return status; }
/****************************************************************** diff --git a/server/async.c b/server/async.c index 4832d69b7bf..26946b5f5ce 100644 --- a/server/async.c +++ b/server/async.c @@ -588,6 +588,27 @@ restart: return woken; }
+static int cancel_blocking( struct process *process, struct thread *thread, client_ptr_t iosb ) +{ + struct async *async; + int woken = 0; + +restart: + LIST_FOR_EACH_ENTRY( async, &process->asyncs, struct async, process_entry ) + { + if (async->terminated || async->canceled) continue; + if (async->blocking && async->thread == thread && + (!iosb || async->data.iosb == iosb)) + { + async->canceled = 1; + fd_cancel_async( async->fd, async ); + woken++; + goto restart; + } + } + return woken; +} + void cancel_process_asyncs( struct process *process ) { cancel_async( process, NULL, NULL, 0 ); @@ -731,6 +752,19 @@ struct async *find_pending_async( struct async_queue *queue ) return NULL; }
+/* cancels sync I/O on a thread */ +DECL_HANDLER(cancel_sync) +{ + struct thread *thread = get_thread_from_handle( req->handle, THREAD_TERMINATE ); + + if (thread) + { + if (!cancel_blocking( current->process, thread, req->iosb )) + set_error( STATUS_NOT_FOUND ); + release_object( thread ); + } +} + /* cancels all async I/O */ DECL_HANDLER(cancel_async) { diff --git a/server/protocol.def b/server/protocol.def index d828d41d1f7..86fb10951f0 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2159,6 +2159,11 @@ enum message_type #define SERIALINFO_PENDING_WRITE 0x04 #define SERIALINFO_PENDING_WAIT 0x08
+/* Cancel all sync io on a thread */ +@REQ(cancel_sync) + obj_handle_t handle; /* thread handle on which to cancel io */ + client_ptr_t iosb; /* I/O status block (NULL=all) */ +@END
/* Create an async I/O */ @REQ(register_async)
From: Daniel Lehman dlehman25@gmail.com
Signed-off-by: Daniel Lehman dlehman25@gmail.com --- dlls/kernel32/tests/pipe.c | 8 -------- dlls/kernelbase/file.c | 6 +++--- 2 files changed, 3 insertions(+), 11 deletions(-)
diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c index 55890cc9172..9481835b49b 100644 --- a/dlls/kernel32/tests/pipe.c +++ b/dlls/kernel32/tests/pipe.c @@ -4247,14 +4247,12 @@ static void test_CancelSynchronousIo(void) SetLastError(0xdeadbeef); res = pCancelSynchronousIo((HANDLE)0xdeadbeef); ok(!res, "CancelSynchronousIo succeeded unexpectedly\n"); - todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "In CancelSynchronousIo failure, expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError());
SetLastError(0xdeadbeef); res = pCancelSynchronousIo(GetCurrentThread()); ok(!res, "CancelSynchronousIo succeeded unexpectedly\n"); - todo_wine ok(GetLastError() == ERROR_NOT_FOUND, "In CancelSynchronousIo failure, expected ERROR_NOT_FOUND, got %ld\n", GetLastError());
@@ -4269,14 +4267,9 @@ static void test_CancelSynchronousIo(void) ok(wait == WAIT_TIMEOUT, "WaitForSingleObject returned %lu (error %lu)\n", wait, GetLastError()); SetLastError(0xdeadbeef); res = pCancelSynchronousIo(thread); - todo_wine - { ok(res, "CancelSynchronousIo failed with error %ld\n", GetLastError()); ok(GetLastError() == 0xdeadbeef, "In CancelSynchronousIo failure, expected 0xdeadbeef got %ld\n", GetLastError()); - } - if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) - CancelIoEx(pipe, NULL); wait = WaitForSingleObject(thread, 1000); ok(wait == WAIT_OBJECT_0, "WaitForSingleObject returned %lx\n", wait); CloseHandle(thread); @@ -4294,7 +4287,6 @@ static void test_CancelSynchronousIo(void) SetLastError(0xdeadbeef); res = pCancelSynchronousIo(thread); ok(!res, "CancelSynchronousIo succeeded unexpectedly\n"); - todo_wine ok(GetLastError() == ERROR_NOT_FOUND, "In CancelSynchronousIo failure, expected ERROR_NOT_FOUND, got %ld\n", GetLastError()); file = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c index 5ba7e0be419..3e1fd5aec4e 100644 --- a/dlls/kernelbase/file.c +++ b/dlls/kernelbase/file.c @@ -2900,9 +2900,9 @@ BOOL WINAPI DECLSPEC_HOTPATCH CancelIoEx( HANDLE handle, LPOVERLAPPED overlapped */ BOOL WINAPI DECLSPEC_HOTPATCH CancelSynchronousIo( HANDLE thread ) { - FIXME( "(%p): stub\n", thread ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + IO_STATUS_BLOCK io; + + return set_ntstatus( NtCancelSynchronousIoFile( thread, NULL, &io )); }
This merge request was approved by Zebediah Figura.