[NTDLL_WINETEST] Sync with Wine Staging 3.3. CORE-14434
[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 "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 *pNtQueryVolumeInformationFile)(HANDLE handle, PIO_STATUS_BLOCK io, void *buffer, ULONG length, FS_INFORMATION_CLASS info_class);
77 static NTSTATUS (WINAPI *pNtSetInformationFile) (HANDLE handle, PIO_STATUS_BLOCK io, PVOID ptr, ULONG len, FILE_INFORMATION_CLASS class);
78 static NTSTATUS (WINAPI *pNtCancelIoFile) (HANDLE hFile, PIO_STATUS_BLOCK io_status);
79 static NTSTATUS (WINAPI *pNtCancelIoFileEx) (HANDLE hFile, IO_STATUS_BLOCK *iosb, IO_STATUS_BLOCK *io_status);
80 static void (WINAPI *pRtlInitUnicodeString) (PUNICODE_STRING target, PCWSTR source);
81
82 static HANDLE (WINAPI *pOpenThread)(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId);
83 static DWORD (WINAPI *pQueueUserAPC)(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData);
84
85
86 static BOOL init_func_ptrs(void)
87 {
88 HMODULE module = GetModuleHandleA("ntdll.dll");
89
90 #define loadfunc(name) if (!(p##name = (void *)GetProcAddress(module, #name))) { \
91 trace("GetProcAddress(%s) failed\n", #name); \
92 return FALSE; \
93 }
94
95 loadfunc(NtFsControlFile)
96 loadfunc(NtCreateNamedPipeFile)
97 loadfunc(NtQueryInformationFile)
98 loadfunc(NtQueryVolumeInformationFile)
99 loadfunc(NtSetInformationFile)
100 loadfunc(NtCancelIoFile)
101 loadfunc(RtlInitUnicodeString)
102
103 /* not fatal */
104 pNtCancelIoFileEx = (void *)GetProcAddress(module, "NtCancelIoFileEx");
105 module = GetModuleHandleA("kernel32.dll");
106 pOpenThread = (void *)GetProcAddress(module, "OpenThread");
107 pQueueUserAPC = (void *)GetProcAddress(module, "QueueUserAPC");
108 return TRUE;
109 }
110
111 static inline BOOL is_signaled( HANDLE obj )
112 {
113 return WaitForSingleObject( obj, 0 ) == WAIT_OBJECT_0;
114 }
115
116 static const WCHAR testpipe[] = { '\\', '\\', '.', '\\', 'p', 'i', 'p', 'e', '\\',
117 't', 'e', 's', 't', 'p', 'i', 'p', 'e', 0 };
118 static const WCHAR testpipe_nt[] = { '\\', '?', '?', '\\', 'p', 'i', 'p', 'e', '\\',
119 't', 'e', 's', 't', 'p', 'i', 'p', 'e', 0 };
120
121 static NTSTATUS create_pipe(PHANDLE handle, ULONG sharing, ULONG options)
122 {
123 IO_STATUS_BLOCK iosb;
124 OBJECT_ATTRIBUTES attr;
125 UNICODE_STRING name;
126 LARGE_INTEGER timeout;
127 NTSTATUS res;
128
129 pRtlInitUnicodeString(&name, testpipe_nt);
130
131 attr.Length = sizeof(attr);
132 attr.RootDirectory = 0;
133 attr.ObjectName = &name;
134 attr.Attributes = 0x40; /*case insensitive */
135 attr.SecurityDescriptor = NULL;
136 attr.SecurityQualityOfService = NULL;
137
138 timeout.QuadPart = -100000000;
139
140 res = pNtCreateNamedPipeFile(handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, sharing, 2 /*FILE_CREATE*/,
141 options, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
142 return res;
143 }
144
145 static BOOL ioapc_called;
146 static void CALLBACK ioapc(void *arg, PIO_STATUS_BLOCK io, ULONG reserved)
147 {
148 ioapc_called = TRUE;
149 }
150
151 static NTSTATUS listen_pipe(HANDLE hPipe, HANDLE hEvent, PIO_STATUS_BLOCK iosb, BOOL use_apc)
152 {
153 int dummy;
154
155 ioapc_called = FALSE;
156
157 return pNtFsControlFile(hPipe, hEvent, use_apc ? &ioapc: NULL, use_apc ? &dummy: NULL, iosb, FSCTL_PIPE_LISTEN, 0, 0, 0, 0);
158 }
159
160 static void test_create_invalid(void)
161 {
162 IO_STATUS_BLOCK iosb;
163 OBJECT_ATTRIBUTES attr;
164 UNICODE_STRING name;
165 LARGE_INTEGER timeout;
166 NTSTATUS res;
167 HANDLE handle, handle2;
168 FILE_PIPE_LOCAL_INFORMATION info;
169
170 pRtlInitUnicodeString(&name, testpipe_nt);
171
172 attr.Length = sizeof(attr);
173 attr.RootDirectory = 0;
174 attr.ObjectName = &name;
175 attr.Attributes = 0x40; /*case insensitive */
176 attr.SecurityDescriptor = NULL;
177 attr.SecurityQualityOfService = NULL;
178
179 timeout.QuadPart = -100000000;
180
181 /* create a pipe with FILE_OVERWRITE */
182 res = pNtCreateNamedPipeFile(&handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ, 4 /*FILE_OVERWRITE*/,
183 0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
184 todo_wine ok(res == STATUS_INVALID_PARAMETER, "NtCreateNamedPipeFile returned %x\n", res);
185 if (!res)
186 CloseHandle(handle);
187
188 /* create a pipe with FILE_OVERWRITE_IF */
189 res = pNtCreateNamedPipeFile(&handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ, 5 /*FILE_OVERWRITE_IF*/,
190 0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
191 todo_wine ok(res == STATUS_INVALID_PARAMETER, "NtCreateNamedPipeFile returned %x\n", res);
192 if (!res)
193 CloseHandle(handle);
194
195 /* create a pipe with sharing = 0 */
196 res = pNtCreateNamedPipeFile(&handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, 0, 2 /*FILE_CREATE*/,
197 0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
198 ok(res == STATUS_INVALID_PARAMETER, "NtCreateNamedPipeFile returned %x\n", res);
199 if (!res)
200 CloseHandle(handle);
201
202 /* create a pipe without r/w access */
203 res = pNtCreateNamedPipeFile(&handle, SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, 2 /*FILE_CREATE*/,
204 0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
205 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
206
207 res = pNtQueryInformationFile(handle, &iosb, &info, sizeof(info), (FILE_INFORMATION_CLASS)24);
208 ok(res == STATUS_ACCESS_DENIED, "NtQueryInformationFile returned %x\n", res);
209
210 /* test FILE_CREATE creation disposition */
211 res = pNtCreateNamedPipeFile(&handle2, SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, 2 /*FILE_CREATE*/,
212 0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
213 todo_wine ok(res == STATUS_ACCESS_DENIED, "NtCreateNamedPipeFile returned %x\n", res);
214 if (!res)
215 CloseHandle(handle2);
216
217 CloseHandle(handle);
218 }
219
220 static void test_create(void)
221 {
222 HANDLE hserver;
223 NTSTATUS res;
224 int j, k;
225 FILE_PIPE_LOCAL_INFORMATION info;
226 IO_STATUS_BLOCK iosb;
227 HANDLE hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
228
229 static const DWORD access[] = { 0, GENERIC_READ, GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE};
230 static const DWORD sharing[] = { FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE };
231 static const DWORD pipe_config[]= { 1, 0, 2 };
232
233 for (j = 0; j < sizeof(sharing) / sizeof(DWORD); j++) {
234 for (k = 0; k < sizeof(access) / sizeof(DWORD); k++) {
235 HANDLE hclient;
236 BOOL should_succeed = TRUE;
237
238 res = create_pipe(&hserver, sharing[j], 0);
239 if (res) {
240 ok(0, "NtCreateNamedPipeFile returned %x, sharing: %x\n", res, sharing[j]);
241 continue;
242 }
243
244 res = listen_pipe(hserver, hEvent, &iosb, FALSE);
245 ok(res == STATUS_PENDING, "NtFsControlFile returned %x\n", res);
246
247 res = pNtQueryInformationFile(hserver, &iosb, &info, sizeof(info), (FILE_INFORMATION_CLASS)24);
248 ok(!res, "NtQueryInformationFile for server returned %x, sharing: %x\n", res, sharing[j]);
249 ok(info.NamedPipeConfiguration == pipe_config[j], "wrong duplex status for pipe: %d, expected %d\n",
250 info.NamedPipeConfiguration, pipe_config[j]);
251
252 hclient = CreateFileW(testpipe, access[k], 0, 0, OPEN_EXISTING, 0, 0);
253 if (hclient != INVALID_HANDLE_VALUE) {
254 res = pNtQueryInformationFile(hclient, &iosb, &info, sizeof(info), (FILE_INFORMATION_CLASS)24);
255 ok(!res, "NtQueryInformationFile for client returned %x, access: %x, sharing: %x\n",
256 res, access[k], sharing[j]);
257 ok(info.NamedPipeConfiguration == pipe_config[j], "wrong duplex status for pipe: %d, expected %d\n",
258 info.NamedPipeConfiguration, pipe_config[j]);
259
260 res = listen_pipe(hclient, hEvent, &iosb, FALSE);
261 ok(res == STATUS_ILLEGAL_FUNCTION, "expected STATUS_ILLEGAL_FUNCTION, got %x\n", res);
262 CloseHandle(hclient);
263 }
264
265 if (access[k] & GENERIC_WRITE)
266 should_succeed &= !!(sharing[j] & FILE_SHARE_WRITE);
267 if (access[k] & GENERIC_READ)
268 should_succeed &= !!(sharing[j] & FILE_SHARE_READ);
269
270 if (should_succeed)
271 ok(hclient != INVALID_HANDLE_VALUE, "CreateFile failed for sharing %x, access: %x, GetLastError: %d\n",
272 sharing[j], access[k], GetLastError());
273 else
274 ok(hclient == INVALID_HANDLE_VALUE, "CreateFile succeeded for sharing %x, access: %x\n", sharing[j], access[k]);
275
276 CloseHandle(hserver);
277 }
278 }
279 CloseHandle(hEvent);
280 }
281
282 static void test_overlapped(void)
283 {
284 IO_STATUS_BLOCK iosb;
285 HANDLE hEvent;
286 HANDLE hPipe;
287 HANDLE hClient;
288 NTSTATUS res;
289
290 hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
291 ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError());
292
293 res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
294 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
295
296 memset(&iosb, 0x55, sizeof(iosb));
297 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
298 ok(res == STATUS_PENDING, "NtFsControlFile returned %x\n", res);
299 ok(U(iosb).Status == 0x55555555, "iosb.Status got changed to %x\n", U(iosb).Status);
300
301 hClient = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
302 ok(hClient != INVALID_HANDLE_VALUE, "can't open pipe, GetLastError: %x\n", GetLastError());
303
304 ok(U(iosb).Status == 0, "Wrong iostatus %x\n", U(iosb).Status);
305 ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
306
307 ok(!ioapc_called, "IOAPC ran too early\n");
308
309 SleepEx(0, TRUE); /* alertable wait state */
310
311 ok(ioapc_called, "IOAPC didn't run\n");
312
313 CloseHandle(hPipe);
314 CloseHandle(hClient);
315
316 res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
317 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
318
319 hClient = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
320 ok(hClient != INVALID_HANDLE_VALUE || broken(GetLastError() == ERROR_PIPE_BUSY) /* > Win 8 */,
321 "can't open pipe, GetLastError: %x\n", GetLastError());
322
323 if (hClient != INVALID_HANDLE_VALUE)
324 {
325 SetEvent(hEvent);
326 memset(&iosb, 0x55, sizeof(iosb));
327 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
328 ok(res == STATUS_PIPE_CONNECTED, "NtFsControlFile returned %x\n", res);
329 ok(U(iosb).Status == 0x55555555, "iosb.Status got changed to %x\n", U(iosb).Status);
330 ok(!is_signaled(hEvent), "hEvent not signaled\n");
331
332 CloseHandle(hClient);
333 }
334
335 CloseHandle(hPipe);
336 CloseHandle(hEvent);
337 }
338
339 static void test_completion(void)
340 {
341 static const char buf[] = "testdata";
342 FILE_IO_COMPLETION_NOTIFICATION_INFORMATION info;
343 HANDLE port, pipe, client;
344 IO_STATUS_BLOCK iosb;
345 OVERLAPPED ov, *pov;
346 IO_STATUS_BLOCK io;
347 NTSTATUS status;
348 DWORD num_bytes;
349 ULONG_PTR key;
350 DWORD dwret;
351 BOOL ret;
352
353 memset(&ov, 0, sizeof(ov));
354 ov.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
355 ok(ov.hEvent != INVALID_HANDLE_VALUE, "CreateEvent failed, error %u\n", GetLastError());
356
357 status = create_pipe(&pipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
358 ok(!status, "NtCreateNamedPipeFile returned %x\n", status);
359 status = listen_pipe(pipe, ov.hEvent, &iosb, FALSE);
360 ok(status == STATUS_PENDING, "NtFsControlFile returned %x\n", status);
361
362 client = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0,
363 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
364 ok(client != INVALID_HANDLE_VALUE, "CreateFile failed, error %u\n", GetLastError());
365 dwret = WaitForSingleObject(ov.hEvent, 0);
366 ok(dwret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", dwret);
367
368 port = CreateIoCompletionPort(client, NULL, 0xdeadbeef, 0);
369 ok(port != NULL, "CreateIoCompletionPort failed, error %u\n", GetLastError());
370
371 ret = WriteFile(client, buf, sizeof(buf), &num_bytes, &ov);
372 ok(ret, "WriteFile failed, error %u\n", GetLastError());
373 ok(num_bytes == sizeof(buf), "expected sizeof(buf), got %u\n", num_bytes);
374
375 key = 0;
376 pov = NULL;
377 ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 1000);
378 ok(ret, "GetQueuedCompletionStatus failed, error %u\n", GetLastError());
379 ok(key == 0xdeadbeef, "expected 0xdeadbeef, got %lx\n", key);
380 ok(pov == &ov, "expected %p, got %p\n", &ov, pov);
381
382 info.Flags = FILE_SKIP_COMPLETION_PORT_ON_SUCCESS;
383 status = pNtSetInformationFile(client, &io, &info, sizeof(info), FileIoCompletionNotificationInformation);
384 ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
385
386 info.Flags = 0;
387 status = pNtQueryInformationFile(client, &io, &info, sizeof(info), FileIoCompletionNotificationInformation);
388 ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
389 ok((info.Flags & FILE_SKIP_COMPLETION_PORT_ON_SUCCESS) != 0, "got %08x\n", info.Flags);
390
391 ret = WriteFile(client, buf, sizeof(buf), &num_bytes, &ov);
392 ok(ret, "WriteFile failed, error %u\n", GetLastError());
393 ok(num_bytes == sizeof(buf), "expected sizeof(buf), got %u\n", num_bytes);
394
395 pov = (void *)0xdeadbeef;
396 ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 1000);
397 ok(!ret, "GetQueuedCompletionStatus succeeded\n");
398 ok(pov == NULL, "expected NULL, got %p\n", pov);
399
400 CloseHandle(ov.hEvent);
401 CloseHandle(client);
402 CloseHandle(pipe);
403 CloseHandle(port);
404 }
405
406 static BOOL userapc_called;
407 static void CALLBACK userapc(ULONG_PTR dwParam)
408 {
409 userapc_called = TRUE;
410 }
411
412 static BOOL open_succeeded;
413 static DWORD WINAPI thread(PVOID main_thread)
414 {
415 HANDLE h;
416
417 Sleep(400);
418
419 if (main_thread) {
420 DWORD ret;
421 userapc_called = FALSE;
422 ret = pQueueUserAPC(&userapc, main_thread, 0);
423 ok(ret, "can't queue user apc, GetLastError: %x\n", GetLastError());
424 CloseHandle(main_thread);
425 }
426
427 Sleep(400);
428
429 h = CreateFileW(testpipe, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
430
431 if (h != INVALID_HANDLE_VALUE) {
432 open_succeeded = TRUE;
433 Sleep(100);
434 CloseHandle(h);
435 } else
436 open_succeeded = FALSE;
437
438 return 0;
439 }
440
441 static void test_alertable(void)
442 {
443 IO_STATUS_BLOCK iosb;
444 HANDLE hEvent;
445 HANDLE hPipe;
446 NTSTATUS res;
447 HANDLE hThread;
448 DWORD ret;
449
450 memset(&iosb, 0x55, sizeof(iosb));
451
452 hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
453 ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError());
454
455 res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_ALERT);
456 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
457
458 /* queue an user apc before calling listen */
459 userapc_called = FALSE;
460 ret = pQueueUserAPC(&userapc, GetCurrentThread(), 0);
461 ok(ret, "can't queue user apc, GetLastError: %x\n", GetLastError());
462
463 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
464 todo_wine ok(res == STATUS_CANCELLED, "NtFsControlFile returned %x\n", res);
465
466 todo_wine ok(userapc_called, "user apc didn't run\n");
467 ok(U(iosb).Status == 0x55555555, "iosb.Status got changed to %x\n", U(iosb).Status);
468 todo_wine ok(WaitForSingleObjectEx(hEvent, 0, TRUE) == WAIT_TIMEOUT, "hEvent signaled\n");
469 ok(!ioapc_called, "IOAPC ran\n");
470
471 /* queue an user apc from a different thread */
472 hThread = CreateThread(NULL, 0, &thread, pOpenThread(MAXIMUM_ALLOWED, FALSE, GetCurrentThreadId()), 0, 0);
473 ok(hThread != INVALID_HANDLE_VALUE, "can't create thread, GetLastError: %x\n", GetLastError());
474
475 /* wine_todo: the earlier NtFsControlFile call gets cancelled after the pipe gets set into listen state
476 instead of before, so this NtFsControlFile will fail STATUS_INVALID_HANDLE */
477 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
478 todo_wine ok(res == STATUS_CANCELLED, "NtFsControlFile returned %x\n", res);
479
480 ok(userapc_called, "user apc didn't run\n");
481 ok(U(iosb).Status == 0x55555555, "iosb.Status got changed to %x\n", U(iosb).Status);
482 ok(WaitForSingleObjectEx(hEvent, 0, TRUE) == WAIT_TIMEOUT, "hEvent signaled\n");
483 ok(!ioapc_called, "IOAPC ran\n");
484
485 WaitForSingleObject(hThread, INFINITE);
486
487 SleepEx(0, TRUE); /* get rid of the userapc, if NtFsControlFile failed */
488
489 ok(open_succeeded, "couldn't open client side pipe\n");
490
491 CloseHandle(hThread);
492 DisconnectNamedPipe(hPipe);
493
494 /* finally try without an apc */
495 hThread = CreateThread(NULL, 0, &thread, 0, 0, 0);
496 ok(hThread != INVALID_HANDLE_VALUE, "can't create thread, GetLastError: %x\n", GetLastError());
497
498 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
499 todo_wine ok(!res, "NtFsControlFile returned %x\n", res);
500
501 ok(open_succeeded, "couldn't open client side pipe\n");
502 ok(!U(iosb).Status, "Wrong iostatus %x\n", U(iosb).Status);
503 todo_wine ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
504
505 WaitForSingleObject(hThread, INFINITE);
506 CloseHandle(hThread);
507 CloseHandle(hEvent);
508 CloseHandle(hPipe);
509 }
510
511 static void test_nonalertable(void)
512 {
513 IO_STATUS_BLOCK iosb;
514 HANDLE hEvent;
515 HANDLE hPipe;
516 NTSTATUS res;
517 HANDLE hThread;
518 DWORD ret;
519
520 memset(&iosb, 0x55, sizeof(iosb));
521
522 hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
523 ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError());
524
525 res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT);
526 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
527
528 hThread = CreateThread(NULL, 0, &thread, 0, 0, 0);
529 ok(hThread != INVALID_HANDLE_VALUE, "can't create thread, GetLastError: %x\n", GetLastError());
530
531 userapc_called = FALSE;
532 ret = pQueueUserAPC(&userapc, GetCurrentThread(), 0);
533 ok(ret, "can't queue user apc, GetLastError: %x\n", GetLastError());
534
535 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
536 todo_wine ok(!res, "NtFsControlFile returned %x\n", res);
537
538 ok(open_succeeded, "couldn't open client side pipe\n");
539 todo_wine ok(!U(iosb).Status, "Wrong iostatus %x\n", U(iosb).Status);
540 todo_wine ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
541
542 ok(!ioapc_called, "IOAPC ran too early\n");
543 ok(!userapc_called, "user apc ran too early\n");
544
545 SleepEx(0, TRUE); /* alertable wait state */
546
547 ok(ioapc_called, "IOAPC didn't run\n");
548 ok(userapc_called, "user apc didn't run\n");
549
550 WaitForSingleObject(hThread, INFINITE);
551 CloseHandle(hThread);
552 CloseHandle(hEvent);
553 CloseHandle(hPipe);
554 }
555
556 static void test_cancelio(void)
557 {
558 IO_STATUS_BLOCK iosb;
559 IO_STATUS_BLOCK cancel_sb;
560 HANDLE hEvent;
561 HANDLE hPipe;
562 NTSTATUS res;
563
564 hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
565 ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError());
566
567 res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
568 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
569
570 memset(&iosb, 0x55, sizeof(iosb));
571
572 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
573 ok(res == STATUS_PENDING, "NtFsControlFile returned %x\n", res);
574
575 res = pNtCancelIoFile(hPipe, &cancel_sb);
576 ok(!res, "NtCancelIoFile returned %x\n", res);
577
578 ok(U(iosb).Status == STATUS_CANCELLED, "Wrong iostatus %x\n", U(iosb).Status);
579 ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
580
581 ok(!ioapc_called, "IOAPC ran too early\n");
582
583 SleepEx(0, TRUE); /* alertable wait state */
584
585 ok(ioapc_called, "IOAPC didn't run\n");
586
587 CloseHandle(hPipe);
588
589 if (pNtCancelIoFileEx)
590 {
591 res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
592 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
593
594 memset(&iosb, 0x55, sizeof(iosb));
595 res = listen_pipe(hPipe, hEvent, &iosb, FALSE);
596 ok(res == STATUS_PENDING, "NtFsControlFile returned %x\n", res);
597
598 res = pNtCancelIoFileEx(hPipe, &iosb, &cancel_sb);
599 ok(!res, "NtCancelIoFileEx returned %x\n", res);
600
601 ok(U(iosb).Status == STATUS_CANCELLED, "Wrong iostatus %x\n", U(iosb).Status);
602 ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
603
604 CloseHandle(hPipe);
605 }
606 else
607 win_skip("NtCancelIoFileEx not available\n");
608
609 CloseHandle(hEvent);
610 }
611
612 static void _check_pipe_handle_state(int line, HANDLE handle, ULONG read, ULONG completion)
613 {
614 IO_STATUS_BLOCK iosb;
615 FILE_PIPE_INFORMATION fpi;
616 NTSTATUS res;
617 if (handle != INVALID_HANDLE_VALUE)
618 {
619 memset(&fpi, 0x55, sizeof(fpi));
620 res = pNtQueryInformationFile(handle, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
621 ok_(__FILE__, line)(!res, "NtQueryInformationFile returned %x\n", res);
622 ok_(__FILE__, line)(fpi.ReadMode == read, "Unexpected ReadMode, expected %x, got %x\n",
623 read, fpi.ReadMode);
624 ok_(__FILE__, line)(fpi.CompletionMode == completion, "Unexpected CompletionMode, expected %x, got %x\n",
625 completion, fpi.CompletionMode);
626 }
627 }
628 #define check_pipe_handle_state(handle, r, c) _check_pipe_handle_state(__LINE__, handle, r, c)
629
630 static void test_filepipeinfo(void)
631 {
632 IO_STATUS_BLOCK iosb;
633 OBJECT_ATTRIBUTES attr;
634 UNICODE_STRING name;
635 LARGE_INTEGER timeout;
636 HANDLE hServer, hClient;
637 FILE_PIPE_INFORMATION fpi;
638 NTSTATUS res;
639
640 pRtlInitUnicodeString(&name, testpipe_nt);
641
642 attr.Length = sizeof(attr);
643 attr.RootDirectory = 0;
644 attr.ObjectName = &name;
645 attr.Attributes = 0x40; /* case insensitive */
646 attr.SecurityDescriptor = NULL;
647 attr.SecurityQualityOfService = NULL;
648
649 timeout.QuadPart = -100000000;
650
651 /* test with INVALID_HANDLE_VALUE */
652 res = pNtQueryInformationFile(INVALID_HANDLE_VALUE, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
653 ok(res == STATUS_OBJECT_TYPE_MISMATCH, "NtQueryInformationFile returned %x\n", res);
654
655 fpi.ReadMode = 0;
656 fpi.CompletionMode = 0;
657 res = pNtSetInformationFile(INVALID_HANDLE_VALUE, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
658 ok(res == STATUS_OBJECT_TYPE_MISMATCH, "NtSetInformationFile returned %x\n", res);
659
660 /* server end with read-only attributes */
661 res = pNtCreateNamedPipeFile(&hServer, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb,
662 FILE_SHARE_READ | FILE_SHARE_WRITE, 2 /* FILE_CREATE */,
663 0, 0, 0, 1, 0xFFFFFFFF, 500, 500, &timeout);
664 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
665
666 check_pipe_handle_state(hServer, 0, 1);
667
668 hClient = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
669 ok(hClient != INVALID_HANDLE_VALUE || broken(GetLastError() == ERROR_PIPE_BUSY) /* > Win 8 */,
670 "can't open pipe, GetLastError: %x\n", GetLastError());
671
672 check_pipe_handle_state(hServer, 0, 1);
673 check_pipe_handle_state(hClient, 0, 0);
674
675 fpi.ReadMode = 0;
676 fpi.CompletionMode = 0;
677 res = pNtSetInformationFile(hServer, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
678 ok(res == STATUS_ACCESS_DENIED, "NtSetInformationFile returned %x\n", res);
679
680 check_pipe_handle_state(hServer, 0, 1);
681 check_pipe_handle_state(hClient, 0, 0);
682
683 fpi.ReadMode = 1; /* invalid on a byte stream pipe */
684 fpi.CompletionMode = 1;
685 res = pNtSetInformationFile(hServer, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
686 ok(res == STATUS_ACCESS_DENIED, "NtSetInformationFile returned %x\n", res);
687
688 check_pipe_handle_state(hServer, 0, 1);
689 check_pipe_handle_state(hClient, 0, 0);
690
691 if (hClient != INVALID_HANDLE_VALUE)
692 {
693 fpi.ReadMode = 1; /* invalid on a byte stream pipe */
694 fpi.CompletionMode = 1;
695 res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
696 ok(res == STATUS_INVALID_PARAMETER, "NtSetInformationFile returned %x\n", res);
697 }
698
699 check_pipe_handle_state(hServer, 0, 1);
700 check_pipe_handle_state(hClient, 0, 0);
701
702 if (hClient != INVALID_HANDLE_VALUE)
703 {
704 fpi.ReadMode = 0;
705 fpi.CompletionMode = 1;
706 res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
707 ok(!res, "NtSetInformationFile returned %x\n", res);
708 }
709
710 check_pipe_handle_state(hServer, 0, 1);
711 check_pipe_handle_state(hClient, 0, 1);
712
713 if (hClient != INVALID_HANDLE_VALUE)
714 {
715 fpi.ReadMode = 0;
716 fpi.CompletionMode = 2; /* not in range 0-1 */
717 res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
718 ok(res == STATUS_INVALID_PARAMETER || broken(!res) /* < Vista */, "NtSetInformationFile returned %x\n", res);
719
720 fpi.ReadMode = 2; /* not in range 0-1 */
721 fpi.CompletionMode = 0;
722 res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
723 ok(res == STATUS_INVALID_PARAMETER || broken(!res) /* < Vista */, "NtSetInformationFile returned %x\n", res);
724 }
725
726 CloseHandle(hClient);
727
728 check_pipe_handle_state(hServer, 0, 1);
729
730 fpi.ReadMode = 0;
731 fpi.CompletionMode = 0;
732 res = pNtSetInformationFile(hServer, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
733 ok(res == STATUS_ACCESS_DENIED, "NtSetInformationFile returned %x\n", res);
734
735 CloseHandle(hServer);
736
737 /* message mode server with read/write attributes */
738 res = pNtCreateNamedPipeFile(&hServer, FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb,
739 FILE_SHARE_READ | FILE_SHARE_WRITE, 2 /* FILE_CREATE */,
740 0, 1, 1, 0, 0xFFFFFFFF, 500, 500, &timeout);
741 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
742
743 check_pipe_handle_state(hServer, 1, 0);
744
745 hClient = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
746 ok(hClient != INVALID_HANDLE_VALUE || broken(GetLastError() == ERROR_PIPE_BUSY) /* > Win 8 */,
747 "can't open pipe, GetLastError: %x\n", GetLastError());
748
749 check_pipe_handle_state(hServer, 1, 0);
750 check_pipe_handle_state(hClient, 0, 0);
751
752 if (hClient != INVALID_HANDLE_VALUE)
753 {
754 fpi.ReadMode = 1;
755 fpi.CompletionMode = 1;
756 res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
757 ok(!res, "NtSetInformationFile returned %x\n", res);
758 }
759
760 check_pipe_handle_state(hServer, 1, 0);
761 check_pipe_handle_state(hClient, 1, 1);
762
763 fpi.ReadMode = 0;
764 fpi.CompletionMode = 1;
765 res = pNtSetInformationFile(hServer, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
766 ok(!res, "NtSetInformationFile returned %x\n", res);
767
768 check_pipe_handle_state(hServer, 0, 1);
769 check_pipe_handle_state(hClient, 1, 1);
770
771 if (hClient != INVALID_HANDLE_VALUE)
772 {
773 fpi.ReadMode = 0;
774 fpi.CompletionMode = 2; /* not in range 0-1 */
775 res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
776 ok(res == STATUS_INVALID_PARAMETER || broken(!res) /* < Vista */, "NtSetInformationFile returned %x\n", res);
777
778 fpi.ReadMode = 2; /* not in range 0-1 */
779 fpi.CompletionMode = 0;
780 res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
781 ok(res == STATUS_INVALID_PARAMETER || broken(!res) /* < Vista */, "NtSetInformationFile returned %x\n", res);
782 }
783
784 CloseHandle(hClient);
785
786 check_pipe_handle_state(hServer, 0, 1);
787
788 fpi.ReadMode = 1;
789 fpi.CompletionMode = 0;
790 res = pNtSetInformationFile(hServer, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
791 ok(!res, "NtSetInformationFile returned %x\n", res);
792
793 check_pipe_handle_state(hServer, 1, 0);
794
795 CloseHandle(hServer);
796 }
797
798 static void WINAPI apc( void *arg, IO_STATUS_BLOCK *iosb, ULONG reserved )
799 {
800 int *count = arg;
801 (*count)++;
802 ok( !reserved, "reserved is not 0: %x\n", reserved );
803 }
804
805 static void test_peek(HANDLE pipe)
806 {
807 FILE_PIPE_PEEK_BUFFER buf;
808 IO_STATUS_BLOCK iosb;
809 HANDLE event = CreateEventA( NULL, TRUE, FALSE, NULL );
810 NTSTATUS status;
811
812 memset(&iosb, 0x55, sizeof(iosb));
813 status = NtFsControlFile(pipe, NULL, NULL, NULL, &iosb, FSCTL_PIPE_PEEK, NULL, 0, &buf, sizeof(buf));
814 ok(!status || status == STATUS_PENDING, "NtFsControlFile failed: %x\n", status);
815 ok(!iosb.Status, "iosb.Status = %x\n", iosb.Status);
816 ok(buf.ReadDataAvailable == 1, "ReadDataAvailable = %u\n", buf.ReadDataAvailable);
817
818 ResetEvent(event);
819 memset(&iosb, 0x55, sizeof(iosb));
820 status = NtFsControlFile(pipe, event, NULL, NULL, &iosb, FSCTL_PIPE_PEEK, NULL, 0, &buf, sizeof(buf));
821 ok(!status || status == STATUS_PENDING, "NtFsControlFile failed: %x\n", status);
822 ok(buf.ReadDataAvailable == 1, "ReadDataAvailable = %u\n", buf.ReadDataAvailable);
823 ok(!iosb.Status, "iosb.Status = %x\n", iosb.Status);
824 ok(is_signaled(event), "event is not signaled\n");
825
826 CloseHandle(event);
827 }
828
829 #define PIPENAME "\\\\.\\pipe\\ntdll_tests_pipe.c"
830
831 static BOOL create_pipe_pair( HANDLE *read, HANDLE *write, ULONG flags, ULONG type, ULONG size )
832 {
833 const BOOL server_reader = flags & PIPE_ACCESS_INBOUND;
834 HANDLE client, server;
835
836 server = CreateNamedPipeA(PIPENAME, flags, PIPE_WAIT | type,
837 1, size, size, NMPWAIT_USE_DEFAULT_WAIT, NULL);
838 ok(server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
839
840 client = CreateFileA(PIPENAME, server_reader ? GENERIC_WRITE : GENERIC_READ | FILE_WRITE_ATTRIBUTES, 0,
841 NULL, OPEN_EXISTING, flags & FILE_FLAG_OVERLAPPED, 0);
842 ok(client != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError());
843
844 if(server_reader)
845 {
846 *read = server;
847 *write = client;
848 }
849 else
850 {
851 if(type & PIPE_READMODE_MESSAGE)
852 {
853 DWORD read_mode = PIPE_READMODE_MESSAGE;
854 ok(SetNamedPipeHandleState(client, &read_mode, NULL, NULL), "Change mode\n");
855 }
856
857 *read = client;
858 *write = server;
859 }
860 return TRUE;
861 }
862
863 static void read_pipe_test(ULONG pipe_flags, ULONG pipe_type)
864 {
865 IO_STATUS_BLOCK iosb, iosb2;
866 HANDLE handle, read, write;
867 HANDLE event = CreateEventA( NULL, TRUE, FALSE, NULL );
868 int apc_count = 0;
869 char buffer[128];
870 DWORD written;
871 BOOL ret;
872 NTSTATUS status;
873
874 if (!create_pipe_pair( &read, &write, FILE_FLAG_OVERLAPPED | pipe_flags, pipe_type, 4096 )) return;
875
876 /* try read with no data */
877 U(iosb).Status = 0xdeadbabe;
878 iosb.Information = 0xdeadbeef;
879 ok( is_signaled( read ), "read handle is not signaled\n" );
880 status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
881 ok( status == STATUS_PENDING, "wrong status %x\n", status );
882 ok( !is_signaled( read ), "read handle is signaled\n" );
883 ok( !is_signaled( event ), "event is signaled\n" );
884 ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
885 ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
886 ok( !apc_count, "apc was called\n" );
887 ret = WriteFile( write, buffer, 1, &written, NULL );
888 ok(ret && written == 1, "WriteFile error %d\n", GetLastError());
889 /* iosb updated here by async i/o */
890 ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
891 ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
892 ok( !is_signaled( read ), "read handle is signaled\n" );
893 ok( is_signaled( event ), "event is not signaled\n" );
894 ok( !apc_count, "apc was called\n" );
895 apc_count = 0;
896 SleepEx( 1, FALSE ); /* non-alertable sleep */
897 ok( !apc_count, "apc was called\n" );
898 SleepEx( 1, TRUE ); /* alertable sleep */
899 ok( apc_count == 1, "apc not called\n" );
900
901 /* with no event, the pipe handle itself gets signaled */
902 apc_count = 0;
903 U(iosb).Status = 0xdeadbabe;
904 iosb.Information = 0xdeadbeef;
905 ok( !is_signaled( read ), "read handle is signaled\n" );
906 status = NtReadFile( read, 0, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
907 ok( status == STATUS_PENDING, "wrong status %x\n", status );
908 ok( !is_signaled( read ), "read handle is signaled\n" );
909 ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
910 ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
911 ok( !apc_count, "apc was called\n" );
912 ret = WriteFile( write, buffer, 1, &written, NULL );
913 ok(ret && written == 1, "WriteFile error %d\n", GetLastError());
914 /* iosb updated here by async i/o */
915 ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
916 ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
917 ok( is_signaled( read ), "read handle is not signaled\n" );
918 ok( !apc_count, "apc was called\n" );
919 apc_count = 0;
920 SleepEx( 1, FALSE ); /* non-alertable sleep */
921 ok( !apc_count, "apc was called\n" );
922 SleepEx( 1, TRUE ); /* alertable sleep */
923 ok( apc_count == 1, "apc not called\n" );
924
925 /* now read with data ready */
926 apc_count = 0;
927 U(iosb).Status = 0xdeadbabe;
928 iosb.Information = 0xdeadbeef;
929 ResetEvent( event );
930 ret = WriteFile( write, buffer, 1, &written, NULL );
931 ok(ret && written == 1, "WriteFile error %d\n", GetLastError());
932
933 test_peek(read);
934
935 status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
936 ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
937 ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
938 ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
939 ok( is_signaled( event ), "event is not signaled\n" );
940 ok( !apc_count, "apc was called\n" );
941 SleepEx( 1, FALSE ); /* non-alertable sleep */
942 ok( !apc_count, "apc was called\n" );
943 SleepEx( 1, TRUE ); /* alertable sleep */
944 ok( apc_count == 1, "apc not called\n" );
945
946 /* now partial read with data ready */
947 apc_count = 0;
948 U(iosb).Status = 0xdeadbabe;
949 iosb.Information = 0xdeadbeef;
950 ResetEvent( event );
951 ret = WriteFile( write, buffer, 2, &written, NULL );
952 ok(ret && written == 2, "WriteFile error %d\n", GetLastError());
953 status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
954 if (pipe_type & PIPE_READMODE_MESSAGE)
955 {
956 ok( status == STATUS_BUFFER_OVERFLOW, "wrong status %x\n", status );
957 ok( U(iosb).Status == STATUS_BUFFER_OVERFLOW, "wrong status %x\n", U(iosb).Status );
958 }
959 else
960 {
961 ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
962 ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
963 }
964 ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
965 ok( is_signaled( event ), "event is not signaled\n" );
966 ok( !apc_count, "apc was called\n" );
967 SleepEx( 1, FALSE ); /* non-alertable sleep */
968 ok( !apc_count, "apc was called\n" );
969 SleepEx( 1, TRUE ); /* alertable sleep */
970 ok( apc_count == 1, "apc not called\n" );
971 apc_count = 0;
972 status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
973 ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
974 ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
975 ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
976 ok( is_signaled( event ), "event is not signaled\n" );
977 ok( !apc_count, "apc was called\n" );
978 SleepEx( 1, FALSE ); /* non-alertable sleep */
979 ok( !apc_count, "apc was called\n" );
980 SleepEx( 1, TRUE ); /* alertable sleep */
981 ok( apc_count == 1, "apc not called\n" );
982
983 /* try read with no data */
984 apc_count = 0;
985 U(iosb).Status = 0xdeadbabe;
986 iosb.Information = 0xdeadbeef;
987 ok( is_signaled( event ), "event is not signaled\n" ); /* check that read resets the event */
988 status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
989 ok( status == STATUS_PENDING, "wrong status %x\n", status );
990 ok( !is_signaled( event ), "event is signaled\n" );
991 ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
992 ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
993 ok( !apc_count, "apc was called\n" );
994 ret = WriteFile( write, buffer, 1, &written, NULL );
995 ok(ret && written == 1, "WriteFile error %d\n", GetLastError());
996 /* partial read is good enough */
997 Sleep(1); /* FIXME: needed for wine to run the i/o apc */
998 ok( is_signaled( event ), "event is not signaled\n" );
999 ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
1000 ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
1001 ok( !apc_count, "apc was called\n" );
1002 SleepEx( 1, TRUE ); /* alertable sleep */
1003 ok( apc_count == 1, "apc was not called\n" );
1004
1005 /* read from disconnected pipe */
1006 apc_count = 0;
1007 U(iosb).Status = 0xdeadbabe;
1008 iosb.Information = 0xdeadbeef;
1009 CloseHandle( write );
1010 status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
1011 ok( status == STATUS_PIPE_BROKEN, "wrong status %x\n", status );
1012 ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
1013 ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
1014 ok( !is_signaled( event ), "event is signaled\n" );
1015 ok( !apc_count, "apc was called\n" );
1016 SleepEx( 1, TRUE ); /* alertable sleep */
1017 ok( !apc_count, "apc was called\n" );
1018 CloseHandle( read );
1019
1020 /* read from disconnected pipe, with invalid event handle */
1021 apc_count = 0;
1022 U(iosb).Status = 0xdeadbabe;
1023 iosb.Information = 0xdeadbeef;
1024 status = NtReadFile( read, (HANDLE)0xdeadbeef, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
1025 ok( status == STATUS_INVALID_HANDLE, "wrong status %x\n", status );
1026 ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
1027 ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
1028 ok( !apc_count, "apc was called\n" );
1029 SleepEx( 1, TRUE ); /* alertable sleep */
1030 ok( !apc_count, "apc was called\n" );
1031 CloseHandle( read );
1032
1033 /* read from closed handle */
1034 apc_count = 0;
1035 U(iosb).Status = 0xdeadbabe;
1036 iosb.Information = 0xdeadbeef;
1037 SetEvent( event );
1038 status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
1039 ok( status == STATUS_INVALID_HANDLE, "wrong status %x\n", status );
1040 ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
1041 ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
1042 ok( is_signaled( event ), "event is not signaled\n" ); /* not reset on invalid handle */
1043 ok( !apc_count, "apc was called\n" );
1044 SleepEx( 1, TRUE ); /* alertable sleep */
1045 ok( !apc_count, "apc was called\n" );
1046
1047 /* disconnect while async read is in progress */
1048 if (!create_pipe_pair( &read, &write, FILE_FLAG_OVERLAPPED | pipe_flags, pipe_type, 4096 )) return;
1049 apc_count = 0;
1050 U(iosb).Status = 0xdeadbabe;
1051 iosb.Information = 0xdeadbeef;
1052 status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
1053 ok( status == STATUS_PENDING, "wrong status %x\n", status );
1054 ok( !is_signaled( event ), "event is signaled\n" );
1055 ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
1056 ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
1057 ok( !apc_count, "apc was called\n" );
1058 CloseHandle( write );
1059 Sleep(1); /* FIXME: needed for wine to run the i/o apc */
1060 ok( U(iosb).Status == STATUS_PIPE_BROKEN, "wrong status %x\n", U(iosb).Status );
1061 ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
1062 ok( is_signaled( event ), "event is not signaled\n" );
1063 ok( !apc_count, "apc was called\n" );
1064 SleepEx( 1, TRUE ); /* alertable sleep */
1065 ok( apc_count == 1, "apc was not called\n" );
1066 CloseHandle( read );
1067
1068 if (!create_pipe_pair( &read, &write, FILE_FLAG_OVERLAPPED | pipe_flags, pipe_type, 4096 )) return;
1069 ret = DuplicateHandle(GetCurrentProcess(), read, GetCurrentProcess(), &handle, 0, TRUE, DUPLICATE_SAME_ACCESS);
1070 ok(ret, "Failed to duplicate handle: %d\n", GetLastError());
1071
1072 apc_count = 0;
1073 U(iosb).Status = 0xdeadbabe;
1074 iosb.Information = 0xdeadbeef;
1075 status = NtReadFile( handle, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
1076 ok( status == STATUS_PENDING, "wrong status %x\n", status );
1077 ok( !is_signaled( event ), "event is signaled\n" );
1078 ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
1079 ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
1080 ok( !apc_count, "apc was called\n" );
1081 /* Cancel by other handle */
1082 status = pNtCancelIoFile( read, &iosb2 );
1083 ok(status == STATUS_SUCCESS, "failed to cancel by different handle: %x\n", status);
1084 Sleep(1); /* FIXME: needed for wine to run the i/o apc */
1085 ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
1086 ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
1087 ok( is_signaled( event ), "event is not signaled\n" );
1088 ok( !apc_count, "apc was called\n" );
1089 SleepEx( 1, TRUE ); /* alertable sleep */
1090 ok( apc_count == 1, "apc was not called\n" );
1091
1092 apc_count = 0;
1093 U(iosb).Status = 0xdeadbabe;
1094 iosb.Information = 0xdeadbeef;
1095 status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
1096 ok( status == STATUS_PENDING, "wrong status %x\n", status );
1097 ok( !is_signaled( event ), "event is signaled\n" );
1098 ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
1099 ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
1100 ok( !apc_count, "apc was called\n" );
1101 /* Close queued handle */
1102 CloseHandle( read );
1103 SleepEx( 1, TRUE ); /* alertable sleep */
1104 ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
1105 ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
1106 status = pNtCancelIoFile( read, &iosb2 );
1107 ok(status == STATUS_INVALID_HANDLE, "cancelled by closed handle?\n");
1108 status = pNtCancelIoFile( handle, &iosb2 );
1109 ok(status == STATUS_SUCCESS, "failed to cancel: %x\n", status);
1110 Sleep(1); /* FIXME: needed for wine to run the i/o apc */
1111 ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
1112 ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
1113 ok( is_signaled( event ), "event is not signaled\n" );
1114 ok( !apc_count, "apc was called\n" );
1115 SleepEx( 1, TRUE ); /* alertable sleep */
1116 ok( apc_count == 1, "apc was not called\n" );
1117 CloseHandle( handle );
1118 CloseHandle( write );
1119
1120 if (pNtCancelIoFileEx)
1121 {
1122 /* Basic Cancel Ex */
1123 if (!create_pipe_pair( &read, &write, FILE_FLAG_OVERLAPPED | pipe_flags, pipe_type, 4096 )) return;
1124
1125 apc_count = 0;
1126 U(iosb).Status = 0xdeadbabe;
1127 iosb.Information = 0xdeadbeef;
1128 status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
1129 ok( status == STATUS_PENDING, "wrong status %x\n", status );
1130 ok( !is_signaled( event ), "event is signaled\n" );
1131 ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
1132 ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
1133 ok( !apc_count, "apc was called\n" );
1134 status = pNtCancelIoFileEx( read, &iosb, &iosb2 );
1135 ok(status == STATUS_SUCCESS, "Failed to cancel I/O\n");
1136 Sleep(1); /* FIXME: needed for wine to run the i/o apc */
1137 ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
1138 ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
1139 ok( is_signaled( event ), "event is not signaled\n" );
1140 ok( !apc_count, "apc was called\n" );
1141 SleepEx( 1, TRUE ); /* alertable sleep */
1142 ok( apc_count == 1, "apc was not called\n" );
1143
1144 /* Duplicate iosb */
1145 apc_count = 0;
1146 U(iosb).Status = 0xdeadbabe;
1147 iosb.Information = 0xdeadbeef;
1148 status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
1149 ok( status == STATUS_PENDING, "wrong status %x\n", status );
1150 ok( !is_signaled( event ), "event is signaled\n" );
1151 ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
1152 ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
1153 ok( !apc_count, "apc was called\n" );
1154 status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
1155 ok( status == STATUS_PENDING, "wrong status %x\n", status );
1156 ok( !is_signaled( event ), "event is signaled\n" );
1157 ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
1158 ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
1159 ok( !apc_count, "apc was called\n" );
1160 status = pNtCancelIoFileEx( read, &iosb, &iosb2 );
1161 ok(status == STATUS_SUCCESS, "Failed to cancel I/O\n");
1162 Sleep(1); /* FIXME: needed for wine to run the i/o apc */
1163 ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
1164 ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
1165 ok( is_signaled( event ), "event is not signaled\n" );
1166 ok( !apc_count, "apc was called\n" );
1167 SleepEx( 1, TRUE ); /* alertable sleep */
1168 ok( apc_count == 2, "apc was not called\n" );
1169
1170 CloseHandle( read );
1171 CloseHandle( write );
1172 }
1173 else
1174 win_skip("NtCancelIoFileEx not available\n");
1175
1176 CloseHandle(event);
1177 }
1178
1179 static void test_volume_info(void)
1180 {
1181 FILE_FS_DEVICE_INFORMATION *device_info;
1182 IO_STATUS_BLOCK iosb;
1183 HANDLE read, write;
1184 char buffer[128];
1185 NTSTATUS status;
1186
1187 if (!create_pipe_pair( &read, &write, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_INBOUND,
1188 PIPE_TYPE_MESSAGE, 4096 )) return;
1189
1190 memset( buffer, 0xaa, sizeof(buffer) );
1191 status = pNtQueryVolumeInformationFile( read, &iosb, buffer, sizeof(buffer), FileFsDeviceInformation );
1192 ok( status == STATUS_SUCCESS, "NtQueryVolumeInformationFile failed: %x\n", status );
1193 ok( iosb.Information == sizeof(*device_info), "Information = %lu\n", iosb.Information );
1194 device_info = (FILE_FS_DEVICE_INFORMATION*)buffer;
1195 ok( device_info->DeviceType == FILE_DEVICE_NAMED_PIPE, "DeviceType = %u\n", device_info->DeviceType );
1196 ok( !(device_info->Characteristics & ~FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL),
1197 "Characteristics = %x\n", device_info->Characteristics );
1198
1199 memset( buffer, 0xaa, sizeof(buffer) );
1200 status = pNtQueryVolumeInformationFile( write, &iosb, buffer, sizeof(buffer), FileFsDeviceInformation );
1201 ok( status == STATUS_SUCCESS, "NtQueryVolumeInformationFile failed: %x\n", status );
1202 ok( iosb.Information == sizeof(*device_info), "Information = %lu\n", iosb.Information );
1203 device_info = (FILE_FS_DEVICE_INFORMATION*)buffer;
1204 ok( device_info->DeviceType == FILE_DEVICE_NAMED_PIPE, "DeviceType = %u\n", device_info->DeviceType );
1205 ok( !(device_info->Characteristics & ~FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL),
1206 "Characteristics = %x\n", device_info->Characteristics );
1207
1208 CloseHandle( read );
1209 CloseHandle( write );
1210 }
1211
1212 #define test_file_name_fail(a,b) _test_file_name_fail(__LINE__,a,b)
1213 static void _test_file_name_fail(unsigned line, HANDLE pipe, NTSTATUS expected_status)
1214 {
1215 char buffer[512];
1216 IO_STATUS_BLOCK iosb;
1217 NTSTATUS status;
1218
1219 status = NtQueryInformationFile( pipe, &iosb, buffer, sizeof(buffer), FileNameInformation );
1220 ok_(__FILE__,line)( status == expected_status, "NtQueryInformationFile failed: %x, expected %x\n",
1221 status, expected_status );
1222 }
1223
1224 #define test_file_name(a) _test_file_name(__LINE__,a)
1225 static void _test_file_name(unsigned line, HANDLE pipe)
1226 {
1227 char buffer[512];
1228 FILE_NAME_INFORMATION *name_info = (FILE_NAME_INFORMATION*)buffer;
1229 IO_STATUS_BLOCK iosb;
1230 NTSTATUS status;
1231
1232 static const WCHAR nameW[] =
1233 {'\\','n','t','d','l','l','_','t','e','s','t','s','_','p','i','p','e','.','c'};
1234
1235 memset( buffer, 0xaa, sizeof(buffer) );
1236 memset( &iosb, 0xaa, sizeof(iosb) );
1237 status = NtQueryInformationFile( pipe, &iosb, buffer, sizeof(buffer), FileNameInformation );
1238 ok_(__FILE__,line)( status == STATUS_SUCCESS, "NtQueryInformationFile failed: %x\n", status );
1239 ok_(__FILE__,line)( iosb.Status == STATUS_SUCCESS, "Status = %x\n", iosb.Status );
1240 ok_(__FILE__,line)( iosb.Information == sizeof(name_info->FileNameLength) + sizeof(nameW),
1241 "Information = %lu\n", iosb.Information );
1242 ok( name_info->FileNameLength == sizeof(nameW), "FileNameLength = %u\n", name_info->FileNameLength );
1243 ok( !memcmp(name_info->FileName, nameW, sizeof(nameW)), "FileName = %s\n", wine_dbgstr_w(name_info->FileName) );
1244
1245 /* too small buffer */
1246 memset( buffer, 0xaa, sizeof(buffer) );
1247 memset( &iosb, 0xaa, sizeof(iosb) );
1248 status = NtQueryInformationFile( pipe, &iosb, buffer, 20, FileNameInformation );
1249 ok( status == STATUS_BUFFER_OVERFLOW, "NtQueryInformationFile failed: %x\n", status );
1250 ok( iosb.Status == STATUS_BUFFER_OVERFLOW, "Status = %x\n", iosb.Status );
1251 ok( iosb.Information == 20, "Information = %lu\n", iosb.Information );
1252 ok( name_info->FileNameLength == sizeof(nameW), "FileNameLength = %u\n", name_info->FileNameLength );
1253 ok( !memcmp(name_info->FileName, nameW, 16), "FileName = %s\n", wine_dbgstr_w(name_info->FileName) );
1254
1255 /* too small buffer */
1256 memset( buffer, 0xaa, sizeof(buffer) );
1257 memset( &iosb, 0xaa, sizeof(iosb) );
1258 status = NtQueryInformationFile( pipe, &iosb, buffer, 4, FileNameInformation );
1259 ok( status == STATUS_INFO_LENGTH_MISMATCH, "NtQueryInformationFile failed: %x\n", status );
1260 }
1261
1262 static void test_file_info(void)
1263 {
1264 HANDLE server, client;
1265
1266 if (!create_pipe_pair( &server, &client, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_INBOUND,
1267 PIPE_TYPE_MESSAGE, 4096 )) return;
1268
1269 test_file_name( client );
1270 test_file_name( server );
1271
1272 DisconnectNamedPipe( server );
1273 test_file_name_fail( client, STATUS_PIPE_DISCONNECTED );
1274
1275 CloseHandle( server );
1276 CloseHandle( client );
1277 }
1278
1279 static PSECURITY_DESCRIPTOR get_security_descriptor(HANDLE handle, BOOL todo)
1280 {
1281 SECURITY_DESCRIPTOR *sec_desc;
1282 ULONG length = 0;
1283 NTSTATUS status;
1284
1285 status = NtQuerySecurityObject(handle, GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
1286 NULL, 0, &length);
1287 todo_wine_if(todo && status == STATUS_PIPE_DISCONNECTED)
1288 ok(status == STATUS_BUFFER_TOO_SMALL,
1289 "Failed to query object security descriptor length: %08x\n", status);
1290 if(status != STATUS_BUFFER_TOO_SMALL) return NULL;
1291 ok(length != 0, "length = 0\n");
1292
1293 sec_desc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, length);
1294 status = NtQuerySecurityObject(handle, GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
1295 sec_desc, length, &length);
1296 ok(status == STATUS_SUCCESS, "Failed to query object security descriptor: %08x\n", status);
1297
1298 return sec_desc;
1299 }
1300
1301 static TOKEN_OWNER *get_current_owner(void)
1302 {
1303 TOKEN_OWNER *owner;
1304 ULONG length = 0;
1305 HANDLE token;
1306 BOOL ret;
1307
1308 ret = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token);
1309 ok(ret, "Failed to get process token: %u\n", GetLastError());
1310
1311 ret = GetTokenInformation(token, TokenOwner, NULL, 0, &length);
1312 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1313 "GetTokenInformation failed: %u\n", GetLastError());
1314 ok(length != 0, "Failed to get token owner information length: %u\n", GetLastError());
1315
1316 owner = HeapAlloc(GetProcessHeap(), 0, length);
1317 ret = GetTokenInformation(token, TokenOwner, owner, length, &length);
1318 ok(ret, "Failed to get token owner information: %u)\n", GetLastError());
1319
1320 CloseHandle(token);
1321 return owner;
1322 }
1323
1324 static TOKEN_PRIMARY_GROUP *get_current_group(void)
1325 {
1326 TOKEN_PRIMARY_GROUP *group;
1327 ULONG length = 0;
1328 HANDLE token;
1329 BOOL ret;
1330
1331 ret = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token);
1332 ok(ret, "Failed to get process token: %u\n", GetLastError());
1333
1334 ret = GetTokenInformation(token, TokenPrimaryGroup, NULL, 0, &length);
1335 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1336 "GetTokenInformation failed: %u\n", GetLastError());
1337 ok(length != 0, "Failed to get primary group token information length: %u\n", GetLastError());
1338
1339 group = HeapAlloc(GetProcessHeap(), 0, length);
1340 ret = GetTokenInformation(token, TokenPrimaryGroup, group, length, &length);
1341 ok(ret, "Failed to get primary group token information: %u\n", GetLastError());
1342
1343 CloseHandle(token);
1344 return group;
1345 }
1346
1347 static SID *well_known_sid(WELL_KNOWN_SID_TYPE sid_type)
1348 {
1349 DWORD size = SECURITY_MAX_SID_SIZE;
1350 SID *sid;
1351 BOOL ret;
1352
1353 sid = HeapAlloc(GetProcessHeap(), 0, size);
1354 ret = CreateWellKnownSid(sid_type, NULL, sid, &size);
1355 ok(ret, "CreateWellKnownSid failed: %u\n", GetLastError());
1356 return sid;
1357 }
1358
1359 #define test_group(a,b,c) _test_group(__LINE__,a,b,c)
1360 static void _test_group(unsigned line, HANDLE handle, SID *expected_sid, BOOL todo)
1361 {
1362 SECURITY_DESCRIPTOR *sec_desc;
1363 BOOLEAN defaulted;
1364 PSID group_sid;
1365 NTSTATUS status;
1366
1367 sec_desc = get_security_descriptor(handle, todo);
1368 if (!sec_desc) return;
1369
1370 status = RtlGetGroupSecurityDescriptor(sec_desc, &group_sid, &defaulted);
1371 ok_(__FILE__,line)(status == STATUS_SUCCESS,
1372 "Failed to query group from security descriptor: %08x\n", status);
1373 todo_wine_if(todo)
1374 ok_(__FILE__,line)(EqualSid(group_sid, expected_sid), "SIDs are not equal\n");
1375
1376 HeapFree(GetProcessHeap(), 0, sec_desc);
1377 }
1378
1379 static void test_security_info(void)
1380 {
1381 char sec_desc[SECURITY_DESCRIPTOR_MIN_LENGTH];
1382 TOKEN_PRIMARY_GROUP *process_group;
1383 SECURITY_ATTRIBUTES sec_attr;
1384 TOKEN_OWNER *process_owner;
1385 HANDLE server, client, server2;
1386 SID *world_sid, *local_sid;
1387 ULONG length;
1388 NTSTATUS status;
1389 BOOL ret;
1390
1391 trace("security tests...\n");
1392
1393 process_owner = get_current_owner();
1394 process_group = get_current_group();
1395 world_sid = well_known_sid(WinWorldSid);
1396 local_sid = well_known_sid(WinLocalSid);
1397
1398 ret = InitializeSecurityDescriptor(sec_desc, SECURITY_DESCRIPTOR_REVISION);
1399 ok(ret, "InitializeSecurityDescriptor failed\n");
1400
1401 ret = SetSecurityDescriptorOwner(sec_desc, process_owner->Owner, FALSE);
1402 ok(ret, "SetSecurityDescriptorOwner failed\n");
1403
1404 ret = SetSecurityDescriptorGroup(sec_desc, process_group->PrimaryGroup, FALSE);
1405 ok(ret, "SetSecurityDescriptorGroup failed\n");
1406
1407 server = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX | WRITE_OWNER, PIPE_TYPE_BYTE, 10,
1408 0x20000, 0x20000, 0, NULL);
1409 ok(server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %u\n", GetLastError());
1410
1411 client = CreateFileA(PIPENAME, GENERIC_ALL, 0, NULL, OPEN_EXISTING, 0, NULL);
1412 ok(client != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
1413
1414 test_group(server, process_group->PrimaryGroup, TRUE);
1415 test_group(client, process_group->PrimaryGroup, TRUE);
1416
1417 /* set server group, client changes as well */
1418 ret = SetSecurityDescriptorGroup(sec_desc, world_sid, FALSE);
1419 ok(ret, "SetSecurityDescriptorGroup failed\n");
1420 status = NtSetSecurityObject(server, GROUP_SECURITY_INFORMATION, sec_desc);
1421 ok(status == STATUS_SUCCESS, "NtSetSecurityObject failed: %08x\n", status);
1422
1423 test_group(server, world_sid, FALSE);
1424 test_group(client, world_sid, FALSE);
1425
1426 /* new instance of pipe server has the same security descriptor */
1427 server2 = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE, 10,
1428 0x20000, 0x20000, 0, NULL);
1429 ok(server2 != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %u\n", GetLastError());
1430 test_group(server2, world_sid, FALSE);
1431
1432 /* set client group, server changes as well */
1433 ret = SetSecurityDescriptorGroup(sec_desc, local_sid, FALSE);
1434 ok(ret, "SetSecurityDescriptorGroup failed\n");
1435 status = NtSetSecurityObject(server, GROUP_SECURITY_INFORMATION, sec_desc);
1436 ok(status == STATUS_SUCCESS, "NtSetSecurityObject failed: %08x\n", status);
1437
1438 test_group(server, local_sid, FALSE);
1439 test_group(client, local_sid, FALSE);
1440 test_group(server2, local_sid, FALSE);
1441
1442 CloseHandle(server);
1443 /* SD is preserved after closing server object */
1444 test_group(client, local_sid, TRUE);
1445 CloseHandle(client);
1446
1447 server = server2;
1448 client = CreateFileA(PIPENAME, GENERIC_ALL, 0, NULL, OPEN_EXISTING, 0, NULL);
1449 ok(client != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
1450
1451 test_group(client, local_sid, FALSE);
1452
1453 ret = DisconnectNamedPipe(server);
1454 ok(ret, "DisconnectNamedPipe failed: %u\n", GetLastError());
1455
1456 /* disconnected server may be queried for security info, but client does not */
1457 test_group(server, local_sid, FALSE);
1458 status = NtQuerySecurityObject(client, GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
1459 NULL, 0, &length);
1460 ok(status == STATUS_PIPE_DISCONNECTED, "NtQuerySecurityObject returned %08x\n", status);
1461 status = NtSetSecurityObject(client, GROUP_SECURITY_INFORMATION, sec_desc);
1462 ok(status == STATUS_PIPE_DISCONNECTED, "NtQuerySecurityObject returned %08x\n", status);
1463
1464 /* attempting to create another pipe instance with specified sd fails */
1465 sec_attr.nLength = sizeof(sec_attr);
1466 sec_attr.lpSecurityDescriptor = sec_desc;
1467 sec_attr.bInheritHandle = FALSE;
1468 ret = SetSecurityDescriptorGroup(sec_desc, local_sid, FALSE);
1469 ok(ret, "SetSecurityDescriptorGroup failed\n");
1470 server2 = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX | WRITE_OWNER, PIPE_TYPE_BYTE, 10,
1471 0x20000, 0x20000, 0, &sec_attr);
1472 todo_wine
1473 ok(server2 == INVALID_HANDLE_VALUE && GetLastError() == ERROR_ACCESS_DENIED,
1474 "CreateNamedPipe failed: %u\n", GetLastError());
1475 if (server2 != INVALID_HANDLE_VALUE) CloseHandle(server2);
1476
1477 CloseHandle(server);
1478 CloseHandle(client);
1479
1480 server = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX | WRITE_OWNER, PIPE_TYPE_BYTE, 10,
1481 0x20000, 0x20000, 0, &sec_attr);
1482 ok(server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %u\n", GetLastError());
1483 test_group(server, local_sid, FALSE);
1484 CloseHandle(server);
1485
1486 HeapFree(GetProcessHeap(), 0, process_owner);
1487 HeapFree(GetProcessHeap(), 0, process_group);
1488 HeapFree(GetProcessHeap(), 0, world_sid);
1489 HeapFree(GetProcessHeap(), 0, local_sid);
1490 }
1491
1492 START_TEST(pipe)
1493 {
1494 if (!init_func_ptrs())
1495 return;
1496
1497 trace("starting invalid create tests\n");
1498 test_create_invalid();
1499
1500 trace("starting create tests\n");
1501 test_create();
1502
1503 trace("starting overlapped tests\n");
1504 test_overlapped();
1505
1506 trace("starting completion tests\n");
1507 test_completion();
1508
1509 trace("starting FILE_PIPE_INFORMATION tests\n");
1510 test_filepipeinfo();
1511
1512 if (!pOpenThread || !pQueueUserAPC)
1513 return;
1514
1515 trace("starting alertable tests\n");
1516 test_alertable();
1517
1518 trace("starting nonalertable tests\n");
1519 test_nonalertable();
1520
1521 trace("starting cancelio tests\n");
1522 test_cancelio();
1523
1524 trace("starting byte read in byte mode client -> server\n");
1525 read_pipe_test(PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE);
1526 trace("starting byte read in message mode client -> server\n");
1527 read_pipe_test(PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE);
1528 trace("starting message read in message mode client -> server\n");
1529 read_pipe_test(PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE);
1530 trace("starting byte read in byte mode server -> client\n");
1531 read_pipe_test(PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE);
1532 trace("starting byte read in message mode server -> client\n");
1533 read_pipe_test(PIPE_ACCESS_OUTBOUND, PIPE_TYPE_MESSAGE);
1534 trace("starting message read in message mode server -> client\n");
1535 read_pipe_test(PIPE_ACCESS_OUTBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE);
1536
1537 test_volume_info();
1538 test_file_info();
1539 test_security_info();
1540 }