update for HEAD-2003091401
[reactos.git] / 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
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 (strncmp (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 (strncmp(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 (strcmp(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 */