mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 23:22:57 +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…
Add table
Add a link
Reference in a new issue