Use free Windows DDK and compile with latest MinGW releases.
[reactos.git] / reactos / ntoskrnl / cm / regfile.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/cm/regfile.c
5 * PURPOSE: Registry file manipulation routines
6 * UPDATE HISTORY:
7 */
8
9 #include <ntoskrnl.h>
10 #include "cm.h"
11
12 #define NDEBUG
13 #include <internal/debug.h>
14
15
16
17 BOOLEAN CmiDoVerify = FALSE;
18
19 VOID
20 CmiCreateDefaultHiveHeader(PHIVE_HEADER Header)
21 {
22 assert(Header);
23 RtlZeroMemory(Header, sizeof(HIVE_HEADER));
24 Header->BlockId = REG_HIVE_ID;
25 Header->DateModified.dwLowDateTime = 0;
26 Header->DateModified.dwHighDateTime = 0;
27 Header->Version = 1;
28 Header->Unused3 = 1;
29 Header->Unused4 = 3;
30 Header->Unused5 = 0;
31 Header->Unused6 = 1;
32 Header->Unused7 = 1;
33 Header->RootKeyCell = 0;
34 Header->BlockSize = REG_BLOCK_SIZE;
35 Header->Unused6 = 1;
36 Header->Checksum = 0;
37 }
38
39
40 VOID
41 CmiCreateDefaultBinCell(PHBIN BinCell)
42 {
43 assert(BinCell);
44 RtlZeroMemory(BinCell, sizeof(HBIN));
45 BinCell->BlockId = REG_BIN_ID;
46 BinCell->DateModified.dwLowDateTime = 0;
47 BinCell->DateModified.dwHighDateTime = 0;
48 BinCell->BlockSize = REG_BLOCK_SIZE;
49 }
50
51
52 VOID
53 CmiCreateDefaultRootKeyCell(PKEY_CELL RootKeyCell)
54 {
55 assert(RootKeyCell);
56 RtlZeroMemory(RootKeyCell, sizeof(KEY_CELL));
57 RootKeyCell->CellSize = -sizeof(KEY_CELL);
58 RootKeyCell->Id = REG_KEY_CELL_ID;
59 RootKeyCell->Type = REG_ROOT_KEY_CELL_TYPE;
60 ZwQuerySystemTime((PLARGE_INTEGER) &RootKeyCell->LastWriteTime);
61 RootKeyCell->ParentKeyOffset = 0;
62 RootKeyCell->NumberOfSubKeys = 0;
63 RootKeyCell->HashTableOffset = -1;
64 RootKeyCell->NumberOfValues = 0;
65 RootKeyCell->ValuesOffset = -1;
66 RootKeyCell->SecurityKeyOffset = 0;
67 RootKeyCell->ClassNameOffset = -1;
68 RootKeyCell->NameSize = 0;
69 RootKeyCell->ClassSize = 0;
70 }
71
72
73 VOID
74 CmiVerifyBinCell(PHBIN BinCell)
75 {
76 if (CmiDoVerify)
77 {
78
79 assert(BinCell);
80
81 if (BinCell->BlockId != REG_BIN_ID)
82 {
83 DbgPrint("BlockId is %.08x (should be %.08x)\n",
84 BinCell->BlockId, REG_BIN_ID);
85 assert(BinCell->BlockId == REG_BIN_ID);
86 }
87
88 //BinCell->DateModified.dwLowDateTime
89
90 //BinCell->DateModified.dwHighDateTime
91
92
93 if (BinCell->BlockSize != REG_BLOCK_SIZE)
94 {
95 DbgPrint("BlockSize is %.08x (should be %.08x)\n",
96 BinCell->BlockSize, REG_BLOCK_SIZE);
97 assert(BinCell->BlockSize == REG_BLOCK_SIZE);
98 }
99
100 }
101 }
102
103
104 VOID
105 CmiVerifyKeyCell(PKEY_CELL KeyCell)
106 {
107 if (CmiDoVerify)
108 {
109
110 assert(KeyCell);
111
112 if (KeyCell->CellSize == 0)
113 {
114 DbgPrint("CellSize is %d (must not be 0)\n",
115 KeyCell->CellSize);
116 assert(KeyCell->CellSize != 0);
117 }
118
119 if (KeyCell->Id != REG_KEY_CELL_ID)
120 {
121 DbgPrint("Id is %.08x (should be %.08x)\n",
122 KeyCell->Id, REG_KEY_CELL_ID);
123 assert(KeyCell->Id == REG_KEY_CELL_ID);
124 }
125
126 if ((KeyCell->Type != REG_KEY_CELL_TYPE)
127 && (KeyCell->Type != REG_ROOT_KEY_CELL_TYPE))
128 {
129 DbgPrint("Type is %.08x (should be %.08x or %.08x)\n",
130 KeyCell->Type, REG_KEY_CELL_TYPE, REG_ROOT_KEY_CELL_TYPE);
131 assert(FALSE);
132 }
133
134 //KeyCell->LastWriteTime;
135
136 if (KeyCell->ParentKeyOffset < 0)
137 {
138 DbgPrint("ParentKeyOffset is %d (must not be < 0)\n",
139 KeyCell->ParentKeyOffset);
140 assert(KeyCell->ParentKeyOffset >= 0);
141 }
142
143 if (KeyCell->NumberOfSubKeys < 0)
144 {
145 DbgPrint("NumberOfSubKeys is %d (must not be < 0)\n",
146 KeyCell->NumberOfSubKeys);
147 assert(KeyCell->NumberOfSubKeys >= 0);
148 }
149
150 //KeyCell->HashTableOffset;
151
152 if (KeyCell->NumberOfValues < 0)
153 {
154 DbgPrint("NumberOfValues is %d (must not be < 0)\n",
155 KeyCell->NumberOfValues);
156 assert(KeyCell->NumberOfValues >= 0);
157 }
158
159 //KeyCell->ValuesOffset = -1;
160
161 if (KeyCell->SecurityKeyOffset < 0)
162 {
163 DbgPrint("SecurityKeyOffset is %d (must not be < 0)\n",
164 KeyCell->SecurityKeyOffset);
165 assert(KeyCell->SecurityKeyOffset >= 0);
166 }
167
168 //KeyCell->ClassNameOffset = -1;
169
170 //KeyCell->NameSize
171
172 //KeyCell->ClassSize
173
174 }
175 }
176
177
178 VOID
179 CmiVerifyRootKeyCell(PKEY_CELL RootKeyCell)
180 {
181 if (CmiDoVerify)
182 {
183
184 CmiVerifyKeyCell(RootKeyCell);
185
186 if (RootKeyCell->Type != REG_ROOT_KEY_CELL_TYPE)
187 {
188 DbgPrint("Type is %.08x (should be %.08x)\n",
189 RootKeyCell->Type, REG_ROOT_KEY_CELL_TYPE);
190 assert(RootKeyCell->Type == REG_ROOT_KEY_CELL_TYPE);
191 }
192
193 }
194 }
195
196
197 VOID
198 CmiVerifyValueCell(PVALUE_CELL ValueCell)
199 {
200 if (CmiDoVerify)
201 {
202
203 assert(ValueCell);
204
205 if (ValueCell->CellSize == 0)
206 {
207 DbgPrint("CellSize is %d (must not be 0)\n",
208 ValueCell->CellSize);
209 assert(ValueCell->CellSize != 0);
210 }
211
212 if (ValueCell->Id != REG_VALUE_CELL_ID)
213 {
214 DbgPrint("Id is %.08x (should be %.08x)\n",
215 ValueCell->Id, REG_VALUE_CELL_ID);
216 assert(ValueCell->Id == REG_VALUE_CELL_ID);
217 }
218
219 //ValueCell->NameSize;
220 //ValueCell->LONG DataSize;
221 //ValueCell->DataOffset;
222 //ValueCell->ULONG DataType;
223 //ValueCell->USHORT Flags;
224 //ValueCell->USHORT Unused1;
225 //ValueCell->UCHAR Name[0];
226 }
227 }
228
229
230 VOID
231 CmiVerifyValueListCell(PVALUE_LIST_CELL ValueListCell)
232 {
233 if (CmiDoVerify)
234 {
235
236 if (ValueListCell->CellSize == 0)
237 {
238 DbgPrint("CellSize is %d (must not be 0)\n",
239 ValueListCell->CellSize);
240 assert(ValueListCell->CellSize != 0);
241 }
242
243 }
244 }
245
246
247 VOID
248 CmiVerifyKeyObject(PKEY_OBJECT KeyObject)
249 {
250 if (CmiDoVerify)
251 {
252
253 if (KeyObject->RegistryHive == NULL)
254 {
255 DbgPrint("RegistryHive is NULL (must not be NULL)\n",
256 KeyObject->RegistryHive);
257 assert(KeyObject->RegistryHive != NULL);
258 }
259
260 if (KeyObject->KeyCell == NULL)
261 {
262 DbgPrint("KeyCell is NULL (must not be NULL)\n",
263 KeyObject->KeyCell);
264 assert(KeyObject->KeyCell != NULL);
265 }
266
267 if (KeyObject->ParentKey == NULL)
268 {
269 DbgPrint("ParentKey is NULL (must not be NULL)\n",
270 KeyObject->ParentKey);
271 assert(KeyObject->ParentKey != NULL);
272 }
273
274 }
275 }
276
277
278 VOID
279 CmiVerifyHiveHeader(PHIVE_HEADER Header)
280 {
281 if (CmiDoVerify)
282 {
283
284 if (Header->BlockId != REG_HIVE_ID)
285 {
286 DbgPrint("BlockId is %.08x (must be %.08x)\n",
287 Header->BlockId,
288 REG_HIVE_ID);
289 assert(Header->BlockId == REG_HIVE_ID);
290 }
291
292 if (Header->Unused3 != 1)
293 {
294 DbgPrint("Unused3 is %.08x (must be 1)\n",
295 Header->Unused3);
296 assert(Header->Unused3 == 1);
297 }
298
299 if (Header->Unused4 != 3)
300 {
301 DbgPrint("Unused4 is %.08x (must be 3)\n",
302 Header->Unused4);
303 assert(Header->Unused4 == 3);
304 }
305
306 if (Header->Unused5 != 0)
307 {
308 DbgPrint("Unused5 is %.08x (must be 0)\n",
309 Header->Unused5);
310 assert(Header->Unused5 == 0);
311 }
312
313 if (Header->Unused6 != 1)
314 {
315 DbgPrint("Unused6 is %.08x (must be 1)\n",
316 Header->Unused6);
317 assert(Header->Unused6 == 1);
318 }
319
320 if (Header->Unused7 != 1)
321 {
322 DbgPrint("Unused7 is %.08x (must be 1)\n",
323 Header->Unused7);
324 assert(Header->Unused7 == 1);
325 }
326
327 }
328 }
329
330
331 VOID
332 CmiVerifyRegistryHive(PREGISTRY_HIVE RegistryHive)
333 {
334 if (CmiDoVerify)
335 {
336
337 CmiVerifyHiveHeader(RegistryHive->HiveHeader);
338
339 }
340 }
341
342
343 NTSTATUS
344 CmiPopulateHive(HANDLE FileHandle)
345 {
346 IO_STATUS_BLOCK IoStatusBlock;
347 LARGE_INTEGER FileOffset;
348 PCELL_HEADER FreeCell;
349 NTSTATUS Status;
350 PHBIN BinCell;
351 PCHAR tBuf;
352 ULONG i;
353
354 tBuf = (PCHAR) ExAllocatePool(NonPagedPool, REG_BLOCK_SIZE);
355 if (tBuf == NULL)
356 return STATUS_INSUFFICIENT_RESOURCES;
357
358 BinCell = (PHBIN) tBuf;
359 FreeCell = (PCELL_HEADER) (tBuf + REG_HBIN_DATA_OFFSET);
360
361 CmiCreateDefaultBinCell(BinCell);
362
363 // The whole block is free
364 FreeCell->CellSize = REG_BLOCK_SIZE - REG_HBIN_DATA_OFFSET;
365
366 // Add free blocks so we don't need to expand
367 // the file for a while
368 for (i = 0; i < 50; i++)
369 {
370 // Block offset of this bin
371 BinCell->BlockOffset = (2 + i) * REG_BLOCK_SIZE;
372
373 FileOffset.u.HighPart = 0;
374 FileOffset.u.LowPart = (2 + i) * REG_BLOCK_SIZE;
375
376 Status = ZwWriteFile(FileHandle,
377 NULL,
378 NULL,
379 NULL,
380 &IoStatusBlock,
381 tBuf,
382 REG_BLOCK_SIZE,
383 &FileOffset,
384 NULL);
385 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
386 if (!NT_SUCCESS(Status))
387 {
388 ExFreePool(tBuf);
389 return Status;
390 }
391 }
392
393 ExFreePool(tBuf);
394
395 return Status;
396 }
397
398
399 NTSTATUS
400 CmiCreateNewRegFile(HANDLE FileHandle)
401 {
402 IO_STATUS_BLOCK IoStatusBlock;
403 PCELL_HEADER FreeCell;
404 PHIVE_HEADER HiveHeader;
405 PKEY_CELL RootKeyCell;
406 NTSTATUS Status;
407 PHBIN BinCell;
408 PCHAR tBuf;
409
410 tBuf = (PCHAR) ExAllocatePool(NonPagedPool, 2 * REG_BLOCK_SIZE);
411 if (tBuf == NULL)
412 return STATUS_INSUFFICIENT_RESOURCES;
413
414 HiveHeader = (PHIVE_HEADER) tBuf;
415 BinCell = (PHBIN) ((ULONG_PTR) tBuf + REG_BLOCK_SIZE);
416 RootKeyCell = (PKEY_CELL) ((ULONG_PTR) tBuf + REG_BLOCK_SIZE + REG_HBIN_DATA_OFFSET);
417 FreeCell = (PCELL_HEADER) ((ULONG_PTR) tBuf + REG_BLOCK_SIZE + REG_HBIN_DATA_OFFSET + sizeof(KEY_CELL));
418
419 CmiCreateDefaultHiveHeader(HiveHeader);
420 CmiCreateDefaultBinCell(BinCell);
421 CmiCreateDefaultRootKeyCell(RootKeyCell);
422
423 // First block
424 BinCell->BlockOffset = 0;
425
426 // Offset to root key block
427 HiveHeader->RootKeyCell = REG_HBIN_DATA_OFFSET;
428
429 // The rest of the block is free
430 FreeCell->CellSize = REG_BLOCK_SIZE - (REG_HBIN_DATA_OFFSET + sizeof(KEY_CELL));
431
432 Status = ZwWriteFile(FileHandle,
433 NULL,
434 NULL,
435 NULL,
436 &IoStatusBlock,
437 tBuf,
438 2 * REG_BLOCK_SIZE,
439 0,
440 NULL);
441
442 ExFreePool(tBuf);
443
444 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
445
446 #if 1
447 if (NT_SUCCESS(Status))
448 {
449 CmiPopulateHive(FileHandle);
450 }
451 #endif
452
453 return Status;
454 }
455
456
457 NTSTATUS
458 CmiInitPermanentRegistryHive(PREGISTRY_HIVE RegistryHive,
459 PWSTR Filename,
460 BOOLEAN CreateNew)
461 {
462 OBJECT_ATTRIBUTES ObjectAttributes;
463 FILE_STANDARD_INFORMATION fsi;
464 PCELL_HEADER FreeBlock;
465 LARGE_INTEGER FileOffset;
466 BLOCK_OFFSET BlockOffset;
467 ULONG CreateDisposition;
468 IO_STATUS_BLOCK IoSB;
469 HANDLE FileHandle;
470 DWORD FreeOffset;
471 NTSTATUS Status;
472 //BOOLEAN Success;
473 PHBIN tmpBin;
474 ULONG i, j;
475
476 /* Duplicate Filename */
477 Status = RtlCreateUnicodeString(&RegistryHive->Filename, Filename);
478 if (!NT_SUCCESS(Status))
479 return Status;
480
481 InitializeObjectAttributes(&ObjectAttributes,
482 &RegistryHive->Filename,
483 0,
484 NULL,
485 NULL);
486
487 if (CreateNew)
488 CreateDisposition = FILE_OPEN_IF;
489 else
490 CreateDisposition = FILE_OPEN;
491
492 Status = NtCreateFile(&FileHandle,
493 FILE_ALL_ACCESS,
494 &ObjectAttributes,
495 &IoSB,
496 NULL,
497 FILE_ATTRIBUTE_NORMAL,
498 0,
499 CreateDisposition,
500 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
501 NULL,
502 0);
503
504 if ((CreateNew) && (IoSB.Information == FILE_CREATED))
505 {
506 Status = CmiCreateNewRegFile(FileHandle);
507 }
508
509 if (!NT_SUCCESS(Status))
510 {
511 RtlFreeUnicodeString(&RegistryHive->Filename);
512 return Status;
513 }
514
515 Status = ObReferenceObjectByHandle(FileHandle,
516 FILE_ALL_ACCESS,
517 IoFileObjectType,
518 UserMode,
519 (PVOID*) &RegistryHive->FileObject,
520 NULL);
521
522 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
523
524 if (!NT_SUCCESS(Status))
525 {
526 ZwClose(FileHandle);
527 RtlFreeUnicodeString(&RegistryHive->Filename);
528 return Status;
529 }
530
531 FileOffset.u.HighPart = 0;
532 FileOffset.u.LowPart = 0;
533 Status = ZwReadFile(FileHandle,
534 0,
535 0,
536 0,
537 0,
538 RegistryHive->HiveHeader,
539 sizeof(HIVE_HEADER),
540 &FileOffset,
541 0);
542
543 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
544
545 if (!NT_SUCCESS(Status))
546 {
547 ObDereferenceObject(RegistryHive->FileObject);
548 RtlFreeUnicodeString(&RegistryHive->Filename);
549 return Status;
550 }
551
552 Status = ZwQueryInformationFile(FileHandle,
553 &IoSB,
554 &fsi,
555 sizeof(fsi),
556 FileStandardInformation);
557
558 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
559
560 if (!NT_SUCCESS(Status))
561 {
562 ObDereferenceObject(RegistryHive->FileObject);
563 RtlFreeUnicodeString(&RegistryHive->Filename);
564 return Status;
565 }
566 #if 0
567 /* We have a reference to the file object so we don't need the handle anymore */
568 ZwClose(FileHandle);
569 #endif
570
571 RegistryHive->FileSize = fsi.EndOfFile.u.LowPart;
572 RegistryHive->BlockListSize = (RegistryHive->FileSize / 4096) - 1;
573
574 DPRINT("Space needed for block list describing hive: 0x%x\n",
575 sizeof(PHBIN *) * RegistryHive->BlockListSize);
576
577 RegistryHive->BlockList = ExAllocatePool(NonPagedPool,
578 sizeof(PHBIN *) * RegistryHive->BlockListSize);
579
580 if (RegistryHive->BlockList == NULL)
581 {
582 ExFreePool(RegistryHive->BlockList);
583 ObDereferenceObject(RegistryHive->FileObject);
584 RtlFreeUnicodeString(&RegistryHive->Filename);
585 return STATUS_INSUFFICIENT_RESOURCES;
586 }
587
588 #if 0
589 /* Map hive into cache memory (readonly) (skip the base block) */
590 FileOffset.u.HighPart = 0;
591 FileOffset.u.LowPart = 4096;
592 Success = CcMapData(RegistryHive->FileObject, /* File object */
593 &FileOffset, /* File offset */
594 RegistryHive->FileSize - 4096, /* Region length */
595 TRUE, /* Wait if needed */
596 &RegistryHive->Bcb, /* OUT: Buffer Control Block */
597 (PVOID*) &RegistryHive->BlockList[0]); /* OUT: Mapped data pointer */
598
599 assertmsg(Success, ("Success: %d\n", Success));
600
601 if (!Success)
602 {
603 ExFreePool(RegistryHive->BlockList);
604 ObDereferenceObject(RegistryHive->FileObject);
605 RtlFreeUnicodeString(&RegistryHive->Filename);
606 return Status;
607 }
608
609 #else
610
611 RegistryHive->BlockList[0] = ExAllocatePool(PagedPool,
612 RegistryHive->FileSize - 4096);
613
614 if (RegistryHive->BlockList[0] == NULL)
615 {
616 ExFreePool(RegistryHive->BlockList);
617 ObDereferenceObject(RegistryHive->FileObject);
618 RtlFreeUnicodeString(&RegistryHive->Filename);
619 return STATUS_INSUFFICIENT_RESOURCES;
620 }
621
622 FileOffset.u.HighPart = 0;
623 FileOffset.u.LowPart = 4096;
624
625 Status = ZwReadFile(FileHandle,
626 0,
627 0,
628 0,
629 0,
630 (PVOID) RegistryHive->BlockList[0],
631 RegistryHive->FileSize - 4096,
632 &FileOffset,
633 0);
634
635 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
636
637 #endif
638
639 RegistryHive->FreeListSize = 0;
640 RegistryHive->FreeListMax = 0;
641 RegistryHive->FreeList = NULL;
642
643 BlockOffset = 0;
644 for (i = 0; i < RegistryHive->BlockListSize; i++)
645 {
646 RegistryHive->BlockList[i] = (PHBIN) (((ULONG_PTR) RegistryHive->BlockList[0]) + BlockOffset);
647 tmpBin = (PHBIN) (((ULONG_PTR) RegistryHive->BlockList[i]));
648 if (tmpBin->BlockId != REG_BIN_ID)
649 {
650 DPRINT("Bad BlockId %x, offset %x\n", tmpBin->BlockId, BlockOffset);
651 KeBugCheck(0);
652 }
653
654 assertmsg((tmpBin->BlockSize % 4096) == 0, ("BlockSize (0x%.08x) must be multiplum of 4K\n", tmpBin->BlockSize));
655
656 if (tmpBin->BlockSize > 4096)
657 {
658 for (j = 1; j < tmpBin->BlockSize / 4096; j++)
659 {
660 RegistryHive->BlockList[i + j] = RegistryHive->BlockList[i];
661 }
662 i = i + j - 1;
663 }
664
665 /* Search free blocks and add to list */
666 FreeOffset = REG_HBIN_DATA_OFFSET;
667 while (FreeOffset < tmpBin->BlockSize)
668 {
669 FreeBlock = (PCELL_HEADER) ((ULONG_PTR) RegistryHive->BlockList[i] + FreeOffset);
670 if (FreeBlock->CellSize > 0)
671 {
672 Status = CmiAddFree(RegistryHive,
673 FreeBlock,
674 RegistryHive->BlockList[i]->BlockOffset + FreeOffset);
675
676 if (!NT_SUCCESS(Status))
677 {
678 /* FIXME: */
679 assert(FALSE);
680 }
681
682 FreeOffset += FreeBlock->CellSize;
683 }
684 else
685 {
686 FreeOffset -= FreeBlock->CellSize;
687 }
688 }
689 BlockOffset += tmpBin->BlockSize;
690 }
691
692 return STATUS_SUCCESS;
693 }
694
695
696 NTSTATUS
697 CmiInitVolatileRegistryHive(PREGISTRY_HIVE RegistryHive)
698 {
699 PKEY_CELL RootKeyCell;
700
701 RegistryHive->Flags |= HIVE_VOLATILE;
702
703 CmiCreateDefaultHiveHeader(RegistryHive->HiveHeader);
704
705 RootKeyCell = (PKEY_CELL) ExAllocatePool(NonPagedPool, sizeof(KEY_CELL));
706
707 if (RootKeyCell == NULL)
708 return STATUS_INSUFFICIENT_RESOURCES;
709
710 CmiCreateDefaultRootKeyCell(RootKeyCell);
711
712 RegistryHive->HiveHeader->RootKeyCell = (BLOCK_OFFSET) RootKeyCell;
713
714 return STATUS_SUCCESS;
715 }
716
717
718 NTSTATUS
719 CmiCreateRegistryHive(PWSTR Filename,
720 PREGISTRY_HIVE *RegistryHive,
721 BOOLEAN CreateNew)
722 {
723 PREGISTRY_HIVE Hive;
724 NTSTATUS Status;
725
726 DPRINT("CmiCreateRegistryHive(Filename %S)\n", Filename);
727
728 *RegistryHive = NULL;
729
730 Hive = ExAllocatePool(NonPagedPool, sizeof(REGISTRY_HIVE));
731 if (Hive == NULL)
732 return STATUS_INSUFFICIENT_RESOURCES;
733
734 DPRINT("Hive %x\n", Hive);
735
736 RtlZeroMemory(Hive, sizeof(REGISTRY_HIVE));
737
738 Hive->HiveHeader = (PHIVE_HEADER)
739 ExAllocatePool(NonPagedPool, sizeof(HIVE_HEADER));
740
741 if (Hive->HiveHeader == NULL)
742 {
743 ExFreePool(Hive);
744 return STATUS_INSUFFICIENT_RESOURCES;
745 }
746
747 if (Filename != NULL)
748 {
749 Status = CmiInitPermanentRegistryHive(Hive, Filename, CreateNew);
750 }
751 else
752 {
753 Status = CmiInitVolatileRegistryHive(Hive);
754 }
755
756 if (!NT_SUCCESS(Status))
757 {
758 ExFreePool(Hive->HiveHeader);
759 ExFreePool(Hive);
760 return(Status);
761 }
762
763 KeInitializeSemaphore(&Hive->RegSem, 1, 1);
764 VERIFY_REGISTRY_HIVE(Hive);
765
766 *RegistryHive = Hive;
767
768 return(STATUS_SUCCESS);
769 }
770
771
772 ULONG
773 CmiGetMaxNameLength(PREGISTRY_HIVE RegistryHive,
774 PKEY_CELL KeyCell)
775 {
776 PHASH_TABLE_CELL HashBlock;
777 PKEY_CELL CurSubKeyCell;
778 ULONG MaxName;
779 ULONG i;
780
781 VERIFY_KEY_CELL(KeyCell);
782
783 MaxName = 0;
784 HashBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
785 if (HashBlock == NULL)
786 {
787 return 0;
788 }
789
790 for (i = 0; i < HashBlock->HashTableSize; i++)
791 {
792 if (HashBlock->Table[i].KeyOffset != 0)
793 {
794 CurSubKeyCell = CmiGetBlock(RegistryHive,
795 HashBlock->Table[i].KeyOffset,
796 NULL);
797 if (MaxName < CurSubKeyCell->NameSize)
798 {
799 MaxName = CurSubKeyCell->NameSize;
800 }
801 CmiReleaseBlock(RegistryHive, CurSubKeyCell);
802 }
803 }
804
805 CmiReleaseBlock(RegistryHive, HashBlock);
806
807 return MaxName;
808 }
809
810
811 ULONG
812 CmiGetMaxClassLength(PREGISTRY_HIVE RegistryHive,
813 PKEY_CELL KeyCell)
814 {
815 PHASH_TABLE_CELL HashBlock;
816 PKEY_CELL CurSubKeyCell;
817 ULONG MaxClass;
818 ULONG i;
819
820 VERIFY_KEY_CELL(KeyCell);
821
822 MaxClass = 0;
823 HashBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
824 if (HashBlock == NULL)
825 {
826 return 0;
827 }
828
829 for (i = 0; i < HashBlock->HashTableSize; i++)
830 {
831 if (HashBlock->Table[i].KeyOffset != 0)
832 {
833 CurSubKeyCell = CmiGetBlock(RegistryHive,
834 HashBlock->Table[i].KeyOffset,
835 NULL);
836 if (MaxClass < CurSubKeyCell->ClassSize)
837 {
838 MaxClass = CurSubKeyCell->ClassSize;
839 }
840 CmiReleaseBlock(RegistryHive, CurSubKeyCell);
841 }
842 }
843
844 CmiReleaseBlock(RegistryHive, HashBlock);
845
846 return MaxClass;
847 }
848
849
850 ULONG
851 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive,
852 PKEY_CELL KeyCell)
853 {
854 PVALUE_LIST_CELL ValueListCell;
855 PVALUE_CELL CurValueCell;
856 ULONG MaxValueName;
857 ULONG i;
858
859 VERIFY_KEY_CELL(KeyCell);
860
861 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
862 MaxValueName = 0;
863 if (ValueListCell == NULL)
864 {
865 return 0;
866 }
867
868 for (i = 0; i < KeyCell->NumberOfValues; i++)
869 {
870 CurValueCell = CmiGetBlock(RegistryHive,
871 ValueListCell->Values[i],
872 NULL);
873 if (CurValueCell != NULL &&
874 MaxValueName < CurValueCell->NameSize)
875 {
876 MaxValueName = CurValueCell->NameSize;
877 }
878 CmiReleaseBlock(RegistryHive, CurValueCell);
879 }
880
881 CmiReleaseBlock(RegistryHive, ValueListCell);
882
883 return MaxValueName;
884 }
885
886
887 ULONG
888 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive,
889 PKEY_CELL KeyCell)
890 {
891 PVALUE_LIST_CELL ValueListCell;
892 PVALUE_CELL CurValueCell;
893 ULONG MaxValueData;
894 ULONG i;
895
896 VERIFY_KEY_CELL(KeyCell);
897
898 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
899 MaxValueData = 0;
900 if (ValueListCell == NULL)
901 {
902 return 0;
903 }
904
905 for (i = 0; i < KeyCell->NumberOfValues; i++)
906 {
907 CurValueCell = CmiGetBlock(RegistryHive,
908 ValueListCell->Values[i],NULL);
909 if ((CurValueCell != NULL) &&
910 (MaxValueData < (CurValueCell->DataSize & LONG_MAX)))
911 {
912 MaxValueData = CurValueCell->DataSize & LONG_MAX;
913 }
914 CmiReleaseBlock(RegistryHive, CurValueCell);
915 }
916
917 CmiReleaseBlock(RegistryHive, ValueListCell);
918
919 return MaxValueData;
920 }
921
922
923 NTSTATUS
924 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive,
925 IN PKEY_CELL KeyCell,
926 OUT PKEY_CELL *SubKeyCell,
927 OUT BLOCK_OFFSET *BlockOffset,
928 IN PCHAR KeyName,
929 IN ACCESS_MASK DesiredAccess,
930 IN ULONG Attributes)
931 {
932 PHASH_TABLE_CELL HashBlock;
933 PKEY_CELL CurSubKeyCell;
934 WORD KeyLength;
935 ULONG i;
936
937 VERIFY_KEY_CELL(KeyCell);
938
939 DPRINT("Scanning for sub key %s\n", KeyName);
940
941 assert(RegistryHive);
942
943 KeyLength = strlen(KeyName);
944
945 HashBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
946 *SubKeyCell = NULL;
947 if (HashBlock == NULL)
948 {
949 return STATUS_SUCCESS;
950 }
951
952 for (i = 0; (i < KeyCell->NumberOfSubKeys)
953 && (i < HashBlock->HashTableSize); i++)
954 {
955 if (Attributes & OBJ_CASE_INSENSITIVE)
956 {
957 if ((HashBlock->Table[i].KeyOffset != 0) &&
958 (HashBlock->Table[i].KeyOffset != -1) &&
959 (_strnicmp(KeyName, (PCHAR) &HashBlock->Table[i].HashValue, 4) == 0))
960 {
961 CurSubKeyCell = CmiGetBlock(RegistryHive,
962 HashBlock->Table[i].KeyOffset,
963 NULL);
964 if ((CurSubKeyCell->NameSize == KeyLength)
965 && (_strnicmp(KeyName, CurSubKeyCell->Name, KeyLength) == 0))
966 {
967 *SubKeyCell = CurSubKeyCell;
968 *BlockOffset = HashBlock->Table[i].KeyOffset;
969 break;
970 }
971 else
972 {
973 CmiReleaseBlock(RegistryHive, CurSubKeyCell);
974 }
975 }
976 }
977 else
978 {
979 if (HashBlock->Table[i].KeyOffset != 0 &&
980 HashBlock->Table[i].KeyOffset != -1 &&
981 !strncmp(KeyName, (PCHAR) &HashBlock->Table[i].HashValue, 4))
982 {
983 CurSubKeyCell = CmiGetBlock(RegistryHive,
984 HashBlock->Table[i].KeyOffset,NULL);
985 if (CurSubKeyCell->NameSize == KeyLength
986 && !_strnicmp(KeyName, CurSubKeyCell->Name, KeyLength))
987 {
988 *SubKeyCell = CurSubKeyCell;
989 *BlockOffset = HashBlock->Table[i].KeyOffset;
990 break;
991 }
992 else
993 {
994 CmiReleaseBlock(RegistryHive, CurSubKeyCell);
995 }
996 }
997 }
998 }
999
1000 CmiReleaseBlock(RegistryHive, HashBlock);
1001
1002 return STATUS_SUCCESS;
1003 }
1004
1005
1006 NTSTATUS
1007 CmiAddSubKey(PREGISTRY_HIVE RegistryHive,
1008 PKEY_OBJECT Parent,
1009 PKEY_OBJECT SubKey,
1010 PWSTR NewSubKeyName,
1011 USHORT NewSubKeyNameSize,
1012 ULONG TitleIndex,
1013 PUNICODE_STRING Class,
1014 ULONG CreateOptions)
1015 {
1016 PHASH_TABLE_CELL NewHashBlock;
1017 PHASH_TABLE_CELL HashBlock;
1018 BLOCK_OFFSET NKBOffset;
1019 PKEY_CELL NewKeyCell;
1020 ULONG NewBlockSize;
1021 PKEY_CELL KeyCell;
1022 NTSTATUS Status;
1023 USHORT NameSize;
1024
1025 KeyCell = Parent->KeyCell;
1026
1027 VERIFY_KEY_CELL(KeyCell);
1028
1029 if (NewSubKeyName[0] == L'\\')
1030 {
1031 NewSubKeyName++;
1032 NameSize = NewSubKeyNameSize / 2 - 1;
1033 }
1034 else
1035 {
1036 NameSize = NewSubKeyNameSize / 2;
1037 }
1038 Status = STATUS_SUCCESS;
1039
1040 NewBlockSize = sizeof(KEY_CELL) + NameSize;
1041 Status = CmiAllocateBlock(RegistryHive,
1042 (PVOID) &NewKeyCell,
1043 NewBlockSize,
1044 &NKBOffset);
1045
1046 if (NewKeyCell == NULL)
1047 {
1048 Status = STATUS_INSUFFICIENT_RESOURCES;
1049 }
1050 else
1051 {
1052 NewKeyCell->Id = REG_KEY_CELL_ID;
1053 NewKeyCell->Type = REG_KEY_CELL_TYPE;
1054 ZwQuerySystemTime((PLARGE_INTEGER) &NewKeyCell->LastWriteTime);
1055 NewKeyCell->ParentKeyOffset = -1;
1056 NewKeyCell->NumberOfSubKeys = 0;
1057 NewKeyCell->HashTableOffset = -1;
1058 NewKeyCell->NumberOfValues = 0;
1059 NewKeyCell->ValuesOffset = -1;
1060 NewKeyCell->SecurityKeyOffset = -1;
1061 NewKeyCell->NameSize = NameSize;
1062 wcstombs(NewKeyCell->Name, NewSubKeyName, NameSize);
1063 NewKeyCell->ClassNameOffset = -1;
1064
1065 VERIFY_KEY_CELL(NewKeyCell);
1066
1067 if (Class)
1068 {
1069 PDATA_CELL pClass;
1070
1071 NewKeyCell->ClassSize = Class->Length + sizeof(WCHAR);
1072 Status = CmiAllocateBlock(RegistryHive,
1073 (PVOID) &pClass,
1074 NewKeyCell->ClassSize,
1075 &NewKeyCell->ClassNameOffset);
1076 wcsncpy((PWSTR) pClass->Data, Class->Buffer, Class->Length);
1077 ((PWSTR) (pClass->Data))[Class->Length] = 0;
1078 }
1079 }
1080
1081 if (!NT_SUCCESS(Status))
1082 {
1083 return Status;
1084 }
1085
1086 SubKey->KeyCell = NewKeyCell;
1087 SubKey->BlockOffset = NKBOffset;
1088
1089 /* Don't modify hash table if key is volatile and parent is not */
1090 if (IsVolatileHive(RegistryHive) && (!IsVolatileHive(Parent->RegistryHive)))
1091 {
1092 return Status;
1093 }
1094
1095 if (KeyCell->HashTableOffset == -1)
1096 {
1097 Status = CmiAllocateHashTableBlock(RegistryHive,
1098 &HashBlock,
1099 &KeyCell->HashTableOffset,
1100 REG_INIT_HASH_TABLE_SIZE);
1101
1102 if (!NT_SUCCESS(Status))
1103 {
1104 return Status;
1105 }
1106 }
1107 else
1108 {
1109 HashBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
1110 if (((KeyCell->NumberOfSubKeys + 1) >= HashBlock->HashTableSize))
1111 {
1112 BLOCK_OFFSET HTOffset;
1113
1114 /* Reallocate the hash table block */
1115 Status = CmiAllocateHashTableBlock(RegistryHive,
1116 &NewHashBlock,
1117 &HTOffset,
1118 HashBlock->HashTableSize +
1119 REG_EXTEND_HASH_TABLE_SIZE);
1120
1121 if (!NT_SUCCESS(Status))
1122 {
1123 return Status;
1124 }
1125
1126 RtlZeroMemory(&NewHashBlock->Table[0],
1127 sizeof(NewHashBlock->Table[0]) * NewHashBlock->HashTableSize);
1128 RtlCopyMemory(&NewHashBlock->Table[0],
1129 &HashBlock->Table[0],
1130 sizeof(NewHashBlock->Table[0]) * HashBlock->HashTableSize);
1131 CmiDestroyBlock(RegistryHive, HashBlock, KeyCell->HashTableOffset);
1132 KeyCell->HashTableOffset = HTOffset;
1133 HashBlock = NewHashBlock;
1134 }
1135 }
1136
1137 Status = CmiAddKeyToHashTable(RegistryHive, HashBlock, NewKeyCell, NKBOffset);
1138 if (NT_SUCCESS(Status))
1139 {
1140 KeyCell->NumberOfSubKeys++;
1141 }
1142
1143 return Status;
1144 }
1145
1146
1147 NTSTATUS
1148 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive,
1149 IN PKEY_CELL KeyCell,
1150 IN PCHAR ValueName,
1151 OUT PVALUE_CELL *ValueCell,
1152 OUT BLOCK_OFFSET *VBOffset)
1153 {
1154 PVALUE_LIST_CELL ValueListCell;
1155 PVALUE_CELL CurValueCell;
1156 ULONG Length;
1157 ULONG i;
1158
1159 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
1160
1161 *ValueCell = NULL;
1162
1163 if (ValueListCell == NULL)
1164 {
1165 DPRINT("ValueListCell is NULL\n");
1166 return STATUS_SUCCESS;
1167 }
1168
1169 VERIFY_VALUE_LIST_CELL(ValueListCell);
1170
1171 for (i = 0; i < KeyCell->NumberOfValues; i++)
1172 {
1173 CurValueCell = CmiGetBlock(RegistryHive,
1174 ValueListCell->Values[i],
1175 NULL);
1176 /* FIXME: perhaps we must not ignore case if NtCreateKey has not been */
1177 /* called with OBJ_CASE_INSENSITIVE flag ? */
1178 Length = strlen(ValueName);
1179 if ((CurValueCell != NULL) &&
1180 (CurValueCell->NameSize == Length) &&
1181 (_strnicmp(CurValueCell->Name, ValueName, Length) == 0))
1182 {
1183 *ValueCell = CurValueCell;
1184 if (VBOffset)
1185 *VBOffset = ValueListCell->Values[i];
1186 DPRINT("Found value %s\n", ValueName);
1187 break;
1188 }
1189 CmiReleaseBlock(RegistryHive, CurValueCell);
1190 }
1191
1192 CmiReleaseBlock(RegistryHive, ValueListCell);
1193
1194 return STATUS_SUCCESS;
1195 }
1196
1197
1198 NTSTATUS
1199 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive,
1200 IN PKEY_CELL KeyCell,
1201 IN ULONG Index,
1202 OUT PVALUE_CELL *ValueCell)
1203 {
1204 PVALUE_LIST_CELL ValueListCell;
1205 PVALUE_CELL CurValueCell;
1206
1207 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
1208
1209 *ValueCell = NULL;
1210
1211 if (ValueListCell == NULL)
1212 {
1213 return STATUS_NO_MORE_ENTRIES;
1214 }
1215
1216 VERIFY_VALUE_LIST_CELL(ValueListCell);
1217
1218 if (Index >= KeyCell->NumberOfValues)
1219 {
1220 return STATUS_NO_MORE_ENTRIES;
1221 }
1222
1223 CurValueCell = CmiGetBlock(RegistryHive,
1224 ValueListCell->Values[Index],
1225 NULL);
1226
1227 if (CurValueCell != NULL)
1228 {
1229 *ValueCell = CurValueCell;
1230 }
1231
1232 CmiReleaseBlock(RegistryHive, CurValueCell);
1233 CmiReleaseBlock(RegistryHive, ValueListCell);
1234
1235 return STATUS_SUCCESS;
1236 }
1237
1238
1239 NTSTATUS
1240 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive,
1241 IN PKEY_CELL KeyCell,
1242 IN PCHAR ValueNameBuf,
1243 OUT PVALUE_CELL *pValueCell,
1244 OUT BLOCK_OFFSET *pVBOffset)
1245 {
1246 PVALUE_LIST_CELL NewValueListCell;
1247 PVALUE_LIST_CELL ValueListCell;
1248 PVALUE_CELL NewValueCell;
1249 BLOCK_OFFSET VLBOffset;
1250 BLOCK_OFFSET VBOffset;
1251 NTSTATUS Status;
1252
1253 Status = CmiAllocateValueCell(RegistryHive,
1254 &NewValueCell,
1255 &VBOffset,
1256 ValueNameBuf);
1257 *pVBOffset = VBOffset;
1258
1259 if (!NT_SUCCESS(Status))
1260 {
1261 return Status;
1262 }
1263
1264 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
1265
1266 if (ValueListCell == NULL)
1267 {
1268 Status = CmiAllocateBlock(RegistryHive,
1269 (PVOID) &ValueListCell,
1270 sizeof(BLOCK_OFFSET) * 3,
1271 &VLBOffset);
1272
1273 if (!NT_SUCCESS(Status))
1274 {
1275 CmiDestroyValueCell(RegistryHive, NewValueCell, VBOffset);
1276 return Status;
1277 }
1278 KeyCell->ValuesOffset = VLBOffset;
1279 }
1280 else if ((KeyCell->NumberOfValues
1281 >= ((LONG) (ValueListCell->CellSize - 4)) / (LONG) sizeof(BLOCK_OFFSET)))
1282 {
1283 Status = CmiAllocateBlock(RegistryHive,
1284 (PVOID) &NewValueListCell,
1285 sizeof(BLOCK_OFFSET) * (KeyCell->NumberOfValues + REG_VALUE_LIST_CELL_MULTIPLE),
1286 &VLBOffset);
1287
1288 if (!NT_SUCCESS(Status))
1289 {
1290 CmiDestroyValueCell(RegistryHive, NewValueCell, VBOffset);
1291 return Status;
1292 }
1293
1294 RtlCopyMemory(&NewValueListCell->Values[0],
1295 &ValueListCell->Values[0],
1296 sizeof(BLOCK_OFFSET) * KeyCell->NumberOfValues);
1297 CmiDestroyBlock(RegistryHive, ValueListCell, KeyCell->ValuesOffset);
1298 KeyCell->ValuesOffset = VLBOffset;
1299 ValueListCell = NewValueListCell;
1300 }
1301
1302 DPRINT("KeyCell->NumberOfValues %d, ValueListCell->CellSize %d (%d %x)\n",
1303 KeyCell->NumberOfValues, ValueListCell->CellSize,
1304 -(ValueListCell->CellSize - 4) / sizeof(BLOCK_OFFSET),
1305 -(ValueListCell->CellSize - 4) / sizeof(BLOCK_OFFSET));
1306
1307 ValueListCell->Values[KeyCell->NumberOfValues] = VBOffset;
1308 KeyCell->NumberOfValues++;
1309 CmiReleaseBlock(RegistryHive, ValueListCell);
1310 CmiReleaseBlock(RegistryHive, NewValueCell);
1311 *pValueCell = NewValueCell;
1312
1313 return STATUS_SUCCESS;
1314 }
1315
1316
1317 NTSTATUS
1318 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive,
1319 IN PKEY_CELL KeyCell,
1320 IN PCHAR ValueName)
1321 {
1322 PVALUE_LIST_CELL ValueListCell;
1323 PVALUE_CELL CurValueCell;
1324 ULONG i;
1325
1326 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
1327
1328 if (ValueListCell == NULL)
1329 {
1330 return STATUS_SUCCESS;
1331 }
1332
1333 VERIFY_VALUE_LIST_CELL(ValueListCell);
1334
1335 for (i = 0; i < KeyCell->NumberOfValues; i++)
1336 {
1337 CurValueCell = CmiGetBlock(RegistryHive, ValueListCell->Values[i], NULL);
1338 if ((CurValueCell != NULL) &&
1339 (CurValueCell->NameSize == strlen(ValueName)) &&
1340 (memcmp(CurValueCell->Name, ValueName, strlen(ValueName)) == 0))
1341 {
1342 if ((KeyCell->NumberOfValues - 1) < i)
1343 {
1344 RtlCopyMemory(&ValueListCell->Values[i],
1345 &ValueListCell->Values[i + 1],
1346 sizeof(BLOCK_OFFSET) * (KeyCell->NumberOfValues - 1 - i));
1347 }
1348 else
1349 {
1350 RtlZeroMemory(&ValueListCell->Values[i], sizeof(BLOCK_OFFSET));
1351 }
1352
1353 KeyCell->NumberOfValues -= 1;
1354 CmiDestroyValueCell(RegistryHive, CurValueCell, ValueListCell->Values[i]);
1355 break;
1356 }
1357 CmiReleaseBlock(RegistryHive, CurValueCell);
1358 }
1359
1360 CmiReleaseBlock(RegistryHive, ValueListCell);
1361
1362 return STATUS_SUCCESS;
1363 }
1364
1365
1366 NTSTATUS
1367 CmiAllocateHashTableBlock(IN PREGISTRY_HIVE RegistryHive,
1368 OUT PHASH_TABLE_CELL *HashBlock,
1369 OUT BLOCK_OFFSET *HBOffset,
1370 IN ULONG HashTableSize)
1371 {
1372 PHASH_TABLE_CELL NewHashBlock;
1373 ULONG NewHashSize;
1374 NTSTATUS Status;
1375
1376 Status = STATUS_SUCCESS;
1377 *HashBlock = NULL;
1378 NewHashSize = sizeof(HASH_TABLE_CELL) +
1379 (HashTableSize - 1) * sizeof(HASH_RECORD);
1380 Status = CmiAllocateBlock(RegistryHive,
1381 (PVOID*) &NewHashBlock,
1382 NewHashSize,
1383 HBOffset);
1384
1385 if ((NewHashBlock == NULL) || (!NT_SUCCESS(Status)))
1386 {
1387 Status = STATUS_INSUFFICIENT_RESOURCES;
1388 }
1389 else
1390 {
1391 NewHashBlock->Id = REG_HASH_TABLE_BLOCK_ID;
1392 NewHashBlock->HashTableSize = HashTableSize;
1393 *HashBlock = NewHashBlock;
1394 }
1395
1396 return Status;
1397 }
1398
1399
1400 PKEY_CELL
1401 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive,
1402 PHASH_TABLE_CELL HashBlock,
1403 ULONG Index)
1404 {
1405 BLOCK_OFFSET KeyOffset;
1406 PKEY_CELL KeyCell;
1407
1408 if (HashBlock == NULL)
1409 return NULL;
1410
1411 if (IsVolatileHive(RegistryHive))
1412 {
1413 KeyCell = (PKEY_CELL) HashBlock->Table[Index].KeyOffset;
1414 }
1415 else
1416 {
1417 KeyOffset = HashBlock->Table[Index].KeyOffset;
1418 KeyCell = CmiGetBlock(RegistryHive, KeyOffset, NULL);
1419 }
1420 CmiLockBlock(RegistryHive, KeyCell);
1421
1422 return KeyCell;
1423 }
1424
1425
1426 NTSTATUS
1427 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive,
1428 PHASH_TABLE_CELL HashBlock,
1429 PKEY_CELL NewKeyCell,
1430 BLOCK_OFFSET NKBOffset)
1431 {
1432 ULONG i;
1433
1434 for (i = 0; i < HashBlock->HashTableSize; i++)
1435 {
1436 if (HashBlock->Table[i].KeyOffset == 0)
1437 {
1438 HashBlock->Table[i].KeyOffset = NKBOffset;
1439 RtlCopyMemory(&HashBlock->Table[i].HashValue, NewKeyCell->Name, 4);
1440 return STATUS_SUCCESS;
1441 }
1442 }
1443
1444 return STATUS_UNSUCCESSFUL;
1445 }
1446
1447
1448 NTSTATUS
1449 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive,
1450 PVALUE_CELL *ValueCell,
1451 BLOCK_OFFSET *VBOffset,
1452 IN PCHAR ValueNameBuf)
1453 {
1454 PVALUE_CELL NewValueCell;
1455 ULONG NewValueSize;
1456 NTSTATUS Status;
1457
1458 Status = STATUS_SUCCESS;
1459
1460 NewValueSize = sizeof(VALUE_CELL) + strlen(ValueNameBuf);
1461 Status = CmiAllocateBlock(RegistryHive,
1462 (PVOID*) &NewValueCell,
1463 NewValueSize,
1464 VBOffset);
1465
1466 if ((NewValueCell == NULL) || (!NT_SUCCESS(Status)))
1467 {
1468 Status = STATUS_INSUFFICIENT_RESOURCES;
1469 }
1470 else
1471 {
1472 NewValueCell->Id = REG_VALUE_CELL_ID;
1473 NewValueCell->NameSize = strlen(ValueNameBuf);
1474 memcpy(NewValueCell->Name, ValueNameBuf, strlen(ValueNameBuf));
1475 NewValueCell->DataType = 0;
1476 NewValueCell->DataSize = 0;
1477 NewValueCell->DataOffset = 0xffffffff;
1478 *ValueCell = NewValueCell;
1479 }
1480
1481 return Status;
1482 }
1483
1484
1485 NTSTATUS
1486 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive,
1487 PVALUE_CELL ValueCell,
1488 BLOCK_OFFSET VBOffset)
1489 {
1490 NTSTATUS Status;
1491 PVOID pBlock;
1492 PHBIN pBin;
1493
1494 VERIFY_VALUE_CELL(ValueCell);
1495
1496 /* First, release datas: */
1497 if (ValueCell->DataSize > 0)
1498 {
1499 pBlock = CmiGetBlock(RegistryHive, ValueCell->DataOffset, &pBin);
1500 Status = CmiDestroyBlock(RegistryHive, pBlock, ValueCell->DataOffset);
1501 if (!NT_SUCCESS(Status))
1502 {
1503 return Status;
1504 }
1505
1506 /* Update time of heap */
1507 if (IsPermanentHive(RegistryHive))
1508 ZwQuerySystemTime((PLARGE_INTEGER) &pBin->DateModified);
1509 }
1510
1511 Status = CmiDestroyBlock(RegistryHive, ValueCell, VBOffset);
1512
1513 /* Update time of heap */
1514 if (IsPermanentHive(RegistryHive) && CmiGetBlock(RegistryHive, VBOffset, &pBin))
1515 {
1516 ZwQuerySystemTime((PLARGE_INTEGER) &pBin->DateModified);
1517 }
1518
1519 return Status;
1520 }
1521
1522
1523 NTSTATUS
1524 CmiAddBin(PREGISTRY_HIVE RegistryHive,
1525 PVOID *NewBlock,
1526 BLOCK_OFFSET *NewBlockOffset)
1527 {
1528 PCELL_HEADER tmpBlock;
1529 PHBIN * tmpBlockList;
1530 PHBIN tmpBin;
1531
1532 tmpBin = ExAllocatePool(PagedPool, REG_BLOCK_SIZE);
1533 if (tmpBin == NULL)
1534 {
1535 return STATUS_INSUFFICIENT_RESOURCES;
1536 }
1537
1538 tmpBin->BlockId = REG_BIN_ID;
1539 tmpBin->BlockOffset = RegistryHive->FileSize - REG_BLOCK_SIZE;
1540 RegistryHive->FileSize += REG_BLOCK_SIZE;
1541 tmpBin->BlockSize = REG_BLOCK_SIZE;
1542 tmpBin->Unused1 = 0;
1543 ZwQuerySystemTime((PLARGE_INTEGER) &tmpBin->DateModified);
1544 tmpBin->Unused2 = 0;
1545
1546 /* Increase size of list of blocks */
1547 tmpBlockList = ExAllocatePool(NonPagedPool,
1548 sizeof(PHBIN *) * (RegistryHive->BlockListSize + 1));
1549 if (tmpBlockList == NULL)
1550 {
1551 ExFreePool(tmpBin);
1552 return STATUS_INSUFFICIENT_RESOURCES;
1553 }
1554
1555 if (RegistryHive->BlockListSize > 0)
1556 {
1557 memcpy(tmpBlockList,
1558 RegistryHive->BlockList,
1559 sizeof(PHBIN *)*(RegistryHive->BlockListSize));
1560 ExFreePool(RegistryHive->BlockList);
1561 }
1562
1563 RegistryHive->BlockList = tmpBlockList;
1564 RegistryHive->BlockList[RegistryHive->BlockListSize++] = tmpBin;
1565
1566 /* Initialize a free block in this heap : */
1567 tmpBlock = (PCELL_HEADER)((ULONG_PTR) tmpBin + REG_HBIN_DATA_OFFSET);
1568 tmpBlock->CellSize = (REG_BLOCK_SIZE - REG_HBIN_DATA_OFFSET);
1569 *NewBlock = (PVOID) tmpBlock;
1570
1571 if (NewBlockOffset)
1572 *NewBlockOffset = tmpBin->BlockOffset + REG_HBIN_DATA_OFFSET;
1573
1574 /* FIXME: set first dword to block_offset of another free bloc */
1575
1576 return STATUS_SUCCESS;
1577 }
1578
1579
1580 NTSTATUS
1581 CmiAllocateBlock(PREGISTRY_HIVE RegistryHive,
1582 PVOID *Block,
1583 LONG BlockSize,
1584 BLOCK_OFFSET * pBlockOffset)
1585 {
1586 PCELL_HEADER NewBlock;
1587 NTSTATUS Status;
1588 PHBIN pBin;
1589
1590 Status = STATUS_SUCCESS;
1591
1592 /* Round to 16 bytes multiple */
1593 BlockSize = (BlockSize + sizeof(DWORD) + 15) & 0xfffffff0;
1594
1595 /* Handle volatile hives first */
1596 if (IsVolatileHive(RegistryHive))
1597 {
1598 NewBlock = ExAllocatePool(NonPagedPool, BlockSize);
1599
1600 if (NewBlock == NULL)
1601 {
1602 Status = STATUS_INSUFFICIENT_RESOURCES;
1603 }
1604 else
1605 {
1606 RtlZeroMemory(NewBlock, BlockSize);
1607 NewBlock->CellSize = BlockSize;
1608 CmiLockBlock(RegistryHive, NewBlock);
1609 *Block = NewBlock;
1610 if (pBlockOffset)
1611 *pBlockOffset = (BLOCK_OFFSET) NewBlock;
1612 }
1613 }
1614 else
1615 {
1616 ULONG i;
1617
1618 /* first search in free blocks */
1619 NewBlock = NULL;
1620 for (i = 0; i < RegistryHive->FreeListSize; i++)
1621 {
1622 if (RegistryHive->FreeList[i]->CellSize >= BlockSize)
1623 {
1624 PVOID Temp;
1625 NewBlock = RegistryHive->FreeList[i];
1626
1627 if (pBlockOffset)
1628 *pBlockOffset = RegistryHive->FreeListOffset[i];
1629
1630 /* Update time of heap */
1631 Temp = CmiGetBlock(RegistryHive, RegistryHive->FreeListOffset[i], &pBin);
1632
1633 if (Temp)
1634 ZwQuerySystemTime((PLARGE_INTEGER) &pBin->DateModified);
1635
1636 if ((i + 1) < RegistryHive->FreeListSize)
1637 {
1638 RtlMoveMemory(&RegistryHive->FreeList[i],
1639 &RegistryHive->FreeList[i + 1],
1640 sizeof(RegistryHive->FreeList[0])
1641 * (RegistryHive->FreeListSize - i - 1));
1642 RtlMoveMemory(&RegistryHive->FreeListOffset[i],
1643 &RegistryHive->FreeListOffset[i + 1],
1644 sizeof(RegistryHive->FreeListOffset[0])
1645 * (RegistryHive->FreeListSize - i - 1));
1646 }
1647 RegistryHive->FreeListSize--;
1648 break;
1649 }
1650 }
1651
1652 /* Need to extend hive file : */
1653 if (NewBlock == NULL)
1654 {
1655 /* Add a new block */
1656 Status = CmiAddBin(RegistryHive, (PVOID *) &NewBlock , pBlockOffset);
1657 }
1658
1659 if (NT_SUCCESS(Status))
1660 {
1661 *Block = NewBlock;
1662
1663 /* Split the block in two parts */
1664 if (NewBlock->CellSize > BlockSize)
1665 {
1666 NewBlock = (PCELL_HEADER) ((ULONG_PTR) NewBlock+BlockSize);
1667 NewBlock->CellSize = ((PCELL_HEADER) (*Block))->CellSize - BlockSize;
1668 CmiAddFree(RegistryHive, NewBlock, *pBlockOffset + BlockSize);
1669 }
1670 else if (NewBlock->CellSize < BlockSize)
1671 {
1672 return STATUS_UNSUCCESSFUL;
1673 }
1674 RtlZeroMemory(*Block, BlockSize);
1675 ((PCELL_HEADER) (*Block))->CellSize = -BlockSize;
1676 CmiLockBlock(RegistryHive, *Block);
1677 }
1678 }
1679 return Status;
1680 }
1681
1682
1683 NTSTATUS
1684 CmiDestroyBlock(PREGISTRY_HIVE RegistryHive,
1685 PVOID Block,
1686 BLOCK_OFFSET Offset)
1687 {
1688 NTSTATUS Status;
1689 PHBIN pBin;
1690
1691 Status = STATUS_SUCCESS;
1692
1693 if (IsVolatileHive(RegistryHive))
1694 {
1695 CmiReleaseBlock(RegistryHive, Block);
1696 ExFreePool(Block);
1697 }
1698 else
1699 {
1700 PCELL_HEADER pFree = Block;
1701
1702 if (pFree->CellSize < 0)
1703 pFree->CellSize = -pFree->CellSize;
1704
1705 CmiAddFree(RegistryHive, Block, Offset);
1706 CmiReleaseBlock(RegistryHive, Block);
1707
1708 /* Update time of heap */
1709 if (IsPermanentHive(RegistryHive) && CmiGetBlock(RegistryHive, Offset,&pBin))
1710 ZwQuerySystemTime((PLARGE_INTEGER) &pBin->DateModified);
1711
1712 /* FIXME: Set first dword to block_offset of another free block ? */
1713 /* FIXME: Concatenate with previous and next block if free */
1714 }
1715
1716 return Status;
1717 }
1718
1719
1720 NTSTATUS
1721 CmiAddFree(PREGISTRY_HIVE RegistryHive,
1722 PCELL_HEADER FreeBlock,
1723 BLOCK_OFFSET FreeOffset)
1724 {
1725 PCELL_HEADER *tmpList;
1726 BLOCK_OFFSET *tmpListOffset;
1727 LONG minInd;
1728 LONG maxInd;
1729 LONG medInd;
1730
1731 assert(RegistryHive);
1732 assert(FreeBlock);
1733
1734 DPRINT("FreeBlock %.08x FreeOffset %.08x\n",
1735 FreeBlock, FreeOffset);
1736 DPRINT("\n");
1737 if ((RegistryHive->FreeListSize + 1) > RegistryHive->FreeListMax)
1738 {
1739 DPRINT("\n");
1740 tmpList = ExAllocatePool(PagedPool,
1741 sizeof(PCELL_HEADER) * (RegistryHive->FreeListMax + 32));
1742 DPRINT("\n");
1743
1744 if (tmpList == NULL)
1745 return STATUS_INSUFFICIENT_RESOURCES;
1746 DPRINT("\n");
1747
1748 tmpListOffset = ExAllocatePool(PagedPool,
1749 sizeof(BLOCK_OFFSET *) * (RegistryHive->FreeListMax + 32));
1750 DPRINT("\n");
1751
1752 if (tmpListOffset == NULL)
1753 {
1754 ExFreePool(tmpList);
1755 return STATUS_INSUFFICIENT_RESOURCES;
1756 }
1757 DPRINT("\n");
1758
1759 if (RegistryHive->FreeListMax)
1760 {
1761 DPRINT("\n");
1762 RtlMoveMemory(tmpList, RegistryHive->FreeList,
1763 sizeof(PCELL_HEADER) * (RegistryHive->FreeListMax));
1764 DPRINT("\n");
1765 RtlMoveMemory(tmpListOffset, RegistryHive->FreeListOffset,
1766 sizeof(BLOCK_OFFSET *) * (RegistryHive->FreeListMax));
1767 DPRINT("\n");
1768 ExFreePool(RegistryHive->FreeList);
1769 DPRINT("\n");
1770 ExFreePool(RegistryHive->FreeListOffset);
1771 DPRINT("\n");
1772 }
1773 DPRINT("\n");
1774 RegistryHive->FreeList = tmpList;
1775 RegistryHive->FreeListOffset = tmpListOffset;
1776 RegistryHive->FreeListMax += 32;
1777 DPRINT("\n");
1778 }
1779 DPRINT("\n");
1780
1781 /* Add new offset to free list, maintaining list in ascending order */
1782 if ((RegistryHive->FreeListSize == 0)
1783 || (RegistryHive->FreeListOffset[RegistryHive->FreeListSize-1] < FreeOffset))
1784 {
1785 DPRINT("\n");
1786 /* Add to end of list */
1787 RegistryHive->FreeList[RegistryHive->FreeListSize] = FreeBlock;
1788 RegistryHive->FreeListOffset[RegistryHive->FreeListSize++] = FreeOffset;
1789 }
1790 else if (RegistryHive->FreeListOffset[0] > FreeOffset)
1791 {
1792 DPRINT("\n");
1793 /* Add to begin of list */
1794 RtlMoveMemory(&RegistryHive->FreeList[1],
1795 &RegistryHive->FreeList[0],
1796 sizeof(RegistryHive->FreeList[0]) * RegistryHive->FreeListSize);
1797 RtlMoveMemory(&RegistryHive->FreeListOffset[1],
1798 &RegistryHive->FreeListOffset[0],
1799 sizeof(RegistryHive->FreeListOffset[0]) * RegistryHive->FreeListSize);
1800 RegistryHive->FreeList[0] = FreeBlock;
1801 RegistryHive->FreeListOffset[0] = FreeOffset;
1802 RegistryHive->FreeListSize++;
1803 }
1804 else
1805 {
1806 DPRINT("\n");
1807 /* Search where to insert */
1808 minInd = 0;
1809 maxInd = RegistryHive->FreeListSize - 1;
1810 while ((maxInd - minInd) > 1)
1811 {
1812 medInd = (minInd + maxInd) / 2;
1813 if (RegistryHive->FreeListOffset[medInd] > FreeOffset)
1814 maxInd = medInd;
1815 else
1816 minInd = medInd;
1817 }
1818
1819 /* Insert before maxInd */
1820 RtlMoveMemory(&RegistryHive->FreeList[maxInd+1],
1821 &RegistryHive->FreeList[maxInd],
1822 sizeof(RegistryHive->FreeList[0]) * (RegistryHive->FreeListSize - minInd));
1823 RtlMoveMemory(&RegistryHive->FreeListOffset[maxInd + 1],
1824 &RegistryHive->FreeListOffset[maxInd],
1825 sizeof(RegistryHive->FreeListOffset[0]) * (RegistryHive->FreeListSize-minInd));
1826 RegistryHive->FreeList[maxInd] = FreeBlock;
1827 RegistryHive->FreeListOffset[maxInd] = FreeOffset;
1828 RegistryHive->FreeListSize++;
1829 }
1830 DPRINT("\n");
1831
1832 return STATUS_SUCCESS;
1833 }
1834
1835
1836 PVOID
1837 CmiGetBlock(PREGISTRY_HIVE RegistryHive,
1838 BLOCK_OFFSET BlockOffset,
1839 PHBIN * ppBin)
1840 {
1841 if (ppBin)
1842 *ppBin = NULL;
1843
1844 if ((BlockOffset == 0) || (BlockOffset == -1))
1845 return NULL;
1846
1847 if (IsVolatileHive(RegistryHive))
1848 {
1849 return (PVOID) BlockOffset;
1850 }
1851 else
1852 {
1853 PHBIN pBin;
1854
1855 pBin = RegistryHive->BlockList[BlockOffset / 4096];
1856 if (ppBin)
1857 *ppBin = pBin;
1858 return ((PVOID) ((ULONG_PTR) pBin + (BlockOffset - pBin->BlockOffset)));
1859 }
1860 }
1861
1862
1863 VOID
1864 CmiPrepareForWrite(PREGISTRY_HIVE RegistryHive,
1865 PHBIN pBin)
1866 {
1867 if (IsVolatileHive(RegistryHive))
1868 {
1869 /* No need to do anything special for volatile hives */
1870 return;
1871 }
1872 else
1873 {
1874
1875 }
1876 }
1877
1878
1879 VOID
1880 CmiLockBlock(PREGISTRY_HIVE RegistryHive,
1881 PVOID Block)
1882 {
1883 if (IsPermanentHive(RegistryHive))
1884 {
1885 /* FIXME: Implement */
1886 }
1887 }
1888
1889
1890 VOID
1891 CmiReleaseBlock(PREGISTRY_HIVE RegistryHive,
1892 PVOID Block)
1893 {
1894 if (IsPermanentHive(RegistryHive))
1895 {
1896 /* FIXME: Implement */
1897 }
1898 }