Use symlinks in dosdevices/ for the drive devices too.
Store drive types in the registry instead of in the config file.
Added some more code to convert existing config to the new scheme.

diff --git a/dlls/kernel/Makefile.in b/dlls/kernel/Makefile.in
index 688c497..0f88667 100644
--- a/dlls/kernel/Makefile.in
+++ b/dlls/kernel/Makefile.in
@@ -19,7 +19,6 @@
 
 C_SRCS = \
 	$(TOPOBJDIR)/files/directory.c \
-	$(TOPOBJDIR)/files/drive.c \
 	$(TOPOBJDIR)/files/file.c \
 	$(TOPOBJDIR)/files/smb.c \
 	$(TOPOBJDIR)/misc/options.c \
diff --git a/dlls/kernel/process.c b/dlls/kernel/process.c
index 8ca5d1a..e5e3bd2 100644
--- a/dlls/kernel/process.c
+++ b/dlls/kernel/process.c
@@ -733,8 +733,8 @@
     /* Parse command line arguments */
     if (!info_size) OPTIONS_ParseOptions( argv );
 
-    /* initialise DOS drives */
-    if (!DRIVE_Init()) return FALSE;
+    /* Create device symlinks */
+    VOLUME_CreateDevices();
 
     /* initialise DOS directories */
     if (!DIR_Init()) return FALSE;
@@ -742,9 +742,6 @@
     /* registry initialisation */
     SHELL_LoadRegistry();
 
-    /* Create device symlinks */
-    VOLUME_CreateDevices();
-
     /* global boot finished, the rest is process-local */
     SERVER_START_REQ( boot_done )
     {
diff --git a/dlls/kernel/volume.c b/dlls/kernel/volume.c
index 421398c2..153ef17 100644
--- a/dlls/kernel/volume.c
+++ b/dlls/kernel/volume.c
@@ -167,35 +167,36 @@
 /* fetch the type of a drive from the registry */
 static UINT get_registry_drive_type( const WCHAR *root )
 {
+    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 };
     OBJECT_ATTRIBUTES attr;
     UNICODE_STRING nameW;
     HKEY hkey;
     DWORD dummy;
     UINT ret = DRIVE_UNKNOWN;
     char tmp[32 + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
-    WCHAR path[MAX_PATH];
-    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};
-    static const WCHAR TypeW[] = {'T','y','p','e',0};
+    WCHAR driveW[] = {'A',':',0};
 
-
-    if (!root)
-    {
-        GetCurrentDirectoryW( MAX_PATH, path );
-        root = path;
-    }
     attr.Length = sizeof(attr);
     attr.RootDirectory = 0;
     attr.ObjectName = &nameW;
     attr.Attributes = 0;
     attr.SecurityDescriptor = NULL;
     attr.SecurityQualityOfService = NULL;
-    RtlInitUnicodeString( &nameW, driveW );
-    nameW.Buffer[(nameW.Length / sizeof(WCHAR)) - 1] = root[0];
+    RtlInitUnicodeString( &nameW, drive_types_keyW );
     if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ) != STATUS_SUCCESS) return DRIVE_UNKNOWN;
 
-    RtlInitUnicodeString( &nameW, TypeW );
+    if (root) driveW[0] = root[0];
+    else
+    {
+        WCHAR path[MAX_PATH];
+        GetCurrentDirectoryW( MAX_PATH, path );
+        driveW[0] = path[0];
+    }
+
+    RtlInitUnicodeString( &nameW, driveW );
     if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
     {
         int i;
@@ -216,25 +217,99 @@
 
 
 /* create symlinks for the DOS drives; helper for VOLUME_CreateDevices */
-static int create_drives(void)
+static int create_drives( int devices_only )
 {
-    WCHAR name[3], rootW[MAX_PATHNAME_LEN];
+    static const WCHAR PathW[] = {'P','a','t','h',0};
+    static const WCHAR DeviceW[] = {'D','e','v','i','c','e',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};
+    OBJECT_ATTRIBUTES attr;
+    UNICODE_STRING nameW;
+    char tmp[1024*sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
+    char dest[1024];
+    WCHAR *p, name[3];
+    HKEY hkey;
+    DWORD dummy;
     int i, count = 0;
 
+    attr.Length = sizeof(attr);
+    attr.RootDirectory = 0;
+    attr.ObjectName = &nameW;
+    attr.Attributes = 0;
+    attr.SecurityDescriptor = NULL;
+    attr.SecurityQualityOfService = NULL;
+
+    /* create symlinks for the drive roots */
+
+    if (!devices_only) for (i = 0; i < 26; i++)
+    {
+        RtlInitUnicodeString( &nameW, driveW );
+        nameW.Buffer[(nameW.Length / sizeof(WCHAR)) - 1] = 'A' + i;
+        if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ) != STATUS_SUCCESS) continue;
+
+        RtlInitUnicodeString( &nameW, PathW );
+        if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
+        {
+            WCHAR path[1024];
+            WCHAR *data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
+            ExpandEnvironmentStringsW( data, path, sizeof(path)/sizeof(WCHAR) );
+
+            p = path + strlenW(path) - 1;
+            while ((p > path) && (*p == '/')) *p-- = '\0';
+
+            name[0] = 'a' + i;
+            name[1] = ':';
+            name[2] = 0;
+
+            if (path[0] != '/')
+            {
+                /* relative paths are relative to config dir */
+                memmove( path + 3, path, (strlenW(path) + 1) * sizeof(WCHAR) );
+                path[0] = '.';
+                path[1] = '.';
+                path[2] = '/';
+            }
+            if (DefineDosDeviceW( DDD_RAW_TARGET_PATH, name, path ))
+            {
+                WideCharToMultiByte(CP_UNIXCP, 0, path, -1, dest, sizeof(dest), NULL, NULL);
+                MESSAGE( "Created symlink %s/dosdevices/%c: -> %s\n",
+                         wine_get_config_dir(), 'a' + i, dest );
+                count++;
+            }
+        }
+        NtClose( hkey );
+    }
+
+    /* create symlinks for the drive devices */
+
     for (i = 0; i < 26; i++)
     {
-        const char *root = DRIVE_GetRoot( i );
-        if (!root) continue;
-        name[0] = 'a' + i;
-        name[1] = ':';
-        name[2] = 0;
-        if (MultiByteToWideChar( CP_UNIXCP, 0, root, -1, rootW, MAX_PATHNAME_LEN ) &&
-            DefineDosDeviceW( DDD_RAW_TARGET_PATH, name, rootW ))
+        RtlInitUnicodeString( &nameW, driveW );
+        nameW.Buffer[(nameW.Length / sizeof(WCHAR)) - 1] = 'A' + i;
+        if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ) != STATUS_SUCCESS) continue;
+
+        RtlInitUnicodeString( &nameW, DeviceW );
+        if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
         {
-            MESSAGE( "Created symlink %s/dosdevices/%c: -> %s\n", wine_get_config_dir(), 'a' + i, root );
-            count++;
+            char *path, *p;
+            WCHAR devname[] = {'A',':',':',0 };
+            WCHAR *data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
+            WideCharToMultiByte(CP_UNIXCP, 0, data, -1, dest, sizeof(dest), NULL, NULL);
+            path = get_dos_device_path( devname );
+            p = path + strlen(path);
+            p[-3] = 'a' + i;
+            if (!symlink( dest, path ))
+            {
+                MESSAGE( "Created symlink %s/dosdevices/%c:: -> %s\n",
+                         wine_get_config_dir(), 'a' + i, dest );
+                count++;
+            }
+            HeapFree( GetProcessHeap(), 0, path );
         }
+        NtClose( hkey );
     }
+
     return count;
 }
 
@@ -336,7 +411,7 @@
             }
             NtClose( hkey );
         }
-        count += create_drives();
+        count += create_drives( FALSE );
     }
     else
     {
@@ -351,13 +426,22 @@
             buffer[strlen(buffer)-2] = 'a' + i;
             if (!lstat( buffer, &st )) break;
         }
-        if (i == 26) count += create_drives();
+        if (i == 26) count += create_drives( FALSE );
+        else
+        {
+            strcat( buffer, ":" );
+            for (i = 0; i < 26; i++)
+            {
+                buffer[strlen(buffer)-3] = 'a' + i;
+                if (!lstat( buffer, &st )) break;
+            }
+            if (i == 26) count += create_drives( TRUE );
+        }
     }
 
     if (count)
-        MESSAGE( "\nYou can now remove the [SerialPorts] and [ParallelPorts] sections\n"
-                 "in your configuration file, as well as the \"Path=\" definitions in\n"
-                 "the drive sections, they are replaced by the above symlinks.\n\n" );
+        MESSAGE( "\nYou can now remove the [SerialPorts], [ParallelPorts], and [Drive] sections\n"
+                 "in your configuration file, they are replaced by the above symlinks.\n\n" );
 
     HeapFree( GetProcessHeap(), 0, buffer );
 }
diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c
index bf6ac26..3e35eac 100644
--- a/dlls/ntdll/directory.c
+++ b/dlls/ntdll/directory.c
@@ -840,7 +840,7 @@
     for (i = 0; i < name_len; i++)
         if (name[i] <= 32 || name[i] >= 127) return STATUS_OBJECT_NAME_NOT_FOUND;
 
-    unix_len = strlen(config_dir) + sizeof("/dosdevices/") + name_len;
+    unix_len = strlen(config_dir) + sizeof("/dosdevices/") + name_len + 1;
 
     if (!(unix_name = RtlAllocateHeap( GetProcessHeap(), 0, unix_len )))
         return STATUS_NO_MEMORY;
@@ -853,7 +853,11 @@
     dev[i] = 0;
 
     /* special case for drive devices */
-    if (name_len == 2 && dev[1] == ':') dev[1] = '|';
+    if (name_len == 2 && dev[1] == ':')
+    {
+        dev[i++] = ':';
+        dev[i] = 0;
+    }
 
     for (;;)
     {
diff --git a/documentation/samples/config b/documentation/samples/config
index a56b1a0..2ca0562 100644
--- a/documentation/samples/config
+++ b/documentation/samples/config
@@ -4,35 +4,6 @@
 ;; If you think it is necessary to show others your complete config for a
 ;; bug report, filter out empty lines and comments with
 ;; grep -v "^;" ~/.wine/config | grep '.'
-;;
-;; MS-DOS drives configuration
-;;
-;; Each section has the following format:
-;; [Drive X]
-;; "Path"="xxx"       (Unix path for drive root)
-;; "Type"="xxx"       (supported types are 'floppy', 'hd', 'cdrom' and 'network')
-;; "Device"="/dev/xx" (only if you want to allow raw device access)
-;;
-[Drive A]
-"Type" = "floppy"
-"Device" = "/dev/fd0"
-
-[Drive C]
-"Type" = "hd"
-
-[Drive D]
-"Type" = "cdrom"
-; make sure that device is correct and has proper permissions !
-"Device" = "/dev/cdrom"
-
-[Drive E]
-"Type" = "hd"
-
-[Drive F]
-"Type" = "network"
-
-[Drive Z]
-"Type" = "hd"
 
 [wine]
 "Windows" = "c:\\windows"
diff --git a/documentation/wine.conf.man b/documentation/wine.conf.man
index 58df5eb..3b8c180 100644
--- a/documentation/wine.conf.man
+++ b/documentation/wine.conf.man
@@ -1,5 +1,5 @@
 .\" -*- nroff -*-
-.TH WINE.CONF 5 "September 2003" "Version 20030911" "Wine Configuration File"
+.TH WINE.CONF 5 "April 2004" "Version 20040408" "Wine Configuration File"
 .SH NAME
 wine.conf \- Wine configuration file
 .SH DESCRIPTION
@@ -24,42 +24,12 @@
 The entry and value can be any text strings, included in double
 quotes; it can also contain references to environment variables
 surrounded by
-.I ${}.
+.I %
+signs.
 Inside the double quotes, special characters, backslashes and quotes
 must be escaped with backslashes. Supported section names and entries
 are listed below.
 .PP
-.B [Drive X]
-.br
-This section is used to specify the root directory and type of each emulated
-.B DOS
-drive, since most Windows applications require a DOS/MS-Windows based
-disk drive & directory scheme, which is either provided by a real
-DOS partition mounted somewhere or by some carefully crafted directory layout
-on a Unix file system ("no-windows fake installation").
-There is one such section for every drive you want to configure.
-.PP
-.I format: """Path""=""<rootdirectory>"""
-.br
-default: none
-.br
-If you mounted your dos partition as
-.I /dos
-and installed Microsoft Windows in
-C:\\WINDOWS (thus it shows up as /dos/WINDOWS), then you should specify
-.I """Path""=""/dos"""
-in the
-.I [Drive C]
-section in order to configure /dos as the drive root of drive C:.
-.PP
-.I format: """Type""=""<type>"""
-.br
-default: "hd"
-.br
-Used to specify the drive type this drive appears as in Windows
-or DOS programs; supported types are "floppy", "hd", "cdrom"
-and "network".
-.PP
 .B [wine]
 .br
 .I format: """windows""=""<directory>"""
@@ -331,11 +301,5 @@
 .TP
 .I $WINEPREFIX/config
 User-specific configuration file
-.TP
-.I $WINEPREFIX/dosdevices
-Directory containing the DOS device mappings. Each file in that
-directory is a symlink to the Unix device file implementing a given
-device. For instance, if COM1 is mapped to /dev/ttyS0 you'd have a
-symlink of the form $WINEPREFIX/dosdevices/com1 -> /dev/ttyS0.
 .SH "SEE ALSO"
 .BR wine (1)
diff --git a/documentation/wine.man.in b/documentation/wine.man.in
index 8f28b8e..f19b298 100644
--- a/documentation/wine.man.in
+++ b/documentation/wine.man.in
@@ -115,7 +115,8 @@
 .B wine
 stores its data (the default is 
 .I $HOME/.wine
-). This directory contains also the socket, which is used to communicate with the
+). This directory is also used to identify the socket which is used to
+communicate with the
 .I wineserver.
 All 
 .B wine
@@ -254,18 +255,59 @@
 .TP
 .I DISPLAY
 Specifies the X11 display to use.
-.SH CONFIGURATION FILE
-.B wine
-expects a configuration file (
+.SH FILES
+.TP
+.I @bindir@/wine
+The 
+.B wine 
+program loader.
+.TP
+.I @bindir@/wineconsole
+The 
+.B wine 
+program loader for CUI (console) applications.
+.TP
+.I @bindir@/wineserver
+The 
+.B wine 
+server 
+.TP 
+.I @bindir@/winedbg
+The 
+.B wine 
+debugger
+.TP 
+.I @bindir@/wineclipsrv
+The 
+.B wine 
+clipboard server
+.TP 
+.I @dlldir@
+Directory containing 
+.B wine's
+shared libraries 
+.TP
 .I $WINEPREFIX/config
-or
-.I ~/.wine/config
-if WINEPREFIX is not set), which must conform to the format specified
+User-specific configuration file, which must conform to the format specified
 in the
 .BR wine.conf (5)
 man page. A sample configuration file is documentation/samples/config in the 
 .B wine 
 source archive.
+.TP
+.I $WINEPREFIX/dosdevices
+Directory containing the DOS device mappings. Each file in that
+directory is a symlink to the Unix device file implementing a given
+device. For instance, if COM1 is mapped to /dev/ttyS0 you'd have a
+symlink of the form $WINEPREFIX/dosdevices/com1 -> /dev/ttyS0.
+.br
+DOS drives are also specified with symlinks; for instance if drive D:
+corresponds to the CDROM mounted at /mnt/cdrom, you'd have a symlink
+$WINEPREFIX/dosdevices/d: -> /mnt/cdrom. The Unix device corresponding
+to a DOS drive can be specified the same way, except with '::' instead
+of ':'. So for the previous example, if the CDROM device is mounted
+from /dev/hdc, the corresponding symlink would be
+$WINEPREFIX/dosdevices/d:: -> /dev/hdc.
 .SH AUTHORS
 .B wine
 is available thanks to the work of many developers. For a listing
@@ -276,7 +318,7 @@
 .B wine
 can be distributed under the terms of the LGPL license. A copy of the
 license is in the file
-.B LICENSE
+.B COPYING.LIB
 in the top-level directory of the source distribution.
 .SH BUGS
 .PP
@@ -326,45 +368,6 @@
 .B wine 
 mailing lists at
 .I http://www.winehq.org/forums
-.SH FILES
-.PD 0
-.TP
-.I @bindir@/wine
-The 
-.B wine 
-program loader.
-.TP
-.I @bindir@/wineconsole
-The 
-.B wine 
-program loader for CUI (console) applications.
-.TP
-.I @bindir@/wineserver
-The 
-.B wine 
-server 
-.TP 
-.I @bindir@/winedbg
-The 
-.B wine 
-debugger
-.TP 
-.I @bindir@/wineclipsrv
-The 
-.B wine 
-clipboard server
-.TP 
-.I @dlldir@
-Directory containing 
-.B wine's
-shared libraries 
-.TP
-.I ~/.wine/config
-User-specific configuration file
-.TP 
-.I ~/.wine
-Directory containing user specific data managed by 
-.B wine. 
 
 .SH "SEE ALSO"
 .BR wine.conf (5)
diff --git a/files/directory.c b/files/directory.c
index 92fe9f0..26b8776 100644
--- a/files/directory.c
+++ b/files/directory.c
@@ -44,6 +44,7 @@
 #include "winerror.h"
 #include "winreg.h"
 #include "winternl.h"
+#include "thread.h"
 #include "wine/unicode.h"
 #include "file.h"
 #include "wine/debug.h"
@@ -108,8 +109,6 @@
     char path[MAX_PATHNAME_LEN];
     WCHAR longpath[MAX_PATHNAME_LEN];
     WCHAR *tmp_dir, *profile_dir;
-    int drive;
-    const char *cwd;
     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','\\',
@@ -135,28 +134,6 @@
     static const WCHAR comspecW[] = {'C','O','M','S','P','E','C',0};
     static const WCHAR empty_strW[] = { 0 };
 
-    if (!getcwd( path, MAX_PATHNAME_LEN ))
-    {
-        perror( "Could not get current directory" );
-        return 0;
-    }
-    cwd = path;
-    if ((drive = DRIVE_FindDriveRoot( &cwd )) == -1)
-    {
-        MESSAGE("Warning: could not find wine config [Drive x] entry "
-            "for current working directory %s; "
-	    "starting in windows directory.\n", cwd );
-    }
-    else
-    {
-        longpath[0] = 'a' + drive;
-        longpath[1] = ':';
-        MultiByteToWideChar(CP_UNIXCP, 0, cwd, -1, longpath + 2, MAX_PATHNAME_LEN);
-        SetCurrentDirectoryW( longpath );
-        if(GetDriveTypeW(longpath)==DRIVE_CDROM)
-            chdir("/"); /* change to root directory so as not to lock cdroms */
-    }
-
     attr.Length = sizeof(attr);
     attr.RootDirectory = 0;
     attr.ObjectName = &nameW;
@@ -175,7 +152,25 @@
         return 0;
     }
 
-    if (drive == -1) SetCurrentDirectoryW( DIR_Windows );
+    if (!getcwd( path, MAX_PATHNAME_LEN ))
+    {
+        MESSAGE("Warning: could not get current Unix working directory, "
+                "starting in the Windows directory.\n" );
+        SetCurrentDirectoryW( DIR_Windows );
+    }
+    else
+    {
+        MultiByteToWideChar( CP_UNIXCP, 0, path, -1, longpath, MAX_PATHNAME_LEN);
+        GetFullPathNameW( longpath, MAX_PATHNAME_LEN, longpath, NULL );
+        if (!SetCurrentDirectoryW( longpath ))
+        {
+            MESSAGE("Warning: could not find DOS drive for current working directory '%s', "
+                    "starting in the Windows directory.\n", path );
+            SetCurrentDirectoryW( DIR_Windows );
+        }
+        else if (!NtCurrentTeb()->Peb->ProcessParameters->CurrentDirectory.Handle)
+            chdir("/"); /* change to root directory so as not to lock cdroms */
+    }
 
     /* Set the environment variables */
 
diff --git a/files/drive.c b/files/drive.c
deleted file mode 100644
index 94a56cf..0000000
--- a/files/drive.c
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- * DOS drives handling functions
- *
- * Copyright 1993 Erik Bos
- * Copyright 1996 Alexandre Julliard
- *
- * Label & serial number read support.
- *  (c) 1999 Petr Tomasek <tomasek@etf.cuni.cz>
- *  (c) 2000 Andreas Mohr (changes)
- *
- * 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
- */
-
-#include "config.h"
-#include "wine/port.h"
-
-#include <assert.h>
-#include <ctype.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
-#define NONAMELESSUNION
-#define NONAMELESSSTRUCT
-#include "ntstatus.h"
-#include "windef.h"
-#include "winbase.h"
-#include "winreg.h"
-#include "winternl.h"
-#include "wine/winbase16.h"   /* for GetCurrentTask */
-#include "winerror.h"
-#include "winioctl.h"
-#include "ntddstor.h"
-#include "ntddcdrm.h"
-#include "file.h"
-#include "wine/unicode.h"
-#include "wine/library.h"
-#include "wine/server.h"
-#include "wine/debug.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(dosfs);
-WINE_DECLARE_DEBUG_CHANNEL(file);
-
-typedef struct
-{
-    char     *root;      /* root dir in Unix format without trailing / */
-    char     *device;    /* raw device path */
-    dev_t     dev;       /* unix device number */
-    ino_t     ino;       /* unix inode number */
-} DOSDRIVE;
-
-
-#define MAX_DOS_DRIVES  26
-
-static DOSDRIVE DOSDrives[MAX_DOS_DRIVES];
-
-/* strdup on the process heap */
-inline static char *heap_strdup( const char *str )
-{
-    INT len = strlen(str) + 1;
-    LPSTR p = HeapAlloc( GetProcessHeap(), 0, len );
-    if (p) memcpy( p, str, len );
-    return p;
-}
-
-/***********************************************************************
- *           DRIVE_Init
- */
-int DRIVE_Init(void)
-{
-    int i, len, symlink_count = 0, count = 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};
-    WCHAR path[MAX_PATHNAME_LEN];
-    char tmp[MAX_PATHNAME_LEN*sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
-    struct stat drive_stat_buffer;
-    WCHAR *p;
-    DOSDRIVE *drive;
-    HKEY hkey;
-    DWORD dummy;
-    OBJECT_ATTRIBUTES attr;
-    UNICODE_STRING nameW;
-    char *root;
-    const char *config_dir = wine_get_config_dir();
-
-    static const WCHAR PathW[] = {'P','a','t','h',0};
-    static const WCHAR DeviceW[] = {'D','e','v','i','c','e',0};
-
-    attr.Length = sizeof(attr);
-    attr.RootDirectory = 0;
-    attr.ObjectName = &nameW;
-    attr.Attributes = 0;
-    attr.SecurityDescriptor = NULL;
-    attr.SecurityQualityOfService = NULL;
-
-    /* get the root of the drives from symlinks */
-
-    root = NULL;
-    for (i = 0, drive = DOSDrives; i < MAX_DOS_DRIVES; i++, drive++)
-    {
-        if (!root)
-        {
-            root = HeapAlloc( GetProcessHeap(), 0, strlen(config_dir) + sizeof("/dosdevices/a:") );
-            strcpy( root, config_dir );
-            strcat( root, "/dosdevices/a:" );
-        }
-        root[strlen(root)-2] = 'a' + i;
-        if (stat( root, &drive_stat_buffer ))
-        {
-            if (!lstat( root, &drive_stat_buffer))
-                MESSAGE("Could not stat %s (%s), ignoring drive %c:\n",
-                        root, strerror(errno), 'a' + i);
-            continue;
-        }
-        if (!S_ISDIR(drive_stat_buffer.st_mode))
-        {
-            MESSAGE("%s is not a directory, ignoring drive %c:\n", root, 'a' + i );
-            continue;
-        }
-        drive->root     = root;
-        drive->device   = NULL;
-        drive->dev      = drive_stat_buffer.st_dev;
-        drive->ino      = drive_stat_buffer.st_ino;
-        root = NULL;
-        symlink_count++;
-    }
-    if (root) HeapFree( GetProcessHeap(), 0, root );
-
-    /* now get the parameters from the config file */
-
-    for (i = 0, drive = DOSDrives; i < MAX_DOS_DRIVES; i++, drive++)
-    {
-        RtlInitUnicodeString( &nameW, driveW );
-        nameW.Buffer[(nameW.Length / sizeof(WCHAR)) - 1] = 'A' + i;
-        if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ) != STATUS_SUCCESS) continue;
-
-        /* Get the root path */
-        if (!symlink_count)
-        {
-            RtlInitUnicodeString( &nameW, PathW );
-            if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
-            {
-                WCHAR *data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
-                ExpandEnvironmentStringsW( data, path, sizeof(path)/sizeof(WCHAR) );
-
-                p = path + strlenW(path) - 1;
-                while ((p > path) && (*p == '/')) *p-- = '\0';
-
-                if (path[0] == '/')
-                {
-                    len = WideCharToMultiByte(CP_UNIXCP, 0, path, -1, NULL, 0, NULL, NULL);
-                    drive->root = HeapAlloc(GetProcessHeap(), 0, len);
-                    WideCharToMultiByte(CP_UNIXCP, 0, path, -1, drive->root, len, NULL, NULL);
-                }
-                else
-                {
-                    /* relative paths are relative to config dir */
-                    const char *config = wine_get_config_dir();
-                    len = strlen(config);
-                    len += WideCharToMultiByte(CP_UNIXCP, 0, path, -1, NULL, 0, NULL, NULL) + 2;
-                    drive->root = HeapAlloc( GetProcessHeap(), 0, len );
-                    len -= sprintf( drive->root, "%s/", config );
-                    WideCharToMultiByte(CP_UNIXCP, 0, path, -1,
-                                        drive->root + strlen(drive->root), len, NULL, NULL);
-                }
-
-                if (stat( drive->root, &drive_stat_buffer ))
-                {
-                    MESSAGE("Could not stat %s (%s), ignoring drive %c:\n",
-                            drive->root, strerror(errno), 'A' + i);
-                    HeapFree( GetProcessHeap(), 0, drive->root );
-                    drive->root = NULL;
-                    goto next;
-                }
-                if (!S_ISDIR(drive_stat_buffer.st_mode))
-                {
-                    MESSAGE("%s is not a directory, ignoring drive %c:\n",
-                            drive->root, 'A' + i );
-                    HeapFree( GetProcessHeap(), 0, drive->root );
-                    drive->root = NULL;
-                    goto next;
-                }
-
-                drive->device   = NULL;
-                drive->dev      = drive_stat_buffer.st_dev;
-                drive->ino      = drive_stat_buffer.st_ino;
-            }
-        }
-
-        if (drive->root)
-        {
-            /* Get the device */
-            RtlInitUnicodeString( &nameW, DeviceW );
-            if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
-            {
-                WCHAR *data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
-                len = WideCharToMultiByte(CP_UNIXCP, 0, data, -1, NULL, 0, NULL, NULL);
-                drive->device = HeapAlloc(GetProcessHeap(), 0, len);
-                WideCharToMultiByte(CP_UNIXCP, 0, data, -1, drive->device, len, NULL, NULL);
-            }
-
-            count++;
-            TRACE("Drive %c: path=%s dev=%x ino=%x\n",
-                  'A' + i, drive->root, (int)drive->dev, (int)drive->ino );
-        }
-
-    next:
-        NtClose( hkey );
-    }
-    return 1;
-}
-
-
-/***********************************************************************
- *           DRIVE_IsValid
- */
-int DRIVE_IsValid( int drive )
-{
-    if ((drive < 0) || (drive >= MAX_DOS_DRIVES)) return 0;
-    return (DOSDrives[drive].root != NULL);
-}
-
-
-/***********************************************************************
- *           DRIVE_FindDriveRoot
- *
- * Find a drive for which the root matches the beginning of the given path.
- * This can be used to translate a Unix path into a drive + DOS path.
- * Return value is the drive, or -1 on error. On success, path is modified
- * to point to the beginning of the DOS path.
- *
- * Note: path must be in the encoding of the underlying Unix file system.
- */
-int DRIVE_FindDriveRoot( const char **path )
-{
-    /* Starting with the full path, check if the device and inode match any of
-     * the wine 'drives'. If not then remove the last path component and try
-     * again. If the last component was a '..' then skip a normal component
-     * since it's a directory that's ascended back out of.
-     */
-    int drive, level, len;
-    char buffer[MAX_PATHNAME_LEN];
-    char *p;
-    struct stat st;
-
-    strcpy( buffer, *path );
-    for (p = buffer; *p; p++) if (*p == '\\') *p = '/';
-    len = p - buffer;
-
-    /* strip off trailing slashes */
-    while (len > 1 && buffer[len - 1] == '/') buffer[--len] = 0;
-
-    for (;;)
-    {
-        /* Find the drive */
-        if (stat( buffer, &st ) == 0 && S_ISDIR( st.st_mode ))
-        {
-            for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
-            {
-               if (!DOSDrives[drive].root) continue;
-
-               if ((DOSDrives[drive].dev == st.st_dev) &&
-                   (DOSDrives[drive].ino == st.st_ino))
-               {
-                   if (len == 1) len = 0;  /* preserve root slash in returned path */
-                   TRACE( "%s -> drive %c:, root='%s', name='%s'\n",
-                       *path, 'A' + drive, buffer, *path + len);
-                   *path += len;
-                   if (!**path) *path = "\\";
-                   return drive;
-               }
-            }
-        }
-        if (len <= 1) return -1;  /* reached root */
-
-        level = 0;
-        while (level < 1)
-        {
-            /* find start of the last path component */
-            while (len > 1 && buffer[len - 1] != '/') len--;
-            if (!buffer[len]) break;  /* empty component -> reached root */
-            /* does removing it take us up a level? */
-            if (strcmp( buffer + len, "." ) != 0)
-                level += strcmp( buffer + len, ".." ) ? 1 : -1;
-            buffer[len] = 0;
-            /* strip off trailing slashes */
-            while (len > 1 && buffer[len - 1] == '/') buffer[--len] = 0;
-        }
-    }
-}
-
-
-/***********************************************************************
- *           DRIVE_FindDriveRootW
- *
- * Unicode version of DRIVE_FindDriveRoot.
- */
-int DRIVE_FindDriveRootW( LPCWSTR *path )
-{
-    int drive, level, len;
-    WCHAR buffer[MAX_PATHNAME_LEN];
-    WCHAR *p;
-    struct stat st;
-
-    strcpyW( buffer, *path );
-    for (p = buffer; *p; p++) if (*p == '\\') *p = '/';
-    len = p - buffer;
-
-    /* strip off trailing slashes */
-    while (len > 1 && buffer[len - 1] == '/') buffer[--len] = 0;
-
-    for (;;)
-    {
-        char buffA[MAX_PATHNAME_LEN];
-
-        WideCharToMultiByte( CP_UNIXCP, 0, buffer, -1, buffA, sizeof(buffA), NULL, NULL );
-        if (stat( buffA, &st ) == 0 && S_ISDIR( st.st_mode ))
-        {
-            /* Find the drive */
-            for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
-            {
-                if (!DOSDrives[drive].root) continue;
-
-                if ((DOSDrives[drive].dev == st.st_dev) &&
-                    (DOSDrives[drive].ino == st.st_ino))
-                {
-                    static const WCHAR rootW[] = {'\\',0};
-
-                    if (len == 1) len = 0;  /* preserve root slash in returned path */
-                    TRACE( "%s -> drive %c:, root=%s, name=%s\n",
-                           debugstr_w(*path), 'A' + drive, debugstr_w(buffer), debugstr_w(*path + len));
-                    *path += len;
-                    if (!**path) *path = rootW;
-                    return drive;
-                }
-            }
-        }
-        if (len <= 1) return -1;  /* reached root */
-
-        level = 0;
-        while (level < 1)
-        {
-            static const WCHAR dotW[] = {'.',0};
-            static const WCHAR dotdotW[] = {'.','.',0};
-
-            /* find start of the last path component */
-            while (len > 1 && buffer[len - 1] != '/') len--;
-            if (!buffer[len]) break;  /* empty component -> reached root */
-            /* does removing it take us up a level? */
-            if (strcmpW( buffer + len, dotW ) != 0)
-                level += strcmpW( buffer + len, dotdotW ) ? 1 : -1;
-            buffer[len] = 0;
-            /* strip off trailing slashes */
-            while (len > 1 && buffer[len - 1] == '/') buffer[--len] = 0;
-        }
-    }
-}
-
-
-/***********************************************************************
- *           DRIVE_GetRoot
- */
-const char * DRIVE_GetRoot( int drive )
-{
-    if (!DRIVE_IsValid( drive )) return NULL;
-    return DOSDrives[drive].root;
-}
-
-
-/***********************************************************************
- *           DRIVE_GetDevice
- */
-const char * DRIVE_GetDevice( int drive )
-{
-    return (DRIVE_IsValid( drive )) ? DOSDrives[drive].device : NULL;
-}
diff --git a/files/file.c b/files/file.c
index 3752c59..138c503 100644
--- a/files/file.c
+++ b/files/file.c
@@ -174,78 +174,6 @@
 }
 
 
-/***********************************************************************
- *           FILE_CreateFile
- *
- * Implementation of CreateFile. Takes a Unix path name.
- * Returns 0 on failure.
- */
-HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
-                        LPSECURITY_ATTRIBUTES sa, DWORD creation,
-                        DWORD attributes, HANDLE template )
-{
-    unsigned int err;
-    UINT disp, options;
-    HANDLE ret;
-
-    switch (creation)
-    {
-    case CREATE_ALWAYS:     disp = FILE_OVERWRITE_IF; break;
-    case CREATE_NEW:        disp = FILE_CREATE; break;
-    case OPEN_ALWAYS:       disp = FILE_OPEN_IF; break;
-    case OPEN_EXISTING:     disp = FILE_OPEN; break;
-    case TRUNCATE_EXISTING: disp = FILE_OVERWRITE; break;
-    default:
-        SetLastError( ERROR_INVALID_PARAMETER );
-        return 0;
-    }
-
-    options = 0;
-    if (attributes & FILE_FLAG_BACKUP_SEMANTICS)
-        options |= FILE_OPEN_FOR_BACKUP_INTENT;
-    else
-        options |= FILE_NON_DIRECTORY_FILE;
-    if (attributes & FILE_FLAG_DELETE_ON_CLOSE)
-        options |= FILE_DELETE_ON_CLOSE;
-    if (!(attributes & FILE_FLAG_OVERLAPPED))
-        options |= FILE_SYNCHRONOUS_IO_ALERT;
-    if (attributes & FILE_FLAG_RANDOM_ACCESS)
-        options |= FILE_RANDOM_ACCESS;
-    attributes &= FILE_ATTRIBUTE_VALID_FLAGS;
-
-    SERVER_START_REQ( create_file )
-    {
-        req->access     = access;
-        req->inherit    = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
-        req->sharing    = sharing;
-        req->create     = disp;
-        req->options    = options;
-        req->attrs      = attributes;
-        wine_server_add_data( req, filename, strlen(filename) );
-        SetLastError(0);
-        err = wine_server_call( req );
-        ret = reply->handle;
-    }
-    SERVER_END_REQ;
-
-    if (err)
-    {
-        /* In the case file creation was rejected due to CREATE_NEW flag
-         * was specified and file with that name already exists, correct
-         * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
-         * Note: RtlNtStatusToDosError is not the subject to blame here.
-         */
-        if (err == STATUS_OBJECT_NAME_COLLISION)
-            SetLastError( ERROR_FILE_EXISTS );
-        else
-            SetLastError( RtlNtStatusToDosError(err) );
-    }
-
-    if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
-    return ret;
-}
-
-
 static HANDLE FILE_OpenPipe(LPCWSTR name, DWORD access, LPSECURITY_ATTRIBUTES sa )
 {
     HANDLE ret;
@@ -368,18 +296,7 @@
         }
         else if (isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0')
         {
-            const char *device = DRIVE_GetDevice( toupperW(filename[4]) - 'A' );
-            if (device)
-            {
-                ret = FILE_CreateFile( device, access, sharing, sa, creation,
-                                       attributes, template );
-            }
-            else
-            {
-                SetLastError( ERROR_ACCESS_DENIED );
-                return INVALID_HANDLE_VALUE;
-            }
-            goto done;
+            dosdev = 0;
         }
         else if ((dosdev = RtlIsDosDeviceName_U( filename + 4 )))
         {
diff --git a/include/file.h b/include/file.h
index 8c4a7b2..b234399 100644
--- a/include/file.h
+++ b/include/file.h
@@ -33,13 +33,6 @@
 /* files/directory.c */
 extern int DIR_Init(void);
 
-/* drive.c */
-extern int DRIVE_Init(void);
-extern int DRIVE_FindDriveRoot( const char **path );
-extern int DRIVE_FindDriveRootW( LPCWSTR *path );
-extern const char * DRIVE_GetRoot( int drive );
-extern const char * DRIVE_GetDevice( int drive );
-
 /* vxd.c */
 extern HANDLE VXD_Open( LPCWSTR filename, DWORD access, LPSECURITY_ATTRIBUTES sa );
 
diff --git a/misc/registry.c b/misc/registry.c
index 3835bf9..1c8d4e2 100644
--- a/misc/registry.c
+++ b/misc/registry.c
@@ -1833,6 +1833,59 @@
 }
 
 
+/* 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) 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 );
+}
+
+
 /* load all registry (native and global and home) */
 void SHELL_LoadRegistry( void )
 {
@@ -2002,6 +2055,10 @@
         _save_at_exit(hkey_users_default,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
     }
 
+    /* convert keys from config file to new registry format */
+
+    convert_drive_types();
+
     NtClose(hkey_users_default);
     NtClose(hkey_current_user);
     NtClose(hkey_users);