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