PCM_NAME_CONTROL_BLOCK CmpGetNameControlBlock( PUNICODE_STRING NodeName ) { PCM_NAME_CONTROL_BLOCK Ncb; ULONG Cnt; WCHAR *Cp; WCHAR *Cp2; ULONG Index; ULONG i; ULONG Size; PCM_NAME_HASH CurrentName; ULONG rc; BOOLEAN NameFound = FALSE; USHORT NameSize; BOOLEAN NameCompressed; ULONG NameConvKey=0; LONG Result; // // Calculate the ConvKey for this NadeName; // Cp = NodeName->Buffer; for (Cnt=0; Cnt<NodeName->Length; Cnt += sizeof(WCHAR)) { if (*Cp != OBJ_NAME_PATH_SEPARATOR) { NameConvKey = 37 * NameConvKey + (ULONG) RtlUpcaseUnicodeChar(*Cp); } ++Cp; } // // Find the Name Size; // NameCompressed = TRUE; NameSize = NodeName->Length / sizeof(WCHAR); for (i=0;i<NodeName->Length/sizeof(WCHAR);i++) { if ((USHORT)NodeName->Buffer[i] > (UCHAR)-1) { NameSize = NodeName->Length; NameCompressed = FALSE; } } Index = GET_HASH_INDEX(NameConvKey); CurrentName = CmpNameCacheTable[Index]; while (CurrentName) { Ncb = CONTAINING_RECORD(CurrentName, CM_NAME_CONTROL_BLOCK, NameHash); if ((NameConvKey == CurrentName->ConvKey) && (NameSize == Ncb->NameLength)) { // // Hash value matches, compare the names. // NameFound = TRUE; if (Ncb->Compressed) { if (CmpCompareCompressedName(NodeName, Ncb->Name, NameSize)) { NameFound = FALSE; } } else { Cp = (WCHAR *) NodeName->Buffer; Cp2 = (WCHAR *) Ncb->Name; for (i=0 ;i<Ncb->NameLength; i+= sizeof(WCHAR)) { if (RtlUpcaseUnicodeChar(*Cp) != RtlUpcaseUnicodeChar(*Cp2)) { NameFound = FALSE; break; } ++Cp; ++Cp2; } } if (NameFound) { // // Found it, increase the refcount. // if ((USHORT) (Ncb->RefCount + 1) == 0) { // // We have maxed out the ref count. // fail the call. // Ncb = NULL; } else { ++Ncb->RefCount; } break; } } CurrentName = CurrentName->NextHash; } if (NameFound == FALSE) { // // Now need to create one Name block for this string. // Size = FIELD_OFFSET(CM_NAME_CONTROL_BLOCK, Name) + NameSize; Ncb = ExAllocatePoolWithTag(PagedPool, Size, CM_NAME_TAG | PROTECTED_POOL); if (Ncb == NULL) { return(NULL); } RtlZeroMemory(Ncb, Size); // // Update all the info for this newly created Name block. // if (NameCompressed) { Ncb->Compressed = TRUE; for (i=0;i<NameSize;i++) { ((PUCHAR)Ncb->Name)[i] = (UCHAR)(NodeName->Buffer[i]); } } else { Ncb->Compressed = FALSE; RtlCopyMemory((PVOID)(Ncb->Name), (PVOID)(NodeName->Buffer), NameSize); } Ncb->ConvKey = NameConvKey; Ncb->RefCount = 1; Ncb->NameLength = NameSize; CurrentName = &(Ncb->NameHash); // // Insert into Name Hash table. // CurrentName->NextHash = CmpNameCacheTable[Index]; CmpNameCacheTable[Index] = CurrentName; } return(Ncb); }
VALUE_SEARCH_RETURN_TYPE NTAPI CmpFindValueByNameFromCache(IN PCM_KEY_CONTROL_BLOCK Kcb, IN PCUNICODE_STRING Name, OUT PCM_CACHED_VALUE **CachedValue, OUT ULONG *Index, OUT PCM_KEY_VALUE *Value, OUT BOOLEAN *ValueIsCached, OUT PHCELL_INDEX CellToRelease) { PHHIVE Hive; VALUE_SEARCH_RETURN_TYPE SearchResult = SearchFail; LONG Result; UNICODE_STRING SearchName; PCELL_DATA CellData; PCACHED_CHILD_LIST ChildList; PCM_KEY_VALUE KeyValue; BOOLEAN IndexIsCached; ULONG i = 0; HCELL_INDEX Cell = HCELL_NIL; PCM_KEY_NODE KeyNode; /* Set defaults */ *CellToRelease = HCELL_NIL; *Value = NULL; /* Get the hive and child list */ Hive = Kcb->KeyHive; ChildList = &Kcb->ValueCache; KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Kcb->KeyCell); ChildList = (PCACHED_CHILD_LIST)&KeyNode->ValueList; /* Check if the child list has any entries */ if (ChildList->Count != 0) { /* Get the value list associated to this child list */ SearchResult = CmpGetValueListFromCache(Kcb, &CellData, &IndexIsCached, &Cell); if (SearchResult != SearchSuccess) { /* We either failed or need the exclusive lock */ ASSERT((SearchResult == SearchFail) || !(CmpIsKcbLockedExclusive(Kcb))); ASSERT(Cell == HCELL_NIL); return SearchResult; } /* The index shouldn't be cached right now */ if (IndexIsCached) ASSERT_VALUE_CACHE(); /* Loop every value */ while (TRUE) { /* Check if there's any cell to release */ if (*CellToRelease != HCELL_NIL) { /* Release it now */ HvReleaseCell(Hive, *CellToRelease); *CellToRelease = HCELL_NIL; } /* Get the key value for this index */ SearchResult = CmpGetValueKeyFromCache(Kcb, CellData, i, CachedValue, Value, IndexIsCached, ValueIsCached, CellToRelease); if (SearchResult != SearchSuccess) { /* We either failed or need the exclusive lock */ ASSERT((SearchResult == SearchFail) || !(CmpIsKcbLockedExclusive(Kcb))); ASSERT(Cell == HCELL_NIL); return SearchResult; } /* Check if the both the index and the value are cached */ if ((IndexIsCached) && (*ValueIsCached)) { /* We don't expect this yet */ ASSERT_VALUE_CACHE(); Result = -1; } else { /* No cache, so try to compare the name. Is it compressed? */ KeyValue = *Value; if (KeyValue->Flags & VALUE_COMP_NAME) { /* It is, do a compressed name comparison */ Result = CmpCompareCompressedName(Name, KeyValue->Name, KeyValue->NameLength); } else { /* It's not compressed, so do a standard comparison */ SearchName.Length = KeyValue->NameLength; SearchName.MaximumLength = SearchName.Length; SearchName.Buffer = KeyValue->Name; Result = RtlCompareUnicodeString(Name, &SearchName, TRUE); } } /* Check if we found the value data */ if (!Result) { /* We have, return the index of the value and success */ *Index = i; SearchResult = SearchSuccess; goto Quickie; } /* We didn't find it, try the next entry */ if (++i == ChildList->Count) { /* The entire list was parsed, fail */ *Value = NULL; SearchResult = SearchFail; goto Quickie; } } } /* We should only get here if the child list is empty */ ASSERT(ChildList->Count == 0); Quickie: /* Release the value list cell if required, and return search result */ if (Cell != HCELL_NIL) HvReleaseCell(Hive, Cell); return SearchResult; }
PCM_NAME_CONTROL_BLOCK NTAPI CmpGetNameControlBlock(IN PUNICODE_STRING NodeName) { PCM_NAME_CONTROL_BLOCK Ncb = NULL; ULONG ConvKey = 0; PWCHAR p, pp; ULONG i; BOOLEAN IsCompressed = TRUE, Found = FALSE; PCM_NAME_HASH HashEntry; ULONG Length, NcbSize; /* Loop the name */ p = NodeName->Buffer; for (i = 0; i < NodeName->Length; i += sizeof(WCHAR)) { /* Make sure it's not a slash */ if (*p != OBJ_NAME_PATH_SEPARATOR) { /* Add it to the hash */ ConvKey = 37 * ConvKey + RtlUpcaseUnicodeChar(*p); } /* Next character */ p++; } /* Set assumed lengh and loop to check */ Length = NodeName->Length / sizeof(WCHAR); for (i = 0; i < (NodeName->Length / sizeof(WCHAR)); i++) { /* Check if this is a 16-bit character */ if (NodeName->Buffer[i] > (UCHAR)-1) { /* This is the actual size, and we know we're not compressed */ Length = NodeName->Length; IsCompressed = FALSE; break; } } /* Lock the NCB entry */ CmpAcquireNcbLockExclusiveByKey(ConvKey); /* Get the hash entry */ HashEntry = GET_HASH_ENTRY(CmpNameCacheTable, ConvKey).Entry; while (HashEntry) { /* Get the current NCB */ Ncb = CONTAINING_RECORD(HashEntry, CM_NAME_CONTROL_BLOCK, NameHash); /* Check if the hash matches */ if ((ConvKey == HashEntry->ConvKey) && (Length == Ncb->NameLength)) { /* Assume success */ Found = TRUE; /* If the NCB is compressed, do a compressed name compare */ if (Ncb->Compressed) { /* Compare names */ if (CmpCompareCompressedName(NodeName, Ncb->Name, Length)) { /* We failed */ Found = FALSE; } } else { /* Do a manual compare */ p = NodeName->Buffer; pp = Ncb->Name; for (i = 0; i < Ncb->NameLength; i += sizeof(WCHAR)) { /* Compare the character */ if (RtlUpcaseUnicodeChar(*p) != RtlUpcaseUnicodeChar(*pp)) { /* Failed */ Found = FALSE; break; } /* Next chars */ p++; pp++; } } /* Check if we found a name */ if (Found) { /* Reference it */ ASSERT(Ncb->RefCount != 0xFFFF); Ncb->RefCount++; break; } } /* Go to the next hash */ HashEntry = HashEntry->NextHash; } /* Check if we didn't find it */ if (!Found) { /* Allocate one */ NcbSize = FIELD_OFFSET(CM_NAME_CONTROL_BLOCK, Name) + Length; Ncb = CmpAllocate(NcbSize, TRUE, TAG_CM); if (!Ncb) { /* Release the lock and fail */ CmpReleaseNcbLockByKey(ConvKey); return NULL; } /* Clear it out */ RtlZeroMemory(Ncb, NcbSize); /* Check if the name was compressed */ if (IsCompressed) { /* Copy the compressed name */ for (i = 0; i < NodeName->Length / sizeof(WCHAR); i++) { /* Copy Unicode to ANSI */ ((PCHAR)Ncb->Name)[i] = (CHAR)RtlUpcaseUnicodeChar(NodeName->Buffer[i]); } } else { /* Copy the name directly */ for (i = 0; i < NodeName->Length / sizeof(WCHAR); i++) { /* Copy each unicode character */ Ncb->Name[i] = RtlUpcaseUnicodeChar(NodeName->Buffer[i]); } } /* Setup the rest of the NCB */ Ncb->Compressed = IsCompressed; Ncb->ConvKey = ConvKey; Ncb->RefCount++; Ncb->NameLength = Length; /* Insert the name in the hash table */ HashEntry = &Ncb->NameHash; HashEntry->NextHash = GET_HASH_ENTRY(CmpNameCacheTable, ConvKey).Entry; GET_HASH_ENTRY(CmpNameCacheTable, ConvKey).Entry = HashEntry; } /* Release NCB lock */ CmpReleaseNcbLockByKey(ConvKey); /* Return the NCB found */ return Ncb; }
BOOLEAN NTAPI CmpFindNameInList(IN PHHIVE Hive, IN PCHILD_LIST ChildList, IN PUNICODE_STRING Name, IN PULONG ChildIndex, IN PHCELL_INDEX CellIndex) { PCELL_DATA CellData; HCELL_INDEX CellToRelease = HCELL_NIL; ULONG i; PCM_KEY_VALUE KeyValue; LONG Result; UNICODE_STRING SearchName; BOOLEAN Success; /* Make sure there's actually something on the list */ if (ChildList->Count != 0) { /* Get the cell data */ CellData = (PCELL_DATA)HvGetCell(Hive, ChildList->List); if (!CellData) { /* Couldn't get the cell... tell the caller */ *CellIndex = HCELL_NIL; return FALSE; } /* Now loop every entry */ for (i = 0; i < ChildList->Count; i++) { /* Check if we have a cell to release */ if (CellToRelease != HCELL_NIL) { /* Release it */ HvReleaseCell(Hive, CellToRelease); CellToRelease = HCELL_NIL; } /* Get this value */ KeyValue = (PCM_KEY_VALUE)HvGetCell(Hive, CellData->u.KeyList[i]); if (!KeyValue) { /* Return with no data found */ *CellIndex = HCELL_NIL; Success = FALSE; goto Return; } /* Save the cell to release */ CellToRelease = CellData->u.KeyList[i]; /* Check if it's a compressed value name */ if (KeyValue->Flags & VALUE_COMP_NAME) { /* Use the compressed name check */ Result = CmpCompareCompressedName(Name, KeyValue->Name, KeyValue->NameLength); } else { /* Setup the Unicode string */ SearchName.Length = KeyValue->NameLength; SearchName.MaximumLength = SearchName.Length; SearchName.Buffer = KeyValue->Name; Result = RtlCompareUnicodeString(Name, &SearchName, TRUE); } /* Check if we found it */ if (!Result) { /* We did...return info to caller */ if (ChildIndex) *ChildIndex = i; *CellIndex = CellData->u.KeyList[i]; /* Set success state */ Success = TRUE; goto Return; } } /* Got to the end of the list */ if (ChildIndex) *ChildIndex = i; *CellIndex = HCELL_NIL; /* Nothing found if we got here */ Success = TRUE; goto Return; } /* Nothing found...check if the caller wanted more info */ ASSERT(ChildList->Count == 0); if (ChildIndex) *ChildIndex = 0; *CellIndex = HCELL_NIL; /* Nothing found if we got here */ return TRUE; Return: /* Release the first cell we got */ if (CellData) HvReleaseCell(Hive, ChildList->List); /* Release the secondary one, if we have one */ if (CellToRelease) HvReleaseCell(Hive, CellToRelease); return Success; }
VALUE_SEARCH_RETURN_TYPE CmpFindValueByNameFromCache( IN PCM_KEY_CONTROL_BLOCK KeyControlBlock, IN PUNICODE_STRING Name, OUT PPCM_CACHED_VALUE *ContainingList, OUT ULONG *Index, OUT PCM_KEY_VALUE *Value, OUT BOOLEAN *ValueCached, OUT PHCELL_INDEX CellToRelease ) /*++ Routine Description: Find a value node given a value list array and a value name. It sequentially walk through each value node to look for a match. If the array and value nodes touched are not already cached, cache them. Arguments: Hive - pointer to hive control structure for hive of interest ChildList - pointer/index to the Value Index array Name - name of value to find ContainlingList - The address of the entry that will receive the found cached value. Index - pointer to variable to receive index for child ValueCached - Indicate if the value node is cached. Return Value: HCELL_INDEX for the found cell HCELL_NIL if not found Notes: New hives (Minor >= 4) have ValueList sorted; this implies ValueCache is sorted too; So, we can do a binary search here! --*/ { UNICODE_STRING Candidate; LONG Result; PCELL_DATA List; BOOLEAN IndexCached; ULONG Current; HCELL_INDEX ValueListToRelease = HCELL_NIL; ULONG HashKey = 0; PHHIVE Hive = KeyControlBlock->KeyHive; PCACHED_CHILD_LIST ChildList = &(KeyControlBlock->ValueCache); VALUE_SEARCH_RETURN_TYPE ret = SearchFail; ASSERT_KCB_LOCKED(KeyControlBlock); *CellToRelease = HCELL_NIL; *Value = NULL; if (ChildList->Count != 0) { ret = CmpGetValueListFromCache(KeyControlBlock,&List, &IndexCached,&ValueListToRelease); if( ret != SearchSuccess ) { // // retry with exclusive lock, since we need to update the cache // or fail altogether // ASSERT( (ret == SearchFail) || (CmpIsKCBLockedExclusive(KeyControlBlock) == FALSE) ); ASSERT( ValueListToRelease == HCELL_NIL ); return ret; } if( IndexCached ) { try { HashKey = CmpComputeHashKey(0,Name #if DBG , TRUE #endif ); } except (EXCEPTION_EXECUTE_HANDLER) { ret = SearchFail; goto Exit; } } // // old plain hive; simulate a for // Current = 0; while( TRUE ) { if( *CellToRelease != HCELL_NIL ) { HvReleaseCell(Hive,*CellToRelease); *CellToRelease = HCELL_NIL; } ret = CmpGetValueKeyFromCache(KeyControlBlock, List, Current, ContainingList, Value, IndexCached, ValueCached, CellToRelease); if( ret != SearchSuccess ) { // // retry with exclusive lock, since we need to update the cache // or fail altogether // ASSERT( (ret == SearchFail) || (CmpIsKCBLockedExclusive(KeyControlBlock) == FALSE) ); ASSERT( *CellToRelease == HCELL_NIL ); return ret; } // // only compare names when hash matches. // if( IndexCached && (*ValueCached) && (HashKey != ((PCM_CACHED_VALUE)((CMP_GET_CACHED_ADDRESS(**ContainingList))))->HashKey) ) { // // no hash match; skip it // #if DBG try { // // Name has user-mode buffer. // if ((*Value)->Flags & VALUE_COMP_NAME) { Result = CmpCompareCompressedName( Name, (*Value)->Name, (*Value)->NameLength, 0); } else { Candidate.Length = (*Value)->NameLength; Candidate.MaximumLength = Candidate.Length; Candidate.Buffer = (*Value)->Name; Result = RtlCompareUnicodeString( Name, &Candidate, TRUE); } } except (EXCEPTION_EXECUTE_HANDLER) { CmKdPrintEx((DPFLTR_CONFIG_ID,CML_EXCEPTION,"CmpFindValueByNameFromCache: code:%08lx\n", GetExceptionCode())); // // the caller will bail out. Some ,alicious caller altered the Name buffer since we probed it. // *Value = NULL; ret = SearchFail; goto Exit; } ASSERT( Result != 0 ); #endif Result = 1; } else { try { // // Name has user-mode buffer. // if( (*Value)->Flags & VALUE_COMP_NAME) { Result = CmpCompareCompressedName( Name, (*Value)->Name, (*Value)->NameLength, 0); } else { Candidate.Length = (*Value)->NameLength; Candidate.MaximumLength = Candidate.Length; Candidate.Buffer = (*Value)->Name; Result = RtlCompareUnicodeString( Name, &Candidate, TRUE); } } except (EXCEPTION_EXECUTE_HANDLER) { CmKdPrintEx((DPFLTR_CONFIG_ID,CML_EXCEPTION,"CmpFindValueByNameFromCache: code:%08lx\n", GetExceptionCode())); // // the caller will bail out. Some ,alicious caller altered the Name buffer since we probed it. // *Value = NULL; ret = SearchFail; goto Exit; } } if (Result == 0) { // // Success, fill the index, return data to caller and exit // *Index = Current; ret = SearchSuccess; goto Exit; } // // compute the next index to try: old'n plain hive; go on // Current++; if( Current == ChildList->Count ) { // // we've reached the end of the list; nicely return // (*Value) = NULL; ret = SearchFail; goto Exit; } } // while(TRUE)