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 ******************************************************************/
16 /* FUNCTIONS *****************************************************************/
20 CmpSetValueKeyNew(IN PHHIVE Hive
,
21 IN PCM_KEY_NODE Parent
,
22 IN PUNICODE_STRING ValueName
,
31 HCELL_INDEX ValueCell
;
34 /* Check if we already have a value list */
35 if (Parent
->ValueList
.Count
)
37 /* Then make sure it's valid and dirty it */
38 ASSERT(Parent
->ValueList
.List
!= HCELL_NIL
);
39 HvMarkCellDirty(Hive
, Parent
->ValueList
.List
, FALSE
);
42 /* Allocate avalue cell */
43 ValueCell
= HvAllocateCell(Hive
,
44 FIELD_OFFSET(CM_KEY_VALUE
, Name
) +
45 CmpNameSize(Hive
, ValueName
),
48 if (ValueCell
== HCELL_NIL
) return STATUS_INSUFFICIENT_RESOURCES
;
50 /* Get the actual data for it */
51 CellData
= HvGetCell(Hive
, ValueCell
);
52 if (!CellData
) ASSERT(FALSE
);
54 /* Now we can release it, make sure it's also dirty */
55 HvReleaseCell(Hive
, ValueCell
);
56 ASSERT(HvIsCellDirty(Hive
, ValueCell
));
58 /* Set it up and copy the name */
59 CellData
->u
.KeyValue
.Signature
= CM_KEY_VALUE_SIGNATURE
;
60 CellData
->u
.KeyValue
.Flags
= 0;
61 CellData
->u
.KeyValue
.Type
= Type
;
62 CellData
->u
.KeyValue
.NameLength
= CmpCopyName(Hive
,
63 CellData
->u
.KeyValue
.Name
,
65 if (CellData
->u
.KeyValue
.NameLength
< ValueName
->Length
)
67 /* This is a compressed name */
68 CellData
->u
.KeyValue
.Flags
= VALUE_COMP_NAME
;
71 /* Check if this is a normal key */
72 if (DataSize
> CM_KEY_VALUE_SMALL
)
74 /* Build a data cell for it */
75 Status
= CmpSetValueDataNew(Hive
,
80 &CellData
->u
.KeyValue
.Data
);
81 if (!NT_SUCCESS(Status
))
83 /* We failed, free the cell */
84 HvFreeCell(Hive
, ValueCell
);
88 /* Otherwise, set the data length, and make sure the data is dirty */
89 CellData
->u
.KeyValue
.DataLength
= DataSize
;
90 ASSERT(HvIsCellDirty(Hive
, CellData
->u
.KeyValue
.Data
));
94 /* This is a small key, set the data directly inside */
95 CellData
->u
.KeyValue
.DataLength
= DataSize
+ CM_KEY_VALUE_SPECIAL_SIZE
;
96 CellData
->u
.KeyValue
.Data
= SmallData
;
99 /* Add this value cell to the child list */
100 Status
= CmpAddValueToList(Hive
,
106 /* If we failed, free the entire cell, including the data */
107 if (!NT_SUCCESS(Status
)) CmpFreeValue(Hive
, ValueCell
);
115 CmpSetValueKeyExisting(IN PHHIVE Hive
,
116 IN HCELL_INDEX OldChild
,
117 IN PCM_KEY_VALUE Value
,
121 IN ULONG StorageType
,
124 HCELL_INDEX DataCell
, NewCell
;
127 BOOLEAN WasSmall
, IsSmall
;
129 /* Mark the old child cell dirty */
130 HvMarkCellDirty(Hive
, OldChild
, FALSE
);
132 /* See if this is a small or normal key */
133 WasSmall
= CmpIsKeyValueSmall(&Length
, Value
->DataLength
);
135 /* See if our new data can fit in a small key */
136 IsSmall
= (DataSize
<= CM_KEY_VALUE_SMALL
) ? TRUE
: FALSE
;
138 /* Big keys are unsupported */
139 ASSERT_VALUE_BIG(Hive
, Length
);
140 ASSERT_VALUE_BIG(Hive
, DataSize
);
142 /* Mark the old value dirty */
143 CmpMarkValueDataDirty(Hive
, Value
);
145 /* Check if we have a small key */
148 /* Check if we had a normal key with some data in it */
149 if (!(WasSmall
) && (Length
> 0))
151 /* Free the previous data */
152 CmpFreeValueData(Hive
, Value
->Data
, Length
);
155 /* Write our data directly */
156 Value
->DataLength
= DataSize
+ CM_KEY_VALUE_SPECIAL_SIZE
;
157 Value
->Data
= TempData
;
159 return STATUS_SUCCESS
;
163 /* We have a normal key. Was the old cell also normal and had data? */
164 if (!(WasSmall
) && (Length
> 0))
166 /* Get the current data cell and actual data inside it */
167 DataCell
= Value
->Data
;
168 ASSERT(DataCell
!= HCELL_NIL
);
169 CellData
= HvGetCell(Hive
, DataCell
);
170 if (!CellData
) return STATUS_INSUFFICIENT_RESOURCES
;
172 /* Immediately release the cell */
173 HvReleaseCell(Hive
, DataCell
);
175 /* Make sure that the data cell actually has a size */
176 ASSERT(HvGetCellSize(Hive
, CellData
) > 0);
178 /* Check if the previous data cell could fit our new data */
179 if (DataSize
<= (ULONG
)(HvGetCellSize(Hive
, CellData
)))
186 /* Otherwise, re-allocate the current data cell */
187 NewCell
= HvReallocateCell(Hive
, DataCell
, DataSize
);
188 if (NewCell
== HCELL_NIL
) return STATUS_INSUFFICIENT_RESOURCES
;
193 /* This was a small key, or a key with no data, allocate a cell */
194 NewCell
= HvAllocateCell(Hive
, DataSize
, StorageType
, HCELL_NIL
);
195 if (NewCell
== HCELL_NIL
) return STATUS_INSUFFICIENT_RESOURCES
;
198 /* Now get the actual data for our data cell */
199 CellData
= HvGetCell(Hive
, NewCell
);
200 if (!CellData
) ASSERT(FALSE
);
202 /* Release it immediately */
203 HvReleaseCell(Hive
, NewCell
);
205 /* Copy our data into the data cell's buffer, and set up the value */
206 RtlCopyMemory(CellData
, Data
, DataSize
);
207 Value
->Data
= NewCell
;
208 Value
->DataLength
= DataSize
;
212 ASSERT(HvIsCellDirty(Hive
, NewCell
));
213 return STATUS_SUCCESS
;
219 CmSetValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
220 IN PUNICODE_STRING ValueName
,
227 PCM_KEY_VALUE Value
= NULL
;
228 HCELL_INDEX CurrentChild
, Cell
;
230 BOOLEAN Found
, Result
;
231 ULONG Count
, ChildIndex
, SmallData
, Storage
;
233 /* Acquire hive lock exclusively */
234 KeEnterCriticalRegion();
235 ExAcquireResourceExclusiveLite(&CmpRegistryLock
, TRUE
);
237 /* Get pointer to key cell */
241 /* Prepare to scan the key node */
242 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
243 Count
= Parent
->ValueList
.Count
;
247 /* Try to find the existing name */
248 Result
= CmpFindNameInList(Hive
,
256 Status
= STATUS_INSUFFICIENT_RESOURCES
;
260 /* Check if we found something */
261 if (CurrentChild
!= HCELL_NIL
)
264 Value
= (PCM_KEY_VALUE
)HvGetCell(Hive
, CurrentChild
);
268 Status
= STATUS_INSUFFICIENT_RESOURCES
;
272 /* Remember that we found it */
278 /* No child list, we'll need to add it */
282 /* Mark the cell dirty */
283 HvMarkCellDirty(Hive
, Cell
, FALSE
);
285 /* Get the storage type */
286 Storage
= HvGetCellType(Cell
);
288 /* Check if this is small data */
290 if ((DataLength
<= CM_KEY_VALUE_SMALL
) && (DataLength
> 0))
293 RtlCopyMemory(&SmallData
, Data
, DataLength
);
296 /* Check if we didn't find a matching key */
299 /* Call the internal routine */
300 Status
= CmpSetValueKeyNew(Hive
,
312 /* Call the internal routine */
313 Status
= CmpSetValueKeyExisting(Hive
,
324 if ((Type
== REG_LINK
) &&
325 (_wcsicmp(ValueName
->Buffer
, L
"SymbolicLinkValue") == 0))
327 Parent
->Flags
|= KEY_SYM_LINK
;
330 /* Check for success */
332 if (NT_SUCCESS(Status
))
334 ASSERT(Parent
->MaxValueNameLen
== Kcb
->KcbMaxValueNameLen
);
335 if (Parent
->MaxValueNameLen
< ValueName
->Length
)
337 Parent
->MaxValueNameLen
= ValueName
->Length
;
338 Kcb
->KcbMaxValueNameLen
= ValueName
->Length
;
341 ASSERT(Parent
->MaxValueDataLen
== Kcb
->KcbMaxValueDataLen
);
342 if (Parent
->MaxValueDataLen
< DataLength
)
344 Parent
->MaxValueDataLen
= DataLength
;
345 Kcb
->KcbMaxValueDataLen
= Parent
->MaxValueDataLen
;
348 /* Save the write time */
349 KeQuerySystemTime(&Parent
->LastWriteTime
);
350 KeQuerySystemTime(&Kcb
->KcbLastWriteTime
);
353 /* Release the lock */
354 ExReleaseResourceLite(&CmpRegistryLock
);
355 KeLeaveCriticalRegion();
361 CmDeleteValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
362 IN UNICODE_STRING ValueName
)
364 NTSTATUS Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
367 HCELL_INDEX ChildCell
, Cell
;
368 PCHILD_LIST ChildList
;
369 PCM_KEY_VALUE Value
= NULL
;
373 /* Acquire hive lock */
374 KeEnterCriticalRegion();
375 ExAcquireResourceExclusiveLite(&CmpRegistryLock
, TRUE
);
377 /* Get the hive and the cell index */
381 /* Get the parent key node */
382 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
386 Status
= STATUS_INSUFFICIENT_RESOURCES
;
390 /* Get the value list and check if it has any entries */
391 ChildList
= &Parent
->ValueList
;
392 if (ChildList
->Count
)
394 /* Try to find this value */
395 Result
= CmpFindNameInList(Hive
,
403 Status
= STATUS_INSUFFICIENT_RESOURCES
;
407 /* Value not found, return error */
408 if (ChildCell
== HCELL_NIL
) goto Quickie
;
410 /* We found the value, mark all relevant cells dirty */
411 HvMarkCellDirty(Hive
, Cell
, FALSE
);
412 HvMarkCellDirty(Hive
, Parent
->ValueList
.List
, FALSE
);
413 HvMarkCellDirty(Hive
, ChildCell
, FALSE
);
415 /* Get the key value */
416 Value
= (PCM_KEY_VALUE
)HvGetCell(Hive
,ChildCell
);
417 if (!Value
) ASSERT(FALSE
);
419 /* Mark it and all related data as dirty */
420 CmpMarkValueDataDirty(Hive
, Value
);
423 ASSERT(HvIsCellDirty(Hive
, Parent
->ValueList
.List
));
424 ASSERT(HvIsCellDirty(Hive
, ChildCell
));
426 /* Remove the value from the child list */
427 Status
= CmpRemoveValueFromList(Hive
, ChildIndex
, ChildList
);
428 if(!NT_SUCCESS(Status
)) goto Quickie
;
430 /* Remove the value and its data itself */
431 if (!CmpFreeValue(Hive
, ChildCell
))
433 /* Failed to free the value, fail */
434 Status
= STATUS_INSUFFICIENT_RESOURCES
;
438 /* Set the last write time */
439 KeQuerySystemTime(&Parent
->LastWriteTime
);
440 KeQuerySystemTime(&Kcb
->KcbLastWriteTime
);
443 ASSERT(Parent
->MaxValueNameLen
== Kcb
->KcbMaxValueNameLen
);
444 ASSERT(Parent
->MaxValueDataLen
== Kcb
->KcbMaxValueDataLen
);
445 ASSERT(HvIsCellDirty(Hive
, Cell
));
447 /* Check if the value list is empty now */
448 if (!Parent
->ValueList
.Count
)
450 /* Then clear key node data */
451 Parent
->MaxValueNameLen
= 0;
452 Parent
->MaxValueDataLen
= 0;
453 Kcb
->KcbMaxValueNameLen
= 0;
454 Kcb
->KcbMaxValueDataLen
= 0;
457 /* Change default Status to success */
458 Status
= STATUS_SUCCESS
;
462 /* Release the parent cell, if any */
463 if (Parent
) HvReleaseCell(Hive
, Cell
);
465 /* Check if we had a value */
468 /* Release the child cell */
469 ASSERT(ChildCell
!= HCELL_NIL
);
470 HvReleaseCell(Hive
, ChildCell
);
473 /* Release hive lock */
474 ExReleaseResourceLite(&CmpRegistryLock
);
475 KeLeaveCriticalRegion();
481 CmQueryValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
482 IN UNICODE_STRING ValueName
,
483 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
484 IN PVOID KeyValueInformation
,
486 IN PULONG ResultLength
)
489 PCM_KEY_VALUE ValueData
;
491 BOOLEAN ValueCached
= FALSE
;
492 PCM_CACHED_VALUE
*CachedValue
;
493 HCELL_INDEX CellToRelease
;
494 VALUE_SEARCH_RETURN_TYPE Result
;
498 /* Acquire hive lock */
499 KeEnterCriticalRegion();
500 ExAcquireResourceExclusiveLite(&CmpRegistryLock
, TRUE
);
505 /* Find the key value */
506 Result
= CmpFindValueByNameFromCache(Kcb
,
513 if (Result
== SearchSuccess
)
516 ASSERT(ValueData
!= NULL
);
518 /* Query the information requested */
519 Result
= CmpQueryKeyValueData(Kcb
,
523 KeyValueInformationClass
,
531 /* Failed to find the value */
532 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
535 /* If we have a cell to release, do so */
536 if (CellToRelease
!= HCELL_NIL
) HvReleaseCell(Hive
, CellToRelease
);
538 /* Release hive lock */
539 ExReleaseResourceLite(&CmpRegistryLock
);
540 KeLeaveCriticalRegion();
546 CmEnumerateValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
548 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
549 IN PVOID KeyValueInformation
,
551 IN PULONG ResultLength
)
556 HCELL_INDEX CellToRelease
= HCELL_NIL
, CellToRelease2
= HCELL_NIL
;
557 VALUE_SEARCH_RETURN_TYPE Result
;
558 BOOLEAN IndexIsCached
, ValueIsCached
= FALSE
;
560 PCM_CACHED_VALUE
*CachedValue
;
561 PCM_KEY_VALUE ValueData
;
564 /* Acquire hive lock */
565 KeEnterCriticalRegion();
566 ExAcquireResourceExclusiveLite(&CmpRegistryLock
, TRUE
);
568 /* Get the hive and parent */
570 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, Kcb
->KeyCell
);
574 Status
= STATUS_INSUFFICIENT_RESOURCES
;
578 /* Make sure the index is valid */
579 //if (Index >= Kcb->ValueCache.Count)
580 if (Index
>= Parent
->ValueList
.Count
)
582 /* Release the cell and fail */
583 HvReleaseCell(Hive
, Kcb
->KeyCell
);
584 Status
= STATUS_NO_MORE_ENTRIES
;
588 /* Find the value list */
589 Result
= CmpGetValueListFromCache(Kcb
,
593 if (Result
!= SearchSuccess
)
596 ASSERT(CellData
== NULL
);
598 /* Release the cell and fail */
599 Status
= STATUS_INSUFFICIENT_RESOURCES
;
603 /* Now get the key value */
604 Result
= CmpGetValueKeyFromCache(Kcb
,
612 if (Result
!= SearchSuccess
)
615 ASSERT(CellToRelease2
== HCELL_NIL
);
617 /* Release the cells and fail */
618 Status
= STATUS_INSUFFICIENT_RESOURCES
;
622 /* Query the information requested */
623 Result
= CmpQueryKeyValueData(Kcb
,
627 KeyValueInformationClass
,
634 /* If we have a cell to release, do so */
635 if (CellToRelease
!= HCELL_NIL
) HvReleaseCell(Hive
, CellToRelease
);
637 /* Release the parent cell */
638 HvReleaseCell(Hive
, Kcb
->KeyCell
);
640 /* If we have a cell to release, do so */
641 if (CellToRelease2
!= HCELL_NIL
) HvReleaseCell(Hive
, CellToRelease2
);
643 /* Release hive lock */
644 ExReleaseResourceLite(&CmpRegistryLock
);
645 KeLeaveCriticalRegion();
651 CmpQueryKeyData(IN PHHIVE Hive
,
652 IN PCM_KEY_NODE Node
,
653 IN KEY_INFORMATION_CLASS KeyInformationClass
,
654 IN OUT PVOID KeyInformation
,
656 IN OUT PULONG ResultLength
)
659 ULONG Size
, SizeLeft
, MinimumSize
;
660 PKEY_INFORMATION Info
= (PKEY_INFORMATION
)KeyInformation
;
663 /* Check if the value is compressed */
664 if (Node
->Flags
& KEY_COMP_NAME
)
666 /* Get the compressed name size */
667 NameLength
= CmpCompressedNameSize(Node
->Name
, Node
->NameLength
);
671 /* Get the real size */
672 NameLength
= Node
->NameLength
;
675 /* Check what kind of information is being requested */
676 switch (KeyInformationClass
)
678 /* Basic information */
679 case KeyBasicInformation
:
681 /* This is the size we need */
682 Size
= FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
) + NameLength
;
684 /* And this is the minimum we can work with */
685 MinimumSize
= FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
);
687 /* Let the caller know and assume success */
688 *ResultLength
= Size
;
689 Status
= STATUS_SUCCESS
;
691 /* Check if the bufer we got is too small */
692 if (Length
< MinimumSize
)
694 /* Let the caller know and fail */
695 Status
= STATUS_BUFFER_TOO_SMALL
;
699 /* Copy the basic information */
700 Info
->KeyBasicInformation
.LastWriteTime
= Node
->LastWriteTime
;
701 Info
->KeyBasicInformation
.TitleIndex
= 0;
702 Info
->KeyBasicInformation
.NameLength
= NameLength
;
704 /* Only the name is left */
705 SizeLeft
= Length
- MinimumSize
;
708 /* Check if we don't have enough space for the name */
711 /* Truncate the name we'll return, and tell the caller */
713 Status
= STATUS_BUFFER_OVERFLOW
;
716 /* Check if this is a compressed key */
717 if (Node
->Flags
& KEY_COMP_NAME
)
719 /* Copy the compressed name */
720 CmpCopyCompressedName(Info
->KeyBasicInformation
.Name
,
727 /* Otherwise, copy the raw name */
728 RtlCopyMemory(Info
->KeyBasicInformation
.Name
,
734 /* Node information */
735 case KeyNodeInformation
:
737 /* Calculate the size we need */
738 Size
= FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
) +
742 /* And the minimum size we can support */
743 MinimumSize
= FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
);
745 /* Return the size to the caller and assume succes */
746 *ResultLength
= Size
;
747 Status
= STATUS_SUCCESS
;
749 /* Check if the caller's buffer is too small */
750 if (Length
< MinimumSize
)
752 /* Let them know, and fail */
753 Status
= STATUS_BUFFER_TOO_SMALL
;
757 /* Copy the basic information */
758 Info
->KeyNodeInformation
.LastWriteTime
= Node
->LastWriteTime
;
759 Info
->KeyNodeInformation
.TitleIndex
= 0;
760 Info
->KeyNodeInformation
.ClassLength
= Node
->ClassLength
;
761 Info
->KeyNodeInformation
.NameLength
= NameLength
;
763 /* Now the name is left */
764 SizeLeft
= Length
- MinimumSize
;
767 /* Check if the name can fit entirely */
770 /* It can't, we'll have to truncate. Tell the caller */
772 Status
= STATUS_BUFFER_OVERFLOW
;
775 /* Check if the key node name is compressed */
776 if (Node
->Flags
& KEY_COMP_NAME
)
778 /* Copy the compressed name */
779 CmpCopyCompressedName(Info
->KeyNodeInformation
.Name
,
786 /* It isn't, so copy the raw name */
787 RtlCopyMemory(Info
->KeyNodeInformation
.Name
,
792 /* Check if the node has a class */
793 if (Node
->ClassLength
> 0)
795 /* It does. We don't support these yet */
796 ASSERTMSG("Classes not supported\n", FALSE
);
800 /* It doesn't, so set offset to -1, not 0! */
801 Info
->KeyNodeInformation
.ClassOffset
= 0xFFFFFFFF;
805 /* Full information requsted */
806 case KeyFullInformation
:
808 /* This is the size we need */
809 Size
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
) +
812 /* This is what we can work with */
813 MinimumSize
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
);
815 /* Return it to caller and assume success */
816 *ResultLength
= Size
;
817 Status
= STATUS_SUCCESS
;
819 /* Check if the caller's buffer is to small */
820 if (Length
< MinimumSize
)
822 /* Let them know and fail */
823 Status
= STATUS_BUFFER_TOO_SMALL
;
827 /* Now copy all the basic information */
828 Info
->KeyFullInformation
.LastWriteTime
= Node
->LastWriteTime
;
829 Info
->KeyFullInformation
.TitleIndex
= 0;
830 Info
->KeyFullInformation
.ClassLength
= Node
->ClassLength
;
831 Info
->KeyFullInformation
.SubKeys
= Node
->SubKeyCounts
[Stable
] +
832 Node
->SubKeyCounts
[Volatile
];
833 Info
->KeyFullInformation
.Values
= Node
->ValueList
.Count
;
834 Info
->KeyFullInformation
.MaxNameLen
= Node
->MaxNameLen
;
835 Info
->KeyFullInformation
.MaxClassLen
= Node
->MaxClassLen
;
836 Info
->KeyFullInformation
.MaxValueNameLen
= Node
->MaxValueNameLen
;
837 Info
->KeyFullInformation
.MaxValueDataLen
= Node
->MaxValueDataLen
;
839 /* Check if we have a class */
840 if (Node
->ClassLength
> 0)
842 /* We do, but we currently don't support this */
843 ASSERTMSG("Classes not supported\n", FALSE
);
847 /* We don't have a class, so set offset to -1, not 0! */
848 Info
->KeyNodeInformation
.ClassOffset
= 0xFFFFFFFF;
852 /* Any other class that got sent here is invalid! */
855 /* Set failure code */
856 Status
= STATUS_INVALID_PARAMETER
;
866 CmQueryKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
867 IN KEY_INFORMATION_CLASS KeyInformationClass
,
868 IN PVOID KeyInformation
,
870 IN PULONG ResultLength
)
876 /* Acquire hive lock */
877 KeEnterCriticalRegion();
878 ExAcquireResourceExclusiveLite(&CmpRegistryLock
, TRUE
);
880 /* Get the hive and parent */
882 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, Kcb
->KeyCell
);
886 Status
= STATUS_INSUFFICIENT_RESOURCES
;
890 /* Check what class we got */
891 switch (KeyInformationClass
)
893 /* Typical information */
894 case KeyFullInformation
:
895 case KeyBasicInformation
:
896 case KeyNodeInformation
:
898 /* Call the internal API */
899 Status
= CmpQueryKeyData(Hive
,
907 /* Unsupported classes for now */
908 case KeyNameInformation
:
909 case KeyCachedInformation
:
910 case KeyFlagsInformation
:
912 /* Print message and fail */
913 DPRINT1("Unsupported class: %d!\n", KeyInformationClass
);
914 Status
= STATUS_NOT_IMPLEMENTED
;
917 /* Illegal classes */
920 /* Print message and fail */
921 DPRINT1("Unsupported class: %d!\n", KeyInformationClass
);
922 Status
= STATUS_INVALID_INFO_CLASS
;
927 /* Release hive lock */
928 ExReleaseResourceLite(&CmpRegistryLock
);
929 KeLeaveCriticalRegion();
935 CmEnumerateKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
937 IN KEY_INFORMATION_CLASS KeyInformationClass
,
938 IN PVOID KeyInformation
,
940 IN PULONG ResultLength
)
944 PCM_KEY_NODE Parent
, Child
;
945 HCELL_INDEX ChildCell
;
947 /* Acquire hive lock */
948 KeEnterCriticalRegion();
949 ExAcquireResourceExclusiveLite(&CmpRegistryLock
, TRUE
);
951 /* Get the hive and parent */
953 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, Kcb
->KeyCell
);
957 Status
= STATUS_INSUFFICIENT_RESOURCES
;
961 /* Get the child cell */
962 ChildCell
= CmpFindSubKeyByNumber(Hive
, Parent
, Index
);
964 /* Release the parent cell */
965 HvReleaseCell(Hive
, Kcb
->KeyCell
);
967 /* Check if we found the child */
968 if (ChildCell
== HCELL_NIL
)
970 /* We didn't, fail */
971 Status
= STATUS_NO_MORE_ENTRIES
;
975 /* Now get the actual child node */
976 Child
= (PCM_KEY_NODE
)HvGetCell(Hive
, ChildCell
);
980 Status
= STATUS_INSUFFICIENT_RESOURCES
;
984 /* Query the data requested */
985 Status
= CmpQueryKeyData(Hive
,
993 /* Release hive lock */
994 ExReleaseResourceLite(&CmpRegistryLock
);
995 KeLeaveCriticalRegion();
1001 CmDeleteKey(IN PCM_KEY_CONTROL_BLOCK Kcb
)
1005 PCM_KEY_NODE Node
, Parent
;
1006 HCELL_INDEX Cell
, ParentCell
;
1008 /* Acquire hive lock */
1009 KeEnterCriticalRegion();
1010 ExAcquireResourceExclusiveLite(&CmpRegistryLock
, TRUE
);
1012 /* Get the hive and node */
1013 Hive
= Kcb
->KeyHive
;
1014 Cell
= Kcb
->KeyCell
;
1016 /* Get the key node */
1017 Node
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
1021 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1025 /* Check if we have no parent */
1028 /* This is an attempt to delete \Registry itself! */
1029 Status
= STATUS_CANNOT_DELETE
;
1033 /* Check if we don't have any children */
1034 if (!(Node
->SubKeyCounts
[Stable
] + Node
->SubKeyCounts
[Volatile
]))
1036 /* Get the parent and free the cell */
1037 ParentCell
= Node
->Parent
;
1038 Status
= CmpFreeKeyByCell(Hive
, Cell
, TRUE
);
1039 if (NT_SUCCESS(Status
))
1041 /* Get the parent node */
1042 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, ParentCell
);
1045 /* Make sure we're dirty */
1046 ASSERT(HvIsCellDirty(Hive
, ParentCell
));
1048 /* Update the write time */
1049 KeQuerySystemTime(&Parent
->LastWriteTime
);
1051 /* Release the cell */
1052 HvReleaseCell(Hive
, ParentCell
);
1055 /* Clear the cell */
1056 Kcb
->KeyCell
= HCELL_NIL
;
1062 Status
= STATUS_CANNOT_DELETE
;
1065 /* Make sure we're file-backed */
1066 if (!(IsNoFileHive((PCMHIVE
)Kcb
->KeyHive
)) ||
1067 !(IsNoFileHive((PCMHIVE
)Kcb
->ParentKcb
->KeyHive
)))
1069 /* Sync up the hives */
1074 /* Release the cell */
1075 HvReleaseCell(Hive
, Cell
);
1077 /* Release hive lock */
1078 ExReleaseResourceLite(&CmpRegistryLock
);
1079 KeLeaveCriticalRegion();