mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 16:36:33 +00:00
- Move tests from trunk.
svn path=/trunk/; revision=26663
This commit is contained in:
parent
93510b1a0f
commit
7ba021c0ca
14 changed files with 1928 additions and 0 deletions
5
rostests/drivers/csqtest/SOURCES
Normal file
5
rostests/drivers/csqtest/SOURCES
Normal file
|
@ -0,0 +1,5 @@
|
|||
TARGETNAME=csqtest
|
||||
TARGETTYPE=DRIVER
|
||||
TARGETPATH=obj
|
||||
TARGETLIBS= csq.lib
|
||||
SOURCES= csqtest.c
|
227
rostests/drivers/csqtest/csqtest.c
Normal file
227
rostests/drivers/csqtest/csqtest.c
Normal file
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
* CSQ Test Driver
|
||||
* Copyright (c) 2004, Vizzini (vizzini@plasmic.com)
|
||||
* Released under the GNU GPL for the ReactOS project
|
||||
*
|
||||
* This driver is designed to exercise the cancel-safe IRP queue logic.
|
||||
* Please refer to reactos/include/ddk/csq.h and reactos/drivers/lib/csq.
|
||||
*/
|
||||
#include <ntddk.h>
|
||||
#include <csq.h>
|
||||
|
||||
/* XXX shortcomings in our headers... */
|
||||
#define assert(x)
|
||||
#ifndef KdPrint
|
||||
#define KdPrint(x) DbgPrint x
|
||||
#endif
|
||||
|
||||
/* Device name */
|
||||
#define NT_DEVICE_NAME L"\\Device\\csqtest"
|
||||
|
||||
/* DosDevices name */
|
||||
#define DOS_DEVICE_NAME L"\\??\\csqtest"
|
||||
|
||||
/* Global CSQ struct that the CSQ functions init */
|
||||
IO_CSQ Csq;
|
||||
|
||||
/* List and lock for the actual IRP queue */
|
||||
LIST_ENTRY IrpQueue;
|
||||
KSPIN_LOCK IrpQueueLock;
|
||||
|
||||
/* Device object */
|
||||
PDEVICE_OBJECT DeviceObject;
|
||||
|
||||
/*
|
||||
* CSQ Callbacks
|
||||
*/
|
||||
VOID NTAPI CsqInsertIrp(PIO_CSQ Csq, PIRP Irp)
|
||||
{
|
||||
KdPrint(("Inserting IRP 0x%x into CSQ\n", Irp));
|
||||
InsertTailList(&IrpQueue, &Irp->Tail.Overlay.ListEntry);
|
||||
}
|
||||
|
||||
VOID NTAPI CsqRemoveIrp(PIO_CSQ Csq, PIRP Irp)
|
||||
{
|
||||
KdPrint(("Removing IRP 0x%x from CSQ\n", Irp));
|
||||
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
|
||||
}
|
||||
|
||||
PIRP NTAPI CsqPeekNextIrp(PIO_CSQ Csq, PIRP Irp, PVOID PeekContext)
|
||||
{
|
||||
KdPrint(("Peeking for next IRP\n"));
|
||||
|
||||
if(Irp)
|
||||
return CONTAINING_RECORD(&Irp->Tail.Overlay.ListEntry.Flink, IRP, Tail.Overlay.ListEntry);
|
||||
|
||||
if(IsListEmpty(&IrpQueue))
|
||||
return NULL;
|
||||
|
||||
return CONTAINING_RECORD(IrpQueue.Flink, IRP, Tail.Overlay.ListEntry);
|
||||
}
|
||||
|
||||
VOID NTAPI CsqAcquireLock(PIO_CSQ Csq, PKIRQL Irql)
|
||||
{
|
||||
KdPrint(("Acquiring spin lock\n"));
|
||||
KeAcquireSpinLock(&IrpQueueLock, Irql);
|
||||
}
|
||||
|
||||
VOID NTAPI CsqReleaseLock(PIO_CSQ Csq, KIRQL Irql)
|
||||
{
|
||||
KdPrint(("Releasing spin lock\n"));
|
||||
KeReleaseSpinLock(&IrpQueueLock, Irql);
|
||||
}
|
||||
|
||||
VOID NTAPI CsqCompleteCancelledIrp(PIO_CSQ Csq, PIRP Irp)
|
||||
{
|
||||
KdPrint(("cancelling irp 0x%x\n", Irp));
|
||||
Irp->IoStatus.Status = STATUS_CANCELLED;
|
||||
Irp->IoStatus.Information = 0;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
}
|
||||
|
||||
NTSTATUS NTAPI CsqInsertIrpEx(PIO_CSQ Csq, PIRP Irp, PVOID InsertContext)
|
||||
/*
|
||||
* FUNCTION: Insert into IRP queue, with extra context
|
||||
*
|
||||
* NOTE: Switch call in DriverEntry to IoCsqInitializeEx to use this
|
||||
*/
|
||||
{
|
||||
CsqInsertIrp(Csq, Irp);
|
||||
return STATUS_PENDING;
|
||||
}
|
||||
|
||||
/*
|
||||
* DISPATCH ROUTINES
|
||||
*/
|
||||
|
||||
NTSTATUS NTAPI DispatchCreateCloseCleanup(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
||||
{
|
||||
PIO_STACK_LOCATION StackLocation = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
if(StackLocation->MajorFunction == IRP_MJ_CLEANUP)
|
||||
{
|
||||
/* flush the irp queue */
|
||||
PIRP CurrentIrp;
|
||||
|
||||
KdPrint(("csqtest: Cleanup received; flushing the IRP queue with cancel\n"));
|
||||
|
||||
while((CurrentIrp = IoCsqRemoveNextIrp(&Csq, 0)))
|
||||
{
|
||||
CurrentIrp->IoStatus.Status = STATUS_CANCELLED;
|
||||
CurrentIrp->IoStatus.Information = 0;
|
||||
|
||||
IoCompleteRequest(CurrentIrp, IO_NO_INCREMENT);
|
||||
}
|
||||
}
|
||||
|
||||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||||
Irp->IoStatus.Information = 0;
|
||||
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS NTAPI DispatchReadWrite(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
||||
{
|
||||
/* According to the cancel sample in the DDK, IoCsqInsertIrp() marks the irp pending */
|
||||
/* However, I think it's wrong. */
|
||||
IoMarkIrpPending(Irp);
|
||||
IoCsqInsertIrp(&Csq, Irp, 0);
|
||||
|
||||
return STATUS_PENDING;
|
||||
}
|
||||
|
||||
NTSTATUS NTAPI DispatchIoctl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
||||
/*
|
||||
* all IOCTL requests flush the irp queue
|
||||
*/
|
||||
{
|
||||
PIRP CurrentIrp;
|
||||
|
||||
KdPrint(("csqtest: Ioctl received; flushing the IRP queue with success\n"));
|
||||
|
||||
while((CurrentIrp = IoCsqRemoveNextIrp(&Csq, 0)))
|
||||
{
|
||||
CurrentIrp->IoStatus.Status = STATUS_SUCCESS;
|
||||
CurrentIrp->IoStatus.Information = 0;
|
||||
|
||||
IoCompleteRequest(CurrentIrp, IO_NO_INCREMENT);
|
||||
}
|
||||
|
||||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||||
Irp->IoStatus.Information = 0;
|
||||
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
VOID NTAPI Unload(PDRIVER_OBJECT DriverObject)
|
||||
/*
|
||||
* Function: called by the OS to release resources before unload
|
||||
*/
|
||||
{
|
||||
UNICODE_STRING LinkName;
|
||||
|
||||
RtlInitUnicodeString(&LinkName, DOS_DEVICE_NAME);
|
||||
|
||||
IoDeleteSymbolicLink(&LinkName);
|
||||
|
||||
if(DeviceObject)
|
||||
IoDeleteDevice(DeviceObject);
|
||||
}
|
||||
|
||||
/*
|
||||
* DriverEntry
|
||||
*/
|
||||
|
||||
NTSTATUS NTAPI DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
UNICODE_STRING NtName;
|
||||
UNICODE_STRING DosName;
|
||||
|
||||
DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreateCloseCleanup;
|
||||
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchCreateCloseCleanup;
|
||||
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = DispatchCreateCloseCleanup;
|
||||
DriverObject->MajorFunction[IRP_MJ_READ] = DispatchReadWrite;
|
||||
DriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchReadWrite;
|
||||
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoctl;
|
||||
DriverObject->DriverUnload = Unload;
|
||||
|
||||
Status = IoCsqInitialize(&Csq, CsqInsertIrp, CsqRemoveIrp, CsqPeekNextIrp,
|
||||
CsqAcquireLock, CsqReleaseLock, CsqCompleteCancelledIrp);
|
||||
|
||||
if(Status != STATUS_SUCCESS)
|
||||
KdPrint(("csqtest: IoCsqInitalize failed: 0x%x\n", Status));
|
||||
else
|
||||
KdPrint(("csqtest: IoCsqInitalize succeeded\n"));
|
||||
|
||||
InitializeListHead(&IrpQueue);
|
||||
KeInitializeSpinLock(&IrpQueueLock);
|
||||
|
||||
/* Set up a device */
|
||||
RtlInitUnicodeString(&NtName, NT_DEVICE_NAME);
|
||||
Status = IoCreateDevice(DriverObject, 0, &NtName, FILE_DEVICE_UNKNOWN, 0, 0, &DeviceObject);
|
||||
|
||||
if(!NT_SUCCESS(Status))
|
||||
{
|
||||
KdPrint(("csqtest: Unable to create device: 0x%x\n", Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
RtlInitUnicodeString(&DosName, DOS_DEVICE_NAME);
|
||||
Status = IoCreateSymbolicLink(&DosName, &NtName);
|
||||
|
||||
if(!NT_SUCCESS(Status))
|
||||
{
|
||||
KdPrint(("csqtest: Unable to create link: 0x%x\n", Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
DeviceObject->Flags |= DO_BUFFERED_IO;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
9
rostests/drivers/csqtest/csqtest.rbuild
Normal file
9
rostests/drivers/csqtest/csqtest.rbuild
Normal file
|
@ -0,0 +1,9 @@
|
|||
<module name="csqtest" type="kernelmodedriver" installbase="system32/drivers" installname="csqtest.sys">
|
||||
<bootstrap base="$(CDOUTPUT)" />
|
||||
<define name="__USE_W32API" />
|
||||
<include base="ReactOS">include/reactos/drivers</include>
|
||||
<library>ntoskrnl</library>
|
||||
<library>hal</library>
|
||||
<file>csqtest.c</file>
|
||||
<file>csqtest.rc</file>
|
||||
</module>
|
7
rostests/drivers/csqtest/csqtest.rc
Normal file
7
rostests/drivers/csqtest/csqtest.rc
Normal file
|
@ -0,0 +1,7 @@
|
|||
/* $Id$ */
|
||||
|
||||
#define REACTOS_VERSION_DLL
|
||||
#define REACTOS_STR_FILE_DESCRIPTION "CSQ Test\0"
|
||||
#define REACTOS_STR_INTERNAL_NAME "csqtest\0"
|
||||
#define REACTOS_STR_ORIGINAL_FILENAME "csqtest.sys\0"
|
||||
#include <reactos/version.rc>
|
6
rostests/drivers/directory.rbuild
Normal file
6
rostests/drivers/directory.rbuild
Normal file
|
@ -0,0 +1,6 @@
|
|||
<directory name="csqtest">
|
||||
<xi:include href="csqtest/csqtest.rbuild" />
|
||||
</directory>
|
||||
<directory name="kmtest">
|
||||
<xi:include href="kmtest/kmtest.rbuild" />
|
||||
</directory>
|
545
rostests/drivers/kmtest/deviface.c
Normal file
545
rostests/drivers/kmtest/deviface.c
Normal file
|
@ -0,0 +1,545 @@
|
|||
/*
|
||||
* PnP Test
|
||||
* ReactOS Device Interface functions implementation
|
||||
*
|
||||
* Copyright 2003, 2004 Filip Navara <xnavara@volny.cz>
|
||||
* Copyright 2003, 2004 Matthew Brace <ismarc@austin.rr.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; see the file COPYING.LIB.
|
||||
* If not, write to the Free Software Foundation,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <ddk/ntddk.h>
|
||||
#include "kmtest.h"
|
||||
|
||||
//#define NDEBUG
|
||||
#include "debug.h"
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
/*
|
||||
* IoGetDeviceInterfaces
|
||||
*
|
||||
* Returns a list of device interfaces of a particular device interface class.
|
||||
*
|
||||
* Parameters
|
||||
* InterfaceClassGuid
|
||||
* Points to a class GUID specifying the device interface class.
|
||||
*
|
||||
* PhysicalDeviceObject
|
||||
* Points to an optional PDO that narrows the search to only the
|
||||
* device interfaces of the device represented by the PDO.
|
||||
*
|
||||
* Flags
|
||||
* Specifies flags that modify the search for device interfaces. The
|
||||
* DEVICE_INTERFACE_INCLUDE_NONACTIVE flag specifies that the list of
|
||||
* returned symbolic links should contain also disabled device
|
||||
* interfaces in addition to the enabled ones.
|
||||
*
|
||||
* SymbolicLinkList
|
||||
* Points to a character pointer that is filled in on successful return
|
||||
* with a list of unicode strings identifying the device interfaces
|
||||
* that match the search criteria. The newly allocated buffer contains
|
||||
* a list of symbolic link names. Each unicode string in the list is
|
||||
* null-terminated; the end of the whole list is marked by an additional
|
||||
* NULL. The caller is responsible for freeing the buffer (ExFreePool)
|
||||
* when it is no longer needed.
|
||||
* If no device interfaces match the search criteria, this routine
|
||||
* returns STATUS_SUCCESS and the string contains a single NULL
|
||||
* character.
|
||||
*
|
||||
* Status
|
||||
* @unimplemented
|
||||
*
|
||||
* The parameters PhysicalDeviceObject and Flags aren't correctly
|
||||
* processed. Rest of the cases was tested under Win XP and the
|
||||
* function worked correctly.
|
||||
*/
|
||||
|
||||
NTSTATUS STDCALL
|
||||
ReactOS_IoGetDeviceInterfaces(
|
||||
IN CONST GUID *InterfaceClassGuid,
|
||||
IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL,
|
||||
IN ULONG Flags,
|
||||
OUT PWSTR *SymbolicLinkList)
|
||||
{
|
||||
PWCHAR BaseKeyString = L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\DeviceClasses\\";
|
||||
PWCHAR BaseInterfaceString = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
|
||||
UNICODE_STRING GuidString;
|
||||
UNICODE_STRING BaseKeyName;
|
||||
UNICODE_STRING AliasKeyName;
|
||||
UNICODE_STRING SymbolicLink;
|
||||
UNICODE_STRING Control;
|
||||
UNICODE_STRING SubKeyName;
|
||||
UNICODE_STRING SymbolicLinkKeyName;
|
||||
UNICODE_STRING ControlKeyName;
|
||||
UNICODE_STRING TempString;
|
||||
HANDLE InterfaceKey;
|
||||
HANDLE SubKey;
|
||||
HANDLE SymbolicLinkKey;
|
||||
PKEY_FULL_INFORMATION fip;
|
||||
PKEY_FULL_INFORMATION bfip=NULL;
|
||||
PKEY_BASIC_INFORMATION bip;
|
||||
PKEY_VALUE_PARTIAL_INFORMATION vpip=NULL;
|
||||
PWCHAR SymLinkList = NULL;
|
||||
ULONG SymLinkListSize = 0;
|
||||
NTSTATUS Status;
|
||||
ULONG Size = 0;
|
||||
ULONG i = 0;
|
||||
ULONG j = 0;
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
|
||||
Status = RtlStringFromGUID(InterfaceClassGuid, &GuidString);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("RtlStringFromGUID() Failed.\n");
|
||||
return STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
RtlInitUnicodeString(&AliasKeyName, BaseInterfaceString);
|
||||
RtlInitUnicodeString(&SymbolicLink, L"SymbolicLink");
|
||||
RtlInitUnicodeString(&Control, L"\\Control");
|
||||
BaseKeyName.Length = wcslen(BaseKeyString) * sizeof(WCHAR);
|
||||
BaseKeyName.MaximumLength = BaseKeyName.Length + (38 * sizeof(WCHAR));
|
||||
BaseKeyName.Buffer = ExAllocatePool(
|
||||
NonPagedPool,
|
||||
BaseKeyName.MaximumLength);
|
||||
ASSERT(BaseKeyName.Buffer != NULL);
|
||||
wcscpy(BaseKeyName.Buffer, BaseKeyString);
|
||||
RtlAppendUnicodeStringToString(&BaseKeyName, &GuidString);
|
||||
|
||||
if (PhysicalDeviceObject)
|
||||
{
|
||||
WCHAR GuidBuffer[40];
|
||||
UNICODE_STRING PdoGuidString;
|
||||
|
||||
RtlFreeUnicodeString(&BaseKeyName);
|
||||
|
||||
IoGetDeviceProperty(
|
||||
PhysicalDeviceObject,
|
||||
DevicePropertyClassGuid,
|
||||
sizeof(GuidBuffer),
|
||||
GuidBuffer,
|
||||
&Size);
|
||||
|
||||
RtlInitUnicodeString(&PdoGuidString, GuidBuffer);
|
||||
if (RtlCompareUnicodeString(&GuidString, &PdoGuidString, TRUE))
|
||||
{
|
||||
DPRINT("Inconsistent Guid's asked for in IoGetDeviceInterfaces()\n");
|
||||
return STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
DPRINT("IoGetDeviceInterfaces() called with PDO, not implemented.\n");
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
InitializeObjectAttributes(
|
||||
&ObjectAttributes,
|
||||
&BaseKeyName,
|
||||
OBJ_CASE_INSENSITIVE,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
Status = ZwOpenKey(
|
||||
&InterfaceKey,
|
||||
KEY_READ,
|
||||
&ObjectAttributes);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("ZwOpenKey() Failed. (0x%X)\n", Status);
|
||||
RtlFreeUnicodeString(&BaseKeyName);
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = ZwQueryKey(
|
||||
InterfaceKey,
|
||||
KeyFullInformation,
|
||||
NULL,
|
||||
0,
|
||||
&Size);
|
||||
|
||||
if (Status != STATUS_BUFFER_TOO_SMALL)
|
||||
{
|
||||
DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status);
|
||||
RtlFreeUnicodeString(&BaseKeyName);
|
||||
ZwClose(InterfaceKey);
|
||||
return Status;
|
||||
}
|
||||
|
||||
fip = (PKEY_FULL_INFORMATION)ExAllocatePool(NonPagedPool, Size);
|
||||
ASSERT(fip != NULL);
|
||||
|
||||
Status = ZwQueryKey(
|
||||
InterfaceKey,
|
||||
KeyFullInformation,
|
||||
fip,
|
||||
Size,
|
||||
&Size);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status);
|
||||
ExFreePool(fip);
|
||||
RtlFreeUnicodeString(&BaseKeyName);
|
||||
ZwClose(InterfaceKey);
|
||||
return Status;
|
||||
}
|
||||
|
||||
for (; i < fip->SubKeys; i++)
|
||||
{
|
||||
Status = ZwEnumerateKey(
|
||||
InterfaceKey,
|
||||
i,
|
||||
KeyBasicInformation,
|
||||
NULL,
|
||||
0,
|
||||
&Size);
|
||||
|
||||
if (Status != STATUS_BUFFER_TOO_SMALL)
|
||||
{
|
||||
DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status);
|
||||
ExFreePool(fip);
|
||||
if (SymLinkList != NULL)
|
||||
ExFreePool(SymLinkList);
|
||||
RtlFreeUnicodeString(&BaseKeyName);
|
||||
ZwClose(InterfaceKey);
|
||||
return Status;
|
||||
}
|
||||
|
||||
bip = (PKEY_BASIC_INFORMATION)ExAllocatePool(NonPagedPool, Size);
|
||||
ASSERT(bip != NULL);
|
||||
|
||||
Status = ZwEnumerateKey(
|
||||
InterfaceKey,
|
||||
i,
|
||||
KeyBasicInformation,
|
||||
bip,
|
||||
Size,
|
||||
&Size);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status);
|
||||
ExFreePool(fip);
|
||||
ExFreePool(bip);
|
||||
if (SymLinkList != NULL)
|
||||
ExFreePool(SymLinkList);
|
||||
RtlFreeUnicodeString(&BaseKeyName);
|
||||
ZwClose(InterfaceKey);
|
||||
return Status;
|
||||
}
|
||||
|
||||
SubKeyName.Length = 0;
|
||||
SubKeyName.MaximumLength = BaseKeyName.Length + bip->NameLength + sizeof(WCHAR);
|
||||
SubKeyName.Buffer = ExAllocatePool(NonPagedPool, SubKeyName.MaximumLength);
|
||||
ASSERT(SubKeyName.Buffer != NULL);
|
||||
TempString.Length = TempString.MaximumLength = bip->NameLength;
|
||||
TempString.Buffer = bip->Name;
|
||||
RtlCopyUnicodeString(&SubKeyName, &BaseKeyName);
|
||||
RtlAppendUnicodeToString(&SubKeyName, L"\\");
|
||||
RtlAppendUnicodeStringToString(&SubKeyName, &TempString);
|
||||
|
||||
ExFreePool(bip);
|
||||
|
||||
InitializeObjectAttributes(
|
||||
&ObjectAttributes,
|
||||
&SubKeyName,
|
||||
OBJ_CASE_INSENSITIVE,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
Status = ZwOpenKey(
|
||||
&SubKey,
|
||||
KEY_READ,
|
||||
&ObjectAttributes);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("ZwOpenKey() Failed. (0x%X)\n", Status);
|
||||
ExFreePool(fip);
|
||||
if (SymLinkList != NULL)
|
||||
ExFreePool(SymLinkList);
|
||||
RtlFreeUnicodeString(&SubKeyName);
|
||||
RtlFreeUnicodeString(&BaseKeyName);
|
||||
ZwClose(InterfaceKey);
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = ZwQueryKey(
|
||||
SubKey,
|
||||
KeyFullInformation,
|
||||
NULL,
|
||||
0,
|
||||
&Size);
|
||||
|
||||
if (Status != STATUS_BUFFER_TOO_SMALL)
|
||||
{
|
||||
DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status);
|
||||
ExFreePool(fip);
|
||||
RtlFreeUnicodeString(&BaseKeyName);
|
||||
RtlFreeUnicodeString(&SubKeyName);
|
||||
ZwClose(SubKey);
|
||||
ZwClose(InterfaceKey);
|
||||
return Status;
|
||||
}
|
||||
|
||||
bfip = (PKEY_FULL_INFORMATION)ExAllocatePool(NonPagedPool, Size);
|
||||
ASSERT(bfip != NULL);
|
||||
|
||||
Status = ZwQueryKey(
|
||||
SubKey,
|
||||
KeyFullInformation,
|
||||
bfip,
|
||||
Size,
|
||||
&Size);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status);
|
||||
ExFreePool(fip);
|
||||
RtlFreeUnicodeString(&SubKeyName);
|
||||
RtlFreeUnicodeString(&BaseKeyName);
|
||||
ZwClose(SubKey);
|
||||
ZwClose(InterfaceKey);
|
||||
return Status;
|
||||
}
|
||||
|
||||
for(j = 0; j < bfip->SubKeys; j++)
|
||||
{
|
||||
Status = ZwEnumerateKey(
|
||||
SubKey,
|
||||
j,
|
||||
KeyBasicInformation,
|
||||
NULL,
|
||||
0,
|
||||
&Size);
|
||||
|
||||
if (Status == STATUS_NO_MORE_ENTRIES)
|
||||
continue;
|
||||
|
||||
if (Status != STATUS_BUFFER_TOO_SMALL)
|
||||
{
|
||||
DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status);
|
||||
ExFreePool(bfip);
|
||||
ExFreePool(fip);
|
||||
if (SymLinkList != NULL)
|
||||
ExFreePool(SymLinkList);
|
||||
RtlFreeUnicodeString(&SubKeyName);
|
||||
RtlFreeUnicodeString(&BaseKeyName);
|
||||
ZwClose(SubKey);
|
||||
ZwClose(InterfaceKey);
|
||||
return Status;
|
||||
}
|
||||
|
||||
bip = (PKEY_BASIC_INFORMATION)ExAllocatePool(NonPagedPool, Size);
|
||||
ASSERT(bip != NULL);
|
||||
|
||||
Status = ZwEnumerateKey(
|
||||
SubKey,
|
||||
j,
|
||||
KeyBasicInformation,
|
||||
bip,
|
||||
Size,
|
||||
&Size);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status);
|
||||
ExFreePool(fip);
|
||||
ExFreePool(bfip);
|
||||
ExFreePool(bip);
|
||||
if (SymLinkList != NULL)
|
||||
ExFreePool(SymLinkList);
|
||||
RtlFreeUnicodeString(&SubKeyName);
|
||||
RtlFreeUnicodeString(&BaseKeyName);
|
||||
ZwClose(SubKey);
|
||||
ZwClose(InterfaceKey);
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (!wcsncmp(bip->Name, L"Control", bip->NameLength))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
SymbolicLinkKeyName.Length = 0;
|
||||
SymbolicLinkKeyName.MaximumLength = SubKeyName.Length + bip->NameLength + sizeof(WCHAR);
|
||||
SymbolicLinkKeyName.Buffer = ExAllocatePool(NonPagedPool, SymbolicLinkKeyName.MaximumLength);
|
||||
ASSERT(SymbolicLinkKeyName.Buffer != NULL);
|
||||
TempString.Length = TempString.MaximumLength = bip->NameLength;
|
||||
TempString.Buffer = bip->Name;
|
||||
RtlCopyUnicodeString(&SymbolicLinkKeyName, &SubKeyName);
|
||||
RtlAppendUnicodeToString(&SymbolicLinkKeyName, L"\\");
|
||||
RtlAppendUnicodeStringToString(&SymbolicLinkKeyName, &TempString);
|
||||
|
||||
ControlKeyName.Length = 0;
|
||||
ControlKeyName.MaximumLength = SymbolicLinkKeyName.Length + Control.Length + sizeof(WCHAR);
|
||||
ControlKeyName.Buffer = ExAllocatePool(NonPagedPool, ControlKeyName.MaximumLength);
|
||||
ASSERT(ControlKeyName.Buffer != NULL);
|
||||
RtlCopyUnicodeString(&ControlKeyName, &SymbolicLinkKeyName);
|
||||
RtlAppendUnicodeStringToString(&ControlKeyName, &Control);
|
||||
|
||||
ExFreePool(bip);
|
||||
|
||||
InitializeObjectAttributes(
|
||||
&ObjectAttributes,
|
||||
&SymbolicLinkKeyName,
|
||||
OBJ_CASE_INSENSITIVE,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
Status = ZwOpenKey(
|
||||
&SymbolicLinkKey,
|
||||
KEY_READ,
|
||||
&ObjectAttributes);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("ZwOpenKey() Failed. (0x%X)\n", Status);
|
||||
ExFreePool(fip);
|
||||
ExFreePool(bfip);
|
||||
if (SymLinkList != NULL)
|
||||
ExFreePool(SymLinkList);
|
||||
RtlFreeUnicodeString(&SymbolicLinkKeyName);
|
||||
RtlFreeUnicodeString(&SubKeyName);
|
||||
RtlFreeUnicodeString(&BaseKeyName);
|
||||
ZwClose(SubKey);
|
||||
ZwClose(InterfaceKey);
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = ZwQueryValueKey(
|
||||
SymbolicLinkKey,
|
||||
&SymbolicLink,
|
||||
KeyValuePartialInformation,
|
||||
NULL,
|
||||
0,
|
||||
&Size);
|
||||
|
||||
if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
|
||||
continue;
|
||||
|
||||
if (Status != STATUS_BUFFER_TOO_SMALL)
|
||||
{
|
||||
DPRINT("ZwQueryValueKey() Failed.(0x%X)\n", Status);
|
||||
ExFreePool(fip);
|
||||
ExFreePool(bfip);
|
||||
if (SymLinkList != NULL)
|
||||
ExFreePool(SymLinkList);
|
||||
RtlFreeUnicodeString(&SymbolicLinkKeyName);
|
||||
RtlFreeUnicodeString(&SubKeyName);
|
||||
RtlFreeUnicodeString(&BaseKeyName);
|
||||
ZwClose(SymbolicLinkKey);
|
||||
ZwClose(SubKey);
|
||||
ZwClose(InterfaceKey);
|
||||
return Status;
|
||||
}
|
||||
|
||||
vpip = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePool(NonPagedPool, Size);
|
||||
ASSERT(vpip != NULL);
|
||||
|
||||
Status = ZwQueryValueKey(
|
||||
SymbolicLinkKey,
|
||||
&SymbolicLink,
|
||||
KeyValuePartialInformation,
|
||||
vpip,
|
||||
Size,
|
||||
&Size);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("ZwQueryValueKey() Failed.(0x%X)\n", Status);
|
||||
ExFreePool(fip);
|
||||
ExFreePool(bfip);
|
||||
ExFreePool(vpip);
|
||||
if (SymLinkList != NULL)
|
||||
ExFreePool(SymLinkList);
|
||||
RtlFreeUnicodeString(&SymbolicLinkKeyName);
|
||||
RtlFreeUnicodeString(&SubKeyName);
|
||||
RtlFreeUnicodeString(&BaseKeyName);
|
||||
ZwClose(SymbolicLinkKey);
|
||||
ZwClose(SubKey);
|
||||
ZwClose(InterfaceKey);
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, ControlKeyName.Buffer);
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
/* Put the name in the string here */
|
||||
if (SymLinkList == NULL)
|
||||
{
|
||||
SymLinkListSize = vpip->DataLength;
|
||||
SymLinkList = ExAllocatePool(NonPagedPool, SymLinkListSize + sizeof(WCHAR));
|
||||
ASSERT(SymLinkList != NULL);
|
||||
RtlCopyMemory(SymLinkList, vpip->Data, vpip->DataLength);
|
||||
SymLinkList[vpip->DataLength / sizeof(WCHAR)] = 0;
|
||||
SymLinkList[1] = '?';
|
||||
}
|
||||
else
|
||||
{
|
||||
PWCHAR OldSymLinkList;
|
||||
ULONG OldSymLinkListSize;
|
||||
PWCHAR SymLinkListPtr;
|
||||
|
||||
OldSymLinkList = SymLinkList;
|
||||
OldSymLinkListSize = SymLinkListSize;
|
||||
SymLinkListSize += vpip->DataLength;
|
||||
SymLinkList = ExAllocatePool(NonPagedPool, SymLinkListSize + sizeof(WCHAR));
|
||||
ASSERT(SymLinkList != NULL);
|
||||
RtlCopyMemory(SymLinkList, OldSymLinkList, OldSymLinkListSize);
|
||||
ExFreePool(OldSymLinkList);
|
||||
SymLinkListPtr = SymLinkList + (OldSymLinkListSize / sizeof(WCHAR));
|
||||
RtlCopyMemory(SymLinkListPtr, vpip->Data, vpip->DataLength);
|
||||
SymLinkListPtr[vpip->DataLength / sizeof(WCHAR)] = 0;
|
||||
SymLinkListPtr[1] = '?';
|
||||
}
|
||||
}
|
||||
|
||||
RtlFreeUnicodeString(&SymbolicLinkKeyName);
|
||||
RtlFreeUnicodeString(&ControlKeyName);
|
||||
ZwClose(SymbolicLinkKey);
|
||||
}
|
||||
|
||||
ExFreePool(vpip);
|
||||
RtlFreeUnicodeString(&SubKeyName);
|
||||
ZwClose(SubKey);
|
||||
}
|
||||
|
||||
if (SymLinkList != NULL)
|
||||
{
|
||||
SymLinkList[SymLinkListSize / sizeof(WCHAR)] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
SymLinkList = ExAllocatePool(NonPagedPool, 2 * sizeof(WCHAR));
|
||||
SymLinkList[0] = 0;
|
||||
}
|
||||
|
||||
*SymbolicLinkList = SymLinkList;
|
||||
|
||||
RtlFreeUnicodeString(&BaseKeyName);
|
||||
ZwClose(InterfaceKey);
|
||||
ExFreePool(bfip);
|
||||
ExFreePool(fip);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
154
rostests/drivers/kmtest/deviface_test.c
Normal file
154
rostests/drivers/kmtest/deviface_test.c
Normal file
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* PnP Test
|
||||
* Device Interface functions test
|
||||
*
|
||||
* Copyright 2004 Filip Navara <xnavara@volny.cz>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; see the file COPYING.LIB.
|
||||
* If not, write to the Free Software Foundation,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <ddk/ntddk.h>
|
||||
#include <ndk/iotypes.h>
|
||||
#include "kmtest.h"
|
||||
|
||||
//#define NDEBUG
|
||||
#include "debug.h"
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
NTSTATUS STDCALL
|
||||
(*IoGetDeviceInterfaces_Func)(
|
||||
IN CONST GUID *InterfaceClassGuid,
|
||||
IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL,
|
||||
IN ULONG Flags,
|
||||
OUT PWSTR *SymbolicLinkList);
|
||||
|
||||
NTSTATUS STDCALL
|
||||
ReactOS_IoGetDeviceInterfaces(
|
||||
IN CONST GUID *InterfaceClassGuid,
|
||||
IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL,
|
||||
IN ULONG Flags,
|
||||
OUT PWSTR *SymbolicLinkList);
|
||||
|
||||
VOID FASTCALL DeviceInterfaceTest_Func()
|
||||
{
|
||||
NTSTATUS Status;
|
||||
PWSTR SymbolicLinkList;
|
||||
PWSTR SymbolicLinkListPtr;
|
||||
GUID Guid = {0x378de44c, 0x56ef, 0x11d1, {0xbc, 0x8c, 0x00, 0xa0, 0xc9, 0x14, 0x05, 0xdd}};
|
||||
|
||||
Status = IoGetDeviceInterfaces_Func(
|
||||
&Guid,
|
||||
NULL,
|
||||
0,
|
||||
&SymbolicLinkList);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT(
|
||||
"[PnP Test] IoGetDeviceInterfaces failed with status 0x%X\n",
|
||||
Status);
|
||||
return;
|
||||
}
|
||||
|
||||
DPRINT("[PnP Test] IoGetDeviceInterfaces results:\n");
|
||||
for (SymbolicLinkListPtr = SymbolicLinkList;
|
||||
SymbolicLinkListPtr[0] != 0 && SymbolicLinkListPtr[1] != 0;
|
||||
SymbolicLinkListPtr += wcslen(SymbolicLinkListPtr) + 1)
|
||||
{
|
||||
DPRINT("[PnP Test] %S\n", SymbolicLinkListPtr);
|
||||
}
|
||||
|
||||
#if 0
|
||||
DPRINT("[PnP Test] Trying to get aliases\n");
|
||||
|
||||
for (SymbolicLinkListPtr = SymbolicLinkList;
|
||||
SymbolicLinkListPtr[0] != 0 && SymbolicLinkListPtr[1] != 0;
|
||||
SymbolicLinkListPtr += wcslen(SymbolicLinkListPtr) + 1)
|
||||
{
|
||||
UNICODE_STRING SymbolicLink;
|
||||
UNICODE_STRING AliasSymbolicLink;
|
||||
|
||||
SymbolicLink.Buffer = SymbolicLinkListPtr;
|
||||
SymbolicLink.Length = SymbolicLink.MaximumLength = wcslen(SymbolicLinkListPtr);
|
||||
RtlInitUnicodeString(&AliasSymbolicLink, NULL);
|
||||
IoGetDeviceInterfaceAlias(
|
||||
&SymbolicLink,
|
||||
&AliasGuid,
|
||||
&AliasSymbolicLink);
|
||||
if (AliasSymbolicLink.Buffer != NULL)
|
||||
{
|
||||
DPRINT("[PnP Test] Original: %S\n", SymbolicLinkListPtr);
|
||||
DPRINT("[PnP Test] Alias: %S\n", AliasSymbolicLink.Buffer);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ExFreePool(SymbolicLinkList);
|
||||
}
|
||||
|
||||
VOID RegisterDI_Test()
|
||||
{
|
||||
GUID Guid = {0x378de44c, 0x56ef, 0x11d1, {0xbc, 0x8c, 0x00, 0xa0, 0xc9, 0x14, 0x05, 0xdd}};
|
||||
DEVICE_OBJECT DeviceObject;
|
||||
EXTENDED_DEVOBJ_EXTENSION DeviceObjectExtension;
|
||||
DEVICE_NODE DeviceNode;
|
||||
UNICODE_STRING SymbolicLinkName;
|
||||
NTSTATUS Status;
|
||||
|
||||
RtlInitUnicodeString(&SymbolicLinkName, L"");
|
||||
|
||||
// Prepare our surrogate of a Device Object
|
||||
DeviceObject.DeviceObjectExtension = (PDEVOBJ_EXTENSION)&DeviceObjectExtension;
|
||||
|
||||
// 1. DeviceNode = NULL
|
||||
DeviceObjectExtension.DeviceNode = NULL;
|
||||
Status = IoRegisterDeviceInterface(&DeviceObject, &Guid, NULL,
|
||||
&SymbolicLinkName);
|
||||
|
||||
ok(Status == STATUS_INVALID_DEVICE_REQUEST,
|
||||
"IoRegisterDeviceInterface returned 0x%08lX\n", Status);
|
||||
|
||||
// 2. DeviceNode->InstancePath is of a null length
|
||||
DeviceObjectExtension.DeviceNode = &DeviceNode;
|
||||
DeviceNode.InstancePath.Length = 0;
|
||||
Status = IoRegisterDeviceInterface(&DeviceObject, &Guid, NULL,
|
||||
&SymbolicLinkName);
|
||||
|
||||
ok(Status == STATUS_INVALID_DEVICE_REQUEST,
|
||||
"IoRegisterDeviceInterface returned 0x%08lX\n", Status);
|
||||
}
|
||||
|
||||
VOID FASTCALL NtoskrnlIoDeviceInterface()
|
||||
{
|
||||
StartTest();
|
||||
|
||||
// Test IoRegisterDeviceInterface() failures now
|
||||
RegisterDI_Test();
|
||||
|
||||
/*
|
||||
DPRINT("Calling DeviceInterfaceTest_Func with native functions\n");
|
||||
IoGetDeviceInterfaces_Func = IoGetDeviceInterfaces;
|
||||
DeviceInterfaceTest_Func();
|
||||
DPRINT("Calling DeviceInterfaceTest_Func with ReactOS functions\n");
|
||||
IoGetDeviceInterfaces_Func = ReactOS_IoGetDeviceInterfaces;
|
||||
DeviceInterfaceTest_Func();
|
||||
*/
|
||||
|
||||
FinishTest("NTOSKRNL Io Device Interface Test");
|
||||
}
|
126
rostests/drivers/kmtest/kmtest.c
Normal file
126
rostests/drivers/kmtest/kmtest.c
Normal file
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Kernel Mode regression Test
|
||||
* Driver Core
|
||||
*
|
||||
* Copyright 2004 Filip Navara <xnavara@volny.cz>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; see the file COPYING.LIB.
|
||||
* If not, write to the Free Software Foundation,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <ddk/ntddk.h>
|
||||
#include "kmtest.h"
|
||||
|
||||
LONG successes;
|
||||
LONG failures;
|
||||
tls_data glob_data;
|
||||
|
||||
/* PRIVATE FUNCTIONS ***********************************************************/
|
||||
VOID
|
||||
StartTest()
|
||||
{
|
||||
successes = 0;
|
||||
failures = 0;
|
||||
}
|
||||
|
||||
VOID
|
||||
FinishTest(LPSTR TestName)
|
||||
{
|
||||
DbgPrint("Test %s finished with %d succeses and %d failures\n", TestName, successes, failures);
|
||||
}
|
||||
|
||||
void kmtest_set_location(const char* file, int line)
|
||||
{
|
||||
glob_data.current_file=strrchr(file,'/');
|
||||
if (glob_data.current_file==NULL)
|
||||
glob_data.current_file=strrchr(file,'\\');
|
||||
if (glob_data.current_file==NULL)
|
||||
glob_data.current_file=file;
|
||||
else
|
||||
glob_data.current_file++;
|
||||
glob_data.current_line=line;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks condition.
|
||||
* Parameters:
|
||||
* - condition - condition to check;
|
||||
* - msg test description;
|
||||
* - file - test application source code file name of the check
|
||||
* - line - test application source code file line number of the check
|
||||
* Return:
|
||||
* 0 if condition does not have the expected value, 1 otherwise
|
||||
*/
|
||||
int kmtest_ok(int condition, const char *msg, ... )
|
||||
{
|
||||
va_list valist;
|
||||
|
||||
if (!condition)
|
||||
{
|
||||
if (msg[0])
|
||||
{
|
||||
char string[1024];
|
||||
va_start(valist, msg);
|
||||
vsprintf(string, msg, valist);
|
||||
DbgPrint( "%s:%d: Test failed: %s\n",
|
||||
glob_data.current_file, glob_data.current_line, string );
|
||||
va_end(valist);
|
||||
}
|
||||
else
|
||||
{
|
||||
DbgPrint( "%s:%d: Test failed\n",
|
||||
glob_data.current_file, glob_data.current_line );
|
||||
}
|
||||
InterlockedIncrement(&failures);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{/*
|
||||
if (report_success)
|
||||
fprintf( stdout, "%s:%d: Test succeeded\n",
|
||||
glob_data.current_file, glob_data.current_line);*/
|
||||
InterlockedIncrement(&successes);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
/*
|
||||
* Test Declarations
|
||||
*/
|
||||
VOID FASTCALL NtoskrnlIoMdlTest();
|
||||
VOID FASTCALL NtoskrnlIoDeviceInterface();
|
||||
VOID FASTCALL NtoskrnlObTest();
|
||||
VOID FASTCALL NtoskrnlExecutiveTests();
|
||||
|
||||
/*
|
||||
* DriverEntry
|
||||
*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
DriverEntry(PDRIVER_OBJECT DriverObject,
|
||||
PUNICODE_STRING RegistryPath)
|
||||
{
|
||||
DbgPrint("\n===============================================\nKernel Mode Regression Test driver starting...\n");
|
||||
NtoskrnlExecutiveTests();
|
||||
NtoskrnlIoDeviceInterface();
|
||||
NtoskrnlIoMdlTest();
|
||||
NtoskrnlObTest();
|
||||
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
48
rostests/drivers/kmtest/kmtest.h
Normal file
48
rostests/drivers/kmtest/kmtest.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
#ifndef PNPTEST_H
|
||||
#define PNPTEST_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
Some macros, structs, and vars are based or inspired from the great
|
||||
Wine regression tests Copyright (C) 2002 Alexandre Julliard.
|
||||
Everything else is done by Aleksey Bragin based on PnPTest by Filip Navara
|
||||
*/
|
||||
|
||||
extern LONG successes; /* number of successful tests */
|
||||
extern LONG failures; /* number of failures */
|
||||
//static ULONG todo_successes; /* number of successful tests inside todo block */
|
||||
//static ULONG todo_failures; /* number of failures inside todo block */
|
||||
|
||||
// We don't do multithreading, so we just keep this struct in a global var
|
||||
typedef struct
|
||||
{
|
||||
const char* current_file; /* file of current check */
|
||||
int current_line; /* line of current check */
|
||||
int todo_level; /* current todo nesting level */
|
||||
int todo_do_loop;
|
||||
} tls_data;
|
||||
|
||||
extern tls_data glob_data;
|
||||
|
||||
VOID StartTest();
|
||||
VOID FinishTest(LPSTR TestName);
|
||||
void kmtest_set_location(const char* file, int line);
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
||||
extern int kmtest_ok( int condition, const char *msg, ... ) __attribute__((format (printf,2,3) ));
|
||||
|
||||
#else /* __GNUC__ */
|
||||
|
||||
extern int kmtest_ok( int condition, const char *msg, ... );
|
||||
|
||||
#endif /* __GNUC__ */
|
||||
|
||||
|
||||
#define ok_(file, line) (kmtest_set_location(file, line), 0) ? 0 : kmtest_ok
|
||||
#define ok ok_(__FILE__, __LINE__)
|
||||
|
||||
#endif /* PNPTEST_H */
|
14
rostests/drivers/kmtest/kmtest.rbuild
Normal file
14
rostests/drivers/kmtest/kmtest.rbuild
Normal file
|
@ -0,0 +1,14 @@
|
|||
<module name="kmtest" type="kernelmodedriver" installbase="system32/drivers" installname="kmtest.sys">
|
||||
<bootstrap base="$(CDOUTPUT)" />
|
||||
<define name="__USE_W32API" />
|
||||
<include base="ReactOS">include/reactos/drivers</include>
|
||||
<library>ntoskrnl</library>
|
||||
<library>hal</library>
|
||||
<file>kmtest.c</file>
|
||||
<file>deviface.c</file>
|
||||
<file>deviface_test.c</file>
|
||||
<file>ntos_ex.c</file>
|
||||
<file>ntos_io.c</file>
|
||||
<file>ntos_ob.c</file>
|
||||
<file>kmtest.rc</file>
|
||||
</module>
|
7
rostests/drivers/kmtest/kmtest.rc
Normal file
7
rostests/drivers/kmtest/kmtest.rc
Normal file
|
@ -0,0 +1,7 @@
|
|||
/* $Id: csqtest.rc 21842 2006-05-07 19:16:11Z ion $ */
|
||||
|
||||
#define REACTOS_VERSION_DLL
|
||||
#define REACTOS_STR_FILE_DESCRIPTION "Kernel Mode Regression Tests\0"
|
||||
#define REACTOS_STR_INTERNAL_NAME "kmtest\0"
|
||||
#define REACTOS_STR_ORIGINAL_FILENAME "kmtest.sys\0"
|
||||
#include <reactos/version.rc>
|
180
rostests/drivers/kmtest/ntos_ex.c
Normal file
180
rostests/drivers/kmtest/ntos_ex.c
Normal file
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* NTOSKRNL Executive Regressions KM-Test
|
||||
* ReactOS Kernel Mode Regression Testing framework
|
||||
*
|
||||
* Copyright 2006 Aleksey Bragin <aleksey@reactos.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; see the file COPYING.LIB.
|
||||
* If not, write to the Free Software Foundation,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <ddk/ntddk.h>
|
||||
#include <ntifs.h>
|
||||
#include <ndk/ntndk.h>
|
||||
#include "kmtest.h"
|
||||
|
||||
//#define NDEBUG
|
||||
#include "debug.h"
|
||||
|
||||
/* PRIVATE FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
TestTimerApcRoutine(IN PVOID TimerContext,
|
||||
IN ULONG TimerLowValue,
|
||||
IN LONG TimerHighValue)
|
||||
|
||||
{
|
||||
DPRINT("Timer Apc called!\n");
|
||||
ULONG *ApcCount = (ULONG *)TimerContext;
|
||||
(*ApcCount)++;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
ExTimerTest()
|
||||
{
|
||||
UNICODE_STRING TimerName;
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
HANDLE TimerHandle;
|
||||
HANDLE HandleOpened;
|
||||
LARGE_INTEGER DueTime;
|
||||
BOOLEAN PreviousState, CurrentState;
|
||||
NTSTATUS Status;
|
||||
ULONG ApcCount;
|
||||
|
||||
StartTest();
|
||||
|
||||
// Create the timer
|
||||
RtlInitUnicodeString(&TimerName, L"\\TestTimer");
|
||||
InitializeObjectAttributes(&ObjectAttributes, &TimerName, 0, NULL, NULL);
|
||||
Status = ZwCreateTimer(&TimerHandle, TIMER_ALL_ACCESS,
|
||||
&ObjectAttributes, NotificationTimer);
|
||||
ok(Status == STATUS_SUCCESS, "ZwCreateTimer failed with Status=0x%08lX", Status);
|
||||
|
||||
// Open the timer
|
||||
Status = ZwOpenTimer(&HandleOpened, TIMER_ALL_ACCESS, &ObjectAttributes);
|
||||
ok(Status == STATUS_SUCCESS, "ZwOpenTimer failed with Status=0x%08lX", Status);
|
||||
|
||||
// Set the timer, to some rather high value so it doesn't expire
|
||||
DPRINT("Set timer 1\n");
|
||||
DueTime.LowPart = -10000;
|
||||
DueTime.HighPart = -10;
|
||||
PreviousState = TRUE;
|
||||
Status = ZwSetTimer(HandleOpened, &DueTime, NULL, NULL, FALSE, 0L, &PreviousState);
|
||||
ok(Status == STATUS_SUCCESS, "ZwSetTimer failed with Status=0x%08lX", Status);
|
||||
ok(PreviousState == FALSE, "Incorrect PreviousState returned when setting the timer");
|
||||
|
||||
// Cancel the timer
|
||||
CurrentState = TRUE;
|
||||
Status = ZwCancelTimer(HandleOpened, &CurrentState);
|
||||
ok(Status == STATUS_SUCCESS, "ZwCancelTimer failed with Status=0x%08lX", Status);
|
||||
ok(CurrentState == FALSE, "Incorrect CurrentState returned when canceling the timer");
|
||||
|
||||
// Set the timer to some small value, because we'll wait for it to expire
|
||||
DPRINT("Set timer 2\n");
|
||||
DueTime.LowPart = -100;
|
||||
DueTime.HighPart = -1;
|
||||
PreviousState = TRUE;
|
||||
Status = ZwSetTimer(HandleOpened, &DueTime, NULL, NULL, FALSE, 0L, &PreviousState);
|
||||
ok(Status == STATUS_SUCCESS, "ZwSetTimer failed with Status=0x%08lX", Status);
|
||||
ok(PreviousState == FALSE, "Incorrect PreviousState returned when setting the timer");
|
||||
|
||||
// Wait until it expires
|
||||
DPRINT("Wait till timer expires\n");
|
||||
Status = ZwWaitForSingleObject(HandleOpened, FALSE, NULL);
|
||||
ok(Status == STATUS_SUCCESS, "ZwWaitForSingleObject failed with Status=0x%08lX", Status);
|
||||
|
||||
// And cancel it
|
||||
DPRINT("Cancel it\n");
|
||||
CurrentState = FALSE;
|
||||
Status = ZwCancelTimer(HandleOpened, &CurrentState);
|
||||
ok(Status == STATUS_SUCCESS, "ZwCancelTimer failed with Status=0x%08lX", Status);
|
||||
ok(CurrentState == TRUE, "Incorrect CurrentState returned when setting the timer");
|
||||
|
||||
// Test it with APC: Set, Cancel, check if APC has been called
|
||||
DPRINT("Set timer with Apc (3)\n");
|
||||
ApcCount = 0;
|
||||
DueTime.LowPart = -10000;
|
||||
DueTime.HighPart = -10;
|
||||
PreviousState = FALSE;
|
||||
Status = ZwSetTimer(HandleOpened, &DueTime,
|
||||
(PTIMER_APC_ROUTINE)TestTimerApcRoutine, &ApcCount, FALSE,
|
||||
0L, &PreviousState);
|
||||
|
||||
ok(Status == STATUS_SUCCESS, "ZwSetTimer failed with Status=0x%08lX", Status);
|
||||
ok(PreviousState == TRUE, "Incorrect PreviousState returned when setting the timer");
|
||||
|
||||
DPRINT("Cancel it\n");
|
||||
CurrentState = TRUE;
|
||||
Status = ZwCancelTimer(HandleOpened, &CurrentState);
|
||||
ok(Status == STATUS_SUCCESS, "ZwCancelTimer failed with Status=0x%08lX", Status);
|
||||
ok(CurrentState == FALSE, "Incorrect CurrentState returned when cancelling the timer");
|
||||
ok(ApcCount == 0, "Incorrect count of TimerApcRoutine calls: %ld, should be 0\n", ApcCount);
|
||||
|
||||
// Test setting the timer two times in a row, APC routine must not be called
|
||||
DPRINT("Set timer with Apc (4)\n");
|
||||
ApcCount = 0;
|
||||
DueTime.LowPart = -10000;
|
||||
DueTime.HighPart = -10;
|
||||
PreviousState = TRUE;
|
||||
Status = ZwSetTimer(HandleOpened, &DueTime,
|
||||
(PTIMER_APC_ROUTINE)TestTimerApcRoutine, &ApcCount, FALSE,
|
||||
0L, &PreviousState);
|
||||
ok(Status == STATUS_SUCCESS, "ZwSetTimer failed with Status=0x%08lX", Status);
|
||||
ok(PreviousState == FALSE, "Incorrect PreviousState returned when setting the timer");
|
||||
|
||||
// Set small due time, since we have to wait for timer to finish
|
||||
DPRINT("Set timer with Apc (5)\n");
|
||||
DueTime.LowPart = -10;
|
||||
DueTime.HighPart = -1;
|
||||
PreviousState = TRUE;
|
||||
Status = ZwSetTimer(HandleOpened, &DueTime,
|
||||
(PTIMER_APC_ROUTINE)TestTimerApcRoutine, &ApcCount, FALSE,
|
||||
0L, &PreviousState);
|
||||
ok(Status == STATUS_SUCCESS, "ZwSetTimer failed with Status=0x%08lX", Status);
|
||||
ok(PreviousState == FALSE, "Incorrect PreviousState returned when setting the timer");
|
||||
|
||||
// Now wait till it's finished, and then check APC call
|
||||
DPRINT("Wait for it\n");
|
||||
Status = ZwWaitForSingleObject(HandleOpened, FALSE, NULL);
|
||||
ok(Status == STATUS_SUCCESS, "ZwWaitForSingleObject failed with Status=0x%08lX", Status);
|
||||
|
||||
CurrentState = FALSE;
|
||||
Status = ZwCancelTimer(HandleOpened, &CurrentState);
|
||||
ok(Status == STATUS_SUCCESS, "ZwCancelTimer failed with Status=0x%08lX", Status);
|
||||
ok(CurrentState == TRUE, "Incorrect CurrentState returned when cancelling the timer");
|
||||
ok(ApcCount == 1, "Incorrect count of TimerApcRoutine calls: %ld, should be 1\n", ApcCount);
|
||||
|
||||
// Cleanup...
|
||||
Status = ZwClose(HandleOpened);
|
||||
ok(Status == STATUS_SUCCESS, "ZwClose failed with Status=0x%08lX", Status);
|
||||
|
||||
Status = ZwClose(TimerHandle);
|
||||
ok(Status == STATUS_SUCCESS, "ZwClose failed with Status=0x%08lX", Status);
|
||||
|
||||
FinishTest("NTOSKRNL Executive Timer");
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID
|
||||
FASTCALL
|
||||
NtoskrnlExecutiveTests()
|
||||
{
|
||||
ExTimerTest();
|
||||
}
|
81
rostests/drivers/kmtest/ntos_io.c
Normal file
81
rostests/drivers/kmtest/ntos_io.c
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* NTOSKRNL Io Regressions KM-Test
|
||||
* ReactOS Kernel Mode Regression Testing framework
|
||||
*
|
||||
* Copyright 2006 Aleksey Bragin <aleksey@reactos.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; see the file COPYING.LIB.
|
||||
* If not, write to the Free Software Foundation,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <ddk/ntddk.h>
|
||||
#include "kmtest.h"
|
||||
|
||||
#define NDEBUG
|
||||
#include "debug.h"
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID FASTCALL NtoskrnlIoMdlTest()
|
||||
{
|
||||
PMDL Mdl;
|
||||
PIRP Irp;
|
||||
PVOID VirtualAddress;
|
||||
ULONG MdlSize = 2*4096+184; // 2 pages and some random value
|
||||
|
||||
StartTest();
|
||||
|
||||
// Try to alloc 2Gb MDL
|
||||
Mdl = IoAllocateMdl(NULL, 2048UL*0x100000, FALSE, FALSE, NULL);
|
||||
|
||||
ok(Mdl == NULL,
|
||||
"IoAllocateMdl should fail allocation of 2Gb or more, but got Mdl=0x%X",
|
||||
(UINT)Mdl);
|
||||
|
||||
if (Mdl)
|
||||
IoFreeMdl(Mdl);
|
||||
|
||||
// Now create a valid MDL
|
||||
VirtualAddress = ExAllocatePool(NonPagedPool, MdlSize);
|
||||
Mdl = IoAllocateMdl(VirtualAddress, MdlSize, FALSE, FALSE, NULL);
|
||||
ok(Mdl != NULL, "Mdl allocation failed");
|
||||
// Check fields of the allocated struct
|
||||
ok(Mdl->Next == NULL, "Mdl->Next should be NULL, but is 0x%X",
|
||||
(UINT)Mdl->Next);
|
||||
ok(Mdl->ByteCount == MdlSize,
|
||||
"Mdl->ByteCount should be equal to MdlSize, but is 0x%X",
|
||||
(UINT)Mdl->ByteCount);
|
||||
// TODO: Check other fields of MDL struct
|
||||
|
||||
IoFreeMdl(Mdl);
|
||||
// Allocate now with pointer to an Irp
|
||||
Irp = IoAllocateIrp(1, FALSE);
|
||||
ok(Irp != NULL, "IRP allocation failed");
|
||||
Mdl = IoAllocateMdl(VirtualAddress, MdlSize, FALSE, FALSE, Irp);
|
||||
ok(Mdl != NULL, "Mdl allocation failed");
|
||||
ok(Irp->MdlAddress == Mdl, "Irp->MdlAddress should be 0x%X, but is 0x%X",
|
||||
(UINT)Mdl, (UINT)Irp->MdlAddress);
|
||||
|
||||
IoFreeMdl(Mdl);
|
||||
|
||||
// TODO: Check a case when SecondaryBuffer == TRUE
|
||||
|
||||
IoFreeIrp(Irp);
|
||||
ExFreePool(VirtualAddress);
|
||||
|
||||
FinishTest("NTOSKRNL Io Mdl");
|
||||
}
|
519
rostests/drivers/kmtest/ntos_ob.c
Normal file
519
rostests/drivers/kmtest/ntos_ob.c
Normal file
|
@ -0,0 +1,519 @@
|
|||
/*
|
||||
* NTOSKRNL Ob Regressions KM-Test
|
||||
* ReactOS Kernel Mode Regression Testing framework
|
||||
*
|
||||
* Copyright 2006 Aleksey Bragin <aleksey@reactos.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; see the file COPYING.LIB.
|
||||
* If not, write to the Free Software Foundation,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <ddk/ntddk.h>
|
||||
#include "kmtest.h"
|
||||
|
||||
//#define NDEBUG
|
||||
#include "debug.h"
|
||||
|
||||
#include "ntndk.h"
|
||||
|
||||
// I ment to make this test scalable, but for now
|
||||
// we work with two object types only
|
||||
#define NUM_OBTYPES 2
|
||||
|
||||
typedef struct _MY_OBJECT1
|
||||
{
|
||||
ULONG Something1;
|
||||
} MY_OBJECT1, *PMY_OBJECT1;
|
||||
|
||||
typedef struct _MY_OBJECT2
|
||||
{
|
||||
ULONG Something1;
|
||||
ULONG SomeLong[10];
|
||||
} MY_OBJECT2, *PMY_OBJECT2;
|
||||
|
||||
POBJECT_TYPE ObTypes[NUM_OBTYPES];
|
||||
UNICODE_STRING ObTypeName[NUM_OBTYPES];
|
||||
UNICODE_STRING ObName[NUM_OBTYPES];
|
||||
OBJECT_TYPE_INITIALIZER ObTypeInitializer[NUM_OBTYPES];
|
||||
UNICODE_STRING ObDirectoryName;
|
||||
OBJECT_ATTRIBUTES ObDirectoryAttributes;
|
||||
OBJECT_ATTRIBUTES ObAttributes[NUM_OBTYPES];
|
||||
PVOID ObBody[NUM_OBTYPES];
|
||||
PMY_OBJECT1 ObObject1;
|
||||
PMY_OBJECT2 ObObject2;
|
||||
HANDLE ObHandle1[NUM_OBTYPES];
|
||||
HANDLE ObHandle2[NUM_OBTYPES];
|
||||
HANDLE DirectoryHandle;
|
||||
|
||||
USHORT DumpCount, OpenCount, CloseCount, DeleteCount,
|
||||
ParseCount, OkayToCloseCount, QueryNameCount;
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
DumpProc(IN PVOID Object,
|
||||
IN POB_DUMP_CONTROL DumpControl)
|
||||
{
|
||||
DbgPrint("DumpProc() called\n");
|
||||
DumpCount++;
|
||||
}
|
||||
|
||||
// Tested in Win2k3
|
||||
VOID
|
||||
NTAPI
|
||||
OpenProc(IN OB_OPEN_REASON OpenReason,
|
||||
IN PEPROCESS Process,
|
||||
IN PVOID Object,
|
||||
IN ACCESS_MASK GrantedAccess,
|
||||
IN ULONG HandleCount)
|
||||
{
|
||||
DbgPrint("OpenProc() 0x%p, OpenReason %d, HC %d, AM 0x%X\n",
|
||||
Object, OpenReason, HandleCount, GrantedAccess);
|
||||
OpenCount++;
|
||||
}
|
||||
|
||||
// Tested in Win2k3
|
||||
VOID
|
||||
NTAPI
|
||||
CloseProc(IN PEPROCESS Process,
|
||||
IN PVOID Object,
|
||||
IN ACCESS_MASK GrantedAccess,
|
||||
IN ULONG ProcessHandleCount,
|
||||
IN ULONG SystemHandleCount)
|
||||
{
|
||||
DbgPrint("CloseProc() 0x%p, PHC %d, SHC %d, AM 0x%X\n", Object,
|
||||
ProcessHandleCount, SystemHandleCount, GrantedAccess);
|
||||
CloseCount++;
|
||||
}
|
||||
|
||||
// Tested in Win2k3
|
||||
VOID
|
||||
NTAPI
|
||||
DeleteProc(IN PVOID Object)
|
||||
{
|
||||
DbgPrint("DeleteProc() 0x%p\n", Object);
|
||||
DeleteCount++;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
ParseProc(IN PVOID ParseObject,
|
||||
IN PVOID ObjectType,
|
||||
IN OUT PACCESS_STATE AccessState,
|
||||
IN KPROCESSOR_MODE AccessMode,
|
||||
IN ULONG Attributes,
|
||||
IN OUT PUNICODE_STRING CompleteName,
|
||||
IN OUT PUNICODE_STRING RemainingName,
|
||||
IN OUT PVOID Context OPTIONAL,
|
||||
IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
|
||||
OUT PVOID *Object)
|
||||
{
|
||||
DbgPrint("ParseProc() called\n");
|
||||
*Object = NULL;
|
||||
|
||||
ParseCount++;
|
||||
return STATUS_OBJECT_NAME_NOT_FOUND;//STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Tested in Win2k3
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
OkayToCloseProc(IN PEPROCESS Process OPTIONAL,
|
||||
IN PVOID Object,
|
||||
IN HANDLE Handle,
|
||||
IN KPROCESSOR_MODE AccessMode)
|
||||
{
|
||||
DbgPrint("OkayToCloseProc() 0x%p, H 0x%p, AM 0x%X\n", Object, Handle,
|
||||
AccessMode);
|
||||
OkayToCloseCount++;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
QueryNameProc(IN PVOID Object,
|
||||
IN BOOLEAN HasObjectName,
|
||||
OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
|
||||
IN ULONG Length,
|
||||
OUT PULONG ReturnLength,
|
||||
IN KPROCESSOR_MODE AccessMode)
|
||||
{
|
||||
DbgPrint("QueryNameProc() 0x%p, HON %d, Len %d, AM 0x%X\n",
|
||||
Object, HasObjectName, Length, AccessMode);
|
||||
QueryNameCount++;
|
||||
|
||||
ObjectNameInfo = NULL;
|
||||
ReturnLength = 0;
|
||||
return STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
ObtCreateObjectTypes()
|
||||
{
|
||||
USHORT i;
|
||||
NTSTATUS Status;
|
||||
WCHAR Name[15];
|
||||
|
||||
for (i=0; i<NUM_OBTYPES; i++)
|
||||
{
|
||||
// Prepare object type name
|
||||
// TODO: Generate type names and don't use this unprofessional,
|
||||
swprintf(Name, L"MyObjectType%lx", i);
|
||||
RtlInitUnicodeString(&ObTypeName[i], Name);
|
||||
|
||||
// Prepare initializer
|
||||
RtlZeroMemory(&ObTypeInitializer[i], sizeof(ObTypeInitializer[i]));
|
||||
ObTypeInitializer[i].Length = sizeof(ObTypeInitializer[i]);
|
||||
ObTypeInitializer[i].PoolType = NonPagedPool;
|
||||
ObTypeInitializer[i].MaintainHandleCount = TRUE;
|
||||
ObTypeInitializer[i].ValidAccessMask = OBJECT_TYPE_ALL_ACCESS;
|
||||
|
||||
// Test for invalid parameter
|
||||
// FIXME: Make it more exact, to see which params Win2k3 checks
|
||||
// existence of
|
||||
Status = ObCreateObjectType(&ObTypeName[i], &ObTypeInitializer[i],
|
||||
(PSECURITY_DESCRIPTOR)NULL, &ObTypes[i]);
|
||||
ok(Status == STATUS_INVALID_PARAMETER,
|
||||
"ObCreateObjectType returned 0x%lX", Status);
|
||||
|
||||
// Object procedures
|
||||
ObTypeInitializer[i].CloseProcedure = (OB_CLOSE_METHOD)CloseProc;
|
||||
ObTypeInitializer[i].DeleteProcedure = (OB_DELETE_METHOD)DeleteProc;
|
||||
ObTypeInitializer[i].DumpProcedure = (OB_DUMP_METHOD)DumpProc;
|
||||
ObTypeInitializer[i].OpenProcedure = (OB_OPEN_METHOD)OpenProc;
|
||||
ObTypeInitializer[i].ParseProcedure = (OB_PARSE_METHOD)ParseProc;
|
||||
//ObTypeInitializer[i].OkayToCloseProcedure =
|
||||
// (OB_OKAYTOCLOSE_METHOD)OkayToCloseProc;
|
||||
|
||||
//ObTypeInitializer[i].QueryNameProcedure =
|
||||
// (OB_QUERYNAME_METHOD)QueryNameProc;
|
||||
|
||||
//ObTypeInitializer[i].SecurityProcedure =
|
||||
// (OB_SECURITY_METHOD)SecurityProc;
|
||||
|
||||
Status = ObCreateObjectType(&ObTypeName[i], &ObTypeInitializer[i],
|
||||
(PSECURITY_DESCRIPTOR)NULL, &ObTypes[i]);
|
||||
ok(Status == STATUS_SUCCESS,
|
||||
"Failed to create object type with status=0x%lX", Status);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
ObtCreateDirectory()
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
// Directory will have permanent and case insensitive flags
|
||||
RtlInitUnicodeString(&ObDirectoryName, L"\\ObtDirectory");
|
||||
InitializeObjectAttributes(&ObDirectoryAttributes, &ObDirectoryName,
|
||||
OBJ_PERMANENT | OBJ_CASE_INSENSITIVE, NULL, NULL);
|
||||
|
||||
Status = ZwCreateDirectoryObject(&DirectoryHandle, 0, &ObDirectoryAttributes);
|
||||
ok(Status == STATUS_SUCCESS,
|
||||
"Failed to create directory object with status=0x%lX", Status);
|
||||
}
|
||||
|
||||
VOID
|
||||
ObtCreateObjects()
|
||||
{
|
||||
PVOID ObBody1[2];
|
||||
NTSTATUS Status;
|
||||
USHORT OpenSave, CloseSave, DeleteSave, ParseSave,
|
||||
OkayToCloseSave, QueryNameSave;
|
||||
|
||||
// Create two objects
|
||||
RtlInitUnicodeString(&ObName[0], L"\\ObtDirectory\\MyObject1");
|
||||
InitializeObjectAttributes(&ObAttributes[0], &ObName[0],
|
||||
OBJ_CASE_INSENSITIVE, NULL, NULL);
|
||||
|
||||
RtlInitUnicodeString(&ObName[1], L"\\ObtDirectory\\MyObject2");
|
||||
InitializeObjectAttributes(&ObAttributes[1], &ObName[1],
|
||||
OBJ_CASE_INSENSITIVE, NULL, NULL);
|
||||
|
||||
Status = ObCreateObject(KernelMode, ObTypes[0], &ObAttributes[0],
|
||||
KernelMode, NULL, (ULONG)sizeof(MY_OBJECT1), 0L, 0L,
|
||||
(PVOID *)&ObBody[0]);
|
||||
ok(Status == STATUS_SUCCESS,
|
||||
"Failed to create object with status=0x%lX", Status);
|
||||
|
||||
Status = ObCreateObject(KernelMode, ObTypes[1], &ObAttributes[1],
|
||||
KernelMode, NULL, (ULONG)sizeof(MY_OBJECT2), 0L, 0L,
|
||||
(PVOID *)&ObBody[1]);
|
||||
ok(Status == STATUS_SUCCESS,
|
||||
"Failed to create object with status=0x%lX", Status);
|
||||
|
||||
// save counters
|
||||
OpenSave=OpenCount; CloseSave=CloseCount; DeleteSave=DeleteCount;
|
||||
ParseSave=ParseCount; OkayToCloseSave=OkayToCloseCount;
|
||||
QueryNameSave=QueryNameCount;
|
||||
|
||||
// Insert them
|
||||
Status = ObInsertObject(ObBody[0], NULL, STANDARD_RIGHTS_ALL, 0,
|
||||
&ObBody[0], &ObHandle1[0]);
|
||||
ok(Status == STATUS_SUCCESS,
|
||||
"Failed to insert object 0 with status=0x%lX", Status);
|
||||
ok(ObBody[0] != NULL, "Object body = NULL");
|
||||
ok(ObHandle1[0] != NULL, "Handle = NULL");
|
||||
|
||||
// check counters
|
||||
ok(OpenSave+1 == OpenCount, "Open method calls mismatch\n");
|
||||
ok(CloseSave == CloseCount, "Excessive Close method call\n");
|
||||
ok(DeleteSave == DeleteCount, "Excessive Delete method call\n");
|
||||
ok(ParseSave == ParseCount, "Excessive Parse method call\n");
|
||||
|
||||
// save counters
|
||||
OpenSave=OpenCount; CloseSave=CloseCount; DeleteSave=DeleteCount;
|
||||
ParseSave=ParseCount; OkayToCloseSave=OkayToCloseCount;
|
||||
QueryNameSave=QueryNameCount;
|
||||
|
||||
Status = ObInsertObject(ObBody[1], NULL, GENERIC_ALL, 0,
|
||||
&ObBody[1], &ObHandle1[1]);
|
||||
ok(Status == STATUS_SUCCESS,
|
||||
"Failed to insert object 1 with status=0x%lX", Status);
|
||||
ok(ObBody[1] != NULL, "Object body = NULL");
|
||||
ok(ObHandle1[1] != NULL, "Handle = NULL");
|
||||
|
||||
// check counters
|
||||
ok(OpenSave+1 == OpenCount, "Open method calls mismatch\n");
|
||||
ok(CloseSave == CloseCount, "Excessive Close method call\n");
|
||||
ok(DeleteSave == DeleteCount, "Excessive Delete method call\n");
|
||||
ok(ParseSave == ParseCount, "Excessive Parse method call\n");
|
||||
|
||||
// save counters
|
||||
OpenSave=OpenCount; CloseSave=CloseCount; DeleteSave=DeleteCount;
|
||||
ParseSave=ParseCount; OkayToCloseSave=OkayToCloseCount;
|
||||
QueryNameSave=QueryNameCount;
|
||||
|
||||
// Now create an object of type 0, of the same name and expect it to fail
|
||||
// inserting, but success creation
|
||||
RtlInitUnicodeString(&ObName[0], L"\\ObtDirectory\\MyObject1");
|
||||
InitializeObjectAttributes(&ObAttributes[0], &ObName[0], OBJ_OPENIF,
|
||||
NULL, NULL);
|
||||
|
||||
Status = ObCreateObject(KernelMode, ObTypes[0], &ObAttributes[0], KernelMode,
|
||||
NULL, (ULONG)sizeof(MY_OBJECT1), 0L, 0L, (PVOID *)&ObBody1[0]);
|
||||
ok(Status == STATUS_SUCCESS,
|
||||
"Failed to create object with status=0x%lX", Status);
|
||||
|
||||
// check counters
|
||||
ok(OpenSave == OpenCount, "Excessive Open method call\n");
|
||||
ok(CloseSave == CloseCount, "Excessive Close method call\n");
|
||||
ok(DeleteSave == DeleteCount, "Excessive Delete method call\n");
|
||||
ok(ParseSave == ParseCount, "Excessive Parse method call\n");
|
||||
|
||||
Status = ObInsertObject(ObBody1[0], NULL, GENERIC_ALL, 0,
|
||||
&ObBody1[1], &ObHandle2[0]);
|
||||
ok(Status == STATUS_OBJECT_NAME_EXISTS,
|
||||
"Object insertion should have failed, but got 0x%lX", Status);
|
||||
ok(ObBody[0] == ObBody1[1],
|
||||
"Object bodies doesn't match, 0x%p != 0x%p", ObBody[0], ObBody1[1]);
|
||||
ok(ObHandle2[0] != NULL, "Bad handle returned 0x%lX", (ULONG)ObHandle2[0]);
|
||||
|
||||
DPRINT1("%d %d %d %d %d %d %d\n", DumpCount, OpenCount, // deletecount+1
|
||||
CloseCount, DeleteCount, ParseCount, OkayToCloseCount, QueryNameCount);
|
||||
|
||||
// check counters and then save
|
||||
ok(OpenSave+1 == OpenCount, "Excessive Open method call\n");
|
||||
ok(CloseSave == CloseCount, "Excessive Close method call\n");
|
||||
ok(DeleteSave+1 == DeleteCount, "Delete method call mismatch\n");
|
||||
ok(ParseSave == ParseCount, "Excessive Parse method call\n");
|
||||
OpenSave=OpenCount; CloseSave=CloseCount; DeleteSave=DeleteCount;
|
||||
ParseSave=ParseCount; OkayToCloseSave=OkayToCloseCount;
|
||||
QueryNameSave=QueryNameCount;
|
||||
|
||||
// Close its handle
|
||||
Status = ZwClose(ObHandle2[0]);
|
||||
ok(Status == STATUS_SUCCESS,
|
||||
"Failed to close handle status=0x%lX", Status);
|
||||
|
||||
// check counters and then save
|
||||
ok(OpenSave == OpenCount, "Excessive Open method call\n");
|
||||
ok(CloseSave+1 == CloseCount, "Close method call mismatch\n");
|
||||
ok(DeleteSave == DeleteCount, "Excessive Delete method call\n");
|
||||
ok(ParseSave == ParseCount, "Excessive Parse method call\n");
|
||||
OpenSave=OpenCount; CloseSave=CloseCount; DeleteSave=DeleteCount;
|
||||
ParseSave=ParseCount; OkayToCloseSave=OkayToCloseCount;
|
||||
QueryNameSave=QueryNameCount;
|
||||
|
||||
|
||||
// Object referenced 2 times:
|
||||
// 1) ObInsertObject
|
||||
// 2) AdditionalReferences
|
||||
ObDereferenceObject(ObBody1[1]);
|
||||
|
||||
//DPRINT1("%d %d %d %d %d %d %d\n", DumpCount, OpenCount, // no change
|
||||
// CloseCount, DeleteCount, ParseCount, OkayToCloseCount, QueryNameCount);
|
||||
ok(OpenSave == OpenCount, "Open method call mismatch\n");
|
||||
ok(CloseSave == CloseCount, "Close method call mismatch\n");
|
||||
ok(DeleteSave == DeleteCount, "Delete method call mismatch\n");
|
||||
ok(ParseSave == ParseCount, "Parse method call mismatch\n");
|
||||
}
|
||||
|
||||
VOID
|
||||
ObtClose()
|
||||
{
|
||||
PVOID DirObject;
|
||||
NTSTATUS Status;
|
||||
//PVOID TypeObject;
|
||||
USHORT i;
|
||||
//UNICODE_STRING ObPathName[NUM_OBTYPES];
|
||||
|
||||
// Close what we have opened and free what we allocated
|
||||
ZwClose(ObHandle1[0]);
|
||||
ZwClose(ObHandle1[1]);
|
||||
ZwClose(ObHandle2[0]);
|
||||
ZwClose(ObHandle2[1]);
|
||||
|
||||
// Now we have to get rid of a directory object
|
||||
// Since it is permanent, we have to firstly make it temporary
|
||||
// and only then kill
|
||||
// (this procedure is described in DDK)
|
||||
Status = ObReferenceObjectByHandle(DirectoryHandle, 0L, NULL,
|
||||
KernelMode, &DirObject, NULL);
|
||||
ok(Status == STATUS_SUCCESS,
|
||||
"Failed to reference object by handle with status=0x%lX", Status);
|
||||
|
||||
// Dereference 2 times - first for just previous referencing
|
||||
// and 2nd time for creation of permanent object itself
|
||||
ObDereferenceObject(DirObject);
|
||||
ObDereferenceObject(DirObject);
|
||||
|
||||
Status = ZwMakeTemporaryObject(DirectoryHandle);
|
||||
ok(Status == STATUS_SUCCESS,
|
||||
"Failed to make temp object with status=0x%lX", Status);
|
||||
|
||||
// Close the handle now and we are done
|
||||
Status = ZwClose(DirectoryHandle);
|
||||
ok(Status == STATUS_SUCCESS,
|
||||
"Failed to close handle with status=0x%lX", Status);
|
||||
|
||||
// Now delete the last piece - object types
|
||||
// In fact, it's weird to get rid of object types, especially the way,
|
||||
// how it's done in the commented section below
|
||||
for (i=0; i<NUM_OBTYPES; i++)
|
||||
ObDereferenceObject(ObTypes[i]);
|
||||
/*
|
||||
RtlInitUnicodeString(&ObPathName[0], L"\\ObjectTypes\\MyObjectType1");
|
||||
RtlInitUnicodeString(&ObPathName[1], L"\\ObjectTypes\\MyObjectType2");
|
||||
|
||||
for (i=0; i<NUM_OBTYPES; i++)
|
||||
{
|
||||
Status = ObReferenceObjectByName(&ObPathName[i],
|
||||
OBJ_CASE_INSENSITIVE, NULL, 0L, NULL, KernelMode, NULL,
|
||||
&TypeObject);
|
||||
|
||||
ObDereferenceObject(TypeObject);
|
||||
ObDereferenceObject(TypeObject);
|
||||
DPRINT("Reference Name %S = %p, ObTypes[%d] = %p\n",
|
||||
ObPathName[i], TypeObject, i, ObTypes[i]);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
VOID
|
||||
ObtReferenceTests()
|
||||
{
|
||||
USHORT i;
|
||||
NTSTATUS Status;
|
||||
UNICODE_STRING ObPathName[NUM_OBTYPES];
|
||||
|
||||
// Reference them by handle
|
||||
for (i=0; i<NUM_OBTYPES; i++)
|
||||
{
|
||||
Status = ObReferenceObjectByHandle(ObHandle1[i], 0L, ObTypes[i],
|
||||
KernelMode, &ObBody[i], NULL);
|
||||
ok(Status == STATUS_SUCCESS,
|
||||
"Failed to reference object by handle, status=0x%lX", Status);
|
||||
DPRINT("Ref by handle %lx = %p\n", ObHandle1[i], ObBody[i]);
|
||||
}
|
||||
|
||||
// Reference them by pointer
|
||||
for (i=0; i<NUM_OBTYPES; i++)
|
||||
{
|
||||
Status = ObReferenceObjectByPointer(ObBody[i], 0L, ObTypes[i], KernelMode);
|
||||
ok(Status == STATUS_SUCCESS,
|
||||
"Failed to reference object by pointer, status=0x%lX", Status);
|
||||
}
|
||||
|
||||
// Reference them by name
|
||||
RtlInitUnicodeString(&ObPathName[0], L"\\ObtDirectory\\MyObject1");
|
||||
RtlInitUnicodeString(&ObPathName[1], L"\\ObtDirectory\\MyObject2");
|
||||
|
||||
for (i=0; i<NUM_OBTYPES; i++)
|
||||
{
|
||||
Status = ObReferenceObjectByName(&ObPathName[i],
|
||||
OBJ_CASE_INSENSITIVE, NULL, 0L, ObTypes[i], KernelMode, NULL,
|
||||
&ObBody[0]);
|
||||
|
||||
DPRINT("Ref by name %wZ = %p\n", &ObPathName[i], ObBody[i]);
|
||||
}
|
||||
|
||||
// Dereference now all of them
|
||||
|
||||
// For ObInsertObject, AdditionalReference
|
||||
ObDereferenceObject(ObBody[0]);
|
||||
ObDereferenceObject(ObBody[1]);
|
||||
|
||||
// For ByHandle
|
||||
ObDereferenceObject(ObBody[0]);
|
||||
ObDereferenceObject(ObBody[1]);
|
||||
|
||||
// For ByPointer
|
||||
ObDereferenceObject(ObBody[0]);
|
||||
ObDereferenceObject(ObBody[1]);
|
||||
|
||||
// For ByName
|
||||
ObDereferenceObject(ObBody[0]);
|
||||
ObDereferenceObject(ObBody[1]);
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID
|
||||
FASTCALL
|
||||
NtoskrnlObTest()
|
||||
{
|
||||
StartTest();
|
||||
|
||||
DumpCount = 0; OpenCount = 0; CloseCount = 0;
|
||||
DeleteCount = 0; ParseCount = 0;
|
||||
|
||||
// Create object-types to use in tests
|
||||
ObtCreateObjectTypes();
|
||||
DPRINT("ObtCreateObjectTypes() done\n");
|
||||
|
||||
// Create Directory
|
||||
ObtCreateDirectory();
|
||||
DPRINT("ObtCreateDirectory() done\n");
|
||||
|
||||
// Create and insert objects
|
||||
ObtCreateObjects();
|
||||
DPRINT("ObtCreateObjects() done\n");
|
||||
|
||||
// Reference them in a variety of ways
|
||||
//ObtReferenceTests();
|
||||
|
||||
// Clean up
|
||||
// FIXME: Disable to see results of creating objects in usermode.
|
||||
// Also it has problems with object types removal
|
||||
ObtClose();
|
||||
DPRINT("Cleanup done\n");
|
||||
|
||||
FinishTest("NTOSKRNL Ob Manager");
|
||||
}
|
Loading…
Reference in a new issue