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.
diff --git a/server/main.c b/server/main.c
index b582a03..f92c852 100644
--- a/server/main.c
+++ b/server/main.c
@@ -76,6 +76,7 @@
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 3015064..cda7bfe 100644
--- a/server/object.c
+++ b/server/object.c
@@ -51,7 +51,7 @@
{
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 *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 66ce781..f90d8ac 100644
--- a/server/object.h
+++ b/server/object.h
@@ -174,6 +174,7 @@
/* 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 bd12532..8ae7169 100644
--- a/server/registry.c
+++ b/server/registry.c
@@ -67,12 +67,27 @@
#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 @@
/* 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 @@
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 @@
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 @@
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 @@
{
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 @@
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 @@
}
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 @@
}
}
+/* 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 @@
}
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 @@
{
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 7f0cf64..3c619a4 100644
--- a/server/request.c
+++ b/server/request.c
@@ -72,6 +72,7 @@
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 @@
}
/* 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 @@
}
/* 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 @@
}
/* 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 1615f84..3ad0d33 100644
--- a/server/request.h
+++ b/server/request.h
@@ -28,6 +28,9 @@
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 8a59ca2..7c9ae9e 100644
--- a/server/thread.h
+++ b/server/thread.h
@@ -107,9 +107,10 @@
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; }