1 /*
2  * PROJECT:         ReactOS kernel-mode tests
3  * LICENSE:         LGPLv2+ - See COPYING.LIB in the top level directory
4  * PURPOSE:         Kernel-Mode Test Suite Helper functions for NPFS tests
5  * PROGRAMMER:      Thomas Faber <thomas.faber@reactos.org>
6  */
7 
8 #include <kmt_test.h>
9 #include "npfs.h"
10 
11 NTSTATUS
12 NpCreatePipeEx(
13     OUT PHANDLE ServerHandle,
14     IN PCWSTR PipePath,
15     IN ULONG ReadMode,
16     IN ULONG CompletionMode,
17     IN ULONG NamedPipeType,
18     IN ULONG ShareAccess,
19     IN ULONG MaximumInstances,
20     IN ULONG InboundQuota,
21     IN ULONG OutboundQuota,
22     IN ACCESS_MASK DesiredAccess,
23     IN ULONG Disposition,
24     IN ULONG CreateOptions,
25     IN PLARGE_INTEGER DefaultTimeout OPTIONAL)
26 {
27     UNICODE_STRING ObjectName;
28     OBJECT_ATTRIBUTES ObjectAttributes;
29     NAMED_PIPE_CREATE_PARAMETERS Params;
30     IO_STATUS_BLOCK IoStatusBlock;
31     NTSTATUS Status;
32 
33     RtlInitUnicodeString(&ObjectName, PipePath);
34     InitializeObjectAttributes(&ObjectAttributes,
35                                &ObjectName,
36                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
37                                NULL,
38                                NULL);
39 
40     Params.NamedPipeType = NamedPipeType;
41     Params.ReadMode = ReadMode;
42     Params.CompletionMode = CompletionMode;
43     Params.MaximumInstances = MaximumInstances;
44     Params.InboundQuota = InboundQuota;
45     Params.OutboundQuota = OutboundQuota;
46     if (DefaultTimeout)
47     {
48         Params.DefaultTimeout.QuadPart = DefaultTimeout->QuadPart;
49         Params.TimeoutSpecified = TRUE;
50     }
51     else
52     {
53         Params.DefaultTimeout.QuadPart = 0;
54         Params.TimeoutSpecified = FALSE;
55     }
56 
57     RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
58     Status = IoCreateFile(ServerHandle,
59                           DesiredAccess,
60                           &ObjectAttributes,
61                           &IoStatusBlock,
62                           NULL, /* AllocationSize */
63                           0, /* FileAttributes */
64                           ShareAccess,
65                           Disposition,
66                           CreateOptions,
67                           NULL, /* EaBuffer */
68                           0, /* EaLength */
69                           CreateFileTypeNamedPipe,
70                           &Params,
71                           0);
72     if (NT_SUCCESS(Status))
73     {
74         ok_eq_hex(IoStatusBlock.Status, Status);
75         ok_eq_ulongptr(IoStatusBlock.Information, FILE_CREATED);
76     }
77     else
78     {
79         ok_eq_hex(IoStatusBlock.Status, 0x55555555UL);
80         ok_eq_ulongptr(IoStatusBlock.Information, 0x5555555555555555ULL);
81     }
82     return Status;
83 }
84 
85 NTSTATUS
86 NpCreatePipe(
87     OUT PHANDLE ServerHandle,
88     PCWSTR PipePath,
89     ULONG ReadMode,
90     ULONG CompletionMode,
91     ULONG NamedPipeType,
92     ULONG NamedPipeConfiguration,
93     ULONG MaximumInstances,
94     ULONG InboundQuota,
95     ULONG OutboundQuota)
96 {
97     ULONG ShareAccess;
98     LARGE_INTEGER DefaultTimeout;
99 
100     if (NamedPipeConfiguration == FILE_PIPE_INBOUND)
101         ShareAccess = FILE_SHARE_WRITE;
102     else if (NamedPipeConfiguration == FILE_PIPE_OUTBOUND)
103         ShareAccess = FILE_SHARE_READ;
104     else if (NamedPipeConfiguration == FILE_PIPE_FULL_DUPLEX)
105         ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
106     else
107     {
108         ASSERTMSG("Invalid NamedPipeConfiguration parameter value!\n", FALSE);
109         return STATUS_INVALID_PARAMETER_6;
110     }
111 
112     DefaultTimeout.QuadPart = -50 * 1000 * 10;
113 
114     return NpCreatePipeEx(ServerHandle,
115                           PipePath,
116                           ReadMode,
117                           CompletionMode,
118                           NamedPipeType,
119                           ShareAccess,
120                           MaximumInstances,
121                           InboundQuota,
122                           OutboundQuota,
123                           SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE,
124                           FILE_OPEN_IF,
125                           FILE_SYNCHRONOUS_IO_NONALERT,
126                           &DefaultTimeout);
127 }
128 
129 NTSTATUS
130 NpOpenPipeEx(
131     OUT PHANDLE ClientHandle,
132     IN PCWSTR PipePath,
133     IN ACCESS_MASK DesiredAccess,
134     IN ULONG ShareAccess,
135     IN ULONG Disposition,
136     IN ULONG CreateOptions)
137 {
138     UNICODE_STRING ObjectName;
139     OBJECT_ATTRIBUTES ObjectAttributes;
140     NTSTATUS Status;
141     IO_STATUS_BLOCK IoStatusBlock;
142 
143     RtlInitUnicodeString(&ObjectName, PipePath);
144     InitializeObjectAttributes(&ObjectAttributes,
145                                &ObjectName,
146                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
147                                NULL,
148                                NULL);
149 
150     RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
151     Status = IoCreateFile(ClientHandle,
152                           DesiredAccess,
153                           &ObjectAttributes,
154                           &IoStatusBlock,
155                           NULL, /* AllocationSize */
156                           0, /* FileAttributes */
157                           ShareAccess,
158                           Disposition,
159                           CreateOptions,
160                           NULL, /* EaBuffer */
161                           0, /* EaLength */
162                           CreateFileTypeNone,
163                           NULL,
164                           0);
165     if (NT_SUCCESS(Status))
166     {
167         ok(Status != STATUS_PENDING, "IoCreateFile returned pending\n");
168         ok_eq_hex(IoStatusBlock.Status, Status);
169         ok_eq_ulongptr(IoStatusBlock.Information, FILE_OPENED);
170     }
171     else
172     {
173         ok_eq_hex(IoStatusBlock.Status, 0x55555555UL);
174         ok_eq_ulongptr(IoStatusBlock.Information, 0x5555555555555555ULL);
175     }
176     return Status;
177 }
178 
179 NTSTATUS
180 NpOpenPipe(
181     OUT PHANDLE ClientHandle,
182     IN PCWSTR PipePath,
183     IN ULONG NamedPipeConfiguration)
184 {
185     ULONG ShareAccess;
186 
187     if (NamedPipeConfiguration == FILE_PIPE_INBOUND)
188         ShareAccess = FILE_SHARE_WRITE;
189     else if (NamedPipeConfiguration == FILE_PIPE_OUTBOUND)
190         ShareAccess = FILE_SHARE_READ;
191     else if (NamedPipeConfiguration == FILE_PIPE_FULL_DUPLEX)
192         ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
193     else
194     {
195         ASSERTMSG("Invalid NamedPipeConfiguration parameter value!\n", FALSE);
196         return STATUS_INVALID_PARAMETER_3;
197     }
198 
199     return NpOpenPipeEx(ClientHandle,
200                         PipePath,
201                         SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE,
202                         ShareAccess,
203                         FILE_OPEN,
204                         FILE_SYNCHRONOUS_IO_NONALERT);
205 }
206 
207 NTSTATUS
208 NpControlPipe(
209     IN HANDLE ServerHandle,
210     IN ULONG FsControlCode,
211     IN PVOID InputBuffer,
212     IN ULONG InputBufferLength)
213 {
214     NTSTATUS Status;
215     IO_STATUS_BLOCK IoStatusBlock;
216 
217     RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
218     Status = ZwFsControlFile(ServerHandle,
219                              NULL,
220                              NULL,
221                              NULL,
222                              &IoStatusBlock,
223                              FsControlCode,
224                              InputBuffer,
225                              InputBufferLength,
226                              NULL,
227                              0);
228     if (Status == STATUS_PENDING)
229     {
230         Status = ZwWaitForSingleObject(ServerHandle,
231                                        FALSE,
232                                        NULL);
233         ok_eq_hex(Status, STATUS_SUCCESS);
234         Status = IoStatusBlock.Status;
235     }
236     if (NT_SUCCESS(Status))
237     {
238         ok_eq_hex(IoStatusBlock.Status, Status);
239         ok_eq_ulongptr(IoStatusBlock.Information, 0);
240     }
241     else
242     {
243         ok_eq_hex(IoStatusBlock.Status, 0x55555555UL);
244         ok_eq_ulongptr(IoStatusBlock.Information, 0x5555555555555555ULL);
245     }
246     return Status;
247 }
248 
249 NTSTATUS
250 NpWaitPipe(
251     IN PCWSTR PipeName,
252     IN PLARGE_INTEGER Timeout)
253 {
254     NTSTATUS Status;
255     HANDLE RootHandle;
256     UNICODE_STRING RootDirectoryName = RTL_CONSTANT_STRING(DEVICE_NAMED_PIPE);
257     OBJECT_ATTRIBUTES ObjectAttributes;
258     IO_STATUS_BLOCK IoStatusBlock;
259     PFILE_PIPE_WAIT_FOR_BUFFER WaitForBuffer;
260     ULONG NameLength;
261     ULONG BufferSize;
262 
263     InitializeObjectAttributes(&ObjectAttributes,
264                                &RootDirectoryName,
265                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
266                                NULL,
267                                NULL);
268 
269     RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
270     Status = IoCreateFile(&RootHandle,
271                           FILE_READ_ATTRIBUTES | SYNCHRONIZE,
272                           &ObjectAttributes,
273                           &IoStatusBlock,
274                           NULL,
275                           0,
276                           FILE_SHARE_READ | FILE_SHARE_WRITE,
277                           FILE_OPEN,
278                           FILE_SYNCHRONOUS_IO_NONALERT,
279                           NULL,
280                           0,
281                           CreateFileTypeNone,
282                           NULL,
283                           0);
284     if (!NT_SUCCESS(Status))
285     {
286         ok_eq_hex(IoStatusBlock.Status, 0x55555555UL);
287         ok_eq_ulongptr(IoStatusBlock.Information, 0x5555555555555555ULL);
288         return Status;
289     }
290     ok(Status != STATUS_PENDING, "IoCreateFile returned pending\n");
291     ok_eq_hex(IoStatusBlock.Status, Status);
292     ok_eq_ulongptr(IoStatusBlock.Information, FILE_OPENED);
293 
294     NameLength = wcslen(PipeName) * sizeof(WCHAR);
295     BufferSize = FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER,
296                               Name[NameLength / sizeof(WCHAR)]);
297     WaitForBuffer = ExAllocatePoolWithTag(NonPagedPool, BufferSize, 'WPmK');
298     if (WaitForBuffer == NULL)
299         return STATUS_INSUFFICIENT_RESOURCES;
300 
301     if (Timeout)
302     {
303         WaitForBuffer->Timeout.QuadPart = Timeout->QuadPart;
304         WaitForBuffer->TimeoutSpecified = TRUE;
305     }
306     else
307     {
308         WaitForBuffer->Timeout.QuadPart = 0;
309         WaitForBuffer->TimeoutSpecified = FALSE;
310     }
311     WaitForBuffer->NameLength = NameLength;
312     RtlCopyMemory(WaitForBuffer->Name, PipeName, NameLength);
313     Status = NpControlPipe(RootHandle,
314                            FSCTL_PIPE_WAIT,
315                            WaitForBuffer,
316                            BufferSize);
317     ExFreePoolWithTag(WaitForBuffer, 'WPmK');
318     return Status;
319 }
320 
321 NTSTATUS
322 NpReadPipe(
323     IN HANDLE PipeHandle,
324     OUT PVOID Buffer,
325     IN ULONG BufferSize,
326     OUT PULONG_PTR BytesRead)
327 {
328     NTSTATUS Status;
329     IO_STATUS_BLOCK IoStatusBlock;
330     BOOLEAN PendingReturned = FALSE;
331 
332     RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
333     Status = ZwReadFile(PipeHandle,
334                         NULL,
335                         NULL,
336                         NULL,
337                         &IoStatusBlock,
338                         Buffer,
339                         BufferSize,
340                         NULL,
341                         NULL);
342     if (Status == STATUS_PENDING)
343     {
344         Status = ZwWaitForSingleObject(PipeHandle,
345                                        FALSE,
346                                        NULL);
347         ok_eq_hex(Status, STATUS_SUCCESS);
348         Status = IoStatusBlock.Status;
349         PendingReturned = TRUE;
350     }
351     if (NT_SUCCESS(Status))
352     {
353         ok_eq_hex(IoStatusBlock.Status, Status);
354         *BytesRead = IoStatusBlock.Information;
355     }
356     else
357     {
358         if (PendingReturned)
359         {
360             ok_eq_hex(IoStatusBlock.Status, Status);
361             ok_eq_ulongptr(IoStatusBlock.Information, 0);
362         }
363         else
364         {
365             ok_eq_hex(IoStatusBlock.Status, 0x55555555UL);
366             ok_eq_ulongptr(IoStatusBlock.Information, 0x5555555555555555ULL);
367         }
368         *BytesRead = 0;
369     }
370     return Status;
371 }
372 
373 NTSTATUS
374 NpWritePipe(
375     IN HANDLE PipeHandle,
376     IN const VOID *Buffer,
377     IN ULONG BufferSize,
378     OUT PULONG_PTR BytesWritten)
379 {
380     NTSTATUS Status;
381     IO_STATUS_BLOCK IoStatusBlock;
382 
383     RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
384     Status = ZwWriteFile(PipeHandle,
385                          NULL,
386                          NULL,
387                          NULL,
388                          &IoStatusBlock,
389                          (PVOID)Buffer,
390                          BufferSize,
391                          NULL,
392                          NULL);
393     if (Status == STATUS_PENDING)
394     {
395         Status = ZwWaitForSingleObject(PipeHandle,
396                                        FALSE,
397                                        NULL);
398         ok_eq_hex(Status, STATUS_SUCCESS);
399         Status = IoStatusBlock.Status;
400     }
401     if (NT_SUCCESS(Status))
402     {
403         ok_eq_hex(IoStatusBlock.Status, Status);
404         *BytesWritten = IoStatusBlock.Information;
405     }
406     else
407     {
408         ok_eq_hex(IoStatusBlock.Status, 0x55555555UL);
409         ok_eq_ulongptr(IoStatusBlock.Information, 0x5555555555555555ULL);
410         *BytesWritten = 0;
411     }
412     return Status;
413 }
414 
415 static
416 BOOLEAN
417 CheckBuffer(
418     PVOID Buffer,
419     SIZE_T Size,
420     UCHAR Value)
421 {
422     PUCHAR Array = Buffer;
423     SIZE_T i;
424 
425     for (i = 0; i < Size; i++)
426         if (Array[i] != Value)
427         {
428             trace("Expected %x, found %x at offset %lu\n", Value, Array[i], (ULONG)i);
429             return FALSE;
430         }
431     return TRUE;
432 }
433 
434 #define ok_eq_print_(value, expected, spec, FileAndLine) \
435                                             KmtOk((value) == (expected), FileAndLine, #value " = " spec ", expected " spec "\n", value, expected)
436 #define ok_eq_ulong_(value, expected)       ok_eq_print_(value, expected, "%lu", FileAndLine)
437 #define ok_eq_ulonglong_(value, expected)   ok_eq_print_(value, expected, "%I64u", FileAndLine)
438 #ifndef _WIN64
439 #define ok_eq_ulongptr_(value, expected)    ok_eq_print_(value, (ULONG_PTR)(expected), "%lu", FileAndLine)
440 #elif defined _WIN64
441 #define ok_eq_ulongptr_(value, expected)    ok_eq_print_(value, (ULONG_PTR)(expected), "%I64u", FileAndLine)
442 #endif
443 #define ok_eq_hex_(value, expected)         ok_eq_print_(value, expected, "0x%08lx", FileAndLine)
444 
445 VOID
446 NpCheckServerPipe_(
447     IN HANDLE ServerHandle,
448     /* PipeInformation */
449     IN ULONG ReadMode,
450     IN ULONG CompletionMode,
451     /* PipeLocalInformation */
452     IN ULONG NamedPipeType,
453     IN ULONG NamedPipeConfiguration,
454     IN ULONG MaximumInstances,
455     IN ULONG CurrentInstances,
456     IN ULONG InboundQuota,
457     IN ULONG ReadDataAvailable,
458     IN ULONG OutboundQuota,
459     IN ULONG WriteQuotaAvailable,
460     IN ULONG NamedPipeState,
461     /* PipeRemoteInformation */
462     /* */
463     IN PCSTR FileAndLine)
464 {
465     NTSTATUS Status;
466     IO_STATUS_BLOCK IoStatusBlock;
467     FILE_PIPE_INFORMATION PipeInfo;
468     FILE_PIPE_LOCAL_INFORMATION PipeLocalInfo;
469     FILE_PIPE_REMOTE_INFORMATION PipeRemoteInfo;
470 
471     RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
472     RtlFillMemory(&PipeInfo, sizeof(PipeInfo), 0x55);
473     Status = ZwQueryInformationFile(ServerHandle,
474                                     &IoStatusBlock,
475                                     &PipeInfo,
476                                     sizeof(PipeInfo),
477                                     FilePipeInformation);
478     ok_eq_hex_(Status, STATUS_SUCCESS);
479     ok_eq_hex_(IoStatusBlock.Status, STATUS_SUCCESS);
480     ok_eq_ulongptr_(IoStatusBlock.Information, sizeof(PipeInfo));
481     ok_eq_ulong_(PipeInfo.ReadMode, ReadMode);
482     ok_eq_ulong_(PipeInfo.CompletionMode, CompletionMode);
483 
484     RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
485     RtlFillMemory(&PipeLocalInfo, sizeof(PipeLocalInfo), 0x55);
486     Status = ZwQueryInformationFile(ServerHandle,
487                                     &IoStatusBlock,
488                                     &PipeLocalInfo,
489                                     sizeof(PipeLocalInfo),
490                                     FilePipeLocalInformation);
491     ok_eq_hex_(Status, STATUS_SUCCESS);
492     ok_eq_hex_(IoStatusBlock.Status, STATUS_SUCCESS);
493     ok_eq_ulongptr_(IoStatusBlock.Information, sizeof(PipeLocalInfo));
494     ok_eq_ulong_(PipeLocalInfo.NamedPipeType, NamedPipeType);
495     ok_eq_ulong_(PipeLocalInfo.NamedPipeConfiguration, NamedPipeConfiguration);
496     ok_eq_ulong_(PipeLocalInfo.MaximumInstances, MaximumInstances);
497     ok_eq_ulong_(PipeLocalInfo.CurrentInstances, CurrentInstances);
498     ok_eq_ulong_(PipeLocalInfo.InboundQuota, InboundQuota);
499     ok_eq_ulong_(PipeLocalInfo.ReadDataAvailable, ReadDataAvailable);
500     ok_eq_ulong_(PipeLocalInfo.OutboundQuota, OutboundQuota);
501     ok_eq_ulong_(PipeLocalInfo.WriteQuotaAvailable, WriteQuotaAvailable);
502     ok_eq_ulong_(PipeLocalInfo.NamedPipeState, NamedPipeState);
503     ok_eq_ulong_(PipeLocalInfo.NamedPipeEnd, (ULONG)FILE_PIPE_SERVER_END);
504 
505     RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
506     RtlFillMemory(&PipeRemoteInfo, sizeof(PipeRemoteInfo), 0x55);
507     Status = ZwQueryInformationFile(ServerHandle,
508                                     &IoStatusBlock,
509                                     &PipeRemoteInfo,
510                                     sizeof(PipeRemoteInfo),
511                                     FilePipeInformation);
512     ok_eq_hex_(Status, STATUS_SUCCESS);
513     ok_eq_hex_(IoStatusBlock.Status, STATUS_SUCCESS);
514     ok_eq_ulongptr_(IoStatusBlock.Information, RTL_SIZEOF_THROUGH_FIELD(FILE_PIPE_REMOTE_INFORMATION, CollectDataTime));
515     ok_eq_ulonglong_(PipeRemoteInfo.CollectDataTime.QuadPart, 0ULL);
516     ok_eq_ulong_(PipeRemoteInfo.MaximumCollectionCount, 0x55555555UL);
517 }
518 
519 VOID
520 NpCheckClientPipe_(
521     IN HANDLE ClientHandle,
522     /* PipeInformation */
523     IN ULONG ReadMode,
524     IN ULONG CompletionMode,
525     /* PipeLocalInformation */
526     IN ULONG NamedPipeType,
527     IN ULONG NamedPipeConfiguration,
528     IN ULONG MaximumInstances,
529     IN ULONG CurrentInstances,
530     IN ULONG InboundQuota,
531     IN ULONG ReadDataAvailable,
532     IN ULONG OutboundQuota,
533     IN ULONG WriteQuotaAvailable,
534     IN ULONG NamedPipeState,
535     /* PipeRemoteInformation */
536     /* */
537     IN PCSTR FileAndLine)
538 {
539     NTSTATUS Status;
540     IO_STATUS_BLOCK IoStatusBlock;
541     FILE_PIPE_INFORMATION PipeInfo;
542     FILE_PIPE_LOCAL_INFORMATION PipeLocalInfo;
543     FILE_PIPE_REMOTE_INFORMATION PipeRemoteInfo;
544 
545     RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
546     RtlFillMemory(&PipeInfo, sizeof(PipeInfo), 0x55);
547     Status = ZwQueryInformationFile(ClientHandle,
548                                     &IoStatusBlock,
549                                     &PipeInfo,
550                                     sizeof(PipeInfo),
551                                     FilePipeInformation);
552     ok_eq_hex_(Status, STATUS_SUCCESS);
553     ok_eq_hex_(IoStatusBlock.Status, STATUS_SUCCESS);
554     ok_eq_ulongptr_(IoStatusBlock.Information, sizeof(PipeInfo));
555     ok_eq_ulong_(PipeInfo.ReadMode, ReadMode);
556     ok_eq_ulong_(PipeInfo.CompletionMode, CompletionMode);
557 
558     RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
559     RtlFillMemory(&PipeLocalInfo, sizeof(PipeLocalInfo), 0x55);
560     Status = ZwQueryInformationFile(ClientHandle,
561                                     &IoStatusBlock,
562                                     &PipeLocalInfo,
563                                     sizeof(PipeLocalInfo),
564                                     FilePipeLocalInformation);
565     ok_eq_hex_(Status, STATUS_SUCCESS);
566     ok_eq_hex_(IoStatusBlock.Status, STATUS_SUCCESS);
567     ok_eq_ulongptr_(IoStatusBlock.Information, sizeof(PipeLocalInfo));
568     ok_eq_ulong_(PipeLocalInfo.NamedPipeType, NamedPipeType);
569     ok_eq_ulong_(PipeLocalInfo.NamedPipeConfiguration, NamedPipeConfiguration);
570     ok_eq_ulong_(PipeLocalInfo.MaximumInstances, MaximumInstances);
571     ok_eq_ulong_(PipeLocalInfo.CurrentInstances, CurrentInstances);
572     ok_eq_ulong_(PipeLocalInfo.InboundQuota, InboundQuota);
573     ok_eq_ulong_(PipeLocalInfo.ReadDataAvailable, ReadDataAvailable);
574     ok_eq_ulong_(PipeLocalInfo.OutboundQuota, OutboundQuota);
575     ok_eq_ulong_(PipeLocalInfo.WriteQuotaAvailable, WriteQuotaAvailable);
576     ok_eq_ulong_(PipeLocalInfo.NamedPipeState, NamedPipeState);
577     ok_eq_ulong_(PipeLocalInfo.NamedPipeEnd, (ULONG)FILE_PIPE_CLIENT_END);
578 
579     RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
580     RtlFillMemory(&PipeRemoteInfo, sizeof(PipeRemoteInfo), 0x55);
581     Status = ZwQueryInformationFile(ClientHandle,
582                                     &IoStatusBlock,
583                                     &PipeRemoteInfo,
584                                     sizeof(PipeRemoteInfo),
585                                     FilePipeInformation);
586     ok_eq_hex_(Status, STATUS_SUCCESS);
587     ok_eq_hex_(IoStatusBlock.Status, STATUS_SUCCESS);
588     ok_eq_ulongptr_(IoStatusBlock.Information, RTL_SIZEOF_THROUGH_FIELD(FILE_PIPE_REMOTE_INFORMATION, CollectDataTime));
589     ok_eq_ulonglong_(PipeRemoteInfo.CollectDataTime.QuadPart, 0ULL);
590     ok_eq_ulong_(PipeRemoteInfo.MaximumCollectionCount, 0x55555555UL);
591 }
592 
593 VOID
594 NpQueryPipe_(
595     IN HANDLE PipeHandle,
596     IN NTSTATUS ExpectedStatus,
597     IN PCSTR FileAndLine)
598 {
599     NTSTATUS Status;
600     IO_STATUS_BLOCK IoStatusBlock;
601     FILE_PIPE_INFORMATION PipeInfo;
602     FILE_PIPE_LOCAL_INFORMATION PipeLocalInfo;
603     FILE_PIPE_REMOTE_INFORMATION PipeRemoteInfo;
604 
605     ASSERT(!NT_SUCCESS(ExpectedStatus));
606 
607     RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
608     RtlFillMemory(&PipeInfo, sizeof(PipeInfo), 0x55);
609     Status = ZwQueryInformationFile(PipeHandle,
610                                     &IoStatusBlock,
611                                     &PipeInfo,
612                                     sizeof(PipeInfo),
613                                     FilePipeInformation);
614     ok_eq_hex_(Status, ExpectedStatus);
615     ok_bool_true(CheckBuffer(&IoStatusBlock, sizeof(IoStatusBlock), 0x55), "CheckBuffer returned");
616     ok_bool_true(CheckBuffer(&PipeInfo, sizeof(PipeInfo), 0x55), "CheckBuffer returned");
617 
618     RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
619     RtlFillMemory(&PipeLocalInfo, sizeof(PipeLocalInfo), 0x55);
620     Status = ZwQueryInformationFile(PipeHandle,
621                                     &IoStatusBlock,
622                                     &PipeLocalInfo,
623                                     sizeof(PipeLocalInfo),
624                                     FilePipeLocalInformation);
625     ok_eq_hex_(Status, ExpectedStatus);
626     ok_bool_true(CheckBuffer(&IoStatusBlock, sizeof(IoStatusBlock), 0x55), "CheckBuffer returned");
627     ok_bool_true(CheckBuffer(&PipeLocalInfo, sizeof(PipeLocalInfo), 0x55), "CheckBuffer returned");
628 
629     RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
630     RtlFillMemory(&PipeRemoteInfo, sizeof(PipeRemoteInfo), 0x55);
631     Status = ZwQueryInformationFile(PipeHandle,
632                                     &IoStatusBlock,
633                                     &PipeRemoteInfo,
634                                     sizeof(PipeRemoteInfo),
635                                     FilePipeInformation);
636     ok_eq_hex_(Status, ExpectedStatus);
637     ok_bool_true(CheckBuffer(&IoStatusBlock, sizeof(IoStatusBlock), 0x55), "CheckBuffer returned");
638     ok_bool_true(CheckBuffer(&PipeRemoteInfo, sizeof(PipeRemoteInfo), 0x55), "CheckBuffer returned");
639 }
640 
641 static KSTART_ROUTINE PipeWorkerThread;
642 static
643 VOID
644 NTAPI
645 PipeWorkerThread(
646     IN PVOID ThreadContext)
647 {
648     PTHREAD_CONTEXT Context = ThreadContext;
649     PVOID WaitEvents[2] = { &Context->ThreadDoneEvent,
650                             &Context->StartWorkEvent };
651     NTSTATUS Status;
652 
653     while (TRUE)
654     {
655         Status = KeWaitForMultipleObjects(RTL_NUMBER_OF(WaitEvents),
656                                           WaitEvents,
657                                           WaitAny,
658                                           Executive,
659                                           KernelMode,
660                                           FALSE,
661                                           NULL,
662                                           NULL);
663         if (Status == STATUS_WAIT_0)
664             break;
665         ASSERT(Status == STATUS_WAIT_1);
666 
667         Context->Work(Context);
668 
669         KeSetEvent(&Context->WorkCompleteEvent, IO_NO_INCREMENT, TRUE);
670     }
671 }
672 
673 VOID
674 StartWorkerThread(
675     OUT PTHREAD_CONTEXT Context)
676 {
677     KeInitializeEvent(&Context->ThreadDoneEvent, NotificationEvent, FALSE);
678     KeInitializeEvent(&Context->StartWorkEvent, SynchronizationEvent, FALSE);
679     KeInitializeEvent(&Context->WorkCompleteEvent, NotificationEvent, TRUE);
680 
681     Context->Thread = KmtStartThread(PipeWorkerThread, Context);
682 }
683 
684 VOID
685 FinishWorkerThread(
686     IN PTHREAD_CONTEXT Context)
687 {
688     KmtFinishThread(Context->Thread, &Context->ThreadDoneEvent);
689 }
690 
691 BOOLEAN
692 WaitForWork(
693     IN PTHREAD_CONTEXT Context,
694     IN ULONG MilliSeconds)
695 {
696     LARGE_INTEGER Timeout;
697     NTSTATUS Status;
698 
699     Timeout.QuadPart = -10 * 1000 * (LONGLONG)MilliSeconds;
700     Status = KeWaitForSingleObject(&Context->WorkCompleteEvent,
701                                    Executive,
702                                    KernelMode,
703                                    FALSE,
704                                    &Timeout);
705     ok(Status == STATUS_SUCCESS || Status == STATUS_TIMEOUT, "Wait status %lx\n", Status);
706     return Status != STATUS_TIMEOUT;
707 }
708 
709 BOOLEAN
710 TriggerWork(
711     IN PTHREAD_CONTEXT Context,
712     IN ULONG MilliSeconds)
713 {
714     NTSTATUS Status;
715 
716     Status = KeWaitForSingleObject(&Context->WorkCompleteEvent,
717                                    Executive,
718                                    KernelMode,
719                                    FALSE,
720                                    NULL);
721     ok_eq_hex(Status, STATUS_SUCCESS);
722     KeClearEvent(&Context->WorkCompleteEvent);
723     KeSetEvent(&Context->StartWorkEvent, IO_NO_INCREMENT, TRUE);
724     return WaitForWork(Context, MilliSeconds);
725 }
726