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