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