xref: /reactos/sdk/tools/mkhive/reginf.c (revision 40462c92)
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 2003, 2006 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 along
16  *  with this program; if not, write to the Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 /*
20  * COPYRIGHT:       See COPYING in the top level directory
21  * PROJECT:         ReactOS hive maker
22  * FILE:            tools/mkhive/reginf.c
23  * PURPOSE:         Inf file import code
24  * PROGRAMMERS:     Eric Kohl
25  *                  Herv� Poussineau
26  */
27 
28 /* INCLUDES *****************************************************************/
29 
30 #include <string.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 
34 #define NDEBUG
35 #include "mkhive.h"
36 
37 #define FLG_ADDREG_BINVALUETYPE         0x00000001
38 #define FLG_ADDREG_NOCLOBBER            0x00000002
39 #define FLG_ADDREG_DELVAL               0x00000004
40 #define FLG_ADDREG_APPEND               0x00000008
41 #define FLG_ADDREG_KEYONLY              0x00000010
42 #define FLG_ADDREG_OVERWRITEONLY        0x00000020
43 #define FLG_ADDREG_KEYONLY_COMMON       0x00002000
44 #define FLG_DELREG_KEYONLY_COMMON       FLG_ADDREG_KEYONLY_COMMON
45 #define FLG_ADDREG_DELREG_BIT           0x00008000
46 
47 #define FLG_ADDREG_TYPE_SZ              0x00000000
48 #define FLG_ADDREG_TYPE_MULTI_SZ        0x00010000
49 #define FLG_ADDREG_TYPE_EXPAND_SZ       0x00020000
50 #define FLG_ADDREG_TYPE_BINARY         (0x00000000 | FLG_ADDREG_BINVALUETYPE)
51 #define FLG_ADDREG_TYPE_DWORD          (0x00010000 | FLG_ADDREG_BINVALUETYPE)
52 #define FLG_ADDREG_TYPE_NONE           (0x00020000 | FLG_ADDREG_BINVALUETYPE)
53 #define FLG_ADDREG_TYPE_MASK           (0xFFFF0000 | FLG_ADDREG_BINVALUETYPE)
54 
55 
56 static const WCHAR HKCR[] = {'H','K','C','R',0};
57 static const WCHAR HKCU[] = {'H','K','C','U',0};
58 static const WCHAR HKLM[] = {'H','K','L','M',0};
59 static const WCHAR HKU[] = {'H','K','U',0};
60 static const WCHAR HKR[] = {'H','K','R',0};
61 static const WCHAR BCD[] = {'B','C','D',0};
62 
63 static const WCHAR HKCRPath[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\','S','O','F','T','W','A','R','E','\\','C','l','a','s','s','e','s','\\',0};
64 static const WCHAR HKCUPath[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\','.','D','E','F','A','U','L','T','\\',0};
65 static const WCHAR HKLMPath[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',0};
66 static const WCHAR HKUPath[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\',0};
67 static const WCHAR BCDPath[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',0};
68 
69 static const WCHAR AddReg[] = {'A','d','d','R','e','g',0};
70 static const WCHAR DelReg[] = {'D','e','l','R','e','g',0};
71 
72 /* FUNCTIONS ****************************************************************/
73 
74 static BOOL
75 get_root_key(PWCHAR Name)
76 {
77     if (!strcmpiW(Name, HKCR))
78     {
79         strcpyW(Name, HKCRPath);
80         return TRUE;
81     }
82 
83     if (!strcmpiW(Name, HKCU))
84     {
85         strcpyW(Name, HKCUPath);
86         return TRUE;
87     }
88 
89     if (!strcmpiW(Name, HKLM))
90     {
91         strcpyW(Name, HKLMPath);
92         return TRUE;
93     }
94 
95     if (!strcmpiW(Name, HKU))
96     {
97         strcpyW(Name, HKUPath);
98         return TRUE;
99     }
100 
101     if (!strcmpiW(Name, BCD))
102     {
103         strcpyW(Name, BCDPath);
104         return TRUE;
105     }
106 
107 #if 0
108     if (!strcmpiW(Name, HKR))
109         return FALSE;
110 #endif
111 
112   return FALSE;
113 }
114 
115 
116 /***********************************************************************
117  * append_multi_sz_value
118  *
119  * Append a multisz string to a multisz registry value.
120  */
121 // NOTE: Synced with setupapi/install.c ; see also usetup/registry.c
122 static VOID
123 append_multi_sz_value(
124     IN HKEY KeyHandle,
125     IN PCWSTR ValueName,
126     IN PCWSTR Strings,
127     IN ULONG StringSize) // In characters
128 {
129     ULONG Size, Total;   // In bytes
130     ULONG Type;
131     PWCHAR Buffer;
132     PWCHAR p;
133     size_t len;
134     LONG Error;
135 
136     Error = RegQueryValueExW(KeyHandle,
137                              ValueName,
138                              NULL,
139                              &Type,
140                              NULL,
141                              &Size);
142     if ((Error != ERROR_SUCCESS) || (Type != REG_MULTI_SZ))
143         return;
144 
145     Buffer = malloc(Size + StringSize * sizeof(WCHAR));
146     if (Buffer == NULL)
147         return;
148 
149     Error = RegQueryValueExW(KeyHandle,
150                              ValueName,
151                              NULL,
152                              NULL,
153                              (PUCHAR)Buffer,
154                              &Size);
155     if (Error != ERROR_SUCCESS)
156         goto done;
157 
158     /* compare each string against all the existing ones */
159     Total = Size;
160     while (*Strings != 0)
161     {
162         len = strlenW(Strings) + 1;
163 
164         for (p = Buffer; *p != 0; p += strlenW(p) + 1)
165             if (!strcmpiW(p, Strings))
166                 break;
167 
168         if (*p == 0)  /* not found, need to append it */
169         {
170             memcpy(p, Strings, len * sizeof(WCHAR));
171             p[len] = 0;
172             Total += len * sizeof(WCHAR);
173         }
174         Strings += len;
175     }
176 
177     if (Total != Size)
178     {
179         DPRINT("setting value '%S' to '%S'\n", ValueName, Buffer);
180         RegSetValueExW(KeyHandle,
181                        ValueName,
182                        0,
183                        REG_MULTI_SZ,
184                        (PUCHAR)Buffer,
185                        Total + sizeof(WCHAR));
186     }
187 
188 done:
189     free(Buffer);
190 }
191 
192 
193 /***********************************************************************
194  *            do_reg_operation
195  *
196  * Perform an add/delete registry operation depending on the flags.
197  */
198 static BOOL
199 do_reg_operation(
200     IN HKEY KeyHandle,
201     IN PCWSTR ValueName,
202     IN PINFCONTEXT Context,
203     IN ULONG Flags)
204 {
205     WCHAR EmptyStr = 0;
206     ULONG Type;
207     ULONG Size;
208     LONG Error;
209 
210     if (Flags & (FLG_ADDREG_DELREG_BIT | FLG_ADDREG_DELVAL))  /* deletion */
211     {
212         if (ValueName && *ValueName && !(Flags & FLG_DELREG_KEYONLY_COMMON))
213         {
214             // NOTE: We don't currently handle deleting sub-values inside multi-strings.
215             RegDeleteValueW(KeyHandle, ValueName);
216         }
217         else
218         {
219             RegDeleteKeyW(KeyHandle, NULL);
220         }
221         return TRUE;
222     }
223 
224     if (Flags & (FLG_ADDREG_KEYONLY | FLG_ADDREG_KEYONLY_COMMON))
225         return TRUE;
226 
227     if (Flags & (FLG_ADDREG_NOCLOBBER | FLG_ADDREG_OVERWRITEONLY))
228     {
229         Error = RegQueryValueExW(KeyHandle,
230                                  ValueName,
231                                  NULL,
232                                  NULL,
233                                  NULL,
234                                  NULL);
235 
236         if ((Error == ERROR_SUCCESS) && (Flags & FLG_ADDREG_NOCLOBBER))
237             return TRUE;
238 
239         if ((Error != ERROR_SUCCESS) && (Flags & FLG_ADDREG_OVERWRITEONLY))
240             return TRUE;
241     }
242 
243     switch (Flags & FLG_ADDREG_TYPE_MASK)
244     {
245         case FLG_ADDREG_TYPE_SZ:
246             Type = REG_SZ;
247             break;
248 
249         case FLG_ADDREG_TYPE_MULTI_SZ:
250             Type = REG_MULTI_SZ;
251             break;
252 
253         case FLG_ADDREG_TYPE_EXPAND_SZ:
254             Type = REG_EXPAND_SZ;
255             break;
256 
257         case FLG_ADDREG_TYPE_BINARY:
258             Type = REG_BINARY;
259             break;
260 
261         case FLG_ADDREG_TYPE_DWORD:
262             Type = REG_DWORD;
263             break;
264 
265         case FLG_ADDREG_TYPE_NONE:
266             Type = REG_NONE;
267             break;
268 
269         default:
270             Type = Flags >> 16;
271             break;
272     }
273 
274     if (!(Flags & FLG_ADDREG_BINVALUETYPE) ||
275         (Type == REG_DWORD && InfHostGetFieldCount(Context) == 5))
276     {
277         PWCHAR Str = NULL;
278 
279         if (Type == REG_MULTI_SZ)
280         {
281             if (InfHostGetMultiSzField(Context, 5, NULL, 0, &Size) != 0)
282                 Size = 0;
283 
284             if (Size)
285             {
286                 Str = malloc(Size * sizeof(WCHAR));
287                 if (Str == NULL)
288                     return FALSE;
289 
290                 InfHostGetMultiSzField(Context, 5, Str, Size, NULL);
291             }
292 
293             if (Flags & FLG_ADDREG_APPEND)
294             {
295                 if (Str == NULL)
296                     return TRUE;
297 
298                 DPRINT("append_multi_sz_value(ValueName = '%S')\n", ValueName);
299                 append_multi_sz_value(KeyHandle,
300                                       ValueName,
301                                       Str,
302                                       Size);
303 
304                 free(Str);
305                 return TRUE;
306             }
307             /* else fall through to normal string handling */
308         }
309         else
310         {
311             if (InfHostGetStringField(Context, 5, NULL, 0, &Size) != 0)
312                 Size = 0;
313 
314             if (Size)
315             {
316                 Str = malloc(Size * sizeof(WCHAR));
317                 if (Str == NULL)
318                     return FALSE;
319 
320                 InfHostGetStringField(Context, 5, Str, Size, NULL);
321             }
322         }
323 
324         if (Type == REG_DWORD)
325         {
326             ULONG dw = Str ? strtoulW(Str, NULL, 0) : 0;
327 
328             DPRINT("setting dword '%S' to %x\n", ValueName, dw);
329 
330             RegSetValueExW(KeyHandle,
331                            ValueName,
332                            0,
333                            Type,
334                            (const PUCHAR)&dw,
335                            sizeof(ULONG));
336         }
337         else
338         {
339             DPRINT("setting value '%S' to '%S'\n", ValueName, Str);
340 
341             if (Str)
342             {
343                 RegSetValueExW(KeyHandle,
344                                ValueName,
345                                0,
346                                Type,
347                                (PVOID)Str,
348                                (ULONG)(Size * sizeof(WCHAR)));
349             }
350             else
351             {
352                 RegSetValueExW(KeyHandle,
353                                ValueName,
354                                0,
355                                Type,
356                                (PVOID)&EmptyStr,
357                                sizeof(WCHAR));
358             }
359         }
360         free(Str);
361     }
362     else  /* get the binary data */
363     {
364         PUCHAR Data = NULL;
365 
366         if (InfHostGetBinaryField(Context, 5, NULL, 0, &Size) != 0)
367             Size = 0;
368 
369         if (Size)
370         {
371             Data = malloc(Size);
372             if (Data == NULL)
373                 return FALSE;
374 
375             DPRINT("setting binary data '%S' len %d\n", ValueName, (ULONG)Size);
376             InfHostGetBinaryField(Context, 5, Data, Size, NULL);
377         }
378 
379         RegSetValueExW(KeyHandle,
380                        ValueName,
381                        0,
382                        Type,
383                        (PVOID)Data,
384                        (ULONG)Size);
385 
386         free(Data);
387     }
388 
389     return TRUE;
390 }
391 
392 /***********************************************************************
393  *            registry_callback
394  *
395  * Called once for each AddReg and DelReg entry in a given section.
396  */
397 static BOOL
398 registry_callback(HINF hInf, PCWSTR Section, BOOL Delete)
399 {
400     WCHAR Buffer[MAX_INF_STRING_LENGTH];
401     PWCHAR ValuePtr;
402     ULONG Flags;
403     size_t Length;
404 
405     PINFCONTEXT Context = NULL;
406     HKEY KeyHandle;
407     BOOL Ok;
408 
409     Ok = InfHostFindFirstLine(hInf, Section, NULL, &Context) == 0;
410     if (!Ok)
411         return TRUE; /* Don't fail if the section isn't present */
412 
413     for (Ok = TRUE; Ok; Ok = (InfHostFindNextLine(Context, Context) == 0))
414     {
415         /* Get root */
416         if (InfHostGetStringField(Context, 1, Buffer, sizeof(Buffer)/sizeof(WCHAR), NULL) != 0)
417             continue;
418         if (!get_root_key(Buffer))
419             continue;
420 
421         /* Get key */
422         Length = strlenW(Buffer);
423         if (InfHostGetStringField(Context, 2, Buffer + Length, sizeof(Buffer)/sizeof(WCHAR) - (ULONG)Length, NULL) != 0)
424             *Buffer = 0;
425 
426         DPRINT("KeyName: <%S>\n", Buffer);
427 
428         /* Get flags */
429         if (InfHostGetIntField(Context, 4, (INT*)&Flags) != 0)
430             Flags = 0;
431 
432         if (Delete)
433         {
434             if (!Flags)
435                 Flags = FLG_ADDREG_DELREG_BIT;
436             else if (!(Flags & FLG_ADDREG_DELREG_BIT))
437                 continue; /* ignore this entry */
438         }
439         else
440         {
441             if (Flags & FLG_ADDREG_DELREG_BIT)
442                 continue; /* ignore this entry */
443         }
444 
445         DPRINT("Flags: 0x%x\n", Flags);
446 
447         if (Delete || (Flags & FLG_ADDREG_OVERWRITEONLY))
448         {
449             if (RegOpenKeyW(NULL, Buffer, &KeyHandle) != ERROR_SUCCESS)
450             {
451                 DPRINT("RegOpenKey(%S) failed\n", Buffer);
452                 continue;  /* ignore if it doesn't exist */
453             }
454         }
455         else
456         {
457             if (RegCreateKeyW(NULL, Buffer, &KeyHandle) != ERROR_SUCCESS)
458             {
459                 DPRINT("RegCreateKey(%S) failed\n", Buffer);
460                 continue;
461             }
462         }
463 
464         /* Get value name */
465         if (InfHostGetStringField(Context, 3, Buffer, sizeof(Buffer)/sizeof(WCHAR), NULL) == 0)
466         {
467             ValuePtr = Buffer;
468         }
469         else
470         {
471             ValuePtr = NULL;
472         }
473 
474         /* And now do it */
475         if (!do_reg_operation(KeyHandle, ValuePtr, Context, Flags))
476         {
477             RegCloseKey(KeyHandle);
478             return FALSE;
479         }
480 
481         RegCloseKey(KeyHandle);
482     }
483 
484     InfHostFreeContext(Context);
485 
486     return TRUE;
487 }
488 
489 
490 BOOL
491 ImportRegistryFile(PCHAR FileName)
492 {
493     HINF hInf;
494     ULONG ErrorLine;
495 
496     /* Load inf file from install media. */
497     if (InfHostOpenFile(&hInf, FileName, 0, &ErrorLine) != 0)
498     {
499         DPRINT1("InfHostOpenFile(%s) failed\n", FileName);
500         return FALSE;
501     }
502 
503     if (!registry_callback(hInf, (PWCHAR)DelReg, TRUE))
504     {
505         DPRINT1("registry_callback() for DelReg failed\n");
506         InfHostCloseFile(hInf);
507         return FALSE;
508     }
509 
510     if (!registry_callback(hInf, (PWCHAR)AddReg, FALSE))
511     {
512         DPRINT1("registry_callback() for AddReg failed\n");
513         InfHostCloseFile(hInf);
514         return FALSE;
515     }
516 
517     InfHostCloseFile(hInf);
518     return TRUE;
519 }
520 
521 /* EOF */
522