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