Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1080 lines
33 KiB

/*++
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
devices.c
Abstract:
Plug and Play Manager routines dealing with device manipulation/registration.
Author:
Lonny McMichael (lonnym) 02/14/95
Revision History:
--*/
#include "pnpmgrp.h"
#pragma hdrstop
typedef struct {
BOOLEAN Add;
} PROCESS_DRIVER_CONTEXT, *PPROCESS_DRIVER_CONTEXT;
typedef NTSTATUS (*PDEVICE_SERVICE_ITERATOR_ROUTINE)(
IN PUNICODE_STRING DeviceInstancePath,
IN PUNICODE_STRING ServiceName,
IN ULONG ServiceType,
IN PVOID Context
);
typedef struct {
PUNICODE_STRING DeviceInstancePath;
PDEVICE_SERVICE_ITERATOR_ROUTINE Iterator;
PVOID Context;
} DEVICE_SERVICE_ITERATOR_CONTEXT, *PDEVICE_SERVICE_ITERATOR_CONTEXT;
//
// Prototype utility functions internal to this file.
//
NTSTATUS
PiFindDevInstMatch(
IN HANDLE ServiceEnumHandle,
IN PUNICODE_STRING DeviceInstanceName,
OUT PULONG InstanceCount,
OUT PUNICODE_STRING MatchingValueName,
OUT PULONG MatchingInstance
);
NTSTATUS PiProcessDriverInstance(
IN PUNICODE_STRING DeviceInstancePath,
IN PUNICODE_STRING ServiceName,
IN ULONG ServiceType,
IN PPROCESS_DRIVER_CONTEXT Context
);
NTSTATUS
PpForEachDeviceInstanceDriver(
PUNICODE_STRING DeviceInstancePath,
PDEVICE_SERVICE_ITERATOR_ROUTINE IteratorRoutine,
PVOID Context
);
NTSTATUS
PiForEachDriverQueryRoutine(
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PDEVICE_SERVICE_ITERATOR_CONTEXT InternalContext,
IN ULONG ServiceType
);
VOID
PiRearrangeDeviceInstances(
IN HANDLE ServiceEnumHandle,
IN ULONG InstanceCount,
IN ULONG InstanceDeleted
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, PpDeviceRegistration)
#pragma alloc_text(PAGE, PiDeviceRegistration)
#pragma alloc_text(PAGE, PiProcessDriverInstance)
#pragma alloc_text(PAGE, PiFindDevInstMatch)
#pragma alloc_text(PAGE, PpForEachDeviceInstanceDriver)
#pragma alloc_text(PAGE, PiForEachDriverQueryRoutine)
#pragma alloc_text(PAGE, PiRearrangeDeviceInstances)
#endif // ALLOC_PRAGMA
NTSTATUS
PpDeviceRegistration(
IN PUNICODE_STRING DeviceInstancePath,
IN BOOLEAN Add,
IN PUNICODE_STRING ServiceKeyName OPTIONAL
)
/*++
Routine Description:
If Add is set to TRUE, this Plug and Play Manager API creates (if necessary)
and populates the volatile Enum subkey of a device's service list entry, based
on the device instance path specified. If Add is set to FALSE, the specified
device instance will be removed from the volatile Enum subkey of a device's
service list entry.
For example, if there is a device in the Enum tree as follows:
HKLM\System\Enum\PCI
\foo
\0000
Service = REG_SZ bar
\0001
Service = REG_SZ other
The result of the call, PpDeviceRegistration("PCI\foo\0000", Add = TRUE), would be:
HKLM\CurrentControlSet\Services
\bar
\Enum
Count = REG_DWORD 1
0 = REG_SZ PCI\foo\0000
Arguments:
DeviceInstancePath - Supplies the path in the registry (relative to
HKLM\CCS\System\Enum) of the device to be registered/deregistered.
This path must point to an instance subkey.
Add - Supplies a BOOLEAN value to indicate the operation is for addition or removal.
ServiceKeyName - Optionally, supplies the address of a unicode string to
receive the name of the registry key for this device
instance's service (if one exists). The caller must
release the space once done with it.
Return Value:
NTSTATUS code indicating whether or not the function was successful
--*/
{
NTSTATUS Status;
PAGED_CODE();
//
// Acquire PnP device-specific registry resource for exclusive (read/write) access.
//
PiLockPnpRegistry(TRUE);
Status = PiDeviceRegistration(DeviceInstancePath,
Add,
ServiceKeyName);
PiUnlockPnpRegistry();
return Status;
}
NTSTATUS
PiDeviceRegistration(
IN PUNICODE_STRING DeviceInstancePath,
IN BOOLEAN Add,
IN PUNICODE_STRING ServiceKeyName OPTIONAL
)
/*++
Routine Description:
If Add is set to TRUE, this Plug and Play Manager API creates (if necessary)
and populates the volatile Enum subkey of a device's service list entry, based
on the device instance path specified. If Add is set to FALSE, the specified
device instance will be removed from the volatile Enum subkey of a device's
service list entry.
For example, if there is a device in the Enum tree as follows:
HKLM\System\Enum\PCI
\foo
\0000
Service = REG_SZ bar
\0001
Service = REG_SZ other
The result of the call, PpDeviceRegistration("PCI\foo\0000", Add = TRUE), would be:
HKLM\CurrentControlSet\Services
\bar
\Enum
Count = REG_DWORD 1
0 = REG_SZ PCI\foo\0000
Arguments:
DeviceInstancePath - Supplies the path in the registry (relative to
HKLM\CCS\System\Enum) of the device to be registered/deregistered.
This path must point to an instance subkey.
Add - Supplies a BOOLEAN value to indicate the operation is for addition or removal.
ServiceKeyName - Optionally, supplies the address of a unicode string to
receive the name of the registry key for this device
instance's service (if one exists). The caller must
release the space once done with it.
Return Value:
NTSTATUS code indicating whether or not the function was successful
--*/
{
NTSTATUS Status;
UNICODE_STRING ServiceName;
PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
HANDLE TempKeyHandle;
HANDLE DeviceInstanceHandle = NULL;
PAGED_CODE();
//
// Assume successful completion.
//
Status = STATUS_SUCCESS;
if (ServiceKeyName) {
PiWstrToUnicodeString(ServiceKeyName, NULL);
}
//
// 'Normalize' the DeviceInstancePath by stripping off a trailing
// backslash (if present)
//
if (DeviceInstancePath->Length <= sizeof(WCHAR)) {
Status = STATUS_INVALID_PARAMETER;
goto PrepareForReturn1;
}
if (DeviceInstancePath->Buffer[CB_TO_CWC(DeviceInstancePath->Length) - 1] ==
OBJ_NAME_PATH_SEPARATOR) {
DeviceInstancePath->Length -= sizeof(WCHAR);
}
//
// Open HKLM\System\CurrentControlSet\Enum
//
Status = IopOpenRegistryKeyEx( &TempKeyHandle,
NULL,
&CmRegistryMachineSystemCurrentControlSetEnumName,
KEY_READ
);
if(!NT_SUCCESS(Status)) {
goto PrepareForReturn1;
}
//
// Open the specified device instance key under HKLM\CCS\System\Enum
//
Status = IopOpenRegistryKeyEx( &DeviceInstanceHandle,
TempKeyHandle,
DeviceInstancePath,
KEY_READ
);
ZwClose(TempKeyHandle);
if(!NT_SUCCESS(Status)) {
goto PrepareForReturn1;
}
//
// Read Service= value entry of the specified device instance key.
//
Status = IopGetRegistryValue(DeviceInstanceHandle,
REGSTR_VALUE_SERVICE,
&KeyValueInformation
);
ZwClose(DeviceInstanceHandle);
if (NT_SUCCESS(Status)) {
Status = STATUS_OBJECT_NAME_NOT_FOUND;
if (KeyValueInformation->Type == REG_SZ) {
if (KeyValueInformation->DataLength > sizeof(UNICODE_NULL)) {
IopRegistryDataToUnicodeString(&ServiceName,
(PWSTR)KEY_VALUE_DATA(KeyValueInformation),
KeyValueInformation->DataLength
);
Status = STATUS_SUCCESS;
if (ServiceKeyName) {
//
// If need to return ServiceKeyName, make a copy now.
//
Status = PipConcatenateUnicodeStrings( ServiceKeyName,
&ServiceName,
NULL);
}
}
}
ExFreePool(KeyValueInformation);
} else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
//
// The device instance key may have no Service value entry if the device
// is raw capable.
//
Status = STATUS_SUCCESS;
goto PrepareForReturn1;
}
if (NT_SUCCESS(Status)) {
PROCESS_DRIVER_CONTEXT context;
context.Add = Add;
Status = PpForEachDeviceInstanceDriver(
DeviceInstancePath,
(PDEVICE_SERVICE_ITERATOR_ROUTINE) PiProcessDriverInstance,
&context);
if(!NT_SUCCESS(Status) && Add) {
context.Add = FALSE;
PpForEachDeviceInstanceDriver(DeviceInstancePath,
PiProcessDriverInstance,
&context);
}
}
PrepareForReturn1:
if (!NT_SUCCESS(Status)) {
if (ServiceKeyName) {
if (ServiceKeyName->Length != 0) {
ExFreePool(ServiceKeyName->Buffer);
ServiceKeyName->Buffer = NULL;
ServiceKeyName->Length = ServiceKeyName->MaximumLength = 0;
}
}
}
return Status;
}
NTSTATUS
PiProcessDriverInstance(
IN PUNICODE_STRING DeviceInstancePath,
IN PUNICODE_STRING ServiceName,
IN ULONG ServiceType,
IN PPROCESS_DRIVER_CONTEXT Context
)
{
NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND;
PKEY_VALUE_FULL_INFORMATION KeyValueInformation = NULL;
HANDLE ServiceEnumHandle;
UNICODE_STRING MatchingDeviceInstance;
UNICODE_STRING TempUnicodeString;
CHAR UnicodeBuffer[20];
BOOLEAN UpdateCount = FALSE;
ULONG Count, instance;
UNREFERENCED_PARAMETER( ServiceType );
PAGED_CODE();
ASSERT(Context != NULL);
//
// Next, open the service entry, and volatile Enum subkey
// under HKLM\System\CurrentControlSet\Services (creating it if it
// doesn't exist)
//
Status = PipOpenServiceEnumKeys(ServiceName,
KEY_ALL_ACCESS,
NULL,
&ServiceEnumHandle,
TRUE
);
if(!NT_SUCCESS(Status)) {
goto PrepareForReturn2;
}
//
// Now, search through the service's existing list of device instances, to see
// if this instance has previously been registered.
//
Status = PiFindDevInstMatch(ServiceEnumHandle,
DeviceInstancePath,
&Count,
&MatchingDeviceInstance,
&instance
);
if (!NT_SUCCESS(Status)) {
goto PrepareForReturn3;
}
if (!MatchingDeviceInstance.Buffer) {
//
// If we didn't find a match and caller wants to register the device, then we add
// this instance to the service's Enum list.
//
if (Context->Add) {
PWSTR instancePathBuffer;
ULONG instancePathLength;
PWSTR freeBuffer = NULL;
//
// Create the value entry and update NextInstance= for the madeup key
//
instancePathBuffer = DeviceInstancePath->Buffer;
instancePathLength = DeviceInstancePath->Length;
if (instancePathBuffer[instancePathLength / sizeof(WCHAR) - 1] !=
UNICODE_NULL) {
freeBuffer = (PWSTR)ExAllocatePool(PagedPool, instancePathLength + sizeof(WCHAR));
if (freeBuffer) {
RtlCopyMemory(freeBuffer,
instancePathBuffer,
instancePathLength
);
freeBuffer[instancePathLength / sizeof(WCHAR)] = UNICODE_NULL;
instancePathBuffer = freeBuffer;
instancePathLength += sizeof(WCHAR);
}
}
PiUlongToUnicodeString(&TempUnicodeString, UnicodeBuffer, 20, Count);
Status = ZwSetValueKey(
ServiceEnumHandle,
&TempUnicodeString,
TITLE_INDEX_VALUE,
REG_SZ,
instancePathBuffer,
instancePathLength
);
if (freeBuffer) {
ExFreePool(freeBuffer);
}
Count++;
UpdateCount = TRUE;
}
} else {
//
// If we did find a match and caller wants to deregister the device, then we remove
// this instance from the service's Enum list.
//
ASSERT(instance != (ULONG)-1);
if (Context->Add == FALSE) {
ZwDeleteValueKey(ServiceEnumHandle, &MatchingDeviceInstance);
Count--;
UpdateCount = TRUE;
//
// Finally, if Count is not zero we need to physically reorganize the
// instances under the ServiceKey\Enum key to make them contiguous. We
// optimize by simply moving the last value into the empty slot. This behavior
// is different for .Net Server release from previous releases but we hope
// that no one depends on the ordering of values in this list. This list in a
// way really represents the order in which devices (using this service) were
// enumerated.
//
if (Count != 0) {
PiRearrangeDeviceInstances(
ServiceEnumHandle,
Count,
instance
);
}
}
}
if (UpdateCount) {
PiWstrToUnicodeString(&TempUnicodeString, REGSTR_VALUE_COUNT);
ZwSetValueKey(
ServiceEnumHandle,
&TempUnicodeString,
TITLE_INDEX_VALUE,
REG_DWORD,
&Count,
sizeof(Count)
);
PiWstrToUnicodeString(&TempUnicodeString, REGSTR_VALUE_NEXT_INSTANCE);
ZwSetValueKey(
ServiceEnumHandle,
&TempUnicodeString,
TITLE_INDEX_VALUE,
REG_DWORD,
&Count,
sizeof(Count)
);
}
//
// Need to release the matching device value name
//
if (MatchingDeviceInstance.Buffer) {
RtlFreeUnicodeString(&MatchingDeviceInstance);
}
Status = STATUS_SUCCESS;
PrepareForReturn3:
ZwClose(ServiceEnumHandle);
PrepareForReturn2:
if (KeyValueInformation) {
ExFreePool(KeyValueInformation);
}
return Status;
}
NTSTATUS
PiFindDevInstMatch(
IN HANDLE ServiceEnumHandle,
IN PUNICODE_STRING DeviceInstanceName,
OUT PULONG Count,
OUT PUNICODE_STRING MatchingValueName,
OUT PULONG MatchingInstance
)
/*++
Routine Description:
This routine searches through the specified Service\Enum values entries
for a device instance matching the one specified by KeyInformation.
If a matching is found, the MatchingValueName is returned and caller must
free the unicode string when done with it.
Arguments:
ServiceEnumHandle - Supplies a handle to service enum key.
DeviceInstanceName - Supplies a pointer to a unicode string specifying the
name of the device instance key to search for.
InstanceCount - Supplies a pointer to a ULONG variable to receive the device
instance count under the service enum key.
MatchingNameFound - Supplies a pointer to a UNICODE_STRING to receive the value
name of the matched device instance.
Return Value:
A NTSTATUS code. if a matching is found, the MatchingValueName is the unicode
string of the value name. Otherwise its length and Buffer will be set to empty.
--*/
{
NTSTATUS status;
ULONG i, instanceCount, length = 256, junk;
UNICODE_STRING valueName, unicodeValue;
PWCHAR unicodeBuffer;
PKEY_VALUE_FULL_INFORMATION keyValueInformation = NULL;
PAGED_CODE();
//
// Find out how many instances are referenced in the service's Enum key.
//
MatchingValueName->Length = 0;
MatchingValueName->Buffer = NULL;
*Count = instanceCount = 0;
*MatchingInstance = (ULONG)-1;
status = IopGetRegistryValue(ServiceEnumHandle,
REGSTR_VALUE_COUNT,
&keyValueInformation
);
if (NT_SUCCESS(status)) {
if((keyValueInformation->Type == REG_DWORD) &&
(keyValueInformation->DataLength >= sizeof(ULONG))) {
instanceCount = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
*Count = instanceCount;
}
ExFreePool(keyValueInformation);
} else if(status != STATUS_OBJECT_NAME_NOT_FOUND) {
return status;
} else {
//
// If 'Count' value entry not found, consider this to mean there are simply
// no device instance controlled by this service. Thus we don't have a match.
//
return STATUS_SUCCESS;
}
keyValueInformation = (PKEY_VALUE_FULL_INFORMATION)ExAllocatePool(
PagedPool, length);
if (!keyValueInformation) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Allocate heap to store value name
//
unicodeBuffer = (PWSTR)ExAllocatePool(PagedPool, 10 * sizeof(WCHAR));
if (!unicodeBuffer) {
ExFreePool(keyValueInformation);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Next scan thru each value key to find a match
//
for (i = 0; i < instanceCount ; i++) {
PiUlongToUnicodeString(&valueName, unicodeBuffer, 20, i);
status = ZwQueryValueKey (
ServiceEnumHandle,
&valueName,
KeyValueFullInformation,
keyValueInformation,
length,
&junk
);
if (!NT_SUCCESS(status)) {
if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL) {
ExFreePool(keyValueInformation);
length = junk;
keyValueInformation = (PKEY_VALUE_FULL_INFORMATION)ExAllocatePool(
PagedPool, length);
if (!keyValueInformation) {
ExFreePool(unicodeBuffer);
return STATUS_INSUFFICIENT_RESOURCES;
}
i--;
}
continue;
}
if (keyValueInformation->Type == REG_SZ) {
if (keyValueInformation->DataLength > sizeof(UNICODE_NULL)) {
IopRegistryDataToUnicodeString(&unicodeValue,
(PWSTR)KEY_VALUE_DATA(keyValueInformation),
keyValueInformation->DataLength
);
} else {
continue;
}
} else {
continue;
}
if (RtlEqualUnicodeString(&unicodeValue,
DeviceInstanceName,
TRUE)) {
//
// We found a match.
//
*MatchingValueName= valueName;
*MatchingInstance = i;
break;
}
}
if (keyValueInformation) {
ExFreePool(keyValueInformation);
}
if (MatchingValueName->Length == 0) {
//
// If we did not find a match, we need to release the buffer. Otherwise
// it is caller's responsibility to release the buffer.
//
ExFreePool(unicodeBuffer);
}
return STATUS_SUCCESS;
}
NTSTATUS
PpForEachDeviceInstanceDriver(
PUNICODE_STRING DeviceInstancePath,
PDEVICE_SERVICE_ITERATOR_ROUTINE IteratorRoutine,
PVOID Context
)
/*++
Routine Description:
This routine will call the iterator routine once for each driver listed
for this particular device instance. It will walk through any class
filter drivers and device filter drivers, as well as the service, in the
order they will be added to the PDO. If the iterator routine returns
a failure status at any point the iteration will be terminated.
Arguments:
DeviceInstancePath - the registry path (relative to CCS\Enum)
IteratorRoutine - the routine to be called for each service. This routine
will be passed:
* The device instance path
* The type of driver that this is (filter, service, etc.)
* the Context value passed in
* The name of the service
Context - an arbitrary context passed into the iterator routine
Return Value:
STATUS_SUCCCESS if everything was run across properly
status if an error occurred opening critical keys or if the iterator
routine returns an error.
--*/
{
HANDLE enumKey,instanceKey, classKey, controlKey;
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
DEVICE_SERVICE_ITERATOR_CONTEXT internalContext;
RTL_QUERY_REGISTRY_TABLE queryTable[4];
NTSTATUS status;
UNICODE_STRING unicodeClassGuid;
PAGED_CODE();
//
// Open the HKLM\System\CCS\Enum key.
//
status = IopOpenRegistryKeyEx( &enumKey,
NULL,
&CmRegistryMachineSystemCurrentControlSetEnumName,
KEY_READ
);
if (!NT_SUCCESS(status)) {
return status;
}
//
// Open the instance key for this devnode
//
status = IopOpenRegistryKeyEx( &instanceKey,
enumKey,
DeviceInstancePath,
KEY_READ
);
ZwClose(enumKey);
if(!NT_SUCCESS(status)) {
return status;
}
classKey = NULL;
status = IopGetRegistryValue(instanceKey,
REGSTR_VALUE_CLASSGUID,
&keyValueInformation);
if(NT_SUCCESS(status)) {
if ( keyValueInformation->Type == REG_SZ &&
keyValueInformation->DataLength) {
IopRegistryDataToUnicodeString(
&unicodeClassGuid,
(PWSTR) KEY_VALUE_DATA(keyValueInformation),
keyValueInformation->DataLength);
//
// Open the class key
//
status = IopOpenRegistryKeyEx( &controlKey,
NULL,
&CmRegistryMachineSystemCurrentControlSetControlClass,
KEY_READ
);
if(NT_SUCCESS(status)) {
status = IopOpenRegistryKeyEx( &classKey,
controlKey,
&unicodeClassGuid,
KEY_READ
);
ZwClose(controlKey);
}
}
ExFreePool(keyValueInformation);
keyValueInformation = NULL;
}
//
// For each type of filter driver we want to query for the list and
// call into our callback routine. We should do this in order from
// bottom to top.
//
internalContext.Context = Context;
internalContext.DeviceInstancePath = DeviceInstancePath;
internalContext.Iterator = IteratorRoutine;
//
// First get all the information we have to out of the instance key and
// the device node.
//
if(classKey != NULL) {
RtlZeroMemory(queryTable, sizeof(queryTable));
queryTable[0].QueryRoutine =
(PRTL_QUERY_REGISTRY_ROUTINE) PiForEachDriverQueryRoutine;
queryTable[0].Name = REGSTR_VAL_LOWERFILTERS;
queryTable[0].EntryContext = (PVOID) 0;
status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
(PWSTR) classKey,
queryTable,
&internalContext,
NULL);
if(!NT_SUCCESS(status)) {
goto PrepareForReturn;
}
}
RtlZeroMemory(queryTable, sizeof(queryTable));
queryTable[0].QueryRoutine =
(PRTL_QUERY_REGISTRY_ROUTINE) PiForEachDriverQueryRoutine;
queryTable[0].Name = REGSTR_VAL_LOWERFILTERS;
queryTable[0].EntryContext = (PVOID) 1;
queryTable[1].QueryRoutine =
(PRTL_QUERY_REGISTRY_ROUTINE) PiForEachDriverQueryRoutine;
queryTable[1].Name = REGSTR_VAL_SERVICE;
queryTable[1].EntryContext = (PVOID) 2;
queryTable[2].QueryRoutine =
(PRTL_QUERY_REGISTRY_ROUTINE) PiForEachDriverQueryRoutine;
queryTable[2].Name = REGSTR_VAL_UPPERFILTERS;
queryTable[2].EntryContext = (PVOID) 3;
status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
(PWSTR) instanceKey,
queryTable,
&internalContext,
NULL);
if(!NT_SUCCESS(status)) {
goto PrepareForReturn;
}
if(classKey != NULL) {
RtlZeroMemory(queryTable, sizeof(queryTable));
queryTable[0].QueryRoutine =
(PRTL_QUERY_REGISTRY_ROUTINE) PiForEachDriverQueryRoutine;
queryTable[0].Name = REGSTR_VAL_UPPERFILTERS;
queryTable[0].EntryContext = (PVOID) 4;
status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
(PWSTR) classKey,
queryTable,
&internalContext,
NULL);
if(!NT_SUCCESS(status)) {
goto PrepareForReturn;
}
}
PrepareForReturn:
if(classKey != NULL) {
ZwClose(classKey);
}
ZwClose(instanceKey);
return status;
}
NTSTATUS
PiForEachDriverQueryRoutine(
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PDEVICE_SERVICE_ITERATOR_CONTEXT InternalContext,
IN ULONG ServiceType
)
{
UNICODE_STRING ServiceName;
UNREFERENCED_PARAMETER( ValueName );
if (ValueType != REG_SZ) {
return STATUS_SUCCESS;
}
//
// Make sure the string is a reasonable length.
// copied directly from IopCallDriverAddDeviceQueryRoutine
//
if (ValueLength <= sizeof(WCHAR)) {
return STATUS_SUCCESS;
}
RtlInitUnicodeString(&ServiceName, ValueData);
return InternalContext->Iterator(
InternalContext->DeviceInstancePath,
&ServiceName,
ServiceType,
InternalContext->Context);
}
VOID
PiRearrangeDeviceInstances(
IN HANDLE ServiceEnumHandle,
IN ULONG InstanceCount,
IN ULONG InstanceDeleted
)
{
NTSTATUS Status;
PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
CHAR UnicodeBuffer[20];
UNICODE_STRING TempUnicodeString;
ULONG i, j, junk, maxCount;
BOOLEAN PreserveOrdering;
KEY_FULL_INFORMATION keyInfo;
ULONG tmp;
PAGED_CODE();
KeyValueInformation = NULL;
PreserveOrdering = TRUE;
maxCount = 0x200;
Status = ZwQueryKey(
ServiceEnumHandle,
KeyFullInformation,
&keyInfo,
sizeof(keyInfo),
&tmp
);
if (NT_SUCCESS(Status) && keyInfo.Values) {
maxCount = keyInfo.Values;
if (maxCount > 28) {
PreserveOrdering = FALSE;
}
}
if (PreserveOrdering == FALSE) {
//
// Read the last value.
//
PiUlongToUnicodeString(&TempUnicodeString, UnicodeBuffer, 20, InstanceCount);
Status = IopGetRegistryValue(ServiceEnumHandle,
TempUnicodeString.Buffer,
&KeyValueInformation
);
if (NT_SUCCESS(Status)) {
//
// Delete the last value.
//
ZwDeleteValueKey(ServiceEnumHandle, &TempUnicodeString);
//
// Set the new value with the instance we just deleted above..
//
PiUlongToUnicodeString(&TempUnicodeString, UnicodeBuffer, 20, InstanceDeleted);
ZwSetValueKey (ServiceEnumHandle,
&TempUnicodeString,
TITLE_INDEX_VALUE,
REG_SZ,
(PVOID)KEY_VALUE_DATA(KeyValueInformation),
KeyValueInformation->DataLength
);
ExFreePool(KeyValueInformation);
KeyValueInformation = NULL;
}
} else {
i = j = 0;
while (j < InstanceCount && i < maxCount) {
PiUlongToUnicodeString(&TempUnicodeString, UnicodeBuffer, 20, i);
Status = ZwQueryValueKey(
ServiceEnumHandle,
&TempUnicodeString,
KeyValueFullInformation,
(PVOID)NULL,
0,
&junk
);
if ((Status != STATUS_OBJECT_NAME_NOT_FOUND) && (Status != STATUS_OBJECT_PATH_NOT_FOUND)) {
if (i != j) {
//
// Need to change the instance i to instance j
//
Status = IopGetRegistryValue(
ServiceEnumHandle,
TempUnicodeString.Buffer,
&KeyValueInformation
);
if (NT_SUCCESS(Status)) {
ZwDeleteValueKey(ServiceEnumHandle, &TempUnicodeString);
PiUlongToUnicodeString(&TempUnicodeString, UnicodeBuffer, 20, j);
ZwSetValueKey(
ServiceEnumHandle,
&TempUnicodeString,
TITLE_INDEX_VALUE,
REG_SZ,
(PVOID)KEY_VALUE_DATA(KeyValueInformation),
KeyValueInformation->DataLength
);
ExFreePool(KeyValueInformation);
KeyValueInformation = NULL;
} else {
IopDbgPrint((
IOP_WARNING_LEVEL,
"PiRearrangeDeviceInstances: Failed to rearrange device instances %x\n",
Status
));
break;
}
}
j++;
}
i++;
}
}
//
// Cleanup.
//
if (KeyValueInformation) {
ExFreePool(KeyValueInformation);
}
}