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 CmpDoFlushAll(IN BOOLEAN ForceFlush
)
22 PLIST_ENTRY NextEntry
;
24 BOOLEAN Result
= TRUE
;
26 /* Make sure that the registry isn't read-only now */
27 if (CmpNoWrite
) return TRUE
;
29 /* Otherwise, acquire the hive list lock and disable force flush */
30 CmpForceForceFlush
= FALSE
;
31 ExAcquirePushLockShared(&CmpHiveListHeadLock
);
33 /* Loop the hive list */
34 NextEntry
= CmpHiveListHead
.Flink
;
35 while (NextEntry
!= &CmpHiveListHead
)
38 Hive
= CONTAINING_RECORD(NextEntry
, CMHIVE
, HiveList
);
39 if (!(Hive
->Hive
.HiveFlags
& HIVE_NOLAZYFLUSH
))
42 Status
= HvSyncHive(&Hive
->Hive
);
43 if (!NT_SUCCESS(Status
)) Result
= FALSE
;
46 /* Try the next entry */
47 NextEntry
= NextEntry
->Flink
;
50 /* Release lock and return */
51 ExReleasePushLock(&CmpHiveListHeadLock
);
57 CmpSetValueKeyNew(IN PHHIVE Hive
,
58 IN PCM_KEY_NODE Parent
,
59 IN PUNICODE_STRING ValueName
,
68 HCELL_INDEX ValueCell
;
71 /* Check if we already have a value list */
72 if (Parent
->ValueList
.Count
)
74 /* Then make sure it's valid and dirty it */
75 ASSERT(Parent
->ValueList
.List
!= HCELL_NIL
);
76 HvMarkCellDirty(Hive
, Parent
->ValueList
.List
, FALSE
);
79 /* Allocate avalue cell */
80 ValueCell
= HvAllocateCell(Hive
,
81 FIELD_OFFSET(CM_KEY_VALUE
, Name
) +
82 CmpNameSize(Hive
, ValueName
),
85 if (ValueCell
== HCELL_NIL
) return STATUS_INSUFFICIENT_RESOURCES
;
87 /* Get the actual data for it */
88 CellData
= HvGetCell(Hive
, ValueCell
);
89 if (!CellData
) ASSERT(FALSE
);
91 /* Now we can release it, make sure it's also dirty */
92 HvReleaseCell(Hive
, ValueCell
);
93 ASSERT(HvIsCellDirty(Hive
, ValueCell
));
95 /* Set it up and copy the name */
96 CellData
->u
.KeyValue
.Signature
= CM_KEY_VALUE_SIGNATURE
;
97 CellData
->u
.KeyValue
.Flags
= 0;
98 CellData
->u
.KeyValue
.Type
= Type
;
99 CellData
->u
.KeyValue
.NameLength
= CmpCopyName(Hive
,
100 CellData
->u
.KeyValue
.Name
,
102 if (CellData
->u
.KeyValue
.NameLength
< ValueName
->Length
)
104 /* This is a compressed name */
105 CellData
->u
.KeyValue
.Flags
= VALUE_COMP_NAME
;
108 /* Check if this is a normal key */
109 if (DataSize
> CM_KEY_VALUE_SMALL
)
111 /* Build a data cell for it */
112 Status
= CmpSetValueDataNew(Hive
,
117 &CellData
->u
.KeyValue
.Data
);
118 if (!NT_SUCCESS(Status
))
120 /* We failed, free the cell */
121 HvFreeCell(Hive
, ValueCell
);
125 /* Otherwise, set the data length, and make sure the data is dirty */
126 CellData
->u
.KeyValue
.DataLength
= DataSize
;
127 ASSERT(HvIsCellDirty(Hive
, CellData
->u
.KeyValue
.Data
));
131 /* This is a small key, set the data directly inside */
132 CellData
->u
.KeyValue
.DataLength
= DataSize
+ CM_KEY_VALUE_SPECIAL_SIZE
;
133 CellData
->u
.KeyValue
.Data
= SmallData
;
136 /* Add this value cell to the child list */
137 Status
= CmpAddValueToList(Hive
,
143 /* If we failed, free the entire cell, including the data */
144 if (!NT_SUCCESS(Status
)) CmpFreeValue(Hive
, ValueCell
);
152 CmpSetValueKeyExisting(IN PHHIVE Hive
,
153 IN HCELL_INDEX OldChild
,
154 IN PCM_KEY_VALUE Value
,
158 IN ULONG StorageType
,
161 HCELL_INDEX DataCell
, NewCell
;
164 BOOLEAN WasSmall
, IsSmall
;
166 /* Mark the old child cell dirty */
167 HvMarkCellDirty(Hive
, OldChild
, FALSE
);
169 /* See if this is a small or normal key */
170 WasSmall
= CmpIsKeyValueSmall(&Length
, Value
->DataLength
);
172 /* See if our new data can fit in a small key */
173 IsSmall
= (DataSize
<= CM_KEY_VALUE_SMALL
) ? TRUE
: FALSE
;
175 /* Big keys are unsupported */
176 ASSERT_VALUE_BIG(Hive
, Length
);
177 ASSERT_VALUE_BIG(Hive
, DataSize
);
179 /* Mark the old value dirty */
180 CmpMarkValueDataDirty(Hive
, Value
);
182 /* Check if we have a small key */
185 /* Check if we had a normal key with some data in it */
186 if (!(WasSmall
) && (Length
> 0))
188 /* Free the previous data */
189 CmpFreeValueData(Hive
, Value
->Data
, Length
);
192 /* Write our data directly */
193 Value
->DataLength
= DataSize
+ CM_KEY_VALUE_SPECIAL_SIZE
;
194 Value
->Data
= TempData
;
196 return STATUS_SUCCESS
;
200 /* We have a normal key. Was the old cell also normal and had data? */
201 if (!(WasSmall
) && (Length
> 0))
203 /* Get the current data cell and actual data inside it */
204 DataCell
= Value
->Data
;
205 ASSERT(DataCell
!= HCELL_NIL
);
206 CellData
= HvGetCell(Hive
, DataCell
);
207 if (!CellData
) return STATUS_INSUFFICIENT_RESOURCES
;
209 /* Immediately release the cell */
210 HvReleaseCell(Hive
, DataCell
);
212 /* Make sure that the data cell actually has a size */
213 ASSERT(HvGetCellSize(Hive
, CellData
) > 0);
215 /* Check if the previous data cell could fit our new data */
216 if (DataSize
<= (ULONG
)(HvGetCellSize(Hive
, CellData
)))
223 /* Otherwise, re-allocate the current data cell */
224 NewCell
= HvReallocateCell(Hive
, DataCell
, DataSize
);
225 if (NewCell
== HCELL_NIL
) return STATUS_INSUFFICIENT_RESOURCES
;
230 /* This was a small key, or a key with no data, allocate a cell */
231 NewCell
= HvAllocateCell(Hive
, DataSize
, StorageType
, HCELL_NIL
);
232 if (NewCell
== HCELL_NIL
) return STATUS_INSUFFICIENT_RESOURCES
;
235 /* Now get the actual data for our data cell */
236 CellData
= HvGetCell(Hive
, NewCell
);
237 if (!CellData
) ASSERT(FALSE
);
239 /* Release it immediately */
240 HvReleaseCell(Hive
, NewCell
);
242 /* Copy our data into the data cell's buffer, and set up the value */
243 RtlCopyMemory(CellData
, Data
, DataSize
);
244 Value
->Data
= NewCell
;
245 Value
->DataLength
= DataSize
;
249 ASSERT(HvIsCellDirty(Hive
, NewCell
));
250 return STATUS_SUCCESS
;
256 CmSetValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
257 IN PUNICODE_STRING ValueName
,
264 PCM_KEY_VALUE Value
= NULL
;
265 HCELL_INDEX CurrentChild
, Cell
;
267 BOOLEAN Found
, Result
;
268 ULONG Count
, ChildIndex
, SmallData
, Storage
;
270 /* Acquire hive lock exclusively */
271 KeEnterCriticalRegion();
272 ExAcquireResourceExclusiveLite(&CmpRegistryLock
, TRUE
);
274 /* Get pointer to key cell */
278 /* Prepare to scan the key node */
279 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
280 Count
= Parent
->ValueList
.Count
;
284 /* Try to find the existing name */
285 Result
= CmpFindNameInList(Hive
,
293 Status
= STATUS_INSUFFICIENT_RESOURCES
;
297 /* Check if we found something */
298 if (CurrentChild
!= HCELL_NIL
)
301 Value
= (PCM_KEY_VALUE
)HvGetCell(Hive
, CurrentChild
);
305 Status
= STATUS_INSUFFICIENT_RESOURCES
;
309 /* Remember that we found it */
315 /* No child list, we'll need to add it */
319 /* Mark the cell dirty */
320 HvMarkCellDirty(Hive
, Cell
, FALSE
);
322 /* Get the storage type */
323 Storage
= HvGetCellType(Cell
);
325 /* Check if this is small data */
327 if ((DataLength
<= CM_KEY_VALUE_SMALL
) && (DataLength
> 0))
330 RtlCopyMemory(&SmallData
, Data
, DataLength
);
333 /* Check if we didn't find a matching key */
336 /* Call the internal routine */
337 Status
= CmpSetValueKeyNew(Hive
,
349 /* Call the internal routine */
350 Status
= CmpSetValueKeyExisting(Hive
,
361 if ((Type
== REG_LINK
) &&
362 (_wcsicmp(ValueName
->Buffer
, L
"SymbolicLinkValue") == 0))
364 Parent
->Flags
|= KEY_SYM_LINK
;
367 /* Check for success */
369 if (NT_SUCCESS(Status
))
371 ASSERT(Parent
->MaxValueNameLen
== Kcb
->KcbMaxValueNameLen
);
372 if (Parent
->MaxValueNameLen
< ValueName
->Length
)
374 Parent
->MaxValueNameLen
= ValueName
->Length
;
375 Kcb
->KcbMaxValueNameLen
= ValueName
->Length
;
378 ASSERT(Parent
->MaxValueDataLen
== Kcb
->KcbMaxValueDataLen
);
379 if (Parent
->MaxValueDataLen
< DataLength
)
381 Parent
->MaxValueDataLen
= DataLength
;
382 Kcb
->KcbMaxValueDataLen
= Parent
->MaxValueDataLen
;
385 /* Save the write time */
386 KeQuerySystemTime(&Parent
->LastWriteTime
);
387 KeQuerySystemTime(&Kcb
->KcbLastWriteTime
);
390 /* Release the lock */
391 ExReleaseResourceLite(&CmpRegistryLock
);
392 KeLeaveCriticalRegion();
398 CmDeleteValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
399 IN UNICODE_STRING ValueName
)
401 NTSTATUS Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
404 HCELL_INDEX ChildCell
, Cell
;
405 PCHILD_LIST ChildList
;
406 PCM_KEY_VALUE Value
= NULL
;
410 /* Acquire hive lock */
411 KeEnterCriticalRegion();
412 ExAcquireResourceExclusiveLite(&CmpRegistryLock
, TRUE
);
414 /* Get the hive and the cell index */
418 /* Get the parent key node */
419 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
423 Status
= STATUS_INSUFFICIENT_RESOURCES
;
427 /* Get the value list and check if it has any entries */
428 ChildList
= &Parent
->ValueList
;
429 if (ChildList
->Count
)
431 /* Try to find this value */
432 Result
= CmpFindNameInList(Hive
,
440 Status
= STATUS_INSUFFICIENT_RESOURCES
;
444 /* Value not found, return error */
445 if (ChildCell
== HCELL_NIL
) goto Quickie
;
447 /* We found the value, mark all relevant cells dirty */
448 HvMarkCellDirty(Hive
, Cell
, FALSE
);
449 HvMarkCellDirty(Hive
, Parent
->ValueList
.List
, FALSE
);
450 HvMarkCellDirty(Hive
, ChildCell
, FALSE
);
452 /* Get the key value */
453 Value
= (PCM_KEY_VALUE
)HvGetCell(Hive
,ChildCell
);
454 if (!Value
) ASSERT(FALSE
);
456 /* Mark it and all related data as dirty */
457 CmpMarkValueDataDirty(Hive
, Value
);
460 ASSERT(HvIsCellDirty(Hive
, Parent
->ValueList
.List
));
461 ASSERT(HvIsCellDirty(Hive
, ChildCell
));
463 /* Remove the value from the child list */
464 Status
= CmpRemoveValueFromList(Hive
, ChildIndex
, ChildList
);
465 if(!NT_SUCCESS(Status
)) goto Quickie
;
467 /* Remove the value and its data itself */
468 if (!CmpFreeValue(Hive
, ChildCell
))
470 /* Failed to free the value, fail */
471 Status
= STATUS_INSUFFICIENT_RESOURCES
;
475 /* Set the last write time */
476 KeQuerySystemTime(&Parent
->LastWriteTime
);
477 KeQuerySystemTime(&Kcb
->KcbLastWriteTime
);
480 ASSERT(Parent
->MaxValueNameLen
== Kcb
->KcbMaxValueNameLen
);
481 ASSERT(Parent
->MaxValueDataLen
== Kcb
->KcbMaxValueDataLen
);
482 ASSERT(HvIsCellDirty(Hive
, Cell
));
484 /* Check if the value list is empty now */
485 if (!Parent
->ValueList
.Count
)
487 /* Then clear key node data */
488 Parent
->MaxValueNameLen
= 0;
489 Parent
->MaxValueDataLen
= 0;
490 Kcb
->KcbMaxValueNameLen
= 0;
491 Kcb
->KcbMaxValueDataLen
= 0;
494 /* Change default Status to success */
495 Status
= STATUS_SUCCESS
;
499 /* Release the parent cell, if any */
500 if (Parent
) HvReleaseCell(Hive
, Cell
);
502 /* Check if we had a value */
505 /* Release the child cell */
506 ASSERT(ChildCell
!= HCELL_NIL
);
507 HvReleaseCell(Hive
, ChildCell
);
510 /* Release hive lock */
511 ExReleaseResourceLite(&CmpRegistryLock
);
512 KeLeaveCriticalRegion();
518 CmQueryValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
519 IN UNICODE_STRING ValueName
,
520 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
521 IN PVOID KeyValueInformation
,
523 IN PULONG ResultLength
)
526 PCM_KEY_VALUE ValueData
;
528 BOOLEAN ValueCached
= FALSE
;
529 PCM_CACHED_VALUE
*CachedValue
;
530 HCELL_INDEX CellToRelease
;
531 VALUE_SEARCH_RETURN_TYPE Result
;
535 /* Acquire hive lock */
536 KeEnterCriticalRegion();
537 ExAcquireResourceExclusiveLite(&CmpRegistryLock
, TRUE
);
542 /* Find the key value */
543 Result
= CmpFindValueByNameFromCache(Kcb
,
550 if (Result
== SearchSuccess
)
553 ASSERT(ValueData
!= NULL
);
555 /* Query the information requested */
556 Result
= CmpQueryKeyValueData(Kcb
,
560 KeyValueInformationClass
,
568 /* Failed to find the value */
569 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
572 /* If we have a cell to release, do so */
573 if (CellToRelease
!= HCELL_NIL
) HvReleaseCell(Hive
, CellToRelease
);
575 /* Release hive lock */
576 ExReleaseResourceLite(&CmpRegistryLock
);
577 KeLeaveCriticalRegion();
583 CmEnumerateValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
585 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
586 IN PVOID KeyValueInformation
,
588 IN PULONG ResultLength
)
593 HCELL_INDEX CellToRelease
= HCELL_NIL
, CellToRelease2
= HCELL_NIL
;
594 VALUE_SEARCH_RETURN_TYPE Result
;
595 BOOLEAN IndexIsCached
, ValueIsCached
= FALSE
;
597 PCM_CACHED_VALUE
*CachedValue
;
598 PCM_KEY_VALUE ValueData
;
601 /* Acquire hive lock */
602 KeEnterCriticalRegion();
603 ExAcquireResourceExclusiveLite(&CmpRegistryLock
, TRUE
);
605 /* Get the hive and parent */
607 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, Kcb
->KeyCell
);
611 Status
= STATUS_INSUFFICIENT_RESOURCES
;
615 /* Make sure the index is valid */
616 //if (Index >= Kcb->ValueCache.Count)
617 if (Index
>= Parent
->ValueList
.Count
)
619 /* Release the cell and fail */
620 HvReleaseCell(Hive
, Kcb
->KeyCell
);
621 Status
= STATUS_NO_MORE_ENTRIES
;
625 /* Find the value list */
626 Result
= CmpGetValueListFromCache(Kcb
,
630 if (Result
!= SearchSuccess
)
633 ASSERT(CellData
== NULL
);
635 /* Release the cell and fail */
636 Status
= STATUS_INSUFFICIENT_RESOURCES
;
640 /* Now get the key value */
641 Result
= CmpGetValueKeyFromCache(Kcb
,
649 if (Result
!= SearchSuccess
)
652 ASSERT(CellToRelease2
== HCELL_NIL
);
654 /* Release the cells and fail */
655 Status
= STATUS_INSUFFICIENT_RESOURCES
;
659 /* Query the information requested */
660 Result
= CmpQueryKeyValueData(Kcb
,
664 KeyValueInformationClass
,
671 /* If we have a cell to release, do so */
672 if (CellToRelease
!= HCELL_NIL
) HvReleaseCell(Hive
, CellToRelease
);
674 /* Release the parent cell */
675 HvReleaseCell(Hive
, Kcb
->KeyCell
);
677 /* If we have a cell to release, do so */
678 if (CellToRelease2
!= HCELL_NIL
) HvReleaseCell(Hive
, CellToRelease2
);
680 /* Release hive lock */
681 ExReleaseResourceLite(&CmpRegistryLock
);
682 KeLeaveCriticalRegion();
688 CmpQueryKeyData(IN PHHIVE Hive
,
689 IN PCM_KEY_NODE Node
,
690 IN KEY_INFORMATION_CLASS KeyInformationClass
,
691 IN OUT PVOID KeyInformation
,
693 IN OUT PULONG ResultLength
)
696 ULONG Size
, SizeLeft
, MinimumSize
;
697 PKEY_INFORMATION Info
= (PKEY_INFORMATION
)KeyInformation
;
700 /* Check if the value is compressed */
701 if (Node
->Flags
& KEY_COMP_NAME
)
703 /* Get the compressed name size */
704 NameLength
= CmpCompressedNameSize(Node
->Name
, Node
->NameLength
);
708 /* Get the real size */
709 NameLength
= Node
->NameLength
;
712 /* Check what kind of information is being requested */
713 switch (KeyInformationClass
)
715 /* Basic information */
716 case KeyBasicInformation
:
718 /* This is the size we need */
719 Size
= FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
) + NameLength
;
721 /* And this is the minimum we can work with */
722 MinimumSize
= FIELD_OFFSET(KEY_BASIC_INFORMATION
, Name
);
724 /* Let the caller know and assume success */
725 *ResultLength
= Size
;
726 Status
= STATUS_SUCCESS
;
728 /* Check if the bufer we got is too small */
729 if (Length
< MinimumSize
)
731 /* Let the caller know and fail */
732 Status
= STATUS_BUFFER_TOO_SMALL
;
736 /* Copy the basic information */
737 Info
->KeyBasicInformation
.LastWriteTime
= Node
->LastWriteTime
;
738 Info
->KeyBasicInformation
.TitleIndex
= 0;
739 Info
->KeyBasicInformation
.NameLength
= NameLength
;
741 /* Only the name is left */
742 SizeLeft
= Length
- MinimumSize
;
745 /* Check if we don't have enough space for the name */
748 /* Truncate the name we'll return, and tell the caller */
750 Status
= STATUS_BUFFER_OVERFLOW
;
753 /* Check if this is a compressed key */
754 if (Node
->Flags
& KEY_COMP_NAME
)
756 /* Copy the compressed name */
757 CmpCopyCompressedName(Info
->KeyBasicInformation
.Name
,
764 /* Otherwise, copy the raw name */
765 RtlCopyMemory(Info
->KeyBasicInformation
.Name
,
771 /* Node information */
772 case KeyNodeInformation
:
774 /* Calculate the size we need */
775 Size
= FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
) +
779 /* And the minimum size we can support */
780 MinimumSize
= FIELD_OFFSET(KEY_NODE_INFORMATION
, Name
);
782 /* Return the size to the caller and assume succes */
783 *ResultLength
= Size
;
784 Status
= STATUS_SUCCESS
;
786 /* Check if the caller's buffer is too small */
787 if (Length
< MinimumSize
)
789 /* Let them know, and fail */
790 Status
= STATUS_BUFFER_TOO_SMALL
;
794 /* Copy the basic information */
795 Info
->KeyNodeInformation
.LastWriteTime
= Node
->LastWriteTime
;
796 Info
->KeyNodeInformation
.TitleIndex
= 0;
797 Info
->KeyNodeInformation
.ClassLength
= Node
->ClassLength
;
798 Info
->KeyNodeInformation
.NameLength
= NameLength
;
800 /* Now the name is left */
801 SizeLeft
= Length
- MinimumSize
;
804 /* Check if the name can fit entirely */
807 /* It can't, we'll have to truncate. Tell the caller */
809 Status
= STATUS_BUFFER_OVERFLOW
;
812 /* Check if the key node name is compressed */
813 if (Node
->Flags
& KEY_COMP_NAME
)
815 /* Copy the compressed name */
816 CmpCopyCompressedName(Info
->KeyNodeInformation
.Name
,
823 /* It isn't, so copy the raw name */
824 RtlCopyMemory(Info
->KeyNodeInformation
.Name
,
829 /* Check if the node has a class */
830 if (Node
->ClassLength
> 0)
832 /* It does. We don't support these yet */
833 ASSERTMSG("Classes not supported\n", FALSE
);
837 /* It doesn't, so set offset to -1, not 0! */
838 Info
->KeyNodeInformation
.ClassOffset
= 0xFFFFFFFF;
842 /* Full information requsted */
843 case KeyFullInformation
:
845 /* This is the size we need */
846 Size
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
) +
849 /* This is what we can work with */
850 MinimumSize
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
);
852 /* Return it to caller and assume success */
853 *ResultLength
= Size
;
854 Status
= STATUS_SUCCESS
;
856 /* Check if the caller's buffer is to small */
857 if (Length
< MinimumSize
)
859 /* Let them know and fail */
860 Status
= STATUS_BUFFER_TOO_SMALL
;
864 /* Now copy all the basic information */
865 Info
->KeyFullInformation
.LastWriteTime
= Node
->LastWriteTime
;
866 Info
->KeyFullInformation
.TitleIndex
= 0;
867 Info
->KeyFullInformation
.ClassLength
= Node
->ClassLength
;
868 Info
->KeyFullInformation
.SubKeys
= Node
->SubKeyCounts
[Stable
] +
869 Node
->SubKeyCounts
[Volatile
];
870 Info
->KeyFullInformation
.Values
= Node
->ValueList
.Count
;
871 Info
->KeyFullInformation
.MaxNameLen
= Node
->MaxNameLen
;
872 Info
->KeyFullInformation
.MaxClassLen
= Node
->MaxClassLen
;
873 Info
->KeyFullInformation
.MaxValueNameLen
= Node
->MaxValueNameLen
;
874 Info
->KeyFullInformation
.MaxValueDataLen
= Node
->MaxValueDataLen
;
876 /* Check if we have a class */
877 if (Node
->ClassLength
> 0)
879 /* We do, but we currently don't support this */
880 ASSERTMSG("Classes not supported\n", FALSE
);
884 /* We don't have a class, so set offset to -1, not 0! */
885 Info
->KeyNodeInformation
.ClassOffset
= 0xFFFFFFFF;
889 /* Any other class that got sent here is invalid! */
892 /* Set failure code */
893 Status
= STATUS_INVALID_PARAMETER
;
903 CmQueryKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
904 IN KEY_INFORMATION_CLASS KeyInformationClass
,
905 IN PVOID KeyInformation
,
907 IN PULONG ResultLength
)
913 /* Acquire hive lock */
914 KeEnterCriticalRegion();
915 ExAcquireResourceExclusiveLite(&CmpRegistryLock
, TRUE
);
917 /* Get the hive and parent */
919 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, Kcb
->KeyCell
);
923 Status
= STATUS_INSUFFICIENT_RESOURCES
;
927 /* Check what class we got */
928 switch (KeyInformationClass
)
930 /* Typical information */
931 case KeyFullInformation
:
932 case KeyBasicInformation
:
933 case KeyNodeInformation
:
935 /* Call the internal API */
936 Status
= CmpQueryKeyData(Hive
,
944 /* Unsupported classes for now */
945 case KeyNameInformation
:
946 case KeyCachedInformation
:
947 case KeyFlagsInformation
:
949 /* Print message and fail */
950 DPRINT1("Unsupported class: %d!\n", KeyInformationClass
);
951 Status
= STATUS_NOT_IMPLEMENTED
;
954 /* Illegal classes */
957 /* Print message and fail */
958 DPRINT1("Unsupported class: %d!\n", KeyInformationClass
);
959 Status
= STATUS_INVALID_INFO_CLASS
;
964 /* Release hive lock */
965 ExReleaseResourceLite(&CmpRegistryLock
);
966 KeLeaveCriticalRegion();
972 CmEnumerateKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
974 IN KEY_INFORMATION_CLASS KeyInformationClass
,
975 IN PVOID KeyInformation
,
977 IN PULONG ResultLength
)
981 PCM_KEY_NODE Parent
, Child
;
982 HCELL_INDEX ChildCell
;
984 /* Acquire hive lock */
985 KeEnterCriticalRegion();
986 ExAcquireResourceExclusiveLite(&CmpRegistryLock
, TRUE
);
988 /* Get the hive and parent */
990 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, Kcb
->KeyCell
);
994 Status
= STATUS_INSUFFICIENT_RESOURCES
;
998 /* Get the child cell */
999 ChildCell
= CmpFindSubKeyByNumber(Hive
, Parent
, Index
);
1001 /* Release the parent cell */
1002 HvReleaseCell(Hive
, Kcb
->KeyCell
);
1004 /* Check if we found the child */
1005 if (ChildCell
== HCELL_NIL
)
1007 /* We didn't, fail */
1008 Status
= STATUS_NO_MORE_ENTRIES
;
1012 /* Now get the actual child node */
1013 Child
= (PCM_KEY_NODE
)HvGetCell(Hive
, ChildCell
);
1017 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1021 /* Query the data requested */
1022 Status
= CmpQueryKeyData(Hive
,
1024 KeyInformationClass
,
1030 /* Release hive lock */
1031 ExReleaseResourceLite(&CmpRegistryLock
);
1032 KeLeaveCriticalRegion();
1038 CmDeleteKey(IN PCM_KEY_CONTROL_BLOCK Kcb
)
1042 PCM_KEY_NODE Node
, Parent
;
1043 HCELL_INDEX Cell
, ParentCell
;
1045 /* Acquire hive lock */
1046 KeEnterCriticalRegion();
1047 ExAcquireResourceExclusiveLite(&CmpRegistryLock
, TRUE
);
1049 /* Get the hive and node */
1050 Hive
= Kcb
->KeyHive
;
1051 Cell
= Kcb
->KeyCell
;
1053 /* Get the key node */
1054 Node
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
1058 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1062 /* Check if we have no parent */
1065 /* This is an attempt to delete \Registry itself! */
1066 Status
= STATUS_CANNOT_DELETE
;
1070 /* Check if we're already being deleted */
1073 /* Don't do it twice */
1074 Status
= STATUS_SUCCESS
;
1079 ASSERT(Node
->Flags
== Kcb
->Flags
);
1081 /* Check if we don't have any children */
1082 if (!(Node
->SubKeyCounts
[Stable
] + Node
->SubKeyCounts
[Volatile
]))
1084 /* Get the parent and free the cell */
1085 ParentCell
= Node
->Parent
;
1086 Status
= CmpFreeKeyByCell(Hive
, Cell
, TRUE
);
1087 if (NT_SUCCESS(Status
))
1089 /* Get the parent node */
1090 Parent
= (PCM_KEY_NODE
)HvGetCell(Hive
, ParentCell
);
1093 /* Update the maximum name length */
1094 Kcb
->ParentKcb
->KcbMaxNameLen
= Parent
->MaxNameLen
;
1096 /* Make sure we're dirty */
1097 ASSERT(HvIsCellDirty(Hive
, ParentCell
));
1099 /* Update the write time */
1100 KeQuerySystemTime(&Parent
->LastWriteTime
);
1101 KeQuerySystemTime(&Kcb
->ParentKcb
->KcbLastWriteTime
);
1103 /* Release the cell */
1104 HvReleaseCell(Hive
, ParentCell
);
1107 /* Set the KCB in delete mode and remove it */
1109 CmpRemoveKeyControlBlock(Kcb
);
1111 /* Clear the cell */
1112 Kcb
->KeyCell
= HCELL_NIL
;
1118 Status
= STATUS_CANNOT_DELETE
;
1121 /* Flush the registry */
1125 /* Release the cell */
1126 HvReleaseCell(Hive
, Cell
);
1128 /* Release hive lock */
1129 ExReleaseResourceLite(&CmpRegistryLock
);
1130 KeLeaveCriticalRegion();
1136 CmFlushKey(IN PCM_KEY_CONTROL_BLOCK Kcb
,
1137 IN BOOLEAN ExclusiveLock
)
1140 NTSTATUS Status
= STATUS_SUCCESS
;
1144 Hive
= Kcb
->KeyHive
;
1145 CmHive
= (PCMHIVE
)Hive
;
1147 /* Check if this is the master hive */
1148 if (CmHive
== CmiVolatileHive
)
1150 /* Flush all the hives instead */
1151 CmpDoFlushAll(FALSE
);
1155 /* Flush only this hive */
1156 if (!HvSyncHive(Hive
))
1159 Status
= STATUS_REGISTRY_IO_FAILED
;
1163 /* Return the status */
1169 CmLoadKey(IN POBJECT_ATTRIBUTES TargetKey
,
1170 IN POBJECT_ATTRIBUTES SourceFile
,
1172 IN PCM_KEY_BODY KeyBody
)
1174 SECURITY_QUALITY_OF_SERVICE ServiceQos
;
1175 SECURITY_CLIENT_CONTEXT ClientSecurityContext
;
1177 BOOLEAN Allocate
= TRUE
;
1181 /* Check if we have a trust key */
1185 DPRINT1("Trusted classes not yet supported\n");
1186 return STATUS_NOT_IMPLEMENTED
;
1189 /* Build a service QoS for a security context */
1190 ServiceQos
.Length
= sizeof(SECURITY_QUALITY_OF_SERVICE
);
1191 ServiceQos
.ImpersonationLevel
= SecurityImpersonation
;
1192 ServiceQos
.ContextTrackingMode
= SECURITY_DYNAMIC_TRACKING
;
1193 ServiceQos
.EffectiveOnly
= TRUE
;
1194 Status
= SeCreateClientSecurity(PsGetCurrentThread(),
1197 &ClientSecurityContext
);
1198 if (!NT_SUCCESS(Status
))
1201 DPRINT1("Security context failed\n");
1205 /* Open the target key */
1206 Status
= ZwOpenKey(&KeyHandle
, KEY_READ
, TargetKey
);
1207 if (!NT_SUCCESS(Status
)) KeyHandle
= NULL
;
1210 Status
= CmpCmdHiveOpen(SourceFile
,
1211 &ClientSecurityContext
,
1216 /* Get rid of the security context */
1217 SeDeleteClientSecurity(&ClientSecurityContext
);
1219 /* See if we failed */
1220 if (!NT_SUCCESS(Status
))
1222 /* See if the target already existed */
1225 /* Lock the registry */
1226 CmpLockRegistryExclusive();
1228 /* FIXME: Check if we are already loaded */
1230 /* Release the registry */
1231 CmpUnlockRegistry();
1234 /* Close the key handle if we had one */
1235 if (KeyHandle
) ZwClose(KeyHandle
);
1236 DPRINT1("Failed: %lx\n", Status
);
1240 /* Lock the registry shared */
1241 //CmpLockRegistry();
1243 /* Lock the hive to this thread */
1244 CmHive
->Hive
.HiveFlags
|= HIVE_IS_UNLOADING
;
1245 CmHive
->CreatorOwner
= KeGetCurrentThread();
1248 if (Flags
& REG_NO_LAZY_FLUSH
) CmHive
->Hive
.HiveFlags
|= HIVE_NOLAZYFLUSH
;
1251 Status
= CmpLinkHiveToMaster(TargetKey
->ObjectName
,
1252 TargetKey
->RootDirectory
,
1255 TargetKey
->SecurityDescriptor
);
1256 if (NT_SUCCESS(Status
))
1258 /* FIXME: Add to HiveList key */
1260 /* Sync the hive if necessary */
1264 HvSyncHive(&CmHive
->Hive
);
1267 /* Release the hive */
1268 CmHive
->Hive
.HiveFlags
&= ~HIVE_IS_UNLOADING
;
1269 CmHive
->CreatorOwner
= NULL
;
1277 /* Unlock the registry */
1278 //CmpUnlockRegistry();
1280 /* Close handle and return */
1281 if (KeyHandle
) ZwClose(KeyHandle
);