added #ifdef around headers and some debug message copying/terminating to support...
[reactos.git] / reactos / ntoskrnl / cm / regobj.c
1 /*
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.
6 * UPDATE HISTORY:
7 */
8
9 #ifdef WIN32_REGDBG
10 #include "cm_win32.h"
11 #else
12 #include <ddk/ntddk.h>
13 #include <roscfg.h>
14 #include <internal/ob.h>
15 #include <limits.h>
16 #include <string.h>
17 #include <internal/pool.h>
18 #include <internal/registry.h>
19 #include <ntos/minmax.h>
20
21 #define NDEBUG
22 #include <internal/debug.h>
23
24 #include "cm.h"
25 #endif
26
27
28 static NTSTATUS
29 CmiGetLinkTarget(PREGISTRY_HIVE RegistryHive,
30 PKEY_CELL KeyCell,
31 PUNICODE_STRING TargetPath);
32
33 /* FUNCTONS *****************************************************************/
34
35 NTSTATUS STDCALL
36 CmiObjectParse(PVOID ParsedObject,
37 PVOID *NextObject,
38 PUNICODE_STRING FullPath,
39 PWSTR *Path,
40 ULONG Attributes)
41 {
42 BLOCK_OFFSET BlockOffset;
43 PKEY_OBJECT FoundObject;
44 PKEY_OBJECT ParsedKey;
45 PKEY_CELL SubKeyCell;
46 CHAR cPath[MAX_PATH];
47 NTSTATUS Status;
48 PWSTR end;
49 UNICODE_STRING LinkPath;
50 UNICODE_STRING TargetPath;
51
52 ParsedKey = ParsedObject;
53
54 VERIFY_KEY_OBJECT(ParsedKey);
55
56 *NextObject = NULL;
57
58 if ((*Path) == NULL)
59 {
60 DPRINT("*Path is NULL\n");
61 return STATUS_UNSUCCESSFUL;
62 }
63
64 DPRINT("Path '%S'\n", *Path);
65
66 if ((*Path[0]) == '\\')
67 {
68 end = wcschr((*Path) + 1, '\\');
69 if (end != NULL)
70 *end = 0;
71 wcstombs(cPath, (*Path) + 1, wcslen((*Path) + 1));
72 cPath[wcslen((*Path) + 1)] = 0;
73 }
74 else
75 {
76 end = wcschr((*Path), '\\');
77 if (end != NULL)
78 *end = 0;
79 wcstombs(cPath, (*Path), wcslen((*Path)));
80 cPath[wcslen((*Path))] = 0;
81 }
82
83 FoundObject = CmiScanKeyList(ParsedKey, cPath, Attributes);
84 if (FoundObject == NULL)
85 {
86 Status = CmiScanForSubKey(ParsedKey->RegistryHive,
87 ParsedKey->KeyCell,
88 &SubKeyCell,
89 &BlockOffset,
90 cPath,
91 0,
92 Attributes);
93 if (!NT_SUCCESS(Status) || (SubKeyCell == NULL))
94 {
95 if (end != NULL)
96 {
97 *end = '\\';
98 }
99 return(STATUS_UNSUCCESSFUL);
100 }
101
102 if ((SubKeyCell->Type == REG_LINK_KEY_CELL_TYPE) &&
103 !((Attributes & OBJ_OPENLINK) && (end == NULL)))
104 {
105 RtlInitUnicodeString(&LinkPath, NULL);
106 Status = CmiGetLinkTarget(ParsedKey->RegistryHive,
107 SubKeyCell,
108 &LinkPath);
109 if (NT_SUCCESS(Status))
110 {
111 DPRINT("LinkPath '%wZ'\n", &LinkPath);
112
113 /* build new FullPath for reparsing */
114 TargetPath.MaximumLength = LinkPath.MaximumLength;
115 if (end != NULL)
116 {
117 *end = '\\';
118 TargetPath.MaximumLength += (wcslen(end) * sizeof(WCHAR));
119 }
120 TargetPath.Length = TargetPath.MaximumLength - sizeof(WCHAR);
121 TargetPath.Buffer = ExAllocatePool(NonPagedPool,
122 TargetPath.MaximumLength);
123 wcscpy(TargetPath.Buffer, LinkPath.Buffer);
124 if (end != NULL)
125 {
126 wcscat(TargetPath.Buffer, end);
127 }
128
129 RtlFreeUnicodeString(FullPath);
130 RtlFreeUnicodeString(&LinkPath);
131 FullPath->Length = TargetPath.Length;
132 FullPath->MaximumLength = TargetPath.MaximumLength;
133 FullPath->Buffer = TargetPath.Buffer;
134
135 DPRINT("FullPath '%wZ'\n", FullPath);
136
137 /* reinitialize Path for reparsing */
138 *Path = FullPath->Buffer;
139
140 *NextObject = NULL;
141 return(STATUS_REPARSE);
142 }
143 }
144
145 /* Create new key object and put into linked list */
146 DPRINT("CmiObjectParse: %s\n", cPath);
147 Status = ObCreateObject(NULL,
148 STANDARD_RIGHTS_REQUIRED,
149 NULL,
150 CmiKeyType,
151 (PVOID*)&FoundObject);
152 if (!NT_SUCCESS(Status))
153 {
154 return(Status);
155 }
156
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);
165 }
166 else
167 {
168 if ((FoundObject->KeyCell->Type == REG_LINK_KEY_CELL_TYPE) &&
169 !((Attributes & OBJ_OPENLINK) && (end == NULL)))
170 {
171 RtlInitUnicodeString(&LinkPath, NULL);
172 Status = CmiGetLinkTarget(FoundObject->RegistryHive,
173 FoundObject->KeyCell,
174 &LinkPath);
175 if (NT_SUCCESS(Status))
176 {
177 DPRINT("LinkPath '%wZ'\n", &LinkPath);
178
179 /* build new FullPath for reparsing */
180 TargetPath.MaximumLength = LinkPath.MaximumLength;
181 if (end != NULL)
182 {
183 *end = '\\';
184 TargetPath.MaximumLength += (wcslen(end) * sizeof(WCHAR));
185 }
186 TargetPath.Length = TargetPath.MaximumLength - sizeof(WCHAR);
187 TargetPath.Buffer = ExAllocatePool(NonPagedPool,
188 TargetPath.MaximumLength);
189 wcscpy(TargetPath.Buffer, LinkPath.Buffer);
190 if (end != NULL)
191 {
192 wcscat(TargetPath.Buffer, end);
193 }
194
195 RtlFreeUnicodeString(FullPath);
196 RtlFreeUnicodeString(&LinkPath);
197 FullPath->Length = TargetPath.Length;
198 FullPath->MaximumLength = TargetPath.MaximumLength;
199 FullPath->Buffer = TargetPath.Buffer;
200
201 DPRINT("FullPath '%wZ'\n", FullPath);
202
203 /* reinitialize Path for reparsing */
204 *Path = FullPath->Buffer;
205
206 *NextObject = NULL;
207 return(STATUS_REPARSE);
208 }
209 }
210
211 ObReferenceObjectByPointer(FoundObject,
212 STANDARD_RIGHTS_REQUIRED,
213 NULL,
214 UserMode);
215 }
216 #ifndef WIN32_REGDBG
217 DPRINT("CmiObjectParse: %s\n", FoundObject->Name);
218 #else
219 {
220 char buffer[_BUFFER_LEN];
221 memset(buffer, 0, _BUFFER_LEN);
222 strncpy(buffer, FoundObject->Name, min(FoundObject->NameSize, _BUFFER_LEN - 1));
223 DPRINT("CmiObjectParse: %s\n", buffer);
224 }
225 #endif
226
227 if (end != NULL)
228 {
229 *end = '\\';
230 *Path = end;
231 }
232 else
233 {
234 *Path = NULL;
235 }
236
237 VERIFY_KEY_OBJECT(FoundObject);
238
239 *NextObject = FoundObject;
240
241 return(STATUS_SUCCESS);
242 }
243
244
245 NTSTATUS STDCALL
246 CmiObjectCreate(PVOID ObjectBody,
247 PVOID Parent,
248 PWSTR RemainingPath,
249 struct _OBJECT_ATTRIBUTES* ObjectAttributes)
250 {
251 PKEY_OBJECT pKey = ObjectBody;
252
253 pKey->ParentKey = Parent;
254 if (RemainingPath)
255 {
256 if(RemainingPath[0]== L'\\')
257 {
258 pKey->Name = (PCHAR)(&RemainingPath[1]);
259 pKey->NameSize = wcslen(RemainingPath) - 1;
260 }
261 else
262 {
263 pKey->Name = (PCHAR)RemainingPath;
264 pKey->NameSize = wcslen(RemainingPath);
265 }
266 }
267 else
268 {
269 pKey->NameSize = 0;
270 }
271
272 return STATUS_SUCCESS;
273 }
274
275
276 VOID STDCALL
277 CmiObjectDelete(PVOID DeletedObject)
278 {
279 PKEY_OBJECT KeyObject;
280
281 DPRINT("Delete object key\n");
282
283 KeyObject = (PKEY_OBJECT) DeletedObject;
284
285 if (!NT_SUCCESS(CmiRemoveKeyFromList(KeyObject)))
286 {
287 DPRINT1("Key not found in parent list ???\n");
288 }
289
290 if (KeyObject->Flags & KO_MARKED_FOR_DELETE)
291 {
292 DPRINT("delete really key\n");
293 CmiDestroyBlock(KeyObject->RegistryHive,
294 KeyObject->KeyCell,
295 KeyObject->BlockOffset);
296 }
297 else
298 {
299 CmiReleaseBlock(KeyObject->RegistryHive, KeyObject->KeyCell);
300 }
301 }
302
303
304 VOID
305 CmiAddKeyToList(PKEY_OBJECT ParentKey,
306 PKEY_OBJECT NewKey)
307 {
308 KIRQL OldIrql;
309
310 DPRINT("ParentKey %.08x\n", ParentKey);
311
312 KeAcquireSpinLock(&CmiKeyListLock, &OldIrql);
313
314 if (ParentKey->SizeOfSubKeys <= ParentKey->NumberOfSubKeys)
315 {
316 PKEY_OBJECT *tmpSubKeys = ExAllocatePool(NonPagedPool,
317 (ParentKey->NumberOfSubKeys + 1) * sizeof(DWORD));
318
319 if (ParentKey->NumberOfSubKeys > 0)
320 {
321 memcpy(tmpSubKeys,
322 ParentKey->SubKeys,
323 ParentKey->NumberOfSubKeys * sizeof(DWORD));
324 }
325
326 if (ParentKey->SubKeys)
327 ExFreePool(ParentKey->SubKeys);
328
329 ParentKey->SubKeys = tmpSubKeys;
330 ParentKey->SizeOfSubKeys = ParentKey->NumberOfSubKeys + 1;
331 }
332
333 /* FIXME: Please maintain the list in alphabetic order */
334 /* to allow a dichotomic search */
335 ParentKey->SubKeys[ParentKey->NumberOfSubKeys++] = NewKey;
336
337 DPRINT("Reference parent key: 0x%x\n", ParentKey);
338
339 ObReferenceObjectByPointer(ParentKey,
340 STANDARD_RIGHTS_REQUIRED,
341 NULL,
342 UserMode);
343 NewKey->ParentKey = ParentKey;
344 KeReleaseSpinLock(&CmiKeyListLock, OldIrql);
345 }
346
347
348 NTSTATUS
349 CmiRemoveKeyFromList(PKEY_OBJECT KeyToRemove)
350 {
351 PKEY_OBJECT ParentKey;
352 KIRQL OldIrql;
353 DWORD Index;
354
355 ParentKey = KeyToRemove->ParentKey;
356 KeAcquireSpinLock(&CmiKeyListLock, &OldIrql);
357 /* FIXME: If list maintained in alphabetic order, use dichotomic search */
358 for (Index = 0; Index < ParentKey->NumberOfSubKeys; Index++)
359 {
360 if (ParentKey->SubKeys[Index] == KeyToRemove)
361 {
362 if (Index < ParentKey->NumberOfSubKeys-1)
363 RtlMoveMemory(&ParentKey->SubKeys[Index],
364 &ParentKey->SubKeys[Index + 1],
365 (ParentKey->NumberOfSubKeys - Index - 1) * sizeof(PKEY_OBJECT));
366 ParentKey->NumberOfSubKeys--;
367 KeReleaseSpinLock(&CmiKeyListLock, OldIrql);
368
369 DPRINT("Dereference parent key: 0x%x\n", ParentKey);
370
371 ObDereferenceObject(ParentKey);
372 return STATUS_SUCCESS;
373 }
374 }
375 KeReleaseSpinLock(&CmiKeyListLock, OldIrql);
376
377 return STATUS_UNSUCCESSFUL;
378 }
379
380
381 PKEY_OBJECT
382 CmiScanKeyList(PKEY_OBJECT Parent,
383 PCHAR KeyName,
384 ULONG Attributes)
385 {
386 PKEY_OBJECT CurKey;
387 KIRQL OldIrql;
388 WORD NameSize;
389 DWORD Index;
390
391 #ifndef WIN32_REGDBG
392 DPRINT("Scanning key list for: %s (Parent: %s)\n",
393 KeyName, Parent->Name);
394 #else
395 {
396 char buffer[_BUFFER_LEN];
397 memset(buffer, 0, _BUFFER_LEN);
398 strncpy(buffer, Parent->Name, min(Parent->NameSize, _BUFFER_LEN - 1));
399 DPRINT("Scanning key list for: %s (Parent: %s)\n", KeyName, buffer);
400 }
401 #endif
402
403 NameSize = strlen(KeyName);
404 KeAcquireSpinLock(&CmiKeyListLock, &OldIrql);
405 /* FIXME: if list maintained in alphabetic order, use dichotomic search */
406 for (Index=0; Index < Parent->NumberOfSubKeys; Index++)
407 {
408 CurKey = Parent->SubKeys[Index];
409 if (Attributes & OBJ_CASE_INSENSITIVE)
410 {
411 if ((NameSize == CurKey->NameSize)
412 && (_strnicmp(KeyName, CurKey->Name, NameSize) == 0))
413 {
414 KeReleaseSpinLock(&CmiKeyListLock, OldIrql);
415 return CurKey;
416 }
417 }
418 else
419 {
420 if ((NameSize == CurKey->NameSize)
421 && (strncmp(KeyName,CurKey->Name,NameSize) == 0))
422 {
423 KeReleaseSpinLock(&CmiKeyListLock, OldIrql);
424 return CurKey;
425 }
426 }
427 }
428 KeReleaseSpinLock(&CmiKeyListLock, OldIrql);
429
430 return NULL;
431 }
432
433
434 static NTSTATUS
435 CmiGetLinkTarget(PREGISTRY_HIVE RegistryHive,
436 PKEY_CELL KeyCell,
437 PUNICODE_STRING TargetPath)
438 {
439 PVALUE_CELL ValueCell;
440 PDATA_CELL DataCell;
441 NTSTATUS Status;
442
443 /* Get Value block of interest */
444 Status = CmiScanKeyForValue(RegistryHive,
445 KeyCell,
446 "SymbolicLinkValue",
447 &ValueCell,
448 NULL);
449 if (!NT_SUCCESS(Status))
450 {
451 return(Status);
452 }
453
454 if (ValueCell->DataType != REG_LINK)
455 {
456 DPRINT1("Type != REG_LINK\n!");
457 return(STATUS_UNSUCCESSFUL);
458 }
459
460 if (TargetPath->Buffer == NULL && TargetPath->MaximumLength == 0)
461 {
462 TargetPath->Length = 0;
463 TargetPath->MaximumLength = ValueCell->DataSize + sizeof(WCHAR);
464 TargetPath->Buffer = ExAllocatePool(NonPagedPool,
465 TargetPath->MaximumLength);
466 }
467
468 TargetPath->Length = min(TargetPath->MaximumLength - sizeof(WCHAR),
469 ValueCell->DataSize);
470
471 if (ValueCell->DataSize > 0)
472 {
473 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
474 RtlCopyMemory(TargetPath->Buffer,
475 DataCell->Data,
476 TargetPath->Length);
477 TargetPath->Buffer[TargetPath->Length / sizeof(WCHAR)] = 0;
478 CmiReleaseBlock(RegistryHive, DataCell);
479 }
480 else
481 {
482 RtlCopyMemory(TargetPath->Buffer,
483 &ValueCell->DataOffset,
484 TargetPath->Length);
485 TargetPath->Buffer[TargetPath->Length / sizeof(WCHAR)] = 0;
486 }
487
488 return(STATUS_SUCCESS);
489 }
490
491 /* EOF */