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.
27 #define REG_HIVE_ID 0x66676572 /* "regf" */
28 #define REG_BIN_ID 0x6e696268 /* "hbin" */
29 #define REG_KEY_CELL_ID 0x6b6e
30 #define REG_HASH_TABLE_BLOCK_ID 0x666c
31 #define REG_VALUE_CELL_ID 0x6b76
33 #define REG_BLOCK_SIZE 4096
34 #define REG_HBIN_DATA_OFFSET 32
35 #define REG_INIT_BLOCK_LIST_SIZE 32
36 #define REG_INIT_HASH_TABLE_SIZE 3
37 #define REG_EXTEND_HASH_TABLE_SIZE 4
38 #define REG_VALUE_LIST_CELL_MULTIPLE 4
41 #define ABS_VALUE(V) (((V) < 0) ? -(V) : (V))
44 /* BLOCK_OFFSET = offset in file after header block */
45 typedef ULONG BLOCK_OFFSET
, *PBLOCK_OFFSET
;
47 /* header for registry hive file : */
48 typedef struct _HIVE_HEADER
50 /* Hive identifier "regf" (0x66676572) */
59 /* When this hive file was last modified */
60 ULONGLONG DateModified
; /* FILETIME */
62 /* Registry format version ? (1?) */
65 /* Registry format version ? (3?) */
68 /* Registry format version ? (0?) */
71 /* Registry format version ? (1?) */
74 /* Offset into file from the byte after the end of the base block.
75 If the hive is volatile, this is the actual pointer to the KEY_CELL */
76 BLOCK_OFFSET RootKeyOffset
;
78 /* Size of each hive block ? */
84 /* Name of hive file */
90 /* Checksum of first 0x200 bytes */
92 } __attribute__((packed
)) HIVE_HEADER
, *PHIVE_HEADER
;
95 typedef struct _BIN_HEADER
97 /* Bin identifier "hbin" (0x6E696268) */
101 BLOCK_OFFSET BinOffset
;
103 /* Size in bytes, multiple of the block size (4KB) */
109 /* When this bin was last modified */
110 ULONGLONG DateModified
; /* FILETIME */
114 } __attribute__((packed
)) HBIN
, *PHBIN
;
117 typedef struct _CELL_HEADER
119 /* <0 if used, >0 if free */
121 } __attribute__((packed
)) CELL_HEADER
, *PCELL_HEADER
;
124 typedef struct _KEY_CELL
126 /* Size of this cell */
129 /* Key cell identifier "kn" (0x6b6e) */
135 /* Time of last flush */
136 ULONGLONG LastWriteTime
; /* FILETIME */
141 /* Block offset of parent key cell */
142 BLOCK_OFFSET ParentKeyOffset
;
144 /* Count of sub keys for the key in this key cell */
145 ULONG NumberOfSubKeys
;
150 /* Block offset of has table for FIXME: subkeys/values? */
151 BLOCK_OFFSET HashTableOffset
;
156 /* Count of values contained in this key cell */
157 ULONG NumberOfValues
;
159 /* Block offset of VALUE_LIST_CELL */
160 BLOCK_OFFSET ValueListOffset
;
162 /* Block offset of security cell */
163 BLOCK_OFFSET SecurityKeyOffset
;
165 /* Block offset of registry key class */
166 BLOCK_OFFSET ClassNameOffset
;
171 /* Size in bytes of key name */
174 /* Size of class name in bytes */
177 /* Name of key (not zero terminated) */
179 } __attribute__((packed
)) KEY_CELL
, *PKEY_CELL
;
182 /* KEY_CELL.Type constants */
183 #define REG_LINK_KEY_CELL_TYPE 0x10
184 #define REG_KEY_CELL_TYPE 0x20
185 #define REG_ROOT_KEY_CELL_TYPE 0x2c
189 // HashValue=four letters of value's name
190 typedef struct _HASH_RECORD
192 BLOCK_OFFSET KeyOffset
;
194 } __attribute__((packed
)) HASH_RECORD
, *PHASH_RECORD
;
197 typedef struct _HASH_TABLE_CELL
201 USHORT HashTableSize
;
202 HASH_RECORD Table
[0];
203 } __attribute__((packed
)) HASH_TABLE_CELL
, *PHASH_TABLE_CELL
;
206 typedef struct _VALUE_LIST_CELL
209 BLOCK_OFFSET ValueOffset
[0];
210 } __attribute__((packed
)) VALUE_LIST_CELL
, *PVALUE_LIST_CELL
;
213 typedef struct _VALUE_CELL
217 USHORT NameSize
; // length of Name
218 ULONG DataSize
; // length of datas in the cell pointed by DataOffset
219 BLOCK_OFFSET DataOffset
;// datas are here if high bit of DataSize is set
223 CHAR Name
[0]; /* warning : not zero terminated */
224 } __attribute__((packed
)) VALUE_CELL
, *PVALUE_CELL
;
226 /* VALUE_CELL.Flags constants */
227 #define REG_VALUE_NAME_PACKED 0x0001
229 /* VALUE_CELL.DataSize mask constants */
230 #define REG_DATA_SIZE_MASK 0x7FFFFFFF
231 #define REG_DATA_IN_OFFSET 0x80000000
234 typedef struct _DATA_CELL
238 } __attribute__((packed
)) DATA_CELL
, *PDATA_CELL
;
241 typedef struct _REGISTRY_HIVE
244 PHIVE_HEADER HiveHeader
;
249 PCELL_HEADER
*FreeList
;
250 BLOCK_OFFSET
*FreeListOffset
;
251 } REGISTRY_HIVE
, *PREGISTRY_HIVE
;
254 static PVOID MbBase
= NULL
;
255 static ULONG MbSize
= 0;
257 /* FUNCTIONS ****************************************************************/
260 InitMbMemory (PVOID ChunkBase
)
268 AllocateMbMemory (ULONG MemSize
)
274 MbBase
= (PVOID
)((ULONG
)MbBase
+ MemSize
);
287 GetMbAllocatedSize (VOID
)
294 CmiCreateDefaultHiveHeader (PHIVE_HEADER Header
)
297 memset (Header
, 0, REG_BLOCK_SIZE
);
298 Header
->BlockId
= REG_HIVE_ID
;
299 Header
->UpdateCounter1
= 0;
300 Header
->UpdateCounter2
= 0;
301 Header
->DateModified
= 0ULL;
307 Header
->RootKeyOffset
= -1;
308 Header
->BlockSize
= REG_BLOCK_SIZE
;
310 Header
->Checksum
= 0;
315 CmiCreateDefaultBinCell (PHBIN BinCell
)
318 memset (BinCell
, 0, REG_BLOCK_SIZE
);
319 BinCell
->HeaderId
= REG_BIN_ID
;
320 BinCell
->DateModified
= 0ULL;
321 BinCell
->BinSize
= REG_BLOCK_SIZE
;
326 CmiCreateDefaultRootKeyCell (PKEY_CELL RootKeyCell
, PCSTR KeyName
)
332 assert (RootKeyCell
);
334 BaseKeyName
= strrchr(KeyName
, '\\') + 1;
335 NameSize
= strlen(BaseKeyName
);
336 CellSize
= ROUND_UP(sizeof(KEY_CELL
) + NameSize
- 1, 16);
338 memset (RootKeyCell
, 0, CellSize
);
339 RootKeyCell
->CellSize
= -CellSize
;
340 RootKeyCell
->Id
= REG_KEY_CELL_ID
;
341 RootKeyCell
->Type
= REG_ROOT_KEY_CELL_TYPE
;
342 RootKeyCell
->LastWriteTime
= 0ULL;
343 RootKeyCell
->ParentKeyOffset
= 0;
344 RootKeyCell
->NumberOfSubKeys
= 0;
345 RootKeyCell
->HashTableOffset
= -1;
346 RootKeyCell
->NumberOfValues
= 0;
347 RootKeyCell
->ValueListOffset
= -1;
348 RootKeyCell
->SecurityKeyOffset
= 0;
349 RootKeyCell
->ClassNameOffset
= -1;
350 RootKeyCell
->NameSize
= NameSize
;
351 RootKeyCell
->ClassSize
= 0;
352 memcpy (RootKeyCell
->Name
, BaseKeyName
, NameSize
);
356 static PREGISTRY_HIVE
357 CmiCreateHive (PCSTR KeyName
)
360 PCELL_HEADER FreeCell
;
361 PKEY_CELL RootKeyCell
;
364 Hive
= (PREGISTRY_HIVE
) MmAllocateMemory (sizeof(REGISTRY_HIVE
));
369 memset (Hive
, 0, sizeof(REGISTRY_HIVE
));
371 DbgPrint((DPRINT_REGISTRY
, "Hive %x\n", Hive
));
373 /* Create hive beader (aka 'base block') */
374 Hive
->HiveHeader
= (PHIVE_HEADER
) AllocateMbMemory (REG_BLOCK_SIZE
);
375 if (Hive
->HiveHeader
== NULL
)
380 CmiCreateDefaultHiveHeader(Hive
->HiveHeader
);
381 Hive
->FileSize
= REG_BLOCK_SIZE
;
383 /* Allocate block list */
384 Hive
->BlockListSize
= 1;
385 Hive
->BlockList
= MmAllocateMemory (sizeof(PHBIN
) * Hive
->BlockListSize
);
386 if (Hive
->BlockList
== NULL
)
392 /* Allocate free cell list */
393 Hive
->FreeListMax
= 32;
394 Hive
->FreeList
= MmAllocateMemory(sizeof(PCELL_HEADER
) * Hive
->FreeListMax
);
395 if (Hive
->FreeList
== NULL
)
397 MmFreeMemory (Hive
->BlockList
);
401 Hive
->FreeListOffset
= MmAllocateMemory(sizeof(BLOCK_OFFSET
) * Hive
->FreeListMax
);
402 if (Hive
->FreeListOffset
== NULL
)
404 MmFreeMemory (Hive
->FreeList
);
405 MmFreeMemory (Hive
->BlockList
);
410 /* Allocate first bin */
411 Hive
->BlockList
[0] = (PHBIN
) AllocateMbMemory (REG_BLOCK_SIZE
);
412 if (Hive
->BlockList
[0] == NULL
)
414 MmFreeMemory (Hive
->FreeListOffset
);
415 MmFreeMemory (Hive
->FreeList
);
416 MmFreeMemory (Hive
->BlockList
);
420 Hive
->FileSize
+= REG_BLOCK_SIZE
;
423 BinCell
= (PHBIN
)Hive
->BlockList
[0];
424 CmiCreateDefaultBinCell(BinCell
);
425 BinCell
->BinOffset
= 0;
427 /* Init root key cell */
428 RootKeyCell
= (PKEY_CELL
)((ULONG
)BinCell
+ REG_HBIN_DATA_OFFSET
);
429 CmiCreateDefaultRootKeyCell(RootKeyCell
, KeyName
);
430 Hive
->HiveHeader
->RootKeyOffset
= REG_HBIN_DATA_OFFSET
;
433 FreeCell
= (PCELL_HEADER
)((ULONG
)RootKeyCell
- RootKeyCell
->CellSize
);
434 FreeCell
->CellSize
= REG_BLOCK_SIZE
- (REG_HBIN_DATA_OFFSET
- RootKeyCell
->CellSize
);
436 Hive
->FreeList
[0] = FreeCell
;
437 Hive
->FreeListOffset
[0] = REG_HBIN_DATA_OFFSET
- RootKeyCell
->CellSize
;
438 Hive
->FreeListSize
++;
445 CmiCleanupHive(PREGISTRY_HIVE Hive
, BOOL Release
)
447 MmFreeMemory (Hive
->FreeListOffset
);
448 MmFreeMemory (Hive
->FreeList
);
449 MmFreeMemory (Hive
->BlockList
);
460 CmiGetBin (PREGISTRY_HIVE Hive
,
461 BLOCK_OFFSET BlockOffset
)
465 if (BlockOffset
== (ULONG
) -1)
468 BlockIndex
= BlockOffset
/ REG_BLOCK_SIZE
;
469 if (BlockIndex
>= Hive
->BlockListSize
)
472 return Hive
->BlockList
[BlockIndex
];
477 CmiMergeFree(PREGISTRY_HIVE RegistryHive
,
478 PCELL_HEADER FreeBlock
,
479 BLOCK_OFFSET FreeOffset
)
481 BLOCK_OFFSET BlockOffset
;
482 BLOCK_OFFSET BinOffset
;
488 DbgPrint((DPRINT_REGISTRY
, "CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
489 FreeBlock
, FreeOffset
, FreeBlock
->CellSize
));
491 Bin
= CmiGetBin (RegistryHive
, FreeOffset
);
495 DbgPrint((DPRINT_REGISTRY
, "Bin %p\n", Bin
));
497 BinOffset
= Bin
->BinOffset
;
498 BinSize
= Bin
->BinSize
;
499 DbgPrint((DPRINT_REGISTRY
, "Bin %p Offset %lx Size %lx\n", Bin
, BinOffset
, BinSize
));
501 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
503 BlockOffset
= RegistryHive
->FreeListOffset
[i
];
504 BlockSize
= RegistryHive
->FreeList
[i
]->CellSize
;
505 if (BlockOffset
> BinOffset
&&
506 BlockOffset
< BinOffset
+ BinSize
)
508 DbgPrint((DPRINT_REGISTRY
, "Free block: Offset %lx Size %lx\n",
509 BlockOffset
, BlockSize
));
511 if ((i
< (RegistryHive
->FreeListSize
- 1)) &&
512 (BlockOffset
+ BlockSize
== FreeOffset
) &&
513 (FreeOffset
+ FreeBlock
->CellSize
== RegistryHive
->FreeListOffset
[i
+ 1]))
515 DbgPrint((DPRINT_REGISTRY
, "Merge current block with previous and next block\n"));
517 RegistryHive
->FreeList
[i
]->CellSize
+=
518 (FreeBlock
->CellSize
+ RegistryHive
->FreeList
[i
+ 1]->CellSize
);
520 FreeBlock
->CellSize
= 0;
521 RegistryHive
->FreeList
[i
+ 1]->CellSize
= 0;
524 if ((i
+ 2) < RegistryHive
->FreeListSize
)
526 memmove (&RegistryHive
->FreeList
[i
+ 1],
527 &RegistryHive
->FreeList
[i
+ 2],
528 sizeof(RegistryHive
->FreeList
[0])
529 * (RegistryHive
->FreeListSize
- i
- 2));
530 memmove (&RegistryHive
->FreeListOffset
[i
+ 1],
531 &RegistryHive
->FreeListOffset
[i
+ 2],
532 sizeof(RegistryHive
->FreeListOffset
[0])
533 * (RegistryHive
->FreeListSize
- i
- 2));
535 RegistryHive
->FreeListSize
--;
539 else if (BlockOffset
+ BlockSize
== FreeOffset
)
541 DbgPrint((DPRINT_REGISTRY
, "Merge current block with previous block\n"));
543 RegistryHive
->FreeList
[i
]->CellSize
+= FreeBlock
->CellSize
;
544 FreeBlock
->CellSize
= 0;
548 else if (FreeOffset
+ FreeBlock
->CellSize
== BlockOffset
)
550 DbgPrint((DPRINT_REGISTRY
, "Merge current block with next block\n"));
552 FreeBlock
->CellSize
+= RegistryHive
->FreeList
[i
]->CellSize
;
553 RegistryHive
->FreeList
[i
]->CellSize
= 0;
554 RegistryHive
->FreeList
[i
] = FreeBlock
;
555 RegistryHive
->FreeListOffset
[i
] = FreeOffset
;
567 CmiAddFree(PREGISTRY_HIVE RegistryHive
,
568 PCELL_HEADER FreeBlock
,
569 BLOCK_OFFSET FreeOffset
,
570 BOOL MergeFreeBlocks
)
572 PCELL_HEADER
*tmpList
;
573 BLOCK_OFFSET
*tmpListOffset
;
578 assert(RegistryHive
);
581 DbgPrint((DPRINT_REGISTRY
, "FreeBlock %.08lx FreeOffset %.08lx\n",
582 FreeBlock
, FreeOffset
));
584 /* Merge free blocks */
585 if (MergeFreeBlocks
== TRUE
)
587 if (CmiMergeFree(RegistryHive
, FreeBlock
, FreeOffset
))
591 if ((RegistryHive
->FreeListSize
+ 1) > RegistryHive
->FreeListMax
)
593 tmpList
= MmAllocateMemory (sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
+ 32));
599 tmpListOffset
= MmAllocateMemory (sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
+ 32));
600 if (tmpListOffset
== NULL
)
602 MmFreeMemory (tmpList
);
606 if (RegistryHive
->FreeListMax
)
609 RegistryHive
->FreeList
,
610 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
));
611 memmove (tmpListOffset
,
612 RegistryHive
->FreeListOffset
,
613 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
));
614 MmFreeMemory (RegistryHive
->FreeList
);
615 MmFreeMemory (RegistryHive
->FreeListOffset
);
617 RegistryHive
->FreeList
= tmpList
;
618 RegistryHive
->FreeListOffset
= tmpListOffset
;
619 RegistryHive
->FreeListMax
+= 32;
622 /* Add new offset to free list, maintaining list in ascending order */
623 if ((RegistryHive
->FreeListSize
== 0)
624 || (RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
-1] < FreeOffset
))
626 /* Add to end of list */
627 RegistryHive
->FreeList
[RegistryHive
->FreeListSize
] = FreeBlock
;
628 RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
++] = FreeOffset
;
630 else if (RegistryHive
->FreeListOffset
[0] > FreeOffset
)
632 /* Add to begin of list */
633 memmove (&RegistryHive
->FreeList
[1],
634 &RegistryHive
->FreeList
[0],
635 sizeof(RegistryHive
->FreeList
[0]) * RegistryHive
->FreeListSize
);
636 memmove (&RegistryHive
->FreeListOffset
[1],
637 &RegistryHive
->FreeListOffset
[0],
638 sizeof(RegistryHive
->FreeListOffset
[0]) * RegistryHive
->FreeListSize
);
639 RegistryHive
->FreeList
[0] = FreeBlock
;
640 RegistryHive
->FreeListOffset
[0] = FreeOffset
;
641 RegistryHive
->FreeListSize
++;
645 /* Search where to insert */
647 maxInd
= RegistryHive
->FreeListSize
- 1;
648 while ((maxInd
- minInd
) > 1)
650 medInd
= (minInd
+ maxInd
) / 2;
651 if (RegistryHive
->FreeListOffset
[medInd
] > FreeOffset
)
657 /* Insert before maxInd */
658 memmove (&RegistryHive
->FreeList
[maxInd
+1],
659 &RegistryHive
->FreeList
[maxInd
],
660 sizeof(RegistryHive
->FreeList
[0]) * (RegistryHive
->FreeListSize
- minInd
));
661 memmove (&RegistryHive
->FreeListOffset
[maxInd
+ 1],
662 &RegistryHive
->FreeListOffset
[maxInd
],
663 sizeof(RegistryHive
->FreeListOffset
[0]) * (RegistryHive
->FreeListSize
-minInd
));
664 RegistryHive
->FreeList
[maxInd
] = FreeBlock
;
665 RegistryHive
->FreeListOffset
[maxInd
] = FreeOffset
;
666 RegistryHive
->FreeListSize
++;
674 CmiAddBin(PREGISTRY_HIVE RegistryHive
,
677 PBLOCK_OFFSET NewBlockOffset
)
679 PCELL_HEADER tmpBlock
;
685 BinSize
= BlockCount
* REG_BLOCK_SIZE
;
686 tmpBin
= AllocateMbMemory (BinSize
);
691 memset (tmpBin
, 0, BinSize
);
693 tmpBin
->HeaderId
= REG_BIN_ID
;
694 tmpBin
->BinOffset
= RegistryHive
->FileSize
- REG_BLOCK_SIZE
;
695 RegistryHive
->FileSize
+= BinSize
;
696 tmpBin
->BinSize
= BinSize
;
698 tmpBin
->DateModified
= 0ULL;
701 /* Increase size of list of blocks */
702 BlockList
= MmAllocateMemory (sizeof(PHBIN
) * (RegistryHive
->BlockListSize
+ BlockCount
));
703 if (BlockList
== NULL
)
708 if (RegistryHive
->BlockListSize
> 0)
711 RegistryHive
->BlockList
,
712 sizeof(PHBIN
) * RegistryHive
->BlockListSize
);
713 MmFreeMemory (RegistryHive
->BlockList
);
716 RegistryHive
->BlockList
= BlockList
;
717 for (i
= 0; i
< BlockCount
; i
++)
718 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
+ i
] = tmpBin
;
719 RegistryHive
->BlockListSize
+= BlockCount
;
721 /* Initialize a free block in this heap : */
722 tmpBlock
= (PCELL_HEADER
)((ULONG
) tmpBin
+ REG_HBIN_DATA_OFFSET
);
723 tmpBlock
->CellSize
= (REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
);
725 *NewBlock
= (PVOID
) tmpBlock
;
728 *NewBlockOffset
= tmpBin
->BinOffset
+ REG_HBIN_DATA_OFFSET
;
735 CmiAllocateCell (PREGISTRY_HIVE RegistryHive
,
738 PBLOCK_OFFSET pBlockOffset
)
740 PCELL_HEADER NewBlock
;
745 /* Round to 16 bytes multiple */
746 CellSize
= ROUND_UP(CellSize
, 16);
748 /* first search in free blocks */
750 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
752 if (RegistryHive
->FreeList
[i
]->CellSize
>= CellSize
)
754 NewBlock
= RegistryHive
->FreeList
[i
];
756 *pBlockOffset
= RegistryHive
->FreeListOffset
[i
];
758 if ((i
+ 1) < RegistryHive
->FreeListSize
)
760 memmove (&RegistryHive
->FreeList
[i
],
761 &RegistryHive
->FreeList
[i
+ 1],
762 sizeof(RegistryHive
->FreeList
[0])
763 * (RegistryHive
->FreeListSize
- i
- 1));
764 memmove (&RegistryHive
->FreeListOffset
[i
],
765 &RegistryHive
->FreeListOffset
[i
+ 1],
766 sizeof(RegistryHive
->FreeListOffset
[0])
767 * (RegistryHive
->FreeListSize
- i
- 1));
769 RegistryHive
->FreeListSize
--;
774 /* Need to extend hive file */
775 if (NewBlock
== NULL
)
777 /* Add a new block */
778 if (!CmiAddBin(RegistryHive
,
779 ((sizeof(HBIN
) + CellSize
- 1) / REG_BLOCK_SIZE
) + 1,
780 (PVOID
*)(PVOID
)&NewBlock
,
787 /* Split the block in two parts */
788 if (NewBlock
->CellSize
> CellSize
)
790 NewBlock
= (PCELL_HEADER
) ((ULONG
)NewBlock
+ CellSize
);
791 NewBlock
->CellSize
= ((PCELL_HEADER
) (*Block
))->CellSize
- CellSize
;
792 CmiAddFree (RegistryHive
,
794 *pBlockOffset
+ CellSize
,
797 else if (NewBlock
->CellSize
< CellSize
)
802 memset(*Block
, 0, CellSize
);
803 ((PCELL_HEADER
)(*Block
))->CellSize
= -CellSize
;
810 CmiGetCell (PREGISTRY_HIVE Hive
,
811 BLOCK_OFFSET BlockOffset
)
816 if (BlockOffset
== (ULONG
) -1)
819 BlockIndex
= BlockOffset
/ REG_BLOCK_SIZE
;
820 if (BlockIndex
>= Hive
->BlockListSize
)
823 Bin
= Hive
->BlockList
[BlockIndex
];
827 return (PVOID
)((ULONG
)Bin
+ (BlockOffset
- Bin
->BinOffset
));
832 CmiAllocateHashTableCell (PREGISTRY_HIVE Hive
,
833 PBLOCK_OFFSET HBOffset
,
836 PHASH_TABLE_CELL HashCell
;
840 NewHashSize
= sizeof(HASH_TABLE_CELL
) +
841 (SubKeyCount
* sizeof(HASH_RECORD
));
842 Status
= CmiAllocateCell (Hive
,
844 (PVOID
*)(PVOID
)&HashCell
,
846 if ((HashCell
== NULL
) || (Status
== FALSE
))
851 HashCell
->Id
= REG_HASH_TABLE_BLOCK_ID
;
852 HashCell
->HashTableSize
= SubKeyCount
;
859 CmiAddKeyToParentHashTable (PREGISTRY_HIVE Hive
,
860 BLOCK_OFFSET ParentKeyOffset
,
861 PKEY_CELL NewKeyCell
,
862 BLOCK_OFFSET NKBOffset
)
864 PHASH_TABLE_CELL HashBlock
;
865 PKEY_CELL ParentKeyCell
;
868 ParentKeyCell
= CmiGetCell (Hive
, ParentKeyOffset
);
869 if (ParentKeyCell
== NULL
)
871 DbgPrint((DPRINT_REGISTRY
, "CmiGetCell() failed\n"));
875 HashBlock
=CmiGetCell (Hive
, ParentKeyCell
->HashTableOffset
);
876 if (HashBlock
== NULL
)
878 DbgPrint((DPRINT_REGISTRY
, "CmiGetCell() failed\n"));
882 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
884 if (HashBlock
->Table
[i
].KeyOffset
== 0)
886 HashBlock
->Table
[i
].KeyOffset
= NKBOffset
;
887 memcpy (&HashBlock
->Table
[i
].HashValue
,
890 ParentKeyCell
->NumberOfSubKeys
++;
900 CmiAllocateValueListCell (PREGISTRY_HIVE Hive
,
901 PBLOCK_OFFSET ValueListOffset
,
904 PVALUE_LIST_CELL ValueListCell
;
908 ValueListSize
= sizeof(VALUE_LIST_CELL
) +
909 (ValueCount
* sizeof(BLOCK_OFFSET
));
910 Status
= CmiAllocateCell (Hive
,
912 (PVOID
)&ValueListCell
,
914 if ((ValueListCell
== NULL
) || (Status
== FALSE
))
916 DbgPrint((DPRINT_REGISTRY
, "CmiAllocateCell() failed\n"));
925 CmiAllocateValueCell(PREGISTRY_HIVE Hive
,
926 PVALUE_CELL
*ValueCell
,
927 BLOCK_OFFSET
*ValueCellOffset
,
930 PVALUE_CELL NewValueCell
;
934 NameSize
= (ValueName
== NULL
) ? 0 : strlen (ValueName
);
935 Status
= CmiAllocateCell (Hive
,
936 sizeof(VALUE_CELL
) + NameSize
,
937 (PVOID
*)(PVOID
)&NewValueCell
,
939 if ((NewValueCell
== NULL
) || (Status
== FALSE
))
941 DbgPrint((DPRINT_REGISTRY
, "CmiAllocateCell() failed\n"));
945 NewValueCell
->Id
= REG_VALUE_CELL_ID
;
946 NewValueCell
->NameSize
= NameSize
;
949 memcpy (NewValueCell
->Name
,
952 NewValueCell
->Flags
= REG_VALUE_NAME_PACKED
;
954 NewValueCell
->DataType
= 0;
955 NewValueCell
->DataSize
= 0;
956 NewValueCell
->DataOffset
= -1;
958 *ValueCell
= NewValueCell
;
965 CmiAddValueToKeyValueList(PREGISTRY_HIVE Hive
,
966 BLOCK_OFFSET KeyCellOffset
,
967 BLOCK_OFFSET ValueCellOffset
)
969 PVALUE_LIST_CELL ValueListCell
;
972 KeyCell
= CmiGetCell (Hive
, KeyCellOffset
);
975 DbgPrint((DPRINT_REGISTRY
, "CmiGetCell() failed\n"));
979 ValueListCell
= CmiGetCell (Hive
, KeyCell
->ValueListOffset
);
980 if (ValueListCell
== NULL
)
982 DbgPrint((DPRINT_REGISTRY
, "CmiGetCell() failed\n"));
986 ValueListCell
->ValueOffset
[KeyCell
->NumberOfValues
] = ValueCellOffset
;
987 KeyCell
->NumberOfValues
++;
994 memexpand (PWCHAR Dst
,
1000 for (i
= 0; i
< Length
; i
++)
1001 Dst
[i
] = (WCHAR
)Src
[i
];
1006 CmiExportValue (PREGISTRY_HIVE Hive
,
1007 BLOCK_OFFSET KeyCellOffset
,
1011 BLOCK_OFFSET ValueCellOffset
;
1012 BLOCK_OFFSET DataCellOffset
;
1013 PVALUE_CELL ValueCell
;
1014 PDATA_CELL DataCell
;
1019 BOOL Expand
= FALSE
;
1021 DbgPrint((DPRINT_REGISTRY
, "CmiExportValue('%s') called\n",
1022 (Value
== NULL
) ? "<default>" : (PCHAR
)Value
->Name
));
1023 DbgPrint((DPRINT_REGISTRY
, "DataSize %lu\n",
1024 (Value
== NULL
) ? Key
->DataSize
: Value
->DataSize
));
1026 /* Allocate value cell */
1027 if (!CmiAllocateValueCell(Hive
, &ValueCell
, &ValueCellOffset
, (Value
== NULL
) ? NULL
: Value
->Name
))
1032 if (!CmiAddValueToKeyValueList(Hive
, KeyCellOffset
, ValueCellOffset
))
1039 DataType
= Key
->DataType
;
1040 SrcDataSize
= Key
->DataSize
;
1045 DataType
= Value
->DataType
;
1046 SrcDataSize
= Value
->DataSize
;
1050 DstDataSize
= SrcDataSize
;
1051 if (DataType
== REG_SZ
||
1052 DataType
== REG_EXPAND_SZ
||
1053 DataType
== REG_MULTI_SZ
)
1055 DstDataSize
*= sizeof(WCHAR
);
1059 if (DstDataSize
<= sizeof(BLOCK_OFFSET
))
1061 ValueCell
->DataSize
= DstDataSize
| REG_DATA_IN_OFFSET
;
1062 ValueCell
->DataType
= DataType
;
1065 memexpand ((PWCHAR
)&ValueCell
->DataOffset
,
1071 memcpy (&ValueCell
->DataOffset
,
1078 /* Allocate data cell */
1079 if (!CmiAllocateCell (Hive
,
1080 sizeof(CELL_HEADER
) + DstDataSize
,
1081 (PVOID
*)(PVOID
)&DataCell
,
1087 ValueCell
->DataOffset
= DataCellOffset
;
1088 ValueCell
->DataSize
= DstDataSize
;
1089 ValueCell
->DataType
= DataType
;
1093 if (SrcDataSize
<= sizeof(BLOCK_OFFSET
))
1095 memexpand ((PWCHAR
)DataCell
->Data
,
1101 memexpand ((PWCHAR
)DataCell
->Data
,
1108 memcpy (DataCell
->Data
,
1119 CmiExportSubKey (PREGISTRY_HIVE Hive
,
1120 BLOCK_OFFSET ParentKeyOffset
,
1121 FRLDRHKEY ParentKey
,
1124 BLOCK_OFFSET NKBOffset
;
1125 PKEY_CELL NewKeyCell
;
1133 DbgPrint((DPRINT_REGISTRY
, "CmiExportSubKey('%s') called\n", Key
->Name
));
1135 /* Don't export links */
1136 if (Key
->DataType
== REG_LINK
)
1139 /* Allocate key cell */
1140 KeyCellSize
= sizeof(KEY_CELL
) + Key
->NameSize
- 1;
1141 if (!CmiAllocateCell (Hive
, KeyCellSize
, (PVOID
)&NewKeyCell
, &NKBOffset
))
1143 DbgPrint((DPRINT_REGISTRY
, "CmiAllocateCell() failed\n"));
1147 /* Initialize key cell */
1148 NewKeyCell
->Id
= REG_KEY_CELL_ID
;
1149 NewKeyCell
->Type
= REG_KEY_CELL_TYPE
;
1150 NewKeyCell
->LastWriteTime
= 0ULL;
1151 NewKeyCell
->ParentKeyOffset
= ParentKeyOffset
;
1152 NewKeyCell
->NumberOfSubKeys
= 0;
1153 NewKeyCell
->HashTableOffset
= -1;
1154 NewKeyCell
->NumberOfValues
= 0;
1155 NewKeyCell
->ValueListOffset
= -1;
1156 NewKeyCell
->SecurityKeyOffset
= -1;
1157 NewKeyCell
->ClassNameOffset
= -1;
1158 NewKeyCell
->NameSize
= Key
->NameSize
- 1;
1159 NewKeyCell
->ClassSize
= 0;
1160 memcpy (NewKeyCell
->Name
,
1164 /* Add key cell to the parent key's hash table */
1165 if (!CmiAddKeyToParentHashTable (Hive
,
1170 DbgPrint((DPRINT_REGISTRY
, "CmiAddKeyToParentHashTable() failed\n"));
1174 ValueCount
= RegGetValueCount (Key
);
1175 DbgPrint((DPRINT_REGISTRY
, "ValueCount: %u\n", ValueCount
));
1178 /* Allocate value list cell */
1179 if (!CmiAllocateValueListCell (Hive
,
1180 &NewKeyCell
->ValueListOffset
,
1183 DbgPrint((DPRINT_REGISTRY
, "CmiAllocateValueListCell() failed\n"));
1187 if (Key
->DataSize
!= 0)
1189 if (!CmiExportValue (Hive
, NKBOffset
, Key
, NULL
))
1193 /* Enumerate values */
1194 Entry
= Key
->ValueList
.Flink
;
1195 while (Entry
!= &Key
->ValueList
)
1197 Value
= CONTAINING_RECORD(Entry
,
1201 if (!CmiExportValue (Hive
, NKBOffset
, Key
, Value
))
1204 Entry
= Entry
->Flink
;
1208 SubKeyCount
= RegGetSubKeyCount (Key
);
1209 DbgPrint((DPRINT_REGISTRY
, "SubKeyCount: %u\n", SubKeyCount
));
1210 if (SubKeyCount
> 0)
1212 /* Allocate hash table cell */
1213 if (!CmiAllocateHashTableCell (Hive
,
1214 &NewKeyCell
->HashTableOffset
,
1217 DbgPrint((DPRINT_REGISTRY
, "CmiAllocateHashTableCell() failed\n"));
1221 /* Enumerate subkeys */
1222 Entry
= Key
->SubKeyList
.Flink
;
1223 while (Entry
!= &Key
->SubKeyList
)
1225 SubKey
= CONTAINING_RECORD(Entry
,
1229 if (!CmiExportSubKey (Hive
, NKBOffset
, Key
, SubKey
))
1232 Entry
= Entry
->Flink
;
1241 CmiCalcHiveChecksum (PREGISTRY_HIVE Hive
)
1247 Buffer
= (ULONG
*)Hive
->HiveHeader
;
1249 for (i
= 0; i
< 127; i
++)
1252 Hive
->HiveHeader
->Checksum
= Sum
;
1257 CmiExportHive (PREGISTRY_HIVE Hive
,
1268 DbgPrint((DPRINT_REGISTRY
, "CmiExportHive(%x, '%s') called\n", Hive
, KeyName
));
1270 if (RegOpenKey (NULL
, KeyName
, &Key
) != ERROR_SUCCESS
)
1272 DbgPrint((DPRINT_REGISTRY
, "RegOpenKey() failed\n"));
1276 KeyCell
= CmiGetCell (Hive
, Hive
->HiveHeader
->RootKeyOffset
);
1277 if (KeyCell
== NULL
)
1279 DbgPrint((DPRINT_REGISTRY
, "CmiGetBlock() failed\n"));
1283 ValueCount
= RegGetValueCount (Key
);
1284 DbgPrint((DPRINT_REGISTRY
, "ValueCount: %u\n", ValueCount
));
1287 /* Allocate value list cell */
1288 if (!CmiAllocateValueListCell (Hive
,
1289 &KeyCell
->ValueListOffset
,
1292 DbgPrint((DPRINT_REGISTRY
, "CmiAllocateValueListCell() failed\n"));
1296 if (Key
->DataSize
!= 0)
1298 if (!CmiExportValue (Hive
, Hive
->HiveHeader
->RootKeyOffset
, Key
, NULL
))
1302 /* Enumerate values */
1303 Entry
= Key
->ValueList
.Flink
;
1304 while (Entry
!= &Key
->ValueList
)
1306 Value
= CONTAINING_RECORD(Entry
,
1310 if (!CmiExportValue (Hive
, Hive
->HiveHeader
->RootKeyOffset
, Key
, Value
))
1313 Entry
= Entry
->Flink
;
1317 SubKeyCount
= RegGetSubKeyCount (Key
);
1318 DbgPrint((DPRINT_REGISTRY
, "SubKeyCount: %u\n", SubKeyCount
));
1319 if (SubKeyCount
> 0)
1321 /* Allocate hash table cell */
1322 if (!CmiAllocateHashTableCell (Hive
,
1323 &KeyCell
->HashTableOffset
,
1326 DbgPrint((DPRINT_REGISTRY
, "CmiAllocateHashTableCell() failed\n"));
1330 /* Enumerate subkeys */
1331 Entry
= Key
->SubKeyList
.Flink
;
1332 while (Entry
!= &Key
->SubKeyList
)
1334 SubKey
= CONTAINING_RECORD(Entry
,
1338 if (!CmiExportSubKey (Hive
, Hive
->HiveHeader
->RootKeyOffset
, Key
, SubKey
))
1341 Entry
= Entry
->Flink
;
1345 CmiCalcHiveChecksum (Hive
);
1352 RegImportValue (PHBIN RootBin
,
1353 PVALUE_CELL ValueCell
,
1356 PDATA_CELL DataCell
;
1365 if (ValueCell
->CellSize
>= 0 || ValueCell
->Id
!= REG_VALUE_CELL_ID
)
1367 DbgPrint((DPRINT_REGISTRY
, "Invalid key cell!\n"));
1371 if (ValueCell
->Flags
& REG_VALUE_NAME_PACKED
)
1373 cName
= MmAllocateMemory (ValueCell
->NameSize
+ 1);
1376 ValueCell
->NameSize
);
1377 cName
[ValueCell
->NameSize
] = 0;
1381 wName
= (PWCHAR
)ValueCell
->Name
;
1382 cName
= MmAllocateMemory (ValueCell
->NameSize
/ 2 + 1);
1383 for (i
= 0; i
< ValueCell
->NameSize
/ 2; i
++)
1384 cName
[i
] = (CHAR
)wName
[i
];
1385 cName
[ValueCell
->NameSize
/ 2] = 0;
1388 DataSize
= ValueCell
->DataSize
& REG_DATA_SIZE_MASK
;
1390 DbgPrint((DPRINT_REGISTRY
, "ValueName: '%s'\n", cName
));
1391 DbgPrint((DPRINT_REGISTRY
, "DataSize: %u\n", DataSize
));
1393 if (DataSize
<= sizeof(BLOCK_OFFSET
) && (ValueCell
->DataSize
& REG_DATA_IN_OFFSET
))
1395 Error
= RegSetValue(Key
,
1397 ValueCell
->DataType
,
1398 (PCHAR
)&ValueCell
->DataOffset
,
1400 if (Error
!= ERROR_SUCCESS
)
1402 DbgPrint((DPRINT_REGISTRY
, "RegSetValue() failed!\n"));
1403 MmFreeMemory (cName
);
1409 DataCell
= (PDATA_CELL
)((PUCHAR
)RootBin
+ ValueCell
->DataOffset
);
1410 DbgPrint((DPRINT_REGISTRY
, "DataCell: %x\n", DataCell
));
1412 if (DataCell
->CellSize
>= 0)
1414 DbgPrint((DPRINT_REGISTRY
, "Invalid data cell size!\n"));
1415 MmFreeMemory (cName
);
1419 if (ValueCell
->DataType
== REG_SZ
||
1420 ValueCell
->DataType
== REG_EXPAND_SZ
||
1421 ValueCell
->DataType
== REG_MULTI_SZ
)
1423 wBuffer
= (PWCHAR
)DataCell
->Data
;
1424 cBuffer
= MmAllocateMemory(DataSize
/2);
1425 for (i
= 0; i
< DataSize
/ 2; i
++)
1426 cBuffer
[i
] = (CHAR
)wBuffer
[i
];
1428 Error
= RegSetValue (Key
,
1430 ValueCell
->DataType
,
1434 MmFreeMemory(cBuffer
);
1438 Error
= RegSetValue (Key
,
1440 ValueCell
->DataType
,
1444 if (Error
!= ERROR_SUCCESS
)
1446 DbgPrint((DPRINT_REGISTRY
, "RegSetValue() failed!\n"));
1447 MmFreeMemory (cName
);
1452 MmFreeMemory (cName
);
1459 RegImportSubKey(PHBIN RootBin
,
1461 FRLDRHKEY ParentKey
)
1463 PHASH_TABLE_CELL HashCell
;
1464 PKEY_CELL SubKeyCell
;
1465 PVALUE_LIST_CELL ValueListCell
;
1466 PVALUE_CELL ValueCell
= NULL
;
1473 DbgPrint((DPRINT_REGISTRY
, "KeyCell: %x\n", KeyCell
));
1474 DbgPrint((DPRINT_REGISTRY
, "KeyCell->CellSize: %x\n", KeyCell
->CellSize
));
1475 DbgPrint((DPRINT_REGISTRY
, "KeyCell->Id: %x\n", KeyCell
->Id
));
1476 if (KeyCell
->Id
!= REG_KEY_CELL_ID
|| KeyCell
->CellSize
>= 0)
1478 DbgPrint((DPRINT_REGISTRY
, "Invalid key cell id!\n"));
1482 /* FIXME: implement packed key names */
1483 cName
= MmAllocateMemory (KeyCell
->NameSize
+ 1);
1487 cName
[KeyCell
->NameSize
] = 0;
1489 DbgPrint((DPRINT_REGISTRY
, "KeyName: '%s'\n", cName
));
1491 /* Create new sub key */
1492 Error
= RegCreateKey (ParentKey
,
1495 MmFreeMemory (cName
);
1496 if (Error
!= ERROR_SUCCESS
)
1498 DbgPrint((DPRINT_REGISTRY
, "RegCreateKey() failed!\n"));
1501 DbgPrint((DPRINT_REGISTRY
, "Subkeys: %u\n", KeyCell
->NumberOfSubKeys
));
1502 DbgPrint((DPRINT_REGISTRY
, "Values: %u\n", KeyCell
->NumberOfValues
));
1504 /* Enumerate and add values */
1505 if (KeyCell
->NumberOfValues
> 0)
1507 ValueListCell
= (PVALUE_LIST_CELL
)((PUCHAR
)RootBin
+ KeyCell
->ValueListOffset
);
1508 DbgPrint((DPRINT_REGISTRY
, "ValueListCell: %x\n", ValueListCell
));
1510 for (i
= 0; i
< KeyCell
->NumberOfValues
; i
++)
1512 DbgPrint((DPRINT_REGISTRY
, "ValueOffset[%d]: %x\n", i
, ValueListCell
->ValueOffset
[i
]));
1514 ValueCell
= (PVALUE_CELL
)((PUCHAR
)RootBin
+ ValueListCell
->ValueOffset
[i
]);
1516 DbgPrint((DPRINT_REGISTRY
, "ValueCell[%d]: %x\n", i
, ValueCell
));
1518 if (!RegImportValue(RootBin
, ValueCell
, SubKey
))
1523 /* Enumerate and add subkeys */
1524 if (KeyCell
->NumberOfSubKeys
> 0)
1526 HashCell
= (PHASH_TABLE_CELL
)((PUCHAR
)RootBin
+ KeyCell
->HashTableOffset
);
1527 DbgPrint((DPRINT_REGISTRY
, "HashCell: %x\n", HashCell
));
1529 for (i
= 0; i
< KeyCell
->NumberOfSubKeys
; i
++)
1531 DbgPrint((DPRINT_REGISTRY
, "KeyOffset[%d]: %x\n", i
, HashCell
->Table
[i
].KeyOffset
));
1533 SubKeyCell
= (PKEY_CELL
)((PUCHAR
)RootBin
+ HashCell
->Table
[i
].KeyOffset
);
1535 DbgPrint((DPRINT_REGISTRY
, "SubKeyCell[%d]: %x\n", i
, SubKeyCell
));
1537 if (!RegImportSubKey(RootBin
, SubKeyCell
, SubKey
))
1547 RegImportBinaryHive(PCHAR ChunkBase
,
1550 PHIVE_HEADER HiveHeader
;
1553 PHASH_TABLE_CELL HashCell
;
1554 PKEY_CELL SubKeyCell
;
1555 FRLDRHKEY SystemKey
;
1559 DbgPrint((DPRINT_REGISTRY
, "RegImportBinaryHive(%x, %u) called\n",ChunkBase
,ChunkSize
));
1561 HiveHeader
= (PHIVE_HEADER
)ChunkBase
;
1562 DbgPrint((DPRINT_REGISTRY
, "HiveHeader: %x\n", HiveHeader
));
1563 if (HiveHeader
->BlockId
!= REG_HIVE_ID
)
1565 DbgPrint((DPRINT_REGISTRY
, "Invalid hive id!\n"));
1569 RootBin
= (PHBIN
)((ULONG
)HiveHeader
+ REG_BLOCK_SIZE
);
1570 DbgPrint((DPRINT_REGISTRY
, "RootBin: %x\n", RootBin
));
1571 if (RootBin
->HeaderId
!= REG_BIN_ID
|| RootBin
->BinSize
== 0)
1573 DbgPrint((DPRINT_REGISTRY
, "Invalid bin id!\n"));
1577 KeyCell
= (PKEY_CELL
)((ULONG
)RootBin
+ REG_HBIN_DATA_OFFSET
);
1578 DbgPrint((DPRINT_REGISTRY
, "KeyCell: %x\n", KeyCell
));
1579 DbgPrint((DPRINT_REGISTRY
, "KeyCell->CellSize: %x\n", KeyCell
->CellSize
));
1580 DbgPrint((DPRINT_REGISTRY
, "KeyCell->Id: %x\n", KeyCell
->Id
));
1581 if (KeyCell
->Id
!= REG_KEY_CELL_ID
|| KeyCell
->CellSize
>= 0)
1583 DbgPrint((DPRINT_REGISTRY
, "Invalid key cell id!\n"));
1587 DbgPrint((DPRINT_REGISTRY
, "Subkeys: %u\n", KeyCell
->NumberOfSubKeys
));
1588 DbgPrint((DPRINT_REGISTRY
, "Values: %u\n", KeyCell
->NumberOfValues
));
1590 /* Open 'System' key */
1591 Error
= RegOpenKey(NULL
,
1592 "\\Registry\\Machine\\SYSTEM",
1594 if (Error
!= ERROR_SUCCESS
)
1596 DbgPrint((DPRINT_REGISTRY
, "Failed to open 'system' key!\n"));
1600 /* Enumerate and add subkeys */
1601 if (KeyCell
->NumberOfSubKeys
> 0)
1603 HashCell
= (PHASH_TABLE_CELL
)((ULONG
)RootBin
+ KeyCell
->HashTableOffset
);
1604 DbgPrint((DPRINT_REGISTRY
, "HashCell: %x\n", HashCell
));
1606 for (i
= 0; i
< KeyCell
->NumberOfSubKeys
; i
++)
1608 DbgPrint((DPRINT_REGISTRY
, "KeyOffset[%d]: %x\n", i
, HashCell
->Table
[i
].KeyOffset
));
1610 SubKeyCell
= (PKEY_CELL
)((ULONG
)RootBin
+ HashCell
->Table
[i
].KeyOffset
);
1612 DbgPrint((DPRINT_REGISTRY
, "SubKeyCell[%d]: %x\n", i
, SubKeyCell
));
1614 if (!RegImportSubKey(RootBin
, SubKeyCell
, SystemKey
))
1624 RegExportBinaryHive(PCSTR KeyName
,
1628 PREGISTRY_HIVE Hive
;
1630 DbgPrint((DPRINT_REGISTRY
, "Creating binary hardware hive\n"));
1633 InitMbMemory (ChunkBase
);
1635 Hive
= CmiCreateHive (KeyName
);
1639 if (!CmiExportHive (Hive
, KeyName
))
1641 CmiCleanupHive (Hive
, TRUE
);
1645 CmiCleanupHive (Hive
, FALSE
);
1647 *ChunkSize
= GetMbAllocatedSize ();