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