Signed-off-by: Daniel Lehman dlehman25@gmail.com --- dlls/ntdll/ntdll.spec | 2 + dlls/ntdll/tests/pipe.c | 93 ++++++++++++++++++++++++++++++++++++++++ dlls/ntdll/unix/file.c | 9 ++++ dlls/ntdll/unix/loader.c | 1 + include/winternl.h | 1 + 5 files changed, 106 insertions(+)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 311f99be054..74152ef10bc 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) @@ -1181,6 +1182,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 dc9737e73d8..1298e7a37ae 100644 --- a/dlls/ntdll/tests/pipe.c +++ b/dlls/ntdll/tests/pipe.c @@ -79,6 +79,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);
@@ -103,6 +104,7 @@ static BOOL init_func_ptrs(void) loadfunc(NtQueryVolumeInformationFile) loadfunc(NtSetInformationFile) loadfunc(NtCancelIoFile) + loadfunc(NtCancelSynchronousIoFile) loadfunc(RtlInitUnicodeString) loadfunc(NtRemoveIoCompletion)
@@ -562,6 +564,94 @@ static void test_cancelio(void) CloseHandle(hEvent); }
+static DWORD WINAPI synchronousio_thread(void *arg) +{ + IO_STATUS_BLOCK iosb; + NTSTATUS res; + HANDLE pipe; + + pipe = arg; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + res = listen_pipe(pipe, NULL, &iosb, FALSE); + todo_wine { + ok(res == STATUS_CANCELLED, "NtFsControlFile returned %lx\n", res); + ok(U(iosb).Status == 0xdeadbabe, "wrong status %lx\n", U(iosb).Status); + ok(iosb.Information == 0xdeadbeef, "wrong info %Iu\n", iosb.Information); + } + return 0; +} + +static void test_cancelsynchronousio(void) +{ + DWORD ret; + HANDLE pipe; + HANDLE event; + HANDLE thread; + HANDLE client; + NTSTATUS res; + IO_STATUS_BLOCK iosb; + + /* bogus values */ + res = pNtCancelSynchronousIoFile((HANDLE)0xdeadbeef, NULL, &iosb); + todo_wine + ok(res == STATUS_INVALID_HANDLE, "NtCancelSynchronousIoFile returned %lx\n", res); + res = pNtCancelSynchronousIoFile(GetCurrentThread(), NULL, NULL); + todo_wine + ok(res == STATUS_ACCESS_VIOLATION, "NtCancelSynchronousIoFile returned %lx\n", res); + res = pNtCancelSynchronousIoFile(GetCurrentThread(), NULL, (IO_STATUS_BLOCK*)0xdeadbeef); + todo_wine + ok(res == STATUS_ACCESS_VIOLATION, "NtCancelSynchronousIoFile returned %lx\n", res); + memset(&iosb, 0x55, sizeof(iosb)); + res = pNtCancelSynchronousIoFile(GetCurrentThread(), (HANDLE)0xdeadbeef, &iosb); + todo_wine + ok(res == STATUS_ACCESS_VIOLATION || broken(res == STATUS_NOT_FOUND), + "NtCancelSynchronousIoFile returned %lx\n", res); + + /* synchronous i/o */ + res = create_pipe(&pipe, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT); + ok(!res, "NtCreateNamedPipeFile returned %lx\n", res); + thread = CreateThread(NULL, 0, synchronousio_thread, pipe, 0, 0); + /* wait for thread to start listening */ + Sleep(100); + 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); + } + CloseHandle(pipe); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + + /* asynchronous i/o */ + res = create_pipe(&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()); + memset(&iosb, 0x55, sizeof(iosb)); + res = listen_pipe(pipe, event, &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); + } + 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(pipe); + CloseHandle(event); + CloseHandle(client); +} + static void _check_pipe_handle_state(int line, HANDLE handle, ULONG read, ULONG completion) { IO_STATUS_BLOCK iosb; @@ -2606,6 +2696,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 cc8bf0c6e82..6990f9b4719 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -5970,6 +5970,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 d1c42ddc0f3..a3ddce6414a 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/include/winternl.h b/include/winternl.h index b4942d86b4c..7e41ad6ab60 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -3927,6 +3927,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);