Implemented the import of default registry settings from .inf files.

This is based on Wine's setupapi implementation by Alexandre Julliard.

svn path=/trunk/; revision=4341
This commit is contained in:
Eric Kohl 2003-03-18 20:39:49 +00:00
parent 1b53680503
commit 3c2e048a81
3 changed files with 630 additions and 2 deletions

View file

@ -31,11 +31,623 @@
#include "usetup.h"
#include "registry.h"
#include "infcache.h"
#define FLG_ADDREG_DELREG_BIT 0x00008000
#define FLG_ADDREG_BINVALUETYPE 0x00000001
#define FLG_ADDREG_NOCLOBBER 0x00000002
#define FLG_ADDREG_DELVAL 0x00000004
#define FLG_ADDREG_APPEND 0x00000008
#define FLG_ADDREG_KEYONLY 0x00000010
#define FLG_ADDREG_OVERWRITEONLY 0x00000020
#define FLG_ADDREG_64BITKEY 0x00001000
#define FLG_ADDREG_KEYONLY_COMMON 0x00002000
#define FLG_ADDREG_32BITKEY 0x00004000
#define FLG_ADDREG_TYPE_SZ 0x00000000
#define FLG_ADDREG_TYPE_MULTI_SZ 0x00010000
#define FLG_ADDREG_TYPE_EXPAND_SZ 0x00020000
#define FLG_ADDREG_TYPE_BINARY (0x00000000 | FLG_ADDREG_BINVALUETYPE)
#define FLG_ADDREG_TYPE_DWORD (0x00010000 | FLG_ADDREG_BINVALUETYPE)
#define FLG_ADDREG_TYPE_NONE (0x00020000 | FLG_ADDREG_BINVALUETYPE)
#define FLG_ADDREG_TYPE_MASK (0xFFFF0000 | FLG_ADDREG_BINVALUETYPE)
#define FLG_DELREG_VALUE (0x00000000)
#define FLG_DELREG_TYPE_MASK FLG_ADDREG_TYPE_MASK
#define FLG_DELREG_TYPE_SZ FLG_ADDREG_TYPE_SZ
#define FLG_DELREG_TYPE_MULTI_SZ FLG_ADDREG_TYPE_MULTI_SZ
#define FLG_DELREG_TYPE_EXPAND_SZ FLG_ADDREG_TYPE_EXPAND_SZ
#define FLG_DELREG_TYPE_BINARY FLG_ADDREG_TYPE_BINARY
#define FLG_DELREG_TYPE_DWORD FLG_ADDREG_TYPE_DWORD
#define FLG_DELREG_TYPE_NONE FLG_ADDREG_TYPE_NONE
#define FLG_DELREG_64BITKEY FLG_ADDREG_64BITKEY
#define FLG_DELREG_KEYONLY_COMMON FLG_ADDREG_KEYONLY_COMMON
#define FLG_DELREG_32BITKEY FLG_ADDREG_32BITKEY
#define FLG_DELREG_OPERATION_MASK (0x000000FE)
#define FLG_DELREG_MULTI_SZ_DELSTRING (FLG_DELREG_TYPE_MULTI_SZ | FLG_ADDREG_DELREG_BIT | 0x00000002)
/* FUNCTIONS ****************************************************************/
static BOOLEAN
GetRootKey (PWCHAR Name)
{
if (!_wcsicmp (Name, L"HKCR"))
{
wcscpy (Name, L"\\Registry\\Machine\\SOFTWARE\\Classes\\");
return TRUE;
}
if (!_wcsicmp (Name, L"HKCU"))
{
wcscpy (Name, L"\\Registry\\User\\.DEFAULT\\");
return TRUE;
}
if (!_wcsicmp (Name, L"HKLM"))
{
wcscpy (Name, L"\\Registry\\Machine\\");
return TRUE;
}
if (!_wcsicmp (Name, L"HKU"))
{
wcscpy (Name, L"\\Registry\\User\\");
return TRUE;
}
#if 0
if (!_wcsicmp (Name, L"HKR"))
return FALSE;
#endif
return FALSE;
}
/***********************************************************************
* append_multi_sz_value
*
* Append a multisz string to a multisz registry value.
*/
#if 0
static void
append_multi_sz_value (HANDLE hkey,
const WCHAR *value,
const WCHAR *strings,
DWORD str_size )
{
DWORD size, type, total;
WCHAR *buffer, *p;
if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return;
if (type != REG_MULTI_SZ) return;
if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (size + str_size) * sizeof(WCHAR) ))) return;
if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
/* compare each string against all the existing ones */
total = size;
while (*strings)
{
int len = strlenW(strings) + 1;
for (p = buffer; *p; p += strlenW(p) + 1)
if (!strcmpiW( p, strings )) break;
if (!*p) /* not found, need to append it */
{
memcpy( p, strings, len * sizeof(WCHAR) );
p[len] = 0;
total += len;
}
strings += len;
}
if (total != size)
{
TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer) );
RegSetValueExW( hkey, value, 0, REG_MULTI_SZ, (BYTE *)buffer, total );
}
done:
HeapFree( GetProcessHeap(), 0, buffer );
}
#endif
/***********************************************************************
* delete_multi_sz_value
*
* Remove a string from a multisz registry value.
*/
#if 0
static void delete_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *string )
{
DWORD size, type;
WCHAR *buffer, *src, *dst;
if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return;
if (type != REG_MULTI_SZ) return;
/* allocate double the size, one for value before and one for after */
if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size * 2 * sizeof(WCHAR) ))) return;
if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
src = buffer;
dst = buffer + size;
while (*src)
{
int len = strlenW(src) + 1;
if (strcmpiW( src, string ))
{
memcpy( dst, src, len * sizeof(WCHAR) );
dst += len;
}
src += len;
}
*dst++ = 0;
if (dst != buffer + 2*size) /* did we remove something? */
{
TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer + size) );
RegSetValueExW( hkey, value, 0, REG_MULTI_SZ,
(BYTE *)(buffer + size), dst - (buffer + size) );
}
done:
HeapFree( GetProcessHeap(), 0, buffer );
}
#endif
/***********************************************************************
* do_reg_operation
*
* Perform an add/delete registry operation depending on the flags.
*/
static BOOLEAN
do_reg_operation(HANDLE KeyHandle,
PUNICODE_STRING ValueName,
PINFCONTEXT Context,
ULONG Flags)
{
WCHAR EmptyStr = (WCHAR)0;
ULONG Type;
ULONG Size;
if (Flags & (FLG_ADDREG_DELREG_BIT | FLG_ADDREG_DELVAL)) /* deletion */
{
#if 0
if (ValueName && !(flags & FLG_DELREG_KEYONLY_COMMON))
{
if ((Flags & FLG_DELREG_MULTI_SZ_DELSTRING) == FLG_DELREG_MULTI_SZ_DELSTRING)
{
WCHAR *str;
if (!SetupGetStringFieldW( context, 5, NULL, 0, &size ) || !size) return TRUE;
if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE;
SetupGetStringFieldW( context, 5, str, size, NULL );
delete_multi_sz_value( hkey, value, str );
HeapFree( GetProcessHeap(), 0, str );
}
else
{
RegDeleteValueW( hkey, value );
}
}
else
{
RegDeleteKeyW( hkey, NULL );
}
#endif
return TRUE;
}
if (Flags & (FLG_ADDREG_KEYONLY | FLG_ADDREG_KEYONLY_COMMON))
return TRUE;
#if 0
if (Flags & (FLG_ADDREG_NOCLOBBER | FLG_ADDREG_OVERWRITEONLY))
{
BOOL exists = !RegQueryValueExW( hkey, value, NULL, NULL, NULL, NULL );
if (exists && (flags & FLG_ADDREG_NOCLOBBER))
return TRUE;
if (!exists & (flags & FLG_ADDREG_OVERWRITEONLY))
return TRUE;
}
#endif
switch (Flags & FLG_ADDREG_TYPE_MASK)
{
case FLG_ADDREG_TYPE_SZ:
Type = REG_SZ;
break;
case FLG_ADDREG_TYPE_MULTI_SZ:
Type = REG_MULTI_SZ;
break;
case FLG_ADDREG_TYPE_EXPAND_SZ:
Type = REG_EXPAND_SZ;
break;
case FLG_ADDREG_TYPE_BINARY:
Type = REG_BINARY;
break;
case FLG_ADDREG_TYPE_DWORD:
Type = REG_DWORD;
break;
case FLG_ADDREG_TYPE_NONE:
Type = REG_NONE;
break;
default:
Type = Flags >> 16;
break;
}
if (!(Flags & FLG_ADDREG_BINVALUETYPE) ||
(Type == REG_DWORD && InfGetFieldCount (Context) == 5))
{
PWCHAR Str = NULL;
if (Type == REG_MULTI_SZ)
{
if (!InfGetMultiSzField (Context, 5, NULL, 0, &Size))
Size = 0;
if (Size)
{
Str = RtlAllocateHeap (ProcessHeap, 0, Size * sizeof(WCHAR));
if (Str == NULL)
return FALSE;
InfGetMultiSzField (Context, 5, Str, Size, NULL);
}
if (Flags & FLG_ADDREG_APPEND)
{
if (Str == NULL)
return TRUE;
// append_multi_sz_value( hkey, value, str, size );
RtlFreeHeap (ProcessHeap, 0, Str);
return TRUE;
}
/* else fall through to normal string handling */
}
else
{
if (!InfGetStringField (Context, 5, NULL, 0, &Size))
Size = 0;
if (Size)
{
Str = RtlAllocateHeap (ProcessHeap, 0, Size * sizeof(WCHAR));
if (Str == NULL)
return FALSE;
InfGetStringField (Context, 5, Str, Size, NULL);
}
}
if (Type == REG_DWORD)
{
ULONG dw = Str ? wcstol (Str, NULL, 16) : 0;
DPRINT1("setting dword %wZ to %lx\n", &ValueName, dw);
NtSetValueKey (KeyHandle,
ValueName,
0,
Type,
(PVOID)&dw,
(ULONG)sizeof(dw));
}
else
{
DPRINT1("setting value %wZ to %S\n", ValueName, Str);
if (Str)
{
NtSetValueKey (KeyHandle,
ValueName,
0,
Type,
(PVOID)Str,
Size * sizeof(WCHAR));
}
else
{
NtSetValueKey (KeyHandle,
ValueName,
0,
Type,
(PVOID)&EmptyStr,
sizeof(WCHAR));
}
}
RtlFreeHeap (ProcessHeap, 0, Str);
}
else /* get the binary data */
{
PUCHAR Data = NULL;
if (!InfGetBinaryField (Context, 5, NULL, 0, &Size))
Size = 0;
if (Size)
{
Data = RtlAllocateHeap (ProcessHeap, 0, Size);
if (Data == NULL)
return FALSE;
DPRINT1("setting binary data %wZ len %lu\n", ValueName, Size);
InfGetBinaryField (Context, 5, Data, Size, NULL);
}
NtSetValueKey (KeyHandle,
ValueName,
0,
Type,
(PVOID)Data,
Size);
RtlFreeHeap (ProcessHeap, 0, Data);
return TRUE;
}
return TRUE;
}
NTSTATUS
CreateNestedKey (PHANDLE KeyHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes)
{
OBJECT_ATTRIBUTES LocalObjectAttributes;
UNICODE_STRING LocalKeyName;
ULONG Disposition;
NTSTATUS Status;
ULONG FullNameLength;
ULONG Length;
PWCHAR Ptr;
HANDLE LocalKeyHandle;
Status = NtCreateKey (KeyHandle,
KEY_ALL_ACCESS,
ObjectAttributes,
0,
NULL,
0,
&Disposition);
DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes->ObjectName, Status);
if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
return Status;
/* Copy object attributes */
RtlCopyMemory (&LocalObjectAttributes,
ObjectAttributes,
sizeof(OBJECT_ATTRIBUTES));
RtlCreateUnicodeString (&LocalKeyName,
ObjectAttributes->ObjectName->Buffer);
LocalObjectAttributes.ObjectName = &LocalKeyName;
FullNameLength = LocalKeyName.Length / sizeof(WCHAR);
/* Remove the last part of the key name and try to create the key again. */
while (Status == STATUS_OBJECT_NAME_NOT_FOUND)
{
Ptr = wcsrchr (LocalKeyName.Buffer, '\\');
if (Ptr == NULL || Ptr == LocalKeyName.Buffer)
{
Status = STATUS_UNSUCCESSFUL;
break;
}
*Ptr = (WCHAR)0;
LocalKeyName.Length = wcslen (LocalKeyName.Buffer) * sizeof(WCHAR);
Status = NtCreateKey (&LocalKeyHandle,
KEY_ALL_ACCESS,
&LocalObjectAttributes,
0,
NULL,
0,
&Disposition);
DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
}
if (!NT_SUCCESS(Status))
{
RtlFreeUnicodeString (&LocalKeyName);
return Status;
}
/* Add removed parts of the key name and create them too. */
Length = wcslen (LocalKeyName.Buffer);
while (TRUE)
{
if (Length == FullNameLength)
{
Status == STATUS_SUCCESS;
*KeyHandle = LocalKeyHandle;
break;
}
NtClose (LocalKeyHandle);
LocalKeyName.Buffer[Length] = L'\\';
Length = wcslen (LocalKeyName.Buffer);
LocalKeyName.Length = Length * sizeof(WCHAR);
Status = NtCreateKey (&LocalKeyHandle,
KEY_ALL_ACCESS,
&LocalObjectAttributes,
0,
NULL,
0,
&Disposition);
DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
if (!NT_SUCCESS(Status))
break;
}
RtlFreeUnicodeString (&LocalKeyName);
return Status;
}
/***********************************************************************
* registry_callback
*
* Called once for each AddReg and DelReg entry in a given section.
*/
static BOOLEAN
registry_callback (HINF hInf, PCWSTR Section, BOOLEAN Delete)
{
OBJECT_ATTRIBUTES ObjectAttributes;
WCHAR Buffer[MAX_INF_STRING_LENGTH];
UNICODE_STRING Name;
UNICODE_STRING Value;
PUNICODE_STRING ValuePtr;
NTSTATUS Status;
ULONG Flags;
ULONG Length;
INFCONTEXT Context;
HANDLE KeyHandle;
BOOLEAN Ok;
Ok = InfFindFirstLine (hInf, Section, NULL, &Context);
for (;Ok; Ok = InfFindNextLine (&Context, &Context))
{
/* get root */
if (!InfGetStringField (&Context, 1, Buffer, MAX_INF_STRING_LENGTH, NULL))
continue;
if (!GetRootKey (Buffer))
continue;
/* get key */
Length = wcslen (Buffer);
if (!InfGetStringField (&Context, 2, Buffer + Length, MAX_INF_STRING_LENGTH - Length, NULL))
*Buffer = 0;
DPRINT1("KeyName: <%S>\n", Buffer);
/* get flags */
if (!InfGetIntField (&Context, 4, (PLONG)&Flags))
Flags = 0;
DPRINT1("Flags: %lx\n", Flags);
if (!Delete)
{
if (Flags & FLG_ADDREG_DELREG_BIT)
continue; /* ignore this entry */
}
else
{
if (!Flags)
Flags = FLG_ADDREG_DELREG_BIT;
else if (!(Flags & FLG_ADDREG_DELREG_BIT))
continue; /* ignore this entry */
}
RtlInitUnicodeString (&Name,
Buffer);
InitializeObjectAttributes (&ObjectAttributes,
&Name,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
if (Delete || (Flags & FLG_ADDREG_OVERWRITEONLY))
{
Status = NtOpenKey (&KeyHandle,
KEY_ALL_ACCESS,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtOpenKey(%wZ) failed (Status %lx)\n", &Name, Status);
continue; /* ignore if it doesn't exist */
}
}
else
{
Status = CreateNestedKey (&KeyHandle,
KEY_ALL_ACCESS,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DPRINT1("CreateNestedKey(%wZ) failed (Status %lx)\n", &Name, Status);
continue;
}
}
/* get value name */
if (InfGetStringField (&Context, 3, Buffer, MAX_INF_STRING_LENGTH, NULL))
{
RtlInitUnicodeString (&Value,
Buffer);
ValuePtr = &Value;
}
else
{
ValuePtr = NULL;
}
/* and now do it */
if (!do_reg_operation (KeyHandle, ValuePtr, &Context, Flags))
{
NtClose (KeyHandle);
return FALSE;
}
NtClose (KeyHandle);
}
return TRUE;
}
BOOLEAN
ImportRegistryData(PWSTR Filename)
{
WCHAR FileNameBuffer[MAX_PATH];
UNICODE_STRING FileName;
HINF hInf;
NTSTATUS Status;
ULONG ErrorLine;
/* Load inf file from install media. */
wcscpy(FileNameBuffer, SourceRootPath.Buffer);
wcscat(FileNameBuffer, L"\\install\\");
wcscat(FileNameBuffer, Filename);
RtlInitUnicodeString(&FileName,
FileNameBuffer);
Status = InfOpenFile(&hInf,
&FileName,
&ErrorLine);
if (!NT_SUCCESS(Status))
{
DPRINT1("InfOpenFile() failed (Status %lx)\n", Status);
return FALSE;
}
if (!registry_callback (hInf, L"AddReg", FALSE))
{
DPRINT1("registry_callback() failed\n");
}
InfCloseFile (hInf);
return TRUE;
}
NTSTATUS
SetupUpdateRegistry(VOID)
{
@ -45,7 +657,6 @@ SetupUpdateRegistry(VOID)
HANDLE KeyHandle;
NTSTATUS Status;
RtlInitUnicodeStringFromLiteral(&KeyName,
L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control");
InitializeObjectAttributes(&ObjectAttributes,
@ -68,6 +679,7 @@ SetupUpdateRegistry(VOID)
NtClose(KeyHandle);
#if 0
/* Create '\Registry\Machine\System\Setup' key */
RtlInitUnicodeStringFromLiteral(&KeyName,
L"\\Registry\\Machine\\SYSTEM\\Setup");
@ -92,7 +704,18 @@ SetupUpdateRegistry(VOID)
/* FIXME: Create value 'SystemSetupInProgress' */
NtClose(KeyHandle);
#endif
SetStatusText(" Importing hivesys.inf...");
if (!ImportRegistryData (L"hivesys.inf"))
{
DPRINT1("ImportRegistryData (\"hivesys.inf\") failed\n");
}
SetStatusText(" Done...");
return STATUS_SUCCESS;
}

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: registry.h,v 1.1 2003/03/08 19:29:09 ekohl Exp $
/* $Id: registry.h,v 1.2 2003/03/18 20:39:49 ekohl Exp $
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS text-mode setup
* FILE: subsys/system/usetup/registry.h
@ -30,6 +30,9 @@
NTSTATUS
SetupUpdateRegistry(VOID);
BOOLEAN
ImportRegistryData(PWSTR Filename);
#endif /* __REGISTRY_H__ */
/* EOF */

View file

@ -37,6 +37,8 @@
extern HANDLE ProcessHeap;
extern UNICODE_STRING SourceRootPath;
#endif /* __USETUP_H__*/