4295e69914927670f04d09a2c34ed6627cd1b8bc
[reactos.git] / reactos / subsys / system / usetup / 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 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS text-mode setup
22 * FILE: subsys/system/usetup/registry.c
23 * PURPOSE: Registry creation functions
24 * PROGRAMMER: Eric Kohl
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include <usetup.h>
30
31 #define NDEBUG
32 #include <debug.h>
33
34 #define FLG_ADDREG_BINVALUETYPE 0x00000001
35 #define FLG_ADDREG_NOCLOBBER 0x00000002
36 #define FLG_ADDREG_DELVAL 0x00000004
37 #define FLG_ADDREG_APPEND 0x00000008
38 #define FLG_ADDREG_KEYONLY 0x00000010
39 #define FLG_ADDREG_OVERWRITEONLY 0x00000020
40 #define FLG_ADDREG_TYPE_SZ 0x00000000
41 #define FLG_ADDREG_TYPE_MULTI_SZ 0x00010000
42 #define FLG_ADDREG_TYPE_EXPAND_SZ 0x00020000
43 #define FLG_ADDREG_TYPE_BINARY (0x00000000 | FLG_ADDREG_BINVALUETYPE)
44 #define FLG_ADDREG_TYPE_DWORD (0x00010000 | FLG_ADDREG_BINVALUETYPE)
45 #define FLG_ADDREG_TYPE_NONE (0x00020000 | FLG_ADDREG_BINVALUETYPE)
46 #define FLG_ADDREG_TYPE_MASK (0xFFFF0000 | FLG_ADDREG_BINVALUETYPE)
47
48
49 /* FUNCTIONS ****************************************************************/
50
51 static BOOLEAN
52 GetRootKey (PWCHAR Name)
53 {
54 if (!_wcsicmp (Name, L"HKCR"))
55 {
56 wcscpy (Name, L"\\Registry\\Machine\\SOFTWARE\\Classes\\");
57 return TRUE;
58 }
59
60 if (!_wcsicmp (Name, L"HKCU"))
61 {
62 wcscpy (Name, L"\\Registry\\User\\.DEFAULT\\");
63 return TRUE;
64 }
65
66 if (!_wcsicmp (Name, L"HKLM"))
67 {
68 wcscpy (Name, L"\\Registry\\Machine\\");
69 return TRUE;
70 }
71
72 if (!_wcsicmp (Name, L"HKU"))
73 {
74 wcscpy (Name, L"\\Registry\\User\\");
75 return TRUE;
76 }
77
78 #if 0
79 if (!_wcsicmp (Name, L"HKR"))
80 return FALSE;
81 #endif
82
83 return FALSE;
84 }
85
86
87 /***********************************************************************
88 * append_multi_sz_value
89 *
90 * Append a multisz string to a multisz registry value.
91 */
92 #if 0
93 static void
94 append_multi_sz_value (HANDLE hkey,
95 const WCHAR *value,
96 const WCHAR *strings,
97 DWORD str_size )
98 {
99 DWORD size, type, total;
100 WCHAR *buffer, *p;
101
102 if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return;
103 if (type != REG_MULTI_SZ) return;
104
105 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (size + str_size) * sizeof(WCHAR) ))) return;
106 if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
107
108 /* compare each string against all the existing ones */
109 total = size;
110 while (*strings)
111 {
112 int len = strlenW(strings) + 1;
113
114 for (p = buffer; *p; p += strlenW(p) + 1)
115 if (!strcmpiW( p, strings )) break;
116
117 if (!*p) /* not found, need to append it */
118 {
119 memcpy( p, strings, len * sizeof(WCHAR) );
120 p[len] = 0;
121 total += len;
122 }
123 strings += len;
124 }
125 if (total != size)
126 {
127 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer) );
128 RegSetValueExW( hkey, value, 0, REG_MULTI_SZ, (BYTE *)buffer, total );
129 }
130 done:
131 HeapFree( GetProcessHeap(), 0, buffer );
132 }
133 #endif
134
135 /***********************************************************************
136 * delete_multi_sz_value
137 *
138 * Remove a string from a multisz registry value.
139 */
140 #if 0
141 static void delete_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *string )
142 {
143 DWORD size, type;
144 WCHAR *buffer, *src, *dst;
145
146 if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return;
147 if (type != REG_MULTI_SZ) return;
148 /* allocate double the size, one for value before and one for after */
149 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size * 2 * sizeof(WCHAR) ))) return;
150 if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
151 src = buffer;
152 dst = buffer + size;
153 while (*src)
154 {
155 int len = strlenW(src) + 1;
156 if (strcmpiW( src, string ))
157 {
158 memcpy( dst, src, len * sizeof(WCHAR) );
159 dst += len;
160 }
161 src += len;
162 }
163 *dst++ = 0;
164 if (dst != buffer + 2*size) /* did we remove something? */
165 {
166 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer + size) );
167 RegSetValueExW( hkey, value, 0, REG_MULTI_SZ,
168 (BYTE *)(buffer + size), dst - (buffer + size) );
169 }
170 done:
171 HeapFree( GetProcessHeap(), 0, buffer );
172 }
173 #endif
174
175 /***********************************************************************
176 * do_reg_operation
177 *
178 * Perform an add/delete registry operation depending on the flags.
179 */
180 static BOOLEAN
181 do_reg_operation(HANDLE KeyHandle,
182 PUNICODE_STRING ValueName,
183 PINFCONTEXT Context,
184 ULONG Flags)
185 {
186 WCHAR EmptyStr = (WCHAR)0;
187 ULONG Type;
188 ULONG Size;
189
190 if (Flags & FLG_ADDREG_DELVAL) /* deletion */
191 {
192 #if 0
193 if (ValueName)
194 {
195 RegDeleteValueW( hkey, value );
196 }
197 else
198 {
199 RegDeleteKeyW( hkey, NULL );
200 }
201 #endif
202 return TRUE;
203 }
204
205 if (Flags & FLG_ADDREG_KEYONLY)
206 return TRUE;
207
208 #if 0
209 if (Flags & (FLG_ADDREG_NOCLOBBER | FLG_ADDREG_OVERWRITEONLY))
210 {
211 BOOL exists = !RegQueryValueExW( hkey, value, NULL, NULL, NULL, NULL );
212 if (exists && (flags & FLG_ADDREG_NOCLOBBER))
213 return TRUE;
214 if (!exists & (flags & FLG_ADDREG_OVERWRITEONLY))
215 return TRUE;
216 }
217 #endif
218
219 switch (Flags & FLG_ADDREG_TYPE_MASK)
220 {
221 case FLG_ADDREG_TYPE_SZ:
222 Type = REG_SZ;
223 break;
224
225 case FLG_ADDREG_TYPE_MULTI_SZ:
226 Type = REG_MULTI_SZ;
227 break;
228
229 case FLG_ADDREG_TYPE_EXPAND_SZ:
230 Type = REG_EXPAND_SZ;
231 break;
232
233 case FLG_ADDREG_TYPE_BINARY:
234 Type = REG_BINARY;
235 break;
236
237 case FLG_ADDREG_TYPE_DWORD:
238 Type = REG_DWORD;
239 break;
240
241 case FLG_ADDREG_TYPE_NONE:
242 Type = REG_NONE;
243 break;
244
245 default:
246 Type = Flags >> 16;
247 break;
248 }
249
250 if (!(Flags & FLG_ADDREG_BINVALUETYPE) ||
251 (Type == REG_DWORD && InfGetFieldCount (Context) == 5))
252 {
253 PWCHAR Str = NULL;
254
255 if (Type == REG_MULTI_SZ)
256 {
257 if (!InfGetMultiSzField (Context, 5, NULL, 0, &Size))
258 Size = 0;
259
260 if (Size)
261 {
262 Str = RtlAllocateHeap (ProcessHeap, 0, Size * sizeof(WCHAR));
263 if (Str == NULL)
264 return FALSE;
265
266 InfGetMultiSzField (Context, 5, Str, Size, NULL);
267 }
268
269 if (Flags & FLG_ADDREG_APPEND)
270 {
271 if (Str == NULL)
272 return TRUE;
273
274 // append_multi_sz_value( hkey, value, str, size );
275
276 RtlFreeHeap (ProcessHeap, 0, Str);
277 return TRUE;
278 }
279 /* else fall through to normal string handling */
280 }
281 else
282 {
283 if (!InfGetStringField (Context, 5, NULL, 0, &Size))
284 Size = 0;
285
286 if (Size)
287 {
288 Str = RtlAllocateHeap (ProcessHeap, 0, Size * sizeof(WCHAR));
289 if (Str == NULL)
290 return FALSE;
291
292 InfGetStringField (Context, 5, Str, Size, NULL);
293 }
294 }
295
296 if (Type == REG_DWORD)
297 {
298 ULONG dw = Str ? wcstol (Str, NULL, 0) : 0;
299
300 DPRINT("setting dword %wZ to %lx\n", ValueName, dw);
301
302 NtSetValueKey (KeyHandle,
303 ValueName,
304 0,
305 Type,
306 (PVOID)&dw,
307 sizeof(ULONG));
308 }
309 else
310 {
311 DPRINT("setting value %wZ to %S\n", ValueName, Str);
312
313 if (Str)
314 {
315 NtSetValueKey (KeyHandle,
316 ValueName,
317 0,
318 Type,
319 (PVOID)Str,
320 Size * sizeof(WCHAR));
321 }
322 else
323 {
324 NtSetValueKey (KeyHandle,
325 ValueName,
326 0,
327 Type,
328 (PVOID)&EmptyStr,
329 sizeof(WCHAR));
330 }
331 }
332 RtlFreeHeap (ProcessHeap, 0, Str);
333 }
334 else /* get the binary data */
335 {
336 PUCHAR Data = NULL;
337
338 if (!InfGetBinaryField (Context, 5, NULL, 0, &Size))
339 Size = 0;
340
341 if (Size)
342 {
343 Data = RtlAllocateHeap (ProcessHeap, 0, Size);
344 if (Data == NULL)
345 return FALSE;
346
347 DPRINT("setting binary data %wZ len %lu\n", ValueName, Size);
348 InfGetBinaryField (Context, 5, Data, Size, NULL);
349 }
350
351 NtSetValueKey (KeyHandle,
352 ValueName,
353 0,
354 Type,
355 (PVOID)Data,
356 Size);
357
358 RtlFreeHeap (ProcessHeap, 0, Data);
359 }
360
361 return TRUE;
362 }
363
364
365 NTSTATUS
366 CreateNestedKey (PHANDLE KeyHandle,
367 ACCESS_MASK DesiredAccess,
368 POBJECT_ATTRIBUTES ObjectAttributes)
369 {
370 OBJECT_ATTRIBUTES LocalObjectAttributes;
371 UNICODE_STRING LocalKeyName;
372 ULONG Disposition;
373 NTSTATUS Status;
374 ULONG FullNameLength;
375 ULONG Length;
376 PWCHAR Ptr;
377 HANDLE LocalKeyHandle;
378
379 Status = NtCreateKey (KeyHandle,
380 KEY_ALL_ACCESS,
381 ObjectAttributes,
382 0,
383 NULL,
384 0,
385 &Disposition);
386 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes->ObjectName, Status);
387 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
388 return Status;
389
390 /* Copy object attributes */
391 RtlCopyMemory (&LocalObjectAttributes,
392 ObjectAttributes,
393 sizeof(OBJECT_ATTRIBUTES));
394 RtlCreateUnicodeString (&LocalKeyName,
395 ObjectAttributes->ObjectName->Buffer);
396 LocalObjectAttributes.ObjectName = &LocalKeyName;
397 FullNameLength = LocalKeyName.Length / sizeof(WCHAR);
398
399 /* Remove the last part of the key name and try to create the key again. */
400 while (Status == STATUS_OBJECT_NAME_NOT_FOUND)
401 {
402 Ptr = wcsrchr (LocalKeyName.Buffer, '\\');
403 if (Ptr == NULL || Ptr == LocalKeyName.Buffer)
404 {
405 Status = STATUS_UNSUCCESSFUL;
406 break;
407 }
408 *Ptr = (WCHAR)0;
409 LocalKeyName.Length = wcslen (LocalKeyName.Buffer) * sizeof(WCHAR);
410
411 Status = NtCreateKey (&LocalKeyHandle,
412 KEY_ALL_ACCESS,
413 &LocalObjectAttributes,
414 0,
415 NULL,
416 0,
417 &Disposition);
418 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
419 }
420
421 if (!NT_SUCCESS(Status))
422 {
423 RtlFreeUnicodeString (&LocalKeyName);
424 return Status;
425 }
426
427 /* Add removed parts of the key name and create them too. */
428 Length = wcslen (LocalKeyName.Buffer);
429 while (TRUE)
430 {
431 if (Length == FullNameLength)
432 {
433 Status = STATUS_SUCCESS;
434 *KeyHandle = LocalKeyHandle;
435 break;
436 }
437 NtClose (LocalKeyHandle);
438
439 LocalKeyName.Buffer[Length] = L'\\';
440 Length = wcslen (LocalKeyName.Buffer);
441 LocalKeyName.Length = Length * sizeof(WCHAR);
442
443 Status = NtCreateKey (&LocalKeyHandle,
444 KEY_ALL_ACCESS,
445 &LocalObjectAttributes,
446 0,
447 NULL,
448 0,
449 &Disposition);
450 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
451 if (!NT_SUCCESS(Status))
452 break;
453 }
454
455 RtlFreeUnicodeString (&LocalKeyName);
456
457 return Status;
458 }
459
460
461 /***********************************************************************
462 * registry_callback
463 *
464 * Called once for each AddReg and DelReg entry in a given section.
465 */
466 static BOOLEAN
467 registry_callback (HINF hInf, PCWSTR Section, BOOLEAN Delete)
468 {
469 OBJECT_ATTRIBUTES ObjectAttributes;
470 WCHAR Buffer[MAX_INF_STRING_LENGTH];
471 UNICODE_STRING Name;
472 UNICODE_STRING Value;
473 PUNICODE_STRING ValuePtr;
474 NTSTATUS Status;
475 ULONG Flags;
476 ULONG Length;
477
478 INFCONTEXT Context;
479 HANDLE KeyHandle;
480 BOOLEAN Ok;
481
482
483 Ok = InfFindFirstLine (hInf, Section, NULL, &Context);
484
485 for (;Ok; Ok = InfFindNextLine (&Context, &Context))
486 {
487 /* get root */
488 if (!InfGetStringField (&Context, 1, Buffer, MAX_INF_STRING_LENGTH, NULL))
489 continue;
490 if (!GetRootKey (Buffer))
491 continue;
492
493 /* get key */
494 Length = wcslen (Buffer);
495 if (!InfGetStringField (&Context, 2, Buffer + Length, MAX_INF_STRING_LENGTH - Length, NULL))
496 *Buffer = 0;
497
498 DPRINT("KeyName: <%S>\n", Buffer);
499
500 /* get flags */
501 if (!InfGetIntField (&Context, 4, (PLONG)&Flags))
502 Flags = 0;
503
504 DPRINT("Flags: %lx\n", Flags);
505
506 RtlInitUnicodeString (&Name,
507 Buffer);
508
509 InitializeObjectAttributes (&ObjectAttributes,
510 &Name,
511 OBJ_CASE_INSENSITIVE,
512 NULL,
513 NULL);
514
515 if (Delete || (Flags & FLG_ADDREG_OVERWRITEONLY))
516 {
517 Status = NtOpenKey (&KeyHandle,
518 KEY_ALL_ACCESS,
519 &ObjectAttributes);
520 if (!NT_SUCCESS(Status))
521 {
522 DPRINT("NtOpenKey(%wZ) failed (Status %lx)\n", &Name, Status);
523 continue; /* ignore if it doesn't exist */
524 }
525 }
526 else
527 {
528 Status = CreateNestedKey (&KeyHandle,
529 KEY_ALL_ACCESS,
530 &ObjectAttributes);
531 if (!NT_SUCCESS(Status))
532 {
533 DPRINT("CreateNestedKey(%wZ) failed (Status %lx)\n", &Name, Status);
534 continue;
535 }
536 }
537
538 /* get value name */
539 if (InfGetStringField (&Context, 3, Buffer, MAX_INF_STRING_LENGTH, NULL))
540 {
541 RtlInitUnicodeString (&Value,
542 Buffer);
543 ValuePtr = &Value;
544 }
545 else
546 {
547 ValuePtr = NULL;
548 }
549
550 /* and now do it */
551 if (!do_reg_operation (KeyHandle, ValuePtr, &Context, Flags))
552 {
553 NtClose (KeyHandle);
554 return FALSE;
555 }
556
557 NtClose (KeyHandle);
558 }
559
560 return TRUE;
561 }
562
563
564 BOOLEAN
565 ImportRegistryFile(PWSTR Filename,
566 PWSTR Section,
567 BOOLEAN Delete)
568 {
569 WCHAR FileNameBuffer[MAX_PATH];
570 UNICODE_STRING FileName;
571 HINF hInf;
572 NTSTATUS Status;
573 ULONG ErrorLine;
574
575 /* Load inf file from install media. */
576 wcscpy(FileNameBuffer, SourceRootPath.Buffer);
577 wcscat(FileNameBuffer, L"\\reactos\\");
578 wcscat(FileNameBuffer, Filename);
579
580 RtlInitUnicodeString(&FileName,
581 FileNameBuffer);
582
583 Status = InfOpenFile(&hInf,
584 &FileName,
585 &ErrorLine);
586 if (!NT_SUCCESS(Status))
587 {
588 DPRINT1("InfOpenFile() failed (Status %lx)\n", Status);
589 return FALSE;
590 }
591
592 if (!registry_callback (hInf, L"AddReg", FALSE))
593 {
594 DPRINT1("registry_callback() failed\n");
595 }
596
597 InfCloseFile (hInf);
598
599 return TRUE;
600 }
601
602
603 BOOLEAN
604 SetInstallPathValue(PUNICODE_STRING InstallPath)
605 {
606 OBJECT_ATTRIBUTES ObjectAttributes;
607 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE");
608 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"InstallPath");
609 HANDLE KeyHandle;
610 NTSTATUS Status;
611
612 /* Create the 'secret' InstallPath key */
613 InitializeObjectAttributes (&ObjectAttributes,
614 &KeyName,
615 OBJ_CASE_INSENSITIVE,
616 NULL,
617 NULL);
618 Status = NtOpenKey (&KeyHandle,
619 KEY_ALL_ACCESS,
620 &ObjectAttributes);
621 if (!NT_SUCCESS(Status))
622 {
623 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
624 return FALSE;
625 }
626
627 Status = NtSetValueKey (KeyHandle,
628 &ValueName,
629 0,
630 REG_SZ,
631 (PVOID)InstallPath->Buffer,
632 InstallPath->Length);
633 NtClose(KeyHandle);
634 if (!NT_SUCCESS(Status))
635 {
636 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
637 return FALSE;
638 }
639
640 return TRUE;
641 }
642
643 /* EOF */