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