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.
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 /* FIXME: Calculate header checksum */
1324 File = fopen (FileName, "w+b");
1331 fseek (File, 0, SEEK_SET);
1333 /* Write hive header */
1334 fwrite (Hive->HiveHeader, REG_BLOCK_SIZE, 1, File);
1337 for (i = 0; i < Hive->BlockListSize; i++)
1339 if (Hive->BlockList[i] != Bin)
1341 Bin = Hive->BlockList[i];
1343 DPRINT ("Bin[%lu]: Offset 0x%lx Size 0x%lx\n",
1344 i, Bin->BlockOffset, Bin->BlockSize);
1346 fwrite (Bin, Bin->BlockSize, 1, File);
1357 ExportBinaryHive (PCHAR FileName,
1360 PREGISTRY_HIVE Hive;
1362 printf (" Creating binary hive: %s\n", FileName);
1364 Hive = CmiCreateRegistryHive ();
1368 if (!CmiExportHive (Hive, KeyName))
1370 CmiDestroyRegistryHive (Hive);
1374 if (!CmiWriteHive (Hive, FileName))
1376 CmiDestroyRegistryHive (Hive);
1380 CmiDestroyRegistryHive (Hive);