VOID NTAPI CmpFreeKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb) { ULONG i; PCM_ALLOC_PAGE AllocPage; PAGED_CODE(); /* Sanity checks */ ASSERT(IsListEmpty(&Kcb->KeyBodyListHead) == TRUE); for (i = 0; i < 4; i++) ASSERT(Kcb->KeyBodyArray[i] == NULL); /* Check if it wasn't privately allocated */ if (!Kcb->PrivateAlloc) { /* Free it from the pool */ CmpFree(Kcb, 0); return; } /* Acquire the private allocation lock */ KeAcquireGuardedMutex(&CmpAllocBucketLock); /* Sanity check on lock ownership */ CMP_ASSERT_HASH_ENTRY_LOCK(Kcb->ConvKey); /* Add us to the free list */ InsertTailList(&CmpFreeKCBListHead, &Kcb->FreeListEntry); /* Get the allocation page */ AllocPage = CmpGetAllocPageFromKcb(Kcb); /* Sanity check */ ASSERT(AllocPage->FreeCount != CM_KCBS_PER_PAGE); /* Increase free count */ if (++AllocPage->FreeCount == CM_KCBS_PER_PAGE) { /* Loop all the entries */ for (i = 0; i < CM_KCBS_PER_PAGE; i++) { /* Get the KCB */ Kcb = (PVOID)((ULONG_PTR)AllocPage + FIELD_OFFSET(CM_ALLOC_PAGE, AllocPage) + i * sizeof(CM_KEY_CONTROL_BLOCK)); /* Remove the entry */ RemoveEntryList(&Kcb->FreeListEntry); } /* Free the page */ CmpFree(AllocPage, 0); } /* Release the lock */ KeReleaseGuardedMutex(&CmpAllocBucketLock); }
NTSTATUS NTAPI CmpDestroyHive(IN PCMHIVE CmHive) { /* Remove the hive from the list */ ExAcquirePushLockExclusive(&CmpHiveListHeadLock); RemoveEntryList(&CmHive->HiveList); ExReleasePushLock(&CmpHiveListHeadLock); /* Delete the flusher lock */ ExDeleteResourceLite(CmHive->FlusherLock); ExFreePoolWithTag(CmHive->FlusherLock, TAG_CMHIVE); /* Delete the view lock */ ExFreePoolWithTag(CmHive->ViewLock, TAG_CMHIVE); /* Destroy the security descriptor cache */ CmpDestroySecurityCache(CmHive); /* Destroy the view list */ CmpDestroyHiveViewList(CmHive); /* Free the hive storage */ HvFree(&CmHive->Hive); /* Free the hive */ CmpFree(CmHive, TAG_CM); return STATUS_SUCCESS; }
VOID NTAPI CmpCleanUpKcbValueCache(IN PCM_KEY_CONTROL_BLOCK Kcb) { PULONG_PTR CachedList; ULONG i; /* Sanity check */ ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) || (CmpTestRegistryLockExclusive() == TRUE)); /* Check if the value list is cached */ if (CMP_IS_CELL_CACHED(Kcb->ValueCache.ValueList)) { /* Get the cache list */ CachedList = (PULONG_PTR)CMP_GET_CACHED_DATA(Kcb->ValueCache.ValueList); for (i = 0; i < Kcb->ValueCache.Count; i++) { /* Check if this cell is cached */ if (CMP_IS_CELL_CACHED(CachedList[i])) { /* Free it */ CmpFree((PVOID)CMP_GET_CACHED_CELL(CachedList[i]), 0); } } /* Now free the list */ CmpFree((PVOID)CMP_GET_CACHED_CELL(Kcb->ValueCache.ValueList), 0); Kcb->ValueCache.ValueList = HCELL_NIL; } else if (Kcb->ExtFlags & CM_KCB_SYM_LINK_FOUND) { /* This is a sym link, check if there's only one reference left */ if ((Kcb->ValueCache.RealKcb->RefCount == 1) && !(Kcb->ValueCache.RealKcb->Delete)) { /* Disable delay close for the KCB */ Kcb->ValueCache.RealKcb->ExtFlags |= CM_KCB_NO_DELAY_CLOSE; } /* Dereference the KCB */ CmpDelayDerefKeyControlBlock(Kcb->ValueCache.RealKcb); Kcb->ExtFlags &= ~CM_KCB_SYM_LINK_FOUND; } }
VOID NTAPI CmpCleanUpSubKeyInfo(IN PCM_KEY_CONTROL_BLOCK Kcb) { PCM_KEY_NODE KeyNode; /* Sanity check */ ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) || (CmpTestRegistryLockExclusive() == TRUE)); /* Check if there's any cached subkey */ if (Kcb->ExtFlags & (CM_KCB_NO_SUBKEY | CM_KCB_SUBKEY_ONE | CM_KCB_SUBKEY_HINT)) { /* Check if there's a hint */ if (Kcb->ExtFlags & (CM_KCB_SUBKEY_HINT)) { /* Kill it */ CmpFree(Kcb->IndexHint, 0); } /* Remove subkey flags */ Kcb->ExtFlags &= ~(CM_KCB_NO_SUBKEY | CM_KCB_SUBKEY_ONE | CM_KCB_SUBKEY_HINT); } /* Check if there's no linked cell */ if (Kcb->KeyCell == HCELL_NIL) { /* Make sure it's a delete */ ASSERT(Kcb->Delete); KeyNode = NULL; } else { /* Get the key node */ KeyNode = (PCM_KEY_NODE)HvGetCell(Kcb->KeyHive, Kcb->KeyCell); } /* Check if we got the node */ if (!KeyNode) { /* We didn't, mark the cached data invalid */ Kcb->ExtFlags |= CM_KCB_INVALID_CACHED_INFO; } else { /* We have a keynode, update subkey counts */ Kcb->ExtFlags &= ~CM_KCB_INVALID_CACHED_INFO; Kcb->SubKeyCount = KeyNode->SubKeyCounts[Stable] + KeyNode->SubKeyCounts[Volatile]; /* Release the cell */ HvReleaseCell(Kcb->KeyHive, Kcb->KeyCell); } }
VOID NTAPI CmpCleanUpKcbCacheWithLock(IN PCM_KEY_CONTROL_BLOCK Kcb, IN BOOLEAN LockHeldExclusively) { PCM_KEY_CONTROL_BLOCK Parent; PAGED_CODE(); /* Sanity checks */ ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) || (CmpTestRegistryLockExclusive() == TRUE)); ASSERT(Kcb->RefCount == 0); /* Cleanup the value cache */ CmpCleanUpKcbValueCache(Kcb); /* Dereference the NCB */ CmpDereferenceNameControlBlockWithLock(Kcb->NameBlock); /* Check if we have an index hint block and free it */ if (Kcb->ExtFlags & CM_KCB_SUBKEY_HINT) CmpFree(Kcb->IndexHint, 0); /* Check if we were already deleted */ Parent = Kcb->ParentKcb; if (!Kcb->Delete) CmpRemoveKeyControlBlock(Kcb); /* Set invalid KCB signature */ Kcb->Signature = CM_KCB_INVALID_SIGNATURE; /* Free the KCB as well */ CmpFreeKeyControlBlock(Kcb); /* Check if we have a parent */ if (Parent) { /* Dereference the parent */ LockHeldExclusively ? CmpDereferenceKeyControlBlockWithLock(Parent,LockHeldExclusively) : CmpDelayDerefKeyControlBlock(Parent); } }
VOID NTAPI CmpFreeDelayItem(PVOID Entry) { PCM_DELAY_ALLOC AllocEntry = (PCM_DELAY_ALLOC)Entry; PCM_ALLOC_PAGE AllocPage; ULONG i; PAGED_CODE(); /* Lock the table */ KeAcquireGuardedMutex(&CmpDelayAllocBucketLock); /* Add the entry at the end */ InsertTailList(&CmpFreeDelayItemsListHead, &AllocEntry->ListEntry); /* Get the alloc page */ AllocPage = CmpGetAllocPageFromDelayAlloc(Entry); ASSERT(AllocPage->FreeCount != CM_DELAYS_PER_PAGE); /* Increase the number of free items */ if (++AllocPage->FreeCount == CM_DELAYS_PER_PAGE) { /* Page is totally free now, loop each entry */ for (i = 0; i < CM_DELAYS_PER_PAGE; i++) { /* Get the entry and unlink it */ AllocEntry = (PVOID)((ULONG_PTR)AllocPage + FIELD_OFFSET(CM_ALLOC_PAGE, AllocPage) + i * sizeof(CM_DELAY_ALLOC)); RemoveEntryList(&AllocEntry->ListEntry); } /* Now free the page */ CmpFree(AllocPage, 0); } /* Release the lock */ KeReleaseGuardedMutex(&CmpDelayAllocBucketLock); }
VOID NTAPI CmpDereferenceNameControlBlockWithLock(IN PCM_NAME_CONTROL_BLOCK Ncb) { PCM_NAME_HASH Current, *Next; ULONG ConvKey = Ncb->ConvKey; /* Lock the NCB */ CmpAcquireNcbLockExclusiveByKey(ConvKey); /* Decrease the reference count */ ASSERT(Ncb->RefCount >= 1); if (!(--Ncb->RefCount)) { /* Find the NCB in the table */ Next = &GET_HASH_ENTRY(CmpNameCacheTable, Ncb->ConvKey).Entry; while (TRUE) { /* Check the current entry */ Current = *Next; ASSERT(Current != NULL); if (Current == &Ncb->NameHash) { /* Unlink it */ *Next = Current->NextHash; break; } /* Get to the next one */ Next = &Current->NextHash; } /* Found it, now free it */ CmpFree(Ncb, 0); } /* Release the lock */ CmpReleaseNcbLockByKey(ConvKey); }
VALUE_SEARCH_RETURN_TYPE NTAPI CmpCompareNewValueDataAgainstKCBCache(IN PCM_KEY_CONTROL_BLOCK Kcb, IN PUNICODE_STRING ValueName, IN ULONG Type, IN PVOID Data, IN ULONG DataSize) { VALUE_SEARCH_RETURN_TYPE SearchResult; PCM_KEY_NODE KeyNode; PCM_CACHED_VALUE *CachedValue; ULONG Index; PCM_KEY_VALUE Value; BOOLEAN ValueCached, BufferAllocated = FALSE; PVOID Buffer; HCELL_INDEX ValueCellToRelease = HCELL_NIL, CellToRelease = HCELL_NIL; BOOLEAN IsSmall; ULONG CompareResult; PAGED_CODE(); /* Check if this is a symlink */ if (Kcb->Flags & KEY_SYM_LINK) { /* We need the exclusive lock */ if (!(CmpIsKcbLockedExclusive(Kcb)) && !(CmpTryToConvertKcbSharedToExclusive(Kcb))) { /* We need the exclusive lock */ return SearchNeedExclusiveLock; } /* Otherwise, get the key node */ KeyNode = (PCM_KEY_NODE)HvGetCell(Kcb->KeyHive, Kcb->KeyCell); if (!KeyNode) return SearchFail; /* Cleanup the KCB cache */ CmpCleanUpKcbValueCache(Kcb); /* Sanity checks */ ASSERT(!(CMP_IS_CELL_CACHED(Kcb->ValueCache.ValueList))); ASSERT(!(Kcb->ExtFlags & CM_KCB_SYM_LINK_FOUND)); /* Set the value cache */ Kcb->ValueCache.Count = KeyNode->ValueList.Count; Kcb->ValueCache.ValueList = KeyNode->ValueList.List; /* Release the cell */ HvReleaseCell(Kcb->KeyHive, Kcb->KeyCell); } /* Do the search */ SearchResult = CmpFindValueByNameFromCache(Kcb, ValueName, &CachedValue, &Index, &Value, &ValueCached, &ValueCellToRelease); if (SearchResult == SearchNeedExclusiveLock) { /* We need the exclusive lock */ ASSERT(!CmpIsKcbLockedExclusive(Kcb)); ASSERT(ValueCellToRelease == HCELL_NIL); ASSERT(Value == NULL); goto Quickie; } else if (SearchResult == SearchSuccess) { /* Sanity check */ ASSERT(Value); /* First of all, check if the key size and type matches */ if ((Type == Value->Type) && (DataSize == (Value->DataLength & ~CM_KEY_VALUE_SPECIAL_SIZE))) { /* Check if this is a small key */ IsSmall = (DataSize <= CM_KEY_VALUE_SMALL) ? TRUE: FALSE; if (IsSmall) { /* Compare against the data directly */ Buffer = &Value->Data; } else { /* Do a search */ SearchResult = CmpGetValueDataFromCache(Kcb, CachedValue, (PCELL_DATA)Value, ValueCached, &Buffer, &BufferAllocated, &CellToRelease); if (SearchResult != SearchSuccess) { /* Sanity checks */ ASSERT(Buffer == NULL); ASSERT(BufferAllocated == FALSE); goto Quickie; } } /* Now check the data size */ if (DataSize) { /* Do the compare */ CompareResult = RtlCompareMemory(Buffer, Data, DataSize & ~CM_KEY_VALUE_SPECIAL_SIZE); } else { /* It's equal */ CompareResult = 0; } /* Now check if the compare wasn't equal */ if (CompareResult != DataSize) SearchResult = SearchFail; } else { /* The length or type isn't equal */ SearchResult = SearchFail; } } Quickie: /* Release the value cell */ if (ValueCellToRelease) HvReleaseCell(Kcb->KeyHive, ValueCellToRelease); /* Free the buffer */ if (BufferAllocated) CmpFree(Buffer, 0); /* Free the cell */ if (CellToRelease) HvReleaseCell(Kcb->KeyHive, CellToRelease); /* Return the search result */ return SearchResult; }
VOID HvFreeHive( PHHIVE Hive ) /*++ Routine Description: Free all of the pieces of a hive. Arguments: Hive - supplies a pointer to hive control structure for hive to free. this structure itself will NOT be freed, but everything it points to will. Return Value: NONE. --*/ { PHMAP_DIRECTORY Dir; PHMAP_ENTRY Me; HCELL_INDEX Address; ULONG Type; ULONG Length; PHBIN Bin; ULONG Tables; PFREE_HBIN FreeBin; ASSERT(Hive->Flat == FALSE); ASSERT(Hive->ReadOnly == FALSE); ASSERT(Stable == 0); ASSERT(Volatile == 1); CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"HvFreeHive(%ws) :\n", Hive->BaseBlock->FileName)); // // Iterate through both types of storage // for (Type = 0; Type <= Volatile; Type++) { Address = HCELL_TYPE_MASK * Type; Length = Hive->Storage[Type].Length + (HCELL_TYPE_MASK * Type); if( Hive->Storage[Type].Map && (Length > (HCELL_TYPE_MASK * Type)) ) { // // Sweep through bin set // do { Me = HvpGetCellMap(Hive, Address); VALIDATE_CELL_MAP(__LINE__,Me,Hive,Address); if (Me->BinAddress & HMAP_DISCARDABLE) { // // hbin is either discarded or discardable, check the tombstone // FreeBin = (PFREE_HBIN)Me->BlockAddress; Address += FreeBin->Size; if (FreeBin->Flags & FREE_HBIN_DISCARDABLE) { CmpFree((PHBIN)HBIN_BASE(Me->BinAddress), FreeBin->Size); } else if(Me->BinAddress & HMAP_INPAGEDPOOL) { // // The bin has been freed, but quota is still charged. // Since the hive is being freed, the quota must be // returned here. // CmpReleaseGlobalQuota(FreeBin->Size); } CmpFree(FreeBin, sizeof(FREE_HBIN)); } else { if( Me->BinAddress & HMAP_INPAGEDPOOL ) { ASSERT( Me->BinAddress & HMAP_INPAGEDPOOL ); Bin = (PHBIN)HBIN_BASE(Me->BinAddress); Address += HvpGetBinMemAlloc(Hive,Bin,Type); #if DBG if( Type == Stable ) { CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"HvFreeHive: BinAddress = 0x%p\t Size = 0x%lx\n", Bin, HvpGetBinMemAlloc(Hive,Bin,Type))); } #endif // // free the actual bin only if it is allocated from paged pool // if(HvpGetBinMemAlloc(Hive,Bin,Type)) { CmpFree(Bin, HvpGetBinMemAlloc(Hive,Bin,Type)); } } else { // // bin was mapped into view; advance carefully // Address += HBLOCK_SIZE; } } } while (Address < Length); // // Free map table storage // ASSERT(Hive->Storage[Type].Length != (HCELL_TYPE_MASK * Type)); Tables = (((Hive->Storage[Type].Length) / HBLOCK_SIZE)-1) / HTABLE_SLOTS; Dir = Hive->Storage[Type].Map; HvpFreeMap(Hive, Dir, 0, Tables); if (Tables > 0) { CmpFree(Hive->Storage[Type].Map, sizeof(HMAP_DIRECTORY)); // free dir if it exists } } Hive->Storage[Type].Length = 0; } CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"\n")); // // Free the base block // (Hive->Free)(Hive->BaseBlock,Hive->BaseBlockAlloc); Hive->BaseBlock = NULL; // // Free the dirty vector // if (Hive->DirtyVector.Buffer != NULL) { CmpFree((PVOID)(Hive->DirtyVector.Buffer), Hive->DirtyAlloc); } HvpFreeHiveFreeDisplay(Hive); LogHiveFree(Hive); return; }
VOID HvFreeHivePartial( PHHIVE Hive, HCELL_INDEX Start, HSTORAGE_TYPE Type ) /*++ Routine Description: Free the memory and associated maps for the end of a hive starting at Start. The baseblock, hive, etc will not be touched. Arguments: Hive - supplies a pointer to hive control structure for hive to partially free. Start - HCELL_INDEX of first bin to free, will free from this bin (inclusive) to the end of the hives stable storage. Type - Type of storage (Stable or Volatile) to be freed. Return Value: NONE. --*/ { PHMAP_DIRECTORY Dir; PHMAP_ENTRY Me; HCELL_INDEX Address; ULONG StartTable; ULONG Length; PHBIN Bin; ULONG Tables; ULONG FirstBit; ULONG LastBit; PFREE_HBIN FreeBin; ASSERT(Hive->Flat == FALSE); ASSERT(Hive->ReadOnly == FALSE); Address = Start; Length = Hive->Storage[Type].Length; ASSERT(Address <= Length); if (Address == Length) { return; } // // Sweep through bin set // do { Me = HvpGetCellMap(Hive, Address + (Type*HCELL_TYPE_MASK)); VALIDATE_CELL_MAP(__LINE__,Me,Hive,Address + (Type*HCELL_TYPE_MASK)); if (Me->BinAddress & HMAP_DISCARDABLE) { FreeBin = (PFREE_HBIN)Me->BlockAddress; if (FreeBin->Flags & FREE_HBIN_DISCARDABLE) { CmpFree((PVOID)HBIN_BASE(Me->BinAddress), FreeBin->Size); } else { // // The bin has been freed, but quota is still charged. // Since the file will now shrink, the quota must be // returned here. // if( Me->BinAddress & HMAP_INPAGEDPOOL) { // // we charge quota only for bins in paged-pool // CmpReleaseGlobalQuota(FreeBin->Size); } } RemoveEntryList(&FreeBin->ListEntry); Address += FreeBin->Size; CmpFree(FreeBin, sizeof(FREE_HBIN)); } else { Bin = (PHBIN)HBIN_BASE(Me->BinAddress); Address += HvpGetBinMemAlloc(Hive,Bin,Type); if( Me->BinAddress & HMAP_INPAGEDPOOL && HvpGetBinMemAlloc(Hive,Bin,Type) ) { // // free the bin only if it is allocated from paged pool // CmpFree(Bin, HvpGetBinMemAlloc(Hive,Bin,Type)); } } } while (Address < Length); // // Free map table storage // Tables = (((Hive->Storage[Type].Length) / HBLOCK_SIZE) - 1) / HTABLE_SLOTS; Dir = Hive->Storage[Type].Map; if (Start > 0) { StartTable = ((Start-1) / HBLOCK_SIZE) / HTABLE_SLOTS; } else { StartTable = (ULONG)-1; } HvpFreeMap(Hive, Dir, StartTable+1, Tables); // // update hysteresis (eventually queue work item) // if( Type == Stable) { CmpUpdateSystemHiveHysteresis(Hive,(Start&(~HCELL_TYPE_MASK)),Hive->Storage[Type].Length); } Hive->Storage[Type].Length = (Start&(~HCELL_TYPE_MASK)); if (Type==Stable) { // // Clear dirty vector for data past Hive->Storage[Stable].Length // FirstBit = Start / HSECTOR_SIZE; LastBit = Hive->DirtyVector.SizeOfBitMap; ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector)); RtlClearBits(&Hive->DirtyVector, FirstBit, LastBit-FirstBit); Hive->DirtyCount = RtlNumberOfSetBits(&Hive->DirtyVector); } HvpAdjustHiveFreeDisplay(Hive,Hive->Storage[Type].Length,Type); return; }
BOOLEAN RegImportBinaryHive( PCHAR ChunkBase, ULONG ChunkSize) { PCM_KEY_NODE KeyCell; PCM_KEY_FAST_INDEX HashCell; PCM_KEY_NODE SubKeyCell; FRLDRHKEY SystemKey; ULONG i; LONG Error; PCMHIVE CmHive; PHHIVE Hive; NTSTATUS Status; TRACE("RegImportBinaryHive(%x, %u) called\n", ChunkBase, ChunkSize); CmHive = CmpAllocate(sizeof(CMHIVE), TRUE, 0); Status = HvInitialize(&CmHive->Hive, HINIT_FLAT, 0, 0, ChunkBase, CmpAllocate, CmpFree, NULL, NULL, NULL, NULL, 1, NULL); if (!NT_SUCCESS(Status)) { CmpFree(CmHive, 0); ERR("Invalid hive Signature!\n"); return FALSE; } Hive = &CmHive->Hive; KeyCell = (PCM_KEY_NODE)HvGetCell(Hive, Hive->BaseBlock->RootCell); TRACE("KeyCell: %x\n", KeyCell); TRACE("KeyCell->Signature: %x\n", KeyCell->Signature); if (KeyCell->Signature != CM_KEY_NODE_SIGNATURE) { ERR("Invalid key cell Signature!\n"); return FALSE; } TRACE("Subkeys: %u\n", KeyCell->SubKeyCounts); TRACE("Values: %u\n", KeyCell->ValueList.Count); /* Open 'System' key */ Error = RegOpenKey(NULL, L"\\Registry\\Machine\\SYSTEM", &SystemKey); if (Error != ERROR_SUCCESS) { ERR("Failed to open 'system' key!\n"); return FALSE; } /* Enumerate and add subkeys */ if (KeyCell->SubKeyCounts[Stable] > 0) { HashCell = (PCM_KEY_FAST_INDEX)HvGetCell(Hive, KeyCell->SubKeyLists[Stable]); TRACE("HashCell: %x\n", HashCell); TRACE("SubKeyCounts: %x\n", KeyCell->SubKeyCounts[Stable]); for (i = 0; i < KeyCell->SubKeyCounts[Stable]; i++) { TRACE("Cell[%d]: %x\n", i, HashCell->List[i].Cell); SubKeyCell = (PCM_KEY_NODE)HvGetCell(Hive, HashCell->List[i].Cell); TRACE("SubKeyCell[%d]: %x\n", i, SubKeyCell); if (!RegImportSubKey(Hive, SubKeyCell, SystemKey)) return FALSE; } } return TRUE; }
PUNICODE_STRING NTAPI CmpConstructName(IN PCM_KEY_CONTROL_BLOCK Kcb) { PUNICODE_STRING KeyName; ULONG NameLength, i; PCM_KEY_CONTROL_BLOCK MyKcb; PCM_KEY_NODE KeyNode; BOOLEAN DeletedKey = FALSE; PWCHAR TargetBuffer, CurrentNameW; PUCHAR CurrentName; /* Calculate how much size our key name is going to occupy */ NameLength = 0; MyKcb = Kcb; while (MyKcb) { /* Add length of the name */ if (!MyKcb->NameBlock->Compressed) { NameLength += MyKcb->NameBlock->NameLength; } else { NameLength += CmpCompressedNameSize(MyKcb->NameBlock->Name, MyKcb->NameBlock->NameLength); } /* Sum up the separator too */ NameLength += sizeof(WCHAR); /* Go to the parent KCB */ MyKcb = MyKcb->ParentKcb; } /* Allocate the unicode string now */ KeyName = CmpAllocate(NameLength + sizeof(UNICODE_STRING), TRUE, TAG_CM); if (!KeyName) return NULL; /* Set it up */ KeyName->Buffer = (PWSTR)(KeyName + 1); KeyName->Length = NameLength; KeyName->MaximumLength = NameLength; /* Loop the keys again, now adding names */ NameLength = 0; MyKcb = Kcb; while (MyKcb) { /* Sanity checks for deleted and fake keys */ if ((!MyKcb->KeyCell && !MyKcb->Delete) || !MyKcb->KeyHive || MyKcb->ExtFlags & CM_KCB_KEY_NON_EXIST) { /* Failure */ CmpFree(KeyName, 0); return NULL; } /* Try to get the name from the keynode, if the key is not deleted */ if (!DeletedKey && !MyKcb->Delete) { KeyNode = HvGetCell(MyKcb->KeyHive, MyKcb->KeyCell); if (!KeyNode) { /* Failure */ CmpFree(KeyName, 0); return NULL; } } else { /* The key was deleted */ KeyNode = NULL; DeletedKey = TRUE; } /* Get the pointer to the beginning of the current key name */ NameLength += (MyKcb->NameBlock->NameLength + 1) * sizeof(WCHAR); TargetBuffer = &KeyName->Buffer[(KeyName->Length - NameLength) / sizeof(WCHAR)]; /* Add a separator */ TargetBuffer[0] = OBJ_NAME_PATH_SEPARATOR; /* Add the name, but remember to go from the end to the beginning */ if (!MyKcb->NameBlock->Compressed) { /* Get the pointer to the name (from the keynode, if possible) */ if ((MyKcb->Flags & (KEY_HIVE_ENTRY | KEY_HIVE_EXIT)) || !KeyNode) { CurrentNameW = MyKcb->NameBlock->Name; } else { CurrentNameW = KeyNode->Name; } /* Copy the name */ for (i=0; i < MyKcb->NameBlock->NameLength; i++) { TargetBuffer[i+1] = *CurrentNameW; CurrentNameW++; } } else { /* Get the pointer to the name (from the keynode, if possible) */ if ((MyKcb->Flags & (KEY_HIVE_ENTRY | KEY_HIVE_EXIT)) || !KeyNode) { CurrentName = (PUCHAR)MyKcb->NameBlock->Name; } else { CurrentName = (PUCHAR)KeyNode->Name; } /* Copy the name */ for (i=0; i < MyKcb->NameBlock->NameLength; i++) { TargetBuffer[i+1] = (WCHAR)*CurrentName; CurrentName++; } } /* Release the cell, if needed */ if (KeyNode) HvReleaseCell(MyKcb->KeyHive, MyKcb->KeyCell); /* Go to the parent KCB */ MyKcb = MyKcb->ParentKcb; } /* Return resulting buffer (both UNICODE_STRING and its buffer following it) */ return KeyName; }