diff --git a/reactos/ntoskrnl/cm/cm.h b/reactos/ntoskrnl/cm/cm.h deleted file mode 100644 index da1b4dfc6fa..00000000000 --- a/reactos/ntoskrnl/cm/cm.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef __INCLUDE_CM_H -#define __INCLUDE_CM_H - -#include "ntoskrnl/config/cm.h" - -extern POBJECT_TYPE CmpKeyObjectType; -extern ERESOURCE CmpRegistryLock; -extern EX_PUSH_LOCK CmpHiveListHeadLock; - -#define VERIFY_BIN_HEADER(x) ASSERT(x->HeaderId == REG_BIN_ID) -#define VERIFY_KEY_CELL(x) ASSERT(x->Signature == CM_KEY_NODE_SIGNATURE) -#define VERIFY_ROOT_KEY_CELL(x) ASSERT(x->Signature == CM_KEY_NODE_SIGNATURE) -#define VERIFY_VALUE_CELL(x) ASSERT(x->Signature == CM_KEY_VALUE_SIGNATURE) -#define VERIFY_VALUE_LIST_CELL(x) -#define VERIFY_KEY_OBJECT(x) -#define VERIFY_REGISTRY_HIVE(x) - -#endif /*__INCLUDE_CM_H*/ diff --git a/reactos/ntoskrnl/cm/regobj.c b/reactos/ntoskrnl/cm/regobj.c deleted file mode 100644 index b6bde8345e7..00000000000 --- a/reactos/ntoskrnl/cm/regobj.c +++ /dev/null @@ -1,1055 +0,0 @@ -/* - * PROJECT: ReactOS Kernel - * COPYRIGHT: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/cm/regobj.c - * PURPOSE: Registry object manipulation routines. - * - * PROGRAMMERS: Hartmut Birr - * Alex Ionescu - * Rex Jolliff - * Eric Kohl - * Casper Hornstrup -*/ - -#include -#define NDEBUG -#include - -#include "cm.h" - -extern ULONG CmiTimer; - -static NTSTATUS -CmiGetLinkTarget(PCMHIVE RegistryHive, - PCM_KEY_NODE KeyCell, - PUNICODE_STRING TargetPath); - -/* FUNCTONS *****************************************************************/ - -NTSTATUS -NTAPI -CmpCreateHandle(PVOID ObjectBody, - ACCESS_MASK GrantedAccess, - ULONG HandleAttributes, - PHANDLE HandleReturn) -/* - * FUNCTION: Add a handle referencing an object - * ARGUMENTS: - * obj = Object body that the handle should refer to - * RETURNS: The created handle - * NOTE: The handle is valid only in the context of the current process - */ -{ - HANDLE_TABLE_ENTRY NewEntry; - PEPROCESS CurrentProcess; - PVOID HandleTable; - POBJECT_HEADER ObjectHeader; - HANDLE Handle; - KAPC_STATE ApcState; - BOOLEAN AttachedToProcess = FALSE; - - PAGED_CODE(); - - DPRINT("CmpCreateHandle(obj %p)\n",ObjectBody); - - ASSERT(ObjectBody); - - CurrentProcess = PsGetCurrentProcess(); - - ObjectHeader = OBJECT_TO_OBJECT_HEADER(ObjectBody); - - /* check that this is a valid kernel pointer */ - //ASSERT((ULONG_PTR)ObjectHeader & EX_HANDLE_ENTRY_LOCKED); - - if (GrantedAccess & MAXIMUM_ALLOWED) - { - GrantedAccess &= ~MAXIMUM_ALLOWED; - GrantedAccess |= GENERIC_ALL; - } - - if (GrantedAccess & GENERIC_ACCESS) - { - RtlMapGenericMask(&GrantedAccess, - &ObjectHeader->Type->TypeInfo.GenericMapping); - } - - NewEntry.Object = ObjectHeader; - if(HandleAttributes & OBJ_INHERIT) - NewEntry.ObAttributes |= OBJ_INHERIT; - else - NewEntry.ObAttributes &= ~OBJ_INHERIT; - NewEntry.GrantedAccess = GrantedAccess; - - if ((HandleAttributes & OBJ_KERNEL_HANDLE) && - ExGetPreviousMode() == KernelMode) - { - HandleTable = ObpKernelHandleTable; - if (PsGetCurrentProcess() != PsInitialSystemProcess) - { - KeStackAttachProcess(&PsInitialSystemProcess->Pcb, - &ApcState); - AttachedToProcess = TRUE; - } - } - else - { - HandleTable = PsGetCurrentProcess()->ObjectTable; - } - - Handle = ExCreateHandle(HandleTable, - &NewEntry); - - if (AttachedToProcess) - { - KeUnstackDetachProcess(&ApcState); - } - - if(Handle != NULL) - { - if (HandleAttributes & OBJ_KERNEL_HANDLE) - { - /* mark the handle value */ - Handle = ObMarkHandleAsKernelHandle(Handle); - } - - InterlockedIncrement(&ObjectHeader->HandleCount); - ObReferenceObject(ObjectBody); - - *HandleReturn = Handle; - - return STATUS_SUCCESS; - } - - return STATUS_UNSUCCESSFUL; -} - -PVOID -NTAPI -CmpLookupEntryDirectory(IN POBJECT_DIRECTORY Directory, - IN PUNICODE_STRING Name, - IN ULONG Attributes, - IN UCHAR SearchShadow, - IN POBP_LOOKUP_CONTEXT Context) -{ - BOOLEAN CaseInsensitive = FALSE; - POBJECT_HEADER_NAME_INFO HeaderNameInfo; - ULONG HashValue; - ULONG HashIndex; - LONG TotalChars; - WCHAR CurrentChar; - POBJECT_DIRECTORY_ENTRY *AllocatedEntry; - POBJECT_DIRECTORY_ENTRY *LookupBucket; - POBJECT_DIRECTORY_ENTRY CurrentEntry; - PVOID FoundObject = NULL; - PWSTR Buffer; - PAGED_CODE(); - - /* Always disable this until we have DOS Device Maps */ - SearchShadow = FALSE; - - /* Fail if we don't have a directory or name */ - if (!(Directory) || !(Name)) goto Quickie; - - /* Get name information */ - TotalChars = Name->Length / sizeof(WCHAR); - Buffer = Name->Buffer; - - /* Fail if the name is empty */ - if (!(Buffer) || !(TotalChars)) goto Quickie; - - /* Set up case-sensitivity */ - if (Attributes & OBJ_CASE_INSENSITIVE) CaseInsensitive = TRUE; - - /* Create the Hash */ - for (HashValue = 0; TotalChars; TotalChars--) - { - /* Go to the next Character */ - CurrentChar = *Buffer++; - - /* Prepare the Hash */ - HashValue += (HashValue << 1) + (HashValue >> 1); - - /* Create the rest based on the name */ - if (CurrentChar < 'a') HashValue += CurrentChar; - else if (CurrentChar > 'z') HashValue += RtlUpcaseUnicodeChar(CurrentChar); - else HashValue += (CurrentChar - ('a'-'A')); - } - - /* Merge it with our number of hash buckets */ - HashIndex = HashValue % 37; - - /* Save the result */ - Context->HashValue = HashValue; - Context->HashIndex = (USHORT)HashIndex; - - /* Get the root entry and set it as our lookup bucket */ - AllocatedEntry = &Directory->HashBuckets[HashIndex]; - LookupBucket = AllocatedEntry; - - /* Start looping */ - while ((CurrentEntry = *AllocatedEntry)) - { - /* Do the hashes match? */ - if (CurrentEntry->HashValue == HashValue) - { - /* Make sure that it has a name */ - ASSERT(OBJECT_TO_OBJECT_HEADER(CurrentEntry->Object)->NameInfoOffset != 0); - - /* Get the name information */ - HeaderNameInfo = OBJECT_HEADER_TO_NAME_INFO(OBJECT_TO_OBJECT_HEADER(CurrentEntry->Object)); - - /* Do the names match? */ - if ((Name->Length == HeaderNameInfo->Name.Length) && - (RtlEqualUnicodeString(Name, &HeaderNameInfo->Name, CaseInsensitive))) - { - break; - } - } - - /* Move to the next entry */ - AllocatedEntry = &CurrentEntry->ChainLink; - } - - /* Check if we still have an entry */ - if (CurrentEntry) - { - /* Set this entry as the first, to speed up incoming insertion */ - if (AllocatedEntry != LookupBucket) - { - /* Set the Current Entry */ - *AllocatedEntry = CurrentEntry->ChainLink; - - /* Link to the old Hash Entry */ - CurrentEntry->ChainLink = *LookupBucket; - - /* Set the new Hash Entry */ - *LookupBucket = CurrentEntry; - } - - /* Save the found object */ - FoundObject = CurrentEntry->Object; - if (!FoundObject) goto Quickie; - } - -Quickie: - /* Return the object we found */ - Context->Object = FoundObject; - return FoundObject; -} - -NTSTATUS -NTAPI -CmFindObject(POBJECT_CREATE_INFORMATION ObjectCreateInfo, - PUNICODE_STRING ObjectName, - PVOID* ReturnedObject, - PUNICODE_STRING RemainingPath, - POBJECT_TYPE ObjectType, - IN PACCESS_STATE AccessState, - IN PVOID ParseContext) -{ - PVOID NextObject; - PVOID CurrentObject; - PVOID RootObject; - POBJECT_HEADER CurrentHeader; - NTSTATUS Status; - PWSTR current; - UNICODE_STRING PathString; - ULONG Attributes; - UNICODE_STRING CurrentUs; - OBP_LOOKUP_CONTEXT Context; - - PAGED_CODE(); - - DPRINT("CmFindObject(ObjectCreateInfo %x, ReturnedObject %x, " - "RemainingPath %x)\n",ObjectCreateInfo,ReturnedObject,RemainingPath); - - RtlInitUnicodeString (RemainingPath, NULL); - - if (ObjectCreateInfo->RootDirectory == NULL) - { - ObReferenceObjectByPointer(ObpRootDirectoryObject, - DIRECTORY_TRAVERSE, - CmpKeyObjectType, - ObjectCreateInfo->ProbeMode); - CurrentObject = ObpRootDirectoryObject; - } - else - { - Status = ObReferenceObjectByHandle(ObjectCreateInfo->RootDirectory, - 0, - NULL, - ObjectCreateInfo->ProbeMode, - &CurrentObject, - NULL); - if (!NT_SUCCESS(Status)) - { - return Status; - } - } - - if (ObjectName->Length == 0 || - ObjectName->Buffer[0] == UNICODE_NULL) - { - *ReturnedObject = CurrentObject; - return STATUS_SUCCESS; - } - - if (ObjectCreateInfo->RootDirectory == NULL && - ObjectName->Buffer[0] != L'\\') - { - ObDereferenceObject (CurrentObject); - DPRINT1("failed\n"); - return STATUS_UNSUCCESSFUL; - } - - /* Create a zero-terminated copy of the object name */ - PathString.Length = ObjectName->Length; - PathString.MaximumLength = ObjectName->Length + sizeof(WCHAR); - PathString.Buffer = ExAllocatePool (NonPagedPool, - PathString.MaximumLength); - if (PathString.Buffer == NULL) - { - ObDereferenceObject (CurrentObject); - return STATUS_INSUFFICIENT_RESOURCES; - } - - RtlCopyMemory (PathString.Buffer, - ObjectName->Buffer, - ObjectName->Length); - PathString.Buffer[PathString.Length / sizeof(WCHAR)] = UNICODE_NULL; - - current = PathString.Buffer; - - RootObject = CurrentObject; - Attributes = ObjectCreateInfo->Attributes; - if (ObjectType == ObSymbolicLinkType) - Attributes |= OBJ_OPENLINK; - Attributes |= OBJ_CASE_INSENSITIVE; // hello! My name is ReactOS CM and I'm brain-dead! - - while (TRUE) - { - CurrentHeader = OBJECT_TO_OBJECT_HEADER(CurrentObject); - - /* Loop as long as we're dealing with a directory */ - while (CurrentHeader->Type == ObDirectoryType) - { - PWSTR Start, End; - PVOID FoundObject; - UNICODE_STRING StartUs; - NextObject = NULL; - - if (!current) goto Next; - - Start = current; - if (*Start == L'\\') Start++; - - End = wcschr(Start, L'\\'); - if (End != NULL) *End = 0; - - RtlInitUnicodeString(&StartUs, Start); - ObpInitializeDirectoryLookup(&Context); - Context.DirectoryLocked = TRUE; - Context.Directory = CurrentObject; - FoundObject = CmpLookupEntryDirectory(CurrentObject, &StartUs, Attributes, FALSE, &Context); - if (FoundObject == NULL) - { - if (End != NULL) - { - *End = L'\\'; - } - goto Next; - } - - ObReferenceObjectByPointer(FoundObject, - STANDARD_RIGHTS_REQUIRED, - CmpKeyObjectType, - KernelMode); - if (End != NULL) - { - *End = L'\\'; - current = End; - } - else - { - current = NULL; - } - - NextObject = FoundObject; - -Next: - if (NextObject == NULL) - { - break; - } - ObDereferenceObject(CurrentObject); - CurrentObject = NextObject; - CurrentHeader = OBJECT_TO_OBJECT_HEADER(CurrentObject); - } - - if (CurrentHeader->Type->TypeInfo.ParseProcedure == NULL) - { - DPRINT("Current object can't parse\n"); - break; - } - - RtlInitUnicodeString(&CurrentUs, current); - Status = CurrentHeader->Type->TypeInfo.ParseProcedure(CurrentObject, - CurrentHeader->Type, - AccessState, - ExGetPreviousMode(), // fixme: should be a parameter, since caller decides. - Attributes, - &PathString, - &CurrentUs, - ParseContext, - NULL, // fixme: where do we get this from? captured OBP? - &NextObject); - current = CurrentUs.Buffer; - if (Status == STATUS_REPARSE) - { - /* reparse the object path */ - NextObject = ObpRootDirectoryObject; - current = PathString.Buffer; - - ObReferenceObjectByPointer(NextObject, - DIRECTORY_TRAVERSE, - CmpKeyObjectType, - ObjectCreateInfo->ProbeMode); - } - - - if (NextObject == NULL) - { - break; - } - ObDereferenceObject(CurrentObject); - CurrentObject = NextObject; - } - - if (current) - { - RtlCreateUnicodeString(RemainingPath, current); - } - - RtlFreeUnicodeString (&PathString); - *ReturnedObject = CurrentObject; - - return STATUS_SUCCESS; -} - -/* Preconditions: Must be called with CmpRegistryLock held. */ -NTSTATUS -CmiScanKeyList(PCM_KEY_CONTROL_BLOCK Parent, - PCUNICODE_STRING KeyName, - ULONG Attributes, - PCM_KEY_BODY* ReturnedObject) -{ - PCM_KEY_BODY CurKey = NULL; - PCM_NAME_CONTROL_BLOCK Ncb; - PLIST_ENTRY NextEntry; - PWCHAR p, pp; - ULONG i; - *ReturnedObject = NULL; - - /* Loop child keys in the KCB */ - NextEntry = Parent->KeyBodyListHead.Flink; - while (NextEntry != &Parent->KeyBodyListHead) - { - /* Get the current ReactOS Key Object */ - CurKey = CONTAINING_RECORD(NextEntry, CM_KEY_BODY, KeyBodyList); - - /* Get the NCB */ - Ncb = CurKey->KeyControlBlock->NameBlock; - - /* Check if the key is compressed */ - if (Ncb->Compressed) - { - /* Do a compressed compare */ - if (!CmpCompareCompressedName(KeyName, - Ncb->Name, - Ncb->NameLength)) - { - /* We got it */ - break; - } - } - else - { - /* Do a manual compare */ - p = KeyName->Buffer; - pp = Ncb->Name; - for (i = 0; i < Ncb->NameLength; i += sizeof(WCHAR)) - { - /* Compare the character */ - if (RtlUpcaseUnicodeChar(*p) != RtlUpcaseUnicodeChar(*pp)) - { - /* Failed */ - break; - } - - /* Next chars */ - p++; - pp++; - } - - /* Did we find it? */ - if (i == Ncb->NameLength - 1) - { - /* We found it, break out */ - break; - } - } - - /* Go go the next entry */ - NextEntry = NextEntry->Flink; - } - - /* Check if we got here and found something */ - if (NextEntry != &Parent->KeyBodyListHead) - { - /* Refernece the object and return it */ - ObReferenceObject(CurKey); - *ReturnedObject = CurKey; - } - - /* Return success */ - return STATUS_SUCCESS; -} - -NTSTATUS -NTAPI -CmpParseKey2(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 -CmpParseKey(IN PVOID ParsedObject, - IN PVOID ObjectType, - IN OUT PACCESS_STATE AccessState, - IN KPROCESSOR_MODE AccessMode, - IN ULONG Attributes, - IN OUT PUNICODE_STRING FullPath, - IN OUT PUNICODE_STRING RemainingName, - IN OUT PVOID Context OPTIONAL, - IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL, - OUT PVOID *NextObject) -{ - HCELL_INDEX BlockOffset; - PCM_KEY_BODY FoundObject; - PCM_KEY_BODY ParsedKey; - PCM_KEY_NODE SubKeyCell; - NTSTATUS Status; - PWSTR StartPtr; - PWSTR EndPtr; - ULONG Length; - UNICODE_STRING LinkPath; - UNICODE_STRING TargetPath; - UNICODE_STRING KeyName; - PWSTR *Path = &RemainingName->Buffer; - PCM_KEY_CONTROL_BLOCK ParentKcb = NULL, Kcb; - PCM_KEY_NODE Node; - - /* Detect new-style parse */ - if (Context) - { - /* Call proper parse routine */ - return CmpParseKey2(ParsedObject, - ObjectType, - AccessState, - AccessMode, - Attributes, - FullPath, - RemainingName, - Context, - SecurityQos, - NextObject); - } - - ParsedKey = ParsedObject; - - *NextObject = NULL; - - if ((*Path) == NULL) - { - DPRINT("*Path is NULL\n"); - return STATUS_UNSUCCESSFUL; - } - - DPRINT("Path '%S'\n", *Path); - - /* Extract relevant path name */ - StartPtr = *Path; - if (*StartPtr == L'\\') - StartPtr++; - - EndPtr = wcschr(StartPtr, L'\\'); - if (EndPtr != NULL) - Length = ((PCHAR)EndPtr - (PCHAR)StartPtr) / sizeof(WCHAR); - else - Length = wcslen(StartPtr); - - KeyName.Length = (USHORT)Length * sizeof(WCHAR); - KeyName.MaximumLength = (USHORT)KeyName.Length + sizeof(WCHAR); - KeyName.Buffer = ExAllocatePool(NonPagedPool, - KeyName.MaximumLength); - RtlCopyMemory(KeyName.Buffer, - StartPtr, - KeyName.Length); - KeyName.Buffer[KeyName.Length / sizeof(WCHAR)] = 0; - - /* Acquire hive lock */ - KeEnterCriticalRegion(); - ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); - - Status = CmiScanKeyList(ParsedKey->KeyControlBlock, - &KeyName, - Attributes, - &FoundObject); - if (!NT_SUCCESS(Status)) - { - ExReleaseResourceLite(&CmpRegistryLock); - KeLeaveCriticalRegion(); - RtlFreeUnicodeString(&KeyName); - return Status; - } - - ParentKcb = ParsedKey->KeyControlBlock; - - if (FoundObject == NULL) - { - /* Search for the subkey */ - Node = (PCM_KEY_NODE)HvGetCell(ParsedKey->KeyControlBlock->KeyHive, - ParsedKey->KeyControlBlock->KeyCell); - - BlockOffset = CmpFindSubKeyByName(ParsedKey->KeyControlBlock->KeyHive, - Node, - &KeyName); - if (BlockOffset == HCELL_NIL) - { - ExReleaseResourceLite(&CmpRegistryLock); - KeLeaveCriticalRegion(); - RtlFreeUnicodeString(&KeyName); - return(STATUS_UNSUCCESSFUL); - } - - /* Get the node */ - SubKeyCell = (PCM_KEY_NODE)HvGetCell(ParsedKey->KeyControlBlock->KeyHive, BlockOffset); - - if ((SubKeyCell->Flags & KEY_SYM_LINK) && - !((Attributes & OBJ_OPENLINK) && (EndPtr == NULL))) - { - RtlInitUnicodeString(&LinkPath, NULL); - Status = CmiGetLinkTarget((PCMHIVE)ParsedKey->KeyControlBlock->KeyHive, - SubKeyCell, - &LinkPath); - if (NT_SUCCESS(Status)) - { - ExReleaseResourceLite(&CmpRegistryLock); - KeLeaveCriticalRegion(); - - DPRINT("LinkPath '%wZ'\n", &LinkPath); - - /* build new FullPath for reparsing */ - TargetPath.MaximumLength = LinkPath.MaximumLength; - if (EndPtr != NULL) - { - TargetPath.MaximumLength += (wcslen(EndPtr) * sizeof(WCHAR)); - } - TargetPath.Length = TargetPath.MaximumLength - sizeof(WCHAR); - TargetPath.Buffer = ExAllocatePool(NonPagedPool, - TargetPath.MaximumLength); - wcscpy(TargetPath.Buffer, LinkPath.Buffer); - if (EndPtr != NULL) - { - wcscat(TargetPath.Buffer, EndPtr); - } - - RtlFreeUnicodeString(FullPath); - RtlFreeUnicodeString(&LinkPath); - FullPath->Length = TargetPath.Length; - FullPath->MaximumLength = TargetPath.MaximumLength; - FullPath->Buffer = TargetPath.Buffer; - - DPRINT("FullPath '%wZ'\n", FullPath); - - /* reinitialize Path for reparsing */ - *Path = FullPath->Buffer; - - *NextObject = NULL; - - RtlFreeUnicodeString(&KeyName); - return(STATUS_REPARSE); - } - } - - /* Create new key object and put into linked list */ - DPRINT("CmpParseKey: %S\n", *Path); - Status = ObCreateObject(KernelMode, - CmpKeyObjectType, - NULL, - KernelMode, - NULL, - sizeof(CM_KEY_BODY), - 0, - 0, - (PVOID*)&FoundObject); - if (!NT_SUCCESS(Status)) - { - ExReleaseResourceLite(&CmpRegistryLock); - KeLeaveCriticalRegion(); - RtlFreeUnicodeString(&KeyName); - return(Status); - } -#if 0 - DPRINT("Inserting Key into Object Tree\n"); - Status = ObInsertObject((PVOID)FoundObject, - NULL, - KEY_ALL_ACCESS, - 0, - NULL, - NULL); - DPRINT("Status %x\n", Status); -#else - /* Free the create information */ - ObpFreeAndReleaseCapturedAttributes(OBJECT_TO_OBJECT_HEADER(FoundObject)->ObjectCreateInfo); - OBJECT_TO_OBJECT_HEADER(FoundObject)->ObjectCreateInfo = NULL; -#endif - - /* Add the keep-alive reference */ - ObReferenceObject(FoundObject); - - /* Create the KCB */ - Kcb = CmpCreateKeyControlBlock(ParsedKey->KeyControlBlock->KeyHive, - BlockOffset, - SubKeyCell, - ParentKcb, - 0, - &KeyName); - if (!Kcb) - { - ExReleaseResourceLite(&CmpRegistryLock); - KeLeaveCriticalRegion(); - RtlFreeUnicodeString(&KeyName); - return STATUS_INSUFFICIENT_RESOURCES; - } - - FoundObject->KeyControlBlock = Kcb; - ASSERT(FoundObject->KeyControlBlock->KeyHive == ParsedKey->KeyControlBlock->KeyHive); - InsertTailList(&ParsedKey->KeyControlBlock->KeyBodyListHead, &FoundObject->KeyBodyList); - DPRINT("Created object 0x%p\n", FoundObject); - } - else - { - Node = (PCM_KEY_NODE)HvGetCell(FoundObject->KeyControlBlock->KeyHive, - FoundObject->KeyControlBlock->KeyCell); - - if ((Node->Flags & KEY_SYM_LINK) && - !((Attributes & OBJ_OPENLINK) && (EndPtr == NULL))) - { - DPRINT("Found link\n"); - - RtlInitUnicodeString(&LinkPath, NULL); - Status = CmiGetLinkTarget((PCMHIVE)FoundObject->KeyControlBlock->KeyHive, - Node, - &LinkPath); - if (NT_SUCCESS(Status)) - { - DPRINT("LinkPath '%wZ'\n", &LinkPath); - - ExReleaseResourceLite(&CmpRegistryLock); - KeLeaveCriticalRegion(); - - ObDereferenceObject(FoundObject); - - /* build new FullPath for reparsing */ - TargetPath.MaximumLength = LinkPath.MaximumLength; - if (EndPtr != NULL) - { - TargetPath.MaximumLength += (wcslen(EndPtr) * sizeof(WCHAR)); - } - TargetPath.Length = TargetPath.MaximumLength - sizeof(WCHAR); - TargetPath.Buffer = ExAllocatePool(NonPagedPool, - TargetPath.MaximumLength); - wcscpy(TargetPath.Buffer, LinkPath.Buffer); - if (EndPtr != NULL) - { - wcscat(TargetPath.Buffer, EndPtr); - } - - RtlFreeUnicodeString(FullPath); - RtlFreeUnicodeString(&LinkPath); - FullPath->Length = TargetPath.Length; - FullPath->MaximumLength = TargetPath.MaximumLength; - FullPath->Buffer = TargetPath.Buffer; - - DPRINT("FullPath '%wZ'\n", FullPath); - - /* reinitialize Path for reparsing */ - *Path = FullPath->Buffer; - - *NextObject = NULL; - - RtlFreeUnicodeString(&KeyName); - return(STATUS_REPARSE); - } - } - } - - ExReleaseResourceLite(&CmpRegistryLock); - KeLeaveCriticalRegion(); - - *Path = EndPtr; - - - *NextObject = FoundObject; - - RtlFreeUnicodeString(&KeyName); - - return(STATUS_SUCCESS); -} - -static NTSTATUS -CmiGetLinkTarget(PCMHIVE RegistryHive, - PCM_KEY_NODE KeyCell, - PUNICODE_STRING TargetPath) -{ - UNICODE_STRING LinkName = RTL_CONSTANT_STRING(L"SymbolicLinkValue"); - PCM_KEY_VALUE ValueCell; - PVOID DataCell; - HCELL_INDEX Cell; - - DPRINT("CmiGetLinkTarget() called\n"); - - /* Find the cell */ - Cell = CmpFindValueByName(&RegistryHive->Hive, KeyCell, &LinkName); - if (Cell == HCELL_NIL) - { - DPRINT1("CmiScanKeyForValue() failed\n"); - return STATUS_OBJECT_NAME_NOT_FOUND; - } - - /* Get the cell data */ - ValueCell = (PCM_KEY_VALUE)HvGetCell(&RegistryHive->Hive, Cell); - if (ValueCell->Type != REG_LINK) - { - DPRINT1("Type != REG_LINK\n!"); - return(STATUS_UNSUCCESSFUL); - } - - if (TargetPath->Buffer == NULL && TargetPath->MaximumLength == 0) - { - TargetPath->Length = 0; - TargetPath->MaximumLength = (USHORT)ValueCell->DataLength + sizeof(WCHAR); - TargetPath->Buffer = ExAllocatePool(NonPagedPool, - TargetPath->MaximumLength); - } - - TargetPath->Length = min((USHORT)TargetPath->MaximumLength - sizeof(WCHAR), - (USHORT)ValueCell->DataLength); - - if (ValueCell->DataLength > 0) - { - DataCell = HvGetCell (&RegistryHive->Hive, ValueCell->Data); - RtlCopyMemory(TargetPath->Buffer, - DataCell, - TargetPath->Length); - TargetPath->Buffer[TargetPath->Length / sizeof(WCHAR)] = 0; - } - else - { - RtlCopyMemory(TargetPath->Buffer, - &ValueCell->Data, - TargetPath->Length); - TargetPath->Buffer[TargetPath->Length / sizeof(WCHAR)] = 0; - } - - DPRINT("TargetPath '%wZ'\n", TargetPath); - - return(STATUS_SUCCESS); -} - -NTSTATUS -NTAPI -NtCreateKey(OUT PHANDLE KeyHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - IN ULONG TitleIndex, - IN PUNICODE_STRING Class, - IN ULONG CreateOptions, - OUT PULONG Disposition) -{ - UNICODE_STRING RemainingPath = {0}, ReturnedPath = {0}; - ULONG LocalDisposition; - PCM_KEY_BODY KeyObject, Parent; - NTSTATUS Status = STATUS_SUCCESS; - UNICODE_STRING ObjectName; - OBJECT_CREATE_INFORMATION ObjectCreateInfo; - ULONG i; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - HANDLE hKey; - PCM_KEY_NODE Node, ParentNode; - CM_PARSE_CONTEXT ParseContext = {0}; - PAGED_CODE(); - - /* Setup the parse context */ - ParseContext.CreateOperation = TRUE; - ParseContext.CreateOptions = CreateOptions; - if (Class) ParseContext.Class = *Class; - - /* Capture all the info */ - Status = ObpCaptureObjectAttributes(ObjectAttributes, - PreviousMode, - FALSE, - &ObjectCreateInfo, - &ObjectName); - if (!NT_SUCCESS(Status)) return Status; - - /* Find the key object */ - Status = CmFindObject(&ObjectCreateInfo, - &ObjectName, - (PVOID*)&Parent, - &ReturnedPath, - CmpKeyObjectType, - NULL, - NULL); - if (!NT_SUCCESS(Status)) goto Cleanup; - - /* Check if we found the entire path */ - RemainingPath = ReturnedPath; - if (!RemainingPath.Length) - { - /* Check if the parent has been deleted */ - if (Parent->KeyControlBlock->Delete) - { - /* Fail */ - DPRINT1("Object marked for delete!\n"); - Status = STATUS_UNSUCCESSFUL; - goto Cleanup; - } - - /* Create a new handle to the parent */ - Status = CmpCreateHandle(Parent, - DesiredAccess, - ObjectCreateInfo.Attributes, - &hKey); - if (!NT_SUCCESS(Status)) goto Cleanup; - - /* Tell the caller we did this */ - LocalDisposition = REG_OPENED_EXISTING_KEY; - goto SuccessReturn; - } - - /* Loop every leading slash */ - while ((RemainingPath.Length) && - (*RemainingPath.Buffer == OBJ_NAME_PATH_SEPARATOR)) - { - /* And remove it */ - RemainingPath.Length -= sizeof(WCHAR); - RemainingPath.MaximumLength -= sizeof(WCHAR); - RemainingPath.Buffer++; - } - - /* Loop every terminating slash */ - while ((RemainingPath.Length) && - (RemainingPath.Buffer[(RemainingPath.Length / sizeof(WCHAR)) - 1] == - OBJ_NAME_PATH_SEPARATOR)) - { - /* And remove it */ - RemainingPath.Length -= sizeof(WCHAR); - RemainingPath.MaximumLength -= sizeof(WCHAR); - } - - /* Now loop the entire path */ - for (i = 0; i < RemainingPath.Length / sizeof(WCHAR); i++) - { - /* And check if we found slahes */ - if (RemainingPath.Buffer[i] == OBJ_NAME_PATH_SEPARATOR) - { - /* We don't create trees -- parent key doesn't exist, so fail */ - Status = STATUS_OBJECT_NAME_NOT_FOUND; - goto Cleanup; - } - } - - /* Now check if we're left with no name by this point */ - if (!(RemainingPath.Length) || (RemainingPath.Buffer[0] == UNICODE_NULL)) - { - /* Then fail since we can't do anything */ - Status = STATUS_OBJECT_NAME_NOT_FOUND; - goto Cleanup; - } - - /* Lock the registry */ - CmpLockRegistry(); - - /* Create the key */ - Status = CmpDoCreate(Parent->KeyControlBlock->KeyHive, - Parent->KeyControlBlock->KeyCell, - NULL, - &RemainingPath, - KernelMode, - &ParseContext, - Parent->KeyControlBlock, - (PVOID*)&KeyObject); - if (!NT_SUCCESS(Status)) goto Cleanup; - - /* If we got here, this is a new key */ - LocalDisposition = REG_CREATED_NEW_KEY; - - /* Get the parent node and the child node */ - ParentNode = (PCM_KEY_NODE)HvGetCell(KeyObject->KeyControlBlock->ParentKcb->KeyHive, - KeyObject->KeyControlBlock->ParentKcb->KeyCell); - Node = (PCM_KEY_NODE)HvGetCell(KeyObject->KeyControlBlock->KeyHive, - KeyObject->KeyControlBlock->KeyCell); - - /* Inherit some information */ - Node->Parent = KeyObject->KeyControlBlock->ParentKcb->KeyCell; - Node->Security = ParentNode->Security; - KeyObject->KeyControlBlock->ValueCache.ValueList = Node->ValueList.List; - KeyObject->KeyControlBlock->ValueCache.Count = Node->ValueList.Count; - - /* Link child to parent */ - InsertTailList(&Parent->KeyControlBlock->KeyBodyListHead, &KeyObject->KeyBodyList); - - /* Create the actual handle to the object */ - Status = CmpCreateHandle(KeyObject, - DesiredAccess, - ObjectCreateInfo.Attributes, - &hKey); - - /* Free the create information */ - ObpFreeAndReleaseCapturedAttributes(OBJECT_TO_OBJECT_HEADER(KeyObject)->ObjectCreateInfo); - OBJECT_TO_OBJECT_HEADER(KeyObject)->ObjectCreateInfo = NULL; - if (!NT_SUCCESS(Status)) goto Cleanup; - - /* Add the keep-alive reference */ - ObReferenceObject(KeyObject); - - /* Unlock registry */ - CmpUnlockRegistry(); - - /* Force a lazy flush */ - CmpLazyFlush(); - -SuccessReturn: - /* Return data to user */ - *KeyHandle = hKey; - if (Disposition) *Disposition = LocalDisposition; - -Cleanup: - /* Cleanup */ - ObpReleaseCapturedAttributes(&ObjectCreateInfo); - if (ObjectName.Buffer) ObpFreeObjectNameBuffer(&ObjectName); - RtlFreeUnicodeString(&ReturnedPath); - if (Parent) ObDereferenceObject(Parent); - return Status; -} - -/* EOF */ diff --git a/reactos/ntoskrnl/config/cmalloc.c b/reactos/ntoskrnl/config/cmalloc.c index a3941d56096..cee28aaeac2 100644 --- a/reactos/ntoskrnl/config/cmalloc.c +++ b/reactos/ntoskrnl/config/cmalloc.c @@ -11,7 +11,6 @@ #include #define NDEBUG #include -#include "cm.h" /* GLOBALS *******************************************************************/ diff --git a/reactos/ntoskrnl/config/cmapi.c b/reactos/ntoskrnl/config/cmapi.c index b687c3aec2a..82c8cdff5b8 100644 --- a/reactos/ntoskrnl/config/cmapi.c +++ b/reactos/ntoskrnl/config/cmapi.c @@ -9,7 +9,6 @@ /* INCLUDES ******************************************************************/ #include "ntoskrnl.h" -#include "cm.h" #define NDEBUG #include "debug.h" diff --git a/reactos/ntoskrnl/config/cmboot.c b/reactos/ntoskrnl/config/cmboot.c index 6ac1f22bb35..f1dcc347a20 100644 --- a/reactos/ntoskrnl/config/cmboot.c +++ b/reactos/ntoskrnl/config/cmboot.c @@ -1,127 +1,126 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/config/cmboot.c - * PURPOSE: Configuration Manager - Boot Initialization - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include "ntoskrnl.h" -#include "cm.h" -#define NDEBUG -#include "debug.h" - -/* GLOBALS *******************************************************************/ - -/* FUNCTIONS *****************************************************************/ - -HCELL_INDEX -NTAPI -CmpFindControlSet(IN PHHIVE SystemHive, - IN HCELL_INDEX RootCell, - IN PUNICODE_STRING SelectKeyName, - OUT PBOOLEAN AutoSelect) -{ - UNICODE_STRING KeyName; - PCM_KEY_NODE Node; - HCELL_INDEX SelectCell, AutoSelectCell, SelectValueCell, ControlSetCell; - HCELL_INDEX CurrentValueCell; - PCM_KEY_VALUE KeyValue; - ULONG Length; - PULONG ControlSetId; - ANSI_STRING ControlSetAnsiName; - CHAR Buffer[128]; - WCHAR WideBuffer[128]; - NTSTATUS Status; - PULONG CurrentData; - - /* Sanity check */ - ASSERT(SystemHive->ReleaseCellRoutine == NULL); - - /* Get the Select subkey */ - RtlInitUnicodeString(&KeyName, L"select"); - Node = (PCM_KEY_NODE)HvGetCell(SystemHive, RootCell); - if (!Node) return HCELL_NIL; - SelectCell = CmpFindSubKeyByName(SystemHive, Node, &KeyName); - if (SelectCell == HCELL_NIL) return SelectCell; - - /* Get AutoSelect value */ - RtlInitUnicodeString(&KeyName, L"AutoSelect"); - Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell); - if (!Node) return HCELL_NIL; - AutoSelectCell = CmpFindValueByName(SystemHive, Node, &KeyName); - if (AutoSelectCell == HCELL_NIL) - { - /* Assume TRUE if the value is missing. */ - *AutoSelect = TRUE; - } - else - { - /* Read the value */ - KeyValue = (PCM_KEY_VALUE)HvGetCell(SystemHive, AutoSelectCell); - if (KeyValue == NULL) return HCELL_NIL; - - /* Convert it to a boolean */ - *AutoSelect = *(PBOOLEAN)CmpValueToData(SystemHive, KeyValue, &Length); - } - - /* Now find the control set being looked up */ - Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell); - if (!Node) return HCELL_NIL; - SelectValueCell = CmpFindValueByName(SystemHive, Node, SelectKeyName); - if (SelectValueCell == HCELL_NIL) return SelectValueCell; - - /* Read the value (corresponding to the CCS ID) */ - KeyValue = (PCM_KEY_VALUE)HvGetCell(SystemHive, SelectValueCell); - if (!KeyValue) return HCELL_NIL; - if (KeyValue->Type != REG_DWORD) return HCELL_NIL; - ControlSetId = (PULONG)CmpValueToData(SystemHive, KeyValue, &Length); - - /* Now build an Ansi String for the CCS's Name */ - sprintf(Buffer, "ControlSet%03lu", *ControlSetId); - ControlSetAnsiName.Length = (USHORT)strlen(Buffer); - ControlSetAnsiName.MaximumLength = (USHORT)strlen(Buffer); - ControlSetAnsiName.Buffer = Buffer; - - /* And convert it to Unicode... */ - KeyName.MaximumLength = 256; - KeyName.Buffer = WideBuffer; - Status = RtlAnsiStringToUnicodeString(&KeyName, - &ControlSetAnsiName, - FALSE); - if (!NT_SUCCESS(Status)) return HCELL_NIL; - - /* Now open it */ - Node = (PCM_KEY_NODE)HvGetCell(SystemHive, RootCell); - if (!Node) return HCELL_NIL; - ControlSetCell = CmpFindSubKeyByName(SystemHive, Node, &KeyName); - if (ControlSetCell == HCELL_NIL) return ControlSetCell; - - /* Get the value of the "Current" CCS */ - RtlInitUnicodeString(&KeyName, L"Current"); - Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell); - if (!Node) return HCELL_NIL; - CurrentValueCell = CmpFindValueByName(SystemHive, Node, &KeyName); - - /* Make sure it exists */ - if (CurrentValueCell != HCELL_NIL) - { - /* Get the current value and make sure its a ULONG */ - KeyValue = (PCM_KEY_VALUE)HvGetCell(SystemHive, CurrentValueCell); - if (!KeyValue) return HCELL_NIL; - if (KeyValue->Type == REG_DWORD) - { - /* Get the data and update it */ - CurrentData = (PULONG)CmpValueToData(SystemHive, - KeyValue, - &Length); - if (!CurrentData) return HCELL_NIL; - *CurrentData = *ControlSetId; - } - } - - /* Return the CCS Cell */ - return ControlSetCell; -} +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmboot.c + * PURPOSE: Configuration Manager - Boot Initialization + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#define NDEBUG +#include "debug.h" + +/* GLOBALS *******************************************************************/ + +/* FUNCTIONS *****************************************************************/ + +HCELL_INDEX +NTAPI +CmpFindControlSet(IN PHHIVE SystemHive, + IN HCELL_INDEX RootCell, + IN PUNICODE_STRING SelectKeyName, + OUT PBOOLEAN AutoSelect) +{ + UNICODE_STRING KeyName; + PCM_KEY_NODE Node; + HCELL_INDEX SelectCell, AutoSelectCell, SelectValueCell, ControlSetCell; + HCELL_INDEX CurrentValueCell; + PCM_KEY_VALUE KeyValue; + ULONG Length; + PULONG ControlSetId; + ANSI_STRING ControlSetAnsiName; + CHAR Buffer[128]; + WCHAR WideBuffer[128]; + NTSTATUS Status; + PULONG CurrentData; + + /* Sanity check */ + ASSERT(SystemHive->ReleaseCellRoutine == NULL); + + /* Get the Select subkey */ + RtlInitUnicodeString(&KeyName, L"select"); + Node = (PCM_KEY_NODE)HvGetCell(SystemHive, RootCell); + if (!Node) return HCELL_NIL; + SelectCell = CmpFindSubKeyByName(SystemHive, Node, &KeyName); + if (SelectCell == HCELL_NIL) return SelectCell; + + /* Get AutoSelect value */ + RtlInitUnicodeString(&KeyName, L"AutoSelect"); + Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell); + if (!Node) return HCELL_NIL; + AutoSelectCell = CmpFindValueByName(SystemHive, Node, &KeyName); + if (AutoSelectCell == HCELL_NIL) + { + /* Assume TRUE if the value is missing. */ + *AutoSelect = TRUE; + } + else + { + /* Read the value */ + KeyValue = (PCM_KEY_VALUE)HvGetCell(SystemHive, AutoSelectCell); + if (KeyValue == NULL) return HCELL_NIL; + + /* Convert it to a boolean */ + *AutoSelect = *(PBOOLEAN)CmpValueToData(SystemHive, KeyValue, &Length); + } + + /* Now find the control set being looked up */ + Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell); + if (!Node) return HCELL_NIL; + SelectValueCell = CmpFindValueByName(SystemHive, Node, SelectKeyName); + if (SelectValueCell == HCELL_NIL) return SelectValueCell; + + /* Read the value (corresponding to the CCS ID) */ + KeyValue = (PCM_KEY_VALUE)HvGetCell(SystemHive, SelectValueCell); + if (!KeyValue) return HCELL_NIL; + if (KeyValue->Type != REG_DWORD) return HCELL_NIL; + ControlSetId = (PULONG)CmpValueToData(SystemHive, KeyValue, &Length); + + /* Now build an Ansi String for the CCS's Name */ + sprintf(Buffer, "ControlSet%03lu", *ControlSetId); + ControlSetAnsiName.Length = (USHORT)strlen(Buffer); + ControlSetAnsiName.MaximumLength = (USHORT)strlen(Buffer); + ControlSetAnsiName.Buffer = Buffer; + + /* And convert it to Unicode... */ + KeyName.MaximumLength = 256; + KeyName.Buffer = WideBuffer; + Status = RtlAnsiStringToUnicodeString(&KeyName, + &ControlSetAnsiName, + FALSE); + if (!NT_SUCCESS(Status)) return HCELL_NIL; + + /* Now open it */ + Node = (PCM_KEY_NODE)HvGetCell(SystemHive, RootCell); + if (!Node) return HCELL_NIL; + ControlSetCell = CmpFindSubKeyByName(SystemHive, Node, &KeyName); + if (ControlSetCell == HCELL_NIL) return ControlSetCell; + + /* Get the value of the "Current" CCS */ + RtlInitUnicodeString(&KeyName, L"Current"); + Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell); + if (!Node) return HCELL_NIL; + CurrentValueCell = CmpFindValueByName(SystemHive, Node, &KeyName); + + /* Make sure it exists */ + if (CurrentValueCell != HCELL_NIL) + { + /* Get the current value and make sure its a ULONG */ + KeyValue = (PCM_KEY_VALUE)HvGetCell(SystemHive, CurrentValueCell); + if (!KeyValue) return HCELL_NIL; + if (KeyValue->Type == REG_DWORD) + { + /* Get the data and update it */ + CurrentData = (PULONG)CmpValueToData(SystemHive, + KeyValue, + &Length); + if (!CurrentData) return HCELL_NIL; + *CurrentData = *ControlSetId; + } + } + + /* Return the CCS Cell */ + return ControlSetCell; +} diff --git a/reactos/ntoskrnl/config/cmcheck.c b/reactos/ntoskrnl/config/cmcheck.c index b443374b95a..d166ff48d60 100644 --- a/reactos/ntoskrnl/config/cmcheck.c +++ b/reactos/ntoskrnl/config/cmcheck.c @@ -1,27 +1,26 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/config/cmcheck.c - * PURPOSE: Configuration Manager - Hive and Key Validation - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include "ntoskrnl.h" -#include "cm.h" -#define NDEBUG -#include "debug.h" - -/* GLOBALS *******************************************************************/ - -/* FUNCTIONS *****************************************************************/ - -ULONG -NTAPI -CmCheckRegistry(IN PCMHIVE RegistryHive, - IN ULONG Flags) -{ - /* FIXME: HACK! */ - return 0; -} +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmcheck.c + * PURPOSE: Configuration Manager - Hive and Key Validation + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#define NDEBUG +#include "debug.h" + +/* GLOBALS *******************************************************************/ + +/* FUNCTIONS *****************************************************************/ + +ULONG +NTAPI +CmCheckRegistry(IN PCMHIVE RegistryHive, + IN ULONG Flags) +{ + /* FIXME: HACK! */ + return 0; +} diff --git a/reactos/ntoskrnl/config/cmconfig.c b/reactos/ntoskrnl/config/cmconfig.c index 5bfe76818c9..2880d29904a 100644 --- a/reactos/ntoskrnl/config/cmconfig.c +++ b/reactos/ntoskrnl/config/cmconfig.c @@ -1,399 +1,398 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/config/cmconfig.c - * PURPOSE: Configuration Manager - System Configuration Routines - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include "ntoskrnl.h" -#include "cm.h" -#define NDEBUG -#include "debug.h" - -/* FUNCTIONS *****************************************************************/ - -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 Status; - OBJECT_ATTRIBUTES ObjectAttributes; - UNICODE_STRING KeyName, ValueName, ValueData; - HANDLE KeyHandle, ParentHandle; - ANSI_STRING TempString; - CHAR TempBuffer[12]; - WCHAR Buffer[12]; - PCONFIGURATION_COMPONENT Component; - ULONG Disposition, Length = 0; - - /* Get the component */ - Component = &CurrentEntry->ComponentEntry; - - /* Set system class components to ARC system type */ - if (Component->Class == SystemClass) Component->Type = ArcSystem; - - /* Create a key for the component */ - InitializeObjectAttributes(&ObjectAttributes, - &CmTypeName[Component->Type], - OBJ_CASE_INSENSITIVE, - NodeHandle, - NULL); - Status = NtCreateKey(&KeyHandle, - KEY_READ | KEY_WRITE, - &ObjectAttributes, - 0, - NULL, - 0, - &Disposition); - if (!NT_SUCCESS(Status)) return Status; - - /* Check if this is anything but a system class component */ - if (Component->Class != SystemClass) - { - /* Build the sub-component string */ - RtlIntegerToChar(DeviceIndexTable[Component->Type]++, - 10, - 12, - TempBuffer); - RtlInitAnsiString(&TempString, TempBuffer); - - /* Convert it to Unicode */ - RtlInitEmptyUnicodeString(&KeyName, Buffer, sizeof(Buffer)); - RtlAnsiStringToUnicodeString(&KeyName, &TempString, FALSE); - - /* Create the key */ - ParentHandle = KeyHandle; - InitializeObjectAttributes(&ObjectAttributes, - &KeyName, - OBJ_CASE_INSENSITIVE, - ParentHandle, - NULL); - Status = NtCreateKey(&KeyHandle, - KEY_READ | KEY_WRITE, - &ObjectAttributes, - 0, - NULL, - 0, - &Disposition); - NtClose(ParentHandle); - - /* Fail if the key couldn't be created, and make sure it's a new key */ - if (!NT_SUCCESS(Status)) return Status; - ASSERT(Disposition == REG_CREATED_NEW_KEY); - } - - /* Setup the component information key */ - RtlInitUnicodeString(&ValueName, L"Component Information"); - Status = NtSetValueKey(KeyHandle, - &ValueName, - 0, - REG_BINARY, - &Component->Flags, - FIELD_OFFSET(CONFIGURATION_COMPONENT, - ConfigurationDataLength) - - FIELD_OFFSET(CONFIGURATION_COMPONENT, Flags)); - if (!NT_SUCCESS(Status)) - { - /* Fail */ - NtClose(KeyHandle); - return Status; - } - - /* Check if we have an identifier */ - if (Component->IdentifierLength) - { - /* Build the string and convert it to Unicode */ - RtlInitUnicodeString(&ValueName, L"Identifier"); - RtlInitAnsiString(&TempString, Component->Identifier); - Status = RtlAnsiStringToUnicodeString(&ValueData, - &TempString, - TRUE); - RtlCreateUnicodeString(&ValueData, (PWCHAR)Component->Identifier); - if (NT_SUCCESS(Status)) - { - /* Save the identifier in the registry */ - Status = NtSetValueKey(KeyHandle, - &ValueName, - 0, - REG_SZ, - ValueData.Buffer, - ValueData.Length + sizeof(UNICODE_NULL)); - RtlFreeUnicodeString(&ValueData); - } - - /* Check for failure during conversion or registry write */ - if (!NT_SUCCESS(Status)) - { - /* Fail */ - NtClose(KeyHandle); - return Status; - } - } - - /* Setup the configuration data string */ - RtlInitUnicodeString(&ValueName, L"Configuration Data"); - - /* Check if we got configuration data */ - if (CurrentEntry->ConfigurationData) - { - /* Calculate the total length and check if it fits into our buffer */ - Length = Component->ConfigurationDataLength + - FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList); - if (Length > CmpConfigurationAreaSize) - { - ASSERTMSG("Component too large -- need reallocation!", FALSE); - } - else - { - /* Copy the data */ - RtlCopyMemory(&CmpConfigurationData->PartialResourceList.Version, - CurrentEntry->ConfigurationData, - Component->ConfigurationDataLength); - } - } - else - { - /* No configuration data, setup defaults */ - CmpConfigurationData->PartialResourceList.Version = 0; - CmpConfigurationData->PartialResourceList.Revision = 0; - CmpConfigurationData->PartialResourceList.Count = 0; - Length = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors) + - FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList); - } - - /* Set the interface type and bus number */ - CmpConfigurationData->InterfaceType = InterfaceType; - CmpConfigurationData->BusNumber = BusNumber; - - /* Save the actual data */ - Status = NtSetValueKey(KeyHandle, - &ValueName, - 0, - REG_FULL_RESOURCE_DESCRIPTOR, - CmpConfigurationData, - Length); - if (!NT_SUCCESS(Status)) - { - /* Fail */ - NtClose(KeyHandle); - } - else - { - /* Return the new handle */ - *NewHandle = KeyHandle; - } - - /* Return status */ - return Status; -} - -NTSTATUS -NTAPI -CmpSetupConfigurationTree(IN PCONFIGURATION_COMPONENT_DATA CurrentEntry, - IN HANDLE ParentHandle, - IN INTERFACE_TYPE InterfaceType, - IN ULONG BusNumber) -{ - PCONFIGURATION_COMPONENT Component; - USHORT DeviceIndexTable[MaximumType + 1] = {0}; - ULONG Interface = InterfaceType, Bus = BusNumber, i; - NTSTATUS Status; - HANDLE NewHandle; - - /* Loop each entry */ - while (CurrentEntry) - { - /* Check if this is an adapter */ - Component = &CurrentEntry->ComponentEntry; - if ((Component->Class == AdapterClass) && - (CurrentEntry->Parent->ComponentEntry.Class == SystemClass)) - { - /* Check what kind of adapter it is */ - switch (Component->Type) - { - /* EISA */ - case EisaAdapter: - - /* Fixup information */ - Interface = Eisa; - Bus = CmpTypeCount[EisaAdapter]++; - break; - - /* Turbo-channel */ - case TcAdapter: - - /* Fixup information */ - Interface = TurboChannel; - Bus = CmpTypeCount[TurboChannel]++; - break; - - /* ISA, PCI, etc busses */ - case MultiFunctionAdapter: - - /* Check if we have an identifier */ - if (Component->Identifier) - { - /* Loop each multi-function adapter type */ - for (i = 0; CmpMultifunctionTypes[i].Identifier; i++) - { - /* Check for a name match */ - if (!_wcsicmp(CmpMultifunctionTypes[i].Identifier, - (PWCHAR)Component->Identifier)) - { - /* Match found */ - break; - } - } - - /* Fix up information */ - Interface = CmpMultifunctionTypes[i].InterfaceType; - Bus = CmpMultifunctionTypes[i].Count++; - } - break; - - /* SCSI Bus */ - case ScsiAdapter: - - /* Fix up */ - Interface = Internal; - Bus = CmpTypeCount[ScsiAdapter]++; - break; - - /* Unknown */ - default: - Interface = -1; - Bus = CmpUnknownBusCount++; - break; - } - } - - /* Dump information on the component */ - - /* Setup the hardware node */ - Status = CmpInitializeRegistryNode(CurrentEntry, - ParentHandle, - &NewHandle, - Interface, - Bus, - DeviceIndexTable); - if (!NT_SUCCESS(Status)) return Status; - - /* Check for children */ - if (CurrentEntry->Child) - { - /* Recurse child */ - Status = CmpSetupConfigurationTree(CurrentEntry->Child, - NewHandle, - Interface, - Bus); - if (!NT_SUCCESS(Status)) - { - /* Fail */ - NtClose(NewHandle); - return Status; - } - } - - /* Get to the next entry */ - NtClose(NewHandle); - CurrentEntry = CurrentEntry->Sibling; - } - - /* We're done */ - return STATUS_SUCCESS; -} - -NTSTATUS -NTAPI -CmpInitializeHardwareConfiguration(IN PLOADER_PARAMETER_BLOCK LoaderBlock) -{ - NTSTATUS Status; - OBJECT_ATTRIBUTES ObjectAttributes; - HANDLE KeyHandle; - ULONG Disposition; - UNICODE_STRING KeyName; - - /* Setup the key name */ - RtlInitUnicodeString(&KeyName, - L"\\Registry\\Machine\\Hardware\\DeviceMap"); - InitializeObjectAttributes(&ObjectAttributes, - &KeyName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - - /* Create the device map key */ - Status = NtCreateKey(&KeyHandle, - KEY_READ | KEY_WRITE, - &ObjectAttributes, - 0, - NULL, - 0, - &Disposition); - if (!NT_SUCCESS(Status)) return Status; - NtClose(KeyHandle); - - /* Nobody should've created this key yet! */ - ASSERT(Disposition == REG_CREATED_NEW_KEY); - - /* Setup the key name */ - RtlInitUnicodeString(&KeyName, - L"\\Registry\\Machine\\Hardware\\Description"); - InitializeObjectAttributes(&ObjectAttributes, - &KeyName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - - /* Create the description key */ - Status = NtCreateKey(&KeyHandle, - KEY_READ | KEY_WRITE, - &ObjectAttributes, - 0, - NULL, - 0, - &Disposition); - if (!NT_SUCCESS(Status)) return Status; - - /* Nobody should've created this key yet! */ - ASSERT(Disposition == REG_CREATED_NEW_KEY); - - /* Allocate the configuration data buffer */ - CmpConfigurationData = ExAllocatePoolWithTag(PagedPool, - CmpConfigurationAreaSize, - TAG_CM); - if (!CmpConfigurationData) return STATUS_INSUFFICIENT_RESOURCES; - - /* Check if we got anything from NTLDR */ - if (LoaderBlock->ConfigurationRoot) - { - /* Setup the configuration tree */ - Status = CmpSetupConfigurationTree(LoaderBlock->ConfigurationRoot, - KeyHandle, - -1, - -1); - } - else - { - /* Nothing else to do */ - Status = STATUS_SUCCESS; - } - - /* Close our handle, free the buffer and return status */ - ExFreePool(CmpConfigurationData); - NtClose(KeyHandle); - return Status; -} - - - - - +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmconfig.c + * PURPOSE: Configuration Manager - System Configuration Routines + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#define NDEBUG +#include "debug.h" + +/* FUNCTIONS *****************************************************************/ + +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 Status; + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING KeyName, ValueName, ValueData; + HANDLE KeyHandle, ParentHandle; + ANSI_STRING TempString; + CHAR TempBuffer[12]; + WCHAR Buffer[12]; + PCONFIGURATION_COMPONENT Component; + ULONG Disposition, Length = 0; + + /* Get the component */ + Component = &CurrentEntry->ComponentEntry; + + /* Set system class components to ARC system type */ + if (Component->Class == SystemClass) Component->Type = ArcSystem; + + /* Create a key for the component */ + InitializeObjectAttributes(&ObjectAttributes, + &CmTypeName[Component->Type], + OBJ_CASE_INSENSITIVE, + NodeHandle, + NULL); + Status = NtCreateKey(&KeyHandle, + KEY_READ | KEY_WRITE, + &ObjectAttributes, + 0, + NULL, + 0, + &Disposition); + if (!NT_SUCCESS(Status)) return Status; + + /* Check if this is anything but a system class component */ + if (Component->Class != SystemClass) + { + /* Build the sub-component string */ + RtlIntegerToChar(DeviceIndexTable[Component->Type]++, + 10, + 12, + TempBuffer); + RtlInitAnsiString(&TempString, TempBuffer); + + /* Convert it to Unicode */ + RtlInitEmptyUnicodeString(&KeyName, Buffer, sizeof(Buffer)); + RtlAnsiStringToUnicodeString(&KeyName, &TempString, FALSE); + + /* Create the key */ + ParentHandle = KeyHandle; + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + ParentHandle, + NULL); + Status = NtCreateKey(&KeyHandle, + KEY_READ | KEY_WRITE, + &ObjectAttributes, + 0, + NULL, + 0, + &Disposition); + NtClose(ParentHandle); + + /* Fail if the key couldn't be created, and make sure it's a new key */ + if (!NT_SUCCESS(Status)) return Status; + ASSERT(Disposition == REG_CREATED_NEW_KEY); + } + + /* Setup the component information key */ + RtlInitUnicodeString(&ValueName, L"Component Information"); + Status = NtSetValueKey(KeyHandle, + &ValueName, + 0, + REG_BINARY, + &Component->Flags, + FIELD_OFFSET(CONFIGURATION_COMPONENT, + ConfigurationDataLength) - + FIELD_OFFSET(CONFIGURATION_COMPONENT, Flags)); + if (!NT_SUCCESS(Status)) + { + /* Fail */ + NtClose(KeyHandle); + return Status; + } + + /* Check if we have an identifier */ + if (Component->IdentifierLength) + { + /* Build the string and convert it to Unicode */ + RtlInitUnicodeString(&ValueName, L"Identifier"); + RtlInitAnsiString(&TempString, Component->Identifier); + Status = RtlAnsiStringToUnicodeString(&ValueData, + &TempString, + TRUE); + RtlCreateUnicodeString(&ValueData, (PWCHAR)Component->Identifier); + if (NT_SUCCESS(Status)) + { + /* Save the identifier in the registry */ + Status = NtSetValueKey(KeyHandle, + &ValueName, + 0, + REG_SZ, + ValueData.Buffer, + ValueData.Length + sizeof(UNICODE_NULL)); + RtlFreeUnicodeString(&ValueData); + } + + /* Check for failure during conversion or registry write */ + if (!NT_SUCCESS(Status)) + { + /* Fail */ + NtClose(KeyHandle); + return Status; + } + } + + /* Setup the configuration data string */ + RtlInitUnicodeString(&ValueName, L"Configuration Data"); + + /* Check if we got configuration data */ + if (CurrentEntry->ConfigurationData) + { + /* Calculate the total length and check if it fits into our buffer */ + Length = Component->ConfigurationDataLength + + FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList); + if (Length > CmpConfigurationAreaSize) + { + ASSERTMSG("Component too large -- need reallocation!", FALSE); + } + else + { + /* Copy the data */ + RtlCopyMemory(&CmpConfigurationData->PartialResourceList.Version, + CurrentEntry->ConfigurationData, + Component->ConfigurationDataLength); + } + } + else + { + /* No configuration data, setup defaults */ + CmpConfigurationData->PartialResourceList.Version = 0; + CmpConfigurationData->PartialResourceList.Revision = 0; + CmpConfigurationData->PartialResourceList.Count = 0; + Length = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors) + + FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList); + } + + /* Set the interface type and bus number */ + CmpConfigurationData->InterfaceType = InterfaceType; + CmpConfigurationData->BusNumber = BusNumber; + + /* Save the actual data */ + Status = NtSetValueKey(KeyHandle, + &ValueName, + 0, + REG_FULL_RESOURCE_DESCRIPTOR, + CmpConfigurationData, + Length); + if (!NT_SUCCESS(Status)) + { + /* Fail */ + NtClose(KeyHandle); + } + else + { + /* Return the new handle */ + *NewHandle = KeyHandle; + } + + /* Return status */ + return Status; +} + +NTSTATUS +NTAPI +CmpSetupConfigurationTree(IN PCONFIGURATION_COMPONENT_DATA CurrentEntry, + IN HANDLE ParentHandle, + IN INTERFACE_TYPE InterfaceType, + IN ULONG BusNumber) +{ + PCONFIGURATION_COMPONENT Component; + USHORT DeviceIndexTable[MaximumType + 1] = {0}; + ULONG Interface = InterfaceType, Bus = BusNumber, i; + NTSTATUS Status; + HANDLE NewHandle; + + /* Loop each entry */ + while (CurrentEntry) + { + /* Check if this is an adapter */ + Component = &CurrentEntry->ComponentEntry; + if ((Component->Class == AdapterClass) && + (CurrentEntry->Parent->ComponentEntry.Class == SystemClass)) + { + /* Check what kind of adapter it is */ + switch (Component->Type) + { + /* EISA */ + case EisaAdapter: + + /* Fixup information */ + Interface = Eisa; + Bus = CmpTypeCount[EisaAdapter]++; + break; + + /* Turbo-channel */ + case TcAdapter: + + /* Fixup information */ + Interface = TurboChannel; + Bus = CmpTypeCount[TurboChannel]++; + break; + + /* ISA, PCI, etc busses */ + case MultiFunctionAdapter: + + /* Check if we have an identifier */ + if (Component->Identifier) + { + /* Loop each multi-function adapter type */ + for (i = 0; CmpMultifunctionTypes[i].Identifier; i++) + { + /* Check for a name match */ + if (!_wcsicmp(CmpMultifunctionTypes[i].Identifier, + (PWCHAR)Component->Identifier)) + { + /* Match found */ + break; + } + } + + /* Fix up information */ + Interface = CmpMultifunctionTypes[i].InterfaceType; + Bus = CmpMultifunctionTypes[i].Count++; + } + break; + + /* SCSI Bus */ + case ScsiAdapter: + + /* Fix up */ + Interface = Internal; + Bus = CmpTypeCount[ScsiAdapter]++; + break; + + /* Unknown */ + default: + Interface = -1; + Bus = CmpUnknownBusCount++; + break; + } + } + + /* Dump information on the component */ + + /* Setup the hardware node */ + Status = CmpInitializeRegistryNode(CurrentEntry, + ParentHandle, + &NewHandle, + Interface, + Bus, + DeviceIndexTable); + if (!NT_SUCCESS(Status)) return Status; + + /* Check for children */ + if (CurrentEntry->Child) + { + /* Recurse child */ + Status = CmpSetupConfigurationTree(CurrentEntry->Child, + NewHandle, + Interface, + Bus); + if (!NT_SUCCESS(Status)) + { + /* Fail */ + NtClose(NewHandle); + return Status; + } + } + + /* Get to the next entry */ + NtClose(NewHandle); + CurrentEntry = CurrentEntry->Sibling; + } + + /* We're done */ + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +CmpInitializeHardwareConfiguration(IN PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE KeyHandle; + ULONG Disposition; + UNICODE_STRING KeyName; + + /* Setup the key name */ + RtlInitUnicodeString(&KeyName, + L"\\Registry\\Machine\\Hardware\\DeviceMap"); + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + /* Create the device map key */ + Status = NtCreateKey(&KeyHandle, + KEY_READ | KEY_WRITE, + &ObjectAttributes, + 0, + NULL, + 0, + &Disposition); + if (!NT_SUCCESS(Status)) return Status; + NtClose(KeyHandle); + + /* Nobody should've created this key yet! */ + ASSERT(Disposition == REG_CREATED_NEW_KEY); + + /* Setup the key name */ + RtlInitUnicodeString(&KeyName, + L"\\Registry\\Machine\\Hardware\\Description"); + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + /* Create the description key */ + Status = NtCreateKey(&KeyHandle, + KEY_READ | KEY_WRITE, + &ObjectAttributes, + 0, + NULL, + 0, + &Disposition); + if (!NT_SUCCESS(Status)) return Status; + + /* Nobody should've created this key yet! */ + ASSERT(Disposition == REG_CREATED_NEW_KEY); + + /* Allocate the configuration data buffer */ + CmpConfigurationData = ExAllocatePoolWithTag(PagedPool, + CmpConfigurationAreaSize, + TAG_CM); + if (!CmpConfigurationData) return STATUS_INSUFFICIENT_RESOURCES; + + /* Check if we got anything from NTLDR */ + if (LoaderBlock->ConfigurationRoot) + { + /* Setup the configuration tree */ + Status = CmpSetupConfigurationTree(LoaderBlock->ConfigurationRoot, + KeyHandle, + -1, + -1); + } + else + { + /* Nothing else to do */ + Status = STATUS_SUCCESS; + } + + /* Close our handle, free the buffer and return status */ + ExFreePool(CmpConfigurationData); + NtClose(KeyHandle); + return Status; +} + + + + + diff --git a/reactos/ntoskrnl/config/cmcontrl.c b/reactos/ntoskrnl/config/cmcontrl.c index b6c3038662c..bd3881a7b2c 100644 --- a/reactos/ntoskrnl/config/cmcontrl.c +++ b/reactos/ntoskrnl/config/cmcontrl.c @@ -1,265 +1,264 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/config/cmcontrl.c - * PURPOSE: Configuration Manager - Control Set Management - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include "ntoskrnl.h" -#include "cm.h" -#define NDEBUG -#include "debug.h" - -/* GLOBALS *******************************************************************/ - -/* FUNCTIONS *****************************************************************/ - -LANGID -NTAPI -CmpConvertLangId(IN LPWSTR Name, - IN ULONG NameLength) -{ - ULONG i; - WCHAR p; - LANGID LangId = 0; - ULONG IdCode; - - /* Convert the length in chars and loop */ - NameLength = NameLength / sizeof(WCHAR); - for (i = 0; i < NameLength; i++) - { - /* Get the character */ - p = Name[i]; - - /* Handle each case */ - if ((p >= L'0') && (p <= L'9')) - { - /* Handle digits*/ - IdCode = p - L'0'; - } - else if ((p >= L'A') && (p <= L'F')) - { - /* Handle upper-case letters */ - IdCode = p - L'A' + 10; - } - else if ((p >= L'a') && (p <= L'f')) - { - /* Handle lower-case letters */ - IdCode = p - L'a' + 10; - } - else - { - /* Unhandled case, return what we have till now */ - break; - } - - /* If the ID Code is >= 16, then we're done */ - if (IdCode >= 16) break; - - /* Build the Language ID */ - LangId = (LangId << 4) | (LANGID)IdCode; - } - - /* Return the Language ID */ - return LangId; -} - -HCELL_INDEX -NTAPI -CmpWalkPath(IN PHHIVE SystemHive, - IN HCELL_INDEX ParentCell, - IN LPWSTR Path) -{ - UNICODE_STRING UnicodePath, NextName; - BOOLEAN LastName; - HCELL_INDEX CurrentCell = ParentCell; - PCM_KEY_NODE Node; - - /* We shouldn't have a release routine at this point */ - ASSERT(SystemHive->ReleaseCellRoutine == NULL); - - /* Initialize the Unicode path and start looping */ - RtlInitUnicodeString(&UnicodePath, Path); - while (TRUE) - { - /* Get the next name */ - CmpGetNextName(&UnicodePath, &NextName, &LastName); - if (!NextName.Length) return CurrentCell; - - /* Get the subkey */ - Node = (PCM_KEY_NODE)HvGetCell(SystemHive, CurrentCell); - if (!Node) return HCELL_NIL; - CurrentCell = CmpFindSubKeyByName(SystemHive, Node, &NextName); - if (CurrentCell == HCELL_NIL) return CurrentCell; - } -} - -VOID -NTAPI -CmGetSystemControlValues(IN PVOID SystemHiveData, - IN PCM_SYSTEM_CONTROL_VECTOR ControlVector) -{ - PHHIVE SystemHive = (PHHIVE)&CmControlHive; - NTSTATUS Status; - HCELL_INDEX RootCell, BaseCell, KeyCell, ValueCell; - ULONG Length, DataSize; - PCM_KEY_NODE Node; - PCM_KEY_VALUE ValueData; - UNICODE_STRING KeyName; - BOOLEAN Auto, IsSmallKey; - PVOID Buffer; - - /* LUDDDIIIICRROOOUUSSSS KI^H^H HACKKKK */ - if (!SystemHiveData) return; - - /* Initialize the Hive View List and the security cache */ - RtlZeroMemory(SystemHive, sizeof(SystemHive)); - CmpInitHiveViewList((PCMHIVE)SystemHive); - CmpInitSecurityCache((PCMHIVE)SystemHive); - - /* Initialize the Hive */ - Status = HvInitialize(SystemHive, - HINIT_FLAT, - HIVE_VOLATILE, - HFILE_TYPE_PRIMARY, - SystemHiveData, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - 1, - NULL); - if (!NT_SUCCESS(Status)) KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 1, 1, 0, 0); - - /* Sanity check, flat hives don't have release routines */ - ASSERT(SystemHive->ReleaseCellRoutine == NULL); - - /* FIXME: Prepare it */ - CmPrepareHive(SystemHive); - - /* Set the Root Cell */ - RootCell = ((PHBASE_BLOCK)SystemHiveData)->RootCell; - - /* Find the current control set */ - RtlInitUnicodeString(&KeyName, L"current"); - BaseCell = CmpFindControlSet(SystemHive, RootCell, &KeyName, &Auto); - if (BaseCell == HCELL_NIL) KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 1, 2, 0, 0); - - /* Find the control subkey */ - RtlInitUnicodeString(&KeyName, L"control"); - Node = (PCM_KEY_NODE)HvGetCell(SystemHive, BaseCell); - BaseCell = CmpFindSubKeyByName(SystemHive, Node, &KeyName); - if (BaseCell == HCELL_NIL) KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO,1 , 3, 0, 0); - - /* Loop each key */ - while (ControlVector->KeyPath) - { - /* Assume failure */ - Length = -1; - - /* Get the cell for this key */ - KeyCell = CmpWalkPath(SystemHive, BaseCell, ControlVector->KeyPath); - if (KeyCell != HCELL_NIL) - { - /* Now get the cell for the value */ - RtlInitUnicodeString(&KeyName, ControlVector->ValueName); - Node = (PCM_KEY_NODE)HvGetCell(SystemHive, KeyCell); - ValueCell = CmpFindValueByName(SystemHive, Node, &KeyName); - if (ValueCell != HCELL_NIL) - { - /* Check if there's any data */ - if (!ControlVector->BufferLength) - { - /* No, the buffer will only be large enough for a ULONG */ - DataSize = sizeof(ULONG); - } - else - { - /* Yes, save the data size */ - DataSize = *ControlVector->BufferLength; - } - - /* Get the actual data */ - ValueData = (PCM_KEY_VALUE)HvGetCell(SystemHive, ValueCell); - - /* Check if this is a small key */ - IsSmallKey = CmpIsKeyValueSmall(&Length, ValueData->DataLength); - - /* If the length is bigger then our buffer, normalize it */ - if (DataSize < Length) Length = DataSize; - - /* Make sure we have some data */ - if (Length > 0) - { - /* Check if this was a small key */ - if (IsSmallKey) - { - /* The buffer is directly safe to read */ - Buffer = (PVOID)(&(ValueData->Data)); - } - else - { - /* Use the longer path */ - Buffer = (PVOID)HvGetCell(SystemHive, ValueData->Data); - } - - /* Sanity check if this is a small key */ - ASSERT((IsSmallKey ? - (Length <= CM_KEY_VALUE_SMALL) : TRUE)); - - /* Copy the data in the buffer */ - RtlCopyMemory(ControlVector->Buffer, Buffer, Length); - } - - /* Check if we should return the data type */ - if (ControlVector->Type) - { - /* Return the type that we read */ - *ControlVector->Type = ValueData->Type; - } - } - } - - /* Return the size that we read */ - if (ControlVector->BufferLength) *ControlVector->BufferLength = Length; - - /* Go to the next entry */ - ControlVector++; - } - - /* Check if the ID is in the registry */ - if (CmDefaultLanguageIdType == REG_SZ) - { - /* Read it */ - PsDefaultSystemLocaleId = - (LCID)CmpConvertLangId(CmDefaultLanguageId, - CmDefaultLanguageIdLength); - } - else - { - /* Use EN_US by default */ - PsDefaultSystemLocaleId = 0x409; - } - - /* Check if the ID Is in the registry */ - if (CmInstallUILanguageIdType == REG_SZ) - { - /* Read it */ - PsInstallUILanguageId = CmpConvertLangId(CmInstallUILanguageId, - CmInstallUILanguageIdLength); - } - else - { - /* Otherwise, use the default */ - PsInstallUILanguageId = LANGIDFROMLCID(PsDefaultSystemLocaleId); - } - - /* Set the defaults for the Thread UI */ - PsDefaultThreadLocaleId = PsDefaultSystemLocaleId; - PsDefaultUILanguageId = PsInstallUILanguageId; -} +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmcontrl.c + * PURPOSE: Configuration Manager - Control Set Management + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#define NDEBUG +#include "debug.h" + +/* GLOBALS *******************************************************************/ + +/* FUNCTIONS *****************************************************************/ + +LANGID +NTAPI +CmpConvertLangId(IN LPWSTR Name, + IN ULONG NameLength) +{ + ULONG i; + WCHAR p; + LANGID LangId = 0; + ULONG IdCode; + + /* Convert the length in chars and loop */ + NameLength = NameLength / sizeof(WCHAR); + for (i = 0; i < NameLength; i++) + { + /* Get the character */ + p = Name[i]; + + /* Handle each case */ + if ((p >= L'0') && (p <= L'9')) + { + /* Handle digits*/ + IdCode = p - L'0'; + } + else if ((p >= L'A') && (p <= L'F')) + { + /* Handle upper-case letters */ + IdCode = p - L'A' + 10; + } + else if ((p >= L'a') && (p <= L'f')) + { + /* Handle lower-case letters */ + IdCode = p - L'a' + 10; + } + else + { + /* Unhandled case, return what we have till now */ + break; + } + + /* If the ID Code is >= 16, then we're done */ + if (IdCode >= 16) break; + + /* Build the Language ID */ + LangId = (LangId << 4) | (LANGID)IdCode; + } + + /* Return the Language ID */ + return LangId; +} + +HCELL_INDEX +NTAPI +CmpWalkPath(IN PHHIVE SystemHive, + IN HCELL_INDEX ParentCell, + IN LPWSTR Path) +{ + UNICODE_STRING UnicodePath, NextName; + BOOLEAN LastName; + HCELL_INDEX CurrentCell = ParentCell; + PCM_KEY_NODE Node; + + /* We shouldn't have a release routine at this point */ + ASSERT(SystemHive->ReleaseCellRoutine == NULL); + + /* Initialize the Unicode path and start looping */ + RtlInitUnicodeString(&UnicodePath, Path); + while (TRUE) + { + /* Get the next name */ + CmpGetNextName(&UnicodePath, &NextName, &LastName); + if (!NextName.Length) return CurrentCell; + + /* Get the subkey */ + Node = (PCM_KEY_NODE)HvGetCell(SystemHive, CurrentCell); + if (!Node) return HCELL_NIL; + CurrentCell = CmpFindSubKeyByName(SystemHive, Node, &NextName); + if (CurrentCell == HCELL_NIL) return CurrentCell; + } +} + +VOID +NTAPI +CmGetSystemControlValues(IN PVOID SystemHiveData, + IN PCM_SYSTEM_CONTROL_VECTOR ControlVector) +{ + PHHIVE SystemHive = (PHHIVE)&CmControlHive; + NTSTATUS Status; + HCELL_INDEX RootCell, BaseCell, KeyCell, ValueCell; + ULONG Length, DataSize; + PCM_KEY_NODE Node; + PCM_KEY_VALUE ValueData; + UNICODE_STRING KeyName; + BOOLEAN Auto, IsSmallKey; + PVOID Buffer; + + /* LUDDDIIIICRROOOUUSSSS KI^H^H HACKKKK */ + if (!SystemHiveData) return; + + /* Initialize the Hive View List and the security cache */ + RtlZeroMemory(SystemHive, sizeof(SystemHive)); + CmpInitHiveViewList((PCMHIVE)SystemHive); + CmpInitSecurityCache((PCMHIVE)SystemHive); + + /* Initialize the Hive */ + Status = HvInitialize(SystemHive, + HINIT_FLAT, + HIVE_VOLATILE, + HFILE_TYPE_PRIMARY, + SystemHiveData, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + 1, + NULL); + if (!NT_SUCCESS(Status)) KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 1, 1, 0, 0); + + /* Sanity check, flat hives don't have release routines */ + ASSERT(SystemHive->ReleaseCellRoutine == NULL); + + /* FIXME: Prepare it */ + CmPrepareHive(SystemHive); + + /* Set the Root Cell */ + RootCell = ((PHBASE_BLOCK)SystemHiveData)->RootCell; + + /* Find the current control set */ + RtlInitUnicodeString(&KeyName, L"current"); + BaseCell = CmpFindControlSet(SystemHive, RootCell, &KeyName, &Auto); + if (BaseCell == HCELL_NIL) KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 1, 2, 0, 0); + + /* Find the control subkey */ + RtlInitUnicodeString(&KeyName, L"control"); + Node = (PCM_KEY_NODE)HvGetCell(SystemHive, BaseCell); + BaseCell = CmpFindSubKeyByName(SystemHive, Node, &KeyName); + if (BaseCell == HCELL_NIL) KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO,1 , 3, 0, 0); + + /* Loop each key */ + while (ControlVector->KeyPath) + { + /* Assume failure */ + Length = -1; + + /* Get the cell for this key */ + KeyCell = CmpWalkPath(SystemHive, BaseCell, ControlVector->KeyPath); + if (KeyCell != HCELL_NIL) + { + /* Now get the cell for the value */ + RtlInitUnicodeString(&KeyName, ControlVector->ValueName); + Node = (PCM_KEY_NODE)HvGetCell(SystemHive, KeyCell); + ValueCell = CmpFindValueByName(SystemHive, Node, &KeyName); + if (ValueCell != HCELL_NIL) + { + /* Check if there's any data */ + if (!ControlVector->BufferLength) + { + /* No, the buffer will only be large enough for a ULONG */ + DataSize = sizeof(ULONG); + } + else + { + /* Yes, save the data size */ + DataSize = *ControlVector->BufferLength; + } + + /* Get the actual data */ + ValueData = (PCM_KEY_VALUE)HvGetCell(SystemHive, ValueCell); + + /* Check if this is a small key */ + IsSmallKey = CmpIsKeyValueSmall(&Length, ValueData->DataLength); + + /* If the length is bigger then our buffer, normalize it */ + if (DataSize < Length) Length = DataSize; + + /* Make sure we have some data */ + if (Length > 0) + { + /* Check if this was a small key */ + if (IsSmallKey) + { + /* The buffer is directly safe to read */ + Buffer = (PVOID)(&(ValueData->Data)); + } + else + { + /* Use the longer path */ + Buffer = (PVOID)HvGetCell(SystemHive, ValueData->Data); + } + + /* Sanity check if this is a small key */ + ASSERT((IsSmallKey ? + (Length <= CM_KEY_VALUE_SMALL) : TRUE)); + + /* Copy the data in the buffer */ + RtlCopyMemory(ControlVector->Buffer, Buffer, Length); + } + + /* Check if we should return the data type */ + if (ControlVector->Type) + { + /* Return the type that we read */ + *ControlVector->Type = ValueData->Type; + } + } + } + + /* Return the size that we read */ + if (ControlVector->BufferLength) *ControlVector->BufferLength = Length; + + /* Go to the next entry */ + ControlVector++; + } + + /* Check if the ID is in the registry */ + if (CmDefaultLanguageIdType == REG_SZ) + { + /* Read it */ + PsDefaultSystemLocaleId = + (LCID)CmpConvertLangId(CmDefaultLanguageId, + CmDefaultLanguageIdLength); + } + else + { + /* Use EN_US by default */ + PsDefaultSystemLocaleId = 0x409; + } + + /* Check if the ID Is in the registry */ + if (CmInstallUILanguageIdType == REG_SZ) + { + /* Read it */ + PsInstallUILanguageId = CmpConvertLangId(CmInstallUILanguageId, + CmInstallUILanguageIdLength); + } + else + { + /* Otherwise, use the default */ + PsInstallUILanguageId = LANGIDFROMLCID(PsDefaultSystemLocaleId); + } + + /* Set the defaults for the Thread UI */ + PsDefaultThreadLocaleId = PsDefaultSystemLocaleId; + PsDefaultUILanguageId = PsInstallUILanguageId; +} diff --git a/reactos/ntoskrnl/config/cmdata.c b/reactos/ntoskrnl/config/cmdata.c index 45e532b8218..0a75c1678e6 100644 --- a/reactos/ntoskrnl/config/cmdata.c +++ b/reactos/ntoskrnl/config/cmdata.c @@ -1,821 +1,820 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/config/cmdata.c - * PURPOSE: Configuration Manager - Global Configuration Data - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include "ntoskrnl.h" -#include "cm.h" -#define NDEBUG -#include "debug.h" - -/* GLOBALS *******************************************************************/ - -ULONG DummyData; -ULONG CmNtGlobalFlag; -ULONG CmNtCSDVersion; - -WCHAR CmDefaultLanguageId[12]; -ULONG CmDefaultLanguageIdLength = sizeof(CmDefaultLanguageId); -ULONG CmDefaultLanguageIdType; - -WCHAR CmInstallUILanguageId[12]; -ULONG CmInstallUILanguageIdLength = sizeof(CmInstallUILanguageId); -ULONG CmInstallUILanguageIdType; - -WCHAR CmSuiteBuffer[128]; -ULONG CmSuiteBufferLength = sizeof(CmSuiteBuffer); -ULONG CmSuiteBufferType; - -CMHIVE CmControlHive; - -ULONG CmpConfigurationAreaSize = PAGE_SIZE * 4; -PCM_FULL_RESOURCE_DESCRIPTOR CmpConfigurationData; - -EX_PUSH_LOCK CmpHiveListHeadLock, CmpLoadHiveLock; - -HIVE_LIST_ENTRY CmpMachineHiveList[] = -{ - { L"HARDWARE", L"MACHINE\\", NULL, HIVE_VOLATILE , 0 , NULL, FALSE, FALSE, FALSE}, - { L"SECURITY", L"MACHINE\\", NULL, 0 , 0 , NULL, FALSE, FALSE, FALSE}, - { L"SOFTWARE", L"MACHINE\\", NULL, 0 , 0 , NULL, FALSE, FALSE, FALSE}, - { L"SYSTEM", L"MACHINE\\", NULL, 0 , 0 , NULL, FALSE, FALSE, FALSE}, - { L"DEFAULT", L"USER\\.DEFAULT", NULL, 0 , 0 , NULL, FALSE, FALSE, FALSE}, - { L"SAM", L"MACHINE\\", NULL, HIVE_NOLAZYFLUSH , 0 , NULL, FALSE, FALSE, FALSE}, - { NULL, NULL, 0, 0 , 0 , NULL, FALSE, FALSE, FALSE} -}; - -UNICODE_STRING CmSymbolicLinkValueName = - RTL_CONSTANT_STRING(L"SymbolicLinkValue"); - -UNICODE_STRING CmpLoadOptions; - -BOOLEAN CmpShareSystemHives; -BOOLEAN CmSelfHeal = TRUE; -BOOLEAN CmpSelfHeal = TRUE; -BOOLEAN CmpMiniNTBoot; -ULONG CmpBootType; - -USHORT CmpUnknownBusCount; -ULONG CmpTypeCount[MaximumType + 1]; - -HANDLE CmpRegistryRootHandle; - -UNICODE_STRING CmClassName[MaximumClass + 1] = -{ - RTL_CONSTANT_STRING(L"System"), - RTL_CONSTANT_STRING(L"Processor"), - RTL_CONSTANT_STRING(L"Cache"), - RTL_CONSTANT_STRING(L"Adapter"), - RTL_CONSTANT_STRING(L"Controller"), - RTL_CONSTANT_STRING(L"Peripheral"), - RTL_CONSTANT_STRING(L"MemoryClass"), - RTL_CONSTANT_STRING(L"Undefined") -}; - -UNICODE_STRING CmTypeName[MaximumType + 1] = -{ - RTL_CONSTANT_STRING(L"System"), - RTL_CONSTANT_STRING(L"CentralProcessor"), - RTL_CONSTANT_STRING(L"FloatingPointProcessor"), - RTL_CONSTANT_STRING(L"PrimaryICache"), - RTL_CONSTANT_STRING(L"PrimaryDCache"), - RTL_CONSTANT_STRING(L"SecondaryICache"), - RTL_CONSTANT_STRING(L"SecondaryDCache"), - RTL_CONSTANT_STRING(L"SecondaryCache"), - RTL_CONSTANT_STRING(L"EisaAdapter"), - RTL_CONSTANT_STRING(L"TcAdapter"), - RTL_CONSTANT_STRING(L"ScsiAdapter"), - RTL_CONSTANT_STRING(L"DtiAdapter"), - RTL_CONSTANT_STRING(L"MultifunctionAdapter"), - RTL_CONSTANT_STRING(L"DiskController"), - RTL_CONSTANT_STRING(L"TapeController"), - RTL_CONSTANT_STRING(L"CdRomController"), - RTL_CONSTANT_STRING(L"WormController"), - RTL_CONSTANT_STRING(L"SerialController"), - RTL_CONSTANT_STRING(L"NetworkController"), - RTL_CONSTANT_STRING(L"DisplayController"), - RTL_CONSTANT_STRING(L"ParallelController"), - RTL_CONSTANT_STRING(L"PointerController"), - RTL_CONSTANT_STRING(L"KeyboardController"), - RTL_CONSTANT_STRING(L"AudioController"), - RTL_CONSTANT_STRING(L"OtherController"), - RTL_CONSTANT_STRING(L"DiskPeripheral"), - RTL_CONSTANT_STRING(L"FloppyDiskPeripheral"), - RTL_CONSTANT_STRING(L"TapePeripheral"), - RTL_CONSTANT_STRING(L"ModemPeripheral"), - RTL_CONSTANT_STRING(L"MonitorPeripheral"), - RTL_CONSTANT_STRING(L"PrinterPeripheral"), - RTL_CONSTANT_STRING(L"PointerPeripheral"), - RTL_CONSTANT_STRING(L"KeyboardPeripheral"), - RTL_CONSTANT_STRING(L"TerminalPeripheral"), - RTL_CONSTANT_STRING(L"OtherPeripheral"), - RTL_CONSTANT_STRING(L"LinePeripheral"), - RTL_CONSTANT_STRING(L"NetworkPeripheral"), - RTL_CONSTANT_STRING(L"SystemMemory"), - RTL_CONSTANT_STRING(L"DockingInformation"), - RTL_CONSTANT_STRING(L"RealModeIrqRoutingTable"), - RTL_CONSTANT_STRING(L"RealModePCIEnumeration"), - RTL_CONSTANT_STRING(L"Undefined") -}; - -CMP_MF_TYPE CmpMultifunctionTypes[] = -{ - {L"ISA", Isa, 0}, - {L"MCA", MicroChannel, 0}, - {L"PCI", PCIBus, 0}, - {L"VME", VMEBus, 0}, - {L"PCMCIA", PCMCIABus, 0}, - {L"CBUS", CBus, 0}, - {L"MPIPI", MPIBus, 0}, - {L"MPSA", MPSABus, 0}, - {NULL, Internal, 0} -}; - -CM_SYSTEM_CONTROL_VECTOR CmControlVector[] = -{ - { - L"Session Manager", - L"ProtectionMode", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager", - L"ObjectSecurityMode", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager", - L"LUIDDeviceMapsDisabled", - &DummyData, - NULL, - NULL - }, - - { - L"LSA", - L"AuditBaseDirectories", - &DummyData, - NULL, - NULL - }, - - { - L"LSA", - L"AuditBaseObjects", - &DummyData, - NULL, - NULL - }, - - { - L"LSA\\audit", - L"ProcessAccessesToAudit", - &DummyData, - NULL, - NULL - }, - - { - L"TimeZoneInformation", - L"ActiveTimeBias", - &DummyData, - NULL, - NULL - }, - - { - L"TimeZoneInformation", - L"Bias", - &DummyData, - NULL, - NULL - }, - - { - L"TimeZoneInformation", - L"RealTimeIsUniversal", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager", - L"GlobalFlag", - &CmNtGlobalFlag, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"PagedPoolQuota", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"NonPagedPoolQuota", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"PagingFileQuota", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"AllocationPreference", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"DynamicMemory", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"Mirroring", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"Mirroring", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"SystemViewSize", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"SessionViewSize", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"SessionImageSize", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"SessionPoolSize", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"PoolUsageMaximum", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"MapAllocationFragment", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"PagedPoolSize", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"NonPagedPoolSize", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"NonPagedPoolMaximumPercent", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"LargeSystemCache", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"LargeStackSize", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"SystemPages", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"LowMemoryThreshold", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"HighMemoryThreshold", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"DisablePagingExecutive", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"ModifiedPageLife", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"SecondLevelDataCache", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"ClearPageFileAtShutdown", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"PoolTagSmallTableSize", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"PoolTagBigTableSize", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"PoolTag", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"PoolTagOverruns", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"SnapUnloads", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"ProtectNonPagedPool", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"TrackLockedPages", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"TrackPtes", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"VerifyDrivers", - &DummyData, - &DummyData, - &DummyData - }, - - { - L"Session Manager\\Memory Management", - L"VerifyDriverLevel", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"VerifyMode", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"LargePageMinimum", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"EnforceWriteProtection", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"MakeLowMemory", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Memory Management", - L"WriteWatch", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Executive", - L"AdditionalCriticalWorkerThreads", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Executive", - L"AdditionalDelayedWorkerThreads", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Executive", - L"PriorityQuantumMatrix", - &DummyData, - &DummyData, - NULL - }, - - { - L"Session Manager\\Kernel", - L"DpcQueueDepth", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Kernel", - L"MinimumDpcRate", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Kernel", - L"AdjustDpcThreshold", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Kernel", - L"IdealDpcRate", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\I/O System", - L"CountOperations", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\I/O System", - L"LargeIrpStackLocations", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\I/O System", - L"IoVerifierLevel", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager", - L"ResourceTimeoutCount", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager", - L"CriticalSectionTimeout", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager", - L"HeapSegmentReserve", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager", - L"HeapSegmentCommit", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager", - L"HeapDeCommitTotalFreeThreshold", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager", - L"HeapDeCommitFreeBlockThreshold", - &DummyData, - NULL, - NULL - }, - - { - L"ProductOptions", - L"ProductType", - &DummyData, - NULL, - NULL - }, - - { - L"Terminal Server", - L"TSEnabled", - &DummyData, - NULL, - NULL - }, - - { - L"Terminal Server", - L"TSAppCompat", - &DummyData, - NULL, - NULL - }, - - - { - L"ProductOptions", - L"ProductSuite", - CmSuiteBuffer, - &CmSuiteBufferLength, - &CmSuiteBufferType - }, - - { - L"Windows", - L"CSDVersion", - &CmNtCSDVersion, - NULL, - NULL - }, - - { - L"Nls\\Language", - L"Default", - CmDefaultLanguageId, - &CmDefaultLanguageIdLength, - &CmDefaultLanguageIdType - }, - - { - L"Nls\\Language", - L"InstallLanguage", - CmInstallUILanguageId, - &CmInstallUILanguageIdLength, - &CmInstallUILanguageIdType - }, - - { - L"\0\0", - L"RegistrySizeLimit", - &DummyData, - &DummyData, - &DummyData - }, - - { - L"Session Manager", - L"ForceNpxEmulation", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager", - L"PowerPolicySimulate", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager\\Executive", - L"MaxTimeSeparationBeforeCorrect", - &DummyData, - NULL, - NULL - }, - - { - L"Windows", - L"ShutdownTime", - &DummyData, - &DummyData, - NULL - }, - - { - L"PriorityControl", - L"Win32PrioritySeparation", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager", - L"EnableTimerWatchdog", - &DummyData, - NULL, - NULL - }, - - { - L"Session Manager", - L"Debugger Retries", - &DummyData, - NULL, - NULL - }, - - { - L"WMI", - L"MaxEventSize", - &DummyData, - NULL, - NULL - }, - - { - L"WMI\\Trace", - L"UsePerformanceClock", - &DummyData, - NULL, - NULL - }, - - { - L"WMI\\Trace", - L"TraceAlignment", - &DummyData, - NULL, - NULL - }, - - { - NULL, - NULL, - NULL, - NULL, - NULL - } -}; +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmdata.c + * PURPOSE: Configuration Manager - Global Configuration Data + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#define NDEBUG +#include "debug.h" + +/* GLOBALS *******************************************************************/ + +ULONG DummyData; +ULONG CmNtGlobalFlag; +ULONG CmNtCSDVersion; + +WCHAR CmDefaultLanguageId[12]; +ULONG CmDefaultLanguageIdLength = sizeof(CmDefaultLanguageId); +ULONG CmDefaultLanguageIdType; + +WCHAR CmInstallUILanguageId[12]; +ULONG CmInstallUILanguageIdLength = sizeof(CmInstallUILanguageId); +ULONG CmInstallUILanguageIdType; + +WCHAR CmSuiteBuffer[128]; +ULONG CmSuiteBufferLength = sizeof(CmSuiteBuffer); +ULONG CmSuiteBufferType; + +CMHIVE CmControlHive; + +ULONG CmpConfigurationAreaSize = PAGE_SIZE * 4; +PCM_FULL_RESOURCE_DESCRIPTOR CmpConfigurationData; + +EX_PUSH_LOCK CmpHiveListHeadLock, CmpLoadHiveLock; + +HIVE_LIST_ENTRY CmpMachineHiveList[] = +{ + { L"HARDWARE", L"MACHINE\\", NULL, HIVE_VOLATILE , 0 , NULL, FALSE, FALSE, FALSE}, + { L"SECURITY", L"MACHINE\\", NULL, 0 , 0 , NULL, FALSE, FALSE, FALSE}, + { L"SOFTWARE", L"MACHINE\\", NULL, 0 , 0 , NULL, FALSE, FALSE, FALSE}, + { L"SYSTEM", L"MACHINE\\", NULL, 0 , 0 , NULL, FALSE, FALSE, FALSE}, + { L"DEFAULT", L"USER\\.DEFAULT", NULL, 0 , 0 , NULL, FALSE, FALSE, FALSE}, + { L"SAM", L"MACHINE\\", NULL, HIVE_NOLAZYFLUSH , 0 , NULL, FALSE, FALSE, FALSE}, + { NULL, NULL, 0, 0 , 0 , NULL, FALSE, FALSE, FALSE} +}; + +UNICODE_STRING CmSymbolicLinkValueName = + RTL_CONSTANT_STRING(L"SymbolicLinkValue"); + +UNICODE_STRING CmpLoadOptions; + +BOOLEAN CmpShareSystemHives; +BOOLEAN CmSelfHeal = TRUE; +BOOLEAN CmpSelfHeal = TRUE; +BOOLEAN CmpMiniNTBoot; +ULONG CmpBootType; + +USHORT CmpUnknownBusCount; +ULONG CmpTypeCount[MaximumType + 1]; + +HANDLE CmpRegistryRootHandle; + +UNICODE_STRING CmClassName[MaximumClass + 1] = +{ + RTL_CONSTANT_STRING(L"System"), + RTL_CONSTANT_STRING(L"Processor"), + RTL_CONSTANT_STRING(L"Cache"), + RTL_CONSTANT_STRING(L"Adapter"), + RTL_CONSTANT_STRING(L"Controller"), + RTL_CONSTANT_STRING(L"Peripheral"), + RTL_CONSTANT_STRING(L"MemoryClass"), + RTL_CONSTANT_STRING(L"Undefined") +}; + +UNICODE_STRING CmTypeName[MaximumType + 1] = +{ + RTL_CONSTANT_STRING(L"System"), + RTL_CONSTANT_STRING(L"CentralProcessor"), + RTL_CONSTANT_STRING(L"FloatingPointProcessor"), + RTL_CONSTANT_STRING(L"PrimaryICache"), + RTL_CONSTANT_STRING(L"PrimaryDCache"), + RTL_CONSTANT_STRING(L"SecondaryICache"), + RTL_CONSTANT_STRING(L"SecondaryDCache"), + RTL_CONSTANT_STRING(L"SecondaryCache"), + RTL_CONSTANT_STRING(L"EisaAdapter"), + RTL_CONSTANT_STRING(L"TcAdapter"), + RTL_CONSTANT_STRING(L"ScsiAdapter"), + RTL_CONSTANT_STRING(L"DtiAdapter"), + RTL_CONSTANT_STRING(L"MultifunctionAdapter"), + RTL_CONSTANT_STRING(L"DiskController"), + RTL_CONSTANT_STRING(L"TapeController"), + RTL_CONSTANT_STRING(L"CdRomController"), + RTL_CONSTANT_STRING(L"WormController"), + RTL_CONSTANT_STRING(L"SerialController"), + RTL_CONSTANT_STRING(L"NetworkController"), + RTL_CONSTANT_STRING(L"DisplayController"), + RTL_CONSTANT_STRING(L"ParallelController"), + RTL_CONSTANT_STRING(L"PointerController"), + RTL_CONSTANT_STRING(L"KeyboardController"), + RTL_CONSTANT_STRING(L"AudioController"), + RTL_CONSTANT_STRING(L"OtherController"), + RTL_CONSTANT_STRING(L"DiskPeripheral"), + RTL_CONSTANT_STRING(L"FloppyDiskPeripheral"), + RTL_CONSTANT_STRING(L"TapePeripheral"), + RTL_CONSTANT_STRING(L"ModemPeripheral"), + RTL_CONSTANT_STRING(L"MonitorPeripheral"), + RTL_CONSTANT_STRING(L"PrinterPeripheral"), + RTL_CONSTANT_STRING(L"PointerPeripheral"), + RTL_CONSTANT_STRING(L"KeyboardPeripheral"), + RTL_CONSTANT_STRING(L"TerminalPeripheral"), + RTL_CONSTANT_STRING(L"OtherPeripheral"), + RTL_CONSTANT_STRING(L"LinePeripheral"), + RTL_CONSTANT_STRING(L"NetworkPeripheral"), + RTL_CONSTANT_STRING(L"SystemMemory"), + RTL_CONSTANT_STRING(L"DockingInformation"), + RTL_CONSTANT_STRING(L"RealModeIrqRoutingTable"), + RTL_CONSTANT_STRING(L"RealModePCIEnumeration"), + RTL_CONSTANT_STRING(L"Undefined") +}; + +CMP_MF_TYPE CmpMultifunctionTypes[] = +{ + {L"ISA", Isa, 0}, + {L"MCA", MicroChannel, 0}, + {L"PCI", PCIBus, 0}, + {L"VME", VMEBus, 0}, + {L"PCMCIA", PCMCIABus, 0}, + {L"CBUS", CBus, 0}, + {L"MPIPI", MPIBus, 0}, + {L"MPSA", MPSABus, 0}, + {NULL, Internal, 0} +}; + +CM_SYSTEM_CONTROL_VECTOR CmControlVector[] = +{ + { + L"Session Manager", + L"ProtectionMode", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager", + L"ObjectSecurityMode", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager", + L"LUIDDeviceMapsDisabled", + &DummyData, + NULL, + NULL + }, + + { + L"LSA", + L"AuditBaseDirectories", + &DummyData, + NULL, + NULL + }, + + { + L"LSA", + L"AuditBaseObjects", + &DummyData, + NULL, + NULL + }, + + { + L"LSA\\audit", + L"ProcessAccessesToAudit", + &DummyData, + NULL, + NULL + }, + + { + L"TimeZoneInformation", + L"ActiveTimeBias", + &DummyData, + NULL, + NULL + }, + + { + L"TimeZoneInformation", + L"Bias", + &DummyData, + NULL, + NULL + }, + + { + L"TimeZoneInformation", + L"RealTimeIsUniversal", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager", + L"GlobalFlag", + &CmNtGlobalFlag, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"PagedPoolQuota", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"NonPagedPoolQuota", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"PagingFileQuota", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"AllocationPreference", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"DynamicMemory", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"Mirroring", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"Mirroring", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"SystemViewSize", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"SessionViewSize", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"SessionImageSize", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"SessionPoolSize", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"PoolUsageMaximum", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"MapAllocationFragment", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"PagedPoolSize", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"NonPagedPoolSize", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"NonPagedPoolMaximumPercent", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"LargeSystemCache", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"LargeStackSize", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"SystemPages", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"LowMemoryThreshold", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"HighMemoryThreshold", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"DisablePagingExecutive", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"ModifiedPageLife", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"SecondLevelDataCache", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"ClearPageFileAtShutdown", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"PoolTagSmallTableSize", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"PoolTagBigTableSize", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"PoolTag", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"PoolTagOverruns", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"SnapUnloads", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"ProtectNonPagedPool", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"TrackLockedPages", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"TrackPtes", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"VerifyDrivers", + &DummyData, + &DummyData, + &DummyData + }, + + { + L"Session Manager\\Memory Management", + L"VerifyDriverLevel", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"VerifyMode", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"LargePageMinimum", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"EnforceWriteProtection", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"MakeLowMemory", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"WriteWatch", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Executive", + L"AdditionalCriticalWorkerThreads", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Executive", + L"AdditionalDelayedWorkerThreads", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Executive", + L"PriorityQuantumMatrix", + &DummyData, + &DummyData, + NULL + }, + + { + L"Session Manager\\Kernel", + L"DpcQueueDepth", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Kernel", + L"MinimumDpcRate", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Kernel", + L"AdjustDpcThreshold", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Kernel", + L"IdealDpcRate", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\I/O System", + L"CountOperations", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\I/O System", + L"LargeIrpStackLocations", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\I/O System", + L"IoVerifierLevel", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager", + L"ResourceTimeoutCount", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager", + L"CriticalSectionTimeout", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager", + L"HeapSegmentReserve", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager", + L"HeapSegmentCommit", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager", + L"HeapDeCommitTotalFreeThreshold", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager", + L"HeapDeCommitFreeBlockThreshold", + &DummyData, + NULL, + NULL + }, + + { + L"ProductOptions", + L"ProductType", + &DummyData, + NULL, + NULL + }, + + { + L"Terminal Server", + L"TSEnabled", + &DummyData, + NULL, + NULL + }, + + { + L"Terminal Server", + L"TSAppCompat", + &DummyData, + NULL, + NULL + }, + + + { + L"ProductOptions", + L"ProductSuite", + CmSuiteBuffer, + &CmSuiteBufferLength, + &CmSuiteBufferType + }, + + { + L"Windows", + L"CSDVersion", + &CmNtCSDVersion, + NULL, + NULL + }, + + { + L"Nls\\Language", + L"Default", + CmDefaultLanguageId, + &CmDefaultLanguageIdLength, + &CmDefaultLanguageIdType + }, + + { + L"Nls\\Language", + L"InstallLanguage", + CmInstallUILanguageId, + &CmInstallUILanguageIdLength, + &CmInstallUILanguageIdType + }, + + { + L"\0\0", + L"RegistrySizeLimit", + &DummyData, + &DummyData, + &DummyData + }, + + { + L"Session Manager", + L"ForceNpxEmulation", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager", + L"PowerPolicySimulate", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Executive", + L"MaxTimeSeparationBeforeCorrect", + &DummyData, + NULL, + NULL + }, + + { + L"Windows", + L"ShutdownTime", + &DummyData, + &DummyData, + NULL + }, + + { + L"PriorityControl", + L"Win32PrioritySeparation", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager", + L"EnableTimerWatchdog", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager", + L"Debugger Retries", + &DummyData, + NULL, + NULL + }, + + { + L"WMI", + L"MaxEventSize", + &DummyData, + NULL, + NULL + }, + + { + L"WMI\\Trace", + L"UsePerformanceClock", + &DummyData, + NULL, + NULL + }, + + { + L"WMI\\Trace", + L"TraceAlignment", + &DummyData, + NULL, + NULL + }, + + { + NULL, + NULL, + NULL, + NULL, + NULL + } +}; diff --git a/reactos/ntoskrnl/config/cmdelay.c b/reactos/ntoskrnl/config/cmdelay.c index 0274343bda1..ea821650e1d 100644 --- a/reactos/ntoskrnl/config/cmdelay.c +++ b/reactos/ntoskrnl/config/cmdelay.c @@ -11,7 +11,6 @@ #include #define NDEBUG #include -#include "cm.h" /* GLOBALS *******************************************************************/ diff --git a/reactos/ntoskrnl/config/cmhook.c b/reactos/ntoskrnl/config/cmhook.c index 218a189ed1e..bab02fec22f 100644 --- a/reactos/ntoskrnl/config/cmhook.c +++ b/reactos/ntoskrnl/config/cmhook.c @@ -1,198 +1,197 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/config/cmhook.c - * PURPOSE: Configuration Manager - Registry Notifications/Callbacks - * PROGRAMMERS: Thomas Weidenmueller (w3seek@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include "ntoskrnl.h" -#include "cm.h" -#define NDEBUG -#include "debug.h" - -/* GLOBALS *******************************************************************/ - -ULONG CmpCallBackCount = 0; -EX_CALLBACK CmpCallBackVector[100]; - -LIST_ENTRY CmiCallbackHead; -FAST_MUTEX CmiCallbackLock; - -typedef struct _REGISTRY_CALLBACK -{ - LIST_ENTRY ListEntry; - EX_RUNDOWN_REF RundownRef; - PEX_CALLBACK_FUNCTION Function; - PVOID Context; - LARGE_INTEGER Cookie; - BOOLEAN PendingDelete; -} REGISTRY_CALLBACK, *PREGISTRY_CALLBACK; - -/* PRIVATE FUNCTIONS *********************************************************/ - -VOID -NTAPI -CmpInitCallback(VOID) -{ - ULONG i; - PAGED_CODE(); - - /* Reset counter */ - CmpCallBackCount = 0; - - /* Loop all the callbacks */ - for (i = 0; i < CMP_MAX_CALLBACKS; i++) - { - /* Initialize this one */ - ExInitializeCallBack(&CmpCallBackVector[i]); - } - - /* ROS: Initialize old-style callbacks for now */ - InitializeListHead(&CmiCallbackHead); - ExInitializeFastMutex(&CmiCallbackLock); -} - -NTSTATUS -CmiCallRegisteredCallbacks(IN REG_NOTIFY_CLASS Argument1, - IN PVOID Argument2) -{ - PLIST_ENTRY CurrentEntry; - NTSTATUS Status = STATUS_SUCCESS; - PREGISTRY_CALLBACK CurrentCallback; - PAGED_CODE(); - - ExAcquireFastMutex(&CmiCallbackLock); - - for (CurrentEntry = CmiCallbackHead.Flink; - CurrentEntry != &CmiCallbackHead; - CurrentEntry = CurrentEntry->Flink) - { - CurrentCallback = CONTAINING_RECORD(CurrentEntry, REGISTRY_CALLBACK, ListEntry); - if (!CurrentCallback->PendingDelete && - ExAcquireRundownProtection(&CurrentCallback->RundownRef)) - { - /* don't hold locks during the callbacks! */ - ExReleaseFastMutex(&CmiCallbackLock); - - Status = CurrentCallback->Function(CurrentCallback->Context, - (PVOID)Argument1, - Argument2); - - ExAcquireFastMutex(&CmiCallbackLock); - - /* don't release the rundown protection before holding the callback lock - so the pointer to the next callback isn't cleared in case this callback - get's deleted */ - ExReleaseRundownProtection(&CurrentCallback->RundownRef); - if(!NT_SUCCESS(Status)) - { - /* one callback returned failure, don't call any more callbacks */ - break; - } - } - } - - ExReleaseFastMutex(&CmiCallbackLock); - - return Status; -} - -/* PUBLIC FUNCTIONS **********************************************************/ - -/* - * @implemented - */ -NTSTATUS -NTAPI -CmRegisterCallback(IN PEX_CALLBACK_FUNCTION Function, - IN PVOID Context, - IN OUT PLARGE_INTEGER Cookie) -{ - PREGISTRY_CALLBACK Callback; - PAGED_CODE(); - ASSERT(Function && Cookie); - - Callback = ExAllocatePoolWithTag(PagedPool, - sizeof(REGISTRY_CALLBACK), - TAG('C', 'M', 'c', 'b')); - if (Callback != NULL) - { - /* initialize the callback */ - ExInitializeRundownProtection(&Callback->RundownRef); - Callback->Function = Function; - Callback->Context = Context; - Callback->PendingDelete = FALSE; - - /* add it to the callback list and receive a cookie for the callback */ - ExAcquireFastMutex(&CmiCallbackLock); - - /* FIXME - to receive a unique cookie we'll just return the pointer to the - callback object */ - Callback->Cookie.QuadPart = (ULONG_PTR)Callback; - InsertTailList(&CmiCallbackHead, &Callback->ListEntry); - - ExReleaseFastMutex(&CmiCallbackLock); - - *Cookie = Callback->Cookie; - return STATUS_SUCCESS; - } - - return STATUS_INSUFFICIENT_RESOURCES; -} - -/* - * @implemented - */ -NTSTATUS -NTAPI -CmUnRegisterCallback(IN LARGE_INTEGER Cookie) -{ - PLIST_ENTRY CurrentEntry; - PREGISTRY_CALLBACK CurrentCallback; - PAGED_CODE(); - - ExAcquireFastMutex(&CmiCallbackLock); - - for (CurrentEntry = CmiCallbackHead.Flink; - CurrentEntry != &CmiCallbackHead; - CurrentEntry = CurrentEntry->Flink) - { - CurrentCallback = CONTAINING_RECORD(CurrentEntry, REGISTRY_CALLBACK, ListEntry); - if (CurrentCallback->Cookie.QuadPart == Cookie.QuadPart) - { - if (!CurrentCallback->PendingDelete) - { - /* found the callback, don't unlink it from the list yet so we don't screw - the calling loop */ - CurrentCallback->PendingDelete = TRUE; - ExReleaseFastMutex(&CmiCallbackLock); - - /* if the callback is currently executing, wait until it finished */ - ExWaitForRundownProtectionRelease(&CurrentCallback->RundownRef); - - /* time to unlink it. It's now safe because every attempt to acquire a - runtime protection on this callback will fail */ - ExAcquireFastMutex(&CmiCallbackLock); - RemoveEntryList(&CurrentCallback->ListEntry); - ExReleaseFastMutex(&CmiCallbackLock); - - /* free the callback */ - ExFreePool(CurrentCallback); - return STATUS_SUCCESS; - } - else - { - /* pending delete, pretend like it already is deleted */ - ExReleaseFastMutex(&CmiCallbackLock); - return STATUS_UNSUCCESSFUL; - } - } - } - - ExReleaseFastMutex(&CmiCallbackLock); - - return STATUS_UNSUCCESSFUL; -} +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmhook.c + * PURPOSE: Configuration Manager - Registry Notifications/Callbacks + * PROGRAMMERS: Thomas Weidenmueller (w3seek@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#define NDEBUG +#include "debug.h" + +/* GLOBALS *******************************************************************/ + +ULONG CmpCallBackCount = 0; +EX_CALLBACK CmpCallBackVector[100]; + +LIST_ENTRY CmiCallbackHead; +FAST_MUTEX CmiCallbackLock; + +typedef struct _REGISTRY_CALLBACK +{ + LIST_ENTRY ListEntry; + EX_RUNDOWN_REF RundownRef; + PEX_CALLBACK_FUNCTION Function; + PVOID Context; + LARGE_INTEGER Cookie; + BOOLEAN PendingDelete; +} REGISTRY_CALLBACK, *PREGISTRY_CALLBACK; + +/* PRIVATE FUNCTIONS *********************************************************/ + +VOID +NTAPI +CmpInitCallback(VOID) +{ + ULONG i; + PAGED_CODE(); + + /* Reset counter */ + CmpCallBackCount = 0; + + /* Loop all the callbacks */ + for (i = 0; i < CMP_MAX_CALLBACKS; i++) + { + /* Initialize this one */ + ExInitializeCallBack(&CmpCallBackVector[i]); + } + + /* ROS: Initialize old-style callbacks for now */ + InitializeListHead(&CmiCallbackHead); + ExInitializeFastMutex(&CmiCallbackLock); +} + +NTSTATUS +CmiCallRegisteredCallbacks(IN REG_NOTIFY_CLASS Argument1, + IN PVOID Argument2) +{ + PLIST_ENTRY CurrentEntry; + NTSTATUS Status = STATUS_SUCCESS; + PREGISTRY_CALLBACK CurrentCallback; + PAGED_CODE(); + + ExAcquireFastMutex(&CmiCallbackLock); + + for (CurrentEntry = CmiCallbackHead.Flink; + CurrentEntry != &CmiCallbackHead; + CurrentEntry = CurrentEntry->Flink) + { + CurrentCallback = CONTAINING_RECORD(CurrentEntry, REGISTRY_CALLBACK, ListEntry); + if (!CurrentCallback->PendingDelete && + ExAcquireRundownProtection(&CurrentCallback->RundownRef)) + { + /* don't hold locks during the callbacks! */ + ExReleaseFastMutex(&CmiCallbackLock); + + Status = CurrentCallback->Function(CurrentCallback->Context, + (PVOID)Argument1, + Argument2); + + ExAcquireFastMutex(&CmiCallbackLock); + + /* don't release the rundown protection before holding the callback lock + so the pointer to the next callback isn't cleared in case this callback + get's deleted */ + ExReleaseRundownProtection(&CurrentCallback->RundownRef); + if(!NT_SUCCESS(Status)) + { + /* one callback returned failure, don't call any more callbacks */ + break; + } + } + } + + ExReleaseFastMutex(&CmiCallbackLock); + + return Status; +} + +/* PUBLIC FUNCTIONS **********************************************************/ + +/* + * @implemented + */ +NTSTATUS +NTAPI +CmRegisterCallback(IN PEX_CALLBACK_FUNCTION Function, + IN PVOID Context, + IN OUT PLARGE_INTEGER Cookie) +{ + PREGISTRY_CALLBACK Callback; + PAGED_CODE(); + ASSERT(Function && Cookie); + + Callback = ExAllocatePoolWithTag(PagedPool, + sizeof(REGISTRY_CALLBACK), + TAG('C', 'M', 'c', 'b')); + if (Callback != NULL) + { + /* initialize the callback */ + ExInitializeRundownProtection(&Callback->RundownRef); + Callback->Function = Function; + Callback->Context = Context; + Callback->PendingDelete = FALSE; + + /* add it to the callback list and receive a cookie for the callback */ + ExAcquireFastMutex(&CmiCallbackLock); + + /* FIXME - to receive a unique cookie we'll just return the pointer to the + callback object */ + Callback->Cookie.QuadPart = (ULONG_PTR)Callback; + InsertTailList(&CmiCallbackHead, &Callback->ListEntry); + + ExReleaseFastMutex(&CmiCallbackLock); + + *Cookie = Callback->Cookie; + return STATUS_SUCCESS; + } + + return STATUS_INSUFFICIENT_RESOURCES; +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +CmUnRegisterCallback(IN LARGE_INTEGER Cookie) +{ + PLIST_ENTRY CurrentEntry; + PREGISTRY_CALLBACK CurrentCallback; + PAGED_CODE(); + + ExAcquireFastMutex(&CmiCallbackLock); + + for (CurrentEntry = CmiCallbackHead.Flink; + CurrentEntry != &CmiCallbackHead; + CurrentEntry = CurrentEntry->Flink) + { + CurrentCallback = CONTAINING_RECORD(CurrentEntry, REGISTRY_CALLBACK, ListEntry); + if (CurrentCallback->Cookie.QuadPart == Cookie.QuadPart) + { + if (!CurrentCallback->PendingDelete) + { + /* found the callback, don't unlink it from the list yet so we don't screw + the calling loop */ + CurrentCallback->PendingDelete = TRUE; + ExReleaseFastMutex(&CmiCallbackLock); + + /* if the callback is currently executing, wait until it finished */ + ExWaitForRundownProtectionRelease(&CurrentCallback->RundownRef); + + /* time to unlink it. It's now safe because every attempt to acquire a + runtime protection on this callback will fail */ + ExAcquireFastMutex(&CmiCallbackLock); + RemoveEntryList(&CurrentCallback->ListEntry); + ExReleaseFastMutex(&CmiCallbackLock); + + /* free the callback */ + ExFreePool(CurrentCallback); + return STATUS_SUCCESS; + } + else + { + /* pending delete, pretend like it already is deleted */ + ExReleaseFastMutex(&CmiCallbackLock); + return STATUS_UNSUCCESSFUL; + } + } + } + + ExReleaseFastMutex(&CmiCallbackLock); + + return STATUS_UNSUCCESSFUL; +} diff --git a/reactos/ntoskrnl/config/cmindex.c b/reactos/ntoskrnl/config/cmindex.c index 37800392c38..dfb9b6ca27a 100644 --- a/reactos/ntoskrnl/config/cmindex.c +++ b/reactos/ntoskrnl/config/cmindex.c @@ -1,1527 +1,1526 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/config/cmindex.c - * PURPOSE: Configuration Manager - Cell Indexes - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include "ntoskrnl.h" -#include "cm.h" -#define NDEBUG -#include "debug.h" - -/* GLOBALS *******************************************************************/ - -ULONG CmpMaxFastIndexPerHblock = - (HBLOCK_SIZE - (sizeof(HBIN) + - sizeof(HCELL) + - FIELD_OFFSET(CM_KEY_FAST_INDEX, List))) / sizeof(CM_INDEX); - -ULONG CmpMaxIndexPerHblock = - (HBLOCK_SIZE - (sizeof(HBIN) + - sizeof(HCELL) + - FIELD_OFFSET(CM_KEY_INDEX, List))) / sizeof(HCELL_INDEX) - 1; - -/* FUNCTIONS *****************************************************************/ - -LONG -NTAPI -CmpDoCompareKeyName(IN PHHIVE Hive, - IN PCUNICODE_STRING SearchName, - IN HCELL_INDEX Cell) -{ - PCM_KEY_NODE Node; - UNICODE_STRING KeyName; - LONG Result; - - /* Get the node */ - Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell); - if (!Node) return 2; - - /* Check if it's compressed */ - if (Node->Flags & KEY_COMP_NAME) - { - /* Compare compressed names */ - Result = CmpCompareCompressedName(SearchName, - Node->Name, - Node->NameLength); - } - else - { - /* Compare the Unicode name directly */ - KeyName.Buffer = Node->Name; - KeyName.Length = Node->NameLength; - KeyName.MaximumLength = KeyName.Length; - Result = RtlCompareUnicodeString(SearchName, &KeyName, TRUE); - } - - /* Release the cell and return the normalized result */ - HvReleaseCell(Hive, Cell); - return (Result == 0) ? Result : ((Result > 0) ? 1 : -1); -} - -LONG -NTAPI -CmpCompareInIndex(IN PHHIVE Hive, - IN PCUNICODE_STRING SearchName, - IN ULONG Count, - IN PCM_KEY_INDEX Index, - IN PHCELL_INDEX SubKey) -{ - PCM_KEY_FAST_INDEX FastIndex; - PCM_INDEX FastEntry; - LONG Result; - ULONG i; - ULONG ActualNameLength = 4, CompareLength, NameLength; - WCHAR p, pp; - - /* Assume failure */ - *SubKey = HCELL_NIL; - - /* Check if we are a fast or hashed leaf */ - if ((Index->Signature == CM_KEY_FAST_LEAF) || - (Index->Signature == CM_KEY_HASH_LEAF)) - { - /* Get the Fast/Hash Index */ - FastIndex = (PCM_KEY_FAST_INDEX)Index; - FastEntry = &FastIndex->List[Count]; - - /* Check if we are a hash leaf, in which case we skip all this */ - if (Index->Signature == CM_KEY_FAST_LEAF) - { - /* Find out just how much of the name is there */ - for (i = 0; i < 4; i++) - { - /* Check if this entry is empty */ - if (!FastEntry->NameHint[i]) - { - /* Only this much! */ - ActualNameLength = i; - break; - } - } - - /* How large is the name and how many characters to compare */ - NameLength = SearchName->Length / sizeof(WCHAR); - CompareLength = min(NameLength, ActualNameLength); - - /* Loop all the chars we'll test */ - for (i = 0; i < CompareLength; i++) - { - /* Get one char from each buffer */ - p = SearchName->Buffer[i]; - pp = FastEntry->NameHint[i]; - - /* See if they match and return result if they don't */ - Result = (LONG)RtlUpcaseUnicodeChar(p) - - (LONG)RtlUpcaseUnicodeChar(pp); - if (Result) return (Result > 0) ? 1 : -1; - } - } - - /* If we got here then we have to do a full compare */ - Result = CmpDoCompareKeyName(Hive, SearchName, FastEntry->Cell); - if (Result == 2) return Result; - if (!Result) *SubKey = FastEntry->Cell; - } - else - { - /* We aren't, so do a name compare and return the subkey found */ - Result = CmpDoCompareKeyName(Hive, SearchName, Index->List[Count]); - if (Result == 2) return Result; - if (!Result) *SubKey = Index->List[Count]; - } - - /* Return the comparison result */ - return Result; -} - -ULONG -NTAPI -CmpFindSubKeyInRoot(IN PHHIVE Hive, - IN PCM_KEY_INDEX Index, - IN PCUNICODE_STRING SearchName, - IN PHCELL_INDEX SubKey) -{ - ULONG High, Low = 0, i, ReturnIndex; - HCELL_INDEX LeafCell; - PCM_KEY_INDEX Leaf; - LONG Result; - - /* Verify Index for validity */ - ASSERTMSG("We don't do a linear search yet!\n", FALSE); - ASSERT(Index->Count != 0); - ASSERT(Index->Signature == CM_KEY_INDEX_ROOT); - - /* Set high limit and loop */ - High = Index->Count - 1; - while (TRUE) - { - /* Choose next entry */ - i = ((High - Low) / 2) + Low; - - /* Get the leaf cell and then the leaf itself */ - LeafCell = Index->List[i]; - Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); - if (Leaf) - { - /* Make sure the leaf is valid */ - ASSERT((Leaf->Signature == CM_KEY_INDEX_LEAF) || - (Leaf->Signature == CM_KEY_FAST_LEAF) || - (Leaf->Signature == CM_KEY_HASH_LEAF)); - ASSERT(Leaf->Count != 0); - - /* Do the compare */ - Result = CmpCompareInIndex(Hive, - SearchName, - Leaf->Count - 1, - Leaf, - SubKey); - if (Result == 2) goto Big; - - /* Check if we found the leaf */ - if (!Result) - { - /* We found the leaf */ - *SubKey = LeafCell; - ReturnIndex = i; - goto Return; - } - - /* Check for negative result */ - if (Result < 0) - { - /* If we got here, we should be at -1 */ - ASSERT(Result == -1); - - /* Do another lookup, since we might still be in the right leaf */ - Result = CmpCompareInIndex(Hive, - SearchName, - 0, - Leaf, - SubKey); - if (Result == 2) goto Big; - - /* Check if it's not below */ - if (Result >= 0) - { - /* - * If the name was first below, and now it is above, - * then this means that it is somewhere in this leaf. - * Make sure we didn't get some weird result - */ - ASSERT((Result == 1) || (Result == 0)); - - /* Return it */ - *SubKey = LeafCell; - ReturnIndex = Low; - goto Return; - } - - /* Update the limit to this index, since we know it's not higher. */ - High = i; - } - else - { - /* Update the base to this index, since we know it's not lower. */ - Low = i; - } - } - else - { -Big: - /* This was some sort of special key */ - ReturnIndex = 0x80000000; - goto ReturnFailure; - } - - /* Check if there is only one entry left */ - if ((High - Low) <= 1) break; - - /* Release the leaf cell */ - HvReleaseCell(Hive, LeafCell); - } - - /* Make sure we got here for the right reasons */ - ASSERT((High - Low == 1) || (High == Low)); - - /* Get the leaf cell and the leaf */ - LeafCell = Index->List[Low]; - Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); - if (!Leaf) goto Big; - - /* Do the compare */ - Result = CmpCompareInIndex(Hive, - SearchName, - Leaf->Count-1, - Leaf, - SubKey); - if (Result == 2) goto Big; - - /* Check if we found it */ - if (!Result) - { - /* We got lucky...return it */ - *SubKey = LeafCell; - ReturnIndex = Low; - goto Return; - } - - /* It's below, so could still be in this leaf */ - if (Result < 0) - { - /* Make sure we're -1 */ - ASSERT(Result == -1); - - /* Do a search from the bottom */ - Result = CmpCompareInIndex(Hive, SearchName, 0, Leaf, SubKey); - if (Result == 2) goto Big; - - /* - * Check if it's above, which means that it's within the ranges of our - * leaf (since we were below before). - */ - if (Result >= 0) - { - /* Sanity check */ - ASSERT((Result == 1) || (Result == 0)); - - /* Yep, so we're in the right leaf; return it. */ - *SubKey = LeafCell; - ReturnIndex = Low; - goto Return; - } - - /* It's still below us, so fail */ - ReturnIndex = Low; - goto ReturnFailure; - } - - /* Release the leaf cell */ - HvReleaseCell(Hive, LeafCell); - - /* Well the low didn't work too well, so try the high. */ - LeafCell = Index->List[High]; - Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); - if (!Leaf) goto Big; - - /* Do the compare */ - Result = CmpCompareInIndex(Hive, - SearchName, - Leaf->Count - 1, - Leaf, - SubKey); - if (Result == 2) goto Big; - - /* Check if we found it */ - if (Result == 0) - { - /* We got lucky... return it */ - *SubKey = LeafCell; - ReturnIndex = High; - goto Return; - } - - /* Check if we are too high */ - if (Result < 0) - { - /* Make sure we're -1 */ - ASSERT(Result == -1); - - /* - * Once again... since we were first too low and now too high, then - * this means we are within the range of this leaf... return it. - */ - *SubKey = LeafCell; - ReturnIndex = High; - goto Return; - } - - /* If we got here, then we are too low, again. */ - ReturnIndex = High; - - /* Failure path */ -ReturnFailure: - *SubKey = HCELL_NIL; - - /* Return path...check if we have a leaf to free */ -Return: - if (Leaf) HvReleaseCell(Hive, LeafCell); - - /* Return the index */ - return ReturnIndex; -} - -ULONG -NTAPI -CmpFindSubKeyInLeaf(IN PHHIVE Hive, - IN PCM_KEY_INDEX Index, - IN PCUNICODE_STRING SearchName, - IN PHCELL_INDEX SubKey) -{ - ULONG High, Low = 0, i; - LONG Result; - - /* Verify Index for validity */ - ASSERT((Index->Signature == CM_KEY_INDEX_LEAF) || - (Index->Signature == CM_KEY_FAST_LEAF) || - (Index->Signature == CM_KEY_HASH_LEAF)); - - /* Get the upper bound and middle entry */ - High = Index->Count - 1; -#ifdef SOMEONE_WAS_NICE_ENOUGH_TO_MAKE_OUR_CELLS_LEXICALLY_SORTED - i = High / 2; -#else - i = 0; -#endif - - /* Check if we don't actually have any entries */ - if (!Index->Count) - { - /* Return failure */ - *SubKey = HCELL_NIL; - return 0; - } - - /* Start compare loop */ - while (TRUE) - { - /* Do the actual comparison and check the result */ - Result = CmpCompareInIndex(Hive, SearchName, i, Index, SubKey); - if (Result == 2) - { - /* Fail with special value */ - *SubKey = HCELL_NIL; - return 0x80000000; - } - - /* Check if we got lucky and found it */ - if (!Result) return i; - -#ifdef SOMEONE_WAS_NICE_ENOUGH_TO_MAKE_OUR_CELLS_LEXICALLY_SORTED - /* Check if the result is below us */ - if (Result < 0) - { - /* Set the new bound; it can't be higher then where we are now. */ - ASSERT(Result == -1); - High = i; - } - else - { - /* Set the new bound... it can't be lower then where we are now. */ - ASSERT(Result == 1); - Low = i; - } - - /* Check if this is the last entry, if so, break out and handle it */ - if ((High - Low) <= 1) break; - - /* Set the new index */ - i = ((High - Low) / 2) + Low; -#else - if (++i > High) - { - /* Return failure */ - *SubKey = HCELL_NIL; - return 0; - } -#endif - } - - /* - * If we get here, High - Low = 1 or High == Low - * Simply look first at Low, then at High - */ - Result = CmpCompareInIndex(Hive, SearchName, Low, Index, SubKey); - if (Result == 2) - { - /* Fail with special value */ - *SubKey = HCELL_NIL; - return 0x80000000; - } - - /* Check if we got lucky and found it */ - if (!Result) return Low; - - /* Check if the result is below us */ - if (Result < 0) - { - /* Return the low entry */ - ASSERT(Result == -1); - return Low; - } - - /* - * If we got here, then just check the high and return it no matter what - * the result is (since we're a leaf, it has to be near there anyway). - */ - Result = CmpCompareInIndex(Hive, SearchName, High, Index, SubKey); - if (Result == 2) - { - /* Fail with special value */ - *SubKey = HCELL_NIL; - return 0x80000000; - } - - /* Return the high */ - return High; -} - -ULONG -NTAPI -CmpComputeHashKey(IN ULONG Hash, - IN PCUNICODE_STRING Name, - IN BOOLEAN AllowSeparators) -{ - LPWSTR Cp; - ULONG Value, i; - - /* Make some sanity checks on our parameters */ - ASSERT((Name->Length == 0) || - (AllowSeparators) || - (Name->Buffer[0] != OBJ_NAME_PATH_SEPARATOR)); - - /* If the name is empty, there is nothing to hash! */ - if (!Name->Length) return Hash; - - /* Set the buffer and loop every character */ - Cp = Name->Buffer; - for (i = 0; i < Name->Length; i += sizeof(WCHAR), Cp++) - { - /* Make sure we don't have a separator when we shouldn't */ - ASSERT(AllowSeparators || (*Cp != OBJ_NAME_PATH_SEPARATOR)); - - /* Check what kind of char we have */ - if (*Cp >= L'a') - { - /* In the lower case region... is it truly lower case? */ - if (*Cp < L'z') - { - /* Yes! Calculate it ourselves! */ - Value = *Cp - L'a' + L'A'; - } - else - { - /* No, use the API */ - Value = RtlUpcaseUnicodeChar(*Cp); - } - } - else - { - /* Reuse the char, it's already upcased */ - Value = *Cp; - } - - /* Multiply by a prime and add our value */ - Hash *= 37; - Hash += Value; - } - - /* Return the hash */ - return Hash; -} - -HCELL_INDEX -NTAPI -CmpDoFindSubKeyByNumber(IN PHHIVE Hive, - IN PCM_KEY_INDEX Index, - IN ULONG Number) -{ - ULONG i; - HCELL_INDEX LeafCell = 0; - PCM_KEY_INDEX Leaf = NULL; - PCM_KEY_FAST_INDEX FastIndex; - HCELL_INDEX Result; - - /* Check if this is a root */ - if (Index->Signature == CM_KEY_INDEX_ROOT) - { - /* Loop the index */ - for (i = 0; i < Index->Count; i++) - { - /* Check if this isn't the first iteration */ - if (i) - { - /* Make sure we had something valid, and release it */ - ASSERT(Leaf != NULL ); - ASSERT(LeafCell == Index->List[i - 1]); - HvReleaseCell(Hive, LeafCell); - } - - /* Get the leaf cell and the leaf for this index */ - LeafCell = Index->List[i]; - Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); - if (!Leaf) return HCELL_NIL; - - /* Check if the index may be inside it */ - if (Number < Leaf->Count) - { - /* Check if this is a fast or hash leaf */ - if ((Leaf->Signature == CM_KEY_FAST_LEAF) || - (Leaf->Signature == CM_KEY_HASH_LEAF)) - { - /* Get the fast index */ - FastIndex = (PCM_KEY_FAST_INDEX)Leaf; - - /* Look inside the list to get our actual cell */ - Result = FastIndex->List[Number].Cell; - HvReleaseCell(Hive, LeafCell); - return Result; - } - else - { - /* Regular leaf, so just use the index directly */ - Result = Leaf->List[Number]; - - /* Release and return it */ - HvReleaseCell(Hive,LeafCell); - return Result; - } - } - else - { - /* Otherwise, skip this leaf */ - Number = Number - Leaf->Count; - } - } - - /* Should never get here */ - ASSERT(FALSE); - } - - /* If we got here, then the cell is in this index */ - ASSERT(Number < Index->Count); - - /* Check if we're a fast or hash leaf */ - if ((Index->Signature == CM_KEY_FAST_LEAF) || - (Index->Signature == CM_KEY_HASH_LEAF)) - { - /* We are, get the fast index and get the cell from the list */ - FastIndex = (PCM_KEY_FAST_INDEX)Index; - return FastIndex->List[Number].Cell; - } - else - { - /* We aren't, so use the index directly to grab the cell */ - return Index->List[Number]; - } -} - -HCELL_INDEX -NTAPI -CmpFindSubKeyByNumber(IN PHHIVE Hive, - IN PCM_KEY_NODE Node, - IN ULONG Number) -{ - PCM_KEY_INDEX Index; - HCELL_INDEX Result = HCELL_NIL; - - /* Check if it's in the stable list */ - if (Number < Node->SubKeyCounts[Stable]) - { - /* Get the actual key index */ - Index = (PCM_KEY_INDEX)HvGetCell(Hive, Node->SubKeyLists[Stable]); - if (!Index) return HCELL_NIL; - - /* Do a search inside it */ - Result = CmpDoFindSubKeyByNumber(Hive, Index, Number); - - /* Release the cell and return the result */ - HvReleaseCell(Hive, Node->SubKeyLists[Stable]); - return Result; - } - else if (Hive->StorageTypeCount > Volatile) - { - /* It's in the volatile list */ - Number = Number - Node->SubKeyCounts[Stable]; - if (Number < Node->SubKeyCounts[Volatile]) - { - /* Get the actual key index */ - Index = (PCM_KEY_INDEX)HvGetCell(Hive, - Node->SubKeyLists[Volatile]); - if (!Index) return HCELL_NIL; - - /* Do a search inside it */ - Result = CmpDoFindSubKeyByNumber(Hive, Index, Number); - - /* Release the cell and return the result */ - HvReleaseCell(Hive, Node->SubKeyLists[Volatile]); - return Result; - } - } - - /* Nothing was found */ - return HCELL_NIL; -} - -static HCELL_INDEX -NTAPI -CmpFindSubKeyByHash(IN PHHIVE Hive, - IN PCM_KEY_FAST_INDEX FastIndex, - IN PCUNICODE_STRING SearchName) -{ - ULONG HashKey, i; - PCM_INDEX FastEntry; - - /* Make sure it's really a hash */ - ASSERT(FastIndex->Signature == CM_KEY_HASH_LEAF); - - /* Compute the hash key for the name */ - HashKey = CmpComputeHashKey(0, SearchName, FALSE); - - /* Loop all the entries */ - for (i = 0; i < FastIndex->Count; i++) - { - /* Get the entry */ - FastEntry = &FastIndex->List[i]; - - /* Compare the hash first */ - if (FastEntry->HashKey == HashKey) - { - /* Go ahead for a full compare */ - if (!(CmpDoCompareKeyName(Hive, SearchName, FastEntry->Cell))) - { - /* It matched, return the cell */ - return FastEntry->Cell; - } - } - } - - /* If we got here then we failed */ - return HCELL_NIL; -} - -HCELL_INDEX -NTAPI -CmpFindSubKeyByName(IN PHHIVE Hive, - IN PCM_KEY_NODE Parent, - IN PCUNICODE_STRING SearchName) -{ - ULONG i; - PCM_KEY_INDEX IndexRoot; - HCELL_INDEX SubKey, CellToRelease; - ULONG Found; - - /* Loop each storage type */ - for (i = 0; i < Hive->StorageTypeCount; i++) - { - /* Make sure the parent node has subkeys */ - if (Parent->SubKeyCounts[i]) - { - /* Get the Index */ - IndexRoot = (PCM_KEY_INDEX)HvGetCell(Hive, Parent->SubKeyLists[i]); - if (!IndexRoot) return HCELL_NIL; - - /* Get the cell we'll need to release */ - CellToRelease = Parent->SubKeyLists[i]; - - /* Check if this is another index root */ - if (IndexRoot->Signature == CM_KEY_INDEX_ROOT) - { - /* Lookup the name in the root */ - Found = CmpFindSubKeyInRoot(Hive, - IndexRoot, - SearchName, - &SubKey); - - /* Release the previous cell */ - ASSERT(CellToRelease != HCELL_NIL); - HvReleaseCell(Hive, CellToRelease); - - /* Make sure we found something valid */ - if (Found & 0x80000000) break; - - /* Get the new Index Root and set the new cell to be released */ - if (SubKey == HCELL_NIL) continue; - CellToRelease = SubKey; - IndexRoot = (PCM_KEY_INDEX)HvGetCell(Hive, SubKey); - } - - /* Make sure the signature is what we expect it to be */ - ASSERT((IndexRoot->Signature == CM_KEY_INDEX_LEAF) || - (IndexRoot->Signature == CM_KEY_FAST_LEAF) || - (IndexRoot->Signature == CM_KEY_HASH_LEAF)); - - /* Check if this isn't a hashed leaf */ - if (IndexRoot->Signature != CM_KEY_HASH_LEAF) - { - /* Find the subkey in the leaf */ - Found = CmpFindSubKeyInLeaf(Hive, - IndexRoot, - SearchName, - &SubKey); - - /* Release the previous cell */ - ASSERT(CellToRelease != HCELL_NIL); - HvReleaseCell(Hive, CellToRelease); - - /* Make sure we found a valid index */ - if (Found & 0x80000000) break; - } - else - { - /* Find the subkey in the hash */ - SubKey = CmpFindSubKeyByHash(Hive, - (PCM_KEY_FAST_INDEX)IndexRoot, - SearchName); - - /* Release the previous cell */ - ASSERT(CellToRelease != HCELL_NIL); - HvReleaseCell(Hive, CellToRelease); - } - - /* Make sure we got a valid subkey and return it */ - if (SubKey != HCELL_NIL) return SubKey; - } - } - - /* If we got here, then we failed */ - return HCELL_NIL; -} - -BOOLEAN -NTAPI -CmpMarkIndexDirty(IN PHHIVE Hive, - IN HCELL_INDEX ParentKey, - IN HCELL_INDEX TargetKey) -{ - PCM_KEY_NODE Node; - UNICODE_STRING SearchName; - BOOLEAN IsCompressed; - ULONG i, Result; - PCM_KEY_INDEX Index; - HCELL_INDEX IndexCell, Child = HCELL_NIL, CellToRelease = HCELL_NIL; - - /* Get the target key node */ - Node = (PCM_KEY_NODE)HvGetCell(Hive, TargetKey); - if (!Node) return FALSE; - - /* Check if it's compressed */ - if (Node->Flags & KEY_COMP_NAME) - { - /* Remember this for later */ - IsCompressed = TRUE; - - /* Build the search name */ - SearchName.Length = CmpCompressedNameSize(Node->Name, - Node->NameLength); - SearchName.MaximumLength = SearchName.Length; - SearchName.Buffer = ExAllocatePoolWithTag(PagedPool, - SearchName.Length, - TAG_CM); - if (!SearchName.Buffer) - { - /* Fail */ - HvReleaseCell(Hive, TargetKey); - return FALSE; - } - - /* Copy it */ - CmpCopyCompressedName(SearchName.Buffer, - SearchName.MaximumLength, - Node->Name, - Node->NameLength); - } - else - { - /* Name isn't compressed, build it directly from the node */ - IsCompressed = FALSE; - SearchName.Length = Node->NameLength; - SearchName.MaximumLength = Node->NameLength; - SearchName.Buffer = Node->Name; - } - - /* We can release the target key now */ - HvReleaseCell(Hive, TargetKey); - - /* Now get the parent key node */ - Node = (PCM_KEY_NODE)HvGetCell(Hive, ParentKey); - if (!Node) goto Quickie; - - /* Loop all hive storage */ - for (i = 0; i < Hive->StorageTypeCount; i++) - { - /* Check if any subkeys are in this index */ - if (Node->SubKeyCounts[i]) - { - /* Get the cell index */ - //ASSERT(HvIsCellAllocated(Hive, Node->SubKeyLists[i])); - IndexCell = Node->SubKeyLists[i]; - - /* Check if we had anything to release from before */ - if (CellToRelease != HCELL_NIL) - { - /* Release it now */ - HvReleaseCell(Hive, CellToRelease); - CellToRelease = HCELL_NIL; - } - - /* Get the key index for the cell */ - Index = (PCM_KEY_INDEX)HvGetCell(Hive, IndexCell); - if (!Index) goto Quickie; - - /* Release it at the next iteration or below */ - CellToRelease = IndexCell; - - /* Check if this is a root */ - if (Index->Signature == CM_KEY_INDEX_ROOT) - { - /* Get the child inside the root */ - Result = CmpFindSubKeyInRoot(Hive, Index, &SearchName, &Child); - if (Result & 0x80000000) goto Quickie; - if (Child == HCELL_NIL) continue; - - /* We found it, mark the cell dirty */ - HvMarkCellDirty(Hive, IndexCell, FALSE); - - /* Check if we had anything to release from before */ - if (CellToRelease != HCELL_NIL) - { - /* Release it now */ - HvReleaseCell(Hive, CellToRelease); - CellToRelease = HCELL_NIL; - } - - /* Now this child is the index, get the actual key index */ - IndexCell = Child; - Index = (PCM_KEY_INDEX)HvGetCell(Hive, Child); - if (!Index) goto Quickie; - - /* Release it later */ - CellToRelease = Child; - } - - /* Make sure this is a valid index */ - ASSERT((Index->Signature == CM_KEY_INDEX_LEAF) || - (Index->Signature == CM_KEY_FAST_LEAF) || - (Index->Signature == CM_KEY_HASH_LEAF)); - - /* Find the child in the leaf */ - Result = CmpFindSubKeyInLeaf(Hive, Index, &SearchName, &Child); - if (Result & 0x80000000) goto Quickie; - if (Child != HCELL_NIL) - { - /* We found it, free the name now */ - if (IsCompressed) ExFreePool(SearchName.Buffer); - - /* Release the parent key */ - HvReleaseCell(Hive, ParentKey); - - /* Check if we had a left over cell to release */ - if (CellToRelease != HCELL_NIL) - { - /* Release it */ - HvReleaseCell(Hive, CellToRelease); - } - - /* And mark the index cell dirty */ - HvMarkCellDirty(Hive, IndexCell, FALSE); - return TRUE; - } - } - } - -Quickie: - /* Release any cells that we still hold */ - if (Node) HvReleaseCell(Hive, ParentKey); - if (CellToRelease != HCELL_NIL) HvReleaseCell(Hive, CellToRelease); - - /* Free the search name and return failure */ - if (IsCompressed) ExFreePool(SearchName.Buffer); - return FALSE; -} - -HCELL_INDEX -NTAPI -CmpAddToLeaf(IN PHHIVE Hive, - IN HCELL_INDEX LeafCell, - IN HCELL_INDEX NewKey, - IN PUNICODE_STRING Name) -{ - PCM_KEY_INDEX Leaf; - PCM_KEY_FAST_INDEX FastLeaf; - ULONG Size, OldSize, EntrySize, i, j; - HCELL_INDEX NewCell, Child; - LONG Result; - - /* Mark the leaf dirty */ - HvMarkCellDirty(Hive, LeafCell, FALSE); - - /* Get the leaf cell */ - Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); - if (!Leaf) - { - /* Shouldn't happen */ - ASSERT(FALSE); - return HCELL_NIL; - } - - /* Release it */ - HvReleaseCell(Hive, LeafCell); - - /* Check if this is an index leaf */ - if (Leaf->Signature == CM_KEY_INDEX_LEAF) - { - /* This is an old-style leaf */ - FastLeaf = NULL; - EntrySize = sizeof(HCELL_INDEX); - } - else - { - /* Sanity check */ - ASSERT((Leaf->Signature == CM_KEY_FAST_LEAF) || - (Leaf->Signature == CM_KEY_HASH_LEAF)); - - /* This is a new-style optimized fast (or hash) leaf */ - FastLeaf = (PCM_KEY_FAST_INDEX)Leaf; - EntrySize = sizeof(CM_INDEX); - } - - /* Get the current size of the leaf */ - OldSize = HvGetCellSize(Hive, Leaf); - - /* Calculate the size of the free entries */ - Size = OldSize; - Size -= EntrySize * Leaf->Count + FIELD_OFFSET(CM_KEY_INDEX, List); - - /* Assume we'll re-use the same leaf */ - NewCell = LeafCell; - - /* Check if we're out of space */ - if ((Size / EntrySize) < 1) - { - /* Grow the leaf by 1.5x, making sure we can at least fit this entry */ - Size = OldSize + OldSize / 2; - if (Size < (OldSize + EntrySize)) Size = OldSize + EntrySize; - - /* Re-allocate the leaf */ - NewCell = HvReallocateCell(Hive, LeafCell, Size); - if (NewCell == HCELL_NIL) return HCELL_NIL; - - /* Get the leaf cell */ - Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, NewCell); - if (!Leaf) - { - /* This shouldn't happen */ - ASSERT(FALSE); - return HCELL_NIL; - } - - /* Release the cell */ - HvReleaseCell(Hive, NewCell); - - /* Update the fast leaf pointer if we had one */ - if (FastLeaf) FastLeaf = (PCM_KEY_FAST_INDEX)Leaf; - } - - /* Find the insertion point for our entry */ - i = CmpFindSubKeyInLeaf(Hive, Leaf, Name, &Child); - if (i & 0x80000000) return HCELL_NIL; - ASSERT(Child == HCELL_NIL); - - /* Check if we're not last */ - if (i != Leaf->Count) - { - /* Find out where we should go */ - Result = CmpCompareInIndex(Hive, - Name, - i, - Leaf, - &Child); - if (Result == 2) return HCELL_NIL; - ASSERT(Result != 0); - - /* Check if we come after */ - if (Result > 0) - { - /* We do, insert us after the key */ - ASSERT(Result == 1); - i++; - } - - /* Check if we're still not last */ - if (i != Leaf->Count) - { - /* Check if we had a fast leaf or not */ - if (FastLeaf) - { - /* Copy the fast indexes */ - RtlMoveMemory(&FastLeaf->List[i + 1], - &FastLeaf->List[i], - (FastLeaf->Count - i) * sizeof(CM_INDEX)); - } - else - { - /* Copy the indexes themselves */ - RtlMoveMemory(&Leaf->List[i + 1], - &Leaf->List[i], - (Leaf->Count - i) * sizeof(HCELL_INDEX)); - } - } - } - - /* Check if this is a new-style leaf */ - if (FastLeaf) - { - /* Set our cell */ - FastLeaf->List[i].Cell = NewKey; - - /* Check if this is a hash leaf */ - if( FastLeaf->Signature == CM_KEY_HASH_LEAF ) - { - /* Set our hash key */ - FastLeaf->List[i].HashKey = CmpComputeHashKey(0, Name, FALSE); - } - else - { - /* First, clear the name */ - FastLeaf->List[i].NameHint[0] = 0; - FastLeaf->List[i].NameHint[1] = 0; - FastLeaf->List[i].NameHint[2] = 0; - FastLeaf->List[i].NameHint[3] = 0; - - /* Now, figure out if we can fit */ - if (Name->Length / sizeof(WCHAR) < 4) - { - /* We can fit, use our length */ - j = Name->Length / sizeof(WCHAR); - } - else - { - /* We can't, use a maximum of 4 */ - j = 4; - } - - /* Now fill out the name hint */ - do - { - /* Look for invalid characters and break out if we found one */ - if ((USHORT)Name->Buffer[j - 1] > (UCHAR)-1) break; - - /* Otherwise, copy the a character */ - FastLeaf->List[i].NameHint[j - 1] = (UCHAR)Name->Buffer[j - 1]; - } while (--j > 0); - } - } - else - { - /* This is an old-style leaf, just set our index directly */ - Leaf->List[i] = NewKey; - } - - /* Update the leaf count and return the new cell */ - Leaf->Count += 1; - return NewCell; -} - -BOOLEAN -NTAPI -CmpAddSubKey(IN PHHIVE Hive, - IN HCELL_INDEX Parent, - IN HCELL_INDEX Child) -{ - PCM_KEY_NODE KeyNode; - PCM_KEY_INDEX Index; - PCM_KEY_FAST_INDEX OldIndex; - UNICODE_STRING Name; - HCELL_INDEX IndexCell = HCELL_NIL, CellToRelease = HCELL_NIL, LeafCell; - PHCELL_INDEX RootPointer = NULL; - ULONG Type, i; - BOOLEAN IsCompressed; - PAGED_CODE(); - - /* Get the key node */ - KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Child); - if (!KeyNode) - { - /* Shouldn't happen */ - ASSERT(FALSE); - return FALSE; - } - - /* Check if the name is compressed */ - if (KeyNode->Flags & KEY_COMP_NAME) - { - /* Remember for later */ - IsCompressed = TRUE; - - /* Create the compressed name and allocate it */ - Name.Length = CmpCompressedNameSize(KeyNode->Name, KeyNode->NameLength); - Name.MaximumLength = Name.Length; - Name.Buffer = Hive->Allocate(Name.Length, TRUE, TAG_CM); - if (!Name.Buffer) - { - /* Release the cell and fail */ - HvReleaseCell(Hive, Child); - ASSERT(FALSE); - return FALSE; - } - - /* Copy the compressed name */ - CmpCopyCompressedName(Name.Buffer, - Name.MaximumLength, - KeyNode->Name, - KeyNode->NameLength); - } - else - { - /* Remember for later */ - IsCompressed = FALSE; - - /* Build the unicode string */ - Name.Length = KeyNode->NameLength; - Name.MaximumLength = KeyNode->NameLength; - Name.Buffer = &KeyNode->Name[0]; - } - - /* Release the cell */ - HvReleaseCell(Hive, Child); - - /* Get the parent node */ - KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Parent); - if (!KeyNode) - { - /* Not handled */ - ASSERT(FALSE); - } - - /* Find out the type of the cell, and check if this is the first subkey */ - Type = HvGetCellType(Child); - if (!KeyNode->SubKeyCounts[Type]) - { - /* Allocate a fast leaf */ - IndexCell = HvAllocateCell(Hive, sizeof(CM_KEY_FAST_INDEX), Type, HCELL_NIL); - if (IndexCell == HCELL_NIL) - { - /* Not handled */ - ASSERT(FALSE); - } - - /* Get the leaf cell */ - Index = (PCM_KEY_INDEX)HvGetCell(Hive, IndexCell); - if (!Index) - { - /* Shouldn't happen */ - ASSERT(FALSE); - } - - /* Now check what kind of hive we're dealing with */ - if (Hive->Version >= 5) - { - /* XP Hive: Use hash leaf */ - Index->Signature = CM_KEY_HASH_LEAF; - } - else if (Hive->Version >= 3) - { - /* Windows 2000 and ReactOS: Use fast leaf */ - Index->Signature = CM_KEY_FAST_LEAF; - } - else - { - /* NT 4: Use index leaf */ - Index->Signature = CM_KEY_INDEX_LEAF; - } - - /* Setup the index list */ - Index->Count = 0; - KeyNode->SubKeyLists[Type] = IndexCell; - } - else - { - /* We already have an index, get it */ - Index = (PCM_KEY_INDEX)HvGetCell(Hive, KeyNode->SubKeyLists[Type]); - if (!Index) - { - /* Not handled */ - ASSERT(FALSE); - } - - /* Remember to release the cell later */ - CellToRelease = KeyNode->SubKeyLists[Type]; - - /* Check if this is a fast leaf that's gotten too full */ - if ((Index->Signature == CM_KEY_FAST_LEAF) && - (Index->Count >= CmpMaxFastIndexPerHblock)) - { - DPRINT("Doing Fast->Slow Leaf conversion\n"); - - /* Mark this cell as dirty */ - HvMarkCellDirty(Hive, CellToRelease, FALSE); - - /* Convert */ - OldIndex = (PCM_KEY_FAST_INDEX)Index; - - for (i=0; i < OldIndex->Count; i++) - { - Index->List[i] = OldIndex->List[i].Cell; - } - - /* Set the new type value */ - Index->Signature = CM_KEY_INDEX_LEAF; - } - else if (((Index->Signature == CM_KEY_INDEX_LEAF) || - (Index->Signature == CM_KEY_HASH_LEAF)) && - (Index->Count >= CmpMaxIndexPerHblock)) - { - /* This is an old/hashed leaf that's gotten too large, root it */ - IndexCell = HvAllocateCell(Hive, - sizeof(CM_KEY_INDEX) + - sizeof(HCELL_INDEX), - Type, - HCELL_NIL); - if (IndexCell == HCELL_NIL) - { - /* Not handled */ - ASSERT(FALSE); - } - - /* Get the index cell */ - Index = (PCM_KEY_INDEX)HvGetCell(Hive, IndexCell); - if (!Index) - { - /* Shouldn't happen */ - ASSERT(FALSE); - } - - /* Mark the index as a root, and set the index cell */ - Index->Signature = CM_KEY_INDEX_ROOT; - Index->Count = 1; - Index->List[0] = KeyNode->SubKeyLists[Type]; - KeyNode->SubKeyLists[Type] = IndexCell; - } - } - - /* Now we can choose the leaf cell */ - LeafCell = KeyNode->SubKeyLists[Type]; - - /* Check if we turned the index into a root */ - if (Index->Signature == CM_KEY_INDEX_ROOT) - { - /* Not handled yet */ - DPRINT1("Leaf->Root Index Conversion not yet implemented!\n"); - ASSERT(FALSE); - } - - /* Add our leaf cell */ - LeafCell = CmpAddToLeaf(Hive, LeafCell, Child, &Name); - if (LeafCell == HCELL_NIL) - { - /* Not handled */ - ASSERT(FALSE); - } - - /* Update the key counts */ - KeyNode->SubKeyCounts[Type]++; - - /* Check if caller wants us to return the leaf */ - if (RootPointer) - { - /* Return it */ - *RootPointer = LeafCell; - } - else - { - /* Otherwise, mark it as the list index for the cell */ - KeyNode->SubKeyLists[Type] = LeafCell; - } - - /* If the name was compressed, free our copy */ - if (IsCompressed) Hive->Free(Name.Buffer, 0); - - /* Release all our cells */ - if (IndexCell != HCELL_NIL) HvReleaseCell(Hive, IndexCell); - if (CellToRelease != HCELL_NIL) HvReleaseCell(Hive, CellToRelease); - HvReleaseCell(Hive, Parent); - return TRUE; -} - -BOOLEAN -NTAPI -CmpRemoveSubKey(IN PHHIVE Hive, - IN HCELL_INDEX ParentKey, - IN HCELL_INDEX TargetKey) -{ - PCM_KEY_NODE Node; - UNICODE_STRING SearchName; - BOOLEAN IsCompressed; - WCHAR Buffer[50]; - HCELL_INDEX RootCell = HCELL_NIL, LeafCell, ChildCell; - PCM_KEY_INDEX Root = NULL, Leaf; - PCM_KEY_FAST_INDEX Child; - ULONG Storage, RootIndex = 0x80000000, LeafIndex; - BOOLEAN Result = FALSE; - HCELL_INDEX CellToRelease1 = HCELL_NIL, CellToRelease2 = HCELL_NIL; - - /* Get the target key node */ - Node = (PCM_KEY_NODE)HvGetCell(Hive, TargetKey); - if (!Node) return FALSE; - - /* Make sure it's dirty, then release it */ - ASSERT(HvIsCellDirty(Hive, TargetKey)); - HvReleaseCell(Hive, TargetKey); - - /* Check if the name is compressed */ - if (Node->Flags & KEY_COMP_NAME) - { - /* Remember for later */ - IsCompressed = TRUE; - - /* Build the search name */ - SearchName.Length = CmpCompressedNameSize(Node->Name, - Node->NameLength); - SearchName.MaximumLength = SearchName.Length; - - /* Do we need an extra bufer? */ - if (SearchName.MaximumLength > sizeof(Buffer)) - { - /* Allocate one */ - SearchName.Buffer = ExAllocatePoolWithTag(PagedPool, - SearchName.Length, - TAG_CM); - if (!SearchName.Buffer) return FALSE; - } - else - { - /* Otherwise, use our local stack buffer */ - SearchName.Buffer = Buffer; - } - - /* Copy the compressed name */ - CmpCopyCompressedName(SearchName.Buffer, - SearchName.MaximumLength, - Node->Name, - Node->NameLength); - } - else - { - /* It's not compressed, build the name directly from the node */ - IsCompressed = FALSE; - SearchName.Length = Node->NameLength; - SearchName.MaximumLength = Node->NameLength; - SearchName.Buffer = Node->Name; - } - - /* Now get the parent node */ - Node = (PCM_KEY_NODE)HvGetCell(Hive, ParentKey); - if (!Node) goto Exit; - - /* Make sure it's dirty, then release it */ - ASSERT(HvIsCellDirty(Hive, ParentKey)); - HvReleaseCell(Hive, ParentKey); - - /* Get the storage type and make sure it's not empty */ - Storage = HvGetCellType(TargetKey); - ASSERT(Node->SubKeyCounts[Storage] != 0); - //ASSERT(HvIsCellAllocated(Hive, Node->SubKeyLists[Storage])); - - /* Get the leaf cell now */ - LeafCell = Node->SubKeyLists[Storage]; - Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); - if (!Leaf) goto Exit; - - /* Remember to release it later */ - CellToRelease1 = LeafCell; - - /* Check if the leaf is a root */ - if (Leaf->Signature == CM_KEY_INDEX_ROOT) - { - /* Find the child inside the root */ - RootIndex = CmpFindSubKeyInRoot(Hive, Leaf, &SearchName, &ChildCell); - if (RootIndex & 0x80000000) goto Exit; - ASSERT(ChildCell != FALSE); - - /* The root cell is now this leaf */ - Root = Leaf; - RootCell = LeafCell; - - /* And the new leaf is now this child */ - LeafCell = ChildCell; - Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); - if (!Leaf) goto Exit; - - /* Remember to release it later */ - CellToRelease2 = LeafCell; - } - - /* Make sure the leaf is valid */ - ASSERT((Leaf->Signature == CM_KEY_INDEX_LEAF) || - (Leaf->Signature == CM_KEY_FAST_LEAF) || - (Leaf->Signature == CM_KEY_HASH_LEAF)); - - /* Now get the child in the leaf */ - LeafIndex = CmpFindSubKeyInLeaf(Hive, Leaf, &SearchName, &ChildCell); - if (LeafIndex & 0x80000000) goto Exit; - ASSERT(ChildCell != HCELL_NIL); - - /* Decrement key counts and check if this was the last leaf entry */ - Node->SubKeyCounts[Storage]--; - if (!(--Leaf->Count)) - { - /* Free the leaf */ - HvFreeCell(Hive, LeafCell); - - /* Check if we were inside a root */ - if (Root) - { - /* Decrease the root count too, since the leaf is going away */ - if (!(--Root->Count)) - { - /* The root is gone too,n ow */ - HvFreeCell(Hive, RootCell); - Node->SubKeyLists[Storage] = HCELL_NIL; - } - else if (RootIndex < Root->Count) - { - /* Bring everything up by one */ - RtlMoveMemory(&Root->List[RootIndex], - &Root->List[RootIndex + 1], - (Root->Count - RootIndex) * sizeof(HCELL_INDEX)); - } - } - else - { - /* Otherwise, just clear the cell */ - Node->SubKeyLists[Storage] = HCELL_NIL; - } - } - else if (LeafIndex < Leaf->Count) - { - /* Was the leaf a normal index? */ - if (Leaf->Signature == CM_KEY_INDEX_LEAF) - { - /* Bring everything up by one */ - RtlMoveMemory(&Leaf->List[LeafIndex], - &Leaf->List[LeafIndex + 1], - (Leaf->Count - LeafIndex) * sizeof(HCELL_INDEX)); - } - else - { - /* This is a fast index, bring everything up by one */ - Child = (PCM_KEY_FAST_INDEX)Leaf; - RtlMoveMemory(&Child->List[LeafIndex], - &Child->List[LeafIndex+1], - (Child->Count - LeafIndex) * sizeof(CM_INDEX)); - } - } - - /* If we got here, now we're done */ - Result = TRUE; - -Exit: - /* Release any cells we may have been holding */ - if (CellToRelease1 != HCELL_NIL) HvReleaseCell(Hive, CellToRelease1); - if (CellToRelease2 != HCELL_NIL) HvReleaseCell(Hive, CellToRelease2); - - /* Check if the name was compressed and not inside our local buffer */ - if ((IsCompressed) && (SearchName.MaximumLength > sizeof(Buffer))) - { - /* Free the buffer we allocated */ - ExFreePool(SearchName.Buffer); - } - - /* Return the result */ - return Result; -} +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmindex.c + * PURPOSE: Configuration Manager - Cell Indexes + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#define NDEBUG +#include "debug.h" + +/* GLOBALS *******************************************************************/ + +ULONG CmpMaxFastIndexPerHblock = + (HBLOCK_SIZE - (sizeof(HBIN) + + sizeof(HCELL) + + FIELD_OFFSET(CM_KEY_FAST_INDEX, List))) / sizeof(CM_INDEX); + +ULONG CmpMaxIndexPerHblock = + (HBLOCK_SIZE - (sizeof(HBIN) + + sizeof(HCELL) + + FIELD_OFFSET(CM_KEY_INDEX, List))) / sizeof(HCELL_INDEX) - 1; + +/* FUNCTIONS *****************************************************************/ + +LONG +NTAPI +CmpDoCompareKeyName(IN PHHIVE Hive, + IN PCUNICODE_STRING SearchName, + IN HCELL_INDEX Cell) +{ + PCM_KEY_NODE Node; + UNICODE_STRING KeyName; + LONG Result; + + /* Get the node */ + Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell); + if (!Node) return 2; + + /* Check if it's compressed */ + if (Node->Flags & KEY_COMP_NAME) + { + /* Compare compressed names */ + Result = CmpCompareCompressedName(SearchName, + Node->Name, + Node->NameLength); + } + else + { + /* Compare the Unicode name directly */ + KeyName.Buffer = Node->Name; + KeyName.Length = Node->NameLength; + KeyName.MaximumLength = KeyName.Length; + Result = RtlCompareUnicodeString(SearchName, &KeyName, TRUE); + } + + /* Release the cell and return the normalized result */ + HvReleaseCell(Hive, Cell); + return (Result == 0) ? Result : ((Result > 0) ? 1 : -1); +} + +LONG +NTAPI +CmpCompareInIndex(IN PHHIVE Hive, + IN PCUNICODE_STRING SearchName, + IN ULONG Count, + IN PCM_KEY_INDEX Index, + IN PHCELL_INDEX SubKey) +{ + PCM_KEY_FAST_INDEX FastIndex; + PCM_INDEX FastEntry; + LONG Result; + ULONG i; + ULONG ActualNameLength = 4, CompareLength, NameLength; + WCHAR p, pp; + + /* Assume failure */ + *SubKey = HCELL_NIL; + + /* Check if we are a fast or hashed leaf */ + if ((Index->Signature == CM_KEY_FAST_LEAF) || + (Index->Signature == CM_KEY_HASH_LEAF)) + { + /* Get the Fast/Hash Index */ + FastIndex = (PCM_KEY_FAST_INDEX)Index; + FastEntry = &FastIndex->List[Count]; + + /* Check if we are a hash leaf, in which case we skip all this */ + if (Index->Signature == CM_KEY_FAST_LEAF) + { + /* Find out just how much of the name is there */ + for (i = 0; i < 4; i++) + { + /* Check if this entry is empty */ + if (!FastEntry->NameHint[i]) + { + /* Only this much! */ + ActualNameLength = i; + break; + } + } + + /* How large is the name and how many characters to compare */ + NameLength = SearchName->Length / sizeof(WCHAR); + CompareLength = min(NameLength, ActualNameLength); + + /* Loop all the chars we'll test */ + for (i = 0; i < CompareLength; i++) + { + /* Get one char from each buffer */ + p = SearchName->Buffer[i]; + pp = FastEntry->NameHint[i]; + + /* See if they match and return result if they don't */ + Result = (LONG)RtlUpcaseUnicodeChar(p) - + (LONG)RtlUpcaseUnicodeChar(pp); + if (Result) return (Result > 0) ? 1 : -1; + } + } + + /* If we got here then we have to do a full compare */ + Result = CmpDoCompareKeyName(Hive, SearchName, FastEntry->Cell); + if (Result == 2) return Result; + if (!Result) *SubKey = FastEntry->Cell; + } + else + { + /* We aren't, so do a name compare and return the subkey found */ + Result = CmpDoCompareKeyName(Hive, SearchName, Index->List[Count]); + if (Result == 2) return Result; + if (!Result) *SubKey = Index->List[Count]; + } + + /* Return the comparison result */ + return Result; +} + +ULONG +NTAPI +CmpFindSubKeyInRoot(IN PHHIVE Hive, + IN PCM_KEY_INDEX Index, + IN PCUNICODE_STRING SearchName, + IN PHCELL_INDEX SubKey) +{ + ULONG High, Low = 0, i, ReturnIndex; + HCELL_INDEX LeafCell; + PCM_KEY_INDEX Leaf; + LONG Result; + + /* Verify Index for validity */ + ASSERTMSG("We don't do a linear search yet!\n", FALSE); + ASSERT(Index->Count != 0); + ASSERT(Index->Signature == CM_KEY_INDEX_ROOT); + + /* Set high limit and loop */ + High = Index->Count - 1; + while (TRUE) + { + /* Choose next entry */ + i = ((High - Low) / 2) + Low; + + /* Get the leaf cell and then the leaf itself */ + LeafCell = Index->List[i]; + Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); + if (Leaf) + { + /* Make sure the leaf is valid */ + ASSERT((Leaf->Signature == CM_KEY_INDEX_LEAF) || + (Leaf->Signature == CM_KEY_FAST_LEAF) || + (Leaf->Signature == CM_KEY_HASH_LEAF)); + ASSERT(Leaf->Count != 0); + + /* Do the compare */ + Result = CmpCompareInIndex(Hive, + SearchName, + Leaf->Count - 1, + Leaf, + SubKey); + if (Result == 2) goto Big; + + /* Check if we found the leaf */ + if (!Result) + { + /* We found the leaf */ + *SubKey = LeafCell; + ReturnIndex = i; + goto Return; + } + + /* Check for negative result */ + if (Result < 0) + { + /* If we got here, we should be at -1 */ + ASSERT(Result == -1); + + /* Do another lookup, since we might still be in the right leaf */ + Result = CmpCompareInIndex(Hive, + SearchName, + 0, + Leaf, + SubKey); + if (Result == 2) goto Big; + + /* Check if it's not below */ + if (Result >= 0) + { + /* + * If the name was first below, and now it is above, + * then this means that it is somewhere in this leaf. + * Make sure we didn't get some weird result + */ + ASSERT((Result == 1) || (Result == 0)); + + /* Return it */ + *SubKey = LeafCell; + ReturnIndex = Low; + goto Return; + } + + /* Update the limit to this index, since we know it's not higher. */ + High = i; + } + else + { + /* Update the base to this index, since we know it's not lower. */ + Low = i; + } + } + else + { +Big: + /* This was some sort of special key */ + ReturnIndex = 0x80000000; + goto ReturnFailure; + } + + /* Check if there is only one entry left */ + if ((High - Low) <= 1) break; + + /* Release the leaf cell */ + HvReleaseCell(Hive, LeafCell); + } + + /* Make sure we got here for the right reasons */ + ASSERT((High - Low == 1) || (High == Low)); + + /* Get the leaf cell and the leaf */ + LeafCell = Index->List[Low]; + Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); + if (!Leaf) goto Big; + + /* Do the compare */ + Result = CmpCompareInIndex(Hive, + SearchName, + Leaf->Count-1, + Leaf, + SubKey); + if (Result == 2) goto Big; + + /* Check if we found it */ + if (!Result) + { + /* We got lucky...return it */ + *SubKey = LeafCell; + ReturnIndex = Low; + goto Return; + } + + /* It's below, so could still be in this leaf */ + if (Result < 0) + { + /* Make sure we're -1 */ + ASSERT(Result == -1); + + /* Do a search from the bottom */ + Result = CmpCompareInIndex(Hive, SearchName, 0, Leaf, SubKey); + if (Result == 2) goto Big; + + /* + * Check if it's above, which means that it's within the ranges of our + * leaf (since we were below before). + */ + if (Result >= 0) + { + /* Sanity check */ + ASSERT((Result == 1) || (Result == 0)); + + /* Yep, so we're in the right leaf; return it. */ + *SubKey = LeafCell; + ReturnIndex = Low; + goto Return; + } + + /* It's still below us, so fail */ + ReturnIndex = Low; + goto ReturnFailure; + } + + /* Release the leaf cell */ + HvReleaseCell(Hive, LeafCell); + + /* Well the low didn't work too well, so try the high. */ + LeafCell = Index->List[High]; + Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); + if (!Leaf) goto Big; + + /* Do the compare */ + Result = CmpCompareInIndex(Hive, + SearchName, + Leaf->Count - 1, + Leaf, + SubKey); + if (Result == 2) goto Big; + + /* Check if we found it */ + if (Result == 0) + { + /* We got lucky... return it */ + *SubKey = LeafCell; + ReturnIndex = High; + goto Return; + } + + /* Check if we are too high */ + if (Result < 0) + { + /* Make sure we're -1 */ + ASSERT(Result == -1); + + /* + * Once again... since we were first too low and now too high, then + * this means we are within the range of this leaf... return it. + */ + *SubKey = LeafCell; + ReturnIndex = High; + goto Return; + } + + /* If we got here, then we are too low, again. */ + ReturnIndex = High; + + /* Failure path */ +ReturnFailure: + *SubKey = HCELL_NIL; + + /* Return path...check if we have a leaf to free */ +Return: + if (Leaf) HvReleaseCell(Hive, LeafCell); + + /* Return the index */ + return ReturnIndex; +} + +ULONG +NTAPI +CmpFindSubKeyInLeaf(IN PHHIVE Hive, + IN PCM_KEY_INDEX Index, + IN PCUNICODE_STRING SearchName, + IN PHCELL_INDEX SubKey) +{ + ULONG High, Low = 0, i; + LONG Result; + + /* Verify Index for validity */ + ASSERT((Index->Signature == CM_KEY_INDEX_LEAF) || + (Index->Signature == CM_KEY_FAST_LEAF) || + (Index->Signature == CM_KEY_HASH_LEAF)); + + /* Get the upper bound and middle entry */ + High = Index->Count - 1; +#ifdef SOMEONE_WAS_NICE_ENOUGH_TO_MAKE_OUR_CELLS_LEXICALLY_SORTED + i = High / 2; +#else + i = 0; +#endif + + /* Check if we don't actually have any entries */ + if (!Index->Count) + { + /* Return failure */ + *SubKey = HCELL_NIL; + return 0; + } + + /* Start compare loop */ + while (TRUE) + { + /* Do the actual comparison and check the result */ + Result = CmpCompareInIndex(Hive, SearchName, i, Index, SubKey); + if (Result == 2) + { + /* Fail with special value */ + *SubKey = HCELL_NIL; + return 0x80000000; + } + + /* Check if we got lucky and found it */ + if (!Result) return i; + +#ifdef SOMEONE_WAS_NICE_ENOUGH_TO_MAKE_OUR_CELLS_LEXICALLY_SORTED + /* Check if the result is below us */ + if (Result < 0) + { + /* Set the new bound; it can't be higher then where we are now. */ + ASSERT(Result == -1); + High = i; + } + else + { + /* Set the new bound... it can't be lower then where we are now. */ + ASSERT(Result == 1); + Low = i; + } + + /* Check if this is the last entry, if so, break out and handle it */ + if ((High - Low) <= 1) break; + + /* Set the new index */ + i = ((High - Low) / 2) + Low; +#else + if (++i > High) + { + /* Return failure */ + *SubKey = HCELL_NIL; + return 0; + } +#endif + } + + /* + * If we get here, High - Low = 1 or High == Low + * Simply look first at Low, then at High + */ + Result = CmpCompareInIndex(Hive, SearchName, Low, Index, SubKey); + if (Result == 2) + { + /* Fail with special value */ + *SubKey = HCELL_NIL; + return 0x80000000; + } + + /* Check if we got lucky and found it */ + if (!Result) return Low; + + /* Check if the result is below us */ + if (Result < 0) + { + /* Return the low entry */ + ASSERT(Result == -1); + return Low; + } + + /* + * If we got here, then just check the high and return it no matter what + * the result is (since we're a leaf, it has to be near there anyway). + */ + Result = CmpCompareInIndex(Hive, SearchName, High, Index, SubKey); + if (Result == 2) + { + /* Fail with special value */ + *SubKey = HCELL_NIL; + return 0x80000000; + } + + /* Return the high */ + return High; +} + +ULONG +NTAPI +CmpComputeHashKey(IN ULONG Hash, + IN PCUNICODE_STRING Name, + IN BOOLEAN AllowSeparators) +{ + LPWSTR Cp; + ULONG Value, i; + + /* Make some sanity checks on our parameters */ + ASSERT((Name->Length == 0) || + (AllowSeparators) || + (Name->Buffer[0] != OBJ_NAME_PATH_SEPARATOR)); + + /* If the name is empty, there is nothing to hash! */ + if (!Name->Length) return Hash; + + /* Set the buffer and loop every character */ + Cp = Name->Buffer; + for (i = 0; i < Name->Length; i += sizeof(WCHAR), Cp++) + { + /* Make sure we don't have a separator when we shouldn't */ + ASSERT(AllowSeparators || (*Cp != OBJ_NAME_PATH_SEPARATOR)); + + /* Check what kind of char we have */ + if (*Cp >= L'a') + { + /* In the lower case region... is it truly lower case? */ + if (*Cp < L'z') + { + /* Yes! Calculate it ourselves! */ + Value = *Cp - L'a' + L'A'; + } + else + { + /* No, use the API */ + Value = RtlUpcaseUnicodeChar(*Cp); + } + } + else + { + /* Reuse the char, it's already upcased */ + Value = *Cp; + } + + /* Multiply by a prime and add our value */ + Hash *= 37; + Hash += Value; + } + + /* Return the hash */ + return Hash; +} + +HCELL_INDEX +NTAPI +CmpDoFindSubKeyByNumber(IN PHHIVE Hive, + IN PCM_KEY_INDEX Index, + IN ULONG Number) +{ + ULONG i; + HCELL_INDEX LeafCell = 0; + PCM_KEY_INDEX Leaf = NULL; + PCM_KEY_FAST_INDEX FastIndex; + HCELL_INDEX Result; + + /* Check if this is a root */ + if (Index->Signature == CM_KEY_INDEX_ROOT) + { + /* Loop the index */ + for (i = 0; i < Index->Count; i++) + { + /* Check if this isn't the first iteration */ + if (i) + { + /* Make sure we had something valid, and release it */ + ASSERT(Leaf != NULL ); + ASSERT(LeafCell == Index->List[i - 1]); + HvReleaseCell(Hive, LeafCell); + } + + /* Get the leaf cell and the leaf for this index */ + LeafCell = Index->List[i]; + Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); + if (!Leaf) return HCELL_NIL; + + /* Check if the index may be inside it */ + if (Number < Leaf->Count) + { + /* Check if this is a fast or hash leaf */ + if ((Leaf->Signature == CM_KEY_FAST_LEAF) || + (Leaf->Signature == CM_KEY_HASH_LEAF)) + { + /* Get the fast index */ + FastIndex = (PCM_KEY_FAST_INDEX)Leaf; + + /* Look inside the list to get our actual cell */ + Result = FastIndex->List[Number].Cell; + HvReleaseCell(Hive, LeafCell); + return Result; + } + else + { + /* Regular leaf, so just use the index directly */ + Result = Leaf->List[Number]; + + /* Release and return it */ + HvReleaseCell(Hive,LeafCell); + return Result; + } + } + else + { + /* Otherwise, skip this leaf */ + Number = Number - Leaf->Count; + } + } + + /* Should never get here */ + ASSERT(FALSE); + } + + /* If we got here, then the cell is in this index */ + ASSERT(Number < Index->Count); + + /* Check if we're a fast or hash leaf */ + if ((Index->Signature == CM_KEY_FAST_LEAF) || + (Index->Signature == CM_KEY_HASH_LEAF)) + { + /* We are, get the fast index and get the cell from the list */ + FastIndex = (PCM_KEY_FAST_INDEX)Index; + return FastIndex->List[Number].Cell; + } + else + { + /* We aren't, so use the index directly to grab the cell */ + return Index->List[Number]; + } +} + +HCELL_INDEX +NTAPI +CmpFindSubKeyByNumber(IN PHHIVE Hive, + IN PCM_KEY_NODE Node, + IN ULONG Number) +{ + PCM_KEY_INDEX Index; + HCELL_INDEX Result = HCELL_NIL; + + /* Check if it's in the stable list */ + if (Number < Node->SubKeyCounts[Stable]) + { + /* Get the actual key index */ + Index = (PCM_KEY_INDEX)HvGetCell(Hive, Node->SubKeyLists[Stable]); + if (!Index) return HCELL_NIL; + + /* Do a search inside it */ + Result = CmpDoFindSubKeyByNumber(Hive, Index, Number); + + /* Release the cell and return the result */ + HvReleaseCell(Hive, Node->SubKeyLists[Stable]); + return Result; + } + else if (Hive->StorageTypeCount > Volatile) + { + /* It's in the volatile list */ + Number = Number - Node->SubKeyCounts[Stable]; + if (Number < Node->SubKeyCounts[Volatile]) + { + /* Get the actual key index */ + Index = (PCM_KEY_INDEX)HvGetCell(Hive, + Node->SubKeyLists[Volatile]); + if (!Index) return HCELL_NIL; + + /* Do a search inside it */ + Result = CmpDoFindSubKeyByNumber(Hive, Index, Number); + + /* Release the cell and return the result */ + HvReleaseCell(Hive, Node->SubKeyLists[Volatile]); + return Result; + } + } + + /* Nothing was found */ + return HCELL_NIL; +} + +static HCELL_INDEX +NTAPI +CmpFindSubKeyByHash(IN PHHIVE Hive, + IN PCM_KEY_FAST_INDEX FastIndex, + IN PCUNICODE_STRING SearchName) +{ + ULONG HashKey, i; + PCM_INDEX FastEntry; + + /* Make sure it's really a hash */ + ASSERT(FastIndex->Signature == CM_KEY_HASH_LEAF); + + /* Compute the hash key for the name */ + HashKey = CmpComputeHashKey(0, SearchName, FALSE); + + /* Loop all the entries */ + for (i = 0; i < FastIndex->Count; i++) + { + /* Get the entry */ + FastEntry = &FastIndex->List[i]; + + /* Compare the hash first */ + if (FastEntry->HashKey == HashKey) + { + /* Go ahead for a full compare */ + if (!(CmpDoCompareKeyName(Hive, SearchName, FastEntry->Cell))) + { + /* It matched, return the cell */ + return FastEntry->Cell; + } + } + } + + /* If we got here then we failed */ + return HCELL_NIL; +} + +HCELL_INDEX +NTAPI +CmpFindSubKeyByName(IN PHHIVE Hive, + IN PCM_KEY_NODE Parent, + IN PCUNICODE_STRING SearchName) +{ + ULONG i; + PCM_KEY_INDEX IndexRoot; + HCELL_INDEX SubKey, CellToRelease; + ULONG Found; + + /* Loop each storage type */ + for (i = 0; i < Hive->StorageTypeCount; i++) + { + /* Make sure the parent node has subkeys */ + if (Parent->SubKeyCounts[i]) + { + /* Get the Index */ + IndexRoot = (PCM_KEY_INDEX)HvGetCell(Hive, Parent->SubKeyLists[i]); + if (!IndexRoot) return HCELL_NIL; + + /* Get the cell we'll need to release */ + CellToRelease = Parent->SubKeyLists[i]; + + /* Check if this is another index root */ + if (IndexRoot->Signature == CM_KEY_INDEX_ROOT) + { + /* Lookup the name in the root */ + Found = CmpFindSubKeyInRoot(Hive, + IndexRoot, + SearchName, + &SubKey); + + /* Release the previous cell */ + ASSERT(CellToRelease != HCELL_NIL); + HvReleaseCell(Hive, CellToRelease); + + /* Make sure we found something valid */ + if (Found & 0x80000000) break; + + /* Get the new Index Root and set the new cell to be released */ + if (SubKey == HCELL_NIL) continue; + CellToRelease = SubKey; + IndexRoot = (PCM_KEY_INDEX)HvGetCell(Hive, SubKey); + } + + /* Make sure the signature is what we expect it to be */ + ASSERT((IndexRoot->Signature == CM_KEY_INDEX_LEAF) || + (IndexRoot->Signature == CM_KEY_FAST_LEAF) || + (IndexRoot->Signature == CM_KEY_HASH_LEAF)); + + /* Check if this isn't a hashed leaf */ + if (IndexRoot->Signature != CM_KEY_HASH_LEAF) + { + /* Find the subkey in the leaf */ + Found = CmpFindSubKeyInLeaf(Hive, + IndexRoot, + SearchName, + &SubKey); + + /* Release the previous cell */ + ASSERT(CellToRelease != HCELL_NIL); + HvReleaseCell(Hive, CellToRelease); + + /* Make sure we found a valid index */ + if (Found & 0x80000000) break; + } + else + { + /* Find the subkey in the hash */ + SubKey = CmpFindSubKeyByHash(Hive, + (PCM_KEY_FAST_INDEX)IndexRoot, + SearchName); + + /* Release the previous cell */ + ASSERT(CellToRelease != HCELL_NIL); + HvReleaseCell(Hive, CellToRelease); + } + + /* Make sure we got a valid subkey and return it */ + if (SubKey != HCELL_NIL) return SubKey; + } + } + + /* If we got here, then we failed */ + return HCELL_NIL; +} + +BOOLEAN +NTAPI +CmpMarkIndexDirty(IN PHHIVE Hive, + IN HCELL_INDEX ParentKey, + IN HCELL_INDEX TargetKey) +{ + PCM_KEY_NODE Node; + UNICODE_STRING SearchName; + BOOLEAN IsCompressed; + ULONG i, Result; + PCM_KEY_INDEX Index; + HCELL_INDEX IndexCell, Child = HCELL_NIL, CellToRelease = HCELL_NIL; + + /* Get the target key node */ + Node = (PCM_KEY_NODE)HvGetCell(Hive, TargetKey); + if (!Node) return FALSE; + + /* Check if it's compressed */ + if (Node->Flags & KEY_COMP_NAME) + { + /* Remember this for later */ + IsCompressed = TRUE; + + /* Build the search name */ + SearchName.Length = CmpCompressedNameSize(Node->Name, + Node->NameLength); + SearchName.MaximumLength = SearchName.Length; + SearchName.Buffer = ExAllocatePoolWithTag(PagedPool, + SearchName.Length, + TAG_CM); + if (!SearchName.Buffer) + { + /* Fail */ + HvReleaseCell(Hive, TargetKey); + return FALSE; + } + + /* Copy it */ + CmpCopyCompressedName(SearchName.Buffer, + SearchName.MaximumLength, + Node->Name, + Node->NameLength); + } + else + { + /* Name isn't compressed, build it directly from the node */ + IsCompressed = FALSE; + SearchName.Length = Node->NameLength; + SearchName.MaximumLength = Node->NameLength; + SearchName.Buffer = Node->Name; + } + + /* We can release the target key now */ + HvReleaseCell(Hive, TargetKey); + + /* Now get the parent key node */ + Node = (PCM_KEY_NODE)HvGetCell(Hive, ParentKey); + if (!Node) goto Quickie; + + /* Loop all hive storage */ + for (i = 0; i < Hive->StorageTypeCount; i++) + { + /* Check if any subkeys are in this index */ + if (Node->SubKeyCounts[i]) + { + /* Get the cell index */ + //ASSERT(HvIsCellAllocated(Hive, Node->SubKeyLists[i])); + IndexCell = Node->SubKeyLists[i]; + + /* Check if we had anything to release from before */ + if (CellToRelease != HCELL_NIL) + { + /* Release it now */ + HvReleaseCell(Hive, CellToRelease); + CellToRelease = HCELL_NIL; + } + + /* Get the key index for the cell */ + Index = (PCM_KEY_INDEX)HvGetCell(Hive, IndexCell); + if (!Index) goto Quickie; + + /* Release it at the next iteration or below */ + CellToRelease = IndexCell; + + /* Check if this is a root */ + if (Index->Signature == CM_KEY_INDEX_ROOT) + { + /* Get the child inside the root */ + Result = CmpFindSubKeyInRoot(Hive, Index, &SearchName, &Child); + if (Result & 0x80000000) goto Quickie; + if (Child == HCELL_NIL) continue; + + /* We found it, mark the cell dirty */ + HvMarkCellDirty(Hive, IndexCell, FALSE); + + /* Check if we had anything to release from before */ + if (CellToRelease != HCELL_NIL) + { + /* Release it now */ + HvReleaseCell(Hive, CellToRelease); + CellToRelease = HCELL_NIL; + } + + /* Now this child is the index, get the actual key index */ + IndexCell = Child; + Index = (PCM_KEY_INDEX)HvGetCell(Hive, Child); + if (!Index) goto Quickie; + + /* Release it later */ + CellToRelease = Child; + } + + /* Make sure this is a valid index */ + ASSERT((Index->Signature == CM_KEY_INDEX_LEAF) || + (Index->Signature == CM_KEY_FAST_LEAF) || + (Index->Signature == CM_KEY_HASH_LEAF)); + + /* Find the child in the leaf */ + Result = CmpFindSubKeyInLeaf(Hive, Index, &SearchName, &Child); + if (Result & 0x80000000) goto Quickie; + if (Child != HCELL_NIL) + { + /* We found it, free the name now */ + if (IsCompressed) ExFreePool(SearchName.Buffer); + + /* Release the parent key */ + HvReleaseCell(Hive, ParentKey); + + /* Check if we had a left over cell to release */ + if (CellToRelease != HCELL_NIL) + { + /* Release it */ + HvReleaseCell(Hive, CellToRelease); + } + + /* And mark the index cell dirty */ + HvMarkCellDirty(Hive, IndexCell, FALSE); + return TRUE; + } + } + } + +Quickie: + /* Release any cells that we still hold */ + if (Node) HvReleaseCell(Hive, ParentKey); + if (CellToRelease != HCELL_NIL) HvReleaseCell(Hive, CellToRelease); + + /* Free the search name and return failure */ + if (IsCompressed) ExFreePool(SearchName.Buffer); + return FALSE; +} + +HCELL_INDEX +NTAPI +CmpAddToLeaf(IN PHHIVE Hive, + IN HCELL_INDEX LeafCell, + IN HCELL_INDEX NewKey, + IN PUNICODE_STRING Name) +{ + PCM_KEY_INDEX Leaf; + PCM_KEY_FAST_INDEX FastLeaf; + ULONG Size, OldSize, EntrySize, i, j; + HCELL_INDEX NewCell, Child; + LONG Result; + + /* Mark the leaf dirty */ + HvMarkCellDirty(Hive, LeafCell, FALSE); + + /* Get the leaf cell */ + Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); + if (!Leaf) + { + /* Shouldn't happen */ + ASSERT(FALSE); + return HCELL_NIL; + } + + /* Release it */ + HvReleaseCell(Hive, LeafCell); + + /* Check if this is an index leaf */ + if (Leaf->Signature == CM_KEY_INDEX_LEAF) + { + /* This is an old-style leaf */ + FastLeaf = NULL; + EntrySize = sizeof(HCELL_INDEX); + } + else + { + /* Sanity check */ + ASSERT((Leaf->Signature == CM_KEY_FAST_LEAF) || + (Leaf->Signature == CM_KEY_HASH_LEAF)); + + /* This is a new-style optimized fast (or hash) leaf */ + FastLeaf = (PCM_KEY_FAST_INDEX)Leaf; + EntrySize = sizeof(CM_INDEX); + } + + /* Get the current size of the leaf */ + OldSize = HvGetCellSize(Hive, Leaf); + + /* Calculate the size of the free entries */ + Size = OldSize; + Size -= EntrySize * Leaf->Count + FIELD_OFFSET(CM_KEY_INDEX, List); + + /* Assume we'll re-use the same leaf */ + NewCell = LeafCell; + + /* Check if we're out of space */ + if ((Size / EntrySize) < 1) + { + /* Grow the leaf by 1.5x, making sure we can at least fit this entry */ + Size = OldSize + OldSize / 2; + if (Size < (OldSize + EntrySize)) Size = OldSize + EntrySize; + + /* Re-allocate the leaf */ + NewCell = HvReallocateCell(Hive, LeafCell, Size); + if (NewCell == HCELL_NIL) return HCELL_NIL; + + /* Get the leaf cell */ + Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, NewCell); + if (!Leaf) + { + /* This shouldn't happen */ + ASSERT(FALSE); + return HCELL_NIL; + } + + /* Release the cell */ + HvReleaseCell(Hive, NewCell); + + /* Update the fast leaf pointer if we had one */ + if (FastLeaf) FastLeaf = (PCM_KEY_FAST_INDEX)Leaf; + } + + /* Find the insertion point for our entry */ + i = CmpFindSubKeyInLeaf(Hive, Leaf, Name, &Child); + if (i & 0x80000000) return HCELL_NIL; + ASSERT(Child == HCELL_NIL); + + /* Check if we're not last */ + if (i != Leaf->Count) + { + /* Find out where we should go */ + Result = CmpCompareInIndex(Hive, + Name, + i, + Leaf, + &Child); + if (Result == 2) return HCELL_NIL; + ASSERT(Result != 0); + + /* Check if we come after */ + if (Result > 0) + { + /* We do, insert us after the key */ + ASSERT(Result == 1); + i++; + } + + /* Check if we're still not last */ + if (i != Leaf->Count) + { + /* Check if we had a fast leaf or not */ + if (FastLeaf) + { + /* Copy the fast indexes */ + RtlMoveMemory(&FastLeaf->List[i + 1], + &FastLeaf->List[i], + (FastLeaf->Count - i) * sizeof(CM_INDEX)); + } + else + { + /* Copy the indexes themselves */ + RtlMoveMemory(&Leaf->List[i + 1], + &Leaf->List[i], + (Leaf->Count - i) * sizeof(HCELL_INDEX)); + } + } + } + + /* Check if this is a new-style leaf */ + if (FastLeaf) + { + /* Set our cell */ + FastLeaf->List[i].Cell = NewKey; + + /* Check if this is a hash leaf */ + if( FastLeaf->Signature == CM_KEY_HASH_LEAF ) + { + /* Set our hash key */ + FastLeaf->List[i].HashKey = CmpComputeHashKey(0, Name, FALSE); + } + else + { + /* First, clear the name */ + FastLeaf->List[i].NameHint[0] = 0; + FastLeaf->List[i].NameHint[1] = 0; + FastLeaf->List[i].NameHint[2] = 0; + FastLeaf->List[i].NameHint[3] = 0; + + /* Now, figure out if we can fit */ + if (Name->Length / sizeof(WCHAR) < 4) + { + /* We can fit, use our length */ + j = Name->Length / sizeof(WCHAR); + } + else + { + /* We can't, use a maximum of 4 */ + j = 4; + } + + /* Now fill out the name hint */ + do + { + /* Look for invalid characters and break out if we found one */ + if ((USHORT)Name->Buffer[j - 1] > (UCHAR)-1) break; + + /* Otherwise, copy the a character */ + FastLeaf->List[i].NameHint[j - 1] = (UCHAR)Name->Buffer[j - 1]; + } while (--j > 0); + } + } + else + { + /* This is an old-style leaf, just set our index directly */ + Leaf->List[i] = NewKey; + } + + /* Update the leaf count and return the new cell */ + Leaf->Count += 1; + return NewCell; +} + +BOOLEAN +NTAPI +CmpAddSubKey(IN PHHIVE Hive, + IN HCELL_INDEX Parent, + IN HCELL_INDEX Child) +{ + PCM_KEY_NODE KeyNode; + PCM_KEY_INDEX Index; + PCM_KEY_FAST_INDEX OldIndex; + UNICODE_STRING Name; + HCELL_INDEX IndexCell = HCELL_NIL, CellToRelease = HCELL_NIL, LeafCell; + PHCELL_INDEX RootPointer = NULL; + ULONG Type, i; + BOOLEAN IsCompressed; + PAGED_CODE(); + + /* Get the key node */ + KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Child); + if (!KeyNode) + { + /* Shouldn't happen */ + ASSERT(FALSE); + return FALSE; + } + + /* Check if the name is compressed */ + if (KeyNode->Flags & KEY_COMP_NAME) + { + /* Remember for later */ + IsCompressed = TRUE; + + /* Create the compressed name and allocate it */ + Name.Length = CmpCompressedNameSize(KeyNode->Name, KeyNode->NameLength); + Name.MaximumLength = Name.Length; + Name.Buffer = Hive->Allocate(Name.Length, TRUE, TAG_CM); + if (!Name.Buffer) + { + /* Release the cell and fail */ + HvReleaseCell(Hive, Child); + ASSERT(FALSE); + return FALSE; + } + + /* Copy the compressed name */ + CmpCopyCompressedName(Name.Buffer, + Name.MaximumLength, + KeyNode->Name, + KeyNode->NameLength); + } + else + { + /* Remember for later */ + IsCompressed = FALSE; + + /* Build the unicode string */ + Name.Length = KeyNode->NameLength; + Name.MaximumLength = KeyNode->NameLength; + Name.Buffer = &KeyNode->Name[0]; + } + + /* Release the cell */ + HvReleaseCell(Hive, Child); + + /* Get the parent node */ + KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Parent); + if (!KeyNode) + { + /* Not handled */ + ASSERT(FALSE); + } + + /* Find out the type of the cell, and check if this is the first subkey */ + Type = HvGetCellType(Child); + if (!KeyNode->SubKeyCounts[Type]) + { + /* Allocate a fast leaf */ + IndexCell = HvAllocateCell(Hive, sizeof(CM_KEY_FAST_INDEX), Type, HCELL_NIL); + if (IndexCell == HCELL_NIL) + { + /* Not handled */ + ASSERT(FALSE); + } + + /* Get the leaf cell */ + Index = (PCM_KEY_INDEX)HvGetCell(Hive, IndexCell); + if (!Index) + { + /* Shouldn't happen */ + ASSERT(FALSE); + } + + /* Now check what kind of hive we're dealing with */ + if (Hive->Version >= 5) + { + /* XP Hive: Use hash leaf */ + Index->Signature = CM_KEY_HASH_LEAF; + } + else if (Hive->Version >= 3) + { + /* Windows 2000 and ReactOS: Use fast leaf */ + Index->Signature = CM_KEY_FAST_LEAF; + } + else + { + /* NT 4: Use index leaf */ + Index->Signature = CM_KEY_INDEX_LEAF; + } + + /* Setup the index list */ + Index->Count = 0; + KeyNode->SubKeyLists[Type] = IndexCell; + } + else + { + /* We already have an index, get it */ + Index = (PCM_KEY_INDEX)HvGetCell(Hive, KeyNode->SubKeyLists[Type]); + if (!Index) + { + /* Not handled */ + ASSERT(FALSE); + } + + /* Remember to release the cell later */ + CellToRelease = KeyNode->SubKeyLists[Type]; + + /* Check if this is a fast leaf that's gotten too full */ + if ((Index->Signature == CM_KEY_FAST_LEAF) && + (Index->Count >= CmpMaxFastIndexPerHblock)) + { + DPRINT("Doing Fast->Slow Leaf conversion\n"); + + /* Mark this cell as dirty */ + HvMarkCellDirty(Hive, CellToRelease, FALSE); + + /* Convert */ + OldIndex = (PCM_KEY_FAST_INDEX)Index; + + for (i=0; i < OldIndex->Count; i++) + { + Index->List[i] = OldIndex->List[i].Cell; + } + + /* Set the new type value */ + Index->Signature = CM_KEY_INDEX_LEAF; + } + else if (((Index->Signature == CM_KEY_INDEX_LEAF) || + (Index->Signature == CM_KEY_HASH_LEAF)) && + (Index->Count >= CmpMaxIndexPerHblock)) + { + /* This is an old/hashed leaf that's gotten too large, root it */ + IndexCell = HvAllocateCell(Hive, + sizeof(CM_KEY_INDEX) + + sizeof(HCELL_INDEX), + Type, + HCELL_NIL); + if (IndexCell == HCELL_NIL) + { + /* Not handled */ + ASSERT(FALSE); + } + + /* Get the index cell */ + Index = (PCM_KEY_INDEX)HvGetCell(Hive, IndexCell); + if (!Index) + { + /* Shouldn't happen */ + ASSERT(FALSE); + } + + /* Mark the index as a root, and set the index cell */ + Index->Signature = CM_KEY_INDEX_ROOT; + Index->Count = 1; + Index->List[0] = KeyNode->SubKeyLists[Type]; + KeyNode->SubKeyLists[Type] = IndexCell; + } + } + + /* Now we can choose the leaf cell */ + LeafCell = KeyNode->SubKeyLists[Type]; + + /* Check if we turned the index into a root */ + if (Index->Signature == CM_KEY_INDEX_ROOT) + { + /* Not handled yet */ + DPRINT1("Leaf->Root Index Conversion not yet implemented!\n"); + ASSERT(FALSE); + } + + /* Add our leaf cell */ + LeafCell = CmpAddToLeaf(Hive, LeafCell, Child, &Name); + if (LeafCell == HCELL_NIL) + { + /* Not handled */ + ASSERT(FALSE); + } + + /* Update the key counts */ + KeyNode->SubKeyCounts[Type]++; + + /* Check if caller wants us to return the leaf */ + if (RootPointer) + { + /* Return it */ + *RootPointer = LeafCell; + } + else + { + /* Otherwise, mark it as the list index for the cell */ + KeyNode->SubKeyLists[Type] = LeafCell; + } + + /* If the name was compressed, free our copy */ + if (IsCompressed) Hive->Free(Name.Buffer, 0); + + /* Release all our cells */ + if (IndexCell != HCELL_NIL) HvReleaseCell(Hive, IndexCell); + if (CellToRelease != HCELL_NIL) HvReleaseCell(Hive, CellToRelease); + HvReleaseCell(Hive, Parent); + return TRUE; +} + +BOOLEAN +NTAPI +CmpRemoveSubKey(IN PHHIVE Hive, + IN HCELL_INDEX ParentKey, + IN HCELL_INDEX TargetKey) +{ + PCM_KEY_NODE Node; + UNICODE_STRING SearchName; + BOOLEAN IsCompressed; + WCHAR Buffer[50]; + HCELL_INDEX RootCell = HCELL_NIL, LeafCell, ChildCell; + PCM_KEY_INDEX Root = NULL, Leaf; + PCM_KEY_FAST_INDEX Child; + ULONG Storage, RootIndex = 0x80000000, LeafIndex; + BOOLEAN Result = FALSE; + HCELL_INDEX CellToRelease1 = HCELL_NIL, CellToRelease2 = HCELL_NIL; + + /* Get the target key node */ + Node = (PCM_KEY_NODE)HvGetCell(Hive, TargetKey); + if (!Node) return FALSE; + + /* Make sure it's dirty, then release it */ + ASSERT(HvIsCellDirty(Hive, TargetKey)); + HvReleaseCell(Hive, TargetKey); + + /* Check if the name is compressed */ + if (Node->Flags & KEY_COMP_NAME) + { + /* Remember for later */ + IsCompressed = TRUE; + + /* Build the search name */ + SearchName.Length = CmpCompressedNameSize(Node->Name, + Node->NameLength); + SearchName.MaximumLength = SearchName.Length; + + /* Do we need an extra bufer? */ + if (SearchName.MaximumLength > sizeof(Buffer)) + { + /* Allocate one */ + SearchName.Buffer = ExAllocatePoolWithTag(PagedPool, + SearchName.Length, + TAG_CM); + if (!SearchName.Buffer) return FALSE; + } + else + { + /* Otherwise, use our local stack buffer */ + SearchName.Buffer = Buffer; + } + + /* Copy the compressed name */ + CmpCopyCompressedName(SearchName.Buffer, + SearchName.MaximumLength, + Node->Name, + Node->NameLength); + } + else + { + /* It's not compressed, build the name directly from the node */ + IsCompressed = FALSE; + SearchName.Length = Node->NameLength; + SearchName.MaximumLength = Node->NameLength; + SearchName.Buffer = Node->Name; + } + + /* Now get the parent node */ + Node = (PCM_KEY_NODE)HvGetCell(Hive, ParentKey); + if (!Node) goto Exit; + + /* Make sure it's dirty, then release it */ + ASSERT(HvIsCellDirty(Hive, ParentKey)); + HvReleaseCell(Hive, ParentKey); + + /* Get the storage type and make sure it's not empty */ + Storage = HvGetCellType(TargetKey); + ASSERT(Node->SubKeyCounts[Storage] != 0); + //ASSERT(HvIsCellAllocated(Hive, Node->SubKeyLists[Storage])); + + /* Get the leaf cell now */ + LeafCell = Node->SubKeyLists[Storage]; + Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); + if (!Leaf) goto Exit; + + /* Remember to release it later */ + CellToRelease1 = LeafCell; + + /* Check if the leaf is a root */ + if (Leaf->Signature == CM_KEY_INDEX_ROOT) + { + /* Find the child inside the root */ + RootIndex = CmpFindSubKeyInRoot(Hive, Leaf, &SearchName, &ChildCell); + if (RootIndex & 0x80000000) goto Exit; + ASSERT(ChildCell != FALSE); + + /* The root cell is now this leaf */ + Root = Leaf; + RootCell = LeafCell; + + /* And the new leaf is now this child */ + LeafCell = ChildCell; + Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); + if (!Leaf) goto Exit; + + /* Remember to release it later */ + CellToRelease2 = LeafCell; + } + + /* Make sure the leaf is valid */ + ASSERT((Leaf->Signature == CM_KEY_INDEX_LEAF) || + (Leaf->Signature == CM_KEY_FAST_LEAF) || + (Leaf->Signature == CM_KEY_HASH_LEAF)); + + /* Now get the child in the leaf */ + LeafIndex = CmpFindSubKeyInLeaf(Hive, Leaf, &SearchName, &ChildCell); + if (LeafIndex & 0x80000000) goto Exit; + ASSERT(ChildCell != HCELL_NIL); + + /* Decrement key counts and check if this was the last leaf entry */ + Node->SubKeyCounts[Storage]--; + if (!(--Leaf->Count)) + { + /* Free the leaf */ + HvFreeCell(Hive, LeafCell); + + /* Check if we were inside a root */ + if (Root) + { + /* Decrease the root count too, since the leaf is going away */ + if (!(--Root->Count)) + { + /* The root is gone too,n ow */ + HvFreeCell(Hive, RootCell); + Node->SubKeyLists[Storage] = HCELL_NIL; + } + else if (RootIndex < Root->Count) + { + /* Bring everything up by one */ + RtlMoveMemory(&Root->List[RootIndex], + &Root->List[RootIndex + 1], + (Root->Count - RootIndex) * sizeof(HCELL_INDEX)); + } + } + else + { + /* Otherwise, just clear the cell */ + Node->SubKeyLists[Storage] = HCELL_NIL; + } + } + else if (LeafIndex < Leaf->Count) + { + /* Was the leaf a normal index? */ + if (Leaf->Signature == CM_KEY_INDEX_LEAF) + { + /* Bring everything up by one */ + RtlMoveMemory(&Leaf->List[LeafIndex], + &Leaf->List[LeafIndex + 1], + (Leaf->Count - LeafIndex) * sizeof(HCELL_INDEX)); + } + else + { + /* This is a fast index, bring everything up by one */ + Child = (PCM_KEY_FAST_INDEX)Leaf; + RtlMoveMemory(&Child->List[LeafIndex], + &Child->List[LeafIndex+1], + (Child->Count - LeafIndex) * sizeof(CM_INDEX)); + } + } + + /* If we got here, now we're done */ + Result = TRUE; + +Exit: + /* Release any cells we may have been holding */ + if (CellToRelease1 != HCELL_NIL) HvReleaseCell(Hive, CellToRelease1); + if (CellToRelease2 != HCELL_NIL) HvReleaseCell(Hive, CellToRelease2); + + /* Check if the name was compressed and not inside our local buffer */ + if ((IsCompressed) && (SearchName.MaximumLength > sizeof(Buffer))) + { + /* Free the buffer we allocated */ + ExFreePool(SearchName.Buffer); + } + + /* Return the result */ + return Result; +} diff --git a/reactos/ntoskrnl/config/cminit.c b/reactos/ntoskrnl/config/cminit.c index 7aefd8a5156..8ec8826e6d9 100644 --- a/reactos/ntoskrnl/config/cminit.c +++ b/reactos/ntoskrnl/config/cminit.c @@ -1,579 +1,578 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/config/cminit.c - * PURPOSE: Configuration Manager - Hive Initialization - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include "ntoskrnl.h" -#include "cm.h" -#define NDEBUG -#include "debug.h" - -/* FUNCTIONS *****************************************************************/ - -NTSTATUS -NTAPI -CmpInitializeHive(OUT PCMHIVE *RegistryHive, - IN ULONG OperationType, - IN ULONG HiveFlags, - IN ULONG FileType, - IN PVOID HiveData OPTIONAL, - IN HANDLE Primary, - IN HANDLE Log, - IN HANDLE External, - IN PCUNICODE_STRING FileName OPTIONAL, - IN ULONG CheckFlags) -{ - PCMHIVE Hive; - FILE_STANDARD_INFORMATION FileInformation; - IO_STATUS_BLOCK IoStatusBlock; - FILE_FS_SIZE_INFORMATION FileSizeInformation; - NTSTATUS Status; - ULONG Cluster; - - /* Assume failure */ - *RegistryHive = NULL; - - /* - * The following are invalid: - * An external hive that is also internal. - * A log hive that's not a primary hive too. - * A volatile hive that's linked to permanent storage. - * An in-memory initialization without hive data. - * A log hive that's not linked to a correct file type. - */ - if (((External) && ((Primary) || (Log))) || - ((Log) && !(Primary)) || - ((HiveFlags & HIVE_VOLATILE) && ((Primary) || (External) || (Log))) || - ((OperationType == HINIT_MEMORY) && (!HiveData)) || - ((Log) && (FileType != HFILE_TYPE_LOG))) - { - /* Fail the request */ - return STATUS_INVALID_PARAMETER; - } - - /* Check if this is a primary hive */ - if (Primary) - { - /* Get the cluster size */ - Status = ZwQueryVolumeInformationFile(Primary, - &IoStatusBlock, - &FileSizeInformation, - sizeof(FILE_FS_SIZE_INFORMATION), - FileFsSizeInformation); - if (!NT_SUCCESS(Status)) return Status; - - /* Make sure it's not larger then the block size */ - if (FileSizeInformation.BytesPerSector > HBLOCK_SIZE) - { - /* Fail */ - return STATUS_REGISTRY_IO_FAILED; - } - - /* Otherwise, calculate the cluster */ - Cluster = FileSizeInformation.BytesPerSector / HSECTOR_SIZE; - Cluster = max(1, Cluster); - } - else - { - /* Otherwise use cluster 1 */ - Cluster = 1; - } - - /* Allocate the hive */ - Hive = ExAllocatePoolWithTag(NonPagedPool, sizeof(CMHIVE), TAG_CM); - if (!Hive) return STATUS_INSUFFICIENT_RESOURCES; - - /* Setup null fields */ - Hive->UnloadEvent = NULL; - Hive->RootKcb = NULL; - Hive->Frozen = FALSE; - Hive->UnloadWorkItem = NULL; - Hive->GrowOnlyMode = FALSE; - Hive->GrowOffset = 0; - Hive->CellRemapArray = NULL; - Hive->UseCountLog.Next = 0; - Hive->LockHiveLog.Next = 0; - Hive->FileObject = NULL; - Hive->NotifyList.Flink = NULL; - Hive->NotifyList.Blink = NULL; - - /* Set loading flag */ - Hive->HiveIsLoading = TRUE; - - /* Set the current thread as creator */ - Hive->CreatorOwner = KeGetCurrentThread(); - - /* Initialize lists */ - InitializeListHead(&Hive->KcbConvertListHead); - InitializeListHead(&Hive->KnodeConvertListHead); - InitializeListHead(&Hive->TrustClassEntry); - - /* Allocate the view log */ - Hive->ViewLock = ExAllocatePoolWithTag(NonPagedPool, - sizeof(KGUARDED_MUTEX), - TAG_CM); - if (!Hive->ViewLock) return STATUS_INSUFFICIENT_RESOURCES; - - /* Allocate the flush lock */ - Hive->FlusherLock = ExAllocatePoolWithTag(NonPagedPool, - sizeof(ERESOURCE), - TAG_CM); - if (!Hive->FlusherLock) return STATUS_INSUFFICIENT_RESOURCES; - - /* Setup the handles */ - Hive->FileHandles[HFILE_TYPE_PRIMARY] = Primary; - Hive->FileHandles[HFILE_TYPE_LOG] = Log; - Hive->FileHandles[HFILE_TYPE_EXTERNAL] = External; - - /* Initailize the guarded mutex */ - KeInitializeGuardedMutex(Hive->ViewLock); - Hive->ViewLockOwner = NULL; - - /* Initialize the flush lock */ - ExInitializeResourceLite(Hive->FlusherLock); - - /* Setup hive locks */ - ExInitializePushLock((PULONG_PTR)&Hive->HiveLock); - Hive->HiveLockOwner = NULL; - ExInitializePushLock((PULONG_PTR)&Hive->WriterLock); - Hive->WriterLockOwner = NULL; - ExInitializePushLock((PULONG_PTR)&Hive->SecurityLock); - Hive->HiveSecurityLockOwner = NULL; - - /* Clear file names */ - RtlInitEmptyUnicodeString(&Hive->FileUserName, NULL, 0); - RtlInitEmptyUnicodeString(&Hive->FileFullPath, NULL, 0); - - /* Initialize the view list */ - CmpInitHiveViewList(Hive); - - /* Initailize the security cache */ - CmpInitSecurityCache(Hive); - - /* Setup flags */ - Hive->Flags = 0; - Hive->FlushCount = 0; - - /* Set flags */ - Hive->Flags = HiveFlags; - - /* Check how large the file is */ - ZwQueryInformationFile(Primary, - &IoStatusBlock, - &FileInformation, - sizeof(FileInformation), - FileStandardInformation); - Cluster = FileInformation.EndOfFile.LowPart; - - /* Initialize it */ - Status = HvInitialize(&Hive->Hive, - OperationType, - FileType, - HiveFlags, - HiveData, - CmpAllocate, - CmpFree, - CmpFileSetSize, - CmpFileWrite, - CmpFileRead, - CmpFileFlush, - Cluster, - (PUNICODE_STRING)FileName); - if (!NT_SUCCESS(Status)) - { - /* Clear allocations and fail */ - ExFreePool(Hive->ViewLock); - ExFreePool(Hive->FlusherLock); - ExFreePool(Hive); - return Status; - } - - /* Check if we should verify the registry */ - if ((OperationType == HINIT_FILE) || - (OperationType == HINIT_MEMORY) || - (OperationType == HINIT_MEMORY_INPLACE) || - (OperationType == HINIT_MAPFILE)) - { - /* Verify integrity */ - if (CmCheckRegistry((PCMHIVE)Hive, TRUE)) - { - /* Free all alocations */ - ExFreePool(Hive->ViewLock); - ExFreePool(Hive->FlusherLock); - ExFreePool(Hive); - return STATUS_REGISTRY_CORRUPT; - } - } - - /* Lock the hive list */ - ExAcquirePushLockExclusive(&CmpHiveListHeadLock); - - /* Insert this hive */ - InsertHeadList(&CmpHiveListHead, &Hive->HiveList); - - /* Release the lock */ - ExReleasePushLock(&CmpHiveListHeadLock); - - /* Return the hive and success */ - *RegistryHive = (PCMHIVE)Hive; - return STATUS_SUCCESS; -} - -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) -{ - HANDLE EventHandle; - PKEVENT Event; - NTSTATUS Status; - UNICODE_STRING FullName, ExtensionName; - PWCHAR NameBuffer; - USHORT Length; - OBJECT_ATTRIBUTES ObjectAttributes; - IO_STATUS_BLOCK IoStatusBlock; - ULONG AttributeFlags, ShareMode, DesiredAccess, CreateDisposition, IoFlags; - USHORT CompressionState; - FILE_STANDARD_INFORMATION FileInformation; - FILE_FS_SIZE_INFORMATION FsSizeInformation; - - /* Create event */ - Status = CmpCreateEvent(NotificationEvent, &EventHandle, &Event); - if (!NT_SUCCESS(Status)) return Status; - - /* Initialize the full name */ - RtlInitEmptyUnicodeString(&FullName, NULL, 0); - Length = BaseName->Length; - - /* Check if we have an extension */ - if (Extension) - { - /* Update the name length */ - Length += wcslen(Extension) * sizeof(WCHAR) + sizeof(UNICODE_NULL); - - /* Allocate the buffer for the full name */ - NameBuffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM); - if (!NameBuffer) - { - /* Fail */ - ObDereferenceObject(Event); - ZwClose(EventHandle); - return STATUS_NO_MEMORY; - } - - /* Build the full name */ - FullName.Buffer = NameBuffer; - FullName.MaximumLength = Length; - RtlAppendUnicodeStringToString(&FullName, BaseName); - } - else - { - /* The base name is the full name */ - FullName = *BaseName; - NameBuffer = NULL; - } - - /* Initialize the attributes */ - InitializeObjectAttributes(&ObjectAttributes, - &FullName, - OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, - NULL, - NULL); - - /* Check if we can create the hive */ - if ((CreateAllowed) && !(CmpShareSystemHives)) - { - /* Open only or create */ - CreateDisposition = FILE_OPEN_IF; - } - else - { - /* Open only */ - CreateDisposition = FILE_OPEN; - } - - /* Setup the flags */ - IoFlags = FILE_OPEN_FOR_BACKUP_INTENT | - FILE_NO_COMPRESSION | - FILE_RANDOM_ACCESS | - (NoBuffering) ? FILE_NO_INTERMEDIATE_BUFFERING : 0; - - /* Set share and access modes */ - if ((CmpMiniNTBoot) && (CmpShareSystemHives)) - { - /* We're on Live CD or otherwise sharing */ - DesiredAccess = FILE_READ_DATA; - ShareMode = FILE_SHARE_READ; - } - else - { - /* We want to write exclusively */ - ShareMode = 0; - DesiredAccess = FILE_READ_DATA | FILE_WRITE_DATA; - } - - /* Default attributes */ - AttributeFlags = FILE_ATTRIBUTE_NORMAL; - - /* Now create the file */ - Status = ZwCreateFile(Primary, - DesiredAccess, - &ObjectAttributes, - &IoStatusBlock, - NULL, - AttributeFlags, - ShareMode, - CreateDisposition, - FILE_SYNCHRONOUS_IO_NONALERT | IoFlags, - NULL, - 0); - if ((NT_SUCCESS(Status)) && (MarkAsSystemHive)) - { - /* We opened it, mark it as a system hive */ - Status = ZwFsControlFile(*Primary, - EventHandle, - NULL, - NULL, - &IoStatusBlock, - FSCTL_MARK_AS_SYSTEM_HIVE, - NULL, - 0, - NULL, - 0); - if (Status == STATUS_PENDING) - { - /* Wait for completion */ - KeWaitForSingleObject(Event, - Executive, - KernelMode, - FALSE, - NULL); - Status = IoStatusBlock.Status; - } - - /* If we don't support it, ignore the failure */ - if (Status == STATUS_INVALID_DEVICE_REQUEST) Status = STATUS_SUCCESS; - - /* If we failed, close the handle */ - if (!NT_SUCCESS(Status)) ZwClose(*Primary); - } - - /* Check if anything failed until now */ - if (!NT_SUCCESS(Status)) - { - /* Close handles and free buffers */ - if (NameBuffer) ExFreePool(NameBuffer); - ObDereferenceObject(Event); - ZwClose(EventHandle); - return Status; - } - - /* Disable compression */ - CompressionState = 0; - Status = ZwFsControlFile(*Primary, - EventHandle, - NULL, - NULL, - &IoStatusBlock, - FSCTL_SET_COMPRESSION, - &CompressionState, - sizeof(CompressionState), - NULL, - 0); - if (Status == STATUS_PENDING) - { - /* Wait for completion */ - KeWaitForSingleObject(Event, - Executive, - KernelMode, - FALSE, - NULL); - } - - /* Get the disposition */ - *PrimaryDisposition = IoStatusBlock.Information; - if (IoStatusBlock.Information != FILE_CREATED) - { - /* Check how large the file is */ - Status = ZwQueryInformationFile(*Primary, - &IoStatusBlock, - &FileInformation, - sizeof(FileInformation), - FileStandardInformation); - if (NT_SUCCESS(Status)) - { - /* Check if it's 0 bytes */ - if (!FileInformation.EndOfFile.QuadPart) - { - /* Assume it's a new file */ - *PrimaryDisposition = FILE_CREATED; - } - } - } - - /* Check if the caller wants cluster size returned */ - if (ClusterSize) - { - /* Query it */ - Status = ZwQueryVolumeInformationFile(*Primary, - &IoStatusBlock, - &FsSizeInformation, - sizeof(FsSizeInformation), - FileFsSizeInformation); - if (!NT_SUCCESS(Status)) - { - /* Close handles and free buffers */ - if (NameBuffer) ExFreePool(NameBuffer); - ObDereferenceObject(Event); - ZwClose(EventHandle); - return Status; - } - - /* Check if the sector size is invalid */ - if (FsSizeInformation.BytesPerSector > HBLOCK_SIZE) - { - /* Close handles and free buffers */ - if (NameBuffer) ExFreePool(NameBuffer); - ObDereferenceObject(Event); - ZwClose(EventHandle); - return STATUS_CANNOT_LOAD_REGISTRY_FILE; - } - - /* Return cluster size */ - *ClusterSize = max(1, FsSizeInformation.BytesPerSector / HSECTOR_SIZE); - } - - /* Check if we don't need to create a log file */ - if (!Extension) - { - /* We're done, close handles and free buffers */ - if (NameBuffer) ExFreePool(NameBuffer); - ObDereferenceObject(Event); - ZwClose(EventHandle); - return STATUS_SUCCESS; - } - - /* Check if we can create the hive */ - CreateDisposition = CmpShareSystemHives ? FILE_OPEN : FILE_OPEN_IF; - if (*PrimaryDisposition == FILE_CREATED) - { - /* Over-write the existing log file, since this is a new hive */ - CreateDisposition = FILE_SUPERSEDE; - } - - /* Setup the name */ - RtlInitUnicodeString(&ExtensionName, Extension); - RtlAppendUnicodeStringToString(&FullName, &ExtensionName); - - /* Initialize the attributes */ - InitializeObjectAttributes(&ObjectAttributes, - &FullName, - OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, - NULL, - NULL); - - /* Setup the flags */ - IoFlags = FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING; - - /* Check if this is a log file */ - if (!_wcsnicmp(Extension, L".log", 4)) - { - /* Hide log files */ - AttributeFlags |= FILE_ATTRIBUTE_HIDDEN; - } - - /* Now create the file */ - Status = ZwCreateFile(Log, - DesiredAccess, - &ObjectAttributes, - &IoStatusBlock, - NULL, - AttributeFlags, - ShareMode, - CreateDisposition, - IoFlags, - NULL, - 0); - if ((NT_SUCCESS(Status)) && (MarkAsSystemHive)) - { - /* We opened it, mark it as a system hive */ - Status = ZwFsControlFile(*Log, - EventHandle, - NULL, - NULL, - &IoStatusBlock, - FSCTL_MARK_AS_SYSTEM_HIVE, - NULL, - 0, - NULL, - 0); - if (Status == STATUS_PENDING) - { - /* Wait for completion */ - KeWaitForSingleObject(Event, - Executive, - KernelMode, - FALSE, - NULL); - Status = IoStatusBlock.Status; - } - - /* If we don't support it, ignore the failure */ - if (Status == STATUS_INVALID_DEVICE_REQUEST) Status = STATUS_SUCCESS; - - /* If we failed, close the handle */ - if (!NT_SUCCESS(Status)) ZwClose(*Log); - } - - /* Check if anything failed until now */ - if (!NT_SUCCESS(Status)) - { - /* Clear the handle */ - *Log = NULL; - } - else - { - /* Disable compression */ - Status = ZwFsControlFile(*Log, - EventHandle, - NULL, - NULL, - &IoStatusBlock, - FSCTL_SET_COMPRESSION, - &CompressionState, - sizeof(CompressionState), - NULL, - 0); - if (Status == STATUS_PENDING) - { - /* Wait for completion */ - KeWaitForSingleObject(Event, - Executive, - KernelMode, - FALSE, - NULL); - } - - /* Return the disposition */ - *LogDisposition = IoStatusBlock.Information; - } - - /* We're done, close handles and free buffers */ - if (NameBuffer) ExFreePool(NameBuffer); - ObDereferenceObject(Event); - ZwClose(EventHandle); - return STATUS_SUCCESS; -} +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cminit.c + * PURPOSE: Configuration Manager - Hive Initialization + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#define NDEBUG +#include "debug.h" + +/* FUNCTIONS *****************************************************************/ + +NTSTATUS +NTAPI +CmpInitializeHive(OUT PCMHIVE *RegistryHive, + IN ULONG OperationType, + IN ULONG HiveFlags, + IN ULONG FileType, + IN PVOID HiveData OPTIONAL, + IN HANDLE Primary, + IN HANDLE Log, + IN HANDLE External, + IN PCUNICODE_STRING FileName OPTIONAL, + IN ULONG CheckFlags) +{ + PCMHIVE Hive; + FILE_STANDARD_INFORMATION FileInformation; + IO_STATUS_BLOCK IoStatusBlock; + FILE_FS_SIZE_INFORMATION FileSizeInformation; + NTSTATUS Status; + ULONG Cluster; + + /* Assume failure */ + *RegistryHive = NULL; + + /* + * The following are invalid: + * An external hive that is also internal. + * A log hive that's not a primary hive too. + * A volatile hive that's linked to permanent storage. + * An in-memory initialization without hive data. + * A log hive that's not linked to a correct file type. + */ + if (((External) && ((Primary) || (Log))) || + ((Log) && !(Primary)) || + ((HiveFlags & HIVE_VOLATILE) && ((Primary) || (External) || (Log))) || + ((OperationType == HINIT_MEMORY) && (!HiveData)) || + ((Log) && (FileType != HFILE_TYPE_LOG))) + { + /* Fail the request */ + return STATUS_INVALID_PARAMETER; + } + + /* Check if this is a primary hive */ + if (Primary) + { + /* Get the cluster size */ + Status = ZwQueryVolumeInformationFile(Primary, + &IoStatusBlock, + &FileSizeInformation, + sizeof(FILE_FS_SIZE_INFORMATION), + FileFsSizeInformation); + if (!NT_SUCCESS(Status)) return Status; + + /* Make sure it's not larger then the block size */ + if (FileSizeInformation.BytesPerSector > HBLOCK_SIZE) + { + /* Fail */ + return STATUS_REGISTRY_IO_FAILED; + } + + /* Otherwise, calculate the cluster */ + Cluster = FileSizeInformation.BytesPerSector / HSECTOR_SIZE; + Cluster = max(1, Cluster); + } + else + { + /* Otherwise use cluster 1 */ + Cluster = 1; + } + + /* Allocate the hive */ + Hive = ExAllocatePoolWithTag(NonPagedPool, sizeof(CMHIVE), TAG_CM); + if (!Hive) return STATUS_INSUFFICIENT_RESOURCES; + + /* Setup null fields */ + Hive->UnloadEvent = NULL; + Hive->RootKcb = NULL; + Hive->Frozen = FALSE; + Hive->UnloadWorkItem = NULL; + Hive->GrowOnlyMode = FALSE; + Hive->GrowOffset = 0; + Hive->CellRemapArray = NULL; + Hive->UseCountLog.Next = 0; + Hive->LockHiveLog.Next = 0; + Hive->FileObject = NULL; + Hive->NotifyList.Flink = NULL; + Hive->NotifyList.Blink = NULL; + + /* Set loading flag */ + Hive->HiveIsLoading = TRUE; + + /* Set the current thread as creator */ + Hive->CreatorOwner = KeGetCurrentThread(); + + /* Initialize lists */ + InitializeListHead(&Hive->KcbConvertListHead); + InitializeListHead(&Hive->KnodeConvertListHead); + InitializeListHead(&Hive->TrustClassEntry); + + /* Allocate the view log */ + Hive->ViewLock = ExAllocatePoolWithTag(NonPagedPool, + sizeof(KGUARDED_MUTEX), + TAG_CM); + if (!Hive->ViewLock) return STATUS_INSUFFICIENT_RESOURCES; + + /* Allocate the flush lock */ + Hive->FlusherLock = ExAllocatePoolWithTag(NonPagedPool, + sizeof(ERESOURCE), + TAG_CM); + if (!Hive->FlusherLock) return STATUS_INSUFFICIENT_RESOURCES; + + /* Setup the handles */ + Hive->FileHandles[HFILE_TYPE_PRIMARY] = Primary; + Hive->FileHandles[HFILE_TYPE_LOG] = Log; + Hive->FileHandles[HFILE_TYPE_EXTERNAL] = External; + + /* Initailize the guarded mutex */ + KeInitializeGuardedMutex(Hive->ViewLock); + Hive->ViewLockOwner = NULL; + + /* Initialize the flush lock */ + ExInitializeResourceLite(Hive->FlusherLock); + + /* Setup hive locks */ + ExInitializePushLock((PULONG_PTR)&Hive->HiveLock); + Hive->HiveLockOwner = NULL; + ExInitializePushLock((PULONG_PTR)&Hive->WriterLock); + Hive->WriterLockOwner = NULL; + ExInitializePushLock((PULONG_PTR)&Hive->SecurityLock); + Hive->HiveSecurityLockOwner = NULL; + + /* Clear file names */ + RtlInitEmptyUnicodeString(&Hive->FileUserName, NULL, 0); + RtlInitEmptyUnicodeString(&Hive->FileFullPath, NULL, 0); + + /* Initialize the view list */ + CmpInitHiveViewList(Hive); + + /* Initailize the security cache */ + CmpInitSecurityCache(Hive); + + /* Setup flags */ + Hive->Flags = 0; + Hive->FlushCount = 0; + + /* Set flags */ + Hive->Flags = HiveFlags; + + /* Check how large the file is */ + ZwQueryInformationFile(Primary, + &IoStatusBlock, + &FileInformation, + sizeof(FileInformation), + FileStandardInformation); + Cluster = FileInformation.EndOfFile.LowPart; + + /* Initialize it */ + Status = HvInitialize(&Hive->Hive, + OperationType, + FileType, + HiveFlags, + HiveData, + CmpAllocate, + CmpFree, + CmpFileSetSize, + CmpFileWrite, + CmpFileRead, + CmpFileFlush, + Cluster, + (PUNICODE_STRING)FileName); + if (!NT_SUCCESS(Status)) + { + /* Clear allocations and fail */ + ExFreePool(Hive->ViewLock); + ExFreePool(Hive->FlusherLock); + ExFreePool(Hive); + return Status; + } + + /* Check if we should verify the registry */ + if ((OperationType == HINIT_FILE) || + (OperationType == HINIT_MEMORY) || + (OperationType == HINIT_MEMORY_INPLACE) || + (OperationType == HINIT_MAPFILE)) + { + /* Verify integrity */ + if (CmCheckRegistry((PCMHIVE)Hive, TRUE)) + { + /* Free all alocations */ + ExFreePool(Hive->ViewLock); + ExFreePool(Hive->FlusherLock); + ExFreePool(Hive); + return STATUS_REGISTRY_CORRUPT; + } + } + + /* Lock the hive list */ + ExAcquirePushLockExclusive(&CmpHiveListHeadLock); + + /* Insert this hive */ + InsertHeadList(&CmpHiveListHead, &Hive->HiveList); + + /* Release the lock */ + ExReleasePushLock(&CmpHiveListHeadLock); + + /* Return the hive and success */ + *RegistryHive = (PCMHIVE)Hive; + return STATUS_SUCCESS; +} + +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) +{ + HANDLE EventHandle; + PKEVENT Event; + NTSTATUS Status; + UNICODE_STRING FullName, ExtensionName; + PWCHAR NameBuffer; + USHORT Length; + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + ULONG AttributeFlags, ShareMode, DesiredAccess, CreateDisposition, IoFlags; + USHORT CompressionState; + FILE_STANDARD_INFORMATION FileInformation; + FILE_FS_SIZE_INFORMATION FsSizeInformation; + + /* Create event */ + Status = CmpCreateEvent(NotificationEvent, &EventHandle, &Event); + if (!NT_SUCCESS(Status)) return Status; + + /* Initialize the full name */ + RtlInitEmptyUnicodeString(&FullName, NULL, 0); + Length = BaseName->Length; + + /* Check if we have an extension */ + if (Extension) + { + /* Update the name length */ + Length += wcslen(Extension) * sizeof(WCHAR) + sizeof(UNICODE_NULL); + + /* Allocate the buffer for the full name */ + NameBuffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM); + if (!NameBuffer) + { + /* Fail */ + ObDereferenceObject(Event); + ZwClose(EventHandle); + return STATUS_NO_MEMORY; + } + + /* Build the full name */ + FullName.Buffer = NameBuffer; + FullName.MaximumLength = Length; + RtlAppendUnicodeStringToString(&FullName, BaseName); + } + else + { + /* The base name is the full name */ + FullName = *BaseName; + NameBuffer = NULL; + } + + /* Initialize the attributes */ + InitializeObjectAttributes(&ObjectAttributes, + &FullName, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL); + + /* Check if we can create the hive */ + if ((CreateAllowed) && !(CmpShareSystemHives)) + { + /* Open only or create */ + CreateDisposition = FILE_OPEN_IF; + } + else + { + /* Open only */ + CreateDisposition = FILE_OPEN; + } + + /* Setup the flags */ + IoFlags = FILE_OPEN_FOR_BACKUP_INTENT | + FILE_NO_COMPRESSION | + FILE_RANDOM_ACCESS | + (NoBuffering) ? FILE_NO_INTERMEDIATE_BUFFERING : 0; + + /* Set share and access modes */ + if ((CmpMiniNTBoot) && (CmpShareSystemHives)) + { + /* We're on Live CD or otherwise sharing */ + DesiredAccess = FILE_READ_DATA; + ShareMode = FILE_SHARE_READ; + } + else + { + /* We want to write exclusively */ + ShareMode = 0; + DesiredAccess = FILE_READ_DATA | FILE_WRITE_DATA; + } + + /* Default attributes */ + AttributeFlags = FILE_ATTRIBUTE_NORMAL; + + /* Now create the file */ + Status = ZwCreateFile(Primary, + DesiredAccess, + &ObjectAttributes, + &IoStatusBlock, + NULL, + AttributeFlags, + ShareMode, + CreateDisposition, + FILE_SYNCHRONOUS_IO_NONALERT | IoFlags, + NULL, + 0); + if ((NT_SUCCESS(Status)) && (MarkAsSystemHive)) + { + /* We opened it, mark it as a system hive */ + Status = ZwFsControlFile(*Primary, + EventHandle, + NULL, + NULL, + &IoStatusBlock, + FSCTL_MARK_AS_SYSTEM_HIVE, + NULL, + 0, + NULL, + 0); + if (Status == STATUS_PENDING) + { + /* Wait for completion */ + KeWaitForSingleObject(Event, + Executive, + KernelMode, + FALSE, + NULL); + Status = IoStatusBlock.Status; + } + + /* If we don't support it, ignore the failure */ + if (Status == STATUS_INVALID_DEVICE_REQUEST) Status = STATUS_SUCCESS; + + /* If we failed, close the handle */ + if (!NT_SUCCESS(Status)) ZwClose(*Primary); + } + + /* Check if anything failed until now */ + if (!NT_SUCCESS(Status)) + { + /* Close handles and free buffers */ + if (NameBuffer) ExFreePool(NameBuffer); + ObDereferenceObject(Event); + ZwClose(EventHandle); + return Status; + } + + /* Disable compression */ + CompressionState = 0; + Status = ZwFsControlFile(*Primary, + EventHandle, + NULL, + NULL, + &IoStatusBlock, + FSCTL_SET_COMPRESSION, + &CompressionState, + sizeof(CompressionState), + NULL, + 0); + if (Status == STATUS_PENDING) + { + /* Wait for completion */ + KeWaitForSingleObject(Event, + Executive, + KernelMode, + FALSE, + NULL); + } + + /* Get the disposition */ + *PrimaryDisposition = IoStatusBlock.Information; + if (IoStatusBlock.Information != FILE_CREATED) + { + /* Check how large the file is */ + Status = ZwQueryInformationFile(*Primary, + &IoStatusBlock, + &FileInformation, + sizeof(FileInformation), + FileStandardInformation); + if (NT_SUCCESS(Status)) + { + /* Check if it's 0 bytes */ + if (!FileInformation.EndOfFile.QuadPart) + { + /* Assume it's a new file */ + *PrimaryDisposition = FILE_CREATED; + } + } + } + + /* Check if the caller wants cluster size returned */ + if (ClusterSize) + { + /* Query it */ + Status = ZwQueryVolumeInformationFile(*Primary, + &IoStatusBlock, + &FsSizeInformation, + sizeof(FsSizeInformation), + FileFsSizeInformation); + if (!NT_SUCCESS(Status)) + { + /* Close handles and free buffers */ + if (NameBuffer) ExFreePool(NameBuffer); + ObDereferenceObject(Event); + ZwClose(EventHandle); + return Status; + } + + /* Check if the sector size is invalid */ + if (FsSizeInformation.BytesPerSector > HBLOCK_SIZE) + { + /* Close handles and free buffers */ + if (NameBuffer) ExFreePool(NameBuffer); + ObDereferenceObject(Event); + ZwClose(EventHandle); + return STATUS_CANNOT_LOAD_REGISTRY_FILE; + } + + /* Return cluster size */ + *ClusterSize = max(1, FsSizeInformation.BytesPerSector / HSECTOR_SIZE); + } + + /* Check if we don't need to create a log file */ + if (!Extension) + { + /* We're done, close handles and free buffers */ + if (NameBuffer) ExFreePool(NameBuffer); + ObDereferenceObject(Event); + ZwClose(EventHandle); + return STATUS_SUCCESS; + } + + /* Check if we can create the hive */ + CreateDisposition = CmpShareSystemHives ? FILE_OPEN : FILE_OPEN_IF; + if (*PrimaryDisposition == FILE_CREATED) + { + /* Over-write the existing log file, since this is a new hive */ + CreateDisposition = FILE_SUPERSEDE; + } + + /* Setup the name */ + RtlInitUnicodeString(&ExtensionName, Extension); + RtlAppendUnicodeStringToString(&FullName, &ExtensionName); + + /* Initialize the attributes */ + InitializeObjectAttributes(&ObjectAttributes, + &FullName, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL); + + /* Setup the flags */ + IoFlags = FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING; + + /* Check if this is a log file */ + if (!_wcsnicmp(Extension, L".log", 4)) + { + /* Hide log files */ + AttributeFlags |= FILE_ATTRIBUTE_HIDDEN; + } + + /* Now create the file */ + Status = ZwCreateFile(Log, + DesiredAccess, + &ObjectAttributes, + &IoStatusBlock, + NULL, + AttributeFlags, + ShareMode, + CreateDisposition, + IoFlags, + NULL, + 0); + if ((NT_SUCCESS(Status)) && (MarkAsSystemHive)) + { + /* We opened it, mark it as a system hive */ + Status = ZwFsControlFile(*Log, + EventHandle, + NULL, + NULL, + &IoStatusBlock, + FSCTL_MARK_AS_SYSTEM_HIVE, + NULL, + 0, + NULL, + 0); + if (Status == STATUS_PENDING) + { + /* Wait for completion */ + KeWaitForSingleObject(Event, + Executive, + KernelMode, + FALSE, + NULL); + Status = IoStatusBlock.Status; + } + + /* If we don't support it, ignore the failure */ + if (Status == STATUS_INVALID_DEVICE_REQUEST) Status = STATUS_SUCCESS; + + /* If we failed, close the handle */ + if (!NT_SUCCESS(Status)) ZwClose(*Log); + } + + /* Check if anything failed until now */ + if (!NT_SUCCESS(Status)) + { + /* Clear the handle */ + *Log = NULL; + } + else + { + /* Disable compression */ + Status = ZwFsControlFile(*Log, + EventHandle, + NULL, + NULL, + &IoStatusBlock, + FSCTL_SET_COMPRESSION, + &CompressionState, + sizeof(CompressionState), + NULL, + 0); + if (Status == STATUS_PENDING) + { + /* Wait for completion */ + KeWaitForSingleObject(Event, + Executive, + KernelMode, + FALSE, + NULL); + } + + /* Return the disposition */ + *LogDisposition = IoStatusBlock.Information; + } + + /* We're done, close handles and free buffers */ + if (NameBuffer) ExFreePool(NameBuffer); + ObDereferenceObject(Event); + ZwClose(EventHandle); + return STATUS_SUCCESS; +} diff --git a/reactos/ntoskrnl/config/cmkcbncb.c b/reactos/ntoskrnl/config/cmkcbncb.c index 2375acebfb6..d741dabd047 100644 --- a/reactos/ntoskrnl/config/cmkcbncb.c +++ b/reactos/ntoskrnl/config/cmkcbncb.c @@ -1,825 +1,824 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/config/cmkcbncb.c - * PURPOSE: Routines for handling KCBs, NCBs, as well as key hashes. - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include -#define NDEBUG -#include -#include "cm.h" - -/* GLOBALS *******************************************************************/ - -ULONG CmpHashTableSize = 2048; -PCM_KEY_HASH_TABLE_ENTRY CmpCacheTable; -PCM_NAME_HASH_TABLE_ENTRY CmpNameCacheTable; - -BOOLEAN CmpHoldLazyFlush; - -/* FUNCTIONS *****************************************************************/ - -VOID -NTAPI -CmpInitializeCache(VOID) -{ - ULONG Length, i; - - /* Calculate length for the table */ - Length = CmpHashTableSize * sizeof(CM_KEY_HASH_TABLE_ENTRY); - - /* Allocate it */ - CmpCacheTable = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM); - if (!CmpCacheTable) - { - /* Take the system down */ - KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 3, 1, 0, 0); - } - - /* Zero out the table */ - RtlZeroMemory(CmpCacheTable, Length); - - /* Initialize the locks */ - for (i = 0;i < CmpHashTableSize; i++) - { - /* Setup the pushlock */ - ExInitializePushLock((PULONG_PTR)&CmpCacheTable[i].Lock); - } - - /* Calculate length for the name cache */ - Length = CmpHashTableSize * sizeof(CM_NAME_HASH_TABLE_ENTRY); - - /* Now allocate the name cache table */ - CmpNameCacheTable = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM); - if (!CmpNameCacheTable) - { - /* Take the system down */ - KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 3, 3, 0, 0); - } - - /* Zero out the table */ - RtlZeroMemory(CmpNameCacheTable, Length); - - /* Initialize the locks */ - for (i = 0;i < CmpHashTableSize; i++) - { - /* Setup the pushlock */ - ExInitializePushLock((PULONG_PTR)&CmpNameCacheTable[i].Lock); - } - - /* Setup the delayed close table */ - CmpInitializeDelayedCloseTable(); -} - -VOID -NTAPI -CmpRemoveKeyHash(IN PCM_KEY_HASH KeyHash) -{ - PCM_KEY_HASH *Prev; - PCM_KEY_HASH Current; - - /* Lookup all the keys in this index entry */ - Prev = &GET_HASH_ENTRY(CmpCacheTable, KeyHash->ConvKey).Entry; - while (TRUE) - { - /* Save the current one and make sure it's valid */ - Current = *Prev; - ASSERT(Current != NULL); - - /* Check if it matches */ - if (Current == KeyHash) - { - /* Then write the previous one */ - *Prev = Current->NextHash; - break; - } - - /* Otherwise, keep going */ - Prev = &Current->NextHash; - } -} - -PCM_KEY_CONTROL_BLOCK -NTAPI -CmpInsertKeyHash(IN PCM_KEY_HASH KeyHash, - IN BOOLEAN IsFake) -{ - ULONG i; - PCM_KEY_HASH Entry; - - /* Get the hash index */ - i = GET_HASH_INDEX(KeyHash->ConvKey); - - /* If this is a fake key, increase the key cell to use the parent data */ - if (IsFake) KeyHash->KeyCell++; - - /* Loop the hash table */ - Entry = CmpCacheTable[i].Entry; - while (Entry) - { - /* Check if this matches */ - if ((KeyHash->ConvKey == Entry->ConvKey) && - (KeyHash->KeyCell == Entry->KeyCell) && - (KeyHash->KeyHive == Entry->KeyHive)) - { - /* Return it */ - return CONTAINING_RECORD(Entry, CM_KEY_CONTROL_BLOCK, KeyHash); - } - - /* Keep looping */ - Entry = Entry->NextHash; - } - - /* No entry found, add this one and return NULL since none existed */ - KeyHash->NextHash = CmpCacheTable[i].Entry; - CmpCacheTable[i].Entry = KeyHash; - return NULL; -} - -PCM_NAME_CONTROL_BLOCK -NTAPI -CmpGetNameControlBlock(IN PUNICODE_STRING NodeName) -{ - PCM_NAME_CONTROL_BLOCK Ncb = NULL; - ULONG ConvKey = 0; - PWCHAR p, pp; - ULONG i; - BOOLEAN IsCompressed = TRUE, Found = FALSE; - PCM_NAME_HASH HashEntry; - ULONG Length, NcbSize; - - /* Loop the name */ - p = NodeName->Buffer; - for (i = 0; i < NodeName->Length; i += sizeof(WCHAR)) - { - /* Make sure it's not a slash */ - if (*p != OBJ_NAME_PATH_SEPARATOR) - { - /* Add it to the hash */ - ConvKey = 37 * ConvKey + RtlUpcaseUnicodeChar(*p); - } - - /* Next character */ - p++; - } - - /* Set assumed lengh and loop to check */ - Length = NodeName->Length / sizeof(WCHAR); - for (i = 0; i < (NodeName->Length / sizeof(WCHAR)); i++) - { - /* Check if this is a valid character */ - if (*NodeName->Buffer > (UCHAR)-1) - { - /* This is the actual size, and we know we're not compressed */ - Length = NodeName->Length; - IsCompressed = FALSE; - } - } - - /* Lock the NCB entry */ - CmpAcquireNcbLockExclusiveByKey(ConvKey); - - /* Get the hash entry */ - HashEntry = GET_HASH_ENTRY(CmpNameCacheTable, ConvKey).Entry; - while (HashEntry) - { - /* Get the current NCB */ - Ncb = CONTAINING_RECORD(HashEntry, CM_NAME_CONTROL_BLOCK, NameHash); - - /* Check if the hash matches */ - if ((ConvKey = HashEntry->ConvKey) && (Length = Ncb->NameLength)) - { - /* Assume success */ - Found = TRUE; - - /* If the NCB is compressed, do a compressed name compare */ - if (Ncb->Compressed) - { - /* Compare names */ - if (CmpCompareCompressedName(NodeName, Ncb->Name, Length)) - { - /* We failed */ - Found = FALSE; - } - } - else - { - /* Do a manual compare */ - p = NodeName->Buffer; - pp = Ncb->Name; - for (i = 0; i < Ncb->NameLength; i += sizeof(WCHAR)) - { - /* Compare the character */ - if (RtlUpcaseUnicodeChar(*p) != RtlUpcaseUnicodeChar(*pp)) - { - /* Failed */ - Found = FALSE; - break; - } - - /* Next chars */ - p++; - pp++; - } - } - - /* Check if we found a name */ - if (Found) - { - /* Reference it */ - Ncb->RefCount++; - } - } - - /* Go to the next hash */ - HashEntry = HashEntry->NextHash; - } - - /* Check if we didn't find it */ - if (!Found) - { - /* Allocate one */ - NcbSize = FIELD_OFFSET(CM_NAME_CONTROL_BLOCK, Name) + Length; - Ncb = ExAllocatePoolWithTag(PagedPool, NcbSize, TAG_CM); - if (!Ncb) - { - /* Release the lock and fail */ - CmpReleaseNcbLockByKey(ConvKey); - return NULL; - } - - /* Clear it out */ - RtlZeroMemory(Ncb, NcbSize); - - /* Check if the name was compressed */ - if (IsCompressed) - { - /* Copy the compressed name */ - Ncb->Compressed = TRUE; - for (i = 0; i < Length; i++) - { - /* Copy Unicode to ANSI */ - ((PCHAR)Ncb->Name)[i] = (CHAR)RtlUpcaseUnicodeChar(NodeName->Buffer[i]); - } - } - else - { - /* Copy the name directly */ - Ncb->Compressed = FALSE; - for (i = 0; i < Length; i++) - { - /* Copy each unicode character */ - Ncb->Name[i] = RtlUpcaseUnicodeChar(NodeName->Buffer[i]); - } - } - - /* Setup the rest of the NCB */ - Ncb->ConvKey = ConvKey; - Ncb->RefCount++; - Ncb->NameLength = Length; - - /* Insert the name in the hash table */ - HashEntry = &Ncb->NameHash; - HashEntry->NextHash = GET_HASH_ENTRY(CmpNameCacheTable, ConvKey).Entry; - GET_HASH_ENTRY(CmpNameCacheTable, ConvKey).Entry = HashEntry; - } - - /* Release NCB lock */ - CmpReleaseNcbLockByKey(ConvKey); - - /* Return the NCB found */ - return Ncb; -} - -VOID -NTAPI -CmpRemoveKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb) -{ - /* Make sure that the registry and KCB are utterly locked */ - ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) || - (CmpTestRegistryLockExclusive() == TRUE)); - - /* Remove the key hash */ - CmpRemoveKeyHash(&Kcb->KeyHash); -} - -VOID -NTAPI -CmpDereferenceNameControlBlockWithLock(IN PCM_NAME_CONTROL_BLOCK Ncb) -{ - PCM_NAME_HASH Current, *Next; - ULONG ConvKey = Ncb->ConvKey; - - /* Lock the NCB */ - CmpAcquireNcbLockExclusiveByKey(ConvKey); - - /* Decrease the reference count */ - if (!(--Ncb->RefCount)) - { - /* Find the NCB in the table */ - Next = &GET_HASH_ENTRY(CmpNameCacheTable, Ncb->ConvKey).Entry; - while (TRUE) - { - /* Check the current entry */ - Current = *Next; - ASSERT(Current != NULL); - if (Current == &Ncb->NameHash) - { - /* Unlink it */ - *Next = Current->NextHash; - break; - } - - /* Get to the next one */ - Next = &Current->NextHash; - } - - /* Found it, now free it */ - ExFreePool(Ncb); - } - - /* Release the lock */ - CmpReleaseNcbLockByKey(ConvKey); -} - -BOOLEAN -NTAPI -CmpReferenceKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb) -{ - /* Check if this is the KCB's first reference */ - if (Kcb->RefCount == 0) - { - /* Check if the KCB is locked in shared mode */ - if (!CmpIsKcbLockedExclusive(Kcb)) - { - /* Convert it to exclusive */ - if (!CmpTryToConvertKcbSharedToExclusive(Kcb)) - { - /* Set the delayed close index so that we can be ignored */ - Kcb->DelayedCloseIndex = 1; - - /* Increase the reference count while we release the lock */ - InterlockedIncrement((PLONG)&Kcb->RefCount); - - /* Go from shared to exclusive */ - CmpConvertKcbSharedToExclusive(Kcb); - - /* Decrement the reference count; the lock is now held again */ - InterlockedDecrement((PLONG)&Kcb->RefCount); - - /* Check if we still control the index */ - if (Kcb->DelayedCloseIndex == 1) - { - /* Reset it */ - Kcb->DelayedCloseIndex = 0; - } - else - { - /* Sanity check */ - ASSERT((Kcb->DelayedCloseIndex == CmpDelayedCloseSize) || - (Kcb->DelayedCloseIndex == 0)); - } - } - } - } - - /* Increase the reference count */ - if ((InterlockedIncrement((PLONG)&Kcb->RefCount) & 0xFFFF) == 0) - { - /* We've overflown to 64K references, bail out */ - InterlockedDecrement((PLONG)&Kcb->RefCount); - return FALSE; - } - - /* Check if this was the last close index */ - if (!Kcb->DelayedCloseIndex) - { - /* Check if the KCB is locked in shared mode */ - if (!CmpIsKcbLockedExclusive(Kcb)) - { - /* Convert it to exclusive */ - if (!CmpTryToConvertKcbSharedToExclusive(Kcb)) - { - /* Go from shared to exclusive */ - CmpConvertKcbSharedToExclusive(Kcb); - } - } - - /* If we're still the last entry, remove us */ - if (!Kcb->DelayedCloseIndex) CmpRemoveFromDelayedClose(Kcb); - } - - /* Return success */ - return TRUE; -} - -VOID -NTAPI -CmpCleanUpKcbValueCache(IN PCM_KEY_CONTROL_BLOCK Kcb) -{ - PULONG_PTR CachedList; - ULONG i; - - /* Sanity check */ - ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) || - (CmpTestRegistryLockExclusive() == TRUE)); - - /* Check if the value list is cached */ - if (CMP_IS_CELL_CACHED(Kcb->ValueCache.ValueList)) - { - /* Get the cache list */ - CachedList = (PULONG_PTR)CMP_GET_CACHED_DATA(Kcb->ValueCache.ValueList); - for (i = 0; i < Kcb->ValueCache.Count; i++) - { - /* Check if this cell is cached */ - if (CMP_IS_CELL_CACHED(CachedList[i])) - { - /* Free it */ - ExFreePool((PVOID)CMP_GET_CACHED_CELL(CachedList[i])); - } - } - - /* Now free the list */ - ExFreePool((PVOID)CMP_GET_CACHED_CELL(Kcb->ValueCache.ValueList)); - Kcb->ValueCache.ValueList = HCELL_NIL; - } - else if (Kcb->ExtFlags & CM_KCB_SYM_LINK_FOUND) - { - /* This is a sym link, check if there's only one reference left */ - if ((((PCM_KEY_CONTROL_BLOCK)Kcb->ValueCache.RealKcb)->RefCount == 1) && - !(((PCM_KEY_CONTROL_BLOCK)Kcb->ValueCache.RealKcb)->Delete)) - { - /* Disable delay close for the KCB */ - ((PCM_KEY_CONTROL_BLOCK)Kcb->ValueCache.RealKcb)->ExtFlags |= CM_KCB_NO_DELAY_CLOSE; - } - - /* Dereference the KCB */ - CmpDelayDerefKeyControlBlock((PCM_KEY_CONTROL_BLOCK)Kcb->ValueCache.RealKcb); - Kcb->ExtFlags &= ~CM_KCB_SYM_LINK_FOUND; - } -} - -VOID -NTAPI -CmpCleanUpKcbCacheWithLock(IN PCM_KEY_CONTROL_BLOCK Kcb, - IN BOOLEAN LockHeldExclusively) -{ - PCM_KEY_CONTROL_BLOCK Parent; - PAGED_CODE(); - - /* Sanity checks */ - ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) || - (CmpTestRegistryLockExclusive() == TRUE)); - ASSERT(Kcb->RefCount == 0); - - /* Cleanup the value cache */ - CmpCleanUpKcbValueCache(Kcb); - - /* Reference the NCB */ - CmpDereferenceNameControlBlockWithLock(Kcb->NameBlock); - - /* Check if we have an index hint block and free it */ - if (Kcb->ExtFlags & CM_KCB_SUBKEY_HINT) ExFreePool(Kcb->IndexHint); - - /* Check if we were already deleted */ - Parent = Kcb->ParentKcb; - if (!Kcb->Delete) CmpRemoveKeyControlBlock(Kcb); - - /* Free the KCB as well */ - CmpFreeKeyControlBlock(Kcb); - - /* Check if we have a parent */ - if (Parent) - { - /* Dereference the parent */ - LockHeldExclusively ? - CmpDereferenceKeyControlBlockWithLock(Kcb,LockHeldExclusively) : - CmpDelayDerefKeyControlBlock(Kcb); - } -} - -VOID -NTAPI -CmpDereferenceKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb) -{ - LONG OldRefCount, NewRefCount; - ULONG ConvKey; - - /* Get the ref count and update it */ - OldRefCount = *(PLONG)&Kcb->RefCount; - NewRefCount = OldRefCount - 1; - - /* Check if we still have references */ - if( (NewRefCount & 0xFFFF) > 0) - { - /* Do the dereference */ - if (InterlockedCompareExchange((PLONG)&Kcb->RefCount, - NewRefCount, - OldRefCount) == OldRefCount) - { - /* We'de done */ - return; - } - } - - /* Save the key */ - ConvKey = Kcb->ConvKey; - - /* Do the dereference inside the lock */ - CmpAcquireKcbLockExclusive(Kcb); - CmpDereferenceKeyControlBlockWithLock(Kcb, FALSE); - CmpReleaseKcbLockByKey(ConvKey); -} - -VOID -NTAPI -CmpDereferenceKeyControlBlockWithLock(IN PCM_KEY_CONTROL_BLOCK Kcb, - IN BOOLEAN LockHeldExclusively) -{ - /* Sanity check */ - ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) || - (CmpTestRegistryLockExclusive() == TRUE)); - - /* Check if this is the last reference */ - if ((InterlockedDecrement((PLONG)&Kcb->RefCount) & 0xFFFF) == 0) - { - /* Check if we should do a direct delete */ - if (((CmpHoldLazyFlush) && - !(Kcb->ExtFlags & CM_KCB_SYM_LINK_FOUND) && - !(Kcb->Flags & KEY_SYM_LINK)) || - (Kcb->ExtFlags & CM_KCB_NO_DELAY_CLOSE) || - (Kcb->Delete)) - { - /* Clean up the KCB*/ - CmpCleanUpKcbCacheWithLock(Kcb, LockHeldExclusively); - } - else - { - /* Otherwise, use delayed close */ - CmpAddToDelayedClose(Kcb, LockHeldExclusively); - } - } -} - -VOID -NTAPI -InitializeKCBKeyBodyList(IN PCM_KEY_CONTROL_BLOCK Kcb) -{ - /* Initialize the list */ - InitializeListHead(&Kcb->KeyBodyListHead); - - /* Clear the bodies */ - Kcb->KeyBodyArray[0] = - Kcb->KeyBodyArray[1] = - Kcb->KeyBodyArray[2] = - Kcb->KeyBodyArray[3] = NULL; -} - -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 Kcb, FoundKcb = NULL; - UNICODE_STRING NodeName; - ULONG ConvKey = 0, i; - BOOLEAN IsFake, HashLock; - PWCHAR p; - - /* Make sure we own this hive in case it's being unloaded */ - if ((Hive->HiveFlags & HIVE_IS_UNLOADING) && - (((PCMHIVE)Hive)->CreatorOwner != KeGetCurrentThread())) - { - /* Fail */ - return NULL; - } - - /* Check if this is a fake KCB */ - IsFake = Flags & CMP_CREATE_FAKE_KCB ? TRUE : FALSE; - - /* If we have a parent, use its ConvKey */ - if (Parent) ConvKey = Parent->ConvKey; - - /* Make a copy of the name */ - NodeName = *KeyName; - - /* Remove leading slash */ - while ((NodeName.Length) && (*NodeName.Buffer == OBJ_NAME_PATH_SEPARATOR)) - { - /* Move the buffer by one */ - NodeName.Buffer++; - NodeName.Length -= sizeof(WCHAR); - } - - /* Make sure we didn't get just a slash or something */ - ASSERT(NodeName.Length > 0); - - /* Now setup the hash */ - p = NodeName.Buffer; - for (i = 0; i < NodeName.Length; i += sizeof(WCHAR)) - { - /* Make sure it's a valid character */ - if (*p != OBJ_NAME_PATH_SEPARATOR) - { - /* Add this key to the hash */ - ConvKey = 37 * ConvKey + RtlUpcaseUnicodeChar(*p); - } - - /* Move on */ - p++; - } - - /* Allocate the KCB */ - Kcb = CmpAllocateKeyControlBlock(); - if (!Kcb) return NULL; - - /* Initailize the key list */ - InitializeKCBKeyBodyList(Kcb); - - /* Set it up */ - Kcb->Delete = FALSE; - Kcb->RefCount = 1; - Kcb->KeyHive = Hive; - Kcb->KeyCell = Index; - Kcb->ConvKey = ConvKey; - Kcb->DelayedCloseIndex = CmpDelayedCloseSize; - Kcb->InDelayClose = 0; - - /* Check if we have two hash entires */ - HashLock = Flags & CMP_LOCK_HASHES_FOR_KCB ? TRUE : FALSE; - if (!HashLock) - { - /* It's not locked, do we have a parent? */ - if (Parent) - { - /* Lock the parent KCB and ourselves */ - CmpAcquireTwoKcbLocksExclusiveByKey(ConvKey, Parent->ConvKey); - } - else - { - /* Lock only ourselves */ - CmpAcquireKcbLockExclusive(Kcb); - } - } - - /* Check if we already have a KCB */ - FoundKcb = CmpInsertKeyHash(&Kcb->KeyHash, IsFake); - if (FoundKcb) - { - /* Sanity check */ - ASSERT(!FoundKcb->Delete); - - /* Free the one we allocated and reference this one */ - CmpFreeKeyControlBlock(Kcb); - Kcb = FoundKcb; - if (!CmpReferenceKeyControlBlock(Kcb)) - { - /* We got too many handles */ - ASSERT(Kcb->RefCount + 1 != 0); - Kcb = NULL; - } - else - { - /* Check if we're not creating a fake one, but it used to be fake */ - if ((Kcb->ExtFlags & CM_KCB_KEY_NON_EXIST) && !(IsFake)) - { - /* Set the hive and cell */ - Kcb->KeyHive = Hive; - Kcb->KeyCell = Index; - - /* This means that our current information is invalid */ - Kcb->ExtFlags = CM_KCB_INVALID_CACHED_INFO; - } - - /* Check if we didn't have any valid data */ - if (!(Kcb->ExtFlags & (CM_KCB_NO_SUBKEY | - CM_KCB_SUBKEY_ONE | - CM_KCB_SUBKEY_HINT))) - { - /* Calculate the index hint */ - Kcb->SubKeyCount = Node->SubKeyCounts[Stable] + - Node->SubKeyCounts[Volatile]; - - /* Cached information is now valid */ - Kcb->ExtFlags &= ~CM_KCB_INVALID_CACHED_INFO; - } - - /* Setup the other data */ - Kcb->KcbLastWriteTime = Node->LastWriteTime; - Kcb->KcbMaxNameLen = (USHORT)Node->MaxNameLen; - Kcb->KcbMaxValueNameLen = (USHORT)Node->MaxValueNameLen; - Kcb->KcbMaxValueDataLen = Node->MaxValueDataLen; - } - } - else - { - /* No KCB, do we have a parent? */ - if (Parent) - { - /* Reference the parent */ - if (((Parent->TotalLevels + 1) < 512) && - (CmpReferenceKeyControlBlock(Parent))) - { - /* Link it */ - Kcb->ParentKcb = Parent; - Kcb->TotalLevels = Parent->TotalLevels + 1; - } - else - { - /* Remove the KCB and free it */ - CmpRemoveKeyControlBlock(Kcb); - CmpFreeKeyControlBlock(Kcb); - Kcb = NULL; - } - } - else - { - /* No parent, this is the root node */ - Kcb->ParentKcb = NULL; - Kcb->TotalLevels = 1; - } - - /* Check if we have a KCB */ - if (Kcb) - { - /* Get the NCB */ - Kcb->NameBlock = CmpGetNameControlBlock(&NodeName); - if (Kcb->NameBlock) - { - /* Fill it out */ - Kcb->ValueCache.Count = Node->ValueList.Count; - Kcb->ValueCache.ValueList = Node->ValueList.List; - Kcb->Flags = Node->Flags; - Kcb->ExtFlags = 0; - Kcb->DelayedCloseIndex = CmpDelayedCloseSize; - - /* Remember if this is a fake key */ - if (IsFake) Kcb->ExtFlags |= CM_KCB_KEY_NON_EXIST; - - /* Setup the other data */ - Kcb->SubKeyCount = Node->SubKeyCounts[Stable] + - Node->SubKeyCounts[Volatile]; - Kcb->KcbLastWriteTime = Node->LastWriteTime; - Kcb->KcbMaxNameLen = (USHORT)Node->MaxNameLen; - Kcb->KcbMaxValueNameLen = (USHORT)Node->MaxValueNameLen; - Kcb->KcbMaxValueDataLen = (USHORT)Node->MaxValueDataLen; - } - else - { - /* Dereference the KCB */ - CmpDereferenceKeyControlBlockWithLock(Parent, FALSE); - - /* Remove the KCB and free it */ - CmpRemoveKeyControlBlock(Kcb); - CmpFreeKeyControlBlock(Kcb); - Kcb = NULL; - } - } - } - - /* Sanity check */ - ASSERT((!Kcb) || (Kcb->Delete == FALSE)); - - /* Check if we had locked the hashes */ - if (!HashLock) - { - /* We locked them manually, do we have a parent? */ - if (Parent) - { - /* Unlock the parent KCB and ourselves */ - CmpReleaseTwoKcbLockByKey(ConvKey, Parent->ConvKey); - } - else - { - /* Unlock only ourselves */ - CmpReleaseKcbLockByKey(ConvKey); - } - } - - /* Return the KCB */ - return Kcb; -} - -VOID -NTAPI -EnlistKeyBodyWithKCB(IN PCM_KEY_BODY KeyBody, - IN ULONG Flags) -{ - /* Sanity check */ - ASSERT(KeyBody->KeyControlBlock != NULL); - - /* Initialize the list entry */ - InitializeListHead(&KeyBody->KeyBodyList); - - /* FIXME: Implement once we don't link parents to children anymore */ -} - - +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmkcbncb.c + * PURPOSE: Routines for handling KCBs, NCBs, as well as key hashes. + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include +#define NDEBUG +#include + +/* GLOBALS *******************************************************************/ + +ULONG CmpHashTableSize = 2048; +PCM_KEY_HASH_TABLE_ENTRY CmpCacheTable; +PCM_NAME_HASH_TABLE_ENTRY CmpNameCacheTable; + +BOOLEAN CmpHoldLazyFlush; + +/* FUNCTIONS *****************************************************************/ + +VOID +NTAPI +CmpInitializeCache(VOID) +{ + ULONG Length, i; + + /* Calculate length for the table */ + Length = CmpHashTableSize * sizeof(CM_KEY_HASH_TABLE_ENTRY); + + /* Allocate it */ + CmpCacheTable = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM); + if (!CmpCacheTable) + { + /* Take the system down */ + KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 3, 1, 0, 0); + } + + /* Zero out the table */ + RtlZeroMemory(CmpCacheTable, Length); + + /* Initialize the locks */ + for (i = 0;i < CmpHashTableSize; i++) + { + /* Setup the pushlock */ + ExInitializePushLock((PULONG_PTR)&CmpCacheTable[i].Lock); + } + + /* Calculate length for the name cache */ + Length = CmpHashTableSize * sizeof(CM_NAME_HASH_TABLE_ENTRY); + + /* Now allocate the name cache table */ + CmpNameCacheTable = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM); + if (!CmpNameCacheTable) + { + /* Take the system down */ + KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 3, 3, 0, 0); + } + + /* Zero out the table */ + RtlZeroMemory(CmpNameCacheTable, Length); + + /* Initialize the locks */ + for (i = 0;i < CmpHashTableSize; i++) + { + /* Setup the pushlock */ + ExInitializePushLock((PULONG_PTR)&CmpNameCacheTable[i].Lock); + } + + /* Setup the delayed close table */ + CmpInitializeDelayedCloseTable(); +} + +VOID +NTAPI +CmpRemoveKeyHash(IN PCM_KEY_HASH KeyHash) +{ + PCM_KEY_HASH *Prev; + PCM_KEY_HASH Current; + + /* Lookup all the keys in this index entry */ + Prev = &GET_HASH_ENTRY(CmpCacheTable, KeyHash->ConvKey).Entry; + while (TRUE) + { + /* Save the current one and make sure it's valid */ + Current = *Prev; + ASSERT(Current != NULL); + + /* Check if it matches */ + if (Current == KeyHash) + { + /* Then write the previous one */ + *Prev = Current->NextHash; + break; + } + + /* Otherwise, keep going */ + Prev = &Current->NextHash; + } +} + +PCM_KEY_CONTROL_BLOCK +NTAPI +CmpInsertKeyHash(IN PCM_KEY_HASH KeyHash, + IN BOOLEAN IsFake) +{ + ULONG i; + PCM_KEY_HASH Entry; + + /* Get the hash index */ + i = GET_HASH_INDEX(KeyHash->ConvKey); + + /* If this is a fake key, increase the key cell to use the parent data */ + if (IsFake) KeyHash->KeyCell++; + + /* Loop the hash table */ + Entry = CmpCacheTable[i].Entry; + while (Entry) + { + /* Check if this matches */ + if ((KeyHash->ConvKey == Entry->ConvKey) && + (KeyHash->KeyCell == Entry->KeyCell) && + (KeyHash->KeyHive == Entry->KeyHive)) + { + /* Return it */ + return CONTAINING_RECORD(Entry, CM_KEY_CONTROL_BLOCK, KeyHash); + } + + /* Keep looping */ + Entry = Entry->NextHash; + } + + /* No entry found, add this one and return NULL since none existed */ + KeyHash->NextHash = CmpCacheTable[i].Entry; + CmpCacheTable[i].Entry = KeyHash; + return NULL; +} + +PCM_NAME_CONTROL_BLOCK +NTAPI +CmpGetNameControlBlock(IN PUNICODE_STRING NodeName) +{ + PCM_NAME_CONTROL_BLOCK Ncb = NULL; + ULONG ConvKey = 0; + PWCHAR p, pp; + ULONG i; + BOOLEAN IsCompressed = TRUE, Found = FALSE; + PCM_NAME_HASH HashEntry; + ULONG Length, NcbSize; + + /* Loop the name */ + p = NodeName->Buffer; + for (i = 0; i < NodeName->Length; i += sizeof(WCHAR)) + { + /* Make sure it's not a slash */ + if (*p != OBJ_NAME_PATH_SEPARATOR) + { + /* Add it to the hash */ + ConvKey = 37 * ConvKey + RtlUpcaseUnicodeChar(*p); + } + + /* Next character */ + p++; + } + + /* Set assumed lengh and loop to check */ + Length = NodeName->Length / sizeof(WCHAR); + for (i = 0; i < (NodeName->Length / sizeof(WCHAR)); i++) + { + /* Check if this is a valid character */ + if (*NodeName->Buffer > (UCHAR)-1) + { + /* This is the actual size, and we know we're not compressed */ + Length = NodeName->Length; + IsCompressed = FALSE; + } + } + + /* Lock the NCB entry */ + CmpAcquireNcbLockExclusiveByKey(ConvKey); + + /* Get the hash entry */ + HashEntry = GET_HASH_ENTRY(CmpNameCacheTable, ConvKey).Entry; + while (HashEntry) + { + /* Get the current NCB */ + Ncb = CONTAINING_RECORD(HashEntry, CM_NAME_CONTROL_BLOCK, NameHash); + + /* Check if the hash matches */ + if ((ConvKey = HashEntry->ConvKey) && (Length = Ncb->NameLength)) + { + /* Assume success */ + Found = TRUE; + + /* If the NCB is compressed, do a compressed name compare */ + if (Ncb->Compressed) + { + /* Compare names */ + if (CmpCompareCompressedName(NodeName, Ncb->Name, Length)) + { + /* We failed */ + Found = FALSE; + } + } + else + { + /* Do a manual compare */ + p = NodeName->Buffer; + pp = Ncb->Name; + for (i = 0; i < Ncb->NameLength; i += sizeof(WCHAR)) + { + /* Compare the character */ + if (RtlUpcaseUnicodeChar(*p) != RtlUpcaseUnicodeChar(*pp)) + { + /* Failed */ + Found = FALSE; + break; + } + + /* Next chars */ + p++; + pp++; + } + } + + /* Check if we found a name */ + if (Found) + { + /* Reference it */ + Ncb->RefCount++; + } + } + + /* Go to the next hash */ + HashEntry = HashEntry->NextHash; + } + + /* Check if we didn't find it */ + if (!Found) + { + /* Allocate one */ + NcbSize = FIELD_OFFSET(CM_NAME_CONTROL_BLOCK, Name) + Length; + Ncb = ExAllocatePoolWithTag(PagedPool, NcbSize, TAG_CM); + if (!Ncb) + { + /* Release the lock and fail */ + CmpReleaseNcbLockByKey(ConvKey); + return NULL; + } + + /* Clear it out */ + RtlZeroMemory(Ncb, NcbSize); + + /* Check if the name was compressed */ + if (IsCompressed) + { + /* Copy the compressed name */ + Ncb->Compressed = TRUE; + for (i = 0; i < Length; i++) + { + /* Copy Unicode to ANSI */ + ((PCHAR)Ncb->Name)[i] = (CHAR)RtlUpcaseUnicodeChar(NodeName->Buffer[i]); + } + } + else + { + /* Copy the name directly */ + Ncb->Compressed = FALSE; + for (i = 0; i < Length; i++) + { + /* Copy each unicode character */ + Ncb->Name[i] = RtlUpcaseUnicodeChar(NodeName->Buffer[i]); + } + } + + /* Setup the rest of the NCB */ + Ncb->ConvKey = ConvKey; + Ncb->RefCount++; + Ncb->NameLength = Length; + + /* Insert the name in the hash table */ + HashEntry = &Ncb->NameHash; + HashEntry->NextHash = GET_HASH_ENTRY(CmpNameCacheTable, ConvKey).Entry; + GET_HASH_ENTRY(CmpNameCacheTable, ConvKey).Entry = HashEntry; + } + + /* Release NCB lock */ + CmpReleaseNcbLockByKey(ConvKey); + + /* Return the NCB found */ + return Ncb; +} + +VOID +NTAPI +CmpRemoveKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb) +{ + /* Make sure that the registry and KCB are utterly locked */ + ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) || + (CmpTestRegistryLockExclusive() == TRUE)); + + /* Remove the key hash */ + CmpRemoveKeyHash(&Kcb->KeyHash); +} + +VOID +NTAPI +CmpDereferenceNameControlBlockWithLock(IN PCM_NAME_CONTROL_BLOCK Ncb) +{ + PCM_NAME_HASH Current, *Next; + ULONG ConvKey = Ncb->ConvKey; + + /* Lock the NCB */ + CmpAcquireNcbLockExclusiveByKey(ConvKey); + + /* Decrease the reference count */ + if (!(--Ncb->RefCount)) + { + /* Find the NCB in the table */ + Next = &GET_HASH_ENTRY(CmpNameCacheTable, Ncb->ConvKey).Entry; + while (TRUE) + { + /* Check the current entry */ + Current = *Next; + ASSERT(Current != NULL); + if (Current == &Ncb->NameHash) + { + /* Unlink it */ + *Next = Current->NextHash; + break; + } + + /* Get to the next one */ + Next = &Current->NextHash; + } + + /* Found it, now free it */ + ExFreePool(Ncb); + } + + /* Release the lock */ + CmpReleaseNcbLockByKey(ConvKey); +} + +BOOLEAN +NTAPI +CmpReferenceKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb) +{ + /* Check if this is the KCB's first reference */ + if (Kcb->RefCount == 0) + { + /* Check if the KCB is locked in shared mode */ + if (!CmpIsKcbLockedExclusive(Kcb)) + { + /* Convert it to exclusive */ + if (!CmpTryToConvertKcbSharedToExclusive(Kcb)) + { + /* Set the delayed close index so that we can be ignored */ + Kcb->DelayedCloseIndex = 1; + + /* Increase the reference count while we release the lock */ + InterlockedIncrement((PLONG)&Kcb->RefCount); + + /* Go from shared to exclusive */ + CmpConvertKcbSharedToExclusive(Kcb); + + /* Decrement the reference count; the lock is now held again */ + InterlockedDecrement((PLONG)&Kcb->RefCount); + + /* Check if we still control the index */ + if (Kcb->DelayedCloseIndex == 1) + { + /* Reset it */ + Kcb->DelayedCloseIndex = 0; + } + else + { + /* Sanity check */ + ASSERT((Kcb->DelayedCloseIndex == CmpDelayedCloseSize) || + (Kcb->DelayedCloseIndex == 0)); + } + } + } + } + + /* Increase the reference count */ + if ((InterlockedIncrement((PLONG)&Kcb->RefCount) & 0xFFFF) == 0) + { + /* We've overflown to 64K references, bail out */ + InterlockedDecrement((PLONG)&Kcb->RefCount); + return FALSE; + } + + /* Check if this was the last close index */ + if (!Kcb->DelayedCloseIndex) + { + /* Check if the KCB is locked in shared mode */ + if (!CmpIsKcbLockedExclusive(Kcb)) + { + /* Convert it to exclusive */ + if (!CmpTryToConvertKcbSharedToExclusive(Kcb)) + { + /* Go from shared to exclusive */ + CmpConvertKcbSharedToExclusive(Kcb); + } + } + + /* If we're still the last entry, remove us */ + if (!Kcb->DelayedCloseIndex) CmpRemoveFromDelayedClose(Kcb); + } + + /* Return success */ + return TRUE; +} + +VOID +NTAPI +CmpCleanUpKcbValueCache(IN PCM_KEY_CONTROL_BLOCK Kcb) +{ + PULONG_PTR CachedList; + ULONG i; + + /* Sanity check */ + ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) || + (CmpTestRegistryLockExclusive() == TRUE)); + + /* Check if the value list is cached */ + if (CMP_IS_CELL_CACHED(Kcb->ValueCache.ValueList)) + { + /* Get the cache list */ + CachedList = (PULONG_PTR)CMP_GET_CACHED_DATA(Kcb->ValueCache.ValueList); + for (i = 0; i < Kcb->ValueCache.Count; i++) + { + /* Check if this cell is cached */ + if (CMP_IS_CELL_CACHED(CachedList[i])) + { + /* Free it */ + ExFreePool((PVOID)CMP_GET_CACHED_CELL(CachedList[i])); + } + } + + /* Now free the list */ + ExFreePool((PVOID)CMP_GET_CACHED_CELL(Kcb->ValueCache.ValueList)); + Kcb->ValueCache.ValueList = HCELL_NIL; + } + else if (Kcb->ExtFlags & CM_KCB_SYM_LINK_FOUND) + { + /* This is a sym link, check if there's only one reference left */ + if ((((PCM_KEY_CONTROL_BLOCK)Kcb->ValueCache.RealKcb)->RefCount == 1) && + !(((PCM_KEY_CONTROL_BLOCK)Kcb->ValueCache.RealKcb)->Delete)) + { + /* Disable delay close for the KCB */ + ((PCM_KEY_CONTROL_BLOCK)Kcb->ValueCache.RealKcb)->ExtFlags |= CM_KCB_NO_DELAY_CLOSE; + } + + /* Dereference the KCB */ + CmpDelayDerefKeyControlBlock((PCM_KEY_CONTROL_BLOCK)Kcb->ValueCache.RealKcb); + Kcb->ExtFlags &= ~CM_KCB_SYM_LINK_FOUND; + } +} + +VOID +NTAPI +CmpCleanUpKcbCacheWithLock(IN PCM_KEY_CONTROL_BLOCK Kcb, + IN BOOLEAN LockHeldExclusively) +{ + PCM_KEY_CONTROL_BLOCK Parent; + PAGED_CODE(); + + /* Sanity checks */ + ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) || + (CmpTestRegistryLockExclusive() == TRUE)); + ASSERT(Kcb->RefCount == 0); + + /* Cleanup the value cache */ + CmpCleanUpKcbValueCache(Kcb); + + /* Reference the NCB */ + CmpDereferenceNameControlBlockWithLock(Kcb->NameBlock); + + /* Check if we have an index hint block and free it */ + if (Kcb->ExtFlags & CM_KCB_SUBKEY_HINT) ExFreePool(Kcb->IndexHint); + + /* Check if we were already deleted */ + Parent = Kcb->ParentKcb; + if (!Kcb->Delete) CmpRemoveKeyControlBlock(Kcb); + + /* Free the KCB as well */ + CmpFreeKeyControlBlock(Kcb); + + /* Check if we have a parent */ + if (Parent) + { + /* Dereference the parent */ + LockHeldExclusively ? + CmpDereferenceKeyControlBlockWithLock(Kcb,LockHeldExclusively) : + CmpDelayDerefKeyControlBlock(Kcb); + } +} + +VOID +NTAPI +CmpDereferenceKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb) +{ + LONG OldRefCount, NewRefCount; + ULONG ConvKey; + + /* Get the ref count and update it */ + OldRefCount = *(PLONG)&Kcb->RefCount; + NewRefCount = OldRefCount - 1; + + /* Check if we still have references */ + if( (NewRefCount & 0xFFFF) > 0) + { + /* Do the dereference */ + if (InterlockedCompareExchange((PLONG)&Kcb->RefCount, + NewRefCount, + OldRefCount) == OldRefCount) + { + /* We'de done */ + return; + } + } + + /* Save the key */ + ConvKey = Kcb->ConvKey; + + /* Do the dereference inside the lock */ + CmpAcquireKcbLockExclusive(Kcb); + CmpDereferenceKeyControlBlockWithLock(Kcb, FALSE); + CmpReleaseKcbLockByKey(ConvKey); +} + +VOID +NTAPI +CmpDereferenceKeyControlBlockWithLock(IN PCM_KEY_CONTROL_BLOCK Kcb, + IN BOOLEAN LockHeldExclusively) +{ + /* Sanity check */ + ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) || + (CmpTestRegistryLockExclusive() == TRUE)); + + /* Check if this is the last reference */ + if ((InterlockedDecrement((PLONG)&Kcb->RefCount) & 0xFFFF) == 0) + { + /* Check if we should do a direct delete */ + if (((CmpHoldLazyFlush) && + !(Kcb->ExtFlags & CM_KCB_SYM_LINK_FOUND) && + !(Kcb->Flags & KEY_SYM_LINK)) || + (Kcb->ExtFlags & CM_KCB_NO_DELAY_CLOSE) || + (Kcb->Delete)) + { + /* Clean up the KCB*/ + CmpCleanUpKcbCacheWithLock(Kcb, LockHeldExclusively); + } + else + { + /* Otherwise, use delayed close */ + CmpAddToDelayedClose(Kcb, LockHeldExclusively); + } + } +} + +VOID +NTAPI +InitializeKCBKeyBodyList(IN PCM_KEY_CONTROL_BLOCK Kcb) +{ + /* Initialize the list */ + InitializeListHead(&Kcb->KeyBodyListHead); + + /* Clear the bodies */ + Kcb->KeyBodyArray[0] = + Kcb->KeyBodyArray[1] = + Kcb->KeyBodyArray[2] = + Kcb->KeyBodyArray[3] = NULL; +} + +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 Kcb, FoundKcb = NULL; + UNICODE_STRING NodeName; + ULONG ConvKey = 0, i; + BOOLEAN IsFake, HashLock; + PWCHAR p; + + /* Make sure we own this hive in case it's being unloaded */ + if ((Hive->HiveFlags & HIVE_IS_UNLOADING) && + (((PCMHIVE)Hive)->CreatorOwner != KeGetCurrentThread())) + { + /* Fail */ + return NULL; + } + + /* Check if this is a fake KCB */ + IsFake = Flags & CMP_CREATE_FAKE_KCB ? TRUE : FALSE; + + /* If we have a parent, use its ConvKey */ + if (Parent) ConvKey = Parent->ConvKey; + + /* Make a copy of the name */ + NodeName = *KeyName; + + /* Remove leading slash */ + while ((NodeName.Length) && (*NodeName.Buffer == OBJ_NAME_PATH_SEPARATOR)) + { + /* Move the buffer by one */ + NodeName.Buffer++; + NodeName.Length -= sizeof(WCHAR); + } + + /* Make sure we didn't get just a slash or something */ + ASSERT(NodeName.Length > 0); + + /* Now setup the hash */ + p = NodeName.Buffer; + for (i = 0; i < NodeName.Length; i += sizeof(WCHAR)) + { + /* Make sure it's a valid character */ + if (*p != OBJ_NAME_PATH_SEPARATOR) + { + /* Add this key to the hash */ + ConvKey = 37 * ConvKey + RtlUpcaseUnicodeChar(*p); + } + + /* Move on */ + p++; + } + + /* Allocate the KCB */ + Kcb = CmpAllocateKeyControlBlock(); + if (!Kcb) return NULL; + + /* Initailize the key list */ + InitializeKCBKeyBodyList(Kcb); + + /* Set it up */ + Kcb->Delete = FALSE; + Kcb->RefCount = 1; + Kcb->KeyHive = Hive; + Kcb->KeyCell = Index; + Kcb->ConvKey = ConvKey; + Kcb->DelayedCloseIndex = CmpDelayedCloseSize; + Kcb->InDelayClose = 0; + + /* Check if we have two hash entires */ + HashLock = Flags & CMP_LOCK_HASHES_FOR_KCB ? TRUE : FALSE; + if (!HashLock) + { + /* It's not locked, do we have a parent? */ + if (Parent) + { + /* Lock the parent KCB and ourselves */ + CmpAcquireTwoKcbLocksExclusiveByKey(ConvKey, Parent->ConvKey); + } + else + { + /* Lock only ourselves */ + CmpAcquireKcbLockExclusive(Kcb); + } + } + + /* Check if we already have a KCB */ + FoundKcb = CmpInsertKeyHash(&Kcb->KeyHash, IsFake); + if (FoundKcb) + { + /* Sanity check */ + ASSERT(!FoundKcb->Delete); + + /* Free the one we allocated and reference this one */ + CmpFreeKeyControlBlock(Kcb); + Kcb = FoundKcb; + if (!CmpReferenceKeyControlBlock(Kcb)) + { + /* We got too many handles */ + ASSERT(Kcb->RefCount + 1 != 0); + Kcb = NULL; + } + else + { + /* Check if we're not creating a fake one, but it used to be fake */ + if ((Kcb->ExtFlags & CM_KCB_KEY_NON_EXIST) && !(IsFake)) + { + /* Set the hive and cell */ + Kcb->KeyHive = Hive; + Kcb->KeyCell = Index; + + /* This means that our current information is invalid */ + Kcb->ExtFlags = CM_KCB_INVALID_CACHED_INFO; + } + + /* Check if we didn't have any valid data */ + if (!(Kcb->ExtFlags & (CM_KCB_NO_SUBKEY | + CM_KCB_SUBKEY_ONE | + CM_KCB_SUBKEY_HINT))) + { + /* Calculate the index hint */ + Kcb->SubKeyCount = Node->SubKeyCounts[Stable] + + Node->SubKeyCounts[Volatile]; + + /* Cached information is now valid */ + Kcb->ExtFlags &= ~CM_KCB_INVALID_CACHED_INFO; + } + + /* Setup the other data */ + Kcb->KcbLastWriteTime = Node->LastWriteTime; + Kcb->KcbMaxNameLen = (USHORT)Node->MaxNameLen; + Kcb->KcbMaxValueNameLen = (USHORT)Node->MaxValueNameLen; + Kcb->KcbMaxValueDataLen = Node->MaxValueDataLen; + } + } + else + { + /* No KCB, do we have a parent? */ + if (Parent) + { + /* Reference the parent */ + if (((Parent->TotalLevels + 1) < 512) && + (CmpReferenceKeyControlBlock(Parent))) + { + /* Link it */ + Kcb->ParentKcb = Parent; + Kcb->TotalLevels = Parent->TotalLevels + 1; + } + else + { + /* Remove the KCB and free it */ + CmpRemoveKeyControlBlock(Kcb); + CmpFreeKeyControlBlock(Kcb); + Kcb = NULL; + } + } + else + { + /* No parent, this is the root node */ + Kcb->ParentKcb = NULL; + Kcb->TotalLevels = 1; + } + + /* Check if we have a KCB */ + if (Kcb) + { + /* Get the NCB */ + Kcb->NameBlock = CmpGetNameControlBlock(&NodeName); + if (Kcb->NameBlock) + { + /* Fill it out */ + Kcb->ValueCache.Count = Node->ValueList.Count; + Kcb->ValueCache.ValueList = Node->ValueList.List; + Kcb->Flags = Node->Flags; + Kcb->ExtFlags = 0; + Kcb->DelayedCloseIndex = CmpDelayedCloseSize; + + /* Remember if this is a fake key */ + if (IsFake) Kcb->ExtFlags |= CM_KCB_KEY_NON_EXIST; + + /* Setup the other data */ + Kcb->SubKeyCount = Node->SubKeyCounts[Stable] + + Node->SubKeyCounts[Volatile]; + Kcb->KcbLastWriteTime = Node->LastWriteTime; + Kcb->KcbMaxNameLen = (USHORT)Node->MaxNameLen; + Kcb->KcbMaxValueNameLen = (USHORT)Node->MaxValueNameLen; + Kcb->KcbMaxValueDataLen = (USHORT)Node->MaxValueDataLen; + } + else + { + /* Dereference the KCB */ + CmpDereferenceKeyControlBlockWithLock(Parent, FALSE); + + /* Remove the KCB and free it */ + CmpRemoveKeyControlBlock(Kcb); + CmpFreeKeyControlBlock(Kcb); + Kcb = NULL; + } + } + } + + /* Sanity check */ + ASSERT((!Kcb) || (Kcb->Delete == FALSE)); + + /* Check if we had locked the hashes */ + if (!HashLock) + { + /* We locked them manually, do we have a parent? */ + if (Parent) + { + /* Unlock the parent KCB and ourselves */ + CmpReleaseTwoKcbLockByKey(ConvKey, Parent->ConvKey); + } + else + { + /* Unlock only ourselves */ + CmpReleaseKcbLockByKey(ConvKey); + } + } + + /* Return the KCB */ + return Kcb; +} + +VOID +NTAPI +EnlistKeyBodyWithKCB(IN PCM_KEY_BODY KeyBody, + IN ULONG Flags) +{ + /* Sanity check */ + ASSERT(KeyBody->KeyControlBlock != NULL); + + /* Initialize the list entry */ + InitializeListHead(&KeyBody->KeyBodyList); + + /* FIXME: Implement once we don't link parents to children anymore */ +} + + diff --git a/reactos/ntoskrnl/config/cmkeydel.c b/reactos/ntoskrnl/config/cmkeydel.c index f765807d1f4..e47bc03aa82 100644 --- a/reactos/ntoskrnl/config/cmkeydel.c +++ b/reactos/ntoskrnl/config/cmkeydel.c @@ -1,221 +1,220 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/config/cmkeydel.c - * PURPOSE: Configuration Manager - Key Body Deletion - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include "ntoskrnl.h" -#include "cm.h" -#define NDEBUG -#include "debug.h" - -/* FUNCTIONS *****************************************************************/ - -BOOLEAN -NTAPI -CmpMarkKeyDirty(IN PHHIVE Hive, - IN HCELL_INDEX Cell, - IN BOOLEAN CheckNoSubkeys) -{ - PCELL_DATA CellData, ListData, SecurityData, ValueData; - ULONG i; - - /* Get the cell data for our target */ - CellData = HvGetCell(Hive, Cell); - if (!CellData) return FALSE; - - /* Check if sanity checks requested */ - if (CheckNoSubkeys) - { - /* Do them */ - ASSERT(CellData->u.KeyNode.SubKeyCounts[Stable] == 0); - ASSERT(CellData->u.KeyNode.SubKeyCounts[Volatile] == 0); - } - - /* If this is an exit hive, there's nothing to do */ - if (CellData->u.KeyNode.Flags & KEY_HIVE_EXIT) - { - /* Release the cell and get out */ - HvReleaseCell(Hive, Cell); - return TRUE; - } - - /* Otherwise, mark it dirty and release it */ - HvMarkCellDirty(Hive, Cell, FALSE); - HvReleaseCell(Hive, Cell); - - /* Check if we have a class */ - if (CellData->u.KeyNode.Class != HCELL_NIL) - { - /* Mark it dirty */ - HvMarkCellDirty(Hive, CellData->u.KeyNode.Class, FALSE); - } - - /* Check if we have security */ - if (CellData->u.KeyNode.Security != HCELL_NIL) - { - /* Mark it dirty */ - HvMarkCellDirty(Hive, CellData->u.KeyNode.Security, FALSE); - - /* Get the security data and release it */ - SecurityData = HvGetCell(Hive, CellData->u.KeyNode.Security); - if (!SecurityData) ASSERT(FALSE); - HvReleaseCell(Hive, CellData->u.KeyNode.Security); - - /* Mark the security links dirty too */ - HvMarkCellDirty(Hive, SecurityData->u.KeySecurity.Flink, FALSE); - HvMarkCellDirty(Hive, SecurityData->u.KeySecurity.Blink, FALSE); - } - - /* Check if we have any values */ - if (CellData->u.KeyNode.ValueList.Count > 0) - { - /* Dirty the value list */ - HvMarkCellDirty(Hive, CellData->u.KeyNode.ValueList.List, FALSE); - - /* Get the list data itself, and release it */ - ListData = HvGetCell(Hive, CellData->u.KeyNode.ValueList.List); - if (!ListData) ASSERT(FALSE); - HvReleaseCell(Hive, CellData->u.KeyNode.ValueList.List); - - /* Loop all values */ - for (i = 0; i < CellData->u.KeyNode.ValueList.Count; i++) - { - /* Dirty each value */ - HvMarkCellDirty(Hive, ListData->u.KeyList[i], FALSE); - - /* Get the value data and release it */ - ValueData = HvGetCell(Hive, ListData->u.KeyList[i]); - ASSERT(ValueData); - HvReleaseCell(Hive,ListData->u.KeyList[i]); - - /* Mark the value data dirty too */ - if (!CmpMarkValueDataDirty(Hive, &ValueData->u.KeyValue)) - { - /* Failure */ - return FALSE; - } - } - } - - /* If this is an entry hive, we're done */ - if (CellData->u.KeyNode.Flags & KEY_HIVE_ENTRY) return TRUE; - - /* Otherwise mark the index dirty too */ - if (!CmpMarkIndexDirty(Hive, CellData->u.KeyNode.Parent, Cell)) - { - /* Failure */ - return FALSE; - } - - /* Finally, mark the parent dirty */ - HvMarkCellDirty(Hive, CellData->u.KeyNode.Parent, FALSE); - return TRUE; -} - -BOOLEAN -NTAPI -CmpFreeKeyBody(IN PHHIVE Hive, - IN HCELL_INDEX Cell) -{ - PCELL_DATA CellData; - - /* Get the key node */ - CellData = HvGetCell(Hive, Cell); - if (!CellData) ASSERT(FALSE); - - /* Check if we can delete the child cells */ - if (!(CellData->u.KeyNode.Flags & KEY_HIVE_EXIT)) - { - /* Check if we have a security cell */ - if (CellData->u.KeyNode.Security != HCELL_NIL) - { - /* Free the security cell */ - HvFreeCell(Hive, CellData->u.KeyNode.Security); - } - - /* Check if we have a class */ - if (CellData->u.KeyNode.ClassLength > 0) - { - /* Free it */ - HvFreeCell(Hive, CellData->u.KeyNode.Class); - } - } - - /* Release and free the cell */ - HvReleaseCell(Hive, Cell); - HvFreeCell(Hive, Cell); - return TRUE; -} - -NTSTATUS -NTAPI -CmpFreeKeyByCell(IN PHHIVE Hive, - IN HCELL_INDEX Cell, - IN BOOLEAN Unlink) -{ - PCELL_DATA CellData, ParentData, ListData; - ULONG i; - BOOLEAN Result; - - /* Mark the entire key dirty */ - CmpMarkKeyDirty(Hive, Cell ,TRUE); - - /* Get the target node and release it */ - CellData = HvGetCell(Hive, Cell); - if (!CellData) ASSERT(FALSE); - HvReleaseCell(Hive, Cell); - - /* Make sure we don't have subkeys */ - ASSERT((CellData->u.KeyNode.SubKeyCounts[Stable] + - CellData->u.KeyNode.SubKeyCounts[Volatile]) == 0); - - /* Check if we have to unlink */ - if (Unlink) - { - /* Remove the subkey */ - Result = CmpRemoveSubKey(Hive, CellData->u.KeyNode.Parent, Cell); - if (!Result) return STATUS_INSUFFICIENT_RESOURCES; - - /* Get the parent node and release it */ - ParentData = HvGetCell(Hive, CellData->u.KeyNode.Parent); - if (!ParentData) ASSERT(FALSE); - HvReleaseCell(Hive, CellData->u.KeyNode.Parent); - - /* Check if the parent node has no more subkeys */ - if (!(ParentData->u.KeyNode.SubKeyCounts[Stable] + - ParentData->u.KeyNode.SubKeyCounts[Volatile])) - { - /* Then free the cached name/class lengths */ - ParentData->u.KeyNode.MaxNameLen = 0; - ParentData->u.KeyNode.MaxClassLen = 0; - } - } - - /* Check if we have any values */ - if (CellData->u.KeyNode.ValueList.Count > 0) - { - /* Get the value list and release it */ - ListData = HvGetCell(Hive, CellData->u.KeyNode.ValueList.List); - if (!ListData) ASSERT(FALSE); - HvReleaseCell(Hive, CellData->u.KeyNode.ValueList.List); - - /* Loop every value */ - for (i = 0; i < CellData->u.KeyNode.ValueList.Count; i++) - { - /* Free it */ - if (!CmpFreeValue(Hive, ListData->u.KeyList[i])) ASSERT(FALSE); - } - - /* Free the value list */ - HvFreeCell(Hive, CellData->u.KeyNode.ValueList.List); - } - - /* Free the key body itself, and then return our status */ - if (!CmpFreeKeyBody(Hive, Cell)) return STATUS_INSUFFICIENT_RESOURCES; - return STATUS_SUCCESS; -} +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmkeydel.c + * PURPOSE: Configuration Manager - Key Body Deletion + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#define NDEBUG +#include "debug.h" + +/* FUNCTIONS *****************************************************************/ + +BOOLEAN +NTAPI +CmpMarkKeyDirty(IN PHHIVE Hive, + IN HCELL_INDEX Cell, + IN BOOLEAN CheckNoSubkeys) +{ + PCELL_DATA CellData, ListData, SecurityData, ValueData; + ULONG i; + + /* Get the cell data for our target */ + CellData = HvGetCell(Hive, Cell); + if (!CellData) return FALSE; + + /* Check if sanity checks requested */ + if (CheckNoSubkeys) + { + /* Do them */ + ASSERT(CellData->u.KeyNode.SubKeyCounts[Stable] == 0); + ASSERT(CellData->u.KeyNode.SubKeyCounts[Volatile] == 0); + } + + /* If this is an exit hive, there's nothing to do */ + if (CellData->u.KeyNode.Flags & KEY_HIVE_EXIT) + { + /* Release the cell and get out */ + HvReleaseCell(Hive, Cell); + return TRUE; + } + + /* Otherwise, mark it dirty and release it */ + HvMarkCellDirty(Hive, Cell, FALSE); + HvReleaseCell(Hive, Cell); + + /* Check if we have a class */ + if (CellData->u.KeyNode.Class != HCELL_NIL) + { + /* Mark it dirty */ + HvMarkCellDirty(Hive, CellData->u.KeyNode.Class, FALSE); + } + + /* Check if we have security */ + if (CellData->u.KeyNode.Security != HCELL_NIL) + { + /* Mark it dirty */ + HvMarkCellDirty(Hive, CellData->u.KeyNode.Security, FALSE); + + /* Get the security data and release it */ + SecurityData = HvGetCell(Hive, CellData->u.KeyNode.Security); + if (!SecurityData) ASSERT(FALSE); + HvReleaseCell(Hive, CellData->u.KeyNode.Security); + + /* Mark the security links dirty too */ + HvMarkCellDirty(Hive, SecurityData->u.KeySecurity.Flink, FALSE); + HvMarkCellDirty(Hive, SecurityData->u.KeySecurity.Blink, FALSE); + } + + /* Check if we have any values */ + if (CellData->u.KeyNode.ValueList.Count > 0) + { + /* Dirty the value list */ + HvMarkCellDirty(Hive, CellData->u.KeyNode.ValueList.List, FALSE); + + /* Get the list data itself, and release it */ + ListData = HvGetCell(Hive, CellData->u.KeyNode.ValueList.List); + if (!ListData) ASSERT(FALSE); + HvReleaseCell(Hive, CellData->u.KeyNode.ValueList.List); + + /* Loop all values */ + for (i = 0; i < CellData->u.KeyNode.ValueList.Count; i++) + { + /* Dirty each value */ + HvMarkCellDirty(Hive, ListData->u.KeyList[i], FALSE); + + /* Get the value data and release it */ + ValueData = HvGetCell(Hive, ListData->u.KeyList[i]); + ASSERT(ValueData); + HvReleaseCell(Hive,ListData->u.KeyList[i]); + + /* Mark the value data dirty too */ + if (!CmpMarkValueDataDirty(Hive, &ValueData->u.KeyValue)) + { + /* Failure */ + return FALSE; + } + } + } + + /* If this is an entry hive, we're done */ + if (CellData->u.KeyNode.Flags & KEY_HIVE_ENTRY) return TRUE; + + /* Otherwise mark the index dirty too */ + if (!CmpMarkIndexDirty(Hive, CellData->u.KeyNode.Parent, Cell)) + { + /* Failure */ + return FALSE; + } + + /* Finally, mark the parent dirty */ + HvMarkCellDirty(Hive, CellData->u.KeyNode.Parent, FALSE); + return TRUE; +} + +BOOLEAN +NTAPI +CmpFreeKeyBody(IN PHHIVE Hive, + IN HCELL_INDEX Cell) +{ + PCELL_DATA CellData; + + /* Get the key node */ + CellData = HvGetCell(Hive, Cell); + if (!CellData) ASSERT(FALSE); + + /* Check if we can delete the child cells */ + if (!(CellData->u.KeyNode.Flags & KEY_HIVE_EXIT)) + { + /* Check if we have a security cell */ + if (CellData->u.KeyNode.Security != HCELL_NIL) + { + /* Free the security cell */ + HvFreeCell(Hive, CellData->u.KeyNode.Security); + } + + /* Check if we have a class */ + if (CellData->u.KeyNode.ClassLength > 0) + { + /* Free it */ + HvFreeCell(Hive, CellData->u.KeyNode.Class); + } + } + + /* Release and free the cell */ + HvReleaseCell(Hive, Cell); + HvFreeCell(Hive, Cell); + return TRUE; +} + +NTSTATUS +NTAPI +CmpFreeKeyByCell(IN PHHIVE Hive, + IN HCELL_INDEX Cell, + IN BOOLEAN Unlink) +{ + PCELL_DATA CellData, ParentData, ListData; + ULONG i; + BOOLEAN Result; + + /* Mark the entire key dirty */ + CmpMarkKeyDirty(Hive, Cell ,TRUE); + + /* Get the target node and release it */ + CellData = HvGetCell(Hive, Cell); + if (!CellData) ASSERT(FALSE); + HvReleaseCell(Hive, Cell); + + /* Make sure we don't have subkeys */ + ASSERT((CellData->u.KeyNode.SubKeyCounts[Stable] + + CellData->u.KeyNode.SubKeyCounts[Volatile]) == 0); + + /* Check if we have to unlink */ + if (Unlink) + { + /* Remove the subkey */ + Result = CmpRemoveSubKey(Hive, CellData->u.KeyNode.Parent, Cell); + if (!Result) return STATUS_INSUFFICIENT_RESOURCES; + + /* Get the parent node and release it */ + ParentData = HvGetCell(Hive, CellData->u.KeyNode.Parent); + if (!ParentData) ASSERT(FALSE); + HvReleaseCell(Hive, CellData->u.KeyNode.Parent); + + /* Check if the parent node has no more subkeys */ + if (!(ParentData->u.KeyNode.SubKeyCounts[Stable] + + ParentData->u.KeyNode.SubKeyCounts[Volatile])) + { + /* Then free the cached name/class lengths */ + ParentData->u.KeyNode.MaxNameLen = 0; + ParentData->u.KeyNode.MaxClassLen = 0; + } + } + + /* Check if we have any values */ + if (CellData->u.KeyNode.ValueList.Count > 0) + { + /* Get the value list and release it */ + ListData = HvGetCell(Hive, CellData->u.KeyNode.ValueList.List); + if (!ListData) ASSERT(FALSE); + HvReleaseCell(Hive, CellData->u.KeyNode.ValueList.List); + + /* Loop every value */ + for (i = 0; i < CellData->u.KeyNode.ValueList.Count; i++) + { + /* Free it */ + if (!CmpFreeValue(Hive, ListData->u.KeyList[i])) ASSERT(FALSE); + } + + /* Free the value list */ + HvFreeCell(Hive, CellData->u.KeyNode.ValueList.List); + } + + /* Free the key body itself, and then return our status */ + if (!CmpFreeKeyBody(Hive, Cell)) return STATUS_INSUFFICIENT_RESOURCES; + return STATUS_SUCCESS; +} diff --git a/reactos/ntoskrnl/config/cmlazy.c b/reactos/ntoskrnl/config/cmlazy.c index 7b79e85aa71..fbbf519e6a5 100644 --- a/reactos/ntoskrnl/config/cmlazy.c +++ b/reactos/ntoskrnl/config/cmlazy.c @@ -9,7 +9,6 @@ /* INCLUDES *******************************************************************/ #include "ntoskrnl.h" -#include "cm.h" #define NDEBUG #include "debug.h" diff --git a/reactos/ntoskrnl/config/cmmapvw.c b/reactos/ntoskrnl/config/cmmapvw.c index ae5009e1f66..5ea4d4f0808 100644 --- a/reactos/ntoskrnl/config/cmmapvw.c +++ b/reactos/ntoskrnl/config/cmmapvw.c @@ -1,33 +1,32 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/config/cmmapvw.c - * PURPOSE: Configuration Manager - Map-Viewed Hive Support - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include "ntoskrnl.h" -#include "cm.h" -#define NDEBUG -#include "debug.h" - -/* GLOBALS *******************************************************************/ - -/* FUNCTIONS *****************************************************************/ - -VOID -NTAPI -CmpInitHiveViewList(IN PCMHIVE Hive) -{ - /* Initialize the list heads */ - InitializeListHead(&Hive->LRUViewListHead); - InitializeListHead(&Hive->PinViewListHead); - - /* Reset data */ - Hive->MappedViews = 0; - Hive->PinnedViews = 0; - Hive->UseCount = 0; -} - +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmmapvw.c + * PURPOSE: Configuration Manager - Map-Viewed Hive Support + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#define NDEBUG +#include "debug.h" + +/* GLOBALS *******************************************************************/ + +/* FUNCTIONS *****************************************************************/ + +VOID +NTAPI +CmpInitHiveViewList(IN PCMHIVE Hive) +{ + /* Initialize the list heads */ + InitializeListHead(&Hive->LRUViewListHead); + InitializeListHead(&Hive->PinViewListHead); + + /* Reset data */ + Hive->MappedViews = 0; + Hive->PinnedViews = 0; + Hive->UseCount = 0; +} + diff --git a/reactos/ntoskrnl/config/cmname.c b/reactos/ntoskrnl/config/cmname.c index 46c4c49d239..94b9e07d730 100644 --- a/reactos/ntoskrnl/config/cmname.c +++ b/reactos/ntoskrnl/config/cmname.c @@ -1,254 +1,253 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/config/cmname.c - * PURPOSE: Configuration Manager - Name Management - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include "ntoskrnl.h" -#include "cm.h" -#define NDEBUG -#include "debug.h" - -/* GLOBALS *******************************************************************/ - -/* FUNCTIONS *****************************************************************/ - -USHORT -NTAPI -CmpCopyName(IN PHHIVE Hive, - IN PWCHAR Destination, - IN PUNICODE_STRING Source) -{ - ULONG i; - - /* Check for old hives */ - if (Hive->Version == 1) - { - /* Just copy the source directly */ - RtlCopyMemory(Destination, Source->Buffer, Source->Length); - return Source->Length; - } - - /* For new versions, check for compressed name */ - for (i = 0; i < (Source->Length / sizeof(WCHAR)); i++) - { - /* Check if the name is non compressed */ - if (Source->Buffer[i] > (UCHAR)-1) - { - /* Do the copy */ - RtlCopyMemory(Destination, Source->Buffer, Source->Length); - return Source->Length; - } - - /* Copy this character */ - ((PCHAR)Destination)[i] = (CHAR)(Source->Buffer[i]); - } - - /* Compressed name, return length */ - return Source->Length / sizeof(WCHAR); -} - -VOID -NTAPI -CmpCopyCompressedName(IN PWCHAR Destination, - IN ULONG DestinationLength, - IN PWCHAR Source, - IN ULONG SourceLength) -{ - ULONG i, Length; - - /* Get the actual length to copy */ - Length = min(DestinationLength / sizeof(WCHAR), SourceLength); - for (i = 0; i < Length; i++) - { - /* Copy each character */ - Destination[i] = (WCHAR)((PCHAR)Source)[i]; - } -} - -USHORT -NTAPI -CmpNameSize(IN PHHIVE Hive, - IN PUNICODE_STRING Name) -{ - ULONG i; - - /* For old hives, just retun the length */ - if (Hive->Version == 1) return Name->Length; - - /* For new versions, check for compressed name */ - for (i = 0; i < (Name->Length / sizeof(WCHAR)); i++) - { - /* Check if the name is non compressed */ - if (Name->Buffer[i] > (UCHAR)-1) return Name->Length; - } - - /* Compressed name, return length */ - return Name->Length / sizeof(WCHAR); -} - -USHORT -NTAPI -CmpCompressedNameSize(IN PWCHAR Name, - IN ULONG Length) -{ - /* - * Don't remove this: compressed names are "opaque" and just because - * the current implementation turns them into ansi-names doesn't mean - * that it will remain that way forever, so -never- assume this code - * below internally! - */ - return (USHORT)Length * sizeof(WCHAR); -} - -LONG -NTAPI -CmpCompareCompressedName(IN PCUNICODE_STRING SearchName, - IN PWCHAR CompressedName, - IN ULONG NameLength) -{ - WCHAR *p; - CHAR *pp; - WCHAR p1, p2; - USHORT SearchLength; - LONG Result; - - /* Set the pointers and length and then loop */ - p = SearchName->Buffer; - pp = (PCHAR)CompressedName; - SearchLength = (SearchName->Length / sizeof(WCHAR)); - while ((SearchLength) && (NameLength)) - { - /* Get the characters */ - p1 = *p++; - p2 = (WCHAR)(*pp++); - - /* Check if we have a direct match */ - if (p1 != p2) - { - /* See if they match and return result if they don't */ - Result = (LONG)RtlUpcaseUnicodeChar(p1) - - (LONG)RtlUpcaseUnicodeChar(p2); - if (Result) return Result; - } - - /* Next chars */ - SearchLength--; - NameLength--; - } - - /* Return the difference directly */ - return SearchLength - NameLength; -} - -BOOLEAN -NTAPI -CmpFindNameInList(IN PHHIVE Hive, - IN PCHILD_LIST ChildList, - IN PUNICODE_STRING Name, - IN PULONG ChildIndex, - IN PHCELL_INDEX CellIndex) -{ - PCELL_DATA CellData; - HCELL_INDEX CellToRelease = HCELL_NIL; - ULONG i; - PCM_KEY_VALUE KeyValue; - LONG Result; - UNICODE_STRING SearchName; - BOOLEAN Success; - - /* Make sure there's actually something on the list */ - if (ChildList->Count != 0) - { - /* Get the cell data */ - CellData = (PCELL_DATA)HvGetCell(Hive, ChildList->List); - if (!CellData) - { - /* Couldn't get the cell... tell the caller */ - *CellIndex = HCELL_NIL; - return FALSE; - } - - /* Now loop every entry */ - for (i = 0; i < ChildList->Count; i++) - { - /* Check if we have a cell to release */ - if (CellToRelease != HCELL_NIL) - { - /* Release it */ - HvReleaseCell(Hive, CellToRelease); - CellToRelease = HCELL_NIL; - } - - /* Get this value */ - KeyValue = (PCM_KEY_VALUE)HvGetCell(Hive, CellData->u.KeyList[i]); - if (!KeyValue) - { - /* Return with no data found */ - *CellIndex = HCELL_NIL; - Success = FALSE; - goto Return; - } - - /* Save the cell to release */ - CellToRelease = CellData->u.KeyList[i]; - - /* Check if it's a compressed value name */ - if (KeyValue->Flags & VALUE_COMP_NAME) - { - /* Use the compressed name check */ - Result = CmpCompareCompressedName(Name, - KeyValue->Name, - KeyValue->NameLength); - } - else - { - /* Setup the Unicode string */ - SearchName.Length = KeyValue->NameLength; - SearchName.MaximumLength = SearchName.Length; - SearchName.Buffer = KeyValue->Name; - Result = RtlCompareUnicodeString(Name, &SearchName, TRUE); - } - - /* Check if we found it */ - if (!Result) - { - /* We did...return info to caller */ - if (ChildIndex) *ChildIndex = i; - *CellIndex = CellData->u.KeyList[i]; - - /* Set success state */ - Success = TRUE; - goto Return; - } - } - - /* Got to the end of the list */ - if (ChildIndex) *ChildIndex = i; - *CellIndex = HCELL_NIL; - - /* Nothing found if we got here */ - Success = TRUE; - goto Return; - } - - /* Nothing found...check if the caller wanted more info */ - ASSERT(ChildList->Count == 0); - if (ChildIndex) *ChildIndex = 0; - *CellIndex = HCELL_NIL; - - /* Nothing found if we got here */ - return TRUE; - -Return: - /* Release the first cell we got */ - if (CellData) HvReleaseCell(Hive, ChildList->List); - - /* Release the secondary one, if we have one */ - if (CellToRelease) HvReleaseCell(Hive, CellToRelease); - return Success; -} +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmname.c + * PURPOSE: Configuration Manager - Name Management + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#define NDEBUG +#include "debug.h" + +/* GLOBALS *******************************************************************/ + +/* FUNCTIONS *****************************************************************/ + +USHORT +NTAPI +CmpCopyName(IN PHHIVE Hive, + IN PWCHAR Destination, + IN PUNICODE_STRING Source) +{ + ULONG i; + + /* Check for old hives */ + if (Hive->Version == 1) + { + /* Just copy the source directly */ + RtlCopyMemory(Destination, Source->Buffer, Source->Length); + return Source->Length; + } + + /* For new versions, check for compressed name */ + for (i = 0; i < (Source->Length / sizeof(WCHAR)); i++) + { + /* Check if the name is non compressed */ + if (Source->Buffer[i] > (UCHAR)-1) + { + /* Do the copy */ + RtlCopyMemory(Destination, Source->Buffer, Source->Length); + return Source->Length; + } + + /* Copy this character */ + ((PCHAR)Destination)[i] = (CHAR)(Source->Buffer[i]); + } + + /* Compressed name, return length */ + return Source->Length / sizeof(WCHAR); +} + +VOID +NTAPI +CmpCopyCompressedName(IN PWCHAR Destination, + IN ULONG DestinationLength, + IN PWCHAR Source, + IN ULONG SourceLength) +{ + ULONG i, Length; + + /* Get the actual length to copy */ + Length = min(DestinationLength / sizeof(WCHAR), SourceLength); + for (i = 0; i < Length; i++) + { + /* Copy each character */ + Destination[i] = (WCHAR)((PCHAR)Source)[i]; + } +} + +USHORT +NTAPI +CmpNameSize(IN PHHIVE Hive, + IN PUNICODE_STRING Name) +{ + ULONG i; + + /* For old hives, just retun the length */ + if (Hive->Version == 1) return Name->Length; + + /* For new versions, check for compressed name */ + for (i = 0; i < (Name->Length / sizeof(WCHAR)); i++) + { + /* Check if the name is non compressed */ + if (Name->Buffer[i] > (UCHAR)-1) return Name->Length; + } + + /* Compressed name, return length */ + return Name->Length / sizeof(WCHAR); +} + +USHORT +NTAPI +CmpCompressedNameSize(IN PWCHAR Name, + IN ULONG Length) +{ + /* + * Don't remove this: compressed names are "opaque" and just because + * the current implementation turns them into ansi-names doesn't mean + * that it will remain that way forever, so -never- assume this code + * below internally! + */ + return (USHORT)Length * sizeof(WCHAR); +} + +LONG +NTAPI +CmpCompareCompressedName(IN PCUNICODE_STRING SearchName, + IN PWCHAR CompressedName, + IN ULONG NameLength) +{ + WCHAR *p; + CHAR *pp; + WCHAR p1, p2; + USHORT SearchLength; + LONG Result; + + /* Set the pointers and length and then loop */ + p = SearchName->Buffer; + pp = (PCHAR)CompressedName; + SearchLength = (SearchName->Length / sizeof(WCHAR)); + while ((SearchLength) && (NameLength)) + { + /* Get the characters */ + p1 = *p++; + p2 = (WCHAR)(*pp++); + + /* Check if we have a direct match */ + if (p1 != p2) + { + /* See if they match and return result if they don't */ + Result = (LONG)RtlUpcaseUnicodeChar(p1) - + (LONG)RtlUpcaseUnicodeChar(p2); + if (Result) return Result; + } + + /* Next chars */ + SearchLength--; + NameLength--; + } + + /* Return the difference directly */ + return SearchLength - NameLength; +} + +BOOLEAN +NTAPI +CmpFindNameInList(IN PHHIVE Hive, + IN PCHILD_LIST ChildList, + IN PUNICODE_STRING Name, + IN PULONG ChildIndex, + IN PHCELL_INDEX CellIndex) +{ + PCELL_DATA CellData; + HCELL_INDEX CellToRelease = HCELL_NIL; + ULONG i; + PCM_KEY_VALUE KeyValue; + LONG Result; + UNICODE_STRING SearchName; + BOOLEAN Success; + + /* Make sure there's actually something on the list */ + if (ChildList->Count != 0) + { + /* Get the cell data */ + CellData = (PCELL_DATA)HvGetCell(Hive, ChildList->List); + if (!CellData) + { + /* Couldn't get the cell... tell the caller */ + *CellIndex = HCELL_NIL; + return FALSE; + } + + /* Now loop every entry */ + for (i = 0; i < ChildList->Count; i++) + { + /* Check if we have a cell to release */ + if (CellToRelease != HCELL_NIL) + { + /* Release it */ + HvReleaseCell(Hive, CellToRelease); + CellToRelease = HCELL_NIL; + } + + /* Get this value */ + KeyValue = (PCM_KEY_VALUE)HvGetCell(Hive, CellData->u.KeyList[i]); + if (!KeyValue) + { + /* Return with no data found */ + *CellIndex = HCELL_NIL; + Success = FALSE; + goto Return; + } + + /* Save the cell to release */ + CellToRelease = CellData->u.KeyList[i]; + + /* Check if it's a compressed value name */ + if (KeyValue->Flags & VALUE_COMP_NAME) + { + /* Use the compressed name check */ + Result = CmpCompareCompressedName(Name, + KeyValue->Name, + KeyValue->NameLength); + } + else + { + /* Setup the Unicode string */ + SearchName.Length = KeyValue->NameLength; + SearchName.MaximumLength = SearchName.Length; + SearchName.Buffer = KeyValue->Name; + Result = RtlCompareUnicodeString(Name, &SearchName, TRUE); + } + + /* Check if we found it */ + if (!Result) + { + /* We did...return info to caller */ + if (ChildIndex) *ChildIndex = i; + *CellIndex = CellData->u.KeyList[i]; + + /* Set success state */ + Success = TRUE; + goto Return; + } + } + + /* Got to the end of the list */ + if (ChildIndex) *ChildIndex = i; + *CellIndex = HCELL_NIL; + + /* Nothing found if we got here */ + Success = TRUE; + goto Return; + } + + /* Nothing found...check if the caller wanted more info */ + ASSERT(ChildList->Count == 0); + if (ChildIndex) *ChildIndex = 0; + *CellIndex = HCELL_NIL; + + /* Nothing found if we got here */ + return TRUE; + +Return: + /* Release the first cell we got */ + if (CellData) HvReleaseCell(Hive, ChildList->List); + + /* Release the secondary one, if we have one */ + if (CellToRelease) HvReleaseCell(Hive, CellToRelease); + return Success; +} diff --git a/reactos/ntoskrnl/config/cmparse.c b/reactos/ntoskrnl/config/cmparse.c index efb88ac07d9..71fec205113 100644 --- a/reactos/ntoskrnl/config/cmparse.c +++ b/reactos/ntoskrnl/config/cmparse.c @@ -1,1355 +1,1327 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/config/cmparse.c - * PURPOSE: Configuration Manager - Object Manager Parse Interface - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include "ntoskrnl.h" -#include "cm.h" -#define NDEBUG -#include "debug.h" - -/* GLOBALS *******************************************************************/ - -/* FUNCTIONS *****************************************************************/ - -BOOLEAN -NTAPI -CmpGetNextName(IN OUT PUNICODE_STRING RemainingName, - OUT PUNICODE_STRING NextName, - OUT PBOOLEAN LastName) -{ - BOOLEAN NameValid = TRUE; - - /* Check if there's nothing left in the name */ - if (!(RemainingName->Buffer) || - (!RemainingName->Length) || - !(*RemainingName->Buffer)) - { - /* Clear the next name and set this as last */ - *LastName = TRUE; - NextName->Buffer = NULL; - NextName->Length = 0; - return TRUE; - } - - /* Check if we have a path separator */ - if (*RemainingName->Buffer == OBJ_NAME_PATH_SEPARATOR) - { - /* Skip it */ - RemainingName->Buffer++; - RemainingName->Length -= sizeof(WCHAR); - RemainingName->MaximumLength -= sizeof(WCHAR); - } - - /* Start loop at where the current buffer is */ - NextName->Buffer = RemainingName->Buffer; - while (TRUE) - { - /* Break out if we ran out or hit a path separator */ - if (!(RemainingName->Length) || - (*RemainingName->Buffer == OBJ_NAME_PATH_SEPARATOR)) - { - break; - } - - /* Move to the next character */ - RemainingName->Buffer++; - RemainingName->Length -= sizeof(WCHAR); - RemainingName->MaximumLength -= sizeof(WCHAR); - } - - /* See how many chars we parsed and validate the length */ - NextName->Length = (USHORT)((ULONG_PTR)RemainingName->Buffer - - (ULONG_PTR)NextName->Buffer); - if (NextName->Length > 512) NameValid = FALSE; - NextName->MaximumLength = NextName->Length; - - /* If there's nothing left, we're last */ - *LastName = !RemainingName->Length; - return NameValid; -} - -BOOLEAN -NTAPI -CmpGetSymbolicLink(IN PHHIVE Hive, - IN OUT PUNICODE_STRING ObjectName, - IN OUT PCM_KEY_CONTROL_BLOCK SymbolicKcb, - IN PUNICODE_STRING RemainingName OPTIONAL) -{ - HCELL_INDEX LinkCell = HCELL_NIL; - PCM_KEY_VALUE LinkValue = NULL; - PWSTR LinkName = NULL; - BOOLEAN LinkNameAllocated = FALSE; - PWSTR NewBuffer; - ULONG Length = 0; - ULONG ValueLength = 0; - BOOLEAN Result = FALSE; - HCELL_INDEX CellToRelease = HCELL_NIL; - PCM_KEY_NODE Node; - UNICODE_STRING NewObjectName; - - /* Make sure we're not being deleted */ - if (SymbolicKcb->Delete) return FALSE; - - /* Get the key node */ - Node = (PCM_KEY_NODE)HvGetCell(SymbolicKcb->KeyHive, SymbolicKcb->KeyCell); - if (!Node) goto Exit; - - /* Find the symbolic link key */ - LinkCell = CmpFindValueByName(Hive, Node, &CmSymbolicLinkValueName); - HvReleaseCell(SymbolicKcb->KeyHive, SymbolicKcb->KeyCell); - if (LinkCell == HCELL_NIL) goto Exit; - - /* Get the value cell */ - LinkValue = (PCM_KEY_VALUE)HvGetCell(Hive, LinkCell); - if (!LinkValue) goto Exit; - - /* Make sure it's a registry link */ - if (LinkValue->Type != REG_LINK) goto Exit; - - /* Now read the value data */ - if (!CmpGetValueData(Hive, - LinkValue, - &ValueLength, - (PVOID)&LinkName, - &LinkNameAllocated, - &CellToRelease)) - { - /* Fail */ - goto Exit; - } - - /* Get the length */ - Length = ValueLength + sizeof(WCHAR); - - /* Make sure we start with a slash */ - if (*LinkName != OBJ_NAME_PATH_SEPARATOR) goto Exit; - - /* Add the remaining name if needed */ - if (RemainingName) Length += RemainingName->Length + sizeof(WCHAR); - - /* Check for overflow */ - if (Length > 0xFFFF) goto Exit; - - /* Check if we need a new buffer */ - if (Length > ObjectName->MaximumLength) - { - /* We do -- allocate one */ - NewBuffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM); - if (!NewBuffer) goto Exit; - - /* Setup the new string and copy the symbolic target */ - NewObjectName.Buffer = NewBuffer; - NewObjectName.MaximumLength = (USHORT)Length; - NewObjectName.Length = (USHORT)ValueLength; - RtlCopyMemory(NewBuffer, LinkName, ValueLength); - - /* Check if we need to add anything else */ - if (RemainingName) - { - /* Add the remaining name */ - NewBuffer[ValueLength / sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR; - NewObjectName.Length += sizeof(WCHAR); - RtlAppendUnicodeStringToString(&NewObjectName, RemainingName); - } - - /* Free the old buffer */ - ExFreePool(ObjectName->Buffer); - *ObjectName = NewObjectName; - } - else - { - /* The old name is large enough -- update the length */ - ObjectName->Length = (USHORT)ValueLength; - if (RemainingName) - { - /* Copy the remaining name inside */ - RtlMoveMemory(&ObjectName->Buffer[(ValueLength / sizeof(WCHAR)) + 1], - RemainingName->Buffer, - RemainingName->Length); - - /* Add the slash and update the length */ - ObjectName->Buffer[ValueLength / sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR; - ObjectName->Length += RemainingName->Length + sizeof(WCHAR); - } - - /* Copy the symbolic link target name */ - RtlCopyMemory(ObjectName->Buffer, LinkName, ValueLength); - } - - /* Null-terminate the whole thing */ - ObjectName->Buffer[ObjectName->Length / sizeof(WCHAR)] = UNICODE_NULL; - Result = TRUE; - -Exit: - /* Free the link name */ - if (LinkNameAllocated) ExFreePool(LinkName); - - /* Check if we had a value cell */ - if (LinkValue) - { - /* Release it */ - ASSERT(LinkCell != HCELL_NIL); - HvReleaseCell(Hive, LinkCell); - } - - /* Check if we had an active cell and release it, then return the result */ - if (CellToRelease != HCELL_NIL) HvReleaseCell(Hive, CellToRelease); - return Result; -} - -NTSTATUS -NTAPI -CmpDoCreateChild(IN PHHIVE Hive, - IN HCELL_INDEX ParentCell, - IN PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL, - IN PACCESS_STATE AccessState, - IN PUNICODE_STRING Name, - IN KPROCESSOR_MODE AccessMode, - IN PCM_PARSE_CONTEXT ParseContext, - IN PCM_KEY_CONTROL_BLOCK ParentKcb, - IN ULONG Flags, - OUT PHCELL_INDEX KeyCell, - OUT PVOID *Object) -{ - NTSTATUS Status = STATUS_SUCCESS; - PCM_KEY_BODY KeyBody; - HCELL_INDEX ClassCell = HCELL_NIL; - PCM_KEY_NODE KeyNode; - PCELL_DATA CellData; - ULONG StorageType; - LARGE_INTEGER SystemTime; - BOOLEAN Hack = FALSE; - PCM_KEY_CONTROL_BLOCK Kcb; - - /* ReactOS Hack */ - if (Name->Buffer[0] == OBJ_NAME_PATH_SEPARATOR) - { - /* Skip initial path separator */ - Name->Buffer++; - Name->Length -= sizeof(OBJ_NAME_PATH_SEPARATOR); - Name->MaximumLength -= sizeof(OBJ_NAME_PATH_SEPARATOR); - Hack = TRUE; - } - - /* Get the storage type */ - StorageType = Stable; - if (Flags & REG_OPTION_VOLATILE) StorageType = Volatile; - - /* Allocate the child */ - *KeyCell = HvAllocateCell(Hive, - FIELD_OFFSET(CM_KEY_NODE, Name) + - CmpNameSize(Hive, Name), - StorageType, - HCELL_NIL); - if (*KeyCell == HCELL_NIL) - { - /* Fail */ - Status = STATUS_INSUFFICIENT_RESOURCES; - goto Quickie; - } - - /* Get the key node */ - KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, *KeyCell); - if (!KeyNode) - { - /* Fail, this should never happen */ - ASSERT(FALSE); - Status = STATUS_INSUFFICIENT_RESOURCES; - goto Quickie; - } - - /* Release the cell */ - HvReleaseCell(Hive, *KeyCell); - - /* Check if we have a class name */ - if (ParseContext->Class.Length > 0) - { - /* Allocate a class cell */ - ClassCell = HvAllocateCell(Hive, - ParseContext->Class.Length, - StorageType, - HCELL_NIL); - if (ClassCell == HCELL_NIL) - { - /* Fail */ - Status = STATUS_INSUFFICIENT_RESOURCES; - goto Quickie; - } - } - - /* Allocate the Cm Object */ - Status = ObCreateObject(AccessMode, - CmpKeyObjectType, - NULL, - AccessMode, - NULL, - sizeof(CM_KEY_BODY), - 0, - 0, - Object); - if (!NT_SUCCESS(Status)) goto Quickie; - - /* Setup the key body */ - KeyBody = (PCM_KEY_BODY)(*Object); - KeyBody->Type = TAG('k', 'y', '0', '2'); - KeyBody->KeyControlBlock = NULL; - - /* Check if we had a class */ - if (ParseContext->Class.Length > 0) - { - /* Get the class cell */ - CellData = HvGetCell(Hive, ClassCell); - if (!CellData) - { - /* Fail, this should never happen */ - ASSERT(FALSE); - Status = STATUS_INSUFFICIENT_RESOURCES; - ObDereferenceObject(*Object); - goto Quickie; - } - - /* Release the cell */ - HvReleaseCell(Hive, ClassCell); - - /* Copy the class data */ - RtlCopyMemory(&CellData->u.KeyString[0], - ParseContext->Class.Buffer, - ParseContext->Class.Length); - } - - /* Fill out the key node */ - KeyNode->Signature = CM_KEY_NODE_SIGNATURE; - KeyNode->Flags = Flags &~ REG_OPTION_CREATE_LINK; - KeQuerySystemTime(&SystemTime); - KeyNode->LastWriteTime = SystemTime; - KeyNode->Spare = 0; - KeyNode->Parent = ParentCell; - KeyNode->SubKeyCounts[Stable] = 0; - KeyNode->SubKeyCounts[Volatile] = 0; - KeyNode->SubKeyLists[Stable] = HCELL_NIL; - KeyNode->SubKeyLists[Volatile] = HCELL_NIL; - KeyNode->ValueList.Count = 0; - KeyNode->ValueList.List = HCELL_NIL; - KeyNode->Security = HCELL_NIL; - KeyNode->Class = ClassCell; - KeyNode->ClassLength = ParseContext->Class.Length; - KeyNode->MaxValueDataLen = 0; - KeyNode->MaxNameLen = 0; - KeyNode->MaxValueNameLen = 0; - KeyNode->MaxClassLen = 0; - KeyNode->NameLength = CmpCopyName(Hive, KeyNode->Name, Name); - if (KeyNode->NameLength < Name->Length) KeyNode->Flags |= KEY_COMP_NAME; - - /* Create the KCB */ - Kcb = CmpCreateKeyControlBlock(Hive, - *KeyCell, - KeyNode, - ParentKcb, - CMP_LOCK_HASHES_FOR_KCB, - Name); - if (!Kcb) - { - /* Fail */ - ObDereferenceObjectDeferDelete(*Object); - Status = STATUS_INSUFFICIENT_RESOURCES; - goto Quickie; - } - - /* Sanity check */ - ASSERT(Kcb->RefCount == 1); - - /* Now fill out the Cm object */ - KeyBody->NotifyBlock = NULL; - KeyBody->ProcessID = PsGetCurrentProcessId(); - KeyBody->KeyControlBlock = Kcb; - - /* Link it with the KCB */ - EnlistKeyBodyWithKCB(KeyBody, 0); - -Quickie: - /* Check if we got here because of failure */ - if (!NT_SUCCESS(Status)) - { - /* Free any cells we might've allocated */ - if (ParseContext->Class.Length > 0) HvFreeCell(Hive, ClassCell); - HvFreeCell(Hive, *KeyCell); - } - - /* Check if we applied ReactOS hack */ - if (Hack) - { - /* Restore name */ - Name->Buffer--; - Name->Length += sizeof(OBJ_NAME_PATH_SEPARATOR); - Name->MaximumLength += sizeof(OBJ_NAME_PATH_SEPARATOR); - } - - /* Return status */ - return Status; -} - -NTSTATUS -NTAPI -CmpDoCreate(IN PHHIVE Hive, - IN HCELL_INDEX Cell, - IN PACCESS_STATE AccessState, - IN PUNICODE_STRING Name, - IN KPROCESSOR_MODE AccessMode, - IN PCM_PARSE_CONTEXT ParseContext, - IN PCM_KEY_CONTROL_BLOCK ParentKcb, - OUT PVOID *Object) -{ - NTSTATUS Status; - PCELL_DATA CellData; - HCELL_INDEX KeyCell; - ULONG ParentType; - PCM_KEY_BODY KeyBody; - PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; - LARGE_INTEGER TimeStamp; - PCM_KEY_NODE KeyNode; - - /* Sanity check */ -#if 0 - ASSERT((CmpIsKcbLockedExclusive(ParentKcb) == TRUE) || - (CmpTestRegistryLockExclusive() == TRUE)); -#endif - - /* Acquire the flusher lock */ - ExAcquirePushLockShared((PVOID)&((PCMHIVE)Hive)->FlusherLock); - - /* Check if the parent is being deleted */ - if (ParentKcb->Delete) - { - /* It has, quit */ - ASSERT(FALSE); - Status = STATUS_OBJECT_NAME_NOT_FOUND; - goto Exit; - } - - /* Get the parent node */ - KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Cell); - if (!KeyNode) - { - /* Fail */ - ASSERT(FALSE); - Status = STATUS_INSUFFICIENT_RESOURCES; - goto Exit; - } - - /* Make sure nobody added us yet */ - if (CmpFindSubKeyByName(Hive, KeyNode, Name) != HCELL_NIL) - { - /* Fail */ - ASSERT(FALSE); - Status = STATUS_REPARSE; - goto Exit; - } - - /* Sanity check */ - ASSERT(Cell == ParentKcb->KeyCell); - - /* Get the parent type */ - ParentType = HvGetCellType(Cell); - if ((ParentType == Volatile) && - !(ParseContext->CreateOptions & REG_OPTION_VOLATILE)) - { - /* Children of volatile parents must also be volatile */ - ASSERT(FALSE); - Status = STATUS_CHILD_MUST_BE_VOLATILE; - goto Exit; - } - - /* Don't allow children under symlinks */ - if (ParentKcb->Flags & KEY_SYM_LINK) - { - /* Fail */ - ASSERT(FALSE); - Status = STATUS_ACCESS_DENIED; - goto Exit; - } - - /* Make the cell dirty for now */ - HvMarkCellDirty(Hive, Cell, FALSE); - - /* Do the actual create operation */ - Status = CmpDoCreateChild(Hive, - Cell, - SecurityDescriptor, - AccessState, - Name, - AccessMode, - ParseContext, - ParentKcb, - ParseContext->CreateOptions, // WRONG! - &KeyCell, - Object); - if (NT_SUCCESS(Status)) - { - /* Get the key body */ - KeyBody = (PCM_KEY_BODY)(*Object); - - /* Now add the subkey */ - if (!CmpAddSubKey(Hive, Cell, KeyCell)) - { - /* Failure! We don't handle this yet! */ - ASSERT(FALSE); - } - - /* Get the key node */ - KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Cell); - if (!KeyNode) - { - /* Fail, this shouldn't happen */ - ASSERT(FALSE); - } - - /* Sanity checks */ - ASSERT(KeyBody->KeyControlBlock->ParentKcb->KeyCell == Cell); - ASSERT(KeyBody->KeyControlBlock->ParentKcb->KeyHive == Hive); - ASSERT(KeyBody->KeyControlBlock->ParentKcb == ParentKcb); - ASSERT(KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen == KeyNode->MaxNameLen); - - /* Update the timestamp */ - KeQuerySystemTime(&TimeStamp); - KeyNode->LastWriteTime = TimeStamp; - KeyBody->KeyControlBlock->ParentKcb->KcbLastWriteTime = TimeStamp; - - /* Check if we need to update name maximum */ - if (KeyNode->MaxNameLen < Name->Length) - { - /* Do it */ - KeyNode->MaxNameLen = Name->Length; - KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen = Name->Length; - } - - /* Check if we need toupdate class length maximum */ - if (KeyNode->MaxClassLen < ParseContext->Class.Length) - { - /* Update it */ - KeyNode->MaxClassLen = ParseContext->Class.Length; - } - - /* Check if we're creating a symbolic link */ - if (ParseContext->CreateOptions & REG_OPTION_CREATE_LINK) - { - /* Get the cell data */ - CellData = HvGetCell(Hive, KeyCell); - if (!CellData) - { - /* This shouldn't happen */ - ASSERT(FALSE); - } - - /* Update the flags */ - CellData->u.KeyNode.Flags |= KEY_SYM_LINK; - KeyBody->KeyControlBlock->Flags = CellData->u.KeyNode.Flags; - HvReleaseCell(Hive, KeyCell); - } - } - -Exit: - /* Release the flusher lock and return status */ - ExReleasePushLock((PVOID)&((PCMHIVE)Hive)->FlusherLock); - return Status; -} - -NTSTATUS -NTAPI -CmpDoOpen(IN PHHIVE Hive, - IN HCELL_INDEX Cell, - IN PCM_KEY_NODE Node, - IN PACCESS_STATE AccessState, - IN KPROCESSOR_MODE AccessMode, - IN ULONG Attributes, - IN PCM_PARSE_CONTEXT Context OPTIONAL, - IN ULONG ControlFlags, - IN OUT PCM_KEY_CONTROL_BLOCK *CachedKcb, - IN PUNICODE_STRING KeyName, - OUT PVOID *Object) -{ - NTSTATUS Status; - PCM_KEY_BODY KeyBody = NULL; - PCM_KEY_CONTROL_BLOCK Kcb = NULL; - - /* Make sure the hive isn't locked */ - if ((Hive->HiveFlags & HIVE_IS_UNLOADING) && - (((PCMHIVE)Hive)->CreatorOwner != KeGetCurrentThread())) - { - /* It is, don't touch it */ - return STATUS_OBJECT_NAME_NOT_FOUND; - } - - /* Check if we have a context */ - if (Context) - { - /* Check if this is a link create (which shouldn't be an open) */ - if (Context->CreateLink) - { - return STATUS_ACCESS_DENIED; - } - - /* Check if this is symlink create attempt */ - if (Context->CreateOptions & REG_OPTION_CREATE_LINK) - { - /* Key already exists */ - return STATUS_OBJECT_NAME_COLLISION; - } - - /* Set the disposition */ - Context->Disposition = REG_OPENED_EXISTING_KEY; - } - - /* Do this in the registry lock */ - CmpLockRegistry(); - - /* If we have a KCB, make sure it's locked */ - //ASSERT(CmpIsKcbLockedExclusive(*CachedKcb)); - - /* Check if this is a symlink */ - if ((Node->Flags & KEY_SYM_LINK) && !(Attributes & OBJ_OPENLINK)) - { - /* Create the KCB for the symlink */ - Kcb = CmpCreateKeyControlBlock(Hive, - Cell, - Node, - *CachedKcb, - 0, - KeyName); - if (!Kcb) return STATUS_INSUFFICIENT_RESOURCES; - - /* Make sure it's also locked, and set the pointer */ - //ASSERT(CmpIsKcbLockedExclusive(Kcb)); - *CachedKcb = Kcb; - - /* Release the registry lock */ - CmpUnlockRegistry(); - - /* Return reparse required */ - return STATUS_REPARSE; - } - - /* Create the KCB. FIXME: Use lock flag */ - Kcb = CmpCreateKeyControlBlock(Hive, - Cell, - Node, - *CachedKcb, - 0, - KeyName); - if (!Kcb) return STATUS_INSUFFICIENT_RESOURCES; - - /* Make sure it's also locked, and set the pointer */ - //ASSERT(CmpIsKcbLockedExclusive(Kcb)); - *CachedKcb = Kcb; - - /* Release the registry lock */ - CmpUnlockRegistry(); - - /* Allocate the key object */ - Status = ObCreateObject(AccessMode, - CmpKeyObjectType, - NULL, - AccessMode, - NULL, - sizeof(CM_KEY_BODY), - 0, - 0, - Object); - if (NT_SUCCESS(Status)) - { - /* Get the key body and fill it out */ - KeyBody = (PCM_KEY_BODY)(*Object); - KeyBody->KeyControlBlock = Kcb; - KeyBody->Type = TAG('k', 'y', '0', '2'); - KeyBody->ProcessID = PsGetCurrentProcessId(); - KeyBody->NotifyBlock = NULL; - - /* Link to the KCB */ - EnlistKeyBodyWithKCB(KeyBody, 0); - } - else - { - /* Failed, dereference the KCB */ - CmpDereferenceKeyControlBlockWithLock(Kcb, FALSE); - } - - /* Return status */ - return Status; -} - -/* Remove calls to CmCreateRootNode once this is used! */ -NTSTATUS -NTAPI -CmpCreateLinkNode(IN PHHIVE Hive, - IN HCELL_INDEX Cell, - IN PACCESS_STATE AccessState, - IN UNICODE_STRING Name, - IN KPROCESSOR_MODE AccessMode, - IN ULONG CreateOptions, - IN PCM_PARSE_CONTEXT Context, - IN PCM_KEY_CONTROL_BLOCK ParentKcb, - OUT PVOID *Object) -{ - NTSTATUS Status; - HCELL_INDEX KeyCell, LinkCell, ChildCell; - PCM_KEY_BODY KeyBody; - LARGE_INTEGER TimeStamp; - PCM_KEY_NODE KeyNode; - PCM_KEY_CONTROL_BLOCK Kcb = ParentKcb; -#if 0 - CMP_ASSERT_REGISTRY_LOCK(); -#endif - - /* Link nodes only allowed on the master */ - if (Hive != &CmiVolatileHive->Hive) - { - /* Fail */ - DPRINT1("Invalid link node attempt\n"); - return STATUS_ACCESS_DENIED; - } - - /* Acquire the flusher locks */ - ExAcquirePushLockShared((PVOID)&((PCMHIVE)Hive)->FlusherLock); - ExAcquirePushLockShared((PVOID)&((PCMHIVE)Context->ChildHive.KeyHive)->FlusherLock); - - /* Check if the parent is being deleted */ - if (ParentKcb->Delete) - { - /* It is, quit */ - ASSERT(FALSE); - Status = STATUS_OBJECT_NAME_NOT_FOUND; - goto Exit; - } - - /* Allocate a link node */ - LinkCell = HvAllocateCell(Hive, - FIELD_OFFSET(CM_KEY_NODE, Name) + - CmpNameSize(Hive, &Name), - Stable, - HCELL_NIL); - if (LinkCell == HCELL_NIL) - { - /* Fail */ - Status = STATUS_INSUFFICIENT_RESOURCES; - goto Exit; - } - - /* Get the key cell */ - KeyCell = Context->ChildHive.KeyCell; - if (KeyCell != HCELL_NIL) - { - /* Hive exists! */ - ChildCell = KeyCell; - - /* Get the node data */ - KeyNode = (PCM_KEY_NODE)HvGetCell(Context->ChildHive.KeyHive, ChildCell); - if (!KeyNode) - { - /* Fail */ - ASSERT(FALSE); - Status = STATUS_INSUFFICIENT_RESOURCES; - goto Exit; - } - - /* Fill out the data */ - KeyNode->Parent = LinkCell; - KeyNode->Flags |= KEY_HIVE_ENTRY | KEY_NO_DELETE; - HvReleaseCell(Context->ChildHive.KeyHive, ChildCell); - - /* Now open the key cell */ - KeyNode = (PCM_KEY_NODE)HvGetCell(Context->ChildHive.KeyHive, KeyCell); - if (!KeyNode) - { - /* Fail */ - ASSERT(FALSE); - Status = STATUS_INSUFFICIENT_RESOURCES; - goto Exit; - } - - /* Open the parent */ - Status = CmpDoOpen(Context->ChildHive.KeyHive, - KeyCell, - KeyNode, - AccessState, - AccessMode, - CreateOptions, - NULL, - 0, - &Kcb, - &Name, - Object); - HvReleaseCell(Context->ChildHive.KeyHive, KeyCell); - } - else - { - /* Do the actual create operation */ - Status = CmpDoCreateChild(Context->ChildHive.KeyHive, - Cell, - NULL, - AccessState, - &Name, - AccessMode, - Context, - ParentKcb, - KEY_HIVE_ENTRY | KEY_NO_DELETE, - &ChildCell, - Object); - if (NT_SUCCESS(Status)) - { - /* Setup root pointer */ - Context->ChildHive.KeyHive->BaseBlock->RootCell = ChildCell; - } - } - - /* Check if open or create suceeded */ - if (NT_SUCCESS(Status)) - { - /* Mark the cell dirty */ - HvMarkCellDirty(Context->ChildHive.KeyHive, ChildCell, FALSE); - - /* Get the key node */ - KeyNode = HvGetCell(Context->ChildHive.KeyHive, ChildCell); - if (!KeyNode) - { - /* Fail */ - ASSERT(FALSE); - Status = STATUS_INSUFFICIENT_RESOURCES; - goto Exit; - } - - /* Release it */ - HvReleaseCell(Context->ChildHive.KeyHive, ChildCell); - - /* Set the parent and flags */ - KeyNode->Parent = LinkCell; - KeyNode->Flags |= KEY_HIVE_ENTRY | KEY_NO_DELETE; - - /* Get the link node */ - KeyNode = HvGetCell(Hive, LinkCell); - if (!KeyNode) - { - /* Fail */ - ASSERT(FALSE); - Status = STATUS_INSUFFICIENT_RESOURCES; - goto Exit; - } - - /* Set it up */ - KeyNode->Signature = CM_LINK_NODE_SIGNATURE; - KeyNode->Flags = KEY_HIVE_EXIT | KEY_NO_DELETE; - KeyNode->Parent = Cell; - KeyNode->NameLength = CmpCopyName(Hive, KeyNode->Name, &Name); - if (KeyNode->NameLength < Name.Length) KeyNode->Flags |= KEY_COMP_NAME; - KeQuerySystemTime(&TimeStamp); - KeyNode->LastWriteTime = TimeStamp; - - /* Clear out the rest */ - KeyNode->SubKeyCounts[Stable] = 0; - KeyNode->SubKeyCounts[Volatile] = 0; - KeyNode->SubKeyLists[Stable] = HCELL_NIL; - KeyNode->SubKeyLists[Volatile] = HCELL_NIL; - KeyNode->ValueList.Count = 0; - KeyNode->ValueList.List = HCELL_NIL; - KeyNode->ClassLength = 0; - - /* Reference the root node */ - KeyNode->ChildHiveReference.KeyHive = Context->ChildHive.KeyHive; - KeyNode->ChildHiveReference.KeyCell = ChildCell; - HvReleaseCell(Hive, LinkCell); - - /* Get the parent node */ - KeyNode = HvGetCell(Hive, Cell); - if (!KeyNode) - { - /* Fail */ - ASSERT(FALSE); - Status = STATUS_INSUFFICIENT_RESOURCES; - goto Exit; - } - - /* Now add the subkey */ - if (!CmpAddSubKey(Hive, Cell, LinkCell)) - { - /* Failure! We don't handle this yet! */ - ASSERT(FALSE); - } - - /* Get the key body */ - KeyBody = (PCM_KEY_BODY)*Object; - - /* Sanity checks */ - ASSERT(KeyBody->KeyControlBlock->ParentKcb->KeyCell == Cell); - ASSERT(KeyBody->KeyControlBlock->ParentKcb->KeyHive == Hive); - ASSERT(KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen == KeyNode->MaxNameLen); - - /* Update the timestamp */ - KeQuerySystemTime(&TimeStamp); - KeyNode->LastWriteTime = TimeStamp; - KeyBody->KeyControlBlock->ParentKcb->KcbLastWriteTime = TimeStamp; - - /* Check if we need to update name maximum */ - if (KeyNode->MaxNameLen < Name.Length) - { - /* Do it */ - KeyNode->MaxNameLen = Name.Length; - KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen = Name.Length; - } - - /* Check if we need toupdate class length maximum */ - if (KeyNode->MaxClassLen < Context->Class.Length) - { - /* Update it */ - KeyNode->MaxClassLen = Context->Class.Length; - } - - /* Release the cell */ - HvReleaseCell(Hive, Cell); - } - else - { - /* Release the link cell */ - HvReleaseCell(Hive, LinkCell); - } - -Exit: - /* Release the flusher locks and return status */ - ExReleasePushLock((PVOID)&((PCMHIVE)Context->ChildHive.KeyHive)->FlusherLock); - ExReleasePushLock((PVOID)&((PCMHIVE)Hive)->FlusherLock); - return Status; -} - -VOID -NTAPI -CmpHandleExitNode(IN OUT PHHIVE *Hive, - IN OUT HCELL_INDEX *Cell, - IN OUT PCM_KEY_NODE *KeyNode, - IN OUT PHHIVE *ReleaseHive, - IN OUT HCELL_INDEX *ReleaseCell) -{ - /* Check if we have anything to release */ - if (*ReleaseCell != HCELL_NIL) - { - /* Release it */ - ASSERT(*ReleaseHive != NULL); - HvReleaseCell((*ReleaseHive), *ReleaseCell); - } - - /* Get the link references */ - *Hive = (*KeyNode)->ChildHiveReference.KeyHive; - *Cell = (*KeyNode)->ChildHiveReference.KeyCell; - - /* Get the new node */ - *KeyNode = (PCM_KEY_NODE)HvGetCell((*Hive), *Cell); - if (*KeyNode) - { - /* Set the new release values */ - *ReleaseCell = *Cell; - *ReleaseHive = *Hive; - } - else - { - /* Nothing to release */ - *ReleaseCell = HCELL_NIL; - *ReleaseHive = NULL; - } -} - -NTSTATUS -NTAPI -CmpBuildHashStackAndLookupCache(IN PCM_KEY_BODY ParseObject, - IN OUT PCM_KEY_CONTROL_BLOCK *Kcb, - IN PUNICODE_STRING Current, - OUT PHHIVE *Hive, - OUT HCELL_INDEX *Cell, - OUT PULONG TotalRemainingSubkeys, - OUT PULONG MatchRemainSubkeyLevel, - OUT PULONG TotalSubkeys, - OUT PULONG OuterStackArray, - OUT PULONG *LockedKcbs) -{ - ULONG HashKeyCopy; - - /* We don't lock anything for now */ - *LockedKcbs = NULL; - - /* Make a copy of the hash key */ - HashKeyCopy = (*Kcb)->ConvKey; - - /* Calculate hash values */ - *TotalRemainingSubkeys = 0xBAADF00D; - - /* Lock the registry */ - CmpLockRegistry(); - - /* Return hive and cell data */ - *Hive = (*Kcb)->KeyHive; - *Cell = (*Kcb)->KeyCell; - - /* Return success for now */ - return STATUS_SUCCESS; -} - -NTSTATUS -NTAPI -CmpParseKey2(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 Status; - PCM_KEY_CONTROL_BLOCK Kcb, ParentKcb; - PHHIVE Hive = NULL; - PCM_KEY_NODE Node = NULL; - HCELL_INDEX Cell = HCELL_NIL, NextCell; - PHHIVE HiveToRelease = NULL; - HCELL_INDEX CellToRelease = HCELL_NIL; - UNICODE_STRING Current, NextName; - PCM_PARSE_CONTEXT ParseContext = Context; - ULONG TotalRemainingSubkeys = 0, MatchRemainSubkeyLevel = 0, TotalSubkeys = 0; - PULONG LockedKcbs = NULL; - BOOLEAN Result, Last; - PAGED_CODE(); - - /* Loop path separators at the end */ - while ((RemainingName->Length) && - (RemainingName->Buffer[(RemainingName->Length / sizeof(WCHAR)) - 1] == - OBJ_NAME_PATH_SEPARATOR)) - { - /* Remove path separator */ - RemainingName->Length -= sizeof(WCHAR); - } - - /* Fail if this isn't a key object */ - if (ObjectType != CmpKeyObjectType) return STATUS_OBJECT_TYPE_MISMATCH; - - /* Copy the remaining name */ - Current = *RemainingName; - - /* Check if this is a create */ - if (!(ParseContext) || !(ParseContext->CreateOperation)) - { - /* It isn't, so no context */ - ParseContext = NULL; - } - - /* Grab the KCB */ - Kcb = ((PCM_KEY_BODY)ParseObject)->KeyControlBlock; - - /* Lookup in the cache */ - Status = CmpBuildHashStackAndLookupCache(ParseObject, - &Kcb, - &Current, - &Hive, - &Cell, - &TotalRemainingSubkeys, - &MatchRemainSubkeyLevel, - &TotalSubkeys, - NULL, - &LockedKcbs); - - /* This is now the parent */ - ParentKcb = Kcb; - - /* Check if everything was found cached */ - if (!TotalRemainingSubkeys) ASSERTMSG("Caching not implemented", FALSE); - - /* Don't do anything if we're being deleted */ - if (Kcb->Delete) return STATUS_OBJECT_NAME_NOT_FOUND; - - /* Check if this is a symlink */ - if (Kcb->Flags & KEY_SYM_LINK) - { - /* Get the next name */ - Result = CmpGetNextName(&Current, &NextName, &Last); - Current.Buffer = NextName.Buffer; - - /* Validate the current name string length */ - if (Current.Length + NextName.Length > MAXUSHORT) - { - /* too long */ - Status = STATUS_NAME_TOO_LONG; - goto Quickie; - } - Current.Length += NextName.Length; - - /* Validate the current name string maximum length */ - if (Current.MaximumLength + NextName.MaximumLength > MAXUSHORT) - { - /* too long */ - Status = STATUS_NAME_TOO_LONG; - goto Quickie; - } - Current.MaximumLength += NextName.MaximumLength; - - /* Parse the symlink */ - if (CmpGetSymbolicLink(Hive, - CompleteName, - Kcb, - &Current)) - { - /* Symlink parse succeeded */ - Status = STATUS_REPARSE; - } - else - { - /* Couldn't find symlink */ - Status = STATUS_OBJECT_NAME_NOT_FOUND; - } - - /* We're done */ - goto Quickie; - } - - /* Get the key node */ - Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell); - if (!Node) return STATUS_INSUFFICIENT_RESOURCES; - - /* Start parsing */ - Status = STATUS_NOT_IMPLEMENTED; - while (TRUE) - { - /* Get the next component */ - Result = CmpGetNextName(&Current, &NextName, &Last); - if ((Result) && (NextName.Length)) - { - /* See if this is a sym link */ - if (!(Kcb->Flags & KEY_SYM_LINK)) - { - /* Find the subkey */ - NextCell = CmpFindSubKeyByName(Hive, Node, &NextName); - if (NextCell != HCELL_NIL) - { - /* Get the new node */ - Cell = NextCell; - Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell); - if (!Node) ASSERT(FALSE); - - /* Check if this was the last key */ - if (Last) - { - /* Is this an exit node */ - if (Node->Flags & KEY_HIVE_EXIT) - { - /* Handle it */ - CmpHandleExitNode(&Hive, - &Cell, - &Node, - &HiveToRelease, - &CellToRelease); - if (!Node) ASSERT(FALSE); - } - - /* Do the open */ - Status = CmpDoOpen(Hive, - Cell, - Node, - AccessState, - AccessMode, - Attributes, - ParseContext, - 0, - &Kcb, - &NextName, - Object); - if (Status == STATUS_REPARSE) - { - /* Parse the symlink */ - if (!CmpGetSymbolicLink(Hive, - CompleteName, - Kcb, - NULL)) - { - /* Symlink parse failed */ - Status = STATUS_OBJECT_NAME_NOT_FOUND; - } - } - - /* We are done */ - break; - } - - /* Is this an exit node */ - if (Node->Flags & KEY_HIVE_EXIT) - { - /* Handle it */ - CmpHandleExitNode(&Hive, - &Cell, - &Node, - &HiveToRelease, - &CellToRelease); - if (!Node) ASSERT(FALSE); - } - - /* Create a KCB for this key */ - Kcb = CmpCreateKeyControlBlock(Hive, - Cell, - Node, - ParentKcb, - 0, - &NextName); - if (!Kcb) ASSERT(FALSE); - - /* Dereference the parent and set the new one */ - //CmpDereferenceKeyControlBlock(ParentKcb); - ParentKcb = Kcb; - } - else - { - /* Check if this was the last key for a create */ - if ((Last) && (ParseContext)) - { - PCM_KEY_BODY KeyBody; - - /* Check if we're doing a link node */ - if (ParseContext->CreateLink) - { - /* The only thing we should see */ - Status = CmpCreateLinkNode(Hive, - Cell, - AccessState, - NextName, - AccessMode, - Attributes, - ParseContext, - ParentKcb, - Object); - } - else - { - /* Do the create */ - Status = CmpDoCreate(Hive, - Cell, - AccessState, - &NextName, - AccessMode, - ParseContext, - ParentKcb, - Object); - } - - /* Check for reparse (in this case, someone beat us) */ - if (Status == STATUS_REPARSE) break; - - /* ReactOS Hack: Link this key to the parent */ - KeyBody = (PCM_KEY_BODY)*Object; - InsertTailList(&ParentKcb->KeyBodyListHead, - &KeyBody->KeyBodyList); - - /* Update disposition */ - ParseContext->Disposition = REG_CREATED_NEW_KEY; - break; - } - else - { - /* Key not found */ - Status = STATUS_OBJECT_NAME_NOT_FOUND; - break; - } - } - } - else - { - /* Save the next name */ - Current.Buffer = NextName.Buffer; - - /* Validate the current name string length */ - if (Current.Length + NextName.Length > MAXUSHORT) - { - /* too long */ - Status = STATUS_NAME_TOO_LONG; - break; - } - Current.Length += NextName.Length; - - /* Validate the current name string maximum length */ - if (Current.MaximumLength + NextName.MaximumLength > MAXUSHORT) - { - /* too long */ - Status = STATUS_NAME_TOO_LONG; - break; - } - Current.MaximumLength += NextName.MaximumLength; - - /* Parse the symlink */ - if (CmpGetSymbolicLink(Hive, - CompleteName, - Kcb, - &Current)) - { - /* Symlink parse succeeded */ - Status = STATUS_REPARSE; - } - else - { - /* Couldn't find symlink */ - Status = STATUS_OBJECT_NAME_NOT_FOUND; - } - - /* We're done */ - break; - } - } - else if ((Result) && (Last)) - { - /* Opening the root. Is this an exit node? */ - if (Node->Flags & KEY_HIVE_EXIT) - { - /* Handle it */ - CmpHandleExitNode(&Hive, - &Cell, - &Node, - &HiveToRelease, - &CellToRelease); - if (!Node) ASSERT(FALSE); - } - - /* FIXME: This hack seems required? */ - RtlInitUnicodeString(&NextName, L"\\REGISTRY"); - - /* Do the open */ - Status = CmpDoOpen(Hive, - Cell, - Node, - AccessState, - AccessMode, - Attributes, - ParseContext, - 0, - &Kcb, - &NextName, - Object); - if (Status == STATUS_REPARSE) - { - /* Nothing to do */ - } - - /* We're done */ - break; - } - else - { - /* Bogus */ - Status = STATUS_INVALID_PARAMETER; - break; - } - } - - /* Dereference the parent if it exists */ -Quickie: - //if (ParentKcb) CmpDereferenceKeyControlBlock(ParentKcb); - - /* Unlock the registry */ - CmpUnlockRegistry(); - return Status; -} +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmparse.c + * PURPOSE: Configuration Manager - Object Manager Parse Interface + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#define NDEBUG +#include "debug.h" + +/* GLOBALS *******************************************************************/ + +/* FUNCTIONS *****************************************************************/ + +BOOLEAN +NTAPI +CmpGetNextName(IN OUT PUNICODE_STRING RemainingName, + OUT PUNICODE_STRING NextName, + OUT PBOOLEAN LastName) +{ + BOOLEAN NameValid = TRUE; + + /* Check if there's nothing left in the name */ + if (!(RemainingName->Buffer) || + (!RemainingName->Length) || + !(*RemainingName->Buffer)) + { + /* Clear the next name and set this as last */ + *LastName = TRUE; + NextName->Buffer = NULL; + NextName->Length = 0; + return TRUE; + } + + /* Check if we have a path separator */ + if (*RemainingName->Buffer == OBJ_NAME_PATH_SEPARATOR) + { + /* Skip it */ + RemainingName->Buffer++; + RemainingName->Length -= sizeof(WCHAR); + RemainingName->MaximumLength -= sizeof(WCHAR); + } + + /* Start loop at where the current buffer is */ + NextName->Buffer = RemainingName->Buffer; + while (TRUE) + { + /* Break out if we ran out or hit a path separator */ + if (!(RemainingName->Length) || + (*RemainingName->Buffer == OBJ_NAME_PATH_SEPARATOR)) + { + break; + } + + /* Move to the next character */ + RemainingName->Buffer++; + RemainingName->Length -= sizeof(WCHAR); + RemainingName->MaximumLength -= sizeof(WCHAR); + } + + /* See how many chars we parsed and validate the length */ + NextName->Length = (USHORT)((ULONG_PTR)RemainingName->Buffer - + (ULONG_PTR)NextName->Buffer); + if (NextName->Length > 512) NameValid = FALSE; + NextName->MaximumLength = NextName->Length; + + /* If there's nothing left, we're last */ + *LastName = !RemainingName->Length; + return NameValid; +} + +BOOLEAN +NTAPI +CmpGetSymbolicLink(IN PHHIVE Hive, + IN OUT PUNICODE_STRING ObjectName, + IN OUT PCM_KEY_CONTROL_BLOCK SymbolicKcb, + IN PUNICODE_STRING RemainingName OPTIONAL) +{ + HCELL_INDEX LinkCell = HCELL_NIL; + PCM_KEY_VALUE LinkValue = NULL; + PWSTR LinkName = NULL; + BOOLEAN LinkNameAllocated = FALSE; + PWSTR NewBuffer; + ULONG Length = 0; + ULONG ValueLength = 0; + BOOLEAN Result = FALSE; + HCELL_INDEX CellToRelease = HCELL_NIL; + PCM_KEY_NODE Node; + UNICODE_STRING NewObjectName; + + /* Make sure we're not being deleted */ + if (SymbolicKcb->Delete) return FALSE; + + /* Get the key node */ + Node = (PCM_KEY_NODE)HvGetCell(SymbolicKcb->KeyHive, SymbolicKcb->KeyCell); + if (!Node) goto Exit; + + /* Find the symbolic link key */ + LinkCell = CmpFindValueByName(Hive, Node, &CmSymbolicLinkValueName); + HvReleaseCell(SymbolicKcb->KeyHive, SymbolicKcb->KeyCell); + if (LinkCell == HCELL_NIL) goto Exit; + + /* Get the value cell */ + LinkValue = (PCM_KEY_VALUE)HvGetCell(Hive, LinkCell); + if (!LinkValue) goto Exit; + + /* Make sure it's a registry link */ + if (LinkValue->Type != REG_LINK) goto Exit; + + /* Now read the value data */ + if (!CmpGetValueData(Hive, + LinkValue, + &ValueLength, + (PVOID)&LinkName, + &LinkNameAllocated, + &CellToRelease)) + { + /* Fail */ + goto Exit; + } + + /* Get the length */ + Length = ValueLength + sizeof(WCHAR); + + /* Make sure we start with a slash */ + if (*LinkName != OBJ_NAME_PATH_SEPARATOR) goto Exit; + + /* Add the remaining name if needed */ + if (RemainingName) Length += RemainingName->Length + sizeof(WCHAR); + + /* Check for overflow */ + if (Length > 0xFFFF) goto Exit; + + /* Check if we need a new buffer */ + if (Length > ObjectName->MaximumLength) + { + /* We do -- allocate one */ + NewBuffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM); + if (!NewBuffer) goto Exit; + + /* Setup the new string and copy the symbolic target */ + NewObjectName.Buffer = NewBuffer; + NewObjectName.MaximumLength = (USHORT)Length; + NewObjectName.Length = (USHORT)ValueLength; + RtlCopyMemory(NewBuffer, LinkName, ValueLength); + + /* Check if we need to add anything else */ + if (RemainingName) + { + /* Add the remaining name */ + NewBuffer[ValueLength / sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR; + NewObjectName.Length += sizeof(WCHAR); + RtlAppendUnicodeStringToString(&NewObjectName, RemainingName); + } + + /* Free the old buffer */ + ExFreePool(ObjectName->Buffer); + *ObjectName = NewObjectName; + } + else + { + /* The old name is large enough -- update the length */ + ObjectName->Length = (USHORT)ValueLength; + if (RemainingName) + { + /* Copy the remaining name inside */ + RtlMoveMemory(&ObjectName->Buffer[(ValueLength / sizeof(WCHAR)) + 1], + RemainingName->Buffer, + RemainingName->Length); + + /* Add the slash and update the length */ + ObjectName->Buffer[ValueLength / sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR; + ObjectName->Length += RemainingName->Length + sizeof(WCHAR); + } + + /* Copy the symbolic link target name */ + RtlCopyMemory(ObjectName->Buffer, LinkName, ValueLength); + } + + /* Null-terminate the whole thing */ + ObjectName->Buffer[ObjectName->Length / sizeof(WCHAR)] = UNICODE_NULL; + Result = TRUE; + +Exit: + /* Free the link name */ + if (LinkNameAllocated) ExFreePool(LinkName); + + /* Check if we had a value cell */ + if (LinkValue) + { + /* Release it */ + ASSERT(LinkCell != HCELL_NIL); + HvReleaseCell(Hive, LinkCell); + } + + /* Check if we had an active cell and release it, then return the result */ + if (CellToRelease != HCELL_NIL) HvReleaseCell(Hive, CellToRelease); + return Result; +} + +NTSTATUS +NTAPI +CmpDoCreateChild(IN PHHIVE Hive, + IN HCELL_INDEX ParentCell, + IN PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL, + IN PACCESS_STATE AccessState, + IN PUNICODE_STRING Name, + IN KPROCESSOR_MODE AccessMode, + IN PCM_PARSE_CONTEXT ParseContext, + IN PCM_KEY_CONTROL_BLOCK ParentKcb, + IN ULONG Flags, + OUT PHCELL_INDEX KeyCell, + OUT PVOID *Object) +{ + NTSTATUS Status = STATUS_SUCCESS; + PCM_KEY_BODY KeyBody; + HCELL_INDEX ClassCell = HCELL_NIL; + PCM_KEY_NODE KeyNode; + PCELL_DATA CellData; + ULONG StorageType; + LARGE_INTEGER SystemTime; + PCM_KEY_CONTROL_BLOCK Kcb; + + /* Get the storage type */ + StorageType = Stable; + if (Flags & REG_OPTION_VOLATILE) StorageType = Volatile; + + /* Allocate the child */ + *KeyCell = HvAllocateCell(Hive, + FIELD_OFFSET(CM_KEY_NODE, Name) + + CmpNameSize(Hive, Name), + StorageType, + HCELL_NIL); + if (*KeyCell == HCELL_NIL) + { + /* Fail */ + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Quickie; + } + + /* Get the key node */ + KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, *KeyCell); + if (!KeyNode) + { + /* Fail, this should never happen */ + ASSERT(FALSE); + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Quickie; + } + + /* Release the cell */ + HvReleaseCell(Hive, *KeyCell); + + /* Check if we have a class name */ + if (ParseContext->Class.Length > 0) + { + /* Allocate a class cell */ + ClassCell = HvAllocateCell(Hive, + ParseContext->Class.Length, + StorageType, + HCELL_NIL); + if (ClassCell == HCELL_NIL) + { + /* Fail */ + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Quickie; + } + } + + /* Allocate the Cm Object */ + Status = ObCreateObject(AccessMode, + CmpKeyObjectType, + NULL, + AccessMode, + NULL, + sizeof(CM_KEY_BODY), + 0, + 0, + Object); + if (!NT_SUCCESS(Status)) goto Quickie; + + /* Setup the key body */ + KeyBody = (PCM_KEY_BODY)(*Object); + KeyBody->Type = TAG('k', 'y', '0', '2'); + KeyBody->KeyControlBlock = NULL; + + /* Check if we had a class */ + if (ParseContext->Class.Length > 0) + { + /* Get the class cell */ + CellData = HvGetCell(Hive, ClassCell); + if (!CellData) + { + /* Fail, this should never happen */ + ASSERT(FALSE); + Status = STATUS_INSUFFICIENT_RESOURCES; + ObDereferenceObject(*Object); + goto Quickie; + } + + /* Release the cell */ + HvReleaseCell(Hive, ClassCell); + + /* Copy the class data */ + RtlCopyMemory(&CellData->u.KeyString[0], + ParseContext->Class.Buffer, + ParseContext->Class.Length); + } + + /* Fill out the key node */ + KeyNode->Signature = CM_KEY_NODE_SIGNATURE; + KeyNode->Flags = Flags &~ REG_OPTION_CREATE_LINK; + KeQuerySystemTime(&SystemTime); + KeyNode->LastWriteTime = SystemTime; + KeyNode->Spare = 0; + KeyNode->Parent = ParentCell; + KeyNode->SubKeyCounts[Stable] = 0; + KeyNode->SubKeyCounts[Volatile] = 0; + KeyNode->SubKeyLists[Stable] = HCELL_NIL; + KeyNode->SubKeyLists[Volatile] = HCELL_NIL; + KeyNode->ValueList.Count = 0; + KeyNode->ValueList.List = HCELL_NIL; + KeyNode->Security = HCELL_NIL; + KeyNode->Class = ClassCell; + KeyNode->ClassLength = ParseContext->Class.Length; + KeyNode->MaxValueDataLen = 0; + KeyNode->MaxNameLen = 0; + KeyNode->MaxValueNameLen = 0; + KeyNode->MaxClassLen = 0; + KeyNode->NameLength = CmpCopyName(Hive, KeyNode->Name, Name); + if (KeyNode->NameLength < Name->Length) KeyNode->Flags |= KEY_COMP_NAME; + + /* Create the KCB */ + Kcb = CmpCreateKeyControlBlock(Hive, + *KeyCell, + KeyNode, + ParentKcb, + CMP_LOCK_HASHES_FOR_KCB, + Name); + if (!Kcb) + { + /* Fail */ + ObDereferenceObjectDeferDelete(*Object); + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Quickie; + } + + /* Sanity check */ + ASSERT(Kcb->RefCount == 1); + + /* Now fill out the Cm object */ + KeyBody->NotifyBlock = NULL; + KeyBody->ProcessID = PsGetCurrentProcessId(); + KeyBody->KeyControlBlock = Kcb; + + /* Link it with the KCB */ + EnlistKeyBodyWithKCB(KeyBody, 0); + +Quickie: + /* Check if we got here because of failure */ + if (!NT_SUCCESS(Status)) + { + /* Free any cells we might've allocated */ + if (ParseContext->Class.Length > 0) HvFreeCell(Hive, ClassCell); + HvFreeCell(Hive, *KeyCell); + } + + /* Return status */ + return Status; +} + +NTSTATUS +NTAPI +CmpDoCreate(IN PHHIVE Hive, + IN HCELL_INDEX Cell, + IN PACCESS_STATE AccessState, + IN PUNICODE_STRING Name, + IN KPROCESSOR_MODE AccessMode, + IN PCM_PARSE_CONTEXT ParseContext, + IN PCM_KEY_CONTROL_BLOCK ParentKcb, + OUT PVOID *Object) +{ + NTSTATUS Status; + PCELL_DATA CellData; + HCELL_INDEX KeyCell; + ULONG ParentType; + PCM_KEY_BODY KeyBody; + PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; + LARGE_INTEGER TimeStamp; + PCM_KEY_NODE KeyNode; + + /* Sanity check */ +#if 0 + ASSERT((CmpIsKcbLockedExclusive(ParentKcb) == TRUE) || + (CmpTestRegistryLockExclusive() == TRUE)); +#endif + + /* Acquire the flusher lock */ + ExAcquirePushLockShared((PVOID)&((PCMHIVE)Hive)->FlusherLock); + + /* Check if the parent is being deleted */ + if (ParentKcb->Delete) + { + /* It has, quit */ + ASSERT(FALSE); + Status = STATUS_OBJECT_NAME_NOT_FOUND; + goto Exit; + } + + /* Get the parent node */ + KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Cell); + if (!KeyNode) + { + /* Fail */ + ASSERT(FALSE); + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Exit; + } + + /* Make sure nobody added us yet */ + if (CmpFindSubKeyByName(Hive, KeyNode, Name) != HCELL_NIL) + { + /* Fail */ + ASSERT(FALSE); + Status = STATUS_REPARSE; + goto Exit; + } + + /* Sanity check */ + ASSERT(Cell == ParentKcb->KeyCell); + + /* Get the parent type */ + ParentType = HvGetCellType(Cell); + if ((ParentType == Volatile) && + !(ParseContext->CreateOptions & REG_OPTION_VOLATILE)) + { + /* Children of volatile parents must also be volatile */ + ASSERT(FALSE); + Status = STATUS_CHILD_MUST_BE_VOLATILE; + goto Exit; + } + + /* Don't allow children under symlinks */ + if (ParentKcb->Flags & KEY_SYM_LINK) + { + /* Fail */ + ASSERT(FALSE); + Status = STATUS_ACCESS_DENIED; + goto Exit; + } + + /* Make the cell dirty for now */ + HvMarkCellDirty(Hive, Cell, FALSE); + + /* Do the actual create operation */ + Status = CmpDoCreateChild(Hive, + Cell, + SecurityDescriptor, + AccessState, + Name, + AccessMode, + ParseContext, + ParentKcb, + ParseContext->CreateOptions, // WRONG! + &KeyCell, + Object); + if (NT_SUCCESS(Status)) + { + /* Get the key body */ + KeyBody = (PCM_KEY_BODY)(*Object); + + /* Now add the subkey */ + if (!CmpAddSubKey(Hive, Cell, KeyCell)) + { + /* Failure! We don't handle this yet! */ + ASSERT(FALSE); + } + + /* Get the key node */ + KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Cell); + if (!KeyNode) + { + /* Fail, this shouldn't happen */ + ASSERT(FALSE); + } + + /* Sanity checks */ + ASSERT(KeyBody->KeyControlBlock->ParentKcb->KeyCell == Cell); + ASSERT(KeyBody->KeyControlBlock->ParentKcb->KeyHive == Hive); + ASSERT(KeyBody->KeyControlBlock->ParentKcb == ParentKcb); + ASSERT(KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen == KeyNode->MaxNameLen); + + /* Update the timestamp */ + KeQuerySystemTime(&TimeStamp); + KeyNode->LastWriteTime = TimeStamp; + KeyBody->KeyControlBlock->ParentKcb->KcbLastWriteTime = TimeStamp; + + /* Check if we need to update name maximum */ + if (KeyNode->MaxNameLen < Name->Length) + { + /* Do it */ + KeyNode->MaxNameLen = Name->Length; + KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen = Name->Length; + } + + /* Check if we need toupdate class length maximum */ + if (KeyNode->MaxClassLen < ParseContext->Class.Length) + { + /* Update it */ + KeyNode->MaxClassLen = ParseContext->Class.Length; + } + + /* Check if we're creating a symbolic link */ + if (ParseContext->CreateOptions & REG_OPTION_CREATE_LINK) + { + /* Get the cell data */ + CellData = HvGetCell(Hive, KeyCell); + if (!CellData) + { + /* This shouldn't happen */ + ASSERT(FALSE); + } + + /* Update the flags */ + CellData->u.KeyNode.Flags |= KEY_SYM_LINK; + KeyBody->KeyControlBlock->Flags = CellData->u.KeyNode.Flags; + HvReleaseCell(Hive, KeyCell); + } + } + +Exit: + /* Release the flusher lock and return status */ + ExReleasePushLock((PVOID)&((PCMHIVE)Hive)->FlusherLock); + return Status; +} + +NTSTATUS +NTAPI +CmpDoOpen(IN PHHIVE Hive, + IN HCELL_INDEX Cell, + IN PCM_KEY_NODE Node, + IN PACCESS_STATE AccessState, + IN KPROCESSOR_MODE AccessMode, + IN ULONG Attributes, + IN PCM_PARSE_CONTEXT Context OPTIONAL, + IN ULONG ControlFlags, + IN OUT PCM_KEY_CONTROL_BLOCK *CachedKcb, + IN PUNICODE_STRING KeyName, + OUT PVOID *Object) +{ + NTSTATUS Status; + PCM_KEY_BODY KeyBody = NULL; + PCM_KEY_CONTROL_BLOCK Kcb = NULL; + + /* Make sure the hive isn't locked */ + if ((Hive->HiveFlags & HIVE_IS_UNLOADING) && + (((PCMHIVE)Hive)->CreatorOwner != KeGetCurrentThread())) + { + /* It is, don't touch it */ + return STATUS_OBJECT_NAME_NOT_FOUND; + } + + /* Check if we have a context */ + if (Context) + { + /* Check if this is a link create (which shouldn't be an open) */ + if (Context->CreateLink) + { + return STATUS_ACCESS_DENIED; + } + + /* Check if this is symlink create attempt */ + if (Context->CreateOptions & REG_OPTION_CREATE_LINK) + { + /* Key already exists */ + return STATUS_OBJECT_NAME_COLLISION; + } + + /* Set the disposition */ + Context->Disposition = REG_OPENED_EXISTING_KEY; + } + + /* Do this in the registry lock */ + CmpLockRegistry(); + + /* If we have a KCB, make sure it's locked */ + //ASSERT(CmpIsKcbLockedExclusive(*CachedKcb)); + + /* Check if this is a symlink */ + if ((Node->Flags & KEY_SYM_LINK) && !(Attributes & OBJ_OPENLINK)) + { + /* Create the KCB for the symlink */ + Kcb = CmpCreateKeyControlBlock(Hive, + Cell, + Node, + *CachedKcb, + 0, + KeyName); + if (!Kcb) return STATUS_INSUFFICIENT_RESOURCES; + + /* Make sure it's also locked, and set the pointer */ + //ASSERT(CmpIsKcbLockedExclusive(Kcb)); + *CachedKcb = Kcb; + + /* Release the registry lock */ + CmpUnlockRegistry(); + + /* Return reparse required */ + return STATUS_REPARSE; + } + + /* Create the KCB. FIXME: Use lock flag */ + Kcb = CmpCreateKeyControlBlock(Hive, + Cell, + Node, + *CachedKcb, + 0, + KeyName); + if (!Kcb) return STATUS_INSUFFICIENT_RESOURCES; + + /* Make sure it's also locked, and set the pointer */ + //ASSERT(CmpIsKcbLockedExclusive(Kcb)); + *CachedKcb = Kcb; + + /* Release the registry lock */ + CmpUnlockRegistry(); + + /* Allocate the key object */ + Status = ObCreateObject(AccessMode, + CmpKeyObjectType, + NULL, + AccessMode, + NULL, + sizeof(CM_KEY_BODY), + 0, + 0, + Object); + if (NT_SUCCESS(Status)) + { + /* Get the key body and fill it out */ + KeyBody = (PCM_KEY_BODY)(*Object); + KeyBody->KeyControlBlock = Kcb; + KeyBody->Type = TAG('k', 'y', '0', '2'); + KeyBody->ProcessID = PsGetCurrentProcessId(); + KeyBody->NotifyBlock = NULL; + + /* Link to the KCB */ + EnlistKeyBodyWithKCB(KeyBody, 0); + } + else + { + /* Failed, dereference the KCB */ + CmpDereferenceKeyControlBlockWithLock(Kcb, FALSE); + } + + /* Return status */ + return Status; +} + +/* Remove calls to CmCreateRootNode once this is used! */ +NTSTATUS +NTAPI +CmpCreateLinkNode(IN PHHIVE Hive, + IN HCELL_INDEX Cell, + IN PACCESS_STATE AccessState, + IN UNICODE_STRING Name, + IN KPROCESSOR_MODE AccessMode, + IN ULONG CreateOptions, + IN PCM_PARSE_CONTEXT Context, + IN PCM_KEY_CONTROL_BLOCK ParentKcb, + OUT PVOID *Object) +{ + NTSTATUS Status; + HCELL_INDEX KeyCell, LinkCell, ChildCell; + PCM_KEY_BODY KeyBody; + LARGE_INTEGER TimeStamp; + PCM_KEY_NODE KeyNode; + PCM_KEY_CONTROL_BLOCK Kcb = ParentKcb; +#if 0 + CMP_ASSERT_REGISTRY_LOCK(); +#endif + + /* Link nodes only allowed on the master */ + if (Hive != &CmiVolatileHive->Hive) + { + /* Fail */ + DPRINT1("Invalid link node attempt\n"); + return STATUS_ACCESS_DENIED; + } + + /* Acquire the flusher locks */ + ExAcquirePushLockShared((PVOID)&((PCMHIVE)Hive)->FlusherLock); + ExAcquirePushLockShared((PVOID)&((PCMHIVE)Context->ChildHive.KeyHive)->FlusherLock); + + /* Check if the parent is being deleted */ + if (ParentKcb->Delete) + { + /* It is, quit */ + ASSERT(FALSE); + Status = STATUS_OBJECT_NAME_NOT_FOUND; + goto Exit; + } + + /* Allocate a link node */ + LinkCell = HvAllocateCell(Hive, + FIELD_OFFSET(CM_KEY_NODE, Name) + + CmpNameSize(Hive, &Name), + Stable, + HCELL_NIL); + if (LinkCell == HCELL_NIL) + { + /* Fail */ + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Exit; + } + + /* Get the key cell */ + KeyCell = Context->ChildHive.KeyCell; + if (KeyCell != HCELL_NIL) + { + /* Hive exists! */ + ChildCell = KeyCell; + + /* Get the node data */ + KeyNode = (PCM_KEY_NODE)HvGetCell(Context->ChildHive.KeyHive, ChildCell); + if (!KeyNode) + { + /* Fail */ + ASSERT(FALSE); + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Exit; + } + + /* Fill out the data */ + KeyNode->Parent = LinkCell; + KeyNode->Flags |= KEY_HIVE_ENTRY | KEY_NO_DELETE; + HvReleaseCell(Context->ChildHive.KeyHive, ChildCell); + + /* Now open the key cell */ + KeyNode = (PCM_KEY_NODE)HvGetCell(Context->ChildHive.KeyHive, KeyCell); + if (!KeyNode) + { + /* Fail */ + ASSERT(FALSE); + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Exit; + } + + /* Open the parent */ + Status = CmpDoOpen(Context->ChildHive.KeyHive, + KeyCell, + KeyNode, + AccessState, + AccessMode, + CreateOptions, + NULL, + 0, + &Kcb, + &Name, + Object); + HvReleaseCell(Context->ChildHive.KeyHive, KeyCell); + } + else + { + /* Do the actual create operation */ + Status = CmpDoCreateChild(Context->ChildHive.KeyHive, + Cell, + NULL, + AccessState, + &Name, + AccessMode, + Context, + ParentKcb, + KEY_HIVE_ENTRY | KEY_NO_DELETE, + &ChildCell, + Object); + if (NT_SUCCESS(Status)) + { + /* Setup root pointer */ + Context->ChildHive.KeyHive->BaseBlock->RootCell = ChildCell; + } + } + + /* Check if open or create suceeded */ + if (NT_SUCCESS(Status)) + { + /* Mark the cell dirty */ + HvMarkCellDirty(Context->ChildHive.KeyHive, ChildCell, FALSE); + + /* Get the key node */ + KeyNode = HvGetCell(Context->ChildHive.KeyHive, ChildCell); + if (!KeyNode) + { + /* Fail */ + ASSERT(FALSE); + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Exit; + } + + /* Release it */ + HvReleaseCell(Context->ChildHive.KeyHive, ChildCell); + + /* Set the parent and flags */ + KeyNode->Parent = LinkCell; + KeyNode->Flags |= KEY_HIVE_ENTRY | KEY_NO_DELETE; + + /* Get the link node */ + KeyNode = HvGetCell(Hive, LinkCell); + if (!KeyNode) + { + /* Fail */ + ASSERT(FALSE); + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Exit; + } + + /* Set it up */ + KeyNode->Signature = CM_LINK_NODE_SIGNATURE; + KeyNode->Flags = KEY_HIVE_EXIT | KEY_NO_DELETE; + KeyNode->Parent = Cell; + KeyNode->NameLength = CmpCopyName(Hive, KeyNode->Name, &Name); + if (KeyNode->NameLength < Name.Length) KeyNode->Flags |= KEY_COMP_NAME; + KeQuerySystemTime(&TimeStamp); + KeyNode->LastWriteTime = TimeStamp; + + /* Clear out the rest */ + KeyNode->SubKeyCounts[Stable] = 0; + KeyNode->SubKeyCounts[Volatile] = 0; + KeyNode->SubKeyLists[Stable] = HCELL_NIL; + KeyNode->SubKeyLists[Volatile] = HCELL_NIL; + KeyNode->ValueList.Count = 0; + KeyNode->ValueList.List = HCELL_NIL; + KeyNode->ClassLength = 0; + + /* Reference the root node */ + KeyNode->ChildHiveReference.KeyHive = Context->ChildHive.KeyHive; + KeyNode->ChildHiveReference.KeyCell = ChildCell; + HvReleaseCell(Hive, LinkCell); + + /* Get the parent node */ + KeyNode = HvGetCell(Hive, Cell); + if (!KeyNode) + { + /* Fail */ + ASSERT(FALSE); + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Exit; + } + + /* Now add the subkey */ + if (!CmpAddSubKey(Hive, Cell, LinkCell)) + { + /* Failure! We don't handle this yet! */ + ASSERT(FALSE); + } + + /* Get the key body */ + KeyBody = (PCM_KEY_BODY)*Object; + + /* Sanity checks */ + ASSERT(KeyBody->KeyControlBlock->ParentKcb->KeyCell == Cell); + ASSERT(KeyBody->KeyControlBlock->ParentKcb->KeyHive == Hive); + ASSERT(KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen == KeyNode->MaxNameLen); + + /* Update the timestamp */ + KeQuerySystemTime(&TimeStamp); + KeyNode->LastWriteTime = TimeStamp; + KeyBody->KeyControlBlock->ParentKcb->KcbLastWriteTime = TimeStamp; + + /* Check if we need to update name maximum */ + if (KeyNode->MaxNameLen < Name.Length) + { + /* Do it */ + KeyNode->MaxNameLen = Name.Length; + KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen = Name.Length; + } + + /* Check if we need toupdate class length maximum */ + if (KeyNode->MaxClassLen < Context->Class.Length) + { + /* Update it */ + KeyNode->MaxClassLen = Context->Class.Length; + } + + /* Release the cell */ + HvReleaseCell(Hive, Cell); + } + else + { + /* Release the link cell */ + HvReleaseCell(Hive, LinkCell); + } + +Exit: + /* Release the flusher locks and return status */ + ExReleasePushLock((PVOID)&((PCMHIVE)Context->ChildHive.KeyHive)->FlusherLock); + ExReleasePushLock((PVOID)&((PCMHIVE)Hive)->FlusherLock); + return Status; +} + +VOID +NTAPI +CmpHandleExitNode(IN OUT PHHIVE *Hive, + IN OUT HCELL_INDEX *Cell, + IN OUT PCM_KEY_NODE *KeyNode, + IN OUT PHHIVE *ReleaseHive, + IN OUT HCELL_INDEX *ReleaseCell) +{ + /* Check if we have anything to release */ + if (*ReleaseCell != HCELL_NIL) + { + /* Release it */ + ASSERT(*ReleaseHive != NULL); + HvReleaseCell((*ReleaseHive), *ReleaseCell); + } + + /* Get the link references */ + *Hive = (*KeyNode)->ChildHiveReference.KeyHive; + *Cell = (*KeyNode)->ChildHiveReference.KeyCell; + + /* Get the new node */ + *KeyNode = (PCM_KEY_NODE)HvGetCell((*Hive), *Cell); + if (*KeyNode) + { + /* Set the new release values */ + *ReleaseCell = *Cell; + *ReleaseHive = *Hive; + } + else + { + /* Nothing to release */ + *ReleaseCell = HCELL_NIL; + *ReleaseHive = NULL; + } +} + +NTSTATUS +NTAPI +CmpBuildHashStackAndLookupCache(IN PCM_KEY_BODY ParseObject, + IN OUT PCM_KEY_CONTROL_BLOCK *Kcb, + IN PUNICODE_STRING Current, + OUT PHHIVE *Hive, + OUT HCELL_INDEX *Cell, + OUT PULONG TotalRemainingSubkeys, + OUT PULONG MatchRemainSubkeyLevel, + OUT PULONG TotalSubkeys, + OUT PULONG OuterStackArray, + OUT PULONG *LockedKcbs) +{ + ULONG HashKeyCopy; + + /* We don't lock anything for now */ + *LockedKcbs = NULL; + + /* Make a copy of the hash key */ + HashKeyCopy = (*Kcb)->ConvKey; + + /* Calculate hash values */ + *TotalRemainingSubkeys = 0xBAADF00D; + + /* Lock the registry */ + CmpLockRegistry(); + + /* Return hive and cell data */ + *Hive = (*Kcb)->KeyHive; + *Cell = (*Kcb)->KeyCell; + + /* Return success for now */ + return STATUS_SUCCESS; +} + +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 Status; + PCM_KEY_CONTROL_BLOCK Kcb, ParentKcb; + PHHIVE Hive = NULL; + PCM_KEY_NODE Node = NULL; + HCELL_INDEX Cell = HCELL_NIL, NextCell; + PHHIVE HiveToRelease = NULL; + HCELL_INDEX CellToRelease = HCELL_NIL; + UNICODE_STRING Current, NextName; + PCM_PARSE_CONTEXT ParseContext = Context; + ULONG TotalRemainingSubkeys = 0, MatchRemainSubkeyLevel = 0, TotalSubkeys = 0; + PULONG LockedKcbs = NULL; + BOOLEAN Result, Last; + PAGED_CODE(); + + /* Loop path separators at the end */ + while ((RemainingName->Length) && + (RemainingName->Buffer[(RemainingName->Length / sizeof(WCHAR)) - 1] == + OBJ_NAME_PATH_SEPARATOR)) + { + /* Remove path separator */ + RemainingName->Length -= sizeof(WCHAR); + } + + /* Fail if this isn't a key object */ + if (ObjectType != CmpKeyObjectType) return STATUS_OBJECT_TYPE_MISMATCH; + + /* Copy the remaining name */ + Current = *RemainingName; + + /* Check if this is a create */ + if (!(ParseContext) || !(ParseContext->CreateOperation)) + { + /* It isn't, so no context */ + ParseContext = NULL; + } + + /* Grab the KCB */ + Kcb = ((PCM_KEY_BODY)ParseObject)->KeyControlBlock; + + /* Lookup in the cache */ + Status = CmpBuildHashStackAndLookupCache(ParseObject, + &Kcb, + &Current, + &Hive, + &Cell, + &TotalRemainingSubkeys, + &MatchRemainSubkeyLevel, + &TotalSubkeys, + NULL, + &LockedKcbs); + + /* This is now the parent */ + ParentKcb = Kcb; + + /* Check if everything was found cached */ + if (!TotalRemainingSubkeys) ASSERTMSG("Caching not implemented", FALSE); + + /* Don't do anything if we're being deleted */ + if (Kcb->Delete) return STATUS_OBJECT_NAME_NOT_FOUND; + + /* Check if this is a symlink */ + if (Kcb->Flags & KEY_SYM_LINK) + { + /* Get the next name */ + Result = CmpGetNextName(&Current, &NextName, &Last); + Current.Buffer = NextName.Buffer; + + /* Validate the current name string length */ + if (Current.Length + NextName.Length > MAXUSHORT) + { + /* too long */ + Status = STATUS_NAME_TOO_LONG; + goto Quickie; + } + Current.Length += NextName.Length; + + /* Validate the current name string maximum length */ + if (Current.MaximumLength + NextName.MaximumLength > MAXUSHORT) + { + /* too long */ + Status = STATUS_NAME_TOO_LONG; + goto Quickie; + } + Current.MaximumLength += NextName.MaximumLength; + + /* Parse the symlink */ + if (CmpGetSymbolicLink(Hive, + CompleteName, + Kcb, + &Current)) + { + /* Symlink parse succeeded */ + Status = STATUS_REPARSE; + } + else + { + /* Couldn't find symlink */ + Status = STATUS_OBJECT_NAME_NOT_FOUND; + } + + /* We're done */ + goto Quickie; + } + + /* Get the key node */ + Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell); + if (!Node) return STATUS_INSUFFICIENT_RESOURCES; + + /* Start parsing */ + Status = STATUS_NOT_IMPLEMENTED; + while (TRUE) + { + /* Get the next component */ + Result = CmpGetNextName(&Current, &NextName, &Last); + if ((Result) && (NextName.Length)) + { + /* See if this is a sym link */ + if (!(Kcb->Flags & KEY_SYM_LINK)) + { + /* Find the subkey */ + NextCell = CmpFindSubKeyByName(Hive, Node, &NextName); + if (NextCell != HCELL_NIL) + { + /* Get the new node */ + Cell = NextCell; + Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell); + if (!Node) ASSERT(FALSE); + + /* Check if this was the last key */ + if (Last) + { + /* Is this an exit node */ + if (Node->Flags & KEY_HIVE_EXIT) + { + /* Handle it */ + CmpHandleExitNode(&Hive, + &Cell, + &Node, + &HiveToRelease, + &CellToRelease); + if (!Node) ASSERT(FALSE); + } + + /* Do the open */ + Status = CmpDoOpen(Hive, + Cell, + Node, + AccessState, + AccessMode, + Attributes, + ParseContext, + 0, + &Kcb, + &NextName, + Object); + if (Status == STATUS_REPARSE) + { + /* Parse the symlink */ + if (!CmpGetSymbolicLink(Hive, + CompleteName, + Kcb, + NULL)) + { + /* Symlink parse failed */ + Status = STATUS_OBJECT_NAME_NOT_FOUND; + } + } + + /* We are done */ + break; + } + + /* Is this an exit node */ + if (Node->Flags & KEY_HIVE_EXIT) + { + /* Handle it */ + CmpHandleExitNode(&Hive, + &Cell, + &Node, + &HiveToRelease, + &CellToRelease); + if (!Node) ASSERT(FALSE); + } + + /* Create a KCB for this key */ + Kcb = CmpCreateKeyControlBlock(Hive, + Cell, + Node, + ParentKcb, + 0, + &NextName); + if (!Kcb) ASSERT(FALSE); + + /* Dereference the parent and set the new one */ + //CmpDereferenceKeyControlBlock(ParentKcb); + ParentKcb = Kcb; + } + else + { + /* Check if this was the last key for a create */ + if ((Last) && (ParseContext)) + { + /* Check if we're doing a link node */ + if (ParseContext->CreateLink) + { + /* The only thing we should see */ + Status = CmpCreateLinkNode(Hive, + Cell, + AccessState, + NextName, + AccessMode, + Attributes, + ParseContext, + ParentKcb, + Object); + } + else + { + /* Do the create */ + Status = CmpDoCreate(Hive, + Cell, + AccessState, + &NextName, + AccessMode, + ParseContext, + ParentKcb, + Object); + } + + /* Check for reparse (in this case, someone beat us) */ + if (Status == STATUS_REPARSE) break; + + /* Update disposition */ + ParseContext->Disposition = REG_CREATED_NEW_KEY; + break; + } + else + { + /* Key not found */ + Status = STATUS_OBJECT_NAME_NOT_FOUND; + break; + } + } + } + else + { + /* Save the next name */ + Current.Buffer = NextName.Buffer; + + /* Validate the current name string length */ + if (Current.Length + NextName.Length > MAXUSHORT) + { + /* too long */ + Status = STATUS_NAME_TOO_LONG; + break; + } + Current.Length += NextName.Length; + + /* Validate the current name string maximum length */ + if (Current.MaximumLength + NextName.MaximumLength > MAXUSHORT) + { + /* too long */ + Status = STATUS_NAME_TOO_LONG; + break; + } + Current.MaximumLength += NextName.MaximumLength; + + /* Parse the symlink */ + if (CmpGetSymbolicLink(Hive, + CompleteName, + Kcb, + &Current)) + { + /* Symlink parse succeeded */ + Status = STATUS_REPARSE; + } + else + { + /* Couldn't find symlink */ + Status = STATUS_OBJECT_NAME_NOT_FOUND; + } + + /* We're done */ + break; + } + } + else if ((Result) && (Last)) + { + /* Opening the root. Is this an exit node? */ + if (Node->Flags & KEY_HIVE_EXIT) + { + /* Handle it */ + CmpHandleExitNode(&Hive, + &Cell, + &Node, + &HiveToRelease, + &CellToRelease); + if (!Node) ASSERT(FALSE); + } + + /* FIXME: This hack seems required? */ + RtlInitUnicodeString(&NextName, L"\\REGISTRY"); + + /* Do the open */ + Status = CmpDoOpen(Hive, + Cell, + Node, + AccessState, + AccessMode, + Attributes, + ParseContext, + 0, + &Kcb, + &NextName, + Object); + if (Status == STATUS_REPARSE) + { + /* Nothing to do */ + } + + /* We're done */ + break; + } + else + { + /* Bogus */ + Status = STATUS_INVALID_PARAMETER; + break; + } + } + + /* Dereference the parent if it exists */ +Quickie: + //if (ParentKcb) CmpDereferenceKeyControlBlock(ParentKcb); + + /* Unlock the registry */ + CmpUnlockRegistry(); + return Status; +} diff --git a/reactos/ntoskrnl/config/cmse.c b/reactos/ntoskrnl/config/cmse.c index 17eae5d4012..80d56dde569 100644 --- a/reactos/ntoskrnl/config/cmse.c +++ b/reactos/ntoskrnl/config/cmse.c @@ -1,153 +1,152 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/config/cmse.c - * PURPOSE: Configuration Manager - Security Subsystem Interface - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include "ntoskrnl.h" -#include "cm.h" -#define NDEBUG -#include "debug.h" - -/* GLOBALS *******************************************************************/ - -/* FUNCTIONS *****************************************************************/ - -PSECURITY_DESCRIPTOR -NTAPI -CmpHiveRootSecurityDescriptor(VOID) -{ - NTSTATUS Status; - PSECURITY_DESCRIPTOR SecurityDescriptor; - PACL Acl, AclCopy; - PSID Sid[4]; - SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY}; - SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY}; - ULONG AceLength, AclLength, SidLength; - PACE_HEADER AceHeader; - ULONG i; - PAGED_CODE(); - - /* Phase 1: Allocate SIDs */ - SidLength = RtlLengthRequiredSid(1); - Sid[0] = ExAllocatePoolWithTag(PagedPool, SidLength, TAG_CM); - Sid[1] = ExAllocatePoolWithTag(PagedPool, SidLength, TAG_CM); - Sid[2] = ExAllocatePoolWithTag(PagedPool, SidLength, TAG_CM); - SidLength = RtlLengthRequiredSid(2); - Sid[3] = ExAllocatePoolWithTag(PagedPool, SidLength, TAG_CM); - - /* Make sure all SIDs were allocated */ - if (!(Sid[0]) || !(Sid[1]) || !(Sid[2]) || !(Sid[3])) - { - /* Bugcheck */ - KEBUGCHECKEX(REGISTRY_ERROR, 11, 1, 0, 0); - } - - /* Phase 2: Initialize all SIDs */ - Status = RtlInitializeSid(Sid[0], &WorldAuthority, 1); - Status |= RtlInitializeSid(Sid[1], &NtAuthority, 1); - Status |= RtlInitializeSid(Sid[2], &NtAuthority, 1); - Status |= RtlInitializeSid(Sid[3], &NtAuthority, 2); - if (!NT_SUCCESS(Status)) KEBUGCHECKEX(REGISTRY_ERROR, 11, 2, 0, 0); - - /* Phase 2: Setup SID Sub Authorities */ - *RtlSubAuthoritySid(Sid[0], 0) = SECURITY_WORLD_RID; - *RtlSubAuthoritySid(Sid[1], 0) = SECURITY_RESTRICTED_CODE_RID; - *RtlSubAuthoritySid(Sid[2], 0) = SECURITY_LOCAL_SYSTEM_RID; - *RtlSubAuthoritySid(Sid[3], 0) = SECURITY_BUILTIN_DOMAIN_RID; - *RtlSubAuthoritySid(Sid[3], 1) = DOMAIN_ALIAS_RID_ADMINS; - - /* Make sure all SIDs are valid */ - ASSERT(RtlValidSid(Sid[0])); - ASSERT(RtlValidSid(Sid[1])); - ASSERT(RtlValidSid(Sid[2])); - ASSERT(RtlValidSid(Sid[3])); - - /* Phase 3: Calculate ACL Length */ - AclLength = sizeof(ACL); - for (i = 0; i < 4; i++) - { - /* This is what MSDN says to do */ - AceLength = FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart); - AceLength += SeLengthSid(Sid[i]); - AclLength += AceLength; - } - - /* Phase 3: Allocate the ACL */ - Acl = ExAllocatePoolWithTag(PagedPool, AclLength, TAG_CM); - if (!Acl) KEBUGCHECKEX(REGISTRY_ERROR, 11, 3, 0, 0); - - /* Phase 4: Create the ACL */ - Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION); - if (!NT_SUCCESS(Status)) KEBUGCHECKEX(REGISTRY_ERROR, 11, 4, Status, 0); - - /* Phase 5: Build the ACL */ - Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION, KEY_ALL_ACCESS, Sid[0]); - Status |= RtlAddAccessAllowedAce(Acl, ACL_REVISION, KEY_ALL_ACCESS, Sid[1]); - Status |= RtlAddAccessAllowedAce(Acl, ACL_REVISION, KEY_READ, Sid[2]); - Status |= RtlAddAccessAllowedAce(Acl, ACL_REVISION, KEY_READ, Sid[3]); - if (!NT_SUCCESS(Status)) KEBUGCHECKEX(REGISTRY_ERROR, 11, 5, Status, 0); - - /* Phase 5: Make the ACEs inheritable */ - Status = RtlGetAce(Acl, 0,( PVOID*)&AceHeader); - ASSERT(NT_SUCCESS(Status)); - AceHeader->AceFlags |= CONTAINER_INHERIT_ACE; - Status = RtlGetAce(Acl, 1, (PVOID*)&AceHeader); - ASSERT(NT_SUCCESS(Status)); - AceHeader->AceFlags |= CONTAINER_INHERIT_ACE; - Status = RtlGetAce(Acl, 2, (PVOID*)&AceHeader); - ASSERT(NT_SUCCESS(Status)); - AceHeader->AceFlags |= CONTAINER_INHERIT_ACE; - Status = RtlGetAce(Acl, 3, (PVOID*)&AceHeader); - ASSERT(NT_SUCCESS(Status)); - AceHeader->AceFlags |= CONTAINER_INHERIT_ACE; - - /* Phase 6: Allocate the security descriptor and make space for the ACL */ - SecurityDescriptor = ExAllocatePoolWithTag(PagedPool, - sizeof(SECURITY_DESCRIPTOR) + - AclLength, - TAG_CM); - if (!SecurityDescriptor) KEBUGCHECKEX(REGISTRY_ERROR, 11, 6, 0, 0); - - /* Phase 6: Make a copy of the ACL */ - AclCopy = (PACL)((PISECURITY_DESCRIPTOR)SecurityDescriptor + 1); - RtlCopyMemory(AclCopy, Acl, AclLength); - - /* Phase 7: Create the security descriptor */ - Status = RtlCreateSecurityDescriptor(SecurityDescriptor, - SECURITY_DESCRIPTOR_REVISION); - if (!NT_SUCCESS(Status)) KEBUGCHECKEX(REGISTRY_ERROR, 11, 7, Status, 0); - - /* Phase 8: Set the ACL as a DACL */ - Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor, - TRUE, - AclCopy, - FALSE); - if (!NT_SUCCESS(Status)) KEBUGCHECKEX(REGISTRY_ERROR, 11, 8, Status, 0); - - /* Free the SIDs and original ACL */ - for (i = 0; i < 4; i++) ExFreePool(Sid[i]); - ExFreePool(Acl); - - /* Return the security descriptor */ - return SecurityDescriptor; -} - -NTSTATUS -NTAPI -CmpSecurityMethod(IN PVOID ObjectBody, - IN SECURITY_OPERATION_CODE OperationCode, - IN PSECURITY_INFORMATION SecurityInformation, - IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor, - IN OUT PULONG BufferLength, - IN OUT PSECURITY_DESCRIPTOR *OldSecurityDescriptor, - IN POOL_TYPE PoolType, - IN PGENERIC_MAPPING GenericMapping) -{ - /* HACK */ - return STATUS_SUCCESS; -} +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmse.c + * PURPOSE: Configuration Manager - Security Subsystem Interface + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#define NDEBUG +#include "debug.h" + +/* GLOBALS *******************************************************************/ + +/* FUNCTIONS *****************************************************************/ + +PSECURITY_DESCRIPTOR +NTAPI +CmpHiveRootSecurityDescriptor(VOID) +{ + NTSTATUS Status; + PSECURITY_DESCRIPTOR SecurityDescriptor; + PACL Acl, AclCopy; + PSID Sid[4]; + SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY}; + SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY}; + ULONG AceLength, AclLength, SidLength; + PACE_HEADER AceHeader; + ULONG i; + PAGED_CODE(); + + /* Phase 1: Allocate SIDs */ + SidLength = RtlLengthRequiredSid(1); + Sid[0] = ExAllocatePoolWithTag(PagedPool, SidLength, TAG_CM); + Sid[1] = ExAllocatePoolWithTag(PagedPool, SidLength, TAG_CM); + Sid[2] = ExAllocatePoolWithTag(PagedPool, SidLength, TAG_CM); + SidLength = RtlLengthRequiredSid(2); + Sid[3] = ExAllocatePoolWithTag(PagedPool, SidLength, TAG_CM); + + /* Make sure all SIDs were allocated */ + if (!(Sid[0]) || !(Sid[1]) || !(Sid[2]) || !(Sid[3])) + { + /* Bugcheck */ + KEBUGCHECKEX(REGISTRY_ERROR, 11, 1, 0, 0); + } + + /* Phase 2: Initialize all SIDs */ + Status = RtlInitializeSid(Sid[0], &WorldAuthority, 1); + Status |= RtlInitializeSid(Sid[1], &NtAuthority, 1); + Status |= RtlInitializeSid(Sid[2], &NtAuthority, 1); + Status |= RtlInitializeSid(Sid[3], &NtAuthority, 2); + if (!NT_SUCCESS(Status)) KEBUGCHECKEX(REGISTRY_ERROR, 11, 2, 0, 0); + + /* Phase 2: Setup SID Sub Authorities */ + *RtlSubAuthoritySid(Sid[0], 0) = SECURITY_WORLD_RID; + *RtlSubAuthoritySid(Sid[1], 0) = SECURITY_RESTRICTED_CODE_RID; + *RtlSubAuthoritySid(Sid[2], 0) = SECURITY_LOCAL_SYSTEM_RID; + *RtlSubAuthoritySid(Sid[3], 0) = SECURITY_BUILTIN_DOMAIN_RID; + *RtlSubAuthoritySid(Sid[3], 1) = DOMAIN_ALIAS_RID_ADMINS; + + /* Make sure all SIDs are valid */ + ASSERT(RtlValidSid(Sid[0])); + ASSERT(RtlValidSid(Sid[1])); + ASSERT(RtlValidSid(Sid[2])); + ASSERT(RtlValidSid(Sid[3])); + + /* Phase 3: Calculate ACL Length */ + AclLength = sizeof(ACL); + for (i = 0; i < 4; i++) + { + /* This is what MSDN says to do */ + AceLength = FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart); + AceLength += SeLengthSid(Sid[i]); + AclLength += AceLength; + } + + /* Phase 3: Allocate the ACL */ + Acl = ExAllocatePoolWithTag(PagedPool, AclLength, TAG_CM); + if (!Acl) KEBUGCHECKEX(REGISTRY_ERROR, 11, 3, 0, 0); + + /* Phase 4: Create the ACL */ + Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION); + if (!NT_SUCCESS(Status)) KEBUGCHECKEX(REGISTRY_ERROR, 11, 4, Status, 0); + + /* Phase 5: Build the ACL */ + Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION, KEY_ALL_ACCESS, Sid[0]); + Status |= RtlAddAccessAllowedAce(Acl, ACL_REVISION, KEY_ALL_ACCESS, Sid[1]); + Status |= RtlAddAccessAllowedAce(Acl, ACL_REVISION, KEY_READ, Sid[2]); + Status |= RtlAddAccessAllowedAce(Acl, ACL_REVISION, KEY_READ, Sid[3]); + if (!NT_SUCCESS(Status)) KEBUGCHECKEX(REGISTRY_ERROR, 11, 5, Status, 0); + + /* Phase 5: Make the ACEs inheritable */ + Status = RtlGetAce(Acl, 0,( PVOID*)&AceHeader); + ASSERT(NT_SUCCESS(Status)); + AceHeader->AceFlags |= CONTAINER_INHERIT_ACE; + Status = RtlGetAce(Acl, 1, (PVOID*)&AceHeader); + ASSERT(NT_SUCCESS(Status)); + AceHeader->AceFlags |= CONTAINER_INHERIT_ACE; + Status = RtlGetAce(Acl, 2, (PVOID*)&AceHeader); + ASSERT(NT_SUCCESS(Status)); + AceHeader->AceFlags |= CONTAINER_INHERIT_ACE; + Status = RtlGetAce(Acl, 3, (PVOID*)&AceHeader); + ASSERT(NT_SUCCESS(Status)); + AceHeader->AceFlags |= CONTAINER_INHERIT_ACE; + + /* Phase 6: Allocate the security descriptor and make space for the ACL */ + SecurityDescriptor = ExAllocatePoolWithTag(PagedPool, + sizeof(SECURITY_DESCRIPTOR) + + AclLength, + TAG_CM); + if (!SecurityDescriptor) KEBUGCHECKEX(REGISTRY_ERROR, 11, 6, 0, 0); + + /* Phase 6: Make a copy of the ACL */ + AclCopy = (PACL)((PISECURITY_DESCRIPTOR)SecurityDescriptor + 1); + RtlCopyMemory(AclCopy, Acl, AclLength); + + /* Phase 7: Create the security descriptor */ + Status = RtlCreateSecurityDescriptor(SecurityDescriptor, + SECURITY_DESCRIPTOR_REVISION); + if (!NT_SUCCESS(Status)) KEBUGCHECKEX(REGISTRY_ERROR, 11, 7, Status, 0); + + /* Phase 8: Set the ACL as a DACL */ + Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor, + TRUE, + AclCopy, + FALSE); + if (!NT_SUCCESS(Status)) KEBUGCHECKEX(REGISTRY_ERROR, 11, 8, Status, 0); + + /* Free the SIDs and original ACL */ + for (i = 0; i < 4; i++) ExFreePool(Sid[i]); + ExFreePool(Acl); + + /* Return the security descriptor */ + return SecurityDescriptor; +} + +NTSTATUS +NTAPI +CmpSecurityMethod(IN PVOID ObjectBody, + IN SECURITY_OPERATION_CODE OperationCode, + IN PSECURITY_INFORMATION SecurityInformation, + IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor, + IN OUT PULONG BufferLength, + IN OUT PSECURITY_DESCRIPTOR *OldSecurityDescriptor, + IN POOL_TYPE PoolType, + IN PGENERIC_MAPPING GenericMapping) +{ + /* HACK */ + return STATUS_SUCCESS; +} diff --git a/reactos/ntoskrnl/config/cmsecach.c b/reactos/ntoskrnl/config/cmsecach.c index f2ed365d852..caad874380c 100644 --- a/reactos/ntoskrnl/config/cmsecach.c +++ b/reactos/ntoskrnl/config/cmsecach.c @@ -1,38 +1,37 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/config/cmsecach.c - * PURPOSE: Configuration Manager - Security Cache - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include "ntoskrnl.h" -#include "cm.h" -#define NDEBUG -#include "debug.h" - -/* GLOBALS *******************************************************************/ - -/* FUNCTIONS *****************************************************************/ - -VOID -NTAPI -CmpInitSecurityCache(IN PCMHIVE Hive) -{ - ULONG i; - - /* Reset data */ - Hive->SecurityCount = 0; - Hive->SecurityCacheSize = 0; - Hive->SecurityHitHint = -1; - Hive->SecurityCache = NULL; - - /* Loop every security hash */ - for (i = 0; i < 64; i++) - { - /* Initialize it */ - InitializeListHead(&Hive->SecurityHash[i]); - } -} +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmsecach.c + * PURPOSE: Configuration Manager - Security Cache + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#define NDEBUG +#include "debug.h" + +/* GLOBALS *******************************************************************/ + +/* FUNCTIONS *****************************************************************/ + +VOID +NTAPI +CmpInitSecurityCache(IN PCMHIVE Hive) +{ + ULONG i; + + /* Reset data */ + Hive->SecurityCount = 0; + Hive->SecurityCacheSize = 0; + Hive->SecurityHitHint = -1; + Hive->SecurityCache = NULL; + + /* Loop every security hash */ + for (i = 0; i < 64; i++) + { + /* Initialize it */ + InitializeListHead(&Hive->SecurityHash[i]); + } +} diff --git a/reactos/ntoskrnl/config/cmsysini.c b/reactos/ntoskrnl/config/cmsysini.c index f5531e1a6f8..eb904ff7bcb 100644 --- a/reactos/ntoskrnl/config/cmsysini.c +++ b/reactos/ntoskrnl/config/cmsysini.c @@ -1,1656 +1,1655 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/config/cmsysini.c - * PURPOSE: Configuration Manager - System Initialization Code - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include "ntoskrnl.h" -#include "cm.h" -#define NDEBUG -#include "debug.h" - -POBJECT_TYPE CmpKeyObjectType; -PCMHIVE CmiVolatileHive; -LIST_ENTRY CmpHiveListHead; -ERESOURCE CmpRegistryLock; -KGUARDED_MUTEX CmpSelfHealQueueLock; -LIST_ENTRY CmpSelfHealQueueListHead; -KEVENT CmpLoadWorkerEvent; -LONG CmpLoadWorkerIncrement; -PEPROCESS CmpSystemProcess; -BOOLEAN HvShutdownComplete; -PVOID CmpRegistryLockCallerCaller, CmpRegistryLockCaller; -BOOLEAN CmpFlushStarveWriters; -BOOLEAN CmpFlushOnLockRelease; -BOOLEAN CmpSpecialBootCondition; -BOOLEAN CmpNoWrite; -BOOLEAN CmpForceForceFlush; -BOOLEAN CmpWasSetupBoot; - -/* FUNCTIONS *****************************************************************/ - -VOID -NTAPI -CmpDeleteKeyObject(PVOID DeletedObject) -{ - PCM_KEY_BODY KeyBody = (PCM_KEY_BODY)DeletedObject; - PCM_KEY_CONTROL_BLOCK Kcb; - REG_KEY_HANDLE_CLOSE_INFORMATION KeyHandleCloseInfo; - REG_POST_OPERATION_INFORMATION PostOperationInfo; - NTSTATUS Status; - PAGED_CODE(); - - /* First off, prepare the handle close information callback */ - PostOperationInfo.Object = KeyBody; - KeyHandleCloseInfo.Object = KeyBody; - Status = CmiCallRegisteredCallbacks(RegNtPreKeyHandleClose, - &KeyHandleCloseInfo); - if (!NT_SUCCESS(Status)) - { - /* If we failed, notify the post routine */ - PostOperationInfo.Status = Status; - CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose, &PostOperationInfo); - return; - } - - /* Acquire hive lock */ - CmpLockRegistry(); - - /* Make sure this is a valid key body */ - if (KeyBody->Type == TAG('k', 'y', '0', '2')) - { - /* Get the KCB */ - Kcb = KeyBody->KeyControlBlock; - if (Kcb) - { - /* Delist the key (once new parse routines are used) */ - //DelistKeyBodyFromKCB(KeyBody, FALSE); - } - - /* Dereference the KCB */ - CmpDelayDerefKeyControlBlock(Kcb); - - } - - /* Release the registry lock */ - CmpUnlockRegistry(); - - /* Do the post callback */ - PostOperationInfo.Status = STATUS_SUCCESS; - CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose, &PostOperationInfo); -} - -VOID -NTAPI -CmpCloseKeyObject(IN PEPROCESS Process OPTIONAL, - IN PVOID Object, - IN ACCESS_MASK GrantedAccess, - IN ULONG ProcessHandleCount, - IN ULONG SystemHandleCount) -{ - PCM_KEY_BODY KeyBody = (PCM_KEY_BODY)Object; - PAGED_CODE(); - - /* Don't do anything if we're not the last handle */ - if (SystemHandleCount > 1) return; - - /* Make sure we're a valid key body */ - if (KeyBody->Type == TAG('k', 'y', '0', '2')) - { - /* Don't do anything if we don't have a notify block */ - if (!KeyBody->NotifyBlock) return; - - /* This shouldn't happen yet */ - ASSERT(FALSE); - } -} - -NTSTATUS -NTAPI -CmpQueryKeyName(IN PVOID ObjectBody, - IN BOOLEAN HasName, - IN OUT POBJECT_NAME_INFORMATION ObjectNameInfo, - IN ULONG Length, - OUT PULONG ReturnLength, - IN KPROCESSOR_MODE PreviousMode) -{ - DPRINT1("CmpQueryKeyName() called\n"); - while (TRUE); - return STATUS_SUCCESS; -} - -NTSTATUS -NTAPI -CmpInitHiveFromFile(IN PCUNICODE_STRING HiveName, - IN ULONG HiveFlags, - OUT PCMHIVE *Hive, - IN OUT PBOOLEAN New, - IN ULONG CheckFlags) -{ - ULONG HiveDisposition, LogDisposition; - HANDLE FileHandle = NULL, LogHandle = NULL; - NTSTATUS Status; - ULONG Operation, FileType; - PCMHIVE NewHive; - PAGED_CODE(); - - /* Assume failure */ - *Hive = NULL; - - /* Open or create the hive files */ - Status = CmpOpenHiveFiles(HiveName, - L".LOG", - &FileHandle, - &LogHandle, - &HiveDisposition, - &LogDisposition, - *New, - FALSE, - TRUE, - NULL); - if (!NT_SUCCESS(Status)) return Status; - - /* Check if we have a log handle */ - FileType = (LogHandle) ? HFILE_TYPE_LOG : HFILE_TYPE_PRIMARY; - - /* Check if we created or opened the hive */ - if (HiveDisposition == FILE_CREATED) - { - /* Do a create operation */ - Operation = HINIT_CREATE; - *New = TRUE; - } - else - { - /* Open it as a file */ - Operation = HINIT_FILE; - *New = FALSE; - } - - /* Check if we're sharing hives */ - if (CmpShareSystemHives) - { - /* Then force using the primary hive */ - FileType = HFILE_TYPE_PRIMARY; - if (LogHandle) - { - /* Get rid of the log handle */ - ZwClose(LogHandle); - LogHandle = NULL; - } - } - - /* Check if we're too late */ - if (HvShutdownComplete) - { - /* Fail */ - ZwClose(FileHandle); - if (LogHandle) ZwClose(LogHandle); - return STATUS_TOO_LATE; - } - - /* Initialize the hive */ - Status = CmpInitializeHive((PCMHIVE*)&NewHive, - Operation, - HiveFlags, - FileType, - NULL, - FileHandle, - LogHandle, - NULL, - HiveName, - 0); - if (!NT_SUCCESS(Status)) - { - /* Fail */ - ZwClose(FileHandle); - if (LogHandle) ZwClose(LogHandle); - return Status; - } - - /* Success, return hive */ - *Hive = NewHive; - - /* ROS: Init root key cell and prepare the hive */ - if (Operation == HINIT_CREATE) CmCreateRootNode(&NewHive->Hive, L""); - CmPrepareHive(&NewHive->Hive); - - /* Duplicate the hive name */ - NewHive->FileFullPath.Buffer = ExAllocatePoolWithTag(PagedPool, - HiveName->Length, - TAG_CM); - if (NewHive->FileFullPath.Buffer) - { - /* Copy the string */ - RtlCopyMemory(NewHive->FileFullPath.Buffer, - HiveName->Buffer, - HiveName->Length); - NewHive->FileFullPath.Length = HiveName->Length; - NewHive->FileFullPath.MaximumLength = HiveName->MaximumLength; - } - - /* Return success */ - return STATUS_SUCCESS; -} - -NTSTATUS -NTAPI -CmpSetSystemValues(IN PLOADER_PARAMETER_BLOCK LoaderBlock) -{ - OBJECT_ATTRIBUTES ObjectAttributes; - UNICODE_STRING KeyName, ValueName = {0}; - HANDLE KeyHandle; - NTSTATUS Status; - ASSERT(LoaderBlock != NULL); - - /* Setup attributes for loader options */ - RtlInitUnicodeString(&KeyName, - L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\" - L"Control"); - InitializeObjectAttributes(&ObjectAttributes, - &KeyName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - Status = NtOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes); - if (!NT_SUCCESS(Status)) goto Quickie; - - /* Key opened, now write to the key */ - RtlInitUnicodeString(&KeyName, L"SystemStartOptions"); - Status = NtSetValueKey(KeyHandle, - &KeyName, - 0, - REG_SZ, - CmpLoadOptions.Buffer, - CmpLoadOptions.Length); - if (!NT_SUCCESS(Status)) goto Quickie; - - /* Setup value name for system boot device */ - RtlInitUnicodeString(&KeyName, L"SystemBootDevice"); - RtlCreateUnicodeStringFromAsciiz(&ValueName, LoaderBlock->NtBootPathName); - Status = NtSetValueKey(KeyHandle, - &KeyName, - 0, - REG_SZ, - ValueName.Buffer, - ValueName.Length); - -Quickie: - /* Free the buffers */ - RtlFreeUnicodeString(&ValueName); - - /* Close the key and return */ - NtClose(KeyHandle); - - /* Return the status */ - return (ExpInTextModeSetup ? STATUS_SUCCESS : Status); -} - -NTSTATUS -NTAPI -CmpCreateControlSet(IN PLOADER_PARAMETER_BLOCK LoaderBlock) -{ - UNICODE_STRING ConfigName = RTL_CONSTANT_STRING(L"Control\\IDConfigDB"); - UNICODE_STRING SelectName = - RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\Select"); - UNICODE_STRING KeyName; - OBJECT_ATTRIBUTES ObjectAttributes; - CHAR ValueInfoBuffer[128]; - PKEY_VALUE_FULL_INFORMATION ValueInfo; - CHAR Buffer[128]; - WCHAR UnicodeBuffer[128]; - HANDLE SelectHandle, KeyHandle, ConfigHandle = NULL, ProfileHandle = NULL; - HANDLE ParentHandle = NULL; - ULONG ControlSet, HwProfile; - ANSI_STRING TempString; - NTSTATUS Status; - ULONG ResultLength, Disposition; - PLOADER_PARAMETER_EXTENSION LoaderExtension; - PAGED_CODE(); - - /* Open the select key */ - InitializeObjectAttributes(&ObjectAttributes, - &SelectName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - Status = NtOpenKey(&SelectHandle, KEY_READ, &ObjectAttributes); - if (!NT_SUCCESS(Status)) - { - /* ReactOS Hack: Hard-code current to 001 for SetupLdr */ - if (!LoaderBlock->RegistryBase) - { - /* Build the ControlSet001 key */ - RtlInitUnicodeString(&KeyName, - L"\\Registry\\Machine\\System\\ControlSet001"); - InitializeObjectAttributes(&ObjectAttributes, - &KeyName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - Status = NtCreateKey(&KeyHandle, - KEY_ALL_ACCESS, - &ObjectAttributes, - 0, - NULL, - 0, - &Disposition); - if (!NT_SUCCESS(Status)) return Status; - - /* Don't need the handle */ - ZwClose(KeyHandle); - - /* Use hard-coded setting */ - ControlSet = 1; - goto UseSet; - } - - /* Fail for real boots */ - return Status; - } - - /* Open the current value */ - RtlInitUnicodeString(&KeyName, L"Current"); - Status = NtQueryValueKey(SelectHandle, - &KeyName, - KeyValueFullInformation, - ValueInfoBuffer, - sizeof(ValueInfoBuffer), - &ResultLength); - NtClose(SelectHandle); - if (!NT_SUCCESS(Status)) return Status; - - /* Get the actual value pointer, and get the control set ID */ - ValueInfo = (PKEY_VALUE_FULL_INFORMATION)ValueInfoBuffer; - ControlSet = *(PULONG)((PUCHAR)ValueInfo + ValueInfo->DataOffset); - - /* Create the current control set key */ -UseSet: - RtlInitUnicodeString(&KeyName, - L"\\Registry\\Machine\\System\\CurrentControlSet"); - InitializeObjectAttributes(&ObjectAttributes, - &KeyName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - Status = NtCreateKey(&KeyHandle, - KEY_CREATE_LINK, - &ObjectAttributes, - 0, - NULL, - REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK, - &Disposition); - if (!NT_SUCCESS(Status)) return Status; - - /* Sanity check */ - ASSERT(Disposition == REG_CREATED_NEW_KEY); - - /* Initialize the symbolic link name */ - sprintf(Buffer, - "\\Registry\\Machine\\System\\ControlSet%03ld", - ControlSet); - RtlInitAnsiString(&TempString, Buffer); - - /* Create a Unicode string out of it */ - KeyName.MaximumLength = sizeof(UnicodeBuffer); - KeyName.Buffer = UnicodeBuffer; - Status = RtlAnsiStringToUnicodeString(&KeyName, &TempString, FALSE); - - /* Set the value */ - Status = NtSetValueKey(KeyHandle, - &CmSymbolicLinkValueName, - 0, - REG_LINK, - KeyName.Buffer, - KeyName.Length); - if (!NT_SUCCESS(Status)) return Status; - - /* Get the configuration database key */ - InitializeObjectAttributes(&ObjectAttributes, - &ConfigName, - OBJ_CASE_INSENSITIVE, - KeyHandle, - NULL); - Status = NtOpenKey(&ConfigHandle, KEY_READ, &ObjectAttributes); - NtClose(KeyHandle); - - /* Check if we don't have one */ - if (!NT_SUCCESS(Status)) - { - /* Cleanup and exit */ - ConfigHandle = 0; - goto Cleanup; - } - - /* Now get the current config */ - RtlInitUnicodeString(&KeyName, L"CurrentConfig"); - Status = NtQueryValueKey(ConfigHandle, - &KeyName, - KeyValueFullInformation, - ValueInfoBuffer, - sizeof(ValueInfoBuffer), - &ResultLength); - - /* Set pointer to buffer */ - ValueInfo = (PKEY_VALUE_FULL_INFORMATION)ValueInfoBuffer; - - /* Check if we failed or got a non DWORD-value */ - if (!(NT_SUCCESS(Status)) || (ValueInfo->Type != REG_DWORD)) goto Cleanup; - - /* Get the hadware profile */ - HwProfile = *(PULONG)((PUCHAR)ValueInfo + ValueInfo->DataOffset); - - /* Open the hardware profile key */ - RtlInitUnicodeString(&KeyName, - L"\\Registry\\Machine\\System\\CurrentControlSet" - L"\\Hardware Profiles"); - InitializeObjectAttributes(&ObjectAttributes, - &KeyName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - Status = NtOpenKey(&ParentHandle, KEY_READ, &ObjectAttributes); - if (!NT_SUCCESS(Status)) - { - /* Exit and clean up */ - ParentHandle = 0; - goto Cleanup; - } - - /* Build the profile name */ - sprintf(Buffer, "%04ld", HwProfile); - RtlInitAnsiString(&TempString, Buffer); - - /* Convert it to Unicode */ - KeyName.MaximumLength = sizeof(UnicodeBuffer); - KeyName.Buffer = UnicodeBuffer; - Status = RtlAnsiStringToUnicodeString(&KeyName, - &TempString, - FALSE); - ASSERT(Status == STATUS_SUCCESS); - - /* Open the associated key */ - InitializeObjectAttributes(&ObjectAttributes, - &KeyName, - OBJ_CASE_INSENSITIVE, - ParentHandle, - NULL); - Status = NtOpenKey(&ProfileHandle, - KEY_READ | KEY_WRITE, - &ObjectAttributes); - if (!NT_SUCCESS (Status)) - { - /* Cleanup and exit */ - ProfileHandle = 0; - goto Cleanup; - } - - /* Check if we have a loader block extension */ - LoaderExtension = LoaderBlock->Extension; - if (LoaderExtension) - { - ASSERTMSG("ReactOS doesn't support NTLDR Profiles yet!\n", FALSE); - } - - /* Create the current hardware profile key */ - RtlInitUnicodeString(&KeyName, - L"\\Registry\\Machine\\System\\CurrentControlSet\\" - L"Hardware Profiles\\Current"); - InitializeObjectAttributes(&ObjectAttributes, - &KeyName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - Status = NtCreateKey(&KeyHandle, - KEY_CREATE_LINK, - &ObjectAttributes, - 0, - NULL, - REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK, - &Disposition); - if (NT_SUCCESS(Status)) - { - /* Sanity check */ - ASSERT(Disposition == REG_CREATED_NEW_KEY); - - /* Create the profile name */ - sprintf(Buffer, - "\\Registry\\Machine\\System\\CurrentControlSet\\" - "Hardware Profiles\\%04ld", - HwProfile); - RtlInitAnsiString(&TempString, Buffer); - - /* Convert it to Unicode */ - KeyName.MaximumLength = sizeof(UnicodeBuffer); - KeyName.Buffer = UnicodeBuffer; - Status = RtlAnsiStringToUnicodeString(&KeyName, - &TempString, - FALSE); - ASSERT(STATUS_SUCCESS == Status); - - /* Set it */ - Status = NtSetValueKey(KeyHandle, - &CmSymbolicLinkValueName, - 0, - REG_LINK, - KeyName.Buffer, - KeyName.Length); - NtClose(KeyHandle); - } - - /* Close every opened handle */ -Cleanup: - if (ConfigHandle) NtClose(ConfigHandle); - if (ProfileHandle) NtClose(ProfileHandle); - if (ParentHandle) NtClose(ParentHandle); - - /* Return success */ - return STATUS_SUCCESS; -} - -NTSTATUS -NTAPI -CmpLinkHiveToMaster(IN PUNICODE_STRING LinkName, - IN HANDLE RootDirectory, - IN PCMHIVE RegistryHive, - IN BOOLEAN Allocate, - IN PSECURITY_DESCRIPTOR SecurityDescriptor) -{ - OBJECT_ATTRIBUTES ObjectAttributes; - NTSTATUS Status; - CM_PARSE_CONTEXT ParseContext = {0}; - HANDLE KeyHandle; - PCM_KEY_BODY KeyBody; - PAGED_CODE(); - - /* Setup the object attributes */ - InitializeObjectAttributes(&ObjectAttributes, - LinkName, - OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, - RootDirectory, - SecurityDescriptor); - - /* Setup the parse context */ - ParseContext.CreateLink = TRUE; - ParseContext.CreateOperation = TRUE; - ParseContext.ChildHive.KeyHive = &RegistryHive->Hive; - - /* Check if we have a root keycell or if we need to create it */ - if (Allocate) - { - /* Create it */ - ParseContext.ChildHive.KeyCell = HCELL_NIL; - } - else - { - /* We have one */ - ParseContext.ChildHive.KeyCell = RegistryHive->Hive.BaseBlock->RootCell; - } - - /* Create the link node */ - Status = ObOpenObjectByName(&ObjectAttributes, - CmpKeyObjectType, - KernelMode, - NULL, - KEY_READ | KEY_WRITE, - (PVOID)&ParseContext, - &KeyHandle); - if (!NT_SUCCESS(Status)) return Status; - - /* Mark the hive as clean */ - RegistryHive->Hive.DirtyFlag = FALSE; - - /* ReactOS Hack: Keep alive */ - Status = ObReferenceObjectByHandle(KeyHandle, - 0, - CmpKeyObjectType, - KernelMode, - (PVOID*)&KeyBody, - NULL); - ASSERT(NT_SUCCESS(Status)); - - /* Close the extra handle */ - ZwClose(KeyHandle); - return STATUS_SUCCESS; -} - -BOOLEAN -NTAPI -CmpInitializeSystemHive(IN PLOADER_PARAMETER_BLOCK LoaderBlock) -{ - PVOID HiveBase; - ANSI_STRING LoadString; - PVOID Buffer; - ULONG Length; - NTSTATUS Status; - BOOLEAN Allocate; - UNICODE_STRING KeyName; - PCMHIVE SystemHive = NULL; - UNICODE_STRING HiveName = RTL_CONSTANT_STRING(L"SYSTEM"); - PSECURITY_DESCRIPTOR SecurityDescriptor; - PAGED_CODE(); - - /* Setup the ansi string */ - RtlInitAnsiString(&LoadString, LoaderBlock->LoadOptions); - - /* Allocate the unicode buffer */ - Length = LoadString.Length * sizeof(WCHAR) + sizeof(UNICODE_NULL); - Buffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM); - if (!Buffer) - { - /* Fail */ - KEBUGCHECKEX(BAD_SYSTEM_CONFIG_INFO, 3, 1, (ULONG_PTR)LoaderBlock, 0); - } - - /* Setup the unicode string */ - RtlInitEmptyUnicodeString(&CmpLoadOptions, Buffer, (USHORT)Length); - - /* Add the load options and null-terminate */ - RtlAnsiStringToUnicodeString(&CmpLoadOptions, &LoadString, FALSE); - CmpLoadOptions.Buffer[LoadString.Length] = UNICODE_NULL; - CmpLoadOptions.Length += sizeof(WCHAR); - - /* Get the System Hive base address */ - HiveBase = LoaderBlock->RegistryBase; - if (HiveBase) - { - /* Import it */ - ((PHBASE_BLOCK)HiveBase)->Length = LoaderBlock->RegistryLength; - Status = CmpInitializeHive((PCMHIVE*)&SystemHive, - HINIT_MEMORY, - HIVE_NOLAZYFLUSH, - HFILE_TYPE_LOG, - HiveBase, - NULL, - NULL, - NULL, - &HiveName, - 2); - if (!NT_SUCCESS(Status)) return FALSE; - CmPrepareHive(&SystemHive->Hive); - - /* Set the hive filename */ - RtlCreateUnicodeString(&SystemHive->FileFullPath, - L"\\SystemRoot\\System32\\Config\\SYSTEM"); - - /* We imported, no need to create a new hive */ - Allocate = FALSE; - - /* Manually set the hive as volatile, if in Live CD mode */ - if (CmpShareSystemHives) SystemHive->Hive.HiveFlags = HIVE_VOLATILE; - } - else - { - /* Create it */ - Status = CmpInitializeHive(&SystemHive, - HINIT_CREATE, - HIVE_NOLAZYFLUSH, - HFILE_TYPE_LOG, - NULL, - NULL, - NULL, - NULL, - &HiveName, - 0); - if (!NT_SUCCESS(Status)) return FALSE; - - /* Set the hive filename */ - RtlCreateUnicodeString(&SystemHive->FileFullPath, - L"\\SystemRoot\\System32\\Config\\SYSTEM"); - - /* Tell CmpLinkHiveToMaster to allocate a hive */ - Allocate = TRUE; - } - - /* Save the boot type */ - if (SystemHive) CmpBootType = SystemHive->Hive.BaseBlock->BootType; - - /* Are we in self-healing mode? */ - if (!CmSelfHeal) - { - /* Disable self-healing internally and check if boot type wanted it */ - CmpSelfHeal = FALSE; - if (CmpBootType & 4) - { - /* We're disabled, so bugcheck */ - KEBUGCHECKEX(BAD_SYSTEM_CONFIG_INFO, - 3, - 3, - (ULONG_PTR)SystemHive, - 0); - } - } - - /* Create the default security descriptor */ - SecurityDescriptor = CmpHiveRootSecurityDescriptor(); - - /* Attach it to the system key */ - RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\SYSTEM"); - Status = CmpLinkHiveToMaster(&KeyName, - NULL, - (PCMHIVE)SystemHive, - Allocate, - SecurityDescriptor); - - /* Free the security descriptor */ - ExFreePool(SecurityDescriptor); - if (!NT_SUCCESS(Status)) return FALSE; - - /* Add the hive to the hive list */ - CmpMachineHiveList[3].CmHive = (PCMHIVE)SystemHive; - - /* Success! */ - return TRUE; -} - -NTSTATUS -NTAPI -CmpCreateObjectTypes(VOID) -{ - OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; - UNICODE_STRING Name; - GENERIC_MAPPING CmpKeyMapping = {KEY_READ, - KEY_WRITE, - KEY_EXECUTE, - KEY_ALL_ACCESS}; - PAGED_CODE(); - - /* Initialize the Key object type */ - RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); - RtlInitUnicodeString(&Name, L"Key"); - ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); - ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(CM_KEY_BODY); - ObjectTypeInitializer.GenericMapping = CmpKeyMapping; - ObjectTypeInitializer.PoolType = PagedPool; - ObjectTypeInitializer.ValidAccessMask = KEY_ALL_ACCESS; - ObjectTypeInitializer.UseDefaultObject = TRUE; - ObjectTypeInitializer.DeleteProcedure = CmpDeleteKeyObject; - ObjectTypeInitializer.ParseProcedure = CmpParseKey; - ObjectTypeInitializer.SecurityProcedure = CmpSecurityMethod; - ObjectTypeInitializer.QueryNameProcedure = CmpQueryKeyName; - ObjectTypeInitializer.CloseProcedure = CmpCloseKeyObject; - ObjectTypeInitializer.SecurityRequired = TRUE; - - /* Create it */ - return ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &CmpKeyObjectType); -} - -BOOLEAN -NTAPI -CmpCreateRootNode(IN PHHIVE Hive, - IN PCWSTR Name, - OUT PHCELL_INDEX Index) -{ - UNICODE_STRING KeyName; - PCM_KEY_NODE KeyCell; - LARGE_INTEGER SystemTime; - PAGED_CODE(); - - /* Initialize the node name and allocate it */ - RtlInitUnicodeString(&KeyName, Name); - *Index = HvAllocateCell(Hive, - FIELD_OFFSET(CM_KEY_NODE, Name) + - CmpNameSize(Hive, &KeyName), - Stable, - HCELL_NIL); - if (*Index == HCELL_NIL) return FALSE; - - /* Set the cell index and get the data */ - Hive->BaseBlock->RootCell = *Index; - KeyCell = (PCM_KEY_NODE)HvGetCell(Hive, *Index); - if (!KeyCell) return FALSE; - - /* Setup the cell */ - KeyCell->Signature = (USHORT)CM_KEY_NODE_SIGNATURE; - KeyCell->Flags = KEY_HIVE_ENTRY | KEY_NO_DELETE; - KeQuerySystemTime(&SystemTime); - KeyCell->LastWriteTime = SystemTime; - KeyCell->Parent = HCELL_NIL; - KeyCell->SubKeyCounts[Stable] = 0; - KeyCell->SubKeyCounts[Volatile] = 0; - KeyCell->SubKeyLists[Stable] = HCELL_NIL; - KeyCell->SubKeyLists[Volatile] = HCELL_NIL; - KeyCell->ValueList.Count = 0; - KeyCell->ValueList.List = HCELL_NIL; - KeyCell->Security = HCELL_NIL; - KeyCell->Class = HCELL_NIL; - KeyCell->ClassLength = 0; - KeyCell->MaxNameLen = 0; - KeyCell->MaxClassLen = 0; - KeyCell->MaxValueNameLen = 0; - KeyCell->MaxValueDataLen = 0; - - /* Copy the name (this will also set the length) */ - KeyCell->NameLength = CmpCopyName(Hive, (PWCHAR)KeyCell->Name, &KeyName); - - /* Check if the name was compressed */ - if (KeyCell->NameLength < KeyName.Length) - { - /* Set the flag */ - KeyCell->Flags |= KEY_COMP_NAME; - } - - /* Return success */ - HvReleaseCell(Hive, *Index); - return TRUE; -} - -BOOLEAN -NTAPI -CmpCreateRegistryRoot(VOID) -{ - UNICODE_STRING KeyName; - OBJECT_ATTRIBUTES ObjectAttributes; - PCM_KEY_BODY RootKey; - HCELL_INDEX RootIndex; - NTSTATUS Status; - PCM_KEY_NODE KeyCell; - PSECURITY_DESCRIPTOR SecurityDescriptor; - PCM_KEY_CONTROL_BLOCK Kcb; - PAGED_CODE(); - - /* Setup the root node */ - if (!CmpCreateRootNode(&CmiVolatileHive->Hive, L"REGISTRY", &RootIndex)) - { - /* We failed */ - return FALSE; - } - - /* Create '\Registry' key. */ - RtlInitUnicodeString(&KeyName, L"\\Registry"); - SecurityDescriptor = CmpHiveRootSecurityDescriptor(); - InitializeObjectAttributes(&ObjectAttributes, - &KeyName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - Status = ObCreateObject(KernelMode, - CmpKeyObjectType, - &ObjectAttributes, - KernelMode, - NULL, - sizeof(CM_KEY_BODY), - 0, - 0, - (PVOID*)&RootKey); - ExFreePool(SecurityDescriptor); - if (!NT_SUCCESS(Status)) return FALSE; - - /* Sanity check, and get the key cell */ - ASSERT((&CmiVolatileHive->Hive)->ReleaseCellRoutine == NULL); - KeyCell = (PCM_KEY_NODE)HvGetCell(&CmiVolatileHive->Hive, RootIndex); - if (!KeyCell) return FALSE; - - /* Create the KCB */ - RtlInitUnicodeString(&KeyName, L"Registry"); - Kcb = CmpCreateKeyControlBlock(&CmiVolatileHive->Hive, - RootIndex, - KeyCell, - NULL, - 0, - &KeyName); - if (!Kcb) return FALSE; - - /* Initialize the object */ - RootKey->KeyControlBlock = Kcb; - RootKey->Type = TAG('k', 'y', '0', '2'); - RootKey->NotifyBlock = NULL; - RootKey->ProcessID = PsGetCurrentProcessId(); - - /* Link with KCB */ - EnlistKeyBodyWithKCB(RootKey, 0); - - /* Insert the key into the namespace */ - Status = ObInsertObject(RootKey, - NULL, - KEY_ALL_ACCESS, - 0, - NULL, - &CmpRegistryRootHandle); - if (!NT_SUCCESS(Status)) return FALSE; - - /* Reference the key again so that we never lose it */ - Status = ObReferenceObjectByHandle(CmpRegistryRootHandle, - KEY_READ, - NULL, - KernelMode, - (PVOID*)&RootKey, - NULL); - if (!NT_SUCCESS(Status)) return FALSE; - - /* Completely sucessful */ - return TRUE; -} - -NTSTATUS -NTAPI -CmpGetRegistryPath(IN PWCHAR ConfigPath) -{ - OBJECT_ATTRIBUTES ObjectAttributes; - NTSTATUS Status; - HANDLE KeyHandle; - PKEY_VALUE_PARTIAL_INFORMATION ValueInfo; - UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE"); - UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"InstallPath"); - ULONG BufferSize, ResultSize; - - /* Check if we are booted in setup */ - if (ExpInTextModeSetup) - { - /* Setup the object attributes */ - InitializeObjectAttributes(&ObjectAttributes, - &KeyName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - /* Open the key */ - Status = ZwOpenKey(&KeyHandle, - KEY_ALL_ACCESS, - &ObjectAttributes); - if (!NT_SUCCESS(Status)) return Status; - - /* Allocate the buffer */ - BufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4096; - ValueInfo = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_CM); - if (!ValueInfo) - { - /* Fail */ - ZwClose(KeyHandle); - return STATUS_INSUFFICIENT_RESOURCES; - } - - /* Query the value */ - Status = ZwQueryValueKey(KeyHandle, - &ValueName, - KeyValuePartialInformation, - ValueInfo, - BufferSize, - &ResultSize); - ZwClose(KeyHandle); - if (!NT_SUCCESS(Status)) - { - /* Fail */ - ExFreePool(ValueInfo); - return Status; - } - - /* Copy the config path and null-terminate it */ - RtlCopyMemory(ConfigPath, - ValueInfo->Data, - ValueInfo->DataLength); - ConfigPath[ValueInfo->DataLength / sizeof(WCHAR)] = UNICODE_NULL; - ExFreePool(ValueInfo); - } - else - { - /* Just use default path */ - wcscpy(ConfigPath, L"\\SystemRoot"); - } - - /* Add registry path */ - wcscat(ConfigPath, L"\\System32\\Config\\"); - - /* Done */ - return STATUS_SUCCESS; -} - -VOID -NTAPI -CmpLoadHiveThread(IN PVOID StartContext) -{ - WCHAR FileBuffer[MAX_PATH], RegBuffer[MAX_PATH], ConfigPath[MAX_PATH]; - UNICODE_STRING TempName, FileName, RegName; - ULONG FileStart, RegStart, i, ErrorResponse, WorkerCount, Length; - ULONG PrimaryDisposition, SecondaryDisposition, ClusterSize; - PCMHIVE CmHive; - HANDLE PrimaryHandle, LogHandle; - NTSTATUS Status = STATUS_SUCCESS; - PVOID ErrorParameters; - PAGED_CODE(); - - /* Get the hive index, make sure it makes sense */ - i = (ULONG)StartContext; - ASSERT(CmpMachineHiveList[i].Name != NULL); - - /* We were started */ - CmpMachineHiveList[i].ThreadStarted = TRUE; - - /* Build the file name and registry name strings */ - RtlInitEmptyUnicodeString(&FileName, FileBuffer, MAX_PATH); - RtlInitEmptyUnicodeString(&RegName, RegBuffer, MAX_PATH); - - /* Now build the system root path */ - CmpGetRegistryPath(ConfigPath); - RtlInitUnicodeString(&TempName, ConfigPath); - RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName); - FileStart = FileName.Length; - - /* And build the registry root path */ - RtlInitUnicodeString(&TempName, L"\\REGISTRY\\"); - RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName); - RegStart = RegName.Length; - - /* Build the base name */ - RegName.Length = RegStart; - RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName); - RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName); - - /* Check if this is a child of the root */ - if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == '\\') - { - /* Then setup the whole name */ - RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name); - RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName); - } - - /* Now Add tge rest if the file name */ - RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name); - FileName.Length = FileStart; - RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName); - if (!CmpMachineHiveList[i].CmHive) - { - /* We need to allocate a new hive structure */ - CmpMachineHiveList[i].Allocate = TRUE; - - /* Load the hive file */ - Status = CmpInitHiveFromFile(&FileName, - CmpMachineHiveList[i].HHiveFlags, - &CmHive, - &CmpMachineHiveList[i].Allocate, - 0); - if (!(NT_SUCCESS(Status)) || - (!(CmHive->FileHandles[HFILE_TYPE_LOG]) && !(CmpMiniNTBoot))) // hak - { - /* We failed or couldn't get a log file, raise a hard error */ - ErrorParameters = &FileName; - NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE, - 1, - 1, - (PULONG_PTR)&ErrorParameters, - OptionOk, - &ErrorResponse); - } - - /* Set the hive flags and newly allocated hive pointer */ - CmHive->Flags = CmpMachineHiveList[i].CmHiveFlags; - CmpMachineHiveList[i].CmHive2 = CmHive; - } - else - { - /* We already have a hive, is it volatile? */ - CmHive = CmpMachineHiveList[i].CmHive; - if (!(CmHive->Hive.HiveFlags & HIVE_VOLATILE)) - { - /* It's now, open the hive file and log */ - Status = CmpOpenHiveFiles(&FileName, - L".LOG", - &PrimaryHandle, - &LogHandle, - &PrimaryDisposition, - &SecondaryDisposition, - TRUE, - TRUE, - FALSE, - &ClusterSize); - if (!(NT_SUCCESS(Status)) || !(LogHandle)) - { - /* Couldn't open the hive or its log file, raise a hard error */ - ErrorParameters = &FileName; - NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE, - 1, - 1, - (PULONG_PTR)&ErrorParameters, - OptionOk, - &ErrorResponse); - - /* And bugcheck for posterity's sake */ - KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 0, i, Status); - } - - /* Save the file handles. This should remove our sync hacks */ - CmHive->FileHandles[HFILE_TYPE_LOG] = LogHandle; - CmHive->FileHandles[HFILE_TYPE_PRIMARY] = PrimaryHandle; - - /* Allow lazy flushing since the handles are there -- remove sync hacks */ - //ASSERT(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH); - CmHive->Hive.HiveFlags &= ~HIVE_NOLAZYFLUSH; - - /* Get the real size of the hive */ - Length = CmHive->Hive.Storage[Stable].Length + HBLOCK_SIZE; - - /* Check if the cluster size doesn't match */ - if (CmHive->Hive.Cluster != ClusterSize) ASSERT(FALSE); - - /* Set the file size */ - //if (!CmpFileSetSize((PHHIVE)CmHive, HFILE_TYPE_PRIMARY, Length, Length)) - { - /* This shouldn't fail */ - //ASSERT(FALSE); - } - - /* Another thing we don't support is NTLDR-recovery */ - if (CmHive->Hive.BaseBlock->BootRecover) ASSERT(FALSE); - - /* Finally, set our allocated hive to the same hive we've had */ - CmpMachineHiveList[i].CmHive2 = CmHive; - ASSERT(CmpMachineHiveList[i].CmHive == CmpMachineHiveList[i].CmHive2); - } - } - - /* We're done */ - CmpMachineHiveList[i].ThreadFinished = TRUE; - - /* Check if we're the last worker */ - WorkerCount = InterlockedIncrement(&CmpLoadWorkerIncrement); - if (WorkerCount == CM_NUMBER_OF_MACHINE_HIVES) - { - /* Signal the event */ - KeSetEvent(&CmpLoadWorkerEvent, 0, FALSE); - } - - /* Kill the thread */ - PsTerminateSystemThread(Status); -} - -VOID -NTAPI -CmpInitializeHiveList(IN USHORT Flag) -{ - WCHAR FileBuffer[MAX_PATH], RegBuffer[MAX_PATH], ConfigPath[MAX_PATH]; - UNICODE_STRING TempName, FileName, RegName; - HANDLE Thread; - NTSTATUS Status; - ULONG FileStart, RegStart, i; - PSECURITY_DESCRIPTOR SecurityDescriptor; - PAGED_CODE(); - - /* Allow writing for now */ - CmpNoWrite = FALSE; - - /* Build the file name and registry name strings */ - RtlInitEmptyUnicodeString(&FileName, FileBuffer, MAX_PATH); - RtlInitEmptyUnicodeString(&RegName, RegBuffer, MAX_PATH); - - /* Now build the system root path */ - CmpGetRegistryPath(ConfigPath); - RtlInitUnicodeString(&TempName, ConfigPath); - RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName); - FileStart = FileName.Length; - - /* And build the registry root path */ - RtlInitUnicodeString(&TempName, L"\\REGISTRY\\"); - RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName); - RegStart = RegName.Length; - - /* Setup the event to synchronize workers */ - KeInitializeEvent(&CmpLoadWorkerEvent, SynchronizationEvent, FALSE); - - /* Enter special boot condition */ - CmpSpecialBootCondition = TRUE; - - /* Create the SD for the root hives */ - SecurityDescriptor = CmpHiveRootSecurityDescriptor(); - - /* Loop every hive we care about */ - for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++) - { - /* Make sure the list is setup */ - ASSERT(CmpMachineHiveList[i].Name != NULL); - - /* Create a thread to handle this hive */ - Status = PsCreateSystemThread(&Thread, - THREAD_ALL_ACCESS, - NULL, - 0, - NULL, - CmpLoadHiveThread, - (PVOID)i); - if (NT_SUCCESS(Status)) - { - /* We don't care about the handle -- the thread self-terminates */ - ZwClose(Thread); - } - else - { - /* Can't imagine this happening */ - KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 3, i, Status); - } - } - - /* Make sure we've reached the end of the list */ - ASSERT(CmpMachineHiveList[i].Name == NULL); - - /* Wait for hive loading to finish */ - KeWaitForSingleObject(&CmpLoadWorkerEvent, - Executive, - KernelMode, - FALSE, - NULL); - - /* Exit the special boot condition and make sure all workers completed */ - CmpSpecialBootCondition = FALSE; - ASSERT(CmpLoadWorkerIncrement == CM_NUMBER_OF_MACHINE_HIVES); - - /* Loop hives again */ - for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++) - { - /* Make sure the thread ran and finished */ - ASSERT(CmpMachineHiveList[i].ThreadFinished == TRUE); - ASSERT(CmpMachineHiveList[i].ThreadStarted == TRUE); - - /* Check if this was a new hive */ - if (!CmpMachineHiveList[i].CmHive) - { - /* Make sure we allocated something */ - ASSERT(CmpMachineHiveList[i].CmHive2 != NULL); - - /* Build the base name */ - RegName.Length = RegStart; - RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName); - RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName); - - /* Check if this is a child of the root */ - if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == '\\') - { - /* Then setup the whole name */ - RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name); - RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName); - } - - /* Now link the hive to its master */ - Status = CmpLinkHiveToMaster(&RegName, - NULL, - CmpMachineHiveList[i].CmHive2, - CmpMachineHiveList[i].Allocate, - SecurityDescriptor); - if (Status != STATUS_SUCCESS) - { - /* Linking needs to work */ - KeBugCheckEx(CONFIG_LIST_FAILED, 11, Status, i, (ULONG_PTR)&RegName); - } - - /* Check if we had to allocate a new hive */ - if (CmpMachineHiveList[i].Allocate) - { - /* Sync the new hive */ - //HvSyncHive((PHHIVE)(CmpMachineHiveList[i].CmHive2)); - } - } - - /* Check if we created a new hive */ - if (CmpMachineHiveList[i].CmHive2) - { - /* TODO: Add to HiveList key */ - } - } - - /* Get rid of the SD */ - ExFreePool(SecurityDescriptor); - - /* FIXME: Link SECURITY to SAM */ - - /* FIXME: Link S-1-5-18 to .Default */ -} - -BOOLEAN -NTAPI -CmInitSystem1(VOID) -{ - OBJECT_ATTRIBUTES ObjectAttributes; - UNICODE_STRING KeyName; - HANDLE KeyHandle; - NTSTATUS Status; - PCMHIVE HardwareHive; - PSECURITY_DESCRIPTOR SecurityDescriptor; - PAGED_CODE(); - - /* Check if this is PE-boot */ - if (InitIsWinPEMode) - { - /* Set registry to PE mode */ - CmpMiniNTBoot = TRUE; - CmpShareSystemHives = TRUE; - } - - /* Initialize the hive list and lock */ - InitializeListHead(&CmpHiveListHead); - ExInitializePushLock((PVOID)&CmpHiveListHeadLock); - ExInitializePushLock((PVOID)&CmpLoadHiveLock); - - /* Initialize registry lock */ - ExInitializeResourceLite(&CmpRegistryLock); - - /* Initialize the cache */ - CmpInitializeCache(); - - /* Initialize allocation and delayed dereferencing */ - CmpInitCmPrivateAlloc(); - CmpInitCmPrivateDelayAlloc(); - CmpInitDelayDerefKCBEngine(); - - /* Initialize callbacks */ - CmpInitCallback(); - - /* Initialize self healing */ - KeInitializeGuardedMutex(&CmpSelfHealQueueLock); - InitializeListHead(&CmpSelfHealQueueListHead); - - /* Save the current process and lock the registry */ - CmpSystemProcess = PsGetCurrentProcess(); - - /* Create the key object types */ - Status = CmpCreateObjectTypes(); - if (!NT_SUCCESS(Status)) - { - /* Bugcheck */ - KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 1, Status, 0); - } - - /* Build the master hive */ - Status = CmpInitializeHive((PCMHIVE*)&CmiVolatileHive, - HINIT_CREATE, - HIVE_VOLATILE, - HFILE_TYPE_PRIMARY, - NULL, - NULL, - NULL, - NULL, - NULL, - 0); - if (!NT_SUCCESS(Status)) - { - /* Bugcheck */ - KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 2, Status, 0); - } - - /* Create the \REGISTRY key node */ - if (!CmpCreateRegistryRoot()) - { - /* Bugcheck */ - KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 3, 0, 0); - } - - /* Create the default security descriptor */ - SecurityDescriptor = CmpHiveRootSecurityDescriptor(); - - /* Create '\Registry\Machine' key. */ - RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE"); - InitializeObjectAttributes(&ObjectAttributes, - &KeyName, - OBJ_CASE_INSENSITIVE, - NULL, - SecurityDescriptor); - Status = NtCreateKey(&KeyHandle, - KEY_READ | KEY_WRITE, - &ObjectAttributes, - 0, - NULL, - 0, - NULL); - if (!NT_SUCCESS(Status)) - { - /* Bugcheck */ - KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 5, Status, 0); - } - - /* Close the handle */ - NtClose(KeyHandle); - - /* Create '\Registry\User' key. */ - RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\USER"); - InitializeObjectAttributes(&ObjectAttributes, - &KeyName, - OBJ_CASE_INSENSITIVE, - NULL, - SecurityDescriptor); - Status = NtCreateKey(&KeyHandle, - KEY_READ | KEY_WRITE, - &ObjectAttributes, - 0, - NULL, - 0, - NULL); - if (!NT_SUCCESS(Status)) - { - /* Bugcheck */ - KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 6, Status, 0); - } - - /* Close the handle */ - NtClose(KeyHandle); - - /* Initialize the system hive */ - if (!CmpInitializeSystemHive(KeLoaderBlock)) - { - /* Bugcheck */ - KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 7, 0, 0); - } - - /* Create the 'CurrentControlSet' link. */ - Status = CmpCreateControlSet(KeLoaderBlock); - if (!NT_SUCCESS(Status)) - { - /* Bugcheck */ - KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 8, Status, 0); - } - - /* Create the hardware hive */ - Status = CmpInitializeHive((PCMHIVE*)&HardwareHive, - HINIT_CREATE, - HIVE_VOLATILE, - HFILE_TYPE_PRIMARY, - NULL, - NULL, - NULL, - NULL, - NULL, - 0); - if (!NT_SUCCESS(Status)) - { - /* Bugcheck */ - KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 11, Status, 0); - } - - /* Add the hive to the hive list */ - CmpMachineHiveList[0].CmHive = (PCMHIVE)HardwareHive; - - /* Attach it to the machine key */ - RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE"); - Status = CmpLinkHiveToMaster(&KeyName, - NULL, - (PCMHIVE)HardwareHive, - TRUE, - SecurityDescriptor); - if (!NT_SUCCESS(Status)) - { - /* Bugcheck */ - KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 12, Status, 0); - } - - /* FIXME: Add to HiveList key */ - - /* Free the security descriptor */ - ExFreePool(SecurityDescriptor); - - /* Fill out the Hardware key with the ARC Data from the Loader */ - Status = CmpInitializeHardwareConfiguration(KeLoaderBlock); - if (!NT_SUCCESS(Status)) - { - /* Bugcheck */ - KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 13, Status, 0); - } - - /* Initialize machine-dependent information into the registry */ - Status = CmpInitializeMachineDependentConfiguration(KeLoaderBlock); - if (!NT_SUCCESS(Status)) - { - /* Bugcheck */ - KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 14, Status, 0); - } - - /* Initialize volatile registry settings */ - Status = CmpSetSystemValues(KeLoaderBlock); - if (!NT_SUCCESS(Status)) - { - /* Bugcheck */ - KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 15, Status, 0); - } - - /* Free the load options */ - ExFreePool(CmpLoadOptions.Buffer); - - /* If we got here, all went well */ - return TRUE; -} - -VOID -NTAPI -CmpLockRegistryExclusive(VOID) -{ - /* Enter a critical region and lock the registry */ - KeEnterCriticalRegion(); - ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); - - /* Sanity check */ - ASSERT(CmpFlushStarveWriters == 0); - RtlGetCallersAddress(&CmpRegistryLockCaller, &CmpRegistryLockCallerCaller); -} - -VOID -NTAPI -CmpLockRegistry(VOID) -{ - /* Enter a critical region */ - KeEnterCriticalRegion(); - - /* Check if we have to starve writers */ - if (CmpFlushStarveWriters) - { - /* Starve exlusive waiters */ - ExAcquireSharedStarveExclusive(&CmpRegistryLock, TRUE); - } - else - { - /* Just grab the lock */ - ExAcquireResourceSharedLite(&CmpRegistryLock, TRUE); - } -} - -BOOLEAN -NTAPI -CmpTestRegistryLock(VOID) -{ - /* Test the lock */ - return !ExIsResourceAcquiredSharedLite(&CmpRegistryLock) ? FALSE : TRUE; -} - -BOOLEAN -NTAPI -CmpTestRegistryLockExclusive(VOID) -{ - /* Test the lock */ - return !ExIsResourceAcquiredExclusiveLite(&CmpRegistryLock) ? FALSE : TRUE; -} - -VOID -NTAPI -CmpUnlockRegistry(VOID) -{ - /* Sanity check */ - CMP_ASSERT_REGISTRY_LOCK(); - - /* Check if we should flush the registry */ - if (CmpFlushOnLockRelease) - { - /* The registry should be exclusively locked for this */ - CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK(); - - /* Flush the registry */ - CmpDoFlushAll(TRUE); - CmpFlushOnLockRelease = FALSE; - } - - /* Release the lock and leave the critical region */ - ExReleaseResourceLite(&CmpRegistryLock); - KeLeaveCriticalRegion(); -} - -VOID -NTAPI -CmpAcquireTwoKcbLocksExclusiveByKey(IN ULONG ConvKey1, - IN ULONG ConvKey2) -{ - ULONG Index1, Index2; - - /* Sanity check */ - CMP_ASSERT_REGISTRY_LOCK(); - - /* Get hash indexes */ - Index1 = GET_HASH_INDEX(ConvKey1); - Index2 = GET_HASH_INDEX(ConvKey2); - - /* See which one is highest */ - if (Index1 < Index2) - { - /* Grab them in the proper order */ - CmpAcquireKcbLockExclusiveByKey(ConvKey1); - CmpAcquireKcbLockExclusiveByKey(ConvKey2); - } - else - { - /* Grab the second one first, then the first */ - CmpAcquireKcbLockExclusiveByKey(ConvKey2); - if (Index1 != Index2) CmpAcquireKcbLockExclusiveByKey(ConvKey1); - } -} - -VOID -NTAPI -CmpReleaseTwoKcbLockByKey(IN ULONG ConvKey1, - IN ULONG ConvKey2) -{ - ULONG Index1, Index2; - - /* Sanity check */ - CMP_ASSERT_REGISTRY_LOCK(); - - /* Get hash indexes */ - Index1 = GET_HASH_INDEX(ConvKey1); - Index2 = GET_HASH_INDEX(ConvKey2); - ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey2).Owner == KeGetCurrentThread()) || - (CmpTestRegistryLockExclusive())); - - /* See which one is highest */ - if (Index1 < Index2) - { - /* Grab them in the proper order */ - ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1).Owner == KeGetCurrentThread()) || - (CmpTestRegistryLockExclusive())); - CmpReleaseKcbLockByKey(ConvKey2); - CmpReleaseKcbLockByKey(ConvKey1); - } - else - { - /* Release the first one first, then the second */ - if (Index1 != Index2) - { - ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1).Owner == KeGetCurrentThread()) || - (CmpTestRegistryLockExclusive())); - CmpReleaseKcbLockByKey(ConvKey1); - } - CmpReleaseKcbLockByKey(ConvKey2); - } -} - -VOID -NTAPI -CmShutdownSystem(VOID) -{ - /* Kill the workers and fush all hives */ - CmpShutdownWorkers(); - CmpDoFlushAll(TRUE); -} +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmsysini.c + * PURPOSE: Configuration Manager - System Initialization Code + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#define NDEBUG +#include "debug.h" + +POBJECT_TYPE CmpKeyObjectType; +PCMHIVE CmiVolatileHive; +LIST_ENTRY CmpHiveListHead; +ERESOURCE CmpRegistryLock; +KGUARDED_MUTEX CmpSelfHealQueueLock; +LIST_ENTRY CmpSelfHealQueueListHead; +KEVENT CmpLoadWorkerEvent; +LONG CmpLoadWorkerIncrement; +PEPROCESS CmpSystemProcess; +BOOLEAN HvShutdownComplete; +PVOID CmpRegistryLockCallerCaller, CmpRegistryLockCaller; +BOOLEAN CmpFlushStarveWriters; +BOOLEAN CmpFlushOnLockRelease; +BOOLEAN CmpSpecialBootCondition; +BOOLEAN CmpNoWrite; +BOOLEAN CmpForceForceFlush; +BOOLEAN CmpWasSetupBoot; + +/* FUNCTIONS *****************************************************************/ + +VOID +NTAPI +CmpDeleteKeyObject(PVOID DeletedObject) +{ + PCM_KEY_BODY KeyBody = (PCM_KEY_BODY)DeletedObject; + PCM_KEY_CONTROL_BLOCK Kcb; + REG_KEY_HANDLE_CLOSE_INFORMATION KeyHandleCloseInfo; + REG_POST_OPERATION_INFORMATION PostOperationInfo; + NTSTATUS Status; + PAGED_CODE(); + + /* First off, prepare the handle close information callback */ + PostOperationInfo.Object = KeyBody; + KeyHandleCloseInfo.Object = KeyBody; + Status = CmiCallRegisteredCallbacks(RegNtPreKeyHandleClose, + &KeyHandleCloseInfo); + if (!NT_SUCCESS(Status)) + { + /* If we failed, notify the post routine */ + PostOperationInfo.Status = Status; + CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose, &PostOperationInfo); + return; + } + + /* Acquire hive lock */ + CmpLockRegistry(); + + /* Make sure this is a valid key body */ + if (KeyBody->Type == TAG('k', 'y', '0', '2')) + { + /* Get the KCB */ + Kcb = KeyBody->KeyControlBlock; + if (Kcb) + { + /* Delist the key (once new parse routines are used) */ + //DelistKeyBodyFromKCB(KeyBody, FALSE); + } + + /* Dereference the KCB */ + CmpDelayDerefKeyControlBlock(Kcb); + + } + + /* Release the registry lock */ + CmpUnlockRegistry(); + + /* Do the post callback */ + PostOperationInfo.Status = STATUS_SUCCESS; + CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose, &PostOperationInfo); +} + +VOID +NTAPI +CmpCloseKeyObject(IN PEPROCESS Process OPTIONAL, + IN PVOID Object, + IN ACCESS_MASK GrantedAccess, + IN ULONG ProcessHandleCount, + IN ULONG SystemHandleCount) +{ + PCM_KEY_BODY KeyBody = (PCM_KEY_BODY)Object; + PAGED_CODE(); + + /* Don't do anything if we're not the last handle */ + if (SystemHandleCount > 1) return; + + /* Make sure we're a valid key body */ + if (KeyBody->Type == TAG('k', 'y', '0', '2')) + { + /* Don't do anything if we don't have a notify block */ + if (!KeyBody->NotifyBlock) return; + + /* This shouldn't happen yet */ + ASSERT(FALSE); + } +} + +NTSTATUS +NTAPI +CmpQueryKeyName(IN PVOID ObjectBody, + IN BOOLEAN HasName, + IN OUT POBJECT_NAME_INFORMATION ObjectNameInfo, + IN ULONG Length, + OUT PULONG ReturnLength, + IN KPROCESSOR_MODE PreviousMode) +{ + DPRINT1("CmpQueryKeyName() called\n"); + while (TRUE); + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +CmpInitHiveFromFile(IN PCUNICODE_STRING HiveName, + IN ULONG HiveFlags, + OUT PCMHIVE *Hive, + IN OUT PBOOLEAN New, + IN ULONG CheckFlags) +{ + ULONG HiveDisposition, LogDisposition; + HANDLE FileHandle = NULL, LogHandle = NULL; + NTSTATUS Status; + ULONG Operation, FileType; + PCMHIVE NewHive; + PAGED_CODE(); + + /* Assume failure */ + *Hive = NULL; + + /* Open or create the hive files */ + Status = CmpOpenHiveFiles(HiveName, + L".LOG", + &FileHandle, + &LogHandle, + &HiveDisposition, + &LogDisposition, + *New, + FALSE, + TRUE, + NULL); + if (!NT_SUCCESS(Status)) return Status; + + /* Check if we have a log handle */ + FileType = (LogHandle) ? HFILE_TYPE_LOG : HFILE_TYPE_PRIMARY; + + /* Check if we created or opened the hive */ + if (HiveDisposition == FILE_CREATED) + { + /* Do a create operation */ + Operation = HINIT_CREATE; + *New = TRUE; + } + else + { + /* Open it as a file */ + Operation = HINIT_FILE; + *New = FALSE; + } + + /* Check if we're sharing hives */ + if (CmpShareSystemHives) + { + /* Then force using the primary hive */ + FileType = HFILE_TYPE_PRIMARY; + if (LogHandle) + { + /* Get rid of the log handle */ + ZwClose(LogHandle); + LogHandle = NULL; + } + } + + /* Check if we're too late */ + if (HvShutdownComplete) + { + /* Fail */ + ZwClose(FileHandle); + if (LogHandle) ZwClose(LogHandle); + return STATUS_TOO_LATE; + } + + /* Initialize the hive */ + Status = CmpInitializeHive((PCMHIVE*)&NewHive, + Operation, + HiveFlags, + FileType, + NULL, + FileHandle, + LogHandle, + NULL, + HiveName, + 0); + if (!NT_SUCCESS(Status)) + { + /* Fail */ + ZwClose(FileHandle); + if (LogHandle) ZwClose(LogHandle); + return Status; + } + + /* Success, return hive */ + *Hive = NewHive; + + /* ROS: Init root key cell and prepare the hive */ + if (Operation == HINIT_CREATE) CmCreateRootNode(&NewHive->Hive, L""); + CmPrepareHive(&NewHive->Hive); + + /* Duplicate the hive name */ + NewHive->FileFullPath.Buffer = ExAllocatePoolWithTag(PagedPool, + HiveName->Length, + TAG_CM); + if (NewHive->FileFullPath.Buffer) + { + /* Copy the string */ + RtlCopyMemory(NewHive->FileFullPath.Buffer, + HiveName->Buffer, + HiveName->Length); + NewHive->FileFullPath.Length = HiveName->Length; + NewHive->FileFullPath.MaximumLength = HiveName->MaximumLength; + } + + /* Return success */ + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +CmpSetSystemValues(IN PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING KeyName, ValueName = {0}; + HANDLE KeyHandle; + NTSTATUS Status; + ASSERT(LoaderBlock != NULL); + + /* Setup attributes for loader options */ + RtlInitUnicodeString(&KeyName, + L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\" + L"Control"); + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + Status = NtOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes); + if (!NT_SUCCESS(Status)) goto Quickie; + + /* Key opened, now write to the key */ + RtlInitUnicodeString(&KeyName, L"SystemStartOptions"); + Status = NtSetValueKey(KeyHandle, + &KeyName, + 0, + REG_SZ, + CmpLoadOptions.Buffer, + CmpLoadOptions.Length); + if (!NT_SUCCESS(Status)) goto Quickie; + + /* Setup value name for system boot device */ + RtlInitUnicodeString(&KeyName, L"SystemBootDevice"); + RtlCreateUnicodeStringFromAsciiz(&ValueName, LoaderBlock->NtBootPathName); + Status = NtSetValueKey(KeyHandle, + &KeyName, + 0, + REG_SZ, + ValueName.Buffer, + ValueName.Length); + +Quickie: + /* Free the buffers */ + RtlFreeUnicodeString(&ValueName); + + /* Close the key and return */ + NtClose(KeyHandle); + + /* Return the status */ + return (ExpInTextModeSetup ? STATUS_SUCCESS : Status); +} + +NTSTATUS +NTAPI +CmpCreateControlSet(IN PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + UNICODE_STRING ConfigName = RTL_CONSTANT_STRING(L"Control\\IDConfigDB"); + UNICODE_STRING SelectName = + RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\Select"); + UNICODE_STRING KeyName; + OBJECT_ATTRIBUTES ObjectAttributes; + CHAR ValueInfoBuffer[128]; + PKEY_VALUE_FULL_INFORMATION ValueInfo; + CHAR Buffer[128]; + WCHAR UnicodeBuffer[128]; + HANDLE SelectHandle, KeyHandle, ConfigHandle = NULL, ProfileHandle = NULL; + HANDLE ParentHandle = NULL; + ULONG ControlSet, HwProfile; + ANSI_STRING TempString; + NTSTATUS Status; + ULONG ResultLength, Disposition; + PLOADER_PARAMETER_EXTENSION LoaderExtension; + PAGED_CODE(); + + /* Open the select key */ + InitializeObjectAttributes(&ObjectAttributes, + &SelectName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + Status = NtOpenKey(&SelectHandle, KEY_READ, &ObjectAttributes); + if (!NT_SUCCESS(Status)) + { + /* ReactOS Hack: Hard-code current to 001 for SetupLdr */ + if (!LoaderBlock->RegistryBase) + { + /* Build the ControlSet001 key */ + RtlInitUnicodeString(&KeyName, + L"\\Registry\\Machine\\System\\ControlSet001"); + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + Status = NtCreateKey(&KeyHandle, + KEY_ALL_ACCESS, + &ObjectAttributes, + 0, + NULL, + 0, + &Disposition); + if (!NT_SUCCESS(Status)) return Status; + + /* Don't need the handle */ + ZwClose(KeyHandle); + + /* Use hard-coded setting */ + ControlSet = 1; + goto UseSet; + } + + /* Fail for real boots */ + return Status; + } + + /* Open the current value */ + RtlInitUnicodeString(&KeyName, L"Current"); + Status = NtQueryValueKey(SelectHandle, + &KeyName, + KeyValueFullInformation, + ValueInfoBuffer, + sizeof(ValueInfoBuffer), + &ResultLength); + NtClose(SelectHandle); + if (!NT_SUCCESS(Status)) return Status; + + /* Get the actual value pointer, and get the control set ID */ + ValueInfo = (PKEY_VALUE_FULL_INFORMATION)ValueInfoBuffer; + ControlSet = *(PULONG)((PUCHAR)ValueInfo + ValueInfo->DataOffset); + + /* Create the current control set key */ +UseSet: + RtlInitUnicodeString(&KeyName, + L"\\Registry\\Machine\\System\\CurrentControlSet"); + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + Status = NtCreateKey(&KeyHandle, + KEY_CREATE_LINK, + &ObjectAttributes, + 0, + NULL, + REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK, + &Disposition); + if (!NT_SUCCESS(Status)) return Status; + + /* Sanity check */ + ASSERT(Disposition == REG_CREATED_NEW_KEY); + + /* Initialize the symbolic link name */ + sprintf(Buffer, + "\\Registry\\Machine\\System\\ControlSet%03ld", + ControlSet); + RtlInitAnsiString(&TempString, Buffer); + + /* Create a Unicode string out of it */ + KeyName.MaximumLength = sizeof(UnicodeBuffer); + KeyName.Buffer = UnicodeBuffer; + Status = RtlAnsiStringToUnicodeString(&KeyName, &TempString, FALSE); + + /* Set the value */ + Status = NtSetValueKey(KeyHandle, + &CmSymbolicLinkValueName, + 0, + REG_LINK, + KeyName.Buffer, + KeyName.Length); + if (!NT_SUCCESS(Status)) return Status; + + /* Get the configuration database key */ + InitializeObjectAttributes(&ObjectAttributes, + &ConfigName, + OBJ_CASE_INSENSITIVE, + KeyHandle, + NULL); + Status = NtOpenKey(&ConfigHandle, KEY_READ, &ObjectAttributes); + NtClose(KeyHandle); + + /* Check if we don't have one */ + if (!NT_SUCCESS(Status)) + { + /* Cleanup and exit */ + ConfigHandle = 0; + goto Cleanup; + } + + /* Now get the current config */ + RtlInitUnicodeString(&KeyName, L"CurrentConfig"); + Status = NtQueryValueKey(ConfigHandle, + &KeyName, + KeyValueFullInformation, + ValueInfoBuffer, + sizeof(ValueInfoBuffer), + &ResultLength); + + /* Set pointer to buffer */ + ValueInfo = (PKEY_VALUE_FULL_INFORMATION)ValueInfoBuffer; + + /* Check if we failed or got a non DWORD-value */ + if (!(NT_SUCCESS(Status)) || (ValueInfo->Type != REG_DWORD)) goto Cleanup; + + /* Get the hadware profile */ + HwProfile = *(PULONG)((PUCHAR)ValueInfo + ValueInfo->DataOffset); + + /* Open the hardware profile key */ + RtlInitUnicodeString(&KeyName, + L"\\Registry\\Machine\\System\\CurrentControlSet" + L"\\Hardware Profiles"); + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + Status = NtOpenKey(&ParentHandle, KEY_READ, &ObjectAttributes); + if (!NT_SUCCESS(Status)) + { + /* Exit and clean up */ + ParentHandle = 0; + goto Cleanup; + } + + /* Build the profile name */ + sprintf(Buffer, "%04ld", HwProfile); + RtlInitAnsiString(&TempString, Buffer); + + /* Convert it to Unicode */ + KeyName.MaximumLength = sizeof(UnicodeBuffer); + KeyName.Buffer = UnicodeBuffer; + Status = RtlAnsiStringToUnicodeString(&KeyName, + &TempString, + FALSE); + ASSERT(Status == STATUS_SUCCESS); + + /* Open the associated key */ + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + ParentHandle, + NULL); + Status = NtOpenKey(&ProfileHandle, + KEY_READ | KEY_WRITE, + &ObjectAttributes); + if (!NT_SUCCESS (Status)) + { + /* Cleanup and exit */ + ProfileHandle = 0; + goto Cleanup; + } + + /* Check if we have a loader block extension */ + LoaderExtension = LoaderBlock->Extension; + if (LoaderExtension) + { + ASSERTMSG("ReactOS doesn't support NTLDR Profiles yet!\n", FALSE); + } + + /* Create the current hardware profile key */ + RtlInitUnicodeString(&KeyName, + L"\\Registry\\Machine\\System\\CurrentControlSet\\" + L"Hardware Profiles\\Current"); + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + Status = NtCreateKey(&KeyHandle, + KEY_CREATE_LINK, + &ObjectAttributes, + 0, + NULL, + REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK, + &Disposition); + if (NT_SUCCESS(Status)) + { + /* Sanity check */ + ASSERT(Disposition == REG_CREATED_NEW_KEY); + + /* Create the profile name */ + sprintf(Buffer, + "\\Registry\\Machine\\System\\CurrentControlSet\\" + "Hardware Profiles\\%04ld", + HwProfile); + RtlInitAnsiString(&TempString, Buffer); + + /* Convert it to Unicode */ + KeyName.MaximumLength = sizeof(UnicodeBuffer); + KeyName.Buffer = UnicodeBuffer; + Status = RtlAnsiStringToUnicodeString(&KeyName, + &TempString, + FALSE); + ASSERT(STATUS_SUCCESS == Status); + + /* Set it */ + Status = NtSetValueKey(KeyHandle, + &CmSymbolicLinkValueName, + 0, + REG_LINK, + KeyName.Buffer, + KeyName.Length); + NtClose(KeyHandle); + } + + /* Close every opened handle */ +Cleanup: + if (ConfigHandle) NtClose(ConfigHandle); + if (ProfileHandle) NtClose(ProfileHandle); + if (ParentHandle) NtClose(ParentHandle); + + /* Return success */ + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +CmpLinkHiveToMaster(IN PUNICODE_STRING LinkName, + IN HANDLE RootDirectory, + IN PCMHIVE RegistryHive, + IN BOOLEAN Allocate, + IN PSECURITY_DESCRIPTOR SecurityDescriptor) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + NTSTATUS Status; + CM_PARSE_CONTEXT ParseContext = {0}; + HANDLE KeyHandle; + PCM_KEY_BODY KeyBody; + PAGED_CODE(); + + /* Setup the object attributes */ + InitializeObjectAttributes(&ObjectAttributes, + LinkName, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + RootDirectory, + SecurityDescriptor); + + /* Setup the parse context */ + ParseContext.CreateLink = TRUE; + ParseContext.CreateOperation = TRUE; + ParseContext.ChildHive.KeyHive = &RegistryHive->Hive; + + /* Check if we have a root keycell or if we need to create it */ + if (Allocate) + { + /* Create it */ + ParseContext.ChildHive.KeyCell = HCELL_NIL; + } + else + { + /* We have one */ + ParseContext.ChildHive.KeyCell = RegistryHive->Hive.BaseBlock->RootCell; + } + + /* Create the link node */ + Status = ObOpenObjectByName(&ObjectAttributes, + CmpKeyObjectType, + KernelMode, + NULL, + KEY_READ | KEY_WRITE, + (PVOID)&ParseContext, + &KeyHandle); + if (!NT_SUCCESS(Status)) return Status; + + /* Mark the hive as clean */ + RegistryHive->Hive.DirtyFlag = FALSE; + + /* ReactOS Hack: Keep alive */ + Status = ObReferenceObjectByHandle(KeyHandle, + 0, + CmpKeyObjectType, + KernelMode, + (PVOID*)&KeyBody, + NULL); + ASSERT(NT_SUCCESS(Status)); + + /* Close the extra handle */ + ZwClose(KeyHandle); + return STATUS_SUCCESS; +} + +BOOLEAN +NTAPI +CmpInitializeSystemHive(IN PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + PVOID HiveBase; + ANSI_STRING LoadString; + PVOID Buffer; + ULONG Length; + NTSTATUS Status; + BOOLEAN Allocate; + UNICODE_STRING KeyName; + PCMHIVE SystemHive = NULL; + UNICODE_STRING HiveName = RTL_CONSTANT_STRING(L"SYSTEM"); + PSECURITY_DESCRIPTOR SecurityDescriptor; + PAGED_CODE(); + + /* Setup the ansi string */ + RtlInitAnsiString(&LoadString, LoaderBlock->LoadOptions); + + /* Allocate the unicode buffer */ + Length = LoadString.Length * sizeof(WCHAR) + sizeof(UNICODE_NULL); + Buffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM); + if (!Buffer) + { + /* Fail */ + KEBUGCHECKEX(BAD_SYSTEM_CONFIG_INFO, 3, 1, (ULONG_PTR)LoaderBlock, 0); + } + + /* Setup the unicode string */ + RtlInitEmptyUnicodeString(&CmpLoadOptions, Buffer, (USHORT)Length); + + /* Add the load options and null-terminate */ + RtlAnsiStringToUnicodeString(&CmpLoadOptions, &LoadString, FALSE); + CmpLoadOptions.Buffer[LoadString.Length] = UNICODE_NULL; + CmpLoadOptions.Length += sizeof(WCHAR); + + /* Get the System Hive base address */ + HiveBase = LoaderBlock->RegistryBase; + if (HiveBase) + { + /* Import it */ + ((PHBASE_BLOCK)HiveBase)->Length = LoaderBlock->RegistryLength; + Status = CmpInitializeHive((PCMHIVE*)&SystemHive, + HINIT_MEMORY, + HIVE_NOLAZYFLUSH, + HFILE_TYPE_LOG, + HiveBase, + NULL, + NULL, + NULL, + &HiveName, + 2); + if (!NT_SUCCESS(Status)) return FALSE; + CmPrepareHive(&SystemHive->Hive); + + /* Set the hive filename */ + RtlCreateUnicodeString(&SystemHive->FileFullPath, + L"\\SystemRoot\\System32\\Config\\SYSTEM"); + + /* We imported, no need to create a new hive */ + Allocate = FALSE; + + /* Manually set the hive as volatile, if in Live CD mode */ + if (CmpShareSystemHives) SystemHive->Hive.HiveFlags = HIVE_VOLATILE; + } + else + { + /* Create it */ + Status = CmpInitializeHive(&SystemHive, + HINIT_CREATE, + HIVE_NOLAZYFLUSH, + HFILE_TYPE_LOG, + NULL, + NULL, + NULL, + NULL, + &HiveName, + 0); + if (!NT_SUCCESS(Status)) return FALSE; + + /* Set the hive filename */ + RtlCreateUnicodeString(&SystemHive->FileFullPath, + L"\\SystemRoot\\System32\\Config\\SYSTEM"); + + /* Tell CmpLinkHiveToMaster to allocate a hive */ + Allocate = TRUE; + } + + /* Save the boot type */ + if (SystemHive) CmpBootType = SystemHive->Hive.BaseBlock->BootType; + + /* Are we in self-healing mode? */ + if (!CmSelfHeal) + { + /* Disable self-healing internally and check if boot type wanted it */ + CmpSelfHeal = FALSE; + if (CmpBootType & 4) + { + /* We're disabled, so bugcheck */ + KEBUGCHECKEX(BAD_SYSTEM_CONFIG_INFO, + 3, + 3, + (ULONG_PTR)SystemHive, + 0); + } + } + + /* Create the default security descriptor */ + SecurityDescriptor = CmpHiveRootSecurityDescriptor(); + + /* Attach it to the system key */ + RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\SYSTEM"); + Status = CmpLinkHiveToMaster(&KeyName, + NULL, + (PCMHIVE)SystemHive, + Allocate, + SecurityDescriptor); + + /* Free the security descriptor */ + ExFreePool(SecurityDescriptor); + if (!NT_SUCCESS(Status)) return FALSE; + + /* Add the hive to the hive list */ + CmpMachineHiveList[3].CmHive = (PCMHIVE)SystemHive; + + /* Success! */ + return TRUE; +} + +NTSTATUS +NTAPI +CmpCreateObjectTypes(VOID) +{ + OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; + UNICODE_STRING Name; + GENERIC_MAPPING CmpKeyMapping = {KEY_READ, + KEY_WRITE, + KEY_EXECUTE, + KEY_ALL_ACCESS}; + PAGED_CODE(); + + /* Initialize the Key object type */ + RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); + RtlInitUnicodeString(&Name, L"Key"); + ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); + ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(CM_KEY_BODY); + ObjectTypeInitializer.GenericMapping = CmpKeyMapping; + ObjectTypeInitializer.PoolType = PagedPool; + ObjectTypeInitializer.ValidAccessMask = KEY_ALL_ACCESS; + ObjectTypeInitializer.UseDefaultObject = TRUE; + ObjectTypeInitializer.DeleteProcedure = CmpDeleteKeyObject; + ObjectTypeInitializer.ParseProcedure = CmpParseKey; + ObjectTypeInitializer.SecurityProcedure = CmpSecurityMethod; + ObjectTypeInitializer.QueryNameProcedure = CmpQueryKeyName; + ObjectTypeInitializer.CloseProcedure = CmpCloseKeyObject; + ObjectTypeInitializer.SecurityRequired = TRUE; + + /* Create it */ + return ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &CmpKeyObjectType); +} + +BOOLEAN +NTAPI +CmpCreateRootNode(IN PHHIVE Hive, + IN PCWSTR Name, + OUT PHCELL_INDEX Index) +{ + UNICODE_STRING KeyName; + PCM_KEY_NODE KeyCell; + LARGE_INTEGER SystemTime; + PAGED_CODE(); + + /* Initialize the node name and allocate it */ + RtlInitUnicodeString(&KeyName, Name); + *Index = HvAllocateCell(Hive, + FIELD_OFFSET(CM_KEY_NODE, Name) + + CmpNameSize(Hive, &KeyName), + Stable, + HCELL_NIL); + if (*Index == HCELL_NIL) return FALSE; + + /* Set the cell index and get the data */ + Hive->BaseBlock->RootCell = *Index; + KeyCell = (PCM_KEY_NODE)HvGetCell(Hive, *Index); + if (!KeyCell) return FALSE; + + /* Setup the cell */ + KeyCell->Signature = (USHORT)CM_KEY_NODE_SIGNATURE; + KeyCell->Flags = KEY_HIVE_ENTRY | KEY_NO_DELETE; + KeQuerySystemTime(&SystemTime); + KeyCell->LastWriteTime = SystemTime; + KeyCell->Parent = HCELL_NIL; + KeyCell->SubKeyCounts[Stable] = 0; + KeyCell->SubKeyCounts[Volatile] = 0; + KeyCell->SubKeyLists[Stable] = HCELL_NIL; + KeyCell->SubKeyLists[Volatile] = HCELL_NIL; + KeyCell->ValueList.Count = 0; + KeyCell->ValueList.List = HCELL_NIL; + KeyCell->Security = HCELL_NIL; + KeyCell->Class = HCELL_NIL; + KeyCell->ClassLength = 0; + KeyCell->MaxNameLen = 0; + KeyCell->MaxClassLen = 0; + KeyCell->MaxValueNameLen = 0; + KeyCell->MaxValueDataLen = 0; + + /* Copy the name (this will also set the length) */ + KeyCell->NameLength = CmpCopyName(Hive, (PWCHAR)KeyCell->Name, &KeyName); + + /* Check if the name was compressed */ + if (KeyCell->NameLength < KeyName.Length) + { + /* Set the flag */ + KeyCell->Flags |= KEY_COMP_NAME; + } + + /* Return success */ + HvReleaseCell(Hive, *Index); + return TRUE; +} + +BOOLEAN +NTAPI +CmpCreateRegistryRoot(VOID) +{ + UNICODE_STRING KeyName; + OBJECT_ATTRIBUTES ObjectAttributes; + PCM_KEY_BODY RootKey; + HCELL_INDEX RootIndex; + NTSTATUS Status; + PCM_KEY_NODE KeyCell; + PSECURITY_DESCRIPTOR SecurityDescriptor; + PCM_KEY_CONTROL_BLOCK Kcb; + PAGED_CODE(); + + /* Setup the root node */ + if (!CmpCreateRootNode(&CmiVolatileHive->Hive, L"REGISTRY", &RootIndex)) + { + /* We failed */ + return FALSE; + } + + /* Create '\Registry' key. */ + RtlInitUnicodeString(&KeyName, L"\\Registry"); + SecurityDescriptor = CmpHiveRootSecurityDescriptor(); + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + Status = ObCreateObject(KernelMode, + CmpKeyObjectType, + &ObjectAttributes, + KernelMode, + NULL, + sizeof(CM_KEY_BODY), + 0, + 0, + (PVOID*)&RootKey); + ExFreePool(SecurityDescriptor); + if (!NT_SUCCESS(Status)) return FALSE; + + /* Sanity check, and get the key cell */ + ASSERT((&CmiVolatileHive->Hive)->ReleaseCellRoutine == NULL); + KeyCell = (PCM_KEY_NODE)HvGetCell(&CmiVolatileHive->Hive, RootIndex); + if (!KeyCell) return FALSE; + + /* Create the KCB */ + RtlInitUnicodeString(&KeyName, L"Registry"); + Kcb = CmpCreateKeyControlBlock(&CmiVolatileHive->Hive, + RootIndex, + KeyCell, + NULL, + 0, + &KeyName); + if (!Kcb) return FALSE; + + /* Initialize the object */ + RootKey->KeyControlBlock = Kcb; + RootKey->Type = TAG('k', 'y', '0', '2'); + RootKey->NotifyBlock = NULL; + RootKey->ProcessID = PsGetCurrentProcessId(); + + /* Link with KCB */ + EnlistKeyBodyWithKCB(RootKey, 0); + + /* Insert the key into the namespace */ + Status = ObInsertObject(RootKey, + NULL, + KEY_ALL_ACCESS, + 0, + NULL, + &CmpRegistryRootHandle); + if (!NT_SUCCESS(Status)) return FALSE; + + /* Reference the key again so that we never lose it */ + Status = ObReferenceObjectByHandle(CmpRegistryRootHandle, + KEY_READ, + NULL, + KernelMode, + (PVOID*)&RootKey, + NULL); + if (!NT_SUCCESS(Status)) return FALSE; + + /* Completely sucessful */ + return TRUE; +} + +NTSTATUS +NTAPI +CmpGetRegistryPath(IN PWCHAR ConfigPath) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + NTSTATUS Status; + HANDLE KeyHandle; + PKEY_VALUE_PARTIAL_INFORMATION ValueInfo; + UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE"); + UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"InstallPath"); + ULONG BufferSize, ResultSize; + + /* Check if we are booted in setup */ + if (ExpInTextModeSetup) + { + /* Setup the object attributes */ + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + /* Open the key */ + Status = ZwOpenKey(&KeyHandle, + KEY_ALL_ACCESS, + &ObjectAttributes); + if (!NT_SUCCESS(Status)) return Status; + + /* Allocate the buffer */ + BufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4096; + ValueInfo = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_CM); + if (!ValueInfo) + { + /* Fail */ + ZwClose(KeyHandle); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Query the value */ + Status = ZwQueryValueKey(KeyHandle, + &ValueName, + KeyValuePartialInformation, + ValueInfo, + BufferSize, + &ResultSize); + ZwClose(KeyHandle); + if (!NT_SUCCESS(Status)) + { + /* Fail */ + ExFreePool(ValueInfo); + return Status; + } + + /* Copy the config path and null-terminate it */ + RtlCopyMemory(ConfigPath, + ValueInfo->Data, + ValueInfo->DataLength); + ConfigPath[ValueInfo->DataLength / sizeof(WCHAR)] = UNICODE_NULL; + ExFreePool(ValueInfo); + } + else + { + /* Just use default path */ + wcscpy(ConfigPath, L"\\SystemRoot"); + } + + /* Add registry path */ + wcscat(ConfigPath, L"\\System32\\Config\\"); + + /* Done */ + return STATUS_SUCCESS; +} + +VOID +NTAPI +CmpLoadHiveThread(IN PVOID StartContext) +{ + WCHAR FileBuffer[MAX_PATH], RegBuffer[MAX_PATH], ConfigPath[MAX_PATH]; + UNICODE_STRING TempName, FileName, RegName; + ULONG FileStart, RegStart, i, ErrorResponse, WorkerCount, Length; + ULONG PrimaryDisposition, SecondaryDisposition, ClusterSize; + PCMHIVE CmHive; + HANDLE PrimaryHandle, LogHandle; + NTSTATUS Status = STATUS_SUCCESS; + PVOID ErrorParameters; + PAGED_CODE(); + + /* Get the hive index, make sure it makes sense */ + i = (ULONG)StartContext; + ASSERT(CmpMachineHiveList[i].Name != NULL); + + /* We were started */ + CmpMachineHiveList[i].ThreadStarted = TRUE; + + /* Build the file name and registry name strings */ + RtlInitEmptyUnicodeString(&FileName, FileBuffer, MAX_PATH); + RtlInitEmptyUnicodeString(&RegName, RegBuffer, MAX_PATH); + + /* Now build the system root path */ + CmpGetRegistryPath(ConfigPath); + RtlInitUnicodeString(&TempName, ConfigPath); + RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName); + FileStart = FileName.Length; + + /* And build the registry root path */ + RtlInitUnicodeString(&TempName, L"\\REGISTRY\\"); + RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName); + RegStart = RegName.Length; + + /* Build the base name */ + RegName.Length = RegStart; + RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName); + RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName); + + /* Check if this is a child of the root */ + if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == '\\') + { + /* Then setup the whole name */ + RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name); + RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName); + } + + /* Now Add tge rest if the file name */ + RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name); + FileName.Length = FileStart; + RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName); + if (!CmpMachineHiveList[i].CmHive) + { + /* We need to allocate a new hive structure */ + CmpMachineHiveList[i].Allocate = TRUE; + + /* Load the hive file */ + Status = CmpInitHiveFromFile(&FileName, + CmpMachineHiveList[i].HHiveFlags, + &CmHive, + &CmpMachineHiveList[i].Allocate, + 0); + if (!(NT_SUCCESS(Status)) || + (!(CmHive->FileHandles[HFILE_TYPE_LOG]) && !(CmpMiniNTBoot))) // hak + { + /* We failed or couldn't get a log file, raise a hard error */ + ErrorParameters = &FileName; + NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE, + 1, + 1, + (PULONG_PTR)&ErrorParameters, + OptionOk, + &ErrorResponse); + } + + /* Set the hive flags and newly allocated hive pointer */ + CmHive->Flags = CmpMachineHiveList[i].CmHiveFlags; + CmpMachineHiveList[i].CmHive2 = CmHive; + } + else + { + /* We already have a hive, is it volatile? */ + CmHive = CmpMachineHiveList[i].CmHive; + if (!(CmHive->Hive.HiveFlags & HIVE_VOLATILE)) + { + /* It's now, open the hive file and log */ + Status = CmpOpenHiveFiles(&FileName, + L".LOG", + &PrimaryHandle, + &LogHandle, + &PrimaryDisposition, + &SecondaryDisposition, + TRUE, + TRUE, + FALSE, + &ClusterSize); + if (!(NT_SUCCESS(Status)) || !(LogHandle)) + { + /* Couldn't open the hive or its log file, raise a hard error */ + ErrorParameters = &FileName; + NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE, + 1, + 1, + (PULONG_PTR)&ErrorParameters, + OptionOk, + &ErrorResponse); + + /* And bugcheck for posterity's sake */ + KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 0, i, Status); + } + + /* Save the file handles. This should remove our sync hacks */ + CmHive->FileHandles[HFILE_TYPE_LOG] = LogHandle; + CmHive->FileHandles[HFILE_TYPE_PRIMARY] = PrimaryHandle; + + /* Allow lazy flushing since the handles are there -- remove sync hacks */ + //ASSERT(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH); + CmHive->Hive.HiveFlags &= ~HIVE_NOLAZYFLUSH; + + /* Get the real size of the hive */ + Length = CmHive->Hive.Storage[Stable].Length + HBLOCK_SIZE; + + /* Check if the cluster size doesn't match */ + if (CmHive->Hive.Cluster != ClusterSize) ASSERT(FALSE); + + /* Set the file size */ + //if (!CmpFileSetSize((PHHIVE)CmHive, HFILE_TYPE_PRIMARY, Length, Length)) + { + /* This shouldn't fail */ + //ASSERT(FALSE); + } + + /* Another thing we don't support is NTLDR-recovery */ + if (CmHive->Hive.BaseBlock->BootRecover) ASSERT(FALSE); + + /* Finally, set our allocated hive to the same hive we've had */ + CmpMachineHiveList[i].CmHive2 = CmHive; + ASSERT(CmpMachineHiveList[i].CmHive == CmpMachineHiveList[i].CmHive2); + } + } + + /* We're done */ + CmpMachineHiveList[i].ThreadFinished = TRUE; + + /* Check if we're the last worker */ + WorkerCount = InterlockedIncrement(&CmpLoadWorkerIncrement); + if (WorkerCount == CM_NUMBER_OF_MACHINE_HIVES) + { + /* Signal the event */ + KeSetEvent(&CmpLoadWorkerEvent, 0, FALSE); + } + + /* Kill the thread */ + PsTerminateSystemThread(Status); +} + +VOID +NTAPI +CmpInitializeHiveList(IN USHORT Flag) +{ + WCHAR FileBuffer[MAX_PATH], RegBuffer[MAX_PATH], ConfigPath[MAX_PATH]; + UNICODE_STRING TempName, FileName, RegName; + HANDLE Thread; + NTSTATUS Status; + ULONG FileStart, RegStart, i; + PSECURITY_DESCRIPTOR SecurityDescriptor; + PAGED_CODE(); + + /* Allow writing for now */ + CmpNoWrite = FALSE; + + /* Build the file name and registry name strings */ + RtlInitEmptyUnicodeString(&FileName, FileBuffer, MAX_PATH); + RtlInitEmptyUnicodeString(&RegName, RegBuffer, MAX_PATH); + + /* Now build the system root path */ + CmpGetRegistryPath(ConfigPath); + RtlInitUnicodeString(&TempName, ConfigPath); + RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName); + FileStart = FileName.Length; + + /* And build the registry root path */ + RtlInitUnicodeString(&TempName, L"\\REGISTRY\\"); + RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName); + RegStart = RegName.Length; + + /* Setup the event to synchronize workers */ + KeInitializeEvent(&CmpLoadWorkerEvent, SynchronizationEvent, FALSE); + + /* Enter special boot condition */ + CmpSpecialBootCondition = TRUE; + + /* Create the SD for the root hives */ + SecurityDescriptor = CmpHiveRootSecurityDescriptor(); + + /* Loop every hive we care about */ + for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++) + { + /* Make sure the list is setup */ + ASSERT(CmpMachineHiveList[i].Name != NULL); + + /* Create a thread to handle this hive */ + Status = PsCreateSystemThread(&Thread, + THREAD_ALL_ACCESS, + NULL, + 0, + NULL, + CmpLoadHiveThread, + (PVOID)i); + if (NT_SUCCESS(Status)) + { + /* We don't care about the handle -- the thread self-terminates */ + ZwClose(Thread); + } + else + { + /* Can't imagine this happening */ + KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 3, i, Status); + } + } + + /* Make sure we've reached the end of the list */ + ASSERT(CmpMachineHiveList[i].Name == NULL); + + /* Wait for hive loading to finish */ + KeWaitForSingleObject(&CmpLoadWorkerEvent, + Executive, + KernelMode, + FALSE, + NULL); + + /* Exit the special boot condition and make sure all workers completed */ + CmpSpecialBootCondition = FALSE; + ASSERT(CmpLoadWorkerIncrement == CM_NUMBER_OF_MACHINE_HIVES); + + /* Loop hives again */ + for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++) + { + /* Make sure the thread ran and finished */ + ASSERT(CmpMachineHiveList[i].ThreadFinished == TRUE); + ASSERT(CmpMachineHiveList[i].ThreadStarted == TRUE); + + /* Check if this was a new hive */ + if (!CmpMachineHiveList[i].CmHive) + { + /* Make sure we allocated something */ + ASSERT(CmpMachineHiveList[i].CmHive2 != NULL); + + /* Build the base name */ + RegName.Length = RegStart; + RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName); + RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName); + + /* Check if this is a child of the root */ + if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == '\\') + { + /* Then setup the whole name */ + RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name); + RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName); + } + + /* Now link the hive to its master */ + Status = CmpLinkHiveToMaster(&RegName, + NULL, + CmpMachineHiveList[i].CmHive2, + CmpMachineHiveList[i].Allocate, + SecurityDescriptor); + if (Status != STATUS_SUCCESS) + { + /* Linking needs to work */ + KeBugCheckEx(CONFIG_LIST_FAILED, 11, Status, i, (ULONG_PTR)&RegName); + } + + /* Check if we had to allocate a new hive */ + if (CmpMachineHiveList[i].Allocate) + { + /* Sync the new hive */ + //HvSyncHive((PHHIVE)(CmpMachineHiveList[i].CmHive2)); + } + } + + /* Check if we created a new hive */ + if (CmpMachineHiveList[i].CmHive2) + { + /* TODO: Add to HiveList key */ + } + } + + /* Get rid of the SD */ + ExFreePool(SecurityDescriptor); + + /* FIXME: Link SECURITY to SAM */ + + /* FIXME: Link S-1-5-18 to .Default */ +} + +BOOLEAN +NTAPI +CmInitSystem1(VOID) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING KeyName; + HANDLE KeyHandle; + NTSTATUS Status; + PCMHIVE HardwareHive; + PSECURITY_DESCRIPTOR SecurityDescriptor; + PAGED_CODE(); + + /* Check if this is PE-boot */ + if (InitIsWinPEMode) + { + /* Set registry to PE mode */ + CmpMiniNTBoot = TRUE; + CmpShareSystemHives = TRUE; + } + + /* Initialize the hive list and lock */ + InitializeListHead(&CmpHiveListHead); + ExInitializePushLock((PVOID)&CmpHiveListHeadLock); + ExInitializePushLock((PVOID)&CmpLoadHiveLock); + + /* Initialize registry lock */ + ExInitializeResourceLite(&CmpRegistryLock); + + /* Initialize the cache */ + CmpInitializeCache(); + + /* Initialize allocation and delayed dereferencing */ + CmpInitCmPrivateAlloc(); + CmpInitCmPrivateDelayAlloc(); + CmpInitDelayDerefKCBEngine(); + + /* Initialize callbacks */ + CmpInitCallback(); + + /* Initialize self healing */ + KeInitializeGuardedMutex(&CmpSelfHealQueueLock); + InitializeListHead(&CmpSelfHealQueueListHead); + + /* Save the current process and lock the registry */ + CmpSystemProcess = PsGetCurrentProcess(); + + /* Create the key object types */ + Status = CmpCreateObjectTypes(); + if (!NT_SUCCESS(Status)) + { + /* Bugcheck */ + KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 1, Status, 0); + } + + /* Build the master hive */ + Status = CmpInitializeHive((PCMHIVE*)&CmiVolatileHive, + HINIT_CREATE, + HIVE_VOLATILE, + HFILE_TYPE_PRIMARY, + NULL, + NULL, + NULL, + NULL, + NULL, + 0); + if (!NT_SUCCESS(Status)) + { + /* Bugcheck */ + KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 2, Status, 0); + } + + /* Create the \REGISTRY key node */ + if (!CmpCreateRegistryRoot()) + { + /* Bugcheck */ + KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 3, 0, 0); + } + + /* Create the default security descriptor */ + SecurityDescriptor = CmpHiveRootSecurityDescriptor(); + + /* Create '\Registry\Machine' key. */ + RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE"); + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + SecurityDescriptor); + Status = NtCreateKey(&KeyHandle, + KEY_READ | KEY_WRITE, + &ObjectAttributes, + 0, + NULL, + 0, + NULL); + if (!NT_SUCCESS(Status)) + { + /* Bugcheck */ + KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 5, Status, 0); + } + + /* Close the handle */ + NtClose(KeyHandle); + + /* Create '\Registry\User' key. */ + RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\USER"); + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + SecurityDescriptor); + Status = NtCreateKey(&KeyHandle, + KEY_READ | KEY_WRITE, + &ObjectAttributes, + 0, + NULL, + 0, + NULL); + if (!NT_SUCCESS(Status)) + { + /* Bugcheck */ + KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 6, Status, 0); + } + + /* Close the handle */ + NtClose(KeyHandle); + + /* Initialize the system hive */ + if (!CmpInitializeSystemHive(KeLoaderBlock)) + { + /* Bugcheck */ + KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 7, 0, 0); + } + + /* Create the 'CurrentControlSet' link. */ + Status = CmpCreateControlSet(KeLoaderBlock); + if (!NT_SUCCESS(Status)) + { + /* Bugcheck */ + KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 8, Status, 0); + } + + /* Create the hardware hive */ + Status = CmpInitializeHive((PCMHIVE*)&HardwareHive, + HINIT_CREATE, + HIVE_VOLATILE, + HFILE_TYPE_PRIMARY, + NULL, + NULL, + NULL, + NULL, + NULL, + 0); + if (!NT_SUCCESS(Status)) + { + /* Bugcheck */ + KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 11, Status, 0); + } + + /* Add the hive to the hive list */ + CmpMachineHiveList[0].CmHive = (PCMHIVE)HardwareHive; + + /* Attach it to the machine key */ + RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE"); + Status = CmpLinkHiveToMaster(&KeyName, + NULL, + (PCMHIVE)HardwareHive, + TRUE, + SecurityDescriptor); + if (!NT_SUCCESS(Status)) + { + /* Bugcheck */ + KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 12, Status, 0); + } + + /* FIXME: Add to HiveList key */ + + /* Free the security descriptor */ + ExFreePool(SecurityDescriptor); + + /* Fill out the Hardware key with the ARC Data from the Loader */ + Status = CmpInitializeHardwareConfiguration(KeLoaderBlock); + if (!NT_SUCCESS(Status)) + { + /* Bugcheck */ + KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 13, Status, 0); + } + + /* Initialize machine-dependent information into the registry */ + Status = CmpInitializeMachineDependentConfiguration(KeLoaderBlock); + if (!NT_SUCCESS(Status)) + { + /* Bugcheck */ + KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 14, Status, 0); + } + + /* Initialize volatile registry settings */ + Status = CmpSetSystemValues(KeLoaderBlock); + if (!NT_SUCCESS(Status)) + { + /* Bugcheck */ + KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 15, Status, 0); + } + + /* Free the load options */ + ExFreePool(CmpLoadOptions.Buffer); + + /* If we got here, all went well */ + return TRUE; +} + +VOID +NTAPI +CmpLockRegistryExclusive(VOID) +{ + /* Enter a critical region and lock the registry */ + KeEnterCriticalRegion(); + ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); + + /* Sanity check */ + ASSERT(CmpFlushStarveWriters == 0); + RtlGetCallersAddress(&CmpRegistryLockCaller, &CmpRegistryLockCallerCaller); +} + +VOID +NTAPI +CmpLockRegistry(VOID) +{ + /* Enter a critical region */ + KeEnterCriticalRegion(); + + /* Check if we have to starve writers */ + if (CmpFlushStarveWriters) + { + /* Starve exlusive waiters */ + ExAcquireSharedStarveExclusive(&CmpRegistryLock, TRUE); + } + else + { + /* Just grab the lock */ + ExAcquireResourceSharedLite(&CmpRegistryLock, TRUE); + } +} + +BOOLEAN +NTAPI +CmpTestRegistryLock(VOID) +{ + /* Test the lock */ + return !ExIsResourceAcquiredSharedLite(&CmpRegistryLock) ? FALSE : TRUE; +} + +BOOLEAN +NTAPI +CmpTestRegistryLockExclusive(VOID) +{ + /* Test the lock */ + return !ExIsResourceAcquiredExclusiveLite(&CmpRegistryLock) ? FALSE : TRUE; +} + +VOID +NTAPI +CmpUnlockRegistry(VOID) +{ + /* Sanity check */ + CMP_ASSERT_REGISTRY_LOCK(); + + /* Check if we should flush the registry */ + if (CmpFlushOnLockRelease) + { + /* The registry should be exclusively locked for this */ + CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK(); + + /* Flush the registry */ + CmpDoFlushAll(TRUE); + CmpFlushOnLockRelease = FALSE; + } + + /* Release the lock and leave the critical region */ + ExReleaseResourceLite(&CmpRegistryLock); + KeLeaveCriticalRegion(); +} + +VOID +NTAPI +CmpAcquireTwoKcbLocksExclusiveByKey(IN ULONG ConvKey1, + IN ULONG ConvKey2) +{ + ULONG Index1, Index2; + + /* Sanity check */ + CMP_ASSERT_REGISTRY_LOCK(); + + /* Get hash indexes */ + Index1 = GET_HASH_INDEX(ConvKey1); + Index2 = GET_HASH_INDEX(ConvKey2); + + /* See which one is highest */ + if (Index1 < Index2) + { + /* Grab them in the proper order */ + CmpAcquireKcbLockExclusiveByKey(ConvKey1); + CmpAcquireKcbLockExclusiveByKey(ConvKey2); + } + else + { + /* Grab the second one first, then the first */ + CmpAcquireKcbLockExclusiveByKey(ConvKey2); + if (Index1 != Index2) CmpAcquireKcbLockExclusiveByKey(ConvKey1); + } +} + +VOID +NTAPI +CmpReleaseTwoKcbLockByKey(IN ULONG ConvKey1, + IN ULONG ConvKey2) +{ + ULONG Index1, Index2; + + /* Sanity check */ + CMP_ASSERT_REGISTRY_LOCK(); + + /* Get hash indexes */ + Index1 = GET_HASH_INDEX(ConvKey1); + Index2 = GET_HASH_INDEX(ConvKey2); + ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey2).Owner == KeGetCurrentThread()) || + (CmpTestRegistryLockExclusive())); + + /* See which one is highest */ + if (Index1 < Index2) + { + /* Grab them in the proper order */ + ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1).Owner == KeGetCurrentThread()) || + (CmpTestRegistryLockExclusive())); + CmpReleaseKcbLockByKey(ConvKey2); + CmpReleaseKcbLockByKey(ConvKey1); + } + else + { + /* Release the first one first, then the second */ + if (Index1 != Index2) + { + ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1).Owner == KeGetCurrentThread()) || + (CmpTestRegistryLockExclusive())); + CmpReleaseKcbLockByKey(ConvKey1); + } + CmpReleaseKcbLockByKey(ConvKey2); + } +} + +VOID +NTAPI +CmShutdownSystem(VOID) +{ + /* Kill the workers and fush all hives */ + CmpShutdownWorkers(); + CmpDoFlushAll(TRUE); +} diff --git a/reactos/ntoskrnl/config/cmvalche.c b/reactos/ntoskrnl/config/cmvalche.c index 5db8b6f930f..0e33fc7ce5b 100644 --- a/reactos/ntoskrnl/config/cmvalche.c +++ b/reactos/ntoskrnl/config/cmvalche.c @@ -1,650 +1,649 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/config/cmvalche.c - * PURPOSE: Configuration Manager - Value Cell Cache - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include "ntoskrnl.h" -#include "cm.h" -#define NDEBUG -#include "debug.h" - -FORCEINLINE -BOOLEAN -CmpIsValueCached(IN HCELL_INDEX CellIndex) -{ - /* Make sure that the cell is valid in the first place */ - if (CellIndex == HCELL_NIL) return FALSE; - - /*Is this cell actually a pointer to the cached value data? */ - if (CellIndex & 1) return TRUE; - - /* This is a regular cell */ - return FALSE; -} - -FORCEINLINE -VOID -CmpSetValueCached(IN PHCELL_INDEX CellIndex) -{ - /* Set the cached bit */ - *CellIndex |= 1; -} - -#define ASSERT_VALUE_CACHE() \ - ASSERTMSG("Cached Values Not Yet Supported!", FALSE); - -/* FUNCTIONS *****************************************************************/ - -VALUE_SEARCH_RETURN_TYPE -NTAPI -CmpGetValueListFromCache(IN PCM_KEY_CONTROL_BLOCK Kcb, - OUT PCELL_DATA *CellData, - OUT BOOLEAN *IndexIsCached, - OUT PHCELL_INDEX ValueListToRelease) -{ - PHHIVE Hive; - PCACHED_CHILD_LIST ChildList; - HCELL_INDEX CellToRelease; - PCM_KEY_NODE KeyNode; - - /* Set defaults */ - *ValueListToRelease = HCELL_NIL; - *IndexIsCached = FALSE; - - /* Get the hive */ - Hive = Kcb->KeyHive; - KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Kcb->KeyCell); - - /* Get the child value cache */ - //ChildList = &Kcb->ValueCache; - ChildList = (PCACHED_CHILD_LIST)&KeyNode->ValueList; - - /* Check if the value is cached */ - if (CmpIsValueCached(ChildList->ValueList)) - { - /* It is: we don't expect this yet! */ - ASSERT_VALUE_CACHE(); - *IndexIsCached = TRUE; - *CellData = NULL; - } - else - { - /* Select the value list as our cell, and get the actual list array */ - CellToRelease = ChildList->ValueList; - *CellData = (PCELL_DATA)HvGetCell(Hive, CellToRelease); - if (!(*CellData)) return SearchFail; - - /* Return the cell to be released */ - *ValueListToRelease = CellToRelease; - } - - /* If we got here, then the value list was found */ - return SearchSuccess; -} - -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) -{ - PHHIVE Hive; - PCM_KEY_VALUE KeyValue; - HCELL_INDEX Cell; - - /* Set defaults */ - *CellToRelease = HCELL_NIL; - *Value = NULL; - *ValueIsCached = FALSE; - - /* Get the hive */ - Hive = Kcb->KeyHive; - - /* Check if the index was cached */ - if (IndexIsCached) - { - /* Not expected yet! */ - ASSERT_VALUE_CACHE(); - *ValueIsCached = TRUE; - } - else - { - /* Get the cell index and the key value associated to it */ - Cell = CellData->u.KeyList[Index]; - KeyValue = (PCM_KEY_VALUE)HvGetCell(Hive, Cell); - if (!KeyValue) return SearchFail; - - /* Return the cell and the actual key value */ - *CellToRelease = Cell; - *Value = KeyValue; - } - - /* If we got here, then we found the key value */ - return SearchSuccess; -} - -VALUE_SEARCH_RETURN_TYPE -NTAPI -CmpGetValueDataFromCache(IN PCM_KEY_CONTROL_BLOCK Kcb, - IN PCM_CACHED_VALUE *CachedValue, - IN PCELL_DATA ValueKey, - IN BOOLEAN ValueIsCached, - OUT PVOID *DataPointer, - OUT PBOOLEAN Allocated, - OUT PHCELL_INDEX CellToRelease) -{ - PHHIVE Hive; - ULONG Length; - - /* Sanity checks */ - ASSERT(MAXIMUM_CACHED_DATA < CM_KEY_VALUE_BIG); - ASSERT((ValueKey->u.KeyValue.DataLength & CM_KEY_VALUE_SPECIAL_SIZE) == 0); - - /* Set defaults */ - *DataPointer = NULL; - *Allocated = FALSE; - *CellToRelease = HCELL_NIL; - - /* Get the hive */ - Hive = Kcb->KeyHive; - - /* Check it the value is cached */ - if (ValueIsCached) - { - /* This isn't expected! */ - ASSERT_VALUE_CACHE(); - } - else - { - /* It's not, get the value data using the typical routine */ - if (!CmpGetValueData(Hive, - &ValueKey->u.KeyValue, - &Length, - DataPointer, - Allocated, - CellToRelease)) - { - /* Nothing found: make sure no data was allocated */ - ASSERT(*Allocated == FALSE); - ASSERT(*DataPointer == NULL); - return SearchFail; - } - } - - /* We found the actual data, return success */ - return SearchSuccess; -} - -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) -{ - PHHIVE Hive; - VALUE_SEARCH_RETURN_TYPE SearchResult = SearchFail; - LONG Result; - UNICODE_STRING SearchName; - PCELL_DATA CellData; - PCACHED_CHILD_LIST ChildList; - PCM_KEY_VALUE KeyValue; - BOOLEAN IndexIsCached; - ULONG i = 0; - HCELL_INDEX Cell = HCELL_NIL; - PCM_KEY_NODE KeyNode; - - /* Set defaults */ - *CellToRelease = HCELL_NIL; - *Value = NULL; - - /* Get the hive */ - Hive = Kcb->KeyHive; - KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Kcb->KeyCell); - - /* Get the child value cache */ - //ChildList = &Kcb->ValueCache; - ChildList = (PCACHED_CHILD_LIST)&KeyNode->ValueList; - - /* Check if the child list has any entries */ - if (ChildList->Count != 0) - { - /* Get the value list associated to this child list */ - SearchResult = CmpGetValueListFromCache(Kcb, - &CellData, - &IndexIsCached, - &Cell); - if (SearchResult != SearchSuccess) return SearchResult; - - /* The index shouldn't be cached right now */ - if (IndexIsCached) ASSERT_VALUE_CACHE(); - - /* Loop every value */ - while (TRUE) - { - /* Check if there's any cell to release */ - if (*CellToRelease != HCELL_NIL) - { - /* Release it now */ - HvReleaseCell(Hive, *CellToRelease); - *CellToRelease = HCELL_NIL; - } - - /* Get the key value for this index */ - SearchResult = CmpGetValueKeyFromCache(Kcb, - CellData, - i, - CachedValue, - Value, - IndexIsCached, - ValueIsCached, - CellToRelease); - if (SearchResult != SearchSuccess) return SearchResult; - - /* Check if the both the index and the value are cached */ - if ((IndexIsCached) && (*ValueIsCached)) - { - /* We don't expect this yet */ - ASSERT_VALUE_CACHE(); - Result = -1; - } - else - { - /* No cache, so try to compare the name. Is it compressed? */ - KeyValue = *Value; - if (KeyValue->Flags & VALUE_COMP_NAME) - { - /* It is, do a compressed name comparison */ - Result = CmpCompareCompressedName(Name, - KeyValue->Name, - KeyValue->NameLength); - } - else - { - /* It's not compressed, so do a standard comparison */ - SearchName.Length = KeyValue->NameLength; - SearchName.MaximumLength = SearchName.Length; - SearchName.Buffer = KeyValue->Name; - Result = RtlCompareUnicodeString(Name, &SearchName, TRUE); - } - } - - /* Check if we found the value data */ - if (!Result) - { - /* We have, return the index of the value and success */ - *Index = i; - SearchResult = SearchSuccess; - goto Quickie; - } - - /* We didn't find it, try the next entry */ - if (++i == ChildList->Count) - { - /* The entire list was parsed, fail */ - *Value = NULL; - SearchResult = SearchFail; - goto Quickie; - } - } - } - - /* We should only get here if the child list is empty */ - ASSERT(ChildList->Count == 0); - -Quickie: - /* Release the value list cell if required, and return search result */ - if (Cell != HCELL_NIL) HvReleaseCell(Hive, Cell); - return SearchResult; -} - -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) -{ - PHHIVE Hive; - PKEY_VALUE_INFORMATION Info = (PKEY_VALUE_INFORMATION)KeyValueInformation; - PCELL_DATA CellData; - USHORT NameSize; - ULONG Size, MinimumSize, SizeLeft, KeySize, AlignedData = 0, DataOffset; - PVOID Buffer; - BOOLEAN IsSmall, BufferAllocated = FALSE; - HCELL_INDEX CellToRelease = HCELL_NIL; - VALUE_SEARCH_RETURN_TYPE Result = SearchSuccess; - - /* Get the hive and cell data */ - Hive = Kcb->KeyHive; - CellData = (PCELL_DATA)ValueKey; - - /* Check if the value is compressed */ - if (CellData->u.KeyValue.Flags & VALUE_COMP_NAME) - { - /* Get the compressed name size */ - NameSize = CmpCompressedNameSize(CellData->u.KeyValue.Name, - CellData->u.KeyValue.NameLength); - } - else - { - /* Get the real size */ - NameSize = CellData->u.KeyValue.NameLength; - } - - /* Check what kind of information the caller is requesting */ - switch (KeyValueInformationClass) - { - /* Basic information */ - case KeyValueBasicInformation: - - /* This is how much size we'll need */ - Size = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name) + NameSize; - - /* This is the minimum we can work with */ - MinimumSize = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name); - - /* Return the size we'd like, and assume success */ - *ResultLength = Size; - *Status = STATUS_SUCCESS; - - /* Check if the caller gave us below our minimum */ - if (Length < MinimumSize) - { - /* Then we must fail */ - *Status = STATUS_BUFFER_TOO_SMALL; - break; - } - - /* Fill out the basic information */ - Info->KeyValueBasicInformation.TitleIndex = 0; - Info->KeyValueBasicInformation.Type = CellData->u.KeyValue.Type; - Info->KeyValueBasicInformation.NameLength = NameSize; - - /* Now only the name is left */ - SizeLeft = Length - MinimumSize; - Size = NameSize; - - /* Check if the remaining buffer is too small for the name */ - if (SizeLeft < Size) - { - /* Copy only as much as can fit, and tell the caller */ - Size = SizeLeft; - *Status = STATUS_BUFFER_OVERFLOW; - } - - /* Check if this is a compressed name */ - if (CellData->u.KeyValue.Flags & VALUE_COMP_NAME) - { - /* Copy as much as we can of the compressed name */ - CmpCopyCompressedName(Info->KeyValueBasicInformation.Name, - Size, - CellData->u.KeyValue.Name, - CellData->u.KeyValue.NameLength); - } - else - { - /* Copy as much as we can of the raw name */ - RtlCopyMemory(Info->KeyValueBasicInformation.Name, - CellData->u.KeyValue.Name, - Size); - } - - /* We're all done */ - break; - - /* Full key information */ - case KeyValueFullInformation: - - /* Check if this is a small key and compute key size */ - IsSmall = CmpIsKeyValueSmall(&KeySize, - CellData->u.KeyValue.DataLength); - - /* Calculate the total size required */ - Size = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name) + - NameSize + - KeySize; - - /* And this is the least we can work with */ - MinimumSize = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name); - - /* Check if there's any key data */ - if (KeySize > 0) - { - /* Calculate the data offset */ - DataOffset = Size - KeySize; - - /* Align the offset to 4 bytes */ - AlignedData = ALIGN_UP(DataOffset, ULONG); - - /* If alignment was required, we'll need more space */ - if (AlignedData > DataOffset) Size += (AlignedData-DataOffset); - } - - /* Tell the caller the size we'll finally need, and set success */ - *ResultLength = Size; - *Status = STATUS_SUCCESS; - - /* Check if the caller is giving us too little */ - if (Length < MinimumSize) - { - /* Then fail right now */ - *Status = STATUS_BUFFER_TOO_SMALL; - break; - } - - /* Fill out the basic information */ - Info->KeyValueFullInformation.TitleIndex = 0; - Info->KeyValueFullInformation.Type = CellData->u.KeyValue.Type; - Info->KeyValueFullInformation.DataLength = KeySize; - Info->KeyValueFullInformation.NameLength = NameSize; - - /* Only the name is left now */ - SizeLeft = Length - MinimumSize; - Size = NameSize; - - /* Check if the name fits */ - if (SizeLeft < Size) - { - /* It doesn't, truncate what we'll copy, and tell the caller */ - Size = SizeLeft; - *Status = STATUS_BUFFER_OVERFLOW; - } - - /* Check if this key value is compressed */ - if (CellData->u.KeyValue.Flags & VALUE_COMP_NAME) - { - /* It is, copy the compressed name */ - CmpCopyCompressedName(Info->KeyValueFullInformation.Name, - Size, - CellData->u.KeyValue.Name, - CellData->u.KeyValue.NameLength); - } - else - { - /* It's not, copy the raw name */ - RtlCopyMemory(Info->KeyValueFullInformation.Name, - CellData->u.KeyValue.Name, - Size); - } - - /* Now check if the key had any data */ - if (KeySize > 0) - { - /* Was it a small key? */ - if (IsSmall) - { - /* Then the data is directly into the cell */ - Buffer = &CellData->u.KeyValue.Data; - } - else - { - /* Otherwise, we must retrieve it from the value cache */ - Result = CmpGetValueDataFromCache(Kcb, - CachedValue, - CellData, - ValueIsCached, - &Buffer, - &BufferAllocated, - &CellToRelease); - if (Result != SearchSuccess) - { - /* We failed, nothing should be allocated */ - ASSERT(Buffer == NULL); - ASSERT(BufferAllocated == FALSE); - *Status = STATUS_INSUFFICIENT_RESOURCES; - } - } - - /* Now that we know we truly have data, set its offset */ - Info->KeyValueFullInformation.DataOffset = AlignedData; - - /* Only the data remains to be copied */ - SizeLeft = (((LONG)Length - (LONG)AlignedData) < 0) ? - 0 : (Length - AlignedData); - Size = KeySize; - - /* Check if the caller has no space for it */ - if (SizeLeft < Size) - { - /* Truncate what we'll copy, and tell the caller */ - Size = SizeLeft; - *Status = STATUS_BUFFER_OVERFLOW; - } - - /* Sanity check */ - ASSERT((IsSmall ? (Size <= CM_KEY_VALUE_SMALL) : TRUE)); - - /* Make sure we have a valid buffer */ - if (Buffer) - { - /* Copy the data into the aligned offset */ - RtlCopyMemory((PVOID)((ULONG_PTR)Info + AlignedData), - Buffer, - Size); - } - } - else - { - /* We don't have any data, set the offset to -1, not 0! */ - Info->KeyValueFullInformation.DataOffset = 0xFFFFFFFF; - } - - /* We're done! */ - break; - - /* Partial information requested (no name or alignment!) */ - case KeyValuePartialInformation: - - /* Check if this is a small key and compute key size */ - IsSmall = CmpIsKeyValueSmall(&KeySize, - CellData->u.KeyValue.DataLength); - - /* Calculate the total size required */ - Size = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + KeySize; - - /* And this is the least we can work with */ - MinimumSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data); - - /* Tell the caller the size we'll finally need, and set success */ - *ResultLength = Size; - *Status = STATUS_SUCCESS; - - /* Check if the caller is giving us too little */ - if (Length < MinimumSize) - { - /* Then fail right now */ - *Status = STATUS_BUFFER_TOO_SMALL; - break; - } - - /* Fill out the basic information */ - Info->KeyValuePartialInformation.TitleIndex = 0; - Info->KeyValuePartialInformation.Type = CellData->u.KeyValue.Type; - Info->KeyValuePartialInformation.DataLength = KeySize; - - /* Now check if the key had any data */ - if (KeySize > 0) - { - /* Was it a small key? */ - if (IsSmall) - { - /* Then the data is directly into the cell */ - Buffer = &CellData->u.KeyValue.Data; - } - else - { - /* Otherwise, we must retrieve it from the value cache */ - Result = CmpGetValueDataFromCache(Kcb, - CachedValue, - CellData, - ValueIsCached, - &Buffer, - &BufferAllocated, - &CellToRelease); - if (Result != SearchSuccess) - { - /* We failed, nothing should be allocated */ - ASSERT(Buffer == NULL); - ASSERT(BufferAllocated == FALSE); - *Status = STATUS_INSUFFICIENT_RESOURCES; - } - } - - /* Only the data remains to be copied */ - SizeLeft = Length - MinimumSize; - Size = KeySize; - - /* Check if the caller has no space for it */ - if (SizeLeft < Size) - { - /* Truncate what we'll copy, and tell the caller */ - Size = SizeLeft; - *Status = STATUS_BUFFER_OVERFLOW; - } - - /* Sanity check */ - ASSERT((IsSmall ? (Size <= CM_KEY_VALUE_SMALL) : TRUE)); - - /* Make sure we have a valid buffer */ - if (Buffer) - { - /* Copy the data into the aligned offset */ - RtlCopyMemory(Info->KeyValuePartialInformation.Data, - Buffer, - Size); - } - } - - /* We're done! */ - break; - - /* Other information class */ - default: - - /* We got some class that we don't support */ - *Status = STATUS_INVALID_PARAMETER; - break; - } - - /* Return the search result as well */ - return Result; -} +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmvalche.c + * PURPOSE: Configuration Manager - Value Cell Cache + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#define NDEBUG +#include "debug.h" + +FORCEINLINE +BOOLEAN +CmpIsValueCached(IN HCELL_INDEX CellIndex) +{ + /* Make sure that the cell is valid in the first place */ + if (CellIndex == HCELL_NIL) return FALSE; + + /*Is this cell actually a pointer to the cached value data? */ + if (CellIndex & 1) return TRUE; + + /* This is a regular cell */ + return FALSE; +} + +FORCEINLINE +VOID +CmpSetValueCached(IN PHCELL_INDEX CellIndex) +{ + /* Set the cached bit */ + *CellIndex |= 1; +} + +#define ASSERT_VALUE_CACHE() \ + ASSERTMSG("Cached Values Not Yet Supported!", FALSE); + +/* FUNCTIONS *****************************************************************/ + +VALUE_SEARCH_RETURN_TYPE +NTAPI +CmpGetValueListFromCache(IN PCM_KEY_CONTROL_BLOCK Kcb, + OUT PCELL_DATA *CellData, + OUT BOOLEAN *IndexIsCached, + OUT PHCELL_INDEX ValueListToRelease) +{ + PHHIVE Hive; + PCACHED_CHILD_LIST ChildList; + HCELL_INDEX CellToRelease; + PCM_KEY_NODE KeyNode; + + /* Set defaults */ + *ValueListToRelease = HCELL_NIL; + *IndexIsCached = FALSE; + + /* Get the hive */ + Hive = Kcb->KeyHive; + KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Kcb->KeyCell); + + /* Get the child value cache */ + //ChildList = &Kcb->ValueCache; + ChildList = (PCACHED_CHILD_LIST)&KeyNode->ValueList; + + /* Check if the value is cached */ + if (CmpIsValueCached(ChildList->ValueList)) + { + /* It is: we don't expect this yet! */ + ASSERT_VALUE_CACHE(); + *IndexIsCached = TRUE; + *CellData = NULL; + } + else + { + /* Select the value list as our cell, and get the actual list array */ + CellToRelease = ChildList->ValueList; + *CellData = (PCELL_DATA)HvGetCell(Hive, CellToRelease); + if (!(*CellData)) return SearchFail; + + /* Return the cell to be released */ + *ValueListToRelease = CellToRelease; + } + + /* If we got here, then the value list was found */ + return SearchSuccess; +} + +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) +{ + PHHIVE Hive; + PCM_KEY_VALUE KeyValue; + HCELL_INDEX Cell; + + /* Set defaults */ + *CellToRelease = HCELL_NIL; + *Value = NULL; + *ValueIsCached = FALSE; + + /* Get the hive */ + Hive = Kcb->KeyHive; + + /* Check if the index was cached */ + if (IndexIsCached) + { + /* Not expected yet! */ + ASSERT_VALUE_CACHE(); + *ValueIsCached = TRUE; + } + else + { + /* Get the cell index and the key value associated to it */ + Cell = CellData->u.KeyList[Index]; + KeyValue = (PCM_KEY_VALUE)HvGetCell(Hive, Cell); + if (!KeyValue) return SearchFail; + + /* Return the cell and the actual key value */ + *CellToRelease = Cell; + *Value = KeyValue; + } + + /* If we got here, then we found the key value */ + return SearchSuccess; +} + +VALUE_SEARCH_RETURN_TYPE +NTAPI +CmpGetValueDataFromCache(IN PCM_KEY_CONTROL_BLOCK Kcb, + IN PCM_CACHED_VALUE *CachedValue, + IN PCELL_DATA ValueKey, + IN BOOLEAN ValueIsCached, + OUT PVOID *DataPointer, + OUT PBOOLEAN Allocated, + OUT PHCELL_INDEX CellToRelease) +{ + PHHIVE Hive; + ULONG Length; + + /* Sanity checks */ + ASSERT(MAXIMUM_CACHED_DATA < CM_KEY_VALUE_BIG); + ASSERT((ValueKey->u.KeyValue.DataLength & CM_KEY_VALUE_SPECIAL_SIZE) == 0); + + /* Set defaults */ + *DataPointer = NULL; + *Allocated = FALSE; + *CellToRelease = HCELL_NIL; + + /* Get the hive */ + Hive = Kcb->KeyHive; + + /* Check it the value is cached */ + if (ValueIsCached) + { + /* This isn't expected! */ + ASSERT_VALUE_CACHE(); + } + else + { + /* It's not, get the value data using the typical routine */ + if (!CmpGetValueData(Hive, + &ValueKey->u.KeyValue, + &Length, + DataPointer, + Allocated, + CellToRelease)) + { + /* Nothing found: make sure no data was allocated */ + ASSERT(*Allocated == FALSE); + ASSERT(*DataPointer == NULL); + return SearchFail; + } + } + + /* We found the actual data, return success */ + return SearchSuccess; +} + +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) +{ + PHHIVE Hive; + VALUE_SEARCH_RETURN_TYPE SearchResult = SearchFail; + LONG Result; + UNICODE_STRING SearchName; + PCELL_DATA CellData; + PCACHED_CHILD_LIST ChildList; + PCM_KEY_VALUE KeyValue; + BOOLEAN IndexIsCached; + ULONG i = 0; + HCELL_INDEX Cell = HCELL_NIL; + PCM_KEY_NODE KeyNode; + + /* Set defaults */ + *CellToRelease = HCELL_NIL; + *Value = NULL; + + /* Get the hive */ + Hive = Kcb->KeyHive; + KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Kcb->KeyCell); + + /* Get the child value cache */ + //ChildList = &Kcb->ValueCache; + ChildList = (PCACHED_CHILD_LIST)&KeyNode->ValueList; + + /* Check if the child list has any entries */ + if (ChildList->Count != 0) + { + /* Get the value list associated to this child list */ + SearchResult = CmpGetValueListFromCache(Kcb, + &CellData, + &IndexIsCached, + &Cell); + if (SearchResult != SearchSuccess) return SearchResult; + + /* The index shouldn't be cached right now */ + if (IndexIsCached) ASSERT_VALUE_CACHE(); + + /* Loop every value */ + while (TRUE) + { + /* Check if there's any cell to release */ + if (*CellToRelease != HCELL_NIL) + { + /* Release it now */ + HvReleaseCell(Hive, *CellToRelease); + *CellToRelease = HCELL_NIL; + } + + /* Get the key value for this index */ + SearchResult = CmpGetValueKeyFromCache(Kcb, + CellData, + i, + CachedValue, + Value, + IndexIsCached, + ValueIsCached, + CellToRelease); + if (SearchResult != SearchSuccess) return SearchResult; + + /* Check if the both the index and the value are cached */ + if ((IndexIsCached) && (*ValueIsCached)) + { + /* We don't expect this yet */ + ASSERT_VALUE_CACHE(); + Result = -1; + } + else + { + /* No cache, so try to compare the name. Is it compressed? */ + KeyValue = *Value; + if (KeyValue->Flags & VALUE_COMP_NAME) + { + /* It is, do a compressed name comparison */ + Result = CmpCompareCompressedName(Name, + KeyValue->Name, + KeyValue->NameLength); + } + else + { + /* It's not compressed, so do a standard comparison */ + SearchName.Length = KeyValue->NameLength; + SearchName.MaximumLength = SearchName.Length; + SearchName.Buffer = KeyValue->Name; + Result = RtlCompareUnicodeString(Name, &SearchName, TRUE); + } + } + + /* Check if we found the value data */ + if (!Result) + { + /* We have, return the index of the value and success */ + *Index = i; + SearchResult = SearchSuccess; + goto Quickie; + } + + /* We didn't find it, try the next entry */ + if (++i == ChildList->Count) + { + /* The entire list was parsed, fail */ + *Value = NULL; + SearchResult = SearchFail; + goto Quickie; + } + } + } + + /* We should only get here if the child list is empty */ + ASSERT(ChildList->Count == 0); + +Quickie: + /* Release the value list cell if required, and return search result */ + if (Cell != HCELL_NIL) HvReleaseCell(Hive, Cell); + return SearchResult; +} + +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) +{ + PHHIVE Hive; + PKEY_VALUE_INFORMATION Info = (PKEY_VALUE_INFORMATION)KeyValueInformation; + PCELL_DATA CellData; + USHORT NameSize; + ULONG Size, MinimumSize, SizeLeft, KeySize, AlignedData = 0, DataOffset; + PVOID Buffer; + BOOLEAN IsSmall, BufferAllocated = FALSE; + HCELL_INDEX CellToRelease = HCELL_NIL; + VALUE_SEARCH_RETURN_TYPE Result = SearchSuccess; + + /* Get the hive and cell data */ + Hive = Kcb->KeyHive; + CellData = (PCELL_DATA)ValueKey; + + /* Check if the value is compressed */ + if (CellData->u.KeyValue.Flags & VALUE_COMP_NAME) + { + /* Get the compressed name size */ + NameSize = CmpCompressedNameSize(CellData->u.KeyValue.Name, + CellData->u.KeyValue.NameLength); + } + else + { + /* Get the real size */ + NameSize = CellData->u.KeyValue.NameLength; + } + + /* Check what kind of information the caller is requesting */ + switch (KeyValueInformationClass) + { + /* Basic information */ + case KeyValueBasicInformation: + + /* This is how much size we'll need */ + Size = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name) + NameSize; + + /* This is the minimum we can work with */ + MinimumSize = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name); + + /* Return the size we'd like, and assume success */ + *ResultLength = Size; + *Status = STATUS_SUCCESS; + + /* Check if the caller gave us below our minimum */ + if (Length < MinimumSize) + { + /* Then we must fail */ + *Status = STATUS_BUFFER_TOO_SMALL; + break; + } + + /* Fill out the basic information */ + Info->KeyValueBasicInformation.TitleIndex = 0; + Info->KeyValueBasicInformation.Type = CellData->u.KeyValue.Type; + Info->KeyValueBasicInformation.NameLength = NameSize; + + /* Now only the name is left */ + SizeLeft = Length - MinimumSize; + Size = NameSize; + + /* Check if the remaining buffer is too small for the name */ + if (SizeLeft < Size) + { + /* Copy only as much as can fit, and tell the caller */ + Size = SizeLeft; + *Status = STATUS_BUFFER_OVERFLOW; + } + + /* Check if this is a compressed name */ + if (CellData->u.KeyValue.Flags & VALUE_COMP_NAME) + { + /* Copy as much as we can of the compressed name */ + CmpCopyCompressedName(Info->KeyValueBasicInformation.Name, + Size, + CellData->u.KeyValue.Name, + CellData->u.KeyValue.NameLength); + } + else + { + /* Copy as much as we can of the raw name */ + RtlCopyMemory(Info->KeyValueBasicInformation.Name, + CellData->u.KeyValue.Name, + Size); + } + + /* We're all done */ + break; + + /* Full key information */ + case KeyValueFullInformation: + + /* Check if this is a small key and compute key size */ + IsSmall = CmpIsKeyValueSmall(&KeySize, + CellData->u.KeyValue.DataLength); + + /* Calculate the total size required */ + Size = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name) + + NameSize + + KeySize; + + /* And this is the least we can work with */ + MinimumSize = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name); + + /* Check if there's any key data */ + if (KeySize > 0) + { + /* Calculate the data offset */ + DataOffset = Size - KeySize; + + /* Align the offset to 4 bytes */ + AlignedData = ALIGN_UP(DataOffset, ULONG); + + /* If alignment was required, we'll need more space */ + if (AlignedData > DataOffset) Size += (AlignedData-DataOffset); + } + + /* Tell the caller the size we'll finally need, and set success */ + *ResultLength = Size; + *Status = STATUS_SUCCESS; + + /* Check if the caller is giving us too little */ + if (Length < MinimumSize) + { + /* Then fail right now */ + *Status = STATUS_BUFFER_TOO_SMALL; + break; + } + + /* Fill out the basic information */ + Info->KeyValueFullInformation.TitleIndex = 0; + Info->KeyValueFullInformation.Type = CellData->u.KeyValue.Type; + Info->KeyValueFullInformation.DataLength = KeySize; + Info->KeyValueFullInformation.NameLength = NameSize; + + /* Only the name is left now */ + SizeLeft = Length - MinimumSize; + Size = NameSize; + + /* Check if the name fits */ + if (SizeLeft < Size) + { + /* It doesn't, truncate what we'll copy, and tell the caller */ + Size = SizeLeft; + *Status = STATUS_BUFFER_OVERFLOW; + } + + /* Check if this key value is compressed */ + if (CellData->u.KeyValue.Flags & VALUE_COMP_NAME) + { + /* It is, copy the compressed name */ + CmpCopyCompressedName(Info->KeyValueFullInformation.Name, + Size, + CellData->u.KeyValue.Name, + CellData->u.KeyValue.NameLength); + } + else + { + /* It's not, copy the raw name */ + RtlCopyMemory(Info->KeyValueFullInformation.Name, + CellData->u.KeyValue.Name, + Size); + } + + /* Now check if the key had any data */ + if (KeySize > 0) + { + /* Was it a small key? */ + if (IsSmall) + { + /* Then the data is directly into the cell */ + Buffer = &CellData->u.KeyValue.Data; + } + else + { + /* Otherwise, we must retrieve it from the value cache */ + Result = CmpGetValueDataFromCache(Kcb, + CachedValue, + CellData, + ValueIsCached, + &Buffer, + &BufferAllocated, + &CellToRelease); + if (Result != SearchSuccess) + { + /* We failed, nothing should be allocated */ + ASSERT(Buffer == NULL); + ASSERT(BufferAllocated == FALSE); + *Status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + /* Now that we know we truly have data, set its offset */ + Info->KeyValueFullInformation.DataOffset = AlignedData; + + /* Only the data remains to be copied */ + SizeLeft = (((LONG)Length - (LONG)AlignedData) < 0) ? + 0 : (Length - AlignedData); + Size = KeySize; + + /* Check if the caller has no space for it */ + if (SizeLeft < Size) + { + /* Truncate what we'll copy, and tell the caller */ + Size = SizeLeft; + *Status = STATUS_BUFFER_OVERFLOW; + } + + /* Sanity check */ + ASSERT((IsSmall ? (Size <= CM_KEY_VALUE_SMALL) : TRUE)); + + /* Make sure we have a valid buffer */ + if (Buffer) + { + /* Copy the data into the aligned offset */ + RtlCopyMemory((PVOID)((ULONG_PTR)Info + AlignedData), + Buffer, + Size); + } + } + else + { + /* We don't have any data, set the offset to -1, not 0! */ + Info->KeyValueFullInformation.DataOffset = 0xFFFFFFFF; + } + + /* We're done! */ + break; + + /* Partial information requested (no name or alignment!) */ + case KeyValuePartialInformation: + + /* Check if this is a small key and compute key size */ + IsSmall = CmpIsKeyValueSmall(&KeySize, + CellData->u.KeyValue.DataLength); + + /* Calculate the total size required */ + Size = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + KeySize; + + /* And this is the least we can work with */ + MinimumSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data); + + /* Tell the caller the size we'll finally need, and set success */ + *ResultLength = Size; + *Status = STATUS_SUCCESS; + + /* Check if the caller is giving us too little */ + if (Length < MinimumSize) + { + /* Then fail right now */ + *Status = STATUS_BUFFER_TOO_SMALL; + break; + } + + /* Fill out the basic information */ + Info->KeyValuePartialInformation.TitleIndex = 0; + Info->KeyValuePartialInformation.Type = CellData->u.KeyValue.Type; + Info->KeyValuePartialInformation.DataLength = KeySize; + + /* Now check if the key had any data */ + if (KeySize > 0) + { + /* Was it a small key? */ + if (IsSmall) + { + /* Then the data is directly into the cell */ + Buffer = &CellData->u.KeyValue.Data; + } + else + { + /* Otherwise, we must retrieve it from the value cache */ + Result = CmpGetValueDataFromCache(Kcb, + CachedValue, + CellData, + ValueIsCached, + &Buffer, + &BufferAllocated, + &CellToRelease); + if (Result != SearchSuccess) + { + /* We failed, nothing should be allocated */ + ASSERT(Buffer == NULL); + ASSERT(BufferAllocated == FALSE); + *Status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + /* Only the data remains to be copied */ + SizeLeft = Length - MinimumSize; + Size = KeySize; + + /* Check if the caller has no space for it */ + if (SizeLeft < Size) + { + /* Truncate what we'll copy, and tell the caller */ + Size = SizeLeft; + *Status = STATUS_BUFFER_OVERFLOW; + } + + /* Sanity check */ + ASSERT((IsSmall ? (Size <= CM_KEY_VALUE_SMALL) : TRUE)); + + /* Make sure we have a valid buffer */ + if (Buffer) + { + /* Copy the data into the aligned offset */ + RtlCopyMemory(Info->KeyValuePartialInformation.Data, + Buffer, + Size); + } + } + + /* We're done! */ + break; + + /* Other information class */ + default: + + /* We got some class that we don't support */ + *Status = STATUS_INVALID_PARAMETER; + break; + } + + /* Return the search result as well */ + return Result; +} diff --git a/reactos/ntoskrnl/config/cmvalue.c b/reactos/ntoskrnl/config/cmvalue.c index 4f584b3a297..5eb5976e568 100644 --- a/reactos/ntoskrnl/config/cmvalue.c +++ b/reactos/ntoskrnl/config/cmvalue.c @@ -1,364 +1,363 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/config/cmvalue.c - * PURPOSE: Configuration Manager - Cell Values - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include "ntoskrnl.h" -#include "cm.h" -#define NDEBUG -#include "debug.h" - -/* FUNCTIONS *****************************************************************/ - -BOOLEAN -NTAPI -CmpMarkValueDataDirty(IN PHHIVE Hive, - IN PCM_KEY_VALUE Value) -{ - ULONG KeySize; - PAGED_CODE(); - - /* Make sure there's actually any data */ - if (Value->Data != HCELL_NIL) - { - /* If this is a small key, there's no need to have it dirty */ - if (CmpIsKeyValueSmall(&KeySize, Value->DataLength)) return TRUE; - - /* Check if this is a big key */ - ASSERT_VALUE_BIG(Hive, KeySize); - - /* Normal value, just mark it dirty */ - HvMarkCellDirty(Hive, Value->Data, FALSE); - } - - /* Operation complete */ - return TRUE; -} - -BOOLEAN -NTAPI -CmpFreeValueData(IN PHHIVE Hive, - IN HCELL_INDEX DataCell, - IN ULONG DataLength) -{ - ULONG KeySize; - PAGED_CODE(); - - /* If this is a small key, the data is built-in */ - if (!CmpIsKeyValueSmall(&KeySize, DataLength)) - { - /* If there's no data cell, there's nothing to do */ - if (DataCell == HCELL_NIL) return TRUE; - - /* Make sure the data cell is allocated */ - //ASSERT(HvIsCellAllocated(Hive, DataCell)); - - /* Unsupported value type */ - ASSERT_VALUE_BIG(Hive, KeySize); - - /* Normal value, just free the data cell */ - HvFreeCell(Hive, DataCell); - } - - /* Operation complete */ - return TRUE; -} - -BOOLEAN -NTAPI -CmpFreeValue(IN PHHIVE Hive, - IN HCELL_INDEX Cell) -{ - PCM_KEY_VALUE Value; - PAGED_CODE(); - - /* Get the cell data */ - Value = (PCM_KEY_VALUE)HvGetCell(Hive, Cell); - if (!Value) ASSERT(FALSE); - - /* Free it */ - if (!CmpFreeValueData(Hive, Value->Data, Value->DataLength)) - { - /* We failed to free the data, return failure */ - HvReleaseCell(Hive, Cell); - return FALSE; - } - - /* Release the cell and free it */ - HvReleaseCell(Hive, Cell); - HvFreeCell(Hive, Cell); - return TRUE; -} - -HCELL_INDEX -NTAPI -CmpFindValueByName(IN PHHIVE Hive, - IN PCM_KEY_NODE KeyNode, - IN PUNICODE_STRING Name) -{ - HCELL_INDEX CellIndex; - - /* Call the main function */ - if (!CmpFindNameInList(Hive, - &KeyNode->ValueList, - Name, - NULL, - &CellIndex)) - { - /* Santy check */ - ASSERT(CellIndex == HCELL_NIL); - } - - /* Return the index */ - return CellIndex; -} - -BOOLEAN -NTAPI -CmpGetValueData(IN PHHIVE Hive, - IN PCM_KEY_VALUE Value, - IN PULONG Length, - OUT PVOID *Buffer, - OUT PBOOLEAN BufferAllocated, - OUT PHCELL_INDEX CellToRelease) -{ - PAGED_CODE(); - - /* Sanity check */ - ASSERT(Value->Signature == CM_KEY_VALUE_SIGNATURE); - - /* Set failure defaults */ - *BufferAllocated = FALSE; - *Buffer = NULL; - *CellToRelease = HCELL_NIL; - - /* Check if this is a small key */ - if (CmpIsKeyValueSmall(Length, Value->DataLength)) - { - /* Return the data immediately */ - *Buffer = &Value->Data; - return TRUE; - } - - /* Unsupported */ - ASSERT_VALUE_BIG(Hive, *Length); - - /* Get the data from the cell */ - *Buffer = HvGetCell(Hive, Value->Data); - if (!(*Buffer)) return FALSE; - - /* Return success and the cell to be released */ - *CellToRelease = Value->Data; - return TRUE; -} - -PCELL_DATA -NTAPI -CmpValueToData(IN PHHIVE Hive, - IN PCM_KEY_VALUE Value, - OUT PULONG Length) -{ - PCELL_DATA Buffer; - BOOLEAN BufferAllocated; - HCELL_INDEX CellToRelease; - PAGED_CODE(); - - /* Sanity check */ - ASSERT(Hive->ReleaseCellRoutine == NULL); - - /* Get the actual data */ - if (!CmpGetValueData(Hive, - Value, - Length, - (PVOID)&Buffer, - &BufferAllocated, - &CellToRelease)) - { - /* We failed */ - ASSERT(BufferAllocated == FALSE); - ASSERT(Buffer == NULL); - return NULL; - } - - /* This should never happen!*/ - if (BufferAllocated) - { - /* Free the buffer and bugcheck */ - ExFreePool(Buffer); - KEBUGCHECKEX(REGISTRY_ERROR, 8, 0, (ULONG_PTR)Hive, (ULONG_PTR)Value); - } - - /* Otherwise, return the cell data */ - return Buffer; -} - -NTSTATUS -NTAPI -CmpAddValueToList(IN PHHIVE Hive, - IN HCELL_INDEX ValueCell, - IN ULONG Index, - IN ULONG Type, - IN OUT PCHILD_LIST ChildList) -{ - HCELL_INDEX ListCell; - ULONG ChildCount, Length, i; - PCELL_DATA CellData; - PAGED_CODE(); - - /* Sanity check */ - ASSERT((((LONG)Index) >= 0) && (Index <= ChildList->Count)); - - /* Get the number of entries in the child list */ - ChildCount = ChildList->Count; - ChildCount++; - if (ChildCount > 1) - { - /* The cell should be dirty at this point */ - ASSERT(HvIsCellDirty(Hive, ChildList->List)); - - /* Check if we have less then 100 children */ - if (ChildCount < 100) - { - /* Allocate just enough as requested */ - Length = ChildCount * sizeof(HCELL_INDEX); - } - else - { - /* Otherwise, we have quite a few, so allocate a batch */ - Length = ROUND_UP(ChildCount, 100) * sizeof(HCELL_INDEX); - if (Length > HBLOCK_SIZE) - { - /* But make sure we don't allocate beyond our block size */ - Length = ROUND_UP(Length, HBLOCK_SIZE); - } - } - - /* Perform the allocation */ - ListCell = HvReallocateCell(Hive, ChildList->List, Length); - } - else - { - /* This is our first child, so allocate a single cell */ - ListCell = HvAllocateCell(Hive, sizeof(HCELL_INDEX), Type, HCELL_NIL); - } - - /* Fail if we couldn't get a cell */ - if (ListCell == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES; - - /* Set this cell as the child list's list cell */ - ChildList->List = ListCell; - - /* Get the actual key list memory */ - CellData = HvGetCell(Hive, ListCell); - ASSERT(CellData != NULL); - - /* Loop all the children */ - for (i = ChildCount - 1; i > Index; i--) - { - /* Move them all down */ - CellData->u.KeyList[i] = CellData->u.KeyList[i - 1]; - } - - /* Insert us on top now */ - CellData->u.KeyList[Index] = ValueCell; - ChildList->Count = ChildCount; - - /* Release the list cell and make sure the value cell is dirty */ - HvReleaseCell(Hive, ListCell); - ASSERT(HvIsCellDirty(Hive, ValueCell)); - - /* We're done here */ - return STATUS_SUCCESS; -} - -NTSTATUS -NTAPI -CmpSetValueDataNew(IN PHHIVE Hive, - IN PVOID Data, - IN ULONG DataSize, - IN ULONG StorageType, - IN HCELL_INDEX ValueCell, - OUT PHCELL_INDEX DataCell) -{ - PCELL_DATA CellData; - PAGED_CODE(); - ASSERT(DataSize > CM_KEY_VALUE_SMALL); - - /* Check if this is a big key */ - ASSERT_VALUE_BIG(Hive, DataSize); - - /* Allocate a data cell */ - *DataCell = HvAllocateCell(Hive, DataSize, StorageType, HCELL_NIL); - if (*DataCell == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES; - - /* Get the actual data */ - CellData = HvGetCell(Hive, *DataCell); - if (!CellData) ASSERT(FALSE); - - /* Copy our buffer into it */ - RtlCopyMemory(CellData, Data, DataSize); - - /* All done */ - return STATUS_SUCCESS; -} - -NTSTATUS -NTAPI -CmpRemoveValueFromList(IN PHHIVE Hive, - IN ULONG Index, - IN OUT PCHILD_LIST ChildList) -{ - ULONG Count; - PCELL_DATA CellData; - HCELL_INDEX NewCell; - PAGED_CODE(); - - /* Sanity check */ - ASSERT((((LONG)Index) >= 0) && (Index <= ChildList->Count)); - - /* Get the new count after removal */ - Count = ChildList->Count - 1; - if (Count > 0) - { - /* Get the actual list array */ - CellData = HvGetCell(Hive, ChildList->List); - if (!CellData) return STATUS_INSUFFICIENT_RESOURCES; - - /* Make sure cells data have been made dirty */ - ASSERT(HvIsCellDirty(Hive, ChildList->List)); - ASSERT(HvIsCellDirty(Hive, CellData->u.KeyList[Index])); - - /* Loop the list */ - while (Index < Count) - { - /* Move everything up */ - CellData->u.KeyList[Index] = CellData->u.KeyList[Index + 1]; - Index++; - } - - /* Re-allocate the cell for the list by decreasing the count */ - NewCell = HvReallocateCell(Hive, - ChildList->List, - Count * sizeof(HCELL_INDEX)); - ASSERT(NewCell != HCELL_NIL); - HvReleaseCell(Hive,ChildList->List); - - /* Update the list cell */ - ChildList->List = NewCell; - } - else - { - /* Otherwise, we were the last entry, so free the list entirely */ - HvFreeCell(Hive, ChildList->List); - ChildList->List = HCELL_NIL; - } - - /* Update the child list with the new count */ - ChildList->Count = Count; - return STATUS_SUCCESS; -} +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmvalue.c + * PURPOSE: Configuration Manager - Cell Values + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#define NDEBUG +#include "debug.h" + +/* FUNCTIONS *****************************************************************/ + +BOOLEAN +NTAPI +CmpMarkValueDataDirty(IN PHHIVE Hive, + IN PCM_KEY_VALUE Value) +{ + ULONG KeySize; + PAGED_CODE(); + + /* Make sure there's actually any data */ + if (Value->Data != HCELL_NIL) + { + /* If this is a small key, there's no need to have it dirty */ + if (CmpIsKeyValueSmall(&KeySize, Value->DataLength)) return TRUE; + + /* Check if this is a big key */ + ASSERT_VALUE_BIG(Hive, KeySize); + + /* Normal value, just mark it dirty */ + HvMarkCellDirty(Hive, Value->Data, FALSE); + } + + /* Operation complete */ + return TRUE; +} + +BOOLEAN +NTAPI +CmpFreeValueData(IN PHHIVE Hive, + IN HCELL_INDEX DataCell, + IN ULONG DataLength) +{ + ULONG KeySize; + PAGED_CODE(); + + /* If this is a small key, the data is built-in */ + if (!CmpIsKeyValueSmall(&KeySize, DataLength)) + { + /* If there's no data cell, there's nothing to do */ + if (DataCell == HCELL_NIL) return TRUE; + + /* Make sure the data cell is allocated */ + //ASSERT(HvIsCellAllocated(Hive, DataCell)); + + /* Unsupported value type */ + ASSERT_VALUE_BIG(Hive, KeySize); + + /* Normal value, just free the data cell */ + HvFreeCell(Hive, DataCell); + } + + /* Operation complete */ + return TRUE; +} + +BOOLEAN +NTAPI +CmpFreeValue(IN PHHIVE Hive, + IN HCELL_INDEX Cell) +{ + PCM_KEY_VALUE Value; + PAGED_CODE(); + + /* Get the cell data */ + Value = (PCM_KEY_VALUE)HvGetCell(Hive, Cell); + if (!Value) ASSERT(FALSE); + + /* Free it */ + if (!CmpFreeValueData(Hive, Value->Data, Value->DataLength)) + { + /* We failed to free the data, return failure */ + HvReleaseCell(Hive, Cell); + return FALSE; + } + + /* Release the cell and free it */ + HvReleaseCell(Hive, Cell); + HvFreeCell(Hive, Cell); + return TRUE; +} + +HCELL_INDEX +NTAPI +CmpFindValueByName(IN PHHIVE Hive, + IN PCM_KEY_NODE KeyNode, + IN PUNICODE_STRING Name) +{ + HCELL_INDEX CellIndex; + + /* Call the main function */ + if (!CmpFindNameInList(Hive, + &KeyNode->ValueList, + Name, + NULL, + &CellIndex)) + { + /* Santy check */ + ASSERT(CellIndex == HCELL_NIL); + } + + /* Return the index */ + return CellIndex; +} + +BOOLEAN +NTAPI +CmpGetValueData(IN PHHIVE Hive, + IN PCM_KEY_VALUE Value, + IN PULONG Length, + OUT PVOID *Buffer, + OUT PBOOLEAN BufferAllocated, + OUT PHCELL_INDEX CellToRelease) +{ + PAGED_CODE(); + + /* Sanity check */ + ASSERT(Value->Signature == CM_KEY_VALUE_SIGNATURE); + + /* Set failure defaults */ + *BufferAllocated = FALSE; + *Buffer = NULL; + *CellToRelease = HCELL_NIL; + + /* Check if this is a small key */ + if (CmpIsKeyValueSmall(Length, Value->DataLength)) + { + /* Return the data immediately */ + *Buffer = &Value->Data; + return TRUE; + } + + /* Unsupported */ + ASSERT_VALUE_BIG(Hive, *Length); + + /* Get the data from the cell */ + *Buffer = HvGetCell(Hive, Value->Data); + if (!(*Buffer)) return FALSE; + + /* Return success and the cell to be released */ + *CellToRelease = Value->Data; + return TRUE; +} + +PCELL_DATA +NTAPI +CmpValueToData(IN PHHIVE Hive, + IN PCM_KEY_VALUE Value, + OUT PULONG Length) +{ + PCELL_DATA Buffer; + BOOLEAN BufferAllocated; + HCELL_INDEX CellToRelease; + PAGED_CODE(); + + /* Sanity check */ + ASSERT(Hive->ReleaseCellRoutine == NULL); + + /* Get the actual data */ + if (!CmpGetValueData(Hive, + Value, + Length, + (PVOID)&Buffer, + &BufferAllocated, + &CellToRelease)) + { + /* We failed */ + ASSERT(BufferAllocated == FALSE); + ASSERT(Buffer == NULL); + return NULL; + } + + /* This should never happen!*/ + if (BufferAllocated) + { + /* Free the buffer and bugcheck */ + ExFreePool(Buffer); + KEBUGCHECKEX(REGISTRY_ERROR, 8, 0, (ULONG_PTR)Hive, (ULONG_PTR)Value); + } + + /* Otherwise, return the cell data */ + return Buffer; +} + +NTSTATUS +NTAPI +CmpAddValueToList(IN PHHIVE Hive, + IN HCELL_INDEX ValueCell, + IN ULONG Index, + IN ULONG Type, + IN OUT PCHILD_LIST ChildList) +{ + HCELL_INDEX ListCell; + ULONG ChildCount, Length, i; + PCELL_DATA CellData; + PAGED_CODE(); + + /* Sanity check */ + ASSERT((((LONG)Index) >= 0) && (Index <= ChildList->Count)); + + /* Get the number of entries in the child list */ + ChildCount = ChildList->Count; + ChildCount++; + if (ChildCount > 1) + { + /* The cell should be dirty at this point */ + ASSERT(HvIsCellDirty(Hive, ChildList->List)); + + /* Check if we have less then 100 children */ + if (ChildCount < 100) + { + /* Allocate just enough as requested */ + Length = ChildCount * sizeof(HCELL_INDEX); + } + else + { + /* Otherwise, we have quite a few, so allocate a batch */ + Length = ROUND_UP(ChildCount, 100) * sizeof(HCELL_INDEX); + if (Length > HBLOCK_SIZE) + { + /* But make sure we don't allocate beyond our block size */ + Length = ROUND_UP(Length, HBLOCK_SIZE); + } + } + + /* Perform the allocation */ + ListCell = HvReallocateCell(Hive, ChildList->List, Length); + } + else + { + /* This is our first child, so allocate a single cell */ + ListCell = HvAllocateCell(Hive, sizeof(HCELL_INDEX), Type, HCELL_NIL); + } + + /* Fail if we couldn't get a cell */ + if (ListCell == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES; + + /* Set this cell as the child list's list cell */ + ChildList->List = ListCell; + + /* Get the actual key list memory */ + CellData = HvGetCell(Hive, ListCell); + ASSERT(CellData != NULL); + + /* Loop all the children */ + for (i = ChildCount - 1; i > Index; i--) + { + /* Move them all down */ + CellData->u.KeyList[i] = CellData->u.KeyList[i - 1]; + } + + /* Insert us on top now */ + CellData->u.KeyList[Index] = ValueCell; + ChildList->Count = ChildCount; + + /* Release the list cell and make sure the value cell is dirty */ + HvReleaseCell(Hive, ListCell); + ASSERT(HvIsCellDirty(Hive, ValueCell)); + + /* We're done here */ + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +CmpSetValueDataNew(IN PHHIVE Hive, + IN PVOID Data, + IN ULONG DataSize, + IN ULONG StorageType, + IN HCELL_INDEX ValueCell, + OUT PHCELL_INDEX DataCell) +{ + PCELL_DATA CellData; + PAGED_CODE(); + ASSERT(DataSize > CM_KEY_VALUE_SMALL); + + /* Check if this is a big key */ + ASSERT_VALUE_BIG(Hive, DataSize); + + /* Allocate a data cell */ + *DataCell = HvAllocateCell(Hive, DataSize, StorageType, HCELL_NIL); + if (*DataCell == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES; + + /* Get the actual data */ + CellData = HvGetCell(Hive, *DataCell); + if (!CellData) ASSERT(FALSE); + + /* Copy our buffer into it */ + RtlCopyMemory(CellData, Data, DataSize); + + /* All done */ + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +CmpRemoveValueFromList(IN PHHIVE Hive, + IN ULONG Index, + IN OUT PCHILD_LIST ChildList) +{ + ULONG Count; + PCELL_DATA CellData; + HCELL_INDEX NewCell; + PAGED_CODE(); + + /* Sanity check */ + ASSERT((((LONG)Index) >= 0) && (Index <= ChildList->Count)); + + /* Get the new count after removal */ + Count = ChildList->Count - 1; + if (Count > 0) + { + /* Get the actual list array */ + CellData = HvGetCell(Hive, ChildList->List); + if (!CellData) return STATUS_INSUFFICIENT_RESOURCES; + + /* Make sure cells data have been made dirty */ + ASSERT(HvIsCellDirty(Hive, ChildList->List)); + ASSERT(HvIsCellDirty(Hive, CellData->u.KeyList[Index])); + + /* Loop the list */ + while (Index < Count) + { + /* Move everything up */ + CellData->u.KeyList[Index] = CellData->u.KeyList[Index + 1]; + Index++; + } + + /* Re-allocate the cell for the list by decreasing the count */ + NewCell = HvReallocateCell(Hive, + ChildList->List, + Count * sizeof(HCELL_INDEX)); + ASSERT(NewCell != HCELL_NIL); + HvReleaseCell(Hive,ChildList->List); + + /* Update the list cell */ + ChildList->List = NewCell; + } + else + { + /* Otherwise, we were the last entry, so free the list entirely */ + HvFreeCell(Hive, ChildList->List); + ChildList->List = HCELL_NIL; + } + + /* Update the child list with the new count */ + ChildList->Count = Count; + return STATUS_SUCCESS; +} diff --git a/reactos/ntoskrnl/config/cmwraprs.c b/reactos/ntoskrnl/config/cmwraprs.c index 27d17dd57ac..33be0dcec4f 100644 --- a/reactos/ntoskrnl/config/cmwraprs.c +++ b/reactos/ntoskrnl/config/cmwraprs.c @@ -1,159 +1,158 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/config/cmwraprs.c - * PURPOSE: Configuration Manager - Wrappers for Hive Operations - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include "ntoskrnl.h" -#include "cm.h" -#define NDEBUG -#include "debug.h" - -/* FUNCTIONS *****************************************************************/ - -NTSTATUS -NTAPI -CmpCreateEvent(IN EVENT_TYPE EventType, - OUT PHANDLE EventHandle, - OUT PKEVENT *Event) -{ - NTSTATUS Status; - OBJECT_ATTRIBUTES ObjectAttributes; - - /* Create the event */ - InitializeObjectAttributes(&ObjectAttributes, - NULL, - OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, - NULL, - NULL); - Status = ZwCreateEvent(EventHandle, - EVENT_ALL_ACCESS, - &ObjectAttributes, - EventType, - FALSE); - if (!NT_SUCCESS(Status)) return Status; - - /* Get a pointer to the object itself */ - Status = ObReferenceObjectByHandle(*EventHandle, - EVENT_ALL_ACCESS, - NULL, - KernelMode, - (PVOID*)Event, - NULL); - if (!NT_SUCCESS(Status)) ZwClose(*EventHandle); - - /* Return status */ - return Status; -} - -PVOID -NTAPI -CmpAllocate(IN ULONG Size, - IN BOOLEAN Paged, - IN ULONG Tag) -{ - return ExAllocatePoolWithTag(Paged ? PagedPool : NonPagedPool, - Size, - Tag); -} - -VOID -NTAPI -CmpFree(IN PVOID Ptr, - IN ULONG Quota) -{ - ExFreePool(Ptr); -} - -BOOLEAN -NTAPI -CmpFileRead(IN PHHIVE RegistryHive, - IN ULONG FileType, - IN PULONG FileOffset, - OUT PVOID Buffer, - IN SIZE_T BufferLength) -{ - PCMHIVE CmHive = (PCMHIVE)RegistryHive; - HANDLE HiveHandle = CmHive->FileHandles[FileType]; - LARGE_INTEGER _FileOffset; - IO_STATUS_BLOCK IoStatusBlock; - NTSTATUS Status; - - _FileOffset.QuadPart = *FileOffset; - Status = ZwReadFile(HiveHandle, 0, 0, 0, &IoStatusBlock, - Buffer, BufferLength, &_FileOffset, 0); - return NT_SUCCESS(Status) ? TRUE : FALSE; -} - -BOOLEAN -NTAPI -CmpFileWrite(IN PHHIVE RegistryHive, - IN ULONG FileType, - IN PULONG FileOffset, - IN PVOID Buffer, - IN SIZE_T BufferLength) -{ - PCMHIVE CmHive = (PCMHIVE)RegistryHive; - HANDLE HiveHandle = CmHive->FileHandles[FileType]; - LARGE_INTEGER _FileOffset; - IO_STATUS_BLOCK IoStatusBlock; - NTSTATUS Status; - - _FileOffset.QuadPart = *FileOffset; - Status = ZwWriteFile(HiveHandle, 0, 0, 0, &IoStatusBlock, - Buffer, BufferLength, &_FileOffset, 0); - return NT_SUCCESS(Status) ? TRUE : FALSE; -} - -BOOLEAN -NTAPI -CmpFileSetSize(IN PHHIVE RegistryHive, - IN ULONG FileType, - IN ULONG FileSize, - IN ULONG OldFileSize) -{ - PCMHIVE CmHive = (PCMHIVE)RegistryHive; - HANDLE HiveHandle = CmHive->FileHandles[FileType]; - FILE_END_OF_FILE_INFORMATION EndOfFileInfo; - FILE_ALLOCATION_INFORMATION FileAllocationInfo; - IO_STATUS_BLOCK IoStatusBlock; - NTSTATUS Status; - - EndOfFileInfo.EndOfFile.QuadPart = FileSize; - Status = ZwSetInformationFile(HiveHandle, - &IoStatusBlock, - &EndOfFileInfo, - sizeof(FILE_END_OF_FILE_INFORMATION), - FileEndOfFileInformation); - if (!NT_SUCCESS(Status)) return FALSE; - - FileAllocationInfo.AllocationSize.QuadPart = FileSize; - Status = ZwSetInformationFile(HiveHandle, - &IoStatusBlock, - &FileAllocationInfo, - sizeof(FILE_ALLOCATION_INFORMATION), - FileAllocationInformation); - if (!NT_SUCCESS(Status)) return FALSE; - - return TRUE; -} - -BOOLEAN -NTAPI -CmpFileFlush(IN PHHIVE RegistryHive, - IN ULONG FileType, - IN OUT PLARGE_INTEGER FileOffset, - IN ULONG Length) -{ - PCMHIVE CmHive = (PCMHIVE)RegistryHive; - HANDLE HiveHandle = CmHive->FileHandles[FileType]; - IO_STATUS_BLOCK IoStatusBlock; - NTSTATUS Status; - - Status = ZwFlushBuffersFile(HiveHandle, &IoStatusBlock); - return NT_SUCCESS(Status) ? TRUE : FALSE; -} +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmwraprs.c + * PURPOSE: Configuration Manager - Wrappers for Hive Operations + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#define NDEBUG +#include "debug.h" + +/* FUNCTIONS *****************************************************************/ + +NTSTATUS +NTAPI +CmpCreateEvent(IN EVENT_TYPE EventType, + OUT PHANDLE EventHandle, + OUT PKEVENT *Event) +{ + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + + /* Create the event */ + InitializeObjectAttributes(&ObjectAttributes, + NULL, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL); + Status = ZwCreateEvent(EventHandle, + EVENT_ALL_ACCESS, + &ObjectAttributes, + EventType, + FALSE); + if (!NT_SUCCESS(Status)) return Status; + + /* Get a pointer to the object itself */ + Status = ObReferenceObjectByHandle(*EventHandle, + EVENT_ALL_ACCESS, + NULL, + KernelMode, + (PVOID*)Event, + NULL); + if (!NT_SUCCESS(Status)) ZwClose(*EventHandle); + + /* Return status */ + return Status; +} + +PVOID +NTAPI +CmpAllocate(IN ULONG Size, + IN BOOLEAN Paged, + IN ULONG Tag) +{ + return ExAllocatePoolWithTag(Paged ? PagedPool : NonPagedPool, + Size, + Tag); +} + +VOID +NTAPI +CmpFree(IN PVOID Ptr, + IN ULONG Quota) +{ + ExFreePool(Ptr); +} + +BOOLEAN +NTAPI +CmpFileRead(IN PHHIVE RegistryHive, + IN ULONG FileType, + IN PULONG FileOffset, + OUT PVOID Buffer, + IN SIZE_T BufferLength) +{ + PCMHIVE CmHive = (PCMHIVE)RegistryHive; + HANDLE HiveHandle = CmHive->FileHandles[FileType]; + LARGE_INTEGER _FileOffset; + IO_STATUS_BLOCK IoStatusBlock; + NTSTATUS Status; + + _FileOffset.QuadPart = *FileOffset; + Status = ZwReadFile(HiveHandle, 0, 0, 0, &IoStatusBlock, + Buffer, BufferLength, &_FileOffset, 0); + return NT_SUCCESS(Status) ? TRUE : FALSE; +} + +BOOLEAN +NTAPI +CmpFileWrite(IN PHHIVE RegistryHive, + IN ULONG FileType, + IN PULONG FileOffset, + IN PVOID Buffer, + IN SIZE_T BufferLength) +{ + PCMHIVE CmHive = (PCMHIVE)RegistryHive; + HANDLE HiveHandle = CmHive->FileHandles[FileType]; + LARGE_INTEGER _FileOffset; + IO_STATUS_BLOCK IoStatusBlock; + NTSTATUS Status; + + _FileOffset.QuadPart = *FileOffset; + Status = ZwWriteFile(HiveHandle, 0, 0, 0, &IoStatusBlock, + Buffer, BufferLength, &_FileOffset, 0); + return NT_SUCCESS(Status) ? TRUE : FALSE; +} + +BOOLEAN +NTAPI +CmpFileSetSize(IN PHHIVE RegistryHive, + IN ULONG FileType, + IN ULONG FileSize, + IN ULONG OldFileSize) +{ + PCMHIVE CmHive = (PCMHIVE)RegistryHive; + HANDLE HiveHandle = CmHive->FileHandles[FileType]; + FILE_END_OF_FILE_INFORMATION EndOfFileInfo; + FILE_ALLOCATION_INFORMATION FileAllocationInfo; + IO_STATUS_BLOCK IoStatusBlock; + NTSTATUS Status; + + EndOfFileInfo.EndOfFile.QuadPart = FileSize; + Status = ZwSetInformationFile(HiveHandle, + &IoStatusBlock, + &EndOfFileInfo, + sizeof(FILE_END_OF_FILE_INFORMATION), + FileEndOfFileInformation); + if (!NT_SUCCESS(Status)) return FALSE; + + FileAllocationInfo.AllocationSize.QuadPart = FileSize; + Status = ZwSetInformationFile(HiveHandle, + &IoStatusBlock, + &FileAllocationInfo, + sizeof(FILE_ALLOCATION_INFORMATION), + FileAllocationInformation); + if (!NT_SUCCESS(Status)) return FALSE; + + return TRUE; +} + +BOOLEAN +NTAPI +CmpFileFlush(IN PHHIVE RegistryHive, + IN ULONG FileType, + IN OUT PLARGE_INTEGER FileOffset, + IN ULONG Length) +{ + PCMHIVE CmHive = (PCMHIVE)RegistryHive; + HANDLE HiveHandle = CmHive->FileHandles[FileType]; + IO_STATUS_BLOCK IoStatusBlock; + NTSTATUS Status; + + Status = ZwFlushBuffersFile(HiveHandle, &IoStatusBlock); + return NT_SUCCESS(Status) ? TRUE : FALSE; +} diff --git a/reactos/ntoskrnl/config/i386/cmhardwr.c b/reactos/ntoskrnl/config/i386/cmhardwr.c index 482566debaf..c550c97431a 100644 --- a/reactos/ntoskrnl/config/i386/cmhardwr.c +++ b/reactos/ntoskrnl/config/i386/cmhardwr.c @@ -1,834 +1,833 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/config/i386/cmhardwr.c - * PURPOSE: Configuration Manager - Hardware-Specific Code - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include "ntoskrnl.h" -#include "../cm.h" -#define NDEBUG -#include "debug.h" - -/* GLOBALS *******************************************************************/ - -PCHAR CmpID1 = "80%u86-%c%x"; -PCHAR CmpID2 = "x86 Family %u Model %u Stepping %u"; -PCHAR CmpBiosStrings[] = -{ - "Ver", - "Rev", - "Rel", - "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", - "v 0", "v 1", "v 2", "v 3", "v 4", "v 5", "v 6", "v 7", "v 8", "v 9", - NULL -}; - -PCHAR CmpBiosBegin, CmpBiosSearchStart, CmpBiosSearchEnd; - -/* FUNCTIONS *****************************************************************/ - -BOOLEAN -NTAPI -CmpGetBiosDate(IN PCHAR BiosStart, - IN ULONG BiosLength, - IN PCHAR BiosDate, - IN BOOLEAN FromBios) -{ - CHAR LastDate[11] = {0}, CurrentDate[11]; - PCHAR p, pp; - - /* Skip the signature and the magic, and loop the BIOS ROM */ - p = BiosStart + 2; - pp = BiosStart + BiosLength - 5; - while (p < pp) - { - /* Check for xx/yy/zz which we assume to be a date */ - if ((p[0] == '/') && - (p[3] == '/') && - (isdigit(p[-1])) && - (isdigit(p[1])) && - (isdigit(p[2])) && - (isdigit(p[4])) && - (isdigit(p[5]))) - { - /* Copy the string proper */ - RtlMoveMemory(&CurrentDate[5], p - 2, 5); - - /* Add a 0 if the month only has one digit */ - if (!isdigit(CurrentDate[5])) CurrentDate[5] = '0'; - - /* Now copy the year */ - CurrentDate[2] = p[4]; - CurrentDate[3] = p[5]; - CurrentDate[4] = CurrentDate[7] = CurrentDate[10] = ANSI_NULL; - - /* If the date comes from the BIOS, check if it's a 4-digit year */ - if ((FromBios) && - (isdigit(p[6])) && - (isdigit(p[7])) && - ((RtlEqualMemory(&p[4], "19", 2)) || - (RtlEqualMemory(&p[4], "20", 2)))) - { - /* Copy the year proper */ - CurrentDate[0] = p[4]; - CurrentDate[1] = p[5]; - CurrentDate[2] = p[6]; - CurrentDate[3] = p[7]; - } - else - { - /* Otherwise, we'll just assume anything under 80 is 2000 */ - if (strtoul(&CurrentDate[2], NULL, 10) < 80) - { - /* Hopefully your BIOS wasn't made in 1979 */ - CurrentDate[0] = '2'; - CurrentDate[1] = '0'; - } - else - { - /* Anything over 80, was probably made in the 1900s... */ - CurrentDate[0] = '1'; - CurrentDate[1] = '9'; - } - } - - /* Add slashes were we previously had NULLs */ - CurrentDate[4] = CurrentDate[7] = '/'; - - /* Check which date is newer */ - if (memcmp(LastDate, CurrentDate, 10) < 0) - { - /* Found a newer date, select it */ - RtlMoveMemory(LastDate, CurrentDate, 10); - } - - p += 2; - } - p++; - } - - /* Make sure we found a date */ - if (LastDate[0]) - { - /* Copy the year at the pp, and keep only the last two digits */ - RtlMoveMemory(BiosDate, &LastDate[5], 5); - BiosDate[5] = '/'; - BiosDate[6] = LastDate[2]; - BiosDate[7] = LastDate[3]; - BiosDate[8] = ANSI_NULL; - return TRUE; - } - - /* No date found, return empty string */ - BiosDate[0] = ANSI_NULL; - return FALSE; -} - -BOOLEAN -NTAPI -CmpGetBiosVersion(IN PCHAR BiosStart, - IN ULONG BiosLength, - IN PCHAR BiosVersion) -{ - CHAR Buffer[128]; - PCHAR p, pp; - USHORT i; - - /* Check if we were given intitial data for the search */ - if (BiosStart) - { - /* Save it for later use */ - CmpBiosBegin = BiosStart; - CmpBiosSearchStart = BiosStart + 1; - CmpBiosSearchEnd = BiosStart + BiosLength - 2; - } - - /* Now loop the BIOS area */ - for (;;) - { - /* Start an initial search looking for numbers and periods */ - pp = NULL; - while (CmpBiosSearchStart <= CmpBiosSearchEnd) - { - /* Check if we have an "x.y" version string */ - if ((*CmpBiosSearchStart == '.') && - (*(CmpBiosSearchStart + 1) >= '0') && - (*(CmpBiosSearchStart + 1) <= '9') && - (*(CmpBiosSearchStart - 1) >= '0') && - (*(CmpBiosSearchStart - 1) <= '9')) - { - /* Start looking in this area for the actual BIOS Version */ - pp = CmpBiosSearchStart; - break; - } - else - { - /* Keep searching */ - CmpBiosSearchStart++; - } - } - - /* Break out if we're went past the BIOS area */ - if (CmpBiosSearchStart > CmpBiosSearchEnd) return FALSE; - - /* Move to the next 2 bytes */ - CmpBiosSearchStart += 2; - - /* Null-terminate our scratch buffer and start the string here */ - Buffer[127] = ANSI_NULL; - p = &Buffer[127]; - - /* Go back one character since we're doing this backwards */ - pp--; - - /* Loop the identifier we found as long as it's valid */ - i = 0; - while ((i++ < 127) && - (pp >= CmpBiosBegin) && - (*pp >= ' ') && - (*pp != '$')) - { - /* Copy the character */ - *--p = *pp--; - } - - /* Go past the last character since we went backwards */ - pp++; - - /* Loop the strings we recognize */ - for (i = 0; CmpBiosStrings[i]; i++) - { - /* Check if a match was found */ - if (strstr(p, CmpBiosStrings[i])) goto Match; - } - } - -Match: - /* Skip until we find a space */ - for (; *pp == ' '; pp++); - - /* Loop the final string */ - i = 0; - do - { - /* Copy the character into the final string */ - BiosVersion[i] = *pp++; - } while ((++i < 127) && - (pp <= (CmpBiosSearchEnd + 1)) && - (*pp >= ' ') && - (*pp != '$')); - - /* Null-terminate the version string */ - BiosVersion[i] = ANSI_NULL; - return TRUE; -} - -NTSTATUS -NTAPI -CmpInitializeMachineDependentConfiguration(IN PLOADER_PARAMETER_BLOCK LoaderBlock) -{ - UNICODE_STRING KeyName, ValueName, Data, SectionName; - OBJECT_ATTRIBUTES ObjectAttributes; - ULONG HavePae, CacheSize, ViewSize, Length, TotalLength = 0, i, Disposition; - NTSTATUS Status; - HANDLE KeyHandle, BiosHandle, SystemHandle, FpuHandle, SectionHandle; - CONFIGURATION_COMPONENT_DATA ConfigData; - CHAR Buffer[128]; - ULONG ExtendedId, Dummy; - PKPRCB Prcb; - USHORT IndexTable[MaximumType + 1] = {0}; - ANSI_STRING TempString; - PCHAR PartialString = NULL, BiosVersion; - CHAR CpuString[48]; - PVOID BaseAddress = NULL; - LARGE_INTEGER ViewBase = {{0}}; - ULONG_PTR VideoRomBase; - PCHAR CurrentVersion; - extern UNICODE_STRING KeRosProcessorName, KeRosBiosDate, KeRosBiosVersion; - extern UNICODE_STRING KeRosVideoBiosDate, KeRosVideoBiosVersion; - - /* Open the SMSS Memory Management key */ - RtlInitUnicodeString(&KeyName, - L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\" - L"Control\\Session Manager\\Memory Management"); - InitializeObjectAttributes(&ObjectAttributes, - &KeyName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - Status = NtOpenKey(&KeyHandle, KEY_READ | KEY_WRITE, &ObjectAttributes); - if (NT_SUCCESS(Status)) - { - /* Detect if PAE is enabled */ - HavePae = SharedUserData->ProcessorFeatures[PF_PAE_ENABLED]; - - /* Set the value */ - RtlInitUnicodeString(&ValueName, L"PhysicalAddressExtension"); - NtSetValueKey(KeyHandle, - &ValueName, - 0, - REG_DWORD, - &HavePae, - sizeof(HavePae)); - - /* Close the key */ - NtClose(KeyHandle); - } - - /* Open the hardware description key */ - RtlInitUnicodeString(&KeyName, - L"\\Registry\\Machine\\Hardware\\Description\\System"); - InitializeObjectAttributes(&ObjectAttributes, - &KeyName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - Status = NtOpenKey(&SystemHandle, KEY_READ | KEY_WRITE, &ObjectAttributes); - if (!NT_SUCCESS(Status)) return Status; - - /* Create the BIOS Information key */ - RtlInitUnicodeString(&KeyName, - L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\" - L"Control\\BIOSINFO"); - InitializeObjectAttributes(&ObjectAttributes, - &KeyName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - Status = NtCreateKey(&BiosHandle, - KEY_ALL_ACCESS, - &ObjectAttributes, - 0, - NULL, - REG_OPTION_NON_VOLATILE, - &Disposition); - if (ExpInTextModeSetup) - { - if (!NT_SUCCESS(Status)) - BiosHandle = NULL; - } - else if (!NT_SUCCESS(Status)) - return Status; - - /* Create the CPU Key, and check if it already existed */ - RtlInitUnicodeString(&KeyName, L"CentralProcessor"); - InitializeObjectAttributes(&ObjectAttributes, - &KeyName, - OBJ_CASE_INSENSITIVE, - SystemHandle, - NULL); - Status = NtCreateKey(&KeyHandle, - KEY_READ | KEY_WRITE, - &ObjectAttributes, - 0, - NULL, - 0, - &Disposition); - NtClose(KeyHandle); - - /* The key shouldn't already exist */ - if (Disposition == REG_CREATED_NEW_KEY) - { - /* Allocate the configuration data for cmconfig.c */ - CmpConfigurationData = ExAllocatePoolWithTag(PagedPool, - CmpConfigurationAreaSize, - TAG_CM); - if (!CmpConfigurationData) return STATUS_INSUFFICIENT_RESOURCES; - - /* Loop all CPUs */ - for (i = 0; i < KeNumberProcessors; i++) - { - /* Get the PRCB */ - Prcb = KiProcessorBlock[i]; - - /* Setup the Configuration Entry for the Processor */ - RtlZeroMemory(&ConfigData, sizeof (ConfigData)); - ConfigData.ComponentEntry.Class = ProcessorClass; - ConfigData.ComponentEntry.Type = CentralProcessor; - ConfigData.ComponentEntry.Key = i; - ConfigData.ComponentEntry.AffinityMask = AFFINITY_MASK(i); - ConfigData.ComponentEntry.Identifier = Buffer; - - /* Check if the CPU doesn't support CPUID */ - if (!Prcb->CpuID) - { - /* Build ID1-style string for older CPUs */ - sprintf(Buffer, - CmpID1, - Prcb->CpuType, - (Prcb->CpuStep >> 8) + 'A', - Prcb->CpuStep & 0xff); - } - else - { - /* Build ID2-style string for newer CPUs */ - sprintf(Buffer, - CmpID2, - Prcb->CpuType, - (Prcb->CpuStep >> 8), - Prcb->CpuStep & 0xff); - } - - /* Save the ID string length now that we've created it */ - ConfigData.ComponentEntry.IdentifierLength = strlen(Buffer) + 1; - - /* Initialize the registry configuration node for it */ - Status = CmpInitializeRegistryNode(&ConfigData, - SystemHandle, - &KeyHandle, - InterfaceTypeUndefined, - 0xFFFFFFFF, - IndexTable); - if (!NT_SUCCESS(Status)) return(Status); - - /* Check if we have an FPU */ - if (KeI386NpxPresent) - { - /* Setup the Configuration Entry for the FPU */ - RtlZeroMemory(&ConfigData, sizeof(ConfigData)); - ConfigData.ComponentEntry.Class = ProcessorClass; - ConfigData.ComponentEntry.Type = FloatingPointProcessor; - ConfigData.ComponentEntry.Key = i; - ConfigData.ComponentEntry.AffinityMask = AFFINITY_MASK(i); - ConfigData.ComponentEntry.Identifier = Buffer; - - /* For 386 cpus, the CPU pp is the identifier */ - if (Prcb->CpuType == 3) strcpy(Buffer, "80387"); - - /* Save the ID string length now that we've created it */ - ConfigData.ComponentEntry.IdentifierLength = strlen(Buffer) + 1; - - /* Initialize the registry configuration node for it */ - Status = CmpInitializeRegistryNode(&ConfigData, - SystemHandle, - &FpuHandle, - InterfaceTypeUndefined, - 0xFFFFFFFF, - IndexTable); - if (!NT_SUCCESS(Status)) - { - /* Failed, close the CPU handle and return */ - NtClose(KeyHandle); - return Status; - } - - /* Close this new handle */ - NtClose(FpuHandle); - - /* Stay on this CPU only */ - KeSetSystemAffinityThread(Prcb->SetMember); - if (!Prcb->CpuID) - { - /* Uh oh, no CPUID! */ - } - else - { - /* Check if we have extended CPUID that supports name ID */ - Ki386Cpuid(0x80000000, &ExtendedId, &Dummy, &Dummy, &Dummy); - if (ExtendedId >= 0x80000004) - { - /* Do all the CPUIDs requred to get the full name */ - PartialString = CpuString; - for (ExtendedId = 2; ExtendedId <= 4; ExtendedId++) - { - /* Do the CPUID and save the name string */ - Ki386Cpuid(0x80000000 | ExtendedId, - (PULONG)PartialString, - (PULONG)PartialString + 1, - (PULONG)PartialString + 2, - (PULONG)PartialString + 3); - - /* Go to the next name string */ - PartialString += 16; - } - - /* Null-terminate it */ - CpuString[48] = ANSI_NULL; - } - } - - /* Get the cache size while we're still localized */ - CacheSize = ((PKIPCR)KeGetPcr())->SecondLevelCacheSize; - - /* Go back to user affinity */ - KeRevertToUserAffinityThread(); - - /* Check if we have a CPU Name */ - if (PartialString) - { - /* Convert it to Unicode */ - RtlInitAnsiString(&TempString, CpuString); - RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); - - /* Add it to the registry */ - RtlInitUnicodeString(&ValueName, L"ProcessorNameString"); - Status = NtSetValueKey(KeyHandle, - &ValueName, - 0, - REG_SZ, - Data.Buffer, - Data.Length + sizeof(UNICODE_NULL)); - - /* ROS: Save a copy for bugzilla reporting */ - RtlCreateUnicodeString(&KeRosProcessorName, Data.Buffer); - - /* Free the temporary buffer */ - RtlFreeUnicodeString(&Data); - } - - /* Check if we had a Vendor ID */ - if (Prcb->VendorString) - { - /* Convert it to Unicode */ - RtlInitAnsiString(&TempString, Prcb->VendorString); - RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); - - /* Add it to the registry */ - RtlInitUnicodeString(&ValueName, L"VendorIdentifier"); - Status = NtSetValueKey(KeyHandle, - &ValueName, - 0, - REG_SZ, - Data.Buffer, - Data.Length + sizeof(UNICODE_NULL)); - - /* Free the temporary buffer */ - RtlFreeUnicodeString(&Data); - } - - /* Check if we have features bits */ - if (Prcb->FeatureBits) - { - /* Add them to the registry */ - RtlInitUnicodeString(&ValueName, L"FeatureSet"); - Status = NtSetValueKey(KeyHandle, - &ValueName, - 0, - REG_DWORD, - &Prcb->FeatureBits, - sizeof(Prcb->FeatureBits)); - } - - /* Check if we detected the CPU Speed */ - if (Prcb->MHz) - { - /* Add it to the registry */ - RtlInitUnicodeString(&ValueName, L"~MHz"); - Status = NtSetValueKey(KeyHandle, - &ValueName, - 0, - REG_DWORD, - &Prcb->MHz, - sizeof(Prcb->MHz)); - } - - /* Check if we have an update signature */ - if (Prcb->UpdateSignature.QuadPart) - { - /* Add it to the registry */ - RtlInitUnicodeString(&ValueName, L"Update Signature"); - Status = NtSetValueKey(KeyHandle, - &ValueName, - 0, - REG_BINARY, - &Prcb->UpdateSignature, - sizeof(Prcb->UpdateSignature)); - } - - /* Close the processor handle */ - NtClose(KeyHandle); - - /* FIXME: Detect CPU mismatches */ - } - } - - /* Free the configuration data */ - ExFreePool(CmpConfigurationData); - } - - /* Open physical memory */ - RtlInitUnicodeString(&SectionName, L"\\Device\\PhysicalMemory"); - InitializeObjectAttributes(&ObjectAttributes, - &SectionName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - Status = ZwOpenSection(&SectionHandle, - SECTION_ALL_ACCESS, - &ObjectAttributes); - if (!NT_SUCCESS(Status)) goto Quickie; - - /* Map the first 1KB of memory to get the IVT */ - ViewSize = PAGE_SIZE; - Status = ZwMapViewOfSection(SectionHandle, - NtCurrentProcess(), - &BaseAddress, - 0, - ViewSize, - &ViewBase, - &ViewSize, - ViewUnmap, - MEM_DOS_LIM, - PAGE_READWRITE); - if (!NT_SUCCESS(Status)) - { - /* Assume default */ - VideoRomBase = 0xC0000; - } - else - { - /* Calculate the base address from the vector */ - VideoRomBase = (*((PULONG)BaseAddress + 0x10) >> 12) & 0xFFFF0; - VideoRomBase += *((PULONG)BaseAddress + 0x10) & 0xFFF0; - - /* Now get to the actual ROM Start and make sure it's not invalid*/ - VideoRomBase &= 0xFFFF8000; - if (VideoRomBase < 0xC0000) VideoRomBase = 0xC0000; - - /* And unmap the section */ - ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); - } - - /* Allocate BIOS Version pp Buffer */ - BiosVersion = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, TAG_CM); - - /* Setup settings to map the 64K BIOS ROM */ - BaseAddress = 0; - ViewSize = 16 * PAGE_SIZE; - ViewBase.LowPart = 0xF0000; - ViewBase.HighPart = 0; - - /* Map it */ - Status = ZwMapViewOfSection(SectionHandle, - NtCurrentProcess(), - &BaseAddress, - 0, - ViewSize, - &ViewBase, - &ViewSize, - ViewUnmap, - MEM_DOS_LIM, - PAGE_READWRITE); - if (NT_SUCCESS(Status)) - { - /* Scan the ROM to get the BIOS Date */ - if (CmpGetBiosDate(BaseAddress, 16 * PAGE_SIZE, Buffer, TRUE)) - { - /* Convert it to Unicode */ - RtlInitAnsiString(&TempString, Buffer); - RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); - - /* Write the date into the registry */ - RtlInitUnicodeString(&ValueName, L"SystemBiosDate"); - Status = NtSetValueKey(SystemHandle, - &ValueName, - 0, - REG_SZ, - Data.Buffer, - Data.Length + sizeof(UNICODE_NULL)); - - /* Free the string */ - RtlFreeUnicodeString(&Data); - - if (BiosHandle) - { - /* Get the BIOS Date Identifier */ - RtlCopyMemory(Buffer, (PCHAR)BaseAddress + (16*PAGE_SIZE - 11), 8); - Buffer[8] = ANSI_NULL; - - /* Convert it to unicode */ - RtlInitAnsiString(&TempString, Buffer); - Status = RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); - if (NT_SUCCESS(Status)) - { - /* Save it to the registry */ - Status = NtSetValueKey(BiosHandle, - &ValueName, - 0, - REG_SZ, - Data.Buffer, - Data.Length + sizeof(UNICODE_NULL)); - - /* ROS: Save a copy for bugzilla reporting */ - RtlCreateUnicodeString(&KeRosBiosDate, Data.Buffer); - - /* Free the string */ - RtlFreeUnicodeString(&Data); - } - - /* Close the bios information handle */ - NtClose(BiosHandle); - } - } - - /* Get the BIOS Version */ - if (CmpGetBiosVersion(BaseAddress, 16* PAGE_SIZE, Buffer)) - { - /* Start at the beginning of our buffer */ - CurrentVersion = BiosVersion; - do - { - /* Convert to Unicode */ - RtlInitAnsiString(&TempString, Buffer); - RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); - - /* Calculate the length of this string and copy it in */ - Length = Data.Length + sizeof(UNICODE_NULL); - RtlMoveMemory(CurrentVersion, Data.Buffer, Length); - - /* Free the unicode string */ - RtlFreeUnicodeString(&Data); - - /* Update the total length and see if we're out of space */ - TotalLength += Length; - if (TotalLength + 256 + sizeof(UNICODE_NULL) > PAGE_SIZE) - { - /* One more string would push us out, so stop here */ - break; - } - - /* Go to the next string inside the multi-string buffer */ - CurrentVersion += Length; - - /* Query the next BIOS Version */ - } while (CmpGetBiosVersion(NULL, 0, Buffer)); - - /* Check if we found any strings at all */ - if (TotalLength) - { - /* Add the final null-terminator */ - *(PWSTR)CurrentVersion = UNICODE_NULL; - TotalLength += sizeof(UNICODE_NULL); - - /* Write the BIOS Version to the registry */ - RtlInitUnicodeString(&ValueName, L"SystemBiosVersion"); - Status = NtSetValueKey(SystemHandle, - &ValueName, - 0, - REG_MULTI_SZ, - BiosVersion, - TotalLength); - - /* ROS: Save a copy for bugzilla reporting */ - RtlCreateUnicodeString(&KeRosBiosVersion, (PWCH)BiosVersion); - } - } - - /* Unmap the section */ - ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); - } - - /* Now prepare for Video BIOS Mapping of 32KB */ - BaseAddress = 0; - ViewSize = 8 * PAGE_SIZE; - ViewBase.LowPart = VideoRomBase; - ViewBase.HighPart = 0; - - /* Map it */ - Status = ZwMapViewOfSection(SectionHandle, - NtCurrentProcess(), - &BaseAddress, - 0, - ViewSize, - &ViewBase, - &ViewSize, - ViewUnmap, - MEM_DOS_LIM, - PAGE_READWRITE); - if (NT_SUCCESS(Status)) - { - /* Scan the ROM to get the BIOS Date */ - if (CmpGetBiosDate(BaseAddress, 8 * PAGE_SIZE, Buffer, FALSE)) - { - /* Convert it to Unicode */ - RtlInitAnsiString(&TempString, Buffer); - RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); - - /* Write the date into the registry */ - RtlInitUnicodeString(&ValueName, L"VideoBiosDate"); - Status = NtSetValueKey(SystemHandle, - &ValueName, - 0, - REG_SZ, - Data.Buffer, - Data.Length + sizeof(UNICODE_NULL)); - - /* ROS: Save a copy for bugzilla reporting */ - RtlCreateUnicodeString(&KeRosVideoBiosDate, Data.Buffer); - - /* Free the string */ - RtlFreeUnicodeString(&Data); - } - - /* Get the Video BIOS Version */ - if (CmpGetBiosVersion(BaseAddress, 8* PAGE_SIZE, Buffer)) - { - /* Start at the beginning of our buffer */ - CurrentVersion = BiosVersion; - do - { - /* Convert to Unicode */ - RtlInitAnsiString(&TempString, Buffer); - RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); - - /* Calculate the length of this string and copy it in */ - Length = Data.Length + sizeof(UNICODE_NULL); - RtlMoveMemory(CurrentVersion, Data.Buffer, Length); - - /* Free the unicode string */ - RtlFreeUnicodeString(&Data); - - /* Update the total length and see if we're out of space */ - TotalLength += Length; - if (TotalLength + 256 + sizeof(UNICODE_NULL) > PAGE_SIZE) - { - /* One more string would push us out, so stop here */ - break; - } - - /* Go to the next string inside the multi-string buffer */ - CurrentVersion += Length; - - /* Query the next BIOS Version */ - } while (CmpGetBiosVersion(NULL, 0, Buffer)); - - /* Check if we found any strings at all */ - if (TotalLength) - { - /* Add the final null-terminator */ - *(PWSTR)CurrentVersion = UNICODE_NULL; - TotalLength += sizeof(UNICODE_NULL); - - /* Write the BIOS Version to the registry */ - RtlInitUnicodeString(&ValueName, L"VideoBiosVersion"); - Status = NtSetValueKey(SystemHandle, - &ValueName, - 0, - REG_MULTI_SZ, - BiosVersion, - TotalLength); - - /* ROS: Save a copy for bugzilla reporting */ - RtlCreateUnicodeString(&KeRosVideoBiosVersion, (PWCH)BiosVersion); - } - } - - /* Unmap the section */ - ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); - } - - /* Close the section */ - ZwClose(SectionHandle); - - /* Free the BIOS version string buffer */ - if (BiosVersion) ExFreePool(BiosVersion); - -Quickie: - /* Close the procesor handle */ - NtClose(KeyHandle); - return STATUS_SUCCESS; -} +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/i386/cmhardwr.c + * PURPOSE: Configuration Manager - Hardware-Specific Code + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#define NDEBUG +#include "debug.h" + +/* GLOBALS *******************************************************************/ + +PCHAR CmpID1 = "80%u86-%c%x"; +PCHAR CmpID2 = "x86 Family %u Model %u Stepping %u"; +PCHAR CmpBiosStrings[] = +{ + "Ver", + "Rev", + "Rel", + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", + "v 0", "v 1", "v 2", "v 3", "v 4", "v 5", "v 6", "v 7", "v 8", "v 9", + NULL +}; + +PCHAR CmpBiosBegin, CmpBiosSearchStart, CmpBiosSearchEnd; + +/* FUNCTIONS *****************************************************************/ + +BOOLEAN +NTAPI +CmpGetBiosDate(IN PCHAR BiosStart, + IN ULONG BiosLength, + IN PCHAR BiosDate, + IN BOOLEAN FromBios) +{ + CHAR LastDate[11] = {0}, CurrentDate[11]; + PCHAR p, pp; + + /* Skip the signature and the magic, and loop the BIOS ROM */ + p = BiosStart + 2; + pp = BiosStart + BiosLength - 5; + while (p < pp) + { + /* Check for xx/yy/zz which we assume to be a date */ + if ((p[0] == '/') && + (p[3] == '/') && + (isdigit(p[-1])) && + (isdigit(p[1])) && + (isdigit(p[2])) && + (isdigit(p[4])) && + (isdigit(p[5]))) + { + /* Copy the string proper */ + RtlMoveMemory(&CurrentDate[5], p - 2, 5); + + /* Add a 0 if the month only has one digit */ + if (!isdigit(CurrentDate[5])) CurrentDate[5] = '0'; + + /* Now copy the year */ + CurrentDate[2] = p[4]; + CurrentDate[3] = p[5]; + CurrentDate[4] = CurrentDate[7] = CurrentDate[10] = ANSI_NULL; + + /* If the date comes from the BIOS, check if it's a 4-digit year */ + if ((FromBios) && + (isdigit(p[6])) && + (isdigit(p[7])) && + ((RtlEqualMemory(&p[4], "19", 2)) || + (RtlEqualMemory(&p[4], "20", 2)))) + { + /* Copy the year proper */ + CurrentDate[0] = p[4]; + CurrentDate[1] = p[5]; + CurrentDate[2] = p[6]; + CurrentDate[3] = p[7]; + } + else + { + /* Otherwise, we'll just assume anything under 80 is 2000 */ + if (strtoul(&CurrentDate[2], NULL, 10) < 80) + { + /* Hopefully your BIOS wasn't made in 1979 */ + CurrentDate[0] = '2'; + CurrentDate[1] = '0'; + } + else + { + /* Anything over 80, was probably made in the 1900s... */ + CurrentDate[0] = '1'; + CurrentDate[1] = '9'; + } + } + + /* Add slashes were we previously had NULLs */ + CurrentDate[4] = CurrentDate[7] = '/'; + + /* Check which date is newer */ + if (memcmp(LastDate, CurrentDate, 10) < 0) + { + /* Found a newer date, select it */ + RtlMoveMemory(LastDate, CurrentDate, 10); + } + + p += 2; + } + p++; + } + + /* Make sure we found a date */ + if (LastDate[0]) + { + /* Copy the year at the pp, and keep only the last two digits */ + RtlMoveMemory(BiosDate, &LastDate[5], 5); + BiosDate[5] = '/'; + BiosDate[6] = LastDate[2]; + BiosDate[7] = LastDate[3]; + BiosDate[8] = ANSI_NULL; + return TRUE; + } + + /* No date found, return empty string */ + BiosDate[0] = ANSI_NULL; + return FALSE; +} + +BOOLEAN +NTAPI +CmpGetBiosVersion(IN PCHAR BiosStart, + IN ULONG BiosLength, + IN PCHAR BiosVersion) +{ + CHAR Buffer[128]; + PCHAR p, pp; + USHORT i; + + /* Check if we were given intitial data for the search */ + if (BiosStart) + { + /* Save it for later use */ + CmpBiosBegin = BiosStart; + CmpBiosSearchStart = BiosStart + 1; + CmpBiosSearchEnd = BiosStart + BiosLength - 2; + } + + /* Now loop the BIOS area */ + for (;;) + { + /* Start an initial search looking for numbers and periods */ + pp = NULL; + while (CmpBiosSearchStart <= CmpBiosSearchEnd) + { + /* Check if we have an "x.y" version string */ + if ((*CmpBiosSearchStart == '.') && + (*(CmpBiosSearchStart + 1) >= '0') && + (*(CmpBiosSearchStart + 1) <= '9') && + (*(CmpBiosSearchStart - 1) >= '0') && + (*(CmpBiosSearchStart - 1) <= '9')) + { + /* Start looking in this area for the actual BIOS Version */ + pp = CmpBiosSearchStart; + break; + } + else + { + /* Keep searching */ + CmpBiosSearchStart++; + } + } + + /* Break out if we're went past the BIOS area */ + if (CmpBiosSearchStart > CmpBiosSearchEnd) return FALSE; + + /* Move to the next 2 bytes */ + CmpBiosSearchStart += 2; + + /* Null-terminate our scratch buffer and start the string here */ + Buffer[127] = ANSI_NULL; + p = &Buffer[127]; + + /* Go back one character since we're doing this backwards */ + pp--; + + /* Loop the identifier we found as long as it's valid */ + i = 0; + while ((i++ < 127) && + (pp >= CmpBiosBegin) && + (*pp >= ' ') && + (*pp != '$')) + { + /* Copy the character */ + *--p = *pp--; + } + + /* Go past the last character since we went backwards */ + pp++; + + /* Loop the strings we recognize */ + for (i = 0; CmpBiosStrings[i]; i++) + { + /* Check if a match was found */ + if (strstr(p, CmpBiosStrings[i])) goto Match; + } + } + +Match: + /* Skip until we find a space */ + for (; *pp == ' '; pp++); + + /* Loop the final string */ + i = 0; + do + { + /* Copy the character into the final string */ + BiosVersion[i] = *pp++; + } while ((++i < 127) && + (pp <= (CmpBiosSearchEnd + 1)) && + (*pp >= ' ') && + (*pp != '$')); + + /* Null-terminate the version string */ + BiosVersion[i] = ANSI_NULL; + return TRUE; +} + +NTSTATUS +NTAPI +CmpInitializeMachineDependentConfiguration(IN PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + UNICODE_STRING KeyName, ValueName, Data, SectionName; + OBJECT_ATTRIBUTES ObjectAttributes; + ULONG HavePae, CacheSize, ViewSize, Length, TotalLength = 0, i, Disposition; + NTSTATUS Status; + HANDLE KeyHandle, BiosHandle, SystemHandle, FpuHandle, SectionHandle; + CONFIGURATION_COMPONENT_DATA ConfigData; + CHAR Buffer[128]; + ULONG ExtendedId, Dummy; + PKPRCB Prcb; + USHORT IndexTable[MaximumType + 1] = {0}; + ANSI_STRING TempString; + PCHAR PartialString = NULL, BiosVersion; + CHAR CpuString[48]; + PVOID BaseAddress = NULL; + LARGE_INTEGER ViewBase = {{0}}; + ULONG_PTR VideoRomBase; + PCHAR CurrentVersion; + extern UNICODE_STRING KeRosProcessorName, KeRosBiosDate, KeRosBiosVersion; + extern UNICODE_STRING KeRosVideoBiosDate, KeRosVideoBiosVersion; + + /* Open the SMSS Memory Management key */ + RtlInitUnicodeString(&KeyName, + L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\" + L"Control\\Session Manager\\Memory Management"); + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + Status = NtOpenKey(&KeyHandle, KEY_READ | KEY_WRITE, &ObjectAttributes); + if (NT_SUCCESS(Status)) + { + /* Detect if PAE is enabled */ + HavePae = SharedUserData->ProcessorFeatures[PF_PAE_ENABLED]; + + /* Set the value */ + RtlInitUnicodeString(&ValueName, L"PhysicalAddressExtension"); + NtSetValueKey(KeyHandle, + &ValueName, + 0, + REG_DWORD, + &HavePae, + sizeof(HavePae)); + + /* Close the key */ + NtClose(KeyHandle); + } + + /* Open the hardware description key */ + RtlInitUnicodeString(&KeyName, + L"\\Registry\\Machine\\Hardware\\Description\\System"); + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + Status = NtOpenKey(&SystemHandle, KEY_READ | KEY_WRITE, &ObjectAttributes); + if (!NT_SUCCESS(Status)) return Status; + + /* Create the BIOS Information key */ + RtlInitUnicodeString(&KeyName, + L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\" + L"Control\\BIOSINFO"); + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + Status = NtCreateKey(&BiosHandle, + KEY_ALL_ACCESS, + &ObjectAttributes, + 0, + NULL, + REG_OPTION_NON_VOLATILE, + &Disposition); + if (ExpInTextModeSetup) + { + if (!NT_SUCCESS(Status)) + BiosHandle = NULL; + } + else if (!NT_SUCCESS(Status)) + return Status; + + /* Create the CPU Key, and check if it already existed */ + RtlInitUnicodeString(&KeyName, L"CentralProcessor"); + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + SystemHandle, + NULL); + Status = NtCreateKey(&KeyHandle, + KEY_READ | KEY_WRITE, + &ObjectAttributes, + 0, + NULL, + 0, + &Disposition); + NtClose(KeyHandle); + + /* The key shouldn't already exist */ + if (Disposition == REG_CREATED_NEW_KEY) + { + /* Allocate the configuration data for cmconfig.c */ + CmpConfigurationData = ExAllocatePoolWithTag(PagedPool, + CmpConfigurationAreaSize, + TAG_CM); + if (!CmpConfigurationData) return STATUS_INSUFFICIENT_RESOURCES; + + /* Loop all CPUs */ + for (i = 0; i < KeNumberProcessors; i++) + { + /* Get the PRCB */ + Prcb = KiProcessorBlock[i]; + + /* Setup the Configuration Entry for the Processor */ + RtlZeroMemory(&ConfigData, sizeof (ConfigData)); + ConfigData.ComponentEntry.Class = ProcessorClass; + ConfigData.ComponentEntry.Type = CentralProcessor; + ConfigData.ComponentEntry.Key = i; + ConfigData.ComponentEntry.AffinityMask = AFFINITY_MASK(i); + ConfigData.ComponentEntry.Identifier = Buffer; + + /* Check if the CPU doesn't support CPUID */ + if (!Prcb->CpuID) + { + /* Build ID1-style string for older CPUs */ + sprintf(Buffer, + CmpID1, + Prcb->CpuType, + (Prcb->CpuStep >> 8) + 'A', + Prcb->CpuStep & 0xff); + } + else + { + /* Build ID2-style string for newer CPUs */ + sprintf(Buffer, + CmpID2, + Prcb->CpuType, + (Prcb->CpuStep >> 8), + Prcb->CpuStep & 0xff); + } + + /* Save the ID string length now that we've created it */ + ConfigData.ComponentEntry.IdentifierLength = strlen(Buffer) + 1; + + /* Initialize the registry configuration node for it */ + Status = CmpInitializeRegistryNode(&ConfigData, + SystemHandle, + &KeyHandle, + InterfaceTypeUndefined, + 0xFFFFFFFF, + IndexTable); + if (!NT_SUCCESS(Status)) return(Status); + + /* Check if we have an FPU */ + if (KeI386NpxPresent) + { + /* Setup the Configuration Entry for the FPU */ + RtlZeroMemory(&ConfigData, sizeof(ConfigData)); + ConfigData.ComponentEntry.Class = ProcessorClass; + ConfigData.ComponentEntry.Type = FloatingPointProcessor; + ConfigData.ComponentEntry.Key = i; + ConfigData.ComponentEntry.AffinityMask = AFFINITY_MASK(i); + ConfigData.ComponentEntry.Identifier = Buffer; + + /* For 386 cpus, the CPU pp is the identifier */ + if (Prcb->CpuType == 3) strcpy(Buffer, "80387"); + + /* Save the ID string length now that we've created it */ + ConfigData.ComponentEntry.IdentifierLength = strlen(Buffer) + 1; + + /* Initialize the registry configuration node for it */ + Status = CmpInitializeRegistryNode(&ConfigData, + SystemHandle, + &FpuHandle, + InterfaceTypeUndefined, + 0xFFFFFFFF, + IndexTable); + if (!NT_SUCCESS(Status)) + { + /* Failed, close the CPU handle and return */ + NtClose(KeyHandle); + return Status; + } + + /* Close this new handle */ + NtClose(FpuHandle); + + /* Stay on this CPU only */ + KeSetSystemAffinityThread(Prcb->SetMember); + if (!Prcb->CpuID) + { + /* Uh oh, no CPUID! */ + } + else + { + /* Check if we have extended CPUID that supports name ID */ + Ki386Cpuid(0x80000000, &ExtendedId, &Dummy, &Dummy, &Dummy); + if (ExtendedId >= 0x80000004) + { + /* Do all the CPUIDs requred to get the full name */ + PartialString = CpuString; + for (ExtendedId = 2; ExtendedId <= 4; ExtendedId++) + { + /* Do the CPUID and save the name string */ + Ki386Cpuid(0x80000000 | ExtendedId, + (PULONG)PartialString, + (PULONG)PartialString + 1, + (PULONG)PartialString + 2, + (PULONG)PartialString + 3); + + /* Go to the next name string */ + PartialString += 16; + } + + /* Null-terminate it */ + CpuString[48] = ANSI_NULL; + } + } + + /* Get the cache size while we're still localized */ + CacheSize = ((PKIPCR)KeGetPcr())->SecondLevelCacheSize; + + /* Go back to user affinity */ + KeRevertToUserAffinityThread(); + + /* Check if we have a CPU Name */ + if (PartialString) + { + /* Convert it to Unicode */ + RtlInitAnsiString(&TempString, CpuString); + RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); + + /* Add it to the registry */ + RtlInitUnicodeString(&ValueName, L"ProcessorNameString"); + Status = NtSetValueKey(KeyHandle, + &ValueName, + 0, + REG_SZ, + Data.Buffer, + Data.Length + sizeof(UNICODE_NULL)); + + /* ROS: Save a copy for bugzilla reporting */ + RtlCreateUnicodeString(&KeRosProcessorName, Data.Buffer); + + /* Free the temporary buffer */ + RtlFreeUnicodeString(&Data); + } + + /* Check if we had a Vendor ID */ + if (Prcb->VendorString) + { + /* Convert it to Unicode */ + RtlInitAnsiString(&TempString, Prcb->VendorString); + RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); + + /* Add it to the registry */ + RtlInitUnicodeString(&ValueName, L"VendorIdentifier"); + Status = NtSetValueKey(KeyHandle, + &ValueName, + 0, + REG_SZ, + Data.Buffer, + Data.Length + sizeof(UNICODE_NULL)); + + /* Free the temporary buffer */ + RtlFreeUnicodeString(&Data); + } + + /* Check if we have features bits */ + if (Prcb->FeatureBits) + { + /* Add them to the registry */ + RtlInitUnicodeString(&ValueName, L"FeatureSet"); + Status = NtSetValueKey(KeyHandle, + &ValueName, + 0, + REG_DWORD, + &Prcb->FeatureBits, + sizeof(Prcb->FeatureBits)); + } + + /* Check if we detected the CPU Speed */ + if (Prcb->MHz) + { + /* Add it to the registry */ + RtlInitUnicodeString(&ValueName, L"~MHz"); + Status = NtSetValueKey(KeyHandle, + &ValueName, + 0, + REG_DWORD, + &Prcb->MHz, + sizeof(Prcb->MHz)); + } + + /* Check if we have an update signature */ + if (Prcb->UpdateSignature.QuadPart) + { + /* Add it to the registry */ + RtlInitUnicodeString(&ValueName, L"Update Signature"); + Status = NtSetValueKey(KeyHandle, + &ValueName, + 0, + REG_BINARY, + &Prcb->UpdateSignature, + sizeof(Prcb->UpdateSignature)); + } + + /* Close the processor handle */ + NtClose(KeyHandle); + + /* FIXME: Detect CPU mismatches */ + } + } + + /* Free the configuration data */ + ExFreePool(CmpConfigurationData); + } + + /* Open physical memory */ + RtlInitUnicodeString(&SectionName, L"\\Device\\PhysicalMemory"); + InitializeObjectAttributes(&ObjectAttributes, + &SectionName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + Status = ZwOpenSection(&SectionHandle, + SECTION_ALL_ACCESS, + &ObjectAttributes); + if (!NT_SUCCESS(Status)) goto Quickie; + + /* Map the first 1KB of memory to get the IVT */ + ViewSize = PAGE_SIZE; + Status = ZwMapViewOfSection(SectionHandle, + NtCurrentProcess(), + &BaseAddress, + 0, + ViewSize, + &ViewBase, + &ViewSize, + ViewUnmap, + MEM_DOS_LIM, + PAGE_READWRITE); + if (!NT_SUCCESS(Status)) + { + /* Assume default */ + VideoRomBase = 0xC0000; + } + else + { + /* Calculate the base address from the vector */ + VideoRomBase = (*((PULONG)BaseAddress + 0x10) >> 12) & 0xFFFF0; + VideoRomBase += *((PULONG)BaseAddress + 0x10) & 0xFFF0; + + /* Now get to the actual ROM Start and make sure it's not invalid*/ + VideoRomBase &= 0xFFFF8000; + if (VideoRomBase < 0xC0000) VideoRomBase = 0xC0000; + + /* And unmap the section */ + ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); + } + + /* Allocate BIOS Version pp Buffer */ + BiosVersion = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, TAG_CM); + + /* Setup settings to map the 64K BIOS ROM */ + BaseAddress = 0; + ViewSize = 16 * PAGE_SIZE; + ViewBase.LowPart = 0xF0000; + ViewBase.HighPart = 0; + + /* Map it */ + Status = ZwMapViewOfSection(SectionHandle, + NtCurrentProcess(), + &BaseAddress, + 0, + ViewSize, + &ViewBase, + &ViewSize, + ViewUnmap, + MEM_DOS_LIM, + PAGE_READWRITE); + if (NT_SUCCESS(Status)) + { + /* Scan the ROM to get the BIOS Date */ + if (CmpGetBiosDate(BaseAddress, 16 * PAGE_SIZE, Buffer, TRUE)) + { + /* Convert it to Unicode */ + RtlInitAnsiString(&TempString, Buffer); + RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); + + /* Write the date into the registry */ + RtlInitUnicodeString(&ValueName, L"SystemBiosDate"); + Status = NtSetValueKey(SystemHandle, + &ValueName, + 0, + REG_SZ, + Data.Buffer, + Data.Length + sizeof(UNICODE_NULL)); + + /* Free the string */ + RtlFreeUnicodeString(&Data); + + if (BiosHandle) + { + /* Get the BIOS Date Identifier */ + RtlCopyMemory(Buffer, (PCHAR)BaseAddress + (16*PAGE_SIZE - 11), 8); + Buffer[8] = ANSI_NULL; + + /* Convert it to unicode */ + RtlInitAnsiString(&TempString, Buffer); + Status = RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); + if (NT_SUCCESS(Status)) + { + /* Save it to the registry */ + Status = NtSetValueKey(BiosHandle, + &ValueName, + 0, + REG_SZ, + Data.Buffer, + Data.Length + sizeof(UNICODE_NULL)); + + /* ROS: Save a copy for bugzilla reporting */ + RtlCreateUnicodeString(&KeRosBiosDate, Data.Buffer); + + /* Free the string */ + RtlFreeUnicodeString(&Data); + } + + /* Close the bios information handle */ + NtClose(BiosHandle); + } + } + + /* Get the BIOS Version */ + if (CmpGetBiosVersion(BaseAddress, 16* PAGE_SIZE, Buffer)) + { + /* Start at the beginning of our buffer */ + CurrentVersion = BiosVersion; + do + { + /* Convert to Unicode */ + RtlInitAnsiString(&TempString, Buffer); + RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); + + /* Calculate the length of this string and copy it in */ + Length = Data.Length + sizeof(UNICODE_NULL); + RtlMoveMemory(CurrentVersion, Data.Buffer, Length); + + /* Free the unicode string */ + RtlFreeUnicodeString(&Data); + + /* Update the total length and see if we're out of space */ + TotalLength += Length; + if (TotalLength + 256 + sizeof(UNICODE_NULL) > PAGE_SIZE) + { + /* One more string would push us out, so stop here */ + break; + } + + /* Go to the next string inside the multi-string buffer */ + CurrentVersion += Length; + + /* Query the next BIOS Version */ + } while (CmpGetBiosVersion(NULL, 0, Buffer)); + + /* Check if we found any strings at all */ + if (TotalLength) + { + /* Add the final null-terminator */ + *(PWSTR)CurrentVersion = UNICODE_NULL; + TotalLength += sizeof(UNICODE_NULL); + + /* Write the BIOS Version to the registry */ + RtlInitUnicodeString(&ValueName, L"SystemBiosVersion"); + Status = NtSetValueKey(SystemHandle, + &ValueName, + 0, + REG_MULTI_SZ, + BiosVersion, + TotalLength); + + /* ROS: Save a copy for bugzilla reporting */ + RtlCreateUnicodeString(&KeRosBiosVersion, (PWCH)BiosVersion); + } + } + + /* Unmap the section */ + ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); + } + + /* Now prepare for Video BIOS Mapping of 32KB */ + BaseAddress = 0; + ViewSize = 8 * PAGE_SIZE; + ViewBase.LowPart = VideoRomBase; + ViewBase.HighPart = 0; + + /* Map it */ + Status = ZwMapViewOfSection(SectionHandle, + NtCurrentProcess(), + &BaseAddress, + 0, + ViewSize, + &ViewBase, + &ViewSize, + ViewUnmap, + MEM_DOS_LIM, + PAGE_READWRITE); + if (NT_SUCCESS(Status)) + { + /* Scan the ROM to get the BIOS Date */ + if (CmpGetBiosDate(BaseAddress, 8 * PAGE_SIZE, Buffer, FALSE)) + { + /* Convert it to Unicode */ + RtlInitAnsiString(&TempString, Buffer); + RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); + + /* Write the date into the registry */ + RtlInitUnicodeString(&ValueName, L"VideoBiosDate"); + Status = NtSetValueKey(SystemHandle, + &ValueName, + 0, + REG_SZ, + Data.Buffer, + Data.Length + sizeof(UNICODE_NULL)); + + /* ROS: Save a copy for bugzilla reporting */ + RtlCreateUnicodeString(&KeRosVideoBiosDate, Data.Buffer); + + /* Free the string */ + RtlFreeUnicodeString(&Data); + } + + /* Get the Video BIOS Version */ + if (CmpGetBiosVersion(BaseAddress, 8* PAGE_SIZE, Buffer)) + { + /* Start at the beginning of our buffer */ + CurrentVersion = BiosVersion; + do + { + /* Convert to Unicode */ + RtlInitAnsiString(&TempString, Buffer); + RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); + + /* Calculate the length of this string and copy it in */ + Length = Data.Length + sizeof(UNICODE_NULL); + RtlMoveMemory(CurrentVersion, Data.Buffer, Length); + + /* Free the unicode string */ + RtlFreeUnicodeString(&Data); + + /* Update the total length and see if we're out of space */ + TotalLength += Length; + if (TotalLength + 256 + sizeof(UNICODE_NULL) > PAGE_SIZE) + { + /* One more string would push us out, so stop here */ + break; + } + + /* Go to the next string inside the multi-string buffer */ + CurrentVersion += Length; + + /* Query the next BIOS Version */ + } while (CmpGetBiosVersion(NULL, 0, Buffer)); + + /* Check if we found any strings at all */ + if (TotalLength) + { + /* Add the final null-terminator */ + *(PWSTR)CurrentVersion = UNICODE_NULL; + TotalLength += sizeof(UNICODE_NULL); + + /* Write the BIOS Version to the registry */ + RtlInitUnicodeString(&ValueName, L"VideoBiosVersion"); + Status = NtSetValueKey(SystemHandle, + &ValueName, + 0, + REG_MULTI_SZ, + BiosVersion, + TotalLength); + + /* ROS: Save a copy for bugzilla reporting */ + RtlCreateUnicodeString(&KeRosVideoBiosVersion, (PWCH)BiosVersion); + } + } + + /* Unmap the section */ + ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); + } + + /* Close the section */ + ZwClose(SectionHandle); + + /* Free the BIOS version string buffer */ + if (BiosVersion) ExFreePool(BiosVersion); + +Quickie: + /* Close the procesor handle */ + NtClose(KeyHandle); + return STATUS_SUCCESS; +} diff --git a/reactos/ntoskrnl/config/ntapi.c b/reactos/ntoskrnl/config/ntapi.c index a3d6f98055e..17642bbe321 100644 --- a/reactos/ntoskrnl/config/ntapi.c +++ b/reactos/ntoskrnl/config/ntapi.c @@ -9,7 +9,6 @@ /* INCLUDES ******************************************************************/ #include "ntoskrnl.h" -#include "cm.h" #define NDEBUG #include "debug.h" @@ -18,7 +17,6 @@ BOOLEAN CmFirstTime = TRUE; /* FUNCTIONS *****************************************************************/ -#if 0 NTSTATUS NTAPI NtCreateKey(OUT PHANDLE KeyHandle, @@ -32,7 +30,9 @@ NtCreateKey(OUT PHANDLE KeyHandle, NTSTATUS Status; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); CM_PARSE_CONTEXT ParseContext = {0}; + HANDLE Handle; PAGED_CODE(); + DPRINT("NtCreateKey(OB 0x%wZ)\n", ObjectAttributes->ObjectName); /* Setup the parse context */ ParseContext.CreateOperation = TRUE; @@ -46,13 +46,13 @@ NtCreateKey(OUT PHANDLE KeyHandle, NULL, DesiredAccess, &ParseContext, - KeyHandle); + &Handle); + if (NT_SUCCESS(Status)) *KeyHandle = Handle; /* Return data to user */ if (Disposition) *Disposition = ParseContext.Disposition; return Status; } -#endif NTSTATUS NTAPI @@ -61,18 +61,26 @@ NtOpenKey(OUT PHANDLE KeyHandle, IN POBJECT_ATTRIBUTES ObjectAttributes) { CM_PARSE_CONTEXT ParseContext = {0}; + HANDLE Handle; + NTSTATUS Status; PAGED_CODE(); - + DPRINT("NtOpenKey(OB 0x%wZ)\n", ObjectAttributes->ObjectName); + /* Just let the object manager handle this */ - return ObOpenObjectByName(ObjectAttributes, - CmpKeyObjectType, - ExGetPreviousMode(), - NULL, - DesiredAccess, - &ParseContext, - KeyHandle); + Status = ObOpenObjectByName(ObjectAttributes, + CmpKeyObjectType, + ExGetPreviousMode(), + NULL, + DesiredAccess, + &ParseContext, + &Handle); + if (NT_SUCCESS(Status)) *KeyHandle = Handle; + + /* Return status */ + return Status; } + NTSTATUS NTAPI NtDeleteKey(IN HANDLE KeyHandle) diff --git a/reactos/ntoskrnl/config/powerpc/cmhardwr.c b/reactos/ntoskrnl/config/powerpc/cmhardwr.c index 5fa25fff937..a14d90a26e0 100644 --- a/reactos/ntoskrnl/config/powerpc/cmhardwr.c +++ b/reactos/ntoskrnl/config/powerpc/cmhardwr.c @@ -1,834 +1,833 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/config/i386/cmhardwr.c - * PURPOSE: Configuration Manager - Hardware-Specific Code - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include "ntoskrnl.h" -#include "../cm.h" -#define NDEBUG -#include "debug.h" - -/* GLOBALS *******************************************************************/ - -PCHAR CmpID1 = "PowerPC %u"; -PCHAR CmpID2 = "No Data"; -PCHAR CmpBiosStrings[] = -{ - "Ver", - "Rev", - "Rel", - "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", - "v 0", "v 1", "v 2", "v 3", "v 4", "v 5", "v 6", "v 7", "v 8", "v 9", - NULL -}; - -PCHAR CmpBiosBegin, CmpBiosSearchStart, CmpBiosSearchEnd; - -/* FUNCTIONS *****************************************************************/ - -BOOLEAN -NTAPI -CmpGetBiosDate(IN PCHAR BiosStart, - IN ULONG BiosLength, - IN PCHAR BiosDate, - IN BOOLEAN FromBios) -{ - CHAR LastDate[11] = {0}, CurrentDate[11]; - PCHAR p, pp; - - /* Skip the signature and the magic, and loop the BIOS ROM */ - p = BiosStart + 2; - pp = BiosStart + BiosLength - 5; - while (p < pp) - { - /* Check for xx/yy/zz which we assume to be a date */ - if ((p[0] == '/') && - (p[3] == '/') && - (isdigit(p[-1])) && - (isdigit(p[1])) && - (isdigit(p[2])) && - (isdigit(p[4])) && - (isdigit(p[5]))) - { - /* Copy the string proper */ - RtlMoveMemory(&CurrentDate[5], p - 2, 5); - - /* Add a 0 if the month only has one digit */ - if (!isdigit(CurrentDate[5])) CurrentDate[5] = '0'; - - /* Now copy the year */ - CurrentDate[2] = p[4]; - CurrentDate[3] = p[5]; - CurrentDate[4] = CurrentDate[7] = CurrentDate[10] = ANSI_NULL; - - /* If the date comes from the BIOS, check if it's a 4-digit year */ - if ((FromBios) && - (isdigit(p[6])) && - (isdigit(p[7])) && - ((RtlEqualMemory(&p[4], "19", 2)) || - (RtlEqualMemory(&p[4], "20", 2)))) - { - /* Copy the year proper */ - CurrentDate[0] = p[4]; - CurrentDate[1] = p[5]; - CurrentDate[2] = p[6]; - CurrentDate[3] = p[7]; - } - else - { - /* Otherwise, we'll just assume anything under 80 is 2000 */ - if (strtoul(&CurrentDate[2], NULL, 10) < 80) - { - /* Hopefully your BIOS wasn't made in 1979 */ - CurrentDate[0] = '2'; - CurrentDate[1] = '0'; - } - else - { - /* Anything over 80, was probably made in the 1900s... */ - CurrentDate[0] = '1'; - CurrentDate[1] = '9'; - } - } - - /* Add slashes were we previously had NULLs */ - CurrentDate[4] = CurrentDate[7] = '/'; - - /* Check which date is newer */ - if (memcmp(LastDate, CurrentDate, 10) < 0) - { - /* Found a newer date, select it */ - RtlMoveMemory(LastDate, CurrentDate, 10); - } - - p += 2; - } - p++; - } - - /* Make sure we found a date */ - if (LastDate[0]) - { - /* Copy the year at the pp, and keep only the last two digits */ - RtlMoveMemory(BiosDate, &LastDate[5], 5); - BiosDate[5] = '/'; - BiosDate[6] = LastDate[2]; - BiosDate[7] = LastDate[3]; - BiosDate[8] = ANSI_NULL; - return TRUE; - } - - /* No date found, return empty string */ - BiosDate[0] = ANSI_NULL; - return FALSE; -} - -BOOLEAN -NTAPI -CmpGetBiosVersion(IN PCHAR BiosStart, - IN ULONG BiosLength, - IN PCHAR BiosVersion) -{ - CHAR Buffer[128]; - PCHAR p, pp; - USHORT i; - - /* Check if we were given intitial data for the search */ - if (BiosStart) - { - /* Save it for later use */ - CmpBiosBegin = BiosStart; - CmpBiosSearchStart = BiosStart + 1; - CmpBiosSearchEnd = BiosStart + BiosLength - 2; - } - - /* Now loop the BIOS area */ - for (;;) - { - /* Start an initial search looking for numbers and periods */ - pp = NULL; - while (CmpBiosSearchStart <= CmpBiosSearchEnd) - { - /* Check if we have an "x.y" version string */ - if ((*CmpBiosSearchStart == '.') && - (*(CmpBiosSearchStart + 1) >= '0') && - (*(CmpBiosSearchStart + 1) <= '9') && - (*(CmpBiosSearchStart - 1) >= '0') && - (*(CmpBiosSearchStart - 1) <= '9')) - { - /* Start looking in this area for the actual BIOS Version */ - pp = CmpBiosSearchStart; - break; - } - else - { - /* Keep searching */ - CmpBiosSearchStart++; - } - } - - /* Break out if we're went past the BIOS area */ - if (CmpBiosSearchStart > CmpBiosSearchEnd) return FALSE; - - /* Move to the next 2 bytes */ - CmpBiosSearchStart += 2; - - /* Null-terminate our scratch buffer and start the string here */ - Buffer[127] = ANSI_NULL; - p = &Buffer[127]; - - /* Go back one character since we're doing this backwards */ - pp--; - - /* Loop the identifier we found as long as it's valid */ - i = 0; - while ((i++ < 127) && - (pp >= CmpBiosBegin) && - (*pp >= ' ') && - (*pp != '$')) - { - /* Copy the character */ - *--p = *pp--; - } - - /* Go past the last character since we went backwards */ - pp++; - - /* Loop the strings we recognize */ - for (i = 0; CmpBiosStrings[i]; i++) - { - /* Check if a match was found */ - if (strstr(p, CmpBiosStrings[i])) goto Match; - } - } - -Match: - /* Skip until we find a space */ - for (; *pp == ' '; pp++); - - /* Loop the final string */ - i = 0; - do - { - /* Copy the character into the final string */ - BiosVersion[i] = *pp++; - } while ((++i < 127) && - (pp <= (CmpBiosSearchEnd + 1)) && - (*pp >= ' ') && - (*pp != '$')); - - /* Null-terminate the version string */ - BiosVersion[i] = ANSI_NULL; - return TRUE; -} - -NTSTATUS -NTAPI -CmpInitializeMachineDependentConfiguration(IN PLOADER_PARAMETER_BLOCK LoaderBlock) -{ - UNICODE_STRING KeyName, ValueName, Data, SectionName; - OBJECT_ATTRIBUTES ObjectAttributes; - ULONG HavePae, CacheSize, ViewSize, Length, TotalLength = 0, i, Disposition; - NTSTATUS Status; - HANDLE KeyHandle, BiosHandle, SystemHandle, FpuHandle, SectionHandle; - CONFIGURATION_COMPONENT_DATA ConfigData; - CHAR Buffer[128]; - ULONG ExtendedId = 0; //, Dummy; - PKPRCB Prcb; - USHORT IndexTable[MaximumType + 1] = {0}; - ANSI_STRING TempString; - PCHAR PartialString = NULL, BiosVersion; - CHAR CpuString[48]; - PVOID BaseAddress = NULL; - LARGE_INTEGER ViewBase = {{0}}; - ULONG_PTR VideoRomBase; - PCHAR CurrentVersion; - extern UNICODE_STRING KeRosProcessorName, KeRosBiosDate, KeRosBiosVersion; - extern UNICODE_STRING KeRosVideoBiosDate, KeRosVideoBiosVersion; - - /* Open the SMSS Memory Management key */ - RtlInitUnicodeString(&KeyName, - L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\" - L"Control\\Session Manager\\Memory Management"); - InitializeObjectAttributes(&ObjectAttributes, - &KeyName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - Status = NtOpenKey(&KeyHandle, KEY_READ | KEY_WRITE, &ObjectAttributes); - if (NT_SUCCESS(Status)) - { - /* Detect if PAE is enabled */ - HavePae = SharedUserData->ProcessorFeatures[PF_PAE_ENABLED]; - - /* Set the value */ - RtlInitUnicodeString(&ValueName, L"PhysicalAddressExtension"); - NtSetValueKey(KeyHandle, - &ValueName, - 0, - REG_DWORD, - &HavePae, - sizeof(HavePae)); - - /* Close the key */ - NtClose(KeyHandle); - } - - /* Open the hardware description key */ - RtlInitUnicodeString(&KeyName, - L"\\Registry\\Machine\\Hardware\\Description\\System"); - InitializeObjectAttributes(&ObjectAttributes, - &KeyName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - Status = NtOpenKey(&SystemHandle, KEY_READ | KEY_WRITE, &ObjectAttributes); - if (!NT_SUCCESS(Status)) return Status; - - /* Create the BIOS Information key */ - RtlInitUnicodeString(&KeyName, - L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\" - L"Control\\BIOSINFO"); - InitializeObjectAttributes(&ObjectAttributes, - &KeyName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - Status = NtCreateKey(&BiosHandle, - KEY_ALL_ACCESS, - &ObjectAttributes, - 0, - NULL, - REG_OPTION_NON_VOLATILE, - &Disposition); - if (ExpInTextModeSetup) - { - if (!NT_SUCCESS(Status)) - BiosHandle = NULL; - } - else if (!NT_SUCCESS(Status)) - return Status; - - /* Create the CPU Key, and check if it already existed */ - RtlInitUnicodeString(&KeyName, L"CentralProcessor"); - InitializeObjectAttributes(&ObjectAttributes, - &KeyName, - OBJ_CASE_INSENSITIVE, - SystemHandle, - NULL); - Status = NtCreateKey(&KeyHandle, - KEY_READ | KEY_WRITE, - &ObjectAttributes, - 0, - NULL, - 0, - &Disposition); - NtClose(KeyHandle); - - /* The key shouldn't already exist */ - if (Disposition == REG_CREATED_NEW_KEY) - { - /* Allocate the configuration data for cmconfig.c */ - CmpConfigurationData = ExAllocatePoolWithTag(PagedPool, - CmpConfigurationAreaSize, - TAG_CM); - if (!CmpConfigurationData) return STATUS_INSUFFICIENT_RESOURCES; - - /* Loop all CPUs */ - for (i = 0; i < KeNumberProcessors; i++) - { - /* Get the PRCB */ - Prcb = KiProcessorBlock[i]; - - /* Setup the Configuration Entry for the Processor */ - RtlZeroMemory(&ConfigData, sizeof (ConfigData)); - ConfigData.ComponentEntry.Class = ProcessorClass; - ConfigData.ComponentEntry.Type = CentralProcessor; - ConfigData.ComponentEntry.Key = i; - ConfigData.ComponentEntry.AffinityMask = AFFINITY_MASK(i); - ConfigData.ComponentEntry.Identifier = Buffer; - - /* Check if the CPU doesn't support CPUID */ - if (!Prcb->CpuID) - { - /* Build ID1-style string for older CPUs */ - sprintf(Buffer, - CmpID1, - Prcb->CpuType, - (Prcb->CpuStep >> 8) + 'A', - Prcb->CpuStep & 0xff); - } - else - { - /* Build ID2-style string for newer CPUs */ - sprintf(Buffer, - CmpID2, - Prcb->CpuType, - (Prcb->CpuStep >> 8), - Prcb->CpuStep & 0xff); - } - - /* Save the ID string length now that we've created it */ - ConfigData.ComponentEntry.IdentifierLength = strlen(Buffer) + 1; - - /* Initialize the registry configuration node for it */ - Status = CmpInitializeRegistryNode(&ConfigData, - SystemHandle, - &KeyHandle, - InterfaceTypeUndefined, - 0xFFFFFFFF, - IndexTable); - if (!NT_SUCCESS(Status)) return(Status); - - { - /* Setup the Configuration Entry for the FPU */ - RtlZeroMemory(&ConfigData, sizeof(ConfigData)); - ConfigData.ComponentEntry.Class = ProcessorClass; - ConfigData.ComponentEntry.Type = FloatingPointProcessor; - ConfigData.ComponentEntry.Key = i; - ConfigData.ComponentEntry.AffinityMask = AFFINITY_MASK(i); - ConfigData.ComponentEntry.Identifier = Buffer; - - /* For 386 cpus, the CPU pp is the identifier */ - if (Prcb->CpuType == 3) strcpy(Buffer, "80387"); - - /* Save the ID string length now that we've created it */ - ConfigData.ComponentEntry.IdentifierLength = strlen(Buffer) + 1; - - /* Initialize the registry configuration node for it */ - Status = CmpInitializeRegistryNode(&ConfigData, - SystemHandle, - &FpuHandle, - InterfaceTypeUndefined, - 0xFFFFFFFF, - IndexTable); - if (!NT_SUCCESS(Status)) - { - /* Failed, close the CPU handle and return */ - NtClose(KeyHandle); - return Status; - } - - /* Close this new handle */ - NtClose(FpuHandle); - - /* Stay on this CPU only */ - KeSetSystemAffinityThread(Prcb->SetMember); - if (!Prcb->CpuID) - { - /* Uh oh, no CPUID! */ - } - else - { - /* Check if we have extended CPUID that supports name ID */ - //Ki386Cpuid(0x80000000, &ExtendedId, &Dummy, &Dummy, &Dummy); - if (ExtendedId >= 0x80000004) - { - /* Do all the CPUIDs requred to get the full name */ - PartialString = CpuString; - for (ExtendedId = 2; ExtendedId <= 4; ExtendedId++) - { -#if 0 - /* Do the CPUID and save the name string */ - Ki386Cpuid(0x80000000 | ExtendedId, - (PULONG)PartialString, - (PULONG)PartialString + 1, - (PULONG)PartialString + 2, - (PULONG)PartialString + 3); -#endif - - /* Go to the next name string */ - PartialString += 16; - } - - /* Null-terminate it */ - CpuString[48] = ANSI_NULL; - } - } - - /* Get the cache size while we're still localized */ - CacheSize = 0; //((PKIPCR)KeGetPcr())->SecondLevelCacheSize; - - /* Go back to user affinity */ - KeRevertToUserAffinityThread(); - - /* Check if we have a CPU Name */ - if (PartialString) - { - /* Convert it to Unicode */ - RtlInitAnsiString(&TempString, CpuString); - RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); - - /* Add it to the registry */ - RtlInitUnicodeString(&ValueName, L"ProcessorNameString"); - Status = NtSetValueKey(KeyHandle, - &ValueName, - 0, - REG_SZ, - Data.Buffer, - Data.Length + sizeof(UNICODE_NULL)); - - /* ROS: Save a copy for bugzilla reporting */ - RtlCreateUnicodeString(&KeRosProcessorName, Data.Buffer); - - /* Free the temporary buffer */ - RtlFreeUnicodeString(&Data); - } - - /* Check if we had a Vendor ID */ - if (Prcb->VendorString) - { - /* Convert it to Unicode */ - RtlInitAnsiString(&TempString, Prcb->VendorString); - RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); - - /* Add it to the registry */ - RtlInitUnicodeString(&ValueName, L"VendorIdentifier"); - Status = NtSetValueKey(KeyHandle, - &ValueName, - 0, - REG_SZ, - Data.Buffer, - Data.Length + sizeof(UNICODE_NULL)); - - /* Free the temporary buffer */ - RtlFreeUnicodeString(&Data); - } - - /* Check if we have features bits */ - if (Prcb->FeatureBits) - { - /* Add them to the registry */ - RtlInitUnicodeString(&ValueName, L"FeatureSet"); - Status = NtSetValueKey(KeyHandle, - &ValueName, - 0, - REG_DWORD, - &Prcb->FeatureBits, - sizeof(Prcb->FeatureBits)); - } - - /* Check if we detected the CPU Speed */ - if (Prcb->MHz) - { - /* Add it to the registry */ - RtlInitUnicodeString(&ValueName, L"~MHz"); - Status = NtSetValueKey(KeyHandle, - &ValueName, - 0, - REG_DWORD, - &Prcb->MHz, - sizeof(Prcb->MHz)); - } - - /* Check if we have an update signature */ - if (Prcb->UpdateSignature.QuadPart) - { - /* Add it to the registry */ - RtlInitUnicodeString(&ValueName, L"Update Signature"); - Status = NtSetValueKey(KeyHandle, - &ValueName, - 0, - REG_BINARY, - &Prcb->UpdateSignature, - sizeof(Prcb->UpdateSignature)); - } - - /* Close the processor handle */ - NtClose(KeyHandle); - - /* FIXME: Detect CPU mismatches */ - } - } - - /* Free the configuration data */ - ExFreePool(CmpConfigurationData); - } - - /* Open physical memory */ - RtlInitUnicodeString(&SectionName, L"\\Device\\PhysicalMemory"); - InitializeObjectAttributes(&ObjectAttributes, - &SectionName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - Status = ZwOpenSection(&SectionHandle, - SECTION_ALL_ACCESS, - &ObjectAttributes); - if (!NT_SUCCESS(Status)) goto Quickie; - - /* Map the first 1KB of memory to get the IVT */ - ViewSize = PAGE_SIZE; - Status = ZwMapViewOfSection(SectionHandle, - NtCurrentProcess(), - &BaseAddress, - 0, - ViewSize, - &ViewBase, - &ViewSize, - ViewUnmap, - MEM_DOS_LIM, - PAGE_READWRITE); - if (!NT_SUCCESS(Status)) - { - /* Assume default */ - VideoRomBase = 0xC0000; - } - else - { - /* Calculate the base address from the vector */ - VideoRomBase = (*((PULONG)BaseAddress + 0x10) >> 12) & 0xFFFF0; - VideoRomBase += *((PULONG)BaseAddress + 0x10) & 0xFFF0; - - /* Now get to the actual ROM Start and make sure it's not invalid*/ - VideoRomBase &= 0xFFFF8000; - if (VideoRomBase < 0xC0000) VideoRomBase = 0xC0000; - - /* And unmap the section */ - ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); - } - - /* Allocate BIOS Version pp Buffer */ - BiosVersion = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, TAG_CM); - - /* Setup settings to map the 64K BIOS ROM */ - BaseAddress = 0; - ViewSize = 16 * PAGE_SIZE; - ViewBase.LowPart = 0xF0000; - ViewBase.HighPart = 0; - - /* Map it */ - Status = ZwMapViewOfSection(SectionHandle, - NtCurrentProcess(), - &BaseAddress, - 0, - ViewSize, - &ViewBase, - &ViewSize, - ViewUnmap, - MEM_DOS_LIM, - PAGE_READWRITE); - if (NT_SUCCESS(Status)) - { - /* Scan the ROM to get the BIOS Date */ - if (CmpGetBiosDate(BaseAddress, 16 * PAGE_SIZE, Buffer, TRUE)) - { - /* Convert it to Unicode */ - RtlInitAnsiString(&TempString, Buffer); - RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); - - /* Write the date into the registry */ - RtlInitUnicodeString(&ValueName, L"SystemBiosDate"); - Status = NtSetValueKey(SystemHandle, - &ValueName, - 0, - REG_SZ, - Data.Buffer, - Data.Length + sizeof(UNICODE_NULL)); - - /* Free the string */ - RtlFreeUnicodeString(&Data); - - if (BiosHandle) - { - /* Get the BIOS Date Identifier */ - RtlCopyMemory(Buffer, (PCHAR)BaseAddress + (16*PAGE_SIZE - 11), 8); - Buffer[8] = ANSI_NULL; - - /* Convert it to unicode */ - RtlInitAnsiString(&TempString, Buffer); - Status = RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); - if (NT_SUCCESS(Status)) - { - /* Save it to the registry */ - Status = NtSetValueKey(BiosHandle, - &ValueName, - 0, - REG_SZ, - Data.Buffer, - Data.Length + sizeof(UNICODE_NULL)); - - /* ROS: Save a copy for bugzilla reporting */ - RtlCreateUnicodeString(&KeRosBiosDate, Data.Buffer); - - /* Free the string */ - RtlFreeUnicodeString(&Data); - } - - /* Close the bios information handle */ - NtClose(BiosHandle); - } - } - - /* Get the BIOS Version */ - if (CmpGetBiosVersion(BaseAddress, 16* PAGE_SIZE, Buffer)) - { - /* Start at the beginning of our buffer */ - CurrentVersion = BiosVersion; - do - { - /* Convert to Unicode */ - RtlInitAnsiString(&TempString, Buffer); - RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); - - /* Calculate the length of this string and copy it in */ - Length = Data.Length + sizeof(UNICODE_NULL); - RtlMoveMemory(CurrentVersion, Data.Buffer, Length); - - /* Free the unicode string */ - RtlFreeUnicodeString(&Data); - - /* Update the total length and see if we're out of space */ - TotalLength += Length; - if (TotalLength + 256 + sizeof(UNICODE_NULL) > PAGE_SIZE) - { - /* One more string would push us out, so stop here */ - break; - } - - /* Go to the next string inside the multi-string buffer */ - CurrentVersion += Length; - - /* Query the next BIOS Version */ - } while (CmpGetBiosVersion(NULL, 0, Buffer)); - - /* Check if we found any strings at all */ - if (TotalLength) - { - /* Add the final null-terminator */ - *(PWSTR)CurrentVersion = UNICODE_NULL; - TotalLength += sizeof(UNICODE_NULL); - - /* Write the BIOS Version to the registry */ - RtlInitUnicodeString(&ValueName, L"SystemBiosVersion"); - Status = NtSetValueKey(SystemHandle, - &ValueName, - 0, - REG_MULTI_SZ, - BiosVersion, - TotalLength); - - /* ROS: Save a copy for bugzilla reporting */ - RtlCreateUnicodeString(&KeRosBiosVersion, (PWCH)BiosVersion); - } - } - - /* Unmap the section */ - ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); - } - - /* Now prepare for Video BIOS Mapping of 32KB */ - BaseAddress = 0; - ViewSize = 8 * PAGE_SIZE; - ViewBase.LowPart = VideoRomBase; - ViewBase.HighPart = 0; - - /* Map it */ - Status = ZwMapViewOfSection(SectionHandle, - NtCurrentProcess(), - &BaseAddress, - 0, - ViewSize, - &ViewBase, - &ViewSize, - ViewUnmap, - MEM_DOS_LIM, - PAGE_READWRITE); - if (NT_SUCCESS(Status)) - { - /* Scan the ROM to get the BIOS Date */ - if (CmpGetBiosDate(BaseAddress, 8 * PAGE_SIZE, Buffer, FALSE)) - { - /* Convert it to Unicode */ - RtlInitAnsiString(&TempString, Buffer); - RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); - - /* Write the date into the registry */ - RtlInitUnicodeString(&ValueName, L"VideoBiosDate"); - Status = NtSetValueKey(SystemHandle, - &ValueName, - 0, - REG_SZ, - Data.Buffer, - Data.Length + sizeof(UNICODE_NULL)); - - /* ROS: Save a copy for bugzilla reporting */ - RtlCreateUnicodeString(&KeRosVideoBiosDate, Data.Buffer); - - /* Free the string */ - RtlFreeUnicodeString(&Data); - } - - /* Get the Video BIOS Version */ - if (CmpGetBiosVersion(BaseAddress, 8* PAGE_SIZE, Buffer)) - { - /* Start at the beginning of our buffer */ - CurrentVersion = BiosVersion; - do - { - /* Convert to Unicode */ - RtlInitAnsiString(&TempString, Buffer); - RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); - - /* Calculate the length of this string and copy it in */ - Length = Data.Length + sizeof(UNICODE_NULL); - RtlMoveMemory(CurrentVersion, Data.Buffer, Length); - - /* Free the unicode string */ - RtlFreeUnicodeString(&Data); - - /* Update the total length and see if we're out of space */ - TotalLength += Length; - if (TotalLength + 256 + sizeof(UNICODE_NULL) > PAGE_SIZE) - { - /* One more string would push us out, so stop here */ - break; - } - - /* Go to the next string inside the multi-string buffer */ - CurrentVersion += Length; - - /* Query the next BIOS Version */ - } while (CmpGetBiosVersion(NULL, 0, Buffer)); - - /* Check if we found any strings at all */ - if (TotalLength) - { - /* Add the final null-terminator */ - *(PWSTR)CurrentVersion = UNICODE_NULL; - TotalLength += sizeof(UNICODE_NULL); - - /* Write the BIOS Version to the registry */ - RtlInitUnicodeString(&ValueName, L"VideoBiosVersion"); - Status = NtSetValueKey(SystemHandle, - &ValueName, - 0, - REG_MULTI_SZ, - BiosVersion, - TotalLength); - - /* ROS: Save a copy for bugzilla reporting */ - RtlCreateUnicodeString(&KeRosVideoBiosVersion, (PWCH)BiosVersion); - } - } - - /* Unmap the section */ - ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); - } - - /* Close the section */ - ZwClose(SectionHandle); - - /* Free the BIOS version string buffer */ - if (BiosVersion) ExFreePool(BiosVersion); - -Quickie: - /* Close the procesor handle */ - NtClose(KeyHandle); - return STATUS_SUCCESS; -} +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/i386/cmhardwr.c + * PURPOSE: Configuration Manager - Hardware-Specific Code + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#define NDEBUG +#include "debug.h" + +/* GLOBALS *******************************************************************/ + +PCHAR CmpID1 = "PowerPC %u"; +PCHAR CmpID2 = "No Data"; +PCHAR CmpBiosStrings[] = +{ + "Ver", + "Rev", + "Rel", + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", + "v 0", "v 1", "v 2", "v 3", "v 4", "v 5", "v 6", "v 7", "v 8", "v 9", + NULL +}; + +PCHAR CmpBiosBegin, CmpBiosSearchStart, CmpBiosSearchEnd; + +/* FUNCTIONS *****************************************************************/ + +BOOLEAN +NTAPI +CmpGetBiosDate(IN PCHAR BiosStart, + IN ULONG BiosLength, + IN PCHAR BiosDate, + IN BOOLEAN FromBios) +{ + CHAR LastDate[11] = {0}, CurrentDate[11]; + PCHAR p, pp; + + /* Skip the signature and the magic, and loop the BIOS ROM */ + p = BiosStart + 2; + pp = BiosStart + BiosLength - 5; + while (p < pp) + { + /* Check for xx/yy/zz which we assume to be a date */ + if ((p[0] == '/') && + (p[3] == '/') && + (isdigit(p[-1])) && + (isdigit(p[1])) && + (isdigit(p[2])) && + (isdigit(p[4])) && + (isdigit(p[5]))) + { + /* Copy the string proper */ + RtlMoveMemory(&CurrentDate[5], p - 2, 5); + + /* Add a 0 if the month only has one digit */ + if (!isdigit(CurrentDate[5])) CurrentDate[5] = '0'; + + /* Now copy the year */ + CurrentDate[2] = p[4]; + CurrentDate[3] = p[5]; + CurrentDate[4] = CurrentDate[7] = CurrentDate[10] = ANSI_NULL; + + /* If the date comes from the BIOS, check if it's a 4-digit year */ + if ((FromBios) && + (isdigit(p[6])) && + (isdigit(p[7])) && + ((RtlEqualMemory(&p[4], "19", 2)) || + (RtlEqualMemory(&p[4], "20", 2)))) + { + /* Copy the year proper */ + CurrentDate[0] = p[4]; + CurrentDate[1] = p[5]; + CurrentDate[2] = p[6]; + CurrentDate[3] = p[7]; + } + else + { + /* Otherwise, we'll just assume anything under 80 is 2000 */ + if (strtoul(&CurrentDate[2], NULL, 10) < 80) + { + /* Hopefully your BIOS wasn't made in 1979 */ + CurrentDate[0] = '2'; + CurrentDate[1] = '0'; + } + else + { + /* Anything over 80, was probably made in the 1900s... */ + CurrentDate[0] = '1'; + CurrentDate[1] = '9'; + } + } + + /* Add slashes were we previously had NULLs */ + CurrentDate[4] = CurrentDate[7] = '/'; + + /* Check which date is newer */ + if (memcmp(LastDate, CurrentDate, 10) < 0) + { + /* Found a newer date, select it */ + RtlMoveMemory(LastDate, CurrentDate, 10); + } + + p += 2; + } + p++; + } + + /* Make sure we found a date */ + if (LastDate[0]) + { + /* Copy the year at the pp, and keep only the last two digits */ + RtlMoveMemory(BiosDate, &LastDate[5], 5); + BiosDate[5] = '/'; + BiosDate[6] = LastDate[2]; + BiosDate[7] = LastDate[3]; + BiosDate[8] = ANSI_NULL; + return TRUE; + } + + /* No date found, return empty string */ + BiosDate[0] = ANSI_NULL; + return FALSE; +} + +BOOLEAN +NTAPI +CmpGetBiosVersion(IN PCHAR BiosStart, + IN ULONG BiosLength, + IN PCHAR BiosVersion) +{ + CHAR Buffer[128]; + PCHAR p, pp; + USHORT i; + + /* Check if we were given intitial data for the search */ + if (BiosStart) + { + /* Save it for later use */ + CmpBiosBegin = BiosStart; + CmpBiosSearchStart = BiosStart + 1; + CmpBiosSearchEnd = BiosStart + BiosLength - 2; + } + + /* Now loop the BIOS area */ + for (;;) + { + /* Start an initial search looking for numbers and periods */ + pp = NULL; + while (CmpBiosSearchStart <= CmpBiosSearchEnd) + { + /* Check if we have an "x.y" version string */ + if ((*CmpBiosSearchStart == '.') && + (*(CmpBiosSearchStart + 1) >= '0') && + (*(CmpBiosSearchStart + 1) <= '9') && + (*(CmpBiosSearchStart - 1) >= '0') && + (*(CmpBiosSearchStart - 1) <= '9')) + { + /* Start looking in this area for the actual BIOS Version */ + pp = CmpBiosSearchStart; + break; + } + else + { + /* Keep searching */ + CmpBiosSearchStart++; + } + } + + /* Break out if we're went past the BIOS area */ + if (CmpBiosSearchStart > CmpBiosSearchEnd) return FALSE; + + /* Move to the next 2 bytes */ + CmpBiosSearchStart += 2; + + /* Null-terminate our scratch buffer and start the string here */ + Buffer[127] = ANSI_NULL; + p = &Buffer[127]; + + /* Go back one character since we're doing this backwards */ + pp--; + + /* Loop the identifier we found as long as it's valid */ + i = 0; + while ((i++ < 127) && + (pp >= CmpBiosBegin) && + (*pp >= ' ') && + (*pp != '$')) + { + /* Copy the character */ + *--p = *pp--; + } + + /* Go past the last character since we went backwards */ + pp++; + + /* Loop the strings we recognize */ + for (i = 0; CmpBiosStrings[i]; i++) + { + /* Check if a match was found */ + if (strstr(p, CmpBiosStrings[i])) goto Match; + } + } + +Match: + /* Skip until we find a space */ + for (; *pp == ' '; pp++); + + /* Loop the final string */ + i = 0; + do + { + /* Copy the character into the final string */ + BiosVersion[i] = *pp++; + } while ((++i < 127) && + (pp <= (CmpBiosSearchEnd + 1)) && + (*pp >= ' ') && + (*pp != '$')); + + /* Null-terminate the version string */ + BiosVersion[i] = ANSI_NULL; + return TRUE; +} + +NTSTATUS +NTAPI +CmpInitializeMachineDependentConfiguration(IN PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + UNICODE_STRING KeyName, ValueName, Data, SectionName; + OBJECT_ATTRIBUTES ObjectAttributes; + ULONG HavePae, CacheSize, ViewSize, Length, TotalLength = 0, i, Disposition; + NTSTATUS Status; + HANDLE KeyHandle, BiosHandle, SystemHandle, FpuHandle, SectionHandle; + CONFIGURATION_COMPONENT_DATA ConfigData; + CHAR Buffer[128]; + ULONG ExtendedId = 0; //, Dummy; + PKPRCB Prcb; + USHORT IndexTable[MaximumType + 1] = {0}; + ANSI_STRING TempString; + PCHAR PartialString = NULL, BiosVersion; + CHAR CpuString[48]; + PVOID BaseAddress = NULL; + LARGE_INTEGER ViewBase = {{0}}; + ULONG_PTR VideoRomBase; + PCHAR CurrentVersion; + extern UNICODE_STRING KeRosProcessorName, KeRosBiosDate, KeRosBiosVersion; + extern UNICODE_STRING KeRosVideoBiosDate, KeRosVideoBiosVersion; + + /* Open the SMSS Memory Management key */ + RtlInitUnicodeString(&KeyName, + L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\" + L"Control\\Session Manager\\Memory Management"); + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + Status = NtOpenKey(&KeyHandle, KEY_READ | KEY_WRITE, &ObjectAttributes); + if (NT_SUCCESS(Status)) + { + /* Detect if PAE is enabled */ + HavePae = SharedUserData->ProcessorFeatures[PF_PAE_ENABLED]; + + /* Set the value */ + RtlInitUnicodeString(&ValueName, L"PhysicalAddressExtension"); + NtSetValueKey(KeyHandle, + &ValueName, + 0, + REG_DWORD, + &HavePae, + sizeof(HavePae)); + + /* Close the key */ + NtClose(KeyHandle); + } + + /* Open the hardware description key */ + RtlInitUnicodeString(&KeyName, + L"\\Registry\\Machine\\Hardware\\Description\\System"); + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + Status = NtOpenKey(&SystemHandle, KEY_READ | KEY_WRITE, &ObjectAttributes); + if (!NT_SUCCESS(Status)) return Status; + + /* Create the BIOS Information key */ + RtlInitUnicodeString(&KeyName, + L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\" + L"Control\\BIOSINFO"); + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + Status = NtCreateKey(&BiosHandle, + KEY_ALL_ACCESS, + &ObjectAttributes, + 0, + NULL, + REG_OPTION_NON_VOLATILE, + &Disposition); + if (ExpInTextModeSetup) + { + if (!NT_SUCCESS(Status)) + BiosHandle = NULL; + } + else if (!NT_SUCCESS(Status)) + return Status; + + /* Create the CPU Key, and check if it already existed */ + RtlInitUnicodeString(&KeyName, L"CentralProcessor"); + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + SystemHandle, + NULL); + Status = NtCreateKey(&KeyHandle, + KEY_READ | KEY_WRITE, + &ObjectAttributes, + 0, + NULL, + 0, + &Disposition); + NtClose(KeyHandle); + + /* The key shouldn't already exist */ + if (Disposition == REG_CREATED_NEW_KEY) + { + /* Allocate the configuration data for cmconfig.c */ + CmpConfigurationData = ExAllocatePoolWithTag(PagedPool, + CmpConfigurationAreaSize, + TAG_CM); + if (!CmpConfigurationData) return STATUS_INSUFFICIENT_RESOURCES; + + /* Loop all CPUs */ + for (i = 0; i < KeNumberProcessors; i++) + { + /* Get the PRCB */ + Prcb = KiProcessorBlock[i]; + + /* Setup the Configuration Entry for the Processor */ + RtlZeroMemory(&ConfigData, sizeof (ConfigData)); + ConfigData.ComponentEntry.Class = ProcessorClass; + ConfigData.ComponentEntry.Type = CentralProcessor; + ConfigData.ComponentEntry.Key = i; + ConfigData.ComponentEntry.AffinityMask = AFFINITY_MASK(i); + ConfigData.ComponentEntry.Identifier = Buffer; + + /* Check if the CPU doesn't support CPUID */ + if (!Prcb->CpuID) + { + /* Build ID1-style string for older CPUs */ + sprintf(Buffer, + CmpID1, + Prcb->CpuType, + (Prcb->CpuStep >> 8) + 'A', + Prcb->CpuStep & 0xff); + } + else + { + /* Build ID2-style string for newer CPUs */ + sprintf(Buffer, + CmpID2, + Prcb->CpuType, + (Prcb->CpuStep >> 8), + Prcb->CpuStep & 0xff); + } + + /* Save the ID string length now that we've created it */ + ConfigData.ComponentEntry.IdentifierLength = strlen(Buffer) + 1; + + /* Initialize the registry configuration node for it */ + Status = CmpInitializeRegistryNode(&ConfigData, + SystemHandle, + &KeyHandle, + InterfaceTypeUndefined, + 0xFFFFFFFF, + IndexTable); + if (!NT_SUCCESS(Status)) return(Status); + + { + /* Setup the Configuration Entry for the FPU */ + RtlZeroMemory(&ConfigData, sizeof(ConfigData)); + ConfigData.ComponentEntry.Class = ProcessorClass; + ConfigData.ComponentEntry.Type = FloatingPointProcessor; + ConfigData.ComponentEntry.Key = i; + ConfigData.ComponentEntry.AffinityMask = AFFINITY_MASK(i); + ConfigData.ComponentEntry.Identifier = Buffer; + + /* For 386 cpus, the CPU pp is the identifier */ + if (Prcb->CpuType == 3) strcpy(Buffer, "80387"); + + /* Save the ID string length now that we've created it */ + ConfigData.ComponentEntry.IdentifierLength = strlen(Buffer) + 1; + + /* Initialize the registry configuration node for it */ + Status = CmpInitializeRegistryNode(&ConfigData, + SystemHandle, + &FpuHandle, + InterfaceTypeUndefined, + 0xFFFFFFFF, + IndexTable); + if (!NT_SUCCESS(Status)) + { + /* Failed, close the CPU handle and return */ + NtClose(KeyHandle); + return Status; + } + + /* Close this new handle */ + NtClose(FpuHandle); + + /* Stay on this CPU only */ + KeSetSystemAffinityThread(Prcb->SetMember); + if (!Prcb->CpuID) + { + /* Uh oh, no CPUID! */ + } + else + { + /* Check if we have extended CPUID that supports name ID */ + //Ki386Cpuid(0x80000000, &ExtendedId, &Dummy, &Dummy, &Dummy); + if (ExtendedId >= 0x80000004) + { + /* Do all the CPUIDs requred to get the full name */ + PartialString = CpuString; + for (ExtendedId = 2; ExtendedId <= 4; ExtendedId++) + { +#if 0 + /* Do the CPUID and save the name string */ + Ki386Cpuid(0x80000000 | ExtendedId, + (PULONG)PartialString, + (PULONG)PartialString + 1, + (PULONG)PartialString + 2, + (PULONG)PartialString + 3); +#endif + + /* Go to the next name string */ + PartialString += 16; + } + + /* Null-terminate it */ + CpuString[48] = ANSI_NULL; + } + } + + /* Get the cache size while we're still localized */ + CacheSize = 0; //((PKIPCR)KeGetPcr())->SecondLevelCacheSize; + + /* Go back to user affinity */ + KeRevertToUserAffinityThread(); + + /* Check if we have a CPU Name */ + if (PartialString) + { + /* Convert it to Unicode */ + RtlInitAnsiString(&TempString, CpuString); + RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); + + /* Add it to the registry */ + RtlInitUnicodeString(&ValueName, L"ProcessorNameString"); + Status = NtSetValueKey(KeyHandle, + &ValueName, + 0, + REG_SZ, + Data.Buffer, + Data.Length + sizeof(UNICODE_NULL)); + + /* ROS: Save a copy for bugzilla reporting */ + RtlCreateUnicodeString(&KeRosProcessorName, Data.Buffer); + + /* Free the temporary buffer */ + RtlFreeUnicodeString(&Data); + } + + /* Check if we had a Vendor ID */ + if (Prcb->VendorString) + { + /* Convert it to Unicode */ + RtlInitAnsiString(&TempString, Prcb->VendorString); + RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); + + /* Add it to the registry */ + RtlInitUnicodeString(&ValueName, L"VendorIdentifier"); + Status = NtSetValueKey(KeyHandle, + &ValueName, + 0, + REG_SZ, + Data.Buffer, + Data.Length + sizeof(UNICODE_NULL)); + + /* Free the temporary buffer */ + RtlFreeUnicodeString(&Data); + } + + /* Check if we have features bits */ + if (Prcb->FeatureBits) + { + /* Add them to the registry */ + RtlInitUnicodeString(&ValueName, L"FeatureSet"); + Status = NtSetValueKey(KeyHandle, + &ValueName, + 0, + REG_DWORD, + &Prcb->FeatureBits, + sizeof(Prcb->FeatureBits)); + } + + /* Check if we detected the CPU Speed */ + if (Prcb->MHz) + { + /* Add it to the registry */ + RtlInitUnicodeString(&ValueName, L"~MHz"); + Status = NtSetValueKey(KeyHandle, + &ValueName, + 0, + REG_DWORD, + &Prcb->MHz, + sizeof(Prcb->MHz)); + } + + /* Check if we have an update signature */ + if (Prcb->UpdateSignature.QuadPart) + { + /* Add it to the registry */ + RtlInitUnicodeString(&ValueName, L"Update Signature"); + Status = NtSetValueKey(KeyHandle, + &ValueName, + 0, + REG_BINARY, + &Prcb->UpdateSignature, + sizeof(Prcb->UpdateSignature)); + } + + /* Close the processor handle */ + NtClose(KeyHandle); + + /* FIXME: Detect CPU mismatches */ + } + } + + /* Free the configuration data */ + ExFreePool(CmpConfigurationData); + } + + /* Open physical memory */ + RtlInitUnicodeString(&SectionName, L"\\Device\\PhysicalMemory"); + InitializeObjectAttributes(&ObjectAttributes, + &SectionName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + Status = ZwOpenSection(&SectionHandle, + SECTION_ALL_ACCESS, + &ObjectAttributes); + if (!NT_SUCCESS(Status)) goto Quickie; + + /* Map the first 1KB of memory to get the IVT */ + ViewSize = PAGE_SIZE; + Status = ZwMapViewOfSection(SectionHandle, + NtCurrentProcess(), + &BaseAddress, + 0, + ViewSize, + &ViewBase, + &ViewSize, + ViewUnmap, + MEM_DOS_LIM, + PAGE_READWRITE); + if (!NT_SUCCESS(Status)) + { + /* Assume default */ + VideoRomBase = 0xC0000; + } + else + { + /* Calculate the base address from the vector */ + VideoRomBase = (*((PULONG)BaseAddress + 0x10) >> 12) & 0xFFFF0; + VideoRomBase += *((PULONG)BaseAddress + 0x10) & 0xFFF0; + + /* Now get to the actual ROM Start and make sure it's not invalid*/ + VideoRomBase &= 0xFFFF8000; + if (VideoRomBase < 0xC0000) VideoRomBase = 0xC0000; + + /* And unmap the section */ + ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); + } + + /* Allocate BIOS Version pp Buffer */ + BiosVersion = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, TAG_CM); + + /* Setup settings to map the 64K BIOS ROM */ + BaseAddress = 0; + ViewSize = 16 * PAGE_SIZE; + ViewBase.LowPart = 0xF0000; + ViewBase.HighPart = 0; + + /* Map it */ + Status = ZwMapViewOfSection(SectionHandle, + NtCurrentProcess(), + &BaseAddress, + 0, + ViewSize, + &ViewBase, + &ViewSize, + ViewUnmap, + MEM_DOS_LIM, + PAGE_READWRITE); + if (NT_SUCCESS(Status)) + { + /* Scan the ROM to get the BIOS Date */ + if (CmpGetBiosDate(BaseAddress, 16 * PAGE_SIZE, Buffer, TRUE)) + { + /* Convert it to Unicode */ + RtlInitAnsiString(&TempString, Buffer); + RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); + + /* Write the date into the registry */ + RtlInitUnicodeString(&ValueName, L"SystemBiosDate"); + Status = NtSetValueKey(SystemHandle, + &ValueName, + 0, + REG_SZ, + Data.Buffer, + Data.Length + sizeof(UNICODE_NULL)); + + /* Free the string */ + RtlFreeUnicodeString(&Data); + + if (BiosHandle) + { + /* Get the BIOS Date Identifier */ + RtlCopyMemory(Buffer, (PCHAR)BaseAddress + (16*PAGE_SIZE - 11), 8); + Buffer[8] = ANSI_NULL; + + /* Convert it to unicode */ + RtlInitAnsiString(&TempString, Buffer); + Status = RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); + if (NT_SUCCESS(Status)) + { + /* Save it to the registry */ + Status = NtSetValueKey(BiosHandle, + &ValueName, + 0, + REG_SZ, + Data.Buffer, + Data.Length + sizeof(UNICODE_NULL)); + + /* ROS: Save a copy for bugzilla reporting */ + RtlCreateUnicodeString(&KeRosBiosDate, Data.Buffer); + + /* Free the string */ + RtlFreeUnicodeString(&Data); + } + + /* Close the bios information handle */ + NtClose(BiosHandle); + } + } + + /* Get the BIOS Version */ + if (CmpGetBiosVersion(BaseAddress, 16* PAGE_SIZE, Buffer)) + { + /* Start at the beginning of our buffer */ + CurrentVersion = BiosVersion; + do + { + /* Convert to Unicode */ + RtlInitAnsiString(&TempString, Buffer); + RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); + + /* Calculate the length of this string and copy it in */ + Length = Data.Length + sizeof(UNICODE_NULL); + RtlMoveMemory(CurrentVersion, Data.Buffer, Length); + + /* Free the unicode string */ + RtlFreeUnicodeString(&Data); + + /* Update the total length and see if we're out of space */ + TotalLength += Length; + if (TotalLength + 256 + sizeof(UNICODE_NULL) > PAGE_SIZE) + { + /* One more string would push us out, so stop here */ + break; + } + + /* Go to the next string inside the multi-string buffer */ + CurrentVersion += Length; + + /* Query the next BIOS Version */ + } while (CmpGetBiosVersion(NULL, 0, Buffer)); + + /* Check if we found any strings at all */ + if (TotalLength) + { + /* Add the final null-terminator */ + *(PWSTR)CurrentVersion = UNICODE_NULL; + TotalLength += sizeof(UNICODE_NULL); + + /* Write the BIOS Version to the registry */ + RtlInitUnicodeString(&ValueName, L"SystemBiosVersion"); + Status = NtSetValueKey(SystemHandle, + &ValueName, + 0, + REG_MULTI_SZ, + BiosVersion, + TotalLength); + + /* ROS: Save a copy for bugzilla reporting */ + RtlCreateUnicodeString(&KeRosBiosVersion, (PWCH)BiosVersion); + } + } + + /* Unmap the section */ + ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); + } + + /* Now prepare for Video BIOS Mapping of 32KB */ + BaseAddress = 0; + ViewSize = 8 * PAGE_SIZE; + ViewBase.LowPart = VideoRomBase; + ViewBase.HighPart = 0; + + /* Map it */ + Status = ZwMapViewOfSection(SectionHandle, + NtCurrentProcess(), + &BaseAddress, + 0, + ViewSize, + &ViewBase, + &ViewSize, + ViewUnmap, + MEM_DOS_LIM, + PAGE_READWRITE); + if (NT_SUCCESS(Status)) + { + /* Scan the ROM to get the BIOS Date */ + if (CmpGetBiosDate(BaseAddress, 8 * PAGE_SIZE, Buffer, FALSE)) + { + /* Convert it to Unicode */ + RtlInitAnsiString(&TempString, Buffer); + RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); + + /* Write the date into the registry */ + RtlInitUnicodeString(&ValueName, L"VideoBiosDate"); + Status = NtSetValueKey(SystemHandle, + &ValueName, + 0, + REG_SZ, + Data.Buffer, + Data.Length + sizeof(UNICODE_NULL)); + + /* ROS: Save a copy for bugzilla reporting */ + RtlCreateUnicodeString(&KeRosVideoBiosDate, Data.Buffer); + + /* Free the string */ + RtlFreeUnicodeString(&Data); + } + + /* Get the Video BIOS Version */ + if (CmpGetBiosVersion(BaseAddress, 8* PAGE_SIZE, Buffer)) + { + /* Start at the beginning of our buffer */ + CurrentVersion = BiosVersion; + do + { + /* Convert to Unicode */ + RtlInitAnsiString(&TempString, Buffer); + RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); + + /* Calculate the length of this string and copy it in */ + Length = Data.Length + sizeof(UNICODE_NULL); + RtlMoveMemory(CurrentVersion, Data.Buffer, Length); + + /* Free the unicode string */ + RtlFreeUnicodeString(&Data); + + /* Update the total length and see if we're out of space */ + TotalLength += Length; + if (TotalLength + 256 + sizeof(UNICODE_NULL) > PAGE_SIZE) + { + /* One more string would push us out, so stop here */ + break; + } + + /* Go to the next string inside the multi-string buffer */ + CurrentVersion += Length; + + /* Query the next BIOS Version */ + } while (CmpGetBiosVersion(NULL, 0, Buffer)); + + /* Check if we found any strings at all */ + if (TotalLength) + { + /* Add the final null-terminator */ + *(PWSTR)CurrentVersion = UNICODE_NULL; + TotalLength += sizeof(UNICODE_NULL); + + /* Write the BIOS Version to the registry */ + RtlInitUnicodeString(&ValueName, L"VideoBiosVersion"); + Status = NtSetValueKey(SystemHandle, + &ValueName, + 0, + REG_MULTI_SZ, + BiosVersion, + TotalLength); + + /* ROS: Save a copy for bugzilla reporting */ + RtlCreateUnicodeString(&KeRosVideoBiosVersion, (PWCH)BiosVersion); + } + } + + /* Unmap the section */ + ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); + } + + /* Close the section */ + ZwClose(SectionHandle); + + /* Free the BIOS version string buffer */ + if (BiosVersion) ExFreePool(BiosVersion); + +Quickie: + /* Close the procesor handle */ + NtClose(KeyHandle); + return STATUS_SUCCESS; +} diff --git a/reactos/ntoskrnl/ex/init.c b/reactos/ntoskrnl/ex/init.c index 289385a9745..cc39da7a24d 100644 --- a/reactos/ntoskrnl/ex/init.c +++ b/reactos/ntoskrnl/ex/init.c @@ -12,7 +12,6 @@ #include #define NDEBUG #include -#include "ntoskrnl/cm/cm.h" #include "ntstrsafe.h" typedef struct _INIT_BUFFER diff --git a/reactos/ntoskrnl/config/cm.h b/reactos/ntoskrnl/include/internal/cm.h similarity index 100% rename from reactos/ntoskrnl/config/cm.h rename to reactos/ntoskrnl/include/internal/cm.h diff --git a/reactos/ntoskrnl/config/cm_x.h b/reactos/ntoskrnl/include/internal/cm_x.h similarity index 97% rename from reactos/ntoskrnl/config/cm_x.h rename to reactos/ntoskrnl/include/internal/cm_x.h index 2706f7c3f75..197fff01b1b 100644 --- a/reactos/ntoskrnl/config/cm_x.h +++ b/reactos/ntoskrnl/include/internal/cm_x.h @@ -1,248 +1,248 @@ -/* -* PROJECT: ReactOS Kernel -* LICENSE: GPL - See COPYING in the top level directory -* FILE: ntoskrnl/cm/cm_x.h -* PURPOSE: Inlined Functions for the Configuration Manager -* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) -*/ - -// -// Returns whether or not this is a small valued key -// -BOOLEAN -FORCEINLINE -CmpIsKeyValueSmall(OUT PULONG RealLength, - IN ULONG Length) -{ - /* Check if the length has the special size value */ - if (Length >= CM_KEY_VALUE_SPECIAL_SIZE) - { - /* It does, so this is a small key: return the real length */ - *RealLength = Length - CM_KEY_VALUE_SPECIAL_SIZE; - return TRUE; - } - - /* This is not a small key, return the length we read */ - *RealLength = Length; - return FALSE; -} - -// -// Returns whether or not this is a big valued key -// -BOOLEAN -FORCEINLINE -CmpIsKeyValueBig(IN PHHIVE Hive, - IN ULONG Length) -{ - /* Check if the hive is XP Beta 1 or newer */ - if (Hive->Version >= HSYS_WHISTLER_BETA1) - { - /* Check if the key length is valid for a big value key */ - if ((Length < CM_KEY_VALUE_SPECIAL_SIZE) && (Length > CM_KEY_VALUE_BIG)) - { - /* Yes, this value is big */ - return TRUE; - } - } - - /* Not a big value key */ - return FALSE; -} - -// -// Returns the hashkey corresponding to a convkey -// -#define GET_HASH_KEY(ConvKey) \ - ((CMP_HASH_IRRATIONAL * (ConvKey)) % CMP_HASH_PRIME) - -// -// Returns the index into the hash table, or the entry itself -// -#define GET_HASH_INDEX(ConvKey) \ - GET_HASH_KEY(ConvKey) % CmpHashTableSize -#define GET_HASH_ENTRY(Table, ConvKey) \ - (Table[GET_HASH_INDEX(ConvKey)]) - -// -// Returns whether or not the cell is cached -// -#define CMP_IS_CELL_CACHED(c) \ - (((c) & HCELL_CACHED) && ((c) != HCELL_NIL)) - -// -// Return data from a cached cell -// -#define CMP_GET_CACHED_CELL(c) \ - (ULONG_PTR)((c) & ~HCELL_CACHED) -#define CMP_GET_CACHED_DATA(c) \ - (&(((PCM_CACHED_VALUE_INDEX)(CMP_GET_CACHED_CELL(c)))->Data.CellData)) -#define CMP_GET_CACHED_INDEX(c) \ - (&(((PCM_CACHED_ENTRY)(CMP_GET_CACHED_CELL(c)))->CellIndex)) -#define CMP_GET_CACHED_VALUE(c) \ - (&(((PCM_CACHED_VALUE)(CMP_GET_CACHED_CELL(c)))->KeyValue)) - -// -// Makes sure that the registry is locked -// -#define CMP_ASSERT_REGISTRY_LOCK() \ - ASSERT((CmpSpecialBootCondition == TRUE) || \ - (CmpTestRegistryLock() == TRUE)) - -// -// Makes sure that the registry is exclusively locked -// -#define CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK() \ - ASSERT((CmpSpecialBootCondition == TRUE) || \ - (CmpTestRegistryLockExclusive() == TRUE)) - -// -// Checks if a KCB is exclusively locked -// -#define CmpIsKcbLockedExclusive(k) \ - (GET_HASH_ENTRY(CmpCacheTable, \ - (k)->ConvKey).Owner == KeGetCurrentThread()) - -// -// Exclusively acquires a KCB -// -#define CmpAcquireKcbLockExclusive(k) \ -{ \ - ExAcquirePushLockExclusive(&GET_HASH_ENTRY(CmpCacheTable, \ - (k)->ConvKey).Lock); \ - GET_HASH_ENTRY(CmpCacheTable, \ - (k)->ConvKey).Owner = KeGetCurrentThread(); \ -} - -// -// Exclusively acquires a KCB by index -// -#define CmpAcquireKcbLockExclusiveByIndex(i) \ -{ \ - ExAcquirePushLockExclusive(&CmpCacheTable[(i)].Lock); \ - CmpCacheTable[(i)].Owner = KeGetCurrentThread(); \ -} - -// -// Exclusively acquires a KCB by key -// -#define CmpAcquireKcbLockExclusiveByKey(k) \ -{ \ - ExAcquirePushLockExclusive(&GET_HASH_ENTRY(CmpCacheTable, \ - (k)).Lock); \ - GET_HASH_ENTRY(CmpCacheTable, \ - (k)).Owner = KeGetCurrentThread(); \ -} - - -// -// Shared acquires a KCB -// -#define CmpAcquireKcbLockShared(k) \ -{ \ - ExAcquirePushLockShared(&GET_HASH_ENTRY(CmpCacheTable, \ - (k)->ConvKey).Lock); \ -} - -// -// Shared acquires a KCB by index -// -#define CmpAcquireKcbLockSharedByIndex(i) \ -{ \ - ExAcquirePushLockShared(&CmpCacheTable[(i)].Lock); \ -} - -// -// Tries to convert a KCB lock -// -FORCEINLINE -BOOLEAN -CmpTryToConvertKcbSharedToExclusive(IN PCM_KEY_CONTROL_BLOCK k) -{ - ASSERT(CmpIsKcbLockedExclusive(k) == FALSE); - if (ExConvertPushLockSharedToExclusive( - &GET_HASH_ENTRY(CmpCacheTable, k->ConvKey).Lock)) - { - GET_HASH_ENTRY(CmpCacheTable, - k->ConvKey).Owner = KeGetCurrentThread(); - return TRUE; - } - return FALSE; -} - -// -// Releases an exlusively or shared acquired KCB -// -#define CmpReleaseKcbLock(k) \ -{ \ - GET_HASH_ENTRY(CmpCacheTable, (k)->ConvKey).Owner = NULL; \ - ExReleasePushLock(&GET_HASH_ENTRY(CmpCacheTable, \ - (k)->ConvKey).Lock); \ -} - -// -// Releases an exlusively or shared acquired KCB by index -// -#define CmpReleaseKcbLockByIndex(i) \ -{ \ - CmpCacheTable[(i)].Owner = NULL; \ - ExReleasePushLock(&CmpCacheTable[(i)].Lock); \ -} - -// -// Releases an exlusively or shared acquired KCB by key -// -#define CmpReleaseKcbLockByKey(k) \ -{ \ - GET_HASH_ENTRY(CmpCacheTable, (k)).Owner = NULL; \ - ExReleasePushLock(&GET_HASH_ENTRY(CmpCacheTable, \ - (k)).Lock); \ -} - -// -// Converts a KCB lock -// -FORCEINLINE -VOID -CmpConvertKcbSharedToExclusive(IN PCM_KEY_CONTROL_BLOCK k) -{ - ASSERT(CmpIsKcbLockedExclusive(k) == FALSE); - CmpReleaseKcbLock(k); - CmpAcquireKcbLockExclusive(k); -} - -// -// Exclusively acquires an NCB -// -#define CmpAcquireNcbLockExclusive(n) \ -{ \ - ExAcquirePushLockExclusive(&GET_HASH_ENTRY(CmpNameCacheTable, \ - (n)->ConvKey).Lock); \ -} - -// -// Exclusively acquires an NCB by key -// -#define CmpAcquireNcbLockExclusiveByKey(k) \ -{ \ - ExAcquirePushLockExclusive(&GET_HASH_ENTRY(CmpNameCacheTable, \ - (k)).Lock); \ -} - -// -// Releases an exlusively or shared acquired NCB -// -#define CmpReleaseNcbLock(k) \ -{ \ - ExReleasePushLock(&GET_HASH_ENTRY(CmpNameCacheTable, \ - (k)->ConvKey).Lock); \ -} - -// -// Releases an exlusively or shared acquired NCB by key -// -#define CmpReleaseNcbLockByKey(k) \ -{ \ - ExReleasePushLock(&GET_HASH_ENTRY(CmpNameCacheTable, \ - (k)).Lock); \ -} +/* +* PROJECT: ReactOS Kernel +* LICENSE: GPL - See COPYING in the top level directory +* FILE: ntoskrnl/cm/cm_x.h +* PURPOSE: Inlined Functions for the Configuration Manager +* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) +*/ + +// +// Returns whether or not this is a small valued key +// +BOOLEAN +FORCEINLINE +CmpIsKeyValueSmall(OUT PULONG RealLength, + IN ULONG Length) +{ + /* Check if the length has the special size value */ + if (Length >= CM_KEY_VALUE_SPECIAL_SIZE) + { + /* It does, so this is a small key: return the real length */ + *RealLength = Length - CM_KEY_VALUE_SPECIAL_SIZE; + return TRUE; + } + + /* This is not a small key, return the length we read */ + *RealLength = Length; + return FALSE; +} + +// +// Returns whether or not this is a big valued key +// +BOOLEAN +FORCEINLINE +CmpIsKeyValueBig(IN PHHIVE Hive, + IN ULONG Length) +{ + /* Check if the hive is XP Beta 1 or newer */ + if (Hive->Version >= HSYS_WHISTLER_BETA1) + { + /* Check if the key length is valid for a big value key */ + if ((Length < CM_KEY_VALUE_SPECIAL_SIZE) && (Length > CM_KEY_VALUE_BIG)) + { + /* Yes, this value is big */ + return TRUE; + } + } + + /* Not a big value key */ + return FALSE; +} + +// +// Returns the hashkey corresponding to a convkey +// +#define GET_HASH_KEY(ConvKey) \ + ((CMP_HASH_IRRATIONAL * (ConvKey)) % CMP_HASH_PRIME) + +// +// Returns the index into the hash table, or the entry itself +// +#define GET_HASH_INDEX(ConvKey) \ + GET_HASH_KEY(ConvKey) % CmpHashTableSize +#define GET_HASH_ENTRY(Table, ConvKey) \ + (Table[GET_HASH_INDEX(ConvKey)]) + +// +// Returns whether or not the cell is cached +// +#define CMP_IS_CELL_CACHED(c) \ + (((c) & HCELL_CACHED) && ((c) != HCELL_NIL)) + +// +// Return data from a cached cell +// +#define CMP_GET_CACHED_CELL(c) \ + (ULONG_PTR)((c) & ~HCELL_CACHED) +#define CMP_GET_CACHED_DATA(c) \ + (&(((PCM_CACHED_VALUE_INDEX)(CMP_GET_CACHED_CELL(c)))->Data.CellData)) +#define CMP_GET_CACHED_INDEX(c) \ + (&(((PCM_CACHED_ENTRY)(CMP_GET_CACHED_CELL(c)))->CellIndex)) +#define CMP_GET_CACHED_VALUE(c) \ + (&(((PCM_CACHED_VALUE)(CMP_GET_CACHED_CELL(c)))->KeyValue)) + +// +// Makes sure that the registry is locked +// +#define CMP_ASSERT_REGISTRY_LOCK() \ + ASSERT((CmpSpecialBootCondition == TRUE) || \ + (CmpTestRegistryLock() == TRUE)) + +// +// Makes sure that the registry is exclusively locked +// +#define CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK() \ + ASSERT((CmpSpecialBootCondition == TRUE) || \ + (CmpTestRegistryLockExclusive() == TRUE)) + +// +// Checks if a KCB is exclusively locked +// +#define CmpIsKcbLockedExclusive(k) \ + (GET_HASH_ENTRY(CmpCacheTable, \ + (k)->ConvKey).Owner == KeGetCurrentThread()) + +// +// Exclusively acquires a KCB +// +#define CmpAcquireKcbLockExclusive(k) \ +{ \ + ExAcquirePushLockExclusive(&GET_HASH_ENTRY(CmpCacheTable, \ + (k)->ConvKey).Lock); \ + GET_HASH_ENTRY(CmpCacheTable, \ + (k)->ConvKey).Owner = KeGetCurrentThread(); \ +} + +// +// Exclusively acquires a KCB by index +// +#define CmpAcquireKcbLockExclusiveByIndex(i) \ +{ \ + ExAcquirePushLockExclusive(&CmpCacheTable[(i)].Lock); \ + CmpCacheTable[(i)].Owner = KeGetCurrentThread(); \ +} + +// +// Exclusively acquires a KCB by key +// +#define CmpAcquireKcbLockExclusiveByKey(k) \ +{ \ + ExAcquirePushLockExclusive(&GET_HASH_ENTRY(CmpCacheTable, \ + (k)).Lock); \ + GET_HASH_ENTRY(CmpCacheTable, \ + (k)).Owner = KeGetCurrentThread(); \ +} + + +// +// Shared acquires a KCB +// +#define CmpAcquireKcbLockShared(k) \ +{ \ + ExAcquirePushLockShared(&GET_HASH_ENTRY(CmpCacheTable, \ + (k)->ConvKey).Lock); \ +} + +// +// Shared acquires a KCB by index +// +#define CmpAcquireKcbLockSharedByIndex(i) \ +{ \ + ExAcquirePushLockShared(&CmpCacheTable[(i)].Lock); \ +} + +// +// Tries to convert a KCB lock +// +FORCEINLINE +BOOLEAN +CmpTryToConvertKcbSharedToExclusive(IN PCM_KEY_CONTROL_BLOCK k) +{ + ASSERT(CmpIsKcbLockedExclusive(k) == FALSE); + if (ExConvertPushLockSharedToExclusive( + &GET_HASH_ENTRY(CmpCacheTable, k->ConvKey).Lock)) + { + GET_HASH_ENTRY(CmpCacheTable, + k->ConvKey).Owner = KeGetCurrentThread(); + return TRUE; + } + return FALSE; +} + +// +// Releases an exlusively or shared acquired KCB +// +#define CmpReleaseKcbLock(k) \ +{ \ + GET_HASH_ENTRY(CmpCacheTable, (k)->ConvKey).Owner = NULL; \ + ExReleasePushLock(&GET_HASH_ENTRY(CmpCacheTable, \ + (k)->ConvKey).Lock); \ +} + +// +// Releases an exlusively or shared acquired KCB by index +// +#define CmpReleaseKcbLockByIndex(i) \ +{ \ + CmpCacheTable[(i)].Owner = NULL; \ + ExReleasePushLock(&CmpCacheTable[(i)].Lock); \ +} + +// +// Releases an exlusively or shared acquired KCB by key +// +#define CmpReleaseKcbLockByKey(k) \ +{ \ + GET_HASH_ENTRY(CmpCacheTable, (k)).Owner = NULL; \ + ExReleasePushLock(&GET_HASH_ENTRY(CmpCacheTable, \ + (k)).Lock); \ +} + +// +// Converts a KCB lock +// +FORCEINLINE +VOID +CmpConvertKcbSharedToExclusive(IN PCM_KEY_CONTROL_BLOCK k) +{ + ASSERT(CmpIsKcbLockedExclusive(k) == FALSE); + CmpReleaseKcbLock(k); + CmpAcquireKcbLockExclusive(k); +} + +// +// Exclusively acquires an NCB +// +#define CmpAcquireNcbLockExclusive(n) \ +{ \ + ExAcquirePushLockExclusive(&GET_HASH_ENTRY(CmpNameCacheTable, \ + (n)->ConvKey).Lock); \ +} + +// +// Exclusively acquires an NCB by key +// +#define CmpAcquireNcbLockExclusiveByKey(k) \ +{ \ + ExAcquirePushLockExclusive(&GET_HASH_ENTRY(CmpNameCacheTable, \ + (k)).Lock); \ +} + +// +// Releases an exlusively or shared acquired NCB +// +#define CmpReleaseNcbLock(k) \ +{ \ + ExReleasePushLock(&GET_HASH_ENTRY(CmpNameCacheTable, \ + (k)->ConvKey).Lock); \ +} + +// +// Releases an exlusively or shared acquired NCB by key +// +#define CmpReleaseNcbLockByKey(k) \ +{ \ + ExReleasePushLock(&GET_HASH_ENTRY(CmpNameCacheTable, \ + (k)).Lock); \ +} diff --git a/reactos/ntoskrnl/include/internal/ntoskrnl.h b/reactos/ntoskrnl/include/internal/ntoskrnl.h index 94327e2d1fa..b07a87e055a 100644 --- a/reactos/ntoskrnl/include/internal/ntoskrnl.h +++ b/reactos/ntoskrnl/include/internal/ntoskrnl.h @@ -30,6 +30,7 @@ #include "ob.h" #include "mm.h" #include "ex.h" +#include "cm.h" #include "ps.h" #include "cc.h" #include "io.h" diff --git a/reactos/ntoskrnl/ntkrnlmp.rbuild b/reactos/ntoskrnl/ntkrnlmp.rbuild index 1d23932e496..8659a959556 100644 --- a/reactos/ntoskrnl/ntkrnlmp.rbuild +++ b/reactos/ntoskrnl/ntkrnlmp.rbuild @@ -142,12 +142,6 @@ cmwraprs.c ntapi.c - - ntfunc.c - regfile.c - registry.c - regobj.c - dbgkutil.c dbgkobj.c diff --git a/reactos/ntoskrnl/ntoskrnl.rbuild b/reactos/ntoskrnl/ntoskrnl.rbuild index aae2e54edc2..b358ed51c9e 100644 --- a/reactos/ntoskrnl/ntoskrnl.rbuild +++ b/reactos/ntoskrnl/ntoskrnl.rbuild @@ -138,9 +138,6 @@ cmwraprs.c ntapi.c - - regobj.c - dbgkutil.c dbgkobj.c