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
;
228 /* Get the storage type */
229 StorageType
= Stable
;
230 if (Flags
& REG_OPTION_VOLATILE
) StorageType
= Volatile
;
232 /* Allocate the child */
233 *KeyCell
= HvAllocateCell(Hive
,
234 FIELD_OFFSET(CM_KEY_NODE
, Name
) +
235 CmpNameSize(Hive
, Name
),
238 if (*KeyCell
== HCELL_NIL
)
241 Status
= STATUS_INSUFFICIENT_RESOURCES
;
245 /* Get the key node */
246 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, *KeyCell
);
249 /* Fail, this should never happen */
251 Status
= STATUS_INSUFFICIENT_RESOURCES
;
255 /* Release the cell */
256 HvReleaseCell(Hive
, *KeyCell
);
258 /* Check if we have a class name */
259 if (ParseContext
->Class
.Length
> 0)
261 /* Allocate a class cell */
262 ClassCell
= HvAllocateCell(Hive
,
263 ParseContext
->Class
.Length
,
266 if (ClassCell
== HCELL_NIL
)
269 Status
= STATUS_INSUFFICIENT_RESOURCES
;
274 /* Allocate the Cm Object */
275 Status
= ObCreateObject(AccessMode
,
284 if (!NT_SUCCESS(Status
)) goto Quickie
;
286 /* Setup the key body */
287 KeyBody
= (PCM_KEY_BODY
)(*Object
);
288 KeyBody
->Type
= TAG('k', 'y', '0', '2');
289 KeyBody
->KeyControlBlock
= NULL
;
291 /* Check if we had a class */
292 if (ParseContext
->Class
.Length
> 0)
294 /* Get the class cell */
295 CellData
= HvGetCell(Hive
, ClassCell
);
298 /* Fail, this should never happen */
300 Status
= STATUS_INSUFFICIENT_RESOURCES
;
301 ObDereferenceObject(*Object
);
305 /* Release the cell */
306 HvReleaseCell(Hive
, ClassCell
);
308 /* Copy the class data */
309 RtlCopyMemory(&CellData
->u
.KeyString
[0],
310 ParseContext
->Class
.Buffer
,
311 ParseContext
->Class
.Length
);
314 /* Fill out the key node */
315 KeyNode
->Signature
= CM_KEY_NODE_SIGNATURE
;
316 KeyNode
->Flags
= Flags
&~ REG_OPTION_CREATE_LINK
;
317 KeQuerySystemTime(&SystemTime
);
318 KeyNode
->LastWriteTime
= SystemTime
;
320 KeyNode
->Parent
= ParentCell
;
321 KeyNode
->SubKeyCounts
[Stable
] = 0;
322 KeyNode
->SubKeyCounts
[Volatile
] = 0;
323 KeyNode
->SubKeyLists
[Stable
] = HCELL_NIL
;
324 KeyNode
->SubKeyLists
[Volatile
] = HCELL_NIL
;
325 KeyNode
->ValueList
.Count
= 0;
326 KeyNode
->ValueList
.List
= HCELL_NIL
;
327 KeyNode
->Security
= HCELL_NIL
;
328 KeyNode
->Class
= ClassCell
;
329 KeyNode
->ClassLength
= ParseContext
->Class
.Length
;
330 KeyNode
->MaxValueDataLen
= 0;
331 KeyNode
->MaxNameLen
= 0;
332 KeyNode
->MaxValueNameLen
= 0;
333 KeyNode
->MaxClassLen
= 0;
334 KeyNode
->NameLength
= CmpCopyName(Hive
, KeyNode
->Name
, Name
);
335 if (KeyNode
->NameLength
< Name
->Length
) KeyNode
->Flags
|= KEY_COMP_NAME
;
338 Kcb
= CmpCreateKeyControlBlock(Hive
,
342 0, // CMP_LOCK_HASHES_FOR_KCB,
347 ObDereferenceObjectDeferDelete(*Object
);
348 Status
= STATUS_INSUFFICIENT_RESOURCES
;
353 ASSERT(Kcb
->RefCount
== 1);
355 /* Now fill out the Cm object */
356 KeyBody
->NotifyBlock
= NULL
;
357 KeyBody
->ProcessID
= PsGetCurrentProcessId();
358 KeyBody
->KeyControlBlock
= Kcb
;
360 /* Link it with the KCB */
361 EnlistKeyBodyWithKCB(KeyBody
, 0);
364 /* Check if we got here because of failure */
365 if (!NT_SUCCESS(Status
))
367 /* Free any cells we might've allocated */
368 if (ParseContext
->Class
.Length
> 0) HvFreeCell(Hive
, ClassCell
);
369 HvFreeCell(Hive
, *KeyCell
);
378 CmpDoCreate(IN PHHIVE Hive
,
380 IN PACCESS_STATE AccessState
,
381 IN PUNICODE_STRING Name
,
382 IN KPROCESSOR_MODE AccessMode
,
383 IN PCM_PARSE_CONTEXT ParseContext
,
384 IN PCM_KEY_CONTROL_BLOCK ParentKcb
,
391 PCM_KEY_BODY KeyBody
;
392 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
393 LARGE_INTEGER TimeStamp
;
394 PCM_KEY_NODE KeyNode
;
398 ASSERT((CmpIsKcbLockedExclusive(ParentKcb
) == TRUE
) ||
399 (CmpTestRegistryLockExclusive() == TRUE
));
402 /* Acquire the flusher lock */
403 ExAcquirePushLockShared((PVOID
)&((PCMHIVE
)Hive
)->FlusherLock
);
405 /* Check if the parent is being deleted */
406 if (ParentKcb
->Delete
)
410 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
414 /* Get the parent node */
415 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
420 Status
= STATUS_INSUFFICIENT_RESOURCES
;
424 /* Make sure nobody added us yet */
425 if (CmpFindSubKeyByName(Hive
, KeyNode
, Name
) != HCELL_NIL
)
429 Status
= STATUS_REPARSE
;
434 ASSERT(Cell
== ParentKcb
->KeyCell
);
436 /* Get the parent type */
437 ParentType
= HvGetCellType(Cell
);
438 if ((ParentType
== Volatile
) &&
439 !(ParseContext
->CreateOptions
& REG_OPTION_VOLATILE
))
441 /* Children of volatile parents must also be volatile */
443 Status
= STATUS_CHILD_MUST_BE_VOLATILE
;
447 /* Don't allow children under symlinks */
448 if (ParentKcb
->Flags
& KEY_SYM_LINK
)
452 Status
= STATUS_ACCESS_DENIED
;
456 /* Make the cell dirty for now */
457 HvMarkCellDirty(Hive
, Cell
, FALSE
);
459 /* Do the actual create operation */
460 Status
= CmpDoCreateChild(Hive
,
468 ParseContext
->CreateOptions
, // WRONG!
471 if (NT_SUCCESS(Status
))
473 /* Get the key body */
474 KeyBody
= (PCM_KEY_BODY
)(*Object
);
476 /* Now add the subkey */
477 if (!CmpAddSubKey(Hive
, Cell
, KeyCell
))
479 /* Failure! We don't handle this yet! */
483 /* Get the key node */
484 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
487 /* Fail, this shouldn't happen */
492 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
->KeyCell
== Cell
);
493 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
->KeyHive
== Hive
);
494 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
== ParentKcb
);
495 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
->KcbMaxNameLen
== KeyNode
->MaxNameLen
);
497 /* Update the timestamp */
498 KeQuerySystemTime(&TimeStamp
);
499 KeyNode
->LastWriteTime
= TimeStamp
;
500 KeyBody
->KeyControlBlock
->ParentKcb
->KcbLastWriteTime
= TimeStamp
;
502 /* Check if we need to update name maximum */
503 if (KeyNode
->MaxNameLen
< Name
->Length
)
506 KeyNode
->MaxNameLen
= Name
->Length
;
507 KeyBody
->KeyControlBlock
->ParentKcb
->KcbMaxNameLen
= Name
->Length
;
510 /* Check if we need toupdate class length maximum */
511 if (KeyNode
->MaxClassLen
< ParseContext
->Class
.Length
)
514 KeyNode
->MaxClassLen
= ParseContext
->Class
.Length
;
517 /* Check if we're creating a symbolic link */
518 if (ParseContext
->CreateOptions
& REG_OPTION_CREATE_LINK
)
520 /* Get the cell data */
521 CellData
= HvGetCell(Hive
, KeyCell
);
524 /* This shouldn't happen */
528 /* Update the flags */
529 CellData
->u
.KeyNode
.Flags
|= KEY_SYM_LINK
;
530 KeyBody
->KeyControlBlock
->Flags
= CellData
->u
.KeyNode
.Flags
;
531 HvReleaseCell(Hive
, KeyCell
);
536 /* Release the flusher lock and return status */
537 ExReleasePushLock((PVOID
)&((PCMHIVE
)Hive
)->FlusherLock
);
543 CmpDoOpen(IN PHHIVE Hive
,
545 IN PCM_KEY_NODE Node
,
546 IN PACCESS_STATE AccessState
,
547 IN KPROCESSOR_MODE AccessMode
,
549 IN PCM_PARSE_CONTEXT Context OPTIONAL
,
550 IN ULONG ControlFlags
,
551 IN OUT PCM_KEY_CONTROL_BLOCK
*CachedKcb
,
552 IN PUNICODE_STRING KeyName
,
556 PCM_KEY_BODY KeyBody
= NULL
;
557 PCM_KEY_CONTROL_BLOCK Kcb
= NULL
;
559 /* Make sure the hive isn't locked */
560 if ((Hive
->HiveFlags
& HIVE_IS_UNLOADING
) &&
561 (((PCMHIVE
)Hive
)->CreatorOwner
!= KeGetCurrentThread()))
563 /* It is, don't touch it */
564 return STATUS_OBJECT_NAME_NOT_FOUND
;
567 /* Check if we have a context */
570 /* Check if this is a link create (which shouldn't be an open) */
571 if (Context
->CreateLink
)
573 return STATUS_ACCESS_DENIED
;
576 /* Check if this is symlink create attempt */
577 if (Context
->CreateOptions
& REG_OPTION_CREATE_LINK
)
579 /* Key already exists */
580 return STATUS_OBJECT_NAME_COLLISION
;
583 /* Set the disposition */
584 Context
->Disposition
= REG_OPENED_EXISTING_KEY
;
587 /* Do this in the registry lock */
590 /* If we have a KCB, make sure it's locked */
591 //ASSERT(CmpIsKcbLockedExclusive(*CachedKcb));
593 /* Check if caller doesn't want to create a KCB */
594 if (ControlFlags
& CMP_OPEN_KCB_NO_CREATE
)
596 /* Check if this is a symlink */
597 if ((Node
->Flags
& KEY_SYM_LINK
) && !(Attributes
& OBJ_OPENLINK
))
599 /* This case for a cached KCB is not implemented yet */
603 /* The caller wants to open a cached KCB */
604 if (!CmpReferenceKeyControlBlock(*CachedKcb
))
606 /* Release the registry lock */
609 /* Return failure code */
610 return STATUS_INSUFFICIENT_RESOURCES
;
613 /* Our kcb is that one */
618 /* Check if this is a symlink */
619 if ((Node
->Flags
& KEY_SYM_LINK
) && !(Attributes
& OBJ_OPENLINK
))
621 /* Create the KCB for the symlink */
622 Kcb
= CmpCreateKeyControlBlock(Hive
,
630 /* Release registry lock and return failure */
632 return STATUS_INSUFFICIENT_RESOURCES
;
635 /* Make sure it's also locked, and set the pointer */
636 //ASSERT(CmpIsKcbLockedExclusive(Kcb));
639 /* Release the registry lock */
642 /* Return reparse required */
643 return STATUS_REPARSE
;
646 /* Create the KCB. FIXME: Use lock flag */
647 Kcb
= CmpCreateKeyControlBlock(Hive
,
655 /* Release registry lock and return failure */
657 return STATUS_INSUFFICIENT_RESOURCES
;
661 /* Make sure it's also locked, and set the pointer */
662 //ASSERT(CmpIsKcbLockedExclusive(Kcb));
665 /* Release the registry lock */
668 /* Allocate the key object */
669 Status
= ObCreateObject(AccessMode
,
678 if (NT_SUCCESS(Status
))
680 /* Get the key body and fill it out */
681 KeyBody
= (PCM_KEY_BODY
)(*Object
);
682 KeyBody
->KeyControlBlock
= Kcb
;
683 KeyBody
->Type
= TAG('k', 'y', '0', '2');
684 KeyBody
->ProcessID
= PsGetCurrentProcessId();
685 KeyBody
->NotifyBlock
= NULL
;
687 /* Link to the KCB */
688 EnlistKeyBodyWithKCB(KeyBody
, 0);
692 /* Failed, dereference the KCB */
693 CmpDereferenceKeyControlBlockWithLock(Kcb
, FALSE
);
700 /* Remove calls to CmCreateRootNode once this is used! */
703 CmpCreateLinkNode(IN PHHIVE Hive
,
705 IN PACCESS_STATE AccessState
,
706 IN UNICODE_STRING Name
,
707 IN KPROCESSOR_MODE AccessMode
,
708 IN ULONG CreateOptions
,
709 IN PCM_PARSE_CONTEXT Context
,
710 IN PCM_KEY_CONTROL_BLOCK ParentKcb
,
714 HCELL_INDEX KeyCell
, LinkCell
, ChildCell
;
715 PCM_KEY_BODY KeyBody
;
716 LARGE_INTEGER TimeStamp
;
717 PCM_KEY_NODE KeyNode
;
718 PCM_KEY_CONTROL_BLOCK Kcb
= ParentKcb
;
720 CMP_ASSERT_REGISTRY_LOCK();
723 /* Link nodes only allowed on the master */
724 if (Hive
!= &CmiVolatileHive
->Hive
)
727 DPRINT1("Invalid link node attempt\n");
728 return STATUS_ACCESS_DENIED
;
731 /* Acquire the flusher locks */
732 ExAcquirePushLockShared((PVOID
)&((PCMHIVE
)Hive
)->FlusherLock
);
733 ExAcquirePushLockShared((PVOID
)&((PCMHIVE
)Context
->ChildHive
.KeyHive
)->FlusherLock
);
735 /* Check if the parent is being deleted */
736 if (ParentKcb
->Delete
)
740 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
744 /* Allocate a link node */
745 LinkCell
= HvAllocateCell(Hive
,
746 FIELD_OFFSET(CM_KEY_NODE
, Name
) +
747 CmpNameSize(Hive
, &Name
),
750 if (LinkCell
== HCELL_NIL
)
753 Status
= STATUS_INSUFFICIENT_RESOURCES
;
757 /* Get the key cell */
758 KeyCell
= Context
->ChildHive
.KeyCell
;
759 if (KeyCell
!= HCELL_NIL
)
764 /* Get the node data */
765 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Context
->ChildHive
.KeyHive
, ChildCell
);
770 Status
= STATUS_INSUFFICIENT_RESOURCES
;
774 /* Fill out the data */
775 KeyNode
->Parent
= LinkCell
;
776 KeyNode
->Flags
|= KEY_HIVE_ENTRY
| KEY_NO_DELETE
;
777 HvReleaseCell(Context
->ChildHive
.KeyHive
, ChildCell
);
779 /* Now open the key cell */
780 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Context
->ChildHive
.KeyHive
, KeyCell
);
785 Status
= STATUS_INSUFFICIENT_RESOURCES
;
789 /* Open the parent */
790 Status
= CmpDoOpen(Context
->ChildHive
.KeyHive
,
801 HvReleaseCell(Context
->ChildHive
.KeyHive
, KeyCell
);
805 /* Do the actual create operation */
806 Status
= CmpDoCreateChild(Context
->ChildHive
.KeyHive
,
814 KEY_HIVE_ENTRY
| KEY_NO_DELETE
,
817 if (NT_SUCCESS(Status
))
819 /* Setup root pointer */
820 Context
->ChildHive
.KeyHive
->BaseBlock
->RootCell
= ChildCell
;
824 /* Check if open or create suceeded */
825 if (NT_SUCCESS(Status
))
827 /* Mark the cell dirty */
828 HvMarkCellDirty(Context
->ChildHive
.KeyHive
, ChildCell
, FALSE
);
830 /* Get the key node */
831 KeyNode
= HvGetCell(Context
->ChildHive
.KeyHive
, ChildCell
);
836 Status
= STATUS_INSUFFICIENT_RESOURCES
;
841 HvReleaseCell(Context
->ChildHive
.KeyHive
, ChildCell
);
843 /* Set the parent and flags */
844 KeyNode
->Parent
= LinkCell
;
845 KeyNode
->Flags
|= KEY_HIVE_ENTRY
| KEY_NO_DELETE
;
847 /* Get the link node */
848 KeyNode
= HvGetCell(Hive
, LinkCell
);
853 Status
= STATUS_INSUFFICIENT_RESOURCES
;
858 KeyNode
->Signature
= CM_LINK_NODE_SIGNATURE
;
859 KeyNode
->Flags
= KEY_HIVE_EXIT
| KEY_NO_DELETE
;
860 KeyNode
->Parent
= Cell
;
861 KeyNode
->NameLength
= CmpCopyName(Hive
, KeyNode
->Name
, &Name
);
862 if (KeyNode
->NameLength
< Name
.Length
) KeyNode
->Flags
|= KEY_COMP_NAME
;
863 KeQuerySystemTime(&TimeStamp
);
864 KeyNode
->LastWriteTime
= TimeStamp
;
866 /* Clear out the rest */
867 KeyNode
->SubKeyCounts
[Stable
] = 0;
868 KeyNode
->SubKeyCounts
[Volatile
] = 0;
869 KeyNode
->SubKeyLists
[Stable
] = HCELL_NIL
;
870 KeyNode
->SubKeyLists
[Volatile
] = HCELL_NIL
;
871 KeyNode
->ValueList
.Count
= 0;
872 KeyNode
->ValueList
.List
= HCELL_NIL
;
873 KeyNode
->ClassLength
= 0;
875 /* Reference the root node */
876 KeyNode
->ChildHiveReference
.KeyHive
= Context
->ChildHive
.KeyHive
;
877 KeyNode
->ChildHiveReference
.KeyCell
= ChildCell
;
878 HvReleaseCell(Hive
, LinkCell
);
880 /* Get the parent node */
881 KeyNode
= HvGetCell(Hive
, Cell
);
886 Status
= STATUS_INSUFFICIENT_RESOURCES
;
890 /* Now add the subkey */
891 if (!CmpAddSubKey(Hive
, Cell
, LinkCell
))
893 /* Failure! We don't handle this yet! */
897 /* Get the key body */
898 KeyBody
= (PCM_KEY_BODY
)*Object
;
901 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
->KeyCell
== Cell
);
902 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
->KeyHive
== Hive
);
903 ASSERT(KeyBody
->KeyControlBlock
->ParentKcb
->KcbMaxNameLen
== KeyNode
->MaxNameLen
);
905 /* Update the timestamp */
906 KeQuerySystemTime(&TimeStamp
);
907 KeyNode
->LastWriteTime
= TimeStamp
;
908 KeyBody
->KeyControlBlock
->ParentKcb
->KcbLastWriteTime
= TimeStamp
;
910 /* Check if we need to update name maximum */
911 if (KeyNode
->MaxNameLen
< Name
.Length
)
914 KeyNode
->MaxNameLen
= Name
.Length
;
915 KeyBody
->KeyControlBlock
->ParentKcb
->KcbMaxNameLen
= Name
.Length
;
918 /* Check if we need toupdate class length maximum */
919 if (KeyNode
->MaxClassLen
< Context
->Class
.Length
)
922 KeyNode
->MaxClassLen
= Context
->Class
.Length
;
925 /* Release the cell */
926 HvReleaseCell(Hive
, Cell
);
930 /* Release the link cell */
931 HvReleaseCell(Hive
, LinkCell
);
935 /* Release the flusher locks and return status */
936 ExReleasePushLock((PVOID
)&((PCMHIVE
)Context
->ChildHive
.KeyHive
)->FlusherLock
);
937 ExReleasePushLock((PVOID
)&((PCMHIVE
)Hive
)->FlusherLock
);
943 CmpHandleExitNode(IN OUT PHHIVE
*Hive
,
944 IN OUT HCELL_INDEX
*Cell
,
945 IN OUT PCM_KEY_NODE
*KeyNode
,
946 IN OUT PHHIVE
*ReleaseHive
,
947 IN OUT HCELL_INDEX
*ReleaseCell
)
949 /* Check if we have anything to release */
950 if (*ReleaseCell
!= HCELL_NIL
)
953 ASSERT(*ReleaseHive
!= NULL
);
954 HvReleaseCell((*ReleaseHive
), *ReleaseCell
);
957 /* Get the link references */
958 *Hive
= (*KeyNode
)->ChildHiveReference
.KeyHive
;
959 *Cell
= (*KeyNode
)->ChildHiveReference
.KeyCell
;
961 /* Get the new node */
962 *KeyNode
= (PCM_KEY_NODE
)HvGetCell((*Hive
), *Cell
);
965 /* Set the new release values */
966 *ReleaseCell
= *Cell
;
967 *ReleaseHive
= *Hive
;
971 /* Nothing to release */
972 *ReleaseCell
= HCELL_NIL
;
979 CmpBuildHashStackAndLookupCache(IN PCM_KEY_BODY ParseObject
,
980 IN OUT PCM_KEY_CONTROL_BLOCK
*Kcb
,
981 IN PUNICODE_STRING Current
,
983 OUT HCELL_INDEX
*Cell
,
984 OUT PULONG TotalRemainingSubkeys
,
985 OUT PULONG MatchRemainSubkeyLevel
,
986 OUT PULONG TotalSubkeys
,
987 OUT PULONG OuterStackArray
,
988 OUT PULONG
*LockedKcbs
)
992 /* We don't lock anything for now */
995 /* Make a copy of the hash key */
996 HashKeyCopy
= (*Kcb
)->ConvKey
;
998 /* Calculate hash values */
999 *TotalRemainingSubkeys
= 0xBAADF00D;
1001 /* Lock the registry */
1004 /* Return hive and cell data */
1005 *Hive
= (*Kcb
)->KeyHive
;
1006 *Cell
= (*Kcb
)->KeyCell
;
1008 /* Make sure it's not a dead KCB */
1009 ASSERT((*Kcb
)->RefCount
> 0);
1012 (VOID
)CmpReferenceKeyControlBlock(*Kcb
);
1014 /* Return success for now */
1015 return STATUS_SUCCESS
;
1020 CmpParseKey(IN PVOID ParseObject
,
1021 IN PVOID ObjectType
,
1022 IN OUT PACCESS_STATE AccessState
,
1023 IN KPROCESSOR_MODE AccessMode
,
1024 IN ULONG Attributes
,
1025 IN OUT PUNICODE_STRING CompleteName
,
1026 IN OUT PUNICODE_STRING RemainingName
,
1027 IN OUT PVOID Context OPTIONAL
,
1028 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
1032 PCM_KEY_CONTROL_BLOCK Kcb
, ParentKcb
;
1034 PCM_KEY_NODE Node
= NULL
;
1035 HCELL_INDEX Cell
= HCELL_NIL
, NextCell
;
1036 PHHIVE HiveToRelease
= NULL
;
1037 HCELL_INDEX CellToRelease
= HCELL_NIL
;
1038 UNICODE_STRING Current
, NextName
;
1039 PCM_PARSE_CONTEXT ParseContext
= Context
;
1040 ULONG TotalRemainingSubkeys
= 0, MatchRemainSubkeyLevel
= 0, TotalSubkeys
= 0;
1041 PULONG LockedKcbs
= NULL
;
1042 BOOLEAN Result
, Last
;
1045 /* Loop path separators at the end */
1046 while ((RemainingName
->Length
) &&
1047 (RemainingName
->Buffer
[(RemainingName
->Length
/ sizeof(WCHAR
)) - 1] ==
1048 OBJ_NAME_PATH_SEPARATOR
))
1050 /* Remove path separator */
1051 RemainingName
->Length
-= sizeof(WCHAR
);
1054 /* Fail if this isn't a key object */
1055 if (ObjectType
!= CmpKeyObjectType
) return STATUS_OBJECT_TYPE_MISMATCH
;
1057 /* Copy the remaining name */
1058 Current
= *RemainingName
;
1060 /* Check if this is a create */
1061 if (!(ParseContext
) || !(ParseContext
->CreateOperation
))
1063 /* It isn't, so no context */
1064 ParseContext
= NULL
;
1068 Kcb
= ((PCM_KEY_BODY
)ParseObject
)->KeyControlBlock
;
1070 /* Lookup in the cache */
1071 Status
= CmpBuildHashStackAndLookupCache(ParseObject
,
1076 &TotalRemainingSubkeys
,
1077 &MatchRemainSubkeyLevel
,
1082 /* This is now the parent */
1085 /* Check if everything was found cached */
1086 if (!TotalRemainingSubkeys
) ASSERTMSG("Caching not implemented", FALSE
);
1088 /* Don't do anything if we're being deleted */
1091 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1095 /* Check if this is a symlink */
1096 if (Kcb
->Flags
& KEY_SYM_LINK
)
1098 /* Get the next name */
1099 Result
= CmpGetNextName(&Current
, &NextName
, &Last
);
1100 Current
.Buffer
= NextName
.Buffer
;
1102 /* Validate the current name string length */
1103 if (Current
.Length
+ NextName
.Length
> MAXUSHORT
)
1106 Status
= STATUS_NAME_TOO_LONG
;
1109 Current
.Length
+= NextName
.Length
;
1111 /* Validate the current name string maximum length */
1112 if (Current
.MaximumLength
+ NextName
.MaximumLength
> MAXUSHORT
)
1115 Status
= STATUS_NAME_TOO_LONG
;
1118 Current
.MaximumLength
+= NextName
.MaximumLength
;
1120 /* Parse the symlink */
1121 if (CmpGetSymbolicLink(Hive
,
1126 /* Symlink parse succeeded */
1127 Status
= STATUS_REPARSE
;
1131 /* Couldn't find symlink */
1132 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1139 /* Get the key node */
1140 Node
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
1143 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1148 Status
= STATUS_NOT_IMPLEMENTED
;
1151 /* Get the next component */
1152 Result
= CmpGetNextName(&Current
, &NextName
, &Last
);
1153 if ((Result
) && (NextName
.Length
))
1155 /* See if this is a sym link */
1156 if (!(Kcb
->Flags
& KEY_SYM_LINK
))
1158 /* Find the subkey */
1159 NextCell
= CmpFindSubKeyByName(Hive
, Node
, &NextName
);
1160 if (NextCell
!= HCELL_NIL
)
1162 /* Get the new node */
1164 Node
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
1165 if (!Node
) ASSERT(FALSE
);
1167 /* Check if this was the last key */
1170 /* Is this an exit node */
1171 if (Node
->Flags
& KEY_HIVE_EXIT
)
1174 CmpHandleExitNode(&Hive
,
1179 if (!Node
) ASSERT(FALSE
);
1183 Status
= CmpDoOpen(Hive
,
1194 if (Status
== STATUS_REPARSE
)
1196 /* Parse the symlink */
1197 if (!CmpGetSymbolicLink(Hive
,
1202 /* Symlink parse failed */
1203 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1211 /* Is this an exit node */
1212 if (Node
->Flags
& KEY_HIVE_EXIT
)
1215 CmpHandleExitNode(&Hive
,
1220 if (!Node
) ASSERT(FALSE
);
1223 /* Create a KCB for this key */
1224 Kcb
= CmpCreateKeyControlBlock(Hive
,
1230 if (!Kcb
) ASSERT(FALSE
);
1232 /* Dereference the parent and set the new one */
1233 CmpDereferenceKeyControlBlock(ParentKcb
);
1238 /* Check if this was the last key for a create */
1239 if ((Last
) && (ParseContext
))
1241 /* Check if we're doing a link node */
1242 if (ParseContext
->CreateLink
)
1244 /* The only thing we should see */
1245 Status
= CmpCreateLinkNode(Hive
,
1258 Status
= CmpDoCreate(Hive
,
1268 /* Check for reparse (in this case, someone beat us) */
1269 if (Status
== STATUS_REPARSE
) break;
1271 /* Update disposition */
1272 ParseContext
->Disposition
= REG_CREATED_NEW_KEY
;
1278 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1285 /* Save the next name */
1286 Current
.Buffer
= NextName
.Buffer
;
1288 /* Validate the current name string length */
1289 if (Current
.Length
+ NextName
.Length
> MAXUSHORT
)
1292 Status
= STATUS_NAME_TOO_LONG
;
1295 Current
.Length
+= NextName
.Length
;
1297 /* Validate the current name string maximum length */
1298 if (Current
.MaximumLength
+ NextName
.MaximumLength
> MAXUSHORT
)
1301 Status
= STATUS_NAME_TOO_LONG
;
1304 Current
.MaximumLength
+= NextName
.MaximumLength
;
1306 /* Parse the symlink */
1307 if (CmpGetSymbolicLink(Hive
,
1312 /* Symlink parse succeeded */
1313 Status
= STATUS_REPARSE
;
1317 /* Couldn't find symlink */
1318 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
1325 else if ((Result
) && (Last
))
1327 /* Opening the root. Is this an exit node? */
1328 if (Node
->Flags
& KEY_HIVE_EXIT
)
1331 CmpHandleExitNode(&Hive
,
1336 if (!Node
) ASSERT(FALSE
);
1340 Status
= CmpDoOpen(Hive
,
1347 CMP_OPEN_KCB_NO_CREATE
/* | CMP_CREATE_KCB_KCB_LOCKED */,
1351 if (Status
== STATUS_REPARSE
)
1362 Status
= STATUS_INVALID_PARAMETER
;
1367 /* Dereference the parent if it exists */
1369 if (ParentKcb
) CmpDereferenceKeyControlBlock(ParentKcb
);
1371 /* Unlock the registry */
1372 CmpUnlockRegistry();