- Update cached KCB values when necessary.
[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 #include "cm.h"
13 #define NDEBUG
14 #include "debug.h"
15
16 /* FUNCTIONS *****************************************************************/
17
18 NTSTATUS
19 NTAPI
20 CmpSetValueKeyNew(IN PHHIVE Hive,
21 IN PCM_KEY_NODE Parent,
22 IN PUNICODE_STRING ValueName,
23 IN ULONG Index,
24 IN ULONG Type,
25 IN PVOID Data,
26 IN ULONG DataSize,
27 IN ULONG StorageType,
28 IN ULONG SmallData)
29 {
30 PCELL_DATA CellData;
31 HCELL_INDEX ValueCell;
32 NTSTATUS Status;
33
34 /* Check if we already have a value list */
35 if (Parent->ValueList.Count)
36 {
37 /* Then make sure it's valid and dirty it */
38 ASSERT(Parent->ValueList.List != HCELL_NIL);
39 HvMarkCellDirty(Hive, Parent->ValueList.List, FALSE);
40 }
41
42 /* Allocate avalue cell */
43 ValueCell = HvAllocateCell(Hive,
44 FIELD_OFFSET(CM_KEY_VALUE, Name) +
45 CmpNameSize(Hive, ValueName),
46 StorageType,
47 HCELL_NIL);
48 if (ValueCell == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES;
49
50 /* Get the actual data for it */
51 CellData = HvGetCell(Hive, ValueCell);
52 if (!CellData) ASSERT(FALSE);
53
54 /* Now we can release it, make sure it's also dirty */
55 HvReleaseCell(Hive, ValueCell);
56 ASSERT(HvIsCellDirty(Hive, ValueCell));
57
58 /* Set it up and copy the name */
59 CellData->u.KeyValue.Signature = CM_KEY_VALUE_SIGNATURE;
60 CellData->u.KeyValue.Flags = 0;
61 CellData->u.KeyValue.Type = Type;
62 CellData->u.KeyValue.NameLength = CmpCopyName(Hive,
63 CellData->u.KeyValue.Name,
64 ValueName);
65 if (CellData->u.KeyValue.NameLength < ValueName->Length)
66 {
67 /* This is a compressed name */
68 CellData->u.KeyValue.Flags = VALUE_COMP_NAME;
69 }
70
71 /* Check if this is a normal key */
72 if (DataSize > CM_KEY_VALUE_SMALL)
73 {
74 /* Build a data cell for it */
75 Status = CmpSetValueDataNew(Hive,
76 Data,
77 DataSize,
78 StorageType,
79 ValueCell,
80 &CellData->u.KeyValue.Data);
81 if (!NT_SUCCESS(Status))
82 {
83 /* We failed, free the cell */
84 HvFreeCell(Hive, ValueCell);
85 return Status;
86 }
87
88 /* Otherwise, set the data length, and make sure the data is dirty */
89 CellData->u.KeyValue.DataLength = DataSize;
90 ASSERT(HvIsCellDirty(Hive, CellData->u.KeyValue.Data));
91 }
92 else
93 {
94 /* This is a small key, set the data directly inside */
95 CellData->u.KeyValue.DataLength = DataSize + CM_KEY_VALUE_SPECIAL_SIZE;
96 CellData->u.KeyValue.Data = SmallData;
97 }
98
99 /* Add this value cell to the child list */
100 Status = CmpAddValueToList(Hive,
101 ValueCell,
102 Index,
103 StorageType,
104 &Parent->ValueList);
105
106 /* If we failed, free the entire cell, including the data */
107 if (!NT_SUCCESS(Status)) CmpFreeValue(Hive, ValueCell);
108
109 /* Return Status */
110 return Status;
111 }
112
113 NTSTATUS
114 NTAPI
115 CmpSetValueKeyExisting(IN PHHIVE Hive,
116 IN HCELL_INDEX OldChild,
117 IN PCM_KEY_VALUE Value,
118 IN ULONG Type,
119 IN PVOID Data,
120 IN ULONG DataSize,
121 IN ULONG StorageType,
122 IN ULONG TempData)
123 {
124 HCELL_INDEX DataCell, NewCell;
125 PCELL_DATA CellData;
126 ULONG Length;
127 BOOLEAN WasSmall, IsSmall;
128
129 /* Mark the old child cell dirty */
130 HvMarkCellDirty(Hive, OldChild, FALSE);
131
132 /* See if this is a small or normal key */
133 WasSmall = CmpIsKeyValueSmall(&Length, Value->DataLength);
134
135 /* See if our new data can fit in a small key */
136 IsSmall = (DataSize <= CM_KEY_VALUE_SMALL) ? TRUE: FALSE;
137
138 /* Big keys are unsupported */
139 ASSERT_VALUE_BIG(Hive, Length);
140 ASSERT_VALUE_BIG(Hive, DataSize);
141
142 /* Mark the old value dirty */
143 CmpMarkValueDataDirty(Hive, Value);
144
145 /* Check if we have a small key */
146 if (IsSmall)
147 {
148 /* Check if we had a normal key with some data in it */
149 if (!(WasSmall) && (Length > 0))
150 {
151 /* Free the previous data */
152 CmpFreeValueData(Hive, Value->Data, Length);
153 }
154
155 /* Write our data directly */
156 Value->DataLength = DataSize + CM_KEY_VALUE_SPECIAL_SIZE;
157 Value->Data = TempData;
158 Value->Type = Type;
159 return STATUS_SUCCESS;
160 }
161 else
162 {
163 /* We have a normal key. Was the old cell also normal and had data? */
164 if (!(WasSmall) && (Length > 0))
165 {
166 /* Get the current data cell and actual data inside it */
167 DataCell = Value->Data;
168 ASSERT(DataCell != HCELL_NIL);
169 CellData = HvGetCell(Hive, DataCell);
170 if (!CellData) return STATUS_INSUFFICIENT_RESOURCES;
171
172 /* Immediately release the cell */
173 HvReleaseCell(Hive, DataCell);
174
175 /* Make sure that the data cell actually has a size */
176 ASSERT(HvGetCellSize(Hive, CellData) > 0);
177
178 /* Check if the previous data cell could fit our new data */
179 if (DataSize <= (ULONG)(HvGetCellSize(Hive, CellData)))
180 {
181 /* Re-use it then */
182 NewCell = DataCell;
183 }
184 else
185 {
186 /* Otherwise, re-allocate the current data cell */
187 NewCell = HvReallocateCell(Hive, DataCell, DataSize);
188 if (NewCell == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES;
189 }
190 }
191 else
192 {
193 /* This was a small key, or a key with no data, allocate a cell */
194 NewCell = HvAllocateCell(Hive, DataSize, StorageType, HCELL_NIL);
195 if (NewCell == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES;
196 }
197
198 /* Now get the actual data for our data cell */
199 CellData = HvGetCell(Hive, NewCell);
200 if (!CellData) ASSERT(FALSE);
201
202 /* Release it immediately */
203 HvReleaseCell(Hive, NewCell);
204
205 /* Copy our data into the data cell's buffer, and set up the value */
206 RtlCopyMemory(CellData, Data, DataSize);
207 Value->Data = NewCell;
208 Value->DataLength = DataSize;
209 Value->Type = Type;
210
211 /* Return success */
212 ASSERT(HvIsCellDirty(Hive, NewCell));
213 return STATUS_SUCCESS;
214 }
215 }
216
217 NTSTATUS
218 NTAPI
219 CmSetValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
220 IN PUNICODE_STRING ValueName,
221 IN ULONG Type,
222 IN PVOID Data,
223 IN ULONG DataLength)
224 {
225 PHHIVE Hive;
226 PCM_KEY_NODE Parent;
227 PCM_KEY_VALUE Value = NULL;
228 HCELL_INDEX CurrentChild, Cell;
229 NTSTATUS Status;
230 BOOLEAN Found, Result;
231 ULONG Count, ChildIndex, SmallData, Storage;
232
233 /* Acquire hive lock exclusively */
234 KeEnterCriticalRegion();
235 ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE);
236
237 /* Get pointer to key cell */
238 Hive = Kcb->KeyHive;
239 Cell = Kcb->KeyCell;
240
241 /* Prepare to scan the key node */
242 Parent = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
243 Count = Parent->ValueList.Count;
244 Found = FALSE;
245 if (Count > 0)
246 {
247 /* Try to find the existing name */
248 Result = CmpFindNameInList(Hive,
249 &Parent->ValueList,
250 ValueName,
251 &ChildIndex,
252 &CurrentChild);
253 if (!Result)
254 {
255 /* Fail */
256 Status = STATUS_INSUFFICIENT_RESOURCES;
257 goto Quickie;
258 }
259
260 /* Check if we found something */
261 if (CurrentChild != HCELL_NIL)
262 {
263 /* Get its value */
264 Value = (PCM_KEY_VALUE)HvGetCell(Hive, CurrentChild);
265 if (!Value)
266 {
267 /* Fail */
268 Status = STATUS_INSUFFICIENT_RESOURCES;
269 goto Quickie;
270 }
271
272 /* Remember that we found it */
273 Found = TRUE;
274 }
275 }
276 else
277 {
278 /* No child list, we'll need to add it */
279 ChildIndex = 0;
280 }
281
282 /* Mark the cell dirty */
283 HvMarkCellDirty(Hive, Cell, FALSE);
284
285 /* Get the storage type */
286 Storage = HvGetCellType(Cell);
287
288 /* Check if this is small data */
289 SmallData = 0;
290 if ((DataLength <= CM_KEY_VALUE_SMALL) && (DataLength > 0))
291 {
292 /* Copy it */
293 RtlCopyMemory(&SmallData, Data, DataLength);
294 }
295
296 /* Check if we didn't find a matching key */
297 if (!Found)
298 {
299 /* Call the internal routine */
300 Status = CmpSetValueKeyNew(Hive,
301 Parent,
302 ValueName,
303 ChildIndex,
304 Type,
305 Data,
306 DataLength,
307 Storage,
308 SmallData);
309 }
310 else
311 {
312 /* Call the internal routine */
313 Status = CmpSetValueKeyExisting(Hive,
314 CurrentChild,
315 Value,
316 Type,
317 Data,
318 DataLength,
319 Storage,
320 SmallData);
321 }
322
323 /* Mark link key */
324 if ((Type == REG_LINK) &&
325 (_wcsicmp(ValueName->Buffer, L"SymbolicLinkValue") == 0))
326 {
327 Parent->Flags |= KEY_SYM_LINK;
328 }
329
330 /* Check for success */
331 Quickie:
332 if (NT_SUCCESS(Status))
333 {
334 ASSERT(Parent->MaxValueNameLen == Kcb->KcbMaxValueNameLen);
335 if (Parent->MaxValueNameLen < ValueName->Length)
336 {
337 Parent->MaxValueNameLen = ValueName->Length;
338 Kcb->KcbMaxValueNameLen = ValueName->Length;
339 }
340
341 ASSERT(Parent->MaxValueDataLen == Kcb->KcbMaxValueDataLen);
342 if (Parent->MaxValueDataLen < DataLength)
343 {
344 Parent->MaxValueDataLen = DataLength;
345 Kcb->KcbMaxValueDataLen = Parent->MaxValueDataLen;
346 }
347
348 /* Save the write time */
349 KeQuerySystemTime(&Parent->LastWriteTime);
350 KeQuerySystemTime(&Kcb->KcbLastWriteTime);
351 }
352
353 /* Release the lock */
354 ExReleaseResourceLite(&CmpRegistryLock);
355 KeLeaveCriticalRegion();
356 return Status;
357 }
358
359 NTSTATUS
360 NTAPI
361 CmDeleteValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
362 IN UNICODE_STRING ValueName)
363 {
364 NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND;
365 PHHIVE Hive;
366 PCM_KEY_NODE Parent;
367 HCELL_INDEX ChildCell, Cell;
368 PCHILD_LIST ChildList;
369 PCM_KEY_VALUE Value = NULL;
370 ULONG ChildIndex;
371 BOOLEAN Result;
372
373 /* Acquire hive lock */
374 KeEnterCriticalRegion();
375 ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE);
376
377 /* Get the hive and the cell index */
378 Hive = Kcb->KeyHive;
379 Cell = Kcb->KeyCell;
380
381 /* Get the parent key node */
382 Parent = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
383 if (!Parent)
384 {
385 /* Fail */
386 Status = STATUS_INSUFFICIENT_RESOURCES;
387 goto Quickie;
388 }
389
390 /* Get the value list and check if it has any entries */
391 ChildList = &Parent->ValueList;
392 if (ChildList->Count)
393 {
394 /* Try to find this value */
395 Result = CmpFindNameInList(Hive,
396 ChildList,
397 &ValueName,
398 &ChildIndex,
399 &ChildCell);
400 if (!Result)
401 {
402 /* Fail */
403 Status = STATUS_INSUFFICIENT_RESOURCES;
404 goto Quickie;
405 }
406
407 /* Value not found, return error */
408 if (ChildCell == HCELL_NIL) goto Quickie;
409
410 /* We found the value, mark all relevant cells dirty */
411 HvMarkCellDirty(Hive, Cell, FALSE);
412 HvMarkCellDirty(Hive, Parent->ValueList.List, FALSE);
413 HvMarkCellDirty(Hive, ChildCell, FALSE);
414
415 /* Get the key value */
416 Value = (PCM_KEY_VALUE)HvGetCell(Hive,ChildCell);
417 if (!Value) ASSERT(FALSE);
418
419 /* Mark it and all related data as dirty */
420 CmpMarkValueDataDirty(Hive, Value);
421
422 /* Ssanity checks */
423 ASSERT(HvIsCellDirty(Hive, Parent->ValueList.List));
424 ASSERT(HvIsCellDirty(Hive, ChildCell));
425
426 /* Remove the value from the child list */
427 Status = CmpRemoveValueFromList(Hive, ChildIndex, ChildList);
428 if(!NT_SUCCESS(Status)) goto Quickie;
429
430 /* Remove the value and its data itself */
431 if (!CmpFreeValue(Hive, ChildCell))
432 {
433 /* Failed to free the value, fail */
434 Status = STATUS_INSUFFICIENT_RESOURCES;
435 goto Quickie;
436 }
437
438 /* Set the last write time */
439 KeQuerySystemTime(&Parent->LastWriteTime);
440 KeQuerySystemTime(&Kcb->KcbLastWriteTime);
441
442 /* Sanity check */
443 ASSERT(Parent->MaxValueNameLen == Kcb->KcbMaxValueNameLen);
444 ASSERT(Parent->MaxValueDataLen == Kcb->KcbMaxValueDataLen);
445 ASSERT(HvIsCellDirty(Hive, Cell));
446
447 /* Check if the value list is empty now */
448 if (!Parent->ValueList.Count)
449 {
450 /* Then clear key node data */
451 Parent->MaxValueNameLen = 0;
452 Parent->MaxValueDataLen = 0;
453 Kcb->KcbMaxValueNameLen = 0;
454 Kcb->KcbMaxValueDataLen = 0;
455 }
456
457 /* Change default Status to success */
458 Status = STATUS_SUCCESS;
459 }
460
461 Quickie:
462 /* Release the parent cell, if any */
463 if (Parent) HvReleaseCell(Hive, Cell);
464
465 /* Check if we had a value */
466 if (Value)
467 {
468 /* Release the child cell */
469 ASSERT(ChildCell != HCELL_NIL);
470 HvReleaseCell(Hive, ChildCell);
471 }
472
473 /* Release hive lock */
474 ExReleaseResourceLite(&CmpRegistryLock);
475 KeLeaveCriticalRegion();
476 return Status;
477 }
478
479 NTSTATUS
480 NTAPI
481 CmQueryValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
482 IN UNICODE_STRING ValueName,
483 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
484 IN PVOID KeyValueInformation,
485 IN ULONG Length,
486 IN PULONG ResultLength)
487 {
488 NTSTATUS Status;
489 PCM_KEY_VALUE ValueData;
490 ULONG Index;
491 BOOLEAN ValueCached = FALSE;
492 PCM_CACHED_VALUE *CachedValue;
493 HCELL_INDEX CellToRelease;
494 VALUE_SEARCH_RETURN_TYPE Result;
495 PHHIVE Hive;
496 PAGED_CODE();
497
498 /* Acquire hive lock */
499 KeEnterCriticalRegion();
500 ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE);
501
502 /* Get the hive */
503 Hive = Kcb->KeyHive;
504
505 /* Find the key value */
506 Result = CmpFindValueByNameFromCache(Kcb,
507 &ValueName,
508 &CachedValue,
509 &Index,
510 &ValueData,
511 &ValueCached,
512 &CellToRelease);
513 if (Result == SearchSuccess)
514 {
515 /* Sanity check */
516 ASSERT(ValueData != NULL);
517
518 /* Query the information requested */
519 Result = CmpQueryKeyValueData(Kcb,
520 CachedValue,
521 ValueData,
522 ValueCached,
523 KeyValueInformationClass,
524 KeyValueInformation,
525 Length,
526 ResultLength,
527 &Status);
528 }
529 else
530 {
531 /* Failed to find the value */
532 Status = STATUS_OBJECT_NAME_NOT_FOUND;
533 }
534
535 /* If we have a cell to release, do so */
536 if (CellToRelease != HCELL_NIL) HvReleaseCell(Hive, CellToRelease);
537
538 /* Release hive lock */
539 ExReleaseResourceLite(&CmpRegistryLock);
540 KeLeaveCriticalRegion();
541 return Status;
542 }
543
544 NTSTATUS
545 NTAPI
546 CmEnumerateValueKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
547 IN ULONG Index,
548 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
549 IN PVOID KeyValueInformation,
550 IN ULONG Length,
551 IN PULONG ResultLength)
552 {
553 NTSTATUS Status;
554 PHHIVE Hive;
555 PCM_KEY_NODE Parent;
556 HCELL_INDEX CellToRelease = HCELL_NIL, CellToRelease2 = HCELL_NIL;
557 VALUE_SEARCH_RETURN_TYPE Result;
558 BOOLEAN IndexIsCached, ValueIsCached = FALSE;
559 PCELL_DATA CellData;
560 PCM_CACHED_VALUE *CachedValue;
561 PCM_KEY_VALUE ValueData;
562 PAGED_CODE();
563
564 /* Acquire hive lock */
565 KeEnterCriticalRegion();
566 ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE);
567
568 /* Get the hive and parent */
569 Hive = Kcb->KeyHive;
570 Parent = (PCM_KEY_NODE)HvGetCell(Hive, Kcb->KeyCell);
571 if (!Parent)
572 {
573 /* Fail */
574 Status = STATUS_INSUFFICIENT_RESOURCES;
575 goto Quickie;
576 }
577
578 /* Make sure the index is valid */
579 //if (Index >= Kcb->ValueCache.Count)
580 if (Index >= Parent->ValueList.Count)
581 {
582 /* Release the cell and fail */
583 HvReleaseCell(Hive, Kcb->KeyCell);
584 Status = STATUS_NO_MORE_ENTRIES;
585 goto Quickie;
586 }
587
588 /* Find the value list */
589 Result = CmpGetValueListFromCache(Kcb,
590 &CellData,
591 &IndexIsCached,
592 &CellToRelease);
593 if (Result != SearchSuccess)
594 {
595 /* Sanity check */
596 ASSERT(CellData == NULL);
597
598 /* Release the cell and fail */
599 Status = STATUS_INSUFFICIENT_RESOURCES;
600 goto Quickie;
601 }
602
603 /* Now get the key value */
604 Result = CmpGetValueKeyFromCache(Kcb,
605 CellData,
606 Index,
607 &CachedValue,
608 &ValueData,
609 IndexIsCached,
610 &ValueIsCached,
611 &CellToRelease2);
612 if (Result != SearchSuccess)
613 {
614 /* Sanity check */
615 ASSERT(CellToRelease2 == HCELL_NIL);
616
617 /* Release the cells and fail */
618 Status = STATUS_INSUFFICIENT_RESOURCES;
619 goto Quickie;
620 }
621
622 /* Query the information requested */
623 Result = CmpQueryKeyValueData(Kcb,
624 CachedValue,
625 ValueData,
626 ValueIsCached,
627 KeyValueInformationClass,
628 KeyValueInformation,
629 Length,
630 ResultLength,
631 &Status);
632
633 Quickie:
634 /* If we have a cell to release, do so */
635 if (CellToRelease != HCELL_NIL) HvReleaseCell(Hive, CellToRelease);
636
637 /* Release the parent cell */
638 HvReleaseCell(Hive, Kcb->KeyCell);
639
640 /* If we have a cell to release, do so */
641 if (CellToRelease2 != HCELL_NIL) HvReleaseCell(Hive, CellToRelease2);
642
643 /* Release hive lock */
644 ExReleaseResourceLite(&CmpRegistryLock);
645 KeLeaveCriticalRegion();
646 return Status;
647 }
648
649 NTSTATUS
650 NTAPI
651 CmpQueryKeyData(IN PHHIVE Hive,
652 IN PCM_KEY_NODE Node,
653 IN KEY_INFORMATION_CLASS KeyInformationClass,
654 IN OUT PVOID KeyInformation,
655 IN ULONG Length,
656 IN OUT PULONG ResultLength)
657 {
658 NTSTATUS Status;
659 ULONG Size, SizeLeft, MinimumSize;
660 PKEY_INFORMATION Info = (PKEY_INFORMATION)KeyInformation;
661 USHORT NameLength;
662
663 /* Check if the value is compressed */
664 if (Node->Flags & KEY_COMP_NAME)
665 {
666 /* Get the compressed name size */
667 NameLength = CmpCompressedNameSize(Node->Name, Node->NameLength);
668 }
669 else
670 {
671 /* Get the real size */
672 NameLength = Node->NameLength;
673 }
674
675 /* Check what kind of information is being requested */
676 switch (KeyInformationClass)
677 {
678 /* Basic information */
679 case KeyBasicInformation:
680
681 /* This is the size we need */
682 Size = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name) + NameLength;
683
684 /* And this is the minimum we can work with */
685 MinimumSize = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name);
686
687 /* Let the caller know and assume success */
688 *ResultLength = Size;
689 Status = STATUS_SUCCESS;
690
691 /* Check if the bufer we got is too small */
692 if (Length < MinimumSize)
693 {
694 /* Let the caller know and fail */
695 Status = STATUS_BUFFER_TOO_SMALL;
696 break;
697 }
698
699 /* Copy the basic information */
700 Info->KeyBasicInformation.LastWriteTime = Node->LastWriteTime;
701 Info->KeyBasicInformation.TitleIndex = 0;
702 Info->KeyBasicInformation.NameLength = NameLength;
703
704 /* Only the name is left */
705 SizeLeft = Length - MinimumSize;
706 Size = NameLength;
707
708 /* Check if we don't have enough space for the name */
709 if (SizeLeft < Size)
710 {
711 /* Truncate the name we'll return, and tell the caller */
712 Size = SizeLeft;
713 Status = STATUS_BUFFER_OVERFLOW;
714 }
715
716 /* Check if this is a compressed key */
717 if (Node->Flags & KEY_COMP_NAME)
718 {
719 /* Copy the compressed name */
720 CmpCopyCompressedName(Info->KeyBasicInformation.Name,
721 SizeLeft,
722 Node->Name,
723 Node->NameLength);
724 }
725 else
726 {
727 /* Otherwise, copy the raw name */
728 RtlCopyMemory(Info->KeyBasicInformation.Name,
729 Node->Name,
730 Size);
731 }
732 break;
733
734 /* Node information */
735 case KeyNodeInformation:
736
737 /* Calculate the size we need */
738 Size = FIELD_OFFSET(KEY_NODE_INFORMATION, Name) +
739 NameLength +
740 Node->ClassLength;
741
742 /* And the minimum size we can support */
743 MinimumSize = FIELD_OFFSET(KEY_NODE_INFORMATION, Name);
744
745 /* Return the size to the caller and assume succes */
746 *ResultLength = Size;
747 Status = STATUS_SUCCESS;
748
749 /* Check if the caller's buffer is too small */
750 if (Length < MinimumSize)
751 {
752 /* Let them know, and fail */
753 Status = STATUS_BUFFER_TOO_SMALL;
754 break;
755 }
756
757 /* Copy the basic information */
758 Info->KeyNodeInformation.LastWriteTime = Node->LastWriteTime;
759 Info->KeyNodeInformation.TitleIndex = 0;
760 Info->KeyNodeInformation.ClassLength = Node->ClassLength;
761 Info->KeyNodeInformation.NameLength = NameLength;
762
763 /* Now the name is left */
764 SizeLeft = Length - MinimumSize;
765 Size = NameLength;
766
767 /* Check if the name can fit entirely */
768 if (SizeLeft < Size)
769 {
770 /* It can't, we'll have to truncate. Tell the caller */
771 Size = SizeLeft;
772 Status = STATUS_BUFFER_OVERFLOW;
773 }
774
775 /* Check if the key node name is compressed */
776 if (Node->Flags & KEY_COMP_NAME)
777 {
778 /* Copy the compressed name */
779 CmpCopyCompressedName(Info->KeyNodeInformation.Name,
780 SizeLeft,
781 Node->Name,
782 Node->NameLength);
783 }
784 else
785 {
786 /* It isn't, so copy the raw name */
787 RtlCopyMemory(Info->KeyNodeInformation.Name,
788 Node->Name,
789 Size);
790 }
791
792 /* Check if the node has a class */
793 if (Node->ClassLength > 0)
794 {
795 /* It does. We don't support these yet */
796 ASSERTMSG("Classes not supported\n", FALSE);
797 }
798 else
799 {
800 /* It doesn't, so set offset to -1, not 0! */
801 Info->KeyNodeInformation.ClassOffset = 0xFFFFFFFF;
802 }
803 break;
804
805 /* Full information requsted */
806 case KeyFullInformation:
807
808 /* This is the size we need */
809 Size = FIELD_OFFSET(KEY_FULL_INFORMATION, Class) +
810 Node->ClassLength;
811
812 /* This is what we can work with */
813 MinimumSize = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
814
815 /* Return it to caller and assume success */
816 *ResultLength = Size;
817 Status = STATUS_SUCCESS;
818
819 /* Check if the caller's buffer is to small */
820 if (Length < MinimumSize)
821 {
822 /* Let them know and fail */
823 Status = STATUS_BUFFER_TOO_SMALL;
824 break;
825 }
826
827 /* Now copy all the basic information */
828 Info->KeyFullInformation.LastWriteTime = Node->LastWriteTime;
829 Info->KeyFullInformation.TitleIndex = 0;
830 Info->KeyFullInformation.ClassLength = Node->ClassLength;
831 Info->KeyFullInformation.SubKeys = Node->SubKeyCounts[Stable] +
832 Node->SubKeyCounts[Volatile];
833 Info->KeyFullInformation.Values = Node->ValueList.Count;
834 Info->KeyFullInformation.MaxNameLen = Node->MaxNameLen;
835 Info->KeyFullInformation.MaxClassLen = Node->MaxClassLen;
836 Info->KeyFullInformation.MaxValueNameLen = Node->MaxValueNameLen;
837 Info->KeyFullInformation.MaxValueDataLen = Node->MaxValueDataLen;
838
839 /* Check if we have a class */
840 if (Node->ClassLength > 0)
841 {
842 /* We do, but we currently don't support this */
843 ASSERTMSG("Classes not supported\n", FALSE);
844 }
845 else
846 {
847 /* We don't have a class, so set offset to -1, not 0! */
848 Info->KeyNodeInformation.ClassOffset = 0xFFFFFFFF;
849 }
850 break;
851
852 /* Any other class that got sent here is invalid! */
853 default:
854
855 /* Set failure code */
856 Status = STATUS_INVALID_PARAMETER;
857 break;
858 }
859
860 /* Return status */
861 return Status;
862 }
863
864 NTSTATUS
865 NTAPI
866 CmQueryKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
867 IN KEY_INFORMATION_CLASS KeyInformationClass,
868 IN PVOID KeyInformation,
869 IN ULONG Length,
870 IN PULONG ResultLength)
871 {
872 NTSTATUS Status;
873 PHHIVE Hive;
874 PCM_KEY_NODE Parent;
875
876 /* Acquire hive lock */
877 KeEnterCriticalRegion();
878 ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE);
879
880 /* Get the hive and parent */
881 Hive = Kcb->KeyHive;
882 Parent = (PCM_KEY_NODE)HvGetCell(Hive, Kcb->KeyCell);
883 if (!Parent)
884 {
885 /* Fail */
886 Status = STATUS_INSUFFICIENT_RESOURCES;
887 goto Quickie;
888 }
889
890 /* Check what class we got */
891 switch (KeyInformationClass)
892 {
893 /* Typical information */
894 case KeyFullInformation:
895 case KeyBasicInformation:
896 case KeyNodeInformation:
897
898 /* Call the internal API */
899 Status = CmpQueryKeyData(Hive,
900 Parent,
901 KeyInformationClass,
902 KeyInformation,
903 Length,
904 ResultLength);
905 break;
906
907 /* Unsupported classes for now */
908 case KeyNameInformation:
909 case KeyCachedInformation:
910 case KeyFlagsInformation:
911
912 /* Print message and fail */
913 DPRINT1("Unsupported class: %d!\n", KeyInformationClass);
914 Status = STATUS_NOT_IMPLEMENTED;
915 break;
916
917 /* Illegal classes */
918 default:
919
920 /* Print message and fail */
921 DPRINT1("Unsupported class: %d!\n", KeyInformationClass);
922 Status = STATUS_INVALID_INFO_CLASS;
923 break;
924 }
925
926 Quickie:
927 /* Release hive lock */
928 ExReleaseResourceLite(&CmpRegistryLock);
929 KeLeaveCriticalRegion();
930 return Status;
931 }
932
933 NTSTATUS
934 NTAPI
935 CmEnumerateKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
936 IN ULONG Index,
937 IN KEY_INFORMATION_CLASS KeyInformationClass,
938 IN PVOID KeyInformation,
939 IN ULONG Length,
940 IN PULONG ResultLength)
941 {
942 NTSTATUS Status;
943 PHHIVE Hive;
944 PCM_KEY_NODE Parent, Child;
945 HCELL_INDEX ChildCell;
946
947 /* Acquire hive lock */
948 KeEnterCriticalRegion();
949 ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE);
950
951 /* Get the hive and parent */
952 Hive = Kcb->KeyHive;
953 Parent = (PCM_KEY_NODE)HvGetCell(Hive, Kcb->KeyCell);
954 if (!Parent)
955 {
956 /* Fail */
957 Status = STATUS_INSUFFICIENT_RESOURCES;
958 goto Quickie;
959 }
960
961 /* Get the child cell */
962 ChildCell = CmpFindSubKeyByNumber(Hive, Parent, Index);
963
964 /* Release the parent cell */
965 HvReleaseCell(Hive, Kcb->KeyCell);
966
967 /* Check if we found the child */
968 if (ChildCell == HCELL_NIL)
969 {
970 /* We didn't, fail */
971 Status = STATUS_NO_MORE_ENTRIES;
972 goto Quickie;
973 }
974
975 /* Now get the actual child node */
976 Child = (PCM_KEY_NODE)HvGetCell(Hive, ChildCell);
977 if (!Child)
978 {
979 /* Fail */
980 Status = STATUS_INSUFFICIENT_RESOURCES;
981 goto Quickie;
982 }
983
984 /* Query the data requested */
985 Status = CmpQueryKeyData(Hive,
986 Child,
987 KeyInformationClass,
988 KeyInformation,
989 Length,
990 ResultLength);
991
992 Quickie:
993 /* Release hive lock */
994 ExReleaseResourceLite(&CmpRegistryLock);
995 KeLeaveCriticalRegion();
996 return Status;
997 }
998
999 NTSTATUS
1000 NTAPI
1001 CmDeleteKey(IN PCM_KEY_CONTROL_BLOCK Kcb)
1002 {
1003 NTSTATUS Status;
1004 PHHIVE Hive;
1005 PCM_KEY_NODE Node, Parent;
1006 HCELL_INDEX Cell, ParentCell;
1007
1008 /* Acquire hive lock */
1009 KeEnterCriticalRegion();
1010 ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE);
1011
1012 /* Get the hive and node */
1013 Hive = Kcb->KeyHive;
1014 Cell = Kcb->KeyCell;
1015
1016 /* Get the key node */
1017 Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
1018 if (!Node)
1019 {
1020 /* Fail */
1021 Status = STATUS_INSUFFICIENT_RESOURCES;
1022 goto Quickie;
1023 }
1024
1025 /* Check if we have no parent */
1026 if (!Node->Parent)
1027 {
1028 /* This is an attempt to delete \Registry itself! */
1029 Status = STATUS_CANNOT_DELETE;
1030 goto Quickie;
1031 }
1032
1033 /* Check if we don't have any children */
1034 if (!(Node->SubKeyCounts[Stable] + Node->SubKeyCounts[Volatile]))
1035 {
1036 /* Get the parent and free the cell */
1037 ParentCell = Node->Parent;
1038 Status = CmpFreeKeyByCell(Hive, Cell, TRUE);
1039 if (NT_SUCCESS(Status))
1040 {
1041 /* Get the parent node */
1042 Parent = (PCM_KEY_NODE)HvGetCell(Hive, ParentCell);
1043 if (Parent)
1044 {
1045 /* Make sure we're dirty */
1046 ASSERT(HvIsCellDirty(Hive, ParentCell));
1047
1048 /* Update the write time */
1049 KeQuerySystemTime(&Parent->LastWriteTime);
1050
1051 /* Release the cell */
1052 HvReleaseCell(Hive, ParentCell);
1053 }
1054
1055 /* Clear the cell */
1056 Kcb->KeyCell = HCELL_NIL;
1057 }
1058 }
1059 else
1060 {
1061 /* Fail */
1062 Status = STATUS_CANNOT_DELETE;
1063 }
1064
1065 /* Make sure we're file-backed */
1066 if (!(IsNoFileHive((PCMHIVE)Kcb->KeyHive)) ||
1067 !(IsNoFileHive((PCMHIVE)Kcb->ParentKcb->KeyHive)))
1068 {
1069 /* Sync up the hives */
1070 CmiSyncHives();
1071 }
1072
1073 Quickie:
1074 /* Release the cell */
1075 HvReleaseCell(Hive, Cell);
1076
1077 /* Release hive lock */
1078 ExReleaseResourceLite(&CmpRegistryLock);
1079 KeLeaveCriticalRegion();
1080 return Status;
1081 }