Use a list to store linked hives.

Enable enumeration of linked hive root keys.
Patch partially written by Filip Navara.

svn path=/trunk/; revision=7510
This commit is contained in:
Eric Kohl 2004-01-08 15:02:45 +00:00
parent f35801a5a9
commit 0dd0b373bc
5 changed files with 307 additions and 158 deletions

View file

@ -199,7 +199,13 @@ typedef struct _KEY_CELL
/* /*
* Hash record * Hash record
* *
* HashValue : * KeyOffset:
* The least significant bit is used to distinguish
* between real key offsets and pointers to registry hives:
* 0 : offset
* 1 : pointer to registry hive
*
* HashValue:
* packed name: four letters of value's name * packed name: four letters of value's name
* otherwise: Zero! * otherwise: Zero!
*/ */
@ -297,6 +303,18 @@ typedef struct _REGISTRY_HIVE
#define IsUsedCell(Cell)(Cell->CellSize < 0) #define IsUsedCell(Cell)(Cell->CellSize < 0)
typedef struct _HIVE_LINK
{
LIST_ENTRY Entry;
PREGISTRY_HIVE ParentKeyRegistryHive;
BLOCK_OFFSET ParentKeyCellOffset;
PREGISTRY_HIVE SubKeyRegistryHive;
BLOCK_OFFSET SubKeyCellOffset;
} HIVE_LINK, *PHIVE_LINK;
/* KEY_OBJECT.Flags */ /* KEY_OBJECT.Flags */
/* When set, the key is scheduled for deletion, and all /* When set, the key is scheduled for deletion, and all
@ -352,6 +370,7 @@ extern PREGISTRY_HIVE CmiVolatileHive;
extern POBJECT_TYPE CmiKeyType; extern POBJECT_TYPE CmiKeyType;
extern KSPIN_LOCK CmiKeyListLock; extern KSPIN_LOCK CmiKeyListLock;
extern LIST_ENTRY CmiHiveLinkListHead;
extern LIST_ENTRY CmiHiveListHead; extern LIST_ENTRY CmiHiveListHead;
extern ERESOURCE CmiHiveListLock; extern ERESOURCE CmiHiveListLock;
@ -472,12 +491,13 @@ CmiGetMaxValueDataLength(IN PREGISTRY_HIVE RegistryHive,
IN PKEY_CELL KeyCell); IN PKEY_CELL KeyCell);
NTSTATUS NTSTATUS
CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive, CmiScanForSubKey(IN PREGISTRY_HIVE ParentKeyRegistryHive,
IN PKEY_CELL KeyCell, IN PKEY_CELL ParentKeyCell,
OUT PKEY_CELL *SubKeyCell, OUT PREGISTRY_HIVE *SubKeyRegistryHive,
OUT BLOCK_OFFSET *BlockOffset, OUT PKEY_CELL *SubKeyCell,
OUT BLOCK_OFFSET *SubKeyCellOffset,
IN PUNICODE_STRING KeyName, IN PUNICODE_STRING KeyName,
IN ACCESS_MASK DesiredAccess, IN ACCESS_MASK DesiredAccess,
IN ULONG Attributes); IN ULONG Attributes);
NTSTATUS NTSTATUS
@ -521,22 +541,23 @@ CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive,
IN PUNICODE_STRING ValueName); IN PUNICODE_STRING ValueName);
NTSTATUS NTSTATUS
CmiAllocateHashTableCell(IN PREGISTRY_HIVE RegistryHive, CmiAllocateHashTableCell(IN PREGISTRY_HIVE RegistryHive,
OUT PHASH_TABLE_CELL *HashBlock, OUT PHASH_TABLE_CELL *HashCell,
OUT BLOCK_OFFSET *HBOffset, OUT BLOCK_OFFSET *HBOffset,
IN ULONG HashTableSize); IN ULONG HashTableSize);
PKEY_CELL PKEY_CELL
CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive, CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive,
PHASH_TABLE_CELL HashBlock, PHASH_TABLE_CELL HashCell,
ULONG Index); ULONG Index);
NTSTATUS NTSTATUS
CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive, CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive,
PHASH_TABLE_CELL HashCell, PKEY_CELL ParentKeyCell,
BLOCK_OFFSET HashCellOffset, BLOCK_OFFSET ParentKeyCellOffset,
PKEY_CELL NewKeyCell, PREGISTRY_HIVE NewKeyRegistryHive,
BLOCK_OFFSET NKBOffset); PKEY_CELL NewKeyCell,
BLOCK_OFFSET NewKeyCellOffset);
NTSTATUS NTSTATUS
CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive, CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive,

View file

@ -275,7 +275,7 @@ NtEnumerateKey(IN HANDLE KeyHandle,
PKEY_OBJECT KeyObject; PKEY_OBJECT KeyObject;
PREGISTRY_HIVE RegistryHive; PREGISTRY_HIVE RegistryHive;
PKEY_CELL KeyCell, SubKeyCell; PKEY_CELL KeyCell, SubKeyCell;
PHASH_TABLE_CELL HashTableBlock; PHASH_TABLE_CELL HashTableCell;
PKEY_BASIC_INFORMATION BasicInformation; PKEY_BASIC_INFORMATION BasicInformation;
PKEY_NODE_INFORMATION NodeInformation; PKEY_NODE_INFORMATION NodeInformation;
PKEY_FULL_INFORMATION FullInformation; PKEY_FULL_INFORMATION FullInformation;
@ -317,38 +317,17 @@ NtEnumerateKey(IN HANDLE KeyHandle,
/* Get pointer to SubKey */ /* Get pointer to SubKey */
if (Index >= KeyCell->NumberOfSubKeys) if (Index >= KeyCell->NumberOfSubKeys)
{ {
if (RegistryHive == CmiVolatileHive) if (Index >= KeyObject->NumberOfSubKeys)
{ {
ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource); ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
KeLeaveCriticalRegion(); KeLeaveCriticalRegion();
ObDereferenceObject(KeyObject); ObDereferenceObject(KeyObject);
DPRINT("No more volatile entries\n"); DPRINT("No more volatile entries\n");
return(STATUS_NO_MORE_ENTRIES); return(STATUS_NO_MORE_ENTRIES);
} }
else else
{ {
ULONG i; SubKeyCell = KeyObject->SubKeys[Index]->KeyCell;
PKEY_OBJECT CurKey = NULL;
/* Search volatile keys */
for (i = 0; i < KeyObject->NumberOfSubKeys; i++)
{
CurKey = KeyObject->SubKeys[i];
if (CurKey->RegistryHive == CmiVolatileHive)
{
if (Index-- == KeyCell->NumberOfSubKeys)
break;
}
}
if (Index >= KeyCell->NumberOfSubKeys)
{
ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
KeLeaveCriticalRegion();
ObDereferenceObject(KeyObject);
DPRINT("No more non-volatile entries\n");
return(STATUS_NO_MORE_ENTRIES);
}
SubKeyCell = CurKey->KeyCell;
} }
} }
else else
@ -356,25 +335,27 @@ NtEnumerateKey(IN HANDLE KeyHandle,
if (KeyCell->HashTableOffset == (BLOCK_OFFSET)-1) if (KeyCell->HashTableOffset == (BLOCK_OFFSET)-1)
{ {
ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource); ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
KeLeaveCriticalRegion(); KeLeaveCriticalRegion();
ObDereferenceObject(KeyObject); ObDereferenceObject(KeyObject);
return(STATUS_NO_MORE_ENTRIES); return(STATUS_NO_MORE_ENTRIES);
} }
HashTableBlock = CmiGetCell (RegistryHive, KeyCell->HashTableOffset, NULL); HashTableCell = CmiGetCell (RegistryHive, KeyCell->HashTableOffset, NULL);
if (HashTableBlock == NULL) if (HashTableCell == NULL)
{ {
DPRINT("CmiGetBlock() failed\n"); DPRINT("CmiGetBlock() failed\n");
ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource); ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
KeLeaveCriticalRegion(); KeLeaveCriticalRegion();
ObDereferenceObject(KeyObject); ObDereferenceObject(KeyObject);
return STATUS_UNSUCCESSFUL; return STATUS_UNSUCCESSFUL;
} }
SubKeyCell = CmiGetKeyFromHashByIndex(RegistryHive, SubKeyCell = CmiGetKeyFromHashByIndex(RegistryHive,
HashTableBlock, HashTableCell,
Index); Index);
} }
DPRINT("SubKeyCell %p\n", SubKeyCell);
if (SubKeyCell == NULL) if (SubKeyCell == NULL)
{ {
ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource); ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);

View file

@ -2262,19 +2262,21 @@ CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive,
NTSTATUS NTSTATUS
CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive, CmiScanForSubKey(IN PREGISTRY_HIVE ParentKeyRegistryHive,
IN PKEY_CELL KeyCell, IN PKEY_CELL ParentKeyCell,
OUT PREGISTRY_HIVE *SubKeyRegistryHive,
OUT PKEY_CELL *SubKeyCell, OUT PKEY_CELL *SubKeyCell,
OUT BLOCK_OFFSET *BlockOffset, OUT BLOCK_OFFSET *SubKeyCellOffset,
IN PUNICODE_STRING KeyName, IN PUNICODE_STRING KeyName,
IN ACCESS_MASK DesiredAccess, IN ACCESS_MASK DesiredAccess,
IN ULONG Attributes) IN ULONG Attributes)
{ {
PHASH_TABLE_CELL HashBlock; PHASH_TABLE_CELL HashCell;
PKEY_CELL CurSubKeyCell; PKEY_CELL CurSubKeyCell;
PHIVE_LINK HiveLink;
ULONG i; ULONG i;
VERIFY_KEY_CELL(KeyCell); VERIFY_KEY_CELL(ParentKeyCell);
DPRINT("Scanning for sub key %wZ\n", KeyName); DPRINT("Scanning for sub key %wZ\n", KeyName);
@ -2283,66 +2285,116 @@ CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive,
*SubKeyCell = NULL; *SubKeyCell = NULL;
/* The key does not have any subkeys */ /* The key does not have any subkeys */
if (KeyCell->HashTableOffset == (BLOCK_OFFSET)-1) if (ParentKeyCell->HashTableOffset == (BLOCK_OFFSET)-1)
{ {
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
/* Get hash table */ /* Get hash table */
HashBlock = CmiGetCell (RegistryHive, KeyCell->HashTableOffset, NULL); HashCell = CmiGetCell (ParentKeyRegistryHive, ParentKeyCell->HashTableOffset, NULL);
if (HashBlock == NULL) if (HashCell == NULL)
{ {
DPRINT("CmiGetBlock() failed\n"); DPRINT("CmiGetBlock() failed\n");
return STATUS_UNSUCCESSFUL; return STATUS_UNSUCCESSFUL;
} }
for (i = 0; (i < KeyCell->NumberOfSubKeys) && (i < HashBlock->HashTableSize); i++) for (i = 0; (i < ParentKeyCell->NumberOfSubKeys) && (i < HashCell->HashTableSize); i++)
{ {
if (Attributes & OBJ_CASE_INSENSITIVE) if (Attributes & OBJ_CASE_INSENSITIVE)
{ {
if (HashBlock->Table[i].KeyOffset != 0 && if (HashCell->Table[i].KeyOffset != 0 &&
HashBlock->Table[i].KeyOffset != (ULONG_PTR)-1 && HashCell->Table[i].KeyOffset != (ULONG_PTR)-1 &&
(HashBlock->Table[i].HashValue == 0 || (HashCell->Table[i].HashValue == 0 ||
CmiCompareHashI(KeyName, (PCHAR)&HashBlock->Table[i].HashValue))) CmiCompareHashI(KeyName, (PCHAR)&HashCell->Table[i].HashValue)))
{ {
CurSubKeyCell = CmiGetCell (RegistryHive, if (HashCell->Table[i].KeyOffset & 1)
HashBlock->Table[i].KeyOffset,
NULL);
if (CurSubKeyCell == NULL)
{ {
DPRINT("CmiGetBlock() failed\n"); HiveLink = (PHIVE_LINK)(HashCell->Table[i].KeyOffset & ~1);
return STATUS_UNSUCCESSFUL;
}
if (CmiCompareKeyNamesI(KeyName, CurSubKeyCell)) CurSubKeyCell = CmiGetCell (HiveLink->SubKeyRegistryHive,
HiveLink->SubKeyCellOffset,
NULL);
if (CurSubKeyCell == NULL)
{
DPRINT("CmiGetBlock() failed\n");
return STATUS_UNSUCCESSFUL;
}
if (CmiCompareKeyNamesI(KeyName, CurSubKeyCell))
{
*SubKeyRegistryHive = HiveLink->SubKeyRegistryHive;
*SubKeyCell = CurSubKeyCell;
*SubKeyCellOffset = HiveLink->SubKeyCellOffset;
break;
}
}
else
{ {
*SubKeyCell = CurSubKeyCell; CurSubKeyCell = CmiGetCell (ParentKeyRegistryHive,
*BlockOffset = HashBlock->Table[i].KeyOffset; HashCell->Table[i].KeyOffset,
break; NULL);
if (CurSubKeyCell == NULL)
{
DPRINT("CmiGetBlock() failed\n");
return STATUS_UNSUCCESSFUL;
}
if (CmiCompareKeyNamesI(KeyName, CurSubKeyCell))
{
*SubKeyRegistryHive = ParentKeyRegistryHive;
*SubKeyCell = CurSubKeyCell;
*SubKeyCellOffset = HashCell->Table[i].KeyOffset;
break;
}
} }
} }
} }
else else
{ {
if (HashBlock->Table[i].KeyOffset != 0 && if (HashCell->Table[i].KeyOffset != 0 &&
HashBlock->Table[i].KeyOffset != (ULONG_PTR) -1 && HashCell->Table[i].KeyOffset != (ULONG_PTR) -1 &&
(HashBlock->Table[i].HashValue == 0 || (HashCell->Table[i].HashValue == 0 ||
CmiCompareHash(KeyName, (PCHAR)&HashBlock->Table[i].HashValue))) CmiCompareHash(KeyName, (PCHAR)&HashCell->Table[i].HashValue)))
{ {
CurSubKeyCell = CmiGetCell (RegistryHive, if (HashCell->Table[i].KeyOffset & 1)
HashBlock->Table[i].KeyOffset,
NULL);
if (CurSubKeyCell == NULL)
{ {
DPRINT("CmiGetBlock() failed\n"); HiveLink = (PHIVE_LINK)(HashCell->Table[i].KeyOffset & ~1);
return STATUS_UNSUCCESSFUL;
}
if (CmiCompareKeyNames(KeyName, CurSubKeyCell)) CurSubKeyCell = CmiGetCell (HiveLink->SubKeyRegistryHive,
HiveLink->SubKeyCellOffset,
NULL);
if (CurSubKeyCell == NULL)
{
DPRINT("CmiGetBlock() failed\n");
return STATUS_UNSUCCESSFUL;
}
if (CmiCompareKeyNames(KeyName, CurSubKeyCell))
{
*SubKeyRegistryHive = HiveLink->SubKeyRegistryHive;
*SubKeyCell = CurSubKeyCell;
*SubKeyCellOffset = HiveLink->SubKeyCellOffset;
break;
}
}
else
{ {
*SubKeyCell = CurSubKeyCell; CurSubKeyCell = CmiGetCell (ParentKeyRegistryHive,
*BlockOffset = HashBlock->Table[i].KeyOffset; HashCell->Table[i].KeyOffset,
break; NULL);
if (CurSubKeyCell == NULL)
{
DPRINT("CmiGetBlock() failed\n");
return STATUS_UNSUCCESSFUL;
}
if (CmiCompareKeyNames(KeyName, CurSubKeyCell))
{
*SubKeyRegistryHive = ParentKeyRegistryHive;
*SubKeyCell = CurSubKeyCell;
*SubKeyCellOffset = HashCell->Table[i].KeyOffset;
break;
}
} }
} }
} }
@ -2361,7 +2413,6 @@ CmiAddSubKey(PREGISTRY_HIVE RegistryHive,
PUNICODE_STRING Class, PUNICODE_STRING Class,
ULONG CreateOptions) ULONG CreateOptions)
{ {
PHASH_TABLE_CELL HashBlock;
BLOCK_OFFSET NKBOffset; BLOCK_OFFSET NKBOffset;
PKEY_CELL NewKeyCell; PKEY_CELL NewKeyCell;
ULONG NewBlockSize; ULONG NewBlockSize;
@ -2478,69 +2529,19 @@ CmiAddSubKey(PREGISTRY_HIVE RegistryHive,
return(Status); return(Status);
} }
if (ParentKeyCell->HashTableOffset == (ULONG_PTR) -1) Status = CmiAddKeyToHashTable(ParentKey->RegistryHive,
{ ParentKeyCell,
Status = CmiAllocateHashTableCell (RegistryHive, ParentKey->KeyCellOffset,
&HashBlock, NULL,
&ParentKeyCell->HashTableOffset,
REG_INIT_HASH_TABLE_SIZE);
if (!NT_SUCCESS(Status))
{
return(Status);
}
}
else
{
HashBlock = CmiGetCell (RegistryHive,
ParentKeyCell->HashTableOffset,
NULL);
if (HashBlock == NULL)
{
DPRINT("CmiGetCell() failed\n");
return STATUS_UNSUCCESSFUL;
}
if (((ParentKeyCell->NumberOfSubKeys + 1) >= HashBlock->HashTableSize))
{
PHASH_TABLE_CELL NewHashBlock;
BLOCK_OFFSET HTOffset;
/* Reallocate the hash table cell */
Status = CmiAllocateHashTableCell (RegistryHive,
&NewHashBlock,
&HTOffset,
HashBlock->HashTableSize +
REG_EXTEND_HASH_TABLE_SIZE);
if (!NT_SUCCESS(Status))
{
return Status;
}
RtlZeroMemory(&NewHashBlock->Table[0],
sizeof(NewHashBlock->Table[0]) * NewHashBlock->HashTableSize);
RtlCopyMemory(&NewHashBlock->Table[0],
&HashBlock->Table[0],
sizeof(NewHashBlock->Table[0]) * HashBlock->HashTableSize);
CmiDestroyCell (RegistryHive,
HashBlock,
ParentKeyCell->HashTableOffset);
ParentKeyCell->HashTableOffset = HTOffset;
HashBlock = NewHashBlock;
}
}
Status = CmiAddKeyToHashTable(RegistryHive,
HashBlock,
ParentKeyCell->HashTableOffset,
NewKeyCell, NewKeyCell,
NKBOffset); NKBOffset);
if (NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
ParentKeyCell->NumberOfSubKeys++; return Status;
} }
NtQuerySystemTime (&ParentKeyCell->LastWriteTime); NtQuerySystemTime (&ParentKeyCell->LastWriteTime);
CmiMarkBlockDirty (RegistryHive, ParentKey->KeyCellOffset); CmiMarkBlockDirty (ParentKey->RegistryHive, ParentKey->KeyCellOffset);
return(Status); return(Status);
} }
@ -3005,22 +3006,30 @@ CmiAllocateHashTableCell (IN PREGISTRY_HIVE RegistryHive,
PKEY_CELL PKEY_CELL
CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive, CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive,
PHASH_TABLE_CELL HashBlock, PHASH_TABLE_CELL HashCell,
ULONG Index) ULONG Index)
{ {
BLOCK_OFFSET KeyOffset; BLOCK_OFFSET KeyOffset;
PHIVE_LINK HiveLink;
PKEY_CELL KeyCell; PKEY_CELL KeyCell;
if (HashBlock == NULL) if (HashCell == NULL)
return NULL; return NULL;
if (IsPointerHive(RegistryHive)) if (HashCell->Table[Index].KeyOffset & 1)
{ {
KeyCell = (PKEY_CELL) HashBlock->Table[Index].KeyOffset; HiveLink = (PHIVE_LINK)(HashCell->Table[Index].KeyOffset & ~1);
KeyCell = CmiGetCell (HiveLink->SubKeyRegistryHive,
HiveLink->SubKeyCellOffset,
NULL);
}
else if (IsPointerHive(RegistryHive))
{
KeyCell = (PKEY_CELL) HashCell->Table[Index].KeyOffset;
} }
else else
{ {
KeyOffset = HashBlock->Table[Index].KeyOffset; KeyOffset = HashCell->Table[Index].KeyOffset;
KeyCell = CmiGetCell (RegistryHive, KeyOffset, NULL); KeyCell = CmiGetCell (RegistryHive, KeyOffset, NULL);
} }
@ -3030,18 +3039,94 @@ CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive,
NTSTATUS NTSTATUS
CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive, CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive,
PHASH_TABLE_CELL HashCell, PKEY_CELL ParentKeyCell,
BLOCK_OFFSET HashCellOffset, BLOCK_OFFSET ParentKeyCellOffset,
PREGISTRY_HIVE NewKeyRegistryHive,
PKEY_CELL NewKeyCell, PKEY_CELL NewKeyCell,
BLOCK_OFFSET NKBOffset) BLOCK_OFFSET NewKeyCellOffset)
{ {
BLOCK_OFFSET HashCellOffset;
PHASH_TABLE_CELL HashCell;
ULONG i; ULONG i;
NTSTATUS Status;
if (ParentKeyCell->HashTableOffset == (ULONG_PTR) -1)
{
Status = CmiAllocateHashTableCell (RegistryHive,
&HashCell,
&ParentKeyCell->HashTableOffset,
REG_INIT_HASH_TABLE_SIZE);
if (!NT_SUCCESS(Status))
{
return(Status);
}
CmiMarkBlockDirty(RegistryHive, ParentKeyCellOffset);
}
else
{
HashCell = CmiGetCell (RegistryHive,
ParentKeyCell->HashTableOffset,
NULL);
if (HashCell == NULL)
{
DPRINT("CmiGetCell() failed\n");
return STATUS_UNSUCCESSFUL;
}
if (((ParentKeyCell->NumberOfSubKeys + 1) >= HashCell->HashTableSize))
{
PHASH_TABLE_CELL NewHashCell;
BLOCK_OFFSET NewHashCellOffset;
/* Reallocate the hash table cell */
Status = CmiAllocateHashTableCell (RegistryHive,
&NewHashCell,
&NewHashCellOffset,
HashCell->HashTableSize +
REG_EXTEND_HASH_TABLE_SIZE);
if (!NT_SUCCESS(Status))
{
return Status;
}
RtlZeroMemory(&NewHashCell->Table[0],
sizeof(NewHashCell->Table[0]) * NewHashCell->HashTableSize);
RtlCopyMemory(&NewHashCell->Table[0],
&HashCell->Table[0],
sizeof(NewHashCell->Table[0]) * HashCell->HashTableSize);
CmiDestroyCell (RegistryHive,
HashCell,
ParentKeyCell->HashTableOffset);
ParentKeyCell->HashTableOffset = NewHashCellOffset;
HashCell = NewHashCell;
CmiMarkBlockDirty(RegistryHive, ParentKeyCellOffset);
}
}
for (i = 0; i < HashCell->HashTableSize; i++) for (i = 0; i < HashCell->HashTableSize; i++)
{ {
if (HashCell->Table[i].KeyOffset == 0) if (HashCell->Table[i].KeyOffset == 0)
{ {
HashCell->Table[i].KeyOffset = NKBOffset; if (NewKeyRegistryHive != NULL && NewKeyRegistryHive != RegistryHive)
{
PHIVE_LINK HiveLink;
HiveLink = ExAllocatePool (NonPagedPool, sizeof(HIVE_LINK));
if (HiveLink == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
InsertTailList (&CmiHiveLinkListHead, &HiveLink->Entry);
HiveLink->ParentKeyRegistryHive = RegistryHive;
HiveLink->ParentKeyCellOffset = ParentKeyCellOffset;
HiveLink->SubKeyRegistryHive = NewKeyRegistryHive;
HiveLink->SubKeyCellOffset = NewKeyCellOffset;
HashCell->Table[i].KeyOffset = (BLOCK_OFFSET)((ULONG)HiveLink | 1);
}
else
{
HashCell->Table[i].KeyOffset = NewKeyCellOffset;
}
HashCell->Table[i].HashValue = 0; HashCell->Table[i].HashValue = 0;
if (NewKeyCell->Flags & REG_KEY_NAME_PACKED) if (NewKeyCell->Flags & REG_KEY_NAME_PACKED)
{ {
@ -3050,6 +3135,8 @@ CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive,
min(NewKeyCell->NameSize, sizeof(ULONG))); min(NewKeyCell->NameSize, sizeof(ULONG)));
} }
CmiMarkBlockDirty(RegistryHive, HashCellOffset); CmiMarkBlockDirty(RegistryHive, HashCellOffset);
ParentKeyCell->NumberOfSubKeys++;
CmiMarkBlockDirty(RegistryHive, ParentKeyCellOffset);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
} }

View file

@ -1,4 +1,4 @@
/* $Id: registry.c,v 1.116 2003/12/30 18:52:03 fireball Exp $ /* $Id: registry.c,v 1.117 2004/01/08 15:02:45 ekohl Exp $
* *
* COPYRIGHT: See COPYING in the top level directory * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel * PROJECT: ReactOS kernel
@ -31,6 +31,7 @@ POBJECT_TYPE CmiKeyType = NULL;
PREGISTRY_HIVE CmiVolatileHive = NULL; PREGISTRY_HIVE CmiVolatileHive = NULL;
KSPIN_LOCK CmiKeyListLock; KSPIN_LOCK CmiKeyListLock;
LIST_ENTRY CmiHiveLinkListHead;
LIST_ENTRY CmiHiveListHead; LIST_ENTRY CmiHiveListHead;
ERESOURCE CmiHiveListLock; ERESOURCE CmiHiveListLock;
@ -281,6 +282,9 @@ CmInitializeRegistry(VOID)
ObpCreateTypeObject (CmiKeyType); ObpCreateTypeObject (CmiKeyType);
/* Initialize the hive link list */
InitializeListHead(&CmiHiveLinkListHead);
/* Initialize the hive list */ /* Initialize the hive list */
InitializeListHead(&CmiHiveListHead); InitializeListHead(&CmiHiveListHead);
ExInitializeResourceLite(&CmiHiveListLock); ExInitializeResourceLite(&CmiHiveListLock);
@ -596,12 +600,30 @@ CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
Status = CmiAddKeyToHashTable(ParentKey->RegistryHive,
ParentKey->KeyCell,
ParentKey->KeyCellOffset,
NewKey->RegistryHive,
NewKey->KeyCell,
NewKey->KeyCellOffset);
if (!NT_SUCCESS(Status))
{
DPRINT1("CmiAddKeyToHashTable() failed (Status %lx)\n", Status);
if (NewKey->SubKeys != NULL)
{
ExFreePool (NewKey->SubKeys);
}
ObDereferenceObject (NewKey);
ObDereferenceObject (ParentKey);
return Status;
}
CmiAddKeyToList (ParentKey, NewKey); CmiAddKeyToList (ParentKey, NewKey);
ObDereferenceObject (ParentKey);
VERIFY_KEY_OBJECT(NewKey); VERIFY_KEY_OBJECT(NewKey);
/* Note: Do not dereference NewKey here! */ ObDereferenceObject (NewKey);
ObDereferenceObject (ParentKey);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -614,6 +636,10 @@ CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
PKEY_OBJECT KeyObject; PKEY_OBJECT KeyObject;
PREGISTRY_HIVE Hive; PREGISTRY_HIVE Hive;
HANDLE KeyHandle; HANDLE KeyHandle;
PLIST_ENTRY Entry;
PHIVE_LINK HiveLink;
PKEY_CELL ParentKeyCell;
PHASH_TABLE_CELL HashCell;
NTSTATUS Status; NTSTATUS Status;
DPRINT("CmiDisconnectHive() called\n"); DPRINT("CmiDisconnectHive() called\n");
@ -663,10 +689,42 @@ CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
} }
Hive = KeyObject->RegistryHive; Hive = KeyObject->RegistryHive;
CmiRemoveKeyFromList (KeyObject); CmiRemoveKeyFromList (KeyObject);
/* Dereference KeyObject twice to delete it */ /* Remove hive link and hash table entry */
ObDereferenceObject (KeyObject); Entry = CmiHiveLinkListHead.Flink;
while (Entry != &CmiHiveLinkListHead)
{
HiveLink = CONTAINING_RECORD(Entry, HIVE_LINK, Entry);
if (HiveLink->SubKeyRegistryHive == Hive &&
HiveLink->SubKeyCellOffset == KeyObject->KeyCellOffset)
{
ParentKeyCell = CmiGetCell (HiveLink->ParentKeyRegistryHive,
HiveLink->ParentKeyCellOffset,
NULL);
if (ParentKeyCell != NULL)
{
HashCell = CmiGetCell (HiveLink->ParentKeyRegistryHive,
ParentKeyCell->HashTableOffset,
NULL);
if (HashCell != NULL)
{
CmiRemoveKeyFromHashTable(HiveLink->ParentKeyRegistryHive,
HashCell,
(BLOCK_OFFSET)((ULONG)HiveLink | 1));
ParentKeyCell->NumberOfSubKeys--;
}
}
RemoveEntryList (Entry);
ExFreePool (Entry);
break;
}
Entry = Entry->Flink;
}
ObDereferenceObject (KeyObject); ObDereferenceObject (KeyObject);
*RegistryHive = Hive; *RegistryHive = Hive;

View file

@ -46,6 +46,7 @@ CmiObjectParse(PVOID ParsedObject,
UNICODE_STRING LinkPath; UNICODE_STRING LinkPath;
UNICODE_STRING TargetPath; UNICODE_STRING TargetPath;
UNICODE_STRING KeyName; UNICODE_STRING KeyName;
PREGISTRY_HIVE RegistryHive;
ParsedKey = ParsedObject; ParsedKey = ParsedObject;
@ -90,6 +91,7 @@ CmiObjectParse(PVOID ParsedObject,
{ {
Status = CmiScanForSubKey(ParsedKey->RegistryHive, Status = CmiScanForSubKey(ParsedKey->RegistryHive,
ParsedKey->KeyCell, ParsedKey->KeyCell,
&RegistryHive,
&SubKeyCell, &SubKeyCell,
&BlockOffset, &BlockOffset,
&KeyName, &KeyName,
@ -165,7 +167,7 @@ CmiObjectParse(PVOID ParsedObject,
FoundObject->Flags = 0; FoundObject->Flags = 0;
FoundObject->KeyCell = SubKeyCell; FoundObject->KeyCell = SubKeyCell;
FoundObject->KeyCellOffset = BlockOffset; FoundObject->KeyCellOffset = BlockOffset;
FoundObject->RegistryHive = ParsedKey->RegistryHive; FoundObject->RegistryHive = RegistryHive;
RtlCreateUnicodeString(&FoundObject->Name, RtlCreateUnicodeString(&FoundObject->Name,
KeyName.Buffer); KeyName.Buffer);
CmiAddKeyToList(ParsedKey, FoundObject); CmiAddKeyToList(ParsedKey, FoundObject);