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