diff --git a/reactos/ntoskrnl/cm/cm.h b/reactos/ntoskrnl/cm/cm.h index 1309d7d955a..c11fc72b1df 100644 --- a/reactos/ntoskrnl/cm/cm.h +++ b/reactos/ntoskrnl/cm/cm.h @@ -37,24 +37,6 @@ #define REG_SAM_FILE_NAME L"\\sam" #define REG_SEC_FILE_NAME L"\\security" -/* When set, the hive is not backed by a file. - Therefore, it can not be flushed to disk. */ -#define HIVE_NO_FILE 0x00000002 - -/* When set, a modified (dirty) hive is not synchronized automatically. - Explicit synchronization (save/flush) works. */ -#define HIVE_NO_SYNCH 0x00000004 - -#define IsNoFileHive(Hive) ((Hive)->Flags & HIVE_NO_FILE) -#define IsNoSynchHive(Hive) ((Hive)->Flags & HIVE_NO_SYNCH) - - -/* KEY_OBJECT.Flags */ - -/* When set, the key is scheduled for deletion, and all - attempts to access the key must not succeed */ -#define KO_MARKED_FOR_DELETE 0x00000001 - /* Bits 31-22 (top 10 bits) of the cell index is the directory index */ #define CmiDirectoryIndex(CellIndex)(CellIndex & 0xffc000000) /* Bits 21-12 (middle 10 bits) of the cell index is the table index */ @@ -105,29 +87,11 @@ VOID CmiAddKeyToList(IN PKEY_OBJECT ParentKey, IN PKEY_OBJECT NewKey); -NTSTATUS -CmiScanKeyList(IN PKEY_OBJECT Parent, - IN PCUNICODE_STRING KeyName, - IN ULONG Attributes, - PKEY_OBJECT* ReturnedObject); - NTSTATUS CmiLoadHive(POBJECT_ATTRIBUTES KeyObjectAttributes, PCUNICODE_STRING FileName, ULONG Flags); -NTSTATUS -CmiFlushRegistryHive(PCMHIVE RegistryHive); - -NTSTATUS -CmiScanForSubKey(IN PCMHIVE RegistryHive, - IN PCM_KEY_NODE KeyCell, - OUT PCM_KEY_NODE *SubKeyCell, - OUT HCELL_INDEX *BlockOffset, - IN PCUNICODE_STRING KeyName, - IN ACCESS_MASK DesiredAccess, - IN ULONG Attributes); - NTSTATUS CmiScanKeyForValue(IN PCMHIVE RegistryHive, IN PCM_KEY_NODE KeyCell, @@ -135,6 +99,9 @@ CmiScanKeyForValue(IN PCMHIVE RegistryHive, OUT PCM_KEY_VALUE *ValueCell, OUT HCELL_INDEX *VBOffset); +VOID +NTAPI +CmpLazyFlush(VOID); NTSTATUS CmiConnectHive(POBJECT_ATTRIBUTES KeyObjectAttributes, @@ -143,9 +110,6 @@ CmiConnectHive(POBJECT_ATTRIBUTES KeyObjectAttributes, NTSTATUS CmiInitHives(BOOLEAN SetupBoot); -VOID -CmiSyncHives(VOID); - NTSTATUS NTAPI CmFindObject( diff --git a/reactos/ntoskrnl/cm/ntfunc.c b/reactos/ntoskrnl/cm/ntfunc.c index 632e581ecf2..a6049dd0bd7 100644 --- a/reactos/ntoskrnl/cm/ntfunc.c +++ b/reactos/ntoskrnl/cm/ntfunc.c @@ -389,7 +389,7 @@ NtCreateKey(OUT PHANDLE KeyHandle, PostCreateKeyInfo.Status = Status; CmiCallRegisteredCallbacks(RegNtPostCreateKey, &PostCreateKeyInfo); - CmiSyncHives(); + CmpLazyFlush(); LocalDisposition = REG_CREATED_NEW_KEY; @@ -422,59 +422,6 @@ Cleanup: return Status; } -NTSTATUS -NTAPI -NtFlushKey(IN HANDLE KeyHandle) -{ - NTSTATUS Status; - PKEY_OBJECT KeyObject; - PCMHIVE RegistryHive; - KPROCESSOR_MODE PreviousMode; - - PAGED_CODE(); - - DPRINT("NtFlushKey (KeyHandle %lx) called\n", KeyHandle); - - PreviousMode = ExGetPreviousMode(); - - /* Verify that the handle is valid and is a registry key */ - Status = ObReferenceObjectByHandle(KeyHandle, - 0, - CmpKeyObjectType, - PreviousMode, - (PVOID *)&KeyObject, - NULL); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - - VERIFY_KEY_OBJECT(KeyObject); - - RegistryHive = (PCMHIVE)KeyObject->KeyControlBlock->KeyHive; - - /* Acquire hive lock */ - KeEnterCriticalRegion(); - ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); - - if (IsNoFileHive(RegistryHive)) - { - Status = STATUS_SUCCESS; - } - else - { - /* Flush non-volatile hive */ - Status = CmiFlushRegistryHive(RegistryHive); - } - - ExReleaseResourceLite(&CmpRegistryLock); - KeLeaveCriticalRegion(); - - ObDereferenceObject(KeyObject); - - return STATUS_SUCCESS; -} - NTSTATUS NTAPI NtOpenKey(OUT PHANDLE KeyHandle, @@ -687,6 +634,7 @@ NtInitializeRegistry (IN USHORT Flag) Status = CmiInitHives (Flag); + CmpCmdInit(Flag); CmiRegistryInitialized = TRUE; return Status; diff --git a/reactos/ntoskrnl/cm/regfile.c b/reactos/ntoskrnl/cm/regfile.c index 0bfe640de20..d9260a5572a 100644 --- a/reactos/ntoskrnl/cm/regfile.c +++ b/reactos/ntoskrnl/cm/regfile.c @@ -58,49 +58,6 @@ CmiLoadHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes, return Status; } -VOID -CmCloseHiveFiles(PCMHIVE RegistryHive) -{ - ZwClose(RegistryHive->FileHandles[HFILE_TYPE_PRIMARY]); - ZwClose(RegistryHive->FileHandles[HFILE_TYPE_LOG]); -} - -NTSTATUS -CmiFlushRegistryHive(PCMHIVE RegistryHive) -{ - BOOLEAN Success; - NTSTATUS Status; - ULONG Disposition; - - ASSERT(!RegistryHive->Hive.HiveFlags & HIVE_VOLATILE); - - if (RtlFindSetBits(&RegistryHive->Hive.DirtyVector, 1, 0) == ~0) - { - return(STATUS_SUCCESS); - } - - Status = CmpOpenHiveFiles(&RegistryHive->FileFullPath, - L".LOG", - &RegistryHive->FileHandles[HFILE_TYPE_PRIMARY], - &RegistryHive->FileHandles[HFILE_TYPE_LOG], - &Disposition, - &Disposition, - FALSE, - FALSE, - TRUE, - NULL); - if (!NT_SUCCESS(Status)) - { - return Status; - } - - Success = HvSyncHive(&RegistryHive->Hive); - - CmCloseHiveFiles(RegistryHive); - - return Success ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; -} - NTSTATUS CmiScanKeyForValue(IN PCMHIVE RegistryHive, IN PCM_KEY_NODE KeyCell, diff --git a/reactos/ntoskrnl/cm/registry.c b/reactos/ntoskrnl/cm/registry.c index 036dbeeb1c9..8282036bb73 100644 --- a/reactos/ntoskrnl/cm/registry.c +++ b/reactos/ntoskrnl/cm/registry.c @@ -37,18 +37,6 @@ ERESOURCE CmpRegistryLock; LIST_ENTRY CmiKeyObjectListHead; LIST_ENTRY CmiConnectedHiveList; -volatile BOOLEAN CmiHiveSyncEnabled = FALSE; -volatile BOOLEAN CmiHiveSyncPending = FALSE; -KDPC CmiHiveSyncDpc; -KTIMER CmiHiveSyncTimer; - -static VOID -NTAPI -CmiHiveSyncDpcRoutine(PKDPC Dpc, - PVOID DeferredContext, - PVOID SystemArgument1, - PVOID SystemArgument2); - extern LIST_ENTRY CmiCallbackHead; extern FAST_MUTEX CmiCallbackLock; @@ -520,15 +508,6 @@ CmiInitHives(BOOLEAN SetupBoot) return(Status); } - //CmiCheckRegistry(TRUE); - - /* Start automatic hive synchronization */ - KeInitializeDpc(&CmiHiveSyncDpc, - CmiHiveSyncDpcRoutine, - NULL); - KeInitializeTimer(&CmiHiveSyncTimer); - CmiHiveSyncEnabled = TRUE; - DPRINT("CmiInitHives() done\n"); return(STATUS_SUCCESS); @@ -538,128 +517,7 @@ VOID NTAPI CmShutdownRegistry(VOID) { - PCMHIVE Hive; - PLIST_ENTRY Entry; - - DPRINT("CmShutdownRegistry() called\n"); - - /* Stop automatic hive synchronization */ - CmiHiveSyncEnabled = FALSE; - - /* Cancel pending hive synchronization */ - if (CmiHiveSyncPending == TRUE) - { - KeCancelTimer(&CmiHiveSyncTimer); - CmiHiveSyncPending = FALSE; - } - - /* Lock the hive list */ - ExAcquirePushLockExclusive(&CmpHiveListHeadLock); - - Entry = CmpHiveListHead.Flink; - while (Entry != &CmpHiveListHead) - { - Hive = CONTAINING_RECORD(Entry, CMHIVE, HiveList); - - if (!(IsNoFileHive(Hive) || - IsNoSynchHive(Hive) || - (Hive->Hive.HiveFlags & HIVE_VOLATILE))) - { - /* Flush non-volatile hive */ - CmiFlushRegistryHive(Hive); - } - - Entry = Entry->Flink; - } - - /* Release the lock */ - ExReleasePushLock(&CmpHiveListHeadLock); - - DPRINT("CmShutdownRegistry() done\n"); -} - -VOID -NTAPI -CmiHiveSyncRoutine(PVOID DeferredContext) -{ - PCMHIVE Hive; - PLIST_ENTRY Entry; - - DPRINT("CmiHiveSyncRoutine() called\n"); - - CmiHiveSyncPending = FALSE; - - /* Lock the hive list */ - ExAcquirePushLockExclusive(&CmpHiveListHeadLock); - - Entry = CmpHiveListHead.Flink; - while (Entry != &CmpHiveListHead) - { - Hive = CONTAINING_RECORD(Entry, CMHIVE, HiveList); - - if (!(IsNoFileHive(Hive) || - IsNoSynchHive(Hive) || - (Hive->Hive.HiveFlags & HIVE_VOLATILE))) - { - /* Flush non-volatile hive */ - CmiFlushRegistryHive(Hive); - } - - Entry = Entry->Flink; - } - - /* Release the lock */ - ExReleasePushLock(&CmpHiveListHeadLock); - - DPRINT("DeferredContext 0x%p\n", DeferredContext); - ExFreePool(DeferredContext); - - DPRINT("CmiHiveSyncRoutine() done\n"); -} - -static VOID -NTAPI -CmiHiveSyncDpcRoutine(PKDPC Dpc, - PVOID DeferredContext, - PVOID SystemArgument1, - PVOID SystemArgument2) -{ - PWORK_QUEUE_ITEM WorkQueueItem; - - WorkQueueItem = ExAllocatePool(NonPagedPool, - sizeof(WORK_QUEUE_ITEM)); - if (WorkQueueItem == NULL) - { - DPRINT1("Failed to allocate work item\n"); - return; - } - - ExInitializeWorkItem(WorkQueueItem, - CmiHiveSyncRoutine, - WorkQueueItem); - - DPRINT("DeferredContext 0x%p\n", WorkQueueItem); - ExQueueWorkItem(WorkQueueItem, - CriticalWorkQueue); -} - -VOID -CmiSyncHives(VOID) -{ - LARGE_INTEGER Timeout; - - DPRINT("CmiSyncHives() called\n"); - - if (CmiHiveSyncEnabled == FALSE || - CmiHiveSyncPending == TRUE) - return; - - CmiHiveSyncPending = TRUE; - - Timeout.QuadPart = (LONGLONG)-50000000; - KeSetTimer(&CmiHiveSyncTimer, - Timeout, - &CmiHiveSyncDpc); + CmShutdownSystem(); } /* EOF */ diff --git a/reactos/ntoskrnl/cm/regobj.c b/reactos/ntoskrnl/cm/regobj.c index 90389e086eb..3d108a9c1c2 100644 --- a/reactos/ntoskrnl/cm/regobj.c +++ b/reactos/ntoskrnl/cm/regobj.c @@ -340,6 +340,64 @@ Next: return STATUS_SUCCESS; } + +/* Preconditions: Must be called with CmpRegistryLock held. */ +NTSTATUS +CmiScanKeyList(PKEY_OBJECT Parent, + PCUNICODE_STRING KeyName, + ULONG Attributes, + PKEY_OBJECT* ReturnedObject) +{ + PKEY_OBJECT CurKey = NULL; + ULONG Index; + + DPRINT("Scanning key list for: %wZ (Parent: %wZ)\n", + KeyName, &Parent->Name); + + /* FIXME: if list maintained in alphabetic order, use dichotomic search */ + /* (a binary search) */ + for (Index=0; Index < Parent->SubKeyCounts; Index++) + { + CurKey = Parent->SubKeys[Index]; + if (Attributes & OBJ_CASE_INSENSITIVE) + { + DPRINT("Comparing %wZ and %wZ\n", KeyName, &CurKey->Name); + if ((KeyName->Length == CurKey->Name.Length) + && (_wcsicmp(KeyName->Buffer, CurKey->Name.Buffer) == 0)) + { + break; + } + } + else + { + if ((KeyName->Length == CurKey->Name.Length) + && (wcscmp(KeyName->Buffer, CurKey->Name.Buffer) == 0)) + { + break; + } + } + } + + if (Index < Parent->SubKeyCounts) + { + if (CurKey->KeyControlBlock->Delete) + { + CHECKPOINT; + *ReturnedObject = NULL; + return STATUS_UNSUCCESSFUL; + } + ObReferenceObject(CurKey); + *ReturnedObject = CurKey; + } + else + { + *ReturnedObject = NULL; + } + return STATUS_SUCCESS; +} + + + NTSTATUS NTAPI CmpParseKey(IN PVOID ParsedObject, @@ -772,61 +830,6 @@ CmiAddKeyToList(PKEY_OBJECT ParentKey, //NewKey->ParentKey = ParentKey; } -/* Preconditions: Must be called with CmpRegistryLock held. */ -NTSTATUS -CmiScanKeyList(PKEY_OBJECT Parent, - PCUNICODE_STRING KeyName, - ULONG Attributes, - PKEY_OBJECT* ReturnedObject) -{ - PKEY_OBJECT CurKey = NULL; - ULONG Index; - - DPRINT("Scanning key list for: %wZ (Parent: %wZ)\n", - KeyName, &Parent->Name); - - /* FIXME: if list maintained in alphabetic order, use dichotomic search */ - /* (a binary search) */ - for (Index=0; Index < Parent->SubKeyCounts; Index++) - { - CurKey = Parent->SubKeys[Index]; - if (Attributes & OBJ_CASE_INSENSITIVE) - { - DPRINT("Comparing %wZ and %wZ\n", KeyName, &CurKey->Name); - if ((KeyName->Length == CurKey->Name.Length) - && (_wcsicmp(KeyName->Buffer, CurKey->Name.Buffer) == 0)) - { - break; - } - } - else - { - if ((KeyName->Length == CurKey->Name.Length) - && (wcscmp(KeyName->Buffer, CurKey->Name.Buffer) == 0)) - { - break; - } - } - } - - if (Index < Parent->SubKeyCounts) - { - if (CurKey->KeyControlBlock->Delete) - { - CHECKPOINT; - *ReturnedObject = NULL; - return STATUS_UNSUCCESSFUL; - } - ObReferenceObject(CurKey); - *ReturnedObject = CurKey; - } - else - { - *ReturnedObject = NULL; - } - return STATUS_SUCCESS; -} - static NTSTATUS CmiGetLinkTarget(PCMHIVE RegistryHive, PCM_KEY_NODE KeyCell, diff --git a/reactos/ntoskrnl/config/cm.h b/reactos/ntoskrnl/config/cm.h index 67f27d71fea..8c58b56fe12 100644 --- a/reactos/ntoskrnl/config/cm.h +++ b/reactos/ntoskrnl/config/cm.h @@ -1,1365 +1,1373 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/cm/cm.h - * PURPOSE: Internal header for the Configuration Manager - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - */ -#define _CM_ -#include "cmlib.h" - -// -// Define this if you want debugging support -// -#define _CM_DEBUG_ 0x00 - -// -// These define the Debug Masks Supported -// -#define CM_HANDLE_DEBUG 0x01 -#define CM_NAMESPACE_DEBUG 0x02 -#define CM_SECURITY_DEBUG 0x04 -#define CM_REFERENCE_DEBUG 0x08 -#define CM_CALLBACK_DEBUG 0x10 - -// -// Debug/Tracing support -// -#if _CM_DEBUG_ -#ifdef NEW_DEBUG_SYSTEM_IMPLEMENTED // enable when Debug Filters are implemented -#define CMTRACE DbgPrintEx -#else -#define CMTRACE(x, ...) \ - if (x & CmpTraceLevel) DbgPrint(__VA_ARGS__) -#endif -#else -#define CMTRACE(x, ...) DPRINT(__VA_ARGS__) -#endif - - -// -// Hack since bigkeys are not yet supported -// -#define ASSERT_VALUE_BIG(h, s) \ - ASSERTMSG("Big keys not supported!", !CmpIsKeyValueBig(h, s)); - -// -// CM_KEY_CONTROL_BLOCK Flags -// -#define CM_KCB_NO_SUBKEY 0x01 -#define CM_KCB_SUBKEY_ONE 0x02 -#define CM_KCB_SUBKEY_HINT 0x04 -#define CM_KCB_SYM_LINK_FOUND 0x08 -#define CM_KCB_KEY_NON_EXIST 0x10 -#define CM_KCB_NO_DELAY_CLOSE 0x20 -#define CM_KCB_INVALID_CACHED_INFO 0x40 -#define CM_KEY_READ_ONLY_KEY 0x80 - -// -// CM_KEY_VALUE Types -// -#define CM_KEY_VALUE_SMALL 0x4 -#define CM_KEY_VALUE_BIG 0x3FD8 -#define CM_KEY_VALUE_SPECIAL_SIZE 0x80000000 - -// -// Number of various lists and hashes -// -#define CMP_SECURITY_HASH_LISTS 64 -#define CMP_MAX_CALLBACKS 100 - -// -// Hashing Constants -// -#define CMP_HASH_IRRATIONAL 314159269 -#define CMP_HASH_PRIME 1000000007 - -// -// CmpCreateKeyControlBlock Flags -// -#define CMP_CREATE_FAKE_KCB 0x1 -#define CMP_LOCK_HASHES_FOR_KCB 0x2 - -// -// Maximum size of Value Cache -// -#define MAXIMUM_CACHED_DATA 2 * PAGE_SIZE - -// -// Number of items that can fit inside an Allocation Page -// -#define CM_KCBS_PER_PAGE \ - PAGE_SIZE / sizeof(CM_KEY_CONTROL_BLOCK) -#define CM_DELAYS_PER_PAGE \ - PAGE_SIZE / sizeof(CM_DELAYED_CLOSE_ENTRY) - -// -// Value Search Results -// -typedef enum _VALUE_SEARCH_RETURN_TYPE -{ - SearchSuccess, - SearchNeedExclusiveLock, - SearchFail -} VALUE_SEARCH_RETURN_TYPE; - -// -// Key Hash -// -typedef struct _CM_KEY_HASH -{ - ULONG ConvKey; - struct _CM_KEY_HASH *NextHash; - PHHIVE KeyHive; - HCELL_INDEX KeyCell; -} CM_KEY_HASH, *PCM_KEY_HASH; - -// -// Key Hash Table Entry -// -typedef struct _CM_KEY_HASH_TABLE_ENTRY -{ - EX_PUSH_LOCK Lock; - PKTHREAD Owner; - PCM_KEY_HASH Entry; -} CM_KEY_HASH_TABLE_ENTRY, *PCM_KEY_HASH_TABLE_ENTRY; - -// -// Name Hash -// -typedef struct _CM_NAME_HASH -{ - ULONG ConvKey; - struct _CM_NAME_HASH *NextHash; - USHORT NameLength; - WCHAR Name[ANYSIZE_ARRAY]; -} CM_NAME_HASH, *PCM_NAME_HASH; - -// -// Name Hash Table Entry -// -typedef struct _CM_NAME_HASH_TABLE_ENTRY -{ - EX_PUSH_LOCK Lock; - PCM_NAME_HASH Entry; -} CM_NAME_HASH_TABLE_ENTRY, *PCM_NAME_HASH_TABLE_ENTRY; - -// -// Key Security Cache -// -typedef struct _CM_KEY_SECURITY_CACHE -{ - HCELL_INDEX Cell; - ULONG ConvKey; - LIST_ENTRY List; - ULONG DescriptorLength; - SECURITY_DESCRIPTOR_RELATIVE Descriptor; -} CM_KEY_SECURITY_CACHE, *PCM_KEY_SECURITY_CACHE; - -// -// Key Security Cache Entry -// -typedef struct _CM_KEY_SECURITY_CACHE_ENTRY -{ - HCELL_INDEX Cell; - PCM_KEY_SECURITY_CACHE CachedSecurity; -} CM_KEY_SECURITY_CACHE_ENTRY, *PCM_KEY_SECURITY_CACHE_ENTRY; - -// -// Cached Child List -// -typedef struct _CACHED_CHILD_LIST -{ - ULONG Count; - union - { - ULONG ValueList; - //struct _CM_KEY_CONTROL_BLOCK *RealKcb; - struct _KEY_OBJECT *RealKcb; - }; -} CACHED_CHILD_LIST, *PCACHED_CHILD_LIST; - -// -// Index Hint Block -// -typedef struct _CM_INDEX_HINT_BLOCK -{ - ULONG Count; - ULONG HashKey[ANYSIZE_ARRAY]; -} CM_INDEX_HINT_BLOCK, *PCM_INDEX_HINT_BLOCK; - -// -// Key Reference -// -typedef struct _CM_KEY_REFERENCE -{ - HCELL_INDEX KeyCell; - PHHIVE KeyHive; -} CM_KEY_REFERENCE, *PCM_KEY_REFERENCE; - -// -// Key Body -// -typedef struct _CM_KEY_BODY -{ - ULONG Type; - struct _CM_KEY_CONTROL_BLOCK *KeyControlBlock; - struct _CM_NOTIFY_BLOCK *NotifyBlock; - HANDLE ProcessID; - ULONG Callers; - PVOID CallerAddress[10]; - LIST_ENTRY KeyBodyList; -} CM_KEY_BODY, *PCM_KEY_BODY; - -// -// Name Control Block (NCB) -// -typedef struct _CM_NAME_CONTROL_BLOCK -{ - BOOLEAN Compressed; - USHORT RefCount; - union - { - CM_NAME_HASH NameHash; - struct - { - ULONG ConvKey; - PCM_KEY_HASH NextHash; - USHORT NameLength; - WCHAR Name[ANYSIZE_ARRAY]; - }; - }; -} CM_NAME_CONTROL_BLOCK, *PCM_NAME_CONTROL_BLOCK; - -// -// Key Control Block (KCB) -// -typedef struct _CM_KEY_CONTROL_BLOCK -{ - USHORT RefCount; - USHORT Flags; - ULONG ExtFlags:8; - ULONG PrivateAlloc:1; - ULONG Delete:1; - ULONG DelayedCloseIndex:12; - ULONG TotalLevels:10; - union - { - CM_KEY_HASH KeyHash; - struct - { - ULONG ConvKey; - PCM_KEY_HASH NextHash; - PHHIVE KeyHive; - HCELL_INDEX KeyCell; - }; - }; - struct _CM_KEY_CONTROL_BLOCK *ParentKcb; - PCM_NAME_CONTROL_BLOCK NameBlock; - PCM_KEY_SECURITY_CACHE CachedSecurity; - CACHED_CHILD_LIST ValueCache; - PCM_INDEX_HINT_BLOCK IndexHint; - ULONG HashKey; - ULONG SubKeyCount; - union - { - LIST_ENTRY KeyBodyListHead; - LIST_ENTRY FreeListEntry; - }; - PCM_KEY_BODY KeyBodyArray[4]; - PVOID DelayCloseEntry; - LARGE_INTEGER KcbLastWriteTime; - USHORT KcbMaxNameLen; - USHORT KcbMaxValueNameLen; - ULONG KcbMaxValueDataLen; - ULONG InDelayClose; -} CM_KEY_CONTROL_BLOCK, *PCM_KEY_CONTROL_BLOCK; - -// -// Notify Block -// -typedef struct _CM_NOTIFY_BLOCK -{ - LIST_ENTRY HiveList; - LIST_ENTRY PostList; - PCM_KEY_CONTROL_BLOCK KeyControlBlock; - PCM_KEY_BODY KeyBody; - ULONG Filter:29; - ULONG WatchTree:30; - ULONG NotifyPending:31; -} CM_NOTIFY_BLOCK, *PCM_NOTIFY_BLOCK; - -// -// Re-map Block -// -typedef struct _CM_CELL_REMAP_BLOCK -{ - HCELL_INDEX OldCell; - HCELL_INDEX NewCell; -} CM_CELL_REMAP_BLOCK, *PCM_CELL_REMAP_BLOCK; - -// -// Allocation Page -// -typedef struct _CM_ALLOC_PAGE -{ - ULONG FreeCount; - ULONG Reserved; - PVOID AllocPage; -} CM_ALLOC_PAGE, *PCM_ALLOC_PAGE; - -// -// Allocation Page Entry -// -typedef struct _CM_DELAY_ALLOC -{ - LIST_ENTRY ListEntry; - PCM_KEY_CONTROL_BLOCK Kcb; -} CM_DELAY_ALLOC, *PCM_DELAY_ALLOC; - -// -// Delayed Close Entry -// -typedef struct _CM_DELAYED_CLOSE_ENTRY -{ - LIST_ENTRY DelayedLRUList; - PCM_KEY_CONTROL_BLOCK KeyControlBlock; -} CM_DELAYED_CLOSE_ENTRY, *PCM_DELAYED_CLOSE_ENTRY; - -// -// Delayed KCB Dereference Entry -// -typedef struct _CM_DELAY_DEREF_KCB_ITEM -{ - LIST_ENTRY ListEntry; - PCM_KEY_CONTROL_BLOCK Kcb; -} CM_DELAY_DEREF_KCB_ITEM, *PCM_DELAY_DEREF_KCB_ITEM; - -// -// Use Count Log and Entry -// -typedef struct _CM_USE_COUNT_LOG_ENTRY -{ - HCELL_INDEX Cell; - PVOID Stack[7]; -} CM_USE_COUNT_LOG_ENTRY, *PCM_USE_COUNT_LOG_ENTRY; - -typedef struct _CM_USE_COUNT_LOG -{ - USHORT Next; - USHORT Size; - CM_USE_COUNT_LOG_ENTRY Log[32]; -} CM_USE_COUNT_LOG, *PCM_USE_COUNT_LOG; - -// -// Configuration Manager Hive Structure -// -typedef struct _CMHIVE -{ - HHIVE Hive; - HANDLE FileHandles[3]; - LIST_ENTRY NotifyList; - LIST_ENTRY HiveList; - EX_PUSH_LOCK HiveLock; - PKTHREAD HiveLockOwner; - PKGUARDED_MUTEX ViewLock; - PKTHREAD ViewLockOwner; - EX_PUSH_LOCK WriterLock; - PKTHREAD WriterLockOwner; - PERESOURCE FlusherLock; - EX_PUSH_LOCK SecurityLock; - PKTHREAD HiveSecurityLockOwner; - LIST_ENTRY LRUViewListHead; - LIST_ENTRY PinViewListHead; - PFILE_OBJECT FileObject; - UNICODE_STRING FileFullPath; - UNICODE_STRING FileUserName; - USHORT MappedViews; - USHORT PinnedViews; - ULONG UseCount; - ULONG SecurityCount; - ULONG SecurityCacheSize; - LONG SecurityHitHint; - PCM_KEY_SECURITY_CACHE_ENTRY SecurityCache; - LIST_ENTRY SecurityHash[CMP_SECURITY_HASH_LISTS]; - PKEVENT UnloadEvent; - PCM_KEY_CONTROL_BLOCK RootKcb; - BOOLEAN Frozen; - PWORK_QUEUE_ITEM UnloadWorkItem; - BOOLEAN GrowOnlyMode; - ULONG GrowOffset; - LIST_ENTRY KcbConvertListHead; - LIST_ENTRY KnodeConvertListHead; - PCM_CELL_REMAP_BLOCK CellRemapArray; - CM_USE_COUNT_LOG UseCountLog; - CM_USE_COUNT_LOG LockHiveLog; - ULONG Flags; - LIST_ENTRY TrustClassEntry; - ULONG FlushCount; - BOOLEAN HiveIsLoading; - PKTHREAD CreatorOwner; -} CMHIVE, *PCMHIVE; - -// -// Cached Value Index -// -typedef struct _CM_CACHED_VALUE_INDEX -{ - HCELL_INDEX CellIndex; - union - { - CELL_DATA CellData; - ULONG_PTR List[ANYSIZE_ARRAY]; - } Data; -} CM_CACHED_VALUE_INDEX, *PCM_CACHED_VALUE_INDEX; - -// -// Cached Value -// -typedef struct _CM_CACHED_VALUE -{ - USHORT DataCacheType; - USHORT ValueKeySize; - ULONG HashKey; - CM_KEY_VALUE KeyValue; -} CM_CACHED_VALUE, *PCM_CACHED_VALUE; - -// -// Hive List Entry -// -typedef struct _HIVE_LIST_ENTRY -{ - PWCHAR FileName; - PWCHAR BaseName; - PWCHAR RegRootName; - PCMHIVE CmHive; - ULONG HHiveFlags; - ULONG CmHiveFlags; - PCMHIVE CmHive2; - BOOLEAN ThreadFinished; - BOOLEAN ThreadStarted; - BOOLEAN Allocate; - BOOLEAN WinPERequired; -} HIVE_LIST_ENTRY, *PHIVE_LIST_ENTRY; - -// -// Parse context for Key Object -// -typedef struct _CM_PARSE_CONTEXT -{ - ULONG TitleIndex; - UNICODE_STRING Class; - ULONG CreateOptions; - ULONG Disposition; - CM_KEY_REFERENCE ChildHive; - BOOLEAN CreateLink; - BOOLEAN Flag2; - HANDLE PredefinedHandle; - ULONG PostActions; -} CM_PARSE_CONTEXT, *PCM_PARSE_CONTEXT; - -// -// System Control Vector -// -typedef struct _CM_SYSTEM_CONTROL_VECTOR -{ - PWCHAR KeyPath; - PWCHAR ValueName; - PVOID Buffer; - PULONG BufferLength; - PULONG Type; -} CM_SYSTEM_CONTROL_VECTOR, *PCM_SYSTEM_CONTROL_VECTOR; - -// -// Structure for CmpQueryValueDataFromCache -// -typedef struct _KEY_VALUE_INFORMATION -{ - union - { - KEY_VALUE_BASIC_INFORMATION KeyValueBasicInformation; - KEY_VALUE_FULL_INFORMATION KeyValueFullInformation; - KEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInformation; - KEY_VALUE_PARTIAL_INFORMATION_ALIGN64 KeyValuePartialInformationAlign64; - }; -} KEY_VALUE_INFORMATION, *PKEY_VALUE_INFORMATION; - -typedef struct _KEY_INFORMATION -{ - union - { - KEY_BASIC_INFORMATION KeyBasicInformation; - KEY_FULL_INFORMATION KeyFullInformation; - KEY_NODE_INFORMATION KeyNodeInformation; - }; -} KEY_INFORMATION, *PKEY_INFORMATION; - -/////////////////////////////////////////////////////////////////////////////// -// -// BUGBUG Old Hive Stuff for Temporary Support -// -#define SYSTEM_REG_FILE L"\\SystemRoot\\System32\\Config\\SYSTEM" -#define SYSTEM_LOG_FILE L"\\SystemRoot\\System32\\Config\\SYSTEM.log" -#define REG_SYSTEM_KEY_NAME L"\\Registry\\Machine\\SYSTEM" -#define REG_HARDWARE_KEY_NAME L"\\Registry\\Machine\\HARDWARE" -typedef struct _KEY_OBJECT -{ - ULONG Type; - UNICODE_STRING Name; - LIST_ENTRY KeyBodyList; - ULONG SubKeyCounts; - ULONG SizeOfSubKeys; - struct _KEY_OBJECT **SubKeys; - PCM_KEY_CONTROL_BLOCK KeyControlBlock; -} KEY_OBJECT, *PKEY_OBJECT; -extern PCMHIVE CmiVolatileHive; -extern LIST_ENTRY CmiKeyObjectListHead, CmiConnectedHiveList; -PVOID NTAPI CmpRosGetHardwareHive(OUT PULONG Length); -NTSTATUS CmiCallRegisteredCallbacks(IN REG_NOTIFY_CLASS Argument1, IN PVOID Argument2); -VOID CmiSyncHives(VOID); -/////////////////////////////////////////////////////////////////////////////// - -// -// Mapped View Hive Functions -// -VOID -NTAPI -CmpInitHiveViewList( - IN PCMHIVE Hive -); - -// -// Security Cache Functions -// -VOID -NTAPI -CmpInitSecurityCache( - IN PCMHIVE Hive -); - -// -// Value Cache Functions -// -VALUE_SEARCH_RETURN_TYPE -NTAPI -CmpFindValueByNameFromCache( - IN PCM_KEY_CONTROL_BLOCK Kcb, - IN PCUNICODE_STRING Name, - OUT PCM_CACHED_VALUE **CachedValue, - OUT ULONG *Index, - OUT PCM_KEY_VALUE *Value, - OUT BOOLEAN *ValueIsCached, - OUT PHCELL_INDEX CellToRelease -); - -VALUE_SEARCH_RETURN_TYPE -NTAPI -CmpQueryKeyValueData( - IN PCM_KEY_CONTROL_BLOCK Kcb, - IN PCM_CACHED_VALUE *CachedValue, - IN PCM_KEY_VALUE ValueKey, - IN BOOLEAN ValueIsCached, - IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, - IN PVOID KeyValueInformation, - IN ULONG Length, - OUT PULONG ResultLength, - OUT PNTSTATUS Status -); - -VALUE_SEARCH_RETURN_TYPE -NTAPI -CmpGetValueListFromCache( - IN PCM_KEY_CONTROL_BLOCK Kcb, - OUT PCELL_DATA *CellData, - OUT BOOLEAN *IndexIsCached, - OUT PHCELL_INDEX ValueListToRelease -); - -VALUE_SEARCH_RETURN_TYPE -NTAPI -CmpGetValueKeyFromCache( - IN PCM_KEY_CONTROL_BLOCK Kcb, - IN PCELL_DATA CellData, - IN ULONG Index, - OUT PCM_CACHED_VALUE **CachedValue, - OUT PCM_KEY_VALUE *Value, - IN BOOLEAN IndexIsCached, - OUT BOOLEAN *ValueIsCached, - OUT PHCELL_INDEX CellToRelease -); - -// -// Registry Validation Functions -// -ULONG -NTAPI -CmCheckRegistry( - IN PCMHIVE Hive, - IN ULONG Flags -); - -// -// Notification Routines -// -VOID -NTAPI -CmpReportNotify( - IN PCM_KEY_CONTROL_BLOCK Kcb, - IN PHHIVE Hive, - IN HCELL_INDEX Cell, - IN ULONG Filter -); - -VOID -NTAPI -CmpInitCallback( - VOID -); - -// -// KCB Cache/Delay Routines -// -VOID -NTAPI -CmpInitializeCache( - VOID -); - -VOID -NTAPI -CmpInitCmPrivateDelayAlloc( - VOID -); - -VOID -NTAPI -CmpInitCmPrivateAlloc( - VOID -); - -VOID -NTAPI -CmpInitDelayDerefKCBEngine( - VOID -); - -// -// Key Object Routines -// -VOID -NTAPI -CmpCloseKeyObject( - IN PEPROCESS Process OPTIONAL, - IN PVOID Object, - IN ACCESS_MASK GrantedAccess, - IN ULONG ProcessHandleCount, - IN ULONG SystemHandleCount -); - -VOID -NTAPI -CmpDeleteKeyObject( - IN PVOID Object -); - -NTSTATUS -NTAPI -CmpParseKey( - IN PVOID ParseObject, - IN PVOID ObjectType, - IN OUT PACCESS_STATE AccessState, - IN KPROCESSOR_MODE AccessMode, - IN ULONG Attributes, - IN OUT PUNICODE_STRING CompleteName, - IN OUT PUNICODE_STRING RemainingName, - IN OUT PVOID Context OPTIONAL, - IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL, - OUT PVOID *Object -); - -NTSTATUS -NTAPI -CmpSecurityMethod( - IN PVOID Object, - IN SECURITY_OPERATION_CODE OperationType, - IN PSECURITY_INFORMATION SecurityInformation, - IN PSECURITY_DESCRIPTOR SecurityDescriptor, - IN OUT PULONG CapturedLength, - IN OUT PSECURITY_DESCRIPTOR *ObjectSecurityDescriptor, - IN POOL_TYPE PoolType, - IN PGENERIC_MAPPING GenericMapping -); - -NTSTATUS -NTAPI -CmpQueryKeyName( - IN PVOID Object, - IN BOOLEAN HasObjectName, - OUT POBJECT_NAME_INFORMATION ObjectNameInfo, - IN ULONG Length, - OUT PULONG ReturnLength, - IN KPROCESSOR_MODE AccessMode -); - -// -// Hive Routines -// -NTSTATUS -NTAPI -CmpInitializeHive( - OUT PCMHIVE *CmHive, - IN ULONG Operation, - IN ULONG Flags, - IN ULONG FileType, - IN PVOID HiveData OPTIONAL, - IN HANDLE Primary, - IN HANDLE Log, - IN HANDLE External, - IN PCUNICODE_STRING FileName OPTIONAL, - IN ULONG CheckFlags -); - -PSECURITY_DESCRIPTOR -NTAPI -CmpHiveRootSecurityDescriptor( - VOID -); - -NTSTATUS -NTAPI -CmpLinkHiveToMaster( - IN PUNICODE_STRING LinkName, - IN HANDLE RootDirectory, - IN PCMHIVE CmHive, - IN BOOLEAN Allocate, - IN PSECURITY_DESCRIPTOR SecurityDescriptor -); - -NTSTATUS -NTAPI -CmpOpenHiveFiles( - IN PCUNICODE_STRING BaseName, - IN PCWSTR Extension OPTIONAL, - IN PHANDLE Primary, - IN PHANDLE Log, - IN PULONG PrimaryDisposition, - IN PULONG LogDisposition, - IN BOOLEAN CreateAllowed, - IN BOOLEAN MarkAsSystemHive, - IN BOOLEAN NoBuffering, - OUT PULONG ClusterSize OPTIONAL -); - -NTSTATUS -NTAPI -CmpInitHiveFromFile( - IN PCUNICODE_STRING HiveName, - IN ULONG HiveFlags, - OUT PCMHIVE *Hive, - IN OUT PBOOLEAN New, - IN ULONG CheckFlags -); - -// -// Registry Utility Functions -// -BOOLEAN -NTAPI -CmpTestRegistryLockExclusive( - VOID -); - -VOID -NTAPI -CmpLockRegistryExclusive( - VOID -); - -VOID -NTAPI -CmpLockRegistry( - VOID -); - -VOID -NTAPI -CmpUnlockRegistry( - VOID -); - -// -// Delay Functions -// -PVOID -NTAPI -CmpAllocateDelayItem( - VOID -); - -VOID -NTAPI -CmpFreeDelayItem( - PVOID Entry -); - -VOID -NTAPI -CmpDelayDerefKeyControlBlock( - IN PCM_KEY_CONTROL_BLOCK Kcb -); - -VOID -NTAPI -CmpAddToDelayedClose( - IN PCM_KEY_CONTROL_BLOCK Kcb, - IN BOOLEAN LockHeldExclusively -); - -VOID -NTAPI -CmpRemoveFromDelayedClose(IN PCM_KEY_CONTROL_BLOCK Kcb); - -VOID -NTAPI -CmpInitializeDelayedCloseTable( - VOID -); - -// -// KCB Functions -// -PCM_KEY_CONTROL_BLOCK -NTAPI -CmpCreateKeyControlBlock( - IN PHHIVE Hive, - IN HCELL_INDEX Index, - IN PCM_KEY_NODE Node, - IN PCM_KEY_CONTROL_BLOCK Parent, - IN ULONG Flags, - IN PUNICODE_STRING KeyName -); - -PCM_KEY_CONTROL_BLOCK -NTAPI -CmpAllocateKeyControlBlock( - VOID -); - -VOID -NTAPI -CmpFreeKeyControlBlock( - IN PCM_KEY_CONTROL_BLOCK Kcb -); - -VOID -NTAPI -CmpRemoveKeyControlBlock( - IN PCM_KEY_CONTROL_BLOCK Kcb -); - -VOID -NTAPI -CmpCleanUpKcbCacheWithLock( - IN PCM_KEY_CONTROL_BLOCK Kcb, - IN BOOLEAN LockHeldExclusively -); - -VOID -NTAPI -CmpDereferenceKeyControlBlockWithLock( - IN PCM_KEY_CONTROL_BLOCK Kcb, - IN BOOLEAN LockHeldExclusively -); - -VOID -NTAPI -EnlistKeyBodyWithKCB( - IN PCM_KEY_BODY KeyObject, - IN ULONG Flags -); - -VOID -NTAPI -EnlistKeyBodyWithKeyObject( - IN PKEY_OBJECT KeyObject, - IN ULONG Flags -); - -NTSTATUS -NTAPI -CmpFreeKeyByCell( - IN PHHIVE Hive, - IN HCELL_INDEX Cell, - IN BOOLEAN Unlink -); - -// -// Name Functions -// -LONG -NTAPI -CmpCompareCompressedName( - IN PCUNICODE_STRING SearchName, - IN PWCHAR CompressedName, - IN ULONG NameLength -); - -USHORT -NTAPI -CmpNameSize( - IN PHHIVE Hive, - IN PUNICODE_STRING Name -); - -USHORT -NTAPI -CmpCompressedNameSize( - IN PWCHAR Name, - IN ULONG Length -); - -VOID -NTAPI -CmpCopyCompressedName( - IN PWCHAR Destination, - IN ULONG DestinationLength, - IN PWCHAR Source, - IN ULONG SourceLength -); - -USHORT -NTAPI -CmpCopyName( - IN PHHIVE Hive, - IN PWCHAR Destination, - IN PUNICODE_STRING Source -); - -BOOLEAN -NTAPI -CmpFindNameInList( - IN PHHIVE Hive, - IN PCHILD_LIST ChildList, - IN PUNICODE_STRING Name, - IN PULONG ChildIndex, - IN PHCELL_INDEX CellIndex -); - -// -// Parse Routines -// -BOOLEAN -NTAPI -CmpGetNextName( - IN OUT PUNICODE_STRING RemainingName, - OUT PUNICODE_STRING NextName, - OUT PBOOLEAN LastName -); - -// -// Flush Routines -// -BOOLEAN -NTAPI -CmpDoFlushAll( - IN BOOLEAN ForceFlush -); - -VOID -NTAPI -CmpShutdownWorkers( - VOID -); - -VOID -NTAPI -CmpCmdInit( - IN BOOLEAN SetupBoot -); - -VOID -NTAPI -CmpLazyFlush( - VOID -); - -// -// Open/Create Routines -// -NTSTATUS -NTAPI -CmpDoCreate( - IN PHHIVE Hive, - IN HCELL_INDEX Cell, - IN PACCESS_STATE AccessState, - IN PUNICODE_STRING Name, - IN KPROCESSOR_MODE AccessMode, - IN PUNICODE_STRING Class, - IN ULONG CreateOptions, - IN PCM_KEY_CONTROL_BLOCK ParentKcb, - IN PCMHIVE OriginatingHive OPTIONAL, - OUT PVOID *Object -); - -// -// Cell Index Routines -// - -HCELL_INDEX -NTAPI -CmpFindSubKeyByName( - IN PHHIVE Hive, - IN PCM_KEY_NODE Parent, - IN PCUNICODE_STRING SearchName -); - -HCELL_INDEX -NTAPI -CmpFindSubKeyByNumber( - IN PHHIVE Hive, - IN PCM_KEY_NODE Node, - IN ULONG Number -); - -ULONG -NTAPI -CmpComputeHashKey( - IN ULONG Hash, - IN PCUNICODE_STRING Name, - IN BOOLEAN AllowSeparators -); - -BOOLEAN -NTAPI -CmpAddSubKey( - IN PHHIVE Hive, - IN HCELL_INDEX Parent, - IN HCELL_INDEX Child -); - -BOOLEAN -NTAPI -CmpRemoveSubKey( - IN PHHIVE Hive, - IN HCELL_INDEX ParentKey, - IN HCELL_INDEX TargetKey -); - -BOOLEAN -NTAPI -CmpMarkIndexDirty( - IN PHHIVE Hive, - HCELL_INDEX ParentKey, - HCELL_INDEX TargetKey -); - -// -// Cell Value Routines -// -HCELL_INDEX -NTAPI -CmpFindValueByName( - IN PHHIVE Hive, - IN PCM_KEY_NODE KeyNode, - IN PUNICODE_STRING Name -); - -PCELL_DATA -NTAPI -CmpValueToData( - IN PHHIVE Hive, - IN PCM_KEY_VALUE Value, - OUT PULONG Length -); - -NTSTATUS -NTAPI -CmpSetValueDataNew( - IN PHHIVE Hive, - IN PVOID Data, - IN ULONG DataSize, - IN ULONG StorageType, - IN HCELL_INDEX ValueCell, - OUT PHCELL_INDEX DataCell -); - -NTSTATUS -NTAPI -CmpAddValueToList( - IN PHHIVE Hive, - IN HCELL_INDEX ValueCell, - IN ULONG Index, - IN ULONG Type, - IN OUT PCHILD_LIST ChildList -); - -BOOLEAN -NTAPI -CmpFreeValue( - IN PHHIVE Hive, - IN HCELL_INDEX Cell -); - -BOOLEAN -NTAPI -CmpMarkValueDataDirty( - IN PHHIVE Hive, - IN PCM_KEY_VALUE Value -); - -BOOLEAN -NTAPI -CmpFreeValueData( - IN PHHIVE Hive, - IN HCELL_INDEX DataCell, - IN ULONG DataLength -); - -NTSTATUS -NTAPI -CmpRemoveValueFromList( - IN PHHIVE Hive, - IN ULONG Index, - IN OUT PCHILD_LIST ChildList -); - -BOOLEAN -NTAPI -CmpGetValueData( - IN PHHIVE Hive, - IN PCM_KEY_VALUE Value, - IN PULONG Length, - OUT PVOID *Buffer, - OUT PBOOLEAN BufferAllocated, - OUT PHCELL_INDEX CellToRelease -); - -// -// Boot Routines -// -HCELL_INDEX -NTAPI -CmpFindControlSet( - IN PHHIVE SystemHive, - IN HCELL_INDEX RootCell, - IN PUNICODE_STRING SelectKeyName, - OUT PBOOLEAN AutoSelect -); - -VOID -NTAPI -CmGetSystemControlValues( - IN PVOID SystemHiveData, - IN PCM_SYSTEM_CONTROL_VECTOR ControlVector -); - - -// -// Hardware Configuration Routines -// -NTSTATUS -NTAPI -CmpInitializeRegistryNode( - IN PCONFIGURATION_COMPONENT_DATA CurrentEntry, - IN HANDLE NodeHandle, - OUT PHANDLE NewHandle, - IN INTERFACE_TYPE InterfaceType, - IN ULONG BusNumber, - IN PUSHORT DeviceIndexTable -); - -NTSTATUS -NTAPI -CmpInitializeMachineDependentConfiguration( - IN PLOADER_PARAMETER_BLOCK LoaderBlock -); - -NTSTATUS -NTAPI -CmpInitializeHardwareConfiguration( - IN PLOADER_PARAMETER_BLOCK LoaderBlock -); - -// -// Wrapper Routines -// -NTSTATUS -NTAPI -CmpCreateEvent( - IN EVENT_TYPE EventType, - OUT PHANDLE EventHandle, - OUT PKEVENT *Event -); - -PVOID -NTAPI -CmpAllocate( - IN ULONG Size, - IN BOOLEAN Paged, - IN ULONG Tag -); - -VOID -NTAPI -CmpFree( - IN PVOID Ptr, - IN ULONG Quota -); - -BOOLEAN -NTAPI -CmpFileRead( - IN PHHIVE RegistryHive, - IN ULONG FileType, - IN OUT PULONG FileOffset, - OUT PVOID Buffer, - IN SIZE_T BufferLength -); - -BOOLEAN -NTAPI -CmpFileWrite( - IN PHHIVE RegistryHive, - IN ULONG FileType, - IN OUT PULONG FileOffset, - IN PVOID Buffer, - IN SIZE_T BufferLength -); - -BOOLEAN -NTAPI -CmpFileSetSize( - IN PHHIVE RegistryHive, - IN ULONG FileType, - IN ULONG FileSize, - IN ULONG OldFileSize -); - -BOOLEAN -NTAPI -CmpFileFlush( - IN PHHIVE RegistryHive, - IN ULONG FileType, - IN OUT PLARGE_INTEGER FileOffset, - IN ULONG Length -); - -// -// Configuration Manager side of Registry System Calls -// -NTSTATUS -NTAPI -CmEnumerateValueKey( - IN PCM_KEY_CONTROL_BLOCK Kcb, - IN ULONG Index, - IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, - IN PVOID KeyValueInformation, - IN ULONG Length, - IN PULONG ResultLength); - -NTSTATUS -NTAPI -CmSetValueKey( - IN PCM_KEY_CONTROL_BLOCK Kcb, - IN PUNICODE_STRING ValueName, - IN ULONG Type, - IN PVOID Data, - IN ULONG DataSize); - -NTSTATUS -NTAPI -CmQueryKey(IN PCM_KEY_CONTROL_BLOCK Kcb, - IN KEY_INFORMATION_CLASS KeyInformationClass, - IN PVOID KeyInformation, - IN ULONG Length, - IN PULONG ResultLength -); - -NTSTATUS -NTAPI -CmEnumerateKey(IN PCM_KEY_CONTROL_BLOCK Kcb, - IN ULONG Index, - IN KEY_INFORMATION_CLASS KeyInformationClass, - IN PVOID KeyInformation, - IN ULONG Length, - IN PULONG ResultLength -); - -NTSTATUS -NTAPI -CmDeleteKey( - IN PCM_KEY_CONTROL_BLOCK Kcb -); - -NTSTATUS -NTAPI -CmFlushKey( - IN PCM_KEY_CONTROL_BLOCK Kcb, - IN BOOLEAN EclusiveLock -); - -NTSTATUS -NTAPI -CmDeleteValueKey( - IN PCM_KEY_CONTROL_BLOCK Kcb, - IN UNICODE_STRING ValueName -); - -NTSTATUS -NTAPI -CmQueryValueKey( - IN PCM_KEY_CONTROL_BLOCK Kcb, - IN UNICODE_STRING ValueName, - IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, - IN PVOID KeyValueInformation, - IN ULONG Length, - IN PULONG ResultLength -); - -// -// Global variables accessible from all of Cm -// -extern BOOLEAN CmpSpecialBootCondition; -extern BOOLEAN CmpFlushOnLockRelease; -extern BOOLEAN CmpShareSystemHives; -extern BOOLEAN CmpMiniNTBoot; -extern EX_PUSH_LOCK CmpHiveListHeadLock, CmpLoadHiveLock; -extern LIST_ENTRY CmpHiveListHead; -extern POBJECT_TYPE CmpKeyObjectType; -extern ERESOURCE CmpRegistryLock; -extern PCM_KEY_HASH_TABLE_ENTRY CmpCacheTable; -extern PCM_NAME_HASH_TABLE_ENTRY CmpNameCacheTable; -extern KGUARDED_MUTEX CmpDelayedCloseTableLock; -extern CMHIVE CmControlHive; -extern WCHAR CmDefaultLanguageId[]; -extern ULONG CmDefaultLanguageIdLength; -extern ULONG CmDefaultLanguageIdType; -extern WCHAR CmInstallUILanguageId[]; -extern ULONG CmInstallUILanguageIdLength; -extern ULONG CmInstallUILanguageIdType; -extern LANGID PsInstallUILanguageId; -extern LANGID PsDefaultUILanguageId; -extern CM_SYSTEM_CONTROL_VECTOR CmControlVector[]; -extern ULONG CmpConfigurationAreaSize; -extern PCM_FULL_RESOURCE_DESCRIPTOR CmpConfigurationData; -extern UNICODE_STRING CmTypeName[]; -extern HIVE_LIST_ENTRY CmpMachineHiveList[5]; -extern UNICODE_STRING CmSymbolicLinkValueName; -extern UNICODE_STRING CmpSystemStartOptions; -extern UNICODE_STRING CmpLoadOptions; -extern BOOLEAN CmSelfHeal; -extern BOOLEAN CmpSelfHeal; -extern ULONG CmpBootType; -extern HANDLE CmpRegistryRootHandle; -extern BOOLEAN ExpInTextModeSetup; -extern BOOLEAN InitIsWinPEMode; -extern ULONG CmpHashTableSize; -extern ULONG CmpDelayedCloseSize, CmpDelayedCloseIndex; -extern BOOLEAN CmpNoWrite; -extern BOOLEAN CmpForceForceFlush; -extern BOOLEAN CmpWasSetupBoot; - -// -// Inlined functions -// -#include "cm_x.h" +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/cm/cm.h + * PURPOSE: Internal header for the Configuration Manager + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ +#define _CM_ +#include "cmlib.h" + +// +// Define this if you want debugging support +// +#define _CM_DEBUG_ 0x00 + +// +// These define the Debug Masks Supported +// +#define CM_HANDLE_DEBUG 0x01 +#define CM_NAMESPACE_DEBUG 0x02 +#define CM_SECURITY_DEBUG 0x04 +#define CM_REFERENCE_DEBUG 0x08 +#define CM_CALLBACK_DEBUG 0x10 + +// +// Debug/Tracing support +// +#if _CM_DEBUG_ +#ifdef NEW_DEBUG_SYSTEM_IMPLEMENTED // enable when Debug Filters are implemented +#define CMTRACE DbgPrintEx +#else +#define CMTRACE(x, ...) \ + if (x & CmpTraceLevel) DbgPrint(__VA_ARGS__) +#endif +#else +#define CMTRACE(x, ...) DPRINT(__VA_ARGS__) +#endif + + +// +// Hack since bigkeys are not yet supported +// +#define ASSERT_VALUE_BIG(h, s) \ + ASSERTMSG("Big keys not supported!", !CmpIsKeyValueBig(h, s)); + +// +// CM_KEY_CONTROL_BLOCK Flags +// +#define CM_KCB_NO_SUBKEY 0x01 +#define CM_KCB_SUBKEY_ONE 0x02 +#define CM_KCB_SUBKEY_HINT 0x04 +#define CM_KCB_SYM_LINK_FOUND 0x08 +#define CM_KCB_KEY_NON_EXIST 0x10 +#define CM_KCB_NO_DELAY_CLOSE 0x20 +#define CM_KCB_INVALID_CACHED_INFO 0x40 +#define CM_KEY_READ_ONLY_KEY 0x80 + +// +// CM_KEY_VALUE Types +// +#define CM_KEY_VALUE_SMALL 0x4 +#define CM_KEY_VALUE_BIG 0x3FD8 +#define CM_KEY_VALUE_SPECIAL_SIZE 0x80000000 + +// +// Number of various lists and hashes +// +#define CMP_SECURITY_HASH_LISTS 64 +#define CMP_MAX_CALLBACKS 100 + +// +// Hashing Constants +// +#define CMP_HASH_IRRATIONAL 314159269 +#define CMP_HASH_PRIME 1000000007 + +// +// CmpCreateKeyControlBlock Flags +// +#define CMP_CREATE_FAKE_KCB 0x1 +#define CMP_LOCK_HASHES_FOR_KCB 0x2 + +// +// Maximum size of Value Cache +// +#define MAXIMUM_CACHED_DATA 2 * PAGE_SIZE + +// +// Number of items that can fit inside an Allocation Page +// +#define CM_KCBS_PER_PAGE \ + PAGE_SIZE / sizeof(CM_KEY_CONTROL_BLOCK) +#define CM_DELAYS_PER_PAGE \ + PAGE_SIZE / sizeof(CM_DELAYED_CLOSE_ENTRY) + +// +// Value Search Results +// +typedef enum _VALUE_SEARCH_RETURN_TYPE +{ + SearchSuccess, + SearchNeedExclusiveLock, + SearchFail +} VALUE_SEARCH_RETURN_TYPE; + +// +// Key Hash +// +typedef struct _CM_KEY_HASH +{ + ULONG ConvKey; + struct _CM_KEY_HASH *NextHash; + PHHIVE KeyHive; + HCELL_INDEX KeyCell; +} CM_KEY_HASH, *PCM_KEY_HASH; + +// +// Key Hash Table Entry +// +typedef struct _CM_KEY_HASH_TABLE_ENTRY +{ + EX_PUSH_LOCK Lock; + PKTHREAD Owner; + PCM_KEY_HASH Entry; +} CM_KEY_HASH_TABLE_ENTRY, *PCM_KEY_HASH_TABLE_ENTRY; + +// +// Name Hash +// +typedef struct _CM_NAME_HASH +{ + ULONG ConvKey; + struct _CM_NAME_HASH *NextHash; + USHORT NameLength; + WCHAR Name[ANYSIZE_ARRAY]; +} CM_NAME_HASH, *PCM_NAME_HASH; + +// +// Name Hash Table Entry +// +typedef struct _CM_NAME_HASH_TABLE_ENTRY +{ + EX_PUSH_LOCK Lock; + PCM_NAME_HASH Entry; +} CM_NAME_HASH_TABLE_ENTRY, *PCM_NAME_HASH_TABLE_ENTRY; + +// +// Key Security Cache +// +typedef struct _CM_KEY_SECURITY_CACHE +{ + HCELL_INDEX Cell; + ULONG ConvKey; + LIST_ENTRY List; + ULONG DescriptorLength; + SECURITY_DESCRIPTOR_RELATIVE Descriptor; +} CM_KEY_SECURITY_CACHE, *PCM_KEY_SECURITY_CACHE; + +// +// Key Security Cache Entry +// +typedef struct _CM_KEY_SECURITY_CACHE_ENTRY +{ + HCELL_INDEX Cell; + PCM_KEY_SECURITY_CACHE CachedSecurity; +} CM_KEY_SECURITY_CACHE_ENTRY, *PCM_KEY_SECURITY_CACHE_ENTRY; + +// +// Cached Child List +// +typedef struct _CACHED_CHILD_LIST +{ + ULONG Count; + union + { + ULONG ValueList; + //struct _CM_KEY_CONTROL_BLOCK *RealKcb; + struct _KEY_OBJECT *RealKcb; + }; +} CACHED_CHILD_LIST, *PCACHED_CHILD_LIST; + +// +// Index Hint Block +// +typedef struct _CM_INDEX_HINT_BLOCK +{ + ULONG Count; + ULONG HashKey[ANYSIZE_ARRAY]; +} CM_INDEX_HINT_BLOCK, *PCM_INDEX_HINT_BLOCK; + +// +// Key Reference +// +typedef struct _CM_KEY_REFERENCE +{ + HCELL_INDEX KeyCell; + PHHIVE KeyHive; +} CM_KEY_REFERENCE, *PCM_KEY_REFERENCE; + +// +// Key Body +// +typedef struct _CM_KEY_BODY +{ + ULONG Type; + struct _CM_KEY_CONTROL_BLOCK *KeyControlBlock; + struct _CM_NOTIFY_BLOCK *NotifyBlock; + HANDLE ProcessID; + ULONG Callers; + PVOID CallerAddress[10]; + LIST_ENTRY KeyBodyList; +} CM_KEY_BODY, *PCM_KEY_BODY; + +// +// Name Control Block (NCB) +// +typedef struct _CM_NAME_CONTROL_BLOCK +{ + BOOLEAN Compressed; + USHORT RefCount; + union + { + CM_NAME_HASH NameHash; + struct + { + ULONG ConvKey; + PCM_KEY_HASH NextHash; + USHORT NameLength; + WCHAR Name[ANYSIZE_ARRAY]; + }; + }; +} CM_NAME_CONTROL_BLOCK, *PCM_NAME_CONTROL_BLOCK; + +// +// Key Control Block (KCB) +// +typedef struct _CM_KEY_CONTROL_BLOCK +{ + USHORT RefCount; + USHORT Flags; + ULONG ExtFlags:8; + ULONG PrivateAlloc:1; + ULONG Delete:1; + ULONG DelayedCloseIndex:12; + ULONG TotalLevels:10; + union + { + CM_KEY_HASH KeyHash; + struct + { + ULONG ConvKey; + PCM_KEY_HASH NextHash; + PHHIVE KeyHive; + HCELL_INDEX KeyCell; + }; + }; + struct _CM_KEY_CONTROL_BLOCK *ParentKcb; + PCM_NAME_CONTROL_BLOCK NameBlock; + PCM_KEY_SECURITY_CACHE CachedSecurity; + CACHED_CHILD_LIST ValueCache; + PCM_INDEX_HINT_BLOCK IndexHint; + ULONG HashKey; + ULONG SubKeyCount; + union + { + LIST_ENTRY KeyBodyListHead; + LIST_ENTRY FreeListEntry; + }; + PCM_KEY_BODY KeyBodyArray[4]; + PVOID DelayCloseEntry; + LARGE_INTEGER KcbLastWriteTime; + USHORT KcbMaxNameLen; + USHORT KcbMaxValueNameLen; + ULONG KcbMaxValueDataLen; + ULONG InDelayClose; +} CM_KEY_CONTROL_BLOCK, *PCM_KEY_CONTROL_BLOCK; + +// +// Notify Block +// +typedef struct _CM_NOTIFY_BLOCK +{ + LIST_ENTRY HiveList; + LIST_ENTRY PostList; + PCM_KEY_CONTROL_BLOCK KeyControlBlock; + PCM_KEY_BODY KeyBody; + ULONG Filter:29; + ULONG WatchTree:30; + ULONG NotifyPending:31; +} CM_NOTIFY_BLOCK, *PCM_NOTIFY_BLOCK; + +// +// Re-map Block +// +typedef struct _CM_CELL_REMAP_BLOCK +{ + HCELL_INDEX OldCell; + HCELL_INDEX NewCell; +} CM_CELL_REMAP_BLOCK, *PCM_CELL_REMAP_BLOCK; + +// +// Allocation Page +// +typedef struct _CM_ALLOC_PAGE +{ + ULONG FreeCount; + ULONG Reserved; + PVOID AllocPage; +} CM_ALLOC_PAGE, *PCM_ALLOC_PAGE; + +// +// Allocation Page Entry +// +typedef struct _CM_DELAY_ALLOC +{ + LIST_ENTRY ListEntry; + PCM_KEY_CONTROL_BLOCK Kcb; +} CM_DELAY_ALLOC, *PCM_DELAY_ALLOC; + +// +// Delayed Close Entry +// +typedef struct _CM_DELAYED_CLOSE_ENTRY +{ + LIST_ENTRY DelayedLRUList; + PCM_KEY_CONTROL_BLOCK KeyControlBlock; +} CM_DELAYED_CLOSE_ENTRY, *PCM_DELAYED_CLOSE_ENTRY; + +// +// Delayed KCB Dereference Entry +// +typedef struct _CM_DELAY_DEREF_KCB_ITEM +{ + LIST_ENTRY ListEntry; + PCM_KEY_CONTROL_BLOCK Kcb; +} CM_DELAY_DEREF_KCB_ITEM, *PCM_DELAY_DEREF_KCB_ITEM; + +// +// Use Count Log and Entry +// +typedef struct _CM_USE_COUNT_LOG_ENTRY +{ + HCELL_INDEX Cell; + PVOID Stack[7]; +} CM_USE_COUNT_LOG_ENTRY, *PCM_USE_COUNT_LOG_ENTRY; + +typedef struct _CM_USE_COUNT_LOG +{ + USHORT Next; + USHORT Size; + CM_USE_COUNT_LOG_ENTRY Log[32]; +} CM_USE_COUNT_LOG, *PCM_USE_COUNT_LOG; + +// +// Configuration Manager Hive Structure +// +typedef struct _CMHIVE +{ + HHIVE Hive; + HANDLE FileHandles[3]; + LIST_ENTRY NotifyList; + LIST_ENTRY HiveList; + EX_PUSH_LOCK HiveLock; + PKTHREAD HiveLockOwner; + PKGUARDED_MUTEX ViewLock; + PKTHREAD ViewLockOwner; + EX_PUSH_LOCK WriterLock; + PKTHREAD WriterLockOwner; + PERESOURCE FlusherLock; + EX_PUSH_LOCK SecurityLock; + PKTHREAD HiveSecurityLockOwner; + LIST_ENTRY LRUViewListHead; + LIST_ENTRY PinViewListHead; + PFILE_OBJECT FileObject; + UNICODE_STRING FileFullPath; + UNICODE_STRING FileUserName; + USHORT MappedViews; + USHORT PinnedViews; + ULONG UseCount; + ULONG SecurityCount; + ULONG SecurityCacheSize; + LONG SecurityHitHint; + PCM_KEY_SECURITY_CACHE_ENTRY SecurityCache; + LIST_ENTRY SecurityHash[CMP_SECURITY_HASH_LISTS]; + PKEVENT UnloadEvent; + PCM_KEY_CONTROL_BLOCK RootKcb; + BOOLEAN Frozen; + PWORK_QUEUE_ITEM UnloadWorkItem; + BOOLEAN GrowOnlyMode; + ULONG GrowOffset; + LIST_ENTRY KcbConvertListHead; + LIST_ENTRY KnodeConvertListHead; + PCM_CELL_REMAP_BLOCK CellRemapArray; + CM_USE_COUNT_LOG UseCountLog; + CM_USE_COUNT_LOG LockHiveLog; + ULONG Flags; + LIST_ENTRY TrustClassEntry; + ULONG FlushCount; + BOOLEAN HiveIsLoading; + PKTHREAD CreatorOwner; +} CMHIVE, *PCMHIVE; + +// +// Cached Value Index +// +typedef struct _CM_CACHED_VALUE_INDEX +{ + HCELL_INDEX CellIndex; + union + { + CELL_DATA CellData; + ULONG_PTR List[ANYSIZE_ARRAY]; + } Data; +} CM_CACHED_VALUE_INDEX, *PCM_CACHED_VALUE_INDEX; + +// +// Cached Value +// +typedef struct _CM_CACHED_VALUE +{ + USHORT DataCacheType; + USHORT ValueKeySize; + ULONG HashKey; + CM_KEY_VALUE KeyValue; +} CM_CACHED_VALUE, *PCM_CACHED_VALUE; + +// +// Hive List Entry +// +typedef struct _HIVE_LIST_ENTRY +{ + PWCHAR FileName; + PWCHAR BaseName; + PWCHAR RegRootName; + PCMHIVE CmHive; + ULONG HHiveFlags; + ULONG CmHiveFlags; + PCMHIVE CmHive2; + BOOLEAN ThreadFinished; + BOOLEAN ThreadStarted; + BOOLEAN Allocate; + BOOLEAN WinPERequired; +} HIVE_LIST_ENTRY, *PHIVE_LIST_ENTRY; + +// +// Parse context for Key Object +// +typedef struct _CM_PARSE_CONTEXT +{ + ULONG TitleIndex; + UNICODE_STRING Class; + ULONG CreateOptions; + ULONG Disposition; + CM_KEY_REFERENCE ChildHive; + BOOLEAN CreateLink; + BOOLEAN Flag2; + HANDLE PredefinedHandle; + ULONG PostActions; +} CM_PARSE_CONTEXT, *PCM_PARSE_CONTEXT; + +// +// System Control Vector +// +typedef struct _CM_SYSTEM_CONTROL_VECTOR +{ + PWCHAR KeyPath; + PWCHAR ValueName; + PVOID Buffer; + PULONG BufferLength; + PULONG Type; +} CM_SYSTEM_CONTROL_VECTOR, *PCM_SYSTEM_CONTROL_VECTOR; + +// +// Structure for CmpQueryValueDataFromCache +// +typedef struct _KEY_VALUE_INFORMATION +{ + union + { + KEY_VALUE_BASIC_INFORMATION KeyValueBasicInformation; + KEY_VALUE_FULL_INFORMATION KeyValueFullInformation; + KEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInformation; + KEY_VALUE_PARTIAL_INFORMATION_ALIGN64 KeyValuePartialInformationAlign64; + }; +} KEY_VALUE_INFORMATION, *PKEY_VALUE_INFORMATION; + +typedef struct _KEY_INFORMATION +{ + union + { + KEY_BASIC_INFORMATION KeyBasicInformation; + KEY_FULL_INFORMATION KeyFullInformation; + KEY_NODE_INFORMATION KeyNodeInformation; + }; +} KEY_INFORMATION, *PKEY_INFORMATION; + +/////////////////////////////////////////////////////////////////////////////// +// +// BUGBUG Old Hive Stuff for Temporary Support +// +#define SYSTEM_REG_FILE L"\\SystemRoot\\System32\\Config\\SYSTEM" +#define SYSTEM_LOG_FILE L"\\SystemRoot\\System32\\Config\\SYSTEM.log" +#define REG_SYSTEM_KEY_NAME L"\\Registry\\Machine\\SYSTEM" +#define REG_HARDWARE_KEY_NAME L"\\Registry\\Machine\\HARDWARE" +typedef struct _KEY_OBJECT +{ + ULONG Type; + UNICODE_STRING Name; + LIST_ENTRY KeyBodyList; + ULONG SubKeyCounts; + ULONG SizeOfSubKeys; + struct _KEY_OBJECT **SubKeys; + PCM_KEY_CONTROL_BLOCK KeyControlBlock; +} KEY_OBJECT, *PKEY_OBJECT; +extern PCMHIVE CmiVolatileHive; +extern LIST_ENTRY CmiKeyObjectListHead, CmiConnectedHiveList; +PVOID NTAPI CmpRosGetHardwareHive(OUT PULONG Length); +NTSTATUS CmiCallRegisteredCallbacks(IN REG_NOTIFY_CLASS Argument1, IN PVOID Argument2); +/////////////////////////////////////////////////////////////////////////////// + +// +// Mapped View Hive Functions +// +VOID +NTAPI +CmpInitHiveViewList( + IN PCMHIVE Hive +); + +// +// Security Cache Functions +// +VOID +NTAPI +CmpInitSecurityCache( + IN PCMHIVE Hive +); + +// +// Value Cache Functions +// +VALUE_SEARCH_RETURN_TYPE +NTAPI +CmpFindValueByNameFromCache( + IN PCM_KEY_CONTROL_BLOCK Kcb, + IN PCUNICODE_STRING Name, + OUT PCM_CACHED_VALUE **CachedValue, + OUT ULONG *Index, + OUT PCM_KEY_VALUE *Value, + OUT BOOLEAN *ValueIsCached, + OUT PHCELL_INDEX CellToRelease +); + +VALUE_SEARCH_RETURN_TYPE +NTAPI +CmpQueryKeyValueData( + IN PCM_KEY_CONTROL_BLOCK Kcb, + IN PCM_CACHED_VALUE *CachedValue, + IN PCM_KEY_VALUE ValueKey, + IN BOOLEAN ValueIsCached, + IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + IN PVOID KeyValueInformation, + IN ULONG Length, + OUT PULONG ResultLength, + OUT PNTSTATUS Status +); + +VALUE_SEARCH_RETURN_TYPE +NTAPI +CmpGetValueListFromCache( + IN PCM_KEY_CONTROL_BLOCK Kcb, + OUT PCELL_DATA *CellData, + OUT BOOLEAN *IndexIsCached, + OUT PHCELL_INDEX ValueListToRelease +); + +VALUE_SEARCH_RETURN_TYPE +NTAPI +CmpGetValueKeyFromCache( + IN PCM_KEY_CONTROL_BLOCK Kcb, + IN PCELL_DATA CellData, + IN ULONG Index, + OUT PCM_CACHED_VALUE **CachedValue, + OUT PCM_KEY_VALUE *Value, + IN BOOLEAN IndexIsCached, + OUT BOOLEAN *ValueIsCached, + OUT PHCELL_INDEX CellToRelease +); + +// +// Registry Validation Functions +// +ULONG +NTAPI +CmCheckRegistry( + IN PCMHIVE Hive, + IN ULONG Flags +); + +// +// Notification Routines +// +VOID +NTAPI +CmpReportNotify( + IN PCM_KEY_CONTROL_BLOCK Kcb, + IN PHHIVE Hive, + IN HCELL_INDEX Cell, + IN ULONG Filter +); + +VOID +NTAPI +CmpInitCallback( + VOID +); + +// +// KCB Cache/Delay Routines +// +VOID +NTAPI +CmpInitializeCache( + VOID +); + +VOID +NTAPI +CmpInitCmPrivateDelayAlloc( + VOID +); + +VOID +NTAPI +CmpInitCmPrivateAlloc( + VOID +); + +VOID +NTAPI +CmpInitDelayDerefKCBEngine( + VOID +); + +// +// Key Object Routines +// +VOID +NTAPI +CmpCloseKeyObject( + IN PEPROCESS Process OPTIONAL, + IN PVOID Object, + IN ACCESS_MASK GrantedAccess, + IN ULONG ProcessHandleCount, + IN ULONG SystemHandleCount +); + +VOID +NTAPI +CmpDeleteKeyObject( + IN PVOID Object +); + +NTSTATUS +NTAPI +CmpParseKey( + IN PVOID ParseObject, + IN PVOID ObjectType, + IN OUT PACCESS_STATE AccessState, + IN KPROCESSOR_MODE AccessMode, + IN ULONG Attributes, + IN OUT PUNICODE_STRING CompleteName, + IN OUT PUNICODE_STRING RemainingName, + IN OUT PVOID Context OPTIONAL, + IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL, + OUT PVOID *Object +); + +NTSTATUS +NTAPI +CmpSecurityMethod( + IN PVOID Object, + IN SECURITY_OPERATION_CODE OperationType, + IN PSECURITY_INFORMATION SecurityInformation, + IN PSECURITY_DESCRIPTOR SecurityDescriptor, + IN OUT PULONG CapturedLength, + IN OUT PSECURITY_DESCRIPTOR *ObjectSecurityDescriptor, + IN POOL_TYPE PoolType, + IN PGENERIC_MAPPING GenericMapping +); + +NTSTATUS +NTAPI +CmpQueryKeyName( + IN PVOID Object, + IN BOOLEAN HasObjectName, + OUT POBJECT_NAME_INFORMATION ObjectNameInfo, + IN ULONG Length, + OUT PULONG ReturnLength, + IN KPROCESSOR_MODE AccessMode +); + +// +// Hive Routines +// +NTSTATUS +NTAPI +CmpInitializeHive( + OUT PCMHIVE *CmHive, + IN ULONG Operation, + IN ULONG Flags, + IN ULONG FileType, + IN PVOID HiveData OPTIONAL, + IN HANDLE Primary, + IN HANDLE Log, + IN HANDLE External, + IN PCUNICODE_STRING FileName OPTIONAL, + IN ULONG CheckFlags +); + +PSECURITY_DESCRIPTOR +NTAPI +CmpHiveRootSecurityDescriptor( + VOID +); + +NTSTATUS +NTAPI +CmpLinkHiveToMaster( + IN PUNICODE_STRING LinkName, + IN HANDLE RootDirectory, + IN PCMHIVE CmHive, + IN BOOLEAN Allocate, + IN PSECURITY_DESCRIPTOR SecurityDescriptor +); + +NTSTATUS +NTAPI +CmpOpenHiveFiles( + IN PCUNICODE_STRING BaseName, + IN PCWSTR Extension OPTIONAL, + IN PHANDLE Primary, + IN PHANDLE Log, + IN PULONG PrimaryDisposition, + IN PULONG LogDisposition, + IN BOOLEAN CreateAllowed, + IN BOOLEAN MarkAsSystemHive, + IN BOOLEAN NoBuffering, + OUT PULONG ClusterSize OPTIONAL +); + +NTSTATUS +NTAPI +CmpInitHiveFromFile( + IN PCUNICODE_STRING HiveName, + IN ULONG HiveFlags, + OUT PCMHIVE *Hive, + IN OUT PBOOLEAN New, + IN ULONG CheckFlags +); + +// +// Registry Utility Functions +// +BOOLEAN +NTAPI +CmpTestRegistryLockExclusive( + VOID +); + +VOID +NTAPI +CmpLockRegistryExclusive( + VOID +); + +VOID +NTAPI +CmpLockRegistry( + VOID +); + +VOID +NTAPI +CmpUnlockRegistry( + VOID +); + +// +// Delay Functions +// +PVOID +NTAPI +CmpAllocateDelayItem( + VOID +); + +VOID +NTAPI +CmpFreeDelayItem( + PVOID Entry +); + +VOID +NTAPI +CmpDelayDerefKeyControlBlock( + IN PCM_KEY_CONTROL_BLOCK Kcb +); + +VOID +NTAPI +CmpAddToDelayedClose( + IN PCM_KEY_CONTROL_BLOCK Kcb, + IN BOOLEAN LockHeldExclusively +); + +VOID +NTAPI +CmpRemoveFromDelayedClose(IN PCM_KEY_CONTROL_BLOCK Kcb); + +VOID +NTAPI +CmpInitializeDelayedCloseTable( + VOID +); + +// +// KCB Functions +// +PCM_KEY_CONTROL_BLOCK +NTAPI +CmpCreateKeyControlBlock( + IN PHHIVE Hive, + IN HCELL_INDEX Index, + IN PCM_KEY_NODE Node, + IN PCM_KEY_CONTROL_BLOCK Parent, + IN ULONG Flags, + IN PUNICODE_STRING KeyName +); + +PCM_KEY_CONTROL_BLOCK +NTAPI +CmpAllocateKeyControlBlock( + VOID +); + +VOID +NTAPI +CmpFreeKeyControlBlock( + IN PCM_KEY_CONTROL_BLOCK Kcb +); + +VOID +NTAPI +CmpRemoveKeyControlBlock( + IN PCM_KEY_CONTROL_BLOCK Kcb +); + +VOID +NTAPI +CmpCleanUpKcbCacheWithLock( + IN PCM_KEY_CONTROL_BLOCK Kcb, + IN BOOLEAN LockHeldExclusively +); + +VOID +NTAPI +CmpDereferenceKeyControlBlockWithLock( + IN PCM_KEY_CONTROL_BLOCK Kcb, + IN BOOLEAN LockHeldExclusively +); + +VOID +NTAPI +EnlistKeyBodyWithKCB( + IN PCM_KEY_BODY KeyObject, + IN ULONG Flags +); + +VOID +NTAPI +EnlistKeyBodyWithKeyObject( + IN PKEY_OBJECT KeyObject, + IN ULONG Flags +); + +NTSTATUS +NTAPI +CmpFreeKeyByCell( + IN PHHIVE Hive, + IN HCELL_INDEX Cell, + IN BOOLEAN Unlink +); + +// +// Name Functions +// +LONG +NTAPI +CmpCompareCompressedName( + IN PCUNICODE_STRING SearchName, + IN PWCHAR CompressedName, + IN ULONG NameLength +); + +USHORT +NTAPI +CmpNameSize( + IN PHHIVE Hive, + IN PUNICODE_STRING Name +); + +USHORT +NTAPI +CmpCompressedNameSize( + IN PWCHAR Name, + IN ULONG Length +); + +VOID +NTAPI +CmpCopyCompressedName( + IN PWCHAR Destination, + IN ULONG DestinationLength, + IN PWCHAR Source, + IN ULONG SourceLength +); + +USHORT +NTAPI +CmpCopyName( + IN PHHIVE Hive, + IN PWCHAR Destination, + IN PUNICODE_STRING Source +); + +BOOLEAN +NTAPI +CmpFindNameInList( + IN PHHIVE Hive, + IN PCHILD_LIST ChildList, + IN PUNICODE_STRING Name, + IN PULONG ChildIndex, + IN PHCELL_INDEX CellIndex +); + +// +// Parse Routines +// +BOOLEAN +NTAPI +CmpGetNextName( + IN OUT PUNICODE_STRING RemainingName, + OUT PUNICODE_STRING NextName, + OUT PBOOLEAN LastName +); + +// +// Flush Routines +// +BOOLEAN +NTAPI +CmpDoFlushAll( + IN BOOLEAN ForceFlush +); + +VOID +NTAPI +CmpShutdownWorkers( + VOID +); + +VOID +NTAPI +CmpCmdInit( + IN BOOLEAN SetupBoot +); + +VOID +NTAPI +CmpLazyFlush( + VOID +); + +// +// Open/Create Routines +// +NTSTATUS +NTAPI +CmpDoCreate( + IN PHHIVE Hive, + IN HCELL_INDEX Cell, + IN PACCESS_STATE AccessState, + IN PUNICODE_STRING Name, + IN KPROCESSOR_MODE AccessMode, + IN PUNICODE_STRING Class, + IN ULONG CreateOptions, + IN PCM_KEY_CONTROL_BLOCK ParentKcb, + IN PCMHIVE OriginatingHive OPTIONAL, + OUT PVOID *Object +); + +// +// Cell Index Routines +// + +HCELL_INDEX +NTAPI +CmpFindSubKeyByName( + IN PHHIVE Hive, + IN PCM_KEY_NODE Parent, + IN PCUNICODE_STRING SearchName +); + +HCELL_INDEX +NTAPI +CmpFindSubKeyByNumber( + IN PHHIVE Hive, + IN PCM_KEY_NODE Node, + IN ULONG Number +); + +ULONG +NTAPI +CmpComputeHashKey( + IN ULONG Hash, + IN PCUNICODE_STRING Name, + IN BOOLEAN AllowSeparators +); + +BOOLEAN +NTAPI +CmpAddSubKey( + IN PHHIVE Hive, + IN HCELL_INDEX Parent, + IN HCELL_INDEX Child +); + +BOOLEAN +NTAPI +CmpRemoveSubKey( + IN PHHIVE Hive, + IN HCELL_INDEX ParentKey, + IN HCELL_INDEX TargetKey +); + +BOOLEAN +NTAPI +CmpMarkIndexDirty( + IN PHHIVE Hive, + HCELL_INDEX ParentKey, + HCELL_INDEX TargetKey +); + +// +// Cell Value Routines +// +HCELL_INDEX +NTAPI +CmpFindValueByName( + IN PHHIVE Hive, + IN PCM_KEY_NODE KeyNode, + IN PUNICODE_STRING Name +); + +PCELL_DATA +NTAPI +CmpValueToData( + IN PHHIVE Hive, + IN PCM_KEY_VALUE Value, + OUT PULONG Length +); + +NTSTATUS +NTAPI +CmpSetValueDataNew( + IN PHHIVE Hive, + IN PVOID Data, + IN ULONG DataSize, + IN ULONG StorageType, + IN HCELL_INDEX ValueCell, + OUT PHCELL_INDEX DataCell +); + +NTSTATUS +NTAPI +CmpAddValueToList( + IN PHHIVE Hive, + IN HCELL_INDEX ValueCell, + IN ULONG Index, + IN ULONG Type, + IN OUT PCHILD_LIST ChildList +); + +BOOLEAN +NTAPI +CmpFreeValue( + IN PHHIVE Hive, + IN HCELL_INDEX Cell +); + +BOOLEAN +NTAPI +CmpMarkValueDataDirty( + IN PHHIVE Hive, + IN PCM_KEY_VALUE Value +); + +BOOLEAN +NTAPI +CmpFreeValueData( + IN PHHIVE Hive, + IN HCELL_INDEX DataCell, + IN ULONG DataLength +); + +NTSTATUS +NTAPI +CmpRemoveValueFromList( + IN PHHIVE Hive, + IN ULONG Index, + IN OUT PCHILD_LIST ChildList +); + +BOOLEAN +NTAPI +CmpGetValueData( + IN PHHIVE Hive, + IN PCM_KEY_VALUE Value, + IN PULONG Length, + OUT PVOID *Buffer, + OUT PBOOLEAN BufferAllocated, + OUT PHCELL_INDEX CellToRelease +); + +// +// Boot Routines +// +HCELL_INDEX +NTAPI +CmpFindControlSet( + IN PHHIVE SystemHive, + IN HCELL_INDEX RootCell, + IN PUNICODE_STRING SelectKeyName, + OUT PBOOLEAN AutoSelect +); + +VOID +NTAPI +CmGetSystemControlValues( + IN PVOID SystemHiveData, + IN PCM_SYSTEM_CONTROL_VECTOR ControlVector +); + + +// +// Hardware Configuration Routines +// +NTSTATUS +NTAPI +CmpInitializeRegistryNode( + IN PCONFIGURATION_COMPONENT_DATA CurrentEntry, + IN HANDLE NodeHandle, + OUT PHANDLE NewHandle, + IN INTERFACE_TYPE InterfaceType, + IN ULONG BusNumber, + IN PUSHORT DeviceIndexTable +); + +NTSTATUS +NTAPI +CmpInitializeMachineDependentConfiguration( + IN PLOADER_PARAMETER_BLOCK LoaderBlock +); + +NTSTATUS +NTAPI +CmpInitializeHardwareConfiguration( + IN PLOADER_PARAMETER_BLOCK LoaderBlock +); + +// +// Wrapper Routines +// +NTSTATUS +NTAPI +CmpCreateEvent( + IN EVENT_TYPE EventType, + OUT PHANDLE EventHandle, + OUT PKEVENT *Event +); + +PVOID +NTAPI +CmpAllocate( + IN ULONG Size, + IN BOOLEAN Paged, + IN ULONG Tag +); + +VOID +NTAPI +CmpFree( + IN PVOID Ptr, + IN ULONG Quota +); + +BOOLEAN +NTAPI +CmpFileRead( + IN PHHIVE RegistryHive, + IN ULONG FileType, + IN OUT PULONG FileOffset, + OUT PVOID Buffer, + IN SIZE_T BufferLength +); + +BOOLEAN +NTAPI +CmpFileWrite( + IN PHHIVE RegistryHive, + IN ULONG FileType, + IN OUT PULONG FileOffset, + IN PVOID Buffer, + IN SIZE_T BufferLength +); + +BOOLEAN +NTAPI +CmpFileSetSize( + IN PHHIVE RegistryHive, + IN ULONG FileType, + IN ULONG FileSize, + IN ULONG OldFileSize +); + +BOOLEAN +NTAPI +CmpFileFlush( + IN PHHIVE RegistryHive, + IN ULONG FileType, + IN OUT PLARGE_INTEGER FileOffset, + IN ULONG Length +); + +// +// Configuration Manager side of Registry System Calls +// +NTSTATUS +NTAPI +CmEnumerateValueKey( + IN PCM_KEY_CONTROL_BLOCK Kcb, + IN ULONG Index, + IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + IN PVOID KeyValueInformation, + IN ULONG Length, + IN PULONG ResultLength); + +NTSTATUS +NTAPI +CmSetValueKey( + IN PCM_KEY_CONTROL_BLOCK Kcb, + IN PUNICODE_STRING ValueName, + IN ULONG Type, + IN PVOID Data, + IN ULONG DataSize); + +NTSTATUS +NTAPI +CmQueryKey(IN PCM_KEY_CONTROL_BLOCK Kcb, + IN KEY_INFORMATION_CLASS KeyInformationClass, + IN PVOID KeyInformation, + IN ULONG Length, + IN PULONG ResultLength +); + +NTSTATUS +NTAPI +CmEnumerateKey(IN PCM_KEY_CONTROL_BLOCK Kcb, + IN ULONG Index, + IN KEY_INFORMATION_CLASS KeyInformationClass, + IN PVOID KeyInformation, + IN ULONG Length, + IN PULONG ResultLength +); + +NTSTATUS +NTAPI +CmDeleteKey( + IN PCM_KEY_CONTROL_BLOCK Kcb +); + +NTSTATUS +NTAPI +CmFlushKey( + IN PCM_KEY_CONTROL_BLOCK Kcb, + IN BOOLEAN EclusiveLock +); + +NTSTATUS +NTAPI +CmDeleteValueKey( + IN PCM_KEY_CONTROL_BLOCK Kcb, + IN UNICODE_STRING ValueName +); + +NTSTATUS +NTAPI +CmQueryValueKey( + IN PCM_KEY_CONTROL_BLOCK Kcb, + IN UNICODE_STRING ValueName, + IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + IN PVOID KeyValueInformation, + IN ULONG Length, + IN PULONG ResultLength +); + +// +// Startup and Shutdown +// +VOID +NTAPI +CmShutdownSystem( + VOID +); + +// +// Global variables accessible from all of Cm +// +extern BOOLEAN CmpSpecialBootCondition; +extern BOOLEAN CmpFlushOnLockRelease; +extern BOOLEAN CmpShareSystemHives; +extern BOOLEAN CmpMiniNTBoot; +extern EX_PUSH_LOCK CmpHiveListHeadLock, CmpLoadHiveLock; +extern LIST_ENTRY CmpHiveListHead; +extern POBJECT_TYPE CmpKeyObjectType; +extern ERESOURCE CmpRegistryLock; +extern PCM_KEY_HASH_TABLE_ENTRY CmpCacheTable; +extern PCM_NAME_HASH_TABLE_ENTRY CmpNameCacheTable; +extern KGUARDED_MUTEX CmpDelayedCloseTableLock; +extern CMHIVE CmControlHive; +extern WCHAR CmDefaultLanguageId[]; +extern ULONG CmDefaultLanguageIdLength; +extern ULONG CmDefaultLanguageIdType; +extern WCHAR CmInstallUILanguageId[]; +extern ULONG CmInstallUILanguageIdLength; +extern ULONG CmInstallUILanguageIdType; +extern LANGID PsInstallUILanguageId; +extern LANGID PsDefaultUILanguageId; +extern CM_SYSTEM_CONTROL_VECTOR CmControlVector[]; +extern ULONG CmpConfigurationAreaSize; +extern PCM_FULL_RESOURCE_DESCRIPTOR CmpConfigurationData; +extern UNICODE_STRING CmTypeName[]; +extern HIVE_LIST_ENTRY CmpMachineHiveList[5]; +extern UNICODE_STRING CmSymbolicLinkValueName; +extern UNICODE_STRING CmpSystemStartOptions; +extern UNICODE_STRING CmpLoadOptions; +extern BOOLEAN CmSelfHeal; +extern BOOLEAN CmpSelfHeal; +extern ULONG CmpBootType; +extern HANDLE CmpRegistryRootHandle; +extern BOOLEAN ExpInTextModeSetup; +extern BOOLEAN InitIsWinPEMode; +extern ULONG CmpHashTableSize; +extern ULONG CmpDelayedCloseSize, CmpDelayedCloseIndex; +extern BOOLEAN CmpNoWrite; +extern BOOLEAN CmpForceForceFlush; +extern BOOLEAN CmpWasSetupBoot; + +// +// Inlined functions +// +#include "cm_x.h" diff --git a/reactos/ntoskrnl/config/cmapi.c b/reactos/ntoskrnl/config/cmapi.c index b4e906ca790..075064da26d 100644 --- a/reactos/ntoskrnl/config/cmapi.c +++ b/reactos/ntoskrnl/config/cmapi.c @@ -1,1181 +1,1204 @@ -/* - * 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" -#include "cm.h" -#define NDEBUG -#include "debug.h" - -/* FUNCTIONS *****************************************************************/ - -BOOLEAN -NTAPI -CmpDoFlushAll(IN BOOLEAN ForceFlush) -{ - NTSTATUS Status; - PLIST_ENTRY NextEntry; - PCMHIVE Hive; - BOOLEAN Result = TRUE; - - /* Make sure that the registry isn't read-only now */ - if (CmpNoWrite) return TRUE; - - /* Otherwise, acquire the hive list lock and disable force flush */ - CmpForceForceFlush = FALSE; - ExAcquirePushLockShared(&CmpHiveListHeadLock); - - /* Loop the hive list */ - NextEntry = CmpHiveListHead.Flink; - while (NextEntry != &CmpHiveListHead) - { - /* Get the hive */ - Hive = CONTAINING_RECORD(NextEntry, CMHIVE, HiveList); - if (!(Hive->Hive.HiveFlags & HIVE_NOLAZYFLUSH)) - { - /* Find out why this is needed? [Aleksey] */ - ULONG Disposition; - Status = CmpOpenHiveFiles(&Hive->FileFullPath, - L".LOG", - &Hive->FileHandles[HFILE_TYPE_PRIMARY], - &Hive->FileHandles[HFILE_TYPE_LOG], - &Disposition, - &Disposition, - FALSE, - FALSE, - TRUE, - NULL); - - /* Do the sync */ - DPRINT1("Flushing: %wZ\n", &Hive->FileFullPath); - DPRINT1("Handle: %lx\n", Hive->FileHandles[HFILE_TYPE_PRIMARY]); - Status = HvSyncHive(&Hive->Hive); - if (!NT_SUCCESS(Status)) Result = FALSE; - } - - /* Try the next entry */ - NextEntry = NextEntry->Flink; - } - - /* Release lock and return */ - ExReleasePushLock(&CmpHiveListHeadLock); - return Result; -} - -NTSTATUS -NTAPI -CmpSetValueKeyNew(IN PHHIVE Hive, - IN PCM_KEY_NODE Parent, - IN PUNICODE_STRING ValueName, - IN ULONG Index, - IN ULONG Type, - IN PVOID Data, - IN ULONG DataSize, - IN ULONG StorageType, - IN ULONG SmallData) -{ - PCELL_DATA CellData; - HCELL_INDEX ValueCell; - NTSTATUS Status; - - /* Check if we already have a value list */ - if (Parent->ValueList.Count) - { - /* Then make sure it's valid and dirty it */ - ASSERT(Parent->ValueList.List != HCELL_NIL); - HvMarkCellDirty(Hive, Parent->ValueList.List, FALSE); - } - - /* Allocate avalue cell */ - ValueCell = HvAllocateCell(Hive, - FIELD_OFFSET(CM_KEY_VALUE, Name) + - CmpNameSize(Hive, ValueName), - StorageType, - HCELL_NIL); - if (ValueCell == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES; - - /* Get the actual data for it */ - CellData = HvGetCell(Hive, ValueCell); - if (!CellData) ASSERT(FALSE); - - /* Now we can release it, make sure it's also dirty */ - HvReleaseCell(Hive, ValueCell); - ASSERT(HvIsCellDirty(Hive, ValueCell)); - - /* Set it up and copy the name */ - CellData->u.KeyValue.Signature = CM_KEY_VALUE_SIGNATURE; - CellData->u.KeyValue.Flags = 0; - CellData->u.KeyValue.Type = Type; - CellData->u.KeyValue.NameLength = CmpCopyName(Hive, - CellData->u.KeyValue.Name, - ValueName); - if (CellData->u.KeyValue.NameLength < ValueName->Length) - { - /* This is a compressed name */ - CellData->u.KeyValue.Flags = VALUE_COMP_NAME; - } - - /* Check if this is a normal key */ - if (DataSize > CM_KEY_VALUE_SMALL) - { - /* Build a data cell for it */ - Status = CmpSetValueDataNew(Hive, - Data, - DataSize, - StorageType, - ValueCell, - &CellData->u.KeyValue.Data); - if (!NT_SUCCESS(Status)) - { - /* We failed, free the cell */ - HvFreeCell(Hive, ValueCell); - return Status; - } - - /* Otherwise, set the data length, and make sure the data is dirty */ - CellData->u.KeyValue.DataLength = DataSize; - ASSERT(HvIsCellDirty(Hive, CellData->u.KeyValue.Data)); - } - else - { - /* This is a small key, set the data directly inside */ - CellData->u.KeyValue.DataLength = DataSize + CM_KEY_VALUE_SPECIAL_SIZE; - CellData->u.KeyValue.Data = SmallData; - } - - /* Add this value cell to the child list */ - Status = CmpAddValueToList(Hive, - ValueCell, - Index, - StorageType, - &Parent->ValueList); - - /* If we failed, free the entire cell, including the data */ - if (!NT_SUCCESS(Status)) CmpFreeValue(Hive, ValueCell); - - /* Return Status */ - return Status; -} - -NTSTATUS -NTAPI -CmpSetValueKeyExisting(IN PHHIVE Hive, - IN HCELL_INDEX OldChild, - IN PCM_KEY_VALUE Value, - IN ULONG Type, - IN PVOID Data, - IN ULONG DataSize, - IN ULONG StorageType, - IN ULONG TempData) -{ - HCELL_INDEX DataCell, NewCell; - PCELL_DATA CellData; - ULONG Length; - BOOLEAN WasSmall, IsSmall; - - /* Mark the old child cell dirty */ - HvMarkCellDirty(Hive, OldChild, FALSE); - - /* See if this is a small or normal key */ - WasSmall = CmpIsKeyValueSmall(&Length, Value->DataLength); - - /* See if our new data can fit in a small key */ - IsSmall = (DataSize <= CM_KEY_VALUE_SMALL) ? TRUE: FALSE; - - /* Big keys are unsupported */ - ASSERT_VALUE_BIG(Hive, Length); - ASSERT_VALUE_BIG(Hive, DataSize); - - /* Mark the old value dirty */ - CmpMarkValueDataDirty(Hive, Value); - - /* Check if we have a small key */ - if (IsSmall) - { - /* Check if we had a normal key with some data in it */ - if (!(WasSmall) && (Length > 0)) - { - /* Free the previous data */ - CmpFreeValueData(Hive, Value->Data, Length); - } - - /* Write our data directly */ - Value->DataLength = DataSize + CM_KEY_VALUE_SPECIAL_SIZE; - Value->Data = TempData; - Value->Type = Type; - return STATUS_SUCCESS; - } - else - { - /* We have a normal key. Was the old cell also normal and had data? */ - if (!(WasSmall) && (Length > 0)) - { - /* Get the current data cell and actual data inside it */ - DataCell = Value->Data; - ASSERT(DataCell != HCELL_NIL); - CellData = HvGetCell(Hive, DataCell); - if (!CellData) return STATUS_INSUFFICIENT_RESOURCES; - - /* Immediately release the cell */ - HvReleaseCell(Hive, DataCell); - - /* Make sure that the data cell actually has a size */ - ASSERT(HvGetCellSize(Hive, CellData) > 0); - - /* Check if the previous data cell could fit our new data */ - if (DataSize <= (ULONG)(HvGetCellSize(Hive, CellData))) - { - /* Re-use it then */ - NewCell = DataCell; - } - else - { - /* Otherwise, re-allocate the current data cell */ - NewCell = HvReallocateCell(Hive, DataCell, DataSize); - if (NewCell == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES; - } - } - else - { - /* This was a small key, or a key with no data, allocate a cell */ - NewCell = HvAllocateCell(Hive, DataSize, StorageType, HCELL_NIL); - if (NewCell == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES; - } - - /* Now get the actual data for our data cell */ - CellData = HvGetCell(Hive, NewCell); - if (!CellData) ASSERT(FALSE); - - /* Release it immediately */ - HvReleaseCell(Hive, NewCell); - - /* Copy our data into the data cell's buffer, and set up the value */ - RtlCopyMemory(CellData, Data, DataSize); - Value->Data = NewCell; - Value->DataLength = DataSize; - Value->Type = Type; - - /* Return success */ - ASSERT(HvIsCellDirty(Hive, NewCell)); - return STATUS_SUCCESS; - } -} - -NTSTATUS -NTAPI -CmSetValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb, - IN PUNICODE_STRING ValueName, - IN ULONG Type, - IN PVOID Data, - IN ULONG DataLength) -{ - PHHIVE Hive; - PCM_KEY_NODE Parent; - PCM_KEY_VALUE Value = NULL; - HCELL_INDEX CurrentChild, Cell; - NTSTATUS Status; - BOOLEAN Found, Result; - ULONG Count, ChildIndex, SmallData, Storage; - - /* Acquire hive lock exclusively */ - KeEnterCriticalRegion(); - ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); - - /* Get pointer to key cell */ - Hive = Kcb->KeyHive; - Cell = Kcb->KeyCell; - - /* Prepare to scan the key node */ - Parent = (PCM_KEY_NODE)HvGetCell(Hive, Cell); - Count = Parent->ValueList.Count; - Found = FALSE; - if (Count > 0) - { - /* Try to find the existing name */ - Result = CmpFindNameInList(Hive, - &Parent->ValueList, - ValueName, - &ChildIndex, - &CurrentChild); - if (!Result) - { - /* Fail */ - Status = STATUS_INSUFFICIENT_RESOURCES; - goto Quickie; - } - - /* Check if we found something */ - if (CurrentChild != HCELL_NIL) - { - /* Get its value */ - Value = (PCM_KEY_VALUE)HvGetCell(Hive, CurrentChild); - if (!Value) - { - /* Fail */ - Status = STATUS_INSUFFICIENT_RESOURCES; - goto Quickie; - } - - /* Remember that we found it */ - Found = TRUE; - } - } - else - { - /* No child list, we'll need to add it */ - ChildIndex = 0; - } - - /* Mark the cell dirty */ - HvMarkCellDirty(Hive, Cell, FALSE); - - /* Get the storage type */ - Storage = HvGetCellType(Cell); - - /* Check if this is small data */ - SmallData = 0; - if ((DataLength <= CM_KEY_VALUE_SMALL) && (DataLength > 0)) - { - /* Copy it */ - RtlCopyMemory(&SmallData, Data, DataLength); - } - - /* Check if we didn't find a matching key */ - if (!Found) - { - /* Call the internal routine */ - Status = CmpSetValueKeyNew(Hive, - Parent, - ValueName, - ChildIndex, - Type, - Data, - DataLength, - Storage, - SmallData); - } - else - { - /* Call the internal routine */ - Status = CmpSetValueKeyExisting(Hive, - CurrentChild, - Value, - Type, - Data, - DataLength, - Storage, - SmallData); - } - - /* Mark link key */ - if ((Type == REG_LINK) && - (_wcsicmp(ValueName->Buffer, L"SymbolicLinkValue") == 0)) - { - Parent->Flags |= KEY_SYM_LINK; - } - - /* Check for success */ -Quickie: - if (NT_SUCCESS(Status)) - { - ASSERT(Parent->MaxValueNameLen == Kcb->KcbMaxValueNameLen); - if (Parent->MaxValueNameLen < ValueName->Length) - { - Parent->MaxValueNameLen = ValueName->Length; - Kcb->KcbMaxValueNameLen = ValueName->Length; - } - - ASSERT(Parent->MaxValueDataLen == Kcb->KcbMaxValueDataLen); - if (Parent->MaxValueDataLen < DataLength) - { - Parent->MaxValueDataLen = DataLength; - Kcb->KcbMaxValueDataLen = Parent->MaxValueDataLen; - } - - /* Save the write time */ - KeQuerySystemTime(&Parent->LastWriteTime); - KeQuerySystemTime(&Kcb->KcbLastWriteTime); - } - - /* Release the lock */ - ExReleaseResourceLite(&CmpRegistryLock); - KeLeaveCriticalRegion(); - return Status; -} - -NTSTATUS -NTAPI -CmDeleteValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb, - IN UNICODE_STRING ValueName) -{ - NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND; - PHHIVE Hive; - PCM_KEY_NODE Parent; - HCELL_INDEX ChildCell, Cell; - PCHILD_LIST ChildList; - PCM_KEY_VALUE Value = NULL; - ULONG ChildIndex; - BOOLEAN Result; - - /* Acquire hive lock */ - KeEnterCriticalRegion(); - ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); - - /* Get the hive and the cell index */ - Hive = Kcb->KeyHive; - Cell = Kcb->KeyCell; - - /* Get the parent key node */ - Parent = (PCM_KEY_NODE)HvGetCell(Hive, Cell); - if (!Parent) - { - /* Fail */ - Status = STATUS_INSUFFICIENT_RESOURCES; - goto Quickie; - } - - /* Get the value list and check if it has any entries */ - ChildList = &Parent->ValueList; - if (ChildList->Count) - { - /* Try to find this value */ - Result = CmpFindNameInList(Hive, - ChildList, - &ValueName, - &ChildIndex, - &ChildCell); - if (!Result) - { - /* Fail */ - Status = STATUS_INSUFFICIENT_RESOURCES; - goto Quickie; - } - - /* Value not found, return error */ - if (ChildCell == HCELL_NIL) goto Quickie; - - /* We found the value, mark all relevant cells dirty */ - HvMarkCellDirty(Hive, Cell, FALSE); - HvMarkCellDirty(Hive, Parent->ValueList.List, FALSE); - HvMarkCellDirty(Hive, ChildCell, FALSE); - - /* Get the key value */ - Value = (PCM_KEY_VALUE)HvGetCell(Hive,ChildCell); - if (!Value) ASSERT(FALSE); - - /* Mark it and all related data as dirty */ - CmpMarkValueDataDirty(Hive, Value); - - /* Ssanity checks */ - ASSERT(HvIsCellDirty(Hive, Parent->ValueList.List)); - ASSERT(HvIsCellDirty(Hive, ChildCell)); - - /* Remove the value from the child list */ - Status = CmpRemoveValueFromList(Hive, ChildIndex, ChildList); - if(!NT_SUCCESS(Status)) goto Quickie; - - /* Remove the value and its data itself */ - if (!CmpFreeValue(Hive, ChildCell)) - { - /* Failed to free the value, fail */ - Status = STATUS_INSUFFICIENT_RESOURCES; - goto Quickie; - } - - /* Set the last write time */ - KeQuerySystemTime(&Parent->LastWriteTime); - KeQuerySystemTime(&Kcb->KcbLastWriteTime); - - /* Sanity check */ - ASSERT(Parent->MaxValueNameLen == Kcb->KcbMaxValueNameLen); - ASSERT(Parent->MaxValueDataLen == Kcb->KcbMaxValueDataLen); - ASSERT(HvIsCellDirty(Hive, Cell)); - - /* Check if the value list is empty now */ - if (!Parent->ValueList.Count) - { - /* Then clear key node data */ - Parent->MaxValueNameLen = 0; - Parent->MaxValueDataLen = 0; - Kcb->KcbMaxValueNameLen = 0; - Kcb->KcbMaxValueDataLen = 0; - } - - /* Change default Status to success */ - Status = STATUS_SUCCESS; - } - -Quickie: - /* Release the parent cell, if any */ - if (Parent) HvReleaseCell(Hive, Cell); - - /* Check if we had a value */ - if (Value) - { - /* Release the child cell */ - ASSERT(ChildCell != HCELL_NIL); - HvReleaseCell(Hive, ChildCell); - } - - /* Release hive lock */ - ExReleaseResourceLite(&CmpRegistryLock); - KeLeaveCriticalRegion(); - return Status; -} - -NTSTATUS -NTAPI -CmQueryValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb, - IN UNICODE_STRING ValueName, - IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, - IN PVOID KeyValueInformation, - IN ULONG Length, - IN PULONG ResultLength) -{ - NTSTATUS Status; - PCM_KEY_VALUE ValueData; - ULONG Index; - BOOLEAN ValueCached = FALSE; - PCM_CACHED_VALUE *CachedValue; - HCELL_INDEX CellToRelease; - VALUE_SEARCH_RETURN_TYPE Result; - PHHIVE Hive; - PAGED_CODE(); - - /* Acquire hive lock */ - KeEnterCriticalRegion(); - ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); - - /* Get the hive */ - Hive = Kcb->KeyHive; - - /* Find the key value */ - Result = CmpFindValueByNameFromCache(Kcb, - &ValueName, - &CachedValue, - &Index, - &ValueData, - &ValueCached, - &CellToRelease); - if (Result == SearchSuccess) - { - /* Sanity check */ - ASSERT(ValueData != NULL); - - /* Query the information requested */ - Result = CmpQueryKeyValueData(Kcb, - CachedValue, - ValueData, - ValueCached, - KeyValueInformationClass, - KeyValueInformation, - Length, - ResultLength, - &Status); - } - else - { - /* Failed to find the value */ - Status = STATUS_OBJECT_NAME_NOT_FOUND; - } - - /* If we have a cell to release, do so */ - if (CellToRelease != HCELL_NIL) HvReleaseCell(Hive, CellToRelease); - - /* Release hive lock */ - ExReleaseResourceLite(&CmpRegistryLock); - KeLeaveCriticalRegion(); - return Status; -} - -NTSTATUS -NTAPI -CmEnumerateValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb, - IN ULONG Index, - IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, - IN PVOID KeyValueInformation, - IN ULONG Length, - IN PULONG ResultLength) -{ - NTSTATUS Status; - PHHIVE Hive; - PCM_KEY_NODE Parent; - HCELL_INDEX CellToRelease = HCELL_NIL, CellToRelease2 = HCELL_NIL; - VALUE_SEARCH_RETURN_TYPE Result; - BOOLEAN IndexIsCached, ValueIsCached = FALSE; - PCELL_DATA CellData; - PCM_CACHED_VALUE *CachedValue; - PCM_KEY_VALUE ValueData; - PAGED_CODE(); - - /* Acquire hive lock */ - KeEnterCriticalRegion(); - ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); - - /* Get the hive and parent */ - Hive = Kcb->KeyHive; - Parent = (PCM_KEY_NODE)HvGetCell(Hive, Kcb->KeyCell); - if (!Parent) - { - /* Fail */ - Status = STATUS_INSUFFICIENT_RESOURCES; - goto Quickie; - } - - /* Make sure the index is valid */ - //if (Index >= Kcb->ValueCache.Count) - if (Index >= Parent->ValueList.Count) - { - /* Release the cell and fail */ - HvReleaseCell(Hive, Kcb->KeyCell); - Status = STATUS_NO_MORE_ENTRIES; - goto Quickie; - } - - /* Find the value list */ - Result = CmpGetValueListFromCache(Kcb, - &CellData, - &IndexIsCached, - &CellToRelease); - if (Result != SearchSuccess) - { - /* Sanity check */ - ASSERT(CellData == NULL); - - /* Release the cell and fail */ - Status = STATUS_INSUFFICIENT_RESOURCES; - goto Quickie; - } - - /* Now get the key value */ - Result = CmpGetValueKeyFromCache(Kcb, - CellData, - Index, - &CachedValue, - &ValueData, - IndexIsCached, - &ValueIsCached, - &CellToRelease2); - if (Result != SearchSuccess) - { - /* Sanity check */ - ASSERT(CellToRelease2 == HCELL_NIL); - - /* Release the cells and fail */ - Status = STATUS_INSUFFICIENT_RESOURCES; - goto Quickie; - } - - /* Query the information requested */ - Result = CmpQueryKeyValueData(Kcb, - CachedValue, - ValueData, - ValueIsCached, - KeyValueInformationClass, - KeyValueInformation, - Length, - ResultLength, - &Status); - -Quickie: - /* If we have a cell to release, do so */ - if (CellToRelease != HCELL_NIL) HvReleaseCell(Hive, CellToRelease); - - /* Release the parent cell */ - HvReleaseCell(Hive, Kcb->KeyCell); - - /* If we have a cell to release, do so */ - if (CellToRelease2 != HCELL_NIL) HvReleaseCell(Hive, CellToRelease2); - - /* Release hive lock */ - ExReleaseResourceLite(&CmpRegistryLock); - KeLeaveCriticalRegion(); - return Status; -} - -NTSTATUS -NTAPI -CmpQueryKeyData(IN PHHIVE Hive, - IN PCM_KEY_NODE Node, - IN KEY_INFORMATION_CLASS KeyInformationClass, - IN OUT PVOID KeyInformation, - IN ULONG Length, - IN OUT PULONG ResultLength) -{ - NTSTATUS Status; - ULONG Size, SizeLeft, MinimumSize; - PKEY_INFORMATION Info = (PKEY_INFORMATION)KeyInformation; - USHORT NameLength; - - /* Check if the value is compressed */ - if (Node->Flags & KEY_COMP_NAME) - { - /* Get the compressed name size */ - NameLength = CmpCompressedNameSize(Node->Name, Node->NameLength); - } - else - { - /* Get the real size */ - NameLength = Node->NameLength; - } - - /* Check what kind of information is being requested */ - switch (KeyInformationClass) - { - /* Basic information */ - case KeyBasicInformation: - - /* This is the size we need */ - Size = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name) + NameLength; - - /* And this is the minimum we can work with */ - MinimumSize = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name); - - /* Let the caller know and assume success */ - *ResultLength = Size; - Status = STATUS_SUCCESS; - - /* Check if the bufer we got is too small */ - if (Length < MinimumSize) - { - /* Let the caller know and fail */ - Status = STATUS_BUFFER_TOO_SMALL; - break; - } - - /* Copy the basic information */ - Info->KeyBasicInformation.LastWriteTime = Node->LastWriteTime; - Info->KeyBasicInformation.TitleIndex = 0; - Info->KeyBasicInformation.NameLength = NameLength; - - /* Only the name is left */ - SizeLeft = Length - MinimumSize; - Size = NameLength; - - /* Check if we don't have enough space for the name */ - if (SizeLeft < Size) - { - /* Truncate the name we'll return, and tell the caller */ - Size = SizeLeft; - Status = STATUS_BUFFER_OVERFLOW; - } - - /* Check if this is a compressed key */ - if (Node->Flags & KEY_COMP_NAME) - { - /* Copy the compressed name */ - CmpCopyCompressedName(Info->KeyBasicInformation.Name, - SizeLeft, - Node->Name, - Node->NameLength); - } - else - { - /* Otherwise, copy the raw name */ - RtlCopyMemory(Info->KeyBasicInformation.Name, - Node->Name, - Size); - } - break; - - /* Node information */ - case KeyNodeInformation: - - /* Calculate the size we need */ - Size = FIELD_OFFSET(KEY_NODE_INFORMATION, Name) + - NameLength + - Node->ClassLength; - - /* And the minimum size we can support */ - MinimumSize = FIELD_OFFSET(KEY_NODE_INFORMATION, Name); - - /* Return the size to the caller and assume succes */ - *ResultLength = Size; - Status = STATUS_SUCCESS; - - /* Check if the caller's buffer is too small */ - if (Length < MinimumSize) - { - /* Let them know, and fail */ - Status = STATUS_BUFFER_TOO_SMALL; - break; - } - - /* Copy the basic information */ - Info->KeyNodeInformation.LastWriteTime = Node->LastWriteTime; - Info->KeyNodeInformation.TitleIndex = 0; - Info->KeyNodeInformation.ClassLength = Node->ClassLength; - Info->KeyNodeInformation.NameLength = NameLength; - - /* Now the name is left */ - SizeLeft = Length - MinimumSize; - Size = NameLength; - - /* Check if the name can fit entirely */ - if (SizeLeft < Size) - { - /* It can't, we'll have to truncate. Tell the caller */ - Size = SizeLeft; - Status = STATUS_BUFFER_OVERFLOW; - } - - /* Check if the key node name is compressed */ - if (Node->Flags & KEY_COMP_NAME) - { - /* Copy the compressed name */ - CmpCopyCompressedName(Info->KeyNodeInformation.Name, - SizeLeft, - Node->Name, - Node->NameLength); - } - else - { - /* It isn't, so copy the raw name */ - RtlCopyMemory(Info->KeyNodeInformation.Name, - Node->Name, - Size); - } - - /* Check if the node has a class */ - if (Node->ClassLength > 0) - { - /* It does. We don't support these yet */ - ASSERTMSG("Classes not supported\n", FALSE); - } - else - { - /* It doesn't, so set offset to -1, not 0! */ - Info->KeyNodeInformation.ClassOffset = 0xFFFFFFFF; - } - break; - - /* Full information requsted */ - case KeyFullInformation: - - /* This is the size we need */ - Size = FIELD_OFFSET(KEY_FULL_INFORMATION, Class) + - Node->ClassLength; - - /* This is what we can work with */ - MinimumSize = FIELD_OFFSET(KEY_FULL_INFORMATION, Class); - - /* Return it to caller and assume success */ - *ResultLength = Size; - Status = STATUS_SUCCESS; - - /* Check if the caller's buffer is to small */ - if (Length < MinimumSize) - { - /* Let them know and fail */ - Status = STATUS_BUFFER_TOO_SMALL; - break; - } - - /* Now copy all the basic information */ - Info->KeyFullInformation.LastWriteTime = Node->LastWriteTime; - Info->KeyFullInformation.TitleIndex = 0; - Info->KeyFullInformation.ClassLength = Node->ClassLength; - Info->KeyFullInformation.SubKeys = Node->SubKeyCounts[Stable] + - Node->SubKeyCounts[Volatile]; - Info->KeyFullInformation.Values = Node->ValueList.Count; - Info->KeyFullInformation.MaxNameLen = Node->MaxNameLen; - Info->KeyFullInformation.MaxClassLen = Node->MaxClassLen; - Info->KeyFullInformation.MaxValueNameLen = Node->MaxValueNameLen; - Info->KeyFullInformation.MaxValueDataLen = Node->MaxValueDataLen; - - /* Check if we have a class */ - if (Node->ClassLength > 0) - { - /* We do, but we currently don't support this */ - ASSERTMSG("Classes not supported\n", FALSE); - } - else - { - /* We don't have a class, so set offset to -1, not 0! */ - Info->KeyNodeInformation.ClassOffset = 0xFFFFFFFF; - } - break; - - /* Any other class that got sent here is invalid! */ - default: - - /* Set failure code */ - Status = STATUS_INVALID_PARAMETER; - break; - } - - /* Return status */ - return Status; -} - -NTSTATUS -NTAPI -CmQueryKey(IN PCM_KEY_CONTROL_BLOCK Kcb, - IN KEY_INFORMATION_CLASS KeyInformationClass, - IN PVOID KeyInformation, - IN ULONG Length, - IN PULONG ResultLength) -{ - NTSTATUS Status; - PHHIVE Hive; - PCM_KEY_NODE Parent; - - /* Acquire hive lock */ - KeEnterCriticalRegion(); - ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); - - /* Get the hive and parent */ - Hive = Kcb->KeyHive; - Parent = (PCM_KEY_NODE)HvGetCell(Hive, Kcb->KeyCell); - if (!Parent) - { - /* Fail */ - Status = STATUS_INSUFFICIENT_RESOURCES; - goto Quickie; - } - - /* Check what class we got */ - switch (KeyInformationClass) - { - /* Typical information */ - case KeyFullInformation: - case KeyBasicInformation: - case KeyNodeInformation: - - /* Call the internal API */ - Status = CmpQueryKeyData(Hive, - Parent, - KeyInformationClass, - KeyInformation, - Length, - ResultLength); - break; - - /* Unsupported classes for now */ - case KeyNameInformation: - case KeyCachedInformation: - case KeyFlagsInformation: - - /* Print message and fail */ - DPRINT1("Unsupported class: %d!\n", KeyInformationClass); - Status = STATUS_NOT_IMPLEMENTED; - break; - - /* Illegal classes */ - default: - - /* Print message and fail */ - DPRINT1("Unsupported class: %d!\n", KeyInformationClass); - Status = STATUS_INVALID_INFO_CLASS; - break; - } - -Quickie: - /* Release hive lock */ - ExReleaseResourceLite(&CmpRegistryLock); - KeLeaveCriticalRegion(); - return Status; -} - -NTSTATUS -NTAPI -CmEnumerateKey(IN PCM_KEY_CONTROL_BLOCK Kcb, - IN ULONG Index, - IN KEY_INFORMATION_CLASS KeyInformationClass, - IN PVOID KeyInformation, - IN ULONG Length, - IN PULONG ResultLength) -{ - NTSTATUS Status; - PHHIVE Hive; - PCM_KEY_NODE Parent, Child; - HCELL_INDEX ChildCell; - - /* Acquire hive lock */ - KeEnterCriticalRegion(); - ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); - - /* Get the hive and parent */ - Hive = Kcb->KeyHive; - Parent = (PCM_KEY_NODE)HvGetCell(Hive, Kcb->KeyCell); - if (!Parent) - { - /* Fail */ - Status = STATUS_INSUFFICIENT_RESOURCES; - goto Quickie; - } - - /* Get the child cell */ - ChildCell = CmpFindSubKeyByNumber(Hive, Parent, Index); - - /* Release the parent cell */ - HvReleaseCell(Hive, Kcb->KeyCell); - - /* Check if we found the child */ - if (ChildCell == HCELL_NIL) - { - /* We didn't, fail */ - Status = STATUS_NO_MORE_ENTRIES; - goto Quickie; - } - - /* Now get the actual child node */ - Child = (PCM_KEY_NODE)HvGetCell(Hive, ChildCell); - if (!Child) - { - /* Fail */ - Status = STATUS_INSUFFICIENT_RESOURCES; - goto Quickie; - } - - /* Query the data requested */ - Status = CmpQueryKeyData(Hive, - Child, - KeyInformationClass, - KeyInformation, - Length, - ResultLength); - -Quickie: - /* Release hive lock */ - ExReleaseResourceLite(&CmpRegistryLock); - KeLeaveCriticalRegion(); - return Status; -} - -NTSTATUS -NTAPI -CmDeleteKey(IN PCM_KEY_CONTROL_BLOCK Kcb) -{ - NTSTATUS Status; - PHHIVE Hive; - PCM_KEY_NODE Node, Parent; - HCELL_INDEX Cell, ParentCell; - - /* Acquire hive lock */ - KeEnterCriticalRegion(); - ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); - - /* Get the hive and node */ - Hive = Kcb->KeyHive; - Cell = Kcb->KeyCell; - - /* Get the key node */ - Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell); - if (!Node) - { - /* Fail */ - Status = STATUS_INSUFFICIENT_RESOURCES; - goto Quickie; - } - - /* Check if we have no parent */ - if (!Node->Parent) - { - /* This is an attempt to delete \Registry itself! */ - Status = STATUS_CANNOT_DELETE; - goto Quickie; - } - - /* Check if we're already being deleted */ - if (Kcb->Delete) - { - /* Don't do it twice */ - Status = STATUS_SUCCESS; - goto Quickie; - } - - /* Sanity check */ - ASSERT(Node->Flags == Kcb->Flags); - - /* Check if we don't have any children */ - if (!(Node->SubKeyCounts[Stable] + Node->SubKeyCounts[Volatile])) - { - /* Get the parent and free the cell */ - ParentCell = Node->Parent; - Status = CmpFreeKeyByCell(Hive, Cell, TRUE); - if (NT_SUCCESS(Status)) - { - /* Get the parent node */ - Parent = (PCM_KEY_NODE)HvGetCell(Hive, ParentCell); - if (Parent) - { - /* Update the maximum name length */ - Kcb->ParentKcb->KcbMaxNameLen = Parent->MaxNameLen; - - /* Make sure we're dirty */ - ASSERT(HvIsCellDirty(Hive, ParentCell)); - - /* Update the write time */ - KeQuerySystemTime(&Parent->LastWriteTime); - KeQuerySystemTime(&Kcb->ParentKcb->KcbLastWriteTime); - - /* Release the cell */ - HvReleaseCell(Hive, ParentCell); - } - - /* Set the KCB in delete mode and remove it */ - Kcb->Delete = TRUE; - CmpRemoveKeyControlBlock(Kcb); - - /* Clear the cell */ - Kcb->KeyCell = HCELL_NIL; - } - } - else - { - /* Fail */ - Status = STATUS_CANNOT_DELETE; - } - - /* Flush the registry */ - CmiSyncHives(); - -Quickie: - /* Release the cell */ - HvReleaseCell(Hive, Cell); - - /* Release hive lock */ - ExReleaseResourceLite(&CmpRegistryLock); - KeLeaveCriticalRegion(); - return Status; -} - -NTSTATUS -NTAPI -CmFlushKey(IN PCM_KEY_CONTROL_BLOCK Kcb, - IN BOOLEAN EclusiveLock) -{ - PCMHIVE CmHive; - NTSTATUS Status; - PHHIVE Hive; - - /* Get the hives */ - Hive = Kcb->KeyHive; - CmHive = (PCMHIVE)Hive; - - /* Check if this is the master hive */ - if (CmHive == CmiVolatileHive) - { - /* Flush all the hives instead */ - CmpDoFlushAll(FALSE); - } - else - { - /* Flush only this hive */ - if (!HvSyncHive(Hive)) - { - /* Fail */ - Status = STATUS_REGISTRY_IO_FAILED; - } - } - - /* Return the status */ - return Status; -} +/* + * 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" +#include "cm.h" +#define NDEBUG +#include "debug.h" + +NTSTATUS +CmiFlushRegistryHive(PCMHIVE RegistryHive); + +/* FUNCTIONS *****************************************************************/ + +BOOLEAN +NTAPI +CmpDoFlushAll(IN BOOLEAN ForceFlush) +{ + NTSTATUS Status; + PLIST_ENTRY NextEntry; + PCMHIVE Hive; + BOOLEAN Result = TRUE; + + /* Make sure that the registry isn't read-only now */ + if (CmpNoWrite) return TRUE; + + /* Otherwise, acquire the hive list lock and disable force flush */ + CmpForceForceFlush = FALSE; + ExAcquirePushLockShared(&CmpHiveListHeadLock); + + /* Loop the hive list */ + NextEntry = CmpHiveListHead.Flink; + while (NextEntry != &CmpHiveListHead) + { + /* Get the hive */ + Hive = CONTAINING_RECORD(NextEntry, CMHIVE, HiveList); + if (!(Hive->Hive.HiveFlags & HIVE_NOLAZYFLUSH)) + { + /* Find out why this is needed? [Aleksey] */ + ULONG Disposition; + CmpOpenHiveFiles(&Hive->FileFullPath, + L".LOG", + &Hive->FileHandles[HFILE_TYPE_PRIMARY], + &Hive->FileHandles[HFILE_TYPE_LOG], + &Disposition, + &Disposition, + FALSE, + FALSE, + TRUE, + NULL); + + /* Do the sync */ + Status = HvSyncHive(&Hive->Hive); + if (!NT_SUCCESS(Status)) Result = FALSE; + + /* ReactOS requires this */ + ZwClose(Hive->FileHandles[HFILE_TYPE_PRIMARY]); + ZwClose(Hive->FileHandles[HFILE_TYPE_LOG]); + } + + /* Try the next entry */ + NextEntry = NextEntry->Flink; + } + + /* Release lock and return */ + ExReleasePushLock(&CmpHiveListHeadLock); + return Result; +} + +NTSTATUS +NTAPI +CmpSetValueKeyNew(IN PHHIVE Hive, + IN PCM_KEY_NODE Parent, + IN PUNICODE_STRING ValueName, + IN ULONG Index, + IN ULONG Type, + IN PVOID Data, + IN ULONG DataSize, + IN ULONG StorageType, + IN ULONG SmallData) +{ + PCELL_DATA CellData; + HCELL_INDEX ValueCell; + NTSTATUS Status; + + /* Check if we already have a value list */ + if (Parent->ValueList.Count) + { + /* Then make sure it's valid and dirty it */ + ASSERT(Parent->ValueList.List != HCELL_NIL); + HvMarkCellDirty(Hive, Parent->ValueList.List, FALSE); + } + + /* Allocate avalue cell */ + ValueCell = HvAllocateCell(Hive, + FIELD_OFFSET(CM_KEY_VALUE, Name) + + CmpNameSize(Hive, ValueName), + StorageType, + HCELL_NIL); + if (ValueCell == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES; + + /* Get the actual data for it */ + CellData = HvGetCell(Hive, ValueCell); + if (!CellData) ASSERT(FALSE); + + /* Now we can release it, make sure it's also dirty */ + HvReleaseCell(Hive, ValueCell); + ASSERT(HvIsCellDirty(Hive, ValueCell)); + + /* Set it up and copy the name */ + CellData->u.KeyValue.Signature = CM_KEY_VALUE_SIGNATURE; + CellData->u.KeyValue.Flags = 0; + CellData->u.KeyValue.Type = Type; + CellData->u.KeyValue.NameLength = CmpCopyName(Hive, + CellData->u.KeyValue.Name, + ValueName); + if (CellData->u.KeyValue.NameLength < ValueName->Length) + { + /* This is a compressed name */ + CellData->u.KeyValue.Flags = VALUE_COMP_NAME; + } + + /* Check if this is a normal key */ + if (DataSize > CM_KEY_VALUE_SMALL) + { + /* Build a data cell for it */ + Status = CmpSetValueDataNew(Hive, + Data, + DataSize, + StorageType, + ValueCell, + &CellData->u.KeyValue.Data); + if (!NT_SUCCESS(Status)) + { + /* We failed, free the cell */ + HvFreeCell(Hive, ValueCell); + return Status; + } + + /* Otherwise, set the data length, and make sure the data is dirty */ + CellData->u.KeyValue.DataLength = DataSize; + ASSERT(HvIsCellDirty(Hive, CellData->u.KeyValue.Data)); + } + else + { + /* This is a small key, set the data directly inside */ + CellData->u.KeyValue.DataLength = DataSize + CM_KEY_VALUE_SPECIAL_SIZE; + CellData->u.KeyValue.Data = SmallData; + } + + /* Add this value cell to the child list */ + Status = CmpAddValueToList(Hive, + ValueCell, + Index, + StorageType, + &Parent->ValueList); + + /* If we failed, free the entire cell, including the data */ + if (!NT_SUCCESS(Status)) CmpFreeValue(Hive, ValueCell); + + /* Return Status */ + return Status; +} + +NTSTATUS +NTAPI +CmpSetValueKeyExisting(IN PHHIVE Hive, + IN HCELL_INDEX OldChild, + IN PCM_KEY_VALUE Value, + IN ULONG Type, + IN PVOID Data, + IN ULONG DataSize, + IN ULONG StorageType, + IN ULONG TempData) +{ + HCELL_INDEX DataCell, NewCell; + PCELL_DATA CellData; + ULONG Length; + BOOLEAN WasSmall, IsSmall; + + /* Mark the old child cell dirty */ + HvMarkCellDirty(Hive, OldChild, FALSE); + + /* See if this is a small or normal key */ + WasSmall = CmpIsKeyValueSmall(&Length, Value->DataLength); + + /* See if our new data can fit in a small key */ + IsSmall = (DataSize <= CM_KEY_VALUE_SMALL) ? TRUE: FALSE; + + /* Big keys are unsupported */ + ASSERT_VALUE_BIG(Hive, Length); + ASSERT_VALUE_BIG(Hive, DataSize); + + /* Mark the old value dirty */ + CmpMarkValueDataDirty(Hive, Value); + + /* Check if we have a small key */ + if (IsSmall) + { + /* Check if we had a normal key with some data in it */ + if (!(WasSmall) && (Length > 0)) + { + /* Free the previous data */ + CmpFreeValueData(Hive, Value->Data, Length); + } + + /* Write our data directly */ + Value->DataLength = DataSize + CM_KEY_VALUE_SPECIAL_SIZE; + Value->Data = TempData; + Value->Type = Type; + return STATUS_SUCCESS; + } + else + { + /* We have a normal key. Was the old cell also normal and had data? */ + if (!(WasSmall) && (Length > 0)) + { + /* Get the current data cell and actual data inside it */ + DataCell = Value->Data; + ASSERT(DataCell != HCELL_NIL); + CellData = HvGetCell(Hive, DataCell); + if (!CellData) return STATUS_INSUFFICIENT_RESOURCES; + + /* Immediately release the cell */ + HvReleaseCell(Hive, DataCell); + + /* Make sure that the data cell actually has a size */ + ASSERT(HvGetCellSize(Hive, CellData) > 0); + + /* Check if the previous data cell could fit our new data */ + if (DataSize <= (ULONG)(HvGetCellSize(Hive, CellData))) + { + /* Re-use it then */ + NewCell = DataCell; + } + else + { + /* Otherwise, re-allocate the current data cell */ + NewCell = HvReallocateCell(Hive, DataCell, DataSize); + if (NewCell == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES; + } + } + else + { + /* This was a small key, or a key with no data, allocate a cell */ + NewCell = HvAllocateCell(Hive, DataSize, StorageType, HCELL_NIL); + if (NewCell == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Now get the actual data for our data cell */ + CellData = HvGetCell(Hive, NewCell); + if (!CellData) ASSERT(FALSE); + + /* Release it immediately */ + HvReleaseCell(Hive, NewCell); + + /* Copy our data into the data cell's buffer, and set up the value */ + RtlCopyMemory(CellData, Data, DataSize); + Value->Data = NewCell; + Value->DataLength = DataSize; + Value->Type = Type; + + /* Return success */ + ASSERT(HvIsCellDirty(Hive, NewCell)); + return STATUS_SUCCESS; + } +} + +NTSTATUS +NTAPI +CmSetValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb, + IN PUNICODE_STRING ValueName, + IN ULONG Type, + IN PVOID Data, + IN ULONG DataLength) +{ + PHHIVE Hive; + PCM_KEY_NODE Parent; + PCM_KEY_VALUE Value = NULL; + HCELL_INDEX CurrentChild, Cell; + NTSTATUS Status; + BOOLEAN Found, Result; + ULONG Count, ChildIndex, SmallData, Storage; + + /* Acquire hive lock exclusively */ + KeEnterCriticalRegion(); + ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); + + /* Get pointer to key cell */ + Hive = Kcb->KeyHive; + Cell = Kcb->KeyCell; + + /* Prepare to scan the key node */ + Parent = (PCM_KEY_NODE)HvGetCell(Hive, Cell); + Count = Parent->ValueList.Count; + Found = FALSE; + if (Count > 0) + { + /* Try to find the existing name */ + Result = CmpFindNameInList(Hive, + &Parent->ValueList, + ValueName, + &ChildIndex, + &CurrentChild); + if (!Result) + { + /* Fail */ + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Quickie; + } + + /* Check if we found something */ + if (CurrentChild != HCELL_NIL) + { + /* Get its value */ + Value = (PCM_KEY_VALUE)HvGetCell(Hive, CurrentChild); + if (!Value) + { + /* Fail */ + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Quickie; + } + + /* Remember that we found it */ + Found = TRUE; + } + } + else + { + /* No child list, we'll need to add it */ + ChildIndex = 0; + } + + /* Mark the cell dirty */ + HvMarkCellDirty(Hive, Cell, FALSE); + + /* Get the storage type */ + Storage = HvGetCellType(Cell); + + /* Check if this is small data */ + SmallData = 0; + if ((DataLength <= CM_KEY_VALUE_SMALL) && (DataLength > 0)) + { + /* Copy it */ + RtlCopyMemory(&SmallData, Data, DataLength); + } + + /* Check if we didn't find a matching key */ + if (!Found) + { + /* Call the internal routine */ + Status = CmpSetValueKeyNew(Hive, + Parent, + ValueName, + ChildIndex, + Type, + Data, + DataLength, + Storage, + SmallData); + } + else + { + /* Call the internal routine */ + Status = CmpSetValueKeyExisting(Hive, + CurrentChild, + Value, + Type, + Data, + DataLength, + Storage, + SmallData); + } + + /* Mark link key */ + if ((Type == REG_LINK) && + (_wcsicmp(ValueName->Buffer, L"SymbolicLinkValue") == 0)) + { + Parent->Flags |= KEY_SYM_LINK; + } + + /* Check for success */ +Quickie: + if (NT_SUCCESS(Status)) + { + ASSERT(Parent->MaxValueNameLen == Kcb->KcbMaxValueNameLen); + if (Parent->MaxValueNameLen < ValueName->Length) + { + Parent->MaxValueNameLen = ValueName->Length; + Kcb->KcbMaxValueNameLen = ValueName->Length; + } + + ASSERT(Parent->MaxValueDataLen == Kcb->KcbMaxValueDataLen); + if (Parent->MaxValueDataLen < DataLength) + { + Parent->MaxValueDataLen = DataLength; + Kcb->KcbMaxValueDataLen = Parent->MaxValueDataLen; + } + + /* Save the write time */ + KeQuerySystemTime(&Parent->LastWriteTime); + KeQuerySystemTime(&Kcb->KcbLastWriteTime); + } + + /* Release the lock */ + ExReleaseResourceLite(&CmpRegistryLock); + KeLeaveCriticalRegion(); + return Status; +} + +NTSTATUS +NTAPI +CmDeleteValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb, + IN UNICODE_STRING ValueName) +{ + NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND; + PHHIVE Hive; + PCM_KEY_NODE Parent; + HCELL_INDEX ChildCell, Cell; + PCHILD_LIST ChildList; + PCM_KEY_VALUE Value = NULL; + ULONG ChildIndex; + BOOLEAN Result; + + /* Acquire hive lock */ + KeEnterCriticalRegion(); + ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); + + /* Get the hive and the cell index */ + Hive = Kcb->KeyHive; + Cell = Kcb->KeyCell; + + /* Get the parent key node */ + Parent = (PCM_KEY_NODE)HvGetCell(Hive, Cell); + if (!Parent) + { + /* Fail */ + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Quickie; + } + + /* Get the value list and check if it has any entries */ + ChildList = &Parent->ValueList; + if (ChildList->Count) + { + /* Try to find this value */ + Result = CmpFindNameInList(Hive, + ChildList, + &ValueName, + &ChildIndex, + &ChildCell); + if (!Result) + { + /* Fail */ + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Quickie; + } + + /* Value not found, return error */ + if (ChildCell == HCELL_NIL) goto Quickie; + + /* We found the value, mark all relevant cells dirty */ + HvMarkCellDirty(Hive, Cell, FALSE); + HvMarkCellDirty(Hive, Parent->ValueList.List, FALSE); + HvMarkCellDirty(Hive, ChildCell, FALSE); + + /* Get the key value */ + Value = (PCM_KEY_VALUE)HvGetCell(Hive,ChildCell); + if (!Value) ASSERT(FALSE); + + /* Mark it and all related data as dirty */ + CmpMarkValueDataDirty(Hive, Value); + + /* Ssanity checks */ + ASSERT(HvIsCellDirty(Hive, Parent->ValueList.List)); + ASSERT(HvIsCellDirty(Hive, ChildCell)); + + /* Remove the value from the child list */ + Status = CmpRemoveValueFromList(Hive, ChildIndex, ChildList); + if(!NT_SUCCESS(Status)) goto Quickie; + + /* Remove the value and its data itself */ + if (!CmpFreeValue(Hive, ChildCell)) + { + /* Failed to free the value, fail */ + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Quickie; + } + + /* Set the last write time */ + KeQuerySystemTime(&Parent->LastWriteTime); + KeQuerySystemTime(&Kcb->KcbLastWriteTime); + + /* Sanity check */ + ASSERT(Parent->MaxValueNameLen == Kcb->KcbMaxValueNameLen); + ASSERT(Parent->MaxValueDataLen == Kcb->KcbMaxValueDataLen); + ASSERT(HvIsCellDirty(Hive, Cell)); + + /* Check if the value list is empty now */ + if (!Parent->ValueList.Count) + { + /* Then clear key node data */ + Parent->MaxValueNameLen = 0; + Parent->MaxValueDataLen = 0; + Kcb->KcbMaxValueNameLen = 0; + Kcb->KcbMaxValueDataLen = 0; + } + + /* Change default Status to success */ + Status = STATUS_SUCCESS; + } + +Quickie: + /* Release the parent cell, if any */ + if (Parent) HvReleaseCell(Hive, Cell); + + /* Check if we had a value */ + if (Value) + { + /* Release the child cell */ + ASSERT(ChildCell != HCELL_NIL); + HvReleaseCell(Hive, ChildCell); + } + + /* Release hive lock */ + ExReleaseResourceLite(&CmpRegistryLock); + KeLeaveCriticalRegion(); + return Status; +} + +NTSTATUS +NTAPI +CmQueryValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb, + IN UNICODE_STRING ValueName, + IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + IN PVOID KeyValueInformation, + IN ULONG Length, + IN PULONG ResultLength) +{ + NTSTATUS Status; + PCM_KEY_VALUE ValueData; + ULONG Index; + BOOLEAN ValueCached = FALSE; + PCM_CACHED_VALUE *CachedValue; + HCELL_INDEX CellToRelease; + VALUE_SEARCH_RETURN_TYPE Result; + PHHIVE Hive; + PAGED_CODE(); + + /* Acquire hive lock */ + KeEnterCriticalRegion(); + ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); + + /* Get the hive */ + Hive = Kcb->KeyHive; + + /* Find the key value */ + Result = CmpFindValueByNameFromCache(Kcb, + &ValueName, + &CachedValue, + &Index, + &ValueData, + &ValueCached, + &CellToRelease); + if (Result == SearchSuccess) + { + /* Sanity check */ + ASSERT(ValueData != NULL); + + /* Query the information requested */ + Result = CmpQueryKeyValueData(Kcb, + CachedValue, + ValueData, + ValueCached, + KeyValueInformationClass, + KeyValueInformation, + Length, + ResultLength, + &Status); + } + else + { + /* Failed to find the value */ + Status = STATUS_OBJECT_NAME_NOT_FOUND; + } + + /* If we have a cell to release, do so */ + if (CellToRelease != HCELL_NIL) HvReleaseCell(Hive, CellToRelease); + + /* Release hive lock */ + ExReleaseResourceLite(&CmpRegistryLock); + KeLeaveCriticalRegion(); + return Status; +} + +NTSTATUS +NTAPI +CmEnumerateValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb, + IN ULONG Index, + IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + IN PVOID KeyValueInformation, + IN ULONG Length, + IN PULONG ResultLength) +{ + NTSTATUS Status; + PHHIVE Hive; + PCM_KEY_NODE Parent; + HCELL_INDEX CellToRelease = HCELL_NIL, CellToRelease2 = HCELL_NIL; + VALUE_SEARCH_RETURN_TYPE Result; + BOOLEAN IndexIsCached, ValueIsCached = FALSE; + PCELL_DATA CellData; + PCM_CACHED_VALUE *CachedValue; + PCM_KEY_VALUE ValueData; + PAGED_CODE(); + + /* Acquire hive lock */ + KeEnterCriticalRegion(); + ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); + + /* Get the hive and parent */ + Hive = Kcb->KeyHive; + Parent = (PCM_KEY_NODE)HvGetCell(Hive, Kcb->KeyCell); + if (!Parent) + { + /* Fail */ + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Quickie; + } + + /* Make sure the index is valid */ + //if (Index >= Kcb->ValueCache.Count) + if (Index >= Parent->ValueList.Count) + { + /* Release the cell and fail */ + HvReleaseCell(Hive, Kcb->KeyCell); + Status = STATUS_NO_MORE_ENTRIES; + goto Quickie; + } + + /* Find the value list */ + Result = CmpGetValueListFromCache(Kcb, + &CellData, + &IndexIsCached, + &CellToRelease); + if (Result != SearchSuccess) + { + /* Sanity check */ + ASSERT(CellData == NULL); + + /* Release the cell and fail */ + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Quickie; + } + + /* Now get the key value */ + Result = CmpGetValueKeyFromCache(Kcb, + CellData, + Index, + &CachedValue, + &ValueData, + IndexIsCached, + &ValueIsCached, + &CellToRelease2); + if (Result != SearchSuccess) + { + /* Sanity check */ + ASSERT(CellToRelease2 == HCELL_NIL); + + /* Release the cells and fail */ + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Quickie; + } + + /* Query the information requested */ + Result = CmpQueryKeyValueData(Kcb, + CachedValue, + ValueData, + ValueIsCached, + KeyValueInformationClass, + KeyValueInformation, + Length, + ResultLength, + &Status); + +Quickie: + /* If we have a cell to release, do so */ + if (CellToRelease != HCELL_NIL) HvReleaseCell(Hive, CellToRelease); + + /* Release the parent cell */ + HvReleaseCell(Hive, Kcb->KeyCell); + + /* If we have a cell to release, do so */ + if (CellToRelease2 != HCELL_NIL) HvReleaseCell(Hive, CellToRelease2); + + /* Release hive lock */ + ExReleaseResourceLite(&CmpRegistryLock); + KeLeaveCriticalRegion(); + return Status; +} + +NTSTATUS +NTAPI +CmpQueryKeyData(IN PHHIVE Hive, + IN PCM_KEY_NODE Node, + IN KEY_INFORMATION_CLASS KeyInformationClass, + IN OUT PVOID KeyInformation, + IN ULONG Length, + IN OUT PULONG ResultLength) +{ + NTSTATUS Status; + ULONG Size, SizeLeft, MinimumSize; + PKEY_INFORMATION Info = (PKEY_INFORMATION)KeyInformation; + USHORT NameLength; + + /* Check if the value is compressed */ + if (Node->Flags & KEY_COMP_NAME) + { + /* Get the compressed name size */ + NameLength = CmpCompressedNameSize(Node->Name, Node->NameLength); + } + else + { + /* Get the real size */ + NameLength = Node->NameLength; + } + + /* Check what kind of information is being requested */ + switch (KeyInformationClass) + { + /* Basic information */ + case KeyBasicInformation: + + /* This is the size we need */ + Size = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name) + NameLength; + + /* And this is the minimum we can work with */ + MinimumSize = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name); + + /* Let the caller know and assume success */ + *ResultLength = Size; + Status = STATUS_SUCCESS; + + /* Check if the bufer we got is too small */ + if (Length < MinimumSize) + { + /* Let the caller know and fail */ + Status = STATUS_BUFFER_TOO_SMALL; + break; + } + + /* Copy the basic information */ + Info->KeyBasicInformation.LastWriteTime = Node->LastWriteTime; + Info->KeyBasicInformation.TitleIndex = 0; + Info->KeyBasicInformation.NameLength = NameLength; + + /* Only the name is left */ + SizeLeft = Length - MinimumSize; + Size = NameLength; + + /* Check if we don't have enough space for the name */ + if (SizeLeft < Size) + { + /* Truncate the name we'll return, and tell the caller */ + Size = SizeLeft; + Status = STATUS_BUFFER_OVERFLOW; + } + + /* Check if this is a compressed key */ + if (Node->Flags & KEY_COMP_NAME) + { + /* Copy the compressed name */ + CmpCopyCompressedName(Info->KeyBasicInformation.Name, + SizeLeft, + Node->Name, + Node->NameLength); + } + else + { + /* Otherwise, copy the raw name */ + RtlCopyMemory(Info->KeyBasicInformation.Name, + Node->Name, + Size); + } + break; + + /* Node information */ + case KeyNodeInformation: + + /* Calculate the size we need */ + Size = FIELD_OFFSET(KEY_NODE_INFORMATION, Name) + + NameLength + + Node->ClassLength; + + /* And the minimum size we can support */ + MinimumSize = FIELD_OFFSET(KEY_NODE_INFORMATION, Name); + + /* Return the size to the caller and assume succes */ + *ResultLength = Size; + Status = STATUS_SUCCESS; + + /* Check if the caller's buffer is too small */ + if (Length < MinimumSize) + { + /* Let them know, and fail */ + Status = STATUS_BUFFER_TOO_SMALL; + break; + } + + /* Copy the basic information */ + Info->KeyNodeInformation.LastWriteTime = Node->LastWriteTime; + Info->KeyNodeInformation.TitleIndex = 0; + Info->KeyNodeInformation.ClassLength = Node->ClassLength; + Info->KeyNodeInformation.NameLength = NameLength; + + /* Now the name is left */ + SizeLeft = Length - MinimumSize; + Size = NameLength; + + /* Check if the name can fit entirely */ + if (SizeLeft < Size) + { + /* It can't, we'll have to truncate. Tell the caller */ + Size = SizeLeft; + Status = STATUS_BUFFER_OVERFLOW; + } + + /* Check if the key node name is compressed */ + if (Node->Flags & KEY_COMP_NAME) + { + /* Copy the compressed name */ + CmpCopyCompressedName(Info->KeyNodeInformation.Name, + SizeLeft, + Node->Name, + Node->NameLength); + } + else + { + /* It isn't, so copy the raw name */ + RtlCopyMemory(Info->KeyNodeInformation.Name, + Node->Name, + Size); + } + + /* Check if the node has a class */ + if (Node->ClassLength > 0) + { + /* It does. We don't support these yet */ + ASSERTMSG("Classes not supported\n", FALSE); + } + else + { + /* It doesn't, so set offset to -1, not 0! */ + Info->KeyNodeInformation.ClassOffset = 0xFFFFFFFF; + } + break; + + /* Full information requsted */ + case KeyFullInformation: + + /* This is the size we need */ + Size = FIELD_OFFSET(KEY_FULL_INFORMATION, Class) + + Node->ClassLength; + + /* This is what we can work with */ + MinimumSize = FIELD_OFFSET(KEY_FULL_INFORMATION, Class); + + /* Return it to caller and assume success */ + *ResultLength = Size; + Status = STATUS_SUCCESS; + + /* Check if the caller's buffer is to small */ + if (Length < MinimumSize) + { + /* Let them know and fail */ + Status = STATUS_BUFFER_TOO_SMALL; + break; + } + + /* Now copy all the basic information */ + Info->KeyFullInformation.LastWriteTime = Node->LastWriteTime; + Info->KeyFullInformation.TitleIndex = 0; + Info->KeyFullInformation.ClassLength = Node->ClassLength; + Info->KeyFullInformation.SubKeys = Node->SubKeyCounts[Stable] + + Node->SubKeyCounts[Volatile]; + Info->KeyFullInformation.Values = Node->ValueList.Count; + Info->KeyFullInformation.MaxNameLen = Node->MaxNameLen; + Info->KeyFullInformation.MaxClassLen = Node->MaxClassLen; + Info->KeyFullInformation.MaxValueNameLen = Node->MaxValueNameLen; + Info->KeyFullInformation.MaxValueDataLen = Node->MaxValueDataLen; + + /* Check if we have a class */ + if (Node->ClassLength > 0) + { + /* We do, but we currently don't support this */ + ASSERTMSG("Classes not supported\n", FALSE); + } + else + { + /* We don't have a class, so set offset to -1, not 0! */ + Info->KeyNodeInformation.ClassOffset = 0xFFFFFFFF; + } + break; + + /* Any other class that got sent here is invalid! */ + default: + + /* Set failure code */ + Status = STATUS_INVALID_PARAMETER; + break; + } + + /* Return status */ + return Status; +} + +NTSTATUS +NTAPI +CmQueryKey(IN PCM_KEY_CONTROL_BLOCK Kcb, + IN KEY_INFORMATION_CLASS KeyInformationClass, + IN PVOID KeyInformation, + IN ULONG Length, + IN PULONG ResultLength) +{ + NTSTATUS Status; + PHHIVE Hive; + PCM_KEY_NODE Parent; + + /* Acquire hive lock */ + KeEnterCriticalRegion(); + ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); + + /* Get the hive and parent */ + Hive = Kcb->KeyHive; + Parent = (PCM_KEY_NODE)HvGetCell(Hive, Kcb->KeyCell); + if (!Parent) + { + /* Fail */ + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Quickie; + } + + /* Check what class we got */ + switch (KeyInformationClass) + { + /* Typical information */ + case KeyFullInformation: + case KeyBasicInformation: + case KeyNodeInformation: + + /* Call the internal API */ + Status = CmpQueryKeyData(Hive, + Parent, + KeyInformationClass, + KeyInformation, + Length, + ResultLength); + break; + + /* Unsupported classes for now */ + case KeyNameInformation: + case KeyCachedInformation: + case KeyFlagsInformation: + + /* Print message and fail */ + DPRINT1("Unsupported class: %d!\n", KeyInformationClass); + Status = STATUS_NOT_IMPLEMENTED; + break; + + /* Illegal classes */ + default: + + /* Print message and fail */ + DPRINT1("Unsupported class: %d!\n", KeyInformationClass); + Status = STATUS_INVALID_INFO_CLASS; + break; + } + +Quickie: + /* Release hive lock */ + ExReleaseResourceLite(&CmpRegistryLock); + KeLeaveCriticalRegion(); + return Status; +} + +NTSTATUS +NTAPI +CmEnumerateKey(IN PCM_KEY_CONTROL_BLOCK Kcb, + IN ULONG Index, + IN KEY_INFORMATION_CLASS KeyInformationClass, + IN PVOID KeyInformation, + IN ULONG Length, + IN PULONG ResultLength) +{ + NTSTATUS Status; + PHHIVE Hive; + PCM_KEY_NODE Parent, Child; + HCELL_INDEX ChildCell; + + /* Acquire hive lock */ + KeEnterCriticalRegion(); + ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); + + /* Get the hive and parent */ + Hive = Kcb->KeyHive; + Parent = (PCM_KEY_NODE)HvGetCell(Hive, Kcb->KeyCell); + if (!Parent) + { + /* Fail */ + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Quickie; + } + + /* Get the child cell */ + ChildCell = CmpFindSubKeyByNumber(Hive, Parent, Index); + + /* Release the parent cell */ + HvReleaseCell(Hive, Kcb->KeyCell); + + /* Check if we found the child */ + if (ChildCell == HCELL_NIL) + { + /* We didn't, fail */ + Status = STATUS_NO_MORE_ENTRIES; + goto Quickie; + } + + /* Now get the actual child node */ + Child = (PCM_KEY_NODE)HvGetCell(Hive, ChildCell); + if (!Child) + { + /* Fail */ + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Quickie; + } + + /* Query the data requested */ + Status = CmpQueryKeyData(Hive, + Child, + KeyInformationClass, + KeyInformation, + Length, + ResultLength); + +Quickie: + /* Release hive lock */ + ExReleaseResourceLite(&CmpRegistryLock); + KeLeaveCriticalRegion(); + return Status; +} + +NTSTATUS +NTAPI +CmDeleteKey(IN PCM_KEY_CONTROL_BLOCK Kcb) +{ + NTSTATUS Status; + PHHIVE Hive; + PCM_KEY_NODE Node, Parent; + HCELL_INDEX Cell, ParentCell; + + /* Acquire hive lock */ + KeEnterCriticalRegion(); + ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); + + /* Get the hive and node */ + Hive = Kcb->KeyHive; + Cell = Kcb->KeyCell; + + /* Get the key node */ + Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell); + if (!Node) + { + /* Fail */ + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Quickie; + } + + /* Check if we have no parent */ + if (!Node->Parent) + { + /* This is an attempt to delete \Registry itself! */ + Status = STATUS_CANNOT_DELETE; + goto Quickie; + } + + /* Check if we're already being deleted */ + if (Kcb->Delete) + { + /* Don't do it twice */ + Status = STATUS_SUCCESS; + goto Quickie; + } + + /* Sanity check */ + ASSERT(Node->Flags == Kcb->Flags); + + /* Check if we don't have any children */ + if (!(Node->SubKeyCounts[Stable] + Node->SubKeyCounts[Volatile])) + { + /* Get the parent and free the cell */ + ParentCell = Node->Parent; + Status = CmpFreeKeyByCell(Hive, Cell, TRUE); + if (NT_SUCCESS(Status)) + { + /* Get the parent node */ + Parent = (PCM_KEY_NODE)HvGetCell(Hive, ParentCell); + if (Parent) + { + /* Update the maximum name length */ + Kcb->ParentKcb->KcbMaxNameLen = Parent->MaxNameLen; + + /* Make sure we're dirty */ + ASSERT(HvIsCellDirty(Hive, ParentCell)); + + /* Update the write time */ + KeQuerySystemTime(&Parent->LastWriteTime); + KeQuerySystemTime(&Kcb->ParentKcb->KcbLastWriteTime); + + /* Release the cell */ + HvReleaseCell(Hive, ParentCell); + } + + /* Set the KCB in delete mode and remove it */ + Kcb->Delete = TRUE; + CmpRemoveKeyControlBlock(Kcb); + + /* Clear the cell */ + Kcb->KeyCell = HCELL_NIL; + } + } + else + { + /* Fail */ + Status = STATUS_CANNOT_DELETE; + } + + /* Flush the registry */ + CmpLazyFlush(); + +Quickie: + /* Release the cell */ + HvReleaseCell(Hive, Cell); + + /* Release hive lock */ + ExReleaseResourceLite(&CmpRegistryLock); + KeLeaveCriticalRegion(); + return Status; +} + +NTSTATUS +NTAPI +CmFlushKey(IN PCM_KEY_CONTROL_BLOCK Kcb, + IN BOOLEAN ExclusiveLock) +{ + PCMHIVE CmHive; + NTSTATUS Status = STATUS_SUCCESS; + PHHIVE Hive; + + /* Get the hives */ + Hive = Kcb->KeyHive; + CmHive = (PCMHIVE)Hive; + + /* Check if this is the master hive */ + if (CmHive == CmiVolatileHive) + { + /* Flush all the hives instead */ + CmpDoFlushAll(FALSE); + } + else + { + ULONG Disposition; + + /* ReactOS Requires this */ + CmpOpenHiveFiles(&CmHive->FileFullPath, + L".LOG", + &CmHive->FileHandles[HFILE_TYPE_PRIMARY], + &CmHive->FileHandles[HFILE_TYPE_LOG], + &Disposition, + &Disposition, + FALSE, + FALSE, + TRUE, + NULL); + + /* Flush only this hive */ + if (!HvSyncHive(Hive)) + { + /* Fail */ + Status = STATUS_REGISTRY_IO_FAILED; + } + + /* ReactOS requires this */ + ZwClose(CmHive->FileHandles[HFILE_TYPE_PRIMARY]); + ZwClose(CmHive->FileHandles[HFILE_TYPE_LOG]); + } + + /* Return the status */ + return Status; +} diff --git a/reactos/ntoskrnl/config/ntapi.c b/reactos/ntoskrnl/config/ntapi.c index 3dcb58a2256..7e6dbde3012 100644 --- a/reactos/ntoskrnl/config/ntapi.c +++ b/reactos/ntoskrnl/config/ntapi.c @@ -373,7 +373,7 @@ NtSetValueKey(IN HANDLE KeyHandle, ObDereferenceObject(KeyObject); /* Synchronize the hives and return */ - CmiSyncHives(); + CmpLazyFlush(); return Status; } @@ -421,7 +421,49 @@ NtDeleteValueKey(IN HANDLE KeyHandle, /* Dereference the key body and synchronize the hives */ ObDereferenceObject(KeyObject); - CmiSyncHives(); + CmpLazyFlush(); + return Status; +} + +NTSTATUS +NTAPI +NtFlushKey(IN HANDLE KeyHandle) +{ + NTSTATUS Status; + PKEY_OBJECT KeyObject; + PAGED_CODE(); + + /* Get the key object */ + Status = ObReferenceObjectByHandle(KeyHandle, + 0, + CmpKeyObjectType, + ExGetPreviousMode(), + (PVOID*)&KeyObject, + NULL); + if (!NT_SUCCESS(Status)) return Status; + + /* Lock the registry */ + KeEnterCriticalRegion(); + ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); + + /* Make sure KCB isn't deleted */ + if (KeyObject->KeyControlBlock->Delete) + { + /* Fail */ + Status = STATUS_KEY_DELETED; + } + else + { + /* Call the internal API */ + Status = CmFlushKey(KeyObject->KeyControlBlock, FALSE); + } + + /* Release the lock */ + ExReleaseResourceLite(&CmpRegistryLock); + KeLeaveCriticalRegion(); + + /* Dereference the object and return status */ + ObDereferenceObject(KeyObject); return Status; }