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