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; }