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