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