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