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; }
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)