Added a real root key and simplified creation of the HKEY_* special root keys.
Do not prefix all keys with the name of the top key when saving to a file. Try to load $WINEPREFIX/config into the Wine config branch at startup.
This commit is contained in:
parent
b8ba84590b
commit
6c8d9171cd
|
@ -971,6 +971,7 @@ int PROFILE_LoadWineIni(void)
|
|||
const char *p;
|
||||
FILE *f;
|
||||
HKEY hKeySW;
|
||||
DWORD disp;
|
||||
|
||||
/* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
|
||||
if (RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine", &hKeySW ))
|
||||
|
@ -980,7 +981,7 @@ int PROFILE_LoadWineIni(void)
|
|||
}
|
||||
RegCloseKey( hKeySW );
|
||||
if (RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config", 0, NULL,
|
||||
REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &wine_profile_key, NULL ))
|
||||
REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &wine_profile_key, &disp ))
|
||||
{
|
||||
ERR("Cannot create config registry key\n" );
|
||||
return 0;
|
||||
|
@ -1019,11 +1020,23 @@ int PROFILE_LoadWineIni(void)
|
|||
lstrcpynA(PROFILE_WineIniUsed,WINE_INI_GLOBAL,MAX_PATHNAME_LEN);
|
||||
goto found;
|
||||
}
|
||||
|
||||
if (disp == REG_OPENED_EXISTING_KEY) return 1; /* loaded by the server */
|
||||
|
||||
MESSAGE( "Can't open configuration file %s or $HOME%s\n",
|
||||
WINE_INI_GLOBAL, PROFILE_WineIniName );
|
||||
return 0;
|
||||
|
||||
found:
|
||||
|
||||
if (disp == REG_OPENED_EXISTING_KEY)
|
||||
{
|
||||
MESSAGE( "Warning: configuration loaded by the server from %s/config,\n"
|
||||
" file %s was ignored.\n", get_config_dir(), PROFILE_WineIniUsed );
|
||||
fclose( f );
|
||||
return 1;
|
||||
}
|
||||
|
||||
PROFILE_RegistryLoad( wine_profile_key, f );
|
||||
fclose( f );
|
||||
return 1;
|
||||
|
|
|
@ -76,6 +76,7 @@ int main( int argc, char *argv[] )
|
|||
setvbuf( stderr, NULL, _IOLBF, 0 );
|
||||
|
||||
if (debug_level) fprintf( stderr, "Server: starting (pid=%ld)\n", (long) getpid() );
|
||||
init_registry();
|
||||
select_loop();
|
||||
close_registry();
|
||||
if (debug_level) fprintf( stderr, "Server: exiting (pid=%ld)\n", (long) getpid() );
|
||||
|
|
|
@ -51,7 +51,7 @@ void *mem_alloc( size_t size )
|
|||
{
|
||||
void *ptr = malloc( size );
|
||||
if (ptr) memset( ptr, 0x55, size );
|
||||
else if (current) set_error( STATUS_NO_MEMORY );
|
||||
else set_error( STATUS_NO_MEMORY );
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ void *memdup( const void *data, size_t len )
|
|||
{
|
||||
void *ptr = malloc( len );
|
||||
if (ptr) memcpy( ptr, data, len );
|
||||
else if (current) set_error( STATUS_NO_MEMORY );
|
||||
else set_error( STATUS_NO_MEMORY );
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -174,6 +174,7 @@ extern int get_page_size(void);
|
|||
|
||||
/* registry functions */
|
||||
|
||||
extern void init_registry(void);
|
||||
extern void close_registry(void);
|
||||
|
||||
/* atom functions */
|
||||
|
|
|
@ -67,12 +67,27 @@ struct key_value
|
|||
#define MIN_VALUES 8 /* min. number of allocated values per key */
|
||||
|
||||
|
||||
/* the root keys */
|
||||
#define HKEY_ROOT_FIRST HKEY_CLASSES_ROOT
|
||||
#define HKEY_ROOT_LAST HKEY_DYN_DATA
|
||||
#define NB_ROOT_KEYS (HKEY_ROOT_LAST - HKEY_ROOT_FIRST + 1)
|
||||
#define IS_ROOT_HKEY(h) (((h) >= HKEY_ROOT_FIRST) && ((h) <= HKEY_ROOT_LAST))
|
||||
static struct key *root_keys[NB_ROOT_KEYS];
|
||||
/* the special root keys */
|
||||
#define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
|
||||
#define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
|
||||
#define NB_SPECIAL_ROOT_KEYS (HKEY_SPECIAL_ROOT_LAST - HKEY_SPECIAL_ROOT_FIRST + 1)
|
||||
#define IS_SPECIAL_ROOT_HKEY(h) (((h) >= HKEY_SPECIAL_ROOT_FIRST) && ((h) <= HKEY_SPECIAL_ROOT_LAST))
|
||||
static struct key *special_root_keys[NB_SPECIAL_ROOT_KEYS];
|
||||
|
||||
/* the real root key */
|
||||
static struct key *root_key;
|
||||
|
||||
/* the special root key names */
|
||||
static const char * const special_root_names[NB_SPECIAL_ROOT_KEYS] =
|
||||
{
|
||||
"Machine\\Software\\Classes", /* HKEY_CLASSES_ROOT */
|
||||
"User\\", /* we append the user name dynamically */ /* HKEY_CURRENT_USER */
|
||||
"Machine", /* HKEY_LOCAL_MACHINE */
|
||||
"User", /* HKEY_USERS */
|
||||
"PerfData", /* HKEY_PERFORMANCE_DATA */
|
||||
"Machine\\System\\CurrentControlSet\\HardwardProfiles\\Current", /* HKEY_CURRENT_CONFIG */
|
||||
"DynData" /* HKEY_DYN_DATA */
|
||||
};
|
||||
|
||||
|
||||
/* keys saving level */
|
||||
|
@ -148,7 +163,7 @@ static inline char to_hex( char ch )
|
|||
/* dump the full path of a key */
|
||||
static void dump_path( struct key *key, struct key *base, FILE *f )
|
||||
{
|
||||
if (key->parent && key != base)
|
||||
if (key->parent && key->parent != base)
|
||||
{
|
||||
dump_path( key->parent, base, f );
|
||||
fprintf( f, "\\\\" );
|
||||
|
@ -220,7 +235,7 @@ static void save_subkeys( struct key *key, struct key *base, FILE *f )
|
|||
if ((key->level >= saving_level) && ((key->last_value >= 0) || (key->last_subkey == -1)))
|
||||
{
|
||||
fprintf( f, "\n[" );
|
||||
dump_path( key, base, f );
|
||||
if (key != base) dump_path( key, base, f );
|
||||
fprintf( f, "] %ld\n", key->modif );
|
||||
for (i = 0; i <= key->last_value; i++) dump_value( &key->values[i], f );
|
||||
}
|
||||
|
@ -491,6 +506,7 @@ static struct key *create_key( struct key *key, const WCHAR *name, size_t maxlen
|
|||
set_error( STATUS_CHILD_MUST_BE_VOLATILE );
|
||||
return NULL;
|
||||
}
|
||||
if (!modif) modif = time(NULL);
|
||||
|
||||
path = get_path_token( name, maxlen );
|
||||
*created = 0;
|
||||
|
@ -828,60 +844,21 @@ static void delete_value( struct key *key, const WCHAR *name )
|
|||
}
|
||||
}
|
||||
|
||||
static struct key *get_hkey_obj( int hkey, unsigned int access );
|
||||
|
||||
static struct key *create_root_key( int hkey )
|
||||
{
|
||||
int dummy;
|
||||
WCHAR keyname[80];
|
||||
int i, dummy;
|
||||
struct key *key;
|
||||
const char *p;
|
||||
|
||||
switch(hkey)
|
||||
{
|
||||
/* the two real root-keys */
|
||||
case HKEY_LOCAL_MACHINE:
|
||||
{
|
||||
static const WCHAR name[] = { 'M','A','C','H','I','N','E',0 };
|
||||
key = alloc_key( name, time(NULL) );
|
||||
}
|
||||
break;
|
||||
case HKEY_USERS:
|
||||
{
|
||||
static const WCHAR name[] = { 'U','S','E','R',0 };
|
||||
key = alloc_key( name, time(NULL) );
|
||||
}
|
||||
break;
|
||||
/* special subkeys */
|
||||
case HKEY_CLASSES_ROOT:
|
||||
{
|
||||
static const WCHAR name[] =
|
||||
{ 'S','O','F','T','W','A','R','E','\\','C','l','a','s','s','e','s',0 };
|
||||
p = special_root_names[hkey - HKEY_SPECIAL_ROOT_FIRST];
|
||||
i = 0;
|
||||
while (*p) keyname[i++] = *p++;
|
||||
|
||||
struct key *root = get_hkey_obj( HKEY_LOCAL_MACHINE, 0 );
|
||||
assert( root );
|
||||
key = create_key( root, name, sizeof(name), NULL, 0, time(NULL), &dummy );
|
||||
release_object( root );
|
||||
}
|
||||
break;
|
||||
case HKEY_CURRENT_CONFIG:
|
||||
{
|
||||
static const WCHAR name[] = {
|
||||
'S','Y','S','T','E','M','\\',
|
||||
'C','U','R','R','E','N','T','C','O','N','T','R','O','L','S','E','T','\\',
|
||||
'H','A','R','D','W','A','R','E','P','R','O','F','I','L','E','S','\\',
|
||||
'C','U','R','R','E','N','T',0};
|
||||
struct key *root = get_hkey_obj( HKEY_LOCAL_MACHINE, 0 );
|
||||
assert( root );
|
||||
key = create_key( root, name, sizeof(name), NULL, 0, time(NULL), &dummy );
|
||||
release_object( root );
|
||||
}
|
||||
break;
|
||||
case HKEY_CURRENT_USER:
|
||||
if (hkey == HKEY_CURRENT_USER) /* this one is special */
|
||||
{
|
||||
/* get the current user name */
|
||||
int i, len;
|
||||
WCHAR *name;
|
||||
char buffer[10];
|
||||
const char *p;
|
||||
struct passwd *pwd = getpwuid( getuid() );
|
||||
|
||||
if (pwd) p = pwd->pw_name;
|
||||
|
@ -890,40 +867,13 @@ static struct key *create_root_key( int hkey )
|
|||
sprintf( buffer, "%ld", (long) getuid() );
|
||||
p = buffer;
|
||||
}
|
||||
len = strlen(p);
|
||||
if ((name = mem_alloc( (len+1) * sizeof(WCHAR) )))
|
||||
while (*p && i < sizeof(keyname)/sizeof(WCHAR)-1) keyname[i++] = *p++;
|
||||
}
|
||||
keyname[i++] = 0;
|
||||
|
||||
if ((key = create_key( root_key, keyname, i*sizeof(WCHAR), NULL, 0, time(NULL), &dummy )))
|
||||
{
|
||||
struct key *root = get_hkey_obj( HKEY_USERS, 0 );
|
||||
assert( root );
|
||||
for (i = 0; i <= len; i++) name[i] = p[i];
|
||||
key = create_key( root, name, (len+1) * sizeof(WCHAR),
|
||||
NULL, 0, time(NULL), &dummy );
|
||||
release_object( root );
|
||||
free( name );
|
||||
}
|
||||
else key = NULL;
|
||||
}
|
||||
break;
|
||||
/* dynamically generated keys */
|
||||
case HKEY_PERFORMANCE_DATA:
|
||||
{
|
||||
static const WCHAR name[] = { 'P','E','R','F','D','A','T','A',0 }; /* FIXME */
|
||||
key = alloc_key( name, time(NULL) );
|
||||
}
|
||||
break;
|
||||
case HKEY_DYN_DATA:
|
||||
{
|
||||
static const WCHAR name[] = { 'D','Y','N','D','A','T','A',0 }; /* FIXME */
|
||||
key = alloc_key( name, time(NULL) );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
key = NULL;
|
||||
assert(0);
|
||||
}
|
||||
if (key)
|
||||
{
|
||||
root_keys[hkey - HKEY_ROOT_FIRST] = key;
|
||||
special_root_keys[hkey - HKEY_SPECIAL_ROOT_FIRST] = key;
|
||||
key->flags |= KEY_ROOT;
|
||||
}
|
||||
return key;
|
||||
|
@ -934,9 +884,12 @@ static struct key *get_hkey_obj( int hkey, unsigned int access )
|
|||
{
|
||||
struct key *key;
|
||||
|
||||
if (IS_ROOT_HKEY(hkey))
|
||||
if (!hkey) return (struct key *)grab_object( root_key );
|
||||
if (IS_SPECIAL_ROOT_HKEY(hkey))
|
||||
{
|
||||
if (!(key = root_keys[hkey - HKEY_ROOT_FIRST])) key = create_root_key( hkey );
|
||||
if (!(key = special_root_keys[hkey - HKEY_SPECIAL_ROOT_FIRST]))
|
||||
key = create_root_key( hkey );
|
||||
else
|
||||
grab_object( key );
|
||||
}
|
||||
else
|
||||
|
@ -1160,8 +1113,10 @@ static struct key_value *parse_value_name( struct key *key, const char *buffer,
|
|||
if ((*len = parse_strW( (WCHAR *)info->tmp, &maxlen, buffer + 1, '\"' )) == -1) goto error;
|
||||
(*len)++; /* for initial quote */
|
||||
}
|
||||
while (isspace(buffer[*len])) (*len)++;
|
||||
if (buffer[*len] != '=') goto error;
|
||||
(*len)++;
|
||||
while (isspace(buffer[*len])) (*len)++;
|
||||
return insert_value( key, (WCHAR *)info->tmp );
|
||||
|
||||
error:
|
||||
|
@ -1251,12 +1206,12 @@ static int get_prefix_len( struct key *key, const char *name, struct file_load_i
|
|||
}
|
||||
for (p = (WCHAR *)info->tmp; *p; p++) if (*p == '\\') break;
|
||||
*p = 0;
|
||||
for (res = 1; key; res++)
|
||||
for (res = 1; key != root_key; res++)
|
||||
{
|
||||
if (!strcmpiW( (WCHAR *)info->tmp, key->name )) break;
|
||||
key = key->parent;
|
||||
}
|
||||
if (!key) res = 0; /* no matching name */
|
||||
if (key == root_key) res = 0; /* no matching name */
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -1342,6 +1297,51 @@ static void load_registry( struct key *key, int handle )
|
|||
}
|
||||
}
|
||||
|
||||
/* registry initialisation */
|
||||
void init_registry(void)
|
||||
{
|
||||
static const WCHAR root_name[] = { 0 };
|
||||
static const WCHAR config_name[] =
|
||||
{ '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',0 };
|
||||
|
||||
char *filename;
|
||||
const char *config;
|
||||
FILE *f;
|
||||
|
||||
/* create the root key */
|
||||
root_key = alloc_key( root_name, time(NULL) );
|
||||
assert( root_key );
|
||||
root_key->flags |= KEY_ROOT;
|
||||
|
||||
/* load the config file */
|
||||
config = get_config_dir();
|
||||
if (!(filename = malloc( strlen(config) + 8 ))) fatal_error( "out of memory\n" );
|
||||
strcpy( filename, config );
|
||||
strcat( filename, "/config" );
|
||||
if ((f = fopen( filename, "r" )))
|
||||
{
|
||||
struct key *key;
|
||||
int dummy;
|
||||
|
||||
/* create the config key */
|
||||
if (!(key = create_key( root_key, config_name, sizeof(config_name),
|
||||
NULL, 0, time(NULL), &dummy )))
|
||||
fatal_error( "could not create config key\n" );
|
||||
key->flags |= KEY_VOLATILE;
|
||||
|
||||
load_keys( key, f );
|
||||
fclose( f );
|
||||
if (get_error() == STATUS_NOT_REGISTRY_FILE)
|
||||
fatal_error( "%s is not a valid registry file\n", filename );
|
||||
if (get_error())
|
||||
fatal_error( "loading %s failed with error %x\n", filename, get_error() );
|
||||
|
||||
release_object( key );
|
||||
}
|
||||
free( filename );
|
||||
}
|
||||
|
||||
/* update the level of the parents of a key (only needed for the old format) */
|
||||
static int update_level( struct key *key )
|
||||
{
|
||||
|
@ -1513,10 +1513,7 @@ void close_registry(void)
|
|||
}
|
||||
release_object( save_branch_info[i].key );
|
||||
}
|
||||
for (i = 0; i < NB_ROOT_KEYS; i++)
|
||||
{
|
||||
if (root_keys[i]) release_object( root_keys[i] );
|
||||
}
|
||||
release_object( root_key );
|
||||
}
|
||||
|
||||
|
||||
|
@ -1581,7 +1578,7 @@ DECL_HANDLER(close_key)
|
|||
{
|
||||
int hkey = req->hkey;
|
||||
/* ignore attempts to close a root key */
|
||||
if (!IS_ROOT_HKEY(hkey)) close_handle( current->process, hkey );
|
||||
if (hkey && !IS_SPECIAL_ROOT_HKEY(hkey)) close_handle( current->process, hkey );
|
||||
}
|
||||
|
||||
/* enumerate registry subkeys */
|
||||
|
|
|
@ -72,6 +72,7 @@ static const struct object_ops master_socket_ops =
|
|||
|
||||
|
||||
struct thread *current = NULL; /* thread handling the current request */
|
||||
int global_error = 0; /* global error code for when no thread is current */
|
||||
|
||||
static struct master_socket *master_socket; /* the master socket object */
|
||||
|
||||
|
@ -103,8 +104,7 @@ void fatal_protocol_error( struct thread *thread, const char *err, ... )
|
|||
}
|
||||
|
||||
/* die on a fatal error */
|
||||
static void fatal_error( const char *err, ... ) WINE_NORETURN;
|
||||
static void fatal_error( const char *err, ... )
|
||||
void fatal_error( const char *err, ... )
|
||||
{
|
||||
va_list args;
|
||||
|
||||
|
@ -116,8 +116,7 @@ static void fatal_error( const char *err, ... )
|
|||
}
|
||||
|
||||
/* die on a fatal error */
|
||||
static void fatal_perror( const char *err, ... ) WINE_NORETURN;
|
||||
static void fatal_perror( const char *err, ... )
|
||||
void fatal_perror( const char *err, ... )
|
||||
{
|
||||
va_list args;
|
||||
|
||||
|
@ -306,7 +305,7 @@ static void master_socket_destroy( struct object *obj )
|
|||
}
|
||||
|
||||
/* return the configuration directory ($WINEPREFIX or $HOME/.wine) */
|
||||
static const char *get_config_dir(void)
|
||||
const char *get_config_dir(void)
|
||||
{
|
||||
static char *confdir;
|
||||
if (!confdir)
|
||||
|
|
|
@ -28,6 +28,9 @@ extern void fatal_protocol_error( struct thread *thread,
|
|||
extern void fatal_protocol_error( struct thread *thread, const char *err, ... );
|
||||
#endif
|
||||
|
||||
extern void fatal_error( const char *err, ... ) WINE_NORETURN;
|
||||
extern void fatal_perror( const char *err, ... ) WINE_NORETURN;
|
||||
extern const char *get_config_dir(void);
|
||||
extern void read_request( struct thread *thread );
|
||||
extern int write_request( struct thread *thread );
|
||||
extern void set_reply_fd( struct thread *thread, int pass_fd );
|
||||
|
|
|
@ -107,9 +107,10 @@ extern int read_thread_int( struct thread *thread, const int *addr, int *data );
|
|||
extern int write_thread_int( struct thread *thread, int *addr, int data, unsigned int mask );
|
||||
extern void *get_thread_ip( struct thread *thread );
|
||||
|
||||
extern int global_error; /* global error code for when no thread is current */
|
||||
|
||||
static inline int get_error(void) { return current->error; }
|
||||
static inline void set_error( int err ) { current->error = err; }
|
||||
static inline int get_error(void) { return current ? current->error : global_error; }
|
||||
static inline void set_error( int err ) { global_error = err; if (current) current->error = err; }
|
||||
static inline void clear_error(void) { set_error(0); }
|
||||
|
||||
static inline void *get_thread_id( struct thread *thread ) { return thread; }
|
||||
|
|
Loading…
Reference in New Issue