| /* | |
| * Registry Functions | |
| * | |
| * Copyright 1996 Marcus Meissner | |
| * Copyright 1998 Matthew Becker | |
| * Copyright 1999 Sylvain St-Germain | |
| * | |
| * December 21, 1997 - Kevin Cozens | |
| * Fixed bugs in the _w95_loadreg() function. Added extra information | |
| * regarding the format of the Windows '95 registry files. | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| * | |
| * TODO | |
| * Security access | |
| * Option handling | |
| * Time for RegEnumKey*, RegQueryInfoKey* | |
| */ | |
| #include "config.h" | |
| #include "wine/port.h" | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <stdarg.h> | |
| #include <stdio.h> | |
| #ifdef HAVE_UNISTD_H | |
| # include <unistd.h> | |
| #endif | |
| #include <errno.h> | |
| #include <sys/types.h> | |
| #include <sys/stat.h> | |
| #include <fcntl.h> | |
| #ifdef HAVE_SYS_IOCTL_H | |
| #include <sys/ioctl.h> | |
| #endif | |
| #ifdef HAVE_LINUX_HDREG_H | |
| # include <linux/hdreg.h> | |
| #endif | |
| #define NONAMELESSUNION | |
| #define NONAMELESSSTRUCT | |
| #include "ntstatus.h" | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "winerror.h" | |
| #include "winioctl.h" | |
| #include "ntddscsi.h" | |
| #include "wine/library.h" | |
| #include "wine/server.h" | |
| #include "wine/unicode.h" | |
| #include "wine/debug.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(reg); | |
| /****************************************************************************** | |
| * allocate_default_keys [Internal] | |
| * Registry initialisation, allocates some default keys. | |
| */ | |
| static ULONG allocate_default_keys(void) | |
| { | |
| static const WCHAR StatDataW[] = {'D','y','n','D','a','t','a','\\', | |
| 'P','e','r','f','S','t','a','t','s','\\', | |
| 'S','t','a','t','D','a','t','a',0}; | |
| static const WCHAR ConfigManagerW[] = {'D','y','n','D','a','t','a','\\', | |
| 'C','o','n','f','i','g',' ','M','a','n','a','g','e','r','\\', | |
| 'E','n','u','m',0}; | |
| static const WCHAR Clone[] = {'M','a','c','h','i','n','e','\\', | |
| 'S','y','s','t','e','m','\\', | |
| 'C','l','o','n','e',0}; | |
| HKEY hkey; | |
| ULONG dispos; | |
| OBJECT_ATTRIBUTES attr; | |
| UNICODE_STRING nameW; | |
| attr.Length = sizeof(attr); | |
| attr.RootDirectory = 0; | |
| attr.ObjectName = &nameW; | |
| attr.Attributes = 0; | |
| attr.SecurityDescriptor = NULL; | |
| attr.SecurityQualityOfService = NULL; | |
| RtlInitUnicodeString( &nameW, StatDataW ); | |
| if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &dispos )) NtClose( hkey ); | |
| if (dispos == REG_OPENED_EXISTING_KEY) | |
| return dispos; /* someone else already loaded the registry */ | |
| RtlInitUnicodeString( &nameW, ConfigManagerW ); | |
| if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey ); | |
| /* this key is generated when the nt-core booted successfully */ | |
| RtlInitUnicodeString( &nameW, Clone ); | |
| if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey ); | |
| return dispos; | |
| } | |
| /****************************************************************** | |
| * init_cdrom_registry | |
| * | |
| * Initializes registry to contain scsi info about the cdrom in NT. | |
| * All devices (even not real scsi ones) have this info in NT. | |
| * TODO: for now it only works for non scsi devices | |
| * NOTE: programs usually read these registry entries after sending the | |
| * IOCTL_SCSI_GET_ADDRESS ioctl to the cdrom | |
| */ | |
| static void init_cdrom_registry( HANDLE handle ) | |
| { | |
| OBJECT_ATTRIBUTES attr; | |
| UNICODE_STRING nameW; | |
| WCHAR dataW[50]; | |
| DWORD lenW; | |
| char buffer[40]; | |
| DWORD value; | |
| const char *data; | |
| HKEY scsiKey; | |
| HKEY portKey; | |
| HKEY busKey; | |
| HKEY targetKey; | |
| DWORD disp; | |
| IO_STATUS_BLOCK io; | |
| SCSI_ADDRESS scsi_addr; | |
| if (NtDeviceIoControlFile( handle, 0, NULL, NULL, &io, IOCTL_SCSI_GET_ADDRESS, | |
| NULL, 0, &scsi_addr, sizeof(scsi_addr) )) | |
| return; | |
| attr.Length = sizeof(attr); | |
| attr.RootDirectory = 0; | |
| attr.ObjectName = &nameW; | |
| attr.Attributes = 0; | |
| attr.SecurityDescriptor = NULL; | |
| attr.SecurityQualityOfService = NULL; | |
| /* Ensure there is Scsi key */ | |
| if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\HARDWARE\\DEVICEMAP\\Scsi" ) || | |
| NtCreateKey( &scsiKey, KEY_ALL_ACCESS, &attr, 0, | |
| NULL, REG_OPTION_VOLATILE, &disp )) | |
| { | |
| ERR("Cannot create DEVICEMAP\\Scsi registry key\n" ); | |
| return; | |
| } | |
| RtlFreeUnicodeString( &nameW ); | |
| snprintf(buffer,sizeof(buffer),"Scsi Port %d",scsi_addr.PortNumber); | |
| attr.RootDirectory = scsiKey; | |
| if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) || | |
| NtCreateKey( &portKey, KEY_ALL_ACCESS, &attr, 0, | |
| NULL, REG_OPTION_VOLATILE, &disp )) | |
| { | |
| ERR("Cannot create DEVICEMAP\\Scsi Port registry key\n" ); | |
| return; | |
| } | |
| RtlFreeUnicodeString( &nameW ); | |
| RtlCreateUnicodeStringFromAsciiz( &nameW, "Driver" ); | |
| data = "atapi"; | |
| RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data)); | |
| NtSetValueKey( portKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW ); | |
| RtlFreeUnicodeString( &nameW ); | |
| value = 10; | |
| RtlCreateUnicodeStringFromAsciiz( &nameW, "FirstBusTimeScanInMs" ); | |
| NtSetValueKey( portKey,&nameW, 0, REG_DWORD, (BYTE *)&value, sizeof(DWORD)); | |
| RtlFreeUnicodeString( &nameW ); | |
| value = 0; | |
| #ifdef HDIO_GET_DMA | |
| { | |
| int fd, dma; | |
| if (!wine_server_handle_to_fd( handle, 0, &fd, NULL )) | |
| { | |
| if (ioctl(fd,HDIO_GET_DMA, &dma) != -1) value = dma; | |
| wine_server_release_fd( handle, fd ); | |
| } | |
| } | |
| #endif | |
| RtlCreateUnicodeStringFromAsciiz( &nameW, "DMAEnabled" ); | |
| NtSetValueKey( portKey,&nameW, 0, REG_DWORD, (BYTE *)&value, sizeof(DWORD)); | |
| RtlFreeUnicodeString( &nameW ); | |
| snprintf(buffer,40,"Scsi Bus %d", scsi_addr.PathId); | |
| attr.RootDirectory = portKey; | |
| if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) || | |
| NtCreateKey( &busKey, KEY_ALL_ACCESS, &attr, 0, | |
| NULL, REG_OPTION_VOLATILE, &disp )) | |
| { | |
| ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus registry key\n" ); | |
| return; | |
| } | |
| RtlFreeUnicodeString( &nameW ); | |
| attr.RootDirectory = busKey; | |
| if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Initiator Id 255" ) || | |
| NtCreateKey( &targetKey, KEY_ALL_ACCESS, &attr, 0, | |
| NULL, REG_OPTION_VOLATILE, &disp )) | |
| { | |
| ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus\\Initiator Id 255 registry key\n" ); | |
| return; | |
| } | |
| RtlFreeUnicodeString( &nameW ); | |
| NtClose( targetKey ); | |
| snprintf(buffer,40,"Target Id %d", scsi_addr.TargetId); | |
| attr.RootDirectory = busKey; | |
| if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) || | |
| NtCreateKey( &targetKey, KEY_ALL_ACCESS, &attr, 0, | |
| NULL, REG_OPTION_VOLATILE, &disp )) | |
| { | |
| ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus 0\\Target Id registry key\n" ); | |
| return; | |
| } | |
| RtlFreeUnicodeString( &nameW ); | |
| RtlCreateUnicodeStringFromAsciiz( &nameW, "Type" ); | |
| data = "CdRomPeripheral"; | |
| RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data)); | |
| NtSetValueKey( targetKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW ); | |
| RtlFreeUnicodeString( &nameW ); | |
| /* FIXME - maybe read the real identifier?? */ | |
| RtlCreateUnicodeStringFromAsciiz( &nameW, "Identifier" ); | |
| data = "Wine CDROM"; | |
| RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data)); | |
| NtSetValueKey( targetKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW ); | |
| RtlFreeUnicodeString( &nameW ); | |
| /* FIXME - we always use Cdrom0 - do not know about the nt behaviour */ | |
| RtlCreateUnicodeStringFromAsciiz( &nameW, "DeviceName" ); | |
| data = "Cdrom0"; | |
| RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data)); | |
| NtSetValueKey( targetKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW ); | |
| RtlFreeUnicodeString( &nameW ); | |
| NtClose( targetKey ); | |
| NtClose( busKey ); | |
| NtClose( portKey ); | |
| NtClose( scsiKey ); | |
| } | |
| /* create the hardware registry branch */ | |
| static void create_hardware_branch(void) | |
| { | |
| int i; | |
| HANDLE handle; | |
| char drive[] = "\\\\.\\A:"; | |
| /* create entries for cdroms */ | |
| for (i = 0; i < 26; i++) | |
| { | |
| drive[4] = 'A' + i; | |
| handle = CreateFileA( drive, 0, 0, NULL, OPEN_EXISTING, 0, 0 ); | |
| if (handle == INVALID_HANDLE_VALUE) continue; | |
| init_cdrom_registry( handle ); | |
| CloseHandle( handle ); | |
| } | |
| } | |
| /* convert the drive type entries from the old format to the new one */ | |
| static void convert_drive_types(void) | |
| { | |
| static const WCHAR TypeW[] = {'T','y','p','e',0}; | |
| static const WCHAR drive_types_keyW[] = {'M','a','c','h','i','n','e','\\', | |
| 'S','o','f','t','w','a','r','e','\\', | |
| 'W','i','n','e','\\', | |
| 'D','r','i','v','e','s',0 }; | |
| WCHAR driveW[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\', | |
| 'W','i','n','e','\\','W','i','n','e','\\', | |
| 'C','o','n','f','i','g','\\','D','r','i','v','e',' ','A',0}; | |
| char tmp[32*sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)]; | |
| OBJECT_ATTRIBUTES attr; | |
| UNICODE_STRING nameW; | |
| DWORD dummy; | |
| ULONG disp; | |
| HKEY hkey_old, hkey_new; | |
| int i; | |
| attr.Length = sizeof(attr); | |
| attr.RootDirectory = 0; | |
| attr.ObjectName = &nameW; | |
| attr.Attributes = 0; | |
| attr.SecurityDescriptor = NULL; | |
| attr.SecurityQualityOfService = NULL; | |
| RtlInitUnicodeString( &nameW, drive_types_keyW ); | |
| if (NtCreateKey( &hkey_new, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &disp )) return; | |
| if (disp != REG_CREATED_NEW_KEY) | |
| { | |
| NtClose( hkey_new ); | |
| return; | |
| } | |
| for (i = 0; i < 26; i++) | |
| { | |
| RtlInitUnicodeString( &nameW, driveW ); | |
| nameW.Buffer[(nameW.Length / sizeof(WCHAR)) - 1] = 'A' + i; | |
| if (NtOpenKey( &hkey_old, KEY_ALL_ACCESS, &attr ) != STATUS_SUCCESS) continue; | |
| RtlInitUnicodeString( &nameW, TypeW ); | |
| if (!NtQueryValueKey( hkey_old, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy )) | |
| { | |
| WCHAR valueW[] = {'A',':',0}; | |
| WCHAR *type = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data; | |
| valueW[0] = 'A' + i; | |
| RtlInitUnicodeString( &nameW, valueW ); | |
| NtSetValueKey( hkey_new, &nameW, 0, REG_SZ, type, (strlenW(type) + 1) * sizeof(WCHAR) ); | |
| MESSAGE( "Converted drive type to new entry HKLM\\Software\\Wine\\Drives \"%c:\" = %s\n", | |
| 'A' + i, debugstr_w(type) ); | |
| } | |
| NtClose( hkey_old ); | |
| } | |
| NtClose( hkey_new ); | |
| } | |
| /* convert the environment variable entries from the old format to the new one */ | |
| static void convert_environment( HKEY hkey_current_user ) | |
| { | |
| static const WCHAR wineW[] = {'M','a','c','h','i','n','e','\\', | |
| 'S','o','f','t','w','a','r','e','\\', | |
| 'W','i','n','e','\\','W','i','n','e','\\', | |
| 'C','o','n','f','i','g','\\','W','i','n','e',0}; | |
| static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0}; | |
| static const WCHAR systemW[] = {'s','y','s','t','e','m',0}; | |
| static const WCHAR windirW[] = {'w','i','n','d','i','r',0}; | |
| static const WCHAR systemrootW[] = {'S','y','s','t','e','m','r','o','o','t',0}; | |
| static const WCHAR winsysdirW[] = {'w','i','n','s','y','s','d','i','r',0}; | |
| static const WCHAR envW[] = {'E','n','v','i','r','o','n','m','e','n','t',0}; | |
| static const WCHAR tempW[] = {'T','E','M','P',0}; | |
| static const WCHAR tmpW[] = {'T','M','P',0}; | |
| static const WCHAR pathW[] = {'P','A','T','H',0}; | |
| static const WCHAR profileW[] = {'p','r','o','f','i','l','e',0}; | |
| static const WCHAR userprofileW[] = {'U','S','E','R','P','R','O','F','I','L','E',0}; | |
| char buffer[1024*sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)]; | |
| KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; | |
| OBJECT_ATTRIBUTES attr; | |
| UNICODE_STRING nameW; | |
| DWORD dummy; | |
| ULONG disp; | |
| HKEY hkey_old, hkey_env; | |
| attr.Length = sizeof(attr); | |
| attr.RootDirectory = 0; | |
| attr.ObjectName = &nameW; | |
| attr.Attributes = 0; | |
| attr.SecurityDescriptor = NULL; | |
| attr.SecurityQualityOfService = NULL; | |
| RtlInitUnicodeString( &nameW, wineW ); | |
| if (NtOpenKey( &hkey_old, KEY_ALL_ACCESS, &attr ) != STATUS_SUCCESS) return; | |
| attr.RootDirectory = hkey_current_user; | |
| RtlInitUnicodeString( &nameW, envW ); | |
| if (NtCreateKey( &hkey_env, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &disp )) | |
| { | |
| NtClose( hkey_old ); | |
| return; | |
| } | |
| /* Test for existence of TEMP */ | |
| RtlInitUnicodeString( &nameW, tempW ); | |
| if (NtQueryValueKey(hkey_env, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy )) | |
| { | |
| /* convert TEMP */ | |
| RtlInitUnicodeString( &nameW, tempW ); | |
| if (!NtQueryValueKey( hkey_old, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy )) | |
| { | |
| NtSetValueKey( hkey_env, &nameW, 0, info->Type, info->Data, info->DataLength ); | |
| RtlInitUnicodeString( &nameW, tmpW ); | |
| NtSetValueKey( hkey_env, &nameW, 0, info->Type, info->Data, info->DataLength ); | |
| MESSAGE( "Converted temp dir to new entry HKCU\\Environment \"TEMP\" = %s\n", | |
| debugstr_w( (WCHAR*)info->Data ) ); | |
| } | |
| } | |
| /* Test for existence of PATH */ | |
| RtlInitUnicodeString( &nameW, pathW ); | |
| if (NtQueryValueKey(hkey_env, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy )) | |
| { | |
| /* convert PATH */ | |
| RtlInitUnicodeString( &nameW, pathW ); | |
| if (!NtQueryValueKey( hkey_old, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy )) | |
| { | |
| NtSetValueKey( hkey_env, &nameW, 0, info->Type, info->Data, info->DataLength ); | |
| MESSAGE( "Converted path dir to new entry HKCU\\Environment \"PATH\" = %s\n", | |
| debugstr_w( (WCHAR*)info->Data ) ); | |
| } | |
| } | |
| /* Test for existence of USERPROFILE */ | |
| RtlInitUnicodeString( &nameW, userprofileW ); | |
| if (NtQueryValueKey(hkey_env, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy )) | |
| { | |
| /* convert USERPROFILE */ | |
| RtlInitUnicodeString( &nameW, profileW ); | |
| if (!NtQueryValueKey( hkey_old, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy )) | |
| { | |
| RtlInitUnicodeString( &nameW, userprofileW ); | |
| NtSetValueKey( hkey_env, &nameW, 0, info->Type, info->Data, info->DataLength ); | |
| MESSAGE( "Converted profile dir to new entry HKCU\\Environment \"USERPROFILE\" = %s\n", | |
| debugstr_w( (WCHAR*)info->Data ) ); | |
| } | |
| } | |
| /* Test for existence of windir */ | |
| RtlInitUnicodeString( &nameW, windirW ); | |
| if (NtQueryValueKey(hkey_env, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy )) | |
| { | |
| /* convert windir */ | |
| RtlInitUnicodeString( &nameW, windowsW ); | |
| if (!NtQueryValueKey( hkey_old, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy )) | |
| { | |
| RtlInitUnicodeString( &nameW, windirW ); | |
| NtSetValueKey( hkey_env, &nameW, 0, info->Type, info->Data, info->DataLength ); | |
| RtlInitUnicodeString( &nameW, systemrootW ); | |
| NtSetValueKey( hkey_env, &nameW, 0, info->Type, info->Data, info->DataLength ); | |
| MESSAGE( "Converted windows dir to new entry HKCU\\Environment \"windir\" = %s\n", | |
| debugstr_w( (WCHAR*)info->Data ) ); | |
| } | |
| } | |
| /* Test for existence of winsysdir */ | |
| RtlInitUnicodeString( &nameW, winsysdirW ); | |
| if (NtQueryValueKey(hkey_env, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy )) | |
| { | |
| /* convert winsysdir */ | |
| RtlInitUnicodeString( &nameW, systemW ); | |
| if (!NtQueryValueKey( hkey_old, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &dummy )) | |
| { | |
| RtlInitUnicodeString( &nameW, winsysdirW ); | |
| NtSetValueKey( hkey_env, &nameW, 0, info->Type, info->Data, info->DataLength ); | |
| MESSAGE( "Converted system dir to new entry HKCU\\Environment \"winsysdir\" = %s\n", | |
| debugstr_w( (WCHAR*)info->Data ) ); | |
| } | |
| } | |
| NtClose( hkey_old ); | |
| NtClose( hkey_env ); | |
| } | |
| /* load all registry (native and global and home) */ | |
| void SHELL_LoadRegistry( void ) | |
| { | |
| HKEY hkey_current_user; | |
| OBJECT_ATTRIBUTES attr; | |
| UNICODE_STRING nameW; | |
| ULONG dispos; | |
| TRACE("(void)\n"); | |
| attr.Length = sizeof(attr); | |
| attr.RootDirectory = 0; | |
| attr.ObjectName = &nameW; | |
| attr.Attributes = 0; | |
| attr.SecurityDescriptor = NULL; | |
| attr.SecurityQualityOfService = NULL; | |
| dispos = allocate_default_keys(); | |
| if (dispos == REG_OPENED_EXISTING_KEY) | |
| return; /* someone else already loaded the registry */ | |
| RtlOpenCurrentUser( KEY_ALL_ACCESS, &hkey_current_user ); | |
| /* load home registries */ | |
| SERVER_START_REQ( load_user_registries ) | |
| { | |
| req->hkey = hkey_current_user; | |
| wine_server_call( req ); | |
| } | |
| SERVER_END_REQ; | |
| /* create hardware registry branch */ | |
| create_hardware_branch(); | |
| /* convert keys from config file to new registry format */ | |
| convert_drive_types(); | |
| convert_environment( hkey_current_user ); | |
| NtClose(hkey_current_user); | |
| } |