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.
19 /* $Id: binhive.c,v 1.11 2004/05/29 21:15:58 navaraf 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 *****************************************************************/
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(N, S) ((N) + (S) - ((N) % (S)))
53 #define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
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
;
61 typedef unsigned long long FILETIME
;
63 /* header for registry hive file : */
64 typedef struct _HIVE_HEADER
66 /* Hive identifier "regf" (0x66676572) */
75 /* When this hive file was last modified */
76 FILETIME DateModified
;
78 /* Registry format version ? (1?) */
81 /* Registry format version ? (3?) */
84 /* Registry format version ? (0?) */
87 /* Registry format version ? (1?) */
90 /* Offset into file from the byte after the end of the base block.
91 If the hive is volatile, this is the actual pointer to the KEY_CELL */
92 BLOCK_OFFSET RootKeyOffset
;
94 /* Size of each hive block ? */
100 /* Name of hive file */
106 /* Checksum of first 0x200 bytes */
108 } __attribute__((packed
)) HIVE_HEADER
, *PHIVE_HEADER
;
112 /* Bin identifier "hbin" (0x6E696268) */
115 /* Block offset of this bin */
116 BLOCK_OFFSET BinOffset
;
118 /* Size in bytes, multiple of the block size (4KB) */
124 /* When this bin was last modified */
125 FILETIME DateModified
;
129 } __attribute__((packed
)) HBIN
, *PHBIN
;
131 typedef struct _CELL_HEADER
133 /* <0 if used, >0 if free */
135 } __attribute__((packed
)) CELL_HEADER
, *PCELL_HEADER
;
137 typedef struct _KEY_CELL
139 /* Size of this cell */
142 /* Key cell identifier "kn" (0x6b6e) */
148 /* Time of last flush */
149 FILETIME LastWriteTime
;
154 /* Block offset of parent key cell */
155 BLOCK_OFFSET ParentKeyOffset
;
157 /* Count of sub keys for the key in this key cell */
158 ULONG NumberOfSubKeys
;
163 /* Block offset of has table for FIXME: subkeys/values? */
164 BLOCK_OFFSET HashTableOffset
;
169 /* Count of values contained in this key cell */
170 ULONG NumberOfValues
;
172 /* Block offset of VALUE_LIST_CELL */
173 BLOCK_OFFSET ValueListOffset
;
175 /* Block offset of security cell */
176 BLOCK_OFFSET SecurityKeyOffset
;
178 /* Block offset of registry key class */
179 BLOCK_OFFSET ClassNameOffset
;
184 /* Size in bytes of key name */
187 /* Size of class name in bytes */
190 /* Name of key (not zero terminated) */
192 } __attribute__((packed
)) KEY_CELL
, *PKEY_CELL
;
194 /* KEY_CELL.Type constants */
195 #define REG_LINK_KEY_CELL_TYPE 0x10
196 #define REG_KEY_CELL_TYPE 0x20
197 #define REG_ROOT_KEY_CELL_TYPE 0x2c
201 // HashValue=four letters of value's name
202 typedef struct _HASH_RECORD
204 BLOCK_OFFSET KeyOffset
;
206 } __attribute__((packed
)) HASH_RECORD
, *PHASH_RECORD
;
208 typedef struct _HASH_TABLE_CELL
212 USHORT HashTableSize
;
213 HASH_RECORD Table
[0];
214 } __attribute__((packed
)) HASH_TABLE_CELL
, *PHASH_TABLE_CELL
;
216 typedef struct _VALUE_LIST_CELL
219 BLOCK_OFFSET ValueOffset
[0];
220 } __attribute__((packed
)) VALUE_LIST_CELL
, *PVALUE_LIST_CELL
;
222 typedef struct _VALUE_CELL
226 USHORT NameSize
; // length of Name
227 ULONG DataSize
; // length of datas in the cell pointed by DataOffset
228 BLOCK_OFFSET DataOffset
;// datas are here if high bit of DataSize is set
232 UCHAR Name
[0]; /* warning : not zero terminated */
233 } __attribute__((packed
)) VALUE_CELL
, *PVALUE_CELL
;
235 /* VALUE_CELL.Flags constants */
236 #define REG_VALUE_NAME_PACKED 0x0001
238 /* VALUE_CELL.DataSize mask constants */
239 #define REG_DATA_SIZE_MASK 0x7FFFFFFF
240 #define REG_DATA_IN_OFFSET 0x80000000
242 typedef struct _DATA_CELL
246 } __attribute__((packed
)) DATA_CELL
, *PDATA_CELL
;
248 typedef struct _REGISTRY_HIVE
251 PHIVE_HEADER HiveHeader
;
256 PCELL_HEADER
*FreeList
;
257 BLOCK_OFFSET
*FreeListOffset
;
258 } REGISTRY_HIVE
, *PREGISTRY_HIVE
;
260 /* FUNCTIONS ****************************************************************/
263 memexpand (PWCHAR Dst
,
269 for (i
= 0; i
< Length
; i
++)
270 Dst
[i
] = (WCHAR
)Src
[i
];
275 CmiCreateDefaultHiveHeader (PHIVE_HEADER Header
)
278 memset (Header
, 0, REG_BLOCK_SIZE
);
279 Header
->BlockId
= REG_HIVE_ID
;
280 Header
->UpdateCounter1
= 0;
281 Header
->UpdateCounter2
= 0;
282 Header
->DateModified
= 0ULL;
288 Header
->RootKeyOffset
= -1;
289 Header
->BlockSize
= REG_BLOCK_SIZE
;
291 Header
->Checksum
= 0;
296 CmiCreateDefaultBinCell(PHBIN BinCell
)
299 memset (BinCell
, 0, REG_BLOCK_SIZE
);
300 BinCell
->HeaderId
= REG_BIN_ID
;
301 BinCell
->DateModified
= 0ULL;
302 BinCell
->BinSize
= REG_BLOCK_SIZE
;
307 CmiCreateDefaultRootKeyCell(PKEY_CELL RootKeyCell
, PCHAR KeyName
)
313 assert (RootKeyCell
);
315 BaseKeyName
= strrchr(KeyName
, '\\') + 1;
316 NameSize
= strlen(BaseKeyName
);
317 CellSize
= ROUND_UP(sizeof(KEY_CELL
) + NameSize
- 1, 16);
319 memset (RootKeyCell
, 0, CellSize
);
320 RootKeyCell
->CellSize
= -CellSize
;
321 RootKeyCell
->Id
= REG_KEY_CELL_ID
;
322 RootKeyCell
->Type
= REG_ROOT_KEY_CELL_TYPE
;
323 RootKeyCell
->LastWriteTime
= 0ULL;
324 RootKeyCell
->ParentKeyOffset
= 0;
325 RootKeyCell
->NumberOfSubKeys
= 0;
326 RootKeyCell
->HashTableOffset
= -1;
327 RootKeyCell
->NumberOfValues
= 0;
328 RootKeyCell
->ValueListOffset
= -1;
329 RootKeyCell
->SecurityKeyOffset
= 0;
330 RootKeyCell
->ClassNameOffset
= -1;
331 RootKeyCell
->NameSize
= NameSize
;
332 RootKeyCell
->ClassSize
= 0;
333 memcpy (RootKeyCell
->Name
,
339 static PREGISTRY_HIVE
340 CmiCreateRegistryHive (PCHAR KeyName
)
343 PCELL_HEADER FreeCell
;
344 PKEY_CELL RootKeyCell
;
347 Hive
= (PREGISTRY_HIVE
) malloc (sizeof(REGISTRY_HIVE
));
352 memset (Hive
, 0, sizeof(REGISTRY_HIVE
));
354 DPRINT("Hive %p\n", Hive
);
356 /* Create hive beader (aka 'base block') */
357 Hive
->HiveHeader
= (PHIVE_HEADER
) malloc (REG_BLOCK_SIZE
);
358 if (Hive
->HiveHeader
== NULL
)
363 CmiCreateDefaultHiveHeader (Hive
->HiveHeader
);
364 Hive
->FileSize
= REG_BLOCK_SIZE
;
366 /* Allocate block list */
367 Hive
->BlockListSize
= 1;
368 Hive
->BlockList
= malloc (sizeof(PHBIN
) * Hive
->BlockListSize
);
369 if (Hive
->BlockList
== NULL
)
371 free (Hive
->HiveHeader
);
376 /* Allocate free cell list */
377 Hive
->FreeListMax
= 32;
378 Hive
->FreeList
= malloc(sizeof(PCELL_HEADER
) * Hive
->FreeListMax
);
379 if (Hive
->FreeList
== NULL
)
381 free (Hive
->BlockList
);
382 free (Hive
->HiveHeader
);
386 Hive
->FreeListOffset
= malloc(sizeof(BLOCK_OFFSET
) * Hive
->FreeListMax
);
387 if (Hive
->FreeListOffset
== NULL
)
389 free (Hive
->FreeList
);
390 free (Hive
->BlockList
);
391 free (Hive
->HiveHeader
);
396 /* Allocate first bin */
397 Hive
->BlockList
[0] = (PHBIN
) malloc (REG_BLOCK_SIZE
);
398 if (Hive
->BlockList
[0] == NULL
)
400 free (Hive
->FreeListOffset
);
401 free (Hive
->FreeList
);
402 free (Hive
->BlockList
);
403 free (Hive
->HiveHeader
);
407 Hive
->FileSize
+= REG_BLOCK_SIZE
;
410 BinCell
= (PHBIN
)Hive
->BlockList
[0];
411 CmiCreateDefaultBinCell (BinCell
);
412 BinCell
->BinOffset
= 0;
414 /* Init root key cell */
415 RootKeyCell
= (PKEY_CELL
)((ULONG_PTR
)BinCell
+ REG_HBIN_DATA_OFFSET
);
416 CmiCreateDefaultRootKeyCell (RootKeyCell
, KeyName
);
417 Hive
->HiveHeader
->RootKeyOffset
= REG_HBIN_DATA_OFFSET
;
420 FreeCell
= (PCELL_HEADER
)((ULONG_PTR
)RootKeyCell
- RootKeyCell
->CellSize
);
421 FreeCell
->CellSize
= REG_BLOCK_SIZE
- (REG_HBIN_DATA_OFFSET
- RootKeyCell
->CellSize
);
423 Hive
->FreeList
[0] = FreeCell
;
424 Hive
->FreeListOffset
[0] = REG_HBIN_DATA_OFFSET
- RootKeyCell
->CellSize
;
425 Hive
->FreeListSize
++;
432 CmiDestroyRegistryHive (PREGISTRY_HIVE Hive
)
440 /* Release free offset list */
441 if (Hive
->FreeListOffset
!= NULL
)
442 free (Hive
->FreeListOffset
);
444 /* Release free list */
445 if (Hive
->FreeList
!= NULL
)
446 free (Hive
->FreeList
);
448 if (Hive
->BlockList
!= NULL
)
452 for (i
= 0; i
< Hive
->BlockListSize
; i
++)
454 if ((Hive
->BlockList
[i
] != NULL
) &&
455 (Hive
->BlockList
[i
] != Bin
))
457 Bin
= Hive
->BlockList
[i
];
459 DPRINT ("Bin[%lu]: Offset 0x%lx Size 0x%lx\n",
460 i
, Bin
->BinOffset
, Bin
->BinSize
);
466 /* Release block list */
467 free (Hive
->BlockList
);
470 /* Release hive header */
471 if (Hive
->HiveHeader
!= NULL
)
472 free (Hive
->HiveHeader
);
480 CmiGetCell (PREGISTRY_HIVE Hive
,
481 BLOCK_OFFSET BlockOffset
,
490 if (BlockOffset
== (ULONG_PTR
) -1)
493 BlockIndex
= BlockOffset
/ 4096;
494 if (BlockIndex
>= Hive
->BlockListSize
)
497 pBin
= Hive
->BlockList
[BlockIndex
];
501 return (PVOID
)((ULONG_PTR
)pBin
+ (BlockOffset
- pBin
->BinOffset
));
506 CmiMergeFree(PREGISTRY_HIVE RegistryHive
,
507 PCELL_HEADER FreeBlock
,
508 BLOCK_OFFSET FreeOffset
)
510 BLOCK_OFFSET BlockOffset
;
511 BLOCK_OFFSET BinOffset
;
517 DPRINT("CmiMergeFree(Block %p Offset %lx Size %lx) called\n",
518 FreeBlock
, FreeOffset
, FreeBlock
->CellSize
);
520 CmiGetCell (RegistryHive
,
523 DPRINT("Bin %p\n", Bin
);
527 BinOffset
= Bin
->BinOffset
;
528 BinSize
= Bin
->BinSize
;
529 DPRINT("Bin %p Offset %lx Size %lx\n", Bin
, BinOffset
, BinSize
);
531 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
533 BlockOffset
= RegistryHive
->FreeListOffset
[i
];
534 BlockSize
= RegistryHive
->FreeList
[i
]->CellSize
;
535 if (BlockOffset
> BinOffset
&&
536 BlockOffset
< BinOffset
+ BinSize
)
538 DPRINT("Free block: Offset %lx Size %lx\n",
539 BlockOffset
, BlockSize
);
541 if ((i
< (RegistryHive
->FreeListSize
- 1)) &&
542 (BlockOffset
+ BlockSize
== FreeOffset
) &&
543 (FreeOffset
+ FreeBlock
->CellSize
== RegistryHive
->FreeListOffset
[i
+ 1]))
545 DPRINT("Merge current block with previous and next block\n");
547 RegistryHive
->FreeList
[i
]->CellSize
+=
548 (FreeBlock
->CellSize
+ RegistryHive
->FreeList
[i
+ 1]->CellSize
);
550 FreeBlock
->CellSize
= 0;
551 RegistryHive
->FreeList
[i
+ 1]->CellSize
= 0;
554 if ((i
+ 2) < RegistryHive
->FreeListSize
)
556 memmove (&RegistryHive
->FreeList
[i
+ 1],
557 &RegistryHive
->FreeList
[i
+ 2],
558 sizeof(RegistryHive
->FreeList
[0])
559 * (RegistryHive
->FreeListSize
- i
- 2));
560 memmove (&RegistryHive
->FreeListOffset
[i
+ 1],
561 &RegistryHive
->FreeListOffset
[i
+ 2],
562 sizeof(RegistryHive
->FreeListOffset
[0])
563 * (RegistryHive
->FreeListSize
- i
- 2));
565 RegistryHive
->FreeListSize
--;
569 else if (BlockOffset
+ BlockSize
== FreeOffset
)
571 DPRINT("Merge current block with previous block\n");
573 RegistryHive
->FreeList
[i
]->CellSize
+= FreeBlock
->CellSize
;
574 FreeBlock
->CellSize
= 0;
578 else if (FreeOffset
+ FreeBlock
->CellSize
== BlockOffset
)
580 DPRINT("Merge current block with next block\n");
582 FreeBlock
->CellSize
+= RegistryHive
->FreeList
[i
]->CellSize
;
583 RegistryHive
->FreeList
[i
]->CellSize
= 0;
584 RegistryHive
->FreeList
[i
] = FreeBlock
;
585 RegistryHive
->FreeListOffset
[i
] = FreeOffset
;
597 CmiAddFree(PREGISTRY_HIVE RegistryHive
,
598 PCELL_HEADER FreeBlock
,
599 BLOCK_OFFSET FreeOffset
,
600 BOOL MergeFreeBlocks
)
602 PCELL_HEADER
*tmpList
;
603 BLOCK_OFFSET
*tmpListOffset
;
608 assert(RegistryHive
);
611 DPRINT("FreeBlock %p FreeOffset %.08lx\n",
612 FreeBlock
, FreeOffset
);
614 /* Merge free blocks */
615 if (MergeFreeBlocks
== TRUE
)
617 if (CmiMergeFree(RegistryHive
, FreeBlock
, FreeOffset
))
621 if ((RegistryHive
->FreeListSize
+ 1) > RegistryHive
->FreeListMax
)
623 tmpList
= malloc (sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
+ 32));
629 tmpListOffset
= malloc (sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
+ 32));
630 if (tmpListOffset
== NULL
)
636 if (RegistryHive
->FreeListMax
)
639 RegistryHive
->FreeList
,
640 sizeof(PCELL_HEADER
) * (RegistryHive
->FreeListMax
));
641 memmove (tmpListOffset
,
642 RegistryHive
->FreeListOffset
,
643 sizeof(BLOCK_OFFSET
) * (RegistryHive
->FreeListMax
));
644 free (RegistryHive
->FreeList
);
645 free (RegistryHive
->FreeListOffset
);
647 RegistryHive
->FreeList
= tmpList
;
648 RegistryHive
->FreeListOffset
= tmpListOffset
;
649 RegistryHive
->FreeListMax
+= 32;
652 /* Add new offset to free list, maintaining list in ascending order */
653 if ((RegistryHive
->FreeListSize
== 0)
654 || (RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
-1] < FreeOffset
))
656 /* Add to end of list */
657 RegistryHive
->FreeList
[RegistryHive
->FreeListSize
] = FreeBlock
;
658 RegistryHive
->FreeListOffset
[RegistryHive
->FreeListSize
++] = FreeOffset
;
660 else if (RegistryHive
->FreeListOffset
[0] > FreeOffset
)
662 /* Add to begin of list */
663 memmove (&RegistryHive
->FreeList
[1],
664 &RegistryHive
->FreeList
[0],
665 sizeof(RegistryHive
->FreeList
[0]) * RegistryHive
->FreeListSize
);
666 memmove (&RegistryHive
->FreeListOffset
[1],
667 &RegistryHive
->FreeListOffset
[0],
668 sizeof(RegistryHive
->FreeListOffset
[0]) * RegistryHive
->FreeListSize
);
669 RegistryHive
->FreeList
[0] = FreeBlock
;
670 RegistryHive
->FreeListOffset
[0] = FreeOffset
;
671 RegistryHive
->FreeListSize
++;
675 /* Search where to insert */
677 maxInd
= RegistryHive
->FreeListSize
- 1;
678 while ((maxInd
- minInd
) > 1)
680 medInd
= (minInd
+ maxInd
) / 2;
681 if (RegistryHive
->FreeListOffset
[medInd
] > FreeOffset
)
687 /* Insert before maxInd */
688 memmove (&RegistryHive
->FreeList
[maxInd
+1],
689 &RegistryHive
->FreeList
[maxInd
],
690 sizeof(RegistryHive
->FreeList
[0]) * (RegistryHive
->FreeListSize
- minInd
));
691 memmove (&RegistryHive
->FreeListOffset
[maxInd
+ 1],
692 &RegistryHive
->FreeListOffset
[maxInd
],
693 sizeof(RegistryHive
->FreeListOffset
[0]) * (RegistryHive
->FreeListSize
-minInd
));
694 RegistryHive
->FreeList
[maxInd
] = FreeBlock
;
695 RegistryHive
->FreeListOffset
[maxInd
] = FreeOffset
;
696 RegistryHive
->FreeListSize
++;
704 CmiAddBin(PREGISTRY_HIVE RegistryHive
,
707 PBLOCK_OFFSET NewBlockOffset
)
709 PCELL_HEADER tmpBlock
;
710 PHBIN
* tmpBlockList
;
715 BinSize
= BlockCount
*REG_BLOCK_SIZE
;
716 tmpBin
= malloc (BinSize
);
721 memset (tmpBin
, 0, BinSize
);
723 tmpBin
->HeaderId
= REG_BIN_ID
;
724 tmpBin
->BinOffset
= RegistryHive
->FileSize
- REG_BLOCK_SIZE
;
725 RegistryHive
->FileSize
+= BinSize
;
726 tmpBin
->BinSize
= BinSize
;
728 tmpBin
->DateModified
= 0ULL;
731 /* Increase size of list of blocks */
732 tmpBlockList
= malloc (sizeof(PHBIN
) * (RegistryHive
->BlockListSize
+ BlockCount
));
733 if (tmpBlockList
== NULL
)
739 if (RegistryHive
->BlockListSize
> 0)
741 memcpy (tmpBlockList
,
742 RegistryHive
->BlockList
,
743 sizeof(PHBIN
) * RegistryHive
->BlockListSize
);
744 free (RegistryHive
->BlockList
);
747 RegistryHive
->BlockList
= tmpBlockList
;
748 for (i
= 0; i
< BlockCount
; i
++)
749 RegistryHive
->BlockList
[RegistryHive
->BlockListSize
+ i
] = tmpBin
;
750 RegistryHive
->BlockListSize
+= BlockCount
;
752 /* Initialize a free block in this heap : */
753 tmpBlock
= (PCELL_HEADER
)((ULONG_PTR
) tmpBin
+ REG_HBIN_DATA_OFFSET
);
754 tmpBlock
->CellSize
= (REG_BLOCK_SIZE
- REG_HBIN_DATA_OFFSET
);
756 *NewBlock
= (PVOID
) tmpBlock
;
759 *NewBlockOffset
= tmpBin
->BinOffset
+ REG_HBIN_DATA_OFFSET
;
766 CmiAllocateCell (PREGISTRY_HIVE RegistryHive
,
769 PBLOCK_OFFSET pBlockOffset
)
771 PCELL_HEADER NewBlock
;
776 /* Round to 16 bytes multiple */
777 CellSize
= ROUND_UP(CellSize
, 16);
779 /* first search in free blocks */
781 for (i
= 0; i
< RegistryHive
->FreeListSize
; i
++)
783 if (RegistryHive
->FreeList
[i
]->CellSize
>= CellSize
)
785 NewBlock
= RegistryHive
->FreeList
[i
];
787 *pBlockOffset
= RegistryHive
->FreeListOffset
[i
];
789 if ((i
+ 1) < RegistryHive
->FreeListSize
)
791 memmove (&RegistryHive
->FreeList
[i
],
792 &RegistryHive
->FreeList
[i
+ 1],
793 sizeof(RegistryHive
->FreeList
[0])
794 * (RegistryHive
->FreeListSize
- i
- 1));
795 memmove (&RegistryHive
->FreeListOffset
[i
],
796 &RegistryHive
->FreeListOffset
[i
+ 1],
797 sizeof(RegistryHive
->FreeListOffset
[0])
798 * (RegistryHive
->FreeListSize
- i
- 1));
800 RegistryHive
->FreeListSize
--;
805 /* Need to extend hive file : */
806 if (NewBlock
== NULL
)
808 /* Add a new block */
809 if (!CmiAddBin(RegistryHive
,
810 ((sizeof(HBIN
) + CellSize
- 1) / REG_BLOCK_SIZE
) + 1,
818 /* Split the block in two parts */
819 if (NewBlock
->CellSize
> CellSize
)
821 NewBlock
= (PCELL_HEADER
) ((ULONG_PTR
) NewBlock
+ CellSize
);
822 NewBlock
->CellSize
= ((PCELL_HEADER
) (*Block
))->CellSize
- CellSize
;
823 CmiAddFree (RegistryHive
,
825 *pBlockOffset
+ CellSize
,
828 else if (NewBlock
->CellSize
< CellSize
)
833 memset(*Block
, 0, CellSize
);
834 ((PCELL_HEADER
)(*Block
))->CellSize
= -CellSize
;
841 CmiAllocateHashTableCell (PREGISTRY_HIVE Hive
,
842 PBLOCK_OFFSET HBOffset
,
845 PHASH_TABLE_CELL HashCell
;
849 NewHashSize
= sizeof(HASH_TABLE_CELL
) +
850 (SubKeyCount
* sizeof(HASH_RECORD
));
851 Status
= CmiAllocateCell (Hive
,
855 if ((HashCell
== NULL
) || (Status
== FALSE
))
860 HashCell
->Id
= REG_HASH_TABLE_CELL_ID
;
861 HashCell
->HashTableSize
= SubKeyCount
;
868 CmiAddKeyToParentHashTable (PREGISTRY_HIVE Hive
,
869 BLOCK_OFFSET ParentKeyOffset
,
870 PKEY_CELL NewKeyCell
,
871 BLOCK_OFFSET NKBOffset
)
873 PHASH_TABLE_CELL HashBlock
;
874 PKEY_CELL ParentKeyCell
;
877 ParentKeyCell
= CmiGetCell (Hive
,
880 if (ParentKeyCell
== NULL
)
882 DPRINT1 ("CmiGetBlock() failed\n");
886 HashBlock
=CmiGetCell (Hive
,
887 ParentKeyCell
->HashTableOffset
,
889 if (HashBlock
== NULL
)
891 DPRINT1 ("CmiGetBlock() failed\n");
895 for (i
= 0; i
< HashBlock
->HashTableSize
; i
++)
897 if (HashBlock
->Table
[i
].KeyOffset
== 0)
899 HashBlock
->Table
[i
].KeyOffset
= NKBOffset
;
900 memcpy (&HashBlock
->Table
[i
].HashValue
,
903 ParentKeyCell
->NumberOfSubKeys
++;
913 CmiAllocateValueListCell (PREGISTRY_HIVE Hive
,
914 PBLOCK_OFFSET ValueListOffset
,
917 PVALUE_LIST_CELL ValueListCell
;
921 ValueListSize
= sizeof(VALUE_LIST_CELL
) +
922 (ValueCount
* sizeof(BLOCK_OFFSET
));
923 Status
= CmiAllocateCell (Hive
,
925 (PVOID
)&ValueListCell
,
927 if ((ValueListCell
== NULL
) || (Status
== FALSE
))
929 DPRINT1 ("CmiAllocateBlock() failed\n");
938 CmiAllocateValueCell(PREGISTRY_HIVE Hive
,
939 PVALUE_CELL
*ValueCell
,
940 BLOCK_OFFSET
*ValueCellOffset
,
943 PVALUE_CELL NewValueCell
;
947 NameSize
= (ValueName
== NULL
) ? 0 : strlen (ValueName
);
948 Status
= CmiAllocateCell (Hive
,
949 sizeof(VALUE_CELL
) + NameSize
,
950 (PVOID
*)&NewValueCell
,
952 if ((NewValueCell
== NULL
) || (Status
== FALSE
))
954 DPRINT1 ("CmiAllocateBlock() failed\n");
958 NewValueCell
->Id
= REG_VALUE_CELL_ID
;
959 NewValueCell
->NameSize
= NameSize
;
962 memcpy (NewValueCell
->Name
,
965 NewValueCell
->Flags
= REG_VALUE_NAME_PACKED
;
967 NewValueCell
->DataType
= 0;
968 NewValueCell
->DataSize
= 0;
969 NewValueCell
->DataOffset
= -1;
971 *ValueCell
= NewValueCell
;
978 CmiAddValueToKeyValueList(PREGISTRY_HIVE Hive
,
979 BLOCK_OFFSET KeyCellOffset
,
980 BLOCK_OFFSET ValueCellOffset
)
982 PVALUE_LIST_CELL ValueListCell
;
985 KeyCell
= CmiGetCell (Hive
, KeyCellOffset
, NULL
);
988 DPRINT1 ("CmiGetBlock() failed\n");
992 ValueListCell
= CmiGetCell (Hive
, KeyCell
->ValueListOffset
, NULL
);
993 if (ValueListCell
== NULL
)
995 DPRINT1 ("CmiGetBlock() failed\n");
999 ValueListCell
->ValueOffset
[KeyCell
->NumberOfValues
] = ValueCellOffset
;
1000 KeyCell
->NumberOfValues
++;
1007 CmiExportValue (PREGISTRY_HIVE Hive
,
1008 BLOCK_OFFSET KeyCellOffset
,
1012 BLOCK_OFFSET ValueCellOffset
;
1013 BLOCK_OFFSET DataCellOffset
;
1014 PVALUE_CELL ValueCell
;
1015 PDATA_CELL DataCell
;
1020 BOOL Expand
= FALSE
;
1022 DPRINT ("CmiExportValue('%s') called\n", (Value
== NULL
) ? "<default>" : (PCHAR
)Value
->Name
);
1023 DPRINT ("DataSize %lu\n", (Value
== NULL
) ? Key
->DataSize
: Value
->DataSize
);
1025 /* Allocate value cell */
1026 if (!CmiAllocateValueCell(Hive
, &ValueCell
, &ValueCellOffset
, (Value
== NULL
) ? NULL
: Value
->Name
))
1031 if (!CmiAddValueToKeyValueList(Hive
, KeyCellOffset
, ValueCellOffset
))
1038 DataType
= Key
->DataType
;
1039 SrcDataSize
= Key
->DataSize
;
1044 DataType
= Value
->DataType
;
1045 SrcDataSize
= Value
->DataSize
;
1049 DstDataSize
= SrcDataSize
;
1050 if (DataType
== REG_SZ
||
1051 DataType
== REG_EXPAND_SZ
||
1052 DataType
== REG_MULTI_SZ
)
1054 DstDataSize
*= sizeof(WCHAR
);
1058 if ((DstDataSize
& REG_DATA_SIZE_MASK
) <= sizeof(BLOCK_OFFSET
))
1060 ValueCell
->DataSize
= DstDataSize
| REG_DATA_IN_OFFSET
;
1061 ValueCell
->DataType
= DataType
;
1064 memexpand ((PWCHAR
)&ValueCell
->DataOffset
,
1070 memcpy (&ValueCell
->DataOffset
,
1077 /* Allocate data cell */
1078 if (!CmiAllocateCell (Hive
,
1079 sizeof(CELL_HEADER
) + DstDataSize
,
1086 ValueCell
->DataOffset
= DataCellOffset
;
1087 ValueCell
->DataSize
= DstDataSize
& REG_DATA_SIZE_MASK
;
1088 ValueCell
->DataType
= DataType
;
1092 if (SrcDataSize
<= sizeof(BLOCK_OFFSET
))
1094 memexpand ((PWCHAR
)DataCell
->Data
,
1100 memexpand ((PWCHAR
)DataCell
->Data
,
1107 memcpy (DataCell
->Data
,
1118 CmiExportSubKey (PREGISTRY_HIVE Hive
,
1119 BLOCK_OFFSET ParentKeyOffset
,
1123 BLOCK_OFFSET NKBOffset
;
1124 PKEY_CELL NewKeyCell
;
1132 DPRINT ("CmiExportSubKey('%s') called\n", Key
->Name
);
1134 /* Don't export links */
1135 if (Key
->DataType
== REG_LINK
)
1138 /* Allocate key cell */
1139 KeyCellSize
= sizeof(KEY_CELL
) + Key
->NameSize
- 1;
1140 if (!CmiAllocateCell (Hive
, KeyCellSize
, (PVOID
)&NewKeyCell
, &NKBOffset
))
1142 DPRINT1 ("CmiAllocateBlock() failed\n");
1146 /* Initialize key cell */
1147 NewKeyCell
->Id
= REG_KEY_CELL_ID
;
1148 NewKeyCell
->Type
= REG_KEY_CELL_TYPE
;
1149 NewKeyCell
->LastWriteTime
= 0ULL;
1150 NewKeyCell
->ParentKeyOffset
= ParentKeyOffset
;
1151 NewKeyCell
->NumberOfSubKeys
= 0;
1152 NewKeyCell
->HashTableOffset
= -1;
1153 NewKeyCell
->NumberOfValues
= 0;
1154 NewKeyCell
->ValueListOffset
= -1;
1155 NewKeyCell
->SecurityKeyOffset
= -1;
1156 NewKeyCell
->NameSize
= Key
->NameSize
- 1;
1157 NewKeyCell
->ClassNameOffset
= -1;
1158 memcpy (NewKeyCell
->Name
,
1162 /* Add key cell to the parent key's hash table */
1163 if (!CmiAddKeyToParentHashTable (Hive
,
1168 DPRINT1 ("CmiAddKeyToParentHashTable() failed\n");
1172 ValueCount
= RegGetValueCount (Key
);
1173 DPRINT ("ValueCount: %lu\n", ValueCount
);
1176 /* Allocate value list cell */
1177 CmiAllocateValueListCell (Hive
,
1178 &NewKeyCell
->ValueListOffset
,
1181 if (Key
->DataSize
!= 0)
1183 if (!CmiExportValue (Hive
, NKBOffset
, Key
, NULL
))
1187 /* Enumerate values */
1188 Entry
= Key
->ValueList
.Flink
;
1189 while (Entry
!= &Key
->ValueList
)
1191 Value
= CONTAINING_RECORD(Entry
,
1195 if (!CmiExportValue (Hive
, NKBOffset
, Key
, Value
))
1198 Entry
= Entry
->Flink
;
1202 SubKeyCount
= RegGetSubKeyCount (Key
);
1203 DPRINT ("SubKeyCount: %lu\n", SubKeyCount
);
1204 if (SubKeyCount
> 0)
1206 /* Allocate hash table cell */
1207 CmiAllocateHashTableCell (Hive
,
1208 &NewKeyCell
->HashTableOffset
,
1211 /* Enumerate subkeys */
1212 Entry
= Key
->SubKeyList
.Flink
;
1213 while (Entry
!= &Key
->SubKeyList
)
1215 SubKey
= CONTAINING_RECORD(Entry
,
1219 if (!CmiExportSubKey (Hive
, NKBOffset
, Key
, SubKey
))
1222 Entry
= Entry
->Flink
;
1231 CmiCalcHiveChecksum (PREGISTRY_HIVE Hive
)
1237 Buffer
= (PULONG
)Hive
->HiveHeader
;
1239 for (i
= 0; i
< 127; i
++)
1242 Hive
->HiveHeader
->Checksum
= Sum
;
1247 CmiExportHive (PREGISTRY_HIVE Hive
,
1258 DPRINT ("CmiExportHive(%p, '%s') called\n", Hive
, KeyName
);
1260 if (RegOpenKey (NULL
, KeyName
, &Key
) != ERROR_SUCCESS
)
1262 DPRINT1 ("RegOpenKey() failed\n");
1266 DPRINT ("Name: %s\n", KeyName
);
1268 KeyCell
= CmiGetCell (Hive
,
1269 Hive
->HiveHeader
->RootKeyOffset
,
1271 if (KeyCell
== NULL
)
1273 DPRINT1 ("CmiGetCell() failed\n");
1277 ValueCount
= RegGetValueCount (Key
);
1278 DPRINT ("ValueCount: %lu\n", ValueCount
);
1281 /* Allocate value list cell */
1282 CmiAllocateValueListCell (Hive
,
1283 &KeyCell
->ValueListOffset
,
1286 if (Key
->DataSize
!= 0)
1288 if (!CmiExportValue (Hive
, Hive
->HiveHeader
->RootKeyOffset
, Key
, NULL
))
1292 /* Enumerate values */
1293 Entry
= Key
->ValueList
.Flink
;
1294 while (Entry
!= &Key
->ValueList
)
1296 Value
= CONTAINING_RECORD(Entry
,
1300 if (!CmiExportValue (Hive
, Hive
->HiveHeader
->RootKeyOffset
, Key
, Value
))
1303 Entry
= Entry
->Flink
;
1307 SubKeyCount
= RegGetSubKeyCount (Key
);
1308 DPRINT ("SubKeyCount: %lu\n", SubKeyCount
);
1309 if (SubKeyCount
> 0)
1311 /* Allocate hash table cell */
1312 CmiAllocateHashTableCell (Hive
,
1313 &KeyCell
->HashTableOffset
,
1316 /* Enumerate subkeys */
1317 Entry
= Key
->SubKeyList
.Flink
;
1318 while (Entry
!= &Key
->SubKeyList
)
1320 SubKey
= CONTAINING_RECORD(Entry
,
1324 if (!CmiExportSubKey (Hive
, Hive
->HiveHeader
->RootKeyOffset
, Key
, SubKey
))
1327 Entry
= Entry
->Flink
;
1331 CmiCalcHiveChecksum (Hive
);
1338 CmiWriteHive(PREGISTRY_HIVE Hive
,
1346 /* Check for existing hive file */
1347 File
= fopen (FileName
, "rb");
1350 printf (" File already exists\n");
1356 /* Create new hive file */
1357 File
= fopen (FileName
, "w+b");
1363 fseek (File
, 0, SEEK_SET
);
1365 /* Calculate header checksum */
1366 CmiCalcHiveChecksum (Hive
);
1368 /* Write hive header */
1369 fwrite (Hive
->HiveHeader
, REG_BLOCK_SIZE
, 1, File
);
1372 for (i
= 0; i
< Hive
->BlockListSize
; i
++)
1374 if (Hive
->BlockList
[i
] != Bin
)
1376 Bin
= Hive
->BlockList
[i
];
1378 DPRINT ("Bin[%lu]: Offset 0x%lx Size 0x%lx\n",
1379 i
, Bin
->BinOffset
, Bin
->BinSize
);
1381 fwrite (Bin
, Bin
->BinSize
, 1, File
);
1392 ExportBinaryHive (PCHAR FileName
,
1395 PREGISTRY_HIVE Hive
;
1397 printf (" Creating binary hive: %s\n", FileName
);
1399 Hive
= CmiCreateRegistryHive (KeyName
);
1403 if (!CmiExportHive (Hive
, KeyName
))
1405 CmiDestroyRegistryHive (Hive
);
1409 if (!CmiWriteHive (Hive
, FileName
))
1411 CmiDestroyRegistryHive (Hive
);
1415 CmiDestroyRegistryHive (Hive
);