2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/cm/regobj.c
5 * PURPOSE: Registry object manipulation routines.
12 #include <ddk/ntddk.h>
14 #include <internal/ob.h>
17 #include <internal/pool.h>
18 #include <internal/registry.h>
19 #include <ntos/minmax.h>
22 #include <internal/debug.h>
29 CmiGetLinkTarget(PREGISTRY_HIVE RegistryHive
,
31 PUNICODE_STRING TargetPath
);
33 /* FUNCTONS *****************************************************************/
36 CmiObjectParse(PVOID ParsedObject
,
38 PUNICODE_STRING FullPath
,
42 BLOCK_OFFSET BlockOffset
;
43 PKEY_OBJECT FoundObject
;
44 PKEY_OBJECT ParsedKey
;
49 UNICODE_STRING LinkPath
;
50 UNICODE_STRING TargetPath
;
52 ParsedKey
= ParsedObject
;
54 VERIFY_KEY_OBJECT(ParsedKey
);
60 DPRINT("*Path is NULL\n");
61 return STATUS_UNSUCCESSFUL
;
64 DPRINT("Path '%S'\n", *Path
);
66 if ((*Path
[0]) == '\\')
68 end
= wcschr((*Path
) + 1, '\\');
71 wcstombs(cPath
, (*Path
) + 1, wcslen((*Path
) + 1));
72 cPath
[wcslen((*Path
) + 1)] = 0;
76 end
= wcschr((*Path
), '\\');
79 wcstombs(cPath
, (*Path
), wcslen((*Path
)));
80 cPath
[wcslen((*Path
))] = 0;
83 FoundObject
= CmiScanKeyList(ParsedKey
, cPath
, Attributes
);
84 if (FoundObject
== NULL
)
86 Status
= CmiScanForSubKey(ParsedKey
->RegistryHive
,
93 if (!NT_SUCCESS(Status
) || (SubKeyCell
== NULL
))
99 return(STATUS_UNSUCCESSFUL
);
102 if ((SubKeyCell
->Type
== REG_LINK_KEY_CELL_TYPE
) &&
103 !((Attributes
& OBJ_OPENLINK
) && (end
== NULL
)))
105 RtlInitUnicodeString(&LinkPath
, NULL
);
106 Status
= CmiGetLinkTarget(ParsedKey
->RegistryHive
,
109 if (NT_SUCCESS(Status
))
111 DPRINT("LinkPath '%wZ'\n", &LinkPath
);
113 /* build new FullPath for reparsing */
114 TargetPath
.MaximumLength
= LinkPath
.MaximumLength
;
118 TargetPath
.MaximumLength
+= (wcslen(end
) * sizeof(WCHAR
));
120 TargetPath
.Length
= TargetPath
.MaximumLength
- sizeof(WCHAR
);
121 TargetPath
.Buffer
= ExAllocatePool(NonPagedPool
,
122 TargetPath
.MaximumLength
);
123 wcscpy(TargetPath
.Buffer
, LinkPath
.Buffer
);
126 wcscat(TargetPath
.Buffer
, end
);
129 RtlFreeUnicodeString(FullPath
);
130 RtlFreeUnicodeString(&LinkPath
);
131 FullPath
->Length
= TargetPath
.Length
;
132 FullPath
->MaximumLength
= TargetPath
.MaximumLength
;
133 FullPath
->Buffer
= TargetPath
.Buffer
;
135 DPRINT("FullPath '%wZ'\n", FullPath
);
137 /* reinitialize Path for reparsing */
138 *Path
= FullPath
->Buffer
;
141 return(STATUS_REPARSE
);
145 /* Create new key object and put into linked list */
146 DPRINT("CmiObjectParse: %s\n", cPath
);
147 Status
= ObCreateObject(NULL
,
148 STANDARD_RIGHTS_REQUIRED
,
151 (PVOID
*)&FoundObject
);
152 if (!NT_SUCCESS(Status
))
157 FoundObject
->Flags
= 0;
158 FoundObject
->Name
= SubKeyCell
->Name
;
159 FoundObject
->NameSize
= SubKeyCell
->NameSize
;
160 FoundObject
->KeyCell
= SubKeyCell
;
161 FoundObject
->BlockOffset
= BlockOffset
;
162 FoundObject
->RegistryHive
= ParsedKey
->RegistryHive
;
163 CmiAddKeyToList(ParsedKey
, FoundObject
);
164 DPRINT("Created object 0x%x\n", FoundObject
);
168 if ((FoundObject
->KeyCell
->Type
== REG_LINK_KEY_CELL_TYPE
) &&
169 !((Attributes
& OBJ_OPENLINK
) && (end
== NULL
)))
171 DPRINT("Found link\n");
173 RtlInitUnicodeString(&LinkPath
, NULL
);
174 Status
= CmiGetLinkTarget(FoundObject
->RegistryHive
,
175 FoundObject
->KeyCell
,
177 if (NT_SUCCESS(Status
))
179 DPRINT("LinkPath '%wZ'\n", &LinkPath
);
181 /* build new FullPath for reparsing */
182 TargetPath
.MaximumLength
= LinkPath
.MaximumLength
;
186 TargetPath
.MaximumLength
+= (wcslen(end
) * sizeof(WCHAR
));
188 TargetPath
.Length
= TargetPath
.MaximumLength
- sizeof(WCHAR
);
189 TargetPath
.Buffer
= ExAllocatePool(NonPagedPool
,
190 TargetPath
.MaximumLength
);
191 wcscpy(TargetPath
.Buffer
, LinkPath
.Buffer
);
194 wcscat(TargetPath
.Buffer
, end
);
197 RtlFreeUnicodeString(FullPath
);
198 RtlFreeUnicodeString(&LinkPath
);
199 FullPath
->Length
= TargetPath
.Length
;
200 FullPath
->MaximumLength
= TargetPath
.MaximumLength
;
201 FullPath
->Buffer
= TargetPath
.Buffer
;
203 DPRINT("FullPath '%wZ'\n", FullPath
);
205 /* reinitialize Path for reparsing */
206 *Path
= FullPath
->Buffer
;
209 return(STATUS_REPARSE
);
213 ObReferenceObjectByPointer(FoundObject
,
214 STANDARD_RIGHTS_REQUIRED
,
219 DPRINT("CmiObjectParse: %s\n", FoundObject
->Name
);
222 char buffer
[_BUFFER_LEN
];
223 memset(buffer
, 0, _BUFFER_LEN
);
224 strncpy(buffer
, FoundObject
->Name
, min(FoundObject
->NameSize
, _BUFFER_LEN
- 1));
225 DPRINT("CmiObjectParse: %s\n", buffer
);
239 VERIFY_KEY_OBJECT(FoundObject
);
241 *NextObject
= FoundObject
;
243 return(STATUS_SUCCESS
);
248 CmiObjectCreate(PVOID ObjectBody
,
251 struct _OBJECT_ATTRIBUTES
* ObjectAttributes
)
253 PKEY_OBJECT pKey
= ObjectBody
;
255 pKey
->ParentKey
= Parent
;
258 if(RemainingPath
[0]== L
'\\')
260 pKey
->Name
= (PCHAR
)(&RemainingPath
[1]);
261 pKey
->NameSize
= wcslen(RemainingPath
) - 1;
265 pKey
->Name
= (PCHAR
)RemainingPath
;
266 pKey
->NameSize
= wcslen(RemainingPath
);
274 return STATUS_SUCCESS
;
279 CmiObjectDelete(PVOID DeletedObject
)
281 PKEY_OBJECT KeyObject
;
283 DPRINT("Delete object key\n");
285 KeyObject
= (PKEY_OBJECT
) DeletedObject
;
287 if (!NT_SUCCESS(CmiRemoveKeyFromList(KeyObject
)))
289 DPRINT1("Key not found in parent list ???\n");
292 if (KeyObject
->Flags
& KO_MARKED_FOR_DELETE
)
294 DPRINT("delete really key\n");
295 CmiDestroyBlock(KeyObject
->RegistryHive
,
297 KeyObject
->BlockOffset
);
301 CmiReleaseBlock(KeyObject
->RegistryHive
, KeyObject
->KeyCell
);
307 CmiAddKeyToList(PKEY_OBJECT ParentKey
,
312 DPRINT("ParentKey %.08x\n", ParentKey
);
314 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
316 if (ParentKey
->SizeOfSubKeys
<= ParentKey
->NumberOfSubKeys
)
318 PKEY_OBJECT
*tmpSubKeys
= ExAllocatePool(NonPagedPool
,
319 (ParentKey
->NumberOfSubKeys
+ 1) * sizeof(DWORD
));
321 if (ParentKey
->NumberOfSubKeys
> 0)
325 ParentKey
->NumberOfSubKeys
* sizeof(DWORD
));
328 if (ParentKey
->SubKeys
)
329 ExFreePool(ParentKey
->SubKeys
);
331 ParentKey
->SubKeys
= tmpSubKeys
;
332 ParentKey
->SizeOfSubKeys
= ParentKey
->NumberOfSubKeys
+ 1;
335 /* FIXME: Please maintain the list in alphabetic order */
336 /* to allow a dichotomic search */
337 ParentKey
->SubKeys
[ParentKey
->NumberOfSubKeys
++] = NewKey
;
339 DPRINT("Reference parent key: 0x%x\n", ParentKey
);
341 ObReferenceObjectByPointer(ParentKey
,
342 STANDARD_RIGHTS_REQUIRED
,
345 NewKey
->ParentKey
= ParentKey
;
346 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
351 CmiRemoveKeyFromList(PKEY_OBJECT KeyToRemove
)
353 PKEY_OBJECT ParentKey
;
357 ParentKey
= KeyToRemove
->ParentKey
;
358 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
359 /* FIXME: If list maintained in alphabetic order, use dichotomic search */
360 for (Index
= 0; Index
< ParentKey
->NumberOfSubKeys
; Index
++)
362 if (ParentKey
->SubKeys
[Index
] == KeyToRemove
)
364 if (Index
< ParentKey
->NumberOfSubKeys
-1)
365 RtlMoveMemory(&ParentKey
->SubKeys
[Index
],
366 &ParentKey
->SubKeys
[Index
+ 1],
367 (ParentKey
->NumberOfSubKeys
- Index
- 1) * sizeof(PKEY_OBJECT
));
368 ParentKey
->NumberOfSubKeys
--;
369 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
371 DPRINT("Dereference parent key: 0x%x\n", ParentKey
);
373 ObDereferenceObject(ParentKey
);
374 return STATUS_SUCCESS
;
377 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
379 return STATUS_UNSUCCESSFUL
;
384 CmiScanKeyList(PKEY_OBJECT Parent
,
394 DPRINT("Scanning key list for: %s (Parent: %s)\n",
395 KeyName
, Parent
->Name
);
398 char buffer
[_BUFFER_LEN
];
399 memset(buffer
, 0, _BUFFER_LEN
);
400 strncpy(buffer
, Parent
->Name
, min(Parent
->NameSize
, _BUFFER_LEN
- 1));
401 DPRINT("Scanning key list for: %s (Parent: %s)\n", KeyName
, buffer
);
405 NameSize
= strlen(KeyName
);
406 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
407 /* FIXME: if list maintained in alphabetic order, use dichotomic search */
408 for (Index
=0; Index
< Parent
->NumberOfSubKeys
; Index
++)
410 CurKey
= Parent
->SubKeys
[Index
];
411 if (Attributes
& OBJ_CASE_INSENSITIVE
)
413 if ((NameSize
== CurKey
->NameSize
)
414 && (_strnicmp(KeyName
, CurKey
->Name
, NameSize
) == 0))
416 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
422 if ((NameSize
== CurKey
->NameSize
)
423 && (strncmp(KeyName
,CurKey
->Name
,NameSize
) == 0))
425 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
430 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
437 CmiGetLinkTarget(PREGISTRY_HIVE RegistryHive
,
439 PUNICODE_STRING TargetPath
)
441 UNICODE_STRING LinkName
= UNICODE_STRING_INITIALIZER(L
"SymbolicLinkValue");
442 PVALUE_CELL ValueCell
;
446 DPRINT("CmiGetLinkTarget() called\n");
448 /* Get Value block of interest */
449 Status
= CmiScanKeyForValue(RegistryHive
,
454 if (!NT_SUCCESS(Status
))
456 DPRINT1("CmiScanKeyForValue() failed (Status %lx)\n", Status
);
460 if (ValueCell
->DataType
!= REG_LINK
)
462 DPRINT1("Type != REG_LINK\n!");
463 return(STATUS_UNSUCCESSFUL
);
466 if (TargetPath
->Buffer
== NULL
&& TargetPath
->MaximumLength
== 0)
468 TargetPath
->Length
= 0;
469 TargetPath
->MaximumLength
= ValueCell
->DataSize
+ sizeof(WCHAR
);
470 TargetPath
->Buffer
= ExAllocatePool(NonPagedPool
,
471 TargetPath
->MaximumLength
);
474 TargetPath
->Length
= min(TargetPath
->MaximumLength
- sizeof(WCHAR
),
475 (ULONG
) ValueCell
->DataSize
);
477 if (ValueCell
->DataSize
> 0)
479 DataCell
= CmiGetBlock(RegistryHive
, ValueCell
->DataOffset
, NULL
);
480 RtlCopyMemory(TargetPath
->Buffer
,
483 TargetPath
->Buffer
[TargetPath
->Length
/ sizeof(WCHAR
)] = 0;
484 CmiReleaseBlock(RegistryHive
, DataCell
);
488 RtlCopyMemory(TargetPath
->Buffer
,
489 &ValueCell
->DataOffset
,
491 TargetPath
->Buffer
[TargetPath
->Length
/ sizeof(WCHAR
)] = 0;
494 DPRINT("TargetPath '%wZ'\n", TargetPath
);
496 return(STATUS_SUCCESS
);