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