Fix typo.
[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 #include <reactos/bugcodes.h>
21
22 #define NDEBUG
23 #include <internal/debug.h>
24
25 #include "cm.h"
26 #endif
27
28 /* uncomment to enable hive checks (incomplete and probably buggy) */
29 // #define HIVE_CHECK
30
31 /* LOCAL MACROS *************************************************************/
32
33 #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
34 #define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
35
36 #define ABS_VALUE(V) (((V) < 0) ? -(V) : (V))
37
38 BOOLEAN CmiDoVerify = FALSE;
39
40 static ULONG
41 CmiCalcChecksum(PULONG Buffer);
42
43 /* FUNCTIONS ****************************************************************/
44
45 VOID
46 CmiCreateDefaultHiveHeader(PHIVE_HEADER Header)
47 {
48 assert(Header);
49 RtlZeroMemory(Header, sizeof(HIVE_HEADER));
50 Header->BlockId = REG_HIVE_ID;
51 Header->UpdateCounter1 = 0;
52 Header->UpdateCounter2 = 0;
53 Header->DateModified.dwLowDateTime = 0;
54 Header->DateModified.dwHighDateTime = 0;
55 Header->Unused3 = 1;
56 Header->Unused4 = 3;
57 Header->Unused5 = 0;
58 Header->Unused6 = 1;
59 Header->Unused7 = 1;
60 Header->RootKeyCell = 0;
61 Header->BlockSize = REG_BLOCK_SIZE;
62 Header->Unused6 = 1;
63 Header->Checksum = 0;
64 }
65
66
67 VOID
68 CmiCreateDefaultBinCell(PHBIN BinCell)
69 {
70 assert(BinCell);
71 RtlZeroMemory(BinCell, sizeof(HBIN));
72 BinCell->BlockId = REG_BIN_ID;
73 BinCell->DateModified.dwLowDateTime = 0;
74 BinCell->DateModified.dwHighDateTime = 0;
75 BinCell->BlockSize = REG_BLOCK_SIZE;
76 }
77
78
79 VOID
80 CmiCreateDefaultRootKeyCell(PKEY_CELL RootKeyCell)
81 {
82 assert(RootKeyCell);
83 RtlZeroMemory(RootKeyCell, sizeof(KEY_CELL));
84 #ifdef WIN32_REGDBG
85 RootKeyCell->CellSize = -(LONG)sizeof(KEY_CELL);
86 #else
87 RootKeyCell->CellSize = -sizeof(KEY_CELL);
88 #endif
89 RootKeyCell->Id = REG_KEY_CELL_ID;
90 RootKeyCell->Type = REG_ROOT_KEY_CELL_TYPE;
91 NtQuerySystemTime((PTIME) &RootKeyCell->LastWriteTime);
92 RootKeyCell->ParentKeyOffset = 0;
93 RootKeyCell->NumberOfSubKeys = 0;
94 RootKeyCell->HashTableOffset = -1;
95 RootKeyCell->NumberOfValues = 0;
96 RootKeyCell->ValuesOffset = -1;
97 RootKeyCell->SecurityKeyOffset = 0;
98 RootKeyCell->ClassNameOffset = -1;
99 RootKeyCell->NameSize = 0;
100 RootKeyCell->ClassSize = 0;
101 }
102
103
104 VOID
105 CmiVerifyBinCell(PHBIN BinCell)
106 {
107 if (CmiDoVerify)
108 {
109
110 assert(BinCell);
111
112 if (BinCell->BlockId != REG_BIN_ID)
113 {
114 DbgPrint("BlockId is %.08x (should be %.08x)\n",
115 BinCell->BlockId, REG_BIN_ID);
116 assert(BinCell->BlockId == REG_BIN_ID);
117 }
118
119 //BinCell->DateModified.dwLowDateTime
120
121 //BinCell->DateModified.dwHighDateTime
122
123
124 if (BinCell->BlockSize != REG_BLOCK_SIZE)
125 {
126 DbgPrint("BlockSize is %.08x (should be %.08x)\n",
127 BinCell->BlockSize, REG_BLOCK_SIZE);
128 assert(BinCell->BlockSize == REG_BLOCK_SIZE);
129 }
130
131 }
132 }
133
134
135 VOID
136 CmiVerifyKeyCell(PKEY_CELL KeyCell)
137 {
138 if (CmiDoVerify)
139 {
140
141 assert(KeyCell);
142
143 if (KeyCell->CellSize == 0)
144 {
145 DbgPrint("CellSize is %d (must not be 0)\n",
146 KeyCell->CellSize);
147 assert(KeyCell->CellSize != 0);
148 }
149
150 if (KeyCell->Id != REG_KEY_CELL_ID)
151 {
152 DbgPrint("Id is %.08x (should be %.08x)\n",
153 KeyCell->Id, REG_KEY_CELL_ID);
154 assert(KeyCell->Id == REG_KEY_CELL_ID);
155 }
156
157 if ((KeyCell->Type != REG_KEY_CELL_TYPE)
158 && (KeyCell->Type != REG_ROOT_KEY_CELL_TYPE))
159 {
160 DbgPrint("Type is %.08x (should be %.08x or %.08x)\n",
161 KeyCell->Type, REG_KEY_CELL_TYPE, REG_ROOT_KEY_CELL_TYPE);
162 assert(FALSE);
163 }
164
165 //KeyCell->LastWriteTime;
166
167 if (KeyCell->ParentKeyOffset < 0)
168 {
169 DbgPrint("ParentKeyOffset is %d (must not be < 0)\n",
170 KeyCell->ParentKeyOffset);
171 assert(KeyCell->ParentKeyOffset >= 0);
172 }
173
174 if (KeyCell->NumberOfSubKeys < 0)
175 {
176 DbgPrint("NumberOfSubKeys is %d (must not be < 0)\n",
177 KeyCell->NumberOfSubKeys);
178 assert(KeyCell->NumberOfSubKeys >= 0);
179 }
180
181 //KeyCell->HashTableOffset;
182
183 if (KeyCell->NumberOfValues < 0)
184 {
185 DbgPrint("NumberOfValues is %d (must not be < 0)\n",
186 KeyCell->NumberOfValues);
187 assert(KeyCell->NumberOfValues >= 0);
188 }
189
190 //KeyCell->ValuesOffset = -1;
191
192 if (KeyCell->SecurityKeyOffset < 0)
193 {
194 DbgPrint("SecurityKeyOffset is %d (must not be < 0)\n",
195 KeyCell->SecurityKeyOffset);
196 assert(KeyCell->SecurityKeyOffset >= 0);
197 }
198
199 //KeyCell->ClassNameOffset = -1;
200
201 //KeyCell->NameSize
202
203 //KeyCell->ClassSize
204
205 }
206 }
207
208
209 VOID
210 CmiVerifyRootKeyCell(PKEY_CELL RootKeyCell)
211 {
212 if (CmiDoVerify)
213 {
214
215 CmiVerifyKeyCell(RootKeyCell);
216
217 if (RootKeyCell->Type != REG_ROOT_KEY_CELL_TYPE)
218 {
219 DbgPrint("Type is %.08x (should be %.08x)\n",
220 RootKeyCell->Type, REG_ROOT_KEY_CELL_TYPE);
221 assert(RootKeyCell->Type == REG_ROOT_KEY_CELL_TYPE);
222 }
223
224 }
225 }
226
227
228 VOID
229 CmiVerifyValueCell(PVALUE_CELL ValueCell)
230 {
231 if (CmiDoVerify)
232 {
233
234 assert(ValueCell);
235
236 if (ValueCell->CellSize == 0)
237 {
238 DbgPrint("CellSize is %d (must not be 0)\n",
239 ValueCell->CellSize);
240 assert(ValueCell->CellSize != 0);
241 }
242
243 if (ValueCell->Id != REG_VALUE_CELL_ID)
244 {
245 DbgPrint("Id is %.08x (should be %.08x)\n",
246 ValueCell->Id, REG_VALUE_CELL_ID);
247 assert(ValueCell->Id == REG_VALUE_CELL_ID);
248 }
249
250 //ValueCell->NameSize;
251 //ValueCell->LONG DataSize;
252 //ValueCell->DataOffset;
253 //ValueCell->ULONG DataType;
254 //ValueCell->USHORT Flags;
255 //ValueCell->USHORT Unused1;
256 //ValueCell->UCHAR Name[0];
257 }
258 }
259
260
261 VOID
262 CmiVerifyValueListCell(PVALUE_LIST_CELL ValueListCell)
263 {
264 if (CmiDoVerify)
265 {
266
267 if (ValueListCell->CellSize == 0)
268 {
269 DbgPrint("CellSize is %d (must not be 0)\n",
270 ValueListCell->CellSize);
271 assert(ValueListCell->CellSize != 0);
272 }
273
274 }
275 }
276
277
278 VOID
279 CmiVerifyKeyObject(PKEY_OBJECT KeyObject)
280 {
281 if (CmiDoVerify)
282 {
283
284 if (KeyObject->RegistryHive == NULL)
285 {
286 DbgPrint("RegistryHive is NULL (must not be NULL)\n",
287 KeyObject->RegistryHive);
288 assert(KeyObject->RegistryHive != NULL);
289 }
290
291 if (KeyObject->KeyCell == NULL)
292 {
293 DbgPrint("KeyCell is NULL (must not be NULL)\n",
294 KeyObject->KeyCell);
295 assert(KeyObject->KeyCell != NULL);
296 }
297
298 if (KeyObject->ParentKey == NULL)
299 {
300 DbgPrint("ParentKey is NULL (must not be NULL)\n",
301 KeyObject->ParentKey);
302 assert(KeyObject->ParentKey != NULL);
303 }
304
305 }
306 }
307
308
309 VOID
310 CmiVerifyHiveHeader(PHIVE_HEADER Header)
311 {
312 if (CmiDoVerify)
313 {
314
315 if (Header->BlockId != REG_HIVE_ID)
316 {
317 DbgPrint("BlockId is %.08x (must be %.08x)\n",
318 Header->BlockId,
319 REG_HIVE_ID);
320 assert(Header->BlockId == REG_HIVE_ID);
321 }
322
323 if (Header->Unused3 != 1)
324 {
325 DbgPrint("Unused3 is %.08x (must be 1)\n",
326 Header->Unused3);
327 assert(Header->Unused3 == 1);
328 }
329
330 if (Header->Unused4 != 3)
331 {
332 DbgPrint("Unused4 is %.08x (must be 3)\n",
333 Header->Unused4);
334 assert(Header->Unused4 == 3);
335 }
336
337 if (Header->Unused5 != 0)
338 {
339 DbgPrint("Unused5 is %.08x (must be 0)\n",
340 Header->Unused5);
341 assert(Header->Unused5 == 0);
342 }
343
344 if (Header->Unused6 != 1)
345 {
346 DbgPrint("Unused6 is %.08x (must be 1)\n",
347 Header->Unused6);
348 assert(Header->Unused6 == 1);
349 }
350
351 if (Header->Unused7 != 1)
352 {
353 DbgPrint("Unused7 is %.08x (must be 1)\n",
354 Header->Unused7);
355 assert(Header->Unused7 == 1);
356 }
357
358 }
359 }
360
361
362 VOID
363 CmiVerifyRegistryHive(PREGISTRY_HIVE RegistryHive)
364 {
365 if (CmiDoVerify)
366 {
367
368 CmiVerifyHiveHeader(RegistryHive->HiveHeader);
369
370 }
371 }
372
373
374 static NTSTATUS
375 CmiPopulateHive(HANDLE FileHandle)
376 {
377 IO_STATUS_BLOCK IoStatusBlock;
378 LARGE_INTEGER FileOffset;
379 PCELL_HEADER FreeCell;
380 NTSTATUS Status;
381 PHBIN BinCell;
382 PCHAR tBuf;
383 ULONG i;
384
385 tBuf = (PCHAR) ExAllocatePool(NonPagedPool, REG_BLOCK_SIZE);
386 if (tBuf == NULL)
387 return STATUS_INSUFFICIENT_RESOURCES;
388
389 BinCell = (PHBIN) tBuf;
390 FreeCell = (PCELL_HEADER) (tBuf + REG_HBIN_DATA_OFFSET);
391
392 CmiCreateDefaultBinCell(BinCell);
393
394 // The whole block is free
395 FreeCell->CellSize = REG_BLOCK_SIZE - REG_HBIN_DATA_OFFSET;
396
397 // Add free blocks so we don't need to expand
398 // the file for a while
399 for (i = 1; i < 50; i++)
400 {
401 // Block offset of this bin
402 BinCell->BlockOffset = i * REG_BLOCK_SIZE;
403
404 FileOffset.u.HighPart = 0;
405 FileOffset.u.LowPart = (i + 1) * REG_BLOCK_SIZE;
406
407 Status = NtWriteFile(FileHandle,
408 NULL,
409 NULL,
410 NULL,
411 &IoStatusBlock,
412 tBuf,
413 REG_BLOCK_SIZE,
414 &FileOffset,
415 NULL);
416 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
417 if (!NT_SUCCESS(Status))
418 {
419 ExFreePool(tBuf);
420 return Status;
421 }
422 }
423
424 ExFreePool(tBuf);
425
426 return Status;
427 }
428
429
430 static NTSTATUS
431 CmiCreateNewRegFile(HANDLE FileHandle)
432 {
433 IO_STATUS_BLOCK IoStatusBlock;
434 PCELL_HEADER FreeCell;
435 PHIVE_HEADER HiveHeader;
436 PKEY_CELL RootKeyCell;
437 NTSTATUS Status;
438 PHBIN BinCell;
439 PCHAR Buffer;
440
441 Buffer = (PCHAR) ExAllocatePool(NonPagedPool, 2 * REG_BLOCK_SIZE);
442 if (Buffer == NULL)
443 return STATUS_INSUFFICIENT_RESOURCES;
444
445 HiveHeader = (PHIVE_HEADER)Buffer;
446 BinCell = (PHBIN)((ULONG_PTR)Buffer + REG_BLOCK_SIZE);
447 RootKeyCell = (PKEY_CELL)((ULONG_PTR)Buffer + REG_BLOCK_SIZE + REG_HBIN_DATA_OFFSET);
448 FreeCell = (PCELL_HEADER)((ULONG_PTR)Buffer + REG_BLOCK_SIZE + REG_HBIN_DATA_OFFSET + sizeof(KEY_CELL));
449
450 CmiCreateDefaultHiveHeader(HiveHeader);
451 CmiCreateDefaultBinCell(BinCell);
452 CmiCreateDefaultRootKeyCell(RootKeyCell);
453
454 /* First block */
455 BinCell->BlockOffset = 0;
456
457 /* Offset to root key block */
458 HiveHeader->RootKeyCell = REG_HBIN_DATA_OFFSET;
459
460 /* The rest of the block is free */
461 FreeCell->CellSize = REG_BLOCK_SIZE - (REG_HBIN_DATA_OFFSET + sizeof(KEY_CELL));
462
463 Status = NtWriteFile(FileHandle,
464 NULL,
465 NULL,
466 NULL,
467 &IoStatusBlock,
468 Buffer,
469 2 * REG_BLOCK_SIZE,
470 0,
471 NULL);
472
473 ExFreePool(Buffer);
474
475 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
476
477 if (!NT_SUCCESS(Status))
478 {
479 return(Status);
480 }
481
482 #if 1
483 if (NT_SUCCESS(Status))
484 {
485 CmiPopulateHive(FileHandle);
486 }
487 #endif
488
489 Status = NtFlushBuffersFile(FileHandle,
490 &IoStatusBlock);
491
492 return(Status);
493 }
494
495
496 #ifdef HIVE_CHECK
497 static NTSTATUS
498 CmiCheckAndFixHive(PREGISTRY_HIVE RegistryHive)
499 {
500 OBJECT_ATTRIBUTES ObjectAttributes;
501 FILE_STANDARD_INFORMATION fsi;
502 IO_STATUS_BLOCK IoStatusBlock;
503 HANDLE HiveHandle = INVALID_HANDLE_VALUE;
504 HANDLE LogHandle = INVALID_HANDLE_VALUE;
505 PHIVE_HEADER HiveHeader = NULL;
506 PHIVE_HEADER LogHeader = NULL;
507 LARGE_INTEGER FileOffset;
508 ULONG FileSize;
509 ULONG BufferSize;
510 ULONG BitmapSize;
511 RTL_BITMAP BlockBitMap;
512 NTSTATUS Status;
513
514 DPRINT("CmiCheckAndFixHive() called\n");
515
516 /* Try to open the hive file */
517 InitializeObjectAttributes(&ObjectAttributes,
518 &RegistryHive->HiveFileName,
519 0,
520 NULL,
521 NULL);
522
523 Status = NtCreateFile(&HiveHandle,
524 FILE_READ_DATA | FILE_READ_ATTRIBUTES,
525 &ObjectAttributes,
526 &IoStatusBlock,
527 NULL,
528 FILE_ATTRIBUTE_NORMAL,
529 0,
530 FILE_OPEN,
531 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
532 NULL,
533 0);
534 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
535 {
536 return(STATUS_SUCCESS);
537 }
538 if (!NT_SUCCESS(Status))
539 {
540 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
541 return(Status);
542 }
543
544 /* Try to open the log file */
545 InitializeObjectAttributes(&ObjectAttributes,
546 &RegistryHive->LogFileName,
547 0,
548 NULL,
549 NULL);
550
551 Status = NtCreateFile(&LogHandle,
552 FILE_READ_DATA | FILE_READ_ATTRIBUTES,
553 &ObjectAttributes,
554 &IoStatusBlock,
555 NULL,
556 FILE_ATTRIBUTE_NORMAL,
557 0,
558 FILE_OPEN,
559 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
560 NULL,
561 0);
562 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
563 {
564 LogHandle = INVALID_HANDLE_VALUE;
565 }
566 else if (!NT_SUCCESS(Status))
567 {
568 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
569 NtClose(HiveHandle);
570 return(Status);
571 }
572
573 /* Allocate hive header */
574 HiveHeader = ExAllocatePool(PagedPool,
575 sizeof(HIVE_HEADER));
576 if (HiveHeader == NULL)
577 {
578 DPRINT("ExAllocatePool() failed\n");
579 Status = STATUS_INSUFFICIENT_RESOURCES;
580 goto ByeBye;
581 }
582
583 /* Read hive base block */
584 FileOffset.QuadPart = 0ULL;
585 Status = NtReadFile(HiveHandle,
586 0,
587 0,
588 0,
589 &IoStatusBlock,
590 HiveHeader,
591 sizeof(HIVE_HEADER),
592 &FileOffset,
593 0);
594 if (!NT_SUCCESS(Status))
595 {
596 DPRINT("NtReadFile() failed (Status %lx)\n", Status);
597 goto ByeBye;
598 }
599
600 if (LogHandle == INVALID_HANDLE_VALUE)
601 {
602 if (HiveHeader->Checksum != CmiCalcChecksum((PULONG)HiveHeader) ||
603 HiveHeader->UpdateCounter1 != HiveHeader->UpdateCounter2)
604 {
605 /* There is no way to fix the hive without log file - BSOD! */
606 DPRINT("Hive header inconsistent and no log file available!\n");
607 KeBugCheck(CONFIG_LIST_FAILED);
608 }
609
610 Status = STATUS_SUCCESS;
611 goto ByeBye;
612 }
613 else
614 {
615 /* Allocate hive header */
616 LogHeader = ExAllocatePool(PagedPool,
617 sizeof(HIVE_HEADER));
618 if (LogHeader == NULL)
619 {
620 DPRINT("ExAllocatePool() failed\n");
621 Status = STATUS_INSUFFICIENT_RESOURCES;
622 goto ByeBye;
623 }
624
625 /* Read log file header */
626 FileOffset.QuadPart = 0ULL;
627 Status = NtReadFile(LogHandle,
628 0,
629 0,
630 0,
631 &IoStatusBlock,
632 LogHeader,
633 sizeof(HIVE_HEADER),
634 &FileOffset,
635 0);
636 if (!NT_SUCCESS(Status))
637 {
638 DPRINT("NtReadFile() failed (Status %lx)\n", Status);
639 goto ByeBye;
640 }
641
642 /* Check log file header integrity */
643 if (LogHeader->Checksum != CmiCalcChecksum((PULONG)LogHeader) ||
644 LogHeader->UpdateCounter1 != LogHeader->UpdateCounter2)
645 {
646 if (HiveHeader->Checksum != CmiCalcChecksum((PULONG)HiveHeader) ||
647 HiveHeader->UpdateCounter1 != HiveHeader->UpdateCounter2)
648 {
649 DPRINT("Hive file and log file are inconsistent!\n");
650 KeBugCheck(CONFIG_LIST_FAILED);
651 }
652
653 /* Log file damaged but hive is okay */
654 Status = STATUS_SUCCESS;
655 goto ByeBye;
656 }
657
658 if (HiveHeader->UpdateCounter1 == HiveHeader->UpdateCounter2 &&
659 HiveHeader->UpdateCounter1 == LogHeader->UpdateCounter1)
660 {
661 /* Hive and log file are up-to-date */
662 Status = STATUS_SUCCESS;
663 goto ByeBye;
664 }
665
666 /*
667 * Hive needs an update!
668 */
669
670 /* Get file size */
671 Status = NtQueryInformationFile(LogHandle,
672 &IoStatusBlock,
673 &fsi,
674 sizeof(fsi),
675 FileStandardInformation);
676 if (!NT_SUCCESS(Status))
677 {
678 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status);
679 goto ByeBye;
680 }
681 FileSize = fsi.EndOfFile.u.LowPart;
682
683 /* Calculate bitmap and block size */
684 BitmapSize = ROUND_UP((FileSize / 4096) - 1, sizeof(ULONG) * 8) / 8;
685 BufferSize = sizeof(HIVE_HEADER) +
686 sizeof(ULONG) +
687 BitmapSize;
688 BufferSize = ROUND_UP(BufferSize, 4096);
689
690 /* Reallocate log header block */
691 ExFreePool(LogHeader);
692 LogHeader = ExAllocatePool(PagedPool,
693 BufferSize);
694 if (LogHeader == NULL)
695 {
696 DPRINT("ExAllocatePool() failed\n");
697 Status = STATUS_INSUFFICIENT_RESOURCES;
698 goto ByeBye;
699 }
700
701 /* Read log file header */
702 FileOffset.QuadPart = 0ULL;
703 Status = NtReadFile(LogHandle,
704 0,
705 0,
706 0,
707 &IoStatusBlock,
708 LogHeader,
709 BufferSize,
710 &FileOffset,
711 0);
712 if (!NT_SUCCESS(Status))
713 {
714 DPRINT("NtReadFile() failed (Status %lx)\n", Status);
715 goto ByeBye;
716 }
717
718 /* Initialize bitmap */
719 RtlInitializeBitMap(&BlockBitMap,
720 (PVOID)((ULONG)LogHeader + 4096 + sizeof(ULONG)),
721 BitmapSize * 8);
722
723 /* FIXME: Update dirty blocks */
724
725
726 /* FIXME: Update hive header */
727
728
729 Status = STATUS_SUCCESS;
730 }
731
732
733 /* Clean up the mess */
734 ByeBye:
735 if (HiveHeader != NULL)
736 ExFreePool(HiveHeader);
737
738 if (LogHeader != NULL)
739 ExFreePool(LogHeader);
740
741 if (LogHandle != INVALID_HANDLE_VALUE)
742 NtClose(LogHandle);
743
744 NtClose(HiveHandle);
745
746 return(Status);
747 }
748 #endif
749
750
751 static NTSTATUS
752 CmiInitNonVolatileRegistryHive(PREGISTRY_HIVE RegistryHive,
753 PWSTR Filename,
754 BOOLEAN CreateNew)
755 {
756 OBJECT_ATTRIBUTES ObjectAttributes;
757 FILE_STANDARD_INFORMATION fsi;
758 PCELL_HEADER FreeBlock;
759 LARGE_INTEGER FileOffset;
760 BLOCK_OFFSET BlockOffset;
761 ULONG CreateDisposition;
762 IO_STATUS_BLOCK IoSB;
763 HANDLE FileHandle;
764 ULONG FreeOffset;
765 NTSTATUS Status;
766 PHBIN tmpBin;
767 ULONG i, j;
768 ULONG BitmapSize;
769 PULONG BitmapBuffer;
770
771 DPRINT1("CmiInitNonVolatileRegistryHive(%p, %S, %d) - Entered.\n", RegistryHive, Filename, CreateNew);
772
773 /* Duplicate Filename */
774 Status = RtlCreateUnicodeString(&RegistryHive->HiveFileName,
775 Filename);
776 if (!NT_SUCCESS(Status))
777 {
778 DPRINT("RtlCreateUnicodeString() failed (Status %lx)\n", Status);
779 return(Status);
780 }
781
782 /* Create log file name */
783 RegistryHive->LogFileName.Length = (wcslen(Filename) + 4) * sizeof(WCHAR);
784 RegistryHive->LogFileName.MaximumLength = RegistryHive->LogFileName.Length + sizeof(WCHAR);
785 RegistryHive->LogFileName.Buffer = ExAllocatePool(NonPagedPool,
786 RegistryHive->LogFileName.MaximumLength);
787 if (RegistryHive->LogFileName.Buffer == NULL)
788 {
789 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
790 DPRINT("ExAllocatePool() failed\n");
791 return(STATUS_INSUFFICIENT_RESOURCES);
792 }
793 wcscpy(RegistryHive->LogFileName.Buffer,
794 Filename);
795 wcscat(RegistryHive->LogFileName.Buffer,
796 L".log");
797
798 #ifdef HIVE_CHECK
799 /* Check and eventually fix a hive */
800 Status = CmiCheckAndFixHive(RegistryHive);
801 if (!NT_SUCCESS(Status))
802 {
803 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
804 RtlFreeUnicodeString(&RegistryHive->LogFileName);
805 DPRINT1("CmiCheckAndFixHive() failed (Status %lx)\n", Status);
806 return(Status);
807 }
808 #endif
809
810 InitializeObjectAttributes(&ObjectAttributes,
811 &RegistryHive->HiveFileName,
812 0,
813 NULL,
814 NULL);
815
816 /*
817 * Note:
818 * This is a workaround to prevent a BSOD because of missing registry hives.
819 * The workaround is only useful for developers. An implementation for the
820 * ordinary user must bail out on missing registry hives because they are
821 * essential to booting and configuring the OS.
822 */
823 #if 0
824 if (CreateNew == TRUE)
825 CreateDisposition = FILE_OPEN_IF;
826 else
827 CreateDisposition = FILE_OPEN;
828 #endif
829 CreateDisposition = FILE_OPEN_IF;
830
831 Status = NtCreateFile(&FileHandle,
832 FILE_ALL_ACCESS,
833 &ObjectAttributes,
834 &IoSB,
835 NULL,
836 FILE_ATTRIBUTE_NORMAL,
837 0,
838 CreateDisposition,
839 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
840 NULL,
841 0);
842 if (!NT_SUCCESS(Status))
843 {
844 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
845 RtlFreeUnicodeString(&RegistryHive->LogFileName);
846 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
847 return(Status);
848 }
849
850 /* Note: Another workaround! See the note above! */
851 #if 0
852 if ((CreateNew) && (IoSB.Information == FILE_CREATED))
853 #endif
854 if (IoSB.Information != FILE_OPENED)
855 {
856 Status = CmiCreateNewRegFile(FileHandle);
857 if (!NT_SUCCESS(Status))
858 {
859 DPRINT("CmiCreateNewRegFile() failed (Status %lx)\n", Status);
860 NtClose(FileHandle);
861 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
862 RtlFreeUnicodeString(&RegistryHive->LogFileName);
863 return(Status);
864 }
865 }
866
867 /* Read hive header */
868 FileOffset.u.HighPart = 0;
869 FileOffset.u.LowPart = 0;
870 DPRINT(" Attempting to ZwReadFile(%d) for %d bytes into %p\n", FileHandle, sizeof(HIVE_HEADER), RegistryHive->HiveHeader);
871 Status = NtReadFile(FileHandle,
872 0,
873 0,
874 0,
875 &IoSB,
876 RegistryHive->HiveHeader,
877 sizeof(HIVE_HEADER),
878 &FileOffset,
879 0);
880 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
881 if (!NT_SUCCESS(Status))
882 {
883 DPRINT("NtReadFile() failed (Status %lx)\n", Status);
884 NtClose(FileHandle);
885 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
886 RtlFreeUnicodeString(&RegistryHive->LogFileName);
887 return Status;
888 }
889
890 /* Read update counter */
891 RegistryHive->UpdateCounter = RegistryHive->HiveHeader->UpdateCounter1;
892
893 Status = NtQueryInformationFile(FileHandle,
894 &IoSB,
895 &fsi,
896 sizeof(fsi),
897 FileStandardInformation);
898 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
899 if (!NT_SUCCESS(Status))
900 {
901 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status);
902 NtClose(FileHandle);
903 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
904 RtlFreeUnicodeString(&RegistryHive->LogFileName);
905 return Status;
906 }
907
908 RegistryHive->FileSize = fsi.EndOfFile.u.LowPart;
909 #ifdef WIN32_REGDBG
910 // assert(RegistryHive->FileSize);
911 if (RegistryHive->FileSize == 0)
912 {
913 DPRINT("CmiInitPermanentRegistryHive() - Failed, zero length hive file.\n");
914 NtClose(FileHandle);
915 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
916 RtlFreeUnicodeString(&RegistryHive->LogFileName);
917 return STATUS_INSUFFICIENT_RESOURCES;
918 }
919 #endif
920 RegistryHive->BlockListSize = (RegistryHive->FileSize / 4096) - 1;
921
922 DPRINT("Space needed for block list describing hive: 0x%x\n",
923 sizeof(PHBIN *) * RegistryHive->BlockListSize);
924
925 RegistryHive->BlockList = ExAllocatePool(NonPagedPool,
926 sizeof(PHBIN *) * RegistryHive->BlockListSize);
927
928 if (RegistryHive->BlockList == NULL)
929 {
930 ExFreePool(RegistryHive->BlockList);
931 NtClose(FileHandle);
932 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
933 RtlFreeUnicodeString(&RegistryHive->LogFileName);
934 DPRINT("CmiInitNonVolatileRegistryHive() - Failed 6.\n");
935 return STATUS_INSUFFICIENT_RESOURCES;
936 }
937
938 RegistryHive->BlockList[0] = ExAllocatePool(PagedPool,
939 RegistryHive->FileSize - 4096);
940 #ifdef WIN32_REGDBG
941 RtlZeroMemory(RegistryHive->BlockList[0], RegistryHive->FileSize - 4096);
942 #endif
943
944 if (RegistryHive->BlockList[0] == NULL)
945 {
946 ExFreePool(RegistryHive->BlockList);
947 NtClose(FileHandle);
948 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
949 RtlFreeUnicodeString(&RegistryHive->LogFileName);
950 DPRINT("CmiInitNonVolatileRegistryHive() - Failed 8.\n");
951 return STATUS_INSUFFICIENT_RESOURCES;
952 }
953
954 FileOffset.u.HighPart = 0;
955 FileOffset.u.LowPart = 4096;
956
957 DPRINT(" Attempting to NtReadFile(%d) for %d bytes into %p\n",
958 FileHandle, RegistryHive->FileSize - 4096, (PVOID)RegistryHive->BlockList[0]);
959 Status = NtReadFile(FileHandle,
960 0,
961 0,
962 0,
963 &IoSB,
964 (PVOID) RegistryHive->BlockList[0],
965 RegistryHive->FileSize - 4096,
966 &FileOffset,
967 0);
968
969 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
970
971 NtClose(FileHandle);
972
973 RegistryHive->FreeListSize = 0;
974 RegistryHive->FreeListMax = 0;
975 RegistryHive->FreeList = NULL;
976
977 BlockOffset = 0;
978 for (i = 0; i < RegistryHive->BlockListSize; i++)
979 {
980 RegistryHive->BlockList[i] = (PHBIN) (((ULONG_PTR) RegistryHive->BlockList[0]) + BlockOffset);
981 tmpBin = (PHBIN) (((ULONG_PTR) RegistryHive->BlockList[i]));
982 if (tmpBin->BlockId != REG_BIN_ID)
983 {
984 DPRINT("Bad BlockId %x, offset %x\n", tmpBin->BlockId, BlockOffset);
985 //KeBugCheck(0);
986 return STATUS_INSUFFICIENT_RESOURCES;
987 }
988
989 assertmsg((tmpBin->BlockSize % 4096) == 0, ("BlockSize (0x%.08x) must be multiplum of 4K\n", tmpBin->BlockSize));
990
991 if (tmpBin->BlockSize > 4096)
992 {
993 for (j = 1; j < tmpBin->BlockSize / 4096; j++)
994 {
995 RegistryHive->BlockList[i + j] = RegistryHive->BlockList[i];
996 }
997 i = i + j - 1;
998 }
999
1000 /* Search free blocks and add to list */
1001 FreeOffset = REG_HBIN_DATA_OFFSET;
1002 while (FreeOffset < tmpBin->BlockSize)
1003 {
1004 FreeBlock = (PCELL_HEADER) ((ULONG_PTR) RegistryHive->BlockList[i] + FreeOffset);
1005 if (FreeBlock->CellSize > 0)
1006 {
1007 Status = CmiAddFree(RegistryHive,
1008 FreeBlock,
1009 RegistryHive->BlockList[i]->BlockOffset + FreeOffset,
1010 FALSE);
1011
1012 if (!NT_SUCCESS(Status))
1013 {
1014 /* FIXME: */
1015 assert(FALSE);
1016 }
1017
1018 FreeOffset += FreeBlock->CellSize;
1019 }
1020 else
1021 {
1022 FreeOffset -= FreeBlock->CellSize;
1023 }
1024 }
1025 BlockOffset += tmpBin->BlockSize;
1026 }
1027
1028 /*
1029 * Create block bitmap and clear all bits
1030 */
1031 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
1032 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
1033 DPRINT("RegistryHive->BlockListSize: %lu\n", RegistryHive->BlockListSize);
1034 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize, BitmapSize * 8);
1035
1036 /* Allocate bitmap */
1037 BitmapBuffer = (PULONG)ExAllocatePool(PagedPool,
1038 BitmapSize);
1039 RtlInitializeBitMap(&RegistryHive->DirtyBitMap,
1040 BitmapBuffer,
1041 BitmapSize * 8);
1042
1043 /* Initialize bitmap */
1044 RtlClearAllBits(&RegistryHive->DirtyBitMap);
1045 RegistryHive->HiveDirty = FALSE;
1046
1047 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S, %d) - Finished.\n",
1048 RegistryHive, Filename, CreateNew);
1049
1050 return(STATUS_SUCCESS);
1051 }
1052
1053
1054 static NTSTATUS
1055 CmiInitVolatileRegistryHive(PREGISTRY_HIVE RegistryHive)
1056 {
1057 PKEY_CELL RootKeyCell;
1058
1059 RegistryHive->Flags |= HIVE_VOLATILE;
1060
1061 CmiCreateDefaultHiveHeader(RegistryHive->HiveHeader);
1062
1063 RootKeyCell = (PKEY_CELL) ExAllocatePool(NonPagedPool, sizeof(KEY_CELL));
1064
1065 if (RootKeyCell == NULL)
1066 return STATUS_INSUFFICIENT_RESOURCES;
1067
1068 CmiCreateDefaultRootKeyCell(RootKeyCell);
1069
1070 RegistryHive->HiveHeader->RootKeyCell = (BLOCK_OFFSET) RootKeyCell;
1071
1072 return STATUS_SUCCESS;
1073 }
1074
1075
1076 NTSTATUS
1077 CmiCreateRegistryHive(PWSTR Filename,
1078 PREGISTRY_HIVE *RegistryHive,
1079 BOOLEAN CreateNew)
1080 {
1081 PREGISTRY_HIVE Hive;
1082 NTSTATUS Status;
1083
1084 DPRINT("CmiCreateRegistryHive(Filename %S)\n", Filename);
1085
1086 *RegistryHive = NULL;
1087
1088 Hive = ExAllocatePool(NonPagedPool, sizeof(REGISTRY_HIVE));
1089 if (Hive == NULL)
1090 return(STATUS_INSUFFICIENT_RESOURCES);
1091
1092 DPRINT("Hive %x\n", Hive);
1093
1094 RtlZeroMemory(Hive, sizeof(REGISTRY_HIVE));
1095
1096 Hive->HiveHeader = (PHIVE_HEADER)
1097 ExAllocatePool(NonPagedPool, sizeof(HIVE_HEADER));
1098
1099 if (Hive->HiveHeader == NULL)
1100 {
1101 ExFreePool(Hive);
1102 return(STATUS_INSUFFICIENT_RESOURCES);
1103 }
1104
1105 if (Filename != NULL)
1106 {
1107 Status = CmiInitNonVolatileRegistryHive(Hive, Filename, CreateNew);
1108 }
1109 else
1110 {
1111 Status = CmiInitVolatileRegistryHive(Hive);
1112 }
1113
1114 if (!NT_SUCCESS(Status))
1115 {
1116 ExFreePool(Hive->HiveHeader);
1117 ExFreePool(Hive);
1118 return(Status);
1119 }
1120
1121 ExInitializeResourceLite(&Hive->HiveResource);
1122
1123 /* Acquire hive list lock exclusively */
1124 ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
1125
1126 /* Add the new hive to the hive list */
1127 InsertTailList(&CmiHiveListHead, &Hive->HiveList);
1128
1129 /* Release hive list lock */
1130 ExReleaseResourceLite(&CmiHiveListLock);
1131
1132 VERIFY_REGISTRY_HIVE(Hive);
1133
1134 *RegistryHive = Hive;
1135
1136 DPRINT("CmiCreateRegistryHive(Filename %S) - Finished.\n", Filename);
1137
1138 return(STATUS_SUCCESS);
1139 }
1140
1141
1142 NTSTATUS
1143 CmiRemoveRegistryHive(PREGISTRY_HIVE RegistryHive)
1144 {
1145 /* Acquire hive list lock exclusively */
1146 ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
1147
1148 /* Remove hive from hive list */
1149 RemoveEntryList(&RegistryHive->HiveList);
1150
1151 /* Release hive list lock */
1152 ExReleaseResourceLite(&CmiHiveListLock);
1153
1154
1155 /* FIXME: Remove attached keys and values */
1156
1157
1158 /* Release hive header */
1159 ExFreePool(RegistryHive->HiveHeader);
1160
1161 /* Release hive */
1162 ExFreePool(RegistryHive);
1163
1164 return(STATUS_SUCCESS);
1165 }
1166
1167
1168 static ULONG
1169 CmiCalcChecksum(PULONG Buffer)
1170 {
1171 ULONG Sum = 0;
1172 ULONG i;
1173
1174 for (i = 0; i < 127; i++)
1175 Sum += Buffer[i];
1176
1177 return(Sum);
1178 }
1179
1180
1181 static NTSTATUS
1182 CmiStartLogUpdate(PREGISTRY_HIVE RegistryHive)
1183 {
1184 FILE_END_OF_FILE_INFORMATION EndOfFileInfo;
1185 FILE_ALLOCATION_INFORMATION FileAllocationInfo;
1186 OBJECT_ATTRIBUTES ObjectAttributes;
1187 IO_STATUS_BLOCK IoStatusBlock;
1188 HANDLE FileHandle;
1189 LARGE_INTEGER FileOffset;
1190 ULONG BufferSize;
1191 ULONG BitmapSize;
1192 PUCHAR Buffer;
1193 PUCHAR Ptr;
1194 ULONG BlockIndex;
1195 ULONG BlockOffset;
1196 PVOID BlockPtr;
1197 NTSTATUS Status;
1198
1199 DPRINT("CmiStartLogUpdate() called\n");
1200
1201 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
1202 BufferSize = sizeof(HIVE_HEADER) +
1203 sizeof(ULONG) +
1204 BitmapSize;
1205 BufferSize = ROUND_UP(BufferSize, 4096);
1206
1207 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize, BufferSize);
1208
1209 Buffer = (PUCHAR)ExAllocatePool(NonPagedPool, BufferSize);
1210 if (Buffer == NULL)
1211 {
1212 DPRINT("ExAllocatePool() failed\n");
1213 return(STATUS_INSUFFICIENT_RESOURCES);
1214 }
1215
1216 /* Open log file for writing */
1217 InitializeObjectAttributes(&ObjectAttributes,
1218 &RegistryHive->LogFileName,
1219 0,
1220 NULL,
1221 NULL);
1222
1223 Status = NtCreateFile(&FileHandle,
1224 FILE_ALL_ACCESS,
1225 &ObjectAttributes,
1226 &IoStatusBlock,
1227 NULL,
1228 FILE_ATTRIBUTE_NORMAL,
1229 0,
1230 FILE_SUPERSEDE,
1231 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1232 NULL,
1233 0);
1234 if (!NT_SUCCESS(Status))
1235 {
1236 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1237 ExFreePool(Buffer);
1238 return(Status);
1239 }
1240
1241 /* Update firt update counter and checksum */
1242 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1243 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1244
1245 /* Copy hive header */
1246 RtlCopyMemory(Buffer,
1247 RegistryHive->HiveHeader,
1248 sizeof(HIVE_HEADER));
1249 Ptr = Buffer + sizeof(HIVE_HEADER);
1250
1251 RtlCopyMemory(Ptr,
1252 "DIRT",
1253 4);
1254 Ptr += 4;
1255 RtlCopyMemory(Ptr,
1256 RegistryHive->DirtyBitMap.Buffer,
1257 BitmapSize);
1258
1259 /* Write hive block and block bitmap */
1260 FileOffset.QuadPart = 0ULL;
1261 Status = NtWriteFile(FileHandle,
1262 NULL,
1263 NULL,
1264 NULL,
1265 &IoStatusBlock,
1266 Buffer,
1267 BufferSize,
1268 &FileOffset,
1269 NULL);
1270 if (!NT_SUCCESS(Status))
1271 {
1272 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1273 NtClose(FileHandle);
1274 ExFreePool(Buffer);
1275 return(Status);
1276 }
1277 ExFreePool(Buffer);
1278
1279 /* Write dirty blocks */
1280 FileOffset.QuadPart = (ULONGLONG)BufferSize;
1281 BlockIndex = 0;
1282 while (TRUE)
1283 {
1284 BlockIndex = RtlFindSetBits(&RegistryHive->DirtyBitMap,
1285 1,
1286 BlockIndex);
1287 if (BlockIndex == (ULONG)-1)
1288 {
1289 DPRINT("No more set bits\n");
1290 Status = STATUS_SUCCESS;
1291 break;
1292 }
1293
1294 DPRINT("Block %lu is dirty\n", BlockIndex);
1295
1296 BlockOffset = RegistryHive->BlockList[BlockIndex]->BlockOffset;
1297 DPRINT("Block offset %lx\n", BlockOffset);
1298
1299 BlockPtr = RegistryHive->BlockList[BlockIndex] + ((BlockIndex * 4096) - BlockOffset);
1300 DPRINT("BlockPtr %p\n", BlockPtr);
1301
1302 DPRINT("File offset %I64x\n", FileOffset.QuadPart);
1303
1304 /* Write hive block */
1305 Status = NtWriteFile(FileHandle,
1306 NULL,
1307 NULL,
1308 NULL,
1309 &IoStatusBlock,
1310 BlockPtr,
1311 REG_BLOCK_SIZE,
1312 &FileOffset,
1313 NULL);
1314 if (!NT_SUCCESS(Status))
1315 {
1316 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1317 NtClose(FileHandle);
1318 return(Status);
1319 }
1320
1321 BlockIndex++;
1322 FileOffset.QuadPart += 4096ULL;
1323 }
1324
1325 /* Truncate log file */
1326 EndOfFileInfo.EndOfFile.QuadPart = FileOffset.QuadPart;
1327 Status = NtSetInformationFile(FileHandle,
1328 &IoStatusBlock,
1329 &EndOfFileInfo,
1330 sizeof(FILE_END_OF_FILE_INFORMATION),
1331 FileEndOfFileInformation);
1332 if (!NT_SUCCESS(Status))
1333 {
1334 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
1335 NtClose(FileHandle);
1336 return(Status);
1337 }
1338
1339 FileAllocationInfo.AllocationSize.QuadPart = FileOffset.QuadPart;
1340 Status = NtSetInformationFile(FileHandle,
1341 &IoStatusBlock,
1342 &FileAllocationInfo,
1343 sizeof(FILE_ALLOCATION_INFORMATION),
1344 FileAllocationInformation);
1345 if (!NT_SUCCESS(Status))
1346 {
1347 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
1348 NtClose(FileHandle);
1349 return(Status);
1350 }
1351
1352 /* Flush the log file */
1353 Status = NtFlushBuffersFile(FileHandle,
1354 &IoStatusBlock);
1355 if (!NT_SUCCESS(Status))
1356 {
1357 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1358 }
1359
1360 NtClose(FileHandle);
1361
1362 return(Status);
1363 }
1364
1365
1366 static NTSTATUS
1367 CmiFinishLogUpdate(PREGISTRY_HIVE RegistryHive)
1368 {
1369 OBJECT_ATTRIBUTES ObjectAttributes;
1370 IO_STATUS_BLOCK IoStatusBlock;
1371 HANDLE FileHandle;
1372 LARGE_INTEGER FileOffset;
1373 ULONG BufferSize;
1374 ULONG BitmapSize;
1375 PUCHAR Buffer;
1376 PUCHAR Ptr;
1377 NTSTATUS Status;
1378
1379 DPRINT("CmiFinishLogUpdate() called\n");
1380
1381 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
1382 BufferSize = sizeof(HIVE_HEADER) +
1383 sizeof(ULONG) +
1384 BitmapSize;
1385 BufferSize = ROUND_UP(BufferSize, 4096);
1386
1387 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize, BufferSize);
1388
1389 Buffer = (PUCHAR)ExAllocatePool(NonPagedPool, BufferSize);
1390 if (Buffer == NULL)
1391 {
1392 DPRINT("ExAllocatePool() failed\n");
1393 return(STATUS_INSUFFICIENT_RESOURCES);
1394 }
1395
1396 /* Open log file for writing */
1397 InitializeObjectAttributes(&ObjectAttributes,
1398 &RegistryHive->LogFileName,
1399 0,
1400 NULL,
1401 NULL);
1402
1403 Status = NtCreateFile(&FileHandle,
1404 FILE_ALL_ACCESS,
1405 &ObjectAttributes,
1406 &IoStatusBlock,
1407 NULL,
1408 FILE_ATTRIBUTE_NORMAL,
1409 0,
1410 FILE_OPEN,
1411 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1412 NULL,
1413 0);
1414 if (!NT_SUCCESS(Status))
1415 {
1416 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1417 ExFreePool(Buffer);
1418 return(Status);
1419 }
1420
1421 /* Update first and second update counter and checksum */
1422 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1423 RegistryHive->HiveHeader->UpdateCounter2 = RegistryHive->UpdateCounter + 1;
1424 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1425
1426 /* Copy hive header */
1427 RtlCopyMemory(Buffer,
1428 RegistryHive->HiveHeader,
1429 sizeof(HIVE_HEADER));
1430 Ptr = Buffer + sizeof(HIVE_HEADER);
1431
1432 /* Write empty block bitmap */
1433 RtlCopyMemory(Ptr,
1434 "DIRT",
1435 4);
1436 Ptr += 4;
1437 RtlZeroMemory(Ptr,
1438 BitmapSize);
1439
1440 /* Write hive block and block bitmap */
1441 FileOffset.QuadPart = 0ULL;
1442 Status = NtWriteFile(FileHandle,
1443 NULL,
1444 NULL,
1445 NULL,
1446 &IoStatusBlock,
1447 Buffer,
1448 BufferSize,
1449 &FileOffset,
1450 NULL);
1451 if (!NT_SUCCESS(Status))
1452 {
1453 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1454 NtClose(FileHandle);
1455 ExFreePool(Buffer);
1456 return(Status);
1457 }
1458
1459 ExFreePool(Buffer);
1460
1461 /* Flush the log file */
1462 Status = NtFlushBuffersFile(FileHandle,
1463 &IoStatusBlock);
1464 if (!NT_SUCCESS(Status))
1465 {
1466 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1467 }
1468
1469 NtClose(FileHandle);
1470
1471 return(Status);
1472 }
1473
1474
1475 static NTSTATUS
1476 CmiCleanupLogUpdate(PREGISTRY_HIVE RegistryHive)
1477 {
1478 FILE_END_OF_FILE_INFORMATION EndOfFileInfo;
1479 FILE_ALLOCATION_INFORMATION FileAllocationInfo;
1480 OBJECT_ATTRIBUTES ObjectAttributes;
1481 IO_STATUS_BLOCK IoStatusBlock;
1482 HANDLE FileHandle;
1483 ULONG BufferSize;
1484 ULONG BitmapSize;
1485 NTSTATUS Status;
1486
1487 DPRINT("CmiFinishLogUpdate() called\n");
1488
1489 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
1490 BufferSize = sizeof(HIVE_HEADER) +
1491 sizeof(ULONG) +
1492 BitmapSize;
1493 BufferSize = ROUND_UP(BufferSize, 4096);
1494
1495 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize, BufferSize);
1496
1497 /* Open log file for writing */
1498 InitializeObjectAttributes(&ObjectAttributes,
1499 &RegistryHive->LogFileName,
1500 0,
1501 NULL,
1502 NULL);
1503
1504 Status = NtCreateFile(&FileHandle,
1505 FILE_ALL_ACCESS,
1506 &ObjectAttributes,
1507 &IoStatusBlock,
1508 NULL,
1509 FILE_ATTRIBUTE_NORMAL,
1510 0,
1511 FILE_OPEN,
1512 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1513 NULL,
1514 0);
1515 if (!NT_SUCCESS(Status))
1516 {
1517 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1518 return(Status);
1519 }
1520
1521 /* Truncate log file */
1522 EndOfFileInfo.EndOfFile.QuadPart = (ULONGLONG)BufferSize;
1523 Status = NtSetInformationFile(FileHandle,
1524 &IoStatusBlock,
1525 &EndOfFileInfo,
1526 sizeof(FILE_END_OF_FILE_INFORMATION),
1527 FileEndOfFileInformation);
1528 if (!NT_SUCCESS(Status))
1529 {
1530 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
1531 NtClose(FileHandle);
1532 return(Status);
1533 }
1534
1535 FileAllocationInfo.AllocationSize.QuadPart = (ULONGLONG)BufferSize;
1536 Status = NtSetInformationFile(FileHandle,
1537 &IoStatusBlock,
1538 &FileAllocationInfo,
1539 sizeof(FILE_ALLOCATION_INFORMATION),
1540 FileAllocationInformation);
1541 if (!NT_SUCCESS(Status))
1542 {
1543 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
1544 NtClose(FileHandle);
1545 return(Status);
1546 }
1547
1548 /* Flush the log file */
1549 Status = NtFlushBuffersFile(FileHandle,
1550 &IoStatusBlock);
1551 if (!NT_SUCCESS(Status))
1552 {
1553 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1554 }
1555
1556 NtClose(FileHandle);
1557
1558 return(Status);
1559 }
1560
1561
1562 static NTSTATUS
1563 CmiStartHiveUpdate(PREGISTRY_HIVE RegistryHive)
1564 {
1565 OBJECT_ATTRIBUTES ObjectAttributes;
1566 IO_STATUS_BLOCK IoStatusBlock;
1567 HANDLE FileHandle;
1568 LARGE_INTEGER FileOffset;
1569 ULONG BlockIndex;
1570 ULONG BlockOffset;
1571 PVOID BlockPtr;
1572 NTSTATUS Status;
1573
1574 DPRINT("CmiStartHiveUpdate() called\n");
1575
1576 /* Open hive for writing */
1577 InitializeObjectAttributes(&ObjectAttributes,
1578 &RegistryHive->HiveFileName,
1579 0,
1580 NULL,
1581 NULL);
1582
1583 Status = NtCreateFile(&FileHandle,
1584 FILE_ALL_ACCESS,
1585 &ObjectAttributes,
1586 &IoStatusBlock,
1587 NULL,
1588 FILE_ATTRIBUTE_NORMAL,
1589 0,
1590 FILE_OPEN,
1591 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1592 NULL,
1593 0);
1594 if (!NT_SUCCESS(Status))
1595 {
1596 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1597 return(Status);
1598 }
1599
1600 /* Update firt update counter and checksum */
1601 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1602 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1603
1604 /* Write hive block */
1605 FileOffset.QuadPart = 0ULL;
1606 Status = NtWriteFile(FileHandle,
1607 NULL,
1608 NULL,
1609 NULL,
1610 &IoStatusBlock,
1611 RegistryHive->HiveHeader,
1612 sizeof(HIVE_HEADER),
1613 &FileOffset,
1614 NULL);
1615 if (!NT_SUCCESS(Status))
1616 {
1617 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1618 NtClose(FileHandle);
1619 return(Status);
1620 }
1621
1622 BlockIndex = 0;
1623 while (TRUE)
1624 {
1625 BlockIndex = RtlFindSetBits(&RegistryHive->DirtyBitMap,
1626 1,
1627 BlockIndex);
1628 if (BlockIndex == (ULONG)-1)
1629 {
1630 DPRINT("No more set bits\n");
1631 Status = STATUS_SUCCESS;
1632 break;
1633 }
1634
1635 DPRINT("Block %lu is dirty\n", BlockIndex);
1636
1637 BlockOffset = RegistryHive->BlockList[BlockIndex]->BlockOffset;
1638 DPRINT("Block offset %lx\n", BlockOffset);
1639
1640 BlockPtr = RegistryHive->BlockList[BlockIndex] + ((BlockIndex * 4096) - BlockOffset);
1641 DPRINT("BlockPtr %p\n", BlockPtr);
1642
1643 FileOffset.QuadPart = (ULONGLONG)(BlockIndex + 1) * 4096ULL;
1644 DPRINT("File offset %I64x\n", FileOffset.QuadPart);
1645
1646
1647 /* Write hive block */
1648 Status = NtWriteFile(FileHandle,
1649 NULL,
1650 NULL,
1651 NULL,
1652 &IoStatusBlock,
1653 BlockPtr,
1654 REG_BLOCK_SIZE,
1655 &FileOffset,
1656 NULL);
1657 if (!NT_SUCCESS(Status))
1658 {
1659 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1660 NtClose(FileHandle);
1661 return(Status);
1662 }
1663
1664 BlockIndex++;
1665 }
1666
1667 Status = NtFlushBuffersFile(FileHandle,
1668 &IoStatusBlock);
1669 if (!NT_SUCCESS(Status))
1670 {
1671 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1672 }
1673
1674 NtClose(FileHandle);
1675
1676 return(Status);
1677 }
1678
1679
1680 static NTSTATUS
1681 CmiFinishHiveUpdate(PREGISTRY_HIVE RegistryHive)
1682 {
1683 OBJECT_ATTRIBUTES ObjectAttributes;
1684 IO_STATUS_BLOCK IoStatusBlock;
1685 LARGE_INTEGER FileOffset;
1686 HANDLE FileHandle;
1687 NTSTATUS Status;
1688
1689 DPRINT("CmiFinishHiveUpdate() called\n");
1690
1691 InitializeObjectAttributes(&ObjectAttributes,
1692 &RegistryHive->HiveFileName,
1693 0,
1694 NULL,
1695 NULL);
1696
1697 Status = NtCreateFile(&FileHandle,
1698 FILE_ALL_ACCESS,
1699 &ObjectAttributes,
1700 &IoStatusBlock,
1701 NULL,
1702 FILE_ATTRIBUTE_NORMAL,
1703 0,
1704 FILE_OPEN,
1705 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1706 NULL,
1707 0);
1708 if (!NT_SUCCESS(Status))
1709 {
1710 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1711 return(Status);
1712 }
1713
1714 /* Update second update counter and checksum */
1715 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1716 RegistryHive->HiveHeader->UpdateCounter2 = RegistryHive->UpdateCounter + 1;
1717 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1718
1719 /* Write hive block */
1720 FileOffset.QuadPart = 0ULL;
1721 Status = NtWriteFile(FileHandle,
1722 NULL,
1723 NULL,
1724 NULL,
1725 &IoStatusBlock,
1726 RegistryHive->HiveHeader,
1727 sizeof(HIVE_HEADER),
1728 &FileOffset,
1729 NULL);
1730 if (!NT_SUCCESS(Status))
1731 {
1732 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1733 NtClose(FileHandle);
1734 return(Status);
1735 }
1736
1737 Status = NtFlushBuffersFile(FileHandle,
1738 &IoStatusBlock);
1739 if (!NT_SUCCESS(Status))
1740 {
1741 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1742 }
1743
1744 NtClose(FileHandle);
1745
1746 return(Status);
1747 }
1748
1749
1750 NTSTATUS
1751 CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive)
1752 {
1753 NTSTATUS Status;
1754
1755 DPRINT("CmiFlushRegistryHive() called\n");
1756
1757 if (RegistryHive->HiveDirty == FALSE)
1758 {
1759 return(STATUS_SUCCESS);
1760 }
1761
1762 DPRINT("Hive '%wZ' is dirty\n",
1763 &RegistryHive->HiveFileName);
1764 DPRINT("Log file: '%wZ'\n",
1765 &RegistryHive->LogFileName);
1766
1767 /* Update hive header modification time */
1768 NtQuerySystemTime((PTIME)&RegistryHive->HiveHeader->DateModified);
1769
1770 /* Start log update */
1771 Status = CmiStartLogUpdate(RegistryHive);
1772 if (!NT_SUCCESS(Status))
1773 {
1774 DPRINT("CmiStartLogUpdate() failed (Status %lx)\n", Status);
1775 return(Status);
1776 }
1777
1778 /* Finish log update */
1779 Status = CmiFinishLogUpdate(RegistryHive);
1780 if (!NT_SUCCESS(Status))
1781 {
1782 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status);
1783 return(Status);
1784 }
1785
1786 /* Start hive update */
1787 Status = CmiStartHiveUpdate(RegistryHive);
1788 if (!NT_SUCCESS(Status))
1789 {
1790 DPRINT("CmiStartHiveUpdate() failed (Status %lx)\n", Status);
1791 return(Status);
1792 }
1793
1794 /* Finish the hive update */
1795 Status = CmiFinishHiveUpdate(RegistryHive);
1796 if (!NT_SUCCESS(Status))
1797 {
1798 DPRINT("CmiFinishHiveUpdate() failed (Status %lx)\n", Status);
1799 return(Status);
1800 }
1801
1802 /* Cleanup log update */
1803 Status = CmiCleanupLogUpdate(RegistryHive);
1804 if (!NT_SUCCESS(Status))
1805 {
1806 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status);
1807 return(Status);
1808 }
1809
1810 /* Increment hive update counter */
1811 RegistryHive->UpdateCounter++;
1812
1813 /* Clear dirty bitmap and dirty flag */
1814 RtlClearAllBits(&RegistryHive->DirtyBitMap);
1815 RegistryHive->HiveDirty = FALSE;
1816
1817 DPRINT("CmiFlushRegistryHive() done\n");
1818
1819 return(STATUS_SUCCESS);
1820 }
1821
1822
1823 ULONG
1824 CmiGetMaxNameLength(PREGISTRY_HIVE RegistryHive,
1825 PKEY_CELL KeyCell)
1826 {
1827 PHASH_TABLE_CELL HashBlock;
1828 PKEY_CELL CurSubKeyCell;
1829 ULONG MaxName;
1830 ULONG i;
1831
1832 VERIFY_KEY_CELL(KeyCell);
1833
1834 MaxName = 0;
1835 HashBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
1836 if (HashBlock == NULL)
1837 {
1838 return 0;
1839 }
1840
1841 for (i = 0; i < HashBlock->HashTableSize; i++)
1842 {
1843 if (HashBlock->Table[i].KeyOffset != 0)
1844 {
1845 CurSubKeyCell = CmiGetBlock(RegistryHive,
1846 HashBlock->Table[i].KeyOffset,
1847 NULL);
1848 if (MaxName < CurSubKeyCell->NameSize)
1849 {
1850 MaxName = CurSubKeyCell->NameSize;
1851 }
1852 CmiReleaseBlock(RegistryHive, CurSubKeyCell);
1853 }
1854 }
1855
1856 CmiReleaseBlock(RegistryHive, HashBlock);
1857
1858 return MaxName;
1859 }
1860
1861
1862 ULONG
1863 CmiGetMaxClassLength(PREGISTRY_HIVE RegistryHive,
1864 PKEY_CELL KeyCell)
1865 {
1866 PHASH_TABLE_CELL HashBlock;
1867 PKEY_CELL CurSubKeyCell;
1868 ULONG MaxClass;
1869 ULONG i;
1870
1871 VERIFY_KEY_CELL(KeyCell);
1872
1873 MaxClass = 0;
1874 HashBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
1875 if (HashBlock == NULL)
1876 {
1877 return 0;
1878 }
1879
1880 for (i = 0; i < HashBlock->HashTableSize; i++)
1881 {
1882 if (HashBlock->Table[i].KeyOffset != 0)
1883 {
1884 CurSubKeyCell = CmiGetBlock(RegistryHive,
1885 HashBlock->Table[i].KeyOffset,
1886 NULL);
1887 if (MaxClass < CurSubKeyCell->ClassSize)
1888 {
1889 MaxClass = CurSubKeyCell->ClassSize;
1890 }
1891 CmiReleaseBlock(RegistryHive, CurSubKeyCell);
1892 }
1893 }
1894
1895 CmiReleaseBlock(RegistryHive, HashBlock);
1896
1897 return MaxClass;
1898 }
1899
1900
1901 ULONG
1902 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive,
1903 PKEY_CELL KeyCell)
1904 {
1905 PVALUE_LIST_CELL ValueListCell;
1906 PVALUE_CELL CurValueCell;
1907 ULONG MaxValueName;
1908 ULONG i;
1909
1910 VERIFY_KEY_CELL(KeyCell);
1911
1912 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
1913 MaxValueName = 0;
1914 if (ValueListCell == NULL)
1915 {
1916 return 0;
1917 }
1918
1919 for (i = 0; i < KeyCell->NumberOfValues; i++)
1920 {
1921 CurValueCell = CmiGetBlock(RegistryHive,
1922 ValueListCell->Values[i],
1923 NULL);
1924 if (CurValueCell != NULL &&
1925 MaxValueName < CurValueCell->NameSize)
1926 {
1927 MaxValueName = CurValueCell->NameSize;
1928 }
1929 CmiReleaseBlock(RegistryHive, CurValueCell);
1930 }
1931
1932 CmiReleaseBlock(RegistryHive, ValueListCell);
1933
1934 return MaxValueName;
1935 }
1936
1937
1938 ULONG
1939 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive,
1940 PKEY_CELL KeyCell)
1941 {
1942 PVALUE_LIST_CELL ValueListCell;
1943 PVALUE_CELL CurValueCell;
1944 LONG MaxValueData;
1945 ULONG i;
1946
1947 VERIFY_KEY_CELL(KeyCell);
1948
1949 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
1950 MaxValueData = 0;
1951 if (ValueListCell == NULL)
1952 {
1953 return 0;
1954 }
1955
1956 for (i = 0; i < KeyCell->NumberOfValues; i++)
1957 {
1958 CurValueCell = CmiGetBlock(RegistryHive,
1959 ValueListCell->Values[i],NULL);
1960 if ((CurValueCell != NULL) &&
1961 (MaxValueData < (CurValueCell->DataSize & LONG_MAX)))
1962 {
1963 MaxValueData = CurValueCell->DataSize & LONG_MAX;
1964 }
1965 CmiReleaseBlock(RegistryHive, CurValueCell);
1966 }
1967
1968 CmiReleaseBlock(RegistryHive, ValueListCell);
1969
1970 return MaxValueData;
1971 }
1972
1973
1974 NTSTATUS
1975 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive,
1976 IN PKEY_CELL KeyCell,
1977 OUT PKEY_CELL *SubKeyCell,
1978 OUT BLOCK_OFFSET *BlockOffset,
1979 IN PCHAR KeyName,
1980 IN ACCESS_MASK DesiredAccess,
1981 IN ULONG Attributes)
1982 {
1983 PHASH_TABLE_CELL HashBlock;
1984 PKEY_CELL CurSubKeyCell;
1985 WORD KeyLength;
1986 ULONG i;
1987
1988 VERIFY_KEY_CELL(KeyCell);
1989
1990 //DPRINT("Scanning for sub key %s\n", KeyName);
1991
1992 assert(RegistryHive);
1993
1994 KeyLength = strlen(KeyName);
1995
1996 HashBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
1997 *SubKeyCell = NULL;
1998 if (HashBlock == NULL)
1999 {
2000 return STATUS_SUCCESS;
2001 }
2002
2003 for (i = 0; (i < KeyCell->NumberOfSubKeys)
2004 && (i < HashBlock->HashTableSize); i++)
2005 {
2006 if (Attributes & OBJ_CASE_INSENSITIVE)
2007 {
2008 if ((HashBlock->Table[i].KeyOffset != 0) &&
2009 (HashBlock->Table[i].KeyOffset != (ULONG_PTR)-1) &&
2010 (_strnicmp(KeyName, (PCHAR) &HashBlock->Table[i].HashValue, 4) == 0))
2011 {
2012 CurSubKeyCell = CmiGetBlock(RegistryHive,
2013 HashBlock->Table[i].KeyOffset,
2014 NULL);
2015 if ((CurSubKeyCell->NameSize == KeyLength)
2016 && (_strnicmp(KeyName, CurSubKeyCell->Name, KeyLength) == 0))
2017 {
2018 *SubKeyCell = CurSubKeyCell;
2019 *BlockOffset = HashBlock->Table[i].KeyOffset;
2020 break;
2021 }
2022 else
2023 {
2024 CmiReleaseBlock(RegistryHive, CurSubKeyCell);
2025 }
2026 }
2027 }
2028 else
2029 {
2030 if (HashBlock->Table[i].KeyOffset != 0 &&
2031 HashBlock->Table[i].KeyOffset != (ULONG_PTR) -1 &&
2032 !strncmp(KeyName, (PCHAR) &HashBlock->Table[i].HashValue, 4))
2033 {
2034 CurSubKeyCell = CmiGetBlock(RegistryHive,
2035 HashBlock->Table[i].KeyOffset,NULL);
2036 if (CurSubKeyCell->NameSize == KeyLength
2037 && !_strnicmp(KeyName, CurSubKeyCell->Name, KeyLength))
2038 {
2039 *SubKeyCell = CurSubKeyCell;
2040 *BlockOffset = HashBlock->Table[i].KeyOffset;
2041 break;
2042 }
2043 else
2044 {
2045 CmiReleaseBlock(RegistryHive, CurSubKeyCell);
2046 }
2047 }
2048 }
2049 }
2050
2051 CmiReleaseBlock(RegistryHive, HashBlock);
2052
2053 return STATUS_SUCCESS;
2054 }
2055
2056
2057 NTSTATUS
2058 CmiAddSubKey(PREGISTRY_HIVE RegistryHive,
2059 PKEY_OBJECT Parent,
2060 PKEY_OBJECT SubKey,
2061 PWSTR NewSubKeyName,
2062 USHORT NewSubKeyNameSize,
2063 ULONG TitleIndex,
2064 PUNICODE_STRING Class,
2065 ULONG CreateOptions)
2066 {
2067 PHASH_TABLE_CELL NewHashBlock;
2068 PHASH_TABLE_CELL HashBlock;
2069 BLOCK_OFFSET NKBOffset;
2070 PKEY_CELL NewKeyCell;
2071 ULONG NewBlockSize;
2072 PKEY_CELL KeyCell;
2073 NTSTATUS Status;
2074 USHORT NameSize;
2075
2076 KeyCell = Parent->KeyCell;
2077
2078 VERIFY_KEY_CELL(KeyCell);
2079
2080 if (NewSubKeyName[0] == L'\\')
2081 {
2082 NewSubKeyName++;
2083 NameSize = NewSubKeyNameSize / 2 - 1;
2084 }
2085 else
2086 {
2087 NameSize = NewSubKeyNameSize / 2;
2088 }
2089 Status = STATUS_SUCCESS;
2090
2091 NewBlockSize = sizeof(KEY_CELL) + NameSize;
2092 Status = CmiAllocateBlock(RegistryHive,
2093 (PVOID) &NewKeyCell,
2094 NewBlockSize,
2095 &NKBOffset);
2096
2097 if (NewKeyCell == NULL)
2098 {
2099 Status = STATUS_INSUFFICIENT_RESOURCES;
2100 }
2101 else
2102 {
2103 NewKeyCell->Id = REG_KEY_CELL_ID;
2104 NewKeyCell->Type = REG_KEY_CELL_TYPE;
2105 ZwQuerySystemTime((PTIME) &NewKeyCell->LastWriteTime);
2106 NewKeyCell->ParentKeyOffset = -1;
2107 NewKeyCell->NumberOfSubKeys = 0;
2108 NewKeyCell->HashTableOffset = -1;
2109 NewKeyCell->NumberOfValues = 0;
2110 NewKeyCell->ValuesOffset = -1;
2111 NewKeyCell->SecurityKeyOffset = -1;
2112 NewKeyCell->NameSize = NameSize;
2113 wcstombs(NewKeyCell->Name, NewSubKeyName, NameSize);
2114 NewKeyCell->ClassNameOffset = -1;
2115
2116 VERIFY_KEY_CELL(NewKeyCell);
2117
2118 if (Class)
2119 {
2120 PDATA_CELL pClass;
2121
2122 NewKeyCell->ClassSize = Class->Length + sizeof(WCHAR);
2123 Status = CmiAllocateBlock(RegistryHive,
2124 (PVOID) &pClass,
2125 NewKeyCell->ClassSize,
2126 &NewKeyCell->ClassNameOffset);
2127 wcsncpy((PWSTR) pClass->Data, Class->Buffer, Class->Length);
2128 ((PWSTR) (pClass->Data))[Class->Length] = 0;
2129 }
2130 }
2131
2132 if (!NT_SUCCESS(Status))
2133 {
2134 return Status;
2135 }
2136
2137 SubKey->KeyCell = NewKeyCell;
2138 SubKey->BlockOffset = NKBOffset;
2139
2140 /* Don't modify hash table if key is volatile and parent is not */
2141 if (IsVolatileHive(RegistryHive) && (!IsVolatileHive(Parent->RegistryHive)))
2142 {
2143 return(Status);
2144 }
2145
2146 if (KeyCell->HashTableOffset == (ULONG_PTR) -1)
2147 {
2148 Status = CmiAllocateHashTableBlock(RegistryHive,
2149 &HashBlock,
2150 &KeyCell->HashTableOffset,
2151 REG_INIT_HASH_TABLE_SIZE);
2152 if (!NT_SUCCESS(Status))
2153 {
2154 return(Status);
2155 }
2156 }
2157 else
2158 {
2159 HashBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
2160 if (((KeyCell->NumberOfSubKeys + 1) >= HashBlock->HashTableSize))
2161 {
2162 BLOCK_OFFSET HTOffset;
2163
2164 /* Reallocate the hash table block */
2165 Status = CmiAllocateHashTableBlock(RegistryHive,
2166 &NewHashBlock,
2167 &HTOffset,
2168 HashBlock->HashTableSize +
2169 REG_EXTEND_HASH_TABLE_SIZE);
2170 if (!NT_SUCCESS(Status))
2171 {
2172 return Status;
2173 }
2174
2175 RtlZeroMemory(&NewHashBlock->Table[0],
2176 sizeof(NewHashBlock->Table[0]) * NewHashBlock->HashTableSize);
2177 RtlCopyMemory(&NewHashBlock->Table[0],
2178 &HashBlock->Table[0],
2179 sizeof(NewHashBlock->Table[0]) * HashBlock->HashTableSize);
2180 CmiDestroyBlock(RegistryHive,
2181 HashBlock,
2182 KeyCell->HashTableOffset);
2183 KeyCell->HashTableOffset = HTOffset;
2184 HashBlock = NewHashBlock;
2185 }
2186 }
2187
2188 Status = CmiAddKeyToHashTable(RegistryHive,
2189 HashBlock,
2190 NewKeyCell,
2191 NKBOffset);
2192 if (NT_SUCCESS(Status))
2193 {
2194 KeyCell->NumberOfSubKeys++;
2195 }
2196
2197 return(Status);
2198 }
2199
2200
2201 NTSTATUS
2202 CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive,
2203 PKEY_OBJECT ParentKey,
2204 PKEY_OBJECT SubKey)
2205 {
2206 PHASH_TABLE_CELL HashBlock;
2207 PVALUE_LIST_CELL ValueList;
2208 PVALUE_CELL ValueCell;
2209 PDATA_CELL DataCell;
2210 ULONG i;
2211
2212 DPRINT("CmiRemoveSubKey() called\n");
2213
2214 /* Remove all values */
2215 if (SubKey->KeyCell->NumberOfValues != 0)
2216 {
2217 /* Get pointer to the value list cell */
2218 ValueList = CmiGetBlock(RegistryHive,
2219 SubKey->KeyCell->ValuesOffset,
2220 NULL);
2221 if (ValueList != NULL)
2222 {
2223 /* Enumerate all values */
2224 for (i = 0; i < SubKey->KeyCell->NumberOfValues; i++)
2225 {
2226 /* Get pointer to value cell */
2227 ValueCell = CmiGetBlock(RegistryHive,
2228 ValueList->Values[i],
2229 NULL);
2230 if (ValueCell != NULL)
2231 {
2232 if (ValueCell->DataSize > 4)
2233 {
2234 DataCell = CmiGetBlock(RegistryHive,
2235 ValueCell->DataOffset,
2236 NULL);
2237 if (DataCell != NULL)
2238 {
2239 /* Destroy data cell */
2240 CmiDestroyBlock(RegistryHive,
2241 DataCell,
2242 ValueCell->DataOffset);
2243 }
2244 }
2245
2246 /* Destroy value cell */
2247 CmiDestroyBlock(RegistryHive,
2248 ValueCell,
2249 ValueList->Values[i]);
2250 }
2251 }
2252 }
2253
2254 /* Destroy value list cell */
2255 CmiDestroyBlock(RegistryHive,
2256 ValueList,
2257 SubKey->KeyCell->ValuesOffset);
2258
2259 SubKey->KeyCell->NumberOfValues = 0;
2260 SubKey->KeyCell->ValuesOffset = -1;
2261 }
2262
2263 /* Remove the key from the parent key's hash block */
2264 if (ParentKey->KeyCell->HashTableOffset != (BLOCK_OFFSET) -1)
2265 {
2266 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey->KeyCell->HashTableOffset)
2267 HashBlock = CmiGetBlock(RegistryHive,
2268 ParentKey->KeyCell->HashTableOffset,
2269 NULL);
2270 DPRINT("ParentKey HashBlock %p\n", HashBlock)
2271 if (HashBlock != NULL)
2272 {
2273 CmiRemoveKeyFromHashTable(RegistryHive,
2274 HashBlock,
2275 SubKey->BlockOffset);
2276 CmiMarkBlockDirty(RegistryHive,
2277 ParentKey->KeyCell->HashTableOffset);
2278 }
2279 }
2280
2281 /* Remove the key's hash block */
2282 if (SubKey->KeyCell->HashTableOffset != (BLOCK_OFFSET) -1)
2283 {
2284 DPRINT("SubKey HashTableOffset %lx\n", SubKey->KeyCell->HashTableOffset)
2285 HashBlock = CmiGetBlock(RegistryHive,
2286 SubKey->KeyCell->HashTableOffset,
2287 NULL);
2288 DPRINT("SubKey HashBlock %p\n", HashBlock)
2289 if (HashBlock != NULL)
2290 {
2291 CmiDestroyBlock(RegistryHive,
2292 HashBlock,
2293 SubKey->KeyCell->HashTableOffset);
2294 SubKey->KeyCell->HashTableOffset = -1;
2295 }
2296 }
2297
2298 /* Decrement the number of the parent key's sub keys */
2299 if (ParentKey != NULL)
2300 {
2301 DPRINT("ParentKey %p\n", ParentKey)
2302 ParentKey->KeyCell->NumberOfSubKeys--;
2303
2304 /* Remove the parent key's hash table */
2305 if (ParentKey->KeyCell->NumberOfSubKeys == 0)
2306 {
2307 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey->KeyCell->HashTableOffset)
2308 HashBlock = CmiGetBlock(RegistryHive,
2309 ParentKey->KeyCell->HashTableOffset,
2310 NULL);
2311 DPRINT("ParentKey HashBlock %p\n", HashBlock)
2312 if (HashBlock != NULL)
2313 {
2314 CmiDestroyBlock(RegistryHive,
2315 HashBlock,
2316 ParentKey->KeyCell->HashTableOffset);
2317 ParentKey->KeyCell->HashTableOffset = -1;
2318 }
2319 }
2320
2321 NtQuerySystemTime((PTIME)&ParentKey->KeyCell->LastWriteTime);
2322 CmiMarkBlockDirty(RegistryHive,
2323 ParentKey->BlockOffset);
2324 }
2325
2326 /* Destroy key cell */
2327 CmiDestroyBlock(RegistryHive,
2328 SubKey->KeyCell,
2329 SubKey->BlockOffset);
2330 SubKey->BlockOffset = -1;
2331 SubKey->KeyCell = NULL;
2332
2333 return(STATUS_SUCCESS);
2334 }
2335
2336
2337 NTSTATUS
2338 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive,
2339 IN PKEY_CELL KeyCell,
2340 IN PUNICODE_STRING ValueName,
2341 OUT PVALUE_CELL *ValueCell,
2342 OUT BLOCK_OFFSET *VBOffset)
2343 {
2344 PVALUE_LIST_CELL ValueListCell;
2345 PVALUE_CELL CurValueCell;
2346 ULONG i;
2347
2348 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
2349
2350 *ValueCell = NULL;
2351
2352 if (ValueListCell == NULL)
2353 {
2354 DPRINT("ValueListCell is NULL\n");
2355 return STATUS_SUCCESS;
2356 }
2357
2358 VERIFY_VALUE_LIST_CELL(ValueListCell);
2359
2360 for (i = 0; i < KeyCell->NumberOfValues; i++)
2361 {
2362 CurValueCell = CmiGetBlock(RegistryHive,
2363 ValueListCell->Values[i],
2364 NULL);
2365
2366 if ((CurValueCell != NULL) &&
2367 CmiComparePackedNames(ValueName,
2368 CurValueCell->Name,
2369 CurValueCell->NameSize,
2370 CurValueCell->Flags & REG_VALUE_NAME_PACKED))
2371 {
2372 *ValueCell = CurValueCell;
2373 if (VBOffset)
2374 *VBOffset = ValueListCell->Values[i];
2375 //DPRINT("Found value %s\n", ValueName);
2376 break;
2377 }
2378 CmiReleaseBlock(RegistryHive, CurValueCell);
2379 }
2380
2381 CmiReleaseBlock(RegistryHive, ValueListCell);
2382
2383 return STATUS_SUCCESS;
2384 }
2385
2386
2387 NTSTATUS
2388 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive,
2389 IN PKEY_CELL KeyCell,
2390 IN ULONG Index,
2391 OUT PVALUE_CELL *ValueCell)
2392 {
2393 PVALUE_LIST_CELL ValueListCell;
2394 PVALUE_CELL CurValueCell;
2395
2396 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
2397
2398 *ValueCell = NULL;
2399
2400 if (ValueListCell == NULL)
2401 {
2402 return STATUS_NO_MORE_ENTRIES;
2403 }
2404
2405 VERIFY_VALUE_LIST_CELL(ValueListCell);
2406
2407 if (Index >= KeyCell->NumberOfValues)
2408 {
2409 return STATUS_NO_MORE_ENTRIES;
2410 }
2411
2412 CurValueCell = CmiGetBlock(RegistryHive,
2413 ValueListCell->Values[Index],
2414 NULL);
2415
2416 if (CurValueCell != NULL)
2417 {
2418 *ValueCell = CurValueCell;
2419 }
2420
2421 CmiReleaseBlock(RegistryHive, CurValueCell);
2422 CmiReleaseBlock(RegistryHive, ValueListCell);
2423
2424 return STATUS_SUCCESS;
2425 }
2426
2427
2428 NTSTATUS
2429 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive,
2430 IN PKEY_CELL KeyCell,
2431 IN PUNICODE_STRING ValueName,
2432 OUT PVALUE_CELL *pValueCell,
2433 OUT BLOCK_OFFSET *pVBOffset)
2434 {
2435 PVALUE_LIST_CELL NewValueListCell;
2436 PVALUE_LIST_CELL ValueListCell;
2437 PVALUE_CELL NewValueCell;
2438 BLOCK_OFFSET VLBOffset;
2439 BLOCK_OFFSET VBOffset;
2440 NTSTATUS Status;
2441
2442 Status = CmiAllocateValueCell(RegistryHive,
2443 &NewValueCell,
2444 &VBOffset,
2445 ValueName);
2446 *pVBOffset = VBOffset;
2447
2448 if (!NT_SUCCESS(Status))
2449 {
2450 return Status;
2451 }
2452
2453 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
2454
2455 if (ValueListCell == NULL)
2456 {
2457 Status = CmiAllocateBlock(RegistryHive,
2458 (PVOID) &ValueListCell,
2459 sizeof(BLOCK_OFFSET) * 3,
2460 &VLBOffset);
2461
2462 if (!NT_SUCCESS(Status))
2463 {
2464 CmiDestroyValueCell(RegistryHive, NewValueCell, VBOffset);
2465 return Status;
2466 }
2467 KeyCell->ValuesOffset = VLBOffset;
2468 }
2469 else if (KeyCell->NumberOfValues >=
2470 (((ULONG)ABS_VALUE(ValueListCell->CellSize) - 4) / sizeof(BLOCK_OFFSET)))
2471 {
2472 Status = CmiAllocateBlock(RegistryHive,
2473 (PVOID) &NewValueListCell,
2474 (KeyCell->NumberOfValues + REG_VALUE_LIST_CELL_MULTIPLE) *
2475 sizeof(BLOCK_OFFSET),
2476 &VLBOffset);
2477 if (!NT_SUCCESS(Status))
2478 {
2479 CmiDestroyValueCell(RegistryHive, NewValueCell, VBOffset);
2480 return Status;
2481 }
2482
2483 RtlCopyMemory(&NewValueListCell->Values[0],
2484 &ValueListCell->Values[0],
2485 sizeof(BLOCK_OFFSET) * KeyCell->NumberOfValues);
2486 CmiDestroyBlock(RegistryHive, ValueListCell, KeyCell->ValuesOffset);
2487 KeyCell->ValuesOffset = VLBOffset;
2488 ValueListCell = NewValueListCell;
2489 }
2490
2491 DPRINT("KeyCell->NumberOfValues %lu, ValueListCell->CellSize %lu (%lu %lx)\n",
2492 KeyCell->NumberOfValues,
2493 (ULONG)ABS_VALUE(ValueListCell->CellSize),
2494 ((ULONG)ABS_VALUE(ValueListCell->CellSize) - 4) / sizeof(BLOCK_OFFSET),
2495 ((ULONG)ABS_VALUE(ValueListCell->CellSize) - 4) / sizeof(BLOCK_OFFSET));
2496
2497 ValueListCell->Values[KeyCell->NumberOfValues] = VBOffset;
2498 KeyCell->NumberOfValues++;
2499 CmiReleaseBlock(RegistryHive, ValueListCell);
2500 CmiReleaseBlock(RegistryHive, NewValueCell);
2501 *pValueCell = NewValueCell;
2502
2503 return STATUS_SUCCESS;
2504 }
2505
2506
2507 NTSTATUS
2508 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive,
2509 IN PKEY_CELL KeyCell,
2510 IN BLOCK_OFFSET KeyCellOffset,
2511 IN PUNICODE_STRING ValueName)
2512 {
2513 PVALUE_LIST_CELL ValueListCell;
2514 PVALUE_CELL CurValueCell;
2515 ULONG i;
2516
2517 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
2518
2519 if (ValueListCell == NULL)
2520 {
2521 return STATUS_SUCCESS;
2522 }
2523
2524 VERIFY_VALUE_LIST_CELL(ValueListCell);
2525
2526 for (i = 0; i < KeyCell->NumberOfValues; i++)
2527 {
2528 CurValueCell = CmiGetBlock(RegistryHive, ValueListCell->Values[i], NULL);
2529
2530 if ((CurValueCell != NULL) &&
2531 CmiComparePackedNames(ValueName,
2532 CurValueCell->Name,
2533 CurValueCell->NameSize,
2534 CurValueCell->Flags & REG_VALUE_NAME_PACKED))
2535 {
2536 CmiDestroyValueCell(RegistryHive, CurValueCell, ValueListCell->Values[i]);
2537
2538 if ((KeyCell->NumberOfValues - 1) < i)
2539 {
2540 RtlCopyMemory(&ValueListCell->Values[i],
2541 &ValueListCell->Values[i + 1],
2542 sizeof(BLOCK_OFFSET) * (KeyCell->NumberOfValues - 1 - i));
2543 }
2544 else
2545 {
2546 RtlZeroMemory(&ValueListCell->Values[i], sizeof(BLOCK_OFFSET));
2547 }
2548
2549 KeyCell->NumberOfValues -= 1;
2550 break;
2551 }
2552 CmiReleaseBlock(RegistryHive, CurValueCell);
2553 }
2554
2555 CmiReleaseBlock(RegistryHive, ValueListCell);
2556
2557 if (KeyCell->NumberOfValues == 0)
2558 {
2559 CmiDestroyBlock(RegistryHive,
2560 ValueListCell,
2561 KeyCell->ValuesOffset);
2562 }
2563 else
2564 {
2565 CmiMarkBlockDirty(RegistryHive,
2566 KeyCell->ValuesOffset);
2567 }
2568
2569 CmiMarkBlockDirty(RegistryHive,
2570 KeyCellOffset);
2571
2572 return STATUS_SUCCESS;
2573 }
2574
2575
2576 NTSTATUS
2577 CmiAllocateHashTableBlock(IN PREGISTRY_HIVE RegistryHive,
2578 OUT PHASH_TABLE_CELL *HashBlock,
2579 OUT BLOCK_OFFSET *HBOffset,
2580 IN ULONG HashTableSize)
2581 {
2582 PHASH_TABLE_CELL NewHashBlock;
2583 ULONG NewHashSize;
2584 NTSTATUS Status;
2585
2586 Status = STATUS_SUCCESS;
2587 *HashBlock = NULL;
2588 NewHashSize = sizeof(HASH_TABLE_CELL) +
2589 (HashTableSize - 1) * sizeof(HASH_RECORD);
2590 Status = CmiAllocateBlock(RegistryHive,
2591 (PVOID*) &NewHashBlock,
2592 NewHashSize,
2593 HBOffset);
2594
2595 if ((NewHashBlock == NULL) || (!NT_SUCCESS(Status)))
2596 {
2597 Status = STATUS_INSUFFICIENT_RESOURCES;
2598 }
2599 else
2600 {
2601 NewHashBlock->Id = REG_HASH_TABLE_BLOCK_ID;
2602 NewHashBlock->HashTableSize = HashTableSize;
2603 *HashBlock = NewHashBlock;
2604 }
2605
2606 return Status;
2607 }
2608
2609
2610 PKEY_CELL
2611 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive,
2612 PHASH_TABLE_CELL HashBlock,
2613 ULONG Index)
2614 {
2615 BLOCK_OFFSET KeyOffset;
2616 PKEY_CELL KeyCell;
2617
2618 if (HashBlock == NULL)
2619 return NULL;
2620
2621 if (IsVolatileHive(RegistryHive))
2622 {
2623 KeyCell = (PKEY_CELL) HashBlock->Table[Index].KeyOffset;
2624 }
2625 else
2626 {
2627 KeyOffset = HashBlock->Table[Index].KeyOffset;
2628 KeyCell = CmiGetBlock(RegistryHive, KeyOffset, NULL);
2629 }
2630 CmiLockBlock(RegistryHive, KeyCell);
2631
2632 return KeyCell;
2633 }
2634
2635
2636 NTSTATUS
2637 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive,
2638 PHASH_TABLE_CELL HashBlock,
2639 PKEY_CELL NewKeyCell,
2640 BLOCK_OFFSET NKBOffset)
2641 {
2642 ULONG i;
2643
2644 for (i = 0; i < HashBlock->HashTableSize; i++)
2645 {
2646 if (HashBlock->Table[i].KeyOffset == 0)
2647 {
2648 HashBlock->Table[i].KeyOffset = NKBOffset;
2649 RtlCopyMemory(&HashBlock->Table[i].HashValue, NewKeyCell->Name, 4);
2650 return STATUS_SUCCESS;
2651 }
2652 }
2653
2654 return STATUS_UNSUCCESSFUL;
2655 }
2656
2657
2658 NTSTATUS
2659 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive,
2660 PHASH_TABLE_CELL HashBlock,
2661 BLOCK_OFFSET NKBOffset)
2662 {
2663 ULONG i;
2664
2665 for (i = 0; i < HashBlock->HashTableSize; i++)
2666 {
2667 if (HashBlock->Table[i].KeyOffset == NKBOffset)
2668 {
2669 HashBlock->Table[i].KeyOffset = 0;
2670 RtlZeroMemory(&HashBlock->Table[i].HashValue, 4);
2671 return STATUS_SUCCESS;
2672 }
2673 }
2674
2675 return STATUS_UNSUCCESSFUL;
2676 }
2677
2678
2679 NTSTATUS
2680 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive,
2681 PVALUE_CELL *ValueCell,
2682 BLOCK_OFFSET *VBOffset,
2683 IN PUNICODE_STRING ValueName)
2684 {
2685 PVALUE_CELL NewValueCell;
2686 NTSTATUS Status;
2687 BOOLEAN Packable;
2688 ULONG NameSize;
2689 ULONG i;
2690
2691 Status = STATUS_SUCCESS;
2692
2693 NameSize = CmiGetPackedNameLength(ValueName,
2694 &Packable);
2695
2696 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName->Length, NameSize);
2697
2698 Status = CmiAllocateBlock(RegistryHive,
2699 (PVOID*) &NewValueCell,
2700 sizeof(VALUE_CELL) + NameSize,
2701 VBOffset);
2702 if ((NewValueCell == NULL) || (!NT_SUCCESS(Status)))
2703 {
2704 Status = STATUS_INSUFFICIENT_RESOURCES;
2705 }
2706 else
2707 {
2708 NewValueCell->Id = REG_VALUE_CELL_ID;
2709 NewValueCell->NameSize = NameSize;
2710 if (Packable)
2711 {
2712 /* Pack the value name */
2713 for (i = 0; i < NameSize; i++)
2714 NewValueCell->Name[i] = (CHAR)ValueName->Buffer[i];
2715 NewValueCell->Flags |= REG_VALUE_NAME_PACKED;
2716 }
2717 else
2718 {
2719 /* Copy the value name */
2720 RtlCopyMemory(NewValueCell->Name,
2721 ValueName->Buffer,
2722 NameSize);
2723 NewValueCell->Flags = 0;
2724 }
2725 NewValueCell->DataType = 0;
2726 NewValueCell->DataSize = 0;
2727 NewValueCell->DataOffset = 0xffffffff;
2728 *ValueCell = NewValueCell;
2729 }
2730
2731 return Status;
2732 }
2733
2734
2735 NTSTATUS
2736 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive,
2737 PVALUE_CELL ValueCell,
2738 BLOCK_OFFSET VBOffset)
2739 {
2740 NTSTATUS Status;
2741 PVOID pBlock;
2742 PHBIN pBin;
2743
2744 DPRINT("CmiDestroyValueCell(Cell %p Offset %lx)\n", ValueCell, VBOffset);
2745
2746 VERIFY_VALUE_CELL(ValueCell);
2747
2748 /* Destroy the data cell */
2749 if (ValueCell->DataSize > 4)
2750 {
2751 pBlock = CmiGetBlock(RegistryHive, ValueCell->DataOffset, &pBin);
2752 Status = CmiDestroyBlock(RegistryHive, pBlock, ValueCell->DataOffset);
2753 if (!NT_SUCCESS(Status))
2754 {
2755 return Status;
2756 }
2757
2758 /* Update time of heap */
2759 if (IsPermanentHive(RegistryHive))
2760 ZwQuerySystemTime((PTIME) &pBin->DateModified);
2761 }
2762
2763 /* Destroy the value cell */
2764 Status = CmiDestroyBlock(RegistryHive, ValueCell, VBOffset);
2765
2766 /* Update time of heap */
2767 if (IsPermanentHive(RegistryHive) && CmiGetBlock(RegistryHive, VBOffset, &pBin))
2768 {
2769 ZwQuerySystemTime((PTIME) &pBin->DateModified);
2770 }
2771
2772 return Status;
2773 }
2774
2775
2776 NTSTATUS
2777 CmiAddBin(PREGISTRY_HIVE RegistryHive,
2778 PVOID *NewBlock,
2779 BLOCK_OFFSET *NewBlockOffset)
2780 {
2781 PCELL_HEADER tmpBlock;
2782 PHBIN * tmpBlockList;
2783 PHBIN tmpBin;
2784
2785 tmpBin = ExAllocatePool(PagedPool, REG_BLOCK_SIZE);
2786 if (tmpBin == NULL)
2787 {
2788 return STATUS_INSUFFICIENT_RESOURCES;
2789 }
2790
2791 tmpBin->BlockId = REG_BIN_ID;
2792 tmpBin->BlockOffset = RegistryHive->FileSize - REG_BLOCK_SIZE;
2793 RegistryHive->FileSize += REG_BLOCK_SIZE;
2794 tmpBin->BlockSize = REG_BLOCK_SIZE;
2795 tmpBin->Unused1 = 0;
2796 ZwQuerySystemTime((PTIME) &tmpBin->DateModified);
2797 tmpBin->Unused2 = 0;
2798
2799 /* Increase size of list of blocks */
2800 tmpBlockList = ExAllocatePool(NonPagedPool,
2801 sizeof(PHBIN *) * (RegistryHive->BlockListSize + 1));
2802 if (tmpBlockList == NULL)
2803 {
2804 ExFreePool(tmpBin);
2805 return STATUS_INSUFFICIENT_RESOURCES;
2806 }
2807
2808 if (RegistryHive->BlockListSize > 0)
2809 {
2810 memcpy(tmpBlockList,
2811 RegistryHive->BlockList,
2812 sizeof(PHBIN *)*(RegistryHive->BlockListSize));
2813 ExFreePool(RegistryHive->BlockList);
2814 }
2815
2816 RegistryHive->BlockList = tmpBlockList;
2817 RegistryHive->BlockList[RegistryHive->BlockListSize++] = tmpBin;
2818
2819 /* Initialize a free block in this heap : */
2820 tmpBlock = (PCELL_HEADER)((ULONG_PTR) tmpBin + REG_HBIN_DATA_OFFSET);
2821 tmpBlock->CellSize = (REG_BLOCK_SIZE - REG_HBIN_DATA_OFFSET);
2822
2823 /* Grow bitmap if necessary */
2824 if (IsVolatileHive(RegistryHive) &&
2825 (RegistryHive->BlockListSize % (sizeof(ULONG) * 8) == 0))
2826 {
2827 PULONG BitmapBuffer;
2828 ULONG BitmapSize;
2829
2830 DPRINT1("Grow hive bitmap\n");
2831
2832 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
2833 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
2834 DPRINT1("RegistryHive->BlockListSize: %lu\n", RegistryHive->BlockListSize);
2835 DPRINT1("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize, BitmapSize * 8);
2836 BitmapBuffer = (PULONG)ExAllocatePool(PagedPool,
2837 BitmapSize);
2838 RtlZeroMemory(BitmapBuffer, BitmapSize);
2839 RtlCopyMemory(BitmapBuffer,
2840 RegistryHive->DirtyBitMap.Buffer,
2841 RegistryHive->DirtyBitMap.SizeOfBitMap);
2842 ExFreePool(RegistryHive->DirtyBitMap.Buffer);
2843 RtlInitializeBitMap(&RegistryHive->DirtyBitMap,
2844 BitmapBuffer,
2845 BitmapSize * 8);
2846 }
2847
2848 *NewBlock = (PVOID) tmpBlock;
2849
2850 if (NewBlockOffset)
2851 *NewBlockOffset = tmpBin->BlockOffset + REG_HBIN_DATA_OFFSET;
2852
2853 /* FIXME: set first dword to block_offset of another free bloc */
2854
2855 /* Mark new bin dirty */
2856 CmiMarkBinDirty(RegistryHive,
2857 tmpBin->BlockOffset);
2858
2859 return STATUS_SUCCESS;
2860 }
2861
2862
2863 NTSTATUS
2864 CmiAllocateBlock(PREGISTRY_HIVE RegistryHive,
2865 PVOID *Block,
2866 LONG BlockSize,
2867 BLOCK_OFFSET * pBlockOffset)
2868 {
2869 PCELL_HEADER NewBlock;
2870 NTSTATUS Status;
2871 PHBIN pBin;
2872
2873 Status = STATUS_SUCCESS;
2874
2875 /* Round to 16 bytes multiple */
2876 BlockSize = (BlockSize + sizeof(DWORD) + 15) & 0xfffffff0;
2877
2878 /* Handle volatile hives first */
2879 if (IsVolatileHive(RegistryHive))
2880 {
2881 NewBlock = ExAllocatePool(NonPagedPool, BlockSize);
2882
2883 if (NewBlock == NULL)
2884 {
2885 Status = STATUS_INSUFFICIENT_RESOURCES;
2886 }
2887 else
2888 {
2889 RtlZeroMemory(NewBlock, BlockSize);
2890 NewBlock->CellSize = BlockSize;
2891 CmiLockBlock(RegistryHive, NewBlock);
2892 *Block = NewBlock;
2893 if (pBlockOffset)
2894 *pBlockOffset = (BLOCK_OFFSET) NewBlock;
2895 }
2896 }
2897 else
2898 {
2899 ULONG i;
2900
2901 /* first search in free blocks */
2902 NewBlock = NULL;
2903 for (i = 0; i < RegistryHive->FreeListSize; i++)
2904 {
2905 if (RegistryHive->FreeList[i]->CellSize >= BlockSize)
2906 {
2907 PVOID Temp;
2908
2909 NewBlock = RegistryHive->FreeList[i];
2910 if (pBlockOffset)
2911 *pBlockOffset = RegistryHive->FreeListOffset[i];
2912
2913 /* Update time of heap */
2914 Temp = CmiGetBlock(RegistryHive, RegistryHive->FreeListOffset[i], &pBin);
2915
2916 if (Temp)
2917 {
2918 ZwQuerySystemTime((PTIME) &pBin->DateModified);
2919 CmiMarkBlockDirty(RegistryHive, RegistryHive->FreeListOffset[i]);
2920 }
2921
2922 if ((i + 1) < RegistryHive->FreeListSize)
2923 {
2924 RtlMoveMemory(&RegistryHive->FreeList[i],
2925 &RegistryHive->FreeList[i + 1],
2926 sizeof(RegistryHive->FreeList[0])
2927 * (RegistryHive->FreeListSize - i - 1));
2928 RtlMoveMemory(&RegistryHive->FreeListOffset[i],
2929 &RegistryHive->FreeListOffset[i + 1],
2930 sizeof(RegistryHive->FreeListOffset[0])
2931 * (RegistryHive->FreeListSize - i - 1));
2932 }
2933 RegistryHive->FreeListSize--;
2934 break;
2935 }
2936 }
2937
2938 /* Need to extend hive file : */
2939 if (NewBlock == NULL)
2940 {
2941 /* Add a new block */
2942 Status = CmiAddBin(RegistryHive, (PVOID *) &NewBlock , pBlockOffset);
2943 }
2944
2945 if (NT_SUCCESS(Status))
2946 {
2947 *Block = NewBlock;
2948
2949 /* Split the block in two parts */
2950 if (NewBlock->CellSize > BlockSize)
2951 {
2952 NewBlock = (PCELL_HEADER) ((ULONG_PTR) NewBlock+BlockSize);
2953 NewBlock->CellSize = ((PCELL_HEADER) (*Block))->CellSize - BlockSize;
2954 CmiAddFree(RegistryHive,
2955 NewBlock,
2956 *pBlockOffset + BlockSize,
2957 TRUE);
2958 CmiMarkBlockDirty(RegistryHive,
2959 *pBlockOffset + BlockSize);
2960 }
2961 else if (NewBlock->CellSize < BlockSize)
2962 {
2963 return(STATUS_UNSUCCESSFUL);
2964 }
2965
2966 RtlZeroMemory(*Block, BlockSize);
2967 ((PCELL_HEADER) (*Block))->CellSize = -BlockSize;
2968 CmiLockBlock(RegistryHive, *Block);
2969 }
2970 }
2971
2972 return(Status);
2973 }
2974
2975
2976 NTSTATUS
2977 CmiDestroyBlock(PREGISTRY_HIVE RegistryHive,
2978 PVOID Block,
2979 BLOCK_OFFSET Offset)
2980 {
2981 NTSTATUS Status;
2982 PHBIN pBin;
2983
2984 Status = STATUS_SUCCESS;
2985
2986 if (IsVolatileHive(RegistryHive))
2987 {
2988 CmiReleaseBlock(RegistryHive, Block);
2989 ExFreePool(Block);
2990 }
2991 else
2992 {
2993 PCELL_HEADER pFree = Block;
2994
2995 if (pFree->CellSize < 0)
2996 pFree->CellSize = -pFree->CellSize;
2997
2998 /* Clear block (except the block size) */
2999 RtlZeroMemory(((PVOID)pFree) + sizeof(ULONG),
3000 pFree->CellSize - sizeof(ULONG));
3001
3002 /* add block to the list of free blocks */
3003 CmiAddFree(RegistryHive, Block, Offset, TRUE);
3004 CmiReleaseBlock(RegistryHive, Block);
3005
3006 /* Update time of heap */
3007 if (IsPermanentHive(RegistryHive) && CmiGetBlock(RegistryHive, Offset,&pBin))
3008 ZwQuerySystemTime((PTIME) &pBin->DateModified);
3009
3010 CmiMarkBlockDirty(RegistryHive, Offset);
3011
3012 /* FIXME: Set first dword to block_offset of another free block ? */
3013 /* FIXME: Concatenate with previous and next block if free */
3014 }
3015
3016 return Status;
3017 }
3018
3019
3020 static BOOLEAN
3021 CmiMergeFree(PREGISTRY_HIVE RegistryHive,
3022 PCELL_HEADER FreeBlock,
3023 BLOCK_OFFSET FreeOffset)
3024 {
3025 BLOCK_OFFSET BlockOffset;
3026 BLOCK_OFFSET BinOffset;
3027 ULONG BlockSize;
3028 ULONG BinSize;
3029 PHBIN Bin;
3030 ULONG i;
3031
3032 DPRINT("CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
3033 FreeBlock, FreeOffset, FreeBlock->CellSize);
3034
3035 CmiGetBlock(RegistryHive,
3036 FreeOffset,
3037 &Bin);
3038 DPRINT("Bin %p\n", Bin);
3039 if (Bin == NULL)
3040 return(FALSE);
3041
3042 BinOffset = Bin->BlockOffset;
3043 BinSize = Bin->BlockSize;
3044 DPRINT("Bin %p Offset %lx Size %lx\n", Bin, BinOffset, BinSize);
3045
3046 for (i = 0; i < RegistryHive->FreeListSize; i++)
3047 {
3048 BlockOffset = RegistryHive->FreeListOffset[i];
3049 BlockSize = RegistryHive->FreeList[i]->CellSize;
3050 if (BlockOffset > BinOffset &&
3051 BlockOffset < BinOffset + BinSize)
3052 {
3053 DPRINT("Free block: Offset %lx Size %lx\n",
3054 BlockOffset, BlockSize);
3055
3056 if ((i < (RegistryHive->FreeListSize - 1)) &&
3057 (BlockOffset + BlockSize == FreeOffset) &&
3058 (FreeOffset + FreeBlock->CellSize == RegistryHive->FreeListOffset[i + 1]))
3059 {
3060 DPRINT("Merge current block with previous and next block\n");
3061
3062 RegistryHive->FreeList[i]->CellSize +=
3063 (FreeBlock->CellSize + RegistryHive->FreeList[i + 1]->CellSize);
3064
3065 FreeBlock->CellSize = 0;
3066 RegistryHive->FreeList[i + 1]->CellSize = 0;
3067
3068
3069 if ((i + 2) < RegistryHive->FreeListSize)
3070 {
3071 RtlMoveMemory(&RegistryHive->FreeListOffset[i + 1],
3072 &RegistryHive->FreeListOffset[i + 2],
3073 sizeof(RegistryHive->FreeListOffset[0])
3074 * (RegistryHive->FreeListSize - i - 2));
3075 }
3076 RegistryHive->FreeListSize--;
3077
3078 CmiMarkBlockDirty(RegistryHive, BlockOffset);
3079
3080 return(TRUE);
3081 }
3082 else if (BlockOffset + BlockSize == FreeOffset)
3083 {
3084 DPRINT("Merge current block with previous block\n");
3085
3086 RegistryHive->FreeList[i]->CellSize += FreeBlock->CellSize;
3087 FreeBlock->CellSize = 0;
3088
3089 CmiMarkBlockDirty(RegistryHive, BlockOffset);
3090
3091 return(TRUE);
3092 }
3093 else if (FreeOffset + FreeBlock->CellSize == BlockOffset)
3094 {
3095 DPRINT("Merge current block with next block\n");
3096
3097 FreeBlock->CellSize += RegistryHive->FreeList[i]->CellSize;
3098 RegistryHive->FreeList[i]->CellSize = 0;
3099 RegistryHive->FreeList[i] = FreeBlock;
3100 RegistryHive->FreeListOffset[i] = FreeOffset;
3101
3102 CmiMarkBlockDirty(RegistryHive, FreeOffset);
3103
3104 return(TRUE);
3105 }
3106 }
3107 }
3108
3109 return(FALSE);
3110 }
3111
3112
3113 NTSTATUS
3114 CmiAddFree(PREGISTRY_HIVE RegistryHive,
3115 PCELL_HEADER FreeBlock,
3116 BLOCK_OFFSET FreeOffset,
3117 BOOLEAN MergeFreeBlocks)
3118 {
3119 PCELL_HEADER *tmpList;
3120 BLOCK_OFFSET *tmpListOffset;
3121 LONG minInd;
3122 LONG maxInd;
3123 LONG medInd;
3124
3125 assert(RegistryHive);
3126 assert(FreeBlock);
3127
3128 DPRINT("FreeBlock %.08lx FreeOffset %.08lx\n",
3129 FreeBlock, FreeOffset);
3130
3131 /* Merge free blocks */
3132 if (MergeFreeBlocks == TRUE)
3133 {
3134 if (CmiMergeFree(RegistryHive, FreeBlock, FreeOffset))
3135 return(STATUS_SUCCESS);
3136 }
3137
3138 if ((RegistryHive->FreeListSize + 1) > RegistryHive->FreeListMax)
3139 {
3140 tmpList = ExAllocatePool(PagedPool,
3141 sizeof(PCELL_HEADER) * (RegistryHive->FreeListMax + 32));
3142 if (tmpList == NULL)
3143 return STATUS_INSUFFICIENT_RESOURCES;
3144
3145 tmpListOffset = ExAllocatePool(PagedPool,
3146 sizeof(BLOCK_OFFSET *) * (RegistryHive->FreeListMax + 32));
3147
3148 if (tmpListOffset == NULL)
3149 {
3150 ExFreePool(tmpList);
3151 return STATUS_INSUFFICIENT_RESOURCES;
3152 }
3153
3154 if (RegistryHive->FreeListMax)
3155 {
3156 RtlMoveMemory(tmpList,
3157 RegistryHive->FreeList,
3158 sizeof(PCELL_HEADER) * (RegistryHive->FreeListMax));
3159 RtlMoveMemory(tmpListOffset,
3160 RegistryHive->FreeListOffset,
3161 sizeof(BLOCK_OFFSET *) * (RegistryHive->FreeListMax));
3162 ExFreePool(RegistryHive->FreeList);
3163 ExFreePool(RegistryHive->FreeListOffset);
3164 }
3165 RegistryHive->FreeList = tmpList;
3166 RegistryHive->FreeListOffset = tmpListOffset;
3167 RegistryHive->FreeListMax += 32;
3168 }
3169
3170 /* Add new offset to free list, maintaining list in ascending order */
3171 if ((RegistryHive->FreeListSize == 0)
3172 || (RegistryHive->FreeListOffset[RegistryHive->FreeListSize-1] < FreeOffset))
3173 {
3174 /* Add to end of list */
3175 RegistryHive->FreeList[RegistryHive->FreeListSize] = FreeBlock;
3176 RegistryHive->FreeListOffset[RegistryHive->FreeListSize++] = FreeOffset;
3177 }
3178 else if (RegistryHive->FreeListOffset[0] > FreeOffset)
3179 {
3180 /* Add to begin of list */
3181 RtlMoveMemory(&RegistryHive->FreeList[1],
3182 &RegistryHive->FreeList[0],
3183 sizeof(RegistryHive->FreeList[0]) * RegistryHive->FreeListSize);
3184 RtlMoveMemory(&RegistryHive->FreeListOffset[1],
3185 &RegistryHive->FreeListOffset[0],
3186 sizeof(RegistryHive->FreeListOffset[0]) * RegistryHive->FreeListSize);
3187 RegistryHive->FreeList[0] = FreeBlock;
3188 RegistryHive->FreeListOffset[0] = FreeOffset;
3189 RegistryHive->FreeListSize++;
3190 }
3191 else
3192 {
3193 /* Search where to insert */
3194 minInd = 0;
3195 maxInd = RegistryHive->FreeListSize - 1;
3196 while ((maxInd - minInd) > 1)
3197 {
3198 medInd = (minInd + maxInd) / 2;
3199 if (RegistryHive->FreeListOffset[medInd] > FreeOffset)
3200 maxInd = medInd;
3201 else
3202 minInd = medInd;
3203 }
3204
3205 /* Insert before maxInd */
3206 RtlMoveMemory(&RegistryHive->FreeList[maxInd+1],
3207 &RegistryHive->FreeList[maxInd],
3208 sizeof(RegistryHive->FreeList[0]) * (RegistryHive->FreeListSize - minInd));
3209 RtlMoveMemory(&RegistryHive->FreeListOffset[maxInd + 1],
3210 &RegistryHive->FreeListOffset[maxInd],
3211 sizeof(RegistryHive->FreeListOffset[0]) * (RegistryHive->FreeListSize-minInd));
3212 RegistryHive->FreeList[maxInd] = FreeBlock;
3213 RegistryHive->FreeListOffset[maxInd] = FreeOffset;
3214 RegistryHive->FreeListSize++;
3215 }
3216
3217 return STATUS_SUCCESS;
3218 }
3219
3220
3221 PVOID
3222 CmiGetBlock(PREGISTRY_HIVE RegistryHive,
3223 BLOCK_OFFSET BlockOffset,
3224 PHBIN * ppBin)
3225 {
3226 if (ppBin)
3227 *ppBin = NULL;
3228
3229 if ((BlockOffset == 0) || (BlockOffset == (ULONG_PTR) -1))
3230 return NULL;
3231
3232 if (IsVolatileHive(RegistryHive))
3233 {
3234 return (PVOID) BlockOffset;
3235 }
3236 else
3237 {
3238 PHBIN pBin;
3239
3240 pBin = RegistryHive->BlockList[BlockOffset / 4096];
3241 if (ppBin)
3242 *ppBin = pBin;
3243 return((PVOID)((ULONG_PTR)pBin + (BlockOffset - pBin->BlockOffset)));
3244 }
3245 }
3246
3247
3248 VOID
3249 CmiLockBlock(PREGISTRY_HIVE RegistryHive,
3250 PVOID Block)
3251 {
3252 if (IsPermanentHive(RegistryHive))
3253 {
3254 /* FIXME: Implement */
3255 }
3256 }
3257
3258
3259 VOID
3260 CmiReleaseBlock(PREGISTRY_HIVE RegistryHive,
3261 PVOID Block)
3262 {
3263 if (IsPermanentHive(RegistryHive))
3264 {
3265 /* FIXME: Implement */
3266 }
3267 }
3268
3269
3270 VOID
3271 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive,
3272 BLOCK_OFFSET BlockOffset)
3273 {
3274 PDATA_CELL Cell;
3275 LONG CellSize;
3276 ULONG BlockNumber;
3277 ULONG BlockCount;
3278
3279 if (IsVolatileHive(RegistryHive))
3280 return;
3281
3282 DPRINT("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG)BlockOffset);
3283
3284 BlockNumber = (ULONG)BlockOffset / 4096;
3285
3286 Cell = CmiGetBlock(RegistryHive,
3287 BlockOffset,
3288 NULL);
3289
3290 CellSize = Cell->CellSize;
3291 if (CellSize < 0)
3292 CellSize = -CellSize;
3293
3294 BlockCount = (ROUND_UP(BlockOffset + CellSize, 4096) - ROUND_DOWN(BlockOffset, 4096)) / 4096;
3295
3296 DPRINT(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
3297 BlockNumber,
3298 CellSize,
3299 (Cell->CellSize < 0) ? "used" : "free",
3300 BlockCount);
3301
3302 RegistryHive->HiveDirty = TRUE;
3303 RtlSetBits(&RegistryHive->DirtyBitMap,
3304 BlockNumber,
3305 BlockCount);
3306 }
3307
3308
3309 VOID
3310 CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive,
3311 BLOCK_OFFSET BinOffset)
3312 {
3313 ULONG BlockNumber;
3314 ULONG BlockCount;
3315 PHBIN Bin;
3316
3317 if (IsVolatileHive(RegistryHive))
3318 return;
3319
3320 DPRINT("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG)BinOffset);
3321
3322 BlockNumber = (ULONG)BinOffset / 4096;
3323
3324 Bin = RegistryHive->BlockList[BlockNumber];
3325
3326 BlockCount = Bin->BlockSize / 4096;
3327
3328 DPRINT(" BlockNumber %lu Size %lu BlockCount %lu\n",
3329 BlockNumber,
3330 Bin->BlockSize,
3331 BlockCount);
3332
3333 RegistryHive->HiveDirty = TRUE;
3334 RtlSetBits(&RegistryHive->DirtyBitMap,
3335 BlockNumber,
3336 BlockCount);
3337 }
3338
3339
3340 ULONG
3341 CmiGetPackedNameLength(IN PUNICODE_STRING Name,
3342 OUT PBOOLEAN Packable)
3343 {
3344 ULONG i;
3345
3346 if (Packable != NULL)
3347 *Packable = TRUE;
3348
3349 for (i = 0; i < Name->Length; i++)
3350 {
3351 if (Name->Buffer[i] > 0xFF)
3352 {
3353 if (Packable != NULL)
3354 *Packable = FALSE;
3355 return(Name->Length);
3356 }
3357 }
3358
3359 return(Name->Length / sizeof(WCHAR));
3360 }
3361
3362
3363 BOOLEAN
3364 CmiComparePackedNames(IN PUNICODE_STRING Name,
3365 IN PCHAR NameBuffer,
3366 IN USHORT NameBufferSize,
3367 IN BOOLEAN NamePacked)
3368 {
3369 PWCHAR UNameBuffer;
3370 ULONG i;
3371
3372 if (NamePacked == TRUE)
3373 {
3374 if (Name->Length != NameBufferSize * sizeof(WCHAR))
3375 return(FALSE);
3376
3377 for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
3378 {
3379 if (RtlUpcaseUnicodeChar(Name->Buffer[i]) != RtlUpcaseUnicodeChar((WCHAR)NameBuffer[i]))
3380 return(FALSE);
3381 }
3382 }
3383 else
3384 {
3385 if (Name->Length != NameBufferSize)
3386 return(FALSE);
3387
3388 UNameBuffer = (PWCHAR)NameBuffer;
3389
3390 for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
3391 {
3392 if (RtlUpcaseUnicodeChar(Name->Buffer[i]) != RtlUpcaseUnicodeChar(UNameBuffer[i]))
3393 return(FALSE);
3394 }
3395 }
3396
3397 return(TRUE);
3398 }
3399
3400
3401 VOID
3402 CmiCopyPackedName(PWCHAR NameBuffer,
3403 PCHAR PackedNameBuffer,
3404 ULONG PackedNameSize)
3405 {
3406 ULONG i;
3407
3408 for (i = 0; i < PackedNameSize; i++)
3409 NameBuffer[i] = (WCHAR)PackedNameBuffer[i];
3410 }
3411
3412 /* EOF */