You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1381 lines
29 KiB
1381 lines
29 KiB
/*++
|
|
|
|
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
|
|
GTabCmpTableFileTimeEntry(
|
|
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 = CompareFileTime((PFILETIME)Entry1->Key1, (PFILETIME)Entry2->Key1);
|
|
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);
|
|
INITIALIZE_CRITICAL_SECTION(>able->Critical);
|
|
RtlInitializeGenericTable(>able->Table,
|
|
GTabCmpTableNumberEntry,
|
|
GTabAllocTableMem,
|
|
GTabFreeTableMem,
|
|
NULL);
|
|
return GTable;
|
|
}
|
|
|
|
|
|
PGEN_TABLE
|
|
GTabAllocFileTimeTable(
|
|
VOID
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Initialize a generic table + lock for file time.
|
|
|
|
Arguments:
|
|
None.
|
|
|
|
Return Value:
|
|
None.
|
|
--*/
|
|
{
|
|
PGEN_TABLE GTable;
|
|
|
|
GTable = FrsAllocType(GEN_TABLE_TYPE);
|
|
INITIALIZE_CRITICAL_SECTION(>able->Critical);
|
|
RtlInitializeGenericTable(>able->Table,
|
|
GTabCmpTableFileTimeEntry,
|
|
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);
|
|
INITIALIZE_CRITICAL_SECTION(>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);
|
|
INITIALIZE_CRITICAL_SECTION(>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);
|
|
INITIALIZE_CRITICAL_SECTION(>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;
|
|
|
|
}
|
|
|
|
PVOID
|
|
GTabInsertUniqueEntryNoLock(
|
|
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;
|
|
|
|
|
|
OldEntry = RtlInsertElementGenericTable(>able->Table,
|
|
&NewEntry,
|
|
sizeof(NewEntry),
|
|
&IsNew);
|
|
|
|
|
|
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);
|
|
}
|