From 4be482bc825c419acd3b524b4825e03998040bd3 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Thu, 25 Oct 2018 14:55:57 +0200 Subject: [PATCH] ntdll/tests: Added more FILE_SKIP_COMPLETION_PORT_ON_SUCCESS tests. Based on a patch by Sebastian Lackner. Signed-off-by: Jacek Caban Signed-off-by: Alexandre Julliard --- dlls/ntdll/tests/file.c | 38 +++++++++ dlls/ntdll/tests/pipe.c | 169 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 198 insertions(+), 9 deletions(-) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 0c22ca67cb2..db077d6eda9 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -3315,6 +3315,24 @@ static void test_file_all_name_information(void) HeapFree( GetProcessHeap(), 0, file_name ); } +#define test_completion_flags(a,b) _test_completion_flags(__LINE__,a,b) +static void _test_completion_flags(unsigned line, HANDLE handle, DWORD expected_flags) +{ + FILE_IO_COMPLETION_NOTIFICATION_INFORMATION info; + IO_STATUS_BLOCK io; + NTSTATUS status; + + info.Flags = 0xdeadbeef; + status = pNtQueryInformationFile(handle, &io, &info, sizeof(info), + FileIoCompletionNotificationInformation); + ok_(__FILE__,line)(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status); + ok_(__FILE__,line)(io.Status == STATUS_SUCCESS, "Status = %x\n", io.Status); + ok_(__FILE__,line)(io.Information == sizeof(info), "Information = %lu\n", io.Information); + /* FILE_SKIP_SET_USER_EVENT_ON_FAST_IO is not supported on win2k3 */ + ok_(__FILE__,line)((info.Flags & ~FILE_SKIP_SET_USER_EVENT_ON_FAST_IO) == expected_flags, + "got %08x\n", info.Flags); +} + static void test_file_completion_information(void) { static const char buf[] = "testdata"; @@ -3350,13 +3368,31 @@ static void test_file_completion_information(void) info.Flags = FILE_SKIP_SET_EVENT_ON_HANDLE; status = pNtSetInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation); ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status); + test_completion_flags(h, FILE_SKIP_SET_EVENT_ON_HANDLE); info.Flags = FILE_SKIP_SET_USER_EVENT_ON_FAST_IO; status = pNtSetInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation); ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status); + test_completion_flags(h, FILE_SKIP_SET_EVENT_ON_HANDLE); + + info.Flags = 0; + status = pNtSetInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation); + ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status); + test_completion_flags(h, FILE_SKIP_SET_EVENT_ON_HANDLE); + + info.Flags = FILE_SKIP_COMPLETION_PORT_ON_SUCCESS; + status = pNtSetInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation); + ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status); + test_completion_flags(h, FILE_SKIP_SET_EVENT_ON_HANDLE | FILE_SKIP_COMPLETION_PORT_ON_SUCCESS); + + info.Flags = 0xdeadbeef; + status = pNtSetInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation); + ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status); + test_completion_flags(h, FILE_SKIP_SET_EVENT_ON_HANDLE | FILE_SKIP_COMPLETION_PORT_ON_SUCCESS); CloseHandle(h); if (!(h = create_temp_file(FILE_FLAG_OVERLAPPED))) return; + test_completion_flags(h, 0); memset(&ov, 0, sizeof(ov)); ov.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL); @@ -3391,6 +3427,7 @@ static void test_file_completion_information(void) info.Flags = FILE_SKIP_COMPLETION_PORT_ON_SUCCESS; status = pNtSetInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation); ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status); + test_completion_flags(h, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS); for (i = 0; i < 10; i++) { @@ -3418,6 +3455,7 @@ static void test_file_completion_information(void) info.Flags = 0; status = pNtSetInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation); ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status); + test_completion_flags(h, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS); for (i = 0; i < 10; i++) { diff --git a/dlls/ntdll/tests/pipe.c b/dlls/ntdll/tests/pipe.c index 45c846627e4..c4d4d87759a 100644 --- a/dlls/ntdll/tests/pipe.c +++ b/dlls/ntdll/tests/pipe.c @@ -77,6 +77,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 *pNtRemoveIoCompletion)(HANDLE, PULONG_PTR, PULONG_PTR, PIO_STATUS_BLOCK, PLARGE_INTEGER); static void (WINAPI *pRtlInitUnicodeString) (PUNICODE_STRING target, PCWSTR source); static HANDLE (WINAPI *pOpenThread)(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId); @@ -99,6 +100,7 @@ static BOOL init_func_ptrs(void) loadfunc(NtSetInformationFile) loadfunc(NtCancelIoFile) loadfunc(RtlInitUnicodeString) + loadfunc(NtRemoveIoCompletion) /* not fatal */ pNtCancelIoFileEx = (void *)GetProcAddress(module, "NtCancelIoFileEx"); @@ -807,30 +809,31 @@ static void test_peek(HANDLE pipe) static BOOL create_pipe_pair( HANDLE *read, HANDLE *write, ULONG flags, ULONG type, ULONG size ) { - const BOOL server_reader = flags & PIPE_ACCESS_INBOUND; HANDLE client, server; server = CreateNamedPipeA(PIPENAME, flags, PIPE_WAIT | type, 1, size, size, NMPWAIT_USE_DEFAULT_WAIT, NULL); ok(server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); - client = CreateFileA(PIPENAME, server_reader ? GENERIC_WRITE : GENERIC_READ | FILE_WRITE_ATTRIBUTES, 0, + client = CreateFileA(PIPENAME, (flags & PIPE_ACCESS_INBOUND ? GENERIC_WRITE : 0) + | (flags & PIPE_ACCESS_OUTBOUND ? GENERIC_READ : 0) + | FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING, flags & FILE_FLAG_OVERLAPPED, 0); ok(client != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError()); - if(server_reader) + if ((type & PIPE_READMODE_MESSAGE) && (flags & PIPE_ACCESS_OUTBOUND)) + { + DWORD read_mode = PIPE_READMODE_MESSAGE; + ok(SetNamedPipeHandleState(client, &read_mode, NULL, NULL), "Change mode\n"); + } + + if (flags & PIPE_ACCESS_INBOUND) { *read = server; *write = client; } else { - if(type & PIPE_READMODE_MESSAGE) - { - DWORD read_mode = PIPE_READMODE_MESSAGE; - ok(SetNamedPipeHandleState(client, &read_mode, NULL, NULL), "Change mode\n"); - } - *read = client; *write = server; } @@ -1200,6 +1203,151 @@ static void test_transceive(void) CloseHandle( callee ); } +#define test_no_queued_completion(a) _test_no_queued_completion(__LINE__,a) +static void _test_no_queued_completion(unsigned line, HANDLE port) +{ + OVERLAPPED *pov; + DWORD num_bytes; + ULONG_PTR key; + BOOL ret; + + pov = (void *)0xdeadbeef; + ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 10); + ok_(__FILE__,line)(!ret && GetLastError() == WAIT_TIMEOUT, + "GetQueuedCompletionStatus returned %x(%u)\n", ret, GetLastError()); +} + +#define test_queued_completion(a,b,c,d) _test_queued_completion(__LINE__,a,b,c,d) +static void _test_queued_completion(unsigned line, HANDLE port, IO_STATUS_BLOCK *io, + NTSTATUS expected_status, ULONG expected_information) +{ + LARGE_INTEGER timeout = {{0}}; + ULONG_PTR value = 0xdeadbeef; + IO_STATUS_BLOCK iosb; + ULONG_PTR key; + NTSTATUS status; + + status = pNtRemoveIoCompletion(port, &key, &value, &iosb, &timeout); + ok_(__FILE__,line)(status == STATUS_SUCCESS, "NtRemoveIoCompletion returned %x\n", status); + ok_(__FILE__,line)(value == (ULONG_PTR)io, "value = %lx\n", value); + ok_(__FILE__,line)(io->Status == expected_status, "Status = %x\n", io->Status); + ok_(__FILE__,line)(io->Information == expected_information, + "Information = %lu\n", io->Information); +} + +static void test_completion(void) +{ + static const char buf[] = "testdata"; + FILE_IO_COMPLETION_NOTIFICATION_INFORMATION info; + FILE_PIPE_PEEK_BUFFER peek_buf; + char read_buf[16]; + HANDLE port, pipe, client; + OVERLAPPED ov; + IO_STATUS_BLOCK io; + NTSTATUS status; + DWORD num_bytes; + BOOL ret; + + create_pipe_pair( &pipe, &client, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 4096 ); + + status = pNtQueryInformationFile(pipe, &io, &info, sizeof(info), + FileIoCompletionNotificationInformation); + ok(status == STATUS_SUCCESS || broken(status == STATUS_INVALID_INFO_CLASS), + "status = %x\n", status); + if (status) + { + win_skip("FileIoCompletionNotificationInformation not supported\n"); + CloseHandle(pipe); + CloseHandle(client); + return; + } + + memset(&ov, 0, sizeof(ov)); + ov.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL); + ok(ov.hEvent != INVALID_HANDLE_VALUE, "CreateEvent failed, error %u\n", GetLastError()); + + port = CreateIoCompletionPort(client, NULL, 0xdeadbeef, 0); + ok(port != NULL, "CreateIoCompletionPort failed, error %u\n", GetLastError()); + + ret = WriteFile(client, buf, sizeof(buf), &num_bytes, &ov); + ok(ret, "WriteFile failed, error %u\n", GetLastError()); + ok(num_bytes == sizeof(buf), "expected sizeof(buf), got %u\n", num_bytes); + test_queued_completion(port, (IO_STATUS_BLOCK*)&ov, STATUS_SUCCESS, num_bytes); + + status = NtFsControlFile(client, NULL, NULL, &io, &io, FSCTL_PIPE_PEEK, + NULL, 0, &peek_buf, sizeof(peek_buf)); + ok(status == STATUS_PENDING || status == STATUS_SUCCESS, "FSCTL_PIPE_PEEK returned %x\n", status); + test_queued_completion(port, &io, STATUS_SUCCESS, FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data)); + + info.Flags = FILE_SKIP_COMPLETION_PORT_ON_SUCCESS; + status = pNtSetInformationFile(client, &io, &info, sizeof(info), FileIoCompletionNotificationInformation); + ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status); + + ret = WriteFile(client, buf, sizeof(buf), &num_bytes, &ov); + ok(ret, "WriteFile failed, error %u\n", GetLastError()); + ok(num_bytes == sizeof(buf), "expected sizeof(buf), got %u\n", num_bytes); + todo_wine + test_no_queued_completion(port); + + ret = WriteFile(pipe, buf, sizeof(buf), &num_bytes, &ov); + ok(ret, "WriteFile failed, error %u\n", GetLastError()); + ok(num_bytes == sizeof(buf), "expected sizeof(buf), got %u\n", num_bytes); + + status = NtReadFile(client, NULL, NULL, &io, &io, read_buf, 1, NULL, NULL); + ok(status == STATUS_BUFFER_OVERFLOW || status == STATUS_PENDING, "status = %x\n", status); + ok(io.Status == STATUS_BUFFER_OVERFLOW, "Status = %x\n", io.Status); + ok(io.Information == 1, "Information = %lu\n", io.Information); + if(status == STATUS_PENDING) /* win8+ */ + test_queued_completion(port, &io, STATUS_BUFFER_OVERFLOW, 1); + else + todo_wine + test_no_queued_completion(port); + + status = NtReadFile(client, NULL, NULL, &io, &io, read_buf, sizeof(read_buf), NULL, NULL); + ok(status == STATUS_SUCCESS, "status = %x\n", status); + ok(io.Status == STATUS_SUCCESS, "Status = %x\n", io.Status); + ok(io.Information == sizeof(buf)-1, "Information = %lu\n", io.Information); + todo_wine + test_no_queued_completion(port); + + status = NtFsControlFile(client, NULL, NULL, &io, &io, FSCTL_PIPE_PEEK, + NULL, 0, &peek_buf, sizeof(peek_buf)); + ok(status == STATUS_PENDING || status == STATUS_SUCCESS, "FSCTL_PIPE_PEEK returned %x\n", status); + if(status == STATUS_PENDING) /* win8+ */ + test_queued_completion(port, &io, STATUS_SUCCESS, FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data)); + else + todo_wine + test_no_queued_completion(port); + + memset(&io, 0xcc, sizeof(io)); + status = NtReadFile(client, ov.hEvent, NULL, &io, &io, read_buf, sizeof(read_buf), NULL, NULL); + ok(status == STATUS_PENDING, "status = %x\n", status); + ok(!is_signaled(ov.hEvent), "event is signtaled\n"); + test_no_queued_completion(port); + + ret = WriteFile(pipe, buf, sizeof(buf), &num_bytes, NULL); + ok(ret, "WriteFile failed, error %u\n", GetLastError()); + test_queued_completion(port, &io, STATUS_SUCCESS, sizeof(buf)); + + ret = WriteFile(pipe, buf, sizeof(buf), &num_bytes, NULL); + ok(ret, "WriteFile failed, error %u\n", GetLastError()); + status = NtFsControlFile(client, NULL, NULL, &io, &io, FSCTL_PIPE_PEEK, + NULL, 0, &peek_buf, sizeof(peek_buf)); + ok(status == STATUS_PENDING || status == STATUS_BUFFER_OVERFLOW, + "FSCTL_PIPE_PEEK returned %x\n", status); + if(status == STATUS_PENDING) /* win8+ */ + test_queued_completion(port, &io, STATUS_BUFFER_OVERFLOW, sizeof(peek_buf)); + else + todo_wine + test_no_queued_completion(port); + + CloseHandle(ov.hEvent); + CloseHandle(client); + CloseHandle(pipe); + CloseHandle(port); +} + static void test_volume_info(void) { FILE_FS_DEVICE_INFORMATION *device_info; @@ -1946,6 +2094,9 @@ START_TEST(pipe) trace("starting overlapped tests\n"); test_overlapped(); + trace("starting completion tests\n"); + test_completion(); + trace("starting FILE_PIPE_INFORMATION tests\n"); test_filepipeinfo();