[KS]
[reactos.git] / reactos / boot / freeldr / freeldr / reactos / registry.c
1 /*
2 * FreeLoader
3 *
4 * Copyright (C) 2001, 2002 Eric Kohl
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include <freeldr.h>
22 #include <debug.h>
23
24 static FRLDRHKEY RootKey;
25
26
27 VOID
28 RegInitializeRegistry (VOID)
29 {
30 /* Create root key */
31 RootKey = (FRLDRHKEY) MmHeapAlloc (sizeof(KEY));
32
33 InitializeListHead (&RootKey->SubKeyList);
34 InitializeListHead (&RootKey->ValueList);
35 InitializeListHead (&RootKey->KeyList);
36
37 RootKey->SubKeyCount = 0;
38 RootKey->ValueCount = 0;
39
40 RootKey->NameSize = 4;
41 RootKey->Name = MmHeapAlloc (4);
42 wcscpy (RootKey->Name, L"\\");
43
44 RootKey->DataType = 0;
45 RootKey->DataSize = 0;
46 RootKey->Data = NULL;
47
48 /* Create 'SYSTEM' key */
49 RegCreateKey (RootKey,
50 L"Registry\\Machine\\SYSTEM",
51 NULL);
52 }
53
54
55 LONG
56 RegInitCurrentControlSet(BOOLEAN LastKnownGood)
57 {
58 WCHAR ControlSetKeyName[80];
59 FRLDRHKEY SelectKey;
60 FRLDRHKEY SystemKey;
61 FRLDRHKEY ControlSetKey;
62 FRLDRHKEY LinkKey;
63 ULONG CurrentSet = 0;
64 ULONG DefaultSet = 0;
65 ULONG LastKnownGoodSet = 0;
66 ULONG DataSize;
67 LONG Error;
68
69 Error = RegOpenKey(NULL,
70 L"\\Registry\\Machine\\SYSTEM\\Select",
71 &SelectKey);
72 if (Error != ERROR_SUCCESS)
73 {
74 DPRINTM(DPRINT_REGISTRY, "RegOpenKey() failed (Error %u)\n", (int)Error);
75 return(Error);
76 }
77
78 DataSize = sizeof(ULONG);
79 Error = RegQueryValue(SelectKey,
80 L"Default",
81 NULL,
82 (PUCHAR)&DefaultSet,
83 &DataSize);
84 if (Error != ERROR_SUCCESS)
85 {
86 DPRINTM(DPRINT_REGISTRY, "RegQueryValue('Default') failed (Error %u)\n", (int)Error);
87 return(Error);
88 }
89
90 DataSize = sizeof(ULONG);
91 Error = RegQueryValue(SelectKey,
92 L"LastKnownGood",
93 NULL,
94 (PUCHAR)&LastKnownGoodSet,
95 &DataSize);
96 if (Error != ERROR_SUCCESS)
97 {
98 DPRINTM(DPRINT_REGISTRY, "RegQueryValue('Default') failed (Error %u)\n", (int)Error);
99 return(Error);
100 }
101
102 CurrentSet = (LastKnownGood == TRUE) ? LastKnownGoodSet : DefaultSet;
103 wcscpy(ControlSetKeyName, L"ControlSet");
104 switch(CurrentSet)
105 {
106 case 1:
107 wcscat(ControlSetKeyName, L"001");
108 break;
109 case 2:
110 wcscat(ControlSetKeyName, L"002");
111 break;
112 case 3:
113 wcscat(ControlSetKeyName, L"003");
114 break;
115 case 4:
116 wcscat(ControlSetKeyName, L"004");
117 break;
118 case 5:
119 wcscat(ControlSetKeyName, L"005");
120 break;
121 }
122
123 Error = RegOpenKey(NULL,
124 L"\\Registry\\Machine\\SYSTEM",
125 &SystemKey);
126 if (Error != ERROR_SUCCESS)
127 {
128 DPRINTM(DPRINT_REGISTRY, "RegOpenKey(SystemKey) failed (Error %u)\n", (int)Error);
129 return(Error);
130 }
131
132 Error = RegOpenKey(SystemKey,
133 ControlSetKeyName,
134 &ControlSetKey);
135 if (Error != ERROR_SUCCESS)
136 {
137 DPRINTM(DPRINT_REGISTRY, "RegOpenKey(ControlSetKey) failed (Error %u)\n", (int)Error);
138 return(Error);
139 }
140
141 Error = RegCreateKey(SystemKey,
142 L"CurrentControlSet",
143 &LinkKey);
144 if (Error != ERROR_SUCCESS)
145 {
146 DPRINTM(DPRINT_REGISTRY, "RegCreateKey(LinkKey) failed (Error %u)\n", (int)Error);
147 return(Error);
148 }
149
150 Error = RegSetValue(LinkKey,
151 NULL,
152 REG_LINK,
153 (PCHAR)&ControlSetKey,
154 sizeof(PVOID));
155 if (Error != ERROR_SUCCESS)
156 {
157 DPRINTM(DPRINT_REGISTRY, "RegSetValue(LinkKey) failed (Error %u)\n", (int)Error);
158 return(Error);
159 }
160
161 return(ERROR_SUCCESS);
162 }
163
164
165 LONG
166 RegCreateKey(FRLDRHKEY ParentKey,
167 PCWSTR KeyName,
168 PFRLDRHKEY Key)
169 {
170 PLIST_ENTRY Ptr;
171 FRLDRHKEY SearchKey = NULL;
172 FRLDRHKEY CurrentKey;
173 FRLDRHKEY NewKey;
174 PWCHAR p;
175 PCWSTR name;
176 int subkeyLength;
177 int stringLength;
178 ULONG NameSize;
179 int CmpResult;
180
181 DPRINTM(DPRINT_REGISTRY, "KeyName '%S'\n", KeyName);
182
183 if (*KeyName == L'\\')
184 {
185 KeyName++;
186 CurrentKey = RootKey;
187 }
188 else if (ParentKey == NULL)
189 {
190 CurrentKey = RootKey;
191 }
192 else
193 {
194 CurrentKey = ParentKey;
195 }
196
197 /* Check whether current key is a link */
198 if (CurrentKey->DataType == REG_LINK)
199 {
200 CurrentKey = (FRLDRHKEY)CurrentKey->Data;
201 }
202
203 while (*KeyName != 0)
204 {
205 DPRINTM(DPRINT_REGISTRY, "KeyName '%S'\n", KeyName);
206
207 if (*KeyName == L'\\')
208 KeyName++;
209 p = wcschr(KeyName, L'\\');
210 if ((p != NULL) && (p != KeyName))
211 {
212 subkeyLength = p - KeyName;
213 stringLength = subkeyLength + 1;
214 name = KeyName;
215 }
216 else
217 {
218 subkeyLength = wcslen(KeyName);
219 stringLength = subkeyLength;
220 name = KeyName;
221 }
222 NameSize = (subkeyLength + 1) * sizeof(WCHAR);
223
224 Ptr = CurrentKey->SubKeyList.Flink;
225 CmpResult = 1;
226 while (Ptr != &CurrentKey->SubKeyList)
227 {
228 DPRINTM(DPRINT_REGISTRY, "Ptr 0x%x\n", Ptr);
229
230 SearchKey = CONTAINING_RECORD(Ptr,
231 KEY,
232 KeyList);
233 DPRINTM(DPRINT_REGISTRY, "SearchKey 0x%x\n", SearchKey);
234 DPRINTM(DPRINT_REGISTRY, "Searching '%S'\n", SearchKey->Name);
235 CmpResult = _wcsnicmp(SearchKey->Name, name, subkeyLength);
236 if (CmpResult == 0 && SearchKey->NameSize == NameSize)
237 break;
238 else if (CmpResult == -1)
239 break;
240
241 Ptr = Ptr->Flink;
242 }
243
244 if (CmpResult != 0)
245 {
246 /* no key found -> create new subkey */
247 NewKey = (FRLDRHKEY)MmHeapAlloc(sizeof(KEY));
248 if (NewKey == NULL)
249 return(ERROR_OUTOFMEMORY);
250
251 InitializeListHead(&NewKey->SubKeyList);
252 InitializeListHead(&NewKey->ValueList);
253
254 NewKey->SubKeyCount = 0;
255 NewKey->ValueCount = 0;
256
257 NewKey->DataType = 0;
258 NewKey->DataSize = 0;
259 NewKey->Data = NULL;
260
261 InsertTailList(Ptr, &NewKey->KeyList);
262 CurrentKey->SubKeyCount++;
263
264 NewKey->NameSize = NameSize;
265 NewKey->Name = (PWCHAR)MmHeapAlloc(NewKey->NameSize);
266 if (NewKey->Name == NULL)
267 return(ERROR_OUTOFMEMORY);
268 memcpy(NewKey->Name, name, NewKey->NameSize - sizeof(WCHAR));
269 NewKey->Name[subkeyLength] = 0;
270
271 DPRINTM(DPRINT_REGISTRY, "NewKey 0x%x\n", NewKey);
272 DPRINTM(DPRINT_REGISTRY, "NewKey '%S' Length %d\n", NewKey->Name, NewKey->NameSize);
273
274 CurrentKey = NewKey;
275 }
276 else
277 {
278 CurrentKey = SearchKey;
279
280 /* Check whether current key is a link */
281 if (CurrentKey->DataType == REG_LINK)
282 {
283 CurrentKey = (FRLDRHKEY)CurrentKey->Data;
284 }
285 }
286
287 KeyName = KeyName + stringLength;
288 }
289
290 if (Key != NULL)
291 *Key = CurrentKey;
292
293 return(ERROR_SUCCESS);
294 }
295
296
297 LONG
298 RegDeleteKey(FRLDRHKEY Key,
299 PCWSTR Name)
300 {
301
302
303 if (wcschr(Name, L'\\') != NULL)
304 return(ERROR_INVALID_PARAMETER);
305
306
307
308 return(ERROR_SUCCESS);
309 }
310
311
312 LONG
313 RegEnumKey(FRLDRHKEY Key,
314 ULONG Index,
315 PWCHAR Name,
316 ULONG* NameSize)
317 {
318 PLIST_ENTRY Ptr;
319 FRLDRHKEY SearchKey;
320 ULONG Count = 0;
321 ULONG Size;
322
323 Ptr = Key->SubKeyList.Flink;
324 while (Ptr != &Key->SubKeyList)
325 {
326 if (Index == Count)
327 break;
328
329 Count++;
330 Ptr = Ptr->Flink;
331 }
332
333 if (Ptr == &Key->SubKeyList)
334 return(ERROR_NO_MORE_ITEMS);
335
336 SearchKey = CONTAINING_RECORD(Ptr,
337 KEY,
338 KeyList);
339
340 DPRINTM(DPRINT_REGISTRY, "Name '%S' Length %d\n", SearchKey->Name, SearchKey->NameSize);
341
342 Size = min(SearchKey->NameSize, *NameSize);
343 *NameSize = Size;
344 memcpy(Name, SearchKey->Name, Size);
345
346 return(ERROR_SUCCESS);
347 }
348
349
350 LONG
351 RegOpenKey(FRLDRHKEY ParentKey,
352 PCWSTR KeyName,
353 PFRLDRHKEY Key)
354 {
355 PLIST_ENTRY Ptr;
356 FRLDRHKEY SearchKey = NULL;
357 FRLDRHKEY CurrentKey;
358 PWCHAR p;
359 PCWSTR name;
360 int subkeyLength;
361 int stringLength;
362 ULONG NameSize;
363
364 DPRINTM(DPRINT_REGISTRY, "KeyName '%S'\n", KeyName);
365
366 *Key = NULL;
367
368 if (*KeyName == L'\\')
369 {
370 KeyName++;
371 CurrentKey = RootKey;
372 }
373 else if (ParentKey == NULL)
374 {
375 CurrentKey = RootKey;
376 }
377 else
378 {
379 CurrentKey = ParentKey;
380 }
381
382 /* Check whether current key is a link */
383 if (CurrentKey->DataType == REG_LINK)
384 {
385 CurrentKey = (FRLDRHKEY)CurrentKey->Data;
386 }
387
388 while (*KeyName != 0)
389 {
390 DPRINTM(DPRINT_REGISTRY, "KeyName '%S'\n", KeyName);
391
392 if (*KeyName == L'\\')
393 KeyName++;
394 p = wcschr(KeyName, L'\\');
395 if ((p != NULL) && (p != KeyName))
396 {
397 subkeyLength = p - KeyName;
398 stringLength = subkeyLength + 1;
399 name = KeyName;
400 }
401 else
402 {
403 subkeyLength = wcslen(KeyName);
404 stringLength = subkeyLength;
405 name = KeyName;
406 }
407 NameSize = (subkeyLength + 1) * sizeof(WCHAR);
408
409 Ptr = CurrentKey->SubKeyList.Flink;
410 while (Ptr != &CurrentKey->SubKeyList)
411 {
412 DPRINTM(DPRINT_REGISTRY, "Ptr 0x%x\n", Ptr);
413
414 SearchKey = CONTAINING_RECORD(Ptr,
415 KEY,
416 KeyList);
417
418 DPRINTM(DPRINT_REGISTRY, "SearchKey 0x%x\n", SearchKey);
419 DPRINTM(DPRINT_REGISTRY, "Searching '%S'\n", SearchKey->Name);
420
421 if (SearchKey->NameSize == NameSize &&
422 _wcsnicmp(SearchKey->Name, name, subkeyLength) == 0)
423 break;
424
425 Ptr = Ptr->Flink;
426 }
427
428 if (Ptr == &CurrentKey->SubKeyList)
429 {
430 return(ERROR_PATH_NOT_FOUND);
431 }
432 else
433 {
434 CurrentKey = SearchKey;
435
436 /* Check whether current key is a link */
437 if (CurrentKey->DataType == REG_LINK)
438 {
439 CurrentKey = (FRLDRHKEY)CurrentKey->Data;
440 }
441 }
442
443 KeyName = KeyName + stringLength;
444 }
445
446 if (Key != NULL)
447 *Key = CurrentKey;
448
449 return(ERROR_SUCCESS);
450 }
451
452
453 LONG
454 RegSetValue(FRLDRHKEY Key,
455 PCWSTR ValueName,
456 ULONG Type,
457 PCSTR Data,
458 ULONG DataSize)
459 {
460 PLIST_ENTRY Ptr;
461 PVALUE Value = NULL;
462
463 DPRINTM(DPRINT_REGISTRY, "Key 0x%p, ValueName '%S', Type %ld, Data 0x%p, DataSize %ld\n",
464 Key, ValueName, Type, Data, DataSize);
465
466 if ((ValueName == NULL) || (*ValueName == 0))
467 {
468 /* set default value */
469 if ((Key->Data != NULL) && (Key->DataSize > sizeof(PUCHAR)))
470 {
471 MmHeapFree(Key->Data);
472 }
473
474 if (DataSize <= sizeof(PUCHAR))
475 {
476 Key->DataSize = DataSize;
477 Key->DataType = Type;
478 memcpy(&Key->Data, Data, DataSize);
479 }
480 else
481 {
482 Key->Data = MmHeapAlloc(DataSize);
483 Key->DataSize = DataSize;
484 Key->DataType = Type;
485 memcpy(Key->Data, Data, DataSize);
486 }
487 }
488 else
489 {
490 /* set non-default value */
491 Ptr = Key->ValueList.Flink;
492 while (Ptr != &Key->ValueList)
493 {
494 Value = CONTAINING_RECORD(Ptr,
495 VALUE,
496 ValueList);
497
498 DPRINTM(DPRINT_REGISTRY, "Value->Name '%S'\n", Value->Name);
499
500 if (_wcsicmp(Value->Name, ValueName) == 0)
501 break;
502
503 Ptr = Ptr->Flink;
504 }
505
506 if (Ptr == &Key->ValueList)
507 {
508 /* add new value */
509 DPRINTM(DPRINT_REGISTRY, "No value found - adding new value\n");
510
511 Value = (PVALUE)MmHeapAlloc(sizeof(VALUE));
512 if (Value == NULL)
513 return(ERROR_OUTOFMEMORY);
514
515 InsertTailList(&Key->ValueList, &Value->ValueList);
516 Key->ValueCount++;
517
518 Value->NameSize = (wcslen(ValueName)+1)*sizeof(WCHAR);
519 Value->Name = (PWCHAR)MmHeapAlloc(Value->NameSize);
520 if (Value->Name == NULL)
521 return(ERROR_OUTOFMEMORY);
522 wcscpy(Value->Name, ValueName);
523 Value->DataType = REG_NONE;
524 Value->DataSize = 0;
525 Value->Data = NULL;
526 }
527
528 /* set new value */
529 if ((Value->Data != NULL) && (Value->DataSize > sizeof(PUCHAR)))
530 {
531 MmHeapFree(Value->Data);
532 }
533
534 if (DataSize <= sizeof(PUCHAR))
535 {
536 Value->DataSize = DataSize;
537 Value->DataType = Type;
538 memcpy(&Value->Data, Data, DataSize);
539 }
540 else
541 {
542 Value->Data = MmHeapAlloc(DataSize);
543 if (Value->Data == NULL)
544 return(ERROR_OUTOFMEMORY);
545 Value->DataType = Type;
546 Value->DataSize = DataSize;
547 memcpy(Value->Data, Data, DataSize);
548 }
549 }
550 return(ERROR_SUCCESS);
551 }
552
553
554 LONG
555 RegQueryValue(FRLDRHKEY Key,
556 PCWSTR ValueName,
557 ULONG* Type,
558 PUCHAR Data,
559 ULONG* DataSize)
560 {
561 ULONG Size;
562 PLIST_ENTRY Ptr;
563 PVALUE Value = NULL;
564
565 if ((ValueName == NULL) || (*ValueName == 0))
566 {
567 /* query default value */
568 if (Key->Data == NULL)
569 return(ERROR_INVALID_PARAMETER);
570
571 if (Type != NULL)
572 *Type = Key->DataType;
573 if ((Data != NULL) && (DataSize != NULL))
574 {
575 if (Key->DataSize <= sizeof(PUCHAR))
576 {
577 Size = min(Key->DataSize, *DataSize);
578 memcpy(Data, &Key->Data, Size);
579 *DataSize = Size;
580 }
581 else
582 {
583 Size = min(Key->DataSize, *DataSize);
584 memcpy(Data, Key->Data, Size);
585 *DataSize = Size;
586 }
587 }
588 else if ((Data == NULL) && (DataSize != NULL))
589 {
590 *DataSize = Key->DataSize;
591 }
592 }
593 else
594 {
595 /* query non-default value */
596 Ptr = Key->ValueList.Flink;
597 while (Ptr != &Key->ValueList)
598 {
599 Value = CONTAINING_RECORD(Ptr,
600 VALUE,
601 ValueList);
602
603 DPRINTM(DPRINT_REGISTRY, "Searching for '%S'. Value name '%S'\n", ValueName, Value->Name);
604
605 if (_wcsicmp(Value->Name, ValueName) == 0)
606 break;
607
608 Ptr = Ptr->Flink;
609 }
610
611 if (Ptr == &Key->ValueList)
612 return(ERROR_INVALID_PARAMETER);
613
614 if (Type != NULL)
615 *Type = Value->DataType;
616 if ((Data != NULL) && (DataSize != NULL))
617 {
618 if (Value->DataSize <= sizeof(PUCHAR))
619 {
620 Size = min(Value->DataSize, *DataSize);
621 memcpy(Data, &Value->Data, Size);
622 *DataSize = Size;
623 }
624 else
625 {
626 Size = min(Value->DataSize, *DataSize);
627 memcpy(Data, Value->Data, Size);
628 *DataSize = Size;
629 }
630 }
631 else if ((Data == NULL) && (DataSize != NULL))
632 {
633 *DataSize = Value->DataSize;
634 }
635 }
636
637 return(ERROR_SUCCESS);
638 }
639
640
641 LONG
642 RegDeleteValue(FRLDRHKEY Key,
643 PCWSTR ValueName)
644 {
645 PLIST_ENTRY Ptr;
646 PVALUE Value = NULL;
647
648 if ((ValueName == NULL) || (*ValueName == 0))
649 {
650 /* delete default value */
651 if (Key->Data != NULL)
652 MmFreeMemory(Key->Data);
653 Key->Data = NULL;
654 Key->DataSize = 0;
655 Key->DataType = 0;
656 }
657 else
658 {
659 /* delete non-default value */
660 Ptr = Key->ValueList.Flink;
661 while (Ptr != &Key->ValueList)
662 {
663 Value = CONTAINING_RECORD(Ptr,
664 VALUE,
665 ValueList);
666 if (_wcsicmp(Value->Name, ValueName) == 0)
667 break;
668
669 Ptr = Ptr->Flink;
670 }
671
672 if (Ptr == &Key->ValueList)
673 return(ERROR_INVALID_PARAMETER);
674
675 /* delete value */
676 Key->ValueCount--;
677 if (Value->Name != NULL)
678 MmFreeMemory(Value->Name);
679 Value->Name = NULL;
680 Value->NameSize = 0;
681
682 if (Value->DataSize > sizeof(PUCHAR))
683 {
684 if (Value->Data != NULL)
685 MmFreeMemory(Value->Data);
686 }
687 Value->Data = NULL;
688 Value->DataSize = 0;
689 Value->DataType = 0;
690
691 RemoveEntryList(&Value->ValueList);
692 MmFreeMemory(Value);
693 }
694 return(ERROR_SUCCESS);
695 }
696
697
698 LONG
699 RegEnumValue(FRLDRHKEY Key,
700 ULONG Index,
701 PWCHAR ValueName,
702 ULONG* NameSize,
703 ULONG* Type,
704 PUCHAR Data,
705 ULONG* DataSize)
706 {
707 PLIST_ENTRY Ptr;
708 PVALUE Value;
709 ULONG Count = 0;
710
711 if (Key->Data != NULL)
712 {
713 if (Index > 0)
714 {
715 Index--;
716 }
717 else
718 {
719 /* enumerate default value */
720 if (ValueName != NULL)
721 *ValueName = 0;
722 if (Type != NULL)
723 *Type = Key->DataType;
724 if (Data != NULL)
725 {
726 if (Key->DataSize <= sizeof(PUCHAR))
727 {
728 memcpy(Data, &Key->Data, min(Key->DataSize, *DataSize));
729 }
730 else
731 {
732 memcpy(Data, Key->Data, min(Key->DataSize, *DataSize));
733 }
734 }
735 if (DataSize != NULL)
736 *DataSize = min(Key->DataSize, *DataSize);
737
738 return(ERROR_SUCCESS);
739 }
740 }
741
742 Ptr = Key->ValueList.Flink;
743 while (Ptr != &Key->ValueList)
744 {
745 if (Index == Count)
746 break;
747
748 Count++;
749 Ptr = Ptr->Flink;
750 }
751
752 if (Ptr == &Key->ValueList)
753 return(ERROR_NO_MORE_ITEMS);
754
755 Value = CONTAINING_RECORD(Ptr,
756 VALUE,
757 ValueList);
758
759 /* enumerate non-default value */
760 if (ValueName != NULL)
761 memcpy(ValueName, Value->Name, min(Value->NameSize, *NameSize));
762 if (Type != NULL)
763 *Type = Value->DataType;
764
765 if (Data != NULL)
766 {
767 if (Value->DataSize <= sizeof(PUCHAR))
768 {
769 memcpy(Data, &Value->Data, min(Value->DataSize, *DataSize));
770 }
771 else
772 {
773 memcpy(Data, Value->Data, min(Value->DataSize, *DataSize));
774 }
775 }
776
777 if (DataSize != NULL)
778 *DataSize = min(Value->DataSize, *DataSize);
779
780 return(ERROR_SUCCESS);
781 }
782
783
784 ULONG
785 RegGetSubKeyCount (FRLDRHKEY Key)
786 {
787 return Key->SubKeyCount;
788 }
789
790
791 ULONG
792 RegGetValueCount (FRLDRHKEY Key)
793 {
794 if (Key->DataSize != 0)
795 return Key->ValueCount + 1;
796
797 return Key->ValueCount;
798 }
799
800 /* EOF */