297 lines
5.3 KiB
C
297 lines
5.3 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1998-1999 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
hash.h
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
contains prototypes for functions in hash.c
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Paul McDaniel (paulmcd) 28-Apr-2000
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
|
||
|
#ifndef _HASH_H_
|
||
|
#define _HASH_H_
|
||
|
|
||
|
//
|
||
|
// The hash key is the file name, but we need to track both the file
|
||
|
// component of the name in addition to the stream component of the name (if
|
||
|
// there is one). The buffer in the FileName UNICODE_STRING contains the
|
||
|
// full name with stream information, but the length is set to just designate
|
||
|
// the file portion of the name.
|
||
|
//
|
||
|
// Note: The keys will be hashed based on the FileName only, not the stream
|
||
|
// portion of the name. This is done so that we can easily find all the
|
||
|
// entries related to a given file if that file has multiple data streams.
|
||
|
//
|
||
|
|
||
|
typedef struct _HASH_KEY
|
||
|
{
|
||
|
|
||
|
UNICODE_STRING FileName;
|
||
|
|
||
|
USHORT StreamNameLength;
|
||
|
USHORT Reserved;
|
||
|
|
||
|
} HASH_KEY, *PHASH_KEY;
|
||
|
|
||
|
//
|
||
|
// a hash list entry .
|
||
|
//
|
||
|
|
||
|
typedef struct _HASH_ENTRY
|
||
|
{
|
||
|
//
|
||
|
// the hash value
|
||
|
//
|
||
|
|
||
|
ULONG HashValue;
|
||
|
|
||
|
//
|
||
|
// the key
|
||
|
//
|
||
|
|
||
|
HASH_KEY Key;
|
||
|
|
||
|
//
|
||
|
// a context stored with this hash entry
|
||
|
//
|
||
|
|
||
|
PVOID pContext;
|
||
|
|
||
|
} HASH_ENTRY, *PHASH_ENTRY;
|
||
|
|
||
|
//
|
||
|
// a hash bucket, which is basically an array of hash entries
|
||
|
// sorted by (HashValue, Key.Length, Key.Buffer) .
|
||
|
//
|
||
|
|
||
|
#define IS_VALID_HASH_BUCKET(pObject) \
|
||
|
(((pObject) != NULL) && ((pObject)->Signature == HASH_BUCKET_TAG))
|
||
|
|
||
|
typedef struct _HASH_BUCKET
|
||
|
{
|
||
|
//
|
||
|
// = HASH_BUCKET_TAG
|
||
|
//
|
||
|
|
||
|
ULONG Signature;
|
||
|
|
||
|
ULONG AllocCount;
|
||
|
ULONG UsedCount;
|
||
|
|
||
|
HASH_ENTRY Entries[0];
|
||
|
|
||
|
} HASH_BUCKET, *PHASH_BUCKET;
|
||
|
|
||
|
|
||
|
#define HASH_ENTRY_DEFAULT_WIDTH 10
|
||
|
|
||
|
//
|
||
|
// a destructor for hash entries
|
||
|
//
|
||
|
|
||
|
typedef
|
||
|
VOID
|
||
|
(*PHASH_ENTRY_DESTRUCTOR) (
|
||
|
IN PHASH_KEY pKey,
|
||
|
IN PVOID pContext
|
||
|
);
|
||
|
|
||
|
typedef
|
||
|
PVOID
|
||
|
(*PHASH_ENTRY_CALLBACK) (
|
||
|
IN PHASH_KEY pKey,
|
||
|
IN PVOID pEntryContext,
|
||
|
IN PVOID pCallbackContext
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// and a hash header, an array of buckets which is hashed into.
|
||
|
//
|
||
|
|
||
|
#define IS_VALID_HASH_HEADER(pObject) \
|
||
|
(((pObject) != NULL) && ((pObject)->Signature == HASH_HEADER_TAG))
|
||
|
|
||
|
typedef struct _HASH_HEADER
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// NonPagedPool
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// = HASH_HEADER_TAG
|
||
|
//
|
||
|
|
||
|
ULONG Signature;
|
||
|
|
||
|
//
|
||
|
// the count of buckets the hash table has
|
||
|
//
|
||
|
|
||
|
ULONG BucketCount;
|
||
|
|
||
|
//
|
||
|
// the memory this hash table is taking
|
||
|
//
|
||
|
|
||
|
ULONG UsedLength;
|
||
|
|
||
|
//
|
||
|
// the memory this hash table is allowed to use
|
||
|
//
|
||
|
|
||
|
ULONG AllowedLength;
|
||
|
|
||
|
//
|
||
|
// how many times we've trimmed due to memory
|
||
|
//
|
||
|
|
||
|
ULONG TrimCount;
|
||
|
|
||
|
//
|
||
|
// the last time we trim'd
|
||
|
//
|
||
|
|
||
|
LARGE_INTEGER LastTrimTime;
|
||
|
|
||
|
//
|
||
|
// OPTIONAL the length in bytes of the duplicate prefix (if any)
|
||
|
// all keys share in this lists. This will be skipped for all manual
|
||
|
// comparisons as an optimization. this can be 0
|
||
|
//
|
||
|
|
||
|
ULONG PrefixLength;
|
||
|
|
||
|
//
|
||
|
// the lock for this list
|
||
|
//
|
||
|
|
||
|
ERESOURCE Lock;
|
||
|
|
||
|
//
|
||
|
// OPTIONAL destructor
|
||
|
//
|
||
|
|
||
|
PHASH_ENTRY_DESTRUCTOR pDestructor;
|
||
|
|
||
|
//
|
||
|
// and the actual buckets
|
||
|
//
|
||
|
|
||
|
PHASH_BUCKET Buckets[0];
|
||
|
|
||
|
} HASH_HEADER, *PHASH_HEADER;
|
||
|
|
||
|
//
|
||
|
// Function Prototypes.
|
||
|
//
|
||
|
|
||
|
NTSTATUS
|
||
|
HashCreateList (
|
||
|
IN ULONG BucketCount,
|
||
|
IN ULONG AllowedLength,
|
||
|
IN ULONG PrefixLength OPTIONAL,
|
||
|
IN PHASH_ENTRY_DESTRUCTOR pDestructor OPTIONAL,
|
||
|
OUT PHASH_HEADER * ppHashList
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
HashDestroyList (
|
||
|
IN PHASH_HEADER pHashList
|
||
|
);
|
||
|
|
||
|
NTSTATUS
|
||
|
HashAddEntry (
|
||
|
IN PHASH_HEADER pHashList,
|
||
|
IN PHASH_KEY pKey,
|
||
|
IN PVOID pContext
|
||
|
);
|
||
|
|
||
|
NTSTATUS
|
||
|
HashFindEntry (
|
||
|
IN PHASH_HEADER pHashList,
|
||
|
IN PHASH_KEY pKey,
|
||
|
OUT PVOID * ppContext
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
HashClearEntries (
|
||
|
IN PHASH_HEADER pHashList
|
||
|
);
|
||
|
|
||
|
NTSTATUS
|
||
|
HashClearAllFileEntries (
|
||
|
IN PHASH_HEADER pHeader,
|
||
|
IN PUNICODE_STRING pFileName
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
HashProcessEntries (
|
||
|
IN PHASH_HEADER pHeader,
|
||
|
IN PHASH_ENTRY_CALLBACK pfnCallback,
|
||
|
IN PVOID pCallbackContext
|
||
|
);
|
||
|
|
||
|
#if 0
|
||
|
|
||
|
#define HashCompute(Key) HashScramble(HashUnicodeString((Key)))
|
||
|
|
||
|
|
||
|
__inline ULONG
|
||
|
HashUnicodeString(
|
||
|
PUNICODE_STRING pKey
|
||
|
)
|
||
|
{
|
||
|
ULONG Hash = 0;
|
||
|
ULONG Index;
|
||
|
ULONG CharCount;
|
||
|
|
||
|
CharCount = pKey->Length/sizeof(WCHAR);
|
||
|
|
||
|
for (Index = 0 ; Index < CharCount; ++Index)
|
||
|
{
|
||
|
Hash = 37 * Hash + (pKey->Buffer[Index] & 0xFFDF);
|
||
|
}
|
||
|
|
||
|
return Hash;
|
||
|
}
|
||
|
|
||
|
// Produce a scrambled, randomish number in the range 0 to RANDOM_PRIME-1.
|
||
|
// Applying this to the results of the other hash functions is likely to
|
||
|
// produce a much better distribution, especially for the identity hash
|
||
|
// functions such as Hash(char c), where records will tend to cluster at
|
||
|
// the low end of the hashtable otherwise. LKHash applies this internally
|
||
|
// to all hash signatures for exactly this reason.
|
||
|
|
||
|
__inline ULONG
|
||
|
HashScramble(ULONG dwHash)
|
||
|
{
|
||
|
// Here are 10 primes slightly greater than 10^9
|
||
|
// 1000000007, 1000000009, 1000000021, 1000000033, 1000000087,
|
||
|
// 1000000093, 1000000097, 1000000103, 1000000123, 1000000181.
|
||
|
|
||
|
// default value for "scrambling constant"
|
||
|
const ULONG RANDOM_CONSTANT = 314159269UL;
|
||
|
// large prime number, also used for scrambling
|
||
|
const ULONG RANDOM_PRIME = 1000000007UL;
|
||
|
|
||
|
return (RANDOM_CONSTANT * dwHash) % RANDOM_PRIME ;
|
||
|
}
|
||
|
|
||
|
#endif // 0
|
||
|
|
||
|
#endif // _HASH_H_
|
||
|
|
||
|
|