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)
10 /* INCLUDES ******************************************************************/
16 /* FUNCTIONS *****************************************************************/
20 CmpIsHiveAlreadyLoaded(IN HANDLE KeyHandle
,
21 IN POBJECT_ATTRIBUTES SourceFile
,
27 BOOLEAN Loaded
= FALSE
;
31 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK();
33 /* Reference the handle */
34 Status
= ObReferenceObjectByHandle(KeyHandle
,
40 if (!NT_SUCCESS(Status
)) return Loaded
;
42 /* Don't touch deleted KCBs */
43 if (KeyBody
->KeyControlBlock
->Delete
) return Loaded
;
45 Hive
= CONTAINING_RECORD(KeyBody
->KeyControlBlock
->KeyHive
, CMHIVE
, Hive
);
47 /* Must be the root key */
48 if (!(KeyBody
->KeyControlBlock
->Flags
& KEY_HIVE_ENTRY
) ||
49 !(Hive
->FileUserName
.Buffer
))
52 ObDereferenceObject(KeyBody
);
56 /* Now compare the name of the file */
57 if (!RtlCompareUnicodeString(&Hive
->FileUserName
,
58 SourceFile
->ObjectName
,
65 /* If the hive is frozen, not sure what to do */
69 DPRINT1("ERROR: Hive is frozen\n");
74 /* Dereference and return result */
75 ObDereferenceObject(KeyBody
);
81 CmpDoFlushAll(IN BOOLEAN ForceFlush
)
83 PLIST_ENTRY NextEntry
;
86 BOOLEAN Result
= TRUE
;
88 /* Make sure that the registry isn't read-only now */
89 if (CmpNoWrite
) return TRUE
;
91 /* Otherwise, acquire the hive list lock and disable force flush */
92 CmpForceForceFlush
= FALSE
;
93 ExAcquirePushLockShared(&CmpHiveListHeadLock
);
95 /* Loop the hive list */
96 NextEntry
= CmpHiveListHead
.Flink
;
97 while (NextEntry
!= &CmpHiveListHead
)
100 Hive
= CONTAINING_RECORD(NextEntry
, CMHIVE
, HiveList
);
101 if (!(Hive
->Hive
.HiveFlags
& HIVE_NOLAZYFLUSH
))
103 /* Acquire the flusher lock */
104 CmpLockHiveFlusherExclusive(Hive
);
106 /* Check for illegal state */
107 if ((ForceFlush
) && (Hive
->UseCount
))
109 /* Registry needs to be locked down */
110 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK();
111 DPRINT1("FIXME: Hive is damaged and needs fixup\n");
115 /* Only sync if we are forced to or if it won't cause a hive shrink */
116 if ((ForceFlush
) || (!HvHiveWillShrink(&Hive
->Hive
)))
119 Status
= HvSyncHive(&Hive
->Hive
);
121 /* If something failed - set the flag and continue looping */
122 if (!NT_SUCCESS(Status
)) Result
= FALSE
;
126 /* We won't flush if the hive might shrink */
128 CmpForceForceFlush
= TRUE
;
131 /* Release the flusher lock */
132 CmpUnlockHiveFlusher(Hive
);
135 /* Try the next entry */
136 NextEntry
= NextEntry
->Flink
;
139 /* Release lock and return */
140 ExReleasePushLock(&CmpHiveListHeadLock
);
146 CmpSetValueKeyNew(IN PHHIVE Hive
,
147 IN PCM_KEY_NODE Parent
,
148 IN PUNICODE_STRING ValueName
,
153 IN ULONG StorageType
,
157 HCELL_INDEX ValueCell
;
160 /* Check if we already have a value list */
161 if (Parent
->ValueList
.Count
)
163 /* Then make sure it's valid and dirty it */
164 ASSERT(Parent
->ValueList
.List
!= HCELL_NIL
);
165 if (!HvMarkCellDirty(Hive
, Parent
->ValueList
.List
, FALSE
))
167 /* Fail if we're out of space for log changes */
168 return STATUS_NO_LOG_SPACE
;
172 /* Allocate a value cell */
173 ValueCell
= HvAllocateCell(Hive
,
174 FIELD_OFFSET(CM_KEY_VALUE
, Name
) +
175 CmpNameSize(Hive
, ValueName
),
178 if (ValueCell
== HCELL_NIL
) return STATUS_INSUFFICIENT_RESOURCES
;
180 /* Get the actual data for it */
181 CellData
= HvGetCell(Hive
, ValueCell
);
182 if (!CellData
) ASSERT(FALSE
);
184 /* Now we can release it, make sure it's also dirty */
185 HvReleaseCell(Hive
, ValueCell
);
186 ASSERT(HvIsCellDirty(Hive
, ValueCell
));
188 /* Set it up and copy the name */
189 CellData
->u
.KeyValue
.Signature
= CM_KEY_VALUE_SIGNATURE
;
192 /* This can crash since the name is coming from user-mode */
193 CellData
->u
.KeyValue
.NameLength
= CmpCopyName(Hive
,
194 CellData
->u
.KeyValue
.Name
,
197 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
200 DPRINT1("Invalid user data!\n");
201 HvFreeCell(Hive
, ValueCell
);
202 _SEH2_YIELD(return _SEH2_GetExceptionCode());
206 /* Check for compressed name */
207 if (CellData
->u
.KeyValue
.NameLength
< ValueName
->Length
)
209 /* This is a compressed name */
210 CellData
->u
.KeyValue
.Flags
= VALUE_COMP_NAME
;
214 /* No flags to set */
215 CellData
->u
.KeyValue
.Flags
= 0;
218 /* Check if this is a normal key */
219 if (DataSize
> CM_KEY_VALUE_SMALL
)
221 /* Build a data cell for it */
222 Status
= CmpSetValueDataNew(Hive
,
227 &CellData
->u
.KeyValue
.Data
);
228 if (!NT_SUCCESS(Status
))
230 /* We failed, free the cell */
231 HvFreeCell(Hive
, ValueCell
);
235 /* Otherwise, set the data length, and make sure the data is dirty */
236 CellData
->u
.KeyValue
.DataLength
= DataSize
;
237 ASSERT(HvIsCellDirty(Hive
, CellData
->u
.KeyValue
.Data
));
241 /* This is a small key, set the data directly inside */
242 CellData
->u
.KeyValue
.DataLength
= DataSize
+ CM_KEY_VALUE_SPECIAL_SIZE
;
243 CellData
->u
.KeyValue
.Data
= SmallData
;
246 /* Set the type now */
247 CellData
->u
.KeyValue
.Type
= Type
;
249 /* Add this value cell to the child list */
250 Status
= CmpAddValueToList(Hive
,
256 /* If we failed, free the entire cell, including the data */
257 if (!NT_SUCCESS(Status
))
259 /* Overwrite the status with a known one */
260 CmpFreeValue(Hive
, ValueCell
);
261 Status
= STATUS_INSUFFICIENT_RESOURCES
;
270 CmpSetValueKeyExisting(IN PHHIVE Hive
,
271 IN HCELL_INDEX OldChild
,
272 IN PCM_KEY_VALUE Value
,
276 IN ULONG StorageType
,
279 HCELL_INDEX DataCell
, NewCell
;
282 BOOLEAN WasSmall
, IsSmall
;
284 /* Registry writes must be blocked */
285 CMP_ASSERT_FLUSH_LOCK(Hive
);
287 /* Mark the old child cell dirty */
288 if (!HvMarkCellDirty(Hive
, OldChild
, FALSE
)) return STATUS_NO_LOG_SPACE
;
290 /* See if this is a small or normal key */
291 WasSmall
= CmpIsKeyValueSmall(&Length
, Value
->DataLength
);
293 /* See if our new data can fit in a small key */
294 IsSmall
= (DataSize
<= CM_KEY_VALUE_SMALL
) ? TRUE
: FALSE
;
296 /* Big keys are unsupported */
297 ASSERT_VALUE_BIG(Hive
, Length
);
298 ASSERT_VALUE_BIG(Hive
, DataSize
);
300 /* Mark the old value dirty */
301 if (!CmpMarkValueDataDirty(Hive
, Value
)) return STATUS_NO_LOG_SPACE
;
303 /* Check if we have a small key */
306 /* Check if we had a normal key with some data in it */
307 if (!(WasSmall
) && (Length
> 0))
309 /* Free the previous data */
310 CmpFreeValueData(Hive
, Value
->Data
, Length
);
313 /* Write our data directly */
314 Value
->DataLength
= DataSize
+ CM_KEY_VALUE_SPECIAL_SIZE
;
315 Value
->Data
= TempData
;
317 return STATUS_SUCCESS
;
320 /* We have a normal key. Was the old cell also normal and had data? */
321 if (!(WasSmall
) && (Length
> 0))
323 /* Get the current data cell and actual data inside it */
324 DataCell
= Value
->Data
;
325 ASSERT(DataCell
!= HCELL_NIL
);
326 CellData
= HvGetCell(Hive
, DataCell
);
327 if (!CellData
) return STATUS_INSUFFICIENT_RESOURCES
;
329 /* Immediately release the cell */
330 HvReleaseCell(Hive
, DataCell
);
332 /* Make sure that the data cell actually has a size */
333 ASSERT(HvGetCellSize(Hive
, CellData
) > 0);
335 /* Check if the previous data cell could fit our new data */
336 if (DataSize
<= (ULONG
)(HvGetCellSize(Hive
, CellData
)))
343 /* Otherwise, re-allocate the current data cell */
344 NewCell
= HvReallocateCell(Hive
, DataCell
, DataSize
);
345 if (NewCell
== HCELL_NIL
) return STATUS_INSUFFICIENT_RESOURCES
;
350 /* This was a small key, or a key with no data, allocate a cell */
351 NewCell
= HvAllocateCell(Hive
, DataSize
, StorageType
, HCELL_NIL
);
352 if (NewCell
== HCELL_NIL
) return STATUS_INSUFFICIENT_RESOURCES
;
355 /* Now get the actual data for our data cell */
356 CellData
= HvGetCell(Hive
, NewCell
);
357 if (!CellData
) ASSERT(FALSE
);
359 /* Release it immediately */
360 HvReleaseCell(Hive
, NewCell
);
362 /* Copy our data into the data cell's buffer, and set up the value */
363 RtlCopyMemory(CellData
, Data
, DataSize
);
364 Value
->Data
= NewCell
;
365 Value
->DataLength
= DataSize
;
369 ASSERT(HvIsCellDirty(Hive
, NewCell
));
370 return STATUS_SUCCESS
;
375 CmpQueryKeyData(IN PHHIVE Hive
,
376 IN PCM_KEY_NODE Node
,
377 IN KEY_INFORMATION_CLASS KeyInformationClass
,
378 IN OUT PVOID KeyInformation
,
380 IN OUT PULONG ResultLength
)
383 ULONG Size
, SizeLeft
, MinimumSize
;
384 PKEY_INFORMATION Info
= (PKEY_INFORMATION
)KeyInformation
;
387 /* Check if the value is compressed */
388 if (Node
->Flags
& KEY_COMP_NAME
)
390 /* Get the compressed name size */
391 NameLength
= CmpCompressedNameSize(Node
->Name
, Node
->NameLength
);
395 /* Get the real size */
396 NameLength
= Node
->NameLength
;
399 /* Check what kind of information is being requested */
400 switch (KeyInformationClass
)
402 /* Basic information */
403 case KeyBasicInformation
:
405 /* This is the size we need */
406 Size
= FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
) + NameLength
;
408 /* And this is the minimum we can work with */
409 MinimumSize
= FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
);
411 /* Let the caller know and assume success */
412 *ResultLength
= Size
;
413 Status
= STATUS_SUCCESS
;
415 /* Check if the bufer we got is too small */
416 if (Length
< MinimumSize
)
418 /* Let the caller know and fail */
419 Status
= STATUS_BUFFER_TOO_SMALL
;
423 /* Copy the basic information */
424 Info
->KeyBasicInformation
.LastWriteTime
= Node
->LastWriteTime
;
425 Info
->KeyBasicInformation
.TitleIndex
= 0;
426 Info
->KeyBasicInformation
.NameLength
= NameLength
;
428 /* Only the name is left */
429 SizeLeft
= Length
- MinimumSize
;
432 /* Check if we don't have enough space for the name */
435 /* Truncate the name we'll return, and tell the caller */
437 Status
= STATUS_BUFFER_OVERFLOW
;
440 /* Check if this is a compressed key */
441 if (Node
->Flags
& KEY_COMP_NAME
)
443 /* Copy the compressed name */
444 CmpCopyCompressedName(Info
->KeyBasicInformation
.Name
,
451 /* Otherwise, copy the raw name */
452 RtlCopyMemory(Info
->KeyBasicInformation
.Name
,
458 /* Node information */
459 case KeyNodeInformation
:
461 /* Calculate the size we need */
462 Size
= FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
) +
466 /* And the minimum size we can support */
467 MinimumSize
= FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
);
469 /* Return the size to the caller and assume succes */
470 *ResultLength
= Size
;
471 Status
= STATUS_SUCCESS
;
473 /* Check if the caller's buffer is too small */
474 if (Length
< MinimumSize
)
476 /* Let them know, and fail */
477 Status
= STATUS_BUFFER_TOO_SMALL
;
481 /* Copy the basic information */
482 Info
->KeyNodeInformation
.LastWriteTime
= Node
->LastWriteTime
;
483 Info
->KeyNodeInformation
.TitleIndex
= 0;
484 Info
->KeyNodeInformation
.ClassLength
= Node
->ClassLength
;
485 Info
->KeyNodeInformation
.NameLength
= NameLength
;
487 /* Now the name is left */
488 SizeLeft
= Length
- MinimumSize
;
491 /* Check if the name can fit entirely */
494 /* It can't, we'll have to truncate. Tell the caller */
496 Status
= STATUS_BUFFER_OVERFLOW
;
499 /* Check if the key node name is compressed */
500 if (Node
->Flags
& KEY_COMP_NAME
)
502 /* Copy the compressed name */
503 CmpCopyCompressedName(Info
->KeyNodeInformation
.Name
,
510 /* It isn't, so copy the raw name */
511 RtlCopyMemory(Info
->KeyNodeInformation
.Name
,
516 /* Check if the node has a class */
517 if (Node
->ClassLength
> 0)
519 /* It does. We don't support these yet */
520 ASSERTMSG("Classes not supported\n", FALSE
);
524 /* It doesn't, so set offset to -1, not 0! */
525 Info
->KeyNodeInformation
.ClassOffset
= 0xFFFFFFFF;
529 /* Full information requsted */
530 case KeyFullInformation
:
532 /* This is the size we need */
533 Size
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
) +
536 /* This is what we can work with */
537 MinimumSize
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
);
539 /* Return it to caller and assume success */
540 *ResultLength
= Size
;
541 Status
= STATUS_SUCCESS
;
543 /* Check if the caller's buffer is to small */
544 if (Length
< MinimumSize
)
546 /* Let them know and fail */
547 Status
= STATUS_BUFFER_TOO_SMALL
;
551 /* Now copy all the basic information */
552 Info
->KeyFullInformation
.LastWriteTime
= Node
->LastWriteTime
;
553 Info
->KeyFullInformation
.TitleIndex
= 0;
554 Info
->KeyFullInformation
.ClassLength
= Node
->ClassLength
;
555 Info
->KeyFullInformation
.SubKeys
= Node
->SubKeyCounts
[Stable
] +
556 Node
->SubKeyCounts
[Volatile
];
557 Info
->KeyFullInformation
.Values
= Node
->ValueList
.Count
;
558 Info
->KeyFullInformation
.MaxNameLen
= Node
->MaxNameLen
;
559 Info
->KeyFullInformation
.MaxClassLen
= Node
->MaxClassLen
;
560 Info
->KeyFullInformation
.MaxValueNameLen
= Node
->MaxValueNameLen
;
561 Info
->KeyFullInformation
.MaxValueDataLen
= Node
->MaxValueDataLen
;
563 /* Check if we have a class */
564 if (Node
->ClassLength
> 0)
566 /* We do, but we currently don't support this */
567 ASSERTMSG("Classes not supported\n", FALSE
);
571 /* We don't have a class, so set offset to -1, not 0! */
572 Info
->KeyNodeInformation
.ClassOffset
= 0xFFFFFFFF;
576 /* Any other class that got sent here is invalid! */
579 /* Set failure code */
580 Status
= STATUS_INVALID_PARAMETER
;
590 CmSetValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
591 IN PUNICODE_STRING ValueName
,
598 PCM_KEY_VALUE Value
= NULL
;
599 HCELL_INDEX CurrentChild
, Cell
;
601 BOOLEAN Found
, Result
;
602 ULONG Count
, ChildIndex
, SmallData
, Storage
;
603 VALUE_SEARCH_RETURN_TYPE SearchResult
;
604 BOOLEAN FirstTry
= TRUE
, FlusherLocked
= FALSE
;
605 HCELL_INDEX ParentCell
= HCELL_NIL
, ChildCell
= HCELL_NIL
;
607 /* Acquire hive and KCB lock */
609 CmpAcquireKcbLockShared(Kcb
);
612 ASSERT(sizeof(ULONG
) == CM_KEY_VALUE_SMALL
);
614 /* Don't touch deleted KCBs */
619 Status
= STATUS_KEY_DELETED
;
623 /* Don't let anyone mess with symlinks */
624 if ((Kcb
->Flags
& KEY_SYM_LINK
) &&
625 ((Type
!= REG_LINK
) ||
627 !(RtlEqualUnicodeString(&CmSymbolicLinkValueName
, ValueName
, TRUE
))))
629 /* Invalid modification of a symlink key */
630 Status
= STATUS_ACCESS_DENIED
;
634 /* Check if this is the first attempt */
637 /* Search for the value in the cache */
638 SearchResult
= CmpCompareNewValueDataAgainstKCBCache(Kcb
,
643 if (SearchResult
== SearchNeedExclusiveLock
)
645 /* Try again with the exclusive lock */
646 CmpConvertKcbSharedToExclusive(Kcb
);
649 else if (SearchResult
== SearchSuccess
)
651 /* We don't actually need to do anything! */
652 Status
= STATUS_SUCCESS
;
656 /* We need the exclusive KCB lock now */
657 if (!(CmpIsKcbLockedExclusive(Kcb
)) &&
658 !(CmpTryToConvertKcbSharedToExclusive(Kcb
)))
660 /* Acquire exclusive lock */
661 CmpConvertKcbSharedToExclusive(Kcb
);
664 /* Cache lookup failed, so don't try it next time */
667 /* Now grab the flush lock since the key will be modified */
668 ASSERT(FlusherLocked
== FALSE
);
669 CmpLockHiveFlusherShared((PCMHIVE
)Kcb
->KeyHive
);
670 FlusherLocked
= TRUE
;
675 /* Get pointer to key cell */
680 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
684 /* Prepare to scan the key node */
685 Count
= Parent
->ValueList
.Count
;
689 /* Try to find the existing name */
690 Result
= CmpFindNameInList(Hive
,
698 Status
= STATUS_INSUFFICIENT_RESOURCES
;
702 /* Check if we found something */
703 if (CurrentChild
!= HCELL_NIL
)
705 /* Release existing child */
706 if (ChildCell
!= HCELL_NIL
)
708 HvReleaseCell(Hive
, ChildCell
);
709 ChildCell
= HCELL_NIL
;
713 Value
= (PCM_KEY_VALUE
)HvGetCell(Hive
, CurrentChild
);
717 Status
= STATUS_INSUFFICIENT_RESOURCES
;
721 /* Remember that we found it */
722 ChildCell
= CurrentChild
;
728 /* No child list, we'll need to add it */
733 /* Should only get here on the second pass */
734 ASSERT(FirstTry
== FALSE
);
736 /* The KCB must be locked exclusive at this point */
737 CMP_ASSERT_KCB_LOCK(Kcb
);
739 /* Mark the cell dirty */
740 if (!HvMarkCellDirty(Hive
, Cell
, FALSE
))
742 /* Not enough log space, fail */
743 Status
= STATUS_NO_LOG_SPACE
;
747 /* Get the storage type */
748 Storage
= HvGetCellType(Cell
);
750 /* Check if this is small data */
752 if ((DataLength
<= CM_KEY_VALUE_SMALL
) && (DataLength
> 0))
754 /* Need SEH because user data may be invalid */
758 RtlCopyMemory(&SmallData
, Data
, DataLength
);
760 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
762 /* Return failure code */
763 Status
= _SEH2_GetExceptionCode();
764 _SEH2_YIELD(goto Quickie
);
769 /* Check if we didn't find a matching key */
772 /* Call the internal routine */
773 Status
= CmpSetValueKeyNew(Hive
,
785 /* Call the internal routine */
786 Status
= CmpSetValueKeyExisting(Hive
,
796 /* Check for success */
797 if (NT_SUCCESS(Status
))
799 /* Check if the maximum value name length changed */
800 ASSERT(Parent
->MaxValueNameLen
== Kcb
->KcbMaxValueNameLen
);
801 if (Parent
->MaxValueNameLen
< ValueName
->Length
)
803 /* Set the new values */
804 Parent
->MaxValueNameLen
= ValueName
->Length
;
805 Kcb
->KcbMaxValueNameLen
= ValueName
->Length
;
808 /* Check if the maximum data length changed */
809 ASSERT(Parent
->MaxValueDataLen
== Kcb
->KcbMaxValueDataLen
);
810 if (Parent
->MaxValueDataLen
< DataLength
)
813 Parent
->MaxValueDataLen
= DataLength
;
814 Kcb
->KcbMaxValueDataLen
= Parent
->MaxValueDataLen
;
817 /* Save the write time */
818 KeQuerySystemTime(&Parent
->LastWriteTime
);
819 Kcb
->KcbLastWriteTime
= Parent
->LastWriteTime
;
821 /* Check if the cell is cached */
822 if ((Found
) && (CMP_IS_CELL_CACHED(Kcb
->ValueCache
.ValueList
)))
824 /* Shouldn't happen */
829 /* Cleanup the value cache */
830 CmpCleanUpKcbValueCache(Kcb
);
833 ASSERT(!(CMP_IS_CELL_CACHED(Kcb
->ValueCache
.ValueList
)));
834 ASSERT(!(Kcb
->ExtFlags
& CM_KCB_SYM_LINK_FOUND
));
836 /* Set the value cache */
837 Kcb
->ValueCache
.Count
= Parent
->ValueList
.Count
;
838 Kcb
->ValueCache
.ValueList
= Parent
->ValueList
.List
;
841 /* Notify registered callbacks */
845 REG_NOTIFY_CHANGE_LAST_SET
);
848 /* Release the cells */
850 if ((ParentCell
!= HCELL_NIL
) && (Hive
)) HvReleaseCell(Hive
, ParentCell
);
851 if ((ChildCell
!= HCELL_NIL
) && (Hive
)) HvReleaseCell(Hive
, ChildCell
);
853 /* Release the locks */
854 if (FlusherLocked
) CmpUnlockHiveFlusher((PCMHIVE
)Hive
);
855 CmpReleaseKcbLock(Kcb
);
862 CmDeleteValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
863 IN UNICODE_STRING ValueName
)
865 NTSTATUS Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
868 HCELL_INDEX ChildCell
, Cell
;
869 PCHILD_LIST ChildList
;
870 PCM_KEY_VALUE Value
= NULL
;
874 /* Acquire hive lock */
877 /* Lock KCB exclusively */
878 CmpAcquireKcbLockExclusive(Kcb
);
880 /* Don't touch deleted keys */
883 /* Undo everything */
884 CmpReleaseKcbLock(Kcb
);
886 return STATUS_KEY_DELETED
;
889 /* Get the hive and the cell index */
894 CmpLockHiveFlusherShared((PCMHIVE
)Hive
);
896 /* Get the parent key node */
897 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
900 /* Get the value list and check if it has any entries */
901 ChildList
= &Parent
->ValueList
;
902 if (ChildList
->Count
)
904 /* Try to find this value */
905 Result
= CmpFindNameInList(Hive
,
913 Status
= STATUS_INSUFFICIENT_RESOURCES
;
917 /* Value not found, return error */
918 if (ChildCell
== HCELL_NIL
) goto Quickie
;
920 /* We found the value, mark all relevant cells dirty */
921 if (!((HvMarkCellDirty(Hive
, Cell
, FALSE
)) &&
922 (HvMarkCellDirty(Hive
, Parent
->ValueList
.List
, FALSE
)) &&
923 (HvMarkCellDirty(Hive
, ChildCell
, FALSE
))))
925 /* Not enough log space, fail */
926 Status
= STATUS_NO_LOG_SPACE
;
930 /* Get the key value */
931 Value
= (PCM_KEY_VALUE
)HvGetCell(Hive
,ChildCell
);
934 /* Mark it and all related data as dirty */
935 if (!CmpMarkValueDataDirty(Hive
, Value
))
937 /* Not enough log space, fail */
938 Status
= STATUS_NO_LOG_SPACE
;
943 ASSERT(HvIsCellDirty(Hive
, Parent
->ValueList
.List
));
944 ASSERT(HvIsCellDirty(Hive
, ChildCell
));
946 /* Remove the value from the child list */
947 Status
= CmpRemoveValueFromList(Hive
, ChildIndex
, ChildList
);
948 if (!NT_SUCCESS(Status
))
950 /* Set known error */
951 Status
= STATUS_INSUFFICIENT_RESOURCES
;
955 /* Remove the value and its data itself */
956 if (!CmpFreeValue(Hive
, ChildCell
))
958 /* Failed to free the value, fail */
959 Status
= STATUS_INSUFFICIENT_RESOURCES
;
963 /* Set the last write time */
964 KeQuerySystemTime(&Parent
->LastWriteTime
);
965 Kcb
->KcbLastWriteTime
= Parent
->LastWriteTime
;
968 ASSERT(Parent
->MaxValueNameLen
== Kcb
->KcbMaxValueNameLen
);
969 ASSERT(Parent
->MaxValueDataLen
== Kcb
->KcbMaxValueDataLen
);
970 ASSERT(HvIsCellDirty(Hive
, Cell
));
972 /* Check if the value list is empty now */
973 if (!Parent
->ValueList
.Count
)
975 /* Then clear key node data */
976 Parent
->MaxValueNameLen
= 0;
977 Parent
->MaxValueDataLen
= 0;
978 Kcb
->KcbMaxValueNameLen
= 0;
979 Kcb
->KcbMaxValueDataLen
= 0;
982 /* Cleanup the value cache */
983 CmpCleanUpKcbValueCache(Kcb
);
986 ASSERT(!(CMP_IS_CELL_CACHED(Kcb
->ValueCache
.ValueList
)));
987 ASSERT(!(Kcb
->ExtFlags
& CM_KCB_SYM_LINK_FOUND
));
989 /* Set the value cache */
990 Kcb
->ValueCache
.Count
= ChildList
->Count
;
991 Kcb
->ValueCache
.ValueList
= ChildList
->List
;
993 /* Notify registered callbacks */
994 CmpReportNotify(Kcb
, Hive
, Cell
, REG_NOTIFY_CHANGE_LAST_SET
);
996 /* Change default Status to success */
997 Status
= STATUS_SUCCESS
;
1001 /* Release the parent cell, if any */
1002 if (Parent
) HvReleaseCell(Hive
, Cell
);
1004 /* Check if we had a value */
1007 /* Release the child cell */
1008 ASSERT(ChildCell
!= HCELL_NIL
);
1009 HvReleaseCell(Hive
, ChildCell
);
1013 CmpUnlockHiveFlusher((PCMHIVE
)Hive
);
1014 CmpReleaseKcbLock(Kcb
);
1015 CmpUnlockRegistry();
1021 CmQueryValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
1022 IN UNICODE_STRING ValueName
,
1023 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
1024 IN PVOID KeyValueInformation
,
1026 IN PULONG ResultLength
)
1029 PCM_KEY_VALUE ValueData
;
1031 BOOLEAN ValueCached
= FALSE
;
1032 PCM_CACHED_VALUE
*CachedValue
;
1033 HCELL_INDEX CellToRelease
;
1034 VALUE_SEARCH_RETURN_TYPE Result
;
1038 /* Acquire hive lock */
1041 /* Lock the KCB shared */
1042 CmpAcquireKcbLockShared(Kcb
);
1044 /* Don't touch deleted keys */
1048 /* Undo everything */
1049 CmpReleaseKcbLock(Kcb
);
1050 CmpUnlockRegistry();
1051 return STATUS_KEY_DELETED
;
1054 /* We don't deal with this yet */
1055 if (Kcb
->ExtFlags
& CM_KCB_SYM_LINK_FOUND
)
1057 /* Shouldn't happen */
1062 Hive
= Kcb
->KeyHive
;
1064 /* Find the key value */
1065 Result
= CmpFindValueByNameFromCache(Kcb
,
1072 if (Result
== SearchNeedExclusiveLock
)
1074 /* Check if we need an exclusive lock */
1075 ASSERT(CellToRelease
== HCELL_NIL
);
1076 ASSERT(ValueData
== NULL
);
1078 /* Try with exclusive KCB lock */
1079 CmpConvertKcbSharedToExclusive(Kcb
);
1083 if (Result
== SearchSuccess
)
1086 ASSERT(ValueData
!= NULL
);
1088 /* User data, protect against exceptions */
1091 /* Query the information requested */
1092 Result
= CmpQueryKeyValueData(Kcb
,
1096 KeyValueInformationClass
,
1097 KeyValueInformation
,
1101 if (Result
== SearchNeedExclusiveLock
)
1103 /* Release the value cell */
1104 if (CellToRelease
!= HCELL_NIL
)
1106 HvReleaseCell(Hive
, CellToRelease
);
1107 CellToRelease
= HCELL_NIL
;
1110 /* Try with exclusive KCB lock */
1111 CmpConvertKcbSharedToExclusive(Kcb
);
1115 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1117 Status
= _SEH2_GetExceptionCode();
1123 /* Failed to find the value */
1124 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1127 /* If we have a cell to release, do so */
1128 if (CellToRelease
!= HCELL_NIL
) HvReleaseCell(Hive
, CellToRelease
);
1131 CmpReleaseKcbLock(Kcb
);
1132 CmpUnlockRegistry();
1138 CmEnumerateValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
1140 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
1141 IN PVOID KeyValueInformation
,
1143 IN PULONG ResultLength
)
1147 PCM_KEY_NODE Parent
;
1148 HCELL_INDEX CellToRelease
= HCELL_NIL
, CellToRelease2
= HCELL_NIL
;
1149 VALUE_SEARCH_RETURN_TYPE Result
;
1150 BOOLEAN IndexIsCached
, ValueIsCached
= FALSE
;
1151 PCELL_DATA CellData
;
1152 PCM_CACHED_VALUE
*CachedValue
;
1153 PCM_KEY_VALUE ValueData
= NULL
;
1156 /* Acquire hive lock */
1159 /* Lock the KCB shared */
1160 CmpAcquireKcbLockShared(Kcb
);
1162 /* Don't touch deleted keys */
1166 /* Undo everything */
1167 CmpReleaseKcbLock(Kcb
);
1168 CmpUnlockRegistry();
1169 return STATUS_KEY_DELETED
;
1172 /* Get the hive and parent */
1173 Hive
= Kcb
->KeyHive
;
1174 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, Kcb
->KeyCell
);
1177 /* FIXME: Lack of cache? */
1178 if (Kcb
->ValueCache
.Count
!= Parent
->ValueList
.Count
)
1180 DPRINT1("HACK: Overriding value cache count\n");
1181 Kcb
->ValueCache
.Count
= Parent
->ValueList
.Count
;
1184 /* Make sure the index is valid */
1185 if (Index
>= Kcb
->ValueCache
.Count
)
1187 /* Release the cell and fail */
1188 HvReleaseCell(Hive
, Kcb
->KeyCell
);
1189 Status
= STATUS_NO_MORE_ENTRIES
;
1193 /* We don't deal with this yet */
1194 if (Kcb
->ExtFlags
& CM_KCB_SYM_LINK_FOUND
)
1196 /* Shouldn't happen */
1200 /* Find the value list */
1201 Result
= CmpGetValueListFromCache(Kcb
,
1205 if (Result
== SearchNeedExclusiveLock
)
1207 /* Check if we need an exclusive lock */
1208 ASSERT(CellToRelease
== HCELL_NIL
);
1209 HvReleaseCell(Hive
, Kcb
->KeyCell
);
1211 /* Try with exclusive KCB lock */
1212 CmpConvertKcbSharedToExclusive(Kcb
);
1215 else if (Result
!= SearchSuccess
)
1218 ASSERT(CellData
== NULL
);
1220 /* Release the cell and fail */
1221 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1225 /* Now get the key value */
1226 Result
= CmpGetValueKeyFromCache(Kcb
,
1234 if (Result
== SearchNeedExclusiveLock
)
1237 ASSERT(CellToRelease2
== HCELL_NIL
);
1240 HvReleaseCell(Hive
, CellToRelease
);
1241 CellToRelease
= HCELL_NIL
;
1243 HvReleaseCell(Hive
, Kcb
->KeyCell
);
1245 /* Try with exclusive KCB lock */
1246 CmpConvertKcbSharedToExclusive(Kcb
);
1249 else if (Result
!= SearchSuccess
)
1252 ASSERT(ValueData
== NULL
);
1254 /* Release the cells and fail */
1255 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1259 /* User data, need SEH */
1262 /* Query the information requested */
1263 Result
= CmpQueryKeyValueData(Kcb
,
1267 KeyValueInformationClass
,
1268 KeyValueInformation
,
1272 if (Result
== SearchNeedExclusiveLock
)
1275 if (CellToRelease2
) HvReleaseCell(Hive
, CellToRelease2
);
1276 HvReleaseCell(Hive
, Kcb
->KeyCell
);
1277 if (CellToRelease
) HvReleaseCell(Hive
, CellToRelease
);
1279 /* Try with exclusive KCB lock */
1280 CmpConvertKcbSharedToExclusive(Kcb
);
1284 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1286 /* Get exception code */
1287 Status
= _SEH2_GetExceptionCode();
1292 /* If we have a cell to release, do so */
1293 if (CellToRelease
!= HCELL_NIL
) HvReleaseCell(Hive
, CellToRelease
);
1295 /* Release the parent cell */
1296 HvReleaseCell(Hive
, Kcb
->KeyCell
);
1298 /* If we have a cell to release, do so */
1299 if (CellToRelease2
!= HCELL_NIL
) HvReleaseCell(Hive
, CellToRelease2
);
1302 CmpReleaseKcbLock(Kcb
);
1303 CmpUnlockRegistry();
1309 CmQueryKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
1310 IN KEY_INFORMATION_CLASS KeyInformationClass
,
1311 IN PVOID KeyInformation
,
1313 IN PULONG ResultLength
)
1317 PCM_KEY_NODE Parent
;
1318 HV_TRACK_CELL_REF CellReferences
= {0};
1320 /* Acquire hive lock */
1323 /* Lock KCB shared */
1324 CmpAcquireKcbLockShared(Kcb
);
1326 /* Don't touch deleted keys */
1330 Status
= STATUS_KEY_DELETED
;
1334 /* Check what class we got */
1335 switch (KeyInformationClass
)
1337 /* Typical information */
1338 case KeyFullInformation
:
1339 case KeyBasicInformation
:
1340 case KeyNodeInformation
:
1342 /* Get the hive and parent */
1343 Hive
= Kcb
->KeyHive
;
1344 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, Kcb
->KeyCell
);
1347 /* Track cell references */
1348 if (!HvTrackCellRef(&CellReferences
, Hive
, Kcb
->KeyCell
))
1350 /* Not enough memory to track references */
1351 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1355 /* Call the internal API */
1356 Status
= CmpQueryKeyData(Hive
,
1358 KeyInformationClass
,
1365 /* Unsupported classes for now */
1366 case KeyNameInformation
:
1367 case KeyCachedInformation
:
1368 case KeyFlagsInformation
:
1370 /* Print message and fail */
1371 DPRINT1("Unsupported class: %d!\n", KeyInformationClass
);
1372 Status
= STATUS_NOT_IMPLEMENTED
;
1375 /* Illegal classes */
1378 /* Print message and fail */
1379 DPRINT1("Unsupported class: %d!\n", KeyInformationClass
);
1380 Status
= STATUS_INVALID_INFO_CLASS
;
1385 /* Release references */
1386 HvReleaseFreeCellRefArray(&CellReferences
);
1389 CmpReleaseKcbLock(Kcb
);
1390 CmpUnlockRegistry();
1396 CmEnumerateKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
1398 IN KEY_INFORMATION_CLASS KeyInformationClass
,
1399 IN PVOID KeyInformation
,
1401 IN PULONG ResultLength
)
1405 PCM_KEY_NODE Parent
, Child
;
1406 HCELL_INDEX ChildCell
;
1407 HV_TRACK_CELL_REF CellReferences
= {0};
1409 /* Acquire hive lock */
1412 /* Lock the KCB shared */
1413 CmpAcquireKcbLockShared(Kcb
);
1415 /* Don't touch deleted keys */
1418 /* Undo everything */
1419 Status
= STATUS_KEY_DELETED
;
1423 /* Get the hive and parent */
1424 Hive
= Kcb
->KeyHive
;
1425 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, Kcb
->KeyCell
);
1428 /* Get the child cell */
1429 ChildCell
= CmpFindSubKeyByNumber(Hive
, Parent
, Index
);
1431 /* Release the parent cell */
1432 HvReleaseCell(Hive
, Kcb
->KeyCell
);
1434 /* Check if we found the child */
1435 if (ChildCell
== HCELL_NIL
)
1437 /* We didn't, fail */
1438 Status
= STATUS_NO_MORE_ENTRIES
;
1442 /* Now get the actual child node */
1443 Child
= (PCM_KEY_NODE
)HvGetCell(Hive
, ChildCell
);
1446 /* Track references */
1447 if (!HvTrackCellRef(&CellReferences
, Hive
, ChildCell
))
1449 /* Can't allocate memory for tracking */
1450 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1454 /* Data can be user-mode, use SEH */
1457 /* Query the data requested */
1458 Status
= CmpQueryKeyData(Hive
,
1460 KeyInformationClass
,
1465 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1467 /* Fail with exception code */
1468 Status
= _SEH2_GetExceptionCode();
1469 _SEH2_YIELD(goto Quickie
);
1474 /* Release references */
1475 HvReleaseFreeCellRefArray(&CellReferences
);
1478 CmpReleaseKcbLock(Kcb
);
1479 CmpUnlockRegistry();
1485 CmDeleteKey(IN PCM_KEY_BODY KeyBody
)
1489 PCM_KEY_NODE Node
, Parent
;
1490 HCELL_INDEX Cell
, ParentCell
;
1491 PCM_KEY_CONTROL_BLOCK Kcb
;
1493 /* Acquire hive lock */
1497 Kcb
= KeyBody
->KeyControlBlock
;
1499 /* Don't allow deleting the root */
1500 if (!Kcb
->ParentKcb
)
1503 CmpUnlockRegistry();
1504 return STATUS_CANNOT_DELETE
;
1507 /* Lock parent and child */
1508 CmpAcquireTwoKcbLocksExclusiveByKey(Kcb
->ConvKey
, Kcb
->ParentKcb
->ConvKey
);
1510 /* Check if we're already being deleted */
1513 /* Don't do it twice */
1514 Status
= STATUS_SUCCESS
;
1518 /* Get the hive and node */
1519 Hive
= Kcb
->KeyHive
;
1520 Cell
= Kcb
->KeyCell
;
1523 CmpLockHiveFlusherShared((PCMHIVE
)Hive
);
1525 /* Get the key node */
1526 Node
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
1530 ASSERT(Node
->Flags
== Kcb
->Flags
);
1532 /* Check if we don't have any children */
1533 if (!(Node
->SubKeyCounts
[Stable
] + Node
->SubKeyCounts
[Volatile
]) &&
1534 !(Node
->Flags
& KEY_NO_DELETE
))
1536 /* Send notification to registered callbacks */
1537 CmpReportNotify(Kcb
, Hive
, Cell
, REG_NOTIFY_CHANGE_NAME
);
1539 /* Get the parent and free the cell */
1540 ParentCell
= Node
->Parent
;
1541 Status
= CmpFreeKeyByCell(Hive
, Cell
, TRUE
);
1542 if (NT_SUCCESS(Status
))
1544 /* Flush any notifications */
1545 CmpFlushNotifiesOnKeyBodyList(Kcb
, FALSE
);
1547 /* Clean up information we have on the subkey */
1548 CmpCleanUpSubKeyInfo(Kcb
->ParentKcb
);
1550 /* Get the parent node */
1551 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, ParentCell
);
1554 /* Update the maximum name length */
1555 Kcb
->ParentKcb
->KcbMaxNameLen
= Parent
->MaxNameLen
;
1557 /* Make sure we're dirty */
1558 ASSERT(HvIsCellDirty(Hive
, ParentCell
));
1560 /* Update the write time */
1561 KeQuerySystemTime(&Parent
->LastWriteTime
);
1562 Kcb
->ParentKcb
->KcbLastWriteTime
= Parent
->LastWriteTime
;
1564 /* Release the cell */
1565 HvReleaseCell(Hive
, ParentCell
);
1568 /* Set the KCB in delete mode and remove it */
1570 CmpRemoveKeyControlBlock(Kcb
);
1572 /* Clear the cell */
1573 Kcb
->KeyCell
= HCELL_NIL
;
1579 Status
= STATUS_CANNOT_DELETE
;
1582 /* Release the cell */
1583 HvReleaseCell(Hive
, Cell
);
1585 /* Release flush lock */
1586 CmpUnlockHiveFlusher((PCMHIVE
)Hive
);
1588 /* Release the KCB locks */
1590 CmpReleaseTwoKcbLockByKey(Kcb
->ConvKey
, Kcb
->ParentKcb
->ConvKey
);
1592 /* Release hive lock */
1593 CmpUnlockRegistry();
1599 CmFlushKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
1600 IN BOOLEAN ExclusiveLock
)
1603 NTSTATUS Status
= STATUS_SUCCESS
;
1606 /* Ignore flushes until we're ready */
1607 if (CmpNoWrite
) return STATUS_SUCCESS
;
1610 Hive
= Kcb
->KeyHive
;
1611 CmHive
= (PCMHIVE
)Hive
;
1613 /* Check if this is the master hive */
1614 if (CmHive
== CmiVolatileHive
)
1616 /* Flush all the hives instead */
1617 CmpDoFlushAll(FALSE
);
1621 /* Don't touch the hive */
1622 CmpLockHiveFlusherExclusive(CmHive
);
1623 ASSERT(CmHive
->ViewLock
);
1624 KeAcquireGuardedMutex(CmHive
->ViewLock
);
1625 CmHive
->ViewLockOwner
= KeGetCurrentThread();
1627 /* Will the hive shrink? */
1628 if (HvHiveWillShrink(Hive
))
1630 /* I don't believe the current Hv does shrinking */
1635 /* Now we can release views */
1636 ASSERT(CmHive
->ViewLock
);
1637 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK_OR_LOADING(CmHive
);
1638 ASSERT(KeGetCurrentThread() == CmHive
->ViewLockOwner
);
1639 KeReleaseGuardedMutex(CmHive
->ViewLock
);
1642 /* Flush only this hive */
1643 if (!HvSyncHive(Hive
))
1646 Status
= STATUS_REGISTRY_IO_FAILED
;
1649 /* Release the flush lock */
1650 CmpUnlockHiveFlusher((PCMHIVE
)Hive
);
1653 /* Return the status */
1659 CmLoadKey(IN POBJECT_ATTRIBUTES TargetKey
,
1660 IN POBJECT_ATTRIBUTES SourceFile
,
1662 IN PCM_KEY_BODY KeyBody
)
1664 SECURITY_QUALITY_OF_SERVICE ServiceQos
;
1665 SECURITY_CLIENT_CONTEXT ClientSecurityContext
;
1667 BOOLEAN Allocate
= TRUE
;
1668 PCMHIVE CmHive
, LoadedHive
;
1670 CM_PARSE_CONTEXT ParseContext
;
1672 /* Check if we have a trust key */
1676 DPRINT1("Trusted classes not yet supported\n");
1677 return STATUS_NOT_IMPLEMENTED
;
1680 /* Build a service QoS for a security context */
1681 ServiceQos
.Length
= sizeof(SECURITY_QUALITY_OF_SERVICE
);
1682 ServiceQos
.ImpersonationLevel
= SecurityImpersonation
;
1683 ServiceQos
.ContextTrackingMode
= SECURITY_DYNAMIC_TRACKING
;
1684 ServiceQos
.EffectiveOnly
= TRUE
;
1685 Status
= SeCreateClientSecurity(PsGetCurrentThread(),
1688 &ClientSecurityContext
);
1689 if (!NT_SUCCESS(Status
))
1692 DPRINT1("Security context failed\n");
1696 /* Open the target key */
1698 Status
= ZwOpenKey(&KeyHandle
, KEY_READ
, TargetKey
);
1700 RtlZeroMemory(&ParseContext
, sizeof(ParseContext
));
1701 ParseContext
.CreateOperation
= FALSE
;
1702 Status
= ObOpenObjectByName(TargetKey
,
1710 if (!NT_SUCCESS(Status
)) KeyHandle
= NULL
;
1713 Status
= CmpCmdHiveOpen(SourceFile
,
1714 &ClientSecurityContext
,
1719 /* Get rid of the security context */
1720 SeDeleteClientSecurity(&ClientSecurityContext
);
1722 /* See if we failed */
1723 if (!NT_SUCCESS(Status
))
1725 /* See if the target already existed */
1728 /* Lock the registry */
1729 CmpLockRegistryExclusive();
1731 /* Check if we are already loaded */
1732 if (CmpIsHiveAlreadyLoaded(KeyHandle
, SourceFile
, &LoadedHive
))
1734 /* That's okay then */
1736 Status
= STATUS_SUCCESS
;
1739 /* Release the registry */
1740 CmpUnlockRegistry();
1743 /* Close the key handle if we had one */
1744 if (KeyHandle
) ZwClose(KeyHandle
);
1748 /* Lock the registry shared */
1752 ExAcquirePushLockExclusive(&CmpLoadHiveLock
);
1754 /* Lock the hive to this thread */
1755 CmHive
->Hive
.HiveFlags
|= HIVE_IS_UNLOADING
;
1756 CmHive
->CreatorOwner
= KeGetCurrentThread();
1759 if (Flags
& REG_NO_LAZY_FLUSH
) CmHive
->Hive
.HiveFlags
|= HIVE_NOLAZYFLUSH
;
1762 Status
= CmpLinkHiveToMaster(TargetKey
->ObjectName
,
1763 TargetKey
->RootDirectory
,
1766 TargetKey
->SecurityDescriptor
);
1767 if (NT_SUCCESS(Status
))
1769 /* Add to HiveList key */
1770 CmpAddToHiveFileList(CmHive
);
1772 /* Sync the hive if necessary */
1775 /* Sync it under the flusher lock */
1776 CmpLockHiveFlusherExclusive(CmHive
);
1777 HvSyncHive(&CmHive
->Hive
);
1778 CmpUnlockHiveFlusher(CmHive
);
1781 /* Release the hive */
1782 CmHive
->Hive
.HiveFlags
&= ~HIVE_IS_UNLOADING
;
1783 CmHive
->CreatorOwner
= NULL
;
1786 ExReleasePushLock(&CmpLoadHiveLock
);
1794 /* Is this first profile load? */
1795 if (!(CmpProfileLoaded
) && !(CmpWasSetupBoot
))
1797 /* User is now logged on, set quotas */
1798 CmpProfileLoaded
= TRUE
;
1799 CmpSetGlobalQuotaAllowed();
1802 /* Unlock the registry */
1803 CmpUnlockRegistry();
1805 /* Close handle and return */
1806 if (KeyHandle
) ZwClose(KeyHandle
);
1812 CmUnloadKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
1816 return STATUS_NOT_IMPLEMENTED
;
1821 CmCountOpenSubKeys(IN PCM_KEY_CONTROL_BLOCK RootKcb
,
1822 IN BOOLEAN RemoveEmptyCacheEntries
)
1825 PCM_KEY_CONTROL_BLOCK CachedKcb
;
1826 PCM_KEY_CONTROL_BLOCK ParentKcb
;
1827 USHORT ParentKeyCount
;
1832 DPRINT("CmCountOpenSubKeys() called\n");
1834 /* The root key is the only referenced key. There are no refereced sub keys. */
1835 if (RootKcb
->RefCount
== 1)
1837 DPRINT("open sub keys: 0\n");
1841 /* Enumerate all hash lists */
1842 for (i
= 0; i
< CmpHashTableSize
; i
++)
1844 /* Get the first cache entry */
1845 Entry
= CmpCacheTable
[i
].Entry
;
1847 /* Enumerate all cache entries */
1850 /* Get the KCB of the current cache entry */
1851 CachedKcb
= CONTAINING_RECORD(Entry
, CM_KEY_CONTROL_BLOCK
, KeyHash
);
1853 /* Check keys only that are subkeys to our root key */
1854 if (CachedKcb
->TotalLevels
> RootKcb
->TotalLevels
)
1856 /* Calculate the number of parent keys to the root key */
1857 ParentKeyCount
= CachedKcb
->TotalLevels
- RootKcb
->TotalLevels
;
1859 /* Find a parent key that could be the root key */
1860 ParentKcb
= CachedKcb
;
1861 for (j
= 0; j
< ParentKeyCount
; j
++)
1863 ParentKcb
= ParentKcb
->ParentKcb
;
1866 /* Check whether the parent is the root key */
1867 if (ParentKcb
== RootKcb
)
1869 DPRINT("Found a sub key \n");
1870 DPRINT("RefCount = %u\n", CachedKcb
->RefCount
);
1872 if (CachedKcb
->RefCount
> 0)
1874 /* Count the current hash entry if it is in use */
1877 else if ((CachedKcb
->RefCount
== 0) && (RemoveEmptyCacheEntries
== TRUE
))
1879 /* Remove the current key from the delayed close list */
1880 CmpRemoveFromDelayedClose(CachedKcb
);
1882 /* Remove the current cache entry */
1883 CmpCleanUpKcbCacheWithLock(CachedKcb
, TRUE
);
1885 /* Restart, because the hash list has changed */
1886 Entry
= CmpCacheTable
[i
].Entry
;
1892 /* Get the next cache entry */
1893 Entry
= Entry
->NextHash
;
1897 DPRINT("open sub keys: %u\n", SubKeys
);