diff --git a/reactos/subsys/system/usetup/registry.c b/reactos/subsys/system/usetup/registry.c index 0b3a75ffcc4..0d68a64ade7 100644 --- a/reactos/subsys/system/usetup/registry.c +++ b/reactos/subsys/system/usetup/registry.c @@ -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; } diff --git a/reactos/subsys/system/usetup/registry.h b/reactos/subsys/system/usetup/registry.h index f0f0043a968..be853eb4ce6 100644 --- a/reactos/subsys/system/usetup/registry.h +++ b/reactos/subsys/system/usetup/registry.h @@ -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 */ diff --git a/reactos/subsys/system/usetup/usetup.h b/reactos/subsys/system/usetup/usetup.h index b4fc855720d..ebb83c636a6 100644 --- a/reactos/subsys/system/usetup/usetup.h +++ b/reactos/subsys/system/usetup/usetup.h @@ -37,6 +37,8 @@ extern HANDLE ProcessHeap; +extern UNICODE_STRING SourceRootPath; + #endif /* __USETUP_H__*/