3 * Copyright (C) 2003, 2004 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.
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 *****************************************************************/
39 #define REG_HIVE_ID 0x66676572
40 #define REG_BIN_ID 0x6e696268
41 #define REG_KEY_CELL_ID 0x6b6e
42 #define REG_HASH_TABLE_CELL_ID 0x666c
43 #define REG_VALUE_CELL_ID 0x6b76
45 #define REG_BLOCK_SIZE 4096
46 #define REG_HBIN_DATA_OFFSET 32
47 #define REG_INIT_BLOCK_LIST_SIZE 32
48 #define REG_INIT_HASH_TABLE_SIZE 3
49 #define REG_EXTEND_HASH_TABLE_SIZE 4
50 #define REG_VALUE_LIST_CELL_MULTIPLE 4
52 #define ROUND_UP_POW2(N,S) (((N) + (S) - 1) & ~((S) - 1))
53 #define ROUND_DOWN_POW2(N,S) ((N) & ~((S) - 1))
55 #define ABS_VALUE(V) (((V) < 0) ? -(V) : (V))
58 // BLOCK_OFFSET = offset in file after header block
59 typedef ULONG BLOCK_OFFSET
, *PBLOCK_OFFSET
;
62 typedef unsigned __int64 FILETIME
;
64 typedef unsigned long long FILETIME
;
68 #pragma pack ( push, hive_header, 1 )
71 /* header for registry hive file : */
72 typedef struct _HIVE_HEADER
74 /* Hive identifier "regf" (0x66676572) */
83 /* When this hive file was last modified */
84 FILETIME DateModified
;
86 /* Registry format major version (1) */
89 /* Registry format minor version (3)
90 Version 3 added fast indexes, version 5 has large value optimizations */
93 /* Registry file type (0 - Primary, 1 - Log) */
96 /* Registry format (1 is the only defined value so far) */
99 /* Offset into file from the byte after the end of the base block.
100 If the hive is volatile, this is the actual pointer to the KEY_CELL */
101 BLOCK_OFFSET RootKeyOffset
;
103 /* Size of each hive block ? */
109 /* Name of hive file */
114 /* Checksum of first 0x200 bytes */
116 } GCC_PACKED HIVE_HEADER
, *PHIVE_HEADER
;
120 /* Bin identifier "hbin" (0x6E696268) */
123 /* Block offset of this bin */
124 BLOCK_OFFSET BinOffset
;
126 /* Size in bytes, multiple of the block size (4KB) */
131 /* When this bin was last modified */
132 FILETIME DateModified
;
134 /* ? (In-memory only) */
136 } GCC_PACKED HBIN
, *PHBIN
;
138 typedef struct _CELL_HEADER
140 /* <0 if used, >0 if free */
142 } GCC_PACKED CELL_HEADER
, *PCELL_HEADER
;
144 typedef struct _KEY_CELL
146 /* Size of this cell */
149 /* Key cell identifier "kn" (0x6b6e) */
155 /* Time of last flush */
156 FILETIME LastWriteTime
;
161 /* Block offset of parent key cell */
162 BLOCK_OFFSET ParentKeyOffset
;
164 /* Count of sub keys for the key in this key cell */
165 ULONG NumberOfSubKeys
;
170 /* Block offset of has table for FIXME: subkeys/values? */
171 BLOCK_OFFSET HashTableOffset
;
176 /* Count of values contained in this key cell */
177 ULONG NumberOfValues
;
179 /* Block offset of VALUE_LIST_CELL */
180 BLOCK_OFFSET ValueListOffset
;
182 /* Block offset of security cell */
183 BLOCK_OFFSET SecurityKeyOffset
;
185 /* Block offset of registry key class */
186 BLOCK_OFFSET ClassNameOffset
;
191 /* Size in bytes of key name */
194 /* Size of class name in bytes */
197 /* Name of key (not zero terminated) */
199 } GCC_PACKED KEY_CELL
, *PKEY_CELL
;
201 /* KEY_CELL.Type constants */
202 #define REG_LINK_KEY_CELL_TYPE 0x10
203 #define REG_KEY_CELL_TYPE 0x20
204 #define REG_ROOT_KEY_CELL_TYPE 0x2c
208 // HashValue=four letters of value's name
209 typedef struct _HASH_RECORD
211 BLOCK_OFFSET KeyOffset
;
213 } GCC_PACKED HASH_RECORD
, *PHASH_RECORD
;
215 typedef struct _HASH_TABLE_CELL
219 USHORT HashTableSize
;
220 HASH_RECORD Table
[0];
221 } GCC_PACKED HASH_TABLE_CELL
, *PHASH_TABLE_CELL
;
223 typedef struct _VALUE_LIST_CELL
226 BLOCK_OFFSET ValueOffset
[0];
227 } GCC_PACKED VALUE_LIST_CELL
, *PVALUE_LIST_CELL
;
229 typedef struct _VALUE_CELL
233 USHORT NameSize
; // length of Name
234 ULONG DataSize
; // length of datas in the cell pointed by DataOffset
235 BLOCK_OFFSET DataOffset
;// datas are here if high bit of DataSize is set
239 CHAR Name
[0]; /* warning : not zero terminated */
240 } GCC_PACKED VALUE_CELL
, *PVALUE_CELL
;
242 /* VALUE_CELL.Flags constants */
243 #define REG_VALUE_NAME_PACKED 0x0001
245 /* VALUE_CELL.DataSize mask constants */
246 #define REG_DATA_SIZE_MASK 0x7FFFFFFF
247 #define REG_DATA_IN_OFFSET 0x80000000
249 typedef struct _DATA_CELL
253 } GCC_PACKED DATA_CELL
, *PDATA_CELL
;
256 #pragma pack ( pop, hive_header )
259 typedef struct _REGISTRY_HIVE
262 PHIVE_HEADER HiveHeader
;
267 PCELL_HEADER
*FreeList
;
268 BLOCK_OFFSET
*FreeListOffset
;
269 } REGISTRY_HIVE
, *PREGISTRY_HIVE
;
271 /* FUNCTIONS ****************************************************************/
274 memexpand (PWCHAR Dst
,
280 for (i
= 0; i
< Length
; i
++)
281 Dst
[i
] = (WCHAR
)Src
[i
];
286 CmiCreateDefaultHiveHeader (PHIVE_HEADER Header
)
289 memset (Header
, 0, REG_BLOCK_SIZE
);
290 Header
->BlockId
= REG_HIVE_ID
;
291 Header
->UpdateCounter1
= 0;
292 Header
->UpdateCounter2
= 0;
293 Header
->DateModified
= 0;
294 Header
->MajorVersion
= 1;
295 Header
->MinorVersion
= 3;
299 Header
->RootKeyOffset
= -1;
300 Header
->BlockSize
= REG_BLOCK_SIZE
;
301 Header
->Checksum
= 0;
306 CmiCreateDefaultBinCell(PHBIN BinCell
)
309 memset (BinCell
, 0, REG_BLOCK_SIZE
);
310 BinCell
->HeaderId
= REG_BIN_ID
;
311 BinCell
->DateModified
= 0;
312 BinCell
->BinSize
= REG_BLOCK_SIZE
;
317 CmiCreateDefaultRootKeyCell(PKEY_CELL RootKeyCell
, PCHAR KeyName
)
323 assert (RootKeyCell
);
325 BaseKeyName
= strrchr(KeyName
, '\\') + 1;
326 NameSize
= strlen(BaseKeyName
);
327 CellSize
= ROUND_UP_POW2(sizeof(KEY_CELL
) + NameSize
- 1, 16);
329 memset (RootKeyCell
, 0, CellSize
);
330 RootKeyCell
->CellSize
= (ULONG
)-(LONG
)CellSize
;
331 RootKeyCell
->Id
= REG_KEY_CELL_ID
;
332 RootKeyCell
->Type
= REG_ROOT_KEY_CELL_TYPE
;
333 RootKeyCell
->LastWriteTime
= 0;
334 RootKeyCell
->ParentKeyOffset
= 0;
335 RootKeyCell
->NumberOfSubKeys
= 0;
336 RootKeyCell
->HashTableOffset
= -1;
337 RootKeyCell
->NumberOfValues
= 0;
338 RootKeyCell
->ValueListOffset
= -1;
339 RootKeyCell
->SecurityKeyOffset
= 0;
340 RootKeyCell
->ClassNameOffset
= -1;
341 RootKeyCell
->NameSize
= NameSize
;
342 RootKeyCell
->ClassSize
= 0;
343 memcpy (RootKeyCell
->Name
,
349 static PREGISTRY_HIVE
350 CmiCreateRegistryHive (PCHAR KeyName
)
353 PCELL_HEADER FreeCell
;
354 PKEY_CELL RootKeyCell
;
357 Hive
= (PREGISTRY_HIVE
) malloc (sizeof(REGISTRY_HIVE
));
362 memset (Hive
, 0, sizeof(REGISTRY_HIVE
));
364 DPRINT("Hive %p\n", Hive
);
366 /* Create hive beader (aka 'base block') */
367 Hive
->HiveHeader
= (PHIVE_HEADER
) malloc (REG_BLOCK_SIZE
);
368 if (Hive
->HiveHeader
== NULL
)
373 CmiCreateDefaultHiveHeader (Hive
->HiveHeader
);
374 Hive
->FileSize
= REG_BLOCK_SIZE
;
376 /* Allocate block list */
377 Hive
->BlockListSize
= 1;
378 Hive
->BlockList
= malloc (sizeof(PHBIN
) * Hive
->BlockListSize
);
379 if (Hive
->BlockList
== NULL
)
381 free (Hive
->HiveHeader
);
386 /* Allocate free cell list */
387 Hive
->FreeListMax
= 32;
388 Hive
->FreeList
= malloc(sizeof(PCELL_HEADER
) * Hive
->FreeListMax
);
389 if (Hive
->FreeList
== NULL
)
391 free (Hive
->BlockList
);
392 free (Hive
->HiveHeader
);
396 Hive
->FreeListOffset
= malloc(sizeof(BLOCK_OFFSET
) * Hive
->FreeListMax
);
397 if (Hive
->FreeListOffset
== NULL
)
399 free (Hive
->FreeList
);
400 free (Hive
->BlockList
);
401 free (Hive
->HiveHeader
);
406 /* Allocate first bin */
407 Hive
->BlockList
[0] = (PHBIN
) malloc (REG_BLOCK_SIZE
);
408 if (Hive
->BlockList
[0] == NULL
)
410 free (Hive
->FreeListOffset
);
411 free (Hive
->FreeList
);
412 free (Hive
->BlockList
);
413 free (Hive
->HiveHeader
);
417 Hive
->FileSize
+= REG_BLOCK_SIZE
;
420 BinCell
= (PHBIN
)Hive
->BlockList
[0];
421 CmiCreateDefaultBinCell (BinCell
);
422 BinCell
->BinOffset
= 0;
424 /* Init root key cell */
425 RootKeyCell
= (PKEY_CELL
)((ULONG_PTR
)BinCell
+ REG_HBIN_DATA_OFFSET
);
426 CmiCreateDefaultRootKeyCell (RootKeyCell
, KeyName
);
427 Hive
->HiveHeader
->RootKeyOffset
= REG_HBIN_DATA_OFFSET
;
430 FreeCell
= (PCELL_HEADER
)((ULONG_PTR
)RootKeyCell
- RootKeyCell
->CellSize
);
431 FreeCell
->CellSize
= REG_BLOCK_SIZE
- (REG_HBIN_DATA_OFFSET
- RootKeyCell
->CellSize
);
433 Hive
->FreeList
[0] = FreeCell
;
434 Hive
->FreeListOffset
[0] = REG_HBIN_DATA_OFFSET
- RootKeyCell
->CellSize
;
435 Hive
->FreeListSize
++;
442 CmiDestroyRegistryHive (PREGISTRY_HIVE Hive
)
450 /* Release free offset list */
451 if (Hive
->FreeListOffset
!= NULL
)
452 free (Hive
->FreeListOffset
);
454 /* Release free list */
455 if (Hive
->FreeList
!= NULL
)
456 free (Hive
->FreeList
);
458 if (Hive
->BlockList
!= NULL
)
462 for (i
= 0; i
< Hive
->BlockListSize
; i
++)
464 if ((Hive
->BlockList
[i
] != NULL
) &&
465 (Hive
->BlockList
[i
] != Bin
))
467 Bin
= Hive
->BlockList
[i
];
469 DPRINT ("Bin[%lu]: Offset 0x%lx Size 0x%lx\n",
470 i
, Bin
->BinOffset
, Bin
->BinSize
);
476 /* Release block list */
477 free (Hive
->BlockList
);
480 /* Release hive header */
481 if (Hive
->HiveHeader
!= NULL
)
482 free (Hive
->HiveHeader
);
490 CmiGetCell (PREGISTRY_HIVE Hive
,
491 BLOCK_OFFSET BlockOffset
,
500 if (BlockOffset
== (ULONG_PTR
) -1)
503 BlockIndex
= BlockOffset
/ 4096;
504 if (BlockIndex
>= Hive
->BlockListSize
)
507 pBin
= Hive
->BlockList
[BlockIndex
];
511 return (PVOID
)((ULONG_PTR
)pBin
+ (BlockOffset
- pBin
->BinOffset
));
516 CmiMergeFree(PREGISTRY_HIVE RegistryHive
,
517 PCELL_HEADER FreeBlock
,
518 BLOCK_OFFSET FreeOffset
)
520 BLOCK_OFFSET BlockOffset
;
521 BLOCK_OFFSET BinOffset
;
527 DPRINT("CmiMergeFree(Block %p Offset %lx Size %lx) called\n",
528 FreeBlock
, FreeOffset
, FreeBlock
->CellSize
);
530 CmiGetCell (RegistryHive
,
533 DPRINT("Bin %p\n", Bin
);
537 BinOffset
= Bin
->BinOffset
;
538 BinSize
= Bin
->BinSize
;
539 DPRINT("Bin %p Offset %lx Size %lx\n", Bin
, BinOffset
, BinSize
);
541 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
543 BlockOffset
= RegistryHive
->FreeListOffset
[i
];
544 BlockSize
= RegistryHive
->FreeList
[i
]->CellSize
;
545 if (BlockOffset
> BinOffset
&&
546 BlockOffset
< BinOffset
+ BinSize
)
548 DPRINT("Free block: Offset %lx Size %lx\n",
549 BlockOffset
, BlockSize
);
551 if ((i
< (RegistryHive
->FreeListSize
- 1)) &&
552 (BlockOffset
+ BlockSize
== FreeOffset
) &&
553 (FreeOffset
+ FreeBlock
->CellSize
== RegistryHive
->FreeListOffset
[i
+ 1]))
555 DPRINT("Merge current block with previous and next block\n");
557 RegistryHive
->FreeList
[i
]->CellSize
+=
558 (FreeBlock
->CellSize
+ RegistryHive
->FreeList
[i
+ 1]->CellSize
);
560 FreeBlock
->CellSize
= 0;
561 RegistryHive
->FreeList
[i
+ 1]->CellSize
= 0;
564 if ((i
+ 2) < RegistryHive
->FreeListSize
)
566 memmove (&RegistryHive
->FreeList
[i
+ 1],
567 &RegistryHive
->FreeList
[i
+ 2],
568 sizeof(RegistryHive
->FreeList
[0])
569 * (RegistryHive
->FreeListSize
- i
- 2));
570 memmove (&RegistryHive
->FreeListOffset
[i
+ 1],
571 &RegistryHive
->FreeListOffset
[i
+ 2],
572 sizeof(RegistryHive
->FreeListOffset
[0])
573 * (RegistryHive
->FreeListSize
- i
- 2));
575 RegistryHive
->FreeListSize
--;
579 else if (BlockOffset
+ BlockSize
== FreeOffset
)
581 DPRINT("Merge current block with previous block\n");
583 RegistryHive
->FreeList
[i
]->CellSize
+= FreeBlock
->CellSize
;
584 FreeBlock
->CellSize
= 0;
588 else if (FreeOffset
+ FreeBlock
->CellSize
== BlockOffset
)
590 DPRINT("Merge current block with next block\n");
592 FreeBlock
->CellSize
+= RegistryHive
->FreeList
[i
]->CellSize
;
593 RegistryHive
->FreeList
[i
]->CellSize
= 0;
594 RegistryHive
->FreeList
[i
] = FreeBlock
;
595 RegistryHive
->FreeListOffset
[i
] = FreeOffset
;
607 CmiAddFree(PREGISTRY_HIVE RegistryHive
,
608 PCELL_HEADER FreeBlock
,
609 BLOCK_OFFSET FreeOffset
,
610 BOOL MergeFreeBlocks
)
612 PCELL_HEADER
*tmpList
;
613 BLOCK_OFFSET
*tmpListOffset
;
618 assert(RegistryHive
);
621 DPRINT("FreeBlock %p FreeOffset %.08lx\n",
622 FreeBlock
, FreeOffset
);
624 /* Merge free blocks */
625 if (MergeFreeBlocks
== TRUE
)
627 if (CmiMergeFree(RegistryHive
, FreeBlock
, FreeOffset
))
631 if ((RegistryHive
->FreeListSize
+ 1) > RegistryHive
->FreeListMax
)
633 tmpList
= malloc (sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
+ 32));
639 tmpListOffset
= malloc (sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
+ 32));
640 if (tmpListOffset
== NULL
)
646 if (RegistryHive
->FreeListMax
)
649 RegistryHive
->FreeList
,
650 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
));
651 memmove (tmpListOffset
,
652 RegistryHive
->FreeListOffset
,
653 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
));
654 free (RegistryHive
->FreeList
);
655 free (RegistryHive
->FreeListOffset
);
657 RegistryHive
->FreeList
= tmpList
;
658 RegistryHive
->FreeListOffset
= tmpListOffset
;
659 RegistryHive
->FreeListMax
+= 32;
662 /* Add new offset to free list, maintaining list in ascending order */
663 if ((RegistryHive
->FreeListSize
== 0)
664 || (RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
-1] < FreeOffset
))
666 /* Add to end of list */
667 RegistryHive
->FreeList
[RegistryHive
->FreeListSize
] = FreeBlock
;
668 RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
++] = FreeOffset
;
670 else if (RegistryHive
->FreeListOffset
[0] > FreeOffset
)
672 /* Add to begin of list */
673 memmove (&RegistryHive
->FreeList
[1],
674 &RegistryHive
->FreeList
[0],
675 sizeof(RegistryHive
->FreeList
[0]) * RegistryHive
->FreeListSize
);
676 memmove (&RegistryHive
->FreeListOffset
[1],
677 &RegistryHive
->FreeListOffset
[0],
678 sizeof(RegistryHive
->FreeListOffset
[0]) * RegistryHive
->FreeListSize
);
679 RegistryHive
->FreeList
[0] = FreeBlock
;
680 RegistryHive
->FreeListOffset
[0] = FreeOffset
;
681 RegistryHive
->FreeListSize
++;
685 /* Search where to insert */
687 maxInd
= RegistryHive
->FreeListSize
- 1;
688 while ((maxInd
- minInd
) > 1)
690 medInd
= (minInd
+ maxInd
) / 2;
691 if (RegistryHive
->FreeListOffset
[medInd
] > FreeOffset
)
697 /* Insert before maxInd */
698 memmove (&RegistryHive
->FreeList
[maxInd
+1],
699 &RegistryHive
->FreeList
[maxInd
],
700 sizeof(RegistryHive
->FreeList
[0]) * (RegistryHive
->FreeListSize
- minInd
));
701 memmove (&RegistryHive
->FreeListOffset
[maxInd
+ 1],
702 &RegistryHive
->FreeListOffset
[maxInd
],
703 sizeof(RegistryHive
->FreeListOffset
[0]) * (RegistryHive
->FreeListSize
-minInd
));
704 RegistryHive
->FreeList
[maxInd
] = FreeBlock
;
705 RegistryHive
->FreeListOffset
[maxInd
] = FreeOffset
;
706 RegistryHive
->FreeListSize
++;
714 CmiAddBin(PREGISTRY_HIVE RegistryHive
,
717 PBLOCK_OFFSET NewBlockOffset
)
719 PCELL_HEADER tmpBlock
;
720 PHBIN
* tmpBlockList
;
725 BinSize
= BlockCount
*REG_BLOCK_SIZE
;
726 tmpBin
= malloc (BinSize
);
731 memset (tmpBin
, 0, BinSize
);
733 tmpBin
->HeaderId
= REG_BIN_ID
;
734 tmpBin
->BinOffset
= RegistryHive
->FileSize
- REG_BLOCK_SIZE
;
735 RegistryHive
->FileSize
+= BinSize
;
736 tmpBin
->BinSize
= BinSize
;
737 tmpBin
->DateModified
= 0;
738 tmpBin
->MemAlloc
= 0;
740 /* Increase size of list of blocks */
741 tmpBlockList
= malloc (sizeof(PHBIN
) * (RegistryHive
->BlockListSize
+ BlockCount
));
742 if (tmpBlockList
== NULL
)
748 if (RegistryHive
->BlockListSize
> 0)
750 memcpy (tmpBlockList
,
751 RegistryHive
->BlockList
,
752 sizeof(PHBIN
) * RegistryHive
->BlockListSize
);
753 free (RegistryHive
->BlockList
);
756 RegistryHive
->BlockList
= tmpBlockList
;
757 for (i
= 0; i
< BlockCount
; i
++)
758 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
+ i
] = tmpBin
;
759 RegistryHive
->BlockListSize
+= BlockCount
;
761 /* Initialize a free block in this heap : */
762 tmpBlock
= (PCELL_HEADER
)((ULONG_PTR
) tmpBin
+ REG_HBIN_DATA_OFFSET
);
763 tmpBlock
->CellSize
= (REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
);
765 *NewBlock
= (PVOID
) tmpBlock
;
768 *NewBlockOffset
= tmpBin
->BinOffset
+ REG_HBIN_DATA_OFFSET
;
775 CmiAllocateCell (PREGISTRY_HIVE RegistryHive
,
778 PBLOCK_OFFSET pBlockOffset
)
780 PCELL_HEADER NewBlock
;
785 /* Round to 16 bytes multiple */
786 CellSize
= ROUND_UP_POW2(CellSize
, 16);
788 /* first search in free blocks */
790 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
792 if (RegistryHive
->FreeList
[i
]->CellSize
>= CellSize
)
794 NewBlock
= RegistryHive
->FreeList
[i
];
796 *pBlockOffset
= RegistryHive
->FreeListOffset
[i
];
798 if ((i
+ 1) < RegistryHive
->FreeListSize
)
800 memmove (&RegistryHive
->FreeList
[i
],
801 &RegistryHive
->FreeList
[i
+ 1],
802 sizeof(RegistryHive
->FreeList
[0])
803 * (RegistryHive
->FreeListSize
- i
- 1));
804 memmove (&RegistryHive
->FreeListOffset
[i
],
805 &RegistryHive
->FreeListOffset
[i
+ 1],
806 sizeof(RegistryHive
->FreeListOffset
[0])
807 * (RegistryHive
->FreeListSize
- i
- 1));
809 RegistryHive
->FreeListSize
--;
814 /* Need to extend hive file : */
815 if (NewBlock
== NULL
)
817 /* Add a new block */
818 if (!CmiAddBin(RegistryHive
,
819 ((sizeof(HBIN
) + CellSize
- 1) / REG_BLOCK_SIZE
) + 1,
827 /* Split the block in two parts */
828 if (NewBlock
->CellSize
> CellSize
)
830 NewBlock
= (PCELL_HEADER
) ((ULONG_PTR
) NewBlock
+ CellSize
);
831 NewBlock
->CellSize
= ((PCELL_HEADER
) (*Block
))->CellSize
- CellSize
;
832 ((PCELL_HEADER
) (*Block
))->CellSize
= CellSize
;
833 CmiAddFree (RegistryHive
,
835 *pBlockOffset
+ CellSize
,
838 else if (NewBlock
->CellSize
< CellSize
)
843 memset((PVOID
)((ULONG_PTR
)*Block
+ sizeof(CELL_HEADER
)), 0,
844 CellSize
- sizeof(CELL_HEADER
));
845 ((PCELL_HEADER
)(*Block
))->CellSize
*= -1;
852 CmiAllocateHashTableCell (PREGISTRY_HIVE Hive
,
853 PBLOCK_OFFSET HBOffset
,
856 PHASH_TABLE_CELL HashCell
;
860 NewHashSize
= sizeof(HASH_TABLE_CELL
) +
861 (SubKeyCount
* sizeof(HASH_RECORD
));
862 Status
= CmiAllocateCell (Hive
,
866 if ((HashCell
== NULL
) || (Status
== FALSE
))
871 HashCell
->Id
= REG_HASH_TABLE_CELL_ID
;
872 HashCell
->HashTableSize
= SubKeyCount
;
879 CmiAddKeyToParentHashTable (PREGISTRY_HIVE Hive
,
880 BLOCK_OFFSET ParentKeyOffset
,
881 PKEY_CELL NewKeyCell
,
882 BLOCK_OFFSET NKBOffset
)
884 PHASH_TABLE_CELL HashBlock
;
885 PKEY_CELL ParentKeyCell
;
888 ParentKeyCell
= CmiGetCell (Hive
,
891 if (ParentKeyCell
== NULL
)
893 DPRINT1 ("CmiGetBlock() failed\n");
897 HashBlock
=CmiGetCell (Hive
,
898 ParentKeyCell
->HashTableOffset
,
900 if (HashBlock
== NULL
)
902 DPRINT1 ("CmiGetBlock() failed\n");
906 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
908 if (HashBlock
->Table
[i
].KeyOffset
== 0)
910 HashBlock
->Table
[i
].KeyOffset
= NKBOffset
;
911 memcpy (&HashBlock
->Table
[i
].HashValue
,
914 ParentKeyCell
->NumberOfSubKeys
++;
924 CmiAllocateValueListCell (PREGISTRY_HIVE Hive
,
925 PBLOCK_OFFSET ValueListOffset
,
928 PVALUE_LIST_CELL ValueListCell
;
932 ValueListSize
= sizeof(VALUE_LIST_CELL
) +
933 (ValueCount
* sizeof(BLOCK_OFFSET
));
934 Status
= CmiAllocateCell (Hive
,
936 (PVOID
)&ValueListCell
,
938 if ((ValueListCell
== NULL
) || (Status
== FALSE
))
940 DPRINT1 ("CmiAllocateBlock() failed\n");
949 CmiAllocateValueCell(PREGISTRY_HIVE Hive
,
950 PVALUE_CELL
*ValueCell
,
951 BLOCK_OFFSET
*ValueCellOffset
,
954 PVALUE_CELL NewValueCell
;
958 NameSize
= (ValueName
== NULL
) ? 0 : strlen (ValueName
);
959 Status
= CmiAllocateCell (Hive
,
960 sizeof(VALUE_CELL
) + NameSize
,
961 (PVOID
*)&NewValueCell
,
963 if ((NewValueCell
== NULL
) || (Status
== FALSE
))
965 DPRINT1 ("CmiAllocateBlock() failed\n");
969 NewValueCell
->Id
= REG_VALUE_CELL_ID
;
970 NewValueCell
->NameSize
= NameSize
;
973 memcpy (NewValueCell
->Name
,
976 NewValueCell
->Flags
= REG_VALUE_NAME_PACKED
;
978 NewValueCell
->DataType
= 0;
979 NewValueCell
->DataSize
= 0;
980 NewValueCell
->DataOffset
= -1;
982 *ValueCell
= NewValueCell
;
989 CmiAddValueToKeyValueList(PREGISTRY_HIVE Hive
,
990 BLOCK_OFFSET KeyCellOffset
,
991 BLOCK_OFFSET ValueCellOffset
)
993 PVALUE_LIST_CELL ValueListCell
;
996 KeyCell
= CmiGetCell (Hive
, KeyCellOffset
, NULL
);
999 DPRINT1 ("CmiGetBlock() failed\n");
1003 ValueListCell
= CmiGetCell (Hive
, KeyCell
->ValueListOffset
, NULL
);
1004 if (ValueListCell
== NULL
)
1006 DPRINT1 ("CmiGetBlock() failed\n");
1010 ValueListCell
->ValueOffset
[KeyCell
->NumberOfValues
] = ValueCellOffset
;
1011 KeyCell
->NumberOfValues
++;
1018 CmiExportValue (PREGISTRY_HIVE Hive
,
1019 BLOCK_OFFSET KeyCellOffset
,
1023 BLOCK_OFFSET ValueCellOffset
;
1024 BLOCK_OFFSET DataCellOffset
;
1025 PVALUE_CELL ValueCell
;
1026 PDATA_CELL DataCell
;
1031 BOOL Expand
= FALSE
;
1033 DPRINT ("CmiExportValue('%s') called\n", (Value
== NULL
) ? "<default>" : (PCHAR
)Value
->Name
);
1034 DPRINT ("DataSize %lu\n", (Value
== NULL
) ? Key
->DataSize
: Value
->DataSize
);
1036 /* Allocate value cell */
1037 if (!CmiAllocateValueCell(Hive
, &ValueCell
, &ValueCellOffset
, (Value
== NULL
) ? NULL
: Value
->Name
))
1042 if (!CmiAddValueToKeyValueList(Hive
, KeyCellOffset
, ValueCellOffset
))
1049 DataType
= Key
->DataType
;
1050 SrcDataSize
= Key
->DataSize
;
1055 DataType
= Value
->DataType
;
1056 SrcDataSize
= Value
->DataSize
;
1060 DstDataSize
= SrcDataSize
;
1061 if (DataType
== REG_SZ
||
1062 DataType
== REG_EXPAND_SZ
||
1063 DataType
== REG_MULTI_SZ
)
1065 DstDataSize
*= sizeof(WCHAR
);
1069 if ((DstDataSize
& REG_DATA_SIZE_MASK
) <= sizeof(BLOCK_OFFSET
))
1071 ValueCell
->DataSize
= DstDataSize
| REG_DATA_IN_OFFSET
;
1072 ValueCell
->DataType
= DataType
;
1075 memexpand ((PWCHAR
)&ValueCell
->DataOffset
,
1081 memcpy (&ValueCell
->DataOffset
,
1088 /* Allocate data cell */
1089 if (!CmiAllocateCell (Hive
,
1090 sizeof(CELL_HEADER
) + DstDataSize
,
1097 ValueCell
->DataOffset
= DataCellOffset
;
1098 ValueCell
->DataSize
= DstDataSize
& REG_DATA_SIZE_MASK
;
1099 ValueCell
->DataType
= DataType
;
1103 if (SrcDataSize
<= sizeof(BLOCK_OFFSET
))
1105 memexpand ((PWCHAR
)DataCell
->Data
,
1111 memexpand ((PWCHAR
)DataCell
->Data
,
1118 memcpy (DataCell
->Data
,
1129 CmiExportSubKey (PREGISTRY_HIVE Hive
,
1130 BLOCK_OFFSET ParentKeyOffset
,
1134 BLOCK_OFFSET NKBOffset
;
1135 PKEY_CELL NewKeyCell
;
1143 DPRINT ("CmiExportSubKey('%s') called\n", Key
->Name
);
1145 /* Don't export links */
1146 if (Key
->DataType
== REG_LINK
)
1149 /* Allocate key cell */
1150 KeyCellSize
= sizeof(KEY_CELL
) + Key
->NameSize
- 1;
1151 if (!CmiAllocateCell (Hive
, KeyCellSize
, (PVOID
)&NewKeyCell
, &NKBOffset
))
1153 DPRINT1 ("CmiAllocateBlock() failed\n");
1157 /* Initialize key cell */
1158 NewKeyCell
->Id
= REG_KEY_CELL_ID
;
1159 NewKeyCell
->Type
= REG_KEY_CELL_TYPE
;
1160 NewKeyCell
->LastWriteTime
= 0;
1161 NewKeyCell
->ParentKeyOffset
= ParentKeyOffset
;
1162 NewKeyCell
->NumberOfSubKeys
= 0;
1163 NewKeyCell
->HashTableOffset
= -1;
1164 NewKeyCell
->NumberOfValues
= 0;
1165 NewKeyCell
->ValueListOffset
= -1;
1166 NewKeyCell
->SecurityKeyOffset
= -1;
1167 NewKeyCell
->NameSize
= Key
->NameSize
- 1;
1168 NewKeyCell
->ClassNameOffset
= -1;
1169 memcpy (NewKeyCell
->Name
,
1173 /* Add key cell to the parent key's hash table */
1174 if (!CmiAddKeyToParentHashTable (Hive
,
1179 DPRINT1 ("CmiAddKeyToParentHashTable() failed\n");
1183 ValueCount
= RegGetValueCount (Key
);
1184 DPRINT ("ValueCount: %lu\n", ValueCount
);
1187 /* Allocate value list cell */
1188 CmiAllocateValueListCell (Hive
,
1189 &NewKeyCell
->ValueListOffset
,
1192 if (Key
->DataSize
!= 0)
1194 if (!CmiExportValue (Hive
, NKBOffset
, Key
, NULL
))
1198 /* Enumerate values */
1199 Entry
= Key
->ValueList
.Flink
;
1200 while (Entry
!= &Key
->ValueList
)
1202 Value
= CONTAINING_RECORD(Entry
,
1206 if (!CmiExportValue (Hive
, NKBOffset
, Key
, Value
))
1209 Entry
= Entry
->Flink
;
1213 SubKeyCount
= RegGetSubKeyCount (Key
);
1214 DPRINT ("SubKeyCount: %lu\n", SubKeyCount
);
1215 if (SubKeyCount
> 0)
1217 /* Allocate hash table cell */
1218 CmiAllocateHashTableCell (Hive
,
1219 &NewKeyCell
->HashTableOffset
,
1222 /* Enumerate subkeys */
1223 Entry
= Key
->SubKeyList
.Flink
;
1224 while (Entry
!= &Key
->SubKeyList
)
1226 SubKey
= CONTAINING_RECORD(Entry
,
1230 if (!CmiExportSubKey (Hive
, NKBOffset
, Key
, SubKey
))
1233 Entry
= Entry
->Flink
;
1242 CmiCalcHiveChecksum (PREGISTRY_HIVE Hive
)
1248 Buffer
= (PULONG
)Hive
->HiveHeader
;
1250 for (i
= 0; i
< 127; i
++)
1253 Hive
->HiveHeader
->Checksum
= Sum
;
1258 CmiExportHive (PREGISTRY_HIVE Hive
,
1269 DPRINT ("CmiExportHive(%p, '%s') called\n", Hive
, KeyName
);
1271 if (RegOpenKey (NULL
, KeyName
, &Key
) != ERROR_SUCCESS
)
1273 DPRINT1 ("RegOpenKey() failed\n");
1277 DPRINT ("Name: %s\n", KeyName
);
1279 KeyCell
= CmiGetCell (Hive
,
1280 Hive
->HiveHeader
->RootKeyOffset
,
1282 if (KeyCell
== NULL
)
1284 DPRINT1 ("CmiGetCell() failed\n");
1288 ValueCount
= RegGetValueCount (Key
);
1289 DPRINT ("ValueCount: %lu\n", ValueCount
);
1292 /* Allocate value list cell */
1293 CmiAllocateValueListCell (Hive
,
1294 &KeyCell
->ValueListOffset
,
1297 if (Key
->DataSize
!= 0)
1299 if (!CmiExportValue (Hive
, Hive
->HiveHeader
->RootKeyOffset
, Key
, NULL
))
1303 /* Enumerate values */
1304 Entry
= Key
->ValueList
.Flink
;
1305 while (Entry
!= &Key
->ValueList
)
1307 Value
= CONTAINING_RECORD(Entry
,
1311 if (!CmiExportValue (Hive
, Hive
->HiveHeader
->RootKeyOffset
, Key
, Value
))
1314 Entry
= Entry
->Flink
;
1318 SubKeyCount
= RegGetSubKeyCount (Key
);
1319 DPRINT ("SubKeyCount: %lu\n", SubKeyCount
);
1320 if (SubKeyCount
> 0)
1322 /* Allocate hash table cell */
1323 CmiAllocateHashTableCell (Hive
,
1324 &KeyCell
->HashTableOffset
,
1327 /* Enumerate subkeys */
1328 Entry
= Key
->SubKeyList
.Flink
;
1329 while (Entry
!= &Key
->SubKeyList
)
1331 SubKey
= CONTAINING_RECORD(Entry
,
1335 if (!CmiExportSubKey (Hive
, Hive
->HiveHeader
->RootKeyOffset
, Key
, SubKey
))
1338 Entry
= Entry
->Flink
;
1342 CmiCalcHiveChecksum (Hive
);
1349 CmiWriteHive(PREGISTRY_HIVE Hive
,
1357 /* Check for existing hive file */
1358 File
= fopen (FileName
, "rb");
1361 printf (" File already exists\n");
1367 /* Create new hive file */
1368 File
= fopen (FileName
, "w+b");
1371 printf(" Error creating/opening file\n");
1375 fseek (File
, 0, SEEK_SET
);
1377 /* Calculate header checksum */
1378 CmiCalcHiveChecksum (Hive
);
1380 /* Write hive header */
1381 fwrite (Hive
->HiveHeader
, REG_BLOCK_SIZE
, 1, File
);
1384 for (i
= 0; i
< Hive
->BlockListSize
; i
++)
1386 if (Hive
->BlockList
[i
] != Bin
)
1388 Bin
= Hive
->BlockList
[i
];
1390 DPRINT ("Bin[%lu]: Offset 0x%lx Size 0x%lx\n",
1391 i
, Bin
->BinOffset
, Bin
->BinSize
);
1393 fwrite (Bin
, Bin
->BinSize
, 1, File
);
1404 ExportBinaryHive (PCHAR FileName
,
1407 PREGISTRY_HIVE Hive
;
1409 printf (" Creating binary hive: %s\n", FileName
);
1411 Hive
= CmiCreateRegistryHive (KeyName
);
1415 if (!CmiExportHive (Hive
, KeyName
))
1417 CmiDestroyRegistryHive (Hive
);
1421 if (!CmiWriteHive (Hive
, FileName
))
1423 CmiDestroyRegistryHive (Hive
);
1427 CmiDestroyRegistryHive (Hive
);