1258 lines
25 KiB
C
1258 lines
25 KiB
C
/*++
|
||
|
||
Copyright (c) 1997-1999 Microsoft Corporation
|
||
|
||
Module Name:
|
||
frstable.c
|
||
|
||
Abstract:
|
||
These routines manage the tables used by the FRS.
|
||
|
||
Author:
|
||
Billy J. Fuller 19-Apr-1997
|
||
|
||
Environment
|
||
User mode winnt
|
||
|
||
--*/
|
||
|
||
|
||
#include <ntreppch.h>
|
||
#pragma hdrstop
|
||
|
||
#define DEBSUB "FRSTABLE:"
|
||
|
||
#include <frs.h>
|
||
|
||
|
||
PVOID
|
||
GTabAllocTableMem(
|
||
IN PRTL_GENERIC_TABLE Table,
|
||
IN DWORD NodeSize
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Allocate space for a table entry. The entry includes the user-defined
|
||
struct and some overhead used by the generic table routines. The
|
||
generic table routines call this function when they need memory.
|
||
|
||
Arguments:
|
||
Table - Address of the table (not used).
|
||
NodeSize - Bytes to allocate
|
||
|
||
Return Value:
|
||
Address of newly allocated memory.
|
||
--*/
|
||
{
|
||
return FrsAlloc(NodeSize);
|
||
}
|
||
|
||
|
||
|
||
|
||
VOID
|
||
GTabFreeTableMem(
|
||
IN PRTL_GENERIC_TABLE Table,
|
||
IN PVOID Buffer
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Free the space allocated by GTAlloc(). The generic table
|
||
routines call this function to free memory.
|
||
|
||
Arguments:
|
||
Table - Address of the table (not used).
|
||
Buffer - Address of previously allocated memory
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
FrsFree(Buffer);
|
||
}
|
||
|
||
|
||
RTL_GENERIC_COMPARE_RESULTS
|
||
GTabCmpTableEntry(
|
||
IN PRTL_GENERIC_TABLE Table,
|
||
IN PVOID TableEntry1,
|
||
IN PVOID TableEntry2
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Compare two entries in the table for guid/names.
|
||
|
||
Arguments:
|
||
Table - Address of the table (not used).
|
||
Entry1 - PGEN_ENTRY
|
||
Entry2 - PGEN_ENTRY
|
||
|
||
Return Value:
|
||
<0 First < Second
|
||
=0 First == Second
|
||
>0 First > Second
|
||
--*/
|
||
{
|
||
INT Cmp;
|
||
PGEN_ENTRY Entry1 = (PGEN_ENTRY)TableEntry1;
|
||
PGEN_ENTRY Entry2 = (PGEN_ENTRY)TableEntry2;
|
||
|
||
//
|
||
// Primary key must be present
|
||
//
|
||
FRS_ASSERT(Entry1->Key1 && Entry2->Key1);
|
||
|
||
//
|
||
// Compare primary keys
|
||
//
|
||
Cmp = memcmp(Entry1->Key1, Entry2->Key1, sizeof(GUID));
|
||
if (Cmp < 0) {
|
||
return (GenericLessThan);
|
||
}
|
||
if (Cmp > 0) {
|
||
return (GenericGreaterThan);
|
||
}
|
||
|
||
//
|
||
// No second key; done
|
||
//
|
||
if (!Entry1->Key2 || !Entry2->Key2)
|
||
return GenericEqual;
|
||
|
||
//
|
||
// Compare secondary keys
|
||
//
|
||
Cmp = _wcsicmp(Entry1->Key2, Entry2->Key2);
|
||
if (Cmp < 0) {
|
||
return (GenericLessThan);
|
||
}
|
||
if (Cmp > 0){
|
||
return (GenericGreaterThan);
|
||
}
|
||
|
||
return (GenericEqual);
|
||
}
|
||
|
||
|
||
RTL_GENERIC_COMPARE_RESULTS
|
||
GTabCmpTableNumberEntry(
|
||
IN PRTL_GENERIC_TABLE Table,
|
||
IN PVOID TableEntry1,
|
||
IN PVOID TableEntry2
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Compare two entries in the table for number
|
||
|
||
Arguments:
|
||
Table - Address of the table (not used).
|
||
Entry1 - PGEN_ENTRY
|
||
Entry2 - PGEN_ENTRY
|
||
|
||
Return Value:
|
||
<0 First < Second
|
||
=0 First == Second
|
||
>0 First > Second
|
||
--*/
|
||
{
|
||
INT Cmp;
|
||
PGEN_ENTRY Entry1 = (PGEN_ENTRY)TableEntry1;
|
||
PGEN_ENTRY Entry2 = (PGEN_ENTRY)TableEntry2;
|
||
|
||
//
|
||
// Primary key must be present
|
||
//
|
||
FRS_ASSERT(Entry1->Key1 && Entry2->Key1);
|
||
|
||
//
|
||
// Compare primary keys
|
||
//
|
||
Cmp = memcmp(Entry1->Key1, Entry2->Key1, sizeof(ULONG));
|
||
if (Cmp < 0) {
|
||
return (GenericLessThan);
|
||
}
|
||
if (Cmp > 0){
|
||
return (GenericGreaterThan);
|
||
}
|
||
|
||
return GenericEqual;
|
||
}
|
||
|
||
|
||
RTL_GENERIC_COMPARE_RESULTS
|
||
GTabCmpTableStringAndBoolEntry(
|
||
IN PRTL_GENERIC_TABLE Table,
|
||
IN PVOID TableEntry1,
|
||
IN PVOID TableEntry2
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Compare two entries in the table for data with strings used as key.
|
||
|
||
Arguments:
|
||
Table - Address of the table (not used).
|
||
Entry1 - PGEN_ENTRY
|
||
Entry2 - PGEN_ENTRY
|
||
|
||
Return Value:
|
||
<0 First < Second
|
||
=0 First == Second
|
||
>0 First > Second
|
||
--*/
|
||
{
|
||
INT Cmp;
|
||
PGEN_ENTRY Entry1 = (PGEN_ENTRY)TableEntry1;
|
||
PGEN_ENTRY Entry2 = (PGEN_ENTRY)TableEntry2;
|
||
|
||
//
|
||
// Primary key must be present
|
||
//
|
||
FRS_ASSERT(Entry1->Key1 && Entry2->Key1);
|
||
|
||
//
|
||
// Compare primary keys
|
||
//
|
||
Cmp = _wcsicmp((PWCHAR)(Entry1->Key1), (PWCHAR)(Entry2->Key1));
|
||
if (Cmp < 0) {
|
||
return (GenericLessThan);
|
||
}
|
||
if (Cmp > 0){
|
||
return (GenericGreaterThan);
|
||
}
|
||
|
||
//
|
||
// Compare secondary keys if they exist.
|
||
//
|
||
|
||
if ((Entry1->Key2 == NULL) || (Entry2->Key2 == NULL)) {
|
||
return GenericEqual;
|
||
}
|
||
|
||
if (*(Entry1->Key2) == *(Entry2->Key2)) {
|
||
return GenericEqual;
|
||
} else if (*(Entry1->Key2) == FALSE) {
|
||
return GenericLessThan;
|
||
}
|
||
|
||
return GenericGreaterThan;
|
||
}
|
||
|
||
|
||
RTL_GENERIC_COMPARE_RESULTS
|
||
GTabCmpTableStringEntry(
|
||
IN PRTL_GENERIC_TABLE Table,
|
||
IN PVOID TableEntry1,
|
||
IN PVOID TableEntry2
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Compare two entries in the table for data with strings used as key.
|
||
|
||
Arguments:
|
||
Table - Address of the table (not used).
|
||
Entry1 - PGEN_ENTRY
|
||
Entry2 - PGEN_ENTRY
|
||
|
||
Return Value:
|
||
<0 First < Second
|
||
=0 First == Second
|
||
>0 First > Second
|
||
--*/
|
||
{
|
||
INT Cmp;
|
||
PGEN_ENTRY Entry1 = (PGEN_ENTRY)TableEntry1;
|
||
PGEN_ENTRY Entry2 = (PGEN_ENTRY)TableEntry2;
|
||
|
||
//
|
||
// Primary key must be present
|
||
//
|
||
FRS_ASSERT(Entry1->Key1 && Entry2->Key1);
|
||
|
||
//
|
||
// Compare primary keys
|
||
//
|
||
Cmp = _wcsicmp((PWCHAR)(Entry1->Key1), (PWCHAR)(Entry2->Key1));
|
||
if (Cmp < 0) {
|
||
return (GenericLessThan);
|
||
}
|
||
if (Cmp > 0){
|
||
return (GenericGreaterThan);
|
||
}
|
||
|
||
//
|
||
// Compare secondary keys if they exist.
|
||
//
|
||
|
||
if ((Entry1->Key2 == NULL) || (Entry2->Key2 == NULL)) {
|
||
return GenericEqual;
|
||
}
|
||
|
||
Cmp = _wcsicmp(Entry1->Key2, Entry2->Key2);
|
||
if (Cmp < 0) {
|
||
return (GenericLessThan);
|
||
}
|
||
if (Cmp > 0){
|
||
return (GenericGreaterThan);
|
||
}
|
||
|
||
return GenericEqual;
|
||
}
|
||
|
||
|
||
VOID
|
||
GTabLockTable(
|
||
PGEN_TABLE GTable
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Lock the table
|
||
|
||
Arguments:
|
||
GTable - frs generic table
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
EnterCriticalSection(>able->Critical);
|
||
}
|
||
|
||
|
||
VOID
|
||
GTabUnLockTable(
|
||
PGEN_TABLE GTable
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Unlock the table
|
||
|
||
Arguments:
|
||
GTable - frs generic table
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
LeaveCriticalSection(>able->Critical);
|
||
}
|
||
|
||
|
||
PGEN_TABLE
|
||
GTabAllocNumberTable(
|
||
VOID
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Initialize a generic table + lock for numbers.
|
||
|
||
Arguments:
|
||
None.
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
PGEN_TABLE GTable;
|
||
|
||
GTable = FrsAllocType(GEN_TABLE_TYPE);
|
||
InitializeCriticalSection(>able->Critical);
|
||
RtlInitializeGenericTable(>able->Table,
|
||
GTabCmpTableNumberEntry,
|
||
GTabAllocTableMem,
|
||
GTabFreeTableMem,
|
||
NULL);
|
||
return GTable;
|
||
}
|
||
|
||
|
||
PGEN_TABLE
|
||
GTabAllocStringTable(
|
||
VOID
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Initialize a generic table + lock for data with strings
|
||
used as a key.
|
||
|
||
Arguments:
|
||
None.
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
PGEN_TABLE GTable;
|
||
|
||
GTable = FrsAllocType(GEN_TABLE_TYPE);
|
||
InitializeCriticalSection(>able->Critical);
|
||
RtlInitializeGenericTable(>able->Table,
|
||
GTabCmpTableStringEntry,
|
||
GTabAllocTableMem,
|
||
GTabFreeTableMem,
|
||
NULL);
|
||
return GTable;
|
||
}
|
||
|
||
|
||
PGEN_TABLE
|
||
GTabAllocStringAndBoolTable(
|
||
VOID
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Initialize a generic table + lock for data with a string and bool
|
||
used as a key.
|
||
|
||
Arguments:
|
||
None.
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
PGEN_TABLE GTable;
|
||
|
||
GTable = FrsAllocType(GEN_TABLE_TYPE);
|
||
InitializeCriticalSection(>able->Critical);
|
||
RtlInitializeGenericTable(>able->Table,
|
||
GTabCmpTableStringAndBoolEntry,
|
||
GTabAllocTableMem,
|
||
GTabFreeTableMem,
|
||
NULL);
|
||
return GTable;
|
||
}
|
||
|
||
|
||
PGEN_TABLE
|
||
GTabAllocTable(
|
||
VOID
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Initialize a generic table + lock.
|
||
|
||
Arguments:
|
||
None.
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
PGEN_TABLE GTable;
|
||
|
||
GTable = FrsAllocType(GEN_TABLE_TYPE);
|
||
InitializeCriticalSection(>able->Critical);
|
||
RtlInitializeGenericTable(>able->Table,
|
||
GTabCmpTableEntry,
|
||
GTabAllocTableMem,
|
||
GTabFreeTableMem,
|
||
NULL);
|
||
return GTable;
|
||
}
|
||
|
||
|
||
VOID
|
||
GTabEmptyTableNoLock(
|
||
IN PGEN_TABLE GTable,
|
||
IN PVOID (*CallerFree)(PVOID)
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Free every entry in the frs generic table. Caller has acquired the table lock.
|
||
|
||
Arguments:
|
||
|
||
GTable - frs generic table
|
||
CallerFree - The free routine to use to free up the callers datum (optional)
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
PGEN_ENTRY Entry; // Next entry in table
|
||
PGEN_ENTRY Dup; // Next entry in table
|
||
PVOID Data;
|
||
|
||
//
|
||
// For every entry in the table
|
||
//
|
||
while (Entry = RtlEnumerateGenericTable(>able->Table, TRUE)) {
|
||
//
|
||
// Delete the dups
|
||
//
|
||
while (Dup = Entry->Dups) {
|
||
Entry->Dups = Dup->Dups;
|
||
if (CallerFree) {
|
||
//
|
||
// Free up the callers Datum
|
||
//
|
||
(*CallerFree)(Dup->Data);
|
||
}
|
||
Dup = FrsFree(Dup);
|
||
}
|
||
|
||
//
|
||
// Delete the entry from the table
|
||
//
|
||
Data = Entry->Data;
|
||
RtlDeleteElementGenericTable(>able->Table, Entry);
|
||
if (CallerFree) {
|
||
//
|
||
// Free up the callers Datum
|
||
//
|
||
(*CallerFree)(Data);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
GTabEmptyTable(
|
||
IN PGEN_TABLE GTable,
|
||
IN PVOID (*CallerFree)(PVOID)
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Free every entry in the frs generic table.
|
||
|
||
Arguments:
|
||
|
||
GTable - frs generic table
|
||
CallerFree - The free routine to use to free up the callers datum (optional)
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
GTabLockTable(GTable);
|
||
|
||
GTabEmptyTableNoLock(GTable, CallerFree);
|
||
|
||
GTabUnLockTable(GTable);
|
||
}
|
||
|
||
|
||
|
||
|
||
PVOID
|
||
GTabFreeTable(
|
||
IN PGEN_TABLE GTable,
|
||
IN PVOID (*CallerFree)(PVOID)
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Undo the work done by GenTableInitialize.
|
||
|
||
Arguments:
|
||
GTTable - Address of the gen table.
|
||
CallerFree - The free routine to use to free up the callers datum (optional)
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
if (GTable == NULL) {
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// Empty the table
|
||
//
|
||
GTabEmptyTable(GTable, CallerFree);
|
||
|
||
DeleteCriticalSection(>able->Critical);
|
||
return FrsFreeType(GTable);
|
||
}
|
||
|
||
PVOID
|
||
GTabLookupNoLock(
|
||
IN PGEN_TABLE GTable,
|
||
IN GUID *Key1,
|
||
IN PWCHAR Key2
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Find the entry in the table.
|
||
|
||
Arguments:
|
||
GTable - frs generic table
|
||
Key1 - primary key
|
||
Key2 - secondary key (may be NULL)
|
||
|
||
Return Value:
|
||
Data for an entry or NULL
|
||
--*/
|
||
{
|
||
PVOID Data;
|
||
PGEN_ENTRY Entry; // entry in table
|
||
GEN_ENTRY Key; // Search key
|
||
|
||
FRS_ASSERT(Key1);
|
||
|
||
//
|
||
// Set up a search key that is suitable for any table
|
||
//
|
||
Key.Key1 = Key1;
|
||
Key.Key2 = Key2;
|
||
|
||
//
|
||
// Search the table
|
||
//
|
||
Entry = (PVOID)RtlLookupElementGenericTable(>able->Table, &Key);
|
||
Data = (Entry) ? Entry->Data : NULL;
|
||
return Data;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
PVOID
|
||
GTabLookup(
|
||
IN PGEN_TABLE GTable,
|
||
IN GUID *Key1,
|
||
IN PWCHAR Key2
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Find the data for an entry in the table.
|
||
|
||
Arguments:
|
||
GTable - frs generic table
|
||
Key1 - primary key
|
||
Key2 - secondary key (may be NULL)
|
||
|
||
Return Value:
|
||
Data for an entry or NULL
|
||
--*/
|
||
{
|
||
PVOID Data;
|
||
PGEN_ENTRY Entry; // entry in table
|
||
GEN_ENTRY Key; // Search key
|
||
|
||
FRS_ASSERT(Key1);
|
||
|
||
//
|
||
// Set up a search key that is suitable for any table
|
||
//
|
||
Key.Key1 = Key1;
|
||
Key.Key2 = Key2;
|
||
|
||
//
|
||
// Search the table
|
||
//
|
||
GTabLockTable(GTable);
|
||
Entry = (PVOID)RtlLookupElementGenericTable(>able->Table, &Key);
|
||
Data = (Entry) ? Entry->Data : NULL;
|
||
GTabUnLockTable(GTable);
|
||
return Data;
|
||
}
|
||
|
||
|
||
BOOL
|
||
GTabIsEntryPresent(
|
||
IN PGEN_TABLE GTable,
|
||
IN GUID *Key1,
|
||
IN PWCHAR Key2
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Find the entry in the table and return TRUE if found.
|
||
|
||
Arguments:
|
||
GTable - frs generic table
|
||
Key1 - primary key
|
||
Key2 - secondary key (may be NULL)
|
||
|
||
Return Value:
|
||
Boolean
|
||
--*/
|
||
{
|
||
PVOID Data;
|
||
PGEN_ENTRY Entry; // entry in table
|
||
GEN_ENTRY Key; // Search key
|
||
|
||
FRS_ASSERT(Key1);
|
||
|
||
//
|
||
// Set up a search key that is suitable for any table
|
||
//
|
||
Key.Key1 = Key1;
|
||
Key.Key2 = Key2;
|
||
|
||
//
|
||
// Search the table
|
||
//
|
||
GTabLockTable(GTable);
|
||
Entry = (PVOID)RtlLookupElementGenericTable(>able->Table, &Key);
|
||
GTabUnLockTable(GTable);
|
||
return (Entry != NULL);
|
||
}
|
||
|
||
|
||
PVOID
|
||
GTabLookupTableString(
|
||
IN PGEN_TABLE GTable,
|
||
IN PWCHAR Key1,
|
||
IN PWCHAR Key2
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Find the data for an entry in the table that is indexed by string.
|
||
|
||
Arguments:
|
||
GTable - frs generic table
|
||
Key1 - primary key
|
||
Key2 - secondary key (may be NULL)
|
||
|
||
Return Value:
|
||
Data for an entry or NULL
|
||
--*/
|
||
{
|
||
PVOID Data;
|
||
PGEN_ENTRY Entry; // entry in table
|
||
GEN_ENTRY Key; // Search key
|
||
|
||
FRS_ASSERT(Key1);
|
||
|
||
//
|
||
// Set up a search key that is suitable for any table
|
||
//
|
||
Key.Key1 = (GUID *)Key1;
|
||
Key.Key2 = Key2;
|
||
|
||
//
|
||
// Search the table
|
||
//
|
||
GTabLockTable(GTable);
|
||
Entry = (PVOID)RtlLookupElementGenericTable(>able->Table, &Key);
|
||
Data = (Entry) ? Entry->Data : NULL;
|
||
GTabUnLockTable(GTable);
|
||
return Data;
|
||
}
|
||
|
||
|
||
PGEN_ENTRY
|
||
GTabLookupEntryNoLock(
|
||
IN PGEN_TABLE GTable,
|
||
IN GUID *Key1,
|
||
IN PWCHAR Key2
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Find the data for an entry in the table.
|
||
|
||
Arguments:
|
||
GTable - frs generic table
|
||
Key1 - primary key
|
||
Key2 - secondary key (may be NULL)
|
||
|
||
Return Value:
|
||
Data for an entry or NULL
|
||
--*/
|
||
{
|
||
PGEN_ENTRY Entry; // entry in table
|
||
GEN_ENTRY Key; // Search key
|
||
|
||
FRS_ASSERT(Key1);
|
||
|
||
//
|
||
// Set up a search key that is suitable for any table
|
||
//
|
||
Key.Key1 = Key1;
|
||
Key.Key2 = Key2;
|
||
|
||
//
|
||
// Search the table
|
||
//
|
||
Entry = (PVOID)RtlLookupElementGenericTable(>able->Table, &Key);
|
||
return Entry;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
PGEN_ENTRY
|
||
GTabNextEntryNoLock(
|
||
PGEN_TABLE GTable,
|
||
PVOID *Key
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Return the entry for Key in GTable. The caller is responsible for
|
||
insuring synchronization.
|
||
|
||
Arguments:
|
||
GTable - frs generic table
|
||
Key - NULL on first call
|
||
|
||
Return Value:
|
||
The address of an entry in the table or NULL.
|
||
--*/
|
||
{
|
||
PGEN_ENTRY Entry;
|
||
//
|
||
// Return the entry's address
|
||
//
|
||
Entry = (PVOID)RtlEnumerateGenericTableWithoutSplaying(>able->Table, Key);
|
||
return Entry;
|
||
}
|
||
|
||
|
||
PVOID
|
||
GTabNextDatumNoLock(
|
||
PGEN_TABLE GTable,
|
||
PVOID *Key
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Return the data for the entry for Key in GTable.
|
||
Caller acquires the table lock.
|
||
|
||
Arguments:
|
||
GTable - frs generic table
|
||
Key - NULL on first call
|
||
GetData - return the entry or the data for the entry
|
||
|
||
Return Value:
|
||
The address of an entry in the table or NULL.
|
||
--*/
|
||
{
|
||
PVOID Data;
|
||
PGEN_ENTRY Entry;
|
||
|
||
//
|
||
// Return the address of the entry's data
|
||
//
|
||
Entry = GTabNextEntryNoLock(GTable, Key);
|
||
Data = (Entry) ? Entry->Data : NULL;
|
||
return Data;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
PVOID
|
||
GTabNextDatum(
|
||
PGEN_TABLE GTable,
|
||
PVOID *Key
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Return the data for the entry for Key in GTable.
|
||
|
||
Arguments:
|
||
GTable - frs generic table
|
||
Key - NULL on first call
|
||
GetData - return the entry or the data for the entry
|
||
|
||
Return Value:
|
||
The address of an entry in the table or NULL.
|
||
--*/
|
||
{
|
||
PVOID Data;
|
||
PGEN_ENTRY Entry;
|
||
|
||
//
|
||
// Return the address of the entry's data
|
||
//
|
||
GTabLockTable(GTable);
|
||
Entry = GTabNextEntryNoLock(GTable, Key);
|
||
Data = (Entry) ? Entry->Data : NULL;
|
||
GTabUnLockTable(GTable);
|
||
return Data;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
DWORD
|
||
GTabNumberInTable(
|
||
PGEN_TABLE GTable
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Return the number of entries in a table.
|
||
|
||
Arguments:
|
||
GTable - frs generic table
|
||
|
||
Return Value:
|
||
Number of entries in the table.
|
||
--*/
|
||
{
|
||
if (GTable) {
|
||
return RtlNumberGenericTableElements(>able->Table);
|
||
} else {
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
|
||
PVOID
|
||
GTabInsertUniqueEntry(
|
||
IN PGEN_TABLE GTable,
|
||
IN PVOID NewData,
|
||
IN PVOID Key1,
|
||
IN PVOID Key2
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Insert an entry into the table. If a duplicate is found then
|
||
return the original entry. Do not insert in that case.
|
||
|
||
Arguments:
|
||
GTable - frs generic table
|
||
NewData - data for the entry to insert
|
||
Key1 - primary key
|
||
Key2 - secondary key (may be NULL)
|
||
|
||
Return Value:
|
||
NULL if the entry was successfully inserted in the table.
|
||
Pointer to the data from old entry if a collision is found.
|
||
--*/
|
||
{
|
||
PGEN_ENTRY OldEntry; // Existing entry in the table
|
||
BOOLEAN IsNew; // TRUE if insert found existing entry
|
||
GEN_ENTRY NewEntry; // new entry to insert.
|
||
PGEN_ENTRY DupEntry; // Newly allocated table entry for duplicate.
|
||
|
||
//
|
||
// Init the new entry. Have to typecast here becasue the GEN_ENTRY expects a GUID* and PWCHAR.
|
||
//
|
||
NewEntry.Data = NewData;
|
||
NewEntry.Key1 = (GUID*)Key1;
|
||
NewEntry.Key2 = (PWCHAR)Key2;
|
||
NewEntry.Dups = NULL;
|
||
|
||
//
|
||
// Lock the table and Insert the entry
|
||
//
|
||
GTabLockTable(GTable);
|
||
OldEntry = RtlInsertElementGenericTable(>able->Table,
|
||
&NewEntry,
|
||
sizeof(NewEntry),
|
||
&IsNew);
|
||
|
||
GTabUnLockTable(GTable);
|
||
|
||
if (!IsNew) {
|
||
return OldEntry;
|
||
}
|
||
|
||
return NULL;
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
GTabInsertEntry(
|
||
IN PGEN_TABLE GTable,
|
||
IN PVOID NewData,
|
||
IN GUID *Key1,
|
||
IN PWCHAR Key2
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Insert an entry into the table. Duplicates are simply linked
|
||
to the current entry.
|
||
|
||
Arguments:
|
||
GTable - frs generic table
|
||
NewData - data for the entry to insert
|
||
Key1 - primary key
|
||
Key2 - secondary key (may be NULL)
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
PGEN_ENTRY OldEntry; // Existing entry in the table
|
||
BOOLEAN IsNew; // TRUE if insert found existing entry
|
||
GEN_ENTRY NewEntry; // new entry to insert.
|
||
PGEN_ENTRY DupEntry; // Newly allocated table entry for duplicate.
|
||
|
||
//
|
||
// Init the new entry.
|
||
//
|
||
NewEntry.Data = NewData;
|
||
NewEntry.Key1 = Key1;
|
||
NewEntry.Key2 = Key2;
|
||
NewEntry.Dups = NULL;
|
||
|
||
//
|
||
// Lock the table and Insert the entry
|
||
//
|
||
GTabLockTable(GTable);
|
||
OldEntry = RtlInsertElementGenericTable(>able->Table,
|
||
&NewEntry,
|
||
sizeof(NewEntry),
|
||
&IsNew);
|
||
if (!IsNew) {
|
||
//
|
||
// Duplicate entry; add to list
|
||
//
|
||
DupEntry = FrsAlloc(sizeof(GEN_ENTRY));
|
||
CopyMemory(DupEntry, &NewEntry, sizeof(NewEntry));
|
||
DupEntry->Dups = OldEntry->Dups;
|
||
OldEntry->Dups = DupEntry;
|
||
}
|
||
GTabUnLockTable(GTable);
|
||
}
|
||
|
||
|
||
VOID
|
||
GTabInsertEntryNoLock(
|
||
IN PGEN_TABLE GTable,
|
||
IN PVOID NewData,
|
||
IN GUID *Key1,
|
||
IN PWCHAR Key2
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Insert an entry into the table. Duplicates are simply linked
|
||
to the current entry.
|
||
|
||
Caller acquires the table lock.
|
||
|
||
Arguments:
|
||
GTable - frs generic table
|
||
NewData - data for the entry to insert
|
||
Key1 - primary key
|
||
Key2 - secondary key (may be NULL)
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
PGEN_ENTRY OldEntry; // Existing entry in the table
|
||
BOOLEAN IsNew; // TRUE if insert found existing entry
|
||
GEN_ENTRY NewEntry; // new entry to insert.
|
||
PGEN_ENTRY DupEntry; // Newly allocated table entry for duplicate.
|
||
|
||
//
|
||
// Init the new entry.
|
||
//
|
||
NewEntry.Data = NewData;
|
||
NewEntry.Key1 = Key1;
|
||
NewEntry.Key2 = Key2;
|
||
NewEntry.Dups = NULL;
|
||
|
||
//
|
||
// Lock the table and Insert the entry
|
||
//
|
||
OldEntry = RtlInsertElementGenericTable(>able->Table,
|
||
&NewEntry,
|
||
sizeof(NewEntry),
|
||
&IsNew);
|
||
if (!IsNew) {
|
||
//
|
||
// Duplicate entry; add to list
|
||
//
|
||
DupEntry = FrsAlloc(sizeof(GEN_ENTRY));
|
||
CopyMemory(DupEntry, &NewEntry, sizeof(NewEntry));
|
||
DupEntry->Dups = OldEntry->Dups;
|
||
OldEntry->Dups = DupEntry;
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
GTabDelete(
|
||
IN PGEN_TABLE GTable,
|
||
IN GUID *Key1,
|
||
IN PWCHAR Key2,
|
||
IN PVOID (*CallerFree)(PVOID)
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Delete the entry in the table.
|
||
|
||
Arguments:
|
||
GTable - frs generic table
|
||
Key1 - primary key
|
||
Key2 - secondary key (may be NULL)
|
||
CallerFree - The free routine to use to free up the callers datum (optional)
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
GEN_ENTRY Key; // Search key
|
||
PGEN_ENTRY Entry; // entry in table
|
||
PGEN_ENTRY Dup; // dup entry in table
|
||
PVOID Data;
|
||
|
||
FRS_ASSERT(Key1);
|
||
|
||
//
|
||
// Set up a search key that is suitable for either table
|
||
//
|
||
Key.Key1 = Key1;
|
||
Key.Key2 = Key2;
|
||
|
||
//
|
||
// Find the entry
|
||
//
|
||
GTabLockTable(GTable);
|
||
Entry = (PVOID)RtlLookupElementGenericTable(>able->Table, &Key);
|
||
if (Entry == NULL) {
|
||
goto out;
|
||
}
|
||
|
||
//
|
||
// Delete the dups
|
||
//
|
||
while (Dup = Entry->Dups) {
|
||
Entry->Dups = Dup->Dups;
|
||
if (CallerFree) {
|
||
//
|
||
// Free up the callers Datum
|
||
//
|
||
(*CallerFree)(Dup->Data);
|
||
}
|
||
Dup = FrsFree(Dup);
|
||
}
|
||
|
||
//
|
||
// Delete entry
|
||
//
|
||
Data = Entry->Data;
|
||
RtlDeleteElementGenericTable(>able->Table, Entry);
|
||
if (CallerFree) {
|
||
//
|
||
// Free up the callers Datum
|
||
//
|
||
(*CallerFree)(Data);
|
||
}
|
||
|
||
out:
|
||
GTabUnLockTable(GTable);
|
||
}
|
||
|
||
|
||
VOID
|
||
GTabDeleteNoLock(
|
||
IN PGEN_TABLE GTable,
|
||
IN GUID *Key1,
|
||
IN PWCHAR Key2,
|
||
IN PVOID (*CallerFree)(PVOID)
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Delete the entry in the table.
|
||
|
||
Arguments:
|
||
GTable - frs generic table
|
||
Key1 - primary key
|
||
Key2 - secondary key (may be NULL)
|
||
CallerFree - The free routine to use to free up the callers datum (optional)
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
GEN_ENTRY Key; // Search key
|
||
PGEN_ENTRY Entry; // entry in table
|
||
PGEN_ENTRY Dup; // dup entry in table
|
||
PVOID Data;
|
||
|
||
FRS_ASSERT(Key1);
|
||
|
||
//
|
||
// Set up a search key that is suitable for either table
|
||
//
|
||
Key.Key1 = Key1;
|
||
Key.Key2 = Key2;
|
||
|
||
//
|
||
// Find the entry
|
||
//
|
||
Entry = (PVOID)RtlLookupElementGenericTable(>able->Table, &Key);
|
||
if (Entry == NULL) {
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Delete the dups
|
||
//
|
||
while (Dup = Entry->Dups) {
|
||
Entry->Dups = Dup->Dups;
|
||
if (CallerFree) {
|
||
//
|
||
// Free up the callers Datum
|
||
//
|
||
(*CallerFree)(Dup->Data);
|
||
}
|
||
Dup = FrsFree(Dup);
|
||
}
|
||
|
||
//
|
||
// Delete entry
|
||
//
|
||
Data = Entry->Data;
|
||
RtlDeleteElementGenericTable(>able->Table, Entry);
|
||
if (CallerFree) {
|
||
//
|
||
// Free up the callers Datum
|
||
//
|
||
(*CallerFree)(Data);
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
GTabPrintTable(
|
||
IN PGEN_TABLE GTable
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Print the table and all of its dups.
|
||
|
||
Arguments:
|
||
GTable - frs generic table
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
PGEN_ENTRY Entry;
|
||
PGEN_ENTRY Dup;
|
||
PVOID Key;
|
||
CHAR Guid[GUID_CHAR_LEN + 1];
|
||
|
||
//
|
||
// print the entries
|
||
//
|
||
GTabLockTable(GTable);
|
||
Key = NULL;
|
||
|
||
while (Entry = GTabNextEntryNoLock(GTable, &Key)) {
|
||
|
||
GuidToStr(Entry->Key1, &Guid[0]);
|
||
if (Entry->Key2) {
|
||
DPRINT3(0, "\t0x%x %s %ws\n", Entry->Data, Guid, Entry->Key2);
|
||
} else {
|
||
DPRINT2(0, "\t0x%x %s NULL\n", Entry->Data, Guid);
|
||
}
|
||
|
||
for (Dup = Entry->Dups; Dup; Dup = Dup->Dups) {
|
||
|
||
GuidToStr(Entry->Key1, &Guid[0]);
|
||
if (Dup->Key2) {
|
||
DPRINT3(0, "\t0x%x %s %ws\n", Dup->Data, Guid, Dup->Key2);
|
||
} else {
|
||
DPRINT2(0, "\t0x%x %s NULL\n", Dup->Data, Guid);
|
||
}
|
||
}
|
||
}
|
||
|
||
GTabUnLockTable(GTable);
|
||
}
|