sync to trunk revision 36500
[reactos.git] / reactos / ntoskrnl / config / cmapi.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/config/cmapi.c
5 * PURPOSE: Configuration Manager - Internal Registry APIs
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "ntoskrnl.h"
12 #define NDEBUG
13 #include "debug.h"
14
15 /* FUNCTIONS *****************************************************************/
16
17 BOOLEAN
18 NTAPI
19 CmpDoFlushAll(IN BOOLEAN ForceFlush)
20 {
21 PLIST_ENTRY NextEntry;
22 PCMHIVE Hive;
23 NTSTATUS Status;
24 BOOLEAN Result = TRUE;
25
26 /* Make sure that the registry isn't read-only now */
27 if (CmpNoWrite) return TRUE;
28
29 /* Otherwise, acquire the hive list lock and disable force flush */
30 CmpForceForceFlush = FALSE;
31 ExAcquirePushLockShared(&CmpHiveListHeadLock);
32
33 /* Loop the hive list */
34 NextEntry = CmpHiveListHead.Flink;
35 while (NextEntry != &CmpHiveListHead)
36 {
37 /* Get the hive */
38 Hive = CONTAINING_RECORD(NextEntry, CMHIVE, HiveList);
39 if (!(Hive->Hive.HiveFlags & HIVE_NOLAZYFLUSH))
40 {
41 /* Acquire the flusher lock */
42 ExAcquirePushLockExclusive((PVOID)&Hive->FlusherLock);
43
44 /* Do the sync */
45 Status = HvSyncHive(&Hive->Hive);
46
47 /* If something failed - set the flag and continue looping*/
48 if (!NT_SUCCESS(Status)) Result = FALSE;
49
50 /* Release the flusher lock */
51 ExReleasePushLock((PVOID)&Hive->FlusherLock);
52 }
53
54 /* Try the next entry */
55 NextEntry = NextEntry->Flink;
56 }
57
58 /* Release lock and return */
59 ExReleasePushLock(&CmpHiveListHeadLock);
60 return Result;
61 }
62
63 NTSTATUS
64 NTAPI
65 CmpSetValueKeyNew(IN PHHIVE Hive,
66 IN PCM_KEY_NODE Parent,
67 IN PUNICODE_STRING ValueName,
68 IN ULONG Index,
69 IN ULONG Type,
70 IN PVOID Data,
71 IN ULONG DataSize,
72 IN ULONG StorageType,
73 IN ULONG SmallData)
74 {
75 PCELL_DATA CellData;
76 HCELL_INDEX ValueCell;
77 NTSTATUS Status;
78
79 /* Check if we already have a value list */
80 if (Parent->ValueList.Count)
81 {
82 /* Then make sure it's valid and dirty it */
83 ASSERT(Parent->ValueList.List != HCELL_NIL);
84 HvMarkCellDirty(Hive, Parent->ValueList.List, FALSE);
85 }
86
87 /* Allocate avalue cell */
88 ValueCell = HvAllocateCell(Hive,
89 FIELD_OFFSET(CM_KEY_VALUE, Name) +
90 CmpNameSize(Hive, ValueName),
91 StorageType,
92 HCELL_NIL);
93 if (ValueCell == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES;
94
95 /* Get the actual data for it */
96 CellData = HvGetCell(Hive, ValueCell);
97 if (!CellData) ASSERT(FALSE);
98
99 /* Now we can release it, make sure it's also dirty */
100 HvReleaseCell(Hive, ValueCell);
101 ASSERT(HvIsCellDirty(Hive, ValueCell));
102
103 /* Set it up and copy the name */
104 CellData->u.KeyValue.Signature = CM_KEY_VALUE_SIGNATURE;
105 CellData->u.KeyValue.Flags = 0;
106 CellData->u.KeyValue.Type = Type;
107 CellData->u.KeyValue.NameLength = CmpCopyName(Hive,
108 CellData->u.KeyValue.Name,
109 ValueName);
110 if (CellData->u.KeyValue.NameLength < ValueName->Length)
111 {
112 /* This is a compressed name */
113 CellData->u.KeyValue.Flags = VALUE_COMP_NAME;
114 }
115
116 /* Check if this is a normal key */
117 if (DataSize > CM_KEY_VALUE_SMALL)
118 {
119 /* Build a data cell for it */
120 Status = CmpSetValueDataNew(Hive,
121 Data,
122 DataSize,
123 StorageType,
124 ValueCell,
125 &CellData->u.KeyValue.Data);
126 if (!NT_SUCCESS(Status))
127 {
128 /* We failed, free the cell */
129 HvFreeCell(Hive, ValueCell);
130 return Status;
131 }
132
133 /* Otherwise, set the data length, and make sure the data is dirty */
134 CellData->u.KeyValue.DataLength = DataSize;
135 ASSERT(HvIsCellDirty(Hive, CellData->u.KeyValue.Data));
136 }
137 else
138 {
139 /* This is a small key, set the data directly inside */
140 CellData->u.KeyValue.DataLength = DataSize + CM_KEY_VALUE_SPECIAL_SIZE;
141 CellData->u.KeyValue.Data = SmallData;
142 }
143
144 /* Add this value cell to the child list */
145 Status = CmpAddValueToList(Hive,
146 ValueCell,
147 Index,
148 StorageType,
149 &Parent->ValueList);
150
151 /* If we failed, free the entire cell, including the data */
152 if (!NT_SUCCESS(Status)) CmpFreeValue(Hive, ValueCell);
153
154 /* Return Status */
155 return Status;
156 }
157
158 NTSTATUS
159 NTAPI
160 CmpSetValueKeyExisting(IN PHHIVE Hive,
161 IN HCELL_INDEX OldChild,
162 IN PCM_KEY_VALUE Value,
163 IN ULONG Type,
164 IN PVOID Data,
165 IN ULONG DataSize,
166 IN ULONG StorageType,
167 IN ULONG TempData)
168 {
169 HCELL_INDEX DataCell, NewCell;
170 PCELL_DATA CellData;
171 ULONG Length;
172 BOOLEAN WasSmall, IsSmall;
173
174 /* Mark the old child cell dirty */
175 HvMarkCellDirty(Hive, OldChild, FALSE);
176
177 /* See if this is a small or normal key */
178 WasSmall = CmpIsKeyValueSmall(&Length, Value->DataLength);
179
180 /* See if our new data can fit in a small key */
181 IsSmall = (DataSize <= CM_KEY_VALUE_SMALL) ? TRUE: FALSE;
182
183 /* Big keys are unsupported */
184 ASSERT_VALUE_BIG(Hive, Length);
185 ASSERT_VALUE_BIG(Hive, DataSize);
186
187 /* Mark the old value dirty */
188 CmpMarkValueDataDirty(Hive, Value);
189
190 /* Check if we have a small key */
191 if (IsSmall)
192 {
193 /* Check if we had a normal key with some data in it */
194 if (!(WasSmall) && (Length > 0))
195 {
196 /* Free the previous data */
197 CmpFreeValueData(Hive, Value->Data, Length);
198 }
199
200 /* Write our data directly */
201 Value->DataLength = DataSize + CM_KEY_VALUE_SPECIAL_SIZE;
202 Value->Data = TempData;
203 Value->Type = Type;
204 return STATUS_SUCCESS;
205 }
206 else
207 {
208 /* We have a normal key. Was the old cell also normal and had data? */
209 if (!(WasSmall) && (Length > 0))
210 {
211 /* Get the current data cell and actual data inside it */
212 DataCell = Value->Data;
213 ASSERT(DataCell != HCELL_NIL);
214 CellData = HvGetCell(Hive, DataCell);
215 if (!CellData) return STATUS_INSUFFICIENT_RESOURCES;
216
217 /* Immediately release the cell */
218 HvReleaseCell(Hive, DataCell);
219
220 /* Make sure that the data cell actually has a size */
221 ASSERT(HvGetCellSize(Hive, CellData) > 0);
222
223 /* Check if the previous data cell could fit our new data */
224 if (DataSize <= (ULONG)(HvGetCellSize(Hive, CellData)))
225 {
226 /* Re-use it then */
227 NewCell = DataCell;
228 }
229 else
230 {
231 /* Otherwise, re-allocate the current data cell */
232 NewCell = HvReallocateCell(Hive, DataCell, DataSize);
233 if (NewCell == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES;
234 }
235 }
236 else
237 {
238 /* This was a small key, or a key with no data, allocate a cell */
239 NewCell = HvAllocateCell(Hive, DataSize, StorageType, HCELL_NIL);
240 if (NewCell == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES;
241 }
242
243 /* Now get the actual data for our data cell */
244 CellData = HvGetCell(Hive, NewCell);
245 if (!CellData) ASSERT(FALSE);
246
247 /* Release it immediately */
248 HvReleaseCell(Hive, NewCell);
249
250 /* Copy our data into the data cell's buffer, and set up the value */
251 RtlCopyMemory(CellData, Data, DataSize);
252 Value->Data = NewCell;
253 Value->DataLength = DataSize;
254 Value->Type = Type;
255
256 /* Return success */
257 ASSERT(HvIsCellDirty(Hive, NewCell));
258 return STATUS_SUCCESS;
259 }
260 }
261
262 NTSTATUS
263 NTAPI
264 CmSetValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
265 IN PUNICODE_STRING ValueName,
266 IN ULONG Type,
267 IN PVOID Data,
268 IN ULONG DataLength)
269 {
270 PHHIVE Hive;
271 PCM_KEY_NODE Parent;
272 PCM_KEY_VALUE Value = NULL;
273 HCELL_INDEX CurrentChild, Cell;
274 NTSTATUS Status;
275 BOOLEAN Found, Result;
276 ULONG Count, ChildIndex, SmallData, Storage;
277 VALUE_SEARCH_RETURN_TYPE SearchResult;
278
279 /* Acquire hive lock */
280 CmpLockRegistry();
281 CmpAcquireKcbLockShared(Kcb);
282
283 /* Sanity check */
284 ASSERT(sizeof(ULONG) == CM_KEY_VALUE_SMALL);
285
286 /* Don't touch deleted KCBs */
287 DoAgain:
288 if (Kcb->Delete)
289 {
290 /* Fail */
291 Status = STATUS_KEY_DELETED;
292 goto Quickie;
293 }
294
295 /* Don't let anyone mess with symlinks */
296 if ((Kcb->Flags & KEY_SYM_LINK) &&
297 ((Type != REG_LINK) ||
298 !(ValueName) ||
299 !(RtlEqualUnicodeString(&CmSymbolicLinkValueName, ValueName, TRUE))))
300 {
301 /* Invalid modification of a symlink key */
302 Status = STATUS_ACCESS_DENIED;
303 goto Quickie;
304 }
305
306 /* Search for the value */
307 SearchResult = CmpCompareNewValueDataAgainstKCBCache(Kcb,
308 ValueName,
309 Type,
310 Data,
311 DataLength);
312 if (SearchResult == SearchNeedExclusiveLock)
313 {
314 /* Try again with the exclusive lock */
315 CmpConvertKcbSharedToExclusive(Kcb);
316 goto DoAgain;
317 }
318 else if (SearchResult == SearchSuccess)
319 {
320 /* We don't actually need to do anything! */
321 Status = STATUS_SUCCESS;
322 goto Quickie;
323 }
324
325 /* We need the exclusive KCB lock now */
326 if (!(CmpIsKcbLockedExclusive(Kcb)) && !(CmpTryToConvertKcbSharedToExclusive(Kcb)))
327 {
328 /* Acquire exclusive lock */
329 CmpConvertKcbSharedToExclusive(Kcb);
330 }
331
332 /* Get pointer to key cell */
333 Hive = Kcb->KeyHive;
334 Cell = Kcb->KeyCell;
335
336 /* Prepare to scan the key node */
337 Parent = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
338 Count = Parent->ValueList.Count;
339 Found = FALSE;
340 if (Count > 0)
341 {
342 /* Try to find the existing name */
343 Result = CmpFindNameInList(Hive,
344 &Parent->ValueList,
345 ValueName,
346 &ChildIndex,
347 &CurrentChild);
348 if (!Result)
349 {
350 /* Fail */
351 Status = STATUS_INSUFFICIENT_RESOURCES;
352 goto Quickie;
353 }
354
355 /* Check if we found something */
356 if (CurrentChild != HCELL_NIL)
357 {
358 /* Get its value */
359 Value = (PCM_KEY_VALUE)HvGetCell(Hive, CurrentChild);
360 if (!Value)
361 {
362 /* Fail */
363 Status = STATUS_INSUFFICIENT_RESOURCES;
364 goto Quickie;
365 }
366
367 /* Remember that we found it */
368 Found = TRUE;
369 }
370 }
371 else
372 {
373 /* No child list, we'll need to add it */
374 ChildIndex = 0;
375 }
376
377 /* The KCB must be locked exclusive at this point */
378 ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) ||
379 (CmpTestRegistryLockExclusive() == TRUE));
380
381 /* Mark the cell dirty */
382 HvMarkCellDirty(Hive, Cell, FALSE);
383
384 /* Get the storage type */
385 Storage = HvGetCellType(Cell);
386
387 /* Check if this is small data */
388 SmallData = 0;
389 if ((DataLength <= CM_KEY_VALUE_SMALL) && (DataLength > 0))
390 {
391 /* Copy it */
392 RtlCopyMemory(&SmallData, Data, DataLength);
393 }
394
395 /* Check if we didn't find a matching key */
396 if (!Found)
397 {
398 /* Call the internal routine */
399 Status = CmpSetValueKeyNew(Hive,
400 Parent,
401 ValueName,
402 ChildIndex,
403 Type,
404 Data,
405 DataLength,
406 Storage,
407 SmallData);
408 }
409 else
410 {
411 /* Call the internal routine */
412 Status = CmpSetValueKeyExisting(Hive,
413 CurrentChild,
414 Value,
415 Type,
416 Data,
417 DataLength,
418 Storage,
419 SmallData);
420 }
421
422 /* Check for success */
423 if (NT_SUCCESS(Status))
424 {
425 /* Check if the maximum value name length changed */
426 ASSERT(Parent->MaxValueNameLen == Kcb->KcbMaxValueNameLen);
427 if (Parent->MaxValueNameLen < ValueName->Length)
428 {
429 /* Set the new values */
430 Parent->MaxValueNameLen = ValueName->Length;
431 Kcb->KcbMaxValueNameLen = ValueName->Length;
432 }
433
434 /* Check if the maximum data length changed */
435 ASSERT(Parent->MaxValueDataLen == Kcb->KcbMaxValueDataLen);
436 if (Parent->MaxValueDataLen < DataLength)
437 {
438 /* Update it */
439 Parent->MaxValueDataLen = DataLength;
440 Kcb->KcbMaxValueDataLen = Parent->MaxValueDataLen;
441 }
442
443 /* Save the write time */
444 KeQuerySystemTime(&Parent->LastWriteTime);
445 KeQuerySystemTime(&Kcb->KcbLastWriteTime);
446
447 /* Check if the cell is cached */
448 if ((Found) && (CMP_IS_CELL_CACHED(Kcb->ValueCache.ValueList)))
449 {
450 /* Shouldn't happen */
451 ASSERT(FALSE);
452 }
453 else
454 {
455 /* Cleanup the value cache */
456 CmpCleanUpKcbValueCache(Kcb);
457
458 /* Sanity checks */
459 ASSERT(!(CMP_IS_CELL_CACHED(Kcb->ValueCache.ValueList)));
460 ASSERT(!(Kcb->ExtFlags & CM_KCB_SYM_LINK_FOUND));
461
462 /* Set the value cache */
463 Kcb->ValueCache.Count = Parent->ValueList.Count;
464 Kcb->ValueCache.ValueList = Parent->ValueList.List;
465 }
466 }
467
468 Quickie:
469 /* Release the locks */
470 CmpReleaseKcbLock(Kcb);
471 CmpUnlockRegistry();
472 return Status;
473 }
474
475 NTSTATUS
476 NTAPI
477 CmDeleteValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
478 IN UNICODE_STRING ValueName)
479 {
480 NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND;
481 PHHIVE Hive;
482 PCM_KEY_NODE Parent;
483 HCELL_INDEX ChildCell, Cell;
484 PCHILD_LIST ChildList;
485 PCM_KEY_VALUE Value = NULL;
486 ULONG ChildIndex;
487 BOOLEAN Result;
488
489 /* Acquire hive lock */
490 CmpLockRegistry();
491
492 /* Lock KCB exclusively */
493 CmpAcquireKcbLockExclusive(Kcb);
494
495 /* Don't touch deleted keys */
496 if (Kcb->Delete)
497 {
498 /* Undo everything */
499 CmpReleaseKcbLock(Kcb);
500 CmpUnlockRegistry();
501 return STATUS_KEY_DELETED;
502 }
503
504 /* Get the hive and the cell index */
505 Hive = Kcb->KeyHive;
506 Cell = Kcb->KeyCell;
507
508 /* Get the parent key node */
509 Parent = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
510 if (!Parent)
511 {
512 /* Fail */
513 Status = STATUS_INSUFFICIENT_RESOURCES;
514 goto Quickie;
515 }
516
517 /* Get the value list and check if it has any entries */
518 ChildList = &Parent->ValueList;
519 if (ChildList->Count)
520 {
521 /* Try to find this value */
522 Result = CmpFindNameInList(Hive,
523 ChildList,
524 &ValueName,
525 &ChildIndex,
526 &ChildCell);
527 if (!Result)
528 {
529 /* Fail */
530 Status = STATUS_INSUFFICIENT_RESOURCES;
531 goto Quickie;
532 }
533
534 /* Value not found, return error */
535 if (ChildCell == HCELL_NIL) goto Quickie;
536
537 /* We found the value, mark all relevant cells dirty */
538 HvMarkCellDirty(Hive, Cell, FALSE);
539 HvMarkCellDirty(Hive, Parent->ValueList.List, FALSE);
540 HvMarkCellDirty(Hive, ChildCell, FALSE);
541
542 /* Get the key value */
543 Value = (PCM_KEY_VALUE)HvGetCell(Hive,ChildCell);
544 if (!Value) ASSERT(FALSE);
545
546 /* Mark it and all related data as dirty */
547 CmpMarkValueDataDirty(Hive, Value);
548
549 /* Ssanity checks */
550 ASSERT(HvIsCellDirty(Hive, Parent->ValueList.List));
551 ASSERT(HvIsCellDirty(Hive, ChildCell));
552
553 /* Remove the value from the child list */
554 Status = CmpRemoveValueFromList(Hive, ChildIndex, ChildList);
555 if(!NT_SUCCESS(Status)) goto Quickie;
556
557 /* Remove the value and its data itself */
558 if (!CmpFreeValue(Hive, ChildCell))
559 {
560 /* Failed to free the value, fail */
561 Status = STATUS_INSUFFICIENT_RESOURCES;
562 goto Quickie;
563 }
564
565 /* Set the last write time */
566 KeQuerySystemTime(&Parent->LastWriteTime);
567 KeQuerySystemTime(&Kcb->KcbLastWriteTime);
568
569 /* Sanity check */
570 ASSERT(Parent->MaxValueNameLen == Kcb->KcbMaxValueNameLen);
571 ASSERT(Parent->MaxValueDataLen == Kcb->KcbMaxValueDataLen);
572 ASSERT(HvIsCellDirty(Hive, Cell));
573
574 /* Check if the value list is empty now */
575 if (!Parent->ValueList.Count)
576 {
577 /* Then clear key node data */
578 Parent->MaxValueNameLen = 0;
579 Parent->MaxValueDataLen = 0;
580 Kcb->KcbMaxValueNameLen = 0;
581 Kcb->KcbMaxValueDataLen = 0;
582 }
583
584 /* Cleanup the value cache */
585 CmpCleanUpKcbValueCache(Kcb);
586
587 /* Sanity checks */
588 ASSERT(!(CMP_IS_CELL_CACHED(Kcb->ValueCache.ValueList)));
589 ASSERT(!(Kcb->ExtFlags & CM_KCB_SYM_LINK_FOUND));
590
591 /* Set the value cache */
592 Kcb->ValueCache.Count = ChildList->Count;
593 Kcb->ValueCache.ValueList = ChildList->List;
594
595 /* Change default Status to success */
596 Status = STATUS_SUCCESS;
597 }
598
599 Quickie:
600 /* Release the parent cell, if any */
601 if (Parent) HvReleaseCell(Hive, Cell);
602
603 /* Check if we had a value */
604 if (Value)
605 {
606 /* Release the child cell */
607 ASSERT(ChildCell != HCELL_NIL);
608 HvReleaseCell(Hive, ChildCell);
609 }
610
611 /* Release locks */
612 CmpReleaseKcbLock(Kcb);
613 CmpUnlockRegistry();
614 return Status;
615 }
616
617 NTSTATUS
618 NTAPI
619 CmQueryValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
620 IN UNICODE_STRING ValueName,
621 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
622 IN PVOID KeyValueInformation,
623 IN ULONG Length,
624 IN PULONG ResultLength)
625 {
626 NTSTATUS Status;
627 PCM_KEY_VALUE ValueData;
628 ULONG Index;
629 BOOLEAN ValueCached = FALSE;
630 PCM_CACHED_VALUE *CachedValue;
631 HCELL_INDEX CellToRelease;
632 VALUE_SEARCH_RETURN_TYPE Result;
633 PHHIVE Hive;
634 PAGED_CODE();
635
636 /* Acquire hive lock */
637 CmpLockRegistry();
638
639 /* Lock the KCB shared */
640 CmpAcquireKcbLockShared(Kcb);
641
642 /* Don't touch deleted keys */
643 DoAgain:
644 if (Kcb->Delete)
645 {
646 /* Undo everything */
647 CmpReleaseKcbLock(Kcb);
648 CmpUnlockRegistry();
649 return STATUS_KEY_DELETED;
650 }
651
652 /* We don't deal with this yet */
653 if (Kcb->ExtFlags & CM_KCB_SYM_LINK_FOUND)
654 {
655 /* Shouldn't happen */
656 ASSERT(FALSE);
657 }
658
659 /* Get the hive */
660 Hive = Kcb->KeyHive;
661
662 /* Find the key value */
663 Result = CmpFindValueByNameFromCache(Kcb,
664 &ValueName,
665 &CachedValue,
666 &Index,
667 &ValueData,
668 &ValueCached,
669 &CellToRelease);
670 if (Result == SearchNeedExclusiveLock)
671 {
672 /* Check if we need an exclusive lock */
673 ASSERT(CellToRelease == HCELL_NIL);
674 ASSERT(ValueData == NULL);
675
676 /* Try with exclusive KCB lock */
677 CmpConvertKcbSharedToExclusive(Kcb);
678 goto DoAgain;
679 }
680
681 if (Result == SearchSuccess)
682 {
683 /* Sanity check */
684 ASSERT(ValueData != NULL);
685
686 /* Query the information requested */
687 Result = CmpQueryKeyValueData(Kcb,
688 CachedValue,
689 ValueData,
690 ValueCached,
691 KeyValueInformationClass,
692 KeyValueInformation,
693 Length,
694 ResultLength,
695 &Status);
696 if (Result == SearchNeedExclusiveLock)
697 {
698 /* Try with exclusive KCB lock */
699 CmpConvertKcbSharedToExclusive(Kcb);
700 goto DoAgain;
701 }
702 }
703 else
704 {
705 /* Failed to find the value */
706 Status = STATUS_OBJECT_NAME_NOT_FOUND;
707 }
708
709 /* If we have a cell to release, do so */
710 if (CellToRelease != HCELL_NIL) HvReleaseCell(Hive, CellToRelease);
711
712 /* Release locks */
713 CmpReleaseKcbLock(Kcb);
714 CmpUnlockRegistry();
715 return Status;
716 }
717
718 NTSTATUS
719 NTAPI
720 CmEnumerateValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
721 IN ULONG Index,
722 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
723 IN PVOID KeyValueInformation,
724 IN ULONG Length,
725 IN PULONG ResultLength)
726 {
727 NTSTATUS Status;
728 PHHIVE Hive;
729 PCM_KEY_NODE Parent;
730 HCELL_INDEX CellToRelease = HCELL_NIL, CellToRelease2 = HCELL_NIL;
731 VALUE_SEARCH_RETURN_TYPE Result;
732 BOOLEAN IndexIsCached, ValueIsCached = FALSE;
733 PCELL_DATA CellData;
734 PCM_CACHED_VALUE *CachedValue;
735 PCM_KEY_VALUE ValueData = NULL;
736 PAGED_CODE();
737
738 /* Acquire hive lock */
739 CmpLockRegistry();
740
741 /* Lock the KCB shared */
742 CmpAcquireKcbLockShared(Kcb);
743
744 /* Don't touch deleted keys */
745 DoAgain:
746 if (Kcb->Delete)
747 {
748 /* Undo everything */
749 CmpReleaseKcbLock(Kcb);
750 CmpUnlockRegistry();
751 return STATUS_KEY_DELETED;
752 }
753
754 /* Get the hive and parent */
755 Hive = Kcb->KeyHive;
756 Parent = (PCM_KEY_NODE)HvGetCell(Hive, Kcb->KeyCell);
757 if (!Parent)
758 {
759 /* Fail */
760 Status = STATUS_INSUFFICIENT_RESOURCES;
761 goto Quickie;
762 }
763
764 /* Make sure the index is valid */
765 //if (Index >= Kcb->ValueCache.Count)
766 if (Index >= Parent->ValueList.Count)
767 {
768 /* Release the cell and fail */
769 HvReleaseCell(Hive, Kcb->KeyCell);
770 Status = STATUS_NO_MORE_ENTRIES;
771 goto Quickie;
772 }
773
774 /* We don't deal with this yet */
775 if (Kcb->ExtFlags & CM_KCB_SYM_LINK_FOUND)
776 {
777 /* Shouldn't happen */
778 ASSERT(FALSE);
779 }
780
781 /* Find the value list */
782 Result = CmpGetValueListFromCache(Kcb,
783 &CellData,
784 &IndexIsCached,
785 &CellToRelease);
786 if (Result == SearchNeedExclusiveLock)
787 {
788 /* Check if we need an exclusive lock */
789 ASSERT(CellToRelease == HCELL_NIL);
790 ASSERT(ValueData == NULL);
791
792 /* Try with exclusive KCB lock */
793 CmpConvertKcbSharedToExclusive(Kcb);
794 goto DoAgain;
795 }
796 else if (Result != SearchSuccess)
797 {
798 /* Sanity check */
799 ASSERT(CellData == NULL);
800
801 /* Release the cell and fail */
802 Status = STATUS_INSUFFICIENT_RESOURCES;
803 goto Quickie;
804 }
805
806 /* Now get the key value */
807 Result = CmpGetValueKeyFromCache(Kcb,
808 CellData,
809 Index,
810 &CachedValue,
811 &ValueData,
812 IndexIsCached,
813 &ValueIsCached,
814 &CellToRelease2);
815 if (Result == SearchNeedExclusiveLock)
816 {
817 /* Try with exclusive KCB lock */
818 CmpConvertKcbSharedToExclusive(Kcb);
819 goto DoAgain;
820 }
821 else if (Result != SearchSuccess)
822 {
823 /* Sanity check */
824 ASSERT(ValueData == NULL);
825
826 /* Release the cells and fail */
827 Status = STATUS_INSUFFICIENT_RESOURCES;
828 goto Quickie;
829 }
830
831 /* Query the information requested */
832 Result = CmpQueryKeyValueData(Kcb,
833 CachedValue,
834 ValueData,
835 ValueIsCached,
836 KeyValueInformationClass,
837 KeyValueInformation,
838 Length,
839 ResultLength,
840 &Status);
841 if (Result == SearchNeedExclusiveLock)
842 {
843 /* Try with exclusive KCB lock */
844 CmpConvertKcbSharedToExclusive(Kcb);
845 goto DoAgain;
846 }
847
848 Quickie:
849 /* If we have a cell to release, do so */
850 if (CellToRelease != HCELL_NIL) HvReleaseCell(Hive, CellToRelease);
851
852 /* Release the parent cell */
853 HvReleaseCell(Hive, Kcb->KeyCell);
854
855 /* If we have a cell to release, do so */
856 if (CellToRelease2 != HCELL_NIL) HvReleaseCell(Hive, CellToRelease2);
857
858 /* Release locks */
859 CmpReleaseKcbLock(Kcb);
860 CmpUnlockRegistry();
861 return Status;
862 }
863
864 NTSTATUS
865 NTAPI
866 CmpQueryKeyData(IN PHHIVE Hive,
867 IN PCM_KEY_NODE Node,
868 IN KEY_INFORMATION_CLASS KeyInformationClass,
869 IN OUT PVOID KeyInformation,
870 IN ULONG Length,
871 IN OUT PULONG ResultLength)
872 {
873 NTSTATUS Status;
874 ULONG Size, SizeLeft, MinimumSize;
875 PKEY_INFORMATION Info = (PKEY_INFORMATION)KeyInformation;
876 USHORT NameLength;
877
878 /* Check if the value is compressed */
879 if (Node->Flags & KEY_COMP_NAME)
880 {
881 /* Get the compressed name size */
882 NameLength = CmpCompressedNameSize(Node->Name, Node->NameLength);
883 }
884 else
885 {
886 /* Get the real size */
887 NameLength = Node->NameLength;
888 }
889
890 /* Check what kind of information is being requested */
891 switch (KeyInformationClass)
892 {
893 /* Basic information */
894 case KeyBasicInformation:
895
896 /* This is the size we need */
897 Size = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name) + NameLength;
898
899 /* And this is the minimum we can work with */
900 MinimumSize = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name);
901
902 /* Let the caller know and assume success */
903 *ResultLength = Size;
904 Status = STATUS_SUCCESS;
905
906 /* Check if the bufer we got is too small */
907 if (Length < MinimumSize)
908 {
909 /* Let the caller know and fail */
910 Status = STATUS_BUFFER_TOO_SMALL;
911 break;
912 }
913
914 /* Copy the basic information */
915 Info->KeyBasicInformation.LastWriteTime = Node->LastWriteTime;
916 Info->KeyBasicInformation.TitleIndex = 0;
917 Info->KeyBasicInformation.NameLength = NameLength;
918
919 /* Only the name is left */
920 SizeLeft = Length - MinimumSize;
921 Size = NameLength;
922
923 /* Check if we don't have enough space for the name */
924 if (SizeLeft < Size)
925 {
926 /* Truncate the name we'll return, and tell the caller */
927 Size = SizeLeft;
928 Status = STATUS_BUFFER_OVERFLOW;
929 }
930
931 /* Check if this is a compressed key */
932 if (Node->Flags & KEY_COMP_NAME)
933 {
934 /* Copy the compressed name */
935 CmpCopyCompressedName(Info->KeyBasicInformation.Name,
936 SizeLeft,
937 Node->Name,
938 Node->NameLength);
939 }
940 else
941 {
942 /* Otherwise, copy the raw name */
943 RtlCopyMemory(Info->KeyBasicInformation.Name,
944 Node->Name,
945 Size);
946 }
947 break;
948
949 /* Node information */
950 case KeyNodeInformation:
951
952 /* Calculate the size we need */
953 Size = FIELD_OFFSET(KEY_NODE_INFORMATION, Name) +
954 NameLength +
955 Node->ClassLength;
956
957 /* And the minimum size we can support */
958 MinimumSize = FIELD_OFFSET(KEY_NODE_INFORMATION, Name);
959
960 /* Return the size to the caller and assume succes */
961 *ResultLength = Size;
962 Status = STATUS_SUCCESS;
963
964 /* Check if the caller's buffer is too small */
965 if (Length < MinimumSize)
966 {
967 /* Let them know, and fail */
968 Status = STATUS_BUFFER_TOO_SMALL;
969 break;
970 }
971
972 /* Copy the basic information */
973 Info->KeyNodeInformation.LastWriteTime = Node->LastWriteTime;
974 Info->KeyNodeInformation.TitleIndex = 0;
975 Info->KeyNodeInformation.ClassLength = Node->ClassLength;
976 Info->KeyNodeInformation.NameLength = NameLength;
977
978 /* Now the name is left */
979 SizeLeft = Length - MinimumSize;
980 Size = NameLength;
981
982 /* Check if the name can fit entirely */
983 if (SizeLeft < Size)
984 {
985 /* It can't, we'll have to truncate. Tell the caller */
986 Size = SizeLeft;
987 Status = STATUS_BUFFER_OVERFLOW;
988 }
989
990 /* Check if the key node name is compressed */
991 if (Node->Flags & KEY_COMP_NAME)
992 {
993 /* Copy the compressed name */
994 CmpCopyCompressedName(Info->KeyNodeInformation.Name,
995 SizeLeft,
996 Node->Name,
997 Node->NameLength);
998 }
999 else
1000 {
1001 /* It isn't, so copy the raw name */
1002 RtlCopyMemory(Info->KeyNodeInformation.Name,
1003 Node->Name,
1004 Size);
1005 }
1006
1007 /* Check if the node has a class */
1008 if (Node->ClassLength > 0)
1009 {
1010 /* It does. We don't support these yet */
1011 ASSERTMSG("Classes not supported\n", FALSE);
1012 }
1013 else
1014 {
1015 /* It doesn't, so set offset to -1, not 0! */
1016 Info->KeyNodeInformation.ClassOffset = 0xFFFFFFFF;
1017 }
1018 break;
1019
1020 /* Full information requsted */
1021 case KeyFullInformation:
1022
1023 /* This is the size we need */
1024 Size = FIELD_OFFSET(KEY_FULL_INFORMATION, Class) +
1025 Node->ClassLength;
1026
1027 /* This is what we can work with */
1028 MinimumSize = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
1029
1030 /* Return it to caller and assume success */
1031 *ResultLength = Size;
1032 Status = STATUS_SUCCESS;
1033
1034 /* Check if the caller's buffer is to small */
1035 if (Length < MinimumSize)
1036 {
1037 /* Let them know and fail */
1038 Status = STATUS_BUFFER_TOO_SMALL;
1039 break;
1040 }
1041
1042 /* Now copy all the basic information */
1043 Info->KeyFullInformation.LastWriteTime = Node->LastWriteTime;
1044 Info->KeyFullInformation.TitleIndex = 0;
1045 Info->KeyFullInformation.ClassLength = Node->ClassLength;
1046 Info->KeyFullInformation.SubKeys = Node->SubKeyCounts[Stable] +
1047 Node->SubKeyCounts[Volatile];
1048 Info->KeyFullInformation.Values = Node->ValueList.Count;
1049 Info->KeyFullInformation.MaxNameLen = Node->MaxNameLen;
1050 Info->KeyFullInformation.MaxClassLen = Node->MaxClassLen;
1051 Info->KeyFullInformation.MaxValueNameLen = Node->MaxValueNameLen;
1052 Info->KeyFullInformation.MaxValueDataLen = Node->MaxValueDataLen;
1053
1054 /* Check if we have a class */
1055 if (Node->ClassLength > 0)
1056 {
1057 /* We do, but we currently don't support this */
1058 ASSERTMSG("Classes not supported\n", FALSE);
1059 }
1060 else
1061 {
1062 /* We don't have a class, so set offset to -1, not 0! */
1063 Info->KeyNodeInformation.ClassOffset = 0xFFFFFFFF;
1064 }
1065 break;
1066
1067 /* Any other class that got sent here is invalid! */
1068 default:
1069
1070 /* Set failure code */
1071 Status = STATUS_INVALID_PARAMETER;
1072 break;
1073 }
1074
1075 /* Return status */
1076 return Status;
1077 }
1078
1079 NTSTATUS
1080 NTAPI
1081 CmQueryKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
1082 IN KEY_INFORMATION_CLASS KeyInformationClass,
1083 IN PVOID KeyInformation,
1084 IN ULONG Length,
1085 IN PULONG ResultLength)
1086 {
1087 NTSTATUS Status;
1088 PHHIVE Hive;
1089 PCM_KEY_NODE Parent;
1090
1091 /* Acquire hive lock */
1092 CmpLockRegistry();
1093
1094 /* Lock KCB shared */
1095 CmpAcquireKcbLockShared(Kcb);
1096
1097 /* Get the hive and parent */
1098 Hive = Kcb->KeyHive;
1099 Parent = (PCM_KEY_NODE)HvGetCell(Hive, Kcb->KeyCell);
1100 if (!Parent)
1101 {
1102 /* Fail */
1103 Status = STATUS_INSUFFICIENT_RESOURCES;
1104 goto Quickie;
1105 }
1106
1107 /* Don't touch deleted keys */
1108 if (Kcb->Delete)
1109 {
1110 /* Fail */
1111 Status = STATUS_KEY_DELETED;
1112 goto Quickie;
1113 }
1114
1115 /* Check what class we got */
1116 switch (KeyInformationClass)
1117 {
1118 /* Typical information */
1119 case KeyFullInformation:
1120 case KeyBasicInformation:
1121 case KeyNodeInformation:
1122
1123 /* Call the internal API */
1124 Status = CmpQueryKeyData(Hive,
1125 Parent,
1126 KeyInformationClass,
1127 KeyInformation,
1128 Length,
1129 ResultLength);
1130 break;
1131
1132 /* Unsupported classes for now */
1133 case KeyNameInformation:
1134 case KeyCachedInformation:
1135 case KeyFlagsInformation:
1136
1137 /* Print message and fail */
1138 DPRINT1("Unsupported class: %d!\n", KeyInformationClass);
1139 Status = STATUS_NOT_IMPLEMENTED;
1140 break;
1141
1142 /* Illegal classes */
1143 default:
1144
1145 /* Print message and fail */
1146 DPRINT1("Unsupported class: %d!\n", KeyInformationClass);
1147 Status = STATUS_INVALID_INFO_CLASS;
1148 break;
1149 }
1150
1151 Quickie:
1152 /* Release locks */
1153 CmpReleaseKcbLock(Kcb);
1154 CmpUnlockRegistry();
1155 return Status;
1156 }
1157
1158 NTSTATUS
1159 NTAPI
1160 CmEnumerateKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
1161 IN ULONG Index,
1162 IN KEY_INFORMATION_CLASS KeyInformationClass,
1163 IN PVOID KeyInformation,
1164 IN ULONG Length,
1165 IN PULONG ResultLength)
1166 {
1167 NTSTATUS Status;
1168 PHHIVE Hive;
1169 PCM_KEY_NODE Parent, Child;
1170 HCELL_INDEX ChildCell;
1171
1172 /* Acquire hive lock */
1173 CmpLockRegistry();
1174
1175 /* Lock the KCB shared */
1176 CmpAcquireKcbLockShared(Kcb);
1177
1178 /* Don't touch deleted keys */
1179 if (Kcb->Delete)
1180 {
1181 /* Undo everything */
1182 CmpReleaseKcbLock(Kcb);
1183 CmpUnlockRegistry();
1184 return STATUS_KEY_DELETED;
1185 }
1186
1187 /* Get the hive and parent */
1188 Hive = Kcb->KeyHive;
1189 Parent = (PCM_KEY_NODE)HvGetCell(Hive, Kcb->KeyCell);
1190 if (!Parent)
1191 {
1192 /* Fail */
1193 Status = STATUS_INSUFFICIENT_RESOURCES;
1194 goto Quickie;
1195 }
1196
1197 /* Get the child cell */
1198 ChildCell = CmpFindSubKeyByNumber(Hive, Parent, Index);
1199
1200 /* Release the parent cell */
1201 HvReleaseCell(Hive, Kcb->KeyCell);
1202
1203 /* Check if we found the child */
1204 if (ChildCell == HCELL_NIL)
1205 {
1206 /* We didn't, fail */
1207 Status = STATUS_NO_MORE_ENTRIES;
1208 goto Quickie;
1209 }
1210
1211 /* Now get the actual child node */
1212 Child = (PCM_KEY_NODE)HvGetCell(Hive, ChildCell);
1213 if (!Child)
1214 {
1215 /* Fail */
1216 Status = STATUS_INSUFFICIENT_RESOURCES;
1217 goto Quickie;
1218 }
1219
1220 /* Query the data requested */
1221 Status = CmpQueryKeyData(Hive,
1222 Child,
1223 KeyInformationClass,
1224 KeyInformation,
1225 Length,
1226 ResultLength);
1227
1228 Quickie:
1229 /* Release locks */
1230 CmpReleaseKcbLock(Kcb);
1231 CmpUnlockRegistry();
1232 return Status;
1233 }
1234
1235 NTSTATUS
1236 NTAPI
1237 CmDeleteKey(IN PCM_KEY_BODY KeyBody)
1238 {
1239 NTSTATUS Status;
1240 PHHIVE Hive;
1241 PCM_KEY_NODE Node, Parent;
1242 HCELL_INDEX Cell, ParentCell;
1243 PCM_KEY_CONTROL_BLOCK Kcb;
1244
1245 /* Acquire hive lock */
1246 CmpLockRegistry();
1247
1248 /* Get the kcb */
1249 Kcb = KeyBody->KeyControlBlock;
1250
1251 /* Don't allow deleting the root */
1252 if (!Kcb->ParentKcb)
1253 {
1254 /* Fail */
1255 CmpUnlockRegistry();
1256 return STATUS_CANNOT_DELETE;
1257 }
1258
1259 /* Lock parent and child */
1260 CmpAcquireTwoKcbLocksExclusiveByKey(Kcb->ConvKey, Kcb->ParentKcb->ConvKey);
1261
1262 /* Check if we're already being deleted */
1263 if (Kcb->Delete)
1264 {
1265 /* Don't do it twice */
1266 Status = STATUS_SUCCESS;
1267 goto Quickie2;
1268 }
1269
1270 /* Get the hive and node */
1271 Hive = Kcb->KeyHive;
1272 Cell = Kcb->KeyCell;
1273
1274 /* Get the key node */
1275 Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
1276 if (!Node)
1277 {
1278 /* Fail */
1279 Status = STATUS_INSUFFICIENT_RESOURCES;
1280 goto Quickie;
1281 }
1282
1283 /* Sanity check */
1284 ASSERT(Node->Flags == Kcb->Flags);
1285
1286 /* Check if we don't have any children */
1287 if (!(Node->SubKeyCounts[Stable] + Node->SubKeyCounts[Volatile]) &&
1288 !(Node->Flags & KEY_NO_DELETE))
1289 {
1290 /* Get the parent and free the cell */
1291 ParentCell = Node->Parent;
1292 Status = CmpFreeKeyByCell(Hive, Cell, TRUE);
1293 if (NT_SUCCESS(Status))
1294 {
1295 /* Clean up information we have on the subkey */
1296 CmpCleanUpSubKeyInfo(Kcb->ParentKcb);
1297
1298 /* Get the parent node */
1299 Parent = (PCM_KEY_NODE)HvGetCell(Hive, ParentCell);
1300 if (Parent)
1301 {
1302 /* Update the maximum name length */
1303 Kcb->ParentKcb->KcbMaxNameLen = Parent->MaxNameLen;
1304
1305 /* Make sure we're dirty */
1306 ASSERT(HvIsCellDirty(Hive, ParentCell));
1307
1308 /* Update the write time */
1309 KeQuerySystemTime(&Parent->LastWriteTime);
1310 KeQuerySystemTime(&Kcb->ParentKcb->KcbLastWriteTime);
1311
1312 /* Release the cell */
1313 HvReleaseCell(Hive, ParentCell);
1314 }
1315
1316 /* Set the KCB in delete mode and remove it */
1317 Kcb->Delete = TRUE;
1318 CmpRemoveKeyControlBlock(Kcb);
1319
1320 /* Clear the cell */
1321 Kcb->KeyCell = HCELL_NIL;
1322 }
1323 }
1324 else
1325 {
1326 /* Fail */
1327 Status = STATUS_CANNOT_DELETE;
1328 }
1329
1330 Quickie:
1331 /* Release the cell */
1332 HvReleaseCell(Hive, Cell);
1333
1334 /* Release the KCB locks */
1335 Quickie2:
1336 CmpReleaseTwoKcbLockByKey(Kcb->ConvKey, Kcb->ParentKcb->ConvKey);
1337
1338 /* Release hive lock */
1339 CmpUnlockRegistry();
1340 return Status;
1341 }
1342
1343 NTSTATUS
1344 NTAPI
1345 CmFlushKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
1346 IN BOOLEAN ExclusiveLock)
1347 {
1348 PCMHIVE CmHive;
1349 NTSTATUS Status = STATUS_SUCCESS;
1350 PHHIVE Hive;
1351
1352 /* Ignore flushes until we're ready */
1353 if (CmpNoWrite) return STATUS_SUCCESS;
1354
1355 /* Get the hives */
1356 Hive = Kcb->KeyHive;
1357 CmHive = (PCMHIVE)Hive;
1358
1359 /* Check if this is the master hive */
1360 if (CmHive == CmiVolatileHive)
1361 {
1362 /* Flush all the hives instead */
1363 CmpDoFlushAll(FALSE);
1364 }
1365 else
1366 {
1367 /* Flush only this hive */
1368 if (!HvSyncHive(Hive))
1369 {
1370 /* Fail */
1371 Status = STATUS_REGISTRY_IO_FAILED;
1372 }
1373 }
1374
1375 /* Return the status */
1376 return Status;
1377 }
1378
1379 NTSTATUS
1380 NTAPI
1381 CmLoadKey(IN POBJECT_ATTRIBUTES TargetKey,
1382 IN POBJECT_ATTRIBUTES SourceFile,
1383 IN ULONG Flags,
1384 IN PCM_KEY_BODY KeyBody)
1385 {
1386 SECURITY_QUALITY_OF_SERVICE ServiceQos;
1387 SECURITY_CLIENT_CONTEXT ClientSecurityContext;
1388 HANDLE KeyHandle;
1389 BOOLEAN Allocate = TRUE;
1390 PCMHIVE CmHive;
1391 NTSTATUS Status;
1392
1393 /* Check if we have a trust key */
1394 if (KeyBody)
1395 {
1396 /* Fail */
1397 DPRINT1("Trusted classes not yet supported\n");
1398 return STATUS_NOT_IMPLEMENTED;
1399 }
1400
1401 /* Build a service QoS for a security context */
1402 ServiceQos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
1403 ServiceQos.ImpersonationLevel = SecurityImpersonation;
1404 ServiceQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
1405 ServiceQos.EffectiveOnly = TRUE;
1406 Status = SeCreateClientSecurity(PsGetCurrentThread(),
1407 &ServiceQos,
1408 FALSE,
1409 &ClientSecurityContext);
1410 if (!NT_SUCCESS(Status))
1411 {
1412 /* Fail */
1413 DPRINT1("Security context failed\n");
1414 return Status;
1415 }
1416
1417 /* Open the target key */
1418 Status = ZwOpenKey(&KeyHandle, KEY_READ, TargetKey);
1419 if (!NT_SUCCESS(Status)) KeyHandle = NULL;
1420
1421 /* Open the hive */
1422 Status = CmpCmdHiveOpen(SourceFile,
1423 &ClientSecurityContext,
1424 &Allocate,
1425 &CmHive,
1426 0);
1427
1428 /* Get rid of the security context */
1429 SeDeleteClientSecurity(&ClientSecurityContext);
1430
1431 /* See if we failed */
1432 if (!NT_SUCCESS(Status))
1433 {
1434 /* See if the target already existed */
1435 if (KeyHandle)
1436 {
1437 /* Lock the registry */
1438 CmpLockRegistryExclusive();
1439
1440 /* FIXME: Check if we are already loaded */
1441
1442 /* Release the registry */
1443 CmpUnlockRegistry();
1444 }
1445
1446 /* Close the key handle if we had one */
1447 if (KeyHandle) ZwClose(KeyHandle);
1448 DPRINT1("Failed: %lx\n", Status);
1449 return Status;
1450 }
1451
1452 /* Lock the registry shared */
1453 CmpLockRegistry();
1454
1455 /* Lock the hive to this thread */
1456 CmHive->Hive.HiveFlags |= HIVE_IS_UNLOADING;
1457 CmHive->CreatorOwner = KeGetCurrentThread();
1458
1459 /* Set flag */
1460 if (Flags & REG_NO_LAZY_FLUSH) CmHive->Hive.HiveFlags |= HIVE_NOLAZYFLUSH;
1461
1462 /* Link the hive */
1463 Status = CmpLinkHiveToMaster(TargetKey->ObjectName,
1464 TargetKey->RootDirectory,
1465 CmHive,
1466 Allocate,
1467 TargetKey->SecurityDescriptor);
1468 if (NT_SUCCESS(Status))
1469 {
1470 /* FIXME: Add to HiveList key */
1471
1472 /* Sync the hive if necessary */
1473 if (Allocate)
1474 {
1475 /* Sync it */
1476 HvSyncHive(&CmHive->Hive);
1477 }
1478
1479 /* Release the hive */
1480 CmHive->Hive.HiveFlags &= ~HIVE_IS_UNLOADING;
1481 CmHive->CreatorOwner = NULL;
1482 }
1483 else
1484 {
1485 /* FIXME: TODO */
1486
1487 }
1488
1489 /* Unlock the registry */
1490 CmpUnlockRegistry();
1491
1492 /* Close handle and return */
1493 if (KeyHandle) ZwClose(KeyHandle);
1494 return Status;
1495 }