Fix some registry structures to match the Windows format.
[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 CmiAddFree (RegistryHive,
813 NewBlock,
814 *pBlockOffset + CellSize,
815 TRUE);
816 }
817 else if (NewBlock->CellSize < CellSize)
818 {
819 return FALSE;
820 }
821
822 memset(*Block, 0, CellSize);
823 ((PCELL_HEADER)(*Block))->CellSize = -CellSize;
824
825 return TRUE;
826 }
827
828
829 static PVOID
830 CmiGetCell (PREGISTRY_HIVE Hive,
831 BLOCK_OFFSET BlockOffset)
832 {
833 PHBIN Bin;
834 ULONG BlockIndex;
835
836 if (BlockOffset == (ULONG) -1)
837 return NULL;
838
839 BlockIndex = BlockOffset / REG_BLOCK_SIZE;
840 if (BlockIndex >= Hive->BlockListSize)
841 return NULL;
842
843 Bin = Hive->BlockList[BlockIndex];
844 if (Bin == NULL)
845 return NULL;
846
847 return (PVOID)((ULONG)Bin + (BlockOffset - Bin->BinOffset));
848 }
849
850
851 static BOOL
852 CmiAllocateHashTableCell (PREGISTRY_HIVE Hive,
853 PBLOCK_OFFSET HBOffset,
854 ULONG SubKeyCount)
855 {
856 PHASH_TABLE_CELL HashCell;
857 ULONG NewHashSize;
858 BOOL Status;
859
860 NewHashSize = sizeof(HASH_TABLE_CELL) +
861 (SubKeyCount * sizeof(HASH_RECORD));
862 Status = CmiAllocateCell (Hive,
863 NewHashSize,
864 (PVOID*)(PVOID)&HashCell,
865 HBOffset);
866 if ((HashCell == NULL) || (Status == FALSE))
867 {
868 return FALSE;
869 }
870
871 HashCell->Id = REG_HASH_TABLE_BLOCK_ID;
872 HashCell->HashTableSize = SubKeyCount;
873
874 return TRUE;
875 }
876
877
878 static BOOL
879 CmiAddKeyToParentHashTable (PREGISTRY_HIVE Hive,
880 BLOCK_OFFSET ParentKeyOffset,
881 PKEY_CELL NewKeyCell,
882 BLOCK_OFFSET NKBOffset)
883 {
884 PHASH_TABLE_CELL HashBlock;
885 PKEY_CELL ParentKeyCell;
886 ULONG i;
887
888 ParentKeyCell = CmiGetCell (Hive, ParentKeyOffset);
889 if (ParentKeyCell == NULL)
890 {
891 DbgPrint((DPRINT_REGISTRY, "CmiGetCell() failed\n"));
892 return FALSE;
893 }
894
895 HashBlock =CmiGetCell (Hive, ParentKeyCell->HashTableOffset);
896 if (HashBlock == NULL)
897 {
898 DbgPrint((DPRINT_REGISTRY, "CmiGetCell() failed\n"));
899 return FALSE;
900 }
901
902 for (i = 0; i < HashBlock->HashTableSize; i++)
903 {
904 if (HashBlock->Table[i].KeyOffset == 0)
905 {
906 HashBlock->Table[i].KeyOffset = NKBOffset;
907 memcpy (&HashBlock->Table[i].HashValue,
908 NewKeyCell->Name,
909 min(NewKeyCell->NameSize, sizeof(ULONG)));
910 ParentKeyCell->NumberOfSubKeys++;
911 return TRUE;
912 }
913 }
914
915 return FALSE;
916 }
917
918
919 static BOOL
920 CmiAllocateValueListCell (PREGISTRY_HIVE Hive,
921 PBLOCK_OFFSET ValueListOffset,
922 ULONG ValueCount)
923 {
924 PVALUE_LIST_CELL ValueListCell;
925 ULONG ValueListSize;
926 BOOL Status;
927
928 ValueListSize = sizeof(VALUE_LIST_CELL) +
929 (ValueCount * sizeof(BLOCK_OFFSET));
930 Status = CmiAllocateCell (Hive,
931 ValueListSize,
932 (PVOID)&ValueListCell,
933 ValueListOffset);
934 if ((ValueListCell == NULL) || (Status == FALSE))
935 {
936 DbgPrint((DPRINT_REGISTRY, "CmiAllocateCell() failed\n"));
937 return FALSE;
938 }
939
940 return TRUE;
941 }
942
943
944 static BOOL
945 CmiAllocateValueCell(PREGISTRY_HIVE Hive,
946 PVALUE_CELL *ValueCell,
947 BLOCK_OFFSET *ValueCellOffset,
948 PWCHAR ValueName)
949 {
950 PVALUE_CELL NewValueCell;
951 ULONG NameSize;
952 BOOL Status;
953 BOOLEAN Packable = TRUE;
954 ULONG i;
955
956 NameSize = (ValueName == NULL) ? 0 : wcslen (ValueName);
957 for (i = 0; i < NameSize; i++)
958 {
959 if (ValueName[i] & 0xFF00)
960 {
961 NameSize *= sizeof(WCHAR);
962 Packable = FALSE;
963 break;
964 }
965 }
966 Status = CmiAllocateCell (Hive,
967 sizeof(VALUE_CELL) + NameSize,
968 (PVOID*)(PVOID)&NewValueCell,
969 ValueCellOffset);
970 if ((NewValueCell == NULL) || (Status == FALSE))
971 {
972 DbgPrint((DPRINT_REGISTRY, "CmiAllocateCell() failed\n"));
973 return FALSE;
974 }
975
976 NewValueCell->Id = REG_VALUE_CELL_ID;
977 NewValueCell->NameSize = NameSize;
978 NewValueCell->Flags = 0;
979 if (NameSize > 0)
980 {
981 if (Packable)
982 {
983 for (i = 0; i < NameSize; i++)
984 {
985 ((PCHAR)NewValueCell->Name)[i] = (CHAR)ValueName[i];
986 }
987 NewValueCell->Flags |= REG_VALUE_NAME_PACKED;
988 }
989 else
990 {
991 memcpy (NewValueCell->Name,
992 ValueName,
993 NameSize);
994 }
995 }
996 NewValueCell->DataType = 0;
997 NewValueCell->DataSize = 0;
998 NewValueCell->DataOffset = -1;
999
1000 *ValueCell = NewValueCell;
1001
1002 return TRUE;
1003 }
1004
1005
1006 static BOOL
1007 CmiAddValueToKeyValueList(PREGISTRY_HIVE Hive,
1008 BLOCK_OFFSET KeyCellOffset,
1009 BLOCK_OFFSET ValueCellOffset)
1010 {
1011 PVALUE_LIST_CELL ValueListCell;
1012 PKEY_CELL KeyCell;
1013
1014 KeyCell = CmiGetCell (Hive, KeyCellOffset);
1015 if (KeyCell == NULL)
1016 {
1017 DbgPrint((DPRINT_REGISTRY, "CmiGetCell() failed\n"));
1018 return FALSE;
1019 }
1020
1021 ValueListCell = CmiGetCell (Hive, KeyCell->ValueListOffset);
1022 if (ValueListCell == NULL)
1023 {
1024 DbgPrint((DPRINT_REGISTRY, "CmiGetCell() failed\n"));
1025 return FALSE;
1026 }
1027
1028 ValueListCell->ValueOffset[KeyCell->NumberOfValues] = ValueCellOffset;
1029 KeyCell->NumberOfValues++;
1030
1031 return TRUE;
1032 }
1033
1034 static BOOL
1035 CmiExportValue (PREGISTRY_HIVE Hive,
1036 BLOCK_OFFSET KeyCellOffset,
1037 FRLDRHKEY Key,
1038 PVALUE Value)
1039 {
1040 BLOCK_OFFSET ValueCellOffset;
1041 BLOCK_OFFSET DataCellOffset;
1042 PVALUE_CELL ValueCell;
1043 PDATA_CELL DataCell;
1044 ULONG DataSize;
1045 ULONG DataType;
1046 PCHAR Data;
1047
1048 DbgPrint((DPRINT_REGISTRY, "CmiExportValue('%S') called\n",
1049 (Value == NULL) ? "<default>" : (PCHAR)Value->Name));
1050 DbgPrint((DPRINT_REGISTRY, "DataSize %lu\n",
1051 (Value == NULL) ? Key->DataSize : Value->DataSize));
1052
1053 /* Allocate value cell */
1054 if (!CmiAllocateValueCell(Hive, &ValueCell, &ValueCellOffset, (Value == NULL) ? NULL : Value->Name))
1055 {
1056 return FALSE;
1057 }
1058
1059 if (!CmiAddValueToKeyValueList(Hive, KeyCellOffset, ValueCellOffset))
1060 {
1061 return FALSE;
1062 }
1063
1064 if (Value == NULL)
1065 {
1066 DataType = Key->DataType;
1067 DataSize = Key->DataSize;
1068 Data = Key->Data;
1069 }
1070 else
1071 {
1072 DataType = Value->DataType;
1073 DataSize = Value->DataSize;
1074 Data = Value->Data;
1075 }
1076
1077 if (DataSize <= sizeof(BLOCK_OFFSET))
1078 {
1079 ValueCell->DataSize = DataSize | REG_DATA_IN_OFFSET;
1080 ValueCell->DataType = DataType;
1081 memcpy (&ValueCell->DataOffset,
1082 Data,
1083 DataSize);
1084 }
1085 else
1086 {
1087 /* Allocate data cell */
1088 if (!CmiAllocateCell (Hive,
1089 sizeof(CELL_HEADER) + DataSize,
1090 (PVOID *)(PVOID)&DataCell,
1091 &DataCellOffset))
1092 {
1093 return FALSE;
1094 }
1095
1096 ValueCell->DataOffset = DataCellOffset;
1097 ValueCell->DataSize = DataSize;
1098 ValueCell->DataType = DataType;
1099
1100 memcpy (DataCell->Data,
1101 Data,
1102 DataSize);
1103 }
1104
1105 return TRUE;
1106 }
1107
1108
1109 static BOOL
1110 CmiExportSubKey (PREGISTRY_HIVE Hive,
1111 BLOCK_OFFSET ParentKeyOffset,
1112 FRLDRHKEY ParentKey,
1113 FRLDRHKEY Key)
1114 {
1115 BLOCK_OFFSET NKBOffset;
1116 PKEY_CELL NewKeyCell;
1117 ULONG KeyCellSize;
1118 ULONG SubKeyCount;
1119 ULONG ValueCount;
1120 PLIST_ENTRY Entry;
1121 FRLDRHKEY SubKey;
1122 PVALUE Value;
1123 BOOLEAN Packable = TRUE;
1124 ULONG i;
1125 ULONG NameSize;
1126
1127 DbgPrint((DPRINT_REGISTRY, "CmiExportSubKey('%S') called\n", Key->Name));
1128
1129 /* Don't export links */
1130 if (Key->DataType == REG_LINK)
1131 return TRUE;
1132
1133 NameSize = (Key->NameSize - sizeof(WCHAR)) / sizeof(WCHAR);
1134 for (i = 0; i < NameSize; i++)
1135 {
1136 if (Key->Name[i] & 0xFF00)
1137 {
1138 Packable = FALSE;
1139 NameSize *= sizeof(WCHAR);
1140 break;
1141 }
1142 }
1143
1144 /* Allocate key cell */
1145 KeyCellSize = sizeof(KEY_CELL) + NameSize;
1146 if (!CmiAllocateCell (Hive, KeyCellSize, (PVOID)&NewKeyCell, &NKBOffset))
1147 {
1148 DbgPrint((DPRINT_REGISTRY, "CmiAllocateCell() failed\n"));
1149 return FALSE;
1150 }
1151
1152 /* Initialize key cell */
1153 NewKeyCell->Id = REG_KEY_CELL_ID;
1154 NewKeyCell->Flags = 0;
1155 NewKeyCell->LastWriteTime = 0ULL;
1156 NewKeyCell->ParentKeyOffset = ParentKeyOffset;
1157 NewKeyCell->NumberOfSubKeys = 0;
1158 NewKeyCell->HashTableOffset = -1;
1159 NewKeyCell->NumberOfValues = 0;
1160 NewKeyCell->ValueListOffset = -1;
1161 NewKeyCell->SecurityKeyOffset = -1;
1162 NewKeyCell->ClassNameOffset = -1;
1163 NewKeyCell->NameSize = NameSize;
1164 NewKeyCell->ClassSize = 0;
1165 if (Packable)
1166 {
1167 for (i = 0; i < NameSize; i++)
1168 {
1169 ((PCHAR)NewKeyCell->Name)[i] = (CHAR)Key->Name[i];
1170 }
1171 NewKeyCell->Flags |= REG_KEY_NAME_PACKED;
1172
1173 }
1174 else
1175 {
1176 memcpy (NewKeyCell->Name,
1177 Key->Name,
1178 NameSize);
1179 }
1180
1181 /* Add key cell to the parent key's hash table */
1182 if (!CmiAddKeyToParentHashTable (Hive,
1183 ParentKeyOffset,
1184 NewKeyCell,
1185 NKBOffset))
1186 {
1187 DbgPrint((DPRINT_REGISTRY, "CmiAddKeyToParentHashTable() failed\n"));
1188 return FALSE;
1189 }
1190
1191 ValueCount = RegGetValueCount (Key);
1192 DbgPrint((DPRINT_REGISTRY, "ValueCount: %u\n", ValueCount));
1193 if (ValueCount > 0)
1194 {
1195 /* Allocate value list cell */
1196 if (!CmiAllocateValueListCell (Hive,
1197 &NewKeyCell->ValueListOffset,
1198 ValueCount))
1199 {
1200 DbgPrint((DPRINT_REGISTRY, "CmiAllocateValueListCell() failed\n"));
1201 return FALSE;
1202 }
1203
1204 if (Key->DataSize != 0)
1205 {
1206 if (!CmiExportValue (Hive, NKBOffset, Key, NULL))
1207 return FALSE;
1208 }
1209
1210 /* Enumerate values */
1211 Entry = Key->ValueList.Flink;
1212 while (Entry != &Key->ValueList)
1213 {
1214 Value = CONTAINING_RECORD(Entry,
1215 VALUE,
1216 ValueList);
1217
1218 if (!CmiExportValue (Hive, NKBOffset, Key, Value))
1219 return FALSE;
1220
1221 Entry = Entry->Flink;
1222 }
1223 }
1224
1225 SubKeyCount = RegGetSubKeyCount (Key);
1226 DbgPrint((DPRINT_REGISTRY, "SubKeyCount: %u\n", SubKeyCount));
1227 if (SubKeyCount > 0)
1228 {
1229 /* Allocate hash table cell */
1230 if (!CmiAllocateHashTableCell (Hive,
1231 &NewKeyCell->HashTableOffset,
1232 SubKeyCount))
1233 {
1234 DbgPrint((DPRINT_REGISTRY, "CmiAllocateHashTableCell() failed\n"));
1235 return FALSE;
1236 }
1237
1238 /* Enumerate subkeys */
1239 Entry = Key->SubKeyList.Flink;
1240 while (Entry != &Key->SubKeyList)
1241 {
1242 SubKey = CONTAINING_RECORD(Entry,
1243 KEY,
1244 KeyList);
1245
1246 if (!CmiExportSubKey (Hive, NKBOffset, Key, SubKey))
1247 return FALSE;
1248
1249 Entry = Entry->Flink;
1250 }
1251 }
1252
1253 return TRUE;
1254 }
1255
1256
1257 static VOID
1258 CmiCalcHiveChecksum (PREGISTRY_HIVE Hive)
1259 {
1260 ULONG *Buffer;
1261 ULONG Sum;
1262 ULONG i;
1263
1264 Buffer = (ULONG*)Hive->HiveHeader;
1265 Sum = 0;
1266 for (i = 0; i < 127; i++)
1267 Sum += Buffer[i];
1268
1269 Hive->HiveHeader->Checksum = Sum;
1270 }
1271
1272
1273 static BOOL
1274 CmiExportHive (PREGISTRY_HIVE Hive,
1275 PCWSTR KeyName)
1276 {
1277 PKEY_CELL KeyCell;
1278 FRLDRHKEY Key;
1279 ULONG SubKeyCount;
1280 ULONG ValueCount;
1281 PLIST_ENTRY Entry;
1282 FRLDRHKEY SubKey;
1283 PVALUE Value;
1284
1285 DbgPrint((DPRINT_REGISTRY, "CmiExportHive(%x, '%S') called\n", Hive, KeyName));
1286
1287 if (RegOpenKey (NULL, KeyName, &Key) != ERROR_SUCCESS)
1288 {
1289 DbgPrint((DPRINT_REGISTRY, "RegOpenKey() failed\n"));
1290 return FALSE;
1291 }
1292
1293 KeyCell = CmiGetCell (Hive, Hive->HiveHeader->RootKeyOffset);
1294 if (KeyCell == NULL)
1295 {
1296 DbgPrint((DPRINT_REGISTRY, "CmiGetBlock() failed\n"));
1297 return FALSE;
1298 }
1299
1300 ValueCount = RegGetValueCount (Key);
1301 DbgPrint((DPRINT_REGISTRY, "ValueCount: %u\n", ValueCount));
1302 if (ValueCount > 0)
1303 {
1304 /* Allocate value list cell */
1305 if (!CmiAllocateValueListCell (Hive,
1306 &KeyCell->ValueListOffset,
1307 ValueCount))
1308 {
1309 DbgPrint((DPRINT_REGISTRY, "CmiAllocateValueListCell() failed\n"));
1310 return FALSE;
1311 }
1312
1313 if (Key->DataSize != 0)
1314 {
1315 if (!CmiExportValue (Hive, Hive->HiveHeader->RootKeyOffset, Key, NULL))
1316 return FALSE;
1317 }
1318
1319 /* Enumerate values */
1320 Entry = Key->ValueList.Flink;
1321 while (Entry != &Key->ValueList)
1322 {
1323 Value = CONTAINING_RECORD(Entry,
1324 VALUE,
1325 ValueList);
1326
1327 if (!CmiExportValue (Hive, Hive->HiveHeader->RootKeyOffset, Key, Value))
1328 return FALSE;
1329
1330 Entry = Entry->Flink;
1331 }
1332 }
1333
1334 SubKeyCount = RegGetSubKeyCount (Key);
1335 DbgPrint((DPRINT_REGISTRY, "SubKeyCount: %u\n", SubKeyCount));
1336 if (SubKeyCount > 0)
1337 {
1338 /* Allocate hash table cell */
1339 if (!CmiAllocateHashTableCell (Hive,
1340 &KeyCell->HashTableOffset,
1341 SubKeyCount))
1342 {
1343 DbgPrint((DPRINT_REGISTRY, "CmiAllocateHashTableCell() failed\n"));
1344 return FALSE;
1345 }
1346
1347 /* Enumerate subkeys */
1348 Entry = Key->SubKeyList.Flink;
1349 while (Entry != &Key->SubKeyList)
1350 {
1351 SubKey = CONTAINING_RECORD(Entry,
1352 KEY,
1353 KeyList);
1354
1355 if (!CmiExportSubKey (Hive, Hive->HiveHeader->RootKeyOffset, Key, SubKey))
1356 return FALSE;
1357
1358 Entry = Entry->Flink;
1359 }
1360 }
1361
1362 CmiCalcHiveChecksum (Hive);
1363
1364 return TRUE;
1365 }
1366
1367
1368 static BOOL
1369 RegImportValue (PHBIN RootBin,
1370 PVALUE_CELL ValueCell,
1371 FRLDRHKEY Key)
1372 {
1373 PDATA_CELL DataCell;
1374 PWCHAR wName;
1375 LONG Error;
1376 ULONG DataSize;
1377 ULONG i;
1378
1379 if (ValueCell->CellSize >= 0 || ValueCell->Id != REG_VALUE_CELL_ID)
1380 {
1381 DbgPrint((DPRINT_REGISTRY, "Invalid key cell!\n"));
1382 return FALSE;
1383 }
1384
1385 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1386 {
1387 wName = MmAllocateMemory ((ValueCell->NameSize + 1)*sizeof(WCHAR));
1388 for (i = 0; i < ValueCell->NameSize; i++)
1389 {
1390 wName[i] = ((PCHAR)ValueCell->Name)[i];
1391 }
1392 wName[ValueCell->NameSize] = 0;
1393 }
1394 else
1395 {
1396 wName = MmAllocateMemory (ValueCell->NameSize + sizeof(WCHAR));
1397 memcpy (wName,
1398 ValueCell->Name,
1399 ValueCell->NameSize);
1400 wName[ValueCell->NameSize / sizeof(WCHAR)] = 0;
1401 }
1402
1403 DataSize = ValueCell->DataSize & REG_DATA_SIZE_MASK;
1404
1405 DbgPrint((DPRINT_REGISTRY, "ValueName: '%S'\n", wName));
1406 DbgPrint((DPRINT_REGISTRY, "DataSize: %u\n", DataSize));
1407
1408 if (DataSize <= sizeof(BLOCK_OFFSET) && (ValueCell->DataSize & REG_DATA_IN_OFFSET))
1409 {
1410 Error = RegSetValue(Key,
1411 wName,
1412 ValueCell->DataType,
1413 (PCHAR)&ValueCell->DataOffset,
1414 DataSize);
1415 if (Error != ERROR_SUCCESS)
1416 {
1417 DbgPrint((DPRINT_REGISTRY, "RegSetValue() failed!\n"));
1418 MmFreeMemory (wName);
1419 return FALSE;
1420 }
1421 }
1422 else
1423 {
1424 DataCell = (PDATA_CELL)((PUCHAR)RootBin + ValueCell->DataOffset);
1425 DbgPrint((DPRINT_REGISTRY, "DataCell: %x\n", DataCell));
1426
1427 if (DataCell->CellSize >= 0)
1428 {
1429 DbgPrint((DPRINT_REGISTRY, "Invalid data cell size!\n"));
1430 MmFreeMemory (wName);
1431 return FALSE;
1432 }
1433
1434 Error = RegSetValue (Key,
1435 wName,
1436 ValueCell->DataType,
1437 DataCell->Data,
1438 DataSize);
1439
1440 if (Error != ERROR_SUCCESS)
1441 {
1442 DbgPrint((DPRINT_REGISTRY, "RegSetValue() failed!\n"));
1443 MmFreeMemory (wName);
1444 return FALSE;
1445 }
1446 }
1447
1448 MmFreeMemory (wName);
1449
1450 return TRUE;
1451 }
1452
1453
1454 static BOOL
1455 RegImportSubKey(PHBIN RootBin,
1456 PKEY_CELL KeyCell,
1457 FRLDRHKEY ParentKey)
1458 {
1459 PHASH_TABLE_CELL HashCell;
1460 PKEY_CELL SubKeyCell;
1461 PVALUE_LIST_CELL ValueListCell;
1462 PVALUE_CELL ValueCell = NULL;
1463 PWCHAR wName;
1464 FRLDRHKEY SubKey;
1465 LONG Error;
1466 ULONG i;
1467
1468
1469 DbgPrint((DPRINT_REGISTRY, "KeyCell: %x\n", KeyCell));
1470 DbgPrint((DPRINT_REGISTRY, "KeyCell->CellSize: %x\n", KeyCell->CellSize));
1471 DbgPrint((DPRINT_REGISTRY, "KeyCell->Id: %x\n", KeyCell->Id));
1472 if (KeyCell->Id != REG_KEY_CELL_ID || KeyCell->CellSize >= 0)
1473 {
1474 DbgPrint((DPRINT_REGISTRY, "Invalid key cell id!\n"));
1475 return FALSE;
1476 }
1477
1478 if (KeyCell->Flags & REG_KEY_NAME_PACKED)
1479 {
1480 wName = MmAllocateMemory ((KeyCell->NameSize + 1) * sizeof(WCHAR));
1481 for (i = 0; i < KeyCell->NameSize; i++)
1482 {
1483 wName[i] = ((PCHAR)KeyCell->Name)[i];
1484 }
1485 wName[KeyCell->NameSize] = 0;
1486 }
1487 else
1488 {
1489 wName = MmAllocateMemory (KeyCell->NameSize + sizeof(WCHAR));
1490 memcpy (wName,
1491 KeyCell->Name,
1492 KeyCell->NameSize);
1493 wName[KeyCell->NameSize/sizeof(WCHAR)] = 0;
1494 }
1495
1496 DbgPrint((DPRINT_REGISTRY, "KeyName: '%S'\n", wName));
1497
1498 /* Create new sub key */
1499 Error = RegCreateKey (ParentKey,
1500 wName,
1501 &SubKey);
1502 MmFreeMemory (wName);
1503 if (Error != ERROR_SUCCESS)
1504 {
1505 DbgPrint((DPRINT_REGISTRY, "RegCreateKey() failed!\n"));
1506 return FALSE;
1507 }
1508 DbgPrint((DPRINT_REGISTRY, "Subkeys: %u\n", KeyCell->NumberOfSubKeys));
1509 DbgPrint((DPRINT_REGISTRY, "Values: %u\n", KeyCell->NumberOfValues));
1510
1511 /* Enumerate and add values */
1512 if (KeyCell->NumberOfValues > 0)
1513 {
1514 ValueListCell = (PVALUE_LIST_CELL)((PUCHAR)RootBin + KeyCell->ValueListOffset);
1515 DbgPrint((DPRINT_REGISTRY, "ValueListCell: %x\n", ValueListCell));
1516
1517 for (i = 0; i < KeyCell->NumberOfValues; i++)
1518 {
1519 DbgPrint((DPRINT_REGISTRY, "ValueOffset[%d]: %x\n", i, ValueListCell->ValueOffset[i]));
1520
1521 ValueCell = (PVALUE_CELL)((PUCHAR)RootBin + ValueListCell->ValueOffset[i]);
1522
1523 DbgPrint((DPRINT_REGISTRY, "ValueCell[%d]: %x\n", i, ValueCell));
1524
1525 if (!RegImportValue(RootBin, ValueCell, SubKey))
1526 return FALSE;
1527 }
1528 }
1529
1530 /* Enumerate and add subkeys */
1531 if (KeyCell->NumberOfSubKeys > 0)
1532 {
1533 HashCell = (PHASH_TABLE_CELL)((PUCHAR)RootBin + KeyCell->HashTableOffset);
1534 DbgPrint((DPRINT_REGISTRY, "HashCell: %x\n", HashCell));
1535
1536 for (i = 0; i < KeyCell->NumberOfSubKeys; i++)
1537 {
1538 DbgPrint((DPRINT_REGISTRY, "KeyOffset[%d]: %x\n", i, HashCell->Table[i].KeyOffset));
1539
1540 SubKeyCell = (PKEY_CELL)((PUCHAR)RootBin + HashCell->Table[i].KeyOffset);
1541
1542 DbgPrint((DPRINT_REGISTRY, "SubKeyCell[%d]: %x\n", i, SubKeyCell));
1543
1544 if (!RegImportSubKey(RootBin, SubKeyCell, SubKey))
1545 return FALSE;
1546 }
1547 }
1548
1549 return TRUE;
1550 }
1551
1552
1553 BOOL
1554 RegImportBinaryHive(PCHAR ChunkBase,
1555 ULONG ChunkSize)
1556 {
1557 PHIVE_HEADER HiveHeader;
1558 PHBIN RootBin;
1559 PKEY_CELL KeyCell;
1560 PHASH_TABLE_CELL HashCell;
1561 PKEY_CELL SubKeyCell;
1562 FRLDRHKEY SystemKey;
1563 ULONG i;
1564 LONG Error;
1565
1566 DbgPrint((DPRINT_REGISTRY, "RegImportBinaryHive(%x, %u) called\n",ChunkBase,ChunkSize));
1567
1568 HiveHeader = (PHIVE_HEADER)ChunkBase;
1569 DbgPrint((DPRINT_REGISTRY, "HiveHeader: %x\n", HiveHeader));
1570 if (HiveHeader->BlockId != REG_HIVE_ID)
1571 {
1572 DbgPrint((DPRINT_REGISTRY, "Invalid hive id!\n"));
1573 return FALSE;
1574 }
1575
1576 RootBin = (PHBIN)((ULONG)HiveHeader + REG_BLOCK_SIZE);
1577 DbgPrint((DPRINT_REGISTRY, "RootBin: %x\n", RootBin));
1578 if (RootBin->HeaderId != REG_BIN_ID || RootBin->BinSize == 0)
1579 {
1580 DbgPrint((DPRINT_REGISTRY, "Invalid bin id!\n"));
1581 return FALSE;
1582 }
1583
1584 KeyCell = (PKEY_CELL)((ULONG)RootBin + REG_HBIN_DATA_OFFSET);
1585 DbgPrint((DPRINT_REGISTRY, "KeyCell: %x\n", KeyCell));
1586 DbgPrint((DPRINT_REGISTRY, "KeyCell->CellSize: %x\n", KeyCell->CellSize));
1587 DbgPrint((DPRINT_REGISTRY, "KeyCell->Id: %x\n", KeyCell->Id));
1588 if (KeyCell->Id != REG_KEY_CELL_ID || KeyCell->CellSize >= 0)
1589 {
1590 DbgPrint((DPRINT_REGISTRY, "Invalid key cell id!\n"));
1591 return FALSE;
1592 }
1593
1594 DbgPrint((DPRINT_REGISTRY, "Subkeys: %u\n", KeyCell->NumberOfSubKeys));
1595 DbgPrint((DPRINT_REGISTRY, "Values: %u\n", KeyCell->NumberOfValues));
1596
1597 /* Open 'System' key */
1598 Error = RegOpenKey(NULL,
1599 L"\\Registry\\Machine\\SYSTEM",
1600 &SystemKey);
1601 if (Error != ERROR_SUCCESS)
1602 {
1603 DbgPrint((DPRINT_REGISTRY, "Failed to open 'system' key!\n"));
1604 return FALSE;
1605 }
1606
1607 /* Enumerate and add subkeys */
1608 if (KeyCell->NumberOfSubKeys > 0)
1609 {
1610 HashCell = (PHASH_TABLE_CELL)((ULONG)RootBin + KeyCell->HashTableOffset);
1611 DbgPrint((DPRINT_REGISTRY, "HashCell: %x\n", HashCell));
1612
1613 for (i = 0; i < KeyCell->NumberOfSubKeys; i++)
1614 {
1615 DbgPrint((DPRINT_REGISTRY, "KeyOffset[%d]: %x\n", i, HashCell->Table[i].KeyOffset));
1616
1617 SubKeyCell = (PKEY_CELL)((ULONG)RootBin + HashCell->Table[i].KeyOffset);
1618
1619 DbgPrint((DPRINT_REGISTRY, "SubKeyCell[%d]: %x\n", i, SubKeyCell));
1620
1621 if (!RegImportSubKey(RootBin, SubKeyCell, SystemKey))
1622 return FALSE;
1623 }
1624 }
1625
1626 return TRUE;
1627 }
1628
1629
1630 BOOL
1631 RegExportBinaryHive(PCWSTR KeyName,
1632 PCHAR ChunkBase,
1633 ULONG* ChunkSize)
1634 {
1635 PREGISTRY_HIVE Hive;
1636
1637 DbgPrint((DPRINT_REGISTRY, "Creating binary hardware hive\n"));
1638
1639 *ChunkSize = 0;
1640 InitMbMemory (ChunkBase);
1641
1642 Hive = CmiCreateHive (KeyName);
1643 if (Hive == NULL)
1644 return FALSE;
1645
1646 if (!CmiExportHive (Hive, KeyName))
1647 {
1648 CmiCleanupHive (Hive, TRUE);
1649 return FALSE;
1650 }
1651
1652 CmiCleanupHive (Hive, FALSE);
1653
1654 *ChunkSize = GetMbAllocatedSize ();
1655
1656 return TRUE;
1657 }
1658
1659 /* EOF */