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