mirror of
https://github.com/reactos/reactos.git
synced 2024-08-17 00:48:51 +00:00
302 lines
8.5 KiB
C
302 lines
8.5 KiB
C
/*
|
|
* PROJECT: ReactOS Kernel
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: ntoskrnl/config/cmapi.c
|
|
* PURPOSE: Configuration Manager - Internal Registry APIs
|
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
|
*/
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
#include "ntoskrnl.h"
|
|
#define NDEBUG
|
|
#include "debug.h"
|
|
|
|
/* GLOBALS ********************************************************************/
|
|
|
|
KTIMER CmpLazyFlushTimer;
|
|
KDPC CmpLazyFlushDpc;
|
|
WORK_QUEUE_ITEM CmpLazyWorkItem;
|
|
KTIMER CmpEnableLazyFlushTimer;
|
|
KDPC CmpEnableLazyFlushDpc;
|
|
BOOLEAN CmpLazyFlushPending;
|
|
BOOLEAN CmpForceForceFlush;
|
|
BOOLEAN CmpHoldLazyFlush = TRUE;
|
|
ULONG CmpLazyFlushIntervalInSeconds = 5;
|
|
ULONG CmpLazyFlushHiveCount = 7;
|
|
ULONG CmpLazyFlushCount = 1;
|
|
LONG CmpFlushStarveWriters;
|
|
|
|
/* FUNCTIONS ******************************************************************/
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
CmpDoFlushNextHive(IN BOOLEAN ForceFlush,
|
|
OUT PBOOLEAN Error,
|
|
OUT PULONG DirtyCount)
|
|
{
|
|
NTSTATUS Status;
|
|
PLIST_ENTRY NextEntry;
|
|
PCMHIVE CmHive;
|
|
BOOLEAN Result;
|
|
ULONG HiveCount = CmpLazyFlushHiveCount;
|
|
|
|
/* Set Defaults */
|
|
*Error = FALSE;
|
|
*DirtyCount = 0;
|
|
|
|
/* Don't do anything if we're not supposed to */
|
|
if (CmpNoWrite) return TRUE;
|
|
|
|
/* Make sure we have to flush at least one hive */
|
|
if (!HiveCount) HiveCount = 1;
|
|
|
|
/* Don't force flush */
|
|
CmpForceForceFlush = FALSE;
|
|
|
|
/* Acquire the list lock and loop */
|
|
ExAcquirePushLockShared(&CmpHiveListHeadLock);
|
|
NextEntry = CmpHiveListHead.Flink;
|
|
while (NextEntry != &CmpHiveListHead)
|
|
{
|
|
/* Get the hive and check if we should flush it */
|
|
CmHive = CONTAINING_RECORD(NextEntry, CMHIVE, HiveList);
|
|
if (!(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH) &&
|
|
(CmHive->FlushCount != CmpLazyFlushCount))
|
|
{
|
|
/* Great sucess! */
|
|
Result = TRUE;
|
|
|
|
/* Ignore clean or volatile hves */
|
|
if (!(CmHive->Hive.DirtyCount) ||
|
|
(CmHive->Hive.HiveFlags & HIVE_VOLATILE))
|
|
{
|
|
/* Don't do anything but do update the count */
|
|
CmHive->FlushCount = CmpLazyFlushCount;
|
|
}
|
|
else
|
|
{
|
|
/* Do the sync */
|
|
DPRINT1("Flushing: %wZ\n", CmHive->FileFullPath);
|
|
DPRINT1("Handle: %lx\n", CmHive->FileHandles[HFILE_TYPE_PRIMARY]);
|
|
Status = HvSyncHive(&CmHive->Hive);
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
/* Let them know we failed */
|
|
*Error = TRUE;
|
|
Result = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else if ((CmHive->Hive.DirtyCount) &&
|
|
(!(CmHive->Hive.HiveFlags & HIVE_VOLATILE)) &&
|
|
(!(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH)))
|
|
{
|
|
/* Use another lazy flusher for this hive */
|
|
ASSERT(CmHive->FlushCount == CmpLazyFlushCount);
|
|
*DirtyCount += CmHive->Hive.DirtyCount;
|
|
}
|
|
|
|
/* Try the next one */
|
|
NextEntry = NextEntry->Flink;
|
|
}
|
|
|
|
/* Check if we've flushed everything */
|
|
if (NextEntry == &CmpHiveListHead)
|
|
{
|
|
/* We have, tell the caller we're done */
|
|
Result = FALSE;
|
|
}
|
|
else
|
|
{
|
|
/* We need to be called again */
|
|
Result = TRUE;
|
|
}
|
|
|
|
/* Unlock the list and return the result */
|
|
ExReleasePushLock(&CmpHiveListHeadLock);
|
|
return Result;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
CmpEnableLazyFlushDpcRoutine(IN PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SystemArgument1,
|
|
IN PVOID SystemArgument2)
|
|
{
|
|
/* Don't stop lazy flushing from happening anymore */
|
|
CmpHoldLazyFlush = FALSE;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
CmpLazyFlushDpcRoutine(IN PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SystemArgument1,
|
|
IN PVOID SystemArgument2)
|
|
{
|
|
/* Check if we should queue the lazy flush worker */
|
|
if ((!CmpLazyFlushPending) && (!CmpHoldLazyFlush))
|
|
{
|
|
CmpLazyFlushPending = TRUE;
|
|
ExQueueWorkItem(&CmpLazyWorkItem, DelayedWorkQueue);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
CmpLazyFlush(VOID)
|
|
{
|
|
LARGE_INTEGER DueTime;
|
|
PAGED_CODE();
|
|
|
|
/* Check if we should set the lazy flush timer */
|
|
if ((!CmpNoWrite) && (!CmpHoldLazyFlush))
|
|
{
|
|
/* Do it */
|
|
DueTime.QuadPart = Int32x32To64(CmpLazyFlushIntervalInSeconds,
|
|
-10 * 1000 * 1000);
|
|
KeSetTimer(&CmpLazyFlushTimer, DueTime, &CmpLazyFlushDpc);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
CmpLazyFlushWorker(IN PVOID Parameter)
|
|
{
|
|
BOOLEAN ForceFlush, Result, MoreWork = FALSE;
|
|
ULONG DirtyCount = 0;
|
|
PAGED_CODE();
|
|
|
|
/* Don't do anything if lazy flushing isn't enabled yet */
|
|
if (CmpHoldLazyFlush) return;
|
|
|
|
/* Check if we are forcing a flush */
|
|
ForceFlush = CmpForceForceFlush;
|
|
if (ForceFlush)
|
|
{
|
|
/* Lock the registry exclusively */
|
|
CmpLockRegistryExclusive();
|
|
}
|
|
else
|
|
{
|
|
/* Do a normal lock */
|
|
CmpLockRegistry();
|
|
InterlockedIncrement(&CmpFlushStarveWriters);
|
|
}
|
|
|
|
/* Flush the next hive */
|
|
MoreWork = CmpDoFlushNextHive(ForceFlush, &Result, &DirtyCount);
|
|
if (!MoreWork)
|
|
{
|
|
/* We're done */
|
|
InterlockedIncrement((PLONG)&CmpLazyFlushCount);
|
|
}
|
|
|
|
/* Check if we have starved writers */
|
|
if (!ForceFlush) InterlockedDecrement(&CmpFlushStarveWriters);
|
|
|
|
/* Not pending anymore, release the registry lock */
|
|
CmpLazyFlushPending = FALSE;
|
|
CmpUnlockRegistry();
|
|
|
|
/* Check if we need to flush another hive */
|
|
if ((MoreWork) || (DirtyCount)) CmpLazyFlush();
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
CmpCmdInit(IN BOOLEAN SetupBoot)
|
|
{
|
|
LARGE_INTEGER DueTime;
|
|
PAGED_CODE();
|
|
|
|
/* Setup the lazy DPC */
|
|
KeInitializeDpc(&CmpLazyFlushDpc, CmpLazyFlushDpcRoutine, NULL);
|
|
|
|
/* Setup the lazy timer */
|
|
KeInitializeTimer(&CmpLazyFlushTimer);
|
|
|
|
/* Setup the lazy worker */
|
|
ExInitializeWorkItem(&CmpLazyWorkItem, CmpLazyFlushWorker, NULL);
|
|
|
|
/* Setup the forced-lazy DPC and timer */
|
|
KeInitializeDpc(&CmpEnableLazyFlushDpc,
|
|
CmpEnableLazyFlushDpcRoutine,
|
|
NULL);
|
|
KeInitializeTimer(&CmpEnableLazyFlushTimer);
|
|
|
|
/* Enable lazy flushing after 10 minutes */
|
|
DueTime.QuadPart = Int32x32To64(600, -10 * 1000 * 1000);
|
|
KeSetTimer(&CmpEnableLazyFlushTimer, DueTime, &CmpEnableLazyFlushDpc);
|
|
|
|
/* Setup flush variables */
|
|
CmpNoWrite = CmpMiniNTBoot;
|
|
CmpWasSetupBoot = SetupBoot;
|
|
|
|
/* Testing: Force Lazy Flushing */
|
|
CmpHoldLazyFlush = FALSE;
|
|
|
|
/* Setup the hive list */
|
|
CmpInitializeHiveList(SetupBoot);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
CmpCmdHiveOpen(IN POBJECT_ATTRIBUTES FileAttributes,
|
|
IN PSECURITY_CLIENT_CONTEXT ImpersonationContext,
|
|
IN OUT PBOOLEAN Allocate,
|
|
OUT PCMHIVE *NewHive,
|
|
IN ULONG CheckFlags)
|
|
{
|
|
PUNICODE_STRING FileName;
|
|
NTSTATUS Status;
|
|
PAGED_CODE();
|
|
|
|
/* Open the file in the current security context */
|
|
FileName = FileAttributes->ObjectName;
|
|
Status = CmpInitHiveFromFile(FileName,
|
|
0,
|
|
NewHive,
|
|
Allocate,
|
|
CheckFlags);
|
|
if (((Status == STATUS_ACCESS_DENIED) ||
|
|
(Status == STATUS_NO_SUCH_USER) ||
|
|
(Status == STATUS_WRONG_PASSWORD) ||
|
|
(Status == STATUS_ACCOUNT_EXPIRED) ||
|
|
(Status == STATUS_ACCOUNT_DISABLED) ||
|
|
(Status == STATUS_ACCOUNT_RESTRICTION)) &&
|
|
(ImpersonationContext))
|
|
{
|
|
/* We failed due to an account/security error, impersonate SYSTEM */
|
|
Status = SeImpersonateClientEx(ImpersonationContext, NULL);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Now try again */
|
|
Status = CmpInitHiveFromFile(FileName,
|
|
0,
|
|
NewHive,
|
|
Allocate,
|
|
CheckFlags);
|
|
|
|
/* Restore impersonation token */
|
|
PsRevertToSelf();
|
|
}
|
|
}
|
|
|
|
/* Return status of open attempt */
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
CmpShutdownWorkers(VOID)
|
|
{
|
|
/* Stop lazy flushing */
|
|
PAGED_CODE();
|
|
KeCancelTimer(&CmpLazyFlushTimer);
|
|
}
|
|
|
|
/* EOF */
|