reactos/rostests/kmtests/npfs/NpfsHelpers.c
Timo Kreuzer bccd8b7aea [KMTEST]
Revert the DDK compatibility hack and apply a real fix. I kept the hack for NDK exports, we should consider changing them as well for consistency reasons.

svn path=/trunk/; revision=63268
2014-05-12 23:36:05 +00:00

774 lines
27 KiB
C

/*
* PROJECT: ReactOS kernel-mode tests
* LICENSE: LGPLv2+ - See COPYING.LIB in the top level directory
* PURPOSE: Kernel-Mode Test Suite Helper functions for NPFS tests
* PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
*/
#include <kmt_test.h>
#include "npfs.h"
NTSTATUS
NpCreatePipeEx(
OUT PHANDLE ServerHandle,
IN PCWSTR PipePath,
IN ULONG ReadMode,
IN ULONG CompletionMode,
IN ULONG NamedPipeType,
IN ULONG ShareAccess,
IN ULONG MaximumInstances,
IN ULONG InboundQuota,
IN ULONG OutboundQuota,
IN ACCESS_MASK DesiredAccess,
IN ULONG Disposition,
IN ULONG CreateOptions,
IN PLARGE_INTEGER DefaultTimeout OPTIONAL)
{
UNICODE_STRING ObjectName;
OBJECT_ATTRIBUTES ObjectAttributes;
NAMED_PIPE_CREATE_PARAMETERS Params;
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
RtlInitUnicodeString(&ObjectName, PipePath);
InitializeObjectAttributes(&ObjectAttributes,
&ObjectName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL);
Params.NamedPipeType = NamedPipeType;
Params.ReadMode = ReadMode;
Params.CompletionMode = CompletionMode;
Params.MaximumInstances = MaximumInstances;
Params.InboundQuota = InboundQuota;
Params.OutboundQuota = OutboundQuota;
if (DefaultTimeout)
{
Params.DefaultTimeout.QuadPart = DefaultTimeout->QuadPart;
Params.TimeoutSpecified = TRUE;
}
else
{
Params.DefaultTimeout.QuadPart = 0;
Params.TimeoutSpecified = FALSE;
}
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
Status = IoCreateFile(ServerHandle,
DesiredAccess,
&ObjectAttributes,
&IoStatusBlock,
NULL, /* AllocationSize */
0, /* FileAttributes */
ShareAccess,
Disposition,
CreateOptions,
NULL, /* EaBuffer */
0, /* EaLength */
CreateFileTypeNamedPipe,
&Params,
0);
if (NT_SUCCESS(Status))
{
ok_eq_hex(IoStatusBlock.Status, Status);
ok_eq_ulongptr(IoStatusBlock.Information, FILE_CREATED);
}
else
{
ok_eq_hex(IoStatusBlock.Status, 0x55555555UL);
ok_eq_ulongptr(IoStatusBlock.Information, 0x5555555555555555ULL);
}
return Status;
}
NTSTATUS
NpCreatePipe(
OUT PHANDLE ServerHandle,
PCWSTR PipePath,
ULONG ReadMode,
ULONG CompletionMode,
ULONG NamedPipeType,
ULONG NamedPipeConfiguration,
ULONG MaximumInstances,
ULONG InboundQuota,
ULONG OutboundQuota)
{
ULONG ShareAccess;
LARGE_INTEGER DefaultTimeout;
if (NamedPipeConfiguration == FILE_PIPE_INBOUND)
ShareAccess = FILE_SHARE_WRITE;
else if (NamedPipeConfiguration == FILE_PIPE_OUTBOUND)
ShareAccess = FILE_SHARE_READ;
else if (NamedPipeConfiguration == FILE_PIPE_FULL_DUPLEX)
ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
DefaultTimeout.QuadPart = -50 * 1000 * 10;
return NpCreatePipeEx(ServerHandle,
PipePath,
ReadMode,
CompletionMode,
NamedPipeType,
ShareAccess,
MaximumInstances,
InboundQuota,
OutboundQuota,
SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE,
FILE_OPEN_IF,
FILE_SYNCHRONOUS_IO_NONALERT,
&DefaultTimeout);
}
NTSTATUS
NpOpenPipeEx(
OUT PHANDLE ClientHandle,
IN PCWSTR PipePath,
IN ACCESS_MASK DesiredAccess,
IN ULONG ShareAccess,
IN ULONG Disposition,
IN ULONG CreateOptions)
{
UNICODE_STRING ObjectName;
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
RtlInitUnicodeString(&ObjectName, PipePath);
InitializeObjectAttributes(&ObjectAttributes,
&ObjectName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL);
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
Status = IoCreateFile(ClientHandle,
DesiredAccess,
&ObjectAttributes,
&IoStatusBlock,
NULL, /* AllocationSize */
0, /* FileAttributes */
ShareAccess,
Disposition,
CreateOptions,
NULL, /* EaBuffer */
0, /* EaLength */
CreateFileTypeNone,
NULL,
0);
if (NT_SUCCESS(Status))
{
ok(Status != STATUS_PENDING, "IoCreateFile returned pending\n");
ok_eq_hex(IoStatusBlock.Status, Status);
ok_eq_ulongptr(IoStatusBlock.Information, FILE_OPENED);
}
else
{
ok_eq_hex(IoStatusBlock.Status, 0x55555555UL);
ok_eq_ulongptr(IoStatusBlock.Information, 0x5555555555555555ULL);
}
return Status;
}
NTSTATUS
NpOpenPipe(
OUT PHANDLE ClientHandle,
IN PCWSTR PipePath,
IN ULONG NamedPipeConfiguration)
{
ULONG ShareAccess;
if (NamedPipeConfiguration == FILE_PIPE_INBOUND)
ShareAccess = FILE_SHARE_WRITE;
else if (NamedPipeConfiguration == FILE_PIPE_OUTBOUND)
ShareAccess = FILE_SHARE_READ;
else if (NamedPipeConfiguration == FILE_PIPE_FULL_DUPLEX)
ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
return NpOpenPipeEx(ClientHandle,
PipePath,
SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE,
ShareAccess,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT);
}
NTSTATUS
NpControlPipe(
IN HANDLE ServerHandle,
IN ULONG FsControlCode,
IN PVOID InputBuffer,
IN ULONG InputBufferLength)
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
Status = ZwFsControlFile(ServerHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
FsControlCode,
InputBuffer,
InputBufferLength,
NULL,
0);
if (Status == STATUS_PENDING)
{
Status = ZwWaitForSingleObject(ServerHandle,
FALSE,
NULL);
ok_eq_hex(Status, STATUS_SUCCESS);
Status = IoStatusBlock.Status;
}
if (NT_SUCCESS(Status))
{
ok_eq_hex(IoStatusBlock.Status, Status);
ok_eq_ulongptr(IoStatusBlock.Information, 0);
}
else
{
ok_eq_hex(IoStatusBlock.Status, 0x55555555UL);
ok_eq_ulongptr(IoStatusBlock.Information, 0x5555555555555555ULL);
}
return Status;
}
NTSTATUS
NpWaitPipe(
IN PCWSTR PipeName,
IN PLARGE_INTEGER Timeout)
{
NTSTATUS Status;
HANDLE RootHandle;
UNICODE_STRING RootDirectoryName = RTL_CONSTANT_STRING(DEVICE_NAMED_PIPE);
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
PFILE_PIPE_WAIT_FOR_BUFFER WaitForBuffer;
ULONG NameLength;
ULONG BufferSize;
InitializeObjectAttributes(&ObjectAttributes,
&RootDirectoryName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL);
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
Status = IoCreateFile(&RootHandle,
FILE_READ_ATTRIBUTES | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
NULL,
0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0,
CreateFileTypeNone,
NULL,
0);
if (!NT_SUCCESS(Status))
{
ok_eq_hex(IoStatusBlock.Status, 0x55555555UL);
ok_eq_ulongptr(IoStatusBlock.Information, 0x5555555555555555ULL);
return Status;
}
ok(Status != STATUS_PENDING, "IoCreateFile returned pending\n");
ok_eq_hex(IoStatusBlock.Status, Status);
ok_eq_ulongptr(IoStatusBlock.Information, FILE_OPENED);
NameLength = wcslen(PipeName) * sizeof(WCHAR);
BufferSize = FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER,
Name[NameLength / sizeof(WCHAR)]);
WaitForBuffer = ExAllocatePoolWithTag(NonPagedPool, BufferSize, 'WPmK');
if (WaitForBuffer == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
if (Timeout)
{
WaitForBuffer->Timeout.QuadPart = Timeout->QuadPart;
WaitForBuffer->TimeoutSpecified = TRUE;
}
else
{
WaitForBuffer->Timeout.QuadPart = 0;
WaitForBuffer->TimeoutSpecified = FALSE;
}
WaitForBuffer->NameLength = NameLength;
RtlCopyMemory(WaitForBuffer->Name, PipeName, NameLength);
Status = NpControlPipe(RootHandle,
FSCTL_PIPE_WAIT,
WaitForBuffer,
BufferSize);
ExFreePoolWithTag(WaitForBuffer, 'WPmK');
return Status;
}
NTSTATUS
NpReadPipe(
IN HANDLE PipeHandle,
OUT PVOID Buffer,
IN ULONG BufferSize,
OUT PULONG_PTR BytesRead)
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
BOOLEAN PendingReturned = FALSE;
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
Status = ZwReadFile(PipeHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
Buffer,
BufferSize,
NULL,
NULL);
if (Status == STATUS_PENDING)
{
Status = ZwWaitForSingleObject(PipeHandle,
FALSE,
NULL);
ok_eq_hex(Status, STATUS_SUCCESS);
Status = IoStatusBlock.Status;
PendingReturned = TRUE;
}
if (NT_SUCCESS(Status))
{
ok_eq_hex(IoStatusBlock.Status, Status);
*BytesRead = IoStatusBlock.Information;
}
else
{
if (PendingReturned)
{
ok_eq_hex(IoStatusBlock.Status, Status);
ok_eq_ulongptr(IoStatusBlock.Information, 0);
}
else
{
ok_eq_hex(IoStatusBlock.Status, 0x55555555UL);
ok_eq_ulongptr(IoStatusBlock.Information, 0x5555555555555555ULL);
}
*BytesRead = 0;
}
return Status;
}
NTSTATUS
NpWritePipe(
IN HANDLE PipeHandle,
IN const VOID *Buffer,
IN ULONG BufferSize,
OUT PULONG_PTR BytesWritten)
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
Status = ZwWriteFile(PipeHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
(PVOID)Buffer,
BufferSize,
NULL,
NULL);
if (Status == STATUS_PENDING)
{
Status = ZwWaitForSingleObject(PipeHandle,
FALSE,
NULL);
ok_eq_hex(Status, STATUS_SUCCESS);
Status = IoStatusBlock.Status;
}
if (NT_SUCCESS(Status))
{
ok_eq_hex(IoStatusBlock.Status, Status);
*BytesWritten = IoStatusBlock.Information;
}
else
{
ok_eq_hex(IoStatusBlock.Status, 0x55555555UL);
ok_eq_ulongptr(IoStatusBlock.Information, 0x5555555555555555ULL);
*BytesWritten = 0;
}
return Status;
}
static
BOOLEAN
CheckBuffer(
PVOID Buffer,
SIZE_T Size,
UCHAR Value)
{
PUCHAR Array = Buffer;
SIZE_T i;
for (i = 0; i < Size; i++)
if (Array[i] != Value)
{
trace("Expected %x, found %x at offset %lu\n", Value, Array[i], (ULONG)i);
return FALSE;
}
return TRUE;
}
#define ok_eq_print_(value, expected, spec, FileAndLine) \
KmtOk((value) == (expected), FileAndLine, #value " = " spec ", expected " spec "\n", value, expected)
#define ok_eq_ulong_(value, expected) ok_eq_print_(value, expected, "%lu", FileAndLine)
#define ok_eq_ulonglong_(value, expected) ok_eq_print_(value, expected, "%I64u", FileAndLine)
#ifndef _WIN64
#define ok_eq_ulongptr_(value, expected) ok_eq_print_(value, (ULONG_PTR)(expected), "%lu", FileAndLine)
#elif defined _WIN64
#define ok_eq_ulongptr_(value, expected) ok_eq_print_(value, (ULONG_PTR)(expected), "%I64u", FileAndLine)
#endif
#define ok_eq_hex_(value, expected) ok_eq_print_(value, expected, "0x%08lx", FileAndLine)
VOID
NpCheckServerPipe_(
IN HANDLE ServerHandle,
/* PipeInformation */
IN ULONG ReadMode,
IN ULONG CompletionMode,
/* PipeLocalInformation */
IN ULONG NamedPipeType,
IN ULONG NamedPipeConfiguration,
IN ULONG MaximumInstances,
IN ULONG CurrentInstances,
IN ULONG InboundQuota,
IN ULONG ReadDataAvailable,
IN ULONG OutboundQuota,
IN ULONG WriteQuotaAvailable,
IN ULONG NamedPipeState,
/* PipeRemoteInformation */
/* */
IN PCSTR FileAndLine)
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
FILE_PIPE_INFORMATION PipeInfo;
FILE_PIPE_LOCAL_INFORMATION PipeLocalInfo;
FILE_PIPE_REMOTE_INFORMATION PipeRemoteInfo;
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
RtlFillMemory(&PipeInfo, sizeof(PipeInfo), 0x55);
Status = ZwQueryInformationFile(ServerHandle,
&IoStatusBlock,
&PipeInfo,
sizeof(PipeInfo),
FilePipeInformation);
ok_eq_hex_(Status, STATUS_SUCCESS);
ok_eq_hex_(IoStatusBlock.Status, STATUS_SUCCESS);
ok_eq_ulongptr_(IoStatusBlock.Information, sizeof(PipeInfo));
ok_eq_ulong_(PipeInfo.ReadMode, ReadMode);
ok_eq_ulong_(PipeInfo.CompletionMode, CompletionMode);
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
RtlFillMemory(&PipeLocalInfo, sizeof(PipeLocalInfo), 0x55);
Status = ZwQueryInformationFile(ServerHandle,
&IoStatusBlock,
&PipeLocalInfo,
sizeof(PipeLocalInfo),
FilePipeLocalInformation);
ok_eq_hex_(Status, STATUS_SUCCESS);
ok_eq_hex_(IoStatusBlock.Status, STATUS_SUCCESS);
ok_eq_ulongptr_(IoStatusBlock.Information, sizeof(PipeLocalInfo));
ok_eq_ulong_(PipeLocalInfo.NamedPipeType, NamedPipeType);
ok_eq_ulong_(PipeLocalInfo.NamedPipeConfiguration, NamedPipeConfiguration);
ok_eq_ulong_(PipeLocalInfo.MaximumInstances, MaximumInstances);
ok_eq_ulong_(PipeLocalInfo.CurrentInstances, CurrentInstances);
ok_eq_ulong_(PipeLocalInfo.InboundQuota, InboundQuota);
ok_eq_ulong_(PipeLocalInfo.ReadDataAvailable, ReadDataAvailable);
ok_eq_ulong_(PipeLocalInfo.OutboundQuota, OutboundQuota);
ok_eq_ulong_(PipeLocalInfo.WriteQuotaAvailable, WriteQuotaAvailable);
ok_eq_ulong_(PipeLocalInfo.NamedPipeState, NamedPipeState);
ok_eq_ulong_(PipeLocalInfo.NamedPipeEnd, (ULONG)FILE_PIPE_SERVER_END);
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
RtlFillMemory(&PipeRemoteInfo, sizeof(PipeRemoteInfo), 0x55);
Status = ZwQueryInformationFile(ServerHandle,
&IoStatusBlock,
&PipeRemoteInfo,
sizeof(PipeRemoteInfo),
FilePipeInformation);
ok_eq_hex_(Status, STATUS_SUCCESS);
ok_eq_hex_(IoStatusBlock.Status, STATUS_SUCCESS);
ok_eq_ulongptr_(IoStatusBlock.Information, RTL_SIZEOF_THROUGH_FIELD(FILE_PIPE_REMOTE_INFORMATION, CollectDataTime));
ok_eq_ulonglong_(PipeRemoteInfo.CollectDataTime.QuadPart, 0ULL);
ok_eq_ulong_(PipeRemoteInfo.MaximumCollectionCount, 0x55555555UL);
}
VOID
NpCheckClientPipe_(
IN HANDLE ClientHandle,
/* PipeInformation */
IN ULONG ReadMode,
IN ULONG CompletionMode,
/* PipeLocalInformation */
IN ULONG NamedPipeType,
IN ULONG NamedPipeConfiguration,
IN ULONG MaximumInstances,
IN ULONG CurrentInstances,
IN ULONG InboundQuota,
IN ULONG ReadDataAvailable,
IN ULONG OutboundQuota,
IN ULONG WriteQuotaAvailable,
IN ULONG NamedPipeState,
/* PipeRemoteInformation */
/* */
IN PCSTR FileAndLine)
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
FILE_PIPE_INFORMATION PipeInfo;
FILE_PIPE_LOCAL_INFORMATION PipeLocalInfo;
FILE_PIPE_REMOTE_INFORMATION PipeRemoteInfo;
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
RtlFillMemory(&PipeInfo, sizeof(PipeInfo), 0x55);
Status = ZwQueryInformationFile(ClientHandle,
&IoStatusBlock,
&PipeInfo,
sizeof(PipeInfo),
FilePipeInformation);
ok_eq_hex_(Status, STATUS_SUCCESS);
ok_eq_hex_(IoStatusBlock.Status, STATUS_SUCCESS);
ok_eq_ulongptr_(IoStatusBlock.Information, sizeof(PipeInfo));
ok_eq_ulong_(PipeInfo.ReadMode, ReadMode);
ok_eq_ulong_(PipeInfo.CompletionMode, CompletionMode);
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
RtlFillMemory(&PipeLocalInfo, sizeof(PipeLocalInfo), 0x55);
Status = ZwQueryInformationFile(ClientHandle,
&IoStatusBlock,
&PipeLocalInfo,
sizeof(PipeLocalInfo),
FilePipeLocalInformation);
ok_eq_hex_(Status, STATUS_SUCCESS);
ok_eq_hex_(IoStatusBlock.Status, STATUS_SUCCESS);
ok_eq_ulongptr_(IoStatusBlock.Information, sizeof(PipeLocalInfo));
ok_eq_ulong_(PipeLocalInfo.NamedPipeType, NamedPipeType);
ok_eq_ulong_(PipeLocalInfo.NamedPipeConfiguration, NamedPipeConfiguration);
ok_eq_ulong_(PipeLocalInfo.MaximumInstances, MaximumInstances);
ok_eq_ulong_(PipeLocalInfo.CurrentInstances, CurrentInstances);
ok_eq_ulong_(PipeLocalInfo.InboundQuota, InboundQuota);
ok_eq_ulong_(PipeLocalInfo.ReadDataAvailable, ReadDataAvailable);
ok_eq_ulong_(PipeLocalInfo.OutboundQuota, OutboundQuota);
ok_eq_ulong_(PipeLocalInfo.WriteQuotaAvailable, WriteQuotaAvailable);
ok_eq_ulong_(PipeLocalInfo.NamedPipeState, NamedPipeState);
ok_eq_ulong_(PipeLocalInfo.NamedPipeEnd, (ULONG)FILE_PIPE_CLIENT_END);
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
RtlFillMemory(&PipeRemoteInfo, sizeof(PipeRemoteInfo), 0x55);
Status = ZwQueryInformationFile(ClientHandle,
&IoStatusBlock,
&PipeRemoteInfo,
sizeof(PipeRemoteInfo),
FilePipeInformation);
ok_eq_hex_(Status, STATUS_SUCCESS);
ok_eq_hex_(IoStatusBlock.Status, STATUS_SUCCESS);
ok_eq_ulongptr_(IoStatusBlock.Information, RTL_SIZEOF_THROUGH_FIELD(FILE_PIPE_REMOTE_INFORMATION, CollectDataTime));
ok_eq_ulonglong_(PipeRemoteInfo.CollectDataTime.QuadPart, 0ULL);
ok_eq_ulong_(PipeRemoteInfo.MaximumCollectionCount, 0x55555555UL);
}
VOID
NpQueryPipe_(
IN HANDLE PipeHandle,
IN NTSTATUS ExpectedStatus,
IN PCSTR FileAndLine)
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
FILE_PIPE_INFORMATION PipeInfo;
FILE_PIPE_LOCAL_INFORMATION PipeLocalInfo;
FILE_PIPE_REMOTE_INFORMATION PipeRemoteInfo;
ASSERT(!NT_SUCCESS(ExpectedStatus));
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
RtlFillMemory(&PipeInfo, sizeof(PipeInfo), 0x55);
Status = ZwQueryInformationFile(PipeHandle,
&IoStatusBlock,
&PipeInfo,
sizeof(PipeInfo),
FilePipeInformation);
ok_eq_hex_(Status, ExpectedStatus);
ok_bool_true(CheckBuffer(&IoStatusBlock, sizeof(IoStatusBlock), 0x55), "CheckBuffer returned");
ok_bool_true(CheckBuffer(&PipeInfo, sizeof(PipeInfo), 0x55), "CheckBuffer returned");
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
RtlFillMemory(&PipeLocalInfo, sizeof(PipeLocalInfo), 0x55);
Status = ZwQueryInformationFile(PipeHandle,
&IoStatusBlock,
&PipeLocalInfo,
sizeof(PipeLocalInfo),
FilePipeLocalInformation);
ok_eq_hex_(Status, ExpectedStatus);
ok_bool_true(CheckBuffer(&IoStatusBlock, sizeof(IoStatusBlock), 0x55), "CheckBuffer returned");
ok_bool_true(CheckBuffer(&PipeLocalInfo, sizeof(PipeLocalInfo), 0x55), "CheckBuffer returned");
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
RtlFillMemory(&PipeRemoteInfo, sizeof(PipeRemoteInfo), 0x55);
Status = ZwQueryInformationFile(PipeHandle,
&IoStatusBlock,
&PipeRemoteInfo,
sizeof(PipeRemoteInfo),
FilePipeInformation);
ok_eq_hex_(Status, ExpectedStatus);
ok_bool_true(CheckBuffer(&IoStatusBlock, sizeof(IoStatusBlock), 0x55), "CheckBuffer returned");
ok_bool_true(CheckBuffer(&PipeRemoteInfo, sizeof(PipeRemoteInfo), 0x55), "CheckBuffer returned");
}
static KSTART_ROUTINE PipeWorkerThread;
static
VOID
NTAPI
PipeWorkerThread(
IN PVOID ThreadContext)
{
PTHREAD_CONTEXT Context = ThreadContext;
PVOID WaitEvents[2] = { &Context->ThreadDoneEvent,
&Context->StartWorkEvent };
NTSTATUS Status;
while (TRUE)
{
Status = KeWaitForMultipleObjects(RTL_NUMBER_OF(WaitEvents),
WaitEvents,
WaitAny,
Executive,
KernelMode,
FALSE,
NULL,
NULL);
if (Status == STATUS_WAIT_0)
break;
ASSERT(Status == STATUS_WAIT_1);
Context->Work(Context);
KeSetEvent(&Context->WorkCompleteEvent, IO_NO_INCREMENT, TRUE);
}
}
VOID
StartWorkerThread(
OUT PTHREAD_CONTEXT Context)
{
KeInitializeEvent(&Context->ThreadDoneEvent, NotificationEvent, FALSE);
KeInitializeEvent(&Context->StartWorkEvent, SynchronizationEvent, FALSE);
KeInitializeEvent(&Context->WorkCompleteEvent, NotificationEvent, TRUE);
Context->Thread = KmtStartThread(PipeWorkerThread, Context);
}
VOID
FinishWorkerThread(
IN PTHREAD_CONTEXT Context)
{
KmtFinishThread(Context->Thread, &Context->ThreadDoneEvent);
}
BOOLEAN
WaitForWork(
IN PTHREAD_CONTEXT Context,
IN ULONG MilliSeconds)
{
LARGE_INTEGER Timeout;
NTSTATUS Status;
Timeout.QuadPart = -10 * 1000 * (LONGLONG)MilliSeconds;
Status = KeWaitForSingleObject(&Context->WorkCompleteEvent,
Executive,
KernelMode,
FALSE,
&Timeout);
ok(Status == STATUS_SUCCESS || Status == STATUS_TIMEOUT, "Wait status %lx\n", Status);
return Status != STATUS_TIMEOUT;
}
BOOLEAN
TriggerWork(
IN PTHREAD_CONTEXT Context,
IN ULONG MilliSeconds)
{
NTSTATUS Status;
Status = KeWaitForSingleObject(&Context->WorkCompleteEvent,
Executive,
KernelMode,
FALSE,
NULL);
ok_eq_hex(Status, STATUS_SUCCESS);
KeResetEvent(&Context->WorkCompleteEvent);
KeSetEvent(&Context->StartWorkEvent, IO_NO_INCREMENT, TRUE);
return WaitForWork(Context, MilliSeconds);
}
PKTHREAD
KmtStartThread(
IN PKSTART_ROUTINE StartRoutine,
IN PVOID StartContext OPTIONAL)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE ThreadHandle;
PVOID ThreadObject = NULL;
InitializeObjectAttributes(&ObjectAttributes,
NULL,
OBJ_KERNEL_HANDLE,
NULL,
NULL);
ThreadHandle = INVALID_HANDLE_VALUE;
Status = PsCreateSystemThread(&ThreadHandle,
SYNCHRONIZE,
&ObjectAttributes,
NULL,
NULL,
StartRoutine,
StartContext);
ok_eq_hex(Status, STATUS_SUCCESS);
if (!skip(NT_SUCCESS(Status) && ThreadHandle != NULL && ThreadHandle != INVALID_HANDLE_VALUE, "No thread\n"))
{
Status = ObReferenceObjectByHandle(ThreadHandle,
SYNCHRONIZE,
*PsThreadType,
KernelMode,
&ThreadObject,
NULL);
ok_eq_hex(Status, STATUS_SUCCESS);
ObCloseHandle(ThreadHandle, KernelMode);
}
return ThreadObject;
}
VOID
KmtFinishThread(
IN PKTHREAD Thread OPTIONAL,
IN PKEVENT Event OPTIONAL)
{
NTSTATUS Status;
if (skip(Thread != NULL, "No thread\n"))
return;
if (Event)
KeSetEvent(Event, IO_NO_INCREMENT, TRUE);
Status = KeWaitForSingleObject(Thread,
Executive,
KernelMode,
FALSE,
NULL);
ok_eq_hex(Status, STATUS_SUCCESS);
ObDereferenceObject(Thread);
}