581 lines
15 KiB
C
581 lines
15 KiB
C
/*++ BUILD Version: 0005 // Increment this if a change has global effects
|
||
|
||
Copyright (c) 1989-1999 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
llsrtl.h
|
||
|
||
Abstract:
|
||
|
||
Include file for NT runtime routines that are callable by both
|
||
kernel mode code in the executive and user mode code in various
|
||
NT subsystems.
|
||
|
||
Author:
|
||
|
||
Steve Wood (stevewo) 31-Mar-1989
|
||
|
||
Environment:
|
||
|
||
These routines are statically linked in the caller's executable and
|
||
are callable in either kernel mode or user mode.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#ifndef _LLSRTL_
|
||
#define _LLSRTL_
|
||
|
||
#if defined (_MSC_VER)
|
||
#if ( _MSC_VER >= 800 )
|
||
#pragma warning(disable:4514)
|
||
#if _MSC_VER >= 1200
|
||
#pragma warning(push)
|
||
#endif
|
||
#pragma warning(disable:4001)
|
||
#pragma warning(disable:4201)
|
||
#pragma warning(disable:4214)
|
||
#endif
|
||
#if (_MSC_VER > 1020)
|
||
#pragma once
|
||
#endif
|
||
#endif
|
||
|
||
// begin_ntddk begin_wdm begin_winnt begin_ntifs begin_nthal
|
||
//
|
||
// for move macros
|
||
//
|
||
#ifdef _MAC
|
||
#ifndef _INC_STRING
|
||
#include <string.h>
|
||
#endif /* _INC_STRING */
|
||
#else
|
||
#include <string.h>
|
||
#endif // _MAC
|
||
|
||
// end_ntddk end_wdm end_winnt end_ntifs end_nthal
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
// begin_ntddk begin_wdm begin_nthal begin_ntifs begin_ntndis
|
||
//
|
||
// If debugging support enabled, define an ASSERT macro that works. Otherwise
|
||
// define the ASSERT macro to expand to an empty expression.
|
||
//
|
||
|
||
#if DBG
|
||
|
||
NTSYSAPI
|
||
VOID
|
||
NTAPI
|
||
RtlAssert(
|
||
PVOID FailedAssertion,
|
||
PVOID FileName,
|
||
ULONG LineNumber,
|
||
PCHAR Message
|
||
);
|
||
|
||
#ifndef ASSERT
|
||
#define ASSERT( exp ) \
|
||
((!(exp)) ? \
|
||
RtlAssert( #exp, __FILE__, __LINE__, NULL ) : \
|
||
((void)0))
|
||
#endif
|
||
|
||
#ifndef ASSERTMSG
|
||
#define ASSERTMSG( msg, exp ) \
|
||
((!(exp)) ? \
|
||
RtlAssert( #exp, __FILE__, __LINE__, msg ) : \
|
||
((void)0))
|
||
#endif
|
||
|
||
#else
|
||
#ifndef ASSERT
|
||
#define ASSERT( exp ) ((void)0)
|
||
#endif
|
||
|
||
#ifndef ASSERTMSG
|
||
#define ASSERTMSG( msg, exp ) ((void)0)
|
||
#endif
|
||
#endif // DBG
|
||
|
||
// end_ntddk end_wdm end_nthal end_ntifs end_ntndis
|
||
|
||
// begin_ntddk begin_wdm begin_nthal begin_ntifs begin_ntndis
|
||
//
|
||
// Doubly-linked list manipulation routines. Implemented as macros
|
||
// but logically these are procedures.
|
||
//
|
||
|
||
//
|
||
// VOID
|
||
// InitializeListHead(
|
||
// PLIST_ENTRY ListHead
|
||
// );
|
||
//
|
||
|
||
#define InitializeListHead(ListHead) (\
|
||
(ListHead)->Flink = (ListHead)->Blink = (ListHead))
|
||
|
||
//
|
||
// BOOLEAN
|
||
// IsListEmpty(
|
||
// PLIST_ENTRY ListHead
|
||
// );
|
||
//
|
||
|
||
#define IsListEmpty(ListHead) \
|
||
((ListHead)->Flink == (ListHead))
|
||
|
||
//
|
||
// PLIST_ENTRY
|
||
// RemoveHeadList(
|
||
// PLIST_ENTRY ListHead
|
||
// );
|
||
//
|
||
|
||
#define RemoveHeadList(ListHead) \
|
||
(ListHead)->Flink;\
|
||
{RemoveEntryList((ListHead)->Flink)}
|
||
|
||
//
|
||
// PLIST_ENTRY
|
||
// RemoveTailList(
|
||
// PLIST_ENTRY ListHead
|
||
// );
|
||
//
|
||
|
||
#define RemoveTailList(ListHead) \
|
||
(ListHead)->Blink;\
|
||
{RemoveEntryList((ListHead)->Blink)}
|
||
|
||
//
|
||
// VOID
|
||
// RemoveEntryList(
|
||
// PLIST_ENTRY Entry
|
||
// );
|
||
//
|
||
|
||
#define RemoveEntryList(Entry) {\
|
||
PLIST_ENTRY _EX_Blink;\
|
||
PLIST_ENTRY _EX_Flink;\
|
||
_EX_Flink = (Entry)->Flink;\
|
||
_EX_Blink = (Entry)->Blink;\
|
||
_EX_Blink->Flink = _EX_Flink;\
|
||
_EX_Flink->Blink = _EX_Blink;\
|
||
}
|
||
|
||
//
|
||
// VOID
|
||
// InsertTailList(
|
||
// PLIST_ENTRY ListHead,
|
||
// PLIST_ENTRY Entry
|
||
// );
|
||
//
|
||
|
||
#define InsertTailList(ListHead,Entry) {\
|
||
PLIST_ENTRY _EX_Blink;\
|
||
PLIST_ENTRY _EX_ListHead;\
|
||
_EX_ListHead = (ListHead);\
|
||
_EX_Blink = _EX_ListHead->Blink;\
|
||
(Entry)->Flink = _EX_ListHead;\
|
||
(Entry)->Blink = _EX_Blink;\
|
||
_EX_Blink->Flink = (Entry);\
|
||
_EX_ListHead->Blink = (Entry);\
|
||
}
|
||
|
||
//
|
||
// VOID
|
||
// InsertHeadList(
|
||
// PLIST_ENTRY ListHead,
|
||
// PLIST_ENTRY Entry
|
||
// );
|
||
//
|
||
|
||
#define InsertHeadList(ListHead,Entry) {\
|
||
PLIST_ENTRY _EX_Flink;\
|
||
PLIST_ENTRY _EX_ListHead;\
|
||
_EX_ListHead = (ListHead);\
|
||
_EX_Flink = _EX_ListHead->Flink;\
|
||
(Entry)->Flink = _EX_Flink;\
|
||
(Entry)->Blink = _EX_ListHead;\
|
||
_EX_Flink->Blink = (Entry);\
|
||
_EX_ListHead->Flink = (Entry);\
|
||
}
|
||
|
||
//
|
||
//
|
||
// PSINGLE_LIST_ENTRY
|
||
// PopEntryList(
|
||
// PSINGLE_LIST_ENTRY ListHead
|
||
// );
|
||
//
|
||
|
||
#define PopEntryList(ListHead) \
|
||
(ListHead)->Next;\
|
||
{\
|
||
PSINGLE_LIST_ENTRY FirstEntry;\
|
||
FirstEntry = (ListHead)->Next;\
|
||
if (FirstEntry != NULL) { \
|
||
(ListHead)->Next = FirstEntry->Next;\
|
||
} \
|
||
}
|
||
|
||
|
||
//
|
||
// VOID
|
||
// PushEntryList(
|
||
// PSINGLE_LIST_ENTRY ListHead,
|
||
// PSINGLE_LIST_ENTRY Entry
|
||
// );
|
||
//
|
||
|
||
#define PushEntryList(ListHead,Entry) \
|
||
(Entry)->Next = (ListHead)->Next; \
|
||
(ListHead)->Next = (Entry)
|
||
|
||
// end_wdm end_nthal end_ntifs end_ntndis
|
||
|
||
|
||
// end_ntddk
|
||
|
||
|
||
//
|
||
// Define the generic table package. Note a generic table should really
|
||
// be an opaque type. We provide routines to manipulate the structure.
|
||
//
|
||
// A generic table is package for inserting, deleting, and looking up elements
|
||
// in a table (e.g., in a symbol table). To use this package the user
|
||
// defines the structure of the elements stored in the table, provides a
|
||
// comparison function, a memory allocation function, and a memory
|
||
// deallocation function.
|
||
//
|
||
// Note: the user compare function must impose a complete ordering among
|
||
// all of the elements, and the table does not allow for duplicate entries.
|
||
//
|
||
|
||
//
|
||
// Add an empty typedef so that functions can reference the
|
||
// a pointer to the generic table struct before it is declared.
|
||
//
|
||
|
||
struct _LLS_GENERIC_TABLE;
|
||
|
||
//
|
||
// The results of a compare can be less than, equal, or greater than.
|
||
//
|
||
|
||
typedef enum _LLS_GENERIC_COMPARE_RESULTS {
|
||
LLSGenericLessThan,
|
||
LLSGenericGreaterThan,
|
||
LLSGenericEqual
|
||
} LLS_GENERIC_COMPARE_RESULTS;
|
||
|
||
//
|
||
// The comparison function takes as input pointers to elements containing
|
||
// user defined structures and returns the results of comparing the two
|
||
// elements.
|
||
//
|
||
|
||
typedef
|
||
LLS_GENERIC_COMPARE_RESULTS
|
||
(NTAPI *PLLS_GENERIC_COMPARE_ROUTINE) (
|
||
struct _LLS_GENERIC_TABLE *Table,
|
||
PVOID FirstStruct,
|
||
PVOID SecondStruct
|
||
);
|
||
|
||
//
|
||
// The allocation function is called by the generic table package whenever
|
||
// it needs to allocate memory for the table.
|
||
//
|
||
|
||
typedef
|
||
PVOID
|
||
(NTAPI *PLLS_GENERIC_ALLOCATE_ROUTINE) (
|
||
struct _LLS_GENERIC_TABLE *Table,
|
||
CLONG ByteSize
|
||
);
|
||
|
||
//
|
||
// The deallocation function is called by the generic table package whenever
|
||
// it needs to deallocate memory from the table that was allocated by calling
|
||
// the user supplied allocation function.
|
||
//
|
||
|
||
typedef
|
||
VOID
|
||
(NTAPI *PLLS_GENERIC_FREE_ROUTINE) (
|
||
struct _LLS_GENERIC_TABLE *Table,
|
||
PVOID Buffer
|
||
);
|
||
|
||
//
|
||
// To use the generic table package the user declares a variable of type
|
||
// GENERIC_TABLE and then uses the routines described below to initialize
|
||
// the table and to manipulate the table. Note that the generic table
|
||
// should really be an opaque type.
|
||
//
|
||
|
||
typedef struct _LLS_GENERIC_TABLE {
|
||
PRTL_SPLAY_LINKS TableRoot;
|
||
LIST_ENTRY InsertOrderList;
|
||
PLIST_ENTRY OrderedPointer;
|
||
ULONG WhichOrderedElement;
|
||
ULONG NumberGenericTableElements;
|
||
PLLS_GENERIC_COMPARE_ROUTINE CompareRoutine;
|
||
PLLS_GENERIC_ALLOCATE_ROUTINE AllocateRoutine;
|
||
PLLS_GENERIC_FREE_ROUTINE FreeRoutine;
|
||
PVOID TableContext;
|
||
} LLS_GENERIC_TABLE;
|
||
typedef LLS_GENERIC_TABLE *PLLS_GENERIC_TABLE;
|
||
|
||
//
|
||
// This enumerated type is used as the function return value of the function
|
||
// that is used to search the tree for a key. FoundNode indicates that the
|
||
// function found the key. Insert as left indicates that the key was not found
|
||
// and the node should be inserted as the left child of the parent. Insert as
|
||
// right indicates that the key was not found and the node should be inserted
|
||
// as the right child of the parent.
|
||
//
|
||
typedef enum _LLS_TABLE_SEARCH_RESULT{
|
||
LLSTableEmptyTree,
|
||
LLSTableFoundNode,
|
||
LLSTableInsertAsLeft,
|
||
LLSTableInsertAsRight
|
||
} LLS_TABLE_SEARCH_RESULT;
|
||
|
||
//
|
||
// The procedure InitializeGenericTable takes as input an uninitialized
|
||
// generic table variable and pointers to the three user supplied routines.
|
||
// This must be called for every individual generic table variable before
|
||
// it can be used.
|
||
//
|
||
|
||
|
||
VOID
|
||
NTAPI
|
||
LLSInitializeGenericTable (
|
||
PLLS_GENERIC_TABLE Table,
|
||
PLLS_GENERIC_COMPARE_ROUTINE CompareRoutine,
|
||
PLLS_GENERIC_ALLOCATE_ROUTINE AllocateRoutine,
|
||
PLLS_GENERIC_FREE_ROUTINE FreeRoutine,
|
||
PVOID TableContext
|
||
);
|
||
|
||
//
|
||
// The function InsertElementGenericTable will insert a new element
|
||
// in a table. It does this by allocating space for the new element
|
||
// (this includes splay links), inserting the element in the table, and
|
||
// then returning to the user a pointer to the new element. If an element
|
||
// with the same key already exists in the table the return value is a pointer
|
||
// to the old element. The optional output parameter NewElement is used
|
||
// to indicate if the element previously existed in the table. Note: the user
|
||
// supplied Buffer is only used for searching the table, upon insertion its
|
||
// contents are copied to the newly created element. This means that
|
||
// pointer to the input buffer will not point to the new element.
|
||
//
|
||
|
||
|
||
PVOID
|
||
NTAPI
|
||
LLSInsertElementGenericTable (
|
||
PLLS_GENERIC_TABLE Table,
|
||
PVOID Buffer,
|
||
CLONG BufferSize,
|
||
PBOOLEAN NewElement OPTIONAL
|
||
);
|
||
|
||
//
|
||
// The function InsertElementGenericTableFull will insert a new element
|
||
// in a table. It does this by allocating space for the new element
|
||
// (this includes splay links), inserting the element in the table, and
|
||
// then returning to the user a pointer to the new element. If an element
|
||
// with the same key already exists in the table the return value is a pointer
|
||
// to the old element. The optional output parameter NewElement is used
|
||
// to indicate if the element previously existed in the table. Note: the user
|
||
// supplied Buffer is only used for searching the table, upon insertion its
|
||
// contents are copied to the newly created element. This means that
|
||
// pointer to the input buffer will not point to the new element.
|
||
// This routine is passed the NodeOrParent and SearchResult from a
|
||
// previous RtlLookupElementGenericTableFull.
|
||
//
|
||
|
||
|
||
PVOID
|
||
NTAPI
|
||
LLSInsertElementGenericTableFull (
|
||
PLLS_GENERIC_TABLE Table,
|
||
PVOID Buffer,
|
||
CLONG BufferSize,
|
||
PBOOLEAN NewElement OPTIONAL,
|
||
PVOID NodeOrParent,
|
||
LLS_TABLE_SEARCH_RESULT SearchResult
|
||
);
|
||
|
||
//
|
||
// The function DeleteElementGenericTable will find and delete an element
|
||
// from a generic table. If the element is located and deleted the return
|
||
// value is TRUE, otherwise if the element is not located the return value
|
||
// is FALSE. The user supplied input buffer is only used as a key in
|
||
// locating the element in the table.
|
||
//
|
||
|
||
|
||
BOOLEAN
|
||
NTAPI
|
||
LLSDeleteElementGenericTable (
|
||
PLLS_GENERIC_TABLE Table,
|
||
PVOID Buffer
|
||
);
|
||
|
||
//
|
||
// The function LookupElementGenericTable will find an element in a generic
|
||
// table. If the element is located the return value is a pointer to
|
||
// the user defined structure associated with the element, otherwise if
|
||
// the element is not located the return value is NULL. The user supplied
|
||
// input buffer is only used as a key in locating the element in the table.
|
||
//
|
||
|
||
|
||
PVOID
|
||
NTAPI
|
||
LLSLookupElementGenericTable (
|
||
PLLS_GENERIC_TABLE Table,
|
||
PVOID Buffer
|
||
);
|
||
|
||
//
|
||
// The function LookupElementGenericTableFull will find an element in a generic
|
||
// table. If the element is located the return value is a pointer to
|
||
// the user defined structure associated with the element. If the element is not
|
||
// located then a pointer to the parent for the insert location is returned. The
|
||
// user must look at the SearchResult value to determine which is being returned.
|
||
// The user can use the SearchResult and parent for a subsequent FullInsertElement
|
||
// call to optimize the insert.
|
||
//
|
||
|
||
|
||
PVOID
|
||
NTAPI
|
||
LLSLookupElementGenericTableFull (
|
||
PLLS_GENERIC_TABLE Table,
|
||
PVOID Buffer,
|
||
OUT PVOID *NodeOrParent,
|
||
OUT LLS_TABLE_SEARCH_RESULT *SearchResult
|
||
);
|
||
|
||
//
|
||
// The function EnumerateGenericTable will return to the caller one-by-one
|
||
// the elements of of a table. The return value is a pointer to the user
|
||
// defined structure associated with the element. The input parameter
|
||
// Restart indicates if the enumeration should start from the beginning
|
||
// or should return the next element. If the are no more new elements to
|
||
// return the return value is NULL. As an example of its use, to enumerate
|
||
// all of the elements in a table the user would write:
|
||
//
|
||
// for (ptr = EnumerateGenericTable(Table, TRUE);
|
||
// ptr != NULL;
|
||
// ptr = EnumerateGenericTable(Table, FALSE)) {
|
||
// :
|
||
// }
|
||
//
|
||
//
|
||
// PLEASE NOTE:
|
||
//
|
||
// If you enumerate a GenericTable using RtlEnumerateGenericTable, you
|
||
// will flatten the table, turning it into a sorted linked list.
|
||
// To enumerate the table without perturbing the splay links, use
|
||
// RtlEnumerateGenericTableWithoutSplaying
|
||
|
||
|
||
PVOID
|
||
NTAPI
|
||
LLSEnumerateGenericTable (
|
||
PLLS_GENERIC_TABLE Table,
|
||
BOOLEAN Restart
|
||
);
|
||
|
||
//
|
||
// The function EnumerateGenericTableWithoutSplaying will return to the
|
||
// caller one-by-one the elements of of a table. The return value is a
|
||
// pointer to the user defined structure associated with the element.
|
||
// The input parameter RestartKey indicates if the enumeration should
|
||
// start from the beginning or should return the next element. If the
|
||
// are no more new elements to return the return value is NULL. As an
|
||
// example of its use, to enumerate all of the elements in a table the
|
||
// user would write:
|
||
//
|
||
// RestartKey = NULL;
|
||
// for (ptr = EnumerateGenericTableWithoutSplaying(Table, &RestartKey);
|
||
// ptr != NULL;
|
||
// ptr = EnumerateGenericTableWithoutSplaying(Table, &RestartKey)) {
|
||
// :
|
||
// }
|
||
//
|
||
// If RestartKey is NULL, the package will start from the least entry in the
|
||
// table, otherwise it will start from the last entry returned.
|
||
//
|
||
//
|
||
// Note that unlike RtlEnumerateGenericTable, this routine will NOT perturb
|
||
// the splay order of the tree.
|
||
//
|
||
|
||
|
||
PVOID
|
||
NTAPI
|
||
LLSEnumerateGenericTableWithoutSplaying (
|
||
PLLS_GENERIC_TABLE Table,
|
||
PVOID *RestartKey
|
||
);
|
||
|
||
//
|
||
// The function GetElementGenericTable will return the i'th element
|
||
// inserted in the generic table. I = 0 implies the first element,
|
||
// I = (RtlNumberGenericTableElements(Table)-1) will return the last element
|
||
// inserted into the generic table. The type of I is ULONG. Values
|
||
// of I > than (NumberGenericTableElements(Table)-1) will return NULL. If
|
||
// an arbitrary element is deleted from the generic table it will cause
|
||
// all elements inserted after the deleted element to "move up".
|
||
|
||
|
||
PVOID
|
||
NTAPI
|
||
LLSGetElementGenericTable(
|
||
PLLS_GENERIC_TABLE Table,
|
||
ULONG I
|
||
);
|
||
|
||
//
|
||
// The function NumberGenericTableElements returns a ULONG value
|
||
// which is the number of generic table elements currently inserted
|
||
// in the generic table.
|
||
|
||
|
||
ULONG
|
||
NTAPI
|
||
LLSNumberGenericTableElements(
|
||
PLLS_GENERIC_TABLE Table
|
||
);
|
||
|
||
//
|
||
// The function IsGenericTableEmpty will return to the caller TRUE if
|
||
// the input table is empty (i.e., does not contain any elements) and
|
||
// FALSE otherwise.
|
||
//
|
||
|
||
|
||
BOOLEAN
|
||
NTAPI
|
||
LLSIsGenericTableEmpty (
|
||
PLLS_GENERIC_TABLE Table
|
||
);
|
||
|
||
// end_ntifs
|
||
|
||
#endif // _LLSRTL_
|