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