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