VOID CmpDereferenceNameControlBlockWithLock( PCM_NAME_CONTROL_BLOCK Ncb ) { PCM_NAME_HASH *Prev; PCM_NAME_HASH Current; if (--Ncb->RefCount == 0) { // // Remove it from the the Hash Table // Prev = &(GET_HASH_ENTRY(CmpNameCacheTable, Ncb->ConvKey)); while (TRUE) { Current = *Prev; ASSERT(Current != NULL); if (Current == &(Ncb->NameHash)) { *Prev = Current->NextHash; break; } Prev = &Current->NextHash; } // // Free storage // ExFreePoolWithTag(Ncb, CM_NAME_TAG | PROTECTED_POOL); } return; }
VOID NTAPI CmpRemoveKeyHash(IN PCM_KEY_HASH KeyHash) { PCM_KEY_HASH *Prev; PCM_KEY_HASH Current; ASSERT_VALID_HASH(KeyHash); /* Lookup all the keys in this index entry */ Prev = &GET_HASH_ENTRY(CmpCacheTable, KeyHash->ConvKey).Entry; while (TRUE) { /* Save the current one and make sure it's valid */ Current = *Prev; ASSERT(Current != NULL); ASSERT_VALID_HASH(Current); /* Check if it matches */ if (Current == KeyHash) { /* Then write the previous one */ *Prev = Current->NextHash; if (*Prev) ASSERT_VALID_HASH(*Prev); break; } /* Otherwise, keep going */ Prev = &Current->NextHash; } }
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); }
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; }