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.
11 #include <internal/ob.h>
14 #include <internal/pool.h>
15 #include <internal/registry.h>
16 #include <ntos/minmax.h>
19 #include <internal/debug.h>
25 CmiGetLinkTarget(PREGISTRY_HIVE RegistryHive
,
27 PUNICODE_STRING TargetPath
);
29 /* FUNCTONS *****************************************************************/
32 CmiObjectParse(PVOID ParsedObject
,
34 PUNICODE_STRING FullPath
,
38 BLOCK_OFFSET BlockOffset
;
39 PKEY_OBJECT FoundObject
;
40 PKEY_OBJECT ParsedKey
;
45 UNICODE_STRING LinkPath
;
46 UNICODE_STRING TargetPath
;
48 ParsedKey
= ParsedObject
;
50 VERIFY_KEY_OBJECT(ParsedKey
);
56 DPRINT("*Path is NULL\n");
57 return STATUS_UNSUCCESSFUL
;
60 DPRINT("Path '%S'\n", *Path
);
62 if ((*Path
[0]) == '\\')
64 end
= wcschr((*Path
) + 1, '\\');
67 wcstombs(cPath
, (*Path
) + 1, wcslen((*Path
) + 1));
68 cPath
[wcslen((*Path
) + 1)] = 0;
72 end
= wcschr((*Path
), '\\');
75 wcstombs(cPath
, (*Path
), wcslen((*Path
)));
76 cPath
[wcslen((*Path
))] = 0;
79 FoundObject
= CmiScanKeyList(ParsedKey
, cPath
, Attributes
);
80 if (FoundObject
== NULL
)
82 Status
= CmiScanForSubKey(ParsedKey
->RegistryHive
,
89 if (!NT_SUCCESS(Status
) || (SubKeyCell
== NULL
))
95 return(STATUS_UNSUCCESSFUL
);
98 if ((SubKeyCell
->Type
== REG_LINK_KEY_CELL_TYPE
) &&
99 !((Attributes
& OBJ_OPENLINK
) && (end
== NULL
)))
101 RtlInitUnicodeString(&LinkPath
, NULL
);
102 Status
= CmiGetLinkTarget(ParsedKey
->RegistryHive
,
105 if (NT_SUCCESS(Status
))
107 DPRINT("LinkPath '%wZ'\n", &LinkPath
);
109 /* build new FullPath for reparsing */
110 TargetPath
.MaximumLength
= LinkPath
.MaximumLength
;
114 TargetPath
.MaximumLength
+= (wcslen(end
) * sizeof(WCHAR
));
116 TargetPath
.Length
= TargetPath
.MaximumLength
- sizeof(WCHAR
);
117 TargetPath
.Buffer
= ExAllocatePool(NonPagedPool
,
118 TargetPath
.MaximumLength
);
119 wcscpy(TargetPath
.Buffer
, LinkPath
.Buffer
);
122 wcscat(TargetPath
.Buffer
, end
);
125 RtlFreeUnicodeString(FullPath
);
126 RtlFreeUnicodeString(&LinkPath
);
127 FullPath
->Length
= TargetPath
.Length
;
128 FullPath
->MaximumLength
= TargetPath
.MaximumLength
;
129 FullPath
->Buffer
= TargetPath
.Buffer
;
131 DPRINT("FullPath '%wZ'\n", FullPath
);
133 /* reinitialize Path for reparsing */
134 *Path
= FullPath
->Buffer
;
137 return(STATUS_REPARSE
);
141 /* Create new key object and put into linked list */
142 DPRINT("CmiObjectParse %s\n", cPath
);
143 Status
= ObCreateObject(NULL
,
144 STANDARD_RIGHTS_REQUIRED
,
147 (PVOID
*)&FoundObject
);
148 if (!NT_SUCCESS(Status
))
153 FoundObject
->Flags
= 0;
154 FoundObject
->Name
= SubKeyCell
->Name
;
155 FoundObject
->NameSize
= SubKeyCell
->NameSize
;
156 FoundObject
->KeyCell
= SubKeyCell
;
157 FoundObject
->BlockOffset
= BlockOffset
;
158 FoundObject
->RegistryHive
= ParsedKey
->RegistryHive
;
159 CmiAddKeyToList(ParsedKey
, FoundObject
);
160 DPRINT("Created object 0x%x\n", FoundObject
);
164 if ((FoundObject
->KeyCell
->Type
== REG_LINK_KEY_CELL_TYPE
) &&
165 !((Attributes
& OBJ_OPENLINK
) && (end
== NULL
)))
167 RtlInitUnicodeString(&LinkPath
, NULL
);
168 Status
= CmiGetLinkTarget(FoundObject
->RegistryHive
,
169 FoundObject
->KeyCell
,
171 if (NT_SUCCESS(Status
))
173 DPRINT("LinkPath '%wZ'\n", &LinkPath
);
175 /* build new FullPath for reparsing */
176 TargetPath
.MaximumLength
= LinkPath
.MaximumLength
;
180 TargetPath
.MaximumLength
+= (wcslen(end
) * sizeof(WCHAR
));
182 TargetPath
.Length
= TargetPath
.MaximumLength
- sizeof(WCHAR
);
183 TargetPath
.Buffer
= ExAllocatePool(NonPagedPool
,
184 TargetPath
.MaximumLength
);
185 wcscpy(TargetPath
.Buffer
, LinkPath
.Buffer
);
188 wcscat(TargetPath
.Buffer
, end
);
191 RtlFreeUnicodeString(FullPath
);
192 RtlFreeUnicodeString(&LinkPath
);
193 FullPath
->Length
= TargetPath
.Length
;
194 FullPath
->MaximumLength
= TargetPath
.MaximumLength
;
195 FullPath
->Buffer
= TargetPath
.Buffer
;
197 DPRINT("FullPath '%wZ'\n", FullPath
);
199 /* reinitialize Path for reparsing */
200 *Path
= FullPath
->Buffer
;
203 return(STATUS_REPARSE
);
207 ObReferenceObjectByPointer(FoundObject
,
208 STANDARD_RIGHTS_REQUIRED
,
213 DPRINT("CmiObjectParse %s\n", FoundObject
->Name
);
225 VERIFY_KEY_OBJECT(FoundObject
);
227 *NextObject
= FoundObject
;
229 return(STATUS_SUCCESS
);
234 CmiObjectCreate(PVOID ObjectBody
,
237 struct _OBJECT_ATTRIBUTES
* ObjectAttributes
)
239 PKEY_OBJECT pKey
= ObjectBody
;
241 pKey
->ParentKey
= Parent
;
244 if(RemainingPath
[0]== L
'\\')
246 pKey
->Name
= (PCHAR
)(&RemainingPath
[1]);
247 pKey
->NameSize
= wcslen(RemainingPath
) - 1;
251 pKey
->Name
= (PCHAR
)RemainingPath
;
252 pKey
->NameSize
= wcslen(RemainingPath
);
260 return STATUS_SUCCESS
;
265 CmiObjectDelete(PVOID DeletedObject
)
267 PKEY_OBJECT KeyObject
;
269 DPRINT("Delete object key\n");
271 KeyObject
= (PKEY_OBJECT
) DeletedObject
;
273 if (!NT_SUCCESS(CmiRemoveKeyFromList(KeyObject
)))
275 DPRINT1("Key not found in parent list ???\n");
278 if (KeyObject
->Flags
& KO_MARKED_FOR_DELETE
)
280 DPRINT("delete really key\n");
281 CmiDestroyBlock(KeyObject
->RegistryHive
,
283 KeyObject
->BlockOffset
);
287 CmiReleaseBlock(KeyObject
->RegistryHive
, KeyObject
->KeyCell
);
293 CmiAddKeyToList(PKEY_OBJECT ParentKey
,
298 DPRINT("ParentKey %.08x\n", ParentKey
);
300 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
302 if (ParentKey
->SizeOfSubKeys
<= ParentKey
->NumberOfSubKeys
)
304 PKEY_OBJECT
*tmpSubKeys
= ExAllocatePool(NonPagedPool
,
305 (ParentKey
->NumberOfSubKeys
+ 1) * sizeof(DWORD
));
307 if (ParentKey
->NumberOfSubKeys
> 0)
311 ParentKey
->NumberOfSubKeys
* sizeof(DWORD
));
314 if (ParentKey
->SubKeys
)
315 ExFreePool(ParentKey
->SubKeys
);
317 ParentKey
->SubKeys
= tmpSubKeys
;
318 ParentKey
->SizeOfSubKeys
= ParentKey
->NumberOfSubKeys
+ 1;
321 /* FIXME: Please maintain the list in alphabetic order */
322 /* to allow a dichotomic search */
323 ParentKey
->SubKeys
[ParentKey
->NumberOfSubKeys
++] = NewKey
;
325 DPRINT("Reference parent key: 0x%x\n", ParentKey
);
327 ObReferenceObjectByPointer(ParentKey
,
328 STANDARD_RIGHTS_REQUIRED
,
331 NewKey
->ParentKey
= ParentKey
;
332 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
337 CmiRemoveKeyFromList(PKEY_OBJECT KeyToRemove
)
339 PKEY_OBJECT ParentKey
;
343 ParentKey
= KeyToRemove
->ParentKey
;
344 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
345 /* FIXME: If list maintained in alphabetic order, use dichotomic search */
346 for (Index
= 0; Index
< ParentKey
->NumberOfSubKeys
; Index
++)
348 if (ParentKey
->SubKeys
[Index
] == KeyToRemove
)
350 if (Index
< ParentKey
->NumberOfSubKeys
-1)
351 RtlMoveMemory(&ParentKey
->SubKeys
[Index
],
352 &ParentKey
->SubKeys
[Index
+ 1],
353 (ParentKey
->NumberOfSubKeys
- Index
- 1) * sizeof(PKEY_OBJECT
));
354 ParentKey
->NumberOfSubKeys
--;
355 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
357 DPRINT("Dereference parent key: 0x%x\n", ParentKey
);
359 ObDereferenceObject(ParentKey
);
360 return STATUS_SUCCESS
;
363 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
365 return STATUS_UNSUCCESSFUL
;
370 CmiScanKeyList(PKEY_OBJECT Parent
,
379 DPRINT("Scanning key list for %s (Parent %s)\n",
380 KeyName
, Parent
->Name
);
382 NameSize
= strlen(KeyName
);
383 KeAcquireSpinLock(&CmiKeyListLock
, &OldIrql
);
384 /* FIXME: if list maintained in alphabetic order, use dichotomic search */
385 for (Index
=0; Index
< Parent
->NumberOfSubKeys
; Index
++)
387 CurKey
= Parent
->SubKeys
[Index
];
388 if (Attributes
& OBJ_CASE_INSENSITIVE
)
390 if ((NameSize
== CurKey
->NameSize
)
391 && (_strnicmp(KeyName
, CurKey
->Name
, NameSize
) == 0))
393 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
399 if ((NameSize
== CurKey
->NameSize
)
400 && (strncmp(KeyName
,CurKey
->Name
,NameSize
) == 0))
402 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
407 KeReleaseSpinLock(&CmiKeyListLock
, OldIrql
);
414 CmiGetLinkTarget(PREGISTRY_HIVE RegistryHive
,
416 PUNICODE_STRING TargetPath
)
418 PVALUE_CELL ValueCell
;
422 /* Get Value block of interest */
423 Status
= CmiScanKeyForValue(RegistryHive
,
428 if (!NT_SUCCESS(Status
))
433 if (ValueCell
->DataType
!= REG_LINK
)
435 DPRINT1("Type != REG_LINK\n!");
436 return(STATUS_UNSUCCESSFUL
);
439 if (TargetPath
->Buffer
== NULL
&& TargetPath
->MaximumLength
== 0)
441 TargetPath
->Length
= 0;
442 TargetPath
->MaximumLength
= ValueCell
->DataSize
+ sizeof(WCHAR
);
443 TargetPath
->Buffer
= ExAllocatePool(NonPagedPool
,
444 TargetPath
->MaximumLength
);
447 TargetPath
->Length
= min(TargetPath
->MaximumLength
- sizeof(WCHAR
),
448 ValueCell
->DataSize
);
450 if (ValueCell
->DataSize
> 0)
452 DataCell
= CmiGetBlock(RegistryHive
, ValueCell
->DataOffset
, NULL
);
453 RtlCopyMemory(TargetPath
->Buffer
,
456 TargetPath
->Buffer
[TargetPath
->Length
/ sizeof(WCHAR
)] = 0;
457 CmiReleaseBlock(RegistryHive
, DataCell
);
461 RtlCopyMemory(TargetPath
->Buffer
,
462 &ValueCell
->DataOffset
,
464 TargetPath
->Buffer
[TargetPath
->Length
/ sizeof(WCHAR
)] = 0;
467 return(STATUS_SUCCESS
);