windows-nt/Source/XPSP1/NT/drivers/storage/classpnp/dictlib.c

216 lines
4 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (C) Microsoft Corporation, 1990 - 1999
Module Name:
dictlib.c
Abstract:
Support library for maintaining a dictionary list (list of objects
referenced by a key value).
Environment:
kernel mode only
Notes:
This module generates a static library
Revision History:
--*/
#include <ntddk.h>
#include <classpnp.h>
#define DICTIONARY_SIGNATURE (((ULONG)'dict' << 32) + 'sig ')
struct _DICTIONARY_HEADER {
PDICTIONARY_HEADER Next;
ULONGLONG Key;
UCHAR Data[0];
};
struct _DICTIONARY_HEADER;
typedef struct _DICTIONARY_HEADER DICTIONARY_HEADER, *PDICTIONARY_HEADER;
VOID
InitializeDictionary(
IN PDICTIONARY Dictionary
)
{
RtlZeroMemory(Dictionary, sizeof(Dictionary));
Dictionary->Signature = DICTIONARY_SIGNATURE;
KeInitializeSpinLock(&Dictionary->SpinLock);
return;
}
BOOLEAN
TestDictionarySignature(
IN PDICTIONARY Dictionary
)
{
return Dictionary->Signature == DICTIONARY_SIGNATURE;
}
NTSTATUS
AllocateDictionaryEntry(
IN PDICTIONARY Dictionary,
IN ULONGLONG Key,
IN ULONG Size,
IN ULONG Tag,
OUT PVOID *Entry
)
{
PDICTIONARY_HEADER header;
KIRQL oldIrql;
PDICTIONARY_HEADER *entry;
NTSTATUS status = STATUS_SUCCESS;
*Entry = NULL;
header = ExAllocatePoolWithTag(NonPagedPool,
Size + sizeof(DICTIONARY_HEADER),
Tag);
if(header == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(header, sizeof(DICTIONARY_HEADER) + Size);
header->Key = Key;
//
// Find the correct location for this entry in the dictionary.
//
KeAcquireSpinLock(&(Dictionary->SpinLock), &oldIrql);
TRY {
entry = &(Dictionary->List);
while(*entry != NULL) {
if((*entry)->Key == Key) {
//
// Dictionary must have unique keys.
//
status = STATUS_OBJECT_NAME_COLLISION;
LEAVE;
} else if ((*entry)->Key < Key) {
//
// We will go ahead and insert the key in here.
//
break;
} else {
entry = &((*entry)->Next);
}
}
//
// If we make it here then we will go ahead and do the insertion.
//
header->Next = *entry;
*entry = header;
} FINALLY {
KeReleaseSpinLock(&(Dictionary->SpinLock), oldIrql);
if(!NT_SUCCESS(status)) {
ExFreePool(header);
} else {
*Entry = (PVOID) header->Data;
}
}
return status;
}
PVOID
GetDictionaryEntry(
IN PDICTIONARY Dictionary,
IN ULONGLONG Key
)
{
PDICTIONARY_HEADER entry;
PVOID data;
KIRQL oldIrql;
data = NULL;
KeAcquireSpinLock(&(Dictionary->SpinLock), &oldIrql);
entry = Dictionary->List;
while (entry != NULL) {
if (entry->Key == Key) {
data = entry->Data;
break;
} else {
entry = entry->Next;
}
}
KeReleaseSpinLock(&(Dictionary->SpinLock), oldIrql);
return data;
}
VOID
FreeDictionaryEntry(
IN PDICTIONARY Dictionary,
IN PVOID Entry
)
{
PDICTIONARY_HEADER header;
PDICTIONARY_HEADER *entry;
KIRQL oldIrql;
BOOLEAN found;
found = FALSE;
header = CONTAINING_RECORD(Entry, DICTIONARY_HEADER, Data);
KeAcquireSpinLock(&(Dictionary->SpinLock), &oldIrql);
entry = &(Dictionary->List);
while(*entry != NULL) {
if(*entry == header) {
*entry = header->Next;
found = TRUE;
break;
} else {
entry = &(*entry)->Next;
}
}
KeReleaseSpinLock(&(Dictionary->SpinLock), oldIrql);
//
// calling this w/an invalid pointer invalidates the dictionary system,
// so ASSERT() that we never try to Free something not in the list
//
ASSERT(found);
if (found) {
ExFreePool(header);
}
return;
}