reactos/drivers/storage/class/classpnp/dictlib.c
2021-06-11 15:33:08 +03:00

232 lines
4.4 KiB
C

/*++
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>
#ifdef __REACTOS__
#undef MdlMappingNoExecute
#define MdlMappingNoExecute 0
#define NonPagedPoolNx NonPagedPool
#define NonPagedPoolNxCacheAligned NonPagedPoolCacheAligned
#undef POOL_NX_ALLOCATION
#define POOL_NX_ALLOCATION 0
#endif
#define DICTIONARY_SIGNATURE 'tciD'
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4200) // nonstandard extension used : zero-sized array in struct/union
#endif
struct _DICTIONARY_HEADER {
PDICTIONARY_HEADER Next;
ULONGLONG Key;
UCHAR Data[0];
};
#ifdef _MSC_VER
#pragma warning(pop)
#endif
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_range_(0, sizeof(FILE_OBJECT_EXTENSION)) 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(NonPagedPoolNx,
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)) {
FREE_POOL(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 NT_ASSERT() that we never try to Free something not in the list
//
NT_ASSERT(found);
if (found) {
FREE_POOL(header);
}
return;
}