3 * Copyright (C) 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* $Id: binhive.c,v 1.4 2003/05/18 13:50:58 ekohl Exp $
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS hive maker
22 * FILE: tools/mkhive/binhive.c
23 * PURPOSE: Binary hive export code
24 * PROGRAMMER: Eric Kohl
27 /* INCLUDES *****************************************************************/
38 #define REG_HIVE_ID 0x66676572
39 #define REG_BIN_ID 0x6e696268
40 #define REG_KEY_CELL_ID 0x6b6e
41 #define REG_HASH_TABLE_BLOCK_ID 0x666c
42 #define REG_VALUE_CELL_ID 0x6b76
44 #define REG_BLOCK_SIZE 4096
45 #define REG_HBIN_DATA_OFFSET 32
46 #define REG_INIT_BLOCK_LIST_SIZE 32
47 #define REG_INIT_HASH_TABLE_SIZE 3
48 #define REG_EXTEND_HASH_TABLE_SIZE 4
49 #define REG_VALUE_LIST_CELL_MULTIPLE 4
51 #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
52 #define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
54 #define ABS_VALUE(V) (((V) < 0) ? -(V) : (V))
57 // BLOCK_OFFSET = offset in file after header block
58 typedef ULONG BLOCK_OFFSET
, *PBLOCK_OFFSET
;
60 typedef unsigned long long FILETIME
;
62 /* header for registry hive file : */
63 typedef struct _HIVE_HEADER
65 /* Hive identifier "regf" (0x66676572) */
74 /* When this hive file was last modified */
75 FILETIME DateModified
;
77 /* Registry format version ? (1?) */
80 /* Registry format version ? (3?) */
83 /* Registry format version ? (0?) */
86 /* Registry format version ? (1?) */
89 /* Offset into file from the byte after the end of the base block.
90 If the hive is volatile, this is the actual pointer to the KEY_CELL */
91 BLOCK_OFFSET RootKeyCell
;
93 /* Size of each hive block ? */
99 /* Name of hive file */
105 /* Checksum of first 0x200 bytes */
107 } __attribute__((packed
)) HIVE_HEADER
, *PHIVE_HEADER
;
111 /* Bin identifier "hbin" (0x6E696268) */
114 /* Block offset of this bin */
115 BLOCK_OFFSET BlockOffset
;
117 /* Size in bytes, multiple of the block size (4KB) */
123 /* When this bin was last modified */
124 FILETIME DateModified
;
128 } __attribute__((packed
)) HBIN
, *PHBIN
;
130 typedef struct _CELL_HEADER
132 /* <0 if used, >0 if free */
134 } __attribute__((packed
)) CELL_HEADER
, *PCELL_HEADER
;
136 typedef struct _KEY_CELL
138 /* Size of this cell */
141 /* Key cell identifier "kn" (0x6b6e) */
147 /* Time of last flush */
148 FILETIME LastWriteTime
;
153 /* Block offset of parent key cell */
154 BLOCK_OFFSET ParentKeyOffset
;
156 /* Count of sub keys for the key in this key cell */
157 ULONG NumberOfSubKeys
;
162 /* Block offset of has table for FIXME: subkeys/values? */
163 BLOCK_OFFSET HashTableOffset
;
168 /* Count of values contained in this key cell */
169 ULONG NumberOfValues
;
171 /* Block offset of VALUE_LIST_CELL */
172 BLOCK_OFFSET ValuesOffset
;
174 /* Block offset of security cell */
175 BLOCK_OFFSET SecurityKeyOffset
;
177 /* Block offset of registry key class */
178 BLOCK_OFFSET ClassNameOffset
;
183 /* Size in bytes of key name */
186 /* Size of class name in bytes */
189 /* Name of key (not zero terminated) */
191 } __attribute__((packed
)) KEY_CELL
, *PKEY_CELL
;
193 /* KEY_CELL.Type constants */
194 #define REG_LINK_KEY_CELL_TYPE 0x10
195 #define REG_KEY_CELL_TYPE 0x20
196 #define REG_ROOT_KEY_CELL_TYPE 0x2c
200 // HashValue=four letters of value's name
201 typedef struct _HASH_RECORD
203 BLOCK_OFFSET KeyOffset
;
205 } __attribute__((packed
)) HASH_RECORD
, *PHASH_RECORD
;
207 typedef struct _HASH_TABLE_CELL
211 USHORT HashTableSize
;
212 HASH_RECORD Table
[0];
213 } __attribute__((packed
)) HASH_TABLE_CELL
, *PHASH_TABLE_CELL
;
215 typedef struct _VALUE_LIST_CELL
218 BLOCK_OFFSET Values
[0];
219 } __attribute__((packed
)) VALUE_LIST_CELL
, *PVALUE_LIST_CELL
;
221 typedef struct _VALUE_CELL
225 USHORT NameSize
; // length of Name
226 LONG DataSize
; // length of datas in the cell pointed by DataOffset
227 BLOCK_OFFSET DataOffset
;// datas are here if high bit of DataSize is set
231 UCHAR Name
[0]; /* warning : not zero terminated */
232 } __attribute__((packed
)) VALUE_CELL
, *PVALUE_CELL
;
234 /* VALUE_CELL.Flags constants */
235 #define REG_VALUE_NAME_PACKED 0x0001
238 typedef struct _DATA_CELL
242 } __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
;
256 /* FUNCTIONS ****************************************************************/
259 CmiCreateDefaultHiveHeader(PHIVE_HEADER Header
)
262 memset (Header
, 0, REG_BLOCK_SIZE
);
263 Header
->BlockId
= REG_HIVE_ID
;
264 Header
->UpdateCounter1
= 0;
265 Header
->UpdateCounter2
= 0;
266 Header
->DateModified
= 0ULL;
272 Header
->RootKeyCell
= 0;
273 Header
->BlockSize
= REG_BLOCK_SIZE
;
275 Header
->Checksum
= 0;
280 CmiCreateDefaultBinCell(PHBIN BinCell
)
283 memset (BinCell
, 0, REG_BLOCK_SIZE
);
284 BinCell
->BlockId
= REG_BIN_ID
;
285 BinCell
->DateModified
= 0ULL;
286 BinCell
->BlockSize
= REG_BLOCK_SIZE
;
291 CmiCreateDefaultRootKeyCell(PKEY_CELL RootKeyCell
)
294 memset (RootKeyCell
, 0, sizeof(KEY_CELL
));
295 RootKeyCell
->CellSize
= -sizeof(KEY_CELL
);
296 RootKeyCell
->Id
= REG_KEY_CELL_ID
;
297 RootKeyCell
->Type
= REG_ROOT_KEY_CELL_TYPE
;
298 RootKeyCell
->LastWriteTime
= 0ULL;
299 RootKeyCell
->ParentKeyOffset
= 0;
300 RootKeyCell
->NumberOfSubKeys
= 0;
301 RootKeyCell
->HashTableOffset
= -1;
302 RootKeyCell
->NumberOfValues
= 0;
303 RootKeyCell
->ValuesOffset
= -1;
304 RootKeyCell
->SecurityKeyOffset
= 0;
305 RootKeyCell
->ClassNameOffset
= -1;
306 RootKeyCell
->NameSize
= 0;
307 RootKeyCell
->ClassSize
= 0;
311 static PREGISTRY_HIVE
312 CmiCreateRegistryHive (VOID
)
315 PCELL_HEADER FreeCell
;
316 PKEY_CELL RootKeyCell
;
319 Hive
= (PREGISTRY_HIVE
) malloc (sizeof(REGISTRY_HIVE
));
324 memset (Hive
, 0, sizeof(REGISTRY_HIVE
));
326 DPRINT("Hive %x\n", Hive
);
328 /* Create hive beader (aka 'base block') */
329 Hive
->HiveHeader
= (PHIVE_HEADER
) malloc (REG_BLOCK_SIZE
);
330 if (Hive
->HiveHeader
== NULL
)
335 CmiCreateDefaultHiveHeader(Hive
->HiveHeader
);
336 Hive
->FileSize
= REG_BLOCK_SIZE
;
338 /* Allocate block list */
339 Hive
->BlockListSize
= 1;
340 Hive
->BlockList
= malloc (sizeof(PHBIN
) * Hive
->BlockListSize
);
341 if (Hive
->BlockList
== NULL
)
343 free (Hive
->HiveHeader
);
348 /* Allocate free cell list */
349 Hive
->FreeListMax
= 32;
350 Hive
->FreeList
= malloc(sizeof(PCELL_HEADER
) * Hive
->FreeListMax
);
351 if (Hive
->FreeList
== NULL
)
353 free (Hive
->BlockList
);
354 free (Hive
->HiveHeader
);
358 Hive
->FreeListOffset
= malloc(sizeof(BLOCK_OFFSET
) * Hive
->FreeListMax
);
359 if (Hive
->FreeListOffset
== NULL
)
361 free (Hive
->FreeList
);
362 free (Hive
->BlockList
);
363 free (Hive
->HiveHeader
);
368 /* Allocate first bin */
369 Hive
->BlockList
[0] = (PHBIN
) malloc (REG_BLOCK_SIZE
);
370 if (Hive
->BlockList
[0] == NULL
)
372 free (Hive
->FreeListOffset
);
373 free (Hive
->FreeList
);
374 free (Hive
->BlockList
);
375 free (Hive
->HiveHeader
);
379 Hive
->FileSize
+= REG_BLOCK_SIZE
;
382 BinCell
= (PHBIN
)Hive
->BlockList
[0];
383 CmiCreateDefaultBinCell(BinCell
);
384 BinCell
->BlockOffset
= 0;
386 /* Init root key cell */
387 RootKeyCell
= (PKEY_CELL
)((ULONG_PTR
)BinCell
+ REG_HBIN_DATA_OFFSET
);
388 CmiCreateDefaultRootKeyCell(RootKeyCell
);
389 Hive
->HiveHeader
->RootKeyCell
= REG_HBIN_DATA_OFFSET
;
392 FreeCell
= (PCELL_HEADER
)((ULONG_PTR
)RootKeyCell
+ sizeof(KEY_CELL
));
393 FreeCell
->CellSize
= REG_BLOCK_SIZE
- (REG_HBIN_DATA_OFFSET
+ sizeof(KEY_CELL
));
395 Hive
->FreeList
[0] = FreeCell
;
396 Hive
->FreeListOffset
[0] = REG_HBIN_DATA_OFFSET
+ sizeof(KEY_CELL
);
397 Hive
->FreeListSize
++;
404 CmiDestroyRegistryHive (PREGISTRY_HIVE Hive
)
412 /* Release free offset list */
413 if (Hive
->FreeListOffset
!= NULL
)
414 free (Hive
->FreeListOffset
);
416 /* Release free list */
417 if (Hive
->FreeList
!= NULL
)
418 free (Hive
->FreeList
);
420 if (Hive
->BlockList
!= NULL
)
424 for (i
= 0; i
< Hive
->BlockListSize
; i
++)
426 if ((Hive
->BlockList
[i
] != NULL
) &&
427 (Hive
->BlockList
[i
] != Bin
))
429 Bin
= Hive
->BlockList
[i
];
431 DPRINT ("Bin[%lu]: Offset 0x%lx Size 0x%lx\n",
432 i
, Bin
->BlockOffset
, Bin
->BlockSize
);
438 /* Release block list */
439 free (Hive
->BlockList
);
442 /* Release hive header */
443 if (Hive
->HiveHeader
!= NULL
)
444 free (Hive
->HiveHeader
);
452 CmiGetBlock(PREGISTRY_HIVE Hive
,
453 BLOCK_OFFSET BlockOffset
,
462 if (BlockOffset
== (ULONG_PTR
) -1)
465 BlockIndex
= BlockOffset
/ 4096;
466 if (BlockIndex
>= Hive
->BlockListSize
)
469 pBin
= Hive
->BlockList
[BlockIndex
];
473 return (PVOID
)((ULONG_PTR
)pBin
+ (BlockOffset
- pBin
->BlockOffset
));
478 CmiMergeFree(PREGISTRY_HIVE RegistryHive
,
479 PCELL_HEADER FreeBlock
,
480 BLOCK_OFFSET FreeOffset
)
482 BLOCK_OFFSET BlockOffset
;
483 BLOCK_OFFSET BinOffset
;
489 DPRINT("CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
490 FreeBlock
, FreeOffset
, FreeBlock
->CellSize
);
492 CmiGetBlock(RegistryHive
,
495 DPRINT("Bin %p\n", Bin
);
499 BinOffset
= Bin
->BlockOffset
;
500 BinSize
= Bin
->BlockSize
;
501 DPRINT("Bin %p Offset %lx Size %lx\n", Bin
, BinOffset
, BinSize
);
503 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
505 BlockOffset
= RegistryHive
->FreeListOffset
[i
];
506 BlockSize
= RegistryHive
->FreeList
[i
]->CellSize
;
507 if (BlockOffset
> BinOffset
&&
508 BlockOffset
< BinOffset
+ BinSize
)
510 DPRINT("Free block: Offset %lx Size %lx\n",
511 BlockOffset
, BlockSize
);
513 if ((i
< (RegistryHive
->FreeListSize
- 1)) &&
514 (BlockOffset
+ BlockSize
== FreeOffset
) &&
515 (FreeOffset
+ FreeBlock
->CellSize
== RegistryHive
->FreeListOffset
[i
+ 1]))
517 DPRINT("Merge current block with previous and next block\n");
519 RegistryHive
->FreeList
[i
]->CellSize
+=
520 (FreeBlock
->CellSize
+ RegistryHive
->FreeList
[i
+ 1]->CellSize
);
522 FreeBlock
->CellSize
= 0;
523 RegistryHive
->FreeList
[i
+ 1]->CellSize
= 0;
526 if ((i
+ 2) < RegistryHive
->FreeListSize
)
528 memmove (&RegistryHive
->FreeList
[i
+ 1],
529 &RegistryHive
->FreeList
[i
+ 2],
530 sizeof(RegistryHive
->FreeList
[0])
531 * (RegistryHive
->FreeListSize
- i
- 2));
532 memmove (&RegistryHive
->FreeListOffset
[i
+ 1],
533 &RegistryHive
->FreeListOffset
[i
+ 2],
534 sizeof(RegistryHive
->FreeListOffset
[0])
535 * (RegistryHive
->FreeListSize
- i
- 2));
537 RegistryHive
->FreeListSize
--;
541 else if (BlockOffset
+ BlockSize
== FreeOffset
)
543 DPRINT("Merge current block with previous block\n");
545 RegistryHive
->FreeList
[i
]->CellSize
+= FreeBlock
->CellSize
;
546 FreeBlock
->CellSize
= 0;
550 else if (FreeOffset
+ FreeBlock
->CellSize
== BlockOffset
)
552 DPRINT("Merge current block with next block\n");
554 FreeBlock
->CellSize
+= RegistryHive
->FreeList
[i
]->CellSize
;
555 RegistryHive
->FreeList
[i
]->CellSize
= 0;
556 RegistryHive
->FreeList
[i
] = FreeBlock
;
557 RegistryHive
->FreeListOffset
[i
] = FreeOffset
;
569 CmiAddFree(PREGISTRY_HIVE RegistryHive
,
570 PCELL_HEADER FreeBlock
,
571 BLOCK_OFFSET FreeOffset
,
572 BOOL MergeFreeBlocks
)
574 PCELL_HEADER
*tmpList
;
575 BLOCK_OFFSET
*tmpListOffset
;
580 assert(RegistryHive
);
583 DPRINT("FreeBlock %.08lx FreeOffset %.08lx\n",
584 FreeBlock
, FreeOffset
);
586 /* Merge free blocks */
587 if (MergeFreeBlocks
== TRUE
)
589 if (CmiMergeFree(RegistryHive
, FreeBlock
, FreeOffset
))
593 if ((RegistryHive
->FreeListSize
+ 1) > RegistryHive
->FreeListMax
)
595 tmpList
= malloc (sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
+ 32));
601 tmpListOffset
= malloc (sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
+ 32));
602 if (tmpListOffset
== NULL
)
608 if (RegistryHive
->FreeListMax
)
611 RegistryHive
->FreeList
,
612 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
));
613 memmove (tmpListOffset
,
614 RegistryHive
->FreeListOffset
,
615 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
));
616 free (RegistryHive
->FreeList
);
617 free (RegistryHive
->FreeListOffset
);
619 RegistryHive
->FreeList
= tmpList
;
620 RegistryHive
->FreeListOffset
= tmpListOffset
;
621 RegistryHive
->FreeListMax
+= 32;
624 /* Add new offset to free list, maintaining list in ascending order */
625 if ((RegistryHive
->FreeListSize
== 0)
626 || (RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
-1] < FreeOffset
))
628 /* Add to end of list */
629 RegistryHive
->FreeList
[RegistryHive
->FreeListSize
] = FreeBlock
;
630 RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
++] = FreeOffset
;
632 else if (RegistryHive
->FreeListOffset
[0] > FreeOffset
)
634 /* Add to begin of list */
635 memmove (&RegistryHive
->FreeList
[1],
636 &RegistryHive
->FreeList
[0],
637 sizeof(RegistryHive
->FreeList
[0]) * RegistryHive
->FreeListSize
);
638 memmove (&RegistryHive
->FreeListOffset
[1],
639 &RegistryHive
->FreeListOffset
[0],
640 sizeof(RegistryHive
->FreeListOffset
[0]) * RegistryHive
->FreeListSize
);
641 RegistryHive
->FreeList
[0] = FreeBlock
;
642 RegistryHive
->FreeListOffset
[0] = FreeOffset
;
643 RegistryHive
->FreeListSize
++;
647 /* Search where to insert */
649 maxInd
= RegistryHive
->FreeListSize
- 1;
650 while ((maxInd
- minInd
) > 1)
652 medInd
= (minInd
+ maxInd
) / 2;
653 if (RegistryHive
->FreeListOffset
[medInd
] > FreeOffset
)
659 /* Insert before maxInd */
660 memmove (&RegistryHive
->FreeList
[maxInd
+1],
661 &RegistryHive
->FreeList
[maxInd
],
662 sizeof(RegistryHive
->FreeList
[0]) * (RegistryHive
->FreeListSize
- minInd
));
663 memmove (&RegistryHive
->FreeListOffset
[maxInd
+ 1],
664 &RegistryHive
->FreeListOffset
[maxInd
],
665 sizeof(RegistryHive
->FreeListOffset
[0]) * (RegistryHive
->FreeListSize
-minInd
));
666 RegistryHive
->FreeList
[maxInd
] = FreeBlock
;
667 RegistryHive
->FreeListOffset
[maxInd
] = FreeOffset
;
668 RegistryHive
->FreeListSize
++;
676 CmiAddBin(PREGISTRY_HIVE RegistryHive
,
678 PBLOCK_OFFSET NewBlockOffset
)
680 PCELL_HEADER tmpBlock
;
681 PHBIN
* tmpBlockList
;
684 tmpBin
= malloc (REG_BLOCK_SIZE
);
689 memset (tmpBin
, 0, REG_BLOCK_SIZE
);
691 tmpBin
->BlockId
= REG_BIN_ID
;
692 tmpBin
->BlockOffset
= RegistryHive
->FileSize
- REG_BLOCK_SIZE
;
693 RegistryHive
->FileSize
+= REG_BLOCK_SIZE
;
694 tmpBin
->BlockSize
= REG_BLOCK_SIZE
;
696 tmpBin
->DateModified
= 0ULL;
699 /* Increase size of list of blocks */
700 tmpBlockList
= malloc (sizeof(PHBIN
) * (RegistryHive
->BlockListSize
+ 1));
701 if (tmpBlockList
== NULL
)
707 if (RegistryHive
->BlockListSize
> 0)
709 memcpy (tmpBlockList
,
710 RegistryHive
->BlockList
,
711 sizeof(PHBIN
) * RegistryHive
->BlockListSize
);
712 free (RegistryHive
->BlockList
);
715 RegistryHive
->BlockList
= tmpBlockList
;
716 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
++] = tmpBin
;
718 /* Initialize a free block in this heap : */
719 tmpBlock
= (PCELL_HEADER
)((ULONG_PTR
) tmpBin
+ REG_HBIN_DATA_OFFSET
);
720 tmpBlock
->CellSize
= (REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
);
722 *NewBlock
= (PVOID
) tmpBlock
;
725 *NewBlockOffset
= tmpBin
->BlockOffset
+ REG_HBIN_DATA_OFFSET
;
732 CmiAllocateBlock(PREGISTRY_HIVE RegistryHive
,
735 PBLOCK_OFFSET pBlockOffset
)
737 PCELL_HEADER NewBlock
;
743 /* Round to 16 bytes multiple */
744 BlockSize
= (BlockSize
+ sizeof(ULONG
) + 15) & 0xfffffff0;
746 /* first search in free blocks */
748 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
750 if (RegistryHive
->FreeList
[i
]->CellSize
>= BlockSize
)
752 NewBlock
= RegistryHive
->FreeList
[i
];
754 *pBlockOffset
= RegistryHive
->FreeListOffset
[i
];
756 if ((i
+ 1) < RegistryHive
->FreeListSize
)
758 memmove (&RegistryHive
->FreeList
[i
],
759 &RegistryHive
->FreeList
[i
+ 1],
760 sizeof(RegistryHive
->FreeList
[0])
761 * (RegistryHive
->FreeListSize
- i
- 1));
762 memmove (&RegistryHive
->FreeListOffset
[i
],
763 &RegistryHive
->FreeListOffset
[i
+ 1],
764 sizeof(RegistryHive
->FreeListOffset
[0])
765 * (RegistryHive
->FreeListSize
- i
- 1));
767 RegistryHive
->FreeListSize
--;
772 /* Need to extend hive file : */
773 if (NewBlock
== NULL
)
775 /* Add a new block */
776 if (!CmiAddBin(RegistryHive
, (PVOID
*)&NewBlock
, pBlockOffset
))
782 /* Split the block in two parts */
783 if (NewBlock
->CellSize
> BlockSize
)
785 NewBlock
= (PCELL_HEADER
) ((ULONG_PTR
) NewBlock
+BlockSize
);
786 NewBlock
->CellSize
= ((PCELL_HEADER
) (*Block
))->CellSize
- BlockSize
;
787 CmiAddFree (RegistryHive
,
789 *pBlockOffset
+ BlockSize
,
792 else if (NewBlock
->CellSize
< BlockSize
)
797 memset(*Block
, 0, BlockSize
);
798 ((PCELL_HEADER
)(*Block
))->CellSize
= -BlockSize
;
805 CmiAllocateHashTableCell (PREGISTRY_HIVE Hive
,
806 PBLOCK_OFFSET HBOffset
,
809 PHASH_TABLE_CELL HashCell
;
813 NewHashSize
= ROUND_UP(sizeof(HASH_TABLE_CELL
) +
814 (SubKeyCount
- 1) * sizeof(HASH_RECORD
),
816 Status
= CmiAllocateBlock (Hive
,
820 if ((HashCell
== NULL
) || (Status
== FALSE
))
825 HashCell
->Id
= REG_HASH_TABLE_BLOCK_ID
;
826 HashCell
->HashTableSize
= SubKeyCount
;
833 CmiAddKeyToParentHashTable (PREGISTRY_HIVE Hive
,
834 BLOCK_OFFSET ParentKeyOffset
,
835 PKEY_CELL NewKeyCell
,
836 BLOCK_OFFSET NKBOffset
)
838 PHASH_TABLE_CELL HashBlock
;
839 PKEY_CELL ParentKeyCell
;
842 ParentKeyCell
= CmiGetBlock (Hive
,
845 if (ParentKeyCell
== NULL
)
847 DPRINT1 ("CmiGetBlock() failed\n");
851 HashBlock
=CmiGetBlock (Hive
,
852 ParentKeyCell
->HashTableOffset
,
854 if (HashBlock
== NULL
)
856 DPRINT1 ("CmiGetBlock() failed\n");
860 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
862 if (HashBlock
->Table
[i
].KeyOffset
== 0)
864 HashBlock
->Table
[i
].KeyOffset
= NKBOffset
;
865 memcpy (&HashBlock
->Table
[i
].HashValue
,
868 ParentKeyCell
->NumberOfSubKeys
++;
878 CmiAllocateValueListCell (PREGISTRY_HIVE Hive
,
879 PBLOCK_OFFSET ValueListOffset
,
882 PVALUE_LIST_CELL ValueListCell
;
886 ValueListSize
= ROUND_UP (ValueCount
* sizeof(BLOCK_OFFSET
),
888 Status
= CmiAllocateBlock (Hive
,
889 (PVOID
)&ValueListCell
,
892 if ((ValueListCell
== NULL
) || (Status
== FALSE
))
894 DPRINT1 ("CmiAllocateBlock() failed\n");
903 CmiAllocateValueCell(PREGISTRY_HIVE Hive
,
904 PVALUE_CELL
*ValueCell
,
905 BLOCK_OFFSET
*ValueCellOffset
,
908 PVALUE_CELL NewValueCell
;
912 NameSize
= (ValueName
== NULL
) ? 0 : strlen (ValueName
);
913 Status
= CmiAllocateBlock(Hive
,
914 (PVOID
*)&NewValueCell
,
915 sizeof(VALUE_CELL
) + NameSize
,
917 if ((NewValueCell
== NULL
) || (Status
== FALSE
))
919 DPRINT1 ("CmiAllocateBlock() failed\n");
923 NewValueCell
->Id
= REG_VALUE_CELL_ID
;
924 NewValueCell
->NameSize
= NameSize
;
927 memcpy (NewValueCell
->Name
,
930 NewValueCell
->Flags
= REG_VALUE_NAME_PACKED
;
932 NewValueCell
->DataType
= 0;
933 NewValueCell
->DataSize
= 0;
934 NewValueCell
->DataOffset
= -1;
936 *ValueCell
= NewValueCell
;
943 CmiAddValueToKeyValueList(PREGISTRY_HIVE Hive
,
944 BLOCK_OFFSET KeyCellOffset
,
945 BLOCK_OFFSET ValueCellOffset
)
947 PVALUE_LIST_CELL ValueListCell
;
950 KeyCell
= CmiGetBlock (Hive
, KeyCellOffset
, NULL
);
953 DPRINT1 ("CmiGetBlock() failed\n");
957 ValueListCell
= CmiGetBlock (Hive
, KeyCell
->ValuesOffset
, NULL
);
958 if (ValueListCell
== NULL
)
960 DPRINT1 ("CmiGetBlock() failed\n");
964 ValueListCell
->Values
[KeyCell
->NumberOfValues
] = ValueCellOffset
;
965 KeyCell
->NumberOfValues
++;
972 memexpand (PWCHAR Dst
,
978 for (i
= 0; i
< Length
; i
++)
979 Dst
[i
] = (WCHAR
)Src
[i
];
984 CmiExportValue (PREGISTRY_HIVE Hive
,
985 BLOCK_OFFSET KeyCellOffset
,
989 BLOCK_OFFSET ValueCellOffset
;
990 BLOCK_OFFSET DataCellOffset
;
991 PVALUE_CELL ValueCell
;
999 DPRINT ("CmiExportValue('%s') called\n", (Value
== NULL
) ? "<default>" : (PCHAR
)Value
->Name
);
1000 DPRINT ("DataSize %lu\n", (Value
== NULL
) ? Key
->DataSize
: Value
->DataSize
);
1002 /* Allocate value cell */
1003 if (!CmiAllocateValueCell(Hive
, &ValueCell
, &ValueCellOffset
, (Value
== NULL
) ? NULL
: Value
->Name
))
1008 if (!CmiAddValueToKeyValueList(Hive
, KeyCellOffset
, ValueCellOffset
))
1015 DataType
= Key
->DataType
;
1016 SrcDataSize
= Key
->DataSize
;
1021 DataType
= Value
->DataType
;
1022 SrcDataSize
= Value
->DataSize
;
1026 DstDataSize
= SrcDataSize
;
1027 if (DataType
== REG_SZ
||
1028 DataType
== REG_EXPAND_SZ
||
1029 DataType
== REG_MULTI_SZ
)
1031 DstDataSize
*= sizeof(WCHAR
);
1035 if (DstDataSize
<= sizeof(BLOCK_OFFSET
))
1037 ValueCell
->DataSize
= DstDataSize
| 0x80000000;
1038 ValueCell
->DataType
= DataType
;
1041 memexpand ((PWCHAR
)&ValueCell
->DataOffset
,
1047 memcpy (&ValueCell
->DataOffset
,
1054 if (!CmiAllocateBlock (Hive
,
1062 ValueCell
->DataOffset
= DataCellOffset
;
1063 ValueCell
->DataSize
= DstDataSize
;
1064 ValueCell
->DataType
= DataType
;
1068 if (SrcDataSize
<= sizeof(BLOCK_OFFSET
))
1070 memexpand ((PWCHAR
)DataCell
->Data
,
1076 memexpand ((PWCHAR
)DataCell
->Data
,
1083 memcpy (DataCell
->Data
,
1094 CmiExportSubKey (PREGISTRY_HIVE Hive
,
1095 BLOCK_OFFSET ParentKeyOffset
,
1099 BLOCK_OFFSET NKBOffset
;
1100 PKEY_CELL NewKeyCell
;
1108 DPRINT ("CmiExportSubKey('%s') called\n", Key
->Name
);
1110 /* Don't export links */
1111 if (Key
->DataType
== REG_LINK
)
1114 /* Allocate key cell */
1115 KeyCellSize
= sizeof(KEY_CELL
) + Key
->NameSize
- 1;
1116 if (!CmiAllocateBlock (Hive
, (PVOID
)&NewKeyCell
, KeyCellSize
, &NKBOffset
))
1118 DPRINT1 ("CmiAllocateBlock() failed\n");
1122 /* Initialize key cell */
1123 NewKeyCell
->Id
= REG_KEY_CELL_ID
;
1124 NewKeyCell
->Type
= REG_KEY_CELL_TYPE
;
1125 NewKeyCell
->LastWriteTime
= 0ULL;
1126 NewKeyCell
->ParentKeyOffset
= ParentKeyOffset
;
1127 NewKeyCell
->NumberOfSubKeys
= 0;
1128 NewKeyCell
->HashTableOffset
= -1;
1129 NewKeyCell
->NumberOfValues
= 0;
1130 NewKeyCell
->ValuesOffset
= -1;
1131 NewKeyCell
->SecurityKeyOffset
= -1;
1132 NewKeyCell
->NameSize
= Key
->NameSize
- 1;
1133 NewKeyCell
->ClassNameOffset
= -1;
1134 memcpy (NewKeyCell
->Name
,
1138 /* Add key cell to the parent key's hash table */
1139 if (!CmiAddKeyToParentHashTable (Hive
,
1144 DPRINT1 ("CmiAddKeyToParentHashTable() failed\n");
1148 ValueCount
= RegGetValueCount (Key
);
1149 DPRINT ("ValueCount: %lu\n", ValueCount
);
1152 /* Allocate value list cell */
1153 CmiAllocateValueListCell (Hive
,
1154 &NewKeyCell
->ValuesOffset
,
1157 if (Key
->DataSize
!= 0)
1159 if (!CmiExportValue (Hive
, NKBOffset
, Key
, NULL
))
1163 /* Enumerate values */
1164 Entry
= Key
->ValueList
.Flink
;
1165 while (Entry
!= &Key
->ValueList
)
1167 Value
= CONTAINING_RECORD(Entry
,
1171 if (!CmiExportValue (Hive
, NKBOffset
, Key
, Value
))
1174 Entry
= Entry
->Flink
;
1178 SubKeyCount
= RegGetSubKeyCount (Key
);
1179 DPRINT ("SubKeyCount: %lu\n", SubKeyCount
);
1180 if (SubKeyCount
> 0)
1182 /* Allocate hash table cell */
1183 CmiAllocateHashTableCell (Hive
,
1184 &NewKeyCell
->HashTableOffset
,
1187 /* Enumerate subkeys */
1188 Entry
= Key
->SubKeyList
.Flink
;
1189 while (Entry
!= &Key
->SubKeyList
)
1191 SubKey
= CONTAINING_RECORD(Entry
,
1195 if (!CmiExportSubKey (Hive
, NKBOffset
, Key
, SubKey
))
1198 Entry
= Entry
->Flink
;
1207 CmiCalcHiveChecksum (PREGISTRY_HIVE Hive
)
1213 Buffer
= (PULONG
)Hive
->HiveHeader
;
1215 for (i
= 0; i
< 127; i
++)
1218 Hive
->HiveHeader
->Checksum
= Sum
;
1223 CmiExportHive (PREGISTRY_HIVE Hive
,
1235 DPRINT ("CmiExportHive(%p, '%s') called\n", Hive
, KeyName
);
1237 if (RegOpenKey (NULL
, KeyName
, &Key
) != ERROR_SUCCESS
)
1239 DPRINT1 ("RegOpenKey() failed\n");
1243 DPRINT ("Name: %s\n", KeyName
);
1245 KeyCell
= CmiGetBlock (Hive
,
1246 Hive
->HiveHeader
->RootKeyCell
,
1248 if (KeyCell
== NULL
)
1250 DPRINT1 ("CmiGetBlock() failed\n");
1254 ValueCount
= RegGetValueCount (Key
);
1255 DPRINT ("ValueCount: %lu\n", ValueCount
);
1258 /* Allocate value list cell */
1259 CmiAllocateValueListCell (Hive
,
1260 &KeyCell
->ValuesOffset
,
1263 if (Key
->DataSize
!= 0)
1265 if (!CmiExportValue (Hive
, Hive
->HiveHeader
->RootKeyCell
, Key
, NULL
))
1269 /* Enumerate values */
1270 Entry
= Key
->ValueList
.Flink
;
1271 while (Entry
!= &Key
->ValueList
)
1273 Value
= CONTAINING_RECORD(Entry
,
1277 if (!CmiExportValue (Hive
, Hive
->HiveHeader
->RootKeyCell
, Key
, Value
))
1280 Entry
= Entry
->Flink
;
1284 SubKeyCount
= RegGetSubKeyCount (Key
);
1285 DPRINT ("SubKeyCount: %lu\n", SubKeyCount
);
1286 if (SubKeyCount
> 0)
1288 /* Allocate hash table cell */
1289 CmiAllocateHashTableCell (Hive
,
1290 &KeyCell
->HashTableOffset
,
1293 /* Enumerate subkeys */
1294 Entry
= Key
->SubKeyList
.Flink
;
1295 while (Entry
!= &Key
->SubKeyList
)
1297 SubKey
= CONTAINING_RECORD(Entry
,
1301 if (!CmiExportSubKey (Hive
, Hive
->HiveHeader
->RootKeyCell
, Key
, SubKey
))
1304 Entry
= Entry
->Flink
;
1308 CmiCalcHiveChecksum (Hive
);
1315 CmiWriteHive(PREGISTRY_HIVE Hive
,
1322 /* Check for existing hive file */
1323 File
= fopen (FileName
, "rb");
1326 printf (" File already exists\n");
1331 /* Create new hive file */
1332 File
= fopen (FileName
, "w+b");
1338 fseek (File
, 0, SEEK_SET
);
1340 /* Calculate header checksum */
1341 CmiCalcHiveChecksum (Hive
);
1343 /* Write hive header */
1344 fwrite (Hive
->HiveHeader
, REG_BLOCK_SIZE
, 1, File
);
1347 for (i
= 0; i
< Hive
->BlockListSize
; i
++)
1349 if (Hive
->BlockList
[i
] != Bin
)
1351 Bin
= Hive
->BlockList
[i
];
1353 DPRINT ("Bin[%lu]: Offset 0x%lx Size 0x%lx\n",
1354 i
, Bin
->BlockOffset
, Bin
->BlockSize
);
1356 fwrite (Bin
, Bin
->BlockSize
, 1, File
);
1367 ExportBinaryHive (PCHAR FileName
,
1370 PREGISTRY_HIVE Hive
;
1372 printf (" Creating binary hive: %s\n", FileName
);
1374 Hive
= CmiCreateRegistryHive ();
1378 if (!CmiExportHive (Hive
, KeyName
))
1380 CmiDestroyRegistryHive (Hive
);
1384 if (!CmiWriteHive (Hive
, FileName
))
1386 CmiDestroyRegistryHive (Hive
);
1390 CmiDestroyRegistryHive (Hive
);