2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/config/cmapi.c
5 * PURPOSE: Configuration Manager - Internal Registry APIs
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
15 /* FUNCTIONS *****************************************************************/
19 CmpIsHiveAlreadyLoaded(IN HANDLE KeyHandle
,
20 IN POBJECT_ATTRIBUTES SourceFile
,
26 BOOLEAN Loaded
= FALSE
;
30 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK();
32 /* Reference the handle */
33 Status
= ObReferenceObjectByHandle(KeyHandle
,
39 if (!NT_SUCCESS(Status
)) return Loaded
;
41 /* Don't touch deleted KCBs */
42 if (KeyBody
->KeyControlBlock
->Delete
) return Loaded
;
44 Hive
= CONTAINING_RECORD(KeyBody
->KeyControlBlock
->KeyHive
, CMHIVE
, Hive
);
46 /* Must be the root key */
47 if (!(KeyBody
->KeyControlBlock
->Flags
& KEY_HIVE_ENTRY
) ||
48 !(Hive
->FileUserName
.Buffer
))
51 ObDereferenceObject(KeyBody
);
55 /* Now compare the name of the file */
56 if (!RtlCompareUnicodeString(&Hive
->FileUserName
,
57 SourceFile
->ObjectName
,
64 /* If the hive is frozen, not sure what to do */
68 DPRINT1("ERROR: Hive is frozen\n");
73 /* Dereference and return result */
74 ObDereferenceObject(KeyBody
);
80 CmpDoFlushAll(IN BOOLEAN ForceFlush
)
82 PLIST_ENTRY NextEntry
;
85 BOOLEAN Result
= TRUE
;
87 /* Make sure that the registry isn't read-only now */
88 if (CmpNoWrite
) return TRUE
;
90 /* Otherwise, acquire the hive list lock and disable force flush */
91 CmpForceForceFlush
= FALSE
;
92 ExAcquirePushLockShared(&CmpHiveListHeadLock
);
94 /* Loop the hive list */
95 NextEntry
= CmpHiveListHead
.Flink
;
96 while (NextEntry
!= &CmpHiveListHead
)
99 Hive
= CONTAINING_RECORD(NextEntry
, CMHIVE
, HiveList
);
100 if (!(Hive
->Hive
.HiveFlags
& HIVE_NOLAZYFLUSH
))
102 /* Acquire the flusher lock */
103 CmpLockHiveFlusherExclusive(Hive
);
105 /* Check for illegal state */
106 if ((ForceFlush
) && (Hive
->UseCount
))
108 /* Registry needs to be locked down */
109 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK();
110 DPRINT1("FIXME: Hive is damaged and needs fixup\n");
114 /* Only sync if we are forced to or if it won't cause a hive shrink */
115 if ((ForceFlush
) || (!HvHiveWillShrink(&Hive
->Hive
)))
118 Status
= HvSyncHive(&Hive
->Hive
);
120 /* If something failed - set the flag and continue looping */
121 if (!NT_SUCCESS(Status
)) Result
= FALSE
;
125 /* We won't flush if the hive might shrink */
127 CmpForceForceFlush
= TRUE
;
130 /* Release the flusher lock */
131 CmpUnlockHiveFlusher(Hive
);
134 /* Try the next entry */
135 NextEntry
= NextEntry
->Flink
;
138 /* Release lock and return */
139 ExReleasePushLock(&CmpHiveListHeadLock
);
145 CmpSetValueKeyNew(IN PHHIVE Hive
,
146 IN PCM_KEY_NODE Parent
,
147 IN PUNICODE_STRING ValueName
,
152 IN ULONG StorageType
,
156 HCELL_INDEX ValueCell
;
159 /* Check if we already have a value list */
160 if (Parent
->ValueList
.Count
)
162 /* Then make sure it's valid and dirty it */
163 ASSERT(Parent
->ValueList
.List
!= HCELL_NIL
);
164 if (!HvMarkCellDirty(Hive
, Parent
->ValueList
.List
, FALSE
))
166 /* Fail if we're out of space for log changes */
167 return STATUS_NO_LOG_SPACE
;
171 /* Allocate a value cell */
172 ValueCell
= HvAllocateCell(Hive
,
173 FIELD_OFFSET(CM_KEY_VALUE
, Name
) +
174 CmpNameSize(Hive
, ValueName
),
177 if (ValueCell
== HCELL_NIL
) return STATUS_INSUFFICIENT_RESOURCES
;
179 /* Get the actual data for it */
180 CellData
= HvGetCell(Hive
, ValueCell
);
181 if (!CellData
) ASSERT(FALSE
);
183 /* Now we can release it, make sure it's also dirty */
184 HvReleaseCell(Hive
, ValueCell
);
185 ASSERT(HvIsCellDirty(Hive
, ValueCell
));
187 /* Set it up and copy the name */
188 CellData
->u
.KeyValue
.Signature
= CM_KEY_VALUE_SIGNATURE
;
191 /* This can crash since the name is coming from user-mode */
192 CellData
->u
.KeyValue
.NameLength
= CmpCopyName(Hive
,
193 CellData
->u
.KeyValue
.Name
,
196 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
199 DPRINT1("Invalid user data!\n");
200 HvFreeCell(Hive
, ValueCell
);
201 _SEH2_YIELD(return _SEH2_GetExceptionCode());
205 /* Check for compressed name */
206 if (CellData
->u
.KeyValue
.NameLength
< ValueName
->Length
)
208 /* This is a compressed name */
209 CellData
->u
.KeyValue
.Flags
= VALUE_COMP_NAME
;
213 /* No flags to set */
214 CellData
->u
.KeyValue
.Flags
= 0;
217 /* Check if this is a normal key */
218 if (DataSize
> CM_KEY_VALUE_SMALL
)
220 /* Build a data cell for it */
221 Status
= CmpSetValueDataNew(Hive
,
226 &CellData
->u
.KeyValue
.Data
);
227 if (!NT_SUCCESS(Status
))
229 /* We failed, free the cell */
230 HvFreeCell(Hive
, ValueCell
);
234 /* Otherwise, set the data length, and make sure the data is dirty */
235 CellData
->u
.KeyValue
.DataLength
= DataSize
;
236 ASSERT(HvIsCellDirty(Hive
, CellData
->u
.KeyValue
.Data
));
240 /* This is a small key, set the data directly inside */
241 CellData
->u
.KeyValue
.DataLength
= DataSize
+ CM_KEY_VALUE_SPECIAL_SIZE
;
242 CellData
->u
.KeyValue
.Data
= SmallData
;
245 /* Set the type now */
246 CellData
->u
.KeyValue
.Type
= Type
;
248 /* Add this value cell to the child list */
249 Status
= CmpAddValueToList(Hive
,
255 /* If we failed, free the entire cell, including the data */
256 if (!NT_SUCCESS(Status
))
258 /* Overwrite the status with a known one */
259 CmpFreeValue(Hive
, ValueCell
);
260 Status
= STATUS_INSUFFICIENT_RESOURCES
;
269 CmpSetValueKeyExisting(IN PHHIVE Hive
,
270 IN HCELL_INDEX OldChild
,
271 IN PCM_KEY_VALUE Value
,
275 IN ULONG StorageType
,
278 HCELL_INDEX DataCell
, NewCell
;
281 BOOLEAN WasSmall
, IsSmall
;
283 /* Registry writes must be blocked */
284 CMP_ASSERT_FLUSH_LOCK(Hive
);
286 /* Mark the old child cell dirty */
287 if (!HvMarkCellDirty(Hive
, OldChild
, FALSE
)) return STATUS_NO_LOG_SPACE
;
289 /* See if this is a small or normal key */
290 WasSmall
= CmpIsKeyValueSmall(&Length
, Value
->DataLength
);
292 /* See if our new data can fit in a small key */
293 IsSmall
= (DataSize
<= CM_KEY_VALUE_SMALL
) ? TRUE
: FALSE
;
295 /* Big keys are unsupported */
296 ASSERT_VALUE_BIG(Hive
, Length
);
297 ASSERT_VALUE_BIG(Hive
, DataSize
);
299 /* Mark the old value dirty */
300 if (!CmpMarkValueDataDirty(Hive
, Value
)) return STATUS_NO_LOG_SPACE
;
302 /* Check if we have a small key */
305 /* Check if we had a normal key with some data in it */
306 if (!(WasSmall
) && (Length
> 0))
308 /* Free the previous data */
309 CmpFreeValueData(Hive
, Value
->Data
, Length
);
312 /* Write our data directly */
313 Value
->DataLength
= DataSize
+ CM_KEY_VALUE_SPECIAL_SIZE
;
314 Value
->Data
= TempData
;
316 return STATUS_SUCCESS
;
319 /* We have a normal key. Was the old cell also normal and had data? */
320 if (!(WasSmall
) && (Length
> 0))
322 /* Get the current data cell and actual data inside it */
323 DataCell
= Value
->Data
;
324 ASSERT(DataCell
!= HCELL_NIL
);
325 CellData
= HvGetCell(Hive
, DataCell
);
326 if (!CellData
) return STATUS_INSUFFICIENT_RESOURCES
;
328 /* Immediately release the cell */
329 HvReleaseCell(Hive
, DataCell
);
331 /* Make sure that the data cell actually has a size */
332 ASSERT(HvGetCellSize(Hive
, CellData
) > 0);
334 /* Check if the previous data cell could fit our new data */
335 if (DataSize
<= (ULONG
)(HvGetCellSize(Hive
, CellData
)))
342 /* Otherwise, re-allocate the current data cell */
343 NewCell
= HvReallocateCell(Hive
, DataCell
, DataSize
);
344 if (NewCell
== HCELL_NIL
) return STATUS_INSUFFICIENT_RESOURCES
;
349 /* This was a small key, or a key with no data, allocate a cell */
350 NewCell
= HvAllocateCell(Hive
, DataSize
, StorageType
, HCELL_NIL
);
351 if (NewCell
== HCELL_NIL
) return STATUS_INSUFFICIENT_RESOURCES
;
354 /* Now get the actual data for our data cell */
355 CellData
= HvGetCell(Hive
, NewCell
);
356 if (!CellData
) ASSERT(FALSE
);
358 /* Release it immediately */
359 HvReleaseCell(Hive
, NewCell
);
361 /* Copy our data into the data cell's buffer, and set up the value */
362 RtlCopyMemory(CellData
, Data
, DataSize
);
363 Value
->Data
= NewCell
;
364 Value
->DataLength
= DataSize
;
368 ASSERT(HvIsCellDirty(Hive
, NewCell
));
369 return STATUS_SUCCESS
;
374 CmpQueryKeyData(IN PHHIVE Hive
,
375 IN PCM_KEY_NODE Node
,
376 IN KEY_INFORMATION_CLASS KeyInformationClass
,
377 IN OUT PVOID KeyInformation
,
379 IN OUT PULONG ResultLength
)
382 ULONG Size
, SizeLeft
, MinimumSize
;
383 PKEY_INFORMATION Info
= (PKEY_INFORMATION
)KeyInformation
;
386 /* Check if the value is compressed */
387 if (Node
->Flags
& KEY_COMP_NAME
)
389 /* Get the compressed name size */
390 NameLength
= CmpCompressedNameSize(Node
->Name
, Node
->NameLength
);
394 /* Get the real size */
395 NameLength
= Node
->NameLength
;
398 /* Check what kind of information is being requested */
399 switch (KeyInformationClass
)
401 /* Basic information */
402 case KeyBasicInformation
:
404 /* This is the size we need */
405 Size
= FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
) + NameLength
;
407 /* And this is the minimum we can work with */
408 MinimumSize
= FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
);
410 /* Let the caller know and assume success */
411 *ResultLength
= Size
;
412 Status
= STATUS_SUCCESS
;
414 /* Check if the bufer we got is too small */
415 if (Length
< MinimumSize
)
417 /* Let the caller know and fail */
418 Status
= STATUS_BUFFER_TOO_SMALL
;
422 /* Copy the basic information */
423 Info
->KeyBasicInformation
.LastWriteTime
= Node
->LastWriteTime
;
424 Info
->KeyBasicInformation
.TitleIndex
= 0;
425 Info
->KeyBasicInformation
.NameLength
= NameLength
;
427 /* Only the name is left */
428 SizeLeft
= Length
- MinimumSize
;
431 /* Check if we don't have enough space for the name */
434 /* Truncate the name we'll return, and tell the caller */
436 Status
= STATUS_BUFFER_OVERFLOW
;
439 /* Check if this is a compressed key */
440 if (Node
->Flags
& KEY_COMP_NAME
)
442 /* Copy the compressed name */
443 CmpCopyCompressedName(Info
->KeyBasicInformation
.Name
,
450 /* Otherwise, copy the raw name */
451 RtlCopyMemory(Info
->KeyBasicInformation
.Name
,
457 /* Node information */
458 case KeyNodeInformation
:
460 /* Calculate the size we need */
461 Size
= FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
) +
465 /* And the minimum size we can support */
466 MinimumSize
= FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
);
468 /* Return the size to the caller and assume succes */
469 *ResultLength
= Size
;
470 Status
= STATUS_SUCCESS
;
472 /* Check if the caller's buffer is too small */
473 if (Length
< MinimumSize
)
475 /* Let them know, and fail */
476 Status
= STATUS_BUFFER_TOO_SMALL
;
480 /* Copy the basic information */
481 Info
->KeyNodeInformation
.LastWriteTime
= Node
->LastWriteTime
;
482 Info
->KeyNodeInformation
.TitleIndex
= 0;
483 Info
->KeyNodeInformation
.ClassLength
= Node
->ClassLength
;
484 Info
->KeyNodeInformation
.NameLength
= NameLength
;
486 /* Now the name is left */
487 SizeLeft
= Length
- MinimumSize
;
490 /* Check if the name can fit entirely */
493 /* It can't, we'll have to truncate. Tell the caller */
495 Status
= STATUS_BUFFER_OVERFLOW
;
498 /* Check if the key node name is compressed */
499 if (Node
->Flags
& KEY_COMP_NAME
)
501 /* Copy the compressed name */
502 CmpCopyCompressedName(Info
->KeyNodeInformation
.Name
,
509 /* It isn't, so copy the raw name */
510 RtlCopyMemory(Info
->KeyNodeInformation
.Name
,
515 /* Check if the node has a class */
516 if (Node
->ClassLength
> 0)
518 /* It does. We don't support these yet */
519 ASSERTMSG("Classes not supported\n", FALSE
);
523 /* It doesn't, so set offset to -1, not 0! */
524 Info
->KeyNodeInformation
.ClassOffset
= 0xFFFFFFFF;
528 /* Full information requsted */
529 case KeyFullInformation
:
531 /* This is the size we need */
532 Size
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
) +
535 /* This is what we can work with */
536 MinimumSize
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
);
538 /* Return it to caller and assume success */
539 *ResultLength
= Size
;
540 Status
= STATUS_SUCCESS
;
542 /* Check if the caller's buffer is to small */
543 if (Length
< MinimumSize
)
545 /* Let them know and fail */
546 Status
= STATUS_BUFFER_TOO_SMALL
;
550 /* Now copy all the basic information */
551 Info
->KeyFullInformation
.LastWriteTime
= Node
->LastWriteTime
;
552 Info
->KeyFullInformation
.TitleIndex
= 0;
553 Info
->KeyFullInformation
.ClassLength
= Node
->ClassLength
;
554 Info
->KeyFullInformation
.SubKeys
= Node
->SubKeyCounts
[Stable
] +
555 Node
->SubKeyCounts
[Volatile
];
556 Info
->KeyFullInformation
.Values
= Node
->ValueList
.Count
;
557 Info
->KeyFullInformation
.MaxNameLen
= Node
->MaxNameLen
;
558 Info
->KeyFullInformation
.MaxClassLen
= Node
->MaxClassLen
;
559 Info
->KeyFullInformation
.MaxValueNameLen
= Node
->MaxValueNameLen
;
560 Info
->KeyFullInformation
.MaxValueDataLen
= Node
->MaxValueDataLen
;
562 /* Check if we have a class */
563 if (Node
->ClassLength
> 0)
565 /* We do, but we currently don't support this */
566 ASSERTMSG("Classes not supported\n", FALSE
);
570 /* We don't have a class, so set offset to -1, not 0! */
571 Info
->KeyNodeInformation
.ClassOffset
= 0xFFFFFFFF;
575 /* Any other class that got sent here is invalid! */
578 /* Set failure code */
579 Status
= STATUS_INVALID_PARAMETER
;
589 CmSetValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
590 IN PUNICODE_STRING ValueName
,
597 PCM_KEY_VALUE Value
= NULL
;
598 HCELL_INDEX CurrentChild
, Cell
;
600 BOOLEAN Found
, Result
;
601 ULONG Count
, ChildIndex
, SmallData
, Storage
;
602 VALUE_SEARCH_RETURN_TYPE SearchResult
;
603 BOOLEAN FirstTry
= TRUE
, FlusherLocked
= FALSE
;
604 HCELL_INDEX ParentCell
= HCELL_NIL
, ChildCell
= HCELL_NIL
;
606 /* Acquire hive and KCB lock */
608 CmpAcquireKcbLockShared(Kcb
);
611 ASSERT(sizeof(ULONG
) == CM_KEY_VALUE_SMALL
);
613 /* Don't touch deleted KCBs */
618 Status
= STATUS_KEY_DELETED
;
622 /* Don't let anyone mess with symlinks */
623 if ((Kcb
->Flags
& KEY_SYM_LINK
) &&
624 ((Type
!= REG_LINK
) ||
626 !(RtlEqualUnicodeString(&CmSymbolicLinkValueName
, ValueName
, TRUE
))))
628 /* Invalid modification of a symlink key */
629 Status
= STATUS_ACCESS_DENIED
;
633 /* Check if this is the first attempt */
636 /* Search for the value in the cache */
637 SearchResult
= CmpCompareNewValueDataAgainstKCBCache(Kcb
,
642 if (SearchResult
== SearchNeedExclusiveLock
)
644 /* Try again with the exclusive lock */
645 CmpConvertKcbSharedToExclusive(Kcb
);
648 else if (SearchResult
== SearchSuccess
)
650 /* We don't actually need to do anything! */
651 Status
= STATUS_SUCCESS
;
655 /* We need the exclusive KCB lock now */
656 if (!(CmpIsKcbLockedExclusive(Kcb
)) &&
657 !(CmpTryToConvertKcbSharedToExclusive(Kcb
)))
659 /* Acquire exclusive lock */
660 CmpConvertKcbSharedToExclusive(Kcb
);
663 /* Cache lookup failed, so don't try it next time */
666 /* Now grab the flush lock since the key will be modified */
667 ASSERT(FlusherLocked
== FALSE
);
668 CmpLockHiveFlusherShared((PCMHIVE
)Kcb
->KeyHive
);
669 FlusherLocked
= TRUE
;
674 /* Get pointer to key cell */
679 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
683 /* Prepare to scan the key node */
684 Count
= Parent
->ValueList
.Count
;
688 /* Try to find the existing name */
689 Result
= CmpFindNameInList(Hive
,
697 Status
= STATUS_INSUFFICIENT_RESOURCES
;
701 /* Check if we found something */
702 if (CurrentChild
!= HCELL_NIL
)
704 /* Release existing child */
705 if (ChildCell
!= HCELL_NIL
)
707 HvReleaseCell(Hive
, ChildCell
);
708 ChildCell
= HCELL_NIL
;
712 Value
= (PCM_KEY_VALUE
)HvGetCell(Hive
, CurrentChild
);
716 Status
= STATUS_INSUFFICIENT_RESOURCES
;
720 /* Remember that we found it */
721 ChildCell
= CurrentChild
;
727 /* No child list, we'll need to add it */
732 /* Should only get here on the second pass */
733 ASSERT(FirstTry
== FALSE
);
735 /* The KCB must be locked exclusive at this point */
736 CMP_ASSERT_KCB_LOCK(Kcb
);
738 /* Mark the cell dirty */
739 if (!HvMarkCellDirty(Hive
, Cell
, FALSE
))
741 /* Not enough log space, fail */
742 Status
= STATUS_NO_LOG_SPACE
;
746 /* Get the storage type */
747 Storage
= HvGetCellType(Cell
);
749 /* Check if this is small data */
751 if ((DataLength
<= CM_KEY_VALUE_SMALL
) && (DataLength
> 0))
753 /* Need SEH because user data may be invalid */
757 RtlCopyMemory(&SmallData
, Data
, DataLength
);
759 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
761 /* Return failure code */
762 Status
= _SEH2_GetExceptionCode();
763 _SEH2_YIELD(goto Quickie
);
768 /* Check if we didn't find a matching key */
771 /* Call the internal routine */
772 Status
= CmpSetValueKeyNew(Hive
,
784 /* Call the internal routine */
785 Status
= CmpSetValueKeyExisting(Hive
,
795 /* Check for success */
796 if (NT_SUCCESS(Status
))
798 /* Check if the maximum value name length changed */
799 ASSERT(Parent
->MaxValueNameLen
== Kcb
->KcbMaxValueNameLen
);
800 if (Parent
->MaxValueNameLen
< ValueName
->Length
)
802 /* Set the new values */
803 Parent
->MaxValueNameLen
= ValueName
->Length
;
804 Kcb
->KcbMaxValueNameLen
= ValueName
->Length
;
807 /* Check if the maximum data length changed */
808 ASSERT(Parent
->MaxValueDataLen
== Kcb
->KcbMaxValueDataLen
);
809 if (Parent
->MaxValueDataLen
< DataLength
)
812 Parent
->MaxValueDataLen
= DataLength
;
813 Kcb
->KcbMaxValueDataLen
= Parent
->MaxValueDataLen
;
816 /* Save the write time */
817 KeQuerySystemTime(&Parent
->LastWriteTime
);
818 Kcb
->KcbLastWriteTime
= Parent
->LastWriteTime
;
820 /* Check if the cell is cached */
821 if ((Found
) && (CMP_IS_CELL_CACHED(Kcb
->ValueCache
.ValueList
)))
823 /* Shouldn't happen */
828 /* Cleanup the value cache */
829 CmpCleanUpKcbValueCache(Kcb
);
832 ASSERT(!(CMP_IS_CELL_CACHED(Kcb
->ValueCache
.ValueList
)));
833 ASSERT(!(Kcb
->ExtFlags
& CM_KCB_SYM_LINK_FOUND
));
835 /* Set the value cache */
836 Kcb
->ValueCache
.Count
= Parent
->ValueList
.Count
;
837 Kcb
->ValueCache
.ValueList
= Parent
->ValueList
.List
;
840 /* Notify registered callbacks */
844 REG_NOTIFY_CHANGE_LAST_SET
);
847 /* Release the cells */
849 if ((ParentCell
!= HCELL_NIL
) && (Hive
)) HvReleaseCell(Hive
, ParentCell
);
850 if ((ChildCell
!= HCELL_NIL
) && (Hive
)) HvReleaseCell(Hive
, ChildCell
);
852 /* Release the locks */
853 if (FlusherLocked
) CmpUnlockHiveFlusher((PCMHIVE
)Hive
);
854 CmpReleaseKcbLock(Kcb
);
861 CmDeleteValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
862 IN UNICODE_STRING ValueName
)
864 NTSTATUS Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
867 HCELL_INDEX ChildCell
, Cell
;
868 PCHILD_LIST ChildList
;
869 PCM_KEY_VALUE Value
= NULL
;
873 /* Acquire hive lock */
876 /* Lock KCB exclusively */
877 CmpAcquireKcbLockExclusive(Kcb
);
879 /* Don't touch deleted keys */
882 /* Undo everything */
883 CmpReleaseKcbLock(Kcb
);
885 return STATUS_KEY_DELETED
;
888 /* Get the hive and the cell index */
893 CmpLockHiveFlusherShared((PCMHIVE
)Hive
);
895 /* Get the parent key node */
896 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
899 /* Get the value list and check if it has any entries */
900 ChildList
= &Parent
->ValueList
;
901 if (ChildList
->Count
)
903 /* Try to find this value */
904 Result
= CmpFindNameInList(Hive
,
912 Status
= STATUS_INSUFFICIENT_RESOURCES
;
916 /* Value not found, return error */
917 if (ChildCell
== HCELL_NIL
) goto Quickie
;
919 /* We found the value, mark all relevant cells dirty */
920 if (!((HvMarkCellDirty(Hive
, Cell
, FALSE
)) &&
921 (HvMarkCellDirty(Hive
, Parent
->ValueList
.List
, FALSE
)) &&
922 (HvMarkCellDirty(Hive
, ChildCell
, FALSE
))))
924 /* Not enough log space, fail */
925 Status
= STATUS_NO_LOG_SPACE
;
929 /* Get the key value */
930 Value
= (PCM_KEY_VALUE
)HvGetCell(Hive
,ChildCell
);
933 /* Mark it and all related data as dirty */
934 if (!CmpMarkValueDataDirty(Hive
, Value
))
936 /* Not enough log space, fail */
937 Status
= STATUS_NO_LOG_SPACE
;
942 ASSERT(HvIsCellDirty(Hive
, Parent
->ValueList
.List
));
943 ASSERT(HvIsCellDirty(Hive
, ChildCell
));
945 /* Remove the value from the child list */
946 Status
= CmpRemoveValueFromList(Hive
, ChildIndex
, ChildList
);
947 if (!NT_SUCCESS(Status
))
949 /* Set known error */
950 Status
= STATUS_INSUFFICIENT_RESOURCES
;
954 /* Remove the value and its data itself */
955 if (!CmpFreeValue(Hive
, ChildCell
))
957 /* Failed to free the value, fail */
958 Status
= STATUS_INSUFFICIENT_RESOURCES
;
962 /* Set the last write time */
963 KeQuerySystemTime(&Parent
->LastWriteTime
);
964 Kcb
->KcbLastWriteTime
= Parent
->LastWriteTime
;
967 ASSERT(Parent
->MaxValueNameLen
== Kcb
->KcbMaxValueNameLen
);
968 ASSERT(Parent
->MaxValueDataLen
== Kcb
->KcbMaxValueDataLen
);
969 ASSERT(HvIsCellDirty(Hive
, Cell
));
971 /* Check if the value list is empty now */
972 if (!Parent
->ValueList
.Count
)
974 /* Then clear key node data */
975 Parent
->MaxValueNameLen
= 0;
976 Parent
->MaxValueDataLen
= 0;
977 Kcb
->KcbMaxValueNameLen
= 0;
978 Kcb
->KcbMaxValueDataLen
= 0;
981 /* Cleanup the value cache */
982 CmpCleanUpKcbValueCache(Kcb
);
985 ASSERT(!(CMP_IS_CELL_CACHED(Kcb
->ValueCache
.ValueList
)));
986 ASSERT(!(Kcb
->ExtFlags
& CM_KCB_SYM_LINK_FOUND
));
988 /* Set the value cache */
989 Kcb
->ValueCache
.Count
= ChildList
->Count
;
990 Kcb
->ValueCache
.ValueList
= ChildList
->List
;
992 /* Notify registered callbacks */
993 CmpReportNotify(Kcb
, Hive
, Cell
, REG_NOTIFY_CHANGE_LAST_SET
);
995 /* Change default Status to success */
996 Status
= STATUS_SUCCESS
;
1000 /* Release the parent cell, if any */
1001 if (Parent
) HvReleaseCell(Hive
, Cell
);
1003 /* Check if we had a value */
1006 /* Release the child cell */
1007 ASSERT(ChildCell
!= HCELL_NIL
);
1008 HvReleaseCell(Hive
, ChildCell
);
1012 CmpUnlockHiveFlusher((PCMHIVE
)Hive
);
1013 CmpReleaseKcbLock(Kcb
);
1014 CmpUnlockRegistry();
1020 CmQueryValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
1021 IN UNICODE_STRING ValueName
,
1022 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
1023 IN PVOID KeyValueInformation
,
1025 IN PULONG ResultLength
)
1028 PCM_KEY_VALUE ValueData
;
1030 BOOLEAN ValueCached
= FALSE
;
1031 PCM_CACHED_VALUE
*CachedValue
;
1032 HCELL_INDEX CellToRelease
;
1033 VALUE_SEARCH_RETURN_TYPE Result
;
1037 /* Acquire hive lock */
1040 /* Lock the KCB shared */
1041 CmpAcquireKcbLockShared(Kcb
);
1043 /* Don't touch deleted keys */
1047 /* Undo everything */
1048 CmpReleaseKcbLock(Kcb
);
1049 CmpUnlockRegistry();
1050 return STATUS_KEY_DELETED
;
1053 /* We don't deal with this yet */
1054 if (Kcb
->ExtFlags
& CM_KCB_SYM_LINK_FOUND
)
1056 /* Shouldn't happen */
1061 Hive
= Kcb
->KeyHive
;
1063 /* Find the key value */
1064 Result
= CmpFindValueByNameFromCache(Kcb
,
1071 if (Result
== SearchNeedExclusiveLock
)
1073 /* Check if we need an exclusive lock */
1074 ASSERT(CellToRelease
== HCELL_NIL
);
1075 ASSERT(ValueData
== NULL
);
1077 /* Try with exclusive KCB lock */
1078 CmpConvertKcbSharedToExclusive(Kcb
);
1082 if (Result
== SearchSuccess
)
1085 ASSERT(ValueData
!= NULL
);
1087 /* User data, protect against exceptions */
1090 /* Query the information requested */
1091 Result
= CmpQueryKeyValueData(Kcb
,
1095 KeyValueInformationClass
,
1096 KeyValueInformation
,
1100 if (Result
== SearchNeedExclusiveLock
)
1102 /* Release the value cell */
1103 if (CellToRelease
!= HCELL_NIL
)
1105 HvReleaseCell(Hive
, CellToRelease
);
1106 CellToRelease
= HCELL_NIL
;
1109 /* Try with exclusive KCB lock */
1110 CmpConvertKcbSharedToExclusive(Kcb
);
1114 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1116 Status
= _SEH2_GetExceptionCode();
1122 /* Failed to find the value */
1123 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1126 /* If we have a cell to release, do so */
1127 if (CellToRelease
!= HCELL_NIL
) HvReleaseCell(Hive
, CellToRelease
);
1130 CmpReleaseKcbLock(Kcb
);
1131 CmpUnlockRegistry();
1137 CmEnumerateValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
1139 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
1140 IN PVOID KeyValueInformation
,
1142 IN PULONG ResultLength
)
1146 PCM_KEY_NODE Parent
;
1147 HCELL_INDEX CellToRelease
= HCELL_NIL
, CellToRelease2
= HCELL_NIL
;
1148 VALUE_SEARCH_RETURN_TYPE Result
;
1149 BOOLEAN IndexIsCached
, ValueIsCached
= FALSE
;
1150 PCELL_DATA CellData
;
1151 PCM_CACHED_VALUE
*CachedValue
;
1152 PCM_KEY_VALUE ValueData
= NULL
;
1155 /* Acquire hive lock */
1158 /* Lock the KCB shared */
1159 CmpAcquireKcbLockShared(Kcb
);
1161 /* Don't touch deleted keys */
1165 /* Undo everything */
1166 CmpReleaseKcbLock(Kcb
);
1167 CmpUnlockRegistry();
1168 return STATUS_KEY_DELETED
;
1171 /* Get the hive and parent */
1172 Hive
= Kcb
->KeyHive
;
1173 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, Kcb
->KeyCell
);
1176 /* FIXME: Lack of cache? */
1177 if (Kcb
->ValueCache
.Count
!= Parent
->ValueList
.Count
)
1179 DPRINT1("HACK: Overriding value cache count\n");
1180 Kcb
->ValueCache
.Count
= Parent
->ValueList
.Count
;
1183 /* Make sure the index is valid */
1184 if (Index
>= Kcb
->ValueCache
.Count
)
1186 /* Release the cell and fail */
1187 HvReleaseCell(Hive
, Kcb
->KeyCell
);
1188 Status
= STATUS_NO_MORE_ENTRIES
;
1192 /* We don't deal with this yet */
1193 if (Kcb
->ExtFlags
& CM_KCB_SYM_LINK_FOUND
)
1195 /* Shouldn't happen */
1199 /* Find the value list */
1200 Result
= CmpGetValueListFromCache(Kcb
,
1204 if (Result
== SearchNeedExclusiveLock
)
1206 /* Check if we need an exclusive lock */
1207 ASSERT(CellToRelease
== HCELL_NIL
);
1208 HvReleaseCell(Hive
, Kcb
->KeyCell
);
1210 /* Try with exclusive KCB lock */
1211 CmpConvertKcbSharedToExclusive(Kcb
);
1214 else if (Result
!= SearchSuccess
)
1217 ASSERT(CellData
== NULL
);
1219 /* Release the cell and fail */
1220 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1224 /* Now get the key value */
1225 Result
= CmpGetValueKeyFromCache(Kcb
,
1233 if (Result
== SearchNeedExclusiveLock
)
1236 ASSERT(CellToRelease2
== HCELL_NIL
);
1239 HvReleaseCell(Hive
, CellToRelease
);
1240 CellToRelease
= HCELL_NIL
;
1242 HvReleaseCell(Hive
, Kcb
->KeyCell
);
1244 /* Try with exclusive KCB lock */
1245 CmpConvertKcbSharedToExclusive(Kcb
);
1248 else if (Result
!= SearchSuccess
)
1251 ASSERT(ValueData
== NULL
);
1253 /* Release the cells and fail */
1254 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1258 /* User data, need SEH */
1261 /* Query the information requested */
1262 Result
= CmpQueryKeyValueData(Kcb
,
1266 KeyValueInformationClass
,
1267 KeyValueInformation
,
1271 if (Result
== SearchNeedExclusiveLock
)
1274 if (CellToRelease2
) HvReleaseCell(Hive
, CellToRelease2
);
1275 HvReleaseCell(Hive
, Kcb
->KeyCell
);
1276 if (CellToRelease
) HvReleaseCell(Hive
, CellToRelease
);
1278 /* Try with exclusive KCB lock */
1279 CmpConvertKcbSharedToExclusive(Kcb
);
1283 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1285 /* Get exception code */
1286 Status
= _SEH2_GetExceptionCode();
1291 /* If we have a cell to release, do so */
1292 if (CellToRelease
!= HCELL_NIL
) HvReleaseCell(Hive
, CellToRelease
);
1294 /* Release the parent cell */
1295 HvReleaseCell(Hive
, Kcb
->KeyCell
);
1297 /* If we have a cell to release, do so */
1298 if (CellToRelease2
!= HCELL_NIL
) HvReleaseCell(Hive
, CellToRelease2
);
1301 CmpReleaseKcbLock(Kcb
);
1302 CmpUnlockRegistry();
1308 CmQueryKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
1309 IN KEY_INFORMATION_CLASS KeyInformationClass
,
1310 IN PVOID KeyInformation
,
1312 IN PULONG ResultLength
)
1316 PCM_KEY_NODE Parent
;
1317 HV_TRACK_CELL_REF CellReferences
= {0};
1319 /* Acquire hive lock */
1322 /* Lock KCB shared */
1323 CmpAcquireKcbLockShared(Kcb
);
1325 /* Don't touch deleted keys */
1329 Status
= STATUS_KEY_DELETED
;
1333 /* Check what class we got */
1334 switch (KeyInformationClass
)
1336 /* Typical information */
1337 case KeyFullInformation
:
1338 case KeyBasicInformation
:
1339 case KeyNodeInformation
:
1341 /* Get the hive and parent */
1342 Hive
= Kcb
->KeyHive
;
1343 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, Kcb
->KeyCell
);
1346 /* Track cell references */
1347 if (!HvTrackCellRef(&CellReferences
, Hive
, Kcb
->KeyCell
))
1349 /* Not enough memory to track references */
1350 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1354 /* Call the internal API */
1355 Status
= CmpQueryKeyData(Hive
,
1357 KeyInformationClass
,
1364 /* Unsupported classes for now */
1365 case KeyNameInformation
:
1366 case KeyCachedInformation
:
1367 case KeyFlagsInformation
:
1369 /* Print message and fail */
1370 DPRINT1("Unsupported class: %d!\n", KeyInformationClass
);
1371 Status
= STATUS_NOT_IMPLEMENTED
;
1374 /* Illegal classes */
1377 /* Print message and fail */
1378 DPRINT1("Unsupported class: %d!\n", KeyInformationClass
);
1379 Status
= STATUS_INVALID_INFO_CLASS
;
1384 /* Release references */
1385 HvReleaseFreeCellRefArray(&CellReferences
);
1388 CmpReleaseKcbLock(Kcb
);
1389 CmpUnlockRegistry();
1395 CmEnumerateKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
1397 IN KEY_INFORMATION_CLASS KeyInformationClass
,
1398 IN PVOID KeyInformation
,
1400 IN PULONG ResultLength
)
1404 PCM_KEY_NODE Parent
, Child
;
1405 HCELL_INDEX ChildCell
;
1406 HV_TRACK_CELL_REF CellReferences
= {0};
1408 /* Acquire hive lock */
1411 /* Lock the KCB shared */
1412 CmpAcquireKcbLockShared(Kcb
);
1414 /* Don't touch deleted keys */
1417 /* Undo everything */
1418 Status
= STATUS_KEY_DELETED
;
1422 /* Get the hive and parent */
1423 Hive
= Kcb
->KeyHive
;
1424 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, Kcb
->KeyCell
);
1427 /* Get the child cell */
1428 ChildCell
= CmpFindSubKeyByNumber(Hive
, Parent
, Index
);
1430 /* Release the parent cell */
1431 HvReleaseCell(Hive
, Kcb
->KeyCell
);
1433 /* Check if we found the child */
1434 if (ChildCell
== HCELL_NIL
)
1436 /* We didn't, fail */
1437 Status
= STATUS_NO_MORE_ENTRIES
;
1441 /* Now get the actual child node */
1442 Child
= (PCM_KEY_NODE
)HvGetCell(Hive
, ChildCell
);
1445 /* Track references */
1446 if (!HvTrackCellRef(&CellReferences
, Hive
, ChildCell
))
1448 /* Can't allocate memory for tracking */
1449 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1453 /* Data can be user-mode, use SEH */
1456 /* Query the data requested */
1457 Status
= CmpQueryKeyData(Hive
,
1459 KeyInformationClass
,
1464 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1466 /* Fail with exception code */
1467 Status
= _SEH2_GetExceptionCode();
1468 _SEH2_YIELD(goto Quickie
);
1473 /* Release references */
1474 HvReleaseFreeCellRefArray(&CellReferences
);
1477 CmpReleaseKcbLock(Kcb
);
1478 CmpUnlockRegistry();
1484 CmDeleteKey(IN PCM_KEY_BODY KeyBody
)
1488 PCM_KEY_NODE Node
, Parent
;
1489 HCELL_INDEX Cell
, ParentCell
;
1490 PCM_KEY_CONTROL_BLOCK Kcb
;
1492 /* Acquire hive lock */
1496 Kcb
= KeyBody
->KeyControlBlock
;
1498 /* Don't allow deleting the root */
1499 if (!Kcb
->ParentKcb
)
1502 CmpUnlockRegistry();
1503 return STATUS_CANNOT_DELETE
;
1506 /* Lock parent and child */
1507 CmpAcquireTwoKcbLocksExclusiveByKey(Kcb
->ConvKey
, Kcb
->ParentKcb
->ConvKey
);
1509 /* Check if we're already being deleted */
1512 /* Don't do it twice */
1513 Status
= STATUS_SUCCESS
;
1517 /* Get the hive and node */
1518 Hive
= Kcb
->KeyHive
;
1519 Cell
= Kcb
->KeyCell
;
1522 CmpLockHiveFlusherShared((PCMHIVE
)Hive
);
1524 /* Get the key node */
1525 Node
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
1529 ASSERT(Node
->Flags
== Kcb
->Flags
);
1531 /* Check if we don't have any children */
1532 if (!(Node
->SubKeyCounts
[Stable
] + Node
->SubKeyCounts
[Volatile
]) &&
1533 !(Node
->Flags
& KEY_NO_DELETE
))
1535 /* Send notification to registered callbacks */
1536 CmpReportNotify(Kcb
, Hive
, Cell
, REG_NOTIFY_CHANGE_NAME
);
1538 /* Get the parent and free the cell */
1539 ParentCell
= Node
->Parent
;
1540 Status
= CmpFreeKeyByCell(Hive
, Cell
, TRUE
);
1541 if (NT_SUCCESS(Status
))
1543 /* Flush any notifications */
1544 CmpFlushNotifiesOnKeyBodyList(Kcb
, FALSE
);
1546 /* Clean up information we have on the subkey */
1547 CmpCleanUpSubKeyInfo(Kcb
->ParentKcb
);
1549 /* Get the parent node */
1550 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, ParentCell
);
1553 /* Update the maximum name length */
1554 Kcb
->ParentKcb
->KcbMaxNameLen
= Parent
->MaxNameLen
;
1556 /* Make sure we're dirty */
1557 ASSERT(HvIsCellDirty(Hive
, ParentCell
));
1559 /* Update the write time */
1560 KeQuerySystemTime(&Parent
->LastWriteTime
);
1561 Kcb
->ParentKcb
->KcbLastWriteTime
= Parent
->LastWriteTime
;
1563 /* Release the cell */
1564 HvReleaseCell(Hive
, ParentCell
);
1567 /* Set the KCB in delete mode and remove it */
1569 CmpRemoveKeyControlBlock(Kcb
);
1571 /* Clear the cell */
1572 Kcb
->KeyCell
= HCELL_NIL
;
1578 Status
= STATUS_CANNOT_DELETE
;
1581 /* Release the cell */
1582 HvReleaseCell(Hive
, Cell
);
1584 /* Release flush lock */
1585 CmpUnlockHiveFlusher((PCMHIVE
)Hive
);
1587 /* Release the KCB locks */
1589 CmpReleaseTwoKcbLockByKey(Kcb
->ConvKey
, Kcb
->ParentKcb
->ConvKey
);
1591 /* Release hive lock */
1592 CmpUnlockRegistry();
1598 CmFlushKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
1599 IN BOOLEAN ExclusiveLock
)
1602 NTSTATUS Status
= STATUS_SUCCESS
;
1605 /* Ignore flushes until we're ready */
1606 if (CmpNoWrite
) return STATUS_SUCCESS
;
1609 Hive
= Kcb
->KeyHive
;
1610 CmHive
= (PCMHIVE
)Hive
;
1612 /* Check if this is the master hive */
1613 if (CmHive
== CmiVolatileHive
)
1615 /* Flush all the hives instead */
1616 CmpDoFlushAll(FALSE
);
1620 /* Don't touch the hive */
1621 CmpLockHiveFlusherExclusive(CmHive
);
1622 ASSERT(CmHive
->ViewLock
);
1623 KeAcquireGuardedMutex(CmHive
->ViewLock
);
1624 CmHive
->ViewLockOwner
= KeGetCurrentThread();
1626 /* Will the hive shrink? */
1627 if (HvHiveWillShrink(Hive
))
1629 /* I don't believe the current Hv does shrinking */
1634 /* Now we can release views */
1635 ASSERT(CmHive
->ViewLock
);
1636 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK_OR_LOADING(CmHive
);
1637 ASSERT(KeGetCurrentThread() == CmHive
->ViewLockOwner
);
1638 KeReleaseGuardedMutex(CmHive
->ViewLock
);
1641 /* Flush only this hive */
1642 if (!HvSyncHive(Hive
))
1645 Status
= STATUS_REGISTRY_IO_FAILED
;
1648 /* Release the flush lock */
1649 CmpUnlockHiveFlusher((PCMHIVE
)Hive
);
1652 /* Return the status */
1658 CmLoadKey(IN POBJECT_ATTRIBUTES TargetKey
,
1659 IN POBJECT_ATTRIBUTES SourceFile
,
1661 IN PCM_KEY_BODY KeyBody
)
1663 SECURITY_QUALITY_OF_SERVICE ServiceQos
;
1664 SECURITY_CLIENT_CONTEXT ClientSecurityContext
;
1666 BOOLEAN Allocate
= TRUE
;
1667 PCMHIVE CmHive
, LoadedHive
;
1669 CM_PARSE_CONTEXT ParseContext
;
1671 /* Check if we have a trust key */
1675 DPRINT1("Trusted classes not yet supported\n");
1676 return STATUS_NOT_IMPLEMENTED
;
1679 /* Build a service QoS for a security context */
1680 ServiceQos
.Length
= sizeof(SECURITY_QUALITY_OF_SERVICE
);
1681 ServiceQos
.ImpersonationLevel
= SecurityImpersonation
;
1682 ServiceQos
.ContextTrackingMode
= SECURITY_DYNAMIC_TRACKING
;
1683 ServiceQos
.EffectiveOnly
= TRUE
;
1684 Status
= SeCreateClientSecurity(PsGetCurrentThread(),
1687 &ClientSecurityContext
);
1688 if (!NT_SUCCESS(Status
))
1691 DPRINT1("Security context failed\n");
1695 /* Open the target key */
1697 Status
= ZwOpenKey(&KeyHandle
, KEY_READ
, TargetKey
);
1699 RtlZeroMemory(&ParseContext
, sizeof(ParseContext
));
1700 ParseContext
.CreateOperation
= FALSE
;
1701 Status
= ObOpenObjectByName(TargetKey
,
1709 if (!NT_SUCCESS(Status
)) KeyHandle
= NULL
;
1712 Status
= CmpCmdHiveOpen(SourceFile
,
1713 &ClientSecurityContext
,
1718 /* Get rid of the security context */
1719 SeDeleteClientSecurity(&ClientSecurityContext
);
1721 /* See if we failed */
1722 if (!NT_SUCCESS(Status
))
1724 /* See if the target already existed */
1727 /* Lock the registry */
1728 CmpLockRegistryExclusive();
1730 /* Check if we are already loaded */
1731 if (CmpIsHiveAlreadyLoaded(KeyHandle
, SourceFile
, &LoadedHive
))
1733 /* That's okay then */
1735 Status
= STATUS_SUCCESS
;
1738 /* Release the registry */
1739 CmpUnlockRegistry();
1742 /* Close the key handle if we had one */
1743 if (KeyHandle
) ZwClose(KeyHandle
);
1747 /* Lock the registry shared */
1751 ExAcquirePushLockExclusive(&CmpLoadHiveLock
);
1753 /* Lock the hive to this thread */
1754 CmHive
->Hive
.HiveFlags
|= HIVE_IS_UNLOADING
;
1755 CmHive
->CreatorOwner
= KeGetCurrentThread();
1758 if (Flags
& REG_NO_LAZY_FLUSH
) CmHive
->Hive
.HiveFlags
|= HIVE_NOLAZYFLUSH
;
1761 Status
= CmpLinkHiveToMaster(TargetKey
->ObjectName
,
1762 TargetKey
->RootDirectory
,
1765 TargetKey
->SecurityDescriptor
);
1766 if (NT_SUCCESS(Status
))
1768 /* Add to HiveList key */
1769 CmpAddToHiveFileList(CmHive
);
1771 /* Sync the hive if necessary */
1774 /* Sync it under the flusher lock */
1775 CmpLockHiveFlusherExclusive(CmHive
);
1776 HvSyncHive(&CmHive
->Hive
);
1777 CmpUnlockHiveFlusher(CmHive
);
1780 /* Release the hive */
1781 CmHive
->Hive
.HiveFlags
&= ~HIVE_IS_UNLOADING
;
1782 CmHive
->CreatorOwner
= NULL
;
1785 ExReleasePushLock(&CmpLoadHiveLock
);
1793 /* Is this first profile load? */
1794 if (!(CmpProfileLoaded
) && !(CmpWasSetupBoot
))
1796 /* User is now logged on, set quotas */
1797 CmpProfileLoaded
= TRUE
;
1798 CmpSetGlobalQuotaAllowed();
1801 /* Unlock the registry */
1802 CmpUnlockRegistry();
1804 /* Close handle and return */
1805 if (KeyHandle
) ZwClose(KeyHandle
);
1811 CmUnloadKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
1815 return STATUS_NOT_IMPLEMENTED
;