Moved usetup
[reactos.git] / reactos / 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
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 PINFCONTEXT Context;
488 HANDLE KeyHandle;
489 BOOLEAN Ok;
490
491
492 Ok = InfFindFirstLine (hInf, Section, NULL, &Context);
493
494 if (Ok)
495 {
496 for (;Ok; Ok = InfFindNextLine (Context, Context))
497 {
498 /* get root */
499 if (!InfGetStringField (Context, 1, Buffer, MAX_INF_STRING_LENGTH, NULL))
500 continue;
501 if (!GetRootKey (Buffer))
502 continue;
503
504 /* get key */
505 Length = wcslen (Buffer);
506 if (!InfGetStringField (Context, 2, Buffer + Length, MAX_INF_STRING_LENGTH - Length, NULL))
507 *Buffer = 0;
508
509 DPRINT("KeyName: <%S>\n", Buffer);
510
511 /* get flags */
512 if (!InfGetIntField (Context, 4, (PLONG)&Flags))
513 Flags = 0;
514
515 DPRINT("Flags: %lx\n", Flags);
516
517 RtlInitUnicodeString (&Name,
518 Buffer);
519
520 InitializeObjectAttributes (&ObjectAttributes,
521 &Name,
522 OBJ_CASE_INSENSITIVE,
523 NULL,
524 NULL);
525
526 if (Delete || (Flags & FLG_ADDREG_OVERWRITEONLY))
527 {
528 Status = NtOpenKey (&KeyHandle,
529 KEY_ALL_ACCESS,
530 &ObjectAttributes);
531 if (!NT_SUCCESS(Status))
532 {
533 DPRINT("NtOpenKey(%wZ) failed (Status %lx)\n", &Name, Status);
534 continue; /* ignore if it doesn't exist */
535 }
536 }
537 else
538 {
539 Status = CreateNestedKey (&KeyHandle,
540 KEY_ALL_ACCESS,
541 &ObjectAttributes);
542 if (!NT_SUCCESS(Status))
543 {
544 DPRINT("CreateNestedKey(%wZ) failed (Status %lx)\n", &Name, Status);
545 continue;
546 }
547 }
548
549 /* get value name */
550 if (InfGetStringField (Context, 3, Buffer, MAX_INF_STRING_LENGTH, NULL))
551 {
552 RtlInitUnicodeString (&Value,
553 Buffer);
554 ValuePtr = &Value;
555 }
556 else
557 {
558 ValuePtr = NULL;
559 }
560
561 /* and now do it */
562 if (!do_reg_operation (KeyHandle, ValuePtr, Context, Flags))
563 {
564 NtClose (KeyHandle);
565 return FALSE;
566 }
567
568 NtClose (KeyHandle);
569 }
570 InfFreeContext(Context);
571 }
572
573 return TRUE;
574 }
575
576
577 BOOLEAN
578 ImportRegistryFile(PWSTR Filename,
579 PWSTR Section,
580 BOOLEAN Delete)
581 {
582 WCHAR FileNameBuffer[MAX_PATH];
583 UNICODE_STRING FileName;
584 HINF hInf;
585 NTSTATUS Status;
586 ULONG ErrorLine;
587
588 /* Load inf file from install media. */
589 wcscpy(FileNameBuffer, SourceRootPath.Buffer);
590 wcscat(FileNameBuffer, L"\\reactos\\");
591 wcscat(FileNameBuffer, Filename);
592
593 RtlInitUnicodeString(&FileName,
594 FileNameBuffer);
595
596 Status = InfOpenFile(&hInf,
597 &FileName,
598 &ErrorLine);
599 if (!NT_SUCCESS(Status))
600 {
601 DPRINT1("InfOpenFile() failed (Status %lx)\n", Status);
602 return FALSE;
603 }
604
605 if (!registry_callback (hInf, L"AddReg", FALSE))
606 {
607 DPRINT1("registry_callback() failed\n");
608 }
609
610 InfCloseFile (hInf);
611
612 return TRUE;
613 }
614
615
616 BOOLEAN
617 SetInstallPathValue(PUNICODE_STRING InstallPath)
618 {
619 OBJECT_ATTRIBUTES ObjectAttributes;
620 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE");
621 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"InstallPath");
622 HANDLE KeyHandle;
623 NTSTATUS Status;
624
625 /* Create the 'secret' InstallPath key */
626 InitializeObjectAttributes (&ObjectAttributes,
627 &KeyName,
628 OBJ_CASE_INSENSITIVE,
629 NULL,
630 NULL);
631 Status = NtOpenKey (&KeyHandle,
632 KEY_ALL_ACCESS,
633 &ObjectAttributes);
634 if (!NT_SUCCESS(Status))
635 {
636 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
637 return FALSE;
638 }
639
640 Status = NtSetValueKey (KeyHandle,
641 &ValueName,
642 0,
643 REG_SZ,
644 (PVOID)InstallPath->Buffer,
645 InstallPath->Length);
646 NtClose(KeyHandle);
647 if (!NT_SUCCESS(Status))
648 {
649 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
650 return FALSE;
651 }
652
653 return TRUE;
654 }
655
656 BOOLEAN
657 SetMountedDeviceValue(CHAR Letter, ULONG Signature, LARGE_INTEGER StartingOffset)
658 {
659 OBJECT_ATTRIBUTES ObjectAttributes;
660 WCHAR ValueNameBuffer[16];
661 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\MountedDevices");
662 UNICODE_STRING ValueName;
663 REG_DISK_MOUNT_INFO MountInfo;
664 NTSTATUS Status;
665 HANDLE KeyHandle;
666
667 swprintf(ValueNameBuffer, L"\\DosDevices\\%C:", Letter);
668 RtlInitUnicodeString(&ValueName, ValueNameBuffer);
669
670 InitializeObjectAttributes (&ObjectAttributes,
671 &KeyName,
672 OBJ_CASE_INSENSITIVE,
673 NULL,
674 NULL);
675 Status = NtOpenKey (&KeyHandle,
676 KEY_ALL_ACCESS,
677 &ObjectAttributes);
678 if (!NT_SUCCESS(Status))
679 {
680 Status = NtCreateKey(&KeyHandle,
681 KEY_ALL_ACCESS,
682 &ObjectAttributes,
683 0,
684 NULL,
685 REG_OPTION_NON_VOLATILE,
686 NULL);
687 }
688
689 if (!NT_SUCCESS(Status))
690 {
691 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
692 return FALSE;
693 }
694
695 MountInfo.Signature = Signature;
696 MountInfo.StartingOffset = StartingOffset;
697 Status = NtSetValueKey (KeyHandle,
698 &ValueName,
699 0,
700 REG_BINARY,
701 (PVOID)&MountInfo,
702 sizeof(MountInfo));
703 NtClose(KeyHandle);
704 if (!NT_SUCCESS(Status))
705 {
706 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
707 return FALSE;
708 }
709
710 return TRUE;
711 }
712
713 /* EOF */