[KMTESTS:NPFS]

- Add some (pretty incomplete) tests for NPFS Create, Connect and Read/Write operations
CORE-7451

svn path=/trunk/; revision=62695
This commit is contained in:
Thomas Faber 2014-04-09 18:00:33 +00:00
parent 9ef6a8868b
commit 08df30bc8b
7 changed files with 1997 additions and 0 deletions

View file

@ -28,6 +28,10 @@ list(APPEND KMTEST_DRV_SOURCE
example/Example.c
example/KernelType.c
npfs/NpfsConnect.c
npfs/NpfsCreate.c
npfs/NpfsHelpers.c
npfs/NpfsReadWrite.c
ntos_ex/ExCallback.c
ntos_ex/ExDoubleList.c
ntos_ex/ExFastMutex.c

View file

@ -38,6 +38,9 @@ KMT_TESTFUNC Test_KeProcessor;
KMT_TESTFUNC Test_KeTimer;
KMT_TESTFUNC Test_KernelType;
KMT_TESTFUNC Test_MmSection;
KMT_TESTFUNC Test_NpfsConnect;
KMT_TESTFUNC Test_NpfsCreate;
KMT_TESTFUNC Test_NpfsReadWrite;
KMT_TESTFUNC Test_ObReference;
KMT_TESTFUNC Test_ObType;
KMT_TESTFUNC Test_ObTypeClean;
@ -89,6 +92,9 @@ const KMT_TEST TestList[] =
{ "KeTimer", Test_KeTimer },
{ "-KernelType", Test_KernelType },
{ "MmSection", Test_MmSection },
{ "NpfsConnect", Test_NpfsConnect },
{ "NpfsCreate", Test_NpfsCreate },
{ "NpfsReadWrite", Test_NpfsReadWrite },
{ "ObReference", Test_ObReference },
{ "ObType", Test_ObType },
{ "-ObTypeClean", Test_ObTypeClean },

View file

@ -0,0 +1,272 @@
/*
* PROJECT: ReactOS kernel-mode tests
* LICENSE: LGPLv2+ - See COPYING.LIB in the top level directory
* PURPOSE: Kernel-Mode Test Suite NPFS Connect test
* PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
*/
#include <kmt_test.h>
#include "npfs.h"
#define MAX_INSTANCES 5
#define IN_QUOTA 4096
#define OUT_QUOTA 4096
#define CheckServer(ServerHandle, State) \
NpCheckServerPipe(ServerHandle, \
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX, \
MAX_INSTANCES, 1, \
IN_QUOTA, 0, \
OUT_QUOTA, OUT_QUOTA, \
State)
#define CheckClient(ClientHandle, State) \
NpCheckClientPipe(ClientHandle, \
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX, \
MAX_INSTANCES, 1, \
IN_QUOTA, 0, \
OUT_QUOTA, OUT_QUOTA, \
State)
static
VOID
ConnectPipe(
IN OUT PTHREAD_CONTEXT Context)
{
HANDLE ClientHandle;
ClientHandle = NULL;
Context->Connect.Status = NpOpenPipe(&ClientHandle,
Context->Connect.PipePath,
FILE_PIPE_FULL_DUPLEX);
Context->Connect.ClientHandle = ClientHandle;
}
static
VOID
ListenPipe(
IN OUT PTHREAD_CONTEXT Context)
{
Context->Listen.Status = NpListenPipe(Context->Listen.ServerHandle);
}
static
BOOLEAN
CheckConnectPipe(
IN PTHREAD_CONTEXT Context,
IN PCWSTR PipePath,
IN ULONG MilliSeconds)
{
Context->Work = ConnectPipe;
Context->Connect.PipePath = PipePath;
return TriggerWork(Context, MilliSeconds);
}
static
BOOLEAN
CheckListenPipe(
IN PTHREAD_CONTEXT Context,
IN HANDLE ServerHandle,
IN ULONG MilliSeconds)
{
Context->Work = ListenPipe;
Context->Listen.ServerHandle = ServerHandle;
return TriggerWork(Context, MilliSeconds);
}
static
VOID
TestConnect(
IN HANDLE ServerHandle,
IN PCWSTR PipePath)
{
NTSTATUS Status;
THREAD_CONTEXT ConnectContext;
THREAD_CONTEXT ListenContext;
BOOLEAN Okay;
HANDLE ClientHandle;
StartWorkerThread(&ConnectContext);
StartWorkerThread(&ListenContext);
/* Server should start out listening */
CheckServer(ServerHandle, FILE_PIPE_LISTENING_STATE);
/* Connect a client */
ClientHandle = NULL;
Okay = CheckConnectPipe(&ConnectContext, PipePath, 100);
ok_bool_true(Okay, "CheckConnectPipe returned");
ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
if (NT_SUCCESS(ConnectContext.Connect.Status))
{
ClientHandle = ConnectContext.Connect.ClientHandle;
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
}
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
/* Connect another client */
Okay = CheckConnectPipe(&ConnectContext, PipePath, 100);
ok_bool_true(Okay, "CheckConnectPipe returned");
ok_eq_hex(ConnectContext.Connect.Status, STATUS_PIPE_NOT_AVAILABLE);
if (NT_SUCCESS(ConnectContext.Connect.Status))
ObCloseHandle(ConnectContext.Connect.ClientHandle, KernelMode);
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
/* Disconnecting the client should fail */
Status = NpDisconnectPipe(ClientHandle);
ok_eq_hex(Status, STATUS_ILLEGAL_FUNCTION);
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
/* Listening on the client should fail */
Status = NpListenPipe(ClientHandle);
ok_eq_hex(Status, STATUS_ILLEGAL_FUNCTION);
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
/* Close client */
if (ClientHandle)
ObCloseHandle(ClientHandle, KernelMode);
CheckServer(ServerHandle, FILE_PIPE_CLOSING_STATE);
/* Connecting a client now should fail */
Okay = CheckConnectPipe(&ConnectContext, PipePath, 100);
ok_bool_true(Okay, "CheckConnectPipe returned");
ok_eq_hex(ConnectContext.Connect.Status, STATUS_PIPE_NOT_AVAILABLE);
if (NT_SUCCESS(ConnectContext.Connect.Status))
ObCloseHandle(ConnectContext.Connect.ClientHandle, KernelMode);
CheckServer(ServerHandle, FILE_PIPE_CLOSING_STATE);
/* Listening should fail */
Okay = CheckListenPipe(&ListenContext, ServerHandle, 100);
ok_bool_true(Okay, "CheckListenPipe returned");
if (!skip(Okay, "Listen succeeded unexpectedly\n"))
CheckServer(ServerHandle, FILE_PIPE_CLOSING_STATE);
/* Disconnect server */
Status = NpDisconnectPipe(ServerHandle);
ok_eq_hex(Status, STATUS_SUCCESS);
CheckServer(ServerHandle, FILE_PIPE_DISCONNECTED_STATE);
/* Disconnecting again should fail */
Status = NpDisconnectPipe(ServerHandle);
ok_eq_hex(Status, STATUS_PIPE_DISCONNECTED);
CheckServer(ServerHandle, FILE_PIPE_DISCONNECTED_STATE);
/* Connecting a client now should fail */
Okay = CheckConnectPipe(&ConnectContext, PipePath, 100);
ok_bool_true(Okay, "CheckConnectPipe returned");
ok_eq_hex(ConnectContext.Connect.Status, STATUS_PIPE_NOT_AVAILABLE);
if (NT_SUCCESS(ConnectContext.Connect.Status))
ObCloseHandle(ConnectContext.Connect.ClientHandle, KernelMode);
CheckServer(ServerHandle, FILE_PIPE_DISCONNECTED_STATE);
/**************************************************************************/
/* Now listen again */
Okay = CheckListenPipe(&ListenContext, ServerHandle, 100);
ok_bool_false(Okay, "CheckListenPipe returned");
//blocks: CheckServer(ServerHandle, FILE_PIPE_LISTENING_STATE);
/* Connect client */
ClientHandle = NULL;
Okay = CheckConnectPipe(&ConnectContext, PipePath, 100);
ok_bool_true(Okay, "CheckConnectPipe returned");
ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
if (NT_SUCCESS(ConnectContext.Connect.Status))
{
ClientHandle = ConnectContext.Connect.ClientHandle;
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
}
Okay = WaitForWork(&ListenContext, 100);
ok_bool_true(Okay, "WaitForWork returned");
ok_eq_hex(ListenContext.Listen.Status, STATUS_SUCCESS);
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
/* Listening again should fail */
Okay = CheckListenPipe(&ListenContext, ServerHandle, 100);
ok_bool_true(Okay, "CheckListenPipe returned");
ok_eq_hex(ListenContext.Listen.Status, STATUS_PIPE_CONNECTED);
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
/* Disconnect server */
Status = NpDisconnectPipe(ServerHandle);
ok_eq_hex(Status, STATUS_SUCCESS);
NpQueryPipe(ClientHandle, STATUS_PIPE_DISCONNECTED);
CheckServer(ServerHandle, FILE_PIPE_DISCONNECTED_STATE);
/* Close client */
if (ClientHandle)
ObCloseHandle(ClientHandle, KernelMode);
CheckServer(ServerHandle, FILE_PIPE_DISCONNECTED_STATE);
/**************************************************************************/
/* Listen once more */
Okay = CheckListenPipe(&ListenContext, ServerHandle, 100);
ok_bool_false(Okay, "CheckListenPipe returned");
//blocks: CheckServer(ServerHandle, FILE_PIPE_LISTENING_STATE);
/* Connect client */
ClientHandle = NULL;
Okay = CheckConnectPipe(&ConnectContext, PipePath, 100);
ok_bool_true(Okay, "CheckConnectPipe returned");
ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
if (NT_SUCCESS(ConnectContext.Connect.Status))
{
ClientHandle = ConnectContext.Connect.ClientHandle;
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
}
Okay = WaitForWork(&ListenContext, 100);
ok_bool_true(Okay, "WaitForWork returned");
ok_eq_hex(ListenContext.Listen.Status, STATUS_SUCCESS);
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
/* Close server */
Status = ObCloseHandle(ServerHandle, KernelMode);
ok_eq_hex(Status, STATUS_SUCCESS);
CheckClient(ClientHandle, FILE_PIPE_CLOSING_STATE);
/* Close client */
if (ClientHandle)
ObCloseHandle(ClientHandle, KernelMode);
FinishWorkerThread(&ListenContext);
FinishWorkerThread(&ConnectContext);
}
static KSTART_ROUTINE RunTest;
static
VOID
NTAPI
RunTest(
IN PVOID Context)
{
NTSTATUS Status;
HANDLE ServerHandle;
UNREFERENCED_PARAMETER(Context);
ServerHandle = INVALID_HANDLE_VALUE;
Status = NpCreatePipe(&ServerHandle,
DEVICE_NAMED_PIPE L"\\KmtestNpfsConnectTestPipe",
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX,
MAX_INSTANCES,
IN_QUOTA,
OUT_QUOTA);
ok_eq_hex(Status, STATUS_SUCCESS);
ok(ServerHandle != NULL && ServerHandle != INVALID_HANDLE_VALUE, "ServerHandle = %p\n", ServerHandle);
if (!skip(NT_SUCCESS(Status) && ServerHandle != NULL && ServerHandle != INVALID_HANDLE_VALUE, "No pipe\n"))
{
CheckServer(ServerHandle, FILE_PIPE_LISTENING_STATE);
TestConnect(ServerHandle, DEVICE_NAMED_PIPE L"\\KmtestNpfsConnectTestPipe");
}
}
START_TEST(NpfsConnect)
{
PKTHREAD Thread;
Thread = KmtStartThread(RunTest, NULL);
KmtFinishThread(Thread, NULL);
}

View file

@ -0,0 +1,118 @@
/*
* PROJECT: ReactOS kernel-mode tests
* LICENSE: LGPLv2+ - See COPYING.LIB in the top level directory
* PURPOSE: Kernel-Mode Test Suite NPFS Create test
* PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
*/
#include <kmt_test.h>
#include "npfs.h"
static
VOID
TestCreateNamedPipe(VOID)
{
NTSTATUS Status;
HANDLE ServerHandle;
ULONG MaxInstances;
ULONG InQuota, OutQuota;
ULONG Quotas[] = { 0, 1, 2, 1024, PAGE_SIZE - 1, PAGE_SIZE, PAGE_SIZE + 1, 2 * PAGE_SIZE, 8 * PAGE_SIZE, 64 * PAGE_SIZE, 64 * PAGE_SIZE + 1, 128 * PAGE_SIZE };
ULONG i;
LARGE_INTEGER Timeout;
/* Invalid pipe name */
MaxInstances = 1;
InQuota = 4096;
OutQuota = 4096;
ServerHandle = INVALID_HANDLE_VALUE;
Status = NpCreatePipe(&ServerHandle,
DEVICE_NAMED_PIPE L"",
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX,
MaxInstances,
InQuota,
OutQuota);
ok_eq_hex(Status, STATUS_OBJECT_NAME_INVALID);
ok_eq_pointer(ServerHandle, INVALID_HANDLE_VALUE);
if (ServerHandle != NULL && ServerHandle != INVALID_HANDLE_VALUE)
ObCloseHandle(ServerHandle, KernelMode);
ServerHandle = INVALID_HANDLE_VALUE;
Status = NpCreatePipe(&ServerHandle,
DEVICE_NAMED_PIPE L"\\",
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX,
MaxInstances,
InQuota,
OutQuota);
ok_eq_hex(Status, STATUS_OBJECT_NAME_INVALID);
ok_eq_pointer(ServerHandle, INVALID_HANDLE_VALUE);
if (ServerHandle != NULL && ServerHandle != INVALID_HANDLE_VALUE)
ObCloseHandle(ServerHandle, KernelMode);
ServerHandle = INVALID_HANDLE_VALUE;
Status = NpCreatePipe(&ServerHandle,
DEVICE_NAMED_PIPE L"\\\\",
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX,
MaxInstances,
InQuota,
OutQuota);
ok_eq_hex(Status, STATUS_OBJECT_NAME_INVALID);
ok_eq_pointer(ServerHandle, INVALID_HANDLE_VALUE);
if (ServerHandle != NULL && ServerHandle != INVALID_HANDLE_VALUE)
ObCloseHandle(ServerHandle, KernelMode);
/* Test in-quota */
MaxInstances = 1;
OutQuota = 4096;
for (i = 0; i < RTL_NUMBER_OF(Quotas); i++)
{
InQuota = Quotas[i];
ServerHandle = INVALID_HANDLE_VALUE;
Status = NpCreatePipe(&ServerHandle,
DEVICE_NAMED_PIPE L"\\KmtestNpfsCreateTestPipe",
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX,
MaxInstances,
InQuota,
OutQuota);
ok_eq_hex(Status, STATUS_SUCCESS);
ok(ServerHandle != NULL && ServerHandle != INVALID_HANDLE_VALUE, "ServerHandle = %p\n", ServerHandle);
if (!skip(NT_SUCCESS(Status) && ServerHandle != NULL && ServerHandle != INVALID_HANDLE_VALUE, "No pipe\n"))
{
NpCheckServerPipe(ServerHandle,
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX,
MaxInstances, 1,
InQuota, 0,
OutQuota, OutQuota,
FILE_PIPE_LISTENING_STATE);
ObCloseHandle(ServerHandle, KernelMode);
Timeout.QuadPart = -100 * 1000 * 10;
Status = KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
ok_eq_hex(Status, STATUS_SUCCESS);
}
}
}
static
VOID
TestCreate(VOID)
{
}
static KSTART_ROUTINE RunTest;
static
VOID
NTAPI
RunTest(
IN PVOID Context)
{
UNREFERENCED_PARAMETER(Context);
TestCreateNamedPipe();
TestCreate();
}
START_TEST(NpfsCreate)
{
PKTHREAD Thread;
Thread = KmtStartThread(RunTest, NULL);
KmtFinishThread(Thread, NULL);
}

View file

@ -0,0 +1,774 @@
/*
* 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);
}

View file

@ -0,0 +1,598 @@
/*
* PROJECT: ReactOS kernel-mode tests
* LICENSE: LGPLv2+ - See COPYING.LIB in the top level directory
* PURPOSE: Kernel-Mode Test Suite NPFS Read/Write test
* PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
*/
#include <kmt_test.h>
#include "npfs.h"
typedef struct _READ_WRITE_TEST_CONTEXT
{
PCWSTR PipePath;
BOOLEAN ServerSynchronous;
BOOLEAN ClientSynchronous;
} READ_WRITE_TEST_CONTEXT, *PREAD_WRITE_TEST_CONTEXT;
#define MAX_INSTANCES 5
#define IN_QUOTA 4096
#define OUT_QUOTA 4096
#define MakeServer(ServerHandle, PipePath, ServerSynchronous) \
NpCreatePipeEx(ServerHandle, \
PipePath, \
BYTE_STREAM, \
QUEUE, \
BYTE_STREAM, \
FILE_SHARE_READ | FILE_SHARE_WRITE, \
MAX_INSTANCES, \
IN_QUOTA, \
OUT_QUOTA, \
SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE, \
FILE_OPEN_IF, \
(ServerSynchronous) ? FILE_SYNCHRONOUS_IO_NONALERT \
: 0, \
&DefaultTimeout)
#define CheckServer(ServerHandle, State) \
NpCheckServerPipe(ServerHandle, \
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX, \
MAX_INSTANCES, 1, \
IN_QUOTA, 0, \
OUT_QUOTA, OUT_QUOTA, \
State)
#define CheckClient(ClientHandle, State) \
NpCheckClientPipe(ClientHandle, \
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX, \
MAX_INSTANCES, 1, \
IN_QUOTA, 0, \
OUT_QUOTA, OUT_QUOTA, \
State)
#define CheckServerQuota(ServerHandle, InQ, OutQ) \
NpCheckServerPipe(ServerHandle, \
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX, \
MAX_INSTANCES, 1, \
IN_QUOTA, InQ, \
OUT_QUOTA, OUT_QUOTA - (OutQ), \
FILE_PIPE_CONNECTED_STATE)
#define CheckClientQuota(ClientHandle, InQ, OutQ) \
NpCheckClientPipe(ClientHandle, \
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX, \
MAX_INSTANCES, 1, \
IN_QUOTA, InQ, \
OUT_QUOTA, OUT_QUOTA - (OutQ), \
FILE_PIPE_CONNECTED_STATE)
#define CheckPipeContext(Context, ExpectedStatus, ExpectedBytes) do \
{ \
ok_bool_true(Okay, "CheckPipeContext"); \
ok_eq_hex((Context)->ReadWrite.Status, ExpectedStatus); \
ok_eq_ulongptr((Context)->ReadWrite.BytesTransferred, ExpectedBytes); \
} while (0)
static
VOID
ConnectPipe(
IN OUT PTHREAD_CONTEXT Context)
{
HANDLE ClientHandle;
ClientHandle = NULL;
Context->Connect.Status = NpOpenPipeEx(&ClientHandle,
Context->Connect.PipePath,
SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN,
Context->Connect.ClientSynchronous ? FILE_SYNCHRONOUS_IO_NONALERT
: 0);
Context->Connect.ClientHandle = ClientHandle;
}
static
VOID
ListenPipe(
IN OUT PTHREAD_CONTEXT Context)
{
Context->Listen.Status = NpListenPipe(Context->Listen.ServerHandle);
}
static
VOID
ReadPipe(
IN OUT PTHREAD_CONTEXT Context)
{
Context->ReadWrite.Status = NpReadPipe(Context->ReadWrite.PipeHandle,
Context->ReadWrite.Buffer,
Context->ReadWrite.BufferSize,
(PULONG_PTR)&Context->ReadWrite.BytesTransferred);
}
static
VOID
WritePipe(
IN OUT PTHREAD_CONTEXT Context)
{
Context->ReadWrite.Status = NpWritePipe(Context->ReadWrite.PipeHandle,
Context->ReadWrite.Buffer,
Context->ReadWrite.BufferSize,
(PULONG_PTR)&Context->ReadWrite.BytesTransferred);
}
static
BOOLEAN
CheckConnectPipe(
IN PTHREAD_CONTEXT Context,
IN PCWSTR PipePath,
IN BOOLEAN ClientSynchronous,
IN ULONG MilliSeconds)
{
Context->Work = ConnectPipe;
Context->Connect.PipePath = PipePath;
Context->Connect.ClientSynchronous = ClientSynchronous;
return TriggerWork(Context, MilliSeconds);
}
static
BOOLEAN
CheckListenPipe(
IN PTHREAD_CONTEXT Context,
IN HANDLE ServerHandle,
IN ULONG MilliSeconds)
{
Context->Work = ListenPipe;
Context->Listen.ServerHandle = ServerHandle;
return TriggerWork(Context, MilliSeconds);
}
static
BOOLEAN
CheckReadPipe(
IN PTHREAD_CONTEXT Context,
IN HANDLE PipeHandle,
OUT PVOID Buffer,
IN ULONG BufferSize,
IN ULONG MilliSeconds)
{
Context->Work = ReadPipe;
Context->ReadWrite.PipeHandle = PipeHandle;
Context->ReadWrite.Buffer = Buffer;
Context->ReadWrite.BufferSize = BufferSize;
return TriggerWork(Context, MilliSeconds);
}
static
BOOLEAN
CheckWritePipe(
IN PTHREAD_CONTEXT Context,
IN HANDLE PipeHandle,
IN const VOID *Buffer,
IN ULONG BufferSize,
IN ULONG MilliSeconds)
{
Context->Work = WritePipe;
Context->ReadWrite.PipeHandle = PipeHandle;
Context->ReadWrite.Buffer = (PVOID)Buffer;
Context->ReadWrite.BufferSize = BufferSize;
return TriggerWork(Context, MilliSeconds);
}
static KSTART_ROUTINE TestReadWrite;
static
VOID
NTAPI
TestReadWrite(
IN PVOID Context)
{
PREAD_WRITE_TEST_CONTEXT TestContext = Context;
PCWSTR PipePath = TestContext->PipePath;
BOOLEAN ServerSynchronous = TestContext->ServerSynchronous;
BOOLEAN ClientSynchronous = TestContext->ClientSynchronous;
NTSTATUS Status;
HANDLE ServerHandle;
LARGE_INTEGER DefaultTimeout;
THREAD_CONTEXT ConnectContext;
THREAD_CONTEXT ListenContext;
THREAD_CONTEXT ClientReadContext;
THREAD_CONTEXT ClientWriteContext;
THREAD_CONTEXT ServerReadContext;
THREAD_CONTEXT ServerWriteContext;
BOOLEAN Okay;
HANDLE ClientHandle;
UCHAR ReadBuffer[128];
UCHAR WriteBuffer[128];
StartWorkerThread(&ConnectContext);
StartWorkerThread(&ListenContext);
StartWorkerThread(&ClientReadContext);
StartWorkerThread(&ClientWriteContext);
StartWorkerThread(&ServerReadContext);
StartWorkerThread(&ServerWriteContext);
DefaultTimeout.QuadPart = -50 * 1000 * 10;
/* Server should start out listening */
Status = MakeServer(&ServerHandle, PipePath, ServerSynchronous);
ok_eq_hex(Status, STATUS_SUCCESS);
CheckServer(ServerHandle, FILE_PIPE_LISTENING_STATE);
Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, NULL, 0, 100);
ok_bool_true(Okay, "CheckWritePipe returned");
ok_eq_ulongptr(ServerWriteContext.ReadWrite.BytesTransferred, 0);
ok_eq_hex(ServerWriteContext.ReadWrite.Status, STATUS_PIPE_LISTENING);
Okay = CheckReadPipe(&ServerReadContext, ServerHandle, NULL, 0, 100);
ok_bool_true(Okay, "CheckReadPipe returned");
ok_eq_ulongptr(ServerReadContext.ReadWrite.BytesTransferred, 0);
ok_eq_hex(ServerReadContext.ReadWrite.Status, STATUS_PIPE_LISTENING);
/* Connect a client */
Okay = CheckConnectPipe(&ConnectContext, PipePath, ClientSynchronous, 100);
ok_bool_true(Okay, "CheckConnectPipe returned");
ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
ClientHandle = ConnectContext.Connect.ClientHandle;
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
/** Server to client, write first, 1 byte */
WriteBuffer[0] = 'A';
ReadBuffer[0] = 'X';
Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, WriteBuffer, 1, 100);
CheckPipeContext(&ServerWriteContext, STATUS_SUCCESS, 1);
CheckServerQuota(ServerHandle, 0, 1); CheckClientQuota(ClientHandle, 1, 0);
Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
CheckPipeContext(&ClientReadContext, STATUS_SUCCESS, 1);
ok_eq_uint(ReadBuffer[0], 'A');
CheckServerQuota(ServerHandle, 0, 0); CheckClientQuota(ClientHandle, 0, 0);
/** Server to client, read first, 1 byte */
WriteBuffer[0] = 'B';
ReadBuffer[0] = 'X';
Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
ok_bool_false(Okay, "CheckReadPipe returned");
CheckServerQuota(ServerHandle, 0, 1);
Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, WriteBuffer, 1, 100);
CheckPipeContext(&ServerWriteContext, STATUS_SUCCESS, 1);
Okay = WaitForWork(&ClientReadContext, 100);
CheckPipeContext(&ClientReadContext, STATUS_SUCCESS, 1);
ok_eq_uint(ReadBuffer[0], 'B');
CheckServerQuota(ServerHandle, 0, 0); CheckClientQuota(ClientHandle, 0, 0);
/** Client to server, write first, 1 byte */
WriteBuffer[0] = 'C';
ReadBuffer[0] = 'X';
Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, WriteBuffer, 1, 100);
CheckPipeContext(&ClientWriteContext, STATUS_SUCCESS, 1);
CheckClientQuota(ClientHandle, 0, 1); CheckServerQuota(ServerHandle, 1, 0);
Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
CheckPipeContext(&ServerReadContext, STATUS_SUCCESS, 1);
ok_eq_uint(ReadBuffer[0], 'C');
CheckClientQuota(ClientHandle, 0, 0); CheckServerQuota(ServerHandle, 0, 0);
/** Client to server, read first, 1 byte */
WriteBuffer[0] = 'D';
ReadBuffer[0] = 'X';
Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
ok_bool_false(Okay, "CheckReadPipe returned");
CheckClientQuota(ClientHandle, 0, 1);
Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, WriteBuffer, 1, 100);
CheckPipeContext(&ClientWriteContext, STATUS_SUCCESS, 1);
Okay = WaitForWork(&ServerReadContext, 100);
CheckPipeContext(&ServerReadContext, STATUS_SUCCESS, 1);
ok_eq_uint(ReadBuffer[0], 'D');
CheckClientQuota(ClientHandle, 0, 0); CheckServerQuota(ServerHandle, 0, 0);
/** Server to client, write 0 bytes */
Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, (PVOID)1, 0, 100);
CheckPipeContext(&ServerWriteContext, STATUS_SUCCESS, 0);
CheckServerQuota(ServerHandle, 0, 0); CheckClientQuota(ClientHandle, 0, 0);
/** Client to Server, write 0 bytes */
Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, (PVOID)1, 0, 100);
CheckPipeContext(&ClientWriteContext, STATUS_SUCCESS, 0);
CheckClientQuota(ClientHandle, 0, 0); CheckServerQuota(ServerHandle, 0, 0);
/** Server to client, read 0 bytes blocks, write 0 bytes does not unblock, write 1 byte unblocks */
WriteBuffer[0] = 'E';
ReadBuffer[0] = 'X';
Okay = CheckReadPipe(&ClientReadContext, ClientHandle, (PVOID)1, 0, 100);
ok_bool_false(Okay, "CheckReadPipe returned");
CheckServerQuota(ServerHandle, 0, 0);
Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, (PVOID)1, 0, 100);
CheckPipeContext(&ServerWriteContext, STATUS_SUCCESS, 0);
Okay = WaitForWork(&ClientReadContext, 100);
ok_bool_false(Okay, "WaitForWork returned");
CheckServerQuota(ServerHandle, 0, 0);
Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, WriteBuffer, 1, 100);
CheckPipeContext(&ServerWriteContext, STATUS_SUCCESS, 1);
Okay = WaitForWork(&ClientReadContext, 100);
CheckPipeContext(&ClientReadContext, STATUS_SUCCESS, 0);
ok_eq_uint(ReadBuffer[0], 'X');
CheckServerQuota(ServerHandle, 0, 1); CheckClientQuota(ClientHandle, 1, 0);
Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
CheckPipeContext(&ClientReadContext, STATUS_SUCCESS, 1);
ok_eq_uint(ReadBuffer[0], 'E');
CheckServerQuota(ServerHandle, 0, 0); CheckClientQuota(ClientHandle, 0, 0);
/** Client to server, read 0 bytes blocks, write 0 bytes does not unblock, write 1 byte unblocks */
WriteBuffer[0] = 'F';
ReadBuffer[0] = 'X';
Okay = CheckReadPipe(&ServerReadContext, ServerHandle, (PVOID)1, 0, 100);
ok_bool_false(Okay, "CheckReadPipe returned");
CheckClientQuota(ClientHandle, 0, 0);
Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, (PVOID)1, 0, 100);
CheckPipeContext(&ClientWriteContext, STATUS_SUCCESS, 0);
Okay = WaitForWork(&ServerReadContext, 100);
ok_bool_false(Okay, "WaitForWork returned");
CheckClientQuota(ClientHandle, 0, 0);
Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, WriteBuffer, 1, 100);
CheckPipeContext(&ClientWriteContext, STATUS_SUCCESS, 1);
Okay = WaitForWork(&ServerReadContext, 100);
CheckPipeContext(&ServerReadContext, STATUS_SUCCESS, 0);
ok_eq_uint(ReadBuffer[0], 'X');
CheckClientQuota(ClientHandle, 0, 1); CheckServerQuota(ServerHandle, 1, 0);
Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
CheckPipeContext(&ServerReadContext, STATUS_SUCCESS, 1);
ok_eq_uint(ReadBuffer[0], 'F');
CheckClientQuota(ClientHandle, 0, 0); CheckServerQuota(ServerHandle, 0, 0);
/** Disconnect server with pending read on client */
WriteBuffer[0] = 'G';
ReadBuffer[0] = 'X';
Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
ok_bool_false(Okay, "CheckReadPipe returned");
CheckServerQuota(ServerHandle, 0, 1);
Status = NpDisconnectPipe(ServerHandle);
ok_eq_hex(Status, STATUS_SUCCESS);
Okay = WaitForWork(&ClientReadContext, 100);
CheckPipeContext(&ClientReadContext, STATUS_PIPE_DISCONNECTED, 0);
ok_eq_uint(ReadBuffer[0], 'X');
/* Read from server when disconnected */
Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
CheckPipeContext(&ServerReadContext, STATUS_PIPE_DISCONNECTED, 0);
/* Write to server when disconnected */
Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, WriteBuffer, 1, 100);
CheckPipeContext(&ServerWriteContext, STATUS_PIPE_DISCONNECTED, 0);
/* Read from client when disconnected */
Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
CheckPipeContext(&ClientReadContext, STATUS_PIPE_DISCONNECTED, 0);
/* Write to client when disconnected */
Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, WriteBuffer, 1, 100);
CheckPipeContext(&ClientWriteContext, STATUS_PIPE_DISCONNECTED, 0);
Status = ObCloseHandle(ClientHandle, KernelMode);
ok_eq_hex(Status, STATUS_SUCCESS);
/* Restore the connection */
Okay = CheckListenPipe(&ListenContext, ServerHandle, 100);
ok_bool_false(Okay, "CheckListenPipe returned");
Okay = CheckConnectPipe(&ConnectContext, PipePath, ClientSynchronous, 100);
ok_bool_true(Okay, "CheckConnectPipe returned");
ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
Okay = WaitForWork(&ListenContext, 100);
ok_bool_true(Okay, "WaitForWork returned");
ok_eq_hex(ListenContext.Listen.Status, STATUS_SUCCESS);
ClientHandle = ConnectContext.Connect.ClientHandle;
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
/** Close server with pending read on client */
WriteBuffer[0] = 'H';
ReadBuffer[0] = 'X';
Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
ok_bool_false(Okay, "CheckReadPipe returned");
Status = ObCloseHandle(ServerHandle, KernelMode);
ok_eq_hex(Status, STATUS_SUCCESS);
Okay = WaitForWork(&ClientReadContext, 100);
CheckPipeContext(&ClientReadContext, STATUS_PIPE_BROKEN, 0);
ok_eq_uint(ReadBuffer[0], 'X');
/* Read from client when closed */
Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
CheckPipeContext(&ClientReadContext, STATUS_PIPE_BROKEN, 0);
/* Write to client when closed */
Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, WriteBuffer, 1, 100);
CheckPipeContext(&ClientWriteContext, STATUS_PIPE_CLOSING, 0);
Status = ObCloseHandle(ClientHandle, KernelMode);
ok_eq_hex(Status, STATUS_SUCCESS);
/* Restore the connection */
Status = MakeServer(&ServerHandle, PipePath, ServerSynchronous);
ok_eq_hex(Status, STATUS_SUCCESS);
Okay = CheckConnectPipe(&ConnectContext, PipePath, ClientSynchronous, 100);
ok_bool_true(Okay, "CheckConnectPipe returned");
ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
ClientHandle = ConnectContext.Connect.ClientHandle;
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
/** Close client with pending read on server */
WriteBuffer[0] = 'I';
ReadBuffer[0] = 'X';
Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
ok_bool_false(Okay, "CheckReadPipe returned");
Status = ObCloseHandle(ClientHandle, KernelMode);
ok_eq_hex(Status, STATUS_SUCCESS);
Okay = WaitForWork(&ServerReadContext, 100);
CheckPipeContext(&ServerReadContext, STATUS_PIPE_BROKEN, 0);
ok_eq_uint(ReadBuffer[0], 'X');
/* Read from server when closed */
Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
CheckPipeContext(&ServerReadContext, STATUS_PIPE_BROKEN, 0);
/* Write to server when closed */
Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, WriteBuffer, 1, 100);
CheckPipeContext(&ServerWriteContext, STATUS_PIPE_CLOSING, 0);
Status = ObCloseHandle(ServerHandle, KernelMode);
ok_eq_hex(Status, STATUS_SUCCESS);
/* Restore the connection */
Status = MakeServer(&ServerHandle, PipePath, ServerSynchronous);
ok_eq_hex(Status, STATUS_SUCCESS);
Okay = CheckConnectPipe(&ConnectContext, PipePath, ClientSynchronous, 100);
ok_bool_true(Okay, "CheckConnectPipe returned");
ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
ClientHandle = ConnectContext.Connect.ClientHandle;
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
/** Write to server and disconnect, then read from client */
WriteBuffer[0] = 'J';
ReadBuffer[0] = 'X';
Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, WriteBuffer, 1, 100);
CheckPipeContext(&ServerWriteContext, STATUS_SUCCESS, 1);
CheckServerQuota(ServerHandle, 0, 1); CheckClientQuota(ClientHandle, 1, 0);
Status = NpDisconnectPipe(ServerHandle);
ok_eq_hex(Status, STATUS_SUCCESS);
NpQueryPipe(ClientHandle, STATUS_PIPE_DISCONNECTED);
CheckServer(ServerHandle, FILE_PIPE_DISCONNECTED_STATE);
Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
CheckPipeContext(&ClientReadContext, STATUS_PIPE_DISCONNECTED, 0);
ok_eq_uint(ReadBuffer[0], 'X');
Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
CheckPipeContext(&ClientReadContext, STATUS_PIPE_DISCONNECTED, 0);
Status = ObCloseHandle(ClientHandle, KernelMode);
ok_eq_hex(Status, STATUS_SUCCESS);
/* Restore the connection */
Okay = CheckListenPipe(&ListenContext, ServerHandle, 100);
ok_bool_false(Okay, "CheckListenPipe returned");
Okay = CheckConnectPipe(&ConnectContext, PipePath, ClientSynchronous, 100);
ok_bool_true(Okay, "CheckConnectPipe returned");
ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
Okay = WaitForWork(&ListenContext, 100);
ok_bool_true(Okay, "WaitForWork returned");
ok_eq_hex(ListenContext.Listen.Status, STATUS_SUCCESS);
ClientHandle = ConnectContext.Connect.ClientHandle;
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
/** Write to server and close, then read from client */
WriteBuffer[0] = 'K';
ReadBuffer[0] = 'X';
Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, WriteBuffer, 1, 100);
CheckPipeContext(&ServerWriteContext, STATUS_SUCCESS, 1);
CheckServerQuota(ServerHandle, 0, 1); CheckClientQuota(ClientHandle, 1, 0);
Status = ObCloseHandle(ServerHandle, KernelMode);
ok_eq_hex(Status, STATUS_SUCCESS);
NpCheckClientPipe(ClientHandle,
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX,
MAX_INSTANCES, 1,
IN_QUOTA, 1,
OUT_QUOTA, OUT_QUOTA,
FILE_PIPE_CLOSING_STATE);
Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
CheckPipeContext(&ClientReadContext, STATUS_SUCCESS, 1);
ok_eq_uint(ReadBuffer[0], 'K');
Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
CheckPipeContext(&ClientReadContext, STATUS_PIPE_BROKEN, 0);
Status = ObCloseHandle(ClientHandle, KernelMode);
ok_eq_hex(Status, STATUS_SUCCESS);
/* Restore the connection */
Status = MakeServer(&ServerHandle, PipePath, ServerSynchronous);
ok_eq_hex(Status, STATUS_SUCCESS);
Okay = CheckConnectPipe(&ConnectContext, PipePath, ClientSynchronous, 100);
ok_bool_true(Okay, "CheckConnectPipe returned");
ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
ClientHandle = ConnectContext.Connect.ClientHandle;
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
/** Write to client and close, then read from server */
WriteBuffer[0] = 'L';
ReadBuffer[0] = 'X';
Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, WriteBuffer, 1, 100);
CheckPipeContext(&ClientWriteContext, STATUS_SUCCESS, 1);
CheckClientQuota(ClientHandle, 0, 1); CheckServerQuota(ServerHandle, 1, 0);
Status = ObCloseHandle(ClientHandle, KernelMode);
ok_eq_hex(Status, STATUS_SUCCESS);
NpCheckServerPipe(ServerHandle,
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX,
MAX_INSTANCES, 1,
IN_QUOTA, 1,
OUT_QUOTA, OUT_QUOTA,
FILE_PIPE_CLOSING_STATE);
Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
CheckPipeContext(&ServerReadContext, STATUS_SUCCESS, 1);
ok_eq_uint(ReadBuffer[0], 'L');
Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
CheckPipeContext(&ServerReadContext, STATUS_PIPE_BROKEN, 0);
Status = ObCloseHandle(ServerHandle, KernelMode);
ok_eq_hex(Status, STATUS_SUCCESS);
/* Restore the connection */
Status = MakeServer(&ServerHandle, PipePath, ServerSynchronous);
ok_eq_hex(Status, STATUS_SUCCESS);
Okay = CheckConnectPipe(&ConnectContext, PipePath, ClientSynchronous, 100);
ok_bool_true(Okay, "CheckConnectPipe returned");
ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
ClientHandle = ConnectContext.Connect.ClientHandle;
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
/** Write to client and disconnect server, then read from server */
WriteBuffer[0] = 'M';
ReadBuffer[0] = 'X';
Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, WriteBuffer, 1, 100);
CheckPipeContext(&ClientWriteContext, STATUS_SUCCESS, 1);
CheckClientQuota(ClientHandle, 0, 1); CheckServerQuota(ServerHandle, 1, 0);
Status = NpDisconnectPipe(ServerHandle);
ok_eq_hex(Status, STATUS_SUCCESS);
NpQueryPipe(ClientHandle, STATUS_PIPE_DISCONNECTED);
CheckServer(ServerHandle, FILE_PIPE_DISCONNECTED_STATE);
Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
CheckPipeContext(&ServerReadContext, STATUS_PIPE_DISCONNECTED, 0);
ok_eq_uint(ReadBuffer[0], 'X');
Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
CheckPipeContext(&ServerReadContext, STATUS_PIPE_DISCONNECTED, 0);
Status = ObCloseHandle(ClientHandle, KernelMode);
ok_eq_hex(Status, STATUS_SUCCESS);
Status = ObCloseHandle(ServerHandle, KernelMode);
ok_eq_hex(Status, STATUS_SUCCESS);
FinishWorkerThread(&ServerWriteContext);
FinishWorkerThread(&ServerReadContext);
FinishWorkerThread(&ClientWriteContext);
FinishWorkerThread(&ClientReadContext);
FinishWorkerThread(&ListenContext);
FinishWorkerThread(&ConnectContext);
}
START_TEST(NpfsReadWrite)
{
PKTHREAD Thread;
READ_WRITE_TEST_CONTEXT TestContext;
TestContext.PipePath = DEVICE_NAMED_PIPE L"\\KmtestNpfsReadWriteTestPipe";
TestContext.ServerSynchronous = TRUE;
TestContext.ClientSynchronous = TRUE;
Thread = KmtStartThread(TestReadWrite, &TestContext);
KmtFinishThread(Thread, NULL);
TestContext.ServerSynchronous = FALSE;
TestContext.ClientSynchronous = TRUE;
Thread = KmtStartThread(TestReadWrite, &TestContext);
KmtFinishThread(Thread, NULL);
TestContext.ServerSynchronous = TRUE;
TestContext.ClientSynchronous = FALSE;
Thread = KmtStartThread(TestReadWrite, &TestContext);
KmtFinishThread(Thread, NULL);
TestContext.ServerSynchronous = FALSE;
TestContext.ClientSynchronous = FALSE;
Thread = KmtStartThread(TestReadWrite, &TestContext);
KmtFinishThread(Thread, NULL);
}

View file

@ -0,0 +1,225 @@
/*
* PROJECT: ReactOS kernel-mode tests
* LICENSE: LGPLv2+ - See COPYING.LIB in the top level directory
* PURPOSE: Kernel-Mode Test Suite NPFS helper declarations
* PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
*/
#ifndef _KMTEST_NPFS_H_
#define _KMTEST_NPFS_H_
#define DEVICE_NAMED_PIPE L"\\Device\\NamedPipe"
#define BYTE_STREAM FILE_PIPE_BYTE_STREAM_MODE
C_ASSERT(FILE_PIPE_BYTE_STREAM_MODE == FILE_PIPE_BYTE_STREAM_TYPE);
#define MESSAGE FILE_PIPE_MESSAGE_MODE
C_ASSERT(FILE_PIPE_MESSAGE_MODE == FILE_PIPE_MESSAGE_TYPE);
#define QUEUE FILE_PIPE_QUEUE_OPERATION
#define COMPLETE FILE_PIPE_COMPLETE_OPERATION
#define INBOUND FILE_PIPE_INBOUND
#define OUTBOUND FILE_PIPE_OUTBOUND
#define DUPLEX FILE_PIPE_FULL_DUPLEX
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);
NTSTATUS
NpCreatePipe(
OUT PHANDLE ServerHandle,
IN PCWSTR PipePath,
IN ULONG ReadMode,
IN ULONG CompletionMode,
IN ULONG NamedPipeType,
IN ULONG NamedPipeConfiguration,
IN ULONG MaximumInstances,
IN ULONG InboundQuota,
IN ULONG OutboundQuota);
NTSTATUS
NpOpenPipeEx(
OUT PHANDLE ClientHandle,
IN PCWSTR PipePath,
IN ACCESS_MASK DesiredAccess,
IN ULONG ShareAccess,
IN ULONG Disposition,
IN ULONG CreateOptions);
NTSTATUS
NpOpenPipe(
OUT PHANDLE ClientHandle,
IN PCWSTR PipePath,
IN ULONG NamedPipeConfiguration);
NTSTATUS
NpControlPipe(
IN HANDLE PipeHandle,
IN ULONG FsControlCode,
IN PVOID InputBuffer,
IN ULONG InputBufferLength);
#define NpListenPipe(ServerHandle) NpControlPipe(ServerHandle, FSCTL_PIPE_LISTEN, NULL, 0)
#define NpDisconnectPipe(ServerHandle) NpControlPipe(ServerHandle, FSCTL_PIPE_DISCONNECT, NULL, 0)
NTSTATUS
NpWaitPipe(
IN PCWSTR PipeName,
IN PLARGE_INTEGER Timeout);
NTSTATUS
NpReadPipe(
IN HANDLE PipeHandle,
OUT PVOID Buffer,
IN ULONG BufferSize,
OUT PULONG_PTR BytesRead);
NTSTATUS
NpWritePipe(
IN HANDLE PipeHandle,
IN const VOID *Buffer,
IN ULONG BufferSize,
OUT PULONG_PTR BytesWritten);
#define NpCheckServerPipe(h, rm, cm, npt, npc, mi, ci, iq, rsa, oq, wqa, nps) \
NpCheckServerPipe__(h, rm, cm, npt, npc, mi, ci, iq, rsa, oq, wqa, nps, __FILE__, __LINE__)
#define NpCheckServerPipe__(h, rm, cm, npt, npc, mi, ci, iq, rsa, oq, wqa, nps, file, line) \
NpCheckServerPipe_(h, rm, cm, npt, npc, mi, ci, iq, rsa, oq, wqa, nps, file ":" KMT_STRINGIZE(line))
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);
#define NpCheckClientPipe(h, rm, cm, npt, npc, mi, ci, iq, rsa, oq, wqa, nps) \
NpCheckClientPipe__(h, rm, cm, npt, npc, mi, ci, iq, rsa, oq, wqa, nps, __FILE__, __LINE__)
#define NpCheckClientPipe__(h, rm, cm, npt, npc, mi, ci, iq, rsa, oq, wqa, nps, file, line) \
NpCheckClientPipe_(h, rm, cm, npt, npc, mi, ci, iq, rsa, oq, wqa, nps, file ":" KMT_STRINGIZE(line))
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);
#define NpQueryPipe(h, es) \
NpQueryPipe__(h, es, __FILE__, __LINE__)
#define NpQueryPipe__(h, es, file, line) \
NpQueryPipe_(h, es, file ":" KMT_STRINGIZE(line))
VOID
NpQueryPipe_(
IN HANDLE Handle,
IN NTSTATUS ExpectedStatus,
IN PCSTR FileAndLine);
struct _THREAD_CONTEXT;
typedef VOID (WORK_FUNCTION)(IN OUT struct _THREAD_CONTEXT *);
typedef WORK_FUNCTION *PWORK_FUNCTION;
typedef struct _THREAD_CONTEXT
{
volatile PWORK_FUNCTION Work;
volatile union
{
struct
{
PCWSTR PipePath;
BOOLEAN ClientSynchronous;
HANDLE ClientHandle;
NTSTATUS Status;
} Connect;
struct
{
HANDLE ServerHandle;
NTSTATUS Status;
} Listen;
struct
{
HANDLE PipeHandle;
PVOID Buffer;
ULONG BufferSize;
ULONG_PTR BytesTransferred;
NTSTATUS Status;
} ReadWrite;
};
KEVENT ThreadDoneEvent;
KEVENT StartWorkEvent;
KEVENT WorkCompleteEvent;
PKTHREAD Thread;
} THREAD_CONTEXT, *PTHREAD_CONTEXT;
VOID
StartWorkerThread(
OUT PTHREAD_CONTEXT Context);
VOID
FinishWorkerThread(
IN PTHREAD_CONTEXT Context);
BOOLEAN
WaitForWork(
IN PTHREAD_CONTEXT Context,
IN ULONG MilliSeconds);
BOOLEAN
TriggerWork(
IN PTHREAD_CONTEXT Context,
IN ULONG MilliSeconds);
PKTHREAD
KmtStartThread(
IN PKSTART_ROUTINE StartRoutine,
IN PVOID StartContext OPTIONAL);
VOID
KmtFinishThread(
IN PKTHREAD Thread OPTIONAL,
IN PKEVENT Event OPTIONAL);
#endif /* !defined _KMTEST_NPFS_H_ */