9e4fd2f7eaf23e1255187eecbe438660cbdd2375
[reactos.git] / modules / rostests / winetests / ntdll / pipe.c
1 /* Unit test suite for Ntdll NamedPipe API functions
2 *
3 * Copyright 2011 Bernhard Loos
4 *
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.
9 *
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.
14 *
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
18 */
19
20 #include <stdio.h>
21 #include <stdarg.h>
22
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 "wine/winternl.h"
32 #include "winioctl.h"
33
34 #ifndef __WINE_WINTERNL_H
35
36 typedef struct {
37 ULONG ReadMode;
38 ULONG CompletionMode;
39 } FILE_PIPE_INFORMATION;
40
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;
53
54 #ifndef FILE_SYNCHRONOUS_IO_ALERT
55 #define FILE_SYNCHRONOUS_IO_ALERT 0x10
56 #endif
57
58 #ifndef FILE_SYNCHRONOUS_IO_NONALERT
59 #define FILE_SYNCHRONOUS_IO_NONALERT 0x20
60 #endif
61
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
66
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 void (WINAPI *pRtlInitUnicodeString) (PUNICODE_STRING target, PCWSTR source);
79
80 static HANDLE (WINAPI *pOpenThread)(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId);
81 static DWORD (WINAPI *pQueueUserAPC)(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData);
82
83
84 static BOOL init_func_ptrs(void)
85 {
86 HMODULE module = GetModuleHandleA("ntdll.dll");
87
88 #define loadfunc(name) if (!(p##name = (void *)GetProcAddress(module, #name))) { \
89 trace("GetProcAddress(%s) failed\n", #name); \
90 return FALSE; \
91 }
92
93 loadfunc(NtFsControlFile)
94 loadfunc(NtCreateNamedPipeFile)
95 loadfunc(NtQueryInformationFile)
96 loadfunc(NtSetInformationFile)
97 loadfunc(NtCancelIoFile)
98 loadfunc(RtlInitUnicodeString)
99
100 /* not fatal */
101 module = GetModuleHandleA("kernel32.dll");
102 pOpenThread = (void *)GetProcAddress(module, "OpenThread");
103 pQueueUserAPC = (void *)GetProcAddress(module, "QueueUserAPC");
104 return TRUE;
105 }
106
107 static const WCHAR testpipe[] = { '\\', '\\', '.', '\\', 'p', 'i', 'p', 'e', '\\',
108 't', 'e', 's', 't', 'p', 'i', 'p', 'e', 0 };
109 static const WCHAR testpipe_nt[] = { '\\', '?', '?', '\\', 'p', 'i', 'p', 'e', '\\',
110 't', 'e', 's', 't', 'p', 'i', 'p', 'e', 0 };
111
112 static NTSTATUS create_pipe(PHANDLE handle, ULONG sharing, ULONG options)
113 {
114 IO_STATUS_BLOCK iosb;
115 OBJECT_ATTRIBUTES attr;
116 UNICODE_STRING name;
117 LARGE_INTEGER timeout;
118 NTSTATUS res;
119
120 pRtlInitUnicodeString(&name, testpipe_nt);
121
122 attr.Length = sizeof(attr);
123 attr.RootDirectory = 0;
124 attr.ObjectName = &name;
125 attr.Attributes = 0x40; /*case insensitive */
126 attr.SecurityDescriptor = NULL;
127 attr.SecurityQualityOfService = NULL;
128
129 timeout.QuadPart = -100000000;
130
131 res = pNtCreateNamedPipeFile(handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, sharing, 2 /*FILE_CREATE*/,
132 options, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
133 return res;
134 }
135
136 static void test_create_invalid(void)
137 {
138 IO_STATUS_BLOCK iosb;
139 OBJECT_ATTRIBUTES attr;
140 UNICODE_STRING name;
141 LARGE_INTEGER timeout;
142 NTSTATUS res;
143 HANDLE handle, handle2;
144 FILE_PIPE_LOCAL_INFORMATION info;
145
146 pRtlInitUnicodeString(&name, testpipe_nt);
147
148 attr.Length = sizeof(attr);
149 attr.RootDirectory = 0;
150 attr.ObjectName = &name;
151 attr.Attributes = 0x40; /*case insensitive */
152 attr.SecurityDescriptor = NULL;
153 attr.SecurityQualityOfService = NULL;
154
155 timeout.QuadPart = -100000000;
156
157 /* create a pipe with FILE_OVERWRITE */
158 res = pNtCreateNamedPipeFile(&handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ, 4 /*FILE_OVERWRITE*/,
159 0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
160 todo_wine ok(res == STATUS_INVALID_PARAMETER, "NtCreateNamedPipeFile returned %x\n", res);
161 if (!res)
162 CloseHandle(handle);
163
164 /* create a pipe with FILE_OVERWRITE_IF */
165 res = pNtCreateNamedPipeFile(&handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ, 5 /*FILE_OVERWRITE_IF*/,
166 0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
167 todo_wine ok(res == STATUS_INVALID_PARAMETER, "NtCreateNamedPipeFile returned %x\n", res);
168 if (!res)
169 CloseHandle(handle);
170
171 /* create a pipe with sharing = 0 */
172 res = pNtCreateNamedPipeFile(&handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, 0, 2 /*FILE_CREATE*/,
173 0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
174 ok(res == STATUS_INVALID_PARAMETER, "NtCreateNamedPipeFile returned %x\n", res);
175 if (!res)
176 CloseHandle(handle);
177
178 /* create a pipe without r/w access */
179 res = pNtCreateNamedPipeFile(&handle, SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, 2 /*FILE_CREATE*/,
180 0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
181 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
182
183 res = pNtQueryInformationFile(handle, &iosb, &info, sizeof(info), (FILE_INFORMATION_CLASS)24);
184 ok(res == STATUS_ACCESS_DENIED, "NtQueryInformationFile returned %x\n", res);
185
186 /* test FILE_CREATE creation disposition */
187 res = pNtCreateNamedPipeFile(&handle2, SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, 2 /*FILE_CREATE*/,
188 0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
189 todo_wine ok(res == STATUS_ACCESS_DENIED, "NtCreateNamedPipeFile returned %x\n", res);
190 if (!res)
191 CloseHandle(handle2);
192
193 CloseHandle(handle);
194 }
195
196 static void test_create(void)
197 {
198 HANDLE hserver;
199 NTSTATUS res;
200 int j, k;
201 FILE_PIPE_LOCAL_INFORMATION info;
202 IO_STATUS_BLOCK iosb;
203
204 static const DWORD access[] = { 0, GENERIC_READ, GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE};
205 static const DWORD sharing[] = { FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE };
206 static const DWORD pipe_config[]= { 1, 0, 2 };
207
208 for (j = 0; j < sizeof(sharing) / sizeof(DWORD); j++) {
209 for (k = 0; k < sizeof(access) / sizeof(DWORD); k++) {
210 HANDLE hclient;
211 BOOL should_succeed = TRUE;
212
213 res = create_pipe(&hserver, sharing[j], FILE_SYNCHRONOUS_IO_NONALERT);
214 if (res) {
215 ok(0, "NtCreateNamedPipeFile returned %x, sharing: %x\n", res, sharing[j]);
216 continue;
217 }
218
219 res = pNtQueryInformationFile(hserver, &iosb, &info, sizeof(info), (FILE_INFORMATION_CLASS)24);
220 ok(!res, "NtQueryInformationFile for server returned %x, sharing: %x\n", res, sharing[j]);
221 ok(info.NamedPipeConfiguration == pipe_config[j], "wrong duplex status for pipe: %d, expected %d\n",
222 info.NamedPipeConfiguration, pipe_config[j]);
223
224 hclient = CreateFileW(testpipe, access[k], 0, 0, OPEN_EXISTING, 0, 0);
225 if (hclient != INVALID_HANDLE_VALUE) {
226 res = pNtQueryInformationFile(hclient, &iosb, &info, sizeof(info), (FILE_INFORMATION_CLASS)24);
227 ok(!res, "NtQueryInformationFile for client returned %x, access: %x, sharing: %x\n",
228 res, access[k], sharing[j]);
229 ok(info.NamedPipeConfiguration == pipe_config[j], "wrong duplex status for pipe: %d, expected %d\n",
230 info.NamedPipeConfiguration, pipe_config[j]);
231 CloseHandle(hclient);
232 }
233
234 if (access[k] & GENERIC_WRITE)
235 should_succeed &= !!(sharing[j] & FILE_SHARE_WRITE);
236 if (access[k] & GENERIC_READ)
237 should_succeed &= !!(sharing[j] & FILE_SHARE_READ);
238
239 if (should_succeed)
240 ok(hclient != INVALID_HANDLE_VALUE, "CreateFile failed for sharing %x, access: %x, GetLastError: %d\n",
241 sharing[j], access[k], GetLastError());
242 else
243 ok(hclient == INVALID_HANDLE_VALUE, "CreateFile succeeded for sharing %x, access: %x\n", sharing[j], access[k]);
244
245 CloseHandle(hserver);
246 }
247 }
248 }
249
250 static BOOL ioapc_called;
251 static void CALLBACK ioapc(void *arg, PIO_STATUS_BLOCK io, ULONG reserved)
252 {
253 ioapc_called = TRUE;
254 }
255
256 static NTSTATUS listen_pipe(HANDLE hPipe, HANDLE hEvent, PIO_STATUS_BLOCK iosb, BOOL use_apc)
257 {
258 int dummy;
259
260 ioapc_called = FALSE;
261
262 return pNtFsControlFile(hPipe, hEvent, use_apc ? &ioapc: NULL, use_apc ? &dummy: NULL, iosb, FSCTL_PIPE_LISTEN, 0, 0, 0, 0);
263 }
264
265 static void test_overlapped(void)
266 {
267 IO_STATUS_BLOCK iosb;
268 HANDLE hEvent;
269 HANDLE hPipe;
270 HANDLE hClient;
271 NTSTATUS res;
272
273 hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
274 ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError());
275
276 res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
277 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
278
279 memset(&iosb, 0x55, sizeof(iosb));
280 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
281 ok(res == STATUS_PENDING, "NtFsControlFile returned %x\n", res);
282 ok(U(iosb).Status == 0x55555555, "iosb.Status got changed to %x\n", U(iosb).Status);
283
284 hClient = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
285 ok(hClient != INVALID_HANDLE_VALUE, "can't open pipe, GetLastError: %x\n", GetLastError());
286
287 ok(U(iosb).Status == 0, "Wrong iostatus %x\n", U(iosb).Status);
288 ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
289
290 ok(!ioapc_called, "IOAPC ran too early\n");
291
292 SleepEx(0, TRUE); /* alertable wait state */
293
294 ok(ioapc_called, "IOAPC didn't run\n");
295
296 CloseHandle(hPipe);
297 CloseHandle(hClient);
298
299 res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
300 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
301
302 hClient = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
303 ok(hClient != INVALID_HANDLE_VALUE || broken(GetLastError() == ERROR_PIPE_BUSY) /* > Win 8 */,
304 "can't open pipe, GetLastError: %x\n", GetLastError());
305
306 if (hClient != INVALID_HANDLE_VALUE)
307 {
308 memset(&iosb, 0x55, sizeof(iosb));
309 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
310 ok(res == STATUS_PIPE_CONNECTED, "NtFsControlFile returned %x\n", res);
311 ok(U(iosb).Status == 0x55555555, "iosb.Status got changed to %x\n", U(iosb).Status);
312
313 CloseHandle(hClient);
314 }
315
316 CloseHandle(hPipe);
317 CloseHandle(hEvent);
318 }
319
320 static BOOL userapc_called;
321 static void CALLBACK userapc(ULONG_PTR dwParam)
322 {
323 userapc_called = TRUE;
324 }
325
326 static BOOL open_succeeded;
327 static DWORD WINAPI thread(PVOID main_thread)
328 {
329 HANDLE h;
330
331 Sleep(400);
332
333 if (main_thread) {
334 DWORD ret;
335 userapc_called = FALSE;
336 ret = pQueueUserAPC(&userapc, main_thread, 0);
337 ok(ret, "can't queue user apc, GetLastError: %x\n", GetLastError());
338 CloseHandle(main_thread);
339 }
340
341 Sleep(400);
342
343 h = CreateFileW(testpipe, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
344
345 if (h != INVALID_HANDLE_VALUE) {
346 open_succeeded = TRUE;
347 Sleep(100);
348 CloseHandle(h);
349 } else
350 open_succeeded = FALSE;
351
352 return 0;
353 }
354
355 static void test_alertable(void)
356 {
357 IO_STATUS_BLOCK iosb;
358 HANDLE hEvent;
359 HANDLE hPipe;
360 NTSTATUS res;
361 HANDLE hThread;
362 DWORD ret;
363
364 memset(&iosb, 0x55, sizeof(iosb));
365
366 hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
367 ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError());
368
369 res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_ALERT);
370 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
371
372 /* queue an user apc before calling listen */
373 userapc_called = FALSE;
374 ret = pQueueUserAPC(&userapc, GetCurrentThread(), 0);
375 ok(ret, "can't queue user apc, GetLastError: %x\n", GetLastError());
376
377 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
378 todo_wine ok(res == STATUS_CANCELLED, "NtFsControlFile returned %x\n", res);
379
380 todo_wine ok(userapc_called, "user apc didn't run\n");
381 ok(U(iosb).Status == 0x55555555, "iosb.Status got changed to %x\n", U(iosb).Status);
382 todo_wine ok(WaitForSingleObjectEx(hEvent, 0, TRUE) == WAIT_TIMEOUT, "hEvent signaled\n");
383 ok(!ioapc_called, "IOAPC ran\n");
384
385 /* queue an user apc from a different thread */
386 hThread = CreateThread(NULL, 0, &thread, pOpenThread(MAXIMUM_ALLOWED, FALSE, GetCurrentThreadId()), 0, 0);
387 ok(hThread != INVALID_HANDLE_VALUE, "can't create thread, GetLastError: %x\n", GetLastError());
388
389 /* wine_todo: the earlier NtFsControlFile call gets cancelled after the pipe gets set into listen state
390 instead of before, so this NtFsControlFile will fail STATUS_INVALID_HANDLE */
391 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
392 todo_wine ok(res == STATUS_CANCELLED, "NtFsControlFile returned %x\n", res);
393
394 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 ok(WaitForSingleObjectEx(hEvent, 0, TRUE) == WAIT_TIMEOUT, "hEvent signaled\n");
397 ok(!ioapc_called, "IOAPC ran\n");
398
399 WaitForSingleObject(hThread, INFINITE);
400
401 SleepEx(0, TRUE); /* get rid of the userapc, if NtFsControlFile failed */
402
403 ok(open_succeeded, "couldn't open client side pipe\n");
404
405 CloseHandle(hThread);
406 DisconnectNamedPipe(hPipe);
407
408 /* finally try without an apc */
409 hThread = CreateThread(NULL, 0, &thread, 0, 0, 0);
410 ok(hThread != INVALID_HANDLE_VALUE, "can't create thread, GetLastError: %x\n", GetLastError());
411
412 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
413 todo_wine ok(!res, "NtFsControlFile returned %x\n", res);
414
415 ok(open_succeeded, "couldn't open client side pipe\n");
416 ok(!U(iosb).Status, "Wrong iostatus %x\n", U(iosb).Status);
417 todo_wine ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
418
419 WaitForSingleObject(hThread, INFINITE);
420 CloseHandle(hThread);
421 CloseHandle(hEvent);
422 CloseHandle(hPipe);
423 }
424
425 static void test_nonalertable(void)
426 {
427 IO_STATUS_BLOCK iosb;
428 HANDLE hEvent;
429 HANDLE hPipe;
430 NTSTATUS res;
431 HANDLE hThread;
432 DWORD ret;
433
434 memset(&iosb, 0x55, sizeof(iosb));
435
436 hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
437 ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError());
438
439 res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT);
440 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
441
442 hThread = CreateThread(NULL, 0, &thread, 0, 0, 0);
443 ok(hThread != INVALID_HANDLE_VALUE, "can't create thread, GetLastError: %x\n", GetLastError());
444
445 userapc_called = FALSE;
446 ret = pQueueUserAPC(&userapc, GetCurrentThread(), 0);
447 ok(ret, "can't queue user apc, GetLastError: %x\n", GetLastError());
448
449 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
450 todo_wine ok(!res, "NtFsControlFile returned %x\n", res);
451
452 ok(open_succeeded, "couldn't open client side pipe\n");
453 todo_wine ok(!U(iosb).Status, "Wrong iostatus %x\n", U(iosb).Status);
454 todo_wine ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
455
456 ok(!ioapc_called, "IOAPC ran too early\n");
457 ok(!userapc_called, "user apc ran too early\n");
458
459 SleepEx(0, TRUE); /* alertable wait state */
460
461 ok(ioapc_called, "IOAPC didn't run\n");
462 ok(userapc_called, "user apc didn't run\n");
463
464 WaitForSingleObject(hThread, INFINITE);
465 CloseHandle(hThread);
466 CloseHandle(hEvent);
467 CloseHandle(hPipe);
468 }
469
470 static void test_cancelio(void)
471 {
472 IO_STATUS_BLOCK iosb;
473 IO_STATUS_BLOCK cancel_sb;
474 HANDLE hEvent;
475 HANDLE hPipe;
476 NTSTATUS res;
477
478 hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
479 ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError());
480
481 res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
482 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
483
484 memset(&iosb, 0x55, sizeof(iosb));
485
486 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
487 ok(res == STATUS_PENDING, "NtFsControlFile returned %x\n", res);
488
489 res = pNtCancelIoFile(hPipe, &cancel_sb);
490 ok(!res, "NtCancelIoFile returned %x\n", res);
491
492 ok(U(iosb).Status == STATUS_CANCELLED, "Wrong iostatus %x\n", U(iosb).Status);
493 ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
494
495 ok(!ioapc_called, "IOAPC ran too early\n");
496
497 SleepEx(0, TRUE); /* alertable wait state */
498
499 ok(ioapc_called, "IOAPC didn't run\n");
500
501 CloseHandle(hEvent);
502 CloseHandle(hPipe);
503 }
504
505 static void _check_pipe_handle_state(int line, HANDLE handle, ULONG read, ULONG completion)
506 {
507 IO_STATUS_BLOCK iosb;
508 FILE_PIPE_INFORMATION fpi;
509 NTSTATUS res;
510 if (handle != INVALID_HANDLE_VALUE)
511 {
512 memset(&fpi, 0x55, sizeof(fpi));
513 res = pNtQueryInformationFile(handle, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
514 ok_(__FILE__, line)(!res, "NtQueryInformationFile returned %x\n", res);
515 ok_(__FILE__, line)(fpi.ReadMode == read, "Unexpected ReadMode, expected %x, got %x\n",
516 read, fpi.ReadMode);
517 ok_(__FILE__, line)(fpi.CompletionMode == completion, "Unexpected CompletionMode, expected %x, got %x\n",
518 completion, fpi.CompletionMode);
519 }
520 }
521 #define check_pipe_handle_state(handle, r, c) _check_pipe_handle_state(__LINE__, handle, r, c)
522
523 static void test_filepipeinfo(void)
524 {
525 IO_STATUS_BLOCK iosb;
526 OBJECT_ATTRIBUTES attr;
527 UNICODE_STRING name;
528 LARGE_INTEGER timeout;
529 HANDLE hServer, hClient;
530 FILE_PIPE_INFORMATION fpi;
531 NTSTATUS res;
532
533 pRtlInitUnicodeString(&name, testpipe_nt);
534
535 attr.Length = sizeof(attr);
536 attr.RootDirectory = 0;
537 attr.ObjectName = &name;
538 attr.Attributes = 0x40; /* case insensitive */
539 attr.SecurityDescriptor = NULL;
540 attr.SecurityQualityOfService = NULL;
541
542 timeout.QuadPart = -100000000;
543
544 /* test with INVALID_HANDLE_VALUE */
545 res = pNtQueryInformationFile(INVALID_HANDLE_VALUE, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
546 ok(res == STATUS_OBJECT_TYPE_MISMATCH, "NtQueryInformationFile returned %x\n", res);
547
548 fpi.ReadMode = 0;
549 fpi.CompletionMode = 0;
550 res = pNtSetInformationFile(INVALID_HANDLE_VALUE, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
551 ok(res == STATUS_OBJECT_TYPE_MISMATCH, "NtSetInformationFile returned %x\n", res);
552
553 /* server end with read-only attributes */
554 res = pNtCreateNamedPipeFile(&hServer, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb,
555 FILE_SHARE_READ | FILE_SHARE_WRITE, 2 /* FILE_CREATE */,
556 0, 0, 0, 1, 0xFFFFFFFF, 500, 500, &timeout);
557 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
558
559 check_pipe_handle_state(hServer, 0, 1);
560
561 hClient = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
562 ok(hClient != INVALID_HANDLE_VALUE || broken(GetLastError() == ERROR_PIPE_BUSY) /* > Win 8 */,
563 "can't open pipe, GetLastError: %x\n", GetLastError());
564
565 check_pipe_handle_state(hServer, 0, 1);
566 check_pipe_handle_state(hClient, 0, 0);
567
568 fpi.ReadMode = 0;
569 fpi.CompletionMode = 0;
570 res = pNtSetInformationFile(hServer, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
571 ok(res == STATUS_ACCESS_DENIED, "NtSetInformationFile returned %x\n", res);
572
573 check_pipe_handle_state(hServer, 0, 1);
574 check_pipe_handle_state(hClient, 0, 0);
575
576 fpi.ReadMode = 1; /* invalid on a byte stream pipe */
577 fpi.CompletionMode = 1;
578 res = pNtSetInformationFile(hServer, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
579 ok(res == STATUS_ACCESS_DENIED, "NtSetInformationFile returned %x\n", res);
580
581 check_pipe_handle_state(hServer, 0, 1);
582 check_pipe_handle_state(hClient, 0, 0);
583
584 if (hClient != INVALID_HANDLE_VALUE)
585 {
586 fpi.ReadMode = 1; /* invalid on a byte stream pipe */
587 fpi.CompletionMode = 1;
588 res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
589 ok(res == STATUS_INVALID_PARAMETER, "NtSetInformationFile returned %x\n", res);
590 }
591
592 check_pipe_handle_state(hServer, 0, 1);
593 check_pipe_handle_state(hClient, 0, 0);
594
595 if (hClient != INVALID_HANDLE_VALUE)
596 {
597 fpi.ReadMode = 0;
598 fpi.CompletionMode = 1;
599 res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
600 ok(!res, "NtSetInformationFile returned %x\n", res);
601 }
602
603 check_pipe_handle_state(hServer, 0, 1);
604 check_pipe_handle_state(hClient, 0, 1);
605
606 if (hClient != INVALID_HANDLE_VALUE)
607 {
608 fpi.ReadMode = 0;
609 fpi.CompletionMode = 2; /* not in range 0-1 */
610 res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
611 ok(res == STATUS_INVALID_PARAMETER || broken(!res) /* < Vista */, "NtSetInformationFile returned %x\n", res);
612
613 fpi.ReadMode = 2; /* not in range 0-1 */
614 fpi.CompletionMode = 0;
615 res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
616 ok(res == STATUS_INVALID_PARAMETER || broken(!res) /* < Vista */, "NtSetInformationFile returned %x\n", res);
617 }
618
619 CloseHandle(hClient);
620
621 check_pipe_handle_state(hServer, 0, 1);
622
623 fpi.ReadMode = 0;
624 fpi.CompletionMode = 0;
625 res = pNtSetInformationFile(hServer, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
626 ok(res == STATUS_ACCESS_DENIED, "NtSetInformationFile returned %x\n", res);
627
628 CloseHandle(hServer);
629
630 /* message mode server with read/write attributes */
631 res = pNtCreateNamedPipeFile(&hServer, FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb,
632 FILE_SHARE_READ | FILE_SHARE_WRITE, 2 /* FILE_CREATE */,
633 0, 1, 1, 0, 0xFFFFFFFF, 500, 500, &timeout);
634 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
635
636 check_pipe_handle_state(hServer, 1, 0);
637
638 hClient = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
639 ok(hClient != INVALID_HANDLE_VALUE || broken(GetLastError() == ERROR_PIPE_BUSY) /* > Win 8 */,
640 "can't open pipe, GetLastError: %x\n", GetLastError());
641
642 check_pipe_handle_state(hServer, 1, 0);
643 check_pipe_handle_state(hClient, 0, 0);
644
645 if (hClient != INVALID_HANDLE_VALUE)
646 {
647 fpi.ReadMode = 1;
648 fpi.CompletionMode = 1;
649 res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
650 ok(!res, "NtSetInformationFile returned %x\n", res);
651 }
652
653 check_pipe_handle_state(hServer, 1, 0);
654 check_pipe_handle_state(hClient, 1, 1);
655
656 fpi.ReadMode = 0;
657 fpi.CompletionMode = 1;
658 res = pNtSetInformationFile(hServer, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
659 ok(!res, "NtSetInformationFile returned %x\n", res);
660
661 check_pipe_handle_state(hServer, 0, 1);
662 check_pipe_handle_state(hClient, 1, 1);
663
664 if (hClient != INVALID_HANDLE_VALUE)
665 {
666 fpi.ReadMode = 0;
667 fpi.CompletionMode = 2; /* not in range 0-1 */
668 res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
669 ok(res == STATUS_INVALID_PARAMETER || broken(!res) /* < Vista */, "NtSetInformationFile returned %x\n", res);
670
671 fpi.ReadMode = 2; /* not in range 0-1 */
672 fpi.CompletionMode = 0;
673 res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
674 ok(res == STATUS_INVALID_PARAMETER || broken(!res) /* < Vista */, "NtSetInformationFile returned %x\n", res);
675 }
676
677 CloseHandle(hClient);
678
679 check_pipe_handle_state(hServer, 0, 1);
680
681 fpi.ReadMode = 1;
682 fpi.CompletionMode = 0;
683 res = pNtSetInformationFile(hServer, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
684 ok(!res, "NtSetInformationFile returned %x\n", res);
685
686 check_pipe_handle_state(hServer, 1, 0);
687
688 CloseHandle(hServer);
689 }
690
691 START_TEST(pipe)
692 {
693 if (!init_func_ptrs())
694 return;
695
696 trace("starting invalid create tests\n");
697 test_create_invalid();
698
699 trace("starting create tests\n");
700 test_create();
701
702 trace("starting overlapped tests\n");
703 test_overlapped();
704
705 trace("starting FILE_PIPE_INFORMATION tests\n");
706 test_filepipeinfo();
707
708 if (!pOpenThread || !pQueueUserAPC)
709 return;
710
711 trace("starting alertable tests\n");
712 test_alertable();
713
714 trace("starting nonalertable tests\n");
715 test_nonalertable();
716
717 trace("starting cancelio tests\n");
718 test_cancelio();
719 }