4 * Copyright (C) 2001 Rex Jolliff
5 * Copyright (C) 2001 Eric Kohl
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30 #define REG_HIVE_ID 0x66676572 /* "regf" */
31 #define REG_BIN_ID 0x6e696268 /* "hbin" */
32 #define REG_KEY_CELL_ID 0x6b6e
33 #define REG_HASH_TABLE_BLOCK_ID 0x666c
34 #define REG_VALUE_CELL_ID 0x6b76
36 #define REG_BLOCK_SIZE 4096
37 #define REG_HBIN_DATA_OFFSET 32
38 #define REG_INIT_BLOCK_LIST_SIZE 32
39 #define REG_INIT_HASH_TABLE_SIZE 3
40 #define REG_EXTEND_HASH_TABLE_SIZE 4
41 #define REG_VALUE_LIST_CELL_MULTIPLE 4
44 #define ABS_VALUE(V) (((V) < 0) ? -(V) : (V))
47 /* BLOCK_OFFSET = offset in file after header block */
48 typedef ULONG BLOCK_OFFSET
, *PBLOCK_OFFSET
;
50 /* header for registry hive file : */
51 typedef struct _HIVE_HEADER
53 /* Hive identifier "regf" (0x66676572) */
62 /* When this hive file was last modified */
63 ULONGLONG DateModified
; /* FILETIME */
65 /* Registry format version ? (1?) */
68 /* Registry format version ? (3?) */
71 /* Registry format version ? (0?) */
74 /* Registry format version ? (1?) */
77 /* Offset into file from the byte after the end of the base block.
78 If the hive is volatile, this is the actual pointer to the KEY_CELL */
79 BLOCK_OFFSET RootKeyOffset
;
81 /* Size of each hive block ? */
87 /* Name of hive file */
93 /* Checksum of first 0x200 bytes */
95 } __attribute__((packed
)) HIVE_HEADER
, *PHIVE_HEADER
;
98 typedef struct _BIN_HEADER
100 /* Bin identifier "hbin" (0x6E696268) */
104 BLOCK_OFFSET BinOffset
;
106 /* Size in bytes, multiple of the block size (4KB) */
112 /* When this bin was last modified */
113 ULONGLONG DateModified
; /* FILETIME */
117 } __attribute__((packed
)) HBIN
, *PHBIN
;
120 typedef struct _CELL_HEADER
122 /* <0 if used, >0 if free */
124 } __attribute__((packed
)) CELL_HEADER
, *PCELL_HEADER
;
127 typedef struct _KEY_CELL
129 /* Size of this cell */
132 /* Key cell identifier "kn" (0x6b6e) */
138 /* Time of last flush */
139 ULONGLONG LastWriteTime
; /* FILETIME */
144 /* Block offset of parent key cell */
145 BLOCK_OFFSET ParentKeyOffset
;
147 /* Count of sub keys for the key in this key cell */
148 ULONG NumberOfSubKeys
;
153 /* Block offset of has table for FIXME: subkeys/values? */
154 BLOCK_OFFSET HashTableOffset
;
159 /* Count of values contained in this key cell */
160 ULONG NumberOfValues
;
162 /* Block offset of VALUE_LIST_CELL */
163 BLOCK_OFFSET ValueListOffset
;
165 /* Block offset of security cell */
166 BLOCK_OFFSET SecurityKeyOffset
;
168 /* Block offset of registry key class */
169 BLOCK_OFFSET ClassNameOffset
;
174 /* Size in bytes of key name */
177 /* Size of class name in bytes */
180 /* Name of key (not zero terminated) */
182 } __attribute__((packed
)) KEY_CELL
, *PKEY_CELL
;
185 /* KEY_CELL.Type constants */
186 #define REG_LINK_KEY_CELL_TYPE 0x10
187 #define REG_KEY_CELL_TYPE 0x20
188 #define REG_ROOT_KEY_CELL_TYPE 0x2c
192 // HashValue=four letters of value's name
193 typedef struct _HASH_RECORD
195 BLOCK_OFFSET KeyOffset
;
197 } __attribute__((packed
)) HASH_RECORD
, *PHASH_RECORD
;
200 typedef struct _HASH_TABLE_CELL
204 USHORT HashTableSize
;
205 HASH_RECORD Table
[0];
206 } __attribute__((packed
)) HASH_TABLE_CELL
, *PHASH_TABLE_CELL
;
209 typedef struct _VALUE_LIST_CELL
212 BLOCK_OFFSET ValueOffset
[0];
213 } __attribute__((packed
)) VALUE_LIST_CELL
, *PVALUE_LIST_CELL
;
216 typedef struct _VALUE_CELL
220 USHORT NameSize
; // length of Name
221 ULONG DataSize
; // length of datas in the cell pointed by DataOffset
222 BLOCK_OFFSET DataOffset
;// datas are here if high bit of DataSize is set
226 CHAR Name
[0]; /* warning : not zero terminated */
227 } __attribute__((packed
)) VALUE_CELL
, *PVALUE_CELL
;
229 /* VALUE_CELL.Flags constants */
230 #define REG_VALUE_NAME_PACKED 0x0001
232 /* VALUE_CELL.DataSize mask constants */
233 #define REG_DATA_SIZE_MASK 0x7FFFFFFF
234 #define REG_DATA_IN_OFFSET 0x80000000
237 typedef struct _DATA_CELL
241 } __attribute__((packed
)) DATA_CELL
, *PDATA_CELL
;
244 typedef struct _REGISTRY_HIVE
247 PHIVE_HEADER HiveHeader
;
252 PCELL_HEADER
*FreeList
;
253 BLOCK_OFFSET
*FreeListOffset
;
254 } REGISTRY_HIVE
, *PREGISTRY_HIVE
;
257 static PVOID MbBase
= NULL
;
258 static ULONG MbSize
= 0;
260 /* FUNCTIONS ****************************************************************/
263 InitMbMemory (PVOID ChunkBase
)
271 AllocateMbMemory (ULONG MemSize
)
277 MbBase
= (PVOID
)((ULONG
)MbBase
+ MemSize
);
290 GetMbAllocatedSize (VOID
)
297 CmiCreateDefaultHiveHeader (PHIVE_HEADER Header
)
300 memset (Header
, 0, REG_BLOCK_SIZE
);
301 Header
->BlockId
= REG_HIVE_ID
;
302 Header
->UpdateCounter1
= 0;
303 Header
->UpdateCounter2
= 0;
304 Header
->DateModified
= 0ULL;
310 Header
->RootKeyOffset
= -1;
311 Header
->BlockSize
= REG_BLOCK_SIZE
;
313 Header
->Checksum
= 0;
318 CmiCreateDefaultBinCell (PHBIN BinCell
)
321 memset (BinCell
, 0, REG_BLOCK_SIZE
);
322 BinCell
->HeaderId
= REG_BIN_ID
;
323 BinCell
->DateModified
= 0ULL;
324 BinCell
->BinSize
= REG_BLOCK_SIZE
;
329 CmiCreateDefaultRootKeyCell (PKEY_CELL RootKeyCell
, PCSTR KeyName
)
335 assert (RootKeyCell
);
337 BaseKeyName
= strrchr(KeyName
, '\\') + 1;
338 NameSize
= strlen(BaseKeyName
);
339 CellSize
= ROUND_UP(sizeof(KEY_CELL
) + NameSize
- 1, 16);
341 memset (RootKeyCell
, 0, CellSize
);
342 RootKeyCell
->CellSize
= -CellSize
;
343 RootKeyCell
->Id
= REG_KEY_CELL_ID
;
344 RootKeyCell
->Type
= REG_ROOT_KEY_CELL_TYPE
;
345 RootKeyCell
->LastWriteTime
= 0ULL;
346 RootKeyCell
->ParentKeyOffset
= 0;
347 RootKeyCell
->NumberOfSubKeys
= 0;
348 RootKeyCell
->HashTableOffset
= -1;
349 RootKeyCell
->NumberOfValues
= 0;
350 RootKeyCell
->ValueListOffset
= -1;
351 RootKeyCell
->SecurityKeyOffset
= 0;
352 RootKeyCell
->ClassNameOffset
= -1;
353 RootKeyCell
->NameSize
= NameSize
;
354 RootKeyCell
->ClassSize
= 0;
355 memcpy (RootKeyCell
->Name
, BaseKeyName
, NameSize
);
359 static PREGISTRY_HIVE
360 CmiCreateHive (PCSTR KeyName
)
363 PCELL_HEADER FreeCell
;
364 PKEY_CELL RootKeyCell
;
367 Hive
= (PREGISTRY_HIVE
) MmAllocateMemory (sizeof(REGISTRY_HIVE
));
372 memset (Hive
, 0, sizeof(REGISTRY_HIVE
));
374 DbgPrint((DPRINT_REGISTRY
, "Hive %x\n", Hive
));
376 /* Create hive beader (aka 'base block') */
377 Hive
->HiveHeader
= (PHIVE_HEADER
) AllocateMbMemory (REG_BLOCK_SIZE
);
378 if (Hive
->HiveHeader
== NULL
)
383 CmiCreateDefaultHiveHeader(Hive
->HiveHeader
);
384 Hive
->FileSize
= REG_BLOCK_SIZE
;
386 /* Allocate block list */
387 Hive
->BlockListSize
= 1;
388 Hive
->BlockList
= MmAllocateMemory (sizeof(PHBIN
) * Hive
->BlockListSize
);
389 if (Hive
->BlockList
== NULL
)
395 /* Allocate free cell list */
396 Hive
->FreeListMax
= 32;
397 Hive
->FreeList
= MmAllocateMemory(sizeof(PCELL_HEADER
) * Hive
->FreeListMax
);
398 if (Hive
->FreeList
== NULL
)
400 MmFreeMemory (Hive
->BlockList
);
404 Hive
->FreeListOffset
= MmAllocateMemory(sizeof(BLOCK_OFFSET
) * Hive
->FreeListMax
);
405 if (Hive
->FreeListOffset
== NULL
)
407 MmFreeMemory (Hive
->FreeList
);
408 MmFreeMemory (Hive
->BlockList
);
413 /* Allocate first bin */
414 Hive
->BlockList
[0] = (PHBIN
) AllocateMbMemory (REG_BLOCK_SIZE
);
415 if (Hive
->BlockList
[0] == NULL
)
417 MmFreeMemory (Hive
->FreeListOffset
);
418 MmFreeMemory (Hive
->FreeList
);
419 MmFreeMemory (Hive
->BlockList
);
423 Hive
->FileSize
+= REG_BLOCK_SIZE
;
426 BinCell
= (PHBIN
)Hive
->BlockList
[0];
427 CmiCreateDefaultBinCell(BinCell
);
428 BinCell
->BinOffset
= 0;
430 /* Init root key cell */
431 RootKeyCell
= (PKEY_CELL
)((ULONG
)BinCell
+ REG_HBIN_DATA_OFFSET
);
432 CmiCreateDefaultRootKeyCell(RootKeyCell
, KeyName
);
433 Hive
->HiveHeader
->RootKeyOffset
= REG_HBIN_DATA_OFFSET
;
436 FreeCell
= (PCELL_HEADER
)((ULONG
)RootKeyCell
- RootKeyCell
->CellSize
);
437 FreeCell
->CellSize
= REG_BLOCK_SIZE
- (REG_HBIN_DATA_OFFSET
- RootKeyCell
->CellSize
);
439 Hive
->FreeList
[0] = FreeCell
;
440 Hive
->FreeListOffset
[0] = REG_HBIN_DATA_OFFSET
- RootKeyCell
->CellSize
;
441 Hive
->FreeListSize
++;
448 CmiCleanupHive(PREGISTRY_HIVE Hive
, BOOL Release
)
450 MmFreeMemory (Hive
->FreeListOffset
);
451 MmFreeMemory (Hive
->FreeList
);
452 MmFreeMemory (Hive
->BlockList
);
463 CmiGetBin (PREGISTRY_HIVE Hive
,
464 BLOCK_OFFSET BlockOffset
)
468 if (BlockOffset
== (ULONG
) -1)
471 BlockIndex
= BlockOffset
/ REG_BLOCK_SIZE
;
472 if (BlockIndex
>= Hive
->BlockListSize
)
475 return Hive
->BlockList
[BlockIndex
];
480 CmiMergeFree(PREGISTRY_HIVE RegistryHive
,
481 PCELL_HEADER FreeBlock
,
482 BLOCK_OFFSET FreeOffset
)
484 BLOCK_OFFSET BlockOffset
;
485 BLOCK_OFFSET BinOffset
;
491 DbgPrint((DPRINT_REGISTRY
, "CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
492 FreeBlock
, FreeOffset
, FreeBlock
->CellSize
));
494 Bin
= CmiGetBin (RegistryHive
, FreeOffset
);
498 DbgPrint((DPRINT_REGISTRY
, "Bin %p\n", Bin
));
500 BinOffset
= Bin
->BinOffset
;
501 BinSize
= Bin
->BinSize
;
502 DbgPrint((DPRINT_REGISTRY
, "Bin %p Offset %lx Size %lx\n", Bin
, BinOffset
, BinSize
));
504 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
506 BlockOffset
= RegistryHive
->FreeListOffset
[i
];
507 BlockSize
= RegistryHive
->FreeList
[i
]->CellSize
;
508 if (BlockOffset
> BinOffset
&&
509 BlockOffset
< BinOffset
+ BinSize
)
511 DbgPrint((DPRINT_REGISTRY
, "Free block: Offset %lx Size %lx\n",
512 BlockOffset
, BlockSize
));
514 if ((i
< (RegistryHive
->FreeListSize
- 1)) &&
515 (BlockOffset
+ BlockSize
== FreeOffset
) &&
516 (FreeOffset
+ FreeBlock
->CellSize
== RegistryHive
->FreeListOffset
[i
+ 1]))
518 DbgPrint((DPRINT_REGISTRY
, "Merge current block with previous and next block\n"));
520 RegistryHive
->FreeList
[i
]->CellSize
+=
521 (FreeBlock
->CellSize
+ RegistryHive
->FreeList
[i
+ 1]->CellSize
);
523 FreeBlock
->CellSize
= 0;
524 RegistryHive
->FreeList
[i
+ 1]->CellSize
= 0;
527 if ((i
+ 2) < RegistryHive
->FreeListSize
)
529 memmove (&RegistryHive
->FreeList
[i
+ 1],
530 &RegistryHive
->FreeList
[i
+ 2],
531 sizeof(RegistryHive
->FreeList
[0])
532 * (RegistryHive
->FreeListSize
- i
- 2));
533 memmove (&RegistryHive
->FreeListOffset
[i
+ 1],
534 &RegistryHive
->FreeListOffset
[i
+ 2],
535 sizeof(RegistryHive
->FreeListOffset
[0])
536 * (RegistryHive
->FreeListSize
- i
- 2));
538 RegistryHive
->FreeListSize
--;
542 else if (BlockOffset
+ BlockSize
== FreeOffset
)
544 DbgPrint((DPRINT_REGISTRY
, "Merge current block with previous block\n"));
546 RegistryHive
->FreeList
[i
]->CellSize
+= FreeBlock
->CellSize
;
547 FreeBlock
->CellSize
= 0;
551 else if (FreeOffset
+ FreeBlock
->CellSize
== BlockOffset
)
553 DbgPrint((DPRINT_REGISTRY
, "Merge current block with next block\n"));
555 FreeBlock
->CellSize
+= RegistryHive
->FreeList
[i
]->CellSize
;
556 RegistryHive
->FreeList
[i
]->CellSize
= 0;
557 RegistryHive
->FreeList
[i
] = FreeBlock
;
558 RegistryHive
->FreeListOffset
[i
] = FreeOffset
;
570 CmiAddFree(PREGISTRY_HIVE RegistryHive
,
571 PCELL_HEADER FreeBlock
,
572 BLOCK_OFFSET FreeOffset
,
573 BOOL MergeFreeBlocks
)
575 PCELL_HEADER
*tmpList
;
576 BLOCK_OFFSET
*tmpListOffset
;
581 assert(RegistryHive
);
584 DbgPrint((DPRINT_REGISTRY
, "FreeBlock %.08lx FreeOffset %.08lx\n",
585 FreeBlock
, FreeOffset
));
587 /* Merge free blocks */
588 if (MergeFreeBlocks
== TRUE
)
590 if (CmiMergeFree(RegistryHive
, FreeBlock
, FreeOffset
))
594 if ((RegistryHive
->FreeListSize
+ 1) > RegistryHive
->FreeListMax
)
596 tmpList
= MmAllocateMemory (sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
+ 32));
602 tmpListOffset
= MmAllocateMemory (sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
+ 32));
603 if (tmpListOffset
== NULL
)
605 MmFreeMemory (tmpList
);
609 if (RegistryHive
->FreeListMax
)
612 RegistryHive
->FreeList
,
613 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
));
614 memmove (tmpListOffset
,
615 RegistryHive
->FreeListOffset
,
616 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
));
617 MmFreeMemory (RegistryHive
->FreeList
);
618 MmFreeMemory (RegistryHive
->FreeListOffset
);
620 RegistryHive
->FreeList
= tmpList
;
621 RegistryHive
->FreeListOffset
= tmpListOffset
;
622 RegistryHive
->FreeListMax
+= 32;
625 /* Add new offset to free list, maintaining list in ascending order */
626 if ((RegistryHive
->FreeListSize
== 0)
627 || (RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
-1] < FreeOffset
))
629 /* Add to end of list */
630 RegistryHive
->FreeList
[RegistryHive
->FreeListSize
] = FreeBlock
;
631 RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
++] = FreeOffset
;
633 else if (RegistryHive
->FreeListOffset
[0] > FreeOffset
)
635 /* Add to begin of list */
636 memmove (&RegistryHive
->FreeList
[1],
637 &RegistryHive
->FreeList
[0],
638 sizeof(RegistryHive
->FreeList
[0]) * RegistryHive
->FreeListSize
);
639 memmove (&RegistryHive
->FreeListOffset
[1],
640 &RegistryHive
->FreeListOffset
[0],
641 sizeof(RegistryHive
->FreeListOffset
[0]) * RegistryHive
->FreeListSize
);
642 RegistryHive
->FreeList
[0] = FreeBlock
;
643 RegistryHive
->FreeListOffset
[0] = FreeOffset
;
644 RegistryHive
->FreeListSize
++;
648 /* Search where to insert */
650 maxInd
= RegistryHive
->FreeListSize
- 1;
651 while ((maxInd
- minInd
) > 1)
653 medInd
= (minInd
+ maxInd
) / 2;
654 if (RegistryHive
->FreeListOffset
[medInd
] > FreeOffset
)
660 /* Insert before maxInd */
661 memmove (&RegistryHive
->FreeList
[maxInd
+1],
662 &RegistryHive
->FreeList
[maxInd
],
663 sizeof(RegistryHive
->FreeList
[0]) * (RegistryHive
->FreeListSize
- minInd
));
664 memmove (&RegistryHive
->FreeListOffset
[maxInd
+ 1],
665 &RegistryHive
->FreeListOffset
[maxInd
],
666 sizeof(RegistryHive
->FreeListOffset
[0]) * (RegistryHive
->FreeListSize
-minInd
));
667 RegistryHive
->FreeList
[maxInd
] = FreeBlock
;
668 RegistryHive
->FreeListOffset
[maxInd
] = FreeOffset
;
669 RegistryHive
->FreeListSize
++;
677 CmiAddBin(PREGISTRY_HIVE RegistryHive
,
680 PBLOCK_OFFSET NewBlockOffset
)
682 PCELL_HEADER tmpBlock
;
688 BinSize
= BlockCount
* REG_BLOCK_SIZE
;
689 tmpBin
= AllocateMbMemory (BinSize
);
694 memset (tmpBin
, 0, BinSize
);
696 tmpBin
->HeaderId
= REG_BIN_ID
;
697 tmpBin
->BinOffset
= RegistryHive
->FileSize
- REG_BLOCK_SIZE
;
698 RegistryHive
->FileSize
+= BinSize
;
699 tmpBin
->BinSize
= BinSize
;
701 tmpBin
->DateModified
= 0ULL;
704 /* Increase size of list of blocks */
705 BlockList
= MmAllocateMemory (sizeof(PHBIN
) * (RegistryHive
->BlockListSize
+ BlockCount
));
706 if (BlockList
== NULL
)
711 if (RegistryHive
->BlockListSize
> 0)
714 RegistryHive
->BlockList
,
715 sizeof(PHBIN
) * RegistryHive
->BlockListSize
);
716 MmFreeMemory (RegistryHive
->BlockList
);
719 RegistryHive
->BlockList
= BlockList
;
720 for (i
= 0; i
< BlockCount
; i
++)
721 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
+ i
] = tmpBin
;
722 RegistryHive
->BlockListSize
+= BlockCount
;
724 /* Initialize a free block in this heap : */
725 tmpBlock
= (PCELL_HEADER
)((ULONG
) tmpBin
+ REG_HBIN_DATA_OFFSET
);
726 tmpBlock
->CellSize
= (REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
);
728 *NewBlock
= (PVOID
) tmpBlock
;
731 *NewBlockOffset
= tmpBin
->BinOffset
+ REG_HBIN_DATA_OFFSET
;
738 CmiAllocateCell (PREGISTRY_HIVE RegistryHive
,
741 PBLOCK_OFFSET pBlockOffset
)
743 PCELL_HEADER NewBlock
;
748 /* Round to 16 bytes multiple */
749 CellSize
= ROUND_UP(CellSize
, 16);
751 /* first search in free blocks */
753 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
755 if (RegistryHive
->FreeList
[i
]->CellSize
>= CellSize
)
757 NewBlock
= RegistryHive
->FreeList
[i
];
759 *pBlockOffset
= RegistryHive
->FreeListOffset
[i
];
761 if ((i
+ 1) < RegistryHive
->FreeListSize
)
763 memmove (&RegistryHive
->FreeList
[i
],
764 &RegistryHive
->FreeList
[i
+ 1],
765 sizeof(RegistryHive
->FreeList
[0])
766 * (RegistryHive
->FreeListSize
- i
- 1));
767 memmove (&RegistryHive
->FreeListOffset
[i
],
768 &RegistryHive
->FreeListOffset
[i
+ 1],
769 sizeof(RegistryHive
->FreeListOffset
[0])
770 * (RegistryHive
->FreeListSize
- i
- 1));
772 RegistryHive
->FreeListSize
--;
777 /* Need to extend hive file */
778 if (NewBlock
== NULL
)
780 /* Add a new block */
781 if (!CmiAddBin(RegistryHive
,
782 ((sizeof(HBIN
) + CellSize
- 1) / REG_BLOCK_SIZE
) + 1,
783 (PVOID
*)(PVOID
)&NewBlock
,
790 /* Split the block in two parts */
791 if (NewBlock
->CellSize
> CellSize
)
793 NewBlock
= (PCELL_HEADER
) ((ULONG
)NewBlock
+ CellSize
);
794 NewBlock
->CellSize
= ((PCELL_HEADER
) (*Block
))->CellSize
- CellSize
;
795 CmiAddFree (RegistryHive
,
797 *pBlockOffset
+ CellSize
,
800 else if (NewBlock
->CellSize
< CellSize
)
805 memset(*Block
, 0, CellSize
);
806 ((PCELL_HEADER
)(*Block
))->CellSize
= -CellSize
;
813 CmiGetCell (PREGISTRY_HIVE Hive
,
814 BLOCK_OFFSET BlockOffset
)
819 if (BlockOffset
== (ULONG
) -1)
822 BlockIndex
= BlockOffset
/ REG_BLOCK_SIZE
;
823 if (BlockIndex
>= Hive
->BlockListSize
)
826 Bin
= Hive
->BlockList
[BlockIndex
];
830 return (PVOID
)((ULONG
)Bin
+ (BlockOffset
- Bin
->BinOffset
));
835 CmiAllocateHashTableCell (PREGISTRY_HIVE Hive
,
836 PBLOCK_OFFSET HBOffset
,
839 PHASH_TABLE_CELL HashCell
;
843 NewHashSize
= sizeof(HASH_TABLE_CELL
) +
844 (SubKeyCount
* sizeof(HASH_RECORD
));
845 Status
= CmiAllocateCell (Hive
,
847 (PVOID
*)(PVOID
)&HashCell
,
849 if ((HashCell
== NULL
) || (Status
== FALSE
))
854 HashCell
->Id
= REG_HASH_TABLE_BLOCK_ID
;
855 HashCell
->HashTableSize
= SubKeyCount
;
862 CmiAddKeyToParentHashTable (PREGISTRY_HIVE Hive
,
863 BLOCK_OFFSET ParentKeyOffset
,
864 PKEY_CELL NewKeyCell
,
865 BLOCK_OFFSET NKBOffset
)
867 PHASH_TABLE_CELL HashBlock
;
868 PKEY_CELL ParentKeyCell
;
871 ParentKeyCell
= CmiGetCell (Hive
, ParentKeyOffset
);
872 if (ParentKeyCell
== NULL
)
874 DbgPrint((DPRINT_REGISTRY
, "CmiGetCell() failed\n"));
878 HashBlock
=CmiGetCell (Hive
, ParentKeyCell
->HashTableOffset
);
879 if (HashBlock
== NULL
)
881 DbgPrint((DPRINT_REGISTRY
, "CmiGetCell() failed\n"));
885 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
887 if (HashBlock
->Table
[i
].KeyOffset
== 0)
889 HashBlock
->Table
[i
].KeyOffset
= NKBOffset
;
890 memcpy (&HashBlock
->Table
[i
].HashValue
,
893 ParentKeyCell
->NumberOfSubKeys
++;
903 CmiAllocateValueListCell (PREGISTRY_HIVE Hive
,
904 PBLOCK_OFFSET ValueListOffset
,
907 PVALUE_LIST_CELL ValueListCell
;
911 ValueListSize
= sizeof(VALUE_LIST_CELL
) +
912 (ValueCount
* sizeof(BLOCK_OFFSET
));
913 Status
= CmiAllocateCell (Hive
,
915 (PVOID
)&ValueListCell
,
917 if ((ValueListCell
== NULL
) || (Status
== FALSE
))
919 DbgPrint((DPRINT_REGISTRY
, "CmiAllocateCell() failed\n"));
928 CmiAllocateValueCell(PREGISTRY_HIVE Hive
,
929 PVALUE_CELL
*ValueCell
,
930 BLOCK_OFFSET
*ValueCellOffset
,
933 PVALUE_CELL NewValueCell
;
937 NameSize
= (ValueName
== NULL
) ? 0 : strlen (ValueName
);
938 Status
= CmiAllocateCell (Hive
,
939 sizeof(VALUE_CELL
) + NameSize
,
940 (PVOID
*)(PVOID
)&NewValueCell
,
942 if ((NewValueCell
== NULL
) || (Status
== FALSE
))
944 DbgPrint((DPRINT_REGISTRY
, "CmiAllocateCell() failed\n"));
948 NewValueCell
->Id
= REG_VALUE_CELL_ID
;
949 NewValueCell
->NameSize
= NameSize
;
952 memcpy (NewValueCell
->Name
,
955 NewValueCell
->Flags
= REG_VALUE_NAME_PACKED
;
957 NewValueCell
->DataType
= 0;
958 NewValueCell
->DataSize
= 0;
959 NewValueCell
->DataOffset
= -1;
961 *ValueCell
= NewValueCell
;
968 CmiAddValueToKeyValueList(PREGISTRY_HIVE Hive
,
969 BLOCK_OFFSET KeyCellOffset
,
970 BLOCK_OFFSET ValueCellOffset
)
972 PVALUE_LIST_CELL ValueListCell
;
975 KeyCell
= CmiGetCell (Hive
, KeyCellOffset
);
978 DbgPrint((DPRINT_REGISTRY
, "CmiGetCell() failed\n"));
982 ValueListCell
= CmiGetCell (Hive
, KeyCell
->ValueListOffset
);
983 if (ValueListCell
== NULL
)
985 DbgPrint((DPRINT_REGISTRY
, "CmiGetCell() failed\n"));
989 ValueListCell
->ValueOffset
[KeyCell
->NumberOfValues
] = ValueCellOffset
;
990 KeyCell
->NumberOfValues
++;
997 memexpand (PWCHAR Dst
,
1003 for (i
= 0; i
< Length
; i
++)
1004 Dst
[i
] = (WCHAR
)Src
[i
];
1009 CmiExportValue (PREGISTRY_HIVE Hive
,
1010 BLOCK_OFFSET KeyCellOffset
,
1014 BLOCK_OFFSET ValueCellOffset
;
1015 BLOCK_OFFSET DataCellOffset
;
1016 PVALUE_CELL ValueCell
;
1017 PDATA_CELL DataCell
;
1022 BOOL Expand
= FALSE
;
1024 DbgPrint((DPRINT_REGISTRY
, "CmiExportValue('%s') called\n",
1025 (Value
== NULL
) ? "<default>" : (PCHAR
)Value
->Name
));
1026 DbgPrint((DPRINT_REGISTRY
, "DataSize %lu\n",
1027 (Value
== NULL
) ? Key
->DataSize
: Value
->DataSize
));
1029 /* Allocate value cell */
1030 if (!CmiAllocateValueCell(Hive
, &ValueCell
, &ValueCellOffset
, (Value
== NULL
) ? NULL
: Value
->Name
))
1035 if (!CmiAddValueToKeyValueList(Hive
, KeyCellOffset
, ValueCellOffset
))
1042 DataType
= Key
->DataType
;
1043 SrcDataSize
= Key
->DataSize
;
1048 DataType
= Value
->DataType
;
1049 SrcDataSize
= Value
->DataSize
;
1053 DstDataSize
= SrcDataSize
;
1054 if (DataType
== REG_SZ
||
1055 DataType
== REG_EXPAND_SZ
||
1056 DataType
== REG_MULTI_SZ
)
1058 DstDataSize
*= sizeof(WCHAR
);
1062 if (DstDataSize
<= sizeof(BLOCK_OFFSET
))
1064 ValueCell
->DataSize
= DstDataSize
| REG_DATA_IN_OFFSET
;
1065 ValueCell
->DataType
= DataType
;
1068 memexpand ((PWCHAR
)&ValueCell
->DataOffset
,
1074 memcpy (&ValueCell
->DataOffset
,
1081 /* Allocate data cell */
1082 if (!CmiAllocateCell (Hive
,
1083 sizeof(CELL_HEADER
) + DstDataSize
,
1084 (PVOID
*)(PVOID
)&DataCell
,
1090 ValueCell
->DataOffset
= DataCellOffset
;
1091 ValueCell
->DataSize
= DstDataSize
;
1092 ValueCell
->DataType
= DataType
;
1096 if (SrcDataSize
<= sizeof(BLOCK_OFFSET
))
1098 memexpand ((PWCHAR
)DataCell
->Data
,
1104 memexpand ((PWCHAR
)DataCell
->Data
,
1111 memcpy (DataCell
->Data
,
1122 CmiExportSubKey (PREGISTRY_HIVE Hive
,
1123 BLOCK_OFFSET ParentKeyOffset
,
1124 FRLDRHKEY ParentKey
,
1127 BLOCK_OFFSET NKBOffset
;
1128 PKEY_CELL NewKeyCell
;
1136 DbgPrint((DPRINT_REGISTRY
, "CmiExportSubKey('%s') called\n", Key
->Name
));
1138 /* Don't export links */
1139 if (Key
->DataType
== REG_LINK
)
1142 /* Allocate key cell */
1143 KeyCellSize
= sizeof(KEY_CELL
) + Key
->NameSize
- 1;
1144 if (!CmiAllocateCell (Hive
, KeyCellSize
, (PVOID
)&NewKeyCell
, &NKBOffset
))
1146 DbgPrint((DPRINT_REGISTRY
, "CmiAllocateCell() failed\n"));
1150 /* Initialize key cell */
1151 NewKeyCell
->Id
= REG_KEY_CELL_ID
;
1152 NewKeyCell
->Type
= REG_KEY_CELL_TYPE
;
1153 NewKeyCell
->LastWriteTime
= 0ULL;
1154 NewKeyCell
->ParentKeyOffset
= ParentKeyOffset
;
1155 NewKeyCell
->NumberOfSubKeys
= 0;
1156 NewKeyCell
->HashTableOffset
= -1;
1157 NewKeyCell
->NumberOfValues
= 0;
1158 NewKeyCell
->ValueListOffset
= -1;
1159 NewKeyCell
->SecurityKeyOffset
= -1;
1160 NewKeyCell
->ClassNameOffset
= -1;
1161 NewKeyCell
->NameSize
= Key
->NameSize
- 1;
1162 NewKeyCell
->ClassSize
= 0;
1163 memcpy (NewKeyCell
->Name
,
1167 /* Add key cell to the parent key's hash table */
1168 if (!CmiAddKeyToParentHashTable (Hive
,
1173 DbgPrint((DPRINT_REGISTRY
, "CmiAddKeyToParentHashTable() failed\n"));
1177 ValueCount
= RegGetValueCount (Key
);
1178 DbgPrint((DPRINT_REGISTRY
, "ValueCount: %u\n", ValueCount
));
1181 /* Allocate value list cell */
1182 if (!CmiAllocateValueListCell (Hive
,
1183 &NewKeyCell
->ValueListOffset
,
1186 DbgPrint((DPRINT_REGISTRY
, "CmiAllocateValueListCell() failed\n"));
1190 if (Key
->DataSize
!= 0)
1192 if (!CmiExportValue (Hive
, NKBOffset
, Key
, NULL
))
1196 /* Enumerate values */
1197 Entry
= Key
->ValueList
.Flink
;
1198 while (Entry
!= &Key
->ValueList
)
1200 Value
= CONTAINING_RECORD(Entry
,
1204 if (!CmiExportValue (Hive
, NKBOffset
, Key
, Value
))
1207 Entry
= Entry
->Flink
;
1211 SubKeyCount
= RegGetSubKeyCount (Key
);
1212 DbgPrint((DPRINT_REGISTRY
, "SubKeyCount: %u\n", SubKeyCount
));
1213 if (SubKeyCount
> 0)
1215 /* Allocate hash table cell */
1216 if (!CmiAllocateHashTableCell (Hive
,
1217 &NewKeyCell
->HashTableOffset
,
1220 DbgPrint((DPRINT_REGISTRY
, "CmiAllocateHashTableCell() failed\n"));
1224 /* Enumerate subkeys */
1225 Entry
= Key
->SubKeyList
.Flink
;
1226 while (Entry
!= &Key
->SubKeyList
)
1228 SubKey
= CONTAINING_RECORD(Entry
,
1232 if (!CmiExportSubKey (Hive
, NKBOffset
, Key
, SubKey
))
1235 Entry
= Entry
->Flink
;
1244 CmiCalcHiveChecksum (PREGISTRY_HIVE Hive
)
1250 Buffer
= (ULONG
*)Hive
->HiveHeader
;
1252 for (i
= 0; i
< 127; i
++)
1255 Hive
->HiveHeader
->Checksum
= Sum
;
1260 CmiExportHive (PREGISTRY_HIVE Hive
,
1271 DbgPrint((DPRINT_REGISTRY
, "CmiExportHive(%x, '%s') called\n", Hive
, KeyName
));
1273 if (RegOpenKey (NULL
, KeyName
, &Key
) != ERROR_SUCCESS
)
1275 DbgPrint((DPRINT_REGISTRY
, "RegOpenKey() failed\n"));
1279 KeyCell
= CmiGetCell (Hive
, Hive
->HiveHeader
->RootKeyOffset
);
1280 if (KeyCell
== NULL
)
1282 DbgPrint((DPRINT_REGISTRY
, "CmiGetBlock() failed\n"));
1286 ValueCount
= RegGetValueCount (Key
);
1287 DbgPrint((DPRINT_REGISTRY
, "ValueCount: %u\n", ValueCount
));
1290 /* Allocate value list cell */
1291 if (!CmiAllocateValueListCell (Hive
,
1292 &KeyCell
->ValueListOffset
,
1295 DbgPrint((DPRINT_REGISTRY
, "CmiAllocateValueListCell() failed\n"));
1299 if (Key
->DataSize
!= 0)
1301 if (!CmiExportValue (Hive
, Hive
->HiveHeader
->RootKeyOffset
, Key
, NULL
))
1305 /* Enumerate values */
1306 Entry
= Key
->ValueList
.Flink
;
1307 while (Entry
!= &Key
->ValueList
)
1309 Value
= CONTAINING_RECORD(Entry
,
1313 if (!CmiExportValue (Hive
, Hive
->HiveHeader
->RootKeyOffset
, Key
, Value
))
1316 Entry
= Entry
->Flink
;
1320 SubKeyCount
= RegGetSubKeyCount (Key
);
1321 DbgPrint((DPRINT_REGISTRY
, "SubKeyCount: %u\n", SubKeyCount
));
1322 if (SubKeyCount
> 0)
1324 /* Allocate hash table cell */
1325 if (!CmiAllocateHashTableCell (Hive
,
1326 &KeyCell
->HashTableOffset
,
1329 DbgPrint((DPRINT_REGISTRY
, "CmiAllocateHashTableCell() failed\n"));
1333 /* Enumerate subkeys */
1334 Entry
= Key
->SubKeyList
.Flink
;
1335 while (Entry
!= &Key
->SubKeyList
)
1337 SubKey
= CONTAINING_RECORD(Entry
,
1341 if (!CmiExportSubKey (Hive
, Hive
->HiveHeader
->RootKeyOffset
, Key
, SubKey
))
1344 Entry
= Entry
->Flink
;
1348 CmiCalcHiveChecksum (Hive
);
1355 RegImportValue (PHBIN RootBin
,
1356 PVALUE_CELL ValueCell
,
1359 PDATA_CELL DataCell
;
1368 if (ValueCell
->CellSize
>= 0 || ValueCell
->Id
!= REG_VALUE_CELL_ID
)
1370 DbgPrint((DPRINT_REGISTRY
, "Invalid key cell!\n"));
1374 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1376 cName
= MmAllocateMemory (ValueCell
->NameSize
+ 1);
1379 ValueCell
->NameSize
);
1380 cName
[ValueCell
->NameSize
] = 0;
1384 wName
= (PWCHAR
)ValueCell
->Name
;
1385 cName
= MmAllocateMemory (ValueCell
->NameSize
/ 2 + 1);
1386 for (i
= 0; i
< ValueCell
->NameSize
/ 2; i
++)
1387 cName
[i
] = (CHAR
)wName
[i
];
1388 cName
[ValueCell
->NameSize
/ 2] = 0;
1391 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1393 DbgPrint((DPRINT_REGISTRY
, "ValueName: '%s'\n", cName
));
1394 DbgPrint((DPRINT_REGISTRY
, "DataSize: %u\n", DataSize
));
1396 if (DataSize
<= sizeof(BLOCK_OFFSET
) && (ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1398 Error
= RegSetValue(Key
,
1400 ValueCell
->DataType
,
1401 (PCHAR
)&ValueCell
->DataOffset
,
1403 if (Error
!= ERROR_SUCCESS
)
1405 DbgPrint((DPRINT_REGISTRY
, "RegSetValue() failed!\n"));
1406 MmFreeMemory (cName
);
1412 DataCell
= (PDATA_CELL
)((PUCHAR
)RootBin
+ ValueCell
->DataOffset
);
1413 DbgPrint((DPRINT_REGISTRY
, "DataCell: %x\n", DataCell
));
1415 if (DataCell
->CellSize
>= 0)
1417 DbgPrint((DPRINT_REGISTRY
, "Invalid data cell size!\n"));
1418 MmFreeMemory (cName
);
1422 if (ValueCell
->DataType
== REG_SZ
||
1423 ValueCell
->DataType
== REG_EXPAND_SZ
||
1424 ValueCell
->DataType
== REG_MULTI_SZ
)
1426 wBuffer
= (PWCHAR
)DataCell
->Data
;
1427 cBuffer
= MmAllocateMemory(DataSize
/2);
1428 for (i
= 0; i
< DataSize
/ 2; i
++)
1429 cBuffer
[i
] = (CHAR
)wBuffer
[i
];
1431 Error
= RegSetValue (Key
,
1433 ValueCell
->DataType
,
1437 MmFreeMemory(cBuffer
);
1441 Error
= RegSetValue (Key
,
1443 ValueCell
->DataType
,
1447 if (Error
!= ERROR_SUCCESS
)
1449 DbgPrint((DPRINT_REGISTRY
, "RegSetValue() failed!\n"));
1450 MmFreeMemory (cName
);
1455 MmFreeMemory (cName
);
1462 RegImportSubKey(PHBIN RootBin
,
1464 FRLDRHKEY ParentKey
)
1466 PHASH_TABLE_CELL HashCell
;
1467 PKEY_CELL SubKeyCell
;
1468 PVALUE_LIST_CELL ValueListCell
;
1469 PVALUE_CELL ValueCell
= NULL
;
1476 DbgPrint((DPRINT_REGISTRY
, "KeyCell: %x\n", KeyCell
));
1477 DbgPrint((DPRINT_REGISTRY
, "KeyCell->CellSize: %x\n", KeyCell
->CellSize
));
1478 DbgPrint((DPRINT_REGISTRY
, "KeyCell->Id: %x\n", KeyCell
->Id
));
1479 if (KeyCell
->Id
!= REG_KEY_CELL_ID
|| KeyCell
->CellSize
>= 0)
1481 DbgPrint((DPRINT_REGISTRY
, "Invalid key cell id!\n"));
1485 /* FIXME: implement packed key names */
1486 cName
= MmAllocateMemory (KeyCell
->NameSize
+ 1);
1490 cName
[KeyCell
->NameSize
] = 0;
1492 DbgPrint((DPRINT_REGISTRY
, "KeyName: '%s'\n", cName
));
1494 /* Create new sub key */
1495 Error
= RegCreateKey (ParentKey
,
1498 MmFreeMemory (cName
);
1499 if (Error
!= ERROR_SUCCESS
)
1501 DbgPrint((DPRINT_REGISTRY
, "RegCreateKey() failed!\n"));
1504 DbgPrint((DPRINT_REGISTRY
, "Subkeys: %u\n", KeyCell
->NumberOfSubKeys
));
1505 DbgPrint((DPRINT_REGISTRY
, "Values: %u\n", KeyCell
->NumberOfValues
));
1507 /* Enumerate and add values */
1508 if (KeyCell
->NumberOfValues
> 0)
1510 ValueListCell
= (PVALUE_LIST_CELL
)((PUCHAR
)RootBin
+ KeyCell
->ValueListOffset
);
1511 DbgPrint((DPRINT_REGISTRY
, "ValueListCell: %x\n", ValueListCell
));
1513 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
1515 DbgPrint((DPRINT_REGISTRY
, "ValueOffset[%d]: %x\n", i
, ValueListCell
->ValueOffset
[i
]));
1517 ValueCell
= (PVALUE_CELL
)((PUCHAR
)RootBin
+ ValueListCell
->ValueOffset
[i
]);
1519 DbgPrint((DPRINT_REGISTRY
, "ValueCell[%d]: %x\n", i
, ValueCell
));
1521 if (!RegImportValue(RootBin
, ValueCell
, SubKey
))
1526 /* Enumerate and add subkeys */
1527 if (KeyCell
->NumberOfSubKeys
> 0)
1529 HashCell
= (PHASH_TABLE_CELL
)((PUCHAR
)RootBin
+ KeyCell
->HashTableOffset
);
1530 DbgPrint((DPRINT_REGISTRY
, "HashCell: %x\n", HashCell
));
1532 for (i
= 0; i
< KeyCell
->NumberOfSubKeys
; i
++)
1534 DbgPrint((DPRINT_REGISTRY
, "KeyOffset[%d]: %x\n", i
, HashCell
->Table
[i
].KeyOffset
));
1536 SubKeyCell
= (PKEY_CELL
)((PUCHAR
)RootBin
+ HashCell
->Table
[i
].KeyOffset
);
1538 DbgPrint((DPRINT_REGISTRY
, "SubKeyCell[%d]: %x\n", i
, SubKeyCell
));
1540 if (!RegImportSubKey(RootBin
, SubKeyCell
, SubKey
))
1550 RegImportBinaryHive(PCHAR ChunkBase
,
1553 PHIVE_HEADER HiveHeader
;
1556 PHASH_TABLE_CELL HashCell
;
1557 PKEY_CELL SubKeyCell
;
1558 FRLDRHKEY SystemKey
;
1562 DbgPrint((DPRINT_REGISTRY
, "RegImportBinaryHive(%x, %u) called\n",ChunkBase
,ChunkSize
));
1564 HiveHeader
= (PHIVE_HEADER
)ChunkBase
;
1565 DbgPrint((DPRINT_REGISTRY
, "HiveHeader: %x\n", HiveHeader
));
1566 if (HiveHeader
->BlockId
!= REG_HIVE_ID
)
1568 DbgPrint((DPRINT_REGISTRY
, "Invalid hive id!\n"));
1572 RootBin
= (PHBIN
)((ULONG
)HiveHeader
+ REG_BLOCK_SIZE
);
1573 DbgPrint((DPRINT_REGISTRY
, "RootBin: %x\n", RootBin
));
1574 if (RootBin
->HeaderId
!= REG_BIN_ID
|| RootBin
->BinSize
== 0)
1576 DbgPrint((DPRINT_REGISTRY
, "Invalid bin id!\n"));
1580 KeyCell
= (PKEY_CELL
)((ULONG
)RootBin
+ REG_HBIN_DATA_OFFSET
);
1581 DbgPrint((DPRINT_REGISTRY
, "KeyCell: %x\n", KeyCell
));
1582 DbgPrint((DPRINT_REGISTRY
, "KeyCell->CellSize: %x\n", KeyCell
->CellSize
));
1583 DbgPrint((DPRINT_REGISTRY
, "KeyCell->Id: %x\n", KeyCell
->Id
));
1584 if (KeyCell
->Id
!= REG_KEY_CELL_ID
|| KeyCell
->CellSize
>= 0)
1586 DbgPrint((DPRINT_REGISTRY
, "Invalid key cell id!\n"));
1590 DbgPrint((DPRINT_REGISTRY
, "Subkeys: %u\n", KeyCell
->NumberOfSubKeys
));
1591 DbgPrint((DPRINT_REGISTRY
, "Values: %u\n", KeyCell
->NumberOfValues
));
1593 /* Open 'System' key */
1594 Error
= RegOpenKey(NULL
,
1595 "\\Registry\\Machine\\SYSTEM",
1597 if (Error
!= ERROR_SUCCESS
)
1599 DbgPrint((DPRINT_REGISTRY
, "Failed to open 'system' key!\n"));
1603 /* Enumerate and add subkeys */
1604 if (KeyCell
->NumberOfSubKeys
> 0)
1606 HashCell
= (PHASH_TABLE_CELL
)((ULONG
)RootBin
+ KeyCell
->HashTableOffset
);
1607 DbgPrint((DPRINT_REGISTRY
, "HashCell: %x\n", HashCell
));
1609 for (i
= 0; i
< KeyCell
->NumberOfSubKeys
; i
++)
1611 DbgPrint((DPRINT_REGISTRY
, "KeyOffset[%d]: %x\n", i
, HashCell
->Table
[i
].KeyOffset
));
1613 SubKeyCell
= (PKEY_CELL
)((ULONG
)RootBin
+ HashCell
->Table
[i
].KeyOffset
);
1615 DbgPrint((DPRINT_REGISTRY
, "SubKeyCell[%d]: %x\n", i
, SubKeyCell
));
1617 if (!RegImportSubKey(RootBin
, SubKeyCell
, SystemKey
))
1627 RegExportBinaryHive(PCSTR KeyName
,
1631 PREGISTRY_HIVE Hive
;
1633 DbgPrint((DPRINT_REGISTRY
, "Creating binary hardware hive\n"));
1636 InitMbMemory (ChunkBase
);
1638 Hive
= CmiCreateHive (KeyName
);
1642 if (!CmiExportHive (Hive
, KeyName
))
1644 CmiCleanupHive (Hive
, TRUE
);
1648 CmiCleanupHive (Hive
, FALSE
);
1650 *ChunkSize
= GetMbAllocatedSize ();