Implemented packing of value names
[reactos.git] / reactos / ntoskrnl / cm / ntfunc.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/cm/ntfunc.c
5 * PURPOSE: Ntxxx function for registry access
6 * UPDATE HISTORY:
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #ifdef WIN32_REGDBG
12 #include "cm_win32.h"
13 #else
14 #include <ddk/ntddk.h>
15 #include <roscfg.h>
16 #include <internal/ob.h>
17 #include <limits.h>
18 #include <string.h>
19 #include <internal/pool.h>
20 #include <internal/registry.h>
21
22 #define NDEBUG
23 #include <internal/debug.h>
24
25 #include "cm.h"
26 #endif
27
28
29 /* GLOBALS ******************************************************************/
30
31 extern POBJECT_TYPE CmiKeyType;
32 extern PREGISTRY_HIVE CmiVolatileHive;
33
34 static BOOLEAN CmiRegistryInitialized = FALSE;
35
36
37 /* FUNCTIONS ****************************************************************/
38
39 NTSTATUS STDCALL
40 NtCreateKey(OUT PHANDLE KeyHandle,
41 IN ACCESS_MASK DesiredAccess,
42 IN POBJECT_ATTRIBUTES ObjectAttributes,
43 IN ULONG TitleIndex,
44 IN PUNICODE_STRING Class,
45 IN ULONG CreateOptions,
46 OUT PULONG Disposition)
47 {
48 UNICODE_STRING RemainingPath;
49 PKEY_OBJECT KeyObject;
50 NTSTATUS Status;
51 PVOID Object;
52 PWSTR End;
53
54 DPRINT("NtCreateKey (Name %wZ KeyHandle %x Root %x)\n",
55 ObjectAttributes->ObjectName,
56 KeyHandle,
57 ObjectAttributes->RootDirectory);
58
59 /* FIXME: check for standard handle prefix and adjust objectAttributes accordingly */
60
61 Status = ObFindObject(ObjectAttributes,
62 &Object,
63 &RemainingPath,
64 CmiKeyType);
65 if (!NT_SUCCESS(Status))
66 {
67 return(Status);
68 }
69
70 DPRINT("RemainingPath %wZ\n", &RemainingPath);
71
72 if ((RemainingPath.Buffer == NULL) || (RemainingPath.Buffer[0] == 0))
73 {
74 /* Fail if the key has been deleted */
75 if (((PKEY_OBJECT) Object)->Flags & KO_MARKED_FOR_DELETE)
76 {
77 ObDereferenceObject(Object);
78 return(STATUS_UNSUCCESSFUL);
79 }
80
81 if (Disposition)
82 *Disposition = REG_OPENED_EXISTING_KEY;
83
84 Status = ObCreateHandle(PsGetCurrentProcess(),
85 Object,
86 DesiredAccess,
87 FALSE,
88 KeyHandle);
89
90 DPRINT("Status %x\n", Status);
91 ObDereferenceObject(Object);
92 return Status;
93 }
94
95 /* If RemainingPath contains \ we must return error
96 because NtCreateKey don't create trees */
97 if (RemainingPath.Buffer[0] == '\\')
98 End = wcschr(RemainingPath.Buffer + 1, '\\');
99 else
100 End = wcschr(RemainingPath.Buffer, '\\');
101
102 if (End != NULL)
103 {
104 ObDereferenceObject(Object);
105 return STATUS_UNSUCCESSFUL;
106 }
107
108 DPRINT("RemainingPath %S ParentObject %x\n", RemainingPath.Buffer, Object);
109
110 Status = ObCreateObject(KeyHandle,
111 DesiredAccess,
112 NULL,
113 CmiKeyType,
114 (PVOID*)&KeyObject);
115
116 if (!NT_SUCCESS(Status))
117 {
118 return(Status);
119 }
120
121 KeyObject->ParentKey = Object;
122
123 if (CreateOptions & REG_OPTION_VOLATILE)
124 KeyObject->RegistryHive = CmiVolatileHive;
125 else
126 KeyObject->RegistryHive = KeyObject->ParentKey->RegistryHive;
127
128 KeyObject->Flags = 0;
129 KeyObject->NumberOfSubKeys = 0;
130 KeyObject->SizeOfSubKeys = 0;
131 KeyObject->SubKeys = NULL;
132
133 /* Acquire hive lock */
134 ExAcquireResourceExclusiveLite(&KeyObject->RegistryHive->HiveResource, TRUE);
135
136 /* add key to subkeys of parent if needed */
137 Status = CmiAddSubKey(KeyObject->RegistryHive,
138 KeyObject->ParentKey,
139 KeyObject,
140 RemainingPath.Buffer,
141 RemainingPath.Length,
142 TitleIndex,
143 Class,
144 CreateOptions);
145
146 if (!NT_SUCCESS(Status))
147 {
148 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
149 ObDereferenceObject(KeyObject);
150 ObDereferenceObject(Object);
151 return STATUS_UNSUCCESSFUL;
152 }
153
154 KeyObject->Name = KeyObject->KeyCell->Name;
155 KeyObject->NameSize = KeyObject->KeyCell->NameSize;
156
157 if (KeyObject->RegistryHive == KeyObject->ParentKey->RegistryHive)
158 {
159 KeyObject->KeyCell->ParentKeyOffset = KeyObject->ParentKey->BlockOffset;
160 KeyObject->KeyCell->SecurityKeyOffset = KeyObject->ParentKey->KeyCell->SecurityKeyOffset;
161 }
162 else
163 {
164 KeyObject->KeyCell->ParentKeyOffset = -1;
165 KeyObject->KeyCell->SecurityKeyOffset = -1;
166 /* This key must rest in memory unless it is deleted
167 or file is unloaded */
168 ObReferenceObjectByPointer(KeyObject,
169 STANDARD_RIGHTS_REQUIRED,
170 NULL,
171 UserMode);
172 }
173
174 CmiAddKeyToList(KeyObject->ParentKey, KeyObject);
175
176 /* Release hive lock */
177 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
178
179 ObDereferenceObject(KeyObject);
180 ObDereferenceObject(Object);
181
182 if (Disposition)
183 *Disposition = REG_CREATED_NEW_KEY;
184
185 VERIFY_KEY_OBJECT(KeyObject);
186
187 return Status;
188 }
189
190
191 NTSTATUS STDCALL
192 NtDeleteKey(IN HANDLE KeyHandle)
193 {
194 PKEY_OBJECT KeyObject;
195 NTSTATUS Status;
196
197 DPRINT("KeyHandle %x\n", KeyHandle);
198
199 /* Verify that the handle is valid and is a registry key */
200 Status = ObReferenceObjectByHandle(KeyHandle,
201 KEY_WRITE,
202 CmiKeyType,
203 UserMode,
204 (PVOID *) &KeyObject,
205 NULL);
206
207 if (!NT_SUCCESS(Status))
208 {
209 return Status;
210 }
211
212 /* Acquire hive lock */
213 ExAcquireResourceExclusiveLite(&KeyObject->RegistryHive->HiveResource, TRUE);
214
215 VERIFY_KEY_OBJECT(KeyObject);
216
217 /* Set the marked for delete bit in the key object */
218 KeyObject->Flags |= KO_MARKED_FOR_DELETE;
219
220 /* Dereference the object */
221 ObDereferenceObject(KeyObject);
222 if(KeyObject->RegistryHive != KeyObject->ParentKey->RegistryHive)
223 ObDereferenceObject(KeyObject);
224 /* Close the handle */
225 ObDeleteHandle(PsGetCurrentProcess(), KeyHandle);
226 /* FIXME: I think that ObDeleteHandle should dereference the object */
227 ObDereferenceObject(KeyObject);
228
229 /* Release hive lock */
230 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
231
232 return STATUS_SUCCESS;
233 }
234
235
236 NTSTATUS STDCALL
237 NtEnumerateKey(
238 IN HANDLE KeyHandle,
239 IN ULONG Index,
240 IN KEY_INFORMATION_CLASS KeyInformationClass,
241 OUT PVOID KeyInformation,
242 IN ULONG Length,
243 OUT PULONG ResultLength
244 )
245 {
246 NTSTATUS Status;
247 PKEY_OBJECT KeyObject;
248 PREGISTRY_HIVE RegistryHive;
249 PKEY_CELL KeyCell, SubKeyCell;
250 PHASH_TABLE_CELL HashTableBlock;
251 PKEY_BASIC_INFORMATION BasicInformation;
252 PKEY_NODE_INFORMATION NodeInformation;
253 PKEY_FULL_INFORMATION FullInformation;
254 PDATA_CELL pClassData;
255
256 DPRINT("KH %x I %d KIC %x KI %x L %d RL %x\n",
257 KeyHandle,
258 Index,
259 KeyInformationClass,
260 KeyInformation,
261 Length,
262 ResultLength);
263
264 /* Verify that the handle is valid and is a registry key */
265 Status = ObReferenceObjectByHandle(KeyHandle,
266 KEY_ENUMERATE_SUB_KEYS,
267 CmiKeyType,
268 UserMode,
269 (PVOID *) &KeyObject,
270 NULL);
271 if (!NT_SUCCESS(Status))
272 {
273 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status);
274 return(Status);
275 }
276
277 /* Acquire hive lock */
278 ExAcquireResourceSharedLite(&KeyObject->RegistryHive->HiveResource, TRUE);
279
280 VERIFY_KEY_OBJECT(KeyObject);
281
282 /* Get pointer to KeyCell */
283 KeyCell = KeyObject->KeyCell;
284 RegistryHive = KeyObject->RegistryHive;
285
286 /* Get pointer to SubKey */
287 if (Index >= KeyCell->NumberOfSubKeys)
288 {
289 if (RegistryHive == CmiVolatileHive)
290 {
291 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
292 ObDereferenceObject(KeyObject);
293 DPRINT("No more volatile entries\n");
294 return(STATUS_NO_MORE_ENTRIES);
295 }
296 else
297 {
298 ULONG i;
299 PKEY_OBJECT CurKey = NULL;
300
301 /* Search volatile keys */
302 for (i = 0; i < KeyObject->NumberOfSubKeys; i++)
303 {
304 CurKey = KeyObject->SubKeys[i];
305 if (CurKey->RegistryHive == CmiVolatileHive)
306 {
307 if (Index-- == KeyObject->NumberOfSubKeys)
308 break;
309 }
310 }
311 if (Index >= KeyCell->NumberOfSubKeys)
312 {
313 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
314 ObDereferenceObject(KeyObject);
315 DPRINT("No more non-volatile entries\n");
316 return(STATUS_NO_MORE_ENTRIES);
317 }
318 SubKeyCell = CurKey->KeyCell;
319 }
320 }
321 else
322 {
323 HashTableBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
324 SubKeyCell = CmiGetKeyFromHashByIndex(RegistryHive,
325 HashTableBlock,
326 Index);
327 }
328
329 if (SubKeyCell == NULL)
330 {
331 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
332 ObDereferenceObject(KeyObject);
333 DPRINT("No more entries\n");
334 return(STATUS_NO_MORE_ENTRIES);
335 }
336
337 Status = STATUS_SUCCESS;
338 switch (KeyInformationClass)
339 {
340 case KeyBasicInformation:
341 /* Check size of buffer */
342 *ResultLength = sizeof(KEY_BASIC_INFORMATION) +
343 (SubKeyCell->NameSize ) * sizeof(WCHAR);
344 if (Length < *ResultLength)
345 {
346 Status = STATUS_BUFFER_OVERFLOW;
347 }
348 else
349 {
350 /* Fill buffer with requested info */
351 BasicInformation = (PKEY_BASIC_INFORMATION) KeyInformation;
352 BasicInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.dwLowDateTime;
353 BasicInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.dwHighDateTime;
354 BasicInformation->TitleIndex = Index;
355 BasicInformation->NameLength = SubKeyCell->NameSize * sizeof(WCHAR);
356 mbstowcs(BasicInformation->Name,
357 SubKeyCell->Name,
358 SubKeyCell->NameSize * 2);
359 // BasicInformation->Name[SubKeyCell->NameSize] = 0;
360 }
361 break;
362
363 case KeyNodeInformation:
364 /* Check size of buffer */
365 *ResultLength = sizeof(KEY_NODE_INFORMATION) +
366 SubKeyCell->NameSize * sizeof(WCHAR) +
367 SubKeyCell->ClassSize;
368 if (Length < *ResultLength)
369 {
370 Status = STATUS_BUFFER_OVERFLOW;
371 }
372 else
373 {
374 /* Fill buffer with requested info */
375 NodeInformation = (PKEY_NODE_INFORMATION) KeyInformation;
376 NodeInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.dwLowDateTime;
377 NodeInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.dwHighDateTime;
378 NodeInformation->TitleIndex = Index;
379 NodeInformation->ClassOffset = sizeof(KEY_NODE_INFORMATION) +
380 SubKeyCell->NameSize * sizeof(WCHAR);
381 NodeInformation->ClassLength = SubKeyCell->ClassSize;
382 NodeInformation->NameLength = SubKeyCell->NameSize * sizeof(WCHAR);
383 mbstowcs(NodeInformation->Name,
384 SubKeyCell->Name,
385 SubKeyCell->NameSize * 2);
386 // NodeInformation->Name[SubKeyCell->NameSize] = 0;
387 if (SubKeyCell->ClassSize != 0)
388 {
389 pClassData=CmiGetBlock(KeyObject->RegistryHive,
390 SubKeyCell->ClassNameOffset,
391 NULL);
392 wcsncpy(NodeInformation->Name + SubKeyCell->NameSize ,
393 (PWCHAR) pClassData->Data,
394 SubKeyCell->ClassSize);
395 CmiReleaseBlock(RegistryHive, pClassData);
396 }
397 }
398 break;
399
400 case KeyFullInformation:
401 /* check size of buffer */
402 *ResultLength = sizeof(KEY_FULL_INFORMATION) +
403 SubKeyCell->ClassSize;
404 if (Length < *ResultLength)
405 {
406 Status = STATUS_BUFFER_OVERFLOW;
407 }
408 else
409 {
410 /* fill buffer with requested info */
411 FullInformation = (PKEY_FULL_INFORMATION) KeyInformation;
412 FullInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.dwLowDateTime;
413 FullInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.dwHighDateTime;
414 FullInformation->TitleIndex = Index;
415 FullInformation->ClassOffset = sizeof(KEY_FULL_INFORMATION) -
416 sizeof(WCHAR);
417 FullInformation->ClassLength = SubKeyCell->ClassSize;
418 FullInformation->SubKeys = SubKeyCell->NumberOfSubKeys;
419 FullInformation->MaxNameLen =
420 CmiGetMaxNameLength(RegistryHive, SubKeyCell);
421 FullInformation->MaxClassLen =
422 CmiGetMaxClassLength(RegistryHive, SubKeyCell);
423 FullInformation->Values = SubKeyCell->NumberOfValues;
424 FullInformation->MaxValueNameLen =
425 CmiGetMaxValueNameLength(RegistryHive, SubKeyCell);
426 FullInformation->MaxValueDataLen =
427 CmiGetMaxValueDataLength(RegistryHive, SubKeyCell);
428 if (SubKeyCell->ClassSize != 0)
429 {
430 pClassData = CmiGetBlock(KeyObject->RegistryHive,
431 SubKeyCell->ClassNameOffset,
432 NULL);
433 wcsncpy(FullInformation->Class,
434 (PWCHAR) pClassData->Data,
435 SubKeyCell->ClassSize);
436 CmiReleaseBlock(RegistryHive, pClassData);
437 }
438 }
439 break;
440 }
441 CmiReleaseBlock(RegistryHive, SubKeyCell);
442
443 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
444 ObDereferenceObject(KeyObject);
445
446 DPRINT("Returning status %x\n", Status);
447
448 return(Status);
449 }
450
451
452 NTSTATUS STDCALL
453 NtEnumerateValueKey(IN HANDLE KeyHandle,
454 IN ULONG Index,
455 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
456 OUT PVOID KeyValueInformation,
457 IN ULONG Length,
458 OUT PULONG ResultLength)
459 {
460 NTSTATUS Status;
461 PKEY_OBJECT KeyObject;
462 PREGISTRY_HIVE RegistryHive;
463 PKEY_CELL KeyCell;
464 PVALUE_CELL ValueCell;
465 PDATA_CELL DataCell;
466 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation;
467 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation;
468 PKEY_VALUE_FULL_INFORMATION ValueFullInformation;
469
470 DPRINT("KH %x I %d KVIC %x KVI %x L %d RL %x\n",
471 KeyHandle,
472 Index,
473 KeyValueInformationClass,
474 KeyValueInformation,
475 Length,
476 ResultLength);
477
478 /* Verify that the handle is valid and is a registry key */
479 Status = ObReferenceObjectByHandle(KeyHandle,
480 KEY_QUERY_VALUE,
481 CmiKeyType,
482 UserMode,
483 (PVOID *) &KeyObject,
484 NULL);
485
486 if (!NT_SUCCESS(Status))
487 {
488 return Status;
489 }
490
491 /* Acquire hive lock */
492 ExAcquireResourceSharedLite(&KeyObject->RegistryHive->HiveResource, TRUE);
493
494 VERIFY_KEY_OBJECT(KeyObject);
495
496 /* Get pointer to KeyCell */
497 KeyCell = KeyObject->KeyCell;
498 RegistryHive = KeyObject->RegistryHive;
499
500 /* Get Value block of interest */
501 Status = CmiGetValueFromKeyByIndex(RegistryHive,
502 KeyCell,
503 Index,
504 &ValueCell);
505
506 if (!NT_SUCCESS(Status))
507 {
508 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
509 ObDereferenceObject(KeyObject);
510 return Status;
511 }
512
513 if (ValueCell != NULL)
514 {
515 switch (KeyValueInformationClass)
516 {
517 case KeyValueBasicInformation:
518 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
519 {
520 *ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION) +
521 (ValueCell->NameSize + 1) * sizeof(WCHAR);
522 }
523 else
524 {
525 *ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION) +
526 ValueCell->NameSize + sizeof(WCHAR);
527 }
528 if (Length < *ResultLength)
529 {
530 Status = STATUS_BUFFER_OVERFLOW;
531 }
532 else
533 {
534 ValueBasicInformation = (PKEY_VALUE_BASIC_INFORMATION)
535 KeyValueInformation;
536 ValueBasicInformation->TitleIndex = 0;
537 ValueBasicInformation->Type = ValueCell->DataType;
538 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
539 {
540 ValueBasicInformation->NameLength =
541 (ValueCell->NameSize + 1) * sizeof(WCHAR);
542 CmiCopyPackedName(ValueBasicInformation->Name,
543 ValueCell->Name,
544 ValueCell->NameSize);
545 ValueBasicInformation->Name[ValueCell->NameSize] = 0;
546 }
547 else
548 {
549 ValueBasicInformation->NameLength =
550 ValueCell->NameSize + sizeof(WCHAR);
551 RtlCopyMemory(ValueBasicInformation->Name,
552 ValueCell->Name,
553 ValueCell->NameSize * sizeof(WCHAR));
554 ValueBasicInformation->Name[ValueCell->NameSize / sizeof(WCHAR)] = 0;
555 }
556 }
557 break;
558
559 case KeyValuePartialInformation:
560 *ResultLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
561 (ValueCell->DataSize & LONG_MAX);
562 if (Length < *ResultLength)
563 {
564 Status = STATUS_BUFFER_OVERFLOW;
565 }
566 else
567 {
568 ValuePartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)
569 KeyValueInformation;
570 ValuePartialInformation->TitleIndex = 0;
571 ValuePartialInformation->Type = ValueCell->DataType;
572 ValuePartialInformation->DataLength = ValueCell->DataSize & LONG_MAX;
573 if(ValueCell->DataSize >0)
574 {
575 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
576 RtlCopyMemory(ValuePartialInformation->Data,
577 DataCell->Data,
578 ValueCell->DataSize & LONG_MAX);
579 CmiReleaseBlock(RegistryHive, DataCell);
580 }
581 else
582 {
583 RtlCopyMemory(ValuePartialInformation->Data,
584 &ValueCell->DataOffset,
585 ValueCell->DataSize & LONG_MAX);
586 }
587 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
588 }
589 break;
590
591 case KeyValueFullInformation:
592 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
593 {
594 *ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION) +
595 (ValueCell->NameSize + 1) * sizeof(WCHAR) +
596 (ValueCell->DataSize & LONG_MAX);
597 }
598 else
599 {
600 *ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION) +
601 ValueCell->NameSize + sizeof(WCHAR) +
602 (ValueCell->DataSize & LONG_MAX);
603 }
604 if (Length < *ResultLength)
605 {
606 Status = STATUS_BUFFER_OVERFLOW;
607 }
608 else
609 {
610 ValueFullInformation = (PKEY_VALUE_FULL_INFORMATION)
611 KeyValueInformation;
612 ValueFullInformation->TitleIndex = 0;
613 ValueFullInformation->Type = ValueCell->DataType;
614 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
615 {
616 ValueFullInformation->DataOffset =
617 (DWORD)ValueFullInformation->Name - (DWORD) ValueFullInformation
618 + (ValueCell->NameSize + 1) * sizeof(WCHAR);
619 }
620 else
621 {
622 ValueFullInformation->DataOffset =
623 (DWORD)ValueFullInformation->Name - (DWORD) ValueFullInformation
624 + ValueCell->NameSize + sizeof(WCHAR);
625 }
626 ValueFullInformation->DataOffset =
627 (ValueFullInformation->DataOffset + 3) & 0xfffffffc;
628 ValueFullInformation->DataLength = ValueCell->DataSize & LONG_MAX;
629 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
630 {
631 ValueFullInformation->NameLength =
632 (ValueCell->NameSize + 1) * sizeof(WCHAR);
633
634 CmiCopyPackedName(ValueFullInformation->Name,
635 ValueCell->Name,
636 ValueCell->NameSize);
637 ValueFullInformation->Name[ValueCell->NameSize] = 0;
638 }
639 else
640 {
641 ValueFullInformation->NameLength =
642 ValueCell->NameSize + sizeof(WCHAR);
643 RtlCopyMemory(ValueFullInformation->Name,
644 ValueCell->Name,
645 ValueCell->NameSize);
646 ValueFullInformation->Name[ValueCell->NameSize / sizeof(WCHAR)] = 0;
647 }
648 if (ValueCell->DataSize > 0)
649 {
650 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
651 RtlCopyMemory((PCHAR) ValueFullInformation
652 + ValueFullInformation->DataOffset,
653 DataCell->Data,
654 ValueCell->DataSize & LONG_MAX);
655 CmiReleaseBlock(RegistryHive, DataCell);
656 }
657 else
658 {
659 RtlCopyMemory((PCHAR) ValueFullInformation
660 + ValueFullInformation->DataOffset,
661 &ValueCell->DataOffset,
662 ValueCell->DataSize & LONG_MAX);
663 }
664 }
665 break;
666 }
667 }
668 else
669 {
670 Status = STATUS_UNSUCCESSFUL;
671 }
672
673 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
674 ObDereferenceObject(KeyObject);
675
676 return Status;
677 }
678
679
680 NTSTATUS STDCALL
681 NtFlushKey(IN HANDLE KeyHandle)
682 {
683 NTSTATUS Status;
684 PKEY_OBJECT KeyObject;
685 PREGISTRY_HIVE RegistryHive;
686 WCHAR LogName[MAX_PATH];
687 UNICODE_STRING TmpFileName;
688 HANDLE FileHandle;
689 // HANDLE FileHandleLog;
690 OBJECT_ATTRIBUTES ObjectAttributes;
691 LARGE_INTEGER fileOffset;
692 DWORD * pEntDword;
693 ULONG i;
694
695 DPRINT("KeyHandle %x\n", KeyHandle);
696
697 /* Verify that the handle is valid and is a registry key */
698 Status = ObReferenceObjectByHandle(KeyHandle,
699 KEY_QUERY_VALUE,
700 CmiKeyType,
701 UserMode,
702 (PVOID *) &KeyObject,
703 NULL);
704
705 if (!NT_SUCCESS(Status))
706 {
707 return Status;
708 }
709
710 /* Acquire hive lock */
711 ExAcquireResourceExclusiveLite(&KeyObject->RegistryHive->HiveResource, TRUE);
712
713 VERIFY_KEY_OBJECT(KeyObject);
714
715 RegistryHive = KeyObject->RegistryHive;
716
717 /* Then write changed blocks in .log */
718 wcscpy(LogName,RegistryHive->Filename.Buffer);
719 wcscat(LogName,L".log");
720 RtlInitUnicodeString (&TmpFileName, LogName);
721 InitializeObjectAttributes(&ObjectAttributes,
722 &TmpFileName,
723 0,
724 NULL,
725 NULL);
726
727 /* BEGIN FIXME : actually (26 November 200) vfatfs.sys can't create new files
728 so we can't create log file
729 Status = ZwCreateFile(&FileHandleLog,
730 FILE_ALL_ACCESS,
731 &ObjectAttributes,
732 NULL,
733 0,
734 FILE_ATTRIBUTE_NORMAL,
735 0,
736 FILE_SUPERSEDE,
737 0,
738 NULL,
739 0);
740
741 if (!NT_SUCCESS(Status))
742 {
743 ObDereferenceObject(KeyObject);
744 return Status;
745 }
746
747 Status = ZwWriteFile(FileHandleLog,
748 0,
749 0,
750 0,
751 0,
752 RegistryHive->HiveHeader,
753 sizeof(HIVE_HEADER),
754 0,
755 0);
756
757 if (!NT_SUCCESS(Status))
758 {
759 ZwClose(FileHandleLog);
760 ObDereferenceObject(KeyObject);
761 return Status;
762 }
763
764 for (i = 0; i < RegistryHive->BlockListSize ; i++)
765 {
766 if ( RegistryHive->BlockList[i]->DateModified.dwHighDateTime
767 > RegistryHive->HiveHeader->DateModified.dwHighDateTime
768 || (RegistryHive->BlockList[i]->DateModified.dwHighDateTime
769 == RegistryHive->HiveHeader->DateModified.dwHighDateTime
770 && RegistryHive->BlockList[i]->DateModified.dwLowDateTime
771 > RegistryHive->HiveHeader->DateModified.dwLowDateTime
772 )
773 )
774
775 Status = ZwWriteFile(FileHandleLog,
776 0,
777 0,
778 0,
779 0,
780 RegistryHive->BlockList[i],
781 RegistryHive->BlockList[i]->BlockSize ,
782 0,
783 0);
784
785 if (!NT_SUCCESS(Status))
786 {
787 ZwClose(FileHandleLog);
788 ObDereferenceObject(KeyObject);
789 return Status;
790 }
791 }
792 ZwClose(FileHandleLog);
793 END FIXME*/
794
795 /* Update header of RegistryHive with Version >VersionOld */
796 /* this allow recover if system crash while updating hove file */
797 InitializeObjectAttributes(&ObjectAttributes,
798 &RegistryHive->Filename,
799 0,
800 NULL,
801 NULL);
802
803 Status = NtOpenFile(&FileHandle,
804 FILE_ALL_ACCESS,
805 &ObjectAttributes,
806 NULL,
807 0,
808 FILE_SYNCHRONOUS_IO_NONALERT);
809 if (!NT_SUCCESS(Status))
810 {
811 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
812 ObDereferenceObject(KeyObject);
813 return Status;
814 }
815
816 RegistryHive->HiveHeader->Version++;
817
818 Status = ZwWriteFile(FileHandle,
819 0,
820 0,
821 0,
822 0,
823 RegistryHive->HiveHeader,
824 sizeof(HIVE_HEADER),
825 0,
826 0);
827 if (!NT_SUCCESS(Status))
828 {
829 ZwClose(FileHandle);
830 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
831 ObDereferenceObject(KeyObject);
832 return Status;
833 }
834
835 /* Update changed blocks in file */
836 fileOffset.u.HighPart = 0;
837 for (i = 0; i < RegistryHive->BlockListSize ; i++)
838 {
839 if (RegistryHive->BlockList[i]->DateModified.dwHighDateTime
840 > RegistryHive->HiveHeader->DateModified.dwHighDateTime
841 || (RegistryHive->BlockList[i]->DateModified.dwHighDateTime
842 == RegistryHive->HiveHeader->DateModified.dwHighDateTime
843 && RegistryHive->BlockList[i]->DateModified.dwLowDateTime
844 > RegistryHive->HiveHeader->DateModified.dwLowDateTime))
845 {
846 fileOffset.u.LowPart = RegistryHive->BlockList[i]->BlockOffset+4096;
847 Status = NtWriteFile(FileHandle,
848 0,
849 0,
850 0,
851 0,
852 RegistryHive->BlockList[i],
853 RegistryHive->BlockList[i]->BlockSize,
854 &fileOffset,
855 0);
856 if (!NT_SUCCESS(Status))
857 {
858 ZwClose(FileHandle);
859 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
860 ObDereferenceObject(KeyObject);
861 return(Status);
862 }
863 }
864 }
865
866 /* Change version in header */
867 RegistryHive->HiveHeader->VersionOld = RegistryHive->HiveHeader->Version;
868 ZwQuerySystemTime((PTIME) &RegistryHive->HiveHeader->DateModified);
869
870 /* Calculate checksum */
871 RegistryHive->HiveHeader->Checksum = 0;
872 pEntDword = (DWORD *) RegistryHive->HiveHeader;
873 for (i = 0; i < 127 ; i++)
874 {
875 RegistryHive->HiveHeader->Checksum ^= pEntDword[i];
876 }
877
878 /* Write new header */
879 fileOffset.u.LowPart = 0;
880 Status = ZwWriteFile(FileHandle,
881 0,
882 0,
883 0,
884 0,
885 RegistryHive->HiveHeader,
886 sizeof(HIVE_HEADER),
887 &fileOffset,
888 0);
889
890 if (!NT_SUCCESS(Status))
891 {
892 ZwClose(FileHandle);
893 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
894 ObDereferenceObject(KeyObject);
895 return Status;
896 }
897
898 ZwClose(FileHandle);
899 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
900 ObDereferenceObject(KeyObject);
901 return STATUS_SUCCESS;
902 }
903
904
905 NTSTATUS STDCALL
906 NtOpenKey(OUT PHANDLE KeyHandle,
907 IN ACCESS_MASK DesiredAccess,
908 IN POBJECT_ATTRIBUTES ObjectAttributes)
909 {
910 UNICODE_STRING RemainingPath;
911 NTSTATUS Status;
912 PVOID Object;
913
914 DPRINT("NtOpenFile(KH %x DA %x OA %x OA->ON '%wZ'\n",
915 KeyHandle,
916 DesiredAccess,
917 ObjectAttributes,
918 ObjectAttributes ? ObjectAttributes->ObjectName : NULL);
919
920 RemainingPath.Buffer = NULL;
921 Status = ObFindObject(ObjectAttributes,
922 &Object,
923 &RemainingPath,
924 CmiKeyType);
925 if (!NT_SUCCESS(Status))
926 {
927 return(Status);
928 }
929
930 VERIFY_KEY_OBJECT((PKEY_OBJECT) Object);
931
932 DPRINT("RemainingPath '%wZ'\n", &RemainingPath);
933
934 if ((RemainingPath.Buffer != NULL) && (RemainingPath.Buffer[0] != 0))
935 {
936 ObDereferenceObject(Object);
937 return(STATUS_UNSUCCESSFUL);
938 }
939
940 /* Fail if the key has been deleted */
941 if (((PKEY_OBJECT)Object)->Flags & KO_MARKED_FOR_DELETE)
942 {
943 ObDereferenceObject(Object);
944 return(STATUS_UNSUCCESSFUL);
945 }
946
947 Status = ObCreateHandle(PsGetCurrentProcess(),
948 Object,
949 DesiredAccess,
950 FALSE,
951 KeyHandle);
952 ObDereferenceObject(Object);
953
954 if (!NT_SUCCESS(Status))
955 {
956 return(Status);
957 }
958
959 return(STATUS_SUCCESS);
960 }
961
962
963 NTSTATUS STDCALL
964 NtQueryKey(IN HANDLE KeyHandle,
965 IN KEY_INFORMATION_CLASS KeyInformationClass,
966 OUT PVOID KeyInformation,
967 IN ULONG Length,
968 OUT PULONG ResultLength)
969 {
970 PKEY_BASIC_INFORMATION BasicInformation;
971 PKEY_NODE_INFORMATION NodeInformation;
972 PKEY_FULL_INFORMATION FullInformation;
973 PREGISTRY_HIVE RegistryHive;
974 PDATA_CELL pClassData;
975 PKEY_OBJECT KeyObject;
976 PKEY_CELL KeyCell;
977 NTSTATUS Status;
978
979 DPRINT("KH %x KIC %x KI %x L %d RL %x\n",
980 KeyHandle,
981 KeyInformationClass,
982 KeyInformation,
983 Length,
984 ResultLength);
985
986 /* Verify that the handle is valid and is a registry key */
987 Status = ObReferenceObjectByHandle(KeyHandle,
988 KEY_READ,
989 CmiKeyType,
990 UserMode,
991 (PVOID *) &KeyObject,
992 NULL);
993 if (!NT_SUCCESS(Status))
994 {
995 return Status;
996 }
997
998 /* Acquire hive lock */
999 ExAcquireResourceSharedLite(&KeyObject->RegistryHive->HiveResource, TRUE);
1000
1001 VERIFY_KEY_OBJECT(KeyObject);
1002
1003 /* Get pointer to KeyCell */
1004 KeyCell = KeyObject->KeyCell;
1005 RegistryHive = KeyObject->RegistryHive;
1006
1007 Status = STATUS_SUCCESS;
1008 switch (KeyInformationClass)
1009 {
1010 case KeyBasicInformation:
1011 /* Check size of buffer */
1012 if (Length < sizeof(KEY_BASIC_INFORMATION) +
1013 KeyObject->NameSize * sizeof(WCHAR))
1014 {
1015 Status = STATUS_BUFFER_OVERFLOW;
1016 }
1017 else
1018 {
1019 /* Fill buffer with requested info */
1020 BasicInformation = (PKEY_BASIC_INFORMATION) KeyInformation;
1021 BasicInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.dwLowDateTime;
1022 BasicInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.dwHighDateTime;
1023 BasicInformation->TitleIndex = 0;
1024 BasicInformation->NameLength = (KeyObject->NameSize) * sizeof(WCHAR);
1025 mbstowcs(BasicInformation->Name,
1026 KeyObject->Name,
1027 KeyObject->NameSize*sizeof(WCHAR));
1028 *ResultLength = sizeof(KEY_BASIC_INFORMATION) +
1029 KeyObject->NameSize * sizeof(WCHAR);
1030 }
1031 break;
1032
1033 case KeyNodeInformation:
1034 /* Check size of buffer */
1035 if (Length < sizeof(KEY_NODE_INFORMATION)
1036 + KeyObject->NameSize * sizeof(WCHAR)
1037 + KeyCell->ClassSize)
1038 {
1039 Status = STATUS_BUFFER_OVERFLOW;
1040 }
1041 else
1042 {
1043 /* Fill buffer with requested info */
1044 NodeInformation = (PKEY_NODE_INFORMATION) KeyInformation;
1045 NodeInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.dwLowDateTime;
1046 NodeInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.dwHighDateTime;
1047 NodeInformation->TitleIndex = 0;
1048 NodeInformation->ClassOffset = sizeof(KEY_NODE_INFORMATION) +
1049 KeyObject->NameSize * sizeof(WCHAR);
1050 NodeInformation->ClassLength = KeyCell->ClassSize;
1051 NodeInformation->NameLength = KeyObject->NameSize * sizeof(WCHAR);
1052 mbstowcs(NodeInformation->Name,
1053 KeyObject->Name,
1054 KeyObject->NameSize * sizeof(WCHAR));
1055
1056 if (KeyCell->ClassSize != 0)
1057 {
1058 pClassData = CmiGetBlock(KeyObject->RegistryHive,
1059 KeyCell->ClassNameOffset,
1060 NULL);
1061 wcsncpy(NodeInformation->Name + KeyObject->NameSize * sizeof(WCHAR),
1062 (PWCHAR)pClassData->Data,
1063 KeyCell->ClassSize);
1064 CmiReleaseBlock(RegistryHive, pClassData);
1065 }
1066 *ResultLength = sizeof(KEY_NODE_INFORMATION)
1067 + KeyObject->NameSize * sizeof(WCHAR)
1068 + KeyCell->ClassSize;
1069 }
1070 break;
1071
1072 case KeyFullInformation:
1073 /* Check size of buffer */
1074 if (Length < sizeof(KEY_FULL_INFORMATION) + KeyCell->ClassSize)
1075 {
1076 Status = STATUS_BUFFER_OVERFLOW;
1077 }
1078 else
1079 {
1080 /* Fill buffer with requested info */
1081 FullInformation = (PKEY_FULL_INFORMATION) KeyInformation;
1082 FullInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.dwLowDateTime;
1083 FullInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.dwHighDateTime;
1084 FullInformation->TitleIndex = 0;
1085 FullInformation->ClassOffset = sizeof(KEY_FULL_INFORMATION) - sizeof(WCHAR);
1086 FullInformation->ClassLength = KeyCell->ClassSize;
1087 FullInformation->SubKeys = KeyCell->NumberOfSubKeys;
1088 FullInformation->MaxNameLen =
1089 CmiGetMaxNameLength(RegistryHive, KeyCell);
1090 FullInformation->MaxClassLen =
1091 CmiGetMaxClassLength(RegistryHive, KeyCell);
1092 FullInformation->Values = KeyCell->NumberOfValues;
1093 FullInformation->MaxValueNameLen =
1094 CmiGetMaxValueNameLength(RegistryHive, KeyCell);
1095 FullInformation->MaxValueDataLen =
1096 CmiGetMaxValueDataLength(RegistryHive, KeyCell);
1097 if (KeyCell->ClassSize != 0)
1098 {
1099 pClassData=CmiGetBlock(KeyObject->RegistryHive,
1100 KeyCell->ClassNameOffset,
1101 NULL);
1102 wcsncpy(FullInformation->Class,
1103 (PWCHAR)pClassData->Data,
1104 KeyCell->ClassSize);
1105 CmiReleaseBlock(RegistryHive, pClassData);
1106 }
1107 *ResultLength = sizeof(KEY_FULL_INFORMATION) + KeyCell->ClassSize;
1108 }
1109 break;
1110 }
1111
1112 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1113 ObDereferenceObject(KeyObject);
1114
1115 return Status;
1116 }
1117
1118
1119 NTSTATUS STDCALL
1120 NtQueryValueKey(IN HANDLE KeyHandle,
1121 IN PUNICODE_STRING ValueName,
1122 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
1123 OUT PVOID KeyValueInformation,
1124 IN ULONG Length,
1125 OUT PULONG ResultLength)
1126 {
1127 NTSTATUS Status;
1128 PKEY_OBJECT KeyObject;
1129 PREGISTRY_HIVE RegistryHive;
1130 PKEY_CELL KeyCell;
1131 PVALUE_CELL ValueCell;
1132 PDATA_CELL DataCell;
1133 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation;
1134 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation;
1135 PKEY_VALUE_FULL_INFORMATION ValueFullInformation;
1136
1137 DPRINT("NtQueryValueKey(KeyHandle %x ValueName %S Length %x)\n",
1138 KeyHandle, ValueName->Buffer, Length);
1139
1140 /* Verify that the handle is valid and is a registry key */
1141 Status = ObReferenceObjectByHandle(KeyHandle,
1142 KEY_QUERY_VALUE,
1143 CmiKeyType,
1144 UserMode,
1145 (PVOID *)&KeyObject,
1146 NULL);
1147
1148 if (!NT_SUCCESS(Status))
1149 {
1150 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status);
1151 return Status;
1152 }
1153
1154 /* Acquire hive lock */
1155 ExAcquireResourceSharedLite(&KeyObject->RegistryHive->HiveResource, TRUE);
1156
1157 VERIFY_KEY_OBJECT(KeyObject);
1158
1159 /* Get pointer to KeyCell */
1160 KeyCell = KeyObject->KeyCell;
1161 RegistryHive = KeyObject->RegistryHive;
1162
1163 /* Get Value block of interest */
1164 Status = CmiScanKeyForValue(RegistryHive,
1165 KeyCell,
1166 ValueName,
1167 &ValueCell,
1168 NULL);
1169 if (!NT_SUCCESS(Status))
1170 {
1171 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status);
1172 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1173 ObDereferenceObject(KeyObject);
1174 return(Status);
1175 }
1176 else if (ValueCell != NULL)
1177 {
1178 switch (KeyValueInformationClass)
1179 {
1180 case KeyValueBasicInformation:
1181 *ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION)
1182 + ValueCell->NameSize * sizeof(WCHAR);
1183 if (Length < *ResultLength)
1184 {
1185 Status = STATUS_BUFFER_TOO_SMALL;
1186 }
1187 else
1188 {
1189 ValueBasicInformation = (PKEY_VALUE_BASIC_INFORMATION)
1190 KeyValueInformation;
1191 ValueBasicInformation->TitleIndex = 0;
1192 ValueBasicInformation->Type = ValueCell->DataType;
1193 ValueBasicInformation->NameLength =
1194 (ValueCell->NameSize + 1) * sizeof(WCHAR);
1195 mbstowcs(ValueBasicInformation->Name,
1196 ValueCell->Name,ValueCell->NameSize * 2);
1197 ValueBasicInformation->Name[ValueCell->NameSize] = 0;
1198 }
1199 break;
1200
1201 case KeyValuePartialInformation:
1202 *ResultLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION)
1203 + (ValueCell->DataSize & LONG_MAX);
1204 if (Length < *ResultLength)
1205 {
1206 Status = STATUS_BUFFER_TOO_SMALL;
1207 }
1208 else
1209 {
1210 ValuePartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)
1211 KeyValueInformation;
1212 ValuePartialInformation->TitleIndex = 0;
1213 ValuePartialInformation->Type = ValueCell->DataType;
1214 ValuePartialInformation->DataLength = ValueCell->DataSize & LONG_MAX;
1215 if (ValueCell->DataSize > 0)
1216 {
1217 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
1218 RtlCopyMemory(ValuePartialInformation->Data,
1219 DataCell->Data,
1220 ValueCell->DataSize & LONG_MAX);
1221 CmiReleaseBlock(RegistryHive, DataCell);
1222 }
1223 else
1224 {
1225 RtlCopyMemory(ValuePartialInformation->Data,
1226 &ValueCell->DataOffset,
1227 ValueCell->DataSize & LONG_MAX);
1228 }
1229 }
1230 break;
1231
1232 case KeyValueFullInformation:
1233 *ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION)
1234 + (ValueCell->NameSize -1) * sizeof(WCHAR)
1235 + (ValueCell->DataSize & LONG_MAX);
1236 if (Length < *ResultLength)
1237 {
1238 Status = STATUS_BUFFER_TOO_SMALL;
1239 }
1240 else
1241 {
1242 ValueFullInformation = (PKEY_VALUE_FULL_INFORMATION)
1243 KeyValueInformation;
1244 ValueFullInformation->TitleIndex = 0;
1245 ValueFullInformation->Type = ValueCell->DataType;
1246 ValueFullInformation->DataOffset =
1247 (DWORD)ValueFullInformation->Name - (DWORD)ValueFullInformation
1248 + (ValueCell->NameSize + 1) * sizeof(WCHAR);
1249 ValueFullInformation->DataOffset =
1250 (ValueFullInformation->DataOffset + 3) &0xfffffffc;
1251 ValueFullInformation->DataLength = ValueCell->DataSize & LONG_MAX;
1252 ValueFullInformation->NameLength =
1253 (ValueCell->NameSize + 1) * sizeof(WCHAR);
1254 mbstowcs(ValueFullInformation->Name, ValueCell->Name,ValueCell->NameSize*2);
1255 ValueFullInformation->Name[ValueCell->NameSize] = 0;
1256 if (ValueCell->DataSize > 0)
1257 {
1258 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
1259 RtlCopyMemory((PCHAR) ValueFullInformation
1260 + ValueFullInformation->DataOffset,
1261 DataCell->Data,
1262 ValueCell->DataSize & LONG_MAX);
1263 CmiReleaseBlock(RegistryHive, DataCell);
1264 }
1265 else
1266 {
1267 RtlCopyMemory((PCHAR) ValueFullInformation
1268 + ValueFullInformation->DataOffset,
1269 &ValueCell->DataOffset,
1270 ValueCell->DataSize & LONG_MAX);
1271 }
1272 }
1273 break;
1274 }
1275 }
1276 else
1277 {
1278 Status = STATUS_OBJECT_NAME_NOT_FOUND;
1279 }
1280
1281 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1282 ObDereferenceObject(KeyObject);
1283
1284 return Status;
1285 }
1286
1287
1288 NTSTATUS STDCALL
1289 NtSetValueKey(IN HANDLE KeyHandle,
1290 IN PUNICODE_STRING ValueName,
1291 IN ULONG TitleIndex,
1292 IN ULONG Type,
1293 IN PVOID Data,
1294 IN ULONG DataSize)
1295 {
1296 NTSTATUS Status;
1297 PKEY_OBJECT KeyObject;
1298 PREGISTRY_HIVE RegistryHive;
1299 PKEY_CELL KeyCell;
1300 PVALUE_CELL ValueCell;
1301 BLOCK_OFFSET VBOffset;
1302 PDATA_CELL DataCell;
1303 PDATA_CELL NewDataCell;
1304 PHBIN pBin;
1305 ULONG DesiredAccess;
1306
1307 DPRINT("NtSetValueKey(KeyHandle %x ValueName %S Type %d)\n",
1308 KeyHandle, ValueName? ValueName->Buffer : NULL, Type);
1309
1310 DesiredAccess = KEY_SET_VALUE;
1311 if (Type == REG_LINK)
1312 DesiredAccess |= KEY_CREATE_LINK;
1313
1314 /* Verify that the handle is valid and is a registry key */
1315 Status = ObReferenceObjectByHandle(KeyHandle,
1316 DesiredAccess,
1317 CmiKeyType,
1318 UserMode,
1319 (PVOID *)&KeyObject,
1320 NULL);
1321 if (!NT_SUCCESS(Status))
1322 return(Status);
1323
1324 /* Acquire hive lock */
1325 ExAcquireResourceExclusiveLite(&KeyObject->RegistryHive->HiveResource, TRUE);
1326
1327 VERIFY_KEY_OBJECT(KeyObject);
1328
1329 /* Get pointer to key cell */
1330 KeyCell = KeyObject->KeyCell;
1331 RegistryHive = KeyObject->RegistryHive;
1332 Status = CmiScanKeyForValue(RegistryHive,
1333 KeyCell,
1334 ValueName,
1335 &ValueCell,
1336 &VBOffset);
1337 if (!NT_SUCCESS(Status))
1338 {
1339 DPRINT1("Value not found. Status 0x%X\n", Status);
1340
1341 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1342 ObDereferenceObject(KeyObject);
1343 return(Status);
1344 }
1345
1346 if (ValueCell == NULL)
1347 {
1348 DPRINT("Allocate new value cell\n");
1349 Status = CmiAddValueToKey(RegistryHive,
1350 KeyCell,
1351 ValueName,
1352 &ValueCell,
1353 &VBOffset);
1354 }
1355
1356 if (!NT_SUCCESS(Status))
1357 {
1358 DPRINT1("Cannot add value. Status 0x%X\n", Status);
1359
1360 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1361 ObDereferenceObject(KeyObject);
1362 return(Status);
1363 }
1364
1365 DPRINT("DataSize %lu\n", DataSize);
1366 DPRINT("ValueCell %p\n", ValueCell);
1367 DPRINT("ValueCell->DataSize %lu\n", ValueCell->DataSize);
1368
1369 if (DataSize <= 4)
1370 {
1371 /* If datasize <= 4 then write in valueblock directly */
1372 DPRINT("ValueCell->DataSize %lu\n", ValueCell->DataSize);
1373 if ((ValueCell->DataSize >= 0) &&
1374 (DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL)))
1375 {
1376 CmiDestroyBlock(RegistryHive, DataCell, ValueCell->DataOffset);
1377 }
1378
1379 RtlCopyMemory(&ValueCell->DataOffset, Data, DataSize);
1380 ValueCell->DataSize = DataSize | 0x80000000;
1381 ValueCell->DataType = Type;
1382 RtlMoveMemory(&ValueCell->DataOffset, Data, DataSize);
1383 }
1384 else if (DataSize <= (ULONG) (ValueCell->DataSize & 0x7fffffff))
1385 {
1386 /* If new data size is <= current then overwrite current data */
1387 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset,&pBin);
1388 RtlCopyMemory(DataCell->Data, Data, DataSize);
1389 ValueCell->DataSize = DataSize;
1390 ValueCell->DataType = Type;
1391 CmiReleaseBlock(RegistryHive, DataCell);
1392
1393 /* Update time of heap */
1394 if (IsPermanentHive(RegistryHive))
1395 {
1396 ZwQuerySystemTime((PTIME) &pBin->DateModified);
1397 }
1398 }
1399 else
1400 {
1401 /*
1402 * New data size is larger than the current, destroy current
1403 * data block and allocate a new one.
1404 */
1405 BLOCK_OFFSET NewOffset;
1406
1407 DPRINT("ValueCell->DataSize %lu\n", ValueCell->DataSize);
1408
1409 if ((ValueCell->DataSize >= 0) &&
1410 (DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL)))
1411 {
1412 CmiDestroyBlock(RegistryHive, DataCell, ValueCell->DataOffset);
1413 ValueCell->DataSize = 0;
1414 ValueCell->DataType = 0;
1415 ValueCell->DataOffset = 0xffffffff;
1416 }
1417
1418 Status = CmiAllocateBlock(RegistryHive,
1419 (PVOID *)&NewDataCell,
1420 DataSize,
1421 &NewOffset);
1422 if (!NT_SUCCESS(Status))
1423 {
1424 DPRINT("CmiAllocateBlock() failed (Status %lx)\n", Status);
1425
1426 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1427 ObDereferenceObject(KeyObject);
1428
1429 return(Status);
1430 }
1431
1432 RtlCopyMemory(&NewDataCell->Data[0], Data, DataSize);
1433 ValueCell->DataSize = DataSize;
1434 ValueCell->DataType = Type;
1435 CmiReleaseBlock(RegistryHive, NewDataCell);
1436 ValueCell->DataOffset = NewOffset;
1437 }
1438
1439 /* Mark link key */
1440 if ((_wcsicmp(ValueName->Buffer, L"SymbolicLinkValue") == 0) &&
1441 (Type == REG_LINK))
1442 {
1443 KeyCell->Type = REG_LINK_KEY_CELL_TYPE;
1444 }
1445
1446 /* Update time of heap */
1447 if (IsPermanentHive(RegistryHive) && CmiGetBlock(RegistryHive, VBOffset, &pBin))
1448 {
1449 ZwQuerySystemTime((PTIME) &pBin->DateModified);
1450 }
1451
1452 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1453 ObDereferenceObject(KeyObject);
1454
1455 DPRINT("Return Status 0x%X\n", Status);
1456
1457 return(Status);
1458 }
1459
1460
1461 NTSTATUS STDCALL
1462 NtDeleteValueKey(IN HANDLE KeyHandle,
1463 IN PUNICODE_STRING ValueName)
1464 {
1465 PKEY_OBJECT KeyObject;
1466 NTSTATUS Status;
1467
1468 /* Verify that the handle is valid and is a registry key */
1469 Status = ObReferenceObjectByHandle(KeyHandle,
1470 KEY_QUERY_VALUE,
1471 CmiKeyType,
1472 UserMode,
1473 (PVOID *)&KeyObject,
1474 NULL);
1475 if (!NT_SUCCESS(Status))
1476 {
1477 return Status;
1478 }
1479
1480 /* Acquire hive lock */
1481 ExAcquireResourceExclusiveLite(&KeyObject->RegistryHive->HiveResource, TRUE);
1482
1483 VERIFY_KEY_OBJECT(KeyObject);
1484
1485 Status = CmiDeleteValueFromKey(KeyObject->RegistryHive,
1486 KeyObject->KeyCell,
1487 ValueName);
1488
1489 /* Release hive lock */
1490 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1491
1492 ObDereferenceObject(KeyObject);
1493
1494 return Status;
1495 }
1496
1497
1498 NTSTATUS STDCALL
1499 NtLoadKey(PHANDLE KeyHandle,
1500 POBJECT_ATTRIBUTES ObjectAttributes)
1501 {
1502 return NtLoadKey2(KeyHandle, ObjectAttributes, 0);
1503 }
1504
1505
1506 NTSTATUS STDCALL
1507 NtLoadKey2(IN PHANDLE KeyHandle,
1508 IN POBJECT_ATTRIBUTES ObjectAttributes,
1509 IN ULONG Flags)
1510 {
1511 UNIMPLEMENTED;
1512 }
1513
1514
1515 NTSTATUS STDCALL
1516 NtNotifyChangeKey(
1517 IN HANDLE KeyHandle,
1518 IN HANDLE Event,
1519 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1520 IN PVOID ApcContext OPTIONAL,
1521 OUT PIO_STATUS_BLOCK IoStatusBlock,
1522 IN ULONG CompletionFilter,
1523 IN BOOLEAN Asynchroneous,
1524 OUT PVOID ChangeBuffer,
1525 IN ULONG Length,
1526 IN BOOLEAN WatchSubtree)
1527 {
1528 UNIMPLEMENTED;
1529 }
1530
1531
1532 NTSTATUS STDCALL
1533 NtQueryMultipleValueKey(IN HANDLE KeyHandle,
1534 IN OUT PKEY_VALUE_ENTRY ValueList,
1535 IN ULONG NumberOfValues,
1536 OUT PVOID Buffer,
1537 IN OUT PULONG Length,
1538 OUT PULONG ReturnLength)
1539 {
1540 PREGISTRY_HIVE RegistryHive;
1541 PVALUE_CELL ValueCell;
1542 PKEY_OBJECT KeyObject;
1543 PDATA_CELL DataCell;
1544 ULONG BufferLength = 0;
1545 PKEY_CELL KeyCell;
1546 NTSTATUS Status;
1547 PUCHAR DataPtr;
1548 ULONG i;
1549
1550 /* Verify that the handle is valid and is a registry key */
1551 Status = ObReferenceObjectByHandle(KeyHandle,
1552 KEY_QUERY_VALUE,
1553 CmiKeyType,
1554 UserMode,
1555 (PVOID *) &KeyObject,
1556 NULL);
1557 if (!NT_SUCCESS(Status))
1558 {
1559 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status);
1560 return(Status);
1561 }
1562
1563 /* Acquire hive lock */
1564 ExAcquireResourceSharedLite(&KeyObject->RegistryHive->HiveResource, TRUE);
1565
1566 VERIFY_KEY_OBJECT(KeyObject);
1567
1568 /* Get pointer to KeyCell */
1569 KeyCell = KeyObject->KeyCell;
1570 RegistryHive = KeyObject->RegistryHive;
1571
1572 DataPtr = (PUCHAR) Buffer;
1573
1574 for (i = 0; i < NumberOfValues; i++)
1575 {
1576 DPRINT("ValueName: '%wZ'\n", ValueList[i].ValueName);
1577
1578 /* Get Value block of interest */
1579 Status = CmiScanKeyForValue(RegistryHive,
1580 KeyCell,
1581 ValueList[i].ValueName,
1582 &ValueCell,
1583 NULL);
1584
1585 if (!NT_SUCCESS(Status))
1586 {
1587 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status);
1588 break;
1589 }
1590 else if (ValueCell == NULL)
1591 {
1592 Status = STATUS_OBJECT_NAME_NOT_FOUND;
1593 break;
1594 }
1595
1596 BufferLength = (BufferLength + 3) & 0xfffffffc;
1597
1598 if (BufferLength + (ValueCell->DataSize & LONG_MAX) <= *Length)
1599 {
1600 DataPtr = (PUCHAR)(((ULONG)DataPtr + 3) & 0xfffffffc);
1601
1602 ValueList[i].Type = ValueCell->DataType;
1603 ValueList[i].DataLength = ValueCell->DataSize & LONG_MAX;
1604 ValueList[i].DataOffset = (ULONG) DataPtr - (ULONG) Buffer;
1605
1606 if (ValueCell->DataSize > 0)
1607 {
1608 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
1609 RtlCopyMemory(DataPtr, DataCell->Data, ValueCell->DataSize & LONG_MAX);
1610 CmiReleaseBlock(RegistryHive, DataCell);
1611 }
1612 else
1613 {
1614 RtlCopyMemory(DataPtr,
1615 &ValueCell->DataOffset,
1616 ValueCell->DataSize & LONG_MAX);
1617 }
1618
1619 DataPtr += ValueCell->DataSize & LONG_MAX;
1620 }
1621 else
1622 {
1623 Status = STATUS_BUFFER_TOO_SMALL;
1624 }
1625
1626 BufferLength += ValueCell->DataSize & LONG_MAX;
1627 }
1628
1629 if (NT_SUCCESS(Status))
1630 *Length = BufferLength;
1631
1632 *ReturnLength = BufferLength;
1633
1634 /* Release hive lock */
1635 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1636
1637 ObDereferenceObject(KeyObject);
1638
1639 DPRINT("Return Status 0x%X\n", Status);
1640
1641 return(Status);
1642 }
1643
1644
1645 NTSTATUS STDCALL
1646 NtReplaceKey(
1647 IN POBJECT_ATTRIBUTES ObjectAttributes,
1648 IN HANDLE Key,
1649 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
1650 )
1651 {
1652 UNIMPLEMENTED;
1653 }
1654
1655
1656 NTSTATUS STDCALL
1657 NtRestoreKey(
1658 IN HANDLE KeyHandle,
1659 IN HANDLE FileHandle,
1660 IN ULONG RestoreFlags
1661 )
1662 {
1663 UNIMPLEMENTED;
1664 }
1665
1666
1667 NTSTATUS STDCALL
1668 NtSaveKey(
1669 IN HANDLE KeyHandle,
1670 IN HANDLE FileHandle)
1671 {
1672 UNIMPLEMENTED;
1673 }
1674
1675
1676 NTSTATUS STDCALL
1677 NtSetInformationKey(
1678 IN HANDLE KeyHandle,
1679 IN CINT KeyInformationClass,
1680 IN PVOID KeyInformation,
1681 IN ULONG KeyInformationLength)
1682 {
1683 UNIMPLEMENTED;
1684 }
1685
1686
1687 NTSTATUS STDCALL
1688 NtUnloadKey(IN HANDLE KeyHandle)
1689 {
1690 UNIMPLEMENTED;
1691 }
1692
1693
1694 NTSTATUS STDCALL
1695 NtInitializeRegistry(IN BOOLEAN SetUpBoot)
1696 {
1697 NTSTATUS Status = STATUS_ACCESS_DENIED;
1698
1699 if (CmiRegistryInitialized == FALSE)
1700 {
1701 /* FIXME: save boot log file */
1702
1703 Status = CmiInitHives(SetUpBoot);
1704
1705 CmiRegistryInitialized = TRUE;
1706 }
1707
1708 return(Status);
1709 }
1710
1711 /* EOF */