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