mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 16:36:33 +00:00
[NTOSKRNL]
Short commit message: implementation of (names) tunnel cache in file system RTL. This is in the vast majority work done by Johannes Anderwald, I've just reviewed, fixed a few things, and implemented last bits. Thanks to Johannes for his initial implementation (and huge work!). Dedicated to Hervé's secret plans ;-). CORE-7272 CORE-3875 svn path=/trunk/; revision=67886
This commit is contained in:
parent
0d763e60fb
commit
df216184d2
3 changed files with 750 additions and 16 deletions
|
@ -170,6 +170,7 @@ FsRtlInitSystem(VOID)
|
|||
IFS_POOL_TAG,
|
||||
0);
|
||||
|
||||
FsRtlInitializeTunnels();
|
||||
FsRtlInitializeLargeMcbs();
|
||||
|
||||
/* Allocate the Resource Buffer */
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: ntoskrnl/fsrtl/tunnel.c
|
||||
* PURPOSE: Provides the Tunnel Cache implementation for file system drivers.
|
||||
* PROGRAMMERS: None.
|
||||
* PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org)
|
||||
* Pierre Schweitzer (pierre@reactos.org)
|
||||
*/
|
||||
|
||||
/* INCLUDES ******************************************************************/
|
||||
|
@ -12,11 +13,298 @@
|
|||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
typedef struct {
|
||||
RTL_SPLAY_LINKS SplayInfo;
|
||||
LIST_ENTRY TimerQueueEntry;
|
||||
LARGE_INTEGER Time;
|
||||
ULONGLONG DirectoryKey;
|
||||
ULONG Flags;
|
||||
UNICODE_STRING LongName;
|
||||
UNICODE_STRING ShortName;
|
||||
PVOID Data;
|
||||
ULONG DataLength;
|
||||
} TUNNEL_NODE_ENTRY, *PTUNNEL_NODE_ENTRY;
|
||||
|
||||
ULONG TunnelMaxEntries = 256;
|
||||
ULONG TunnelMaxAge = 15;
|
||||
PAGED_LOOKASIDE_LIST TunnelLookasideList;
|
||||
|
||||
#define DEFAULT_EXTRA_SIZE (72)
|
||||
#define DEFAULT_ENTRY_SIZE (sizeof(TUNNEL_NODE_ENTRY) + DEFAULT_EXTRA_SIZE)
|
||||
|
||||
#define TUNNEL_FLAG_POOL 0x2
|
||||
#define TUNNEL_FLAG_KEY_SHORT_NAME 0x1
|
||||
|
||||
VOID
|
||||
FsRtlFreeTunnelNode(
|
||||
IN PTUNNEL_NODE_ENTRY CurEntry,
|
||||
IN PLIST_ENTRY PoolList OPTIONAL)
|
||||
{
|
||||
if (PoolList)
|
||||
{
|
||||
/* divert the linked list entry, it's not required anymore, but we need it */
|
||||
InsertHeadList(PoolList, &CurEntry->TimerQueueEntry);
|
||||
return;
|
||||
}
|
||||
|
||||
if (CurEntry->Flags & TUNNEL_FLAG_POOL)
|
||||
ExFreePool(CurEntry);
|
||||
else
|
||||
ExFreeToPagedLookasideList(&TunnelLookasideList, CurEntry);
|
||||
}
|
||||
|
||||
VOID
|
||||
FsRtlRemoveNodeFromTunnel(
|
||||
IN PTUNNEL Cache,
|
||||
IN PTUNNEL_NODE_ENTRY CurEntry,
|
||||
IN PLIST_ENTRY PoolList,
|
||||
OUT PBOOLEAN Rebalance)
|
||||
{
|
||||
/* delete entry and rebalance if required */
|
||||
if (Rebalance && *Rebalance)
|
||||
{
|
||||
Cache->Cache = RtlDelete(&CurEntry->SplayInfo);
|
||||
/* reset */
|
||||
*Rebalance = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
RtlDeleteNoSplay(&CurEntry->SplayInfo, &Cache->Cache);
|
||||
}
|
||||
|
||||
/* remove entry */
|
||||
RemoveEntryList(&CurEntry->TimerQueueEntry);
|
||||
|
||||
/* free node entry */
|
||||
FsRtlFreeTunnelNode(CurEntry, PoolList);
|
||||
|
||||
/* decrement node count */
|
||||
Cache->NumEntries--;
|
||||
}
|
||||
|
||||
VOID
|
||||
FsRtlPruneTunnelCache(
|
||||
IN PTUNNEL Cache,
|
||||
IN PLIST_ENTRY PoolList)
|
||||
{
|
||||
PLIST_ENTRY Entry, NextEntry;
|
||||
PTUNNEL_NODE_ENTRY CurEntry;
|
||||
LARGE_INTEGER CurTime, OldTime;
|
||||
BOOLEAN Rebalance = TRUE;
|
||||
PAGED_CODE();
|
||||
|
||||
/* query time */
|
||||
KeQuerySystemTime(&CurTime);
|
||||
|
||||
/* subtract maximum node age */
|
||||
OldTime.QuadPart = CurTime.QuadPart - TunnelMaxAge;
|
||||
|
||||
/* free all entries */
|
||||
Entry = Cache->TimerQueue.Flink;
|
||||
|
||||
while(Entry != &Cache->TimerQueue)
|
||||
{
|
||||
/* get node entry */
|
||||
CurEntry = (PTUNNEL_NODE_ENTRY)CONTAINING_RECORD(Entry, TUNNEL_NODE_ENTRY, TimerQueueEntry);
|
||||
|
||||
/* get next entry */
|
||||
NextEntry = Entry->Flink;
|
||||
|
||||
/* prune if expired OR if in advance in time */
|
||||
if (CurEntry->Time.QuadPart < OldTime.QuadPart ||
|
||||
CurEntry->Time.QuadPart > CurTime.QuadPart)
|
||||
{
|
||||
FsRtlRemoveNodeFromTunnel(Cache, CurEntry, PoolList, &Rebalance);
|
||||
}
|
||||
|
||||
/* move to next entry */
|
||||
Entry = NextEntry;
|
||||
}
|
||||
|
||||
/* If we have too many entries */
|
||||
while (Cache->NumEntries > TunnelMaxEntries)
|
||||
{
|
||||
CurEntry = (PTUNNEL_NODE_ENTRY)CONTAINING_RECORD(Entry, TUNNEL_NODE_ENTRY, TimerQueueEntry);
|
||||
FsRtlRemoveNodeFromTunnel(Cache, CurEntry, PoolList, &Rebalance);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
FsRtlGetTunnelParameterValue(
|
||||
IN PUNICODE_STRING ParameterName,
|
||||
OUT PULONG Value)
|
||||
{
|
||||
UNICODE_STRING Root = RTL_CONSTANT_STRING(L"Registry\\Machine\\System\\CurrentControlSet\\Control\\FileSystem");
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
HANDLE hKey;
|
||||
NTSTATUS Status;
|
||||
ULONG Length;
|
||||
PKEY_VALUE_FULL_INFORMATION Info;
|
||||
|
||||
/* initialize object attributes */
|
||||
InitializeObjectAttributes(&ObjectAttributes, &Root, OBJ_CASE_INSENSITIVE, NULL, NULL);
|
||||
|
||||
/* open registry key */
|
||||
Status = ZwOpenKey(&hKey, KEY_READ, &ObjectAttributes);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
/* failed to open key */
|
||||
return;
|
||||
}
|
||||
|
||||
/* query value size */
|
||||
Status = ZwQueryValueKey(hKey, ParameterName, KeyValueFullInformation, NULL, 0, &Length);
|
||||
|
||||
if (Status != STATUS_BUFFER_TOO_SMALL)
|
||||
{
|
||||
/* failed to query size */
|
||||
ZwClose(hKey);
|
||||
return;
|
||||
}
|
||||
|
||||
/* allocate buffer */
|
||||
Info = ExAllocatePool(PagedPool, Length);
|
||||
|
||||
if (!Info)
|
||||
{
|
||||
/* out of memory */
|
||||
ZwClose(hKey);
|
||||
return;
|
||||
}
|
||||
|
||||
/* query value */
|
||||
Status = ZwQueryValueKey(hKey, ParameterName, KeyValueFullInformation, NULL, 0, &Length);
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
if (Info->DataLength)
|
||||
{
|
||||
/* store result */
|
||||
*Value = (ULONG)((ULONG_PTR)Info + Info->DataOffset);
|
||||
}
|
||||
}
|
||||
|
||||
/* free buffer */
|
||||
ExFreePool(Info);
|
||||
|
||||
/* close key */
|
||||
ZwClose(hKey);
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
FsRtlInitializeTunnels()
|
||||
{
|
||||
ULONG TunnelEntries;
|
||||
UNICODE_STRING MaximumTunnelEntryAgeInSeconds = RTL_CONSTANT_STRING(L"MaximumTunnelEntryAgeInSeconds");
|
||||
UNICODE_STRING MaximumTunnelEntries = RTL_CONSTANT_STRING( L"MaximumTunnelEntries");
|
||||
|
||||
/* check for nt */
|
||||
if (MmIsThisAnNtAsSystem())
|
||||
{
|
||||
/* default */
|
||||
TunnelMaxEntries = 1024;
|
||||
}
|
||||
|
||||
/* check for custom override of max entries*/
|
||||
FsRtlGetTunnelParameterValue(&MaximumTunnelEntries, &TunnelMaxEntries);
|
||||
|
||||
/* check for custom override of age*/
|
||||
FsRtlGetTunnelParameterValue(&MaximumTunnelEntryAgeInSeconds, &TunnelMaxAge);
|
||||
|
||||
if (!TunnelMaxAge)
|
||||
{
|
||||
/* no age means no entries */
|
||||
TunnelMaxEntries = 0;
|
||||
}
|
||||
|
||||
/* get max entries */
|
||||
TunnelEntries = TunnelMaxEntries;
|
||||
|
||||
/* convert to ticks */
|
||||
TunnelMaxAge *= 10000000;
|
||||
|
||||
if(TunnelMaxEntries <= 65535)
|
||||
{
|
||||
/* use max 256 entries */
|
||||
TunnelEntries = TunnelMaxEntries / 16;
|
||||
}
|
||||
|
||||
if(!TunnelEntries && TunnelMaxEntries )
|
||||
{
|
||||
/* max tunnel entries was too small */
|
||||
TunnelEntries = TunnelMaxEntries + 1;
|
||||
}
|
||||
|
||||
if (TunnelEntries > 0xFFFF)
|
||||
{
|
||||
/* max entries is 256 */
|
||||
TunnelEntries = 256;
|
||||
}
|
||||
|
||||
/* initialize look aside list */
|
||||
ExInitializePagedLookasideList(&TunnelLookasideList, NULL, NULL, 0, DEFAULT_ENTRY_SIZE, 0 /*FIXME*/, TunnelEntries);
|
||||
}
|
||||
|
||||
LONG
|
||||
FsRtlCompareNodeAndKey(
|
||||
IN PTUNNEL_NODE_ENTRY CurEntry,
|
||||
IN ULONGLONG DirectoryKey,
|
||||
IN PUNICODE_STRING KeyString)
|
||||
{
|
||||
PUNICODE_STRING String;
|
||||
LONG Ret;
|
||||
|
||||
if (DirectoryKey > CurEntry->DirectoryKey)
|
||||
{
|
||||
Ret = 1;
|
||||
}
|
||||
else if (DirectoryKey < CurEntry->DirectoryKey)
|
||||
{
|
||||
Ret = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CurEntry->Flags & TUNNEL_FLAG_KEY_SHORT_NAME)
|
||||
{
|
||||
/* use short name as key */
|
||||
String = &CurEntry->ShortName;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* use long name as key */
|
||||
String = &CurEntry->LongName;
|
||||
}
|
||||
|
||||
Ret = RtlCompareUnicodeString(KeyString, String, TRUE);
|
||||
}
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
VOID
|
||||
FsRtlEmptyFreePoolList(
|
||||
IN PLIST_ENTRY PoolList)
|
||||
{
|
||||
PLIST_ENTRY CurEntry;
|
||||
PTUNNEL_NODE_ENTRY CurNode;
|
||||
|
||||
/* loop over all the entry */
|
||||
while (!IsListEmpty(PoolList))
|
||||
{
|
||||
/* and free them, one by one */
|
||||
CurEntry = RemoveHeadList(PoolList);
|
||||
CurNode = (PTUNNEL_NODE_ENTRY)CONTAINING_RECORD(CurEntry, TUNNEL_NODE_ENTRY, TimerQueueEntry);
|
||||
FsRtlFreeTunnelNode(CurNode, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS **********************************************************/
|
||||
|
||||
/*++
|
||||
* @name FsRtlAddToTunnelCache
|
||||
* @unimplemented
|
||||
* @implemented
|
||||
*
|
||||
* FILLME
|
||||
*
|
||||
|
@ -56,13 +344,228 @@ FsRtlAddToTunnelCache(IN PTUNNEL Cache,
|
|||
IN ULONG DataLength,
|
||||
IN PVOID Data)
|
||||
{
|
||||
/* Unimplemented */
|
||||
KeBugCheck(FILE_SYSTEM);
|
||||
PTUNNEL_NODE_ENTRY NodeEntry;
|
||||
PRTL_SPLAY_LINKS CurEntry, LastEntry;
|
||||
ULONG Length;
|
||||
LONG Result = 0;
|
||||
BOOLEAN AllocatedFromPool = FALSE;
|
||||
PUNICODE_STRING KeyString;
|
||||
LIST_ENTRY PoolList;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
/* check if tunnel cache is enabled */
|
||||
if (!TunnelMaxEntries)
|
||||
{
|
||||
/* entries are disabled */
|
||||
return;
|
||||
}
|
||||
|
||||
/* initialize free pool list */
|
||||
InitializeListHead(&PoolList);
|
||||
|
||||
/* calculate node length */
|
||||
Length = sizeof(TUNNEL_NODE_ENTRY);
|
||||
|
||||
/* add data size */
|
||||
Length += DataLength;
|
||||
|
||||
if (ShortName)
|
||||
{
|
||||
/* add short name length */
|
||||
Length += ShortName->Length;
|
||||
}
|
||||
|
||||
if (LongName)
|
||||
{
|
||||
/* add short name length */
|
||||
Length += LongName->Length;
|
||||
}
|
||||
|
||||
if (Length > DEFAULT_ENTRY_SIZE)
|
||||
{
|
||||
/* bigger than default entry */
|
||||
NodeEntry = ExAllocatePool(NonPagedPool, Length);
|
||||
AllocatedFromPool = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* get standard entry */
|
||||
NodeEntry = ExAllocateFromPagedLookasideList(&TunnelLookasideList);
|
||||
}
|
||||
|
||||
/* check for success */
|
||||
if (!NodeEntry)
|
||||
{
|
||||
/* out of memory */
|
||||
return;
|
||||
}
|
||||
|
||||
/* acquire lock */
|
||||
ExAcquireFastMutex(&Cache->Mutex);
|
||||
|
||||
/* now search cache for existing entries */
|
||||
CurEntry = Cache->Cache;
|
||||
|
||||
/* check which key should be used for search */
|
||||
KeyString = (KeyByShortName ? ShortName : LongName);
|
||||
|
||||
/* initialize last entry */
|
||||
LastEntry = NULL;
|
||||
|
||||
while(CurEntry)
|
||||
{
|
||||
/* compare current node */
|
||||
Result = FsRtlCompareNodeAndKey((PTUNNEL_NODE_ENTRY)CurEntry, DirectoryKey, KeyString);
|
||||
|
||||
/* backup last entry */
|
||||
LastEntry = CurEntry;
|
||||
|
||||
if (Result > 0)
|
||||
{
|
||||
/* current directory key is bigger */
|
||||
CurEntry = CurEntry->LeftChild;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Result == 0)
|
||||
{
|
||||
/* found equal entry */
|
||||
break;
|
||||
}
|
||||
|
||||
/* current directory key is smaller */
|
||||
CurEntry = CurEntry->RightChild;
|
||||
}
|
||||
}
|
||||
|
||||
/* initialize node entry */
|
||||
RtlInitializeSplayLinks(&NodeEntry->SplayInfo);
|
||||
|
||||
if (CurEntry != NULL)
|
||||
{
|
||||
/* found existing item */
|
||||
if (CurEntry->LeftChild)
|
||||
{
|
||||
/* update parent */
|
||||
RtlInsertAsLeftChild(NodeEntry, CurEntry->LeftChild);
|
||||
}
|
||||
|
||||
if (CurEntry->RightChild)
|
||||
{
|
||||
/* update parent */
|
||||
RtlInsertAsRightChild(NodeEntry, CurEntry->RightChild);
|
||||
}
|
||||
|
||||
if (CurEntry->Parent == CurEntry)
|
||||
{
|
||||
/* cur entry was root */
|
||||
Cache->Cache = (struct _RTL_SPLAY_LINKS*)NodeEntry;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* update parent node */
|
||||
if (LastEntry->LeftChild == CurEntry)
|
||||
{
|
||||
RtlInsertAsLeftChild(LastEntry, NodeEntry);
|
||||
}
|
||||
else
|
||||
{
|
||||
RtlInsertAsRightChild(LastEntry, NodeEntry);
|
||||
}
|
||||
}
|
||||
|
||||
/* remove entry */
|
||||
RemoveEntryList(&((PTUNNEL_NODE_ENTRY)LastEntry)->TimerQueueEntry);
|
||||
|
||||
/* free node entry */
|
||||
FsRtlFreeTunnelNode((PTUNNEL_NODE_ENTRY)LastEntry, &PoolList);
|
||||
|
||||
/* decrement node count */
|
||||
Cache->NumEntries--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LastEntry == NULL)
|
||||
{
|
||||
/* first entry in tunnel cache */
|
||||
Cache->Cache = (struct _RTL_SPLAY_LINKS*)NodeEntry;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Result > 0)
|
||||
{
|
||||
/* new left node */
|
||||
RtlInsertAsLeftChild(LastEntry, NodeEntry);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* new right node */
|
||||
RtlInsertAsRightChild(LastEntry, NodeEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* initialize entry */
|
||||
KeQuerySystemTime(&NodeEntry->Time);
|
||||
|
||||
NodeEntry->DirectoryKey = DirectoryKey;
|
||||
NodeEntry->Flags = (AllocatedFromPool ? TUNNEL_FLAG_POOL : 0x0);
|
||||
NodeEntry->Flags |= (KeyByShortName ? TUNNEL_FLAG_KEY_SHORT_NAME : 0x0);
|
||||
|
||||
if (ShortName)
|
||||
{
|
||||
/* copy short name */
|
||||
NodeEntry->ShortName.Length = ShortName->Length;
|
||||
NodeEntry->ShortName.MaximumLength = ShortName->Length;
|
||||
NodeEntry->ShortName.Buffer = (LPWSTR)((ULONG_PTR)NodeEntry + sizeof(TUNNEL_NODE_ENTRY));
|
||||
|
||||
RtlMoveMemory(NodeEntry->ShortName.Buffer, ShortName->Buffer, ShortName->Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
NodeEntry->ShortName.Length = NodeEntry->ShortName.MaximumLength = 0;
|
||||
NodeEntry->ShortName.Buffer = NULL;
|
||||
}
|
||||
|
||||
if (LongName)
|
||||
{
|
||||
/* copy long name */
|
||||
NodeEntry->LongName.Length = LongName->Length;
|
||||
NodeEntry->LongName.MaximumLength = LongName->Length;
|
||||
NodeEntry->LongName.Buffer = (LPWSTR)((ULONG_PTR)NodeEntry + sizeof(TUNNEL_NODE_ENTRY) + NodeEntry->ShortName.Length);
|
||||
|
||||
RtlMoveMemory(NodeEntry->LongName.Buffer, LongName->Buffer, LongName->Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
NodeEntry->LongName.Length = NodeEntry->LongName.MaximumLength = 0;
|
||||
NodeEntry->LongName.Buffer = NULL;
|
||||
}
|
||||
|
||||
NodeEntry->DataLength = DataLength;
|
||||
NodeEntry->Data = (PVOID)((ULONG_PTR)NodeEntry + sizeof(TUNNEL_NODE_ENTRY) + NodeEntry->ShortName.Length + NodeEntry->LongName.Length);
|
||||
RtlMoveMemory(NodeEntry->Data, Data, DataLength);
|
||||
|
||||
/* increment node count */
|
||||
Cache->NumEntries++;
|
||||
|
||||
/* insert into list */
|
||||
InsertTailList(&Cache->TimerQueue, &NodeEntry->TimerQueueEntry);
|
||||
|
||||
/* prune cache */
|
||||
FsRtlPruneTunnelCache(Cache, &PoolList);
|
||||
|
||||
/* release lock */
|
||||
ExReleaseFastMutex(&Cache->Mutex);
|
||||
|
||||
/* free pool list */
|
||||
FsRtlEmptyFreePoolList(&PoolList);
|
||||
}
|
||||
|
||||
/*++
|
||||
* @name FsRtlDeleteKeyFromTunnelCache
|
||||
* @unimplemented
|
||||
* @implemented
|
||||
*
|
||||
* FILLME
|
||||
*
|
||||
|
@ -82,13 +585,92 @@ NTAPI
|
|||
FsRtlDeleteKeyFromTunnelCache(IN PTUNNEL Cache,
|
||||
IN ULONGLONG DirectoryKey)
|
||||
{
|
||||
/* Unimplemented */
|
||||
KeBugCheck(FILE_SYSTEM);
|
||||
BOOLEAN Rebalance = TRUE;
|
||||
LIST_ENTRY PoolList;
|
||||
PTUNNEL_NODE_ENTRY CurNode;
|
||||
PRTL_SPLAY_LINKS CurEntry, LastEntry = NULL, Successors;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
/* check if tunnel cache is enabled */
|
||||
if (!TunnelMaxEntries)
|
||||
{
|
||||
/* entries are disabled */
|
||||
return;
|
||||
}
|
||||
|
||||
/* initialize free pool list */
|
||||
InitializeListHead(&PoolList);
|
||||
|
||||
/* acquire lock */
|
||||
ExAcquireFastMutex(&Cache->Mutex);
|
||||
|
||||
/* Look for the entry */
|
||||
CurEntry = Cache->Cache;
|
||||
while (CurEntry)
|
||||
{
|
||||
CurNode = (PTUNNEL_NODE_ENTRY)CONTAINING_RECORD(CurEntry, TUNNEL_NODE_ENTRY, SplayInfo);
|
||||
|
||||
if (CurNode->DirectoryKey > DirectoryKey)
|
||||
{
|
||||
/* current directory key is bigger */
|
||||
CurEntry = CurEntry->LeftChild;
|
||||
}
|
||||
else if (CurNode->DirectoryKey < DirectoryKey)
|
||||
{
|
||||
/* if we have already found one suitable, break */
|
||||
if (LastEntry != NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* current directory key is smaller */
|
||||
CurEntry = CurEntry->RightChild;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* save and look for another */
|
||||
LastEntry = CurEntry;
|
||||
CurEntry = CurEntry->LeftChild;
|
||||
}
|
||||
}
|
||||
|
||||
/* was it found? */
|
||||
if (LastEntry == NULL)
|
||||
{
|
||||
/* release tunnel lock */
|
||||
ExReleaseFastMutex(&Cache->Mutex);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* delete any matching key */
|
||||
do
|
||||
{
|
||||
CurNode = (PTUNNEL_NODE_ENTRY)CONTAINING_RECORD(LastEntry, TUNNEL_NODE_ENTRY, SplayInfo);
|
||||
|
||||
Successors = RtlRealSuccessor(LastEntry);
|
||||
if (CurNode->DirectoryKey != DirectoryKey)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* remove from tunnel */
|
||||
FsRtlRemoveNodeFromTunnel(Cache, CurNode, &PoolList, &Rebalance);
|
||||
LastEntry = Successors;
|
||||
}
|
||||
while (LastEntry != NULL);
|
||||
|
||||
/* release tunnel lock */
|
||||
ExReleaseFastMutex(&Cache->Mutex);
|
||||
|
||||
/* free pool */
|
||||
FsRtlEmptyFreePoolList(&PoolList);
|
||||
}
|
||||
|
||||
/*++
|
||||
* @name FsRtlDeleteTunnelCache
|
||||
* @unimplemented
|
||||
* @implemented
|
||||
*
|
||||
* FILLME
|
||||
*
|
||||
|
@ -104,12 +686,48 @@ VOID
|
|||
NTAPI
|
||||
FsRtlDeleteTunnelCache(IN PTUNNEL Cache)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
PLIST_ENTRY Entry, NextEntry;
|
||||
PTUNNEL_NODE_ENTRY CurEntry;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
/* check if tunnel cache is enabled */
|
||||
if (!TunnelMaxEntries)
|
||||
{
|
||||
/* entries are disabled */
|
||||
return;
|
||||
}
|
||||
|
||||
/* free all entries */
|
||||
Entry = Cache->TimerQueue.Flink;
|
||||
|
||||
while(Entry != &Cache->TimerQueue)
|
||||
{
|
||||
/* get node entry */
|
||||
CurEntry = (PTUNNEL_NODE_ENTRY)CONTAINING_RECORD(Entry, TUNNEL_NODE_ENTRY, TimerQueueEntry);
|
||||
|
||||
/* get next entry */
|
||||
NextEntry = Entry->Flink;
|
||||
|
||||
/* remove entry from list */
|
||||
RemoveEntryList(&CurEntry->TimerQueueEntry);
|
||||
|
||||
/* free entry */
|
||||
FsRtlFreeTunnelNode(CurEntry, NULL);
|
||||
|
||||
/* move to next entry */
|
||||
Entry = NextEntry;
|
||||
}
|
||||
|
||||
/* reset object */
|
||||
Cache->Cache = NULL;
|
||||
Cache->NumEntries = 0;
|
||||
InitializeListHead(&Cache->TimerQueue);
|
||||
}
|
||||
|
||||
/*++
|
||||
* @name FsRtlFindInTunnelCache
|
||||
* @unimplemented
|
||||
* @implemented
|
||||
*
|
||||
* FILLME
|
||||
*
|
||||
|
@ -149,14 +767,111 @@ FsRtlFindInTunnelCache(IN PTUNNEL Cache,
|
|||
IN OUT PULONG DataLength,
|
||||
OUT PVOID Data)
|
||||
{
|
||||
/* Unimplemented */
|
||||
KeBugCheck(FILE_SYSTEM);
|
||||
return FALSE;
|
||||
BOOLEAN Ret = FALSE;
|
||||
PTUNNEL_NODE_ENTRY CurEntry;
|
||||
LIST_ENTRY PoolList;
|
||||
//NTSTATUS Status;
|
||||
LONG Result;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
/* check if tunnel cache is enabled */
|
||||
if (!TunnelMaxEntries)
|
||||
{
|
||||
/* entries are disabled */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* initialize free pool list */
|
||||
InitializeListHead(&PoolList);
|
||||
|
||||
/* acquire tunnel lock */
|
||||
ExAcquireFastMutex(&Cache->Mutex);
|
||||
|
||||
/* prune old entries */
|
||||
FsRtlPruneTunnelCache(Cache, &PoolList);
|
||||
|
||||
/* now search cache for existing entries */
|
||||
CurEntry = (PTUNNEL_NODE_ENTRY)Cache->Cache;
|
||||
|
||||
while(CurEntry)
|
||||
{
|
||||
/* compare current node */
|
||||
Result = FsRtlCompareNodeAndKey(CurEntry, DirectoryKey, Name);
|
||||
|
||||
if (Result > 0)
|
||||
{
|
||||
/* current directory key is bigger */
|
||||
CurEntry = (PTUNNEL_NODE_ENTRY)CurEntry->SplayInfo.LeftChild;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Result == 0)
|
||||
{
|
||||
/* found equal entry */
|
||||
break;
|
||||
}
|
||||
|
||||
/* current directory key is smaller */
|
||||
CurEntry = (PTUNNEL_NODE_ENTRY)CurEntry->SplayInfo.RightChild;
|
||||
}
|
||||
}
|
||||
|
||||
if (CurEntry != NULL)
|
||||
{
|
||||
_SEH2_TRY
|
||||
{
|
||||
/* copy short name */
|
||||
RtlCopyUnicodeString(ShortName, &CurEntry->ShortName);
|
||||
|
||||
/* check size */
|
||||
if (LongName->MaximumLength < CurEntry->LongName.Length)
|
||||
{
|
||||
/* buffer is too small */
|
||||
LongName->Buffer = ExAllocatePool(PagedPool, CurEntry->LongName.Length);
|
||||
if (LongName->Buffer)
|
||||
{
|
||||
LongName->Length = CurEntry->LongName.Length;
|
||||
LongName->MaximumLength = CurEntry->LongName.MaximumLength;
|
||||
RtlMoveMemory(LongName->Buffer, CurEntry->LongName.Buffer, CurEntry->LongName.Length);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* buffer is big enough */
|
||||
RtlCopyUnicodeString(LongName, &CurEntry->LongName);
|
||||
}
|
||||
|
||||
/* copy data */
|
||||
RtlMoveMemory(Data, CurEntry->Data, CurEntry->DataLength);
|
||||
|
||||
/* store size */
|
||||
*DataLength = CurEntry->DataLength;
|
||||
|
||||
/* done */
|
||||
Ret = TRUE;
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
/* Get the status */
|
||||
//Status = _SEH2_GetExceptionCode();
|
||||
}
|
||||
_SEH2_END;
|
||||
|
||||
}
|
||||
|
||||
/* release tunnel lock */
|
||||
ExReleaseFastMutex(&Cache->Mutex);
|
||||
|
||||
/* free pool */
|
||||
FsRtlEmptyFreePoolList(&PoolList);
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
/*++
|
||||
* @name FsRtlDeleteTunnelCache
|
||||
* @unimplemented
|
||||
* @name FsRtlInitializeTunnelCache
|
||||
* @implemented
|
||||
*
|
||||
* FILLME
|
||||
*
|
||||
|
@ -172,7 +887,19 @@ VOID
|
|||
NTAPI
|
||||
FsRtlInitializeTunnelCache(IN PTUNNEL Cache)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
PAGED_CODE();
|
||||
|
||||
/* initialize mutex */
|
||||
ExInitializeFastMutex(&Cache->Mutex);
|
||||
|
||||
/* initialize node tree */
|
||||
Cache->Cache = NULL;
|
||||
|
||||
/* initialize timer list */
|
||||
InitializeListHead(&Cache->TimerQueue);
|
||||
|
||||
/* initialize node count */
|
||||
Cache->NumEntries = 0;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -114,6 +114,12 @@ FsRtlInitializeLargeMcbs(
|
|||
VOID
|
||||
);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
FsRtlInitializeTunnels(
|
||||
VOID
|
||||
);
|
||||
|
||||
//
|
||||
// File contexts Routines
|
||||
//
|
||||
|
|
Loading…
Reference in a new issue