b062b961aa987fce17792a7b64796767dbf17e6f
[reactos.git] / reactos / boot / freeldr / freeldr / reactos / binhive.c
1 /*
2 * FreeLoader
3 *
4 * Copyright (C) 2001 Rex Jolliff
5 * Copyright (C) 2001 Eric Kohl
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include <freeldr.h>
23
24 #define NDEBUG
25 #include <debug.h>
26
27 #define REG_HIVE_ID 0x66676572 /* "regf" */
28 #define REG_BIN_ID 0x6e696268 /* "hbin" */
29 #define REG_KEY_CELL_ID 0x6b6e
30 #define REG_HASH_TABLE_BLOCK_ID 0x666c
31 #define REG_VALUE_CELL_ID 0x6b76
32
33 #define REG_BLOCK_SIZE 4096
34 #define REG_HBIN_DATA_OFFSET 32
35 #define REG_INIT_BLOCK_LIST_SIZE 32
36 #define REG_INIT_HASH_TABLE_SIZE 3
37 #define REG_EXTEND_HASH_TABLE_SIZE 4
38 #define REG_VALUE_LIST_CELL_MULTIPLE 4
39
40
41 #define ABS_VALUE(V) (((V) < 0) ? -(V) : (V))
42
43
44 /* BLOCK_OFFSET = offset in file after header block */
45 typedef ULONG BLOCK_OFFSET, *PBLOCK_OFFSET;
46
47 /* header for registry hive file : */
48 typedef struct _HIVE_HEADER
49 {
50 /* Hive identifier "regf" (0x66676572) */
51 ULONG BlockId;
52
53 /* Update counter */
54 ULONG UpdateCounter1;
55
56 /* Update counter */
57 ULONG UpdateCounter2;
58
59 /* When this hive file was last modified */
60 ULONGLONG DateModified;
61
62 /* Registry format major version (1) */
63 ULONG MajorVersion;
64
65 /* Registry format minor version (3)
66 Version 3 added fast indexes, version 5 has large value optimizations */
67 ULONG MinorVersion;
68
69 /* Registry file type (0 - Primary, 1 - Log) */
70 ULONG Type;
71
72 /* Registry format (1 is the only defined value so far) */
73 ULONG Format;
74
75 /* Offset into file from the byte after the end of the base block.
76 If the hive is volatile, this is the actual pointer to the KEY_CELL */
77 BLOCK_OFFSET RootKeyOffset;
78
79 /* Size of each hive block ? */
80 ULONG BlockSize;
81
82 /* (1?) */
83 ULONG Unused7;
84
85 /* Name of hive file */
86 WCHAR FileName[48];
87
88 ULONG Reserved[99];
89
90 /* Checksum of first 0x200 bytes */
91 ULONG Checksum;
92 } __attribute__((packed)) HIVE_HEADER, *PHIVE_HEADER;
93
94
95 typedef struct _BIN_HEADER
96 {
97 /* Bin identifier "hbin" (0x6E696268) */
98 ULONG HeaderId;
99
100 /* Block offset of this bin */
101 BLOCK_OFFSET BinOffset;
102
103 /* Size in bytes, multiple of the block size (4KB) */
104 ULONG BinSize;
105
106 ULONG Reserved[2];
107
108 /* When this bin was last modified */
109 ULONGLONG DateModified;
110
111 /* ? (In-memory only) */
112 ULONG MemAlloc;
113 } __attribute__((packed)) HBIN, *PHBIN;
114
115
116 typedef struct _CELL_HEADER
117 {
118 /* <0 if used, >0 if free */
119 LONG CellSize;
120 } __attribute__((packed)) CELL_HEADER, *PCELL_HEADER;
121
122
123 typedef struct _KEY_CELL
124 {
125 /* Size of this cell */
126 LONG CellSize;
127
128 /* Key cell identifier "kn" (0x6b6e) */
129 USHORT Id;
130
131 /* Flags */
132 USHORT Flags;
133
134 /* Time of last flush */
135 ULONGLONG LastWriteTime; /* FILETIME */
136
137 /* ? */
138 ULONG UnUsed1;
139
140 /* Block offset of parent key cell */
141 BLOCK_OFFSET ParentKeyOffset;
142
143 /* Count of sub keys for the key in this key cell */
144 ULONG NumberOfSubKeys;
145
146 /* ? */
147 ULONG UnUsed2;
148
149 /* Block offset of has table for FIXME: subkeys/values? */
150 BLOCK_OFFSET HashTableOffset;
151
152 /* ? */
153 ULONG UnUsed3;
154
155 /* Count of values contained in this key cell */
156 ULONG NumberOfValues;
157
158 /* Block offset of VALUE_LIST_CELL */
159 BLOCK_OFFSET ValueListOffset;
160
161 /* Block offset of security cell */
162 BLOCK_OFFSET SecurityKeyOffset;
163
164 /* Block offset of registry key class */
165 BLOCK_OFFSET ClassNameOffset;
166
167 /* ? */
168 ULONG Unused4[5];
169
170 /* Size in bytes of key name */
171 USHORT NameSize;
172
173 /* Size of class name in bytes */
174 USHORT ClassSize;
175
176 /* Name of key (not zero terminated) */
177 CHAR Name[0];
178 } __attribute__((packed)) KEY_CELL, *PKEY_CELL;
179
180
181 /* KEY_CELL.Type constants */
182 #define REG_LINK_KEY_CELL_TYPE 0x10
183 #define REG_KEY_NAME_PACKED 0x20
184 #define REG_ROOT_KEY_CELL_TYPE 0x0c
185
186
187 // hash record :
188 // HashValue=four letters of value's name
189 typedef struct _HASH_RECORD
190 {
191 BLOCK_OFFSET KeyOffset;
192 ULONG HashValue;
193 } __attribute__((packed)) HASH_RECORD, *PHASH_RECORD;
194
195
196 typedef struct _HASH_TABLE_CELL
197 {
198 LONG CellSize;
199 USHORT Id;
200 USHORT HashTableSize;
201 HASH_RECORD Table[0];
202 } __attribute__((packed)) HASH_TABLE_CELL, *PHASH_TABLE_CELL;
203
204
205 typedef struct _VALUE_LIST_CELL
206 {
207 LONG CellSize;
208 BLOCK_OFFSET ValueOffset[0];
209 } __attribute__((packed)) VALUE_LIST_CELL, *PVALUE_LIST_CELL;
210
211
212 typedef struct _VALUE_CELL
213 {
214 LONG CellSize;
215 USHORT Id; // "kv"
216 USHORT NameSize; // length of Name
217 ULONG DataSize; // length of datas in the cell pointed by DataOffset
218 BLOCK_OFFSET DataOffset;// datas are here if high bit of DataSize is set
219 ULONG DataType;
220 USHORT Flags;
221 USHORT Unused1;
222 CHAR Name[0]; /* warning : not zero terminated */
223 } __attribute__((packed)) VALUE_CELL, *PVALUE_CELL;
224
225 /* VALUE_CELL.Flags constants */
226 #define REG_VALUE_NAME_PACKED 0x0001
227
228 /* VALUE_CELL.DataSize mask constants */
229 #define REG_DATA_SIZE_MASK 0x7FFFFFFF
230 #define REG_DATA_IN_OFFSET 0x80000000
231
232
233 typedef struct _DATA_CELL
234 {
235 LONG CellSize;
236 CHAR Data[0];
237 } __attribute__((packed)) DATA_CELL, *PDATA_CELL;
238
239
240 typedef struct _REGISTRY_HIVE
241 {
242 ULONG FileSize;
243 PHIVE_HEADER HiveHeader;
244 ULONG BlockListSize;
245 PHBIN *BlockList;
246 ULONG FreeListSize;
247 ULONG FreeListMax;
248 PCELL_HEADER *FreeList;
249 BLOCK_OFFSET *FreeListOffset;
250 } REGISTRY_HIVE, *PREGISTRY_HIVE;
251
252
253 static PVOID MbBase = NULL;
254 static ULONG MbSize = 0;
255
256 /* FUNCTIONS ****************************************************************/
257
258 static VOID
259 InitMbMemory (PVOID ChunkBase)
260 {
261 MbBase = ChunkBase;
262 MbSize = 0;
263 }
264
265
266 static PVOID
267 AllocateMbMemory (ULONG MemSize)
268 {
269 PVOID CurBase;
270
271 CurBase = MbBase;
272
273 MbBase = (PVOID)((ULONG)MbBase + MemSize);
274 MbSize += MemSize;
275
276 return CurBase;
277 }
278
279 static VOID
280 FreeMbMemory (VOID)
281 {
282 MbSize = 0;
283 }
284
285 static ULONG
286 GetMbAllocatedSize (VOID)
287 {
288 return MbSize;
289 }
290
291
292 static VOID
293 CmiCreateDefaultHiveHeader (PHIVE_HEADER Header)
294 {
295 assert(Header);
296 memset (Header, 0, REG_BLOCK_SIZE);
297 Header->BlockId = REG_HIVE_ID;
298 Header->UpdateCounter1 = 0;
299 Header->UpdateCounter2 = 0;
300 Header->DateModified = 0;
301 Header->MajorVersion = 1;
302 Header->MinorVersion = 3;
303 Header->Type = 0;
304 Header->Format = 1;
305 Header->Unused7 = 1;
306 Header->RootKeyOffset = -1;
307 Header->BlockSize = REG_BLOCK_SIZE;
308 Header->Checksum = 0;
309 }
310
311
312 static VOID
313 CmiCreateDefaultBinCell (PHBIN BinCell)
314 {
315 assert(BinCell);
316 memset (BinCell, 0, REG_BLOCK_SIZE);
317 BinCell->HeaderId = REG_BIN_ID;
318 BinCell->DateModified = 0ULL;
319 BinCell->BinSize = REG_BLOCK_SIZE;
320 }
321
322
323 static VOID
324 CmiCreateDefaultRootKeyCell (PKEY_CELL RootKeyCell, PCWSTR KeyName)
325 {
326 PWCHAR BaseKeyName;
327 ULONG NameSize;
328 ULONG CellSize;
329 ULONG i;
330 BOOL Packable = TRUE;
331
332 assert (RootKeyCell);
333
334 BaseKeyName = wcsrchr(KeyName, L'\\') + 1;
335 NameSize = wcslen(BaseKeyName);
336 for (i = 0; i < NameSize; i++)
337 {
338 if (KeyName[i] & 0xFF00)
339 {
340 Packable = FALSE;
341 NameSize *= sizeof(WCHAR);
342 break;
343 }
344 }
345
346 CellSize = ROUND_UP(sizeof(KEY_CELL) + NameSize, 16);
347
348 memset (RootKeyCell, 0, CellSize);
349 RootKeyCell->CellSize = -CellSize;
350 RootKeyCell->Id = REG_KEY_CELL_ID;
351 RootKeyCell->Flags = REG_ROOT_KEY_CELL_TYPE;
352 RootKeyCell->LastWriteTime = 0ULL;
353 RootKeyCell->ParentKeyOffset = 0;
354 RootKeyCell->NumberOfSubKeys = 0;
355 RootKeyCell->HashTableOffset = -1;
356 RootKeyCell->NumberOfValues = 0;
357 RootKeyCell->ValueListOffset = -1;
358 RootKeyCell->SecurityKeyOffset = 0;
359 RootKeyCell->ClassNameOffset = -1;
360 RootKeyCell->NameSize = NameSize;
361 RootKeyCell->ClassSize = 0;
362 if (Packable)
363 {
364 for(i = 0; i < NameSize; i++)
365 {
366 ((PCHAR)RootKeyCell->Name)[i] = BaseKeyName[i];
367 }
368 RootKeyCell->Flags |= REG_KEY_NAME_PACKED;
369 }
370 else
371 {
372 memcpy (RootKeyCell->Name, BaseKeyName, NameSize);
373 }
374 }
375
376
377 static PREGISTRY_HIVE
378 CmiCreateHive (PCWSTR KeyName)
379 {
380 PREGISTRY_HIVE Hive;
381 PCELL_HEADER FreeCell;
382 PKEY_CELL RootKeyCell;
383 PHBIN BinCell;
384
385 Hive = (PREGISTRY_HIVE) MmAllocateMemory (sizeof(REGISTRY_HIVE));
386 if (Hive == NULL)
387 {
388 return NULL;
389 }
390 memset (Hive, 0, sizeof(REGISTRY_HIVE));
391
392 DbgPrint((DPRINT_REGISTRY, "Hive %x\n", Hive));
393
394 /* Create hive beader (aka 'base block') */
395 Hive->HiveHeader = (PHIVE_HEADER) AllocateMbMemory (REG_BLOCK_SIZE);
396 if (Hive->HiveHeader == NULL)
397 {
398 MmFreeMemory (Hive);
399 return NULL;
400 }
401 CmiCreateDefaultHiveHeader(Hive->HiveHeader);
402 Hive->FileSize = REG_BLOCK_SIZE;
403
404 /* Allocate block list */
405 Hive->BlockListSize = 1;
406 Hive->BlockList = MmAllocateMemory (sizeof(PHBIN) * Hive->BlockListSize);
407 if (Hive->BlockList == NULL)
408 {
409 MmFreeMemory (Hive);
410 return NULL;
411 }
412
413 /* Allocate free cell list */
414 Hive->FreeListMax = 32;
415 Hive->FreeList = MmAllocateMemory(sizeof(PCELL_HEADER) * Hive->FreeListMax);
416 if (Hive->FreeList == NULL)
417 {
418 MmFreeMemory (Hive->BlockList);
419 MmFreeMemory (Hive);
420 return NULL;
421 }
422 Hive->FreeListOffset = MmAllocateMemory(sizeof(BLOCK_OFFSET) * Hive->FreeListMax);
423 if (Hive->FreeListOffset == NULL)
424 {
425 MmFreeMemory (Hive->FreeList);
426 MmFreeMemory (Hive->BlockList);
427 MmFreeMemory (Hive);
428 return NULL;
429 }
430
431 /* Allocate first bin */
432 Hive->BlockList[0] = (PHBIN) AllocateMbMemory (REG_BLOCK_SIZE);
433 if (Hive->BlockList[0] == NULL)
434 {
435 MmFreeMemory (Hive->FreeListOffset);
436 MmFreeMemory (Hive->FreeList);
437 MmFreeMemory (Hive->BlockList);
438 MmFreeMemory (Hive);
439 return NULL;
440 }
441 Hive->FileSize += REG_BLOCK_SIZE;
442
443 /* Init first bin */
444 BinCell = (PHBIN)Hive->BlockList[0];
445 CmiCreateDefaultBinCell(BinCell);
446 BinCell->BinOffset = 0;
447
448 /* Init root key cell */
449 RootKeyCell = (PKEY_CELL)((ULONG)BinCell + REG_HBIN_DATA_OFFSET);
450 CmiCreateDefaultRootKeyCell(RootKeyCell, KeyName);
451 Hive->HiveHeader->RootKeyOffset = REG_HBIN_DATA_OFFSET;
452
453 /* Init free cell */
454 FreeCell = (PCELL_HEADER)((ULONG)RootKeyCell - RootKeyCell->CellSize);
455 FreeCell->CellSize = REG_BLOCK_SIZE - (REG_HBIN_DATA_OFFSET - RootKeyCell->CellSize);
456
457 Hive->FreeList[0] = FreeCell;
458 Hive->FreeListOffset[0] = REG_HBIN_DATA_OFFSET - RootKeyCell->CellSize;
459 Hive->FreeListSize++;
460
461 return Hive;
462 }
463
464
465 static VOID
466 CmiCleanupHive(PREGISTRY_HIVE Hive, BOOL Release)
467 {
468 MmFreeMemory (Hive->FreeListOffset);
469 MmFreeMemory (Hive->FreeList);
470 MmFreeMemory (Hive->BlockList);
471 MmFreeMemory (Hive);
472
473 if (Release)
474 {
475 FreeMbMemory ();
476 }
477 }
478
479
480 static PHBIN
481 CmiGetBin (PREGISTRY_HIVE Hive,
482 BLOCK_OFFSET BlockOffset)
483 {
484 ULONG BlockIndex;
485
486 if (BlockOffset == (ULONG) -1)
487 return NULL;
488
489 BlockIndex = BlockOffset / REG_BLOCK_SIZE;
490 if (BlockIndex >= Hive->BlockListSize)
491 return NULL;
492
493 return Hive->BlockList[BlockIndex];
494 }
495
496
497 static BOOL
498 CmiMergeFree(PREGISTRY_HIVE RegistryHive,
499 PCELL_HEADER FreeBlock,
500 BLOCK_OFFSET FreeOffset)
501 {
502 BLOCK_OFFSET BlockOffset;
503 BLOCK_OFFSET BinOffset;
504 ULONG BlockSize;
505 ULONG BinSize;
506 PHBIN Bin;
507 ULONG i;
508
509 DbgPrint((DPRINT_REGISTRY, "CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
510 FreeBlock, FreeOffset, FreeBlock->CellSize));
511
512 Bin = CmiGetBin (RegistryHive, FreeOffset);
513 if (Bin == NULL)
514 return FALSE;
515
516 DbgPrint((DPRINT_REGISTRY, "Bin %p\n", Bin));
517
518 BinOffset = Bin->BinOffset;
519 BinSize = Bin->BinSize;
520 DbgPrint((DPRINT_REGISTRY, "Bin %p Offset %lx Size %lx\n", Bin, BinOffset, BinSize));
521
522 for (i = 0; i < RegistryHive->FreeListSize; i++)
523 {
524 BlockOffset = RegistryHive->FreeListOffset[i];
525 BlockSize = RegistryHive->FreeList[i]->CellSize;
526 if (BlockOffset > BinOffset &&
527 BlockOffset < BinOffset + BinSize)
528 {
529 DbgPrint((DPRINT_REGISTRY, "Free block: Offset %lx Size %lx\n",
530 BlockOffset, BlockSize));
531
532 if ((i < (RegistryHive->FreeListSize - 1)) &&
533 (BlockOffset + BlockSize == FreeOffset) &&
534 (FreeOffset + FreeBlock->CellSize == RegistryHive->FreeListOffset[i + 1]))
535 {
536 DbgPrint((DPRINT_REGISTRY, "Merge current block with previous and next block\n"));
537
538 RegistryHive->FreeList[i]->CellSize +=
539 (FreeBlock->CellSize + RegistryHive->FreeList[i + 1]->CellSize);
540
541 FreeBlock->CellSize = 0;
542 RegistryHive->FreeList[i + 1]->CellSize = 0;
543
544
545 if ((i + 2) < RegistryHive->FreeListSize)
546 {
547 memmove (&RegistryHive->FreeList[i + 1],
548 &RegistryHive->FreeList[i + 2],
549 sizeof(RegistryHive->FreeList[0])
550 * (RegistryHive->FreeListSize - i - 2));
551 memmove (&RegistryHive->FreeListOffset[i + 1],
552 &RegistryHive->FreeListOffset[i + 2],
553 sizeof(RegistryHive->FreeListOffset[0])
554 * (RegistryHive->FreeListSize - i - 2));
555 }
556 RegistryHive->FreeListSize--;
557
558 return TRUE;
559 }
560 else if (BlockOffset + BlockSize == FreeOffset)
561 {
562 DbgPrint((DPRINT_REGISTRY, "Merge current block with previous block\n"));
563
564 RegistryHive->FreeList[i]->CellSize += FreeBlock->CellSize;
565 FreeBlock->CellSize = 0;
566
567 return TRUE;
568 }
569 else if (FreeOffset + FreeBlock->CellSize == BlockOffset)
570 {
571 DbgPrint((DPRINT_REGISTRY, "Merge current block with next block\n"));
572
573 FreeBlock->CellSize += RegistryHive->FreeList[i]->CellSize;
574 RegistryHive->FreeList[i]->CellSize = 0;
575 RegistryHive->FreeList[i] = FreeBlock;
576 RegistryHive->FreeListOffset[i] = FreeOffset;
577
578 return TRUE;
579 }
580 }
581 }
582
583 return FALSE;
584 }
585
586
587 static BOOL
588 CmiAddFree(PREGISTRY_HIVE RegistryHive,
589 PCELL_HEADER FreeBlock,
590 BLOCK_OFFSET FreeOffset,
591 BOOL MergeFreeBlocks)
592 {
593 PCELL_HEADER *tmpList;
594 BLOCK_OFFSET *tmpListOffset;
595 LONG minInd;
596 LONG maxInd;
597 LONG medInd;
598
599 assert(RegistryHive);
600 assert(FreeBlock);
601
602 DbgPrint((DPRINT_REGISTRY, "FreeBlock %.08lx FreeOffset %.08lx\n",
603 FreeBlock, FreeOffset));
604
605 /* Merge free blocks */
606 if (MergeFreeBlocks == TRUE)
607 {
608 if (CmiMergeFree(RegistryHive, FreeBlock, FreeOffset))
609 return TRUE;
610 }
611
612 if ((RegistryHive->FreeListSize + 1) > RegistryHive->FreeListMax)
613 {
614 tmpList = MmAllocateMemory (sizeof(PCELL_HEADER) * (RegistryHive->FreeListMax + 32));
615 if (tmpList == NULL)
616 {
617 return FALSE;
618 }
619
620 tmpListOffset = MmAllocateMemory (sizeof(BLOCK_OFFSET) * (RegistryHive->FreeListMax + 32));
621 if (tmpListOffset == NULL)
622 {
623 MmFreeMemory (tmpList);
624 return FALSE;
625 }
626
627 if (RegistryHive->FreeListMax)
628 {
629 memmove (tmpList,
630 RegistryHive->FreeList,
631 sizeof(PCELL_HEADER) * (RegistryHive->FreeListMax));
632 memmove (tmpListOffset,
633 RegistryHive->FreeListOffset,
634 sizeof(BLOCK_OFFSET) * (RegistryHive->FreeListMax));
635 MmFreeMemory (RegistryHive->FreeList);
636 MmFreeMemory (RegistryHive->FreeListOffset);
637 }
638 RegistryHive->FreeList = tmpList;
639 RegistryHive->FreeListOffset = tmpListOffset;
640 RegistryHive->FreeListMax += 32;
641 }
642
643 /* Add new offset to free list, maintaining list in ascending order */
644 if ((RegistryHive->FreeListSize == 0)
645 || (RegistryHive->FreeListOffset[RegistryHive->FreeListSize-1] < FreeOffset))
646 {
647 /* Add to end of list */
648 RegistryHive->FreeList[RegistryHive->FreeListSize] = FreeBlock;
649 RegistryHive->FreeListOffset[RegistryHive->FreeListSize++] = FreeOffset;
650 }
651 else if (RegistryHive->FreeListOffset[0] > FreeOffset)
652 {
653 /* Add to begin of list */
654 memmove (&RegistryHive->FreeList[1],
655 &RegistryHive->FreeList[0],
656 sizeof(RegistryHive->FreeList[0]) * RegistryHive->FreeListSize);
657 memmove (&RegistryHive->FreeListOffset[1],
658 &RegistryHive->FreeListOffset[0],
659 sizeof(RegistryHive->FreeListOffset[0]) * RegistryHive->FreeListSize);
660 RegistryHive->FreeList[0] = FreeBlock;
661 RegistryHive->FreeListOffset[0] = FreeOffset;
662 RegistryHive->FreeListSize++;
663 }
664 else
665 {
666 /* Search where to insert */
667 minInd = 0;
668 maxInd = RegistryHive->FreeListSize - 1;
669 while ((maxInd - minInd) > 1)
670 {
671 medInd = (minInd + maxInd) / 2;
672 if (RegistryHive->FreeListOffset[medInd] > FreeOffset)
673 maxInd = medInd;
674 else
675 minInd = medInd;
676 }
677
678 /* Insert before maxInd */
679 memmove (&RegistryHive->FreeList[maxInd+1],
680 &RegistryHive->FreeList[maxInd],
681 sizeof(RegistryHive->FreeList[0]) * (RegistryHive->FreeListSize - minInd));
682 memmove (&RegistryHive->FreeListOffset[maxInd + 1],
683 &RegistryHive->FreeListOffset[maxInd],
684 sizeof(RegistryHive->FreeListOffset[0]) * (RegistryHive->FreeListSize-minInd));
685 RegistryHive->FreeList[maxInd] = FreeBlock;
686 RegistryHive->FreeListOffset[maxInd] = FreeOffset;
687 RegistryHive->FreeListSize++;
688 }
689
690 return TRUE;
691 }
692
693
694 static BOOL
695 CmiAddBin(PREGISTRY_HIVE RegistryHive,
696 ULONG BlockCount,
697 PVOID *NewBlock,
698 PBLOCK_OFFSET NewBlockOffset)
699 {
700 PCELL_HEADER tmpBlock;
701 PHBIN *BlockList;
702 PHBIN tmpBin;
703 ULONG BinSize;
704 ULONG i;
705
706 BinSize = BlockCount * REG_BLOCK_SIZE;
707 tmpBin = AllocateMbMemory (BinSize);
708 if (tmpBin == NULL)
709 {
710 return FALSE;
711 }
712 memset (tmpBin, 0, BinSize);
713
714 tmpBin->HeaderId = REG_BIN_ID;
715 tmpBin->BinOffset = RegistryHive->FileSize - REG_BLOCK_SIZE;
716 RegistryHive->FileSize += BinSize;
717 tmpBin->BinSize = BinSize;
718 tmpBin->DateModified = 0ULL;
719 tmpBin->MemAlloc = 0;
720
721 /* Increase size of list of blocks */
722 BlockList = MmAllocateMemory (sizeof(PHBIN) * (RegistryHive->BlockListSize + BlockCount));
723 if (BlockList == NULL)
724 {
725 return FALSE;
726 }
727
728 if (RegistryHive->BlockListSize > 0)
729 {
730 memcpy (BlockList,
731 RegistryHive->BlockList,
732 sizeof(PHBIN) * RegistryHive->BlockListSize);
733 MmFreeMemory (RegistryHive->BlockList);
734 }
735
736 RegistryHive->BlockList = BlockList;
737 for (i = 0; i < BlockCount; i++)
738 RegistryHive->BlockList[RegistryHive->BlockListSize + i] = tmpBin;
739 RegistryHive->BlockListSize += BlockCount;
740
741 /* Initialize a free block in this heap : */
742 tmpBlock = (PCELL_HEADER)((ULONG) tmpBin + REG_HBIN_DATA_OFFSET);
743 tmpBlock->CellSize = (REG_BLOCK_SIZE - REG_HBIN_DATA_OFFSET);
744
745 *NewBlock = (PVOID) tmpBlock;
746
747 if (NewBlockOffset)
748 *NewBlockOffset = tmpBin->BinOffset + REG_HBIN_DATA_OFFSET;
749
750 return TRUE;
751 }
752
753
754 static BOOL
755 CmiAllocateCell (PREGISTRY_HIVE RegistryHive,
756 LONG CellSize,
757 PVOID *Block,
758 PBLOCK_OFFSET pBlockOffset)
759 {
760 PCELL_HEADER NewBlock;
761 ULONG i;
762
763 *Block = NULL;
764
765 /* Round to 16 bytes multiple */
766 CellSize = ROUND_UP(CellSize, 16);
767
768 /* first search in free blocks */
769 NewBlock = NULL;
770 for (i = 0; i < RegistryHive->FreeListSize; i++)
771 {
772 if (RegistryHive->FreeList[i]->CellSize >= CellSize)
773 {
774 NewBlock = RegistryHive->FreeList[i];
775 if (pBlockOffset)
776 *pBlockOffset = RegistryHive->FreeListOffset[i];
777
778 if ((i + 1) < RegistryHive->FreeListSize)
779 {
780 memmove (&RegistryHive->FreeList[i],
781 &RegistryHive->FreeList[i + 1],
782 sizeof(RegistryHive->FreeList[0])
783 * (RegistryHive->FreeListSize - i - 1));
784 memmove (&RegistryHive->FreeListOffset[i],
785 &RegistryHive->FreeListOffset[i + 1],
786 sizeof(RegistryHive->FreeListOffset[0])
787 * (RegistryHive->FreeListSize - i - 1));
788 }
789 RegistryHive->FreeListSize--;
790 break;
791 }
792 }
793
794 /* Need to extend hive file */
795 if (NewBlock == NULL)
796 {
797 /* Add a new block */
798 if (!CmiAddBin(RegistryHive,
799 ((sizeof(HBIN) + CellSize - 1) / REG_BLOCK_SIZE) + 1,
800 (PVOID *)(PVOID)&NewBlock,
801 pBlockOffset))
802 return FALSE;
803 }
804
805 *Block = NewBlock;
806
807 /* Split the block in two parts */
808 if (NewBlock->CellSize > CellSize)
809 {
810 NewBlock = (PCELL_HEADER) ((ULONG)NewBlock + CellSize);
811 NewBlock->CellSize = ((PCELL_HEADER) (*Block))->CellSize - CellSize;
812 ((PCELL_HEADER) (*Block))->CellSize = CellSize;
813 CmiAddFree (RegistryHive,
814 NewBlock,
815 *pBlockOffset + CellSize,
816 TRUE);
817 }
818 else if (NewBlock->CellSize < CellSize)
819 {
820 return FALSE;
821 }
822
823 memset(*Block, 0, CellSize);
824 ((PCELL_HEADER)(*Block))->CellSize *= -1;
825
826 return TRUE;
827 }
828
829
830 static PVOID
831 CmiGetCell (PREGISTRY_HIVE Hive,
832 BLOCK_OFFSET BlockOffset)
833 {
834 PHBIN Bin;
835 ULONG BlockIndex;
836
837 if (BlockOffset == (ULONG) -1)
838 return NULL;
839
840 BlockIndex = BlockOffset / REG_BLOCK_SIZE;
841 if (BlockIndex >= Hive->BlockListSize)
842 return NULL;
843
844 Bin = Hive->BlockList[BlockIndex];
845 if (Bin == NULL)
846 return NULL;
847
848 return (PVOID)((ULONG)Bin + (BlockOffset - Bin->BinOffset));
849 }
850
851
852 static BOOL
853 CmiAllocateHashTableCell (PREGISTRY_HIVE Hive,
854 PBLOCK_OFFSET HBOffset,
855 ULONG SubKeyCount)
856 {
857 PHASH_TABLE_CELL HashCell;
858 ULONG NewHashSize;
859 BOOL Status;
860
861 NewHashSize = sizeof(HASH_TABLE_CELL) +
862 (SubKeyCount * sizeof(HASH_RECORD));
863 Status = CmiAllocateCell (Hive,
864 NewHashSize,
865 (PVOID*)(PVOID)&HashCell,
866 HBOffset);
867 if ((HashCell == NULL) || (Status == FALSE))
868 {
869 return FALSE;
870 }
871
872 HashCell->Id = REG_HASH_TABLE_BLOCK_ID;
873 HashCell->HashTableSize = SubKeyCount;
874
875 return TRUE;
876 }
877
878
879 static BOOL
880 CmiAddKeyToParentHashTable (PREGISTRY_HIVE Hive,
881 BLOCK_OFFSET ParentKeyOffset,
882 PKEY_CELL NewKeyCell,
883 BLOCK_OFFSET NKBOffset)
884 {
885 PHASH_TABLE_CELL HashBlock;
886 PKEY_CELL ParentKeyCell;
887 ULONG i;
888
889 ParentKeyCell = CmiGetCell (Hive, ParentKeyOffset);
890 if (ParentKeyCell == NULL)
891 {
892 DbgPrint((DPRINT_REGISTRY, "CmiGetCell() failed\n"));
893 return FALSE;
894 }
895
896 HashBlock =CmiGetCell (Hive, ParentKeyCell->HashTableOffset);
897 if (HashBlock == NULL)
898 {
899 DbgPrint((DPRINT_REGISTRY, "CmiGetCell() failed\n"));
900 return FALSE;
901 }
902
903 for (i = 0; i < HashBlock->HashTableSize; i++)
904 {
905 if (HashBlock->Table[i].KeyOffset == 0)
906 {
907 HashBlock->Table[i].KeyOffset = NKBOffset;
908 memcpy (&HashBlock->Table[i].HashValue,
909 NewKeyCell->Name,
910 min(NewKeyCell->NameSize, sizeof(ULONG)));
911 ParentKeyCell->NumberOfSubKeys++;
912 return TRUE;
913 }
914 }
915
916 return FALSE;
917 }
918
919
920 static BOOL
921 CmiAllocateValueListCell (PREGISTRY_HIVE Hive,
922 PBLOCK_OFFSET ValueListOffset,
923 ULONG ValueCount)
924 {
925 PVALUE_LIST_CELL ValueListCell;
926 ULONG ValueListSize;
927 BOOL Status;
928
929 ValueListSize = sizeof(VALUE_LIST_CELL) +
930 (ValueCount * sizeof(BLOCK_OFFSET));
931 Status = CmiAllocateCell (Hive,
932 ValueListSize,
933 (PVOID)&ValueListCell,
934 ValueListOffset);
935 if ((ValueListCell == NULL) || (Status == FALSE))
936 {
937 DbgPrint((DPRINT_REGISTRY, "CmiAllocateCell() failed\n"));
938 return FALSE;
939 }
940
941 return TRUE;
942 }
943
944
945 static BOOL
946 CmiAllocateValueCell(PREGISTRY_HIVE Hive,
947 PVALUE_CELL *ValueCell,
948 BLOCK_OFFSET *ValueCellOffset,
949 PWCHAR ValueName)
950 {
951 PVALUE_CELL NewValueCell;
952 ULONG NameSize;
953 BOOL Status;
954 BOOLEAN Packable = TRUE;
955 ULONG i;
956
957 NameSize = (ValueName == NULL) ? 0 : wcslen (ValueName);
958 for (i = 0; i < NameSize; i++)
959 {
960 if (ValueName[i] & 0xFF00)
961 {
962 NameSize *= sizeof(WCHAR);
963 Packable = FALSE;
964 break;
965 }
966 }
967 Status = CmiAllocateCell (Hive,
968 sizeof(VALUE_CELL) + NameSize,
969 (PVOID*)(PVOID)&NewValueCell,
970 ValueCellOffset);
971 if ((NewValueCell == NULL) || (Status == FALSE))
972 {
973 DbgPrint((DPRINT_REGISTRY, "CmiAllocateCell() failed\n"));
974 return FALSE;
975 }
976
977 NewValueCell->Id = REG_VALUE_CELL_ID;
978 NewValueCell->NameSize = NameSize;
979 NewValueCell->Flags = 0;
980 if (NameSize > 0)
981 {
982 if (Packable)
983 {
984 for (i = 0; i < NameSize; i++)
985 {
986 ((PCHAR)NewValueCell->Name)[i] = (CHAR)ValueName[i];
987 }
988 NewValueCell->Flags |= REG_VALUE_NAME_PACKED;
989 }
990 else
991 {
992 memcpy (NewValueCell->Name,
993 ValueName,
994 NameSize);
995 }
996 }
997 NewValueCell->DataType = 0;
998 NewValueCell->DataSize = 0;
999 NewValueCell->DataOffset = -1;
1000
1001 *ValueCell = NewValueCell;
1002
1003 return TRUE;
1004 }
1005
1006
1007 static BOOL
1008 CmiAddValueToKeyValueList(PREGISTRY_HIVE Hive,
1009 BLOCK_OFFSET KeyCellOffset,
1010 BLOCK_OFFSET ValueCellOffset)
1011 {
1012 PVALUE_LIST_CELL ValueListCell;
1013 PKEY_CELL KeyCell;
1014
1015 KeyCell = CmiGetCell (Hive, KeyCellOffset);
1016 if (KeyCell == NULL)
1017 {
1018 DbgPrint((DPRINT_REGISTRY, "CmiGetCell() failed\n"));
1019 return FALSE;
1020 }
1021
1022 ValueListCell = CmiGetCell (Hive, KeyCell->ValueListOffset);
1023 if (ValueListCell == NULL)
1024 {
1025 DbgPrint((DPRINT_REGISTRY, "CmiGetCell() failed\n"));
1026 return FALSE;
1027 }
1028
1029 ValueListCell->ValueOffset[KeyCell->NumberOfValues] = ValueCellOffset;
1030 KeyCell->NumberOfValues++;
1031
1032 return TRUE;
1033 }
1034
1035 static BOOL
1036 CmiExportValue (PREGISTRY_HIVE Hive,
1037 BLOCK_OFFSET KeyCellOffset,
1038 FRLDRHKEY Key,
1039 PVALUE Value)
1040 {
1041 BLOCK_OFFSET ValueCellOffset;
1042 BLOCK_OFFSET DataCellOffset;
1043 PVALUE_CELL ValueCell;
1044 PDATA_CELL DataCell;
1045 ULONG DataSize;
1046 ULONG DataType;
1047 PCHAR Data;
1048
1049 DbgPrint((DPRINT_REGISTRY, "CmiExportValue('%S') called\n",
1050 (Value == NULL) ? "<default>" : (PCHAR)Value->Name));
1051 DbgPrint((DPRINT_REGISTRY, "DataSize %lu\n",
1052 (Value == NULL) ? Key->DataSize : Value->DataSize));
1053
1054 /* Allocate value cell */
1055 if (!CmiAllocateValueCell(Hive, &ValueCell, &ValueCellOffset, (Value == NULL) ? NULL : Value->Name))
1056 {
1057 return FALSE;
1058 }
1059
1060 if (!CmiAddValueToKeyValueList(Hive, KeyCellOffset, ValueCellOffset))
1061 {
1062 return FALSE;
1063 }
1064
1065 if (Value == NULL)
1066 {
1067 DataType = Key->DataType;
1068 DataSize = Key->DataSize;
1069 Data = Key->Data;
1070 }
1071 else
1072 {
1073 DataType = Value->DataType;
1074 DataSize = Value->DataSize;
1075 Data = Value->Data;
1076 }
1077
1078 if (DataSize <= sizeof(BLOCK_OFFSET))
1079 {
1080 ValueCell->DataSize = DataSize | REG_DATA_IN_OFFSET;
1081 ValueCell->DataType = DataType;
1082 memcpy (&ValueCell->DataOffset,
1083 Data,
1084 DataSize);
1085 }
1086 else
1087 {
1088 /* Allocate data cell */
1089 if (!CmiAllocateCell (Hive,
1090 sizeof(CELL_HEADER) + DataSize,
1091 (PVOID *)(PVOID)&DataCell,
1092 &DataCellOffset))
1093 {
1094 return FALSE;
1095 }
1096
1097 ValueCell->DataOffset = DataCellOffset;
1098 ValueCell->DataSize = DataSize;
1099 ValueCell->DataType = DataType;
1100
1101 memcpy (DataCell->Data,
1102 Data,
1103 DataSize);
1104 }
1105
1106 return TRUE;
1107 }
1108
1109
1110 static BOOL
1111 CmiExportSubKey (PREGISTRY_HIVE Hive,
1112 BLOCK_OFFSET ParentKeyOffset,
1113 FRLDRHKEY ParentKey,
1114 FRLDRHKEY Key)
1115 {
1116 BLOCK_OFFSET NKBOffset;
1117 PKEY_CELL NewKeyCell;
1118 ULONG KeyCellSize;
1119 ULONG SubKeyCount;
1120 ULONG ValueCount;
1121 PLIST_ENTRY Entry;
1122 FRLDRHKEY SubKey;
1123 PVALUE Value;
1124 BOOLEAN Packable = TRUE;
1125 ULONG i;
1126 ULONG NameSize;
1127
1128 DbgPrint((DPRINT_REGISTRY, "CmiExportSubKey('%S') called\n", Key->Name));
1129
1130 /* Don't export links */
1131 if (Key->DataType == REG_LINK)
1132 return TRUE;
1133
1134 NameSize = (Key->NameSize - sizeof(WCHAR)) / sizeof(WCHAR);
1135 for (i = 0; i < NameSize; i++)
1136 {
1137 if (Key->Name[i] & 0xFF00)
1138 {
1139 Packable = FALSE;
1140 NameSize *= sizeof(WCHAR);
1141 break;
1142 }
1143 }
1144
1145 /* Allocate key cell */
1146 KeyCellSize = sizeof(KEY_CELL) + NameSize;
1147 if (!CmiAllocateCell (Hive, KeyCellSize, (PVOID)&NewKeyCell, &NKBOffset))
1148 {
1149 DbgPrint((DPRINT_REGISTRY, "CmiAllocateCell() failed\n"));
1150 return FALSE;
1151 }
1152
1153 /* Initialize key cell */
1154 NewKeyCell->Id = REG_KEY_CELL_ID;
1155 NewKeyCell->Flags = 0;
1156 NewKeyCell->LastWriteTime = 0ULL;
1157 NewKeyCell->ParentKeyOffset = ParentKeyOffset;
1158 NewKeyCell->NumberOfSubKeys = 0;
1159 NewKeyCell->HashTableOffset = -1;
1160 NewKeyCell->NumberOfValues = 0;
1161 NewKeyCell->ValueListOffset = -1;
1162 NewKeyCell->SecurityKeyOffset = -1;
1163 NewKeyCell->ClassNameOffset = -1;
1164 NewKeyCell->NameSize = NameSize;
1165 NewKeyCell->ClassSize = 0;
1166 if (Packable)
1167 {
1168 for (i = 0; i < NameSize; i++)
1169 {
1170 ((PCHAR)NewKeyCell->Name)[i] = (CHAR)Key->Name[i];
1171 }
1172 NewKeyCell->Flags |= REG_KEY_NAME_PACKED;
1173
1174 }
1175 else
1176 {
1177 memcpy (NewKeyCell->Name,
1178 Key->Name,
1179 NameSize);
1180 }
1181
1182 /* Add key cell to the parent key's hash table */
1183 if (!CmiAddKeyToParentHashTable (Hive,
1184 ParentKeyOffset,
1185 NewKeyCell,
1186 NKBOffset))
1187 {
1188 DbgPrint((DPRINT_REGISTRY, "CmiAddKeyToParentHashTable() failed\n"));
1189 return FALSE;
1190 }
1191
1192 ValueCount = RegGetValueCount (Key);
1193 DbgPrint((DPRINT_REGISTRY, "ValueCount: %u\n", ValueCount));
1194 if (ValueCount > 0)
1195 {
1196 /* Allocate value list cell */
1197 if (!CmiAllocateValueListCell (Hive,
1198 &NewKeyCell->ValueListOffset,
1199 ValueCount))
1200 {
1201 DbgPrint((DPRINT_REGISTRY, "CmiAllocateValueListCell() failed\n"));
1202 return FALSE;
1203 }
1204
1205 if (Key->DataSize != 0)
1206 {
1207 if (!CmiExportValue (Hive, NKBOffset, Key, NULL))
1208 return FALSE;
1209 }
1210
1211 /* Enumerate values */
1212 Entry = Key->ValueList.Flink;
1213 while (Entry != &Key->ValueList)
1214 {
1215 Value = CONTAINING_RECORD(Entry,
1216 VALUE,
1217 ValueList);
1218
1219 if (!CmiExportValue (Hive, NKBOffset, Key, Value))
1220 return FALSE;
1221
1222 Entry = Entry->Flink;
1223 }
1224 }
1225
1226 SubKeyCount = RegGetSubKeyCount (Key);
1227 DbgPrint((DPRINT_REGISTRY, "SubKeyCount: %u\n", SubKeyCount));
1228 if (SubKeyCount > 0)
1229 {
1230 /* Allocate hash table cell */
1231 if (!CmiAllocateHashTableCell (Hive,
1232 &NewKeyCell->HashTableOffset,
1233 SubKeyCount))
1234 {
1235 DbgPrint((DPRINT_REGISTRY, "CmiAllocateHashTableCell() failed\n"));
1236 return FALSE;
1237 }
1238
1239 /* Enumerate subkeys */
1240 Entry = Key->SubKeyList.Flink;
1241 while (Entry != &Key->SubKeyList)
1242 {
1243 SubKey = CONTAINING_RECORD(Entry,
1244 KEY,
1245 KeyList);
1246
1247 if (!CmiExportSubKey (Hive, NKBOffset, Key, SubKey))
1248 return FALSE;
1249
1250 Entry = Entry->Flink;
1251 }
1252 }
1253
1254 return TRUE;
1255 }
1256
1257
1258 static VOID
1259 CmiCalcHiveChecksum (PREGISTRY_HIVE Hive)
1260 {
1261 ULONG *Buffer;
1262 ULONG Sum;
1263 ULONG i;
1264
1265 Buffer = (ULONG*)Hive->HiveHeader;
1266 Sum = 0;
1267 for (i = 0; i < 127; i++)
1268 Sum += Buffer[i];
1269
1270 Hive->HiveHeader->Checksum = Sum;
1271 }
1272
1273
1274 static BOOL
1275 CmiExportHive (PREGISTRY_HIVE Hive,
1276 PCWSTR KeyName)
1277 {
1278 PKEY_CELL KeyCell;
1279 FRLDRHKEY Key;
1280 ULONG SubKeyCount;
1281 ULONG ValueCount;
1282 PLIST_ENTRY Entry;
1283 FRLDRHKEY SubKey;
1284 PVALUE Value;
1285
1286 DbgPrint((DPRINT_REGISTRY, "CmiExportHive(%x, '%S') called\n", Hive, KeyName));
1287
1288 if (RegOpenKey (NULL, KeyName, &Key) != ERROR_SUCCESS)
1289 {
1290 DbgPrint((DPRINT_REGISTRY, "RegOpenKey() failed\n"));
1291 return FALSE;
1292 }
1293
1294 KeyCell = CmiGetCell (Hive, Hive->HiveHeader->RootKeyOffset);
1295 if (KeyCell == NULL)
1296 {
1297 DbgPrint((DPRINT_REGISTRY, "CmiGetBlock() failed\n"));
1298 return FALSE;
1299 }
1300
1301 ValueCount = RegGetValueCount (Key);
1302 DbgPrint((DPRINT_REGISTRY, "ValueCount: %u\n", ValueCount));
1303 if (ValueCount > 0)
1304 {
1305 /* Allocate value list cell */
1306 if (!CmiAllocateValueListCell (Hive,
1307 &KeyCell->ValueListOffset,
1308 ValueCount))
1309 {
1310 DbgPrint((DPRINT_REGISTRY, "CmiAllocateValueListCell() failed\n"));
1311 return FALSE;
1312 }
1313
1314 if (Key->DataSize != 0)
1315 {
1316 if (!CmiExportValue (Hive, Hive->HiveHeader->RootKeyOffset, Key, NULL))
1317 return FALSE;
1318 }
1319
1320 /* Enumerate values */
1321 Entry = Key->ValueList.Flink;
1322 while (Entry != &Key->ValueList)
1323 {
1324 Value = CONTAINING_RECORD(Entry,
1325 VALUE,
1326 ValueList);
1327
1328 if (!CmiExportValue (Hive, Hive->HiveHeader->RootKeyOffset, Key, Value))
1329 return FALSE;
1330
1331 Entry = Entry->Flink;
1332 }
1333 }
1334
1335 SubKeyCount = RegGetSubKeyCount (Key);
1336 DbgPrint((DPRINT_REGISTRY, "SubKeyCount: %u\n", SubKeyCount));
1337 if (SubKeyCount > 0)
1338 {
1339 /* Allocate hash table cell */
1340 if (!CmiAllocateHashTableCell (Hive,
1341 &KeyCell->HashTableOffset,
1342 SubKeyCount))
1343 {
1344 DbgPrint((DPRINT_REGISTRY, "CmiAllocateHashTableCell() failed\n"));
1345 return FALSE;
1346 }
1347
1348 /* Enumerate subkeys */
1349 Entry = Key->SubKeyList.Flink;
1350 while (Entry != &Key->SubKeyList)
1351 {
1352 SubKey = CONTAINING_RECORD(Entry,
1353 KEY,
1354 KeyList);
1355
1356 if (!CmiExportSubKey (Hive, Hive->HiveHeader->RootKeyOffset, Key, SubKey))
1357 return FALSE;
1358
1359 Entry = Entry->Flink;
1360 }
1361 }
1362
1363 CmiCalcHiveChecksum (Hive);
1364
1365 return TRUE;
1366 }
1367
1368
1369 static BOOL
1370 RegImportValue (PHBIN RootBin,
1371 PVALUE_CELL ValueCell,
1372 FRLDRHKEY Key)
1373 {
1374 PDATA_CELL DataCell;
1375 PWCHAR wName;
1376 LONG Error;
1377 ULONG DataSize;
1378 ULONG i;
1379
1380 if (ValueCell->CellSize >= 0 || ValueCell->Id != REG_VALUE_CELL_ID)
1381 {
1382 DbgPrint((DPRINT_REGISTRY, "Invalid key cell!\n"));
1383 return FALSE;
1384 }
1385
1386 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1387 {
1388 wName = MmAllocateMemory ((ValueCell->NameSize + 1)*sizeof(WCHAR));
1389 for (i = 0; i < ValueCell->NameSize; i++)
1390 {
1391 wName[i] = ((PCHAR)ValueCell->Name)[i];
1392 }
1393 wName[ValueCell->NameSize] = 0;
1394 }
1395 else
1396 {
1397 wName = MmAllocateMemory (ValueCell->NameSize + sizeof(WCHAR));
1398 memcpy (wName,
1399 ValueCell->Name,
1400 ValueCell->NameSize);
1401 wName[ValueCell->NameSize / sizeof(WCHAR)] = 0;
1402 }
1403
1404 DataSize = ValueCell->DataSize & REG_DATA_SIZE_MASK;
1405
1406 DbgPrint((DPRINT_REGISTRY, "ValueName: '%S'\n", wName));
1407 DbgPrint((DPRINT_REGISTRY, "DataSize: %u\n", DataSize));
1408
1409 if (DataSize <= sizeof(BLOCK_OFFSET) && (ValueCell->DataSize & REG_DATA_IN_OFFSET))
1410 {
1411 Error = RegSetValue(Key,
1412 wName,
1413 ValueCell->DataType,
1414 (PCHAR)&ValueCell->DataOffset,
1415 DataSize);
1416 if (Error != ERROR_SUCCESS)
1417 {
1418 DbgPrint((DPRINT_REGISTRY, "RegSetValue() failed!\n"));
1419 MmFreeMemory (wName);
1420 return FALSE;
1421 }
1422 }
1423 else
1424 {
1425 DataCell = (PDATA_CELL)((PUCHAR)RootBin + ValueCell->DataOffset);
1426 DbgPrint((DPRINT_REGISTRY, "DataCell: %x\n", DataCell));
1427
1428 if (DataCell->CellSize >= 0)
1429 {
1430 DbgPrint((DPRINT_REGISTRY, "Invalid data cell size!\n"));
1431 MmFreeMemory (wName);
1432 return FALSE;
1433 }
1434
1435 Error = RegSetValue (Key,
1436 wName,
1437 ValueCell->DataType,
1438 DataCell->Data,
1439 DataSize);
1440
1441 if (Error != ERROR_SUCCESS)
1442 {
1443 DbgPrint((DPRINT_REGISTRY, "RegSetValue() failed!\n"));
1444 MmFreeMemory (wName);
1445 return FALSE;
1446 }
1447 }
1448
1449 MmFreeMemory (wName);
1450
1451 return TRUE;
1452 }
1453
1454
1455 static BOOL
1456 RegImportSubKey(PHBIN RootBin,
1457 PKEY_CELL KeyCell,
1458 FRLDRHKEY ParentKey)
1459 {
1460 PHASH_TABLE_CELL HashCell;
1461 PKEY_CELL SubKeyCell;
1462 PVALUE_LIST_CELL ValueListCell;
1463 PVALUE_CELL ValueCell = NULL;
1464 PWCHAR wName;
1465 FRLDRHKEY SubKey;
1466 LONG Error;
1467 ULONG i;
1468
1469
1470 DbgPrint((DPRINT_REGISTRY, "KeyCell: %x\n", KeyCell));
1471 DbgPrint((DPRINT_REGISTRY, "KeyCell->CellSize: %x\n", KeyCell->CellSize));
1472 DbgPrint((DPRINT_REGISTRY, "KeyCell->Id: %x\n", KeyCell->Id));
1473 if (KeyCell->Id != REG_KEY_CELL_ID || KeyCell->CellSize >= 0)
1474 {
1475 DbgPrint((DPRINT_REGISTRY, "Invalid key cell id!\n"));
1476 return FALSE;
1477 }
1478
1479 if (KeyCell->Flags & REG_KEY_NAME_PACKED)
1480 {
1481 wName = MmAllocateMemory ((KeyCell->NameSize + 1) * sizeof(WCHAR));
1482 for (i = 0; i < KeyCell->NameSize; i++)
1483 {
1484 wName[i] = ((PCHAR)KeyCell->Name)[i];
1485 }
1486 wName[KeyCell->NameSize] = 0;
1487 }
1488 else
1489 {
1490 wName = MmAllocateMemory (KeyCell->NameSize + sizeof(WCHAR));
1491 memcpy (wName,
1492 KeyCell->Name,
1493 KeyCell->NameSize);
1494 wName[KeyCell->NameSize/sizeof(WCHAR)] = 0;
1495 }
1496
1497 DbgPrint((DPRINT_REGISTRY, "KeyName: '%S'\n", wName));
1498
1499 /* Create new sub key */
1500 Error = RegCreateKey (ParentKey,
1501 wName,
1502 &SubKey);
1503 MmFreeMemory (wName);
1504 if (Error != ERROR_SUCCESS)
1505 {
1506 DbgPrint((DPRINT_REGISTRY, "RegCreateKey() failed!\n"));
1507 return FALSE;
1508 }
1509 DbgPrint((DPRINT_REGISTRY, "Subkeys: %u\n", KeyCell->NumberOfSubKeys));
1510 DbgPrint((DPRINT_REGISTRY, "Values: %u\n", KeyCell->NumberOfValues));
1511
1512 /* Enumerate and add values */
1513 if (KeyCell->NumberOfValues > 0)
1514 {
1515 ValueListCell = (PVALUE_LIST_CELL)((PUCHAR)RootBin + KeyCell->ValueListOffset);
1516 DbgPrint((DPRINT_REGISTRY, "ValueListCell: %x\n", ValueListCell));
1517
1518 for (i = 0; i < KeyCell->NumberOfValues; i++)
1519 {
1520 DbgPrint((DPRINT_REGISTRY, "ValueOffset[%d]: %x\n", i, ValueListCell->ValueOffset[i]));
1521
1522 ValueCell = (PVALUE_CELL)((PUCHAR)RootBin + ValueListCell->ValueOffset[i]);
1523
1524 DbgPrint((DPRINT_REGISTRY, "ValueCell[%d]: %x\n", i, ValueCell));
1525
1526 if (!RegImportValue(RootBin, ValueCell, SubKey))
1527 return FALSE;
1528 }
1529 }
1530
1531 /* Enumerate and add subkeys */
1532 if (KeyCell->NumberOfSubKeys > 0)
1533 {
1534 HashCell = (PHASH_TABLE_CELL)((PUCHAR)RootBin + KeyCell->HashTableOffset);
1535 DbgPrint((DPRINT_REGISTRY, "HashCell: %x\n", HashCell));
1536
1537 for (i = 0; i < KeyCell->NumberOfSubKeys; i++)
1538 {
1539 DbgPrint((DPRINT_REGISTRY, "KeyOffset[%d]: %x\n", i, HashCell->Table[i].KeyOffset));
1540
1541 SubKeyCell = (PKEY_CELL)((PUCHAR)RootBin + HashCell->Table[i].KeyOffset);
1542
1543 DbgPrint((DPRINT_REGISTRY, "SubKeyCell[%d]: %x\n", i, SubKeyCell));
1544
1545 if (!RegImportSubKey(RootBin, SubKeyCell, SubKey))
1546 return FALSE;
1547 }
1548 }
1549
1550 return TRUE;
1551 }
1552
1553
1554 BOOL
1555 RegImportBinaryHive(PCHAR ChunkBase,
1556 ULONG ChunkSize)
1557 {
1558 PHIVE_HEADER HiveHeader;
1559 PHBIN RootBin;
1560 PKEY_CELL KeyCell;
1561 PHASH_TABLE_CELL HashCell;
1562 PKEY_CELL SubKeyCell;
1563 FRLDRHKEY SystemKey;
1564 ULONG i;
1565 LONG Error;
1566
1567 DbgPrint((DPRINT_REGISTRY, "RegImportBinaryHive(%x, %u) called\n",ChunkBase,ChunkSize));
1568
1569 HiveHeader = (PHIVE_HEADER)ChunkBase;
1570 DbgPrint((DPRINT_REGISTRY, "HiveHeader: %x\n", HiveHeader));
1571 if (HiveHeader->BlockId != REG_HIVE_ID)
1572 {
1573 DbgPrint((DPRINT_REGISTRY, "Invalid hive id!\n"));
1574 return FALSE;
1575 }
1576
1577 RootBin = (PHBIN)((ULONG)HiveHeader + REG_BLOCK_SIZE);
1578 DbgPrint((DPRINT_REGISTRY, "RootBin: %x\n", RootBin));
1579 if (RootBin->HeaderId != REG_BIN_ID || RootBin->BinSize == 0)
1580 {
1581 DbgPrint((DPRINT_REGISTRY, "Invalid bin id!\n"));
1582 return FALSE;
1583 }
1584
1585 KeyCell = (PKEY_CELL)((ULONG)RootBin + REG_HBIN_DATA_OFFSET);
1586 DbgPrint((DPRINT_REGISTRY, "KeyCell: %x\n", KeyCell));
1587 DbgPrint((DPRINT_REGISTRY, "KeyCell->CellSize: %x\n", KeyCell->CellSize));
1588 DbgPrint((DPRINT_REGISTRY, "KeyCell->Id: %x\n", KeyCell->Id));
1589 if (KeyCell->Id != REG_KEY_CELL_ID || KeyCell->CellSize >= 0)
1590 {
1591 DbgPrint((DPRINT_REGISTRY, "Invalid key cell id!\n"));
1592 return FALSE;
1593 }
1594
1595 DbgPrint((DPRINT_REGISTRY, "Subkeys: %u\n", KeyCell->NumberOfSubKeys));
1596 DbgPrint((DPRINT_REGISTRY, "Values: %u\n", KeyCell->NumberOfValues));
1597
1598 /* Open 'System' key */
1599 Error = RegOpenKey(NULL,
1600 L"\\Registry\\Machine\\SYSTEM",
1601 &SystemKey);
1602 if (Error != ERROR_SUCCESS)
1603 {
1604 DbgPrint((DPRINT_REGISTRY, "Failed to open 'system' key!\n"));
1605 return FALSE;
1606 }
1607
1608 /* Enumerate and add subkeys */
1609 if (KeyCell->NumberOfSubKeys > 0)
1610 {
1611 HashCell = (PHASH_TABLE_CELL)((ULONG)RootBin + KeyCell->HashTableOffset);
1612 DbgPrint((DPRINT_REGISTRY, "HashCell: %x\n", HashCell));
1613
1614 for (i = 0; i < KeyCell->NumberOfSubKeys; i++)
1615 {
1616 DbgPrint((DPRINT_REGISTRY, "KeyOffset[%d]: %x\n", i, HashCell->Table[i].KeyOffset));
1617
1618 SubKeyCell = (PKEY_CELL)((ULONG)RootBin + HashCell->Table[i].KeyOffset);
1619
1620 DbgPrint((DPRINT_REGISTRY, "SubKeyCell[%d]: %x\n", i, SubKeyCell));
1621
1622 if (!RegImportSubKey(RootBin, SubKeyCell, SystemKey))
1623 return FALSE;
1624 }
1625 }
1626
1627 return TRUE;
1628 }
1629
1630
1631 BOOL
1632 RegExportBinaryHive(PCWSTR KeyName,
1633 PCHAR ChunkBase,
1634 ULONG* ChunkSize)
1635 {
1636 PREGISTRY_HIVE Hive;
1637
1638 DbgPrint((DPRINT_REGISTRY, "Creating binary hardware hive\n"));
1639
1640 *ChunkSize = 0;
1641 InitMbMemory (ChunkBase);
1642
1643 Hive = CmiCreateHive (KeyName);
1644 if (Hive == NULL)
1645 return FALSE;
1646
1647 if (!CmiExportHive (Hive, KeyName))
1648 {
1649 CmiCleanupHive (Hive, TRUE);
1650 return FALSE;
1651 }
1652
1653 CmiCleanupHive (Hive, FALSE);
1654
1655 *ChunkSize = GetMbAllocatedSize ();
1656
1657 return TRUE;
1658 }
1659
1660 /* EOF */