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
;
419 ASSERT((CmpIsKcbLockedExclusive(ParentKcb
) == TRUE
) ||
420 (CmpTestRegistryLockExclusive() == TRUE
));
423 /* Acquire the flusher lock */
424 ExAcquirePushLockShared((PVOID
)&((PCMHIVE
)Hive
)->FlusherLock
);
426 /* Check if the parent is being deleted */
427 if (ParentKcb
->Delete
)
431 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
435 /* Get the parent node */
436 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
441 Status
= STATUS_INSUFFICIENT_RESOURCES
;
445 /* Make sure nobody added us yet */
446 if (CmpFindSubKeyByName(Hive
, KeyNode
, Name
) != HCELL_NIL
)
450 Status
= STATUS_REPARSE
;
455 ASSERT(Cell
== ParentKcb
->KeyCell
);
457 /* Get the parent type */
458 ParentType
= HvGetCellType(Cell
);
459 if ((ParentType
== Volatile
) &&
460 !(ParseContext
->CreateOptions
& REG_OPTION_VOLATILE
))
462 /* Children of volatile parents must also be volatile */
464 Status
= STATUS_CHILD_MUST_BE_VOLATILE
;
468 /* Don't allow children under symlinks */
469 if (ParentKcb
->Flags
& KEY_SYM_LINK
)
473 Status
= STATUS_ACCESS_DENIED
;
477 /* Make the cell dirty for now */
478 HvMarkCellDirty(Hive
, Cell
, FALSE
);
480 /* Do the actual create operation */
481 Status
= CmpDoCreateChild(Hive
,
489 ParseContext
->CreateOptions
, // WRONG!
492 if (NT_SUCCESS(Status
))
494 /* Get the key body */
495 KeyBody
= (PCM_KEY_BODY
)(*Object
);
497 /* Now add the subkey */
498 if (!CmpAddSubKey(Hive
, Cell
, KeyCell
))
500 /* Failure! We don't handle this yet! */
504 /* Get the key node */
505 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
508 /* Fail, this shouldn't happen */
513 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
->KeyCell
== Cell
);
514 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
->KeyHive
== Hive
);
515 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
== ParentKcb
);
516 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
->KcbMaxNameLen
== KeyNode
->MaxNameLen
);
518 /* Update the timestamp */
519 KeQuerySystemTime(&TimeStamp
);
520 KeyNode
->LastWriteTime
= TimeStamp
;
521 KeyBody
->KeyControlBlock
->ParentKcb
->KcbLastWriteTime
= TimeStamp
;
523 /* Check if we need to update name maximum */
524 if (KeyNode
->MaxNameLen
< Name
->Length
)
527 KeyNode
->MaxNameLen
= Name
->Length
;
528 KeyBody
->KeyControlBlock
->ParentKcb
->KcbMaxNameLen
= Name
->Length
;
531 /* Check if we need toupdate class length maximum */
532 if (KeyNode
->MaxClassLen
< ParseContext
->Class
.Length
)
535 KeyNode
->MaxClassLen
= ParseContext
->Class
.Length
;
538 /* Check if we're creating a symbolic link */
539 if (ParseContext
->CreateOptions
& REG_OPTION_CREATE_LINK
)
541 /* Get the cell data */
542 CellData
= HvGetCell(Hive
, KeyCell
);
545 /* This shouldn't happen */
549 /* Update the flags */
550 CellData
->u
.KeyNode
.Flags
|= KEY_SYM_LINK
;
551 KeyBody
->KeyControlBlock
->Flags
= CellData
->u
.KeyNode
.Flags
;
552 HvReleaseCell(Hive
, KeyCell
);
557 /* Release the flusher lock and return status */
558 ExReleasePushLock((PVOID
)&((PCMHIVE
)Hive
)->FlusherLock
);
564 CmpDoOpen(IN PHHIVE Hive
,
566 IN PCM_KEY_NODE Node
,
567 IN PACCESS_STATE AccessState
,
568 IN KPROCESSOR_MODE AccessMode
,
570 IN PCM_PARSE_CONTEXT Context OPTIONAL
,
571 IN ULONG ControlFlags
,
572 IN OUT PCM_KEY_CONTROL_BLOCK
*CachedKcb
,
573 IN PUNICODE_STRING KeyName
,
577 PCM_KEY_BODY KeyBody
= NULL
;
578 PCM_KEY_CONTROL_BLOCK Kcb
= NULL
;
580 /* Make sure the hive isn't locked */
581 if ((Hive
->HiveFlags
& HIVE_IS_UNLOADING
) &&
582 (((PCMHIVE
)Hive
)->CreatorOwner
!= KeGetCurrentThread()))
584 /* It is, don't touch it */
585 return STATUS_OBJECT_NAME_NOT_FOUND
;
588 /* Check if we have a context */
591 /* Check if this is a link create (which shouldn't be an open) */
592 if (Context
->CreateLink
)
594 return STATUS_ACCESS_DENIED
;
597 /* Check if this is symlink create attempt */
598 if (Context
->CreateOptions
& REG_OPTION_CREATE_LINK
)
600 /* Key already exists */
601 return STATUS_OBJECT_NAME_COLLISION
;
604 /* Set the disposition */
605 Context
->Disposition
= REG_OPENED_EXISTING_KEY
;
608 /* Do this in the registry lock */
611 /* If we have a KCB, make sure it's locked */
612 //ASSERT(CmpIsKcbLockedExclusive(*CachedKcb));
614 /* Check if caller doesn't want to create a KCB */
615 if (ControlFlags
& CMP_OPEN_KCB_NO_CREATE
)
617 /* Check if this is a symlink */
618 if ((Node
->Flags
& KEY_SYM_LINK
) && !(Attributes
& OBJ_OPENLINK
))
620 /* This case for a cached KCB is not implemented yet */
624 /* The caller wants to open a cached KCB */
625 if (!CmpReferenceKeyControlBlock(*CachedKcb
))
627 /* Release the registry lock */
630 /* Return failure code */
631 return STATUS_INSUFFICIENT_RESOURCES
;
634 /* Our kcb is that one */
639 /* Check if this is a symlink */
640 if ((Node
->Flags
& KEY_SYM_LINK
) && !(Attributes
& OBJ_OPENLINK
))
642 /* Create the KCB for the symlink */
643 Kcb
= CmpCreateKeyControlBlock(Hive
,
651 /* Release registry lock and return failure */
653 return STATUS_INSUFFICIENT_RESOURCES
;
656 /* Make sure it's also locked, and set the pointer */
657 //ASSERT(CmpIsKcbLockedExclusive(Kcb));
660 /* Release the registry lock */
663 /* Return reparse required */
664 return STATUS_REPARSE
;
667 /* Create the KCB. FIXME: Use lock flag */
668 Kcb
= CmpCreateKeyControlBlock(Hive
,
676 /* Release registry lock and return failure */
678 return STATUS_INSUFFICIENT_RESOURCES
;
682 /* Make sure it's also locked, and set the pointer */
683 //ASSERT(CmpIsKcbLockedExclusive(Kcb));
686 /* Release the registry lock */
689 /* Allocate the key object */
690 Status
= ObCreateObject(AccessMode
,
699 if (NT_SUCCESS(Status
))
701 /* Get the key body and fill it out */
702 KeyBody
= (PCM_KEY_BODY
)(*Object
);
703 KeyBody
->KeyControlBlock
= Kcb
;
704 KeyBody
->Type
= '20yk';
705 KeyBody
->ProcessID
= PsGetCurrentProcessId();
706 KeyBody
->NotifyBlock
= NULL
;
708 /* Link to the KCB */
709 EnlistKeyBodyWithKCB(KeyBody
, 0);
711 if (!ObCheckObjectAccess(*Object
,
717 /* Access check failed */
718 ObDereferenceObject(*Object
);
723 /* Failed, dereference the KCB */
724 CmpDereferenceKeyControlBlockWithLock(Kcb
, FALSE
);
731 /* Remove calls to CmCreateRootNode once this is used! */
734 CmpCreateLinkNode(IN PHHIVE Hive
,
736 IN PACCESS_STATE AccessState
,
737 IN UNICODE_STRING Name
,
738 IN KPROCESSOR_MODE AccessMode
,
739 IN ULONG CreateOptions
,
740 IN PCM_PARSE_CONTEXT Context
,
741 IN PCM_KEY_CONTROL_BLOCK ParentKcb
,
745 HCELL_INDEX KeyCell
, LinkCell
, ChildCell
;
746 PCM_KEY_BODY KeyBody
;
747 LARGE_INTEGER TimeStamp
;
748 PCM_KEY_NODE KeyNode
;
749 PCM_KEY_CONTROL_BLOCK Kcb
= ParentKcb
;
751 CMP_ASSERT_REGISTRY_LOCK();
754 /* Link nodes only allowed on the master */
755 if (Hive
!= &CmiVolatileHive
->Hive
)
758 DPRINT1("Invalid link node attempt\n");
759 return STATUS_ACCESS_DENIED
;
762 /* Acquire the flusher locks */
763 ExAcquirePushLockShared((PVOID
)&((PCMHIVE
)Hive
)->FlusherLock
);
764 ExAcquirePushLockShared((PVOID
)&((PCMHIVE
)Context
->ChildHive
.KeyHive
)->FlusherLock
);
766 /* Check if the parent is being deleted */
767 if (ParentKcb
->Delete
)
771 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
775 /* Allocate a link node */
776 LinkCell
= HvAllocateCell(Hive
,
777 FIELD_OFFSET(CM_KEY_NODE
, Name
) +
778 CmpNameSize(Hive
, &Name
),
781 if (LinkCell
== HCELL_NIL
)
784 Status
= STATUS_INSUFFICIENT_RESOURCES
;
788 /* Get the key cell */
789 KeyCell
= Context
->ChildHive
.KeyCell
;
790 if (KeyCell
!= HCELL_NIL
)
795 /* Get the node data */
796 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Context
->ChildHive
.KeyHive
, ChildCell
);
801 Status
= STATUS_INSUFFICIENT_RESOURCES
;
805 /* Fill out the data */
806 KeyNode
->Parent
= LinkCell
;
807 KeyNode
->Flags
|= KEY_HIVE_ENTRY
| KEY_NO_DELETE
;
808 HvReleaseCell(Context
->ChildHive
.KeyHive
, ChildCell
);
810 /* Now open the key cell */
811 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Context
->ChildHive
.KeyHive
, KeyCell
);
816 Status
= STATUS_INSUFFICIENT_RESOURCES
;
820 /* Open the parent */
821 Status
= CmpDoOpen(Context
->ChildHive
.KeyHive
,
832 HvReleaseCell(Context
->ChildHive
.KeyHive
, KeyCell
);
836 /* Do the actual create operation */
837 Status
= CmpDoCreateChild(Context
->ChildHive
.KeyHive
,
845 KEY_HIVE_ENTRY
| KEY_NO_DELETE
,
848 if (NT_SUCCESS(Status
))
850 /* Setup root pointer */
851 Context
->ChildHive
.KeyHive
->BaseBlock
->RootCell
= ChildCell
;
855 /* Check if open or create suceeded */
856 if (NT_SUCCESS(Status
))
858 /* Mark the cell dirty */
859 HvMarkCellDirty(Context
->ChildHive
.KeyHive
, ChildCell
, FALSE
);
861 /* Get the key node */
862 KeyNode
= HvGetCell(Context
->ChildHive
.KeyHive
, ChildCell
);
867 Status
= STATUS_INSUFFICIENT_RESOURCES
;
872 HvReleaseCell(Context
->ChildHive
.KeyHive
, ChildCell
);
874 /* Set the parent and flags */
875 KeyNode
->Parent
= LinkCell
;
876 KeyNode
->Flags
|= KEY_HIVE_ENTRY
| KEY_NO_DELETE
;
878 /* Get the link node */
879 KeyNode
= HvGetCell(Hive
, LinkCell
);
884 Status
= STATUS_INSUFFICIENT_RESOURCES
;
889 KeyNode
->Signature
= CM_LINK_NODE_SIGNATURE
;
890 KeyNode
->Flags
= KEY_HIVE_EXIT
| KEY_NO_DELETE
;
891 KeyNode
->Parent
= Cell
;
892 KeyNode
->NameLength
= CmpCopyName(Hive
, KeyNode
->Name
, &Name
);
893 if (KeyNode
->NameLength
< Name
.Length
) KeyNode
->Flags
|= KEY_COMP_NAME
;
894 KeQuerySystemTime(&TimeStamp
);
895 KeyNode
->LastWriteTime
= TimeStamp
;
897 /* Clear out the rest */
898 KeyNode
->SubKeyCounts
[Stable
] = 0;
899 KeyNode
->SubKeyCounts
[Volatile
] = 0;
900 KeyNode
->SubKeyLists
[Stable
] = HCELL_NIL
;
901 KeyNode
->SubKeyLists
[Volatile
] = HCELL_NIL
;
902 KeyNode
->ValueList
.Count
= 0;
903 KeyNode
->ValueList
.List
= HCELL_NIL
;
904 KeyNode
->ClassLength
= 0;
906 /* Reference the root node */
907 KeyNode
->ChildHiveReference
.KeyHive
= Context
->ChildHive
.KeyHive
;
908 KeyNode
->ChildHiveReference
.KeyCell
= ChildCell
;
909 HvReleaseCell(Hive
, LinkCell
);
911 /* Get the parent node */
912 KeyNode
= HvGetCell(Hive
, Cell
);
917 Status
= STATUS_INSUFFICIENT_RESOURCES
;
921 /* Now add the subkey */
922 if (!CmpAddSubKey(Hive
, Cell
, LinkCell
))
924 /* Failure! We don't handle this yet! */
928 /* Get the key body */
929 KeyBody
= (PCM_KEY_BODY
)*Object
;
932 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
->KeyCell
== Cell
);
933 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
->KeyHive
== Hive
);
934 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
->KcbMaxNameLen
== KeyNode
->MaxNameLen
);
936 /* Update the timestamp */
937 KeQuerySystemTime(&TimeStamp
);
938 KeyNode
->LastWriteTime
= TimeStamp
;
939 KeyBody
->KeyControlBlock
->ParentKcb
->KcbLastWriteTime
= TimeStamp
;
941 /* Check if we need to update name maximum */
942 if (KeyNode
->MaxNameLen
< Name
.Length
)
945 KeyNode
->MaxNameLen
= Name
.Length
;
946 KeyBody
->KeyControlBlock
->ParentKcb
->KcbMaxNameLen
= Name
.Length
;
949 /* Check if we need toupdate class length maximum */
950 if (KeyNode
->MaxClassLen
< Context
->Class
.Length
)
953 KeyNode
->MaxClassLen
= Context
->Class
.Length
;
956 /* Release the cell */
957 HvReleaseCell(Hive
, Cell
);
961 /* Release the link cell */
962 HvReleaseCell(Hive
, LinkCell
);
966 /* Release the flusher locks and return status */
967 ExReleasePushLock((PVOID
)&((PCMHIVE
)Context
->ChildHive
.KeyHive
)->FlusherLock
);
968 ExReleasePushLock((PVOID
)&((PCMHIVE
)Hive
)->FlusherLock
);
974 CmpHandleExitNode(IN OUT PHHIVE
*Hive
,
975 IN OUT HCELL_INDEX
*Cell
,
976 IN OUT PCM_KEY_NODE
*KeyNode
,
977 IN OUT PHHIVE
*ReleaseHive
,
978 IN OUT HCELL_INDEX
*ReleaseCell
)
980 /* Check if we have anything to release */
981 if (*ReleaseCell
!= HCELL_NIL
)
984 ASSERT(*ReleaseHive
!= NULL
);
985 HvReleaseCell((*ReleaseHive
), *ReleaseCell
);
988 /* Get the link references */
989 *Hive
= (*KeyNode
)->ChildHiveReference
.KeyHive
;
990 *Cell
= (*KeyNode
)->ChildHiveReference
.KeyCell
;
992 /* Get the new node */
993 *KeyNode
= (PCM_KEY_NODE
)HvGetCell((*Hive
), *Cell
);
996 /* Set the new release values */
997 *ReleaseCell
= *Cell
;
998 *ReleaseHive
= *Hive
;
1002 /* Nothing to release */
1003 *ReleaseCell
= HCELL_NIL
;
1004 *ReleaseHive
= NULL
;
1010 CmpBuildHashStackAndLookupCache(IN PCM_KEY_BODY ParseObject
,
1011 IN OUT PCM_KEY_CONTROL_BLOCK
*Kcb
,
1012 IN PUNICODE_STRING Current
,
1014 OUT HCELL_INDEX
*Cell
,
1015 OUT PULONG TotalRemainingSubkeys
,
1016 OUT PULONG MatchRemainSubkeyLevel
,
1017 OUT PULONG TotalSubkeys
,
1018 OUT PULONG OuterStackArray
,
1019 OUT PULONG
*LockedKcbs
)
1023 /* We don't lock anything for now */
1026 /* Make a copy of the hash key */
1027 HashKeyCopy
= (*Kcb
)->ConvKey
;
1029 /* Calculate hash values */
1030 *TotalRemainingSubkeys
= 0xBAADF00D;
1032 /* Lock the registry */
1035 /* Return hive and cell data */
1036 *Hive
= (*Kcb
)->KeyHive
;
1037 *Cell
= (*Kcb
)->KeyCell
;
1039 /* Make sure it's not a dead KCB */
1040 ASSERT((*Kcb
)->RefCount
> 0);
1043 (VOID
)CmpReferenceKeyControlBlock(*Kcb
);
1045 /* Return success for now */
1046 return STATUS_SUCCESS
;
1051 CmpParseKey(IN PVOID ParseObject
,
1052 IN PVOID ObjectType
,
1053 IN OUT PACCESS_STATE AccessState
,
1054 IN KPROCESSOR_MODE AccessMode
,
1055 IN ULONG Attributes
,
1056 IN OUT PUNICODE_STRING CompleteName
,
1057 IN OUT PUNICODE_STRING RemainingName
,
1058 IN OUT PVOID Context OPTIONAL
,
1059 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
1063 PCM_KEY_CONTROL_BLOCK Kcb
, ParentKcb
;
1065 PCM_KEY_NODE Node
= NULL
;
1066 HCELL_INDEX Cell
= HCELL_NIL
, NextCell
;
1067 PHHIVE HiveToRelease
= NULL
;
1068 HCELL_INDEX CellToRelease
= HCELL_NIL
;
1069 UNICODE_STRING Current
, NextName
;
1070 PCM_PARSE_CONTEXT ParseContext
= Context
;
1071 ULONG TotalRemainingSubkeys
= 0, MatchRemainSubkeyLevel
= 0, TotalSubkeys
= 0;
1072 PULONG LockedKcbs
= NULL
;
1073 BOOLEAN Result
, Last
;
1076 /* Loop path separators at the end */
1077 while ((RemainingName
->Length
) &&
1078 (RemainingName
->Buffer
[(RemainingName
->Length
/ sizeof(WCHAR
)) - 1] ==
1079 OBJ_NAME_PATH_SEPARATOR
))
1081 /* Remove path separator */
1082 RemainingName
->Length
-= sizeof(WCHAR
);
1085 /* Fail if this isn't a key object */
1086 if (ObjectType
!= CmpKeyObjectType
) return STATUS_OBJECT_TYPE_MISMATCH
;
1088 /* Copy the remaining name */
1089 Current
= *RemainingName
;
1091 /* Check if this is a create */
1092 if (!(ParseContext
) || !(ParseContext
->CreateOperation
))
1094 /* It isn't, so no context */
1095 ParseContext
= NULL
;
1099 Kcb
= ((PCM_KEY_BODY
)ParseObject
)->KeyControlBlock
;
1101 /* Lookup in the cache */
1102 Status
= CmpBuildHashStackAndLookupCache(ParseObject
,
1107 &TotalRemainingSubkeys
,
1108 &MatchRemainSubkeyLevel
,
1113 /* This is now the parent */
1116 /* Check if everything was found cached */
1117 if (!TotalRemainingSubkeys
) ASSERTMSG("Caching not implemented", FALSE
);
1119 /* Don't do anything if we're being deleted */
1122 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1126 /* Check if this is a symlink */
1127 if (Kcb
->Flags
& KEY_SYM_LINK
)
1129 /* Get the next name */
1130 Result
= CmpGetNextName(&Current
, &NextName
, &Last
);
1131 Current
.Buffer
= NextName
.Buffer
;
1133 /* Validate the current name string length */
1134 if (Current
.Length
+ NextName
.Length
> MAXUSHORT
)
1137 Status
= STATUS_NAME_TOO_LONG
;
1140 Current
.Length
+= NextName
.Length
;
1142 /* Validate the current name string maximum length */
1143 if (Current
.MaximumLength
+ NextName
.MaximumLength
> MAXUSHORT
)
1146 Status
= STATUS_NAME_TOO_LONG
;
1149 Current
.MaximumLength
+= NextName
.MaximumLength
;
1151 /* Parse the symlink */
1152 if (CmpGetSymbolicLink(Hive
,
1157 /* Symlink parse succeeded */
1158 Status
= STATUS_REPARSE
;
1162 /* Couldn't find symlink */
1163 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1170 /* Get the key node */
1171 Node
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
1174 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1179 Status
= STATUS_NOT_IMPLEMENTED
;
1182 /* Get the next component */
1183 Result
= CmpGetNextName(&Current
, &NextName
, &Last
);
1184 if ((Result
) && (NextName
.Length
))
1186 /* See if this is a sym link */
1187 if (!(Kcb
->Flags
& KEY_SYM_LINK
))
1189 /* Find the subkey */
1190 NextCell
= CmpFindSubKeyByName(Hive
, Node
, &NextName
);
1191 if (NextCell
!= HCELL_NIL
)
1193 /* Get the new node */
1195 Node
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
1196 if (!Node
) ASSERT(FALSE
);
1198 /* Check if this was the last key */
1201 /* Is this an exit node */
1202 if (Node
->Flags
& KEY_HIVE_EXIT
)
1205 CmpHandleExitNode(&Hive
,
1210 if (!Node
) ASSERT(FALSE
);
1214 Status
= CmpDoOpen(Hive
,
1225 if (Status
== STATUS_REPARSE
)
1227 /* Parse the symlink */
1228 if (!CmpGetSymbolicLink(Hive
,
1233 /* Symlink parse failed */
1234 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1242 /* Is this an exit node */
1243 if (Node
->Flags
& KEY_HIVE_EXIT
)
1246 CmpHandleExitNode(&Hive
,
1251 if (!Node
) ASSERT(FALSE
);
1254 /* Create a KCB for this key */
1255 Kcb
= CmpCreateKeyControlBlock(Hive
,
1261 if (!Kcb
) ASSERT(FALSE
);
1263 /* Dereference the parent and set the new one */
1264 CmpDereferenceKeyControlBlock(ParentKcb
);
1269 /* Check if this was the last key for a create */
1270 if ((Last
) && (ParseContext
))
1272 /* Check if we're doing a link node */
1273 if (ParseContext
->CreateLink
)
1275 /* The only thing we should see */
1276 Status
= CmpCreateLinkNode(Hive
,
1289 Status
= CmpDoCreate(Hive
,
1299 /* Check for reparse (in this case, someone beat us) */
1300 if (Status
== STATUS_REPARSE
) break;
1302 /* Update disposition */
1303 ParseContext
->Disposition
= REG_CREATED_NEW_KEY
;
1309 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1316 /* Save the next name */
1317 Current
.Buffer
= NextName
.Buffer
;
1319 /* Validate the current name string length */
1320 if (Current
.Length
+ NextName
.Length
> MAXUSHORT
)
1323 Status
= STATUS_NAME_TOO_LONG
;
1326 Current
.Length
+= NextName
.Length
;
1328 /* Validate the current name string maximum length */
1329 if (Current
.MaximumLength
+ NextName
.MaximumLength
> MAXUSHORT
)
1332 Status
= STATUS_NAME_TOO_LONG
;
1335 Current
.MaximumLength
+= NextName
.MaximumLength
;
1337 /* Parse the symlink */
1338 if (CmpGetSymbolicLink(Hive
,
1343 /* Symlink parse succeeded */
1344 Status
= STATUS_REPARSE
;
1348 /* Couldn't find symlink */
1349 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1356 else if ((Result
) && (Last
))
1358 /* Opening the root. Is this an exit node? */
1359 if (Node
->Flags
& KEY_HIVE_EXIT
)
1362 CmpHandleExitNode(&Hive
,
1367 if (!Node
) ASSERT(FALSE
);
1371 Status
= CmpDoOpen(Hive
,
1378 CMP_OPEN_KCB_NO_CREATE
/* | CMP_CREATE_KCB_KCB_LOCKED */,
1382 if (Status
== STATUS_REPARSE
)
1393 Status
= STATUS_INVALID_PARAMETER
;
1398 /* Dereference the parent if it exists */
1400 if (ParentKcb
) CmpDereferenceKeyControlBlock(ParentKcb
);
1402 /* Unlock the registry */
1403 CmpUnlockRegistry();