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 /* Check if there's nothing left in the name */
28 if (!(RemainingName
->Buffer
) ||
29 (!RemainingName
->Length
) ||
30 !(*RemainingName
->Buffer
))
32 /* Clear the next name and set this as last */
34 NextName
->Buffer
= NULL
;
39 /* Check if we have a path separator */
40 if (*RemainingName
->Buffer
== OBJ_NAME_PATH_SEPARATOR
)
43 RemainingName
->Buffer
++;
44 RemainingName
->Length
-= sizeof(WCHAR
);
45 RemainingName
->MaximumLength
-= sizeof(WCHAR
);
48 /* Start loop at where the current buffer is */
49 NextName
->Buffer
= RemainingName
->Buffer
;
52 /* Break out if we ran out or hit a path separator */
53 if (!(RemainingName
->Length
) ||
54 (*RemainingName
->Buffer
== OBJ_NAME_PATH_SEPARATOR
))
59 /* Move to the next character */
60 RemainingName
->Buffer
++;
61 RemainingName
->Length
-= sizeof(WCHAR
);
62 RemainingName
->MaximumLength
-= sizeof(WCHAR
);
65 /* See how many chars we parsed and validate the length */
66 NextName
->Length
= (USHORT
)((ULONG_PTR
)RemainingName
->Buffer
-
67 (ULONG_PTR
)NextName
->Buffer
);
68 if (NextName
->Length
> 512) NameValid
= FALSE
;
69 NextName
->MaximumLength
= NextName
->Length
;
71 /* If there's nothing left, we're last */
72 *LastName
= !RemainingName
->Length
;
78 CmpGetSymbolicLink(IN PHHIVE Hive
,
79 IN OUT PUNICODE_STRING ObjectName
,
80 IN OUT PCM_KEY_CONTROL_BLOCK SymbolicKcb
,
81 IN PUNICODE_STRING RemainingName OPTIONAL
)
83 HCELL_INDEX LinkCell
= HCELL_NIL
;
84 PCM_KEY_VALUE LinkValue
= NULL
;
85 PWSTR LinkName
= NULL
;
86 BOOLEAN LinkNameAllocated
= FALSE
;
89 ULONG ValueLength
= 0;
90 BOOLEAN Result
= FALSE
;
91 HCELL_INDEX CellToRelease
= HCELL_NIL
;
93 UNICODE_STRING NewObjectName
;
95 /* Make sure we're not being deleted */
96 if (SymbolicKcb
->Delete
) return FALSE
;
98 /* Get the key node */
99 Node
= (PCM_KEY_NODE
)HvGetCell(SymbolicKcb
->KeyHive
, SymbolicKcb
->KeyCell
);
100 if (!Node
) goto Exit
;
102 /* Find the symbolic link key */
103 LinkCell
= CmpFindValueByName(Hive
, Node
, &CmSymbolicLinkValueName
);
104 HvReleaseCell(SymbolicKcb
->KeyHive
, SymbolicKcb
->KeyCell
);
105 if (LinkCell
== HCELL_NIL
) goto Exit
;
107 /* Get the value cell */
108 LinkValue
= (PCM_KEY_VALUE
)HvGetCell(Hive
, LinkCell
);
109 if (!LinkValue
) goto Exit
;
111 /* Make sure it's a registry link */
112 if (LinkValue
->Type
!= REG_LINK
) goto Exit
;
114 /* Now read the value data */
115 if (!CmpGetValueData(Hive
,
127 Length
= ValueLength
+ sizeof(WCHAR
);
129 /* Make sure we start with a slash */
130 if (*LinkName
!= OBJ_NAME_PATH_SEPARATOR
) goto Exit
;
132 /* Add the remaining name if needed */
133 if (RemainingName
) Length
+= RemainingName
->Length
+ sizeof(WCHAR
);
135 /* Check for overflow */
136 if (Length
> 0xFFFF) goto Exit
;
138 /* Check if we need a new buffer */
139 if (Length
> ObjectName
->MaximumLength
)
141 /* We do -- allocate one */
142 NewBuffer
= ExAllocatePoolWithTag(PagedPool
, Length
, TAG_CM
);
143 if (!NewBuffer
) goto Exit
;
145 /* Setup the new string and copy the symbolic target */
146 NewObjectName
.Buffer
= NewBuffer
;
147 NewObjectName
.MaximumLength
= (USHORT
)Length
;
148 NewObjectName
.Length
= (USHORT
)ValueLength
;
149 RtlCopyMemory(NewBuffer
, LinkName
, ValueLength
);
151 /* Check if we need to add anything else */
154 /* Add the remaining name */
155 NewBuffer
[ValueLength
/ sizeof(WCHAR
)] = OBJ_NAME_PATH_SEPARATOR
;
156 NewObjectName
.Length
+= sizeof(WCHAR
);
157 RtlAppendUnicodeStringToString(&NewObjectName
, RemainingName
);
160 /* Free the old buffer */
161 ExFreePool(ObjectName
->Buffer
);
162 *ObjectName
= NewObjectName
;
166 /* The old name is large enough -- update the length */
167 ObjectName
->Length
= (USHORT
)ValueLength
;
170 /* Copy the remaining name inside */
171 RtlMoveMemory(&ObjectName
->Buffer
[(ValueLength
/ sizeof(WCHAR
)) + 1],
172 RemainingName
->Buffer
,
173 RemainingName
->Length
);
175 /* Add the slash and update the length */
176 ObjectName
->Buffer
[ValueLength
/ sizeof(WCHAR
)] = OBJ_NAME_PATH_SEPARATOR
;
177 ObjectName
->Length
+= RemainingName
->Length
+ sizeof(WCHAR
);
180 /* Copy the symbolic link target name */
181 RtlCopyMemory(ObjectName
->Buffer
, LinkName
, ValueLength
);
184 /* Null-terminate the whole thing */
185 ObjectName
->Buffer
[ObjectName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
189 /* Free the link name */
190 if (LinkNameAllocated
) ExFreePool(LinkName
);
192 /* Check if we had a value cell */
196 ASSERT(LinkCell
!= HCELL_NIL
);
197 HvReleaseCell(Hive
, LinkCell
);
200 /* Check if we had an active cell and release it, then return the result */
201 if (CellToRelease
!= HCELL_NIL
) HvReleaseCell(Hive
, CellToRelease
);
207 CmpDoCreateChild(IN PHHIVE Hive
,
208 IN HCELL_INDEX ParentCell
,
209 IN PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL
,
210 IN PACCESS_STATE AccessState
,
211 IN PUNICODE_STRING Name
,
212 IN KPROCESSOR_MODE AccessMode
,
213 IN PCM_PARSE_CONTEXT ParseContext
,
214 IN PCM_KEY_CONTROL_BLOCK ParentKcb
,
216 OUT PHCELL_INDEX KeyCell
,
219 NTSTATUS Status
= STATUS_SUCCESS
;
220 PCM_KEY_BODY KeyBody
;
221 HCELL_INDEX ClassCell
= HCELL_NIL
;
222 PCM_KEY_NODE KeyNode
;
225 LARGE_INTEGER SystemTime
;
226 PCM_KEY_CONTROL_BLOCK Kcb
;
227 PSECURITY_DESCRIPTOR NewDescriptor
;
229 /* Get the storage type */
230 StorageType
= Stable
;
231 if (Flags
& REG_OPTION_VOLATILE
) StorageType
= Volatile
;
233 /* Allocate the child */
234 *KeyCell
= HvAllocateCell(Hive
,
235 FIELD_OFFSET(CM_KEY_NODE
, Name
) +
236 CmpNameSize(Hive
, Name
),
239 if (*KeyCell
== HCELL_NIL
)
242 Status
= STATUS_INSUFFICIENT_RESOURCES
;
246 /* Get the key node */
247 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, *KeyCell
);
250 /* Fail, this should never happen */
252 Status
= STATUS_INSUFFICIENT_RESOURCES
;
256 /* Release the cell */
257 HvReleaseCell(Hive
, *KeyCell
);
259 /* Check if we have a class name */
260 if (ParseContext
->Class
.Length
> 0)
262 /* Allocate a class cell */
263 ClassCell
= HvAllocateCell(Hive
,
264 ParseContext
->Class
.Length
,
267 if (ClassCell
== HCELL_NIL
)
270 Status
= STATUS_INSUFFICIENT_RESOURCES
;
275 /* Allocate the Cm Object */
276 Status
= ObCreateObject(AccessMode
,
285 if (!NT_SUCCESS(Status
)) goto Quickie
;
287 /* Setup the key body */
288 KeyBody
= (PCM_KEY_BODY
)(*Object
);
289 KeyBody
->Type
= '20yk';
290 KeyBody
->KeyControlBlock
= NULL
;
292 /* Check if we had a class */
293 if (ParseContext
->Class
.Length
> 0)
295 /* Get the class cell */
296 CellData
= HvGetCell(Hive
, ClassCell
);
299 /* Fail, this should never happen */
301 Status
= STATUS_INSUFFICIENT_RESOURCES
;
302 ObDereferenceObject(*Object
);
306 /* Release the cell */
307 HvReleaseCell(Hive
, ClassCell
);
309 /* Copy the class data */
310 RtlCopyMemory(&CellData
->u
.KeyString
[0],
311 ParseContext
->Class
.Buffer
,
312 ParseContext
->Class
.Length
);
315 /* Fill out the key node */
316 KeyNode
->Signature
= CM_KEY_NODE_SIGNATURE
;
317 KeyNode
->Flags
= Flags
&~ REG_OPTION_CREATE_LINK
;
318 KeQuerySystemTime(&SystemTime
);
319 KeyNode
->LastWriteTime
= SystemTime
;
321 KeyNode
->Parent
= ParentCell
;
322 KeyNode
->SubKeyCounts
[Stable
] = 0;
323 KeyNode
->SubKeyCounts
[Volatile
] = 0;
324 KeyNode
->SubKeyLists
[Stable
] = HCELL_NIL
;
325 KeyNode
->SubKeyLists
[Volatile
] = HCELL_NIL
;
326 KeyNode
->ValueList
.Count
= 0;
327 KeyNode
->ValueList
.List
= HCELL_NIL
;
328 KeyNode
->Security
= HCELL_NIL
;
329 KeyNode
->Class
= ClassCell
;
330 KeyNode
->ClassLength
= ParseContext
->Class
.Length
;
331 KeyNode
->MaxValueDataLen
= 0;
332 KeyNode
->MaxNameLen
= 0;
333 KeyNode
->MaxValueNameLen
= 0;
334 KeyNode
->MaxClassLen
= 0;
335 KeyNode
->NameLength
= CmpCopyName(Hive
, KeyNode
->Name
, Name
);
336 if (KeyNode
->NameLength
< Name
->Length
) KeyNode
->Flags
|= KEY_COMP_NAME
;
339 Kcb
= CmpCreateKeyControlBlock(Hive
,
343 0, // CMP_LOCK_HASHES_FOR_KCB,
348 ObDereferenceObjectDeferDelete(*Object
);
349 Status
= STATUS_INSUFFICIENT_RESOURCES
;
354 ASSERT(Kcb
->RefCount
== 1);
356 /* Now fill out the Cm object */
357 KeyBody
->NotifyBlock
= NULL
;
358 KeyBody
->ProcessID
= PsGetCurrentProcessId();
359 KeyBody
->KeyControlBlock
= Kcb
;
361 /* Link it with the KCB */
362 EnlistKeyBodyWithKCB(KeyBody
, 0);
364 /* Assign security */
365 Status
= SeAssignSecurity(ParentDescriptor
,
366 AccessState
->SecurityDescriptor
,
369 &AccessState
->SubjectSecurityContext
,
370 &CmpKeyObjectType
->TypeInfo
.GenericMapping
,
371 CmpKeyObjectType
->TypeInfo
.PoolType
);
372 if (NT_SUCCESS(Status
))
374 Status
= CmpSecurityMethod(*Object
,
375 AssignSecurityDescriptor
,
380 CmpKeyObjectType
->TypeInfo
.PoolType
,
381 &CmpKeyObjectType
->TypeInfo
.GenericMapping
);
385 /* Check if we got here because of failure */
386 if (!NT_SUCCESS(Status
))
388 /* Free any cells we might've allocated */
389 if (ParseContext
->Class
.Length
> 0) HvFreeCell(Hive
, ClassCell
);
390 HvFreeCell(Hive
, *KeyCell
);
399 CmpDoCreate(IN PHHIVE Hive
,
401 IN PACCESS_STATE AccessState
,
402 IN PUNICODE_STRING Name
,
403 IN KPROCESSOR_MODE AccessMode
,
404 IN PCM_PARSE_CONTEXT ParseContext
,
405 IN PCM_KEY_CONTROL_BLOCK ParentKcb
,
412 PCM_KEY_BODY KeyBody
;
413 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
414 LARGE_INTEGER TimeStamp
;
415 PCM_KEY_NODE KeyNode
;
417 /* Check if the parent is being deleted */
418 if (ParentKcb
->Delete
)
422 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
426 /* Get the parent node */
427 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
432 Status
= STATUS_INSUFFICIENT_RESOURCES
;
436 /* Make sure nobody added us yet */
437 if (CmpFindSubKeyByName(Hive
, KeyNode
, Name
) != HCELL_NIL
)
441 Status
= STATUS_REPARSE
;
446 ASSERT(Cell
== ParentKcb
->KeyCell
);
448 /* Get the parent type */
449 ParentType
= HvGetCellType(Cell
);
450 if ((ParentType
== Volatile
) &&
451 !(ParseContext
->CreateOptions
& REG_OPTION_VOLATILE
))
453 /* Children of volatile parents must also be volatile */
455 Status
= STATUS_CHILD_MUST_BE_VOLATILE
;
459 /* Don't allow children under symlinks */
460 if (ParentKcb
->Flags
& KEY_SYM_LINK
)
464 Status
= STATUS_ACCESS_DENIED
;
468 /* Make the cell dirty for now */
469 HvMarkCellDirty(Hive
, Cell
, FALSE
);
471 /* Do the actual create operation */
472 Status
= CmpDoCreateChild(Hive
,
480 ParseContext
->CreateOptions
, // WRONG!
483 if (NT_SUCCESS(Status
))
485 /* Get the key body */
486 KeyBody
= (PCM_KEY_BODY
)(*Object
);
488 /* Now add the subkey */
489 if (!CmpAddSubKey(Hive
, Cell
, KeyCell
))
491 /* Failure! We don't handle this yet! */
495 /* Get the key node */
496 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
499 /* Fail, this shouldn't happen */
504 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
->KeyCell
== Cell
);
505 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
->KeyHive
== Hive
);
506 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
== ParentKcb
);
507 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
->KcbMaxNameLen
== KeyNode
->MaxNameLen
);
509 /* Update the timestamp */
510 KeQuerySystemTime(&TimeStamp
);
511 KeyNode
->LastWriteTime
= TimeStamp
;
512 KeyBody
->KeyControlBlock
->ParentKcb
->KcbLastWriteTime
= TimeStamp
;
514 /* Check if we need to update name maximum */
515 if (KeyNode
->MaxNameLen
< Name
->Length
)
518 KeyNode
->MaxNameLen
= Name
->Length
;
519 KeyBody
->KeyControlBlock
->ParentKcb
->KcbMaxNameLen
= Name
->Length
;
522 /* Check if we need toupdate class length maximum */
523 if (KeyNode
->MaxClassLen
< ParseContext
->Class
.Length
)
526 KeyNode
->MaxClassLen
= ParseContext
->Class
.Length
;
529 /* Check if we're creating a symbolic link */
530 if (ParseContext
->CreateOptions
& REG_OPTION_CREATE_LINK
)
532 /* Get the cell data */
533 CellData
= HvGetCell(Hive
, KeyCell
);
536 /* This shouldn't happen */
540 /* Update the flags */
541 CellData
->u
.KeyNode
.Flags
|= KEY_SYM_LINK
;
542 KeyBody
->KeyControlBlock
->Flags
= CellData
->u
.KeyNode
.Flags
;
543 HvReleaseCell(Hive
, KeyCell
);
548 /* Release the flusher lock and return status */
554 CmpDoOpen(IN PHHIVE Hive
,
556 IN PCM_KEY_NODE Node
,
557 IN PACCESS_STATE AccessState
,
558 IN KPROCESSOR_MODE AccessMode
,
560 IN PCM_PARSE_CONTEXT Context OPTIONAL
,
561 IN ULONG ControlFlags
,
562 IN OUT PCM_KEY_CONTROL_BLOCK
*CachedKcb
,
563 IN PUNICODE_STRING KeyName
,
567 PCM_KEY_BODY KeyBody
= NULL
;
568 PCM_KEY_CONTROL_BLOCK Kcb
= NULL
;
570 /* Make sure the hive isn't locked */
571 if ((Hive
->HiveFlags
& HIVE_IS_UNLOADING
) &&
572 (((PCMHIVE
)Hive
)->CreatorOwner
!= KeGetCurrentThread()))
574 /* It is, don't touch it */
575 return STATUS_OBJECT_NAME_NOT_FOUND
;
578 /* Check if we have a context */
581 /* Check if this is a link create (which shouldn't be an open) */
582 if (Context
->CreateLink
)
584 return STATUS_ACCESS_DENIED
;
587 /* Check if this is symlink create attempt */
588 if (Context
->CreateOptions
& REG_OPTION_CREATE_LINK
)
590 /* Key already exists */
591 return STATUS_OBJECT_NAME_COLLISION
;
594 /* Set the disposition */
595 Context
->Disposition
= REG_OPENED_EXISTING_KEY
;
598 /* Do this in the registry lock */
601 /* If we have a KCB, make sure it's locked */
602 //ASSERT(CmpIsKcbLockedExclusive(*CachedKcb));
604 /* Check if caller doesn't want to create a KCB */
605 if (ControlFlags
& CMP_OPEN_KCB_NO_CREATE
)
607 /* Check if this is a symlink */
608 if ((Node
->Flags
& KEY_SYM_LINK
) && !(Attributes
& OBJ_OPENLINK
))
610 /* This case for a cached KCB is not implemented yet */
614 /* The caller wants to open a cached KCB */
615 if (!CmpReferenceKeyControlBlock(*CachedKcb
))
617 /* Release the registry lock */
620 /* Return failure code */
621 return STATUS_INSUFFICIENT_RESOURCES
;
624 /* Our kcb is that one */
629 /* Check if this is a symlink */
630 if ((Node
->Flags
& KEY_SYM_LINK
) && !(Attributes
& OBJ_OPENLINK
))
632 /* Create the KCB for the symlink */
633 Kcb
= CmpCreateKeyControlBlock(Hive
,
641 /* Release registry lock and return failure */
643 return STATUS_INSUFFICIENT_RESOURCES
;
646 /* Make sure it's also locked, and set the pointer */
647 //ASSERT(CmpIsKcbLockedExclusive(Kcb));
650 /* Release the registry lock */
653 /* Return reparse required */
654 return STATUS_REPARSE
;
657 /* Create the KCB. FIXME: Use lock flag */
658 Kcb
= CmpCreateKeyControlBlock(Hive
,
666 /* Release registry lock and return failure */
668 return STATUS_INSUFFICIENT_RESOURCES
;
672 /* Make sure it's also locked, and set the pointer */
673 //ASSERT(CmpIsKcbLockedExclusive(Kcb));
676 /* Release the registry lock */
679 /* Allocate the key object */
680 Status
= ObCreateObject(AccessMode
,
689 if (NT_SUCCESS(Status
))
691 /* Get the key body and fill it out */
692 KeyBody
= (PCM_KEY_BODY
)(*Object
);
693 KeyBody
->KeyControlBlock
= Kcb
;
694 KeyBody
->Type
= '20yk';
695 KeyBody
->ProcessID
= PsGetCurrentProcessId();
696 KeyBody
->NotifyBlock
= NULL
;
698 /* Link to the KCB */
699 EnlistKeyBodyWithKCB(KeyBody
, 0);
701 if (!ObCheckObjectAccess(*Object
,
707 /* Access check failed */
708 ObDereferenceObject(*Object
);
713 /* Failed, dereference the KCB */
714 CmpDereferenceKeyControlBlockWithLock(Kcb
, FALSE
);
721 /* Remove calls to CmCreateRootNode once this is used! */
724 CmpCreateLinkNode(IN PHHIVE Hive
,
726 IN PACCESS_STATE AccessState
,
727 IN UNICODE_STRING Name
,
728 IN KPROCESSOR_MODE AccessMode
,
729 IN ULONG CreateOptions
,
730 IN PCM_PARSE_CONTEXT Context
,
731 IN PCM_KEY_CONTROL_BLOCK ParentKcb
,
735 HCELL_INDEX KeyCell
, LinkCell
, ChildCell
;
736 PCM_KEY_BODY KeyBody
;
737 LARGE_INTEGER TimeStamp
;
738 PCM_KEY_NODE KeyNode
;
739 PCM_KEY_CONTROL_BLOCK Kcb
= ParentKcb
;
741 /* Link nodes only allowed on the master */
742 if (Hive
!= &CmiVolatileHive
->Hive
)
745 DPRINT1("Invalid link node attempt\n");
746 return STATUS_ACCESS_DENIED
;
749 /* Check if the parent is being deleted */
750 if (ParentKcb
->Delete
)
754 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
758 /* Allocate a link node */
759 LinkCell
= HvAllocateCell(Hive
,
760 FIELD_OFFSET(CM_KEY_NODE
, Name
) +
761 CmpNameSize(Hive
, &Name
),
764 if (LinkCell
== HCELL_NIL
)
767 Status
= STATUS_INSUFFICIENT_RESOURCES
;
771 /* Get the key cell */
772 KeyCell
= Context
->ChildHive
.KeyCell
;
773 if (KeyCell
!= HCELL_NIL
)
778 /* Get the node data */
779 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Context
->ChildHive
.KeyHive
, ChildCell
);
784 Status
= STATUS_INSUFFICIENT_RESOURCES
;
788 /* Fill out the data */
789 KeyNode
->Parent
= LinkCell
;
790 KeyNode
->Flags
|= KEY_HIVE_ENTRY
| KEY_NO_DELETE
;
791 HvReleaseCell(Context
->ChildHive
.KeyHive
, ChildCell
);
793 /* Now open the key cell */
794 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Context
->ChildHive
.KeyHive
, KeyCell
);
799 Status
= STATUS_INSUFFICIENT_RESOURCES
;
803 /* Open the parent */
804 Status
= CmpDoOpen(Context
->ChildHive
.KeyHive
,
815 HvReleaseCell(Context
->ChildHive
.KeyHive
, KeyCell
);
819 /* Do the actual create operation */
820 Status
= CmpDoCreateChild(Context
->ChildHive
.KeyHive
,
828 KEY_HIVE_ENTRY
| KEY_NO_DELETE
,
831 if (NT_SUCCESS(Status
))
833 /* Setup root pointer */
834 Context
->ChildHive
.KeyHive
->BaseBlock
->RootCell
= ChildCell
;
838 /* Check if open or create suceeded */
839 if (NT_SUCCESS(Status
))
841 /* Mark the cell dirty */
842 HvMarkCellDirty(Context
->ChildHive
.KeyHive
, ChildCell
, FALSE
);
844 /* Get the key node */
845 KeyNode
= HvGetCell(Context
->ChildHive
.KeyHive
, ChildCell
);
850 Status
= STATUS_INSUFFICIENT_RESOURCES
;
855 HvReleaseCell(Context
->ChildHive
.KeyHive
, ChildCell
);
857 /* Set the parent and flags */
858 KeyNode
->Parent
= LinkCell
;
859 KeyNode
->Flags
|= KEY_HIVE_ENTRY
| KEY_NO_DELETE
;
861 /* Get the link node */
862 KeyNode
= HvGetCell(Hive
, LinkCell
);
867 Status
= STATUS_INSUFFICIENT_RESOURCES
;
872 KeyNode
->Signature
= CM_LINK_NODE_SIGNATURE
;
873 KeyNode
->Flags
= KEY_HIVE_EXIT
| KEY_NO_DELETE
;
874 KeyNode
->Parent
= Cell
;
875 KeyNode
->NameLength
= CmpCopyName(Hive
, KeyNode
->Name
, &Name
);
876 if (KeyNode
->NameLength
< Name
.Length
) KeyNode
->Flags
|= KEY_COMP_NAME
;
877 KeQuerySystemTime(&TimeStamp
);
878 KeyNode
->LastWriteTime
= TimeStamp
;
880 /* Clear out the rest */
881 KeyNode
->SubKeyCounts
[Stable
] = 0;
882 KeyNode
->SubKeyCounts
[Volatile
] = 0;
883 KeyNode
->SubKeyLists
[Stable
] = HCELL_NIL
;
884 KeyNode
->SubKeyLists
[Volatile
] = HCELL_NIL
;
885 KeyNode
->ValueList
.Count
= 0;
886 KeyNode
->ValueList
.List
= HCELL_NIL
;
887 KeyNode
->ClassLength
= 0;
889 /* Reference the root node */
890 KeyNode
->ChildHiveReference
.KeyHive
= Context
->ChildHive
.KeyHive
;
891 KeyNode
->ChildHiveReference
.KeyCell
= ChildCell
;
892 HvReleaseCell(Hive
, LinkCell
);
894 /* Get the parent node */
895 KeyNode
= HvGetCell(Hive
, Cell
);
900 Status
= STATUS_INSUFFICIENT_RESOURCES
;
904 /* Now add the subkey */
905 if (!CmpAddSubKey(Hive
, Cell
, LinkCell
))
907 /* Failure! We don't handle this yet! */
911 /* Get the key body */
912 KeyBody
= (PCM_KEY_BODY
)*Object
;
915 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
->KeyCell
== Cell
);
916 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
->KeyHive
== Hive
);
917 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
->KcbMaxNameLen
== KeyNode
->MaxNameLen
);
919 /* Update the timestamp */
920 KeQuerySystemTime(&TimeStamp
);
921 KeyNode
->LastWriteTime
= TimeStamp
;
922 KeyBody
->KeyControlBlock
->ParentKcb
->KcbLastWriteTime
= TimeStamp
;
924 /* Check if we need to update name maximum */
925 if (KeyNode
->MaxNameLen
< Name
.Length
)
928 KeyNode
->MaxNameLen
= Name
.Length
;
929 KeyBody
->KeyControlBlock
->ParentKcb
->KcbMaxNameLen
= Name
.Length
;
932 /* Check if we need toupdate class length maximum */
933 if (KeyNode
->MaxClassLen
< Context
->Class
.Length
)
936 KeyNode
->MaxClassLen
= Context
->Class
.Length
;
939 /* Release the cell */
940 HvReleaseCell(Hive
, Cell
);
944 /* Release the link cell */
945 HvReleaseCell(Hive
, LinkCell
);
949 /* Release the flusher locks and return status */
955 CmpHandleExitNode(IN OUT PHHIVE
*Hive
,
956 IN OUT HCELL_INDEX
*Cell
,
957 IN OUT PCM_KEY_NODE
*KeyNode
,
958 IN OUT PHHIVE
*ReleaseHive
,
959 IN OUT HCELL_INDEX
*ReleaseCell
)
961 /* Check if we have anything to release */
962 if (*ReleaseCell
!= HCELL_NIL
)
965 ASSERT(*ReleaseHive
!= NULL
);
966 HvReleaseCell((*ReleaseHive
), *ReleaseCell
);
969 /* Get the link references */
970 *Hive
= (*KeyNode
)->ChildHiveReference
.KeyHive
;
971 *Cell
= (*KeyNode
)->ChildHiveReference
.KeyCell
;
973 /* Get the new node */
974 *KeyNode
= (PCM_KEY_NODE
)HvGetCell((*Hive
), *Cell
);
977 /* Set the new release values */
978 *ReleaseCell
= *Cell
;
979 *ReleaseHive
= *Hive
;
983 /* Nothing to release */
984 *ReleaseCell
= HCELL_NIL
;
991 CmpBuildHashStackAndLookupCache(IN PCM_KEY_BODY ParseObject
,
992 IN OUT PCM_KEY_CONTROL_BLOCK
*Kcb
,
993 IN PUNICODE_STRING Current
,
995 OUT HCELL_INDEX
*Cell
,
996 OUT PULONG TotalRemainingSubkeys
,
997 OUT PULONG MatchRemainSubkeyLevel
,
998 OUT PULONG TotalSubkeys
,
999 OUT PULONG OuterStackArray
,
1000 OUT PULONG
*LockedKcbs
)
1002 /* We don't lock anything for now */
1005 /* Calculate hash values */
1006 *TotalRemainingSubkeys
= 0xBAADF00D;
1008 /* Lock the registry */
1011 /* Return hive and cell data */
1012 *Hive
= (*Kcb
)->KeyHive
;
1013 *Cell
= (*Kcb
)->KeyCell
;
1015 /* Make sure it's not a dead KCB */
1016 ASSERT((*Kcb
)->RefCount
> 0);
1019 (VOID
)CmpReferenceKeyControlBlock(*Kcb
);
1021 /* Return success for now */
1022 return STATUS_SUCCESS
;
1027 CmpParseKey(IN PVOID ParseObject
,
1028 IN PVOID ObjectType
,
1029 IN OUT PACCESS_STATE AccessState
,
1030 IN KPROCESSOR_MODE AccessMode
,
1031 IN ULONG Attributes
,
1032 IN OUT PUNICODE_STRING CompleteName
,
1033 IN OUT PUNICODE_STRING RemainingName
,
1034 IN OUT PVOID Context OPTIONAL
,
1035 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
1039 PCM_KEY_CONTROL_BLOCK Kcb
, ParentKcb
;
1041 PCM_KEY_NODE Node
= NULL
;
1042 HCELL_INDEX Cell
= HCELL_NIL
, NextCell
;
1043 PHHIVE HiveToRelease
= NULL
;
1044 HCELL_INDEX CellToRelease
= HCELL_NIL
;
1045 UNICODE_STRING Current
, NextName
;
1046 PCM_PARSE_CONTEXT ParseContext
= Context
;
1047 ULONG TotalRemainingSubkeys
= 0, MatchRemainSubkeyLevel
= 0, TotalSubkeys
= 0;
1048 PULONG LockedKcbs
= NULL
;
1049 BOOLEAN Result
, Last
;
1052 /* Loop path separators at the end */
1053 while ((RemainingName
->Length
) &&
1054 (RemainingName
->Buffer
[(RemainingName
->Length
/ sizeof(WCHAR
)) - 1] ==
1055 OBJ_NAME_PATH_SEPARATOR
))
1057 /* Remove path separator */
1058 RemainingName
->Length
-= sizeof(WCHAR
);
1061 /* Fail if this isn't a key object */
1062 if (ObjectType
!= CmpKeyObjectType
) return STATUS_OBJECT_TYPE_MISMATCH
;
1064 /* Copy the remaining name */
1065 Current
= *RemainingName
;
1067 /* Check if this is a create */
1068 if (!(ParseContext
) || !(ParseContext
->CreateOperation
))
1070 /* It isn't, so no context */
1071 ParseContext
= NULL
;
1075 Kcb
= ((PCM_KEY_BODY
)ParseObject
)->KeyControlBlock
;
1078 ASSERT(Kcb
!= NULL
);
1080 /* Fail if the key was marked as deleted */
1082 return STATUS_KEY_DELETED
;
1084 /* Lookup in the cache */
1085 Status
= CmpBuildHashStackAndLookupCache(ParseObject
,
1090 &TotalRemainingSubkeys
,
1091 &MatchRemainSubkeyLevel
,
1096 /* This is now the parent */
1100 ASSERT(ParentKcb
!= NULL
);
1102 /* Check if everything was found cached */
1103 if (!TotalRemainingSubkeys
) ASSERTMSG("Caching not implemented", FALSE
);
1105 /* Don't do anything if we're being deleted */
1108 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1112 /* Check if this is a symlink */
1113 if (Kcb
->Flags
& KEY_SYM_LINK
)
1115 /* Get the next name */
1116 Result
= CmpGetNextName(&Current
, &NextName
, &Last
);
1117 Current
.Buffer
= NextName
.Buffer
;
1119 /* Validate the current name string length */
1120 if (Current
.Length
+ NextName
.Length
> MAXUSHORT
)
1123 Status
= STATUS_NAME_TOO_LONG
;
1126 Current
.Length
+= NextName
.Length
;
1128 /* Validate the current name string maximum length */
1129 if (Current
.MaximumLength
+ NextName
.MaximumLength
> MAXUSHORT
)
1132 Status
= STATUS_NAME_TOO_LONG
;
1135 Current
.MaximumLength
+= NextName
.MaximumLength
;
1137 /* Parse the symlink */
1138 if (CmpGetSymbolicLink(Hive
,
1143 /* Symlink parse succeeded */
1144 Status
= STATUS_REPARSE
;
1148 /* Couldn't find symlink */
1149 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1156 /* Get the key node */
1157 Node
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
1160 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1165 Status
= STATUS_NOT_IMPLEMENTED
;
1168 /* Get the next component */
1169 Result
= CmpGetNextName(&Current
, &NextName
, &Last
);
1170 if ((Result
) && (NextName
.Length
))
1172 /* See if this is a sym link */
1173 if (!(Kcb
->Flags
& KEY_SYM_LINK
))
1175 /* Find the subkey */
1176 NextCell
= CmpFindSubKeyByName(Hive
, Node
, &NextName
);
1177 if (NextCell
!= HCELL_NIL
)
1179 /* Get the new node */
1181 Node
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
1182 if (!Node
) ASSERT(FALSE
);
1184 /* Check if this was the last key */
1187 /* Is this an exit node */
1188 if (Node
->Flags
& KEY_HIVE_EXIT
)
1191 CmpHandleExitNode(&Hive
,
1196 if (!Node
) ASSERT(FALSE
);
1200 Status
= CmpDoOpen(Hive
,
1211 if (Status
== STATUS_REPARSE
)
1213 /* Parse the symlink */
1214 if (!CmpGetSymbolicLink(Hive
,
1219 /* Symlink parse failed */
1220 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1228 /* Is this an exit node */
1229 if (Node
->Flags
& KEY_HIVE_EXIT
)
1232 CmpHandleExitNode(&Hive
,
1237 if (!Node
) ASSERT(FALSE
);
1240 /* Create a KCB for this key */
1241 Kcb
= CmpCreateKeyControlBlock(Hive
,
1247 if (!Kcb
) ASSERT(FALSE
);
1249 /* Dereference the parent and set the new one */
1250 CmpDereferenceKeyControlBlock(ParentKcb
);
1255 /* Check if this was the last key for a create */
1256 if ((Last
) && (ParseContext
))
1258 /* Check if we're doing a link node */
1259 if (ParseContext
->CreateLink
)
1261 /* The only thing we should see */
1262 Status
= CmpCreateLinkNode(Hive
,
1275 Status
= CmpDoCreate(Hive
,
1285 /* Check for reparse (in this case, someone beat us) */
1286 if (Status
== STATUS_REPARSE
) break;
1288 /* Update disposition */
1289 ParseContext
->Disposition
= REG_CREATED_NEW_KEY
;
1295 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1302 /* Save the next name */
1303 Current
.Buffer
= NextName
.Buffer
;
1305 /* Validate the current name string length */
1306 if (Current
.Length
+ NextName
.Length
> MAXUSHORT
)
1309 Status
= STATUS_NAME_TOO_LONG
;
1312 Current
.Length
+= NextName
.Length
;
1314 /* Validate the current name string maximum length */
1315 if (Current
.MaximumLength
+ NextName
.MaximumLength
> MAXUSHORT
)
1318 Status
= STATUS_NAME_TOO_LONG
;
1321 Current
.MaximumLength
+= NextName
.MaximumLength
;
1323 /* Parse the symlink */
1324 if (CmpGetSymbolicLink(Hive
,
1329 /* Symlink parse succeeded */
1330 Status
= STATUS_REPARSE
;
1334 /* Couldn't find symlink */
1335 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1342 else if ((Result
) && (Last
))
1344 /* Opening the root. Is this an exit node? */
1345 if (Node
->Flags
& KEY_HIVE_EXIT
)
1348 CmpHandleExitNode(&Hive
,
1353 if (!Node
) ASSERT(FALSE
);
1357 Status
= CmpDoOpen(Hive
,
1364 CMP_OPEN_KCB_NO_CREATE
/* | CMP_CREATE_KCB_KCB_LOCKED */,
1368 if (Status
== STATUS_REPARSE
)
1379 Status
= STATUS_INVALID_PARAMETER
;
1384 /* Dereference the parent if it exists */
1386 if (ParentKcb
) CmpDereferenceKeyControlBlock(ParentKcb
);
1388 /* Unlock the registry */
1389 CmpUnlockRegistry();