2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/config/cmparse.c
5 * PURPOSE: Configuration Manager - Object Manager Parse Interface
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
15 /* GLOBALS *******************************************************************/
17 /* FUNCTIONS *****************************************************************/
21 CmpGetNextName(IN OUT PUNICODE_STRING RemainingName
,
22 OUT PUNICODE_STRING NextName
,
23 OUT PBOOLEAN LastName
)
25 BOOLEAN NameValid
= TRUE
;
27 ASSERT(RemainingName
->Length
% sizeof(WCHAR
) == 0);
29 /* Check if there's nothing left in the name */
30 if (!(RemainingName
->Buffer
) ||
31 (!RemainingName
->Length
) ||
32 !(*RemainingName
->Buffer
))
34 /* Clear the next name and set this as last */
36 NextName
->Buffer
= NULL
;
41 /* Check if we have a path separator */
42 while ((RemainingName
->Length
) &&
43 (*RemainingName
->Buffer
== OBJ_NAME_PATH_SEPARATOR
))
46 RemainingName
->Buffer
++;
47 RemainingName
->Length
-= sizeof(WCHAR
);
48 RemainingName
->MaximumLength
-= sizeof(WCHAR
);
51 /* Start loop at where the current buffer is */
52 NextName
->Buffer
= RemainingName
->Buffer
;
53 while ((RemainingName
->Length
) &&
54 (*RemainingName
->Buffer
!= OBJ_NAME_PATH_SEPARATOR
))
56 /* Move to the next character */
57 RemainingName
->Buffer
++;
58 RemainingName
->Length
-= sizeof(WCHAR
);
59 RemainingName
->MaximumLength
-= sizeof(WCHAR
);
62 /* See how many chars we parsed and validate the length */
63 NextName
->Length
= (USHORT
)((ULONG_PTR
)RemainingName
->Buffer
-
64 (ULONG_PTR
)NextName
->Buffer
);
65 if (NextName
->Length
> 512) NameValid
= FALSE
;
66 NextName
->MaximumLength
= NextName
->Length
;
68 /* If there's nothing left, we're last */
69 *LastName
= !RemainingName
->Length
;
75 CmpGetSymbolicLink(IN PHHIVE Hive
,
76 IN OUT PUNICODE_STRING ObjectName
,
77 IN OUT PCM_KEY_CONTROL_BLOCK SymbolicKcb
,
78 IN PUNICODE_STRING RemainingName OPTIONAL
)
80 HCELL_INDEX LinkCell
= HCELL_NIL
;
81 PCM_KEY_VALUE LinkValue
= NULL
;
82 PWSTR LinkName
= NULL
;
83 BOOLEAN LinkNameAllocated
= FALSE
;
86 ULONG ValueLength
= 0;
87 BOOLEAN Result
= FALSE
;
88 HCELL_INDEX CellToRelease
= HCELL_NIL
;
90 UNICODE_STRING NewObjectName
;
92 /* Make sure we're not being deleted */
93 if (SymbolicKcb
->Delete
) return FALSE
;
95 /* Get the key node */
96 Node
= (PCM_KEY_NODE
)HvGetCell(SymbolicKcb
->KeyHive
, SymbolicKcb
->KeyCell
);
99 /* Find the symbolic link key */
100 LinkCell
= CmpFindValueByName(Hive
, Node
, &CmSymbolicLinkValueName
);
101 HvReleaseCell(SymbolicKcb
->KeyHive
, SymbolicKcb
->KeyCell
);
102 if (LinkCell
== HCELL_NIL
) goto Exit
;
104 /* Get the value cell */
105 LinkValue
= (PCM_KEY_VALUE
)HvGetCell(Hive
, LinkCell
);
106 if (!LinkValue
) goto Exit
;
108 /* Make sure it's a registry link */
109 if (LinkValue
->Type
!= REG_LINK
) goto Exit
;
111 /* Now read the value data */
112 if (!CmpGetValueData(Hive
,
124 Length
= ValueLength
+ sizeof(WCHAR
);
126 /* Make sure we start with a slash */
127 if (*LinkName
!= OBJ_NAME_PATH_SEPARATOR
) goto Exit
;
129 /* Add the remaining name if needed */
130 if (RemainingName
) Length
+= RemainingName
->Length
+ sizeof(WCHAR
);
132 /* Check for overflow */
133 if (Length
> 0xFFFF) goto Exit
;
135 /* Check if we need a new buffer */
136 if (Length
> ObjectName
->MaximumLength
)
138 /* We do -- allocate one */
139 NewBuffer
= ExAllocatePoolWithTag(PagedPool
, Length
, TAG_CM
);
140 if (!NewBuffer
) goto Exit
;
142 /* Setup the new string and copy the symbolic target */
143 NewObjectName
.Buffer
= NewBuffer
;
144 NewObjectName
.MaximumLength
= (USHORT
)Length
;
145 NewObjectName
.Length
= (USHORT
)ValueLength
;
146 RtlCopyMemory(NewBuffer
, LinkName
, ValueLength
);
148 /* Check if we need to add anything else */
151 /* Add the remaining name */
152 NewBuffer
[ValueLength
/ sizeof(WCHAR
)] = OBJ_NAME_PATH_SEPARATOR
;
153 NewObjectName
.Length
+= sizeof(WCHAR
);
154 RtlAppendUnicodeStringToString(&NewObjectName
, RemainingName
);
157 /* Free the old buffer */
158 ExFreePool(ObjectName
->Buffer
);
159 *ObjectName
= NewObjectName
;
163 /* The old name is large enough -- update the length */
164 ObjectName
->Length
= (USHORT
)ValueLength
;
167 /* Copy the remaining name inside */
168 RtlMoveMemory(&ObjectName
->Buffer
[(ValueLength
/ sizeof(WCHAR
)) + 1],
169 RemainingName
->Buffer
,
170 RemainingName
->Length
);
172 /* Add the slash and update the length */
173 ObjectName
->Buffer
[ValueLength
/ sizeof(WCHAR
)] = OBJ_NAME_PATH_SEPARATOR
;
174 ObjectName
->Length
+= RemainingName
->Length
+ sizeof(WCHAR
);
177 /* Copy the symbolic link target name */
178 RtlCopyMemory(ObjectName
->Buffer
, LinkName
, ValueLength
);
181 /* Null-terminate the whole thing */
182 ObjectName
->Buffer
[ObjectName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
186 /* Free the link name */
187 if (LinkNameAllocated
) ExFreePool(LinkName
);
189 /* Check if we had a value cell */
193 ASSERT(LinkCell
!= HCELL_NIL
);
194 HvReleaseCell(Hive
, LinkCell
);
197 /* Check if we had an active cell and release it, then return the result */
198 if (CellToRelease
!= HCELL_NIL
) HvReleaseCell(Hive
, CellToRelease
);
204 CmpDoCreateChild(IN PHHIVE Hive
,
205 IN HCELL_INDEX ParentCell
,
206 IN PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL
,
207 IN PACCESS_STATE AccessState
,
208 IN PUNICODE_STRING Name
,
209 IN KPROCESSOR_MODE AccessMode
,
210 IN PCM_PARSE_CONTEXT ParseContext
,
211 IN PCM_KEY_CONTROL_BLOCK ParentKcb
,
213 OUT PHCELL_INDEX KeyCell
,
216 NTSTATUS Status
= STATUS_SUCCESS
;
217 PCM_KEY_BODY KeyBody
;
218 HCELL_INDEX ClassCell
= HCELL_NIL
;
219 PCM_KEY_NODE KeyNode
;
222 PCM_KEY_CONTROL_BLOCK Kcb
;
223 PSECURITY_DESCRIPTOR NewDescriptor
;
225 /* Get the storage type */
226 StorageType
= Stable
;
227 if (ParseContext
->CreateOptions
& REG_OPTION_VOLATILE
) StorageType
= Volatile
;
229 /* Allocate the child */
230 *KeyCell
= HvAllocateCell(Hive
,
231 FIELD_OFFSET(CM_KEY_NODE
, Name
) +
232 CmpNameSize(Hive
, Name
),
235 if (*KeyCell
== HCELL_NIL
)
238 Status
= STATUS_INSUFFICIENT_RESOURCES
;
242 /* Get the key node */
243 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, *KeyCell
);
246 /* Fail, this should never happen */
248 Status
= STATUS_INSUFFICIENT_RESOURCES
;
252 /* Release the cell */
253 HvReleaseCell(Hive
, *KeyCell
);
255 /* Check if we have a class name */
256 if (ParseContext
->Class
.Length
> 0)
258 /* Allocate a class cell */
259 ClassCell
= HvAllocateCell(Hive
,
260 ParseContext
->Class
.Length
,
263 if (ClassCell
== HCELL_NIL
)
266 Status
= STATUS_INSUFFICIENT_RESOURCES
;
271 /* Allocate the Cm Object */
272 Status
= ObCreateObject(AccessMode
,
281 if (!NT_SUCCESS(Status
)) goto Quickie
;
283 /* Setup the key body */
284 KeyBody
= (PCM_KEY_BODY
)(*Object
);
285 KeyBody
->Type
= CM_KEY_BODY_TYPE
;
286 KeyBody
->KeyControlBlock
= NULL
;
288 /* Check if we had a class */
289 if (ParseContext
->Class
.Length
> 0)
291 /* Get the class cell */
292 CellData
= HvGetCell(Hive
, ClassCell
);
295 /* Fail, this should never happen */
297 Status
= STATUS_INSUFFICIENT_RESOURCES
;
298 ObDereferenceObject(*Object
);
302 /* Release the cell */
303 HvReleaseCell(Hive
, ClassCell
);
305 /* Copy the class data */
306 RtlCopyMemory(&CellData
->u
.KeyString
[0],
307 ParseContext
->Class
.Buffer
,
308 ParseContext
->Class
.Length
);
311 /* Fill out the key node */
312 KeyNode
->Signature
= CM_KEY_NODE_SIGNATURE
;
313 KeyNode
->Flags
= Flags
;
314 KeQuerySystemTime(&KeyNode
->LastWriteTime
);
316 KeyNode
->Parent
= ParentCell
;
317 KeyNode
->SubKeyCounts
[Stable
] = 0;
318 KeyNode
->SubKeyCounts
[Volatile
] = 0;
319 KeyNode
->SubKeyLists
[Stable
] = HCELL_NIL
;
320 KeyNode
->SubKeyLists
[Volatile
] = HCELL_NIL
;
321 KeyNode
->ValueList
.Count
= 0;
322 KeyNode
->ValueList
.List
= HCELL_NIL
;
323 KeyNode
->Security
= HCELL_NIL
;
324 KeyNode
->Class
= ClassCell
;
325 KeyNode
->ClassLength
= ParseContext
->Class
.Length
;
326 KeyNode
->MaxValueDataLen
= 0;
327 KeyNode
->MaxNameLen
= 0;
328 KeyNode
->MaxValueNameLen
= 0;
329 KeyNode
->MaxClassLen
= 0;
330 KeyNode
->NameLength
= CmpCopyName(Hive
, KeyNode
->Name
, Name
);
331 if (KeyNode
->NameLength
< Name
->Length
) KeyNode
->Flags
|= KEY_COMP_NAME
;
334 Kcb
= CmpCreateKeyControlBlock(Hive
,
338 0, // CMP_LOCK_HASHES_FOR_KCB,
343 ObDereferenceObjectDeferDelete(*Object
);
344 Status
= STATUS_INSUFFICIENT_RESOURCES
;
349 ASSERT(Kcb
->RefCount
== 1);
351 /* Now fill out the Cm object */
352 KeyBody
->NotifyBlock
= NULL
;
353 KeyBody
->ProcessID
= PsGetCurrentProcessId();
354 KeyBody
->KeyControlBlock
= Kcb
;
356 /* Link it with the KCB */
357 EnlistKeyBodyWithKCB(KeyBody
, 0);
359 /* Assign security */
360 Status
= SeAssignSecurity(ParentDescriptor
,
361 AccessState
->SecurityDescriptor
,
364 &AccessState
->SubjectSecurityContext
,
365 &CmpKeyObjectType
->TypeInfo
.GenericMapping
,
366 CmpKeyObjectType
->TypeInfo
.PoolType
);
367 if (NT_SUCCESS(Status
))
369 Status
= CmpSecurityMethod(*Object
,
370 AssignSecurityDescriptor
,
375 CmpKeyObjectType
->TypeInfo
.PoolType
,
376 &CmpKeyObjectType
->TypeInfo
.GenericMapping
);
379 /* Now that the security descriptor is copied in the hive, we can free the original */
380 SeDeassignSecurity(&NewDescriptor
);
383 /* Check if we got here because of failure */
384 if (!NT_SUCCESS(Status
))
386 /* Free any cells we might've allocated */
387 if (ParseContext
->Class
.Length
> 0) HvFreeCell(Hive
, ClassCell
);
388 HvFreeCell(Hive
, *KeyCell
);
397 CmpDoCreate(IN PHHIVE Hive
,
399 IN PACCESS_STATE AccessState
,
400 IN PUNICODE_STRING Name
,
401 IN KPROCESSOR_MODE AccessMode
,
402 IN PCM_PARSE_CONTEXT ParseContext
,
403 IN PCM_KEY_CONTROL_BLOCK ParentKcb
,
410 PCM_KEY_BODY KeyBody
;
411 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
412 LARGE_INTEGER TimeStamp
;
413 PCM_KEY_NODE KeyNode
;
415 /* Check if the parent is being deleted */
416 if (ParentKcb
->Delete
)
420 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
424 /* Get the parent node */
425 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
430 Status
= STATUS_INSUFFICIENT_RESOURCES
;
434 /* Make sure nobody added us yet */
435 if (CmpFindSubKeyByName(Hive
, KeyNode
, Name
) != HCELL_NIL
)
439 Status
= STATUS_REPARSE
;
444 ASSERT(Cell
== ParentKcb
->KeyCell
);
446 /* Get the parent type */
447 ParentType
= HvGetCellType(Cell
);
448 if ((ParentType
== Volatile
) &&
449 !(ParseContext
->CreateOptions
& REG_OPTION_VOLATILE
))
451 /* Children of volatile parents must also be volatile */
453 Status
= STATUS_CHILD_MUST_BE_VOLATILE
;
457 /* Don't allow children under symlinks */
458 if (ParentKcb
->Flags
& KEY_SYM_LINK
)
462 Status
= STATUS_ACCESS_DENIED
;
466 /* Make the cell dirty for now */
467 HvMarkCellDirty(Hive
, Cell
, FALSE
);
469 /* Do the actual create operation */
470 Status
= CmpDoCreateChild(Hive
,
481 if (NT_SUCCESS(Status
))
483 /* Get the key body */
484 KeyBody
= (PCM_KEY_BODY
)(*Object
);
486 /* Now add the subkey */
487 if (!CmpAddSubKey(Hive
, Cell
, KeyCell
))
489 /* Failure! We don't handle this yet! */
493 /* Get the key node */
494 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
497 /* Fail, this shouldn't happen */
502 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
->KeyCell
== Cell
);
503 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
->KeyHive
== Hive
);
504 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
== ParentKcb
);
505 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
->KcbMaxNameLen
== KeyNode
->MaxNameLen
);
507 /* Update the timestamp */
508 KeQuerySystemTime(&TimeStamp
);
509 KeyNode
->LastWriteTime
= TimeStamp
;
510 KeyBody
->KeyControlBlock
->ParentKcb
->KcbLastWriteTime
= TimeStamp
;
512 /* Check if we need to update name maximum */
513 if (KeyNode
->MaxNameLen
< Name
->Length
)
516 KeyNode
->MaxNameLen
= Name
->Length
;
517 KeyBody
->KeyControlBlock
->ParentKcb
->KcbMaxNameLen
= Name
->Length
;
520 /* Check if we need to update class length maximum */
521 if (KeyNode
->MaxClassLen
< ParseContext
->Class
.Length
)
524 KeyNode
->MaxClassLen
= ParseContext
->Class
.Length
;
527 /* Check if we're creating a symbolic link */
528 if (ParseContext
->CreateOptions
& REG_OPTION_CREATE_LINK
)
530 /* Get the cell data */
531 CellData
= HvGetCell(Hive
, KeyCell
);
534 /* This shouldn't happen */
538 /* Update the flags */
539 CellData
->u
.KeyNode
.Flags
|= KEY_SYM_LINK
;
540 KeyBody
->KeyControlBlock
->Flags
= CellData
->u
.KeyNode
.Flags
;
541 HvReleaseCell(Hive
, KeyCell
);
546 /* Release the flusher lock and return status */
552 CmpDoOpen(IN PHHIVE Hive
,
554 IN PCM_KEY_NODE Node
,
555 IN PACCESS_STATE AccessState
,
556 IN KPROCESSOR_MODE AccessMode
,
558 IN PCM_PARSE_CONTEXT Context OPTIONAL
,
559 IN ULONG ControlFlags
,
560 IN OUT PCM_KEY_CONTROL_BLOCK
*CachedKcb
,
561 IN PUNICODE_STRING KeyName
,
565 PCM_KEY_BODY KeyBody
= NULL
;
566 PCM_KEY_CONTROL_BLOCK Kcb
= NULL
;
568 /* Make sure the hive isn't locked */
569 if ((Hive
->HiveFlags
& HIVE_IS_UNLOADING
) &&
570 (((PCMHIVE
)Hive
)->CreatorOwner
!= KeGetCurrentThread()))
572 /* It is, don't touch it */
573 return STATUS_OBJECT_NAME_NOT_FOUND
;
576 /* Check if we have a context */
579 /* Check if this is a link create (which shouldn't be an open) */
580 if (Context
->CreateLink
)
582 return STATUS_ACCESS_DENIED
;
585 /* Check if this is symlink create attempt */
586 if (Context
->CreateOptions
& REG_OPTION_CREATE_LINK
)
588 /* Key already exists */
589 return STATUS_OBJECT_NAME_COLLISION
;
592 /* Set the disposition */
593 Context
->Disposition
= REG_OPENED_EXISTING_KEY
;
596 /* Do this in the registry lock */
599 /* If we have a KCB, make sure it's locked */
600 //ASSERT(CmpIsKcbLockedExclusive(*CachedKcb));
602 /* Check if caller doesn't want to create a KCB */
603 if (ControlFlags
& CMP_OPEN_KCB_NO_CREATE
)
605 /* Check if this is a symlink */
606 if ((Node
->Flags
& KEY_SYM_LINK
) && !(Attributes
& OBJ_OPENLINK
))
608 /* This case for a cached KCB is not implemented yet */
612 /* The caller wants to open a cached KCB */
613 if (!CmpReferenceKeyControlBlock(*CachedKcb
))
615 /* Release the registry lock */
618 /* Return failure code */
619 return STATUS_INSUFFICIENT_RESOURCES
;
622 /* Our kcb is that one */
627 /* Check if this is a symlink */
628 if ((Node
->Flags
& KEY_SYM_LINK
) && !(Attributes
& OBJ_OPENLINK
))
630 /* Create the KCB for the symlink */
631 Kcb
= CmpCreateKeyControlBlock(Hive
,
639 /* Release registry lock and return failure */
641 return STATUS_INSUFFICIENT_RESOURCES
;
644 /* Make sure it's also locked, and set the pointer */
645 //ASSERT(CmpIsKcbLockedExclusive(Kcb));
648 /* Release the registry lock */
651 /* Return reparse required */
652 return STATUS_REPARSE
;
655 /* Create the KCB. FIXME: Use lock flag */
656 Kcb
= CmpCreateKeyControlBlock(Hive
,
664 /* Release registry lock and return failure */
666 return STATUS_INSUFFICIENT_RESOURCES
;
670 /* Make sure it's also locked, and set the pointer */
671 //ASSERT(CmpIsKcbLockedExclusive(Kcb));
674 /* Release the registry lock */
677 /* Allocate the key object */
678 Status
= ObCreateObject(AccessMode
,
687 if (NT_SUCCESS(Status
))
689 /* Get the key body and fill it out */
690 KeyBody
= (PCM_KEY_BODY
)(*Object
);
691 KeyBody
->KeyControlBlock
= Kcb
;
692 KeyBody
->Type
= CM_KEY_BODY_TYPE
;
693 KeyBody
->ProcessID
= PsGetCurrentProcessId();
694 KeyBody
->NotifyBlock
= NULL
;
696 /* Link to the KCB */
697 EnlistKeyBodyWithKCB(KeyBody
, 0);
699 if (!ObCheckObjectAccess(*Object
,
705 /* Access check failed */
706 ObDereferenceObject(*Object
);
711 /* Failed, dereference the KCB */
712 CmpDereferenceKeyControlBlockWithLock(Kcb
, FALSE
);
721 CmpCreateLinkNode(IN PHHIVE Hive
,
723 IN PACCESS_STATE AccessState
,
724 IN UNICODE_STRING Name
,
725 IN KPROCESSOR_MODE AccessMode
,
726 IN ULONG CreateOptions
,
727 IN PCM_PARSE_CONTEXT Context
,
728 IN PCM_KEY_CONTROL_BLOCK ParentKcb
,
732 HCELL_INDEX KeyCell
, LinkCell
, ChildCell
;
733 PCM_KEY_BODY KeyBody
;
734 LARGE_INTEGER TimeStamp
;
735 PCM_KEY_NODE KeyNode
;
736 PCM_KEY_CONTROL_BLOCK Kcb
= ParentKcb
;
738 /* Link nodes only allowed on the master */
739 if (Hive
!= &CmiVolatileHive
->Hive
)
742 DPRINT1("Invalid link node attempt\n");
743 return STATUS_ACCESS_DENIED
;
746 /* Check if the parent is being deleted */
747 if (ParentKcb
->Delete
)
751 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
755 /* Allocate a link node */
756 LinkCell
= HvAllocateCell(Hive
,
757 FIELD_OFFSET(CM_KEY_NODE
, Name
) +
758 CmpNameSize(Hive
, &Name
),
761 if (LinkCell
== HCELL_NIL
)
764 Status
= STATUS_INSUFFICIENT_RESOURCES
;
768 /* Get the key cell */
769 KeyCell
= Context
->ChildHive
.KeyCell
;
770 if (KeyCell
!= HCELL_NIL
)
775 /* Get the node data */
776 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Context
->ChildHive
.KeyHive
, ChildCell
);
781 Status
= STATUS_INSUFFICIENT_RESOURCES
;
785 /* Fill out the data */
786 KeyNode
->Parent
= LinkCell
;
787 KeyNode
->Flags
|= KEY_HIVE_ENTRY
| KEY_NO_DELETE
;
788 HvReleaseCell(Context
->ChildHive
.KeyHive
, ChildCell
);
790 /* Now open the key cell */
791 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Context
->ChildHive
.KeyHive
, KeyCell
);
796 Status
= STATUS_INSUFFICIENT_RESOURCES
;
800 /* Open the parent */
801 Status
= CmpDoOpen(Context
->ChildHive
.KeyHive
,
812 HvReleaseCell(Context
->ChildHive
.KeyHive
, KeyCell
);
816 /* Do the actual create operation */
817 Status
= CmpDoCreateChild(Context
->ChildHive
.KeyHive
,
825 KEY_HIVE_ENTRY
| KEY_NO_DELETE
,
828 if (NT_SUCCESS(Status
))
830 /* Setup root pointer */
831 Context
->ChildHive
.KeyHive
->BaseBlock
->RootCell
= ChildCell
;
835 /* Check if open or create suceeded */
836 if (NT_SUCCESS(Status
))
838 /* Mark the cell dirty */
839 HvMarkCellDirty(Context
->ChildHive
.KeyHive
, ChildCell
, FALSE
);
841 /* Get the key node */
842 KeyNode
= HvGetCell(Context
->ChildHive
.KeyHive
, ChildCell
);
847 Status
= STATUS_INSUFFICIENT_RESOURCES
;
852 HvReleaseCell(Context
->ChildHive
.KeyHive
, ChildCell
);
854 /* Set the parent and flags */
855 KeyNode
->Parent
= LinkCell
;
856 KeyNode
->Flags
|= KEY_HIVE_ENTRY
| KEY_NO_DELETE
;
858 /* Get the link node */
859 KeyNode
= HvGetCell(Hive
, LinkCell
);
864 Status
= STATUS_INSUFFICIENT_RESOURCES
;
869 KeyNode
->Signature
= CM_LINK_NODE_SIGNATURE
;
870 KeyNode
->Flags
= KEY_HIVE_EXIT
| KEY_NO_DELETE
;
871 KeyNode
->Parent
= Cell
;
872 KeyNode
->NameLength
= CmpCopyName(Hive
, KeyNode
->Name
, &Name
);
873 if (KeyNode
->NameLength
< Name
.Length
) KeyNode
->Flags
|= KEY_COMP_NAME
;
874 KeQuerySystemTime(&TimeStamp
);
875 KeyNode
->LastWriteTime
= TimeStamp
;
877 /* Clear out the rest */
878 KeyNode
->SubKeyCounts
[Stable
] = 0;
879 KeyNode
->SubKeyCounts
[Volatile
] = 0;
880 KeyNode
->SubKeyLists
[Stable
] = HCELL_NIL
;
881 KeyNode
->SubKeyLists
[Volatile
] = HCELL_NIL
;
882 KeyNode
->ValueList
.Count
= 0;
883 KeyNode
->ValueList
.List
= HCELL_NIL
;
884 KeyNode
->ClassLength
= 0;
886 /* Reference the root node */
887 KeyNode
->ChildHiveReference
.KeyHive
= Context
->ChildHive
.KeyHive
;
888 KeyNode
->ChildHiveReference
.KeyCell
= ChildCell
;
889 HvReleaseCell(Hive
, LinkCell
);
891 /* Get the parent node */
892 KeyNode
= HvGetCell(Hive
, Cell
);
897 Status
= STATUS_INSUFFICIENT_RESOURCES
;
901 /* Now add the subkey */
902 if (!CmpAddSubKey(Hive
, Cell
, LinkCell
))
904 /* Failure! We don't handle this yet! */
908 /* Get the key body */
909 KeyBody
= (PCM_KEY_BODY
)*Object
;
912 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
->KeyCell
== Cell
);
913 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
->KeyHive
== Hive
);
914 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
->KcbMaxNameLen
== KeyNode
->MaxNameLen
);
916 /* Update the timestamp */
917 KeQuerySystemTime(&TimeStamp
);
918 KeyNode
->LastWriteTime
= TimeStamp
;
919 KeyBody
->KeyControlBlock
->ParentKcb
->KcbLastWriteTime
= TimeStamp
;
921 /* Check if we need to update name maximum */
922 if (KeyNode
->MaxNameLen
< Name
.Length
)
925 KeyNode
->MaxNameLen
= Name
.Length
;
926 KeyBody
->KeyControlBlock
->ParentKcb
->KcbMaxNameLen
= Name
.Length
;
929 /* Check if we need to update class length maximum */
930 if (KeyNode
->MaxClassLen
< Context
->Class
.Length
)
933 KeyNode
->MaxClassLen
= Context
->Class
.Length
;
936 /* Release the cell */
937 HvReleaseCell(Hive
, Cell
);
941 /* Release the link cell */
942 HvReleaseCell(Hive
, LinkCell
);
946 /* Release the flusher locks and return status */
952 CmpHandleExitNode(IN OUT PHHIVE
*Hive
,
953 IN OUT HCELL_INDEX
*Cell
,
954 IN OUT PCM_KEY_NODE
*KeyNode
,
955 IN OUT PHHIVE
*ReleaseHive
,
956 IN OUT HCELL_INDEX
*ReleaseCell
)
958 /* Check if we have anything to release */
959 if (*ReleaseCell
!= HCELL_NIL
)
962 ASSERT(*ReleaseHive
!= NULL
);
963 HvReleaseCell((*ReleaseHive
), *ReleaseCell
);
966 /* Get the link references */
967 *Hive
= (*KeyNode
)->ChildHiveReference
.KeyHive
;
968 *Cell
= (*KeyNode
)->ChildHiveReference
.KeyCell
;
970 /* Get the new node */
971 *KeyNode
= (PCM_KEY_NODE
)HvGetCell((*Hive
), *Cell
);
974 /* Set the new release values */
975 *ReleaseCell
= *Cell
;
976 *ReleaseHive
= *Hive
;
980 /* Nothing to release */
981 *ReleaseCell
= HCELL_NIL
;
988 CmpBuildHashStackAndLookupCache(IN PCM_KEY_BODY ParseObject
,
989 IN OUT PCM_KEY_CONTROL_BLOCK
*Kcb
,
990 IN PUNICODE_STRING Current
,
992 OUT HCELL_INDEX
*Cell
,
993 OUT PULONG TotalRemainingSubkeys
,
994 OUT PULONG MatchRemainSubkeyLevel
,
995 OUT PULONG TotalSubkeys
,
996 OUT PULONG OuterStackArray
,
997 OUT PULONG
*LockedKcbs
)
999 /* We don't lock anything for now */
1002 /* Calculate hash values */
1003 *TotalRemainingSubkeys
= 0xBAADF00D;
1005 /* Lock the registry */
1008 /* Return hive and cell data */
1009 *Hive
= (*Kcb
)->KeyHive
;
1010 *Cell
= (*Kcb
)->KeyCell
;
1012 /* Make sure it's not a dead KCB */
1013 ASSERT((*Kcb
)->RefCount
> 0);
1016 (VOID
)CmpReferenceKeyControlBlock(*Kcb
);
1018 /* Return success for now */
1019 return STATUS_SUCCESS
;
1024 CmpParseKey(IN PVOID ParseObject
,
1025 IN PVOID ObjectType
,
1026 IN OUT PACCESS_STATE AccessState
,
1027 IN KPROCESSOR_MODE AccessMode
,
1028 IN ULONG Attributes
,
1029 IN OUT PUNICODE_STRING CompleteName
,
1030 IN OUT PUNICODE_STRING RemainingName
,
1031 IN OUT PVOID Context OPTIONAL
,
1032 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
1036 PCM_KEY_CONTROL_BLOCK Kcb
, ParentKcb
;
1038 PCM_KEY_NODE Node
= NULL
;
1039 HCELL_INDEX Cell
= HCELL_NIL
, NextCell
;
1040 PHHIVE HiveToRelease
= NULL
;
1041 HCELL_INDEX CellToRelease
= HCELL_NIL
;
1042 UNICODE_STRING Current
, NextName
;
1043 PCM_PARSE_CONTEXT ParseContext
= Context
;
1044 ULONG TotalRemainingSubkeys
= 0, MatchRemainSubkeyLevel
= 0, TotalSubkeys
= 0;
1045 PULONG LockedKcbs
= NULL
;
1046 BOOLEAN Result
, Last
;
1049 /* Loop path separators at the end */
1050 while ((RemainingName
->Length
) &&
1051 (RemainingName
->Buffer
[(RemainingName
->Length
/ sizeof(WCHAR
)) - 1] ==
1052 OBJ_NAME_PATH_SEPARATOR
))
1054 /* Remove path separator */
1055 RemainingName
->Length
-= sizeof(WCHAR
);
1058 /* Fail if this isn't a key object */
1059 if (ObjectType
!= CmpKeyObjectType
) return STATUS_OBJECT_TYPE_MISMATCH
;
1061 /* Copy the remaining name */
1062 Current
= *RemainingName
;
1064 /* Check if this is a create */
1065 if (!(ParseContext
) || !(ParseContext
->CreateOperation
))
1067 /* It isn't, so no context */
1068 ParseContext
= NULL
;
1072 Kcb
= ((PCM_KEY_BODY
)ParseObject
)->KeyControlBlock
;
1075 ASSERT(Kcb
!= NULL
);
1077 /* Fail if the key was marked as deleted */
1079 return STATUS_KEY_DELETED
;
1081 /* Lookup in the cache */
1082 Status
= CmpBuildHashStackAndLookupCache(ParseObject
,
1087 &TotalRemainingSubkeys
,
1088 &MatchRemainSubkeyLevel
,
1093 /* This is now the parent */
1097 ASSERT(ParentKcb
!= NULL
);
1099 /* Check if everything was found cached */
1100 if (!TotalRemainingSubkeys
) ASSERTMSG("Caching not implemented", FALSE
);
1102 /* Don't do anything if we're being deleted */
1105 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1109 /* Check if this is a symlink */
1110 if (Kcb
->Flags
& KEY_SYM_LINK
)
1112 /* Get the next name */
1113 Result
= CmpGetNextName(&Current
, &NextName
, &Last
);
1114 Current
.Buffer
= NextName
.Buffer
;
1116 /* Validate the current name string length */
1117 if (Current
.Length
+ NextName
.Length
> MAXUSHORT
)
1120 Status
= STATUS_NAME_TOO_LONG
;
1123 Current
.Length
+= NextName
.Length
;
1125 /* Validate the current name string maximum length */
1126 if (Current
.MaximumLength
+ NextName
.MaximumLength
> MAXUSHORT
)
1129 Status
= STATUS_NAME_TOO_LONG
;
1132 Current
.MaximumLength
+= NextName
.MaximumLength
;
1134 /* Parse the symlink */
1135 if (CmpGetSymbolicLink(Hive
,
1140 /* Symlink parse succeeded */
1141 Status
= STATUS_REPARSE
;
1145 /* Couldn't find symlink */
1146 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1153 /* Get the key node */
1154 Node
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
1157 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1162 Status
= STATUS_NOT_IMPLEMENTED
;
1165 /* Get the next component */
1166 Result
= CmpGetNextName(&Current
, &NextName
, &Last
);
1167 if ((Result
) && (NextName
.Length
))
1169 /* See if this is a sym link */
1170 if (!(Kcb
->Flags
& KEY_SYM_LINK
))
1172 /* Find the subkey */
1173 NextCell
= CmpFindSubKeyByName(Hive
, Node
, &NextName
);
1174 if (NextCell
!= HCELL_NIL
)
1176 /* Get the new node */
1178 Node
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
1179 if (!Node
) ASSERT(FALSE
);
1181 /* Check if this was the last key */
1184 /* Is this an exit node */
1185 if (Node
->Flags
& KEY_HIVE_EXIT
)
1188 CmpHandleExitNode(&Hive
,
1193 if (!Node
) ASSERT(FALSE
);
1197 Status
= CmpDoOpen(Hive
,
1208 if (Status
== STATUS_REPARSE
)
1210 /* Parse the symlink */
1211 if (!CmpGetSymbolicLink(Hive
,
1216 /* Symlink parse failed */
1217 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1225 /* Is this an exit node */
1226 if (Node
->Flags
& KEY_HIVE_EXIT
)
1229 CmpHandleExitNode(&Hive
,
1234 if (!Node
) ASSERT(FALSE
);
1237 /* Create a KCB for this key */
1238 Kcb
= CmpCreateKeyControlBlock(Hive
,
1244 if (!Kcb
) ASSERT(FALSE
);
1246 /* Dereference the parent and set the new one */
1247 CmpDereferenceKeyControlBlock(ParentKcb
);
1252 /* Check if this was the last key for a create */
1253 if ((Last
) && (ParseContext
))
1255 /* Check if we're doing a link node */
1256 if (ParseContext
->CreateLink
)
1258 /* The only thing we should see */
1259 Status
= CmpCreateLinkNode(Hive
,
1269 else if (Hive
== &CmiVolatileHive
->Hive
&& CmpNoVolatileCreates
)
1271 /* Creating keys in the master hive is not allowed */
1272 Status
= STATUS_INVALID_PARAMETER
;
1277 Status
= CmpDoCreate(Hive
,
1287 /* Check for reparse (in this case, someone beat us) */
1288 if (Status
== STATUS_REPARSE
) break;
1290 /* Update disposition */
1291 ParseContext
->Disposition
= REG_CREATED_NEW_KEY
;
1297 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1304 /* Save the next name */
1305 Current
.Buffer
= NextName
.Buffer
;
1307 /* Validate the current name string length */
1308 if (Current
.Length
+ NextName
.Length
> MAXUSHORT
)
1311 Status
= STATUS_NAME_TOO_LONG
;
1314 Current
.Length
+= NextName
.Length
;
1316 /* Validate the current name string maximum length */
1317 if (Current
.MaximumLength
+ NextName
.MaximumLength
> MAXUSHORT
)
1320 Status
= STATUS_NAME_TOO_LONG
;
1323 Current
.MaximumLength
+= NextName
.MaximumLength
;
1325 /* Parse the symlink */
1326 if (CmpGetSymbolicLink(Hive
,
1331 /* Symlink parse succeeded */
1332 Status
= STATUS_REPARSE
;
1336 /* Couldn't find symlink */
1337 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1344 else if ((Result
) && (Last
))
1346 /* Opening the root. Is this an exit node? */
1347 if (Node
->Flags
& KEY_HIVE_EXIT
)
1350 CmpHandleExitNode(&Hive
,
1355 if (!Node
) ASSERT(FALSE
);
1359 Status
= CmpDoOpen(Hive
,
1366 CMP_OPEN_KCB_NO_CREATE
/* | CMP_CREATE_KCB_KCB_LOCKED */,
1370 if (Status
== STATUS_REPARSE
)
1381 Status
= STATUS_INVALID_PARAMETER
;
1386 /* Dereference the parent if it exists */
1388 if (ParentKcb
) CmpDereferenceKeyControlBlock(ParentKcb
);
1390 /* Unlock the registry */
1391 CmpUnlockRegistry();