diff --git a/files/profile.c b/files/profile.c index 6ac5db73aef..bdbd121de21 100644 --- a/files/profile.c +++ b/files/profile.c @@ -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; diff --git a/server/main.c b/server/main.c index b582a03c899..f92c852a28b 100644 --- a/server/main.c +++ b/server/main.c @@ -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() ); diff --git a/server/object.c b/server/object.c index 301506451ae..cda7bfefd5b 100644 --- a/server/object.c +++ b/server/object.c @@ -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; } diff --git a/server/object.h b/server/object.h index 66ce78196d2..f90d8ac6821 100644 --- a/server/object.h +++ b/server/object.h @@ -174,6 +174,7 @@ extern int get_page_size(void); /* registry functions */ +extern void init_registry(void); extern void close_registry(void); /* atom functions */ diff --git a/server/registry.c b/server/registry.c index bd125320f37..8ae7169b769 100644 --- a/server/registry.c +++ b/server/registry.c @@ -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; @@ -826,104 +842,38 @@ static void delete_value( struct key *key, const WCHAR *name ) key->values = new_val; key->nb_values = nb_values; } -} - -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) + p = special_root_names[hkey - HKEY_SPECIAL_ROOT_FIRST]; + i = 0; + while (*p) keyname[i++] = *p++; + + if (hkey == HKEY_CURRENT_USER) /* this one is special */ { - /* 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 }; + /* get the current user name */ + char buffer[10]; + struct passwd *pwd = getpwuid( getuid() ); - 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 ); + if (pwd) p = pwd->pw_name; + else + { + sprintf( buffer, "%ld", (long) getuid() ); + p = buffer; } - 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: - { - /* 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; - else - { - sprintf( buffer, "%ld", (long) getuid() ); - p = buffer; - } - len = strlen(p); - if ((name = mem_alloc( (len+1) * sizeof(WCHAR) ))) - { - 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); + while (*p && i < sizeof(keyname)/sizeof(WCHAR)-1) keyname[i++] = *p++; } - if (key) + keyname[i++] = 0; + + if ((key = create_key( root_key, keyname, i*sizeof(WCHAR), NULL, 0, time(NULL), &dummy ))) { - root_keys[hkey - HKEY_ROOT_FIRST] = key; + special_root_keys[hkey - HKEY_SPECIAL_ROOT_FIRST] = key; key->flags |= KEY_ROOT; } return key; @@ -934,10 +884,13 @@ 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 ); - grab_object( key ); + if (!(key = special_root_keys[hkey - HKEY_SPECIAL_ROOT_FIRST])) + key = create_root_key( hkey ); + else + grab_object( key ); } else key = (struct key *)get_handle_obj( current->process, hkey, access, &key_ops ); @@ -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 */ diff --git a/server/request.c b/server/request.c index 7f0cf646679..3c619a4e508 100644 --- a/server/request.c +++ b/server/request.c @@ -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) diff --git a/server/request.h b/server/request.h index 1615f84ef74..3ad0d3304ab 100644 --- a/server/request.h +++ b/server/request.h @@ -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 ); diff --git a/server/thread.h b/server/thread.h index 8a59ca2eb0b..7c9ae9ebbb1 100644 --- a/server/thread.h +++ b/server/thread.h @@ -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; }