server: Create async object in ioctl request handler.
[wine.git] / dlls / ntdll / tests / pipe.c
blob176e9087971d86b2c2e4c57d67c180347e0524d0
1 /* Unit test suite for Ntdll NamedPipe API functions
3 * Copyright 2011 Bernhard Loos
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <stdio.h>
21 #include <stdarg.h>
23 #include "ntstatus.h"
24 #define WIN32_NO_STATUS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "winreg.h"
29 #include "winnls.h"
30 #include "wine/test.h"
31 #include "winternl.h"
32 #include "winioctl.h"
34 #ifndef __WINE_WINTERNL_H
36 typedef struct {
37 ULONG ReadMode;
38 ULONG CompletionMode;
39 } FILE_PIPE_INFORMATION;
41 typedef struct {
42 ULONG NamedPipeType;
43 ULONG NamedPipeConfiguration;
44 ULONG MaximumInstances;
45 ULONG CurrentInstances;
46 ULONG InboundQuota;
47 ULONG ReadDataAvailable;
48 ULONG OutboundQuota;
49 ULONG WriteQuotaAvailable;
50 ULONG NamedPipeState;
51 ULONG NamedPipeEnd;
52 } FILE_PIPE_LOCAL_INFORMATION;
54 #ifndef FILE_SYNCHRONOUS_IO_ALERT
55 #define FILE_SYNCHRONOUS_IO_ALERT 0x10
56 #endif
58 #ifndef FILE_SYNCHRONOUS_IO_NONALERT
59 #define FILE_SYNCHRONOUS_IO_NONALERT 0x20
60 #endif
62 #ifndef FSCTL_PIPE_LISTEN
63 #define FSCTL_PIPE_LISTEN CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2, METHOD_BUFFERED, FILE_ANY_ACCESS)
64 #endif
65 #endif
67 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);
68 static NTSTATUS (WINAPI *pNtCreateNamedPipeFile) (PHANDLE handle, ULONG access,
69 POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK iosb,
70 ULONG sharing, ULONG dispo, ULONG options,
71 ULONG pipe_type, ULONG read_mode,
72 ULONG completion_mode, ULONG max_inst,
73 ULONG inbound_quota, ULONG outbound_quota,
74 PLARGE_INTEGER timeout);
75 static NTSTATUS (WINAPI *pNtQueryInformationFile) (IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass);
76 static NTSTATUS (WINAPI *pNtSetInformationFile) (HANDLE handle, PIO_STATUS_BLOCK io, PVOID ptr, ULONG len, FILE_INFORMATION_CLASS class);
77 static NTSTATUS (WINAPI *pNtCancelIoFile) (HANDLE hFile, PIO_STATUS_BLOCK io_status);
78 static NTSTATUS (WINAPI *pNtCancelIoFileEx) (HANDLE hFile, IO_STATUS_BLOCK *iosb, IO_STATUS_BLOCK *io_status);
79 static void (WINAPI *pRtlInitUnicodeString) (PUNICODE_STRING target, PCWSTR source);
81 static HANDLE (WINAPI *pOpenThread)(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId);
82 static DWORD (WINAPI *pQueueUserAPC)(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData);
85 static BOOL init_func_ptrs(void)
87 HMODULE module = GetModuleHandleA("ntdll.dll");
89 #define loadfunc(name) if (!(p##name = (void *)GetProcAddress(module, #name))) { \
90 trace("GetProcAddress(%s) failed\n", #name); \
91 return FALSE; \
94 loadfunc(NtFsControlFile)
95 loadfunc(NtCreateNamedPipeFile)
96 loadfunc(NtQueryInformationFile)
97 loadfunc(NtSetInformationFile)
98 loadfunc(NtCancelIoFile)
99 loadfunc(NtCancelIoFileEx)
100 loadfunc(RtlInitUnicodeString)
102 /* not fatal */
103 module = GetModuleHandleA("kernel32.dll");
104 pOpenThread = (void *)GetProcAddress(module, "OpenThread");
105 pQueueUserAPC = (void *)GetProcAddress(module, "QueueUserAPC");
106 return TRUE;
109 static inline BOOL is_signaled( HANDLE obj )
111 return WaitForSingleObject( obj, 0 ) == WAIT_OBJECT_0;
114 static const WCHAR testpipe[] = { '\\', '\\', '.', '\\', 'p', 'i', 'p', 'e', '\\',
115 't', 'e', 's', 't', 'p', 'i', 'p', 'e', 0 };
116 static const WCHAR testpipe_nt[] = { '\\', '?', '?', '\\', 'p', 'i', 'p', 'e', '\\',
117 't', 'e', 's', 't', 'p', 'i', 'p', 'e', 0 };
119 static NTSTATUS create_pipe(PHANDLE handle, ULONG sharing, ULONG options)
121 IO_STATUS_BLOCK iosb;
122 OBJECT_ATTRIBUTES attr;
123 UNICODE_STRING name;
124 LARGE_INTEGER timeout;
125 NTSTATUS res;
127 pRtlInitUnicodeString(&name, testpipe_nt);
129 attr.Length = sizeof(attr);
130 attr.RootDirectory = 0;
131 attr.ObjectName = &name;
132 attr.Attributes = 0x40; /*case insensitive */
133 attr.SecurityDescriptor = NULL;
134 attr.SecurityQualityOfService = NULL;
136 timeout.QuadPart = -100000000;
138 res = pNtCreateNamedPipeFile(handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, sharing, 2 /*FILE_CREATE*/,
139 options, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
140 return res;
143 static BOOL ioapc_called;
144 static void CALLBACK ioapc(void *arg, PIO_STATUS_BLOCK io, ULONG reserved)
146 ioapc_called = TRUE;
149 static NTSTATUS listen_pipe(HANDLE hPipe, HANDLE hEvent, PIO_STATUS_BLOCK iosb, BOOL use_apc)
151 int dummy;
153 ioapc_called = FALSE;
155 return pNtFsControlFile(hPipe, hEvent, use_apc ? &ioapc: NULL, use_apc ? &dummy: NULL, iosb, FSCTL_PIPE_LISTEN, 0, 0, 0, 0);
158 static void test_create_invalid(void)
160 IO_STATUS_BLOCK iosb;
161 OBJECT_ATTRIBUTES attr;
162 UNICODE_STRING name;
163 LARGE_INTEGER timeout;
164 NTSTATUS res;
165 HANDLE handle, handle2;
166 FILE_PIPE_LOCAL_INFORMATION info;
168 pRtlInitUnicodeString(&name, testpipe_nt);
170 attr.Length = sizeof(attr);
171 attr.RootDirectory = 0;
172 attr.ObjectName = &name;
173 attr.Attributes = 0x40; /*case insensitive */
174 attr.SecurityDescriptor = NULL;
175 attr.SecurityQualityOfService = NULL;
177 timeout.QuadPart = -100000000;
179 /* create a pipe with FILE_OVERWRITE */
180 res = pNtCreateNamedPipeFile(&handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ, 4 /*FILE_OVERWRITE*/,
181 0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
182 todo_wine ok(res == STATUS_INVALID_PARAMETER, "NtCreateNamedPipeFile returned %x\n", res);
183 if (!res)
184 CloseHandle(handle);
186 /* create a pipe with FILE_OVERWRITE_IF */
187 res = pNtCreateNamedPipeFile(&handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ, 5 /*FILE_OVERWRITE_IF*/,
188 0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
189 todo_wine ok(res == STATUS_INVALID_PARAMETER, "NtCreateNamedPipeFile returned %x\n", res);
190 if (!res)
191 CloseHandle(handle);
193 /* create a pipe with sharing = 0 */
194 res = pNtCreateNamedPipeFile(&handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, 0, 2 /*FILE_CREATE*/,
195 0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
196 ok(res == STATUS_INVALID_PARAMETER, "NtCreateNamedPipeFile returned %x\n", res);
197 if (!res)
198 CloseHandle(handle);
200 /* create a pipe without r/w access */
201 res = pNtCreateNamedPipeFile(&handle, SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, 2 /*FILE_CREATE*/,
202 0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
203 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
205 res = pNtQueryInformationFile(handle, &iosb, &info, sizeof(info), (FILE_INFORMATION_CLASS)24);
206 ok(res == STATUS_ACCESS_DENIED, "NtQueryInformationFile returned %x\n", res);
208 /* test FILE_CREATE creation disposition */
209 res = pNtCreateNamedPipeFile(&handle2, SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, 2 /*FILE_CREATE*/,
210 0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
211 todo_wine ok(res == STATUS_ACCESS_DENIED, "NtCreateNamedPipeFile returned %x\n", res);
212 if (!res)
213 CloseHandle(handle2);
215 CloseHandle(handle);
218 static void test_create(void)
220 HANDLE hserver;
221 NTSTATUS res;
222 int j, k;
223 FILE_PIPE_LOCAL_INFORMATION info;
224 IO_STATUS_BLOCK iosb;
225 HANDLE hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
227 static const DWORD access[] = { 0, GENERIC_READ, GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE};
228 static const DWORD sharing[] = { FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE };
229 static const DWORD pipe_config[]= { 1, 0, 2 };
231 for (j = 0; j < sizeof(sharing) / sizeof(DWORD); j++) {
232 for (k = 0; k < sizeof(access) / sizeof(DWORD); k++) {
233 HANDLE hclient;
234 BOOL should_succeed = TRUE;
236 res = create_pipe(&hserver, sharing[j], 0);
237 if (res) {
238 ok(0, "NtCreateNamedPipeFile returned %x, sharing: %x\n", res, sharing[j]);
239 continue;
242 res = listen_pipe(hserver, hEvent, &iosb, FALSE);
243 ok(res == STATUS_PENDING, "NtFsControlFile returned %x\n", res);
245 res = pNtQueryInformationFile(hserver, &iosb, &info, sizeof(info), (FILE_INFORMATION_CLASS)24);
246 ok(!res, "NtQueryInformationFile for server returned %x, sharing: %x\n", res, sharing[j]);
247 ok(info.NamedPipeConfiguration == pipe_config[j], "wrong duplex status for pipe: %d, expected %d\n",
248 info.NamedPipeConfiguration, pipe_config[j]);
250 hclient = CreateFileW(testpipe, access[k], 0, 0, OPEN_EXISTING, 0, 0);
251 if (hclient != INVALID_HANDLE_VALUE) {
252 res = pNtQueryInformationFile(hclient, &iosb, &info, sizeof(info), (FILE_INFORMATION_CLASS)24);
253 ok(!res, "NtQueryInformationFile for client returned %x, access: %x, sharing: %x\n",
254 res, access[k], sharing[j]);
255 ok(info.NamedPipeConfiguration == pipe_config[j], "wrong duplex status for pipe: %d, expected %d\n",
256 info.NamedPipeConfiguration, pipe_config[j]);
257 CloseHandle(hclient);
260 if (access[k] & GENERIC_WRITE)
261 should_succeed &= !!(sharing[j] & FILE_SHARE_WRITE);
262 if (access[k] & GENERIC_READ)
263 should_succeed &= !!(sharing[j] & FILE_SHARE_READ);
265 if (should_succeed)
266 ok(hclient != INVALID_HANDLE_VALUE, "CreateFile failed for sharing %x, access: %x, GetLastError: %d\n",
267 sharing[j], access[k], GetLastError());
268 else
269 ok(hclient == INVALID_HANDLE_VALUE, "CreateFile succeeded for sharing %x, access: %x\n", sharing[j], access[k]);
271 CloseHandle(hserver);
274 CloseHandle(hEvent);
277 static void test_overlapped(void)
279 IO_STATUS_BLOCK iosb;
280 HANDLE hEvent;
281 HANDLE hPipe;
282 HANDLE hClient;
283 NTSTATUS res;
285 hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
286 ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError());
288 res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
289 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
291 memset(&iosb, 0x55, sizeof(iosb));
292 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
293 ok(res == STATUS_PENDING, "NtFsControlFile returned %x\n", res);
294 ok(U(iosb).Status == 0x55555555, "iosb.Status got changed to %x\n", U(iosb).Status);
296 hClient = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
297 ok(hClient != INVALID_HANDLE_VALUE, "can't open pipe, GetLastError: %x\n", GetLastError());
299 ok(U(iosb).Status == 0, "Wrong iostatus %x\n", U(iosb).Status);
300 ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
302 ok(!ioapc_called, "IOAPC ran too early\n");
304 SleepEx(0, TRUE); /* alertable wait state */
306 ok(ioapc_called, "IOAPC didn't run\n");
308 CloseHandle(hPipe);
309 CloseHandle(hClient);
311 res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
312 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
314 hClient = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
315 ok(hClient != INVALID_HANDLE_VALUE || broken(GetLastError() == ERROR_PIPE_BUSY) /* > Win 8 */,
316 "can't open pipe, GetLastError: %x\n", GetLastError());
318 if (hClient != INVALID_HANDLE_VALUE)
320 SetEvent(hEvent);
321 memset(&iosb, 0x55, sizeof(iosb));
322 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
323 ok(res == STATUS_PIPE_CONNECTED, "NtFsControlFile returned %x\n", res);
324 ok(U(iosb).Status == 0x55555555, "iosb.Status got changed to %x\n", U(iosb).Status);
325 ok(!is_signaled(hEvent), "hEvent not signaled\n");
327 CloseHandle(hClient);
330 CloseHandle(hPipe);
331 CloseHandle(hEvent);
334 static BOOL userapc_called;
335 static void CALLBACK userapc(ULONG_PTR dwParam)
337 userapc_called = TRUE;
340 static BOOL open_succeeded;
341 static DWORD WINAPI thread(PVOID main_thread)
343 HANDLE h;
345 Sleep(400);
347 if (main_thread) {
348 DWORD ret;
349 userapc_called = FALSE;
350 ret = pQueueUserAPC(&userapc, main_thread, 0);
351 ok(ret, "can't queue user apc, GetLastError: %x\n", GetLastError());
352 CloseHandle(main_thread);
355 Sleep(400);
357 h = CreateFileW(testpipe, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
359 if (h != INVALID_HANDLE_VALUE) {
360 open_succeeded = TRUE;
361 Sleep(100);
362 CloseHandle(h);
363 } else
364 open_succeeded = FALSE;
366 return 0;
369 static void test_alertable(void)
371 IO_STATUS_BLOCK iosb;
372 HANDLE hEvent;
373 HANDLE hPipe;
374 NTSTATUS res;
375 HANDLE hThread;
376 DWORD ret;
378 memset(&iosb, 0x55, sizeof(iosb));
380 hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
381 ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError());
383 res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_ALERT);
384 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
386 /* queue an user apc before calling listen */
387 userapc_called = FALSE;
388 ret = pQueueUserAPC(&userapc, GetCurrentThread(), 0);
389 ok(ret, "can't queue user apc, GetLastError: %x\n", GetLastError());
391 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
392 todo_wine ok(res == STATUS_CANCELLED, "NtFsControlFile returned %x\n", res);
394 todo_wine ok(userapc_called, "user apc didn't run\n");
395 ok(U(iosb).Status == 0x55555555, "iosb.Status got changed to %x\n", U(iosb).Status);
396 todo_wine ok(WaitForSingleObjectEx(hEvent, 0, TRUE) == WAIT_TIMEOUT, "hEvent signaled\n");
397 ok(!ioapc_called, "IOAPC ran\n");
399 /* queue an user apc from a different thread */
400 hThread = CreateThread(NULL, 0, &thread, pOpenThread(MAXIMUM_ALLOWED, FALSE, GetCurrentThreadId()), 0, 0);
401 ok(hThread != INVALID_HANDLE_VALUE, "can't create thread, GetLastError: %x\n", GetLastError());
403 /* wine_todo: the earlier NtFsControlFile call gets cancelled after the pipe gets set into listen state
404 instead of before, so this NtFsControlFile will fail STATUS_INVALID_HANDLE */
405 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
406 todo_wine ok(res == STATUS_CANCELLED, "NtFsControlFile returned %x\n", res);
408 ok(userapc_called, "user apc didn't run\n");
409 ok(U(iosb).Status == 0x55555555, "iosb.Status got changed to %x\n", U(iosb).Status);
410 ok(WaitForSingleObjectEx(hEvent, 0, TRUE) == WAIT_TIMEOUT, "hEvent signaled\n");
411 ok(!ioapc_called, "IOAPC ran\n");
413 WaitForSingleObject(hThread, INFINITE);
415 SleepEx(0, TRUE); /* get rid of the userapc, if NtFsControlFile failed */
417 ok(open_succeeded, "couldn't open client side pipe\n");
419 CloseHandle(hThread);
420 DisconnectNamedPipe(hPipe);
422 /* finally try without an apc */
423 hThread = CreateThread(NULL, 0, &thread, 0, 0, 0);
424 ok(hThread != INVALID_HANDLE_VALUE, "can't create thread, GetLastError: %x\n", GetLastError());
426 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
427 todo_wine ok(!res, "NtFsControlFile returned %x\n", res);
429 ok(open_succeeded, "couldn't open client side pipe\n");
430 ok(!U(iosb).Status, "Wrong iostatus %x\n", U(iosb).Status);
431 todo_wine ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
433 WaitForSingleObject(hThread, INFINITE);
434 CloseHandle(hThread);
435 CloseHandle(hEvent);
436 CloseHandle(hPipe);
439 static void test_nonalertable(void)
441 IO_STATUS_BLOCK iosb;
442 HANDLE hEvent;
443 HANDLE hPipe;
444 NTSTATUS res;
445 HANDLE hThread;
446 DWORD ret;
448 memset(&iosb, 0x55, sizeof(iosb));
450 hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
451 ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError());
453 res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT);
454 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
456 hThread = CreateThread(NULL, 0, &thread, 0, 0, 0);
457 ok(hThread != INVALID_HANDLE_VALUE, "can't create thread, GetLastError: %x\n", GetLastError());
459 userapc_called = FALSE;
460 ret = pQueueUserAPC(&userapc, GetCurrentThread(), 0);
461 ok(ret, "can't queue user apc, GetLastError: %x\n", GetLastError());
463 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
464 todo_wine ok(!res, "NtFsControlFile returned %x\n", res);
466 ok(open_succeeded, "couldn't open client side pipe\n");
467 todo_wine ok(!U(iosb).Status, "Wrong iostatus %x\n", U(iosb).Status);
468 todo_wine ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
470 ok(!ioapc_called, "IOAPC ran too early\n");
471 ok(!userapc_called, "user apc ran too early\n");
473 SleepEx(0, TRUE); /* alertable wait state */
475 ok(ioapc_called, "IOAPC didn't run\n");
476 ok(userapc_called, "user apc didn't run\n");
478 WaitForSingleObject(hThread, INFINITE);
479 CloseHandle(hThread);
480 CloseHandle(hEvent);
481 CloseHandle(hPipe);
484 static void test_cancelio(void)
486 IO_STATUS_BLOCK iosb;
487 IO_STATUS_BLOCK cancel_sb;
488 HANDLE hEvent;
489 HANDLE hPipe;
490 NTSTATUS res;
492 hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
493 ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError());
495 res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
496 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
498 memset(&iosb, 0x55, sizeof(iosb));
500 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
501 ok(res == STATUS_PENDING, "NtFsControlFile returned %x\n", res);
503 res = pNtCancelIoFile(hPipe, &cancel_sb);
504 ok(!res, "NtCancelIoFile returned %x\n", res);
506 ok(U(iosb).Status == STATUS_CANCELLED, "Wrong iostatus %x\n", U(iosb).Status);
507 ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
509 ok(!ioapc_called, "IOAPC ran too early\n");
511 SleepEx(0, TRUE); /* alertable wait state */
513 ok(ioapc_called, "IOAPC didn't run\n");
515 CloseHandle(hPipe);
517 res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
518 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
520 memset(&iosb, 0x55, sizeof(iosb));
521 res = listen_pipe(hPipe, hEvent, &iosb, FALSE);
522 ok(res == STATUS_PENDING, "NtFsControlFile returned %x\n", res);
524 res = pNtCancelIoFileEx(hPipe, &iosb, &cancel_sb);
525 ok(!res, "NtCancelIoFileEx returned %x\n", res);
527 ok(U(iosb).Status == STATUS_CANCELLED, "Wrong iostatus %x\n", U(iosb).Status);
528 ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
530 CloseHandle(hEvent);
531 CloseHandle(hPipe);
534 static void _check_pipe_handle_state(int line, HANDLE handle, ULONG read, ULONG completion)
536 IO_STATUS_BLOCK iosb;
537 FILE_PIPE_INFORMATION fpi;
538 NTSTATUS res;
539 if (handle != INVALID_HANDLE_VALUE)
541 memset(&fpi, 0x55, sizeof(fpi));
542 res = pNtQueryInformationFile(handle, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
543 ok_(__FILE__, line)(!res, "NtQueryInformationFile returned %x\n", res);
544 ok_(__FILE__, line)(fpi.ReadMode == read, "Unexpected ReadMode, expected %x, got %x\n",
545 read, fpi.ReadMode);
546 ok_(__FILE__, line)(fpi.CompletionMode == completion, "Unexpected CompletionMode, expected %x, got %x\n",
547 completion, fpi.CompletionMode);
550 #define check_pipe_handle_state(handle, r, c) _check_pipe_handle_state(__LINE__, handle, r, c)
552 static void test_filepipeinfo(void)
554 IO_STATUS_BLOCK iosb;
555 OBJECT_ATTRIBUTES attr;
556 UNICODE_STRING name;
557 LARGE_INTEGER timeout;
558 HANDLE hServer, hClient;
559 FILE_PIPE_INFORMATION fpi;
560 NTSTATUS res;
562 pRtlInitUnicodeString(&name, testpipe_nt);
564 attr.Length = sizeof(attr);
565 attr.RootDirectory = 0;
566 attr.ObjectName = &name;
567 attr.Attributes = 0x40; /* case insensitive */
568 attr.SecurityDescriptor = NULL;
569 attr.SecurityQualityOfService = NULL;
571 timeout.QuadPart = -100000000;
573 /* test with INVALID_HANDLE_VALUE */
574 res = pNtQueryInformationFile(INVALID_HANDLE_VALUE, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
575 ok(res == STATUS_OBJECT_TYPE_MISMATCH, "NtQueryInformationFile returned %x\n", res);
577 fpi.ReadMode = 0;
578 fpi.CompletionMode = 0;
579 res = pNtSetInformationFile(INVALID_HANDLE_VALUE, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
580 ok(res == STATUS_OBJECT_TYPE_MISMATCH, "NtSetInformationFile returned %x\n", res);
582 /* server end with read-only attributes */
583 res = pNtCreateNamedPipeFile(&hServer, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb,
584 FILE_SHARE_READ | FILE_SHARE_WRITE, 2 /* FILE_CREATE */,
585 0, 0, 0, 1, 0xFFFFFFFF, 500, 500, &timeout);
586 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
588 check_pipe_handle_state(hServer, 0, 1);
590 hClient = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
591 ok(hClient != INVALID_HANDLE_VALUE || broken(GetLastError() == ERROR_PIPE_BUSY) /* > Win 8 */,
592 "can't open pipe, GetLastError: %x\n", GetLastError());
594 check_pipe_handle_state(hServer, 0, 1);
595 check_pipe_handle_state(hClient, 0, 0);
597 fpi.ReadMode = 0;
598 fpi.CompletionMode = 0;
599 res = pNtSetInformationFile(hServer, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
600 ok(res == STATUS_ACCESS_DENIED, "NtSetInformationFile returned %x\n", res);
602 check_pipe_handle_state(hServer, 0, 1);
603 check_pipe_handle_state(hClient, 0, 0);
605 fpi.ReadMode = 1; /* invalid on a byte stream pipe */
606 fpi.CompletionMode = 1;
607 res = pNtSetInformationFile(hServer, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
608 ok(res == STATUS_ACCESS_DENIED, "NtSetInformationFile returned %x\n", res);
610 check_pipe_handle_state(hServer, 0, 1);
611 check_pipe_handle_state(hClient, 0, 0);
613 if (hClient != INVALID_HANDLE_VALUE)
615 fpi.ReadMode = 1; /* invalid on a byte stream pipe */
616 fpi.CompletionMode = 1;
617 res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
618 ok(res == STATUS_INVALID_PARAMETER, "NtSetInformationFile returned %x\n", res);
621 check_pipe_handle_state(hServer, 0, 1);
622 check_pipe_handle_state(hClient, 0, 0);
624 if (hClient != INVALID_HANDLE_VALUE)
626 fpi.ReadMode = 0;
627 fpi.CompletionMode = 1;
628 res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
629 ok(!res, "NtSetInformationFile returned %x\n", res);
632 check_pipe_handle_state(hServer, 0, 1);
633 check_pipe_handle_state(hClient, 0, 1);
635 if (hClient != INVALID_HANDLE_VALUE)
637 fpi.ReadMode = 0;
638 fpi.CompletionMode = 2; /* not in range 0-1 */
639 res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
640 ok(res == STATUS_INVALID_PARAMETER || broken(!res) /* < Vista */, "NtSetInformationFile returned %x\n", res);
642 fpi.ReadMode = 2; /* not in range 0-1 */
643 fpi.CompletionMode = 0;
644 res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
645 ok(res == STATUS_INVALID_PARAMETER || broken(!res) /* < Vista */, "NtSetInformationFile returned %x\n", res);
648 CloseHandle(hClient);
650 check_pipe_handle_state(hServer, 0, 1);
652 fpi.ReadMode = 0;
653 fpi.CompletionMode = 0;
654 res = pNtSetInformationFile(hServer, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
655 ok(res == STATUS_ACCESS_DENIED, "NtSetInformationFile returned %x\n", res);
657 CloseHandle(hServer);
659 /* message mode server with read/write attributes */
660 res = pNtCreateNamedPipeFile(&hServer, FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb,
661 FILE_SHARE_READ | FILE_SHARE_WRITE, 2 /* FILE_CREATE */,
662 0, 1, 1, 0, 0xFFFFFFFF, 500, 500, &timeout);
663 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
665 check_pipe_handle_state(hServer, 1, 0);
667 hClient = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
668 ok(hClient != INVALID_HANDLE_VALUE || broken(GetLastError() == ERROR_PIPE_BUSY) /* > Win 8 */,
669 "can't open pipe, GetLastError: %x\n", GetLastError());
671 check_pipe_handle_state(hServer, 1, 0);
672 check_pipe_handle_state(hClient, 0, 0);
674 if (hClient != INVALID_HANDLE_VALUE)
676 fpi.ReadMode = 1;
677 fpi.CompletionMode = 1;
678 res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
679 ok(!res, "NtSetInformationFile returned %x\n", res);
682 check_pipe_handle_state(hServer, 1, 0);
683 check_pipe_handle_state(hClient, 1, 1);
685 fpi.ReadMode = 0;
686 fpi.CompletionMode = 1;
687 res = pNtSetInformationFile(hServer, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
688 ok(!res, "NtSetInformationFile returned %x\n", res);
690 check_pipe_handle_state(hServer, 0, 1);
691 check_pipe_handle_state(hClient, 1, 1);
693 if (hClient != INVALID_HANDLE_VALUE)
695 fpi.ReadMode = 0;
696 fpi.CompletionMode = 2; /* not in range 0-1 */
697 res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
698 ok(res == STATUS_INVALID_PARAMETER || broken(!res) /* < Vista */, "NtSetInformationFile returned %x\n", res);
700 fpi.ReadMode = 2; /* not in range 0-1 */
701 fpi.CompletionMode = 0;
702 res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
703 ok(res == STATUS_INVALID_PARAMETER || broken(!res) /* < Vista */, "NtSetInformationFile returned %x\n", res);
706 CloseHandle(hClient);
708 check_pipe_handle_state(hServer, 0, 1);
710 fpi.ReadMode = 1;
711 fpi.CompletionMode = 0;
712 res = pNtSetInformationFile(hServer, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
713 ok(!res, "NtSetInformationFile returned %x\n", res);
715 check_pipe_handle_state(hServer, 1, 0);
717 CloseHandle(hServer);
720 START_TEST(pipe)
722 if (!init_func_ptrs())
723 return;
725 trace("starting invalid create tests\n");
726 test_create_invalid();
728 trace("starting create tests\n");
729 test_create();
731 trace("starting overlapped tests\n");
732 test_overlapped();
734 trace("starting FILE_PIPE_INFORMATION tests\n");
735 test_filepipeinfo();
737 if (!pOpenThread || !pQueueUserAPC)
738 return;
740 trace("starting alertable tests\n");
741 test_alertable();
743 trace("starting nonalertable tests\n");
744 test_nonalertable();
746 trace("starting cancelio tests\n");
747 test_cancelio();