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