Reimplemented GetVolumeInformation and SetVolumeLabel; volume label
and serial number are now stored in the filesystem instead of in the
config file (partly based on a patch by Eric Pouech).

diff --git a/dlls/kernel/Makefile.in b/dlls/kernel/Makefile.in
index 9892f5c..8f5b15b 100644
--- a/dlls/kernel/Makefile.in
+++ b/dlls/kernel/Makefile.in
@@ -75,6 +75,7 @@
 	utthunk.c \
 	version.c \
 	virtual.c \
+	volume.c \
 	vxd.c \
 	win87em.c \
 	windebug.c \
diff --git a/dlls/kernel/volume.c b/dlls/kernel/volume.c
new file mode 100644
index 0000000..295f54b
--- /dev/null
+++ b/dlls/kernel/volume.c
@@ -0,0 +1,626 @@
+/*
+ * Volume management functions
+ *
+ * Copyright 1993 Erik Bos
+ * Copyright 1996, 2004 Alexandre Julliard
+ * Copyright 1999 Petr Tomasek
+ * Copyright 2000 Andreas Mohr
+ * Copyright 2003 Eric Pouech
+ *
+ * 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 <stdarg.h>
+#include <stdlib.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "winnls.h"
+#include "winternl.h"
+#include "ntstatus.h"
+#include "winioctl.h"
+#include "ntddstor.h"
+#include "ntddcdrm.h"
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(volume);
+
+#define SUPERBLOCK_SIZE 2048
+
+#define CDFRAMES_PERSEC         75
+#define CDFRAMES_PERMIN         (CDFRAMES_PERSEC * 60)
+#define FRAME_OF_ADDR(a)        ((a)[1] * CDFRAMES_PERMIN + (a)[2] * CDFRAMES_PERSEC + (a)[3])
+#define FRAME_OF_TOC(toc, idx)  FRAME_OF_ADDR((toc)->TrackData[(idx) - (toc)->FirstTrack].Address)
+
+#define GETWORD(buf,off)  MAKEWORD(buf[(off)],buf[(off+1)])
+#define GETLONG(buf,off)  MAKELONG(GETWORD(buf,off),GETWORD(buf,off+2))
+
+enum fs_type
+{
+    FS_ERROR,    /* error accessing the device */
+    FS_UNKNOWN,  /* unknown file system */
+    FS_FAT1216,
+    FS_FAT32,
+    FS_ISO9660
+};
+
+
+/******************************************************************
+ *		VOLUME_FindCdRomDataBestVoldesc
+ */
+static DWORD VOLUME_FindCdRomDataBestVoldesc( HANDLE handle )
+{
+    BYTE cur_vd_type, max_vd_type = 0;
+    BYTE buffer[16];
+    DWORD size, offs, best_offs = 0, extra_offs = 0;
+
+    for (offs = 0x8000; offs <= 0x9800; offs += 0x800)
+    {
+        /* if 'CDROM' occurs at position 8, this is a pre-iso9660 cd, and
+         * the volume label is displaced forward by 8
+         */
+        if (SetFilePointer( handle, offs, NULL, FILE_BEGIN ) != offs) break;
+        if (!ReadFile( handle, buffer, sizeof(buffer), &size, NULL )) break;
+        if (size != sizeof(buffer)) break;
+        /* check for non-ISO9660 signature */
+        if (!memcmp( buffer + 11, "ROM", 3 )) extra_offs = 8;
+        cur_vd_type = buffer[extra_offs];
+        if (cur_vd_type == 0xff) /* voldesc set terminator */
+            break;
+        if (cur_vd_type > max_vd_type)
+        {
+            max_vd_type = cur_vd_type;
+            best_offs = offs + extra_offs;
+        }
+    }
+    return best_offs;
+}
+
+
+/***********************************************************************
+ *           VOLUME_ReadFATSuperblock
+ */
+static enum fs_type VOLUME_ReadFATSuperblock( HANDLE handle, BYTE *buff )
+{
+    DWORD size;
+
+    /* try a fixed disk, with a FAT partition */
+    if (SetFilePointer( handle, 0, NULL, FILE_BEGIN ) != 0 ||
+        !ReadFile( handle, buff, SUPERBLOCK_SIZE, &size, NULL ) ||
+        size != SUPERBLOCK_SIZE)
+        return FS_ERROR;
+
+    if (buff[0] == 0xE9 || (buff[0] == 0xEB && buff[2] == 0x90))
+    {
+        /* guess which type of FAT we have */
+        unsigned int sz, nsect, nclust;
+        sz = GETWORD(buff, 0x16);
+        if (!sz) sz = GETLONG(buff, 0x24);
+        nsect = GETWORD(buff, 0x13);
+        if (!nsect) nsect = GETLONG(buff, 0x20);
+        nsect -= GETWORD(buff, 0x0e) + buff[0x10] * sz +
+            (GETWORD(buff, 0x11) * 32 + (GETWORD(buff, 0x0b) - 1)) / GETWORD(buff, 0x0b);
+        nclust = nsect / buff[0x0d];
+
+        if (nclust < 65525)
+        {
+            if (buff[0x26] == 0x29 && !memcmp(buff+0x36, "FAT", 3))
+            {
+                /* FIXME: do really all FAT have their name beginning with
+                 * "FAT" ? (At least FAT12, FAT16 and FAT32 have :)
+                 */
+                return FS_FAT1216;
+            }
+        }
+        else if (!memcmp(buff+0x52, "FAT", 3)) return FS_FAT32;
+    }
+    return FS_UNKNOWN;
+}
+
+
+/***********************************************************************
+ *           VOLUME_ReadCDSuperblock
+ */
+static enum fs_type VOLUME_ReadCDSuperblock( HANDLE handle, BYTE *buff )
+{
+    DWORD size, offs = VOLUME_FindCdRomDataBestVoldesc( handle );
+
+    if (!offs) return FS_UNKNOWN;
+
+    if (SetFilePointer( handle, offs, NULL, FILE_BEGIN ) != offs ||
+        !ReadFile( handle, buff, SUPERBLOCK_SIZE, &size, NULL ) ||
+        size != SUPERBLOCK_SIZE)
+        return FS_ERROR;
+
+    /* check for iso9660 present */
+    if (!memcmp(&buff[1], "CD001", 5)) return FS_ISO9660;
+    return FS_UNKNOWN;
+}
+
+
+/**************************************************************************
+ *                              VOLUME_GetSuperblockLabel
+ */
+static void VOLUME_GetSuperblockLabel( enum fs_type type, const BYTE *superblock,
+                                       WCHAR *label, DWORD len )
+{
+    const BYTE *label_ptr = NULL;
+    DWORD label_len;
+
+    switch(type)
+    {
+    case FS_ERROR:
+    case FS_UNKNOWN:
+        label_len = 0;
+        break;
+    case FS_FAT1216:
+        label_ptr = superblock + 0x2b;
+        label_len = 11;
+        break;
+    case FS_FAT32:
+        label_ptr = superblock + 0x47;
+        label_len = 11;
+        break;
+    case FS_ISO9660:
+        {
+            BYTE ver = superblock[0x5a];
+
+            if (superblock[0x58] == 0x25 && superblock[0x59] == 0x2f &&  /* Unicode ID */
+                ((ver == 0x40) || (ver == 0x43) || (ver == 0x45)))
+            { /* yippee, unicode */
+                int i;
+
+                if (len > 17) len = 17;
+                for (i = 0; i < len-1; i++)
+                    label[i] = (superblock[40+2*i] << 8) | superblock[41+2*i];
+                label[i] = 0;
+                while (i && label[i-1] == ' ') label[--i] = 0;
+                return;
+            }
+            label_ptr = superblock + 40;
+            label_len = 32;
+            break;
+        }
+    }
+    if (label_len) RtlMultiByteToUnicodeN( label, (len-1) * sizeof(WCHAR),
+                                           &label_len, label_ptr, label_len );
+    label_len /= sizeof(WCHAR);
+    label[label_len] = 0;
+    while (label_len && label[label_len-1] == ' ') label[--label_len] = 0;
+}
+
+
+/**************************************************************************
+ *                              VOLUME_SetSuperblockLabel
+ */
+static BOOL VOLUME_SetSuperblockLabel( enum fs_type type, HANDLE handle, const WCHAR *label )
+{
+    BYTE label_data[11];
+    DWORD offset, len;
+
+    switch(type)
+    {
+    case FS_FAT1216:
+        offset = 0x2b;
+        break;
+    case FS_FAT32:
+        offset = 0x47;
+        break;
+    default:
+        SetLastError( ERROR_ACCESS_DENIED );
+        return FALSE;
+    }
+    RtlUnicodeToMultiByteN( label_data, sizeof(label_data), &len,
+                            label, strlenW(label) * sizeof(WCHAR) );
+    if (len < sizeof(label_data))
+        memset( label_data + len, ' ', sizeof(label_data) - len );
+
+    return (SetFilePointer( handle, offset, NULL, FILE_BEGIN ) == offset &&
+            WriteFile( handle, label_data, sizeof(label_data), &len, NULL ));
+}
+
+
+/**************************************************************************
+ *                              VOLUME_GetSuperblockSerial
+ */
+static DWORD VOLUME_GetSuperblockSerial( enum fs_type type, const BYTE *superblock )
+{
+    switch(type)
+    {
+    case FS_ERROR:
+    case FS_UNKNOWN:
+        break;
+    case FS_FAT1216:
+        return GETLONG( superblock, 0x27 );
+    case FS_FAT32:
+        return GETLONG( superblock, 0x33 );
+    case FS_ISO9660:
+        {
+            BYTE sum[4];
+            int i;
+
+            sum[0] = sum[1] = sum[2] = sum[3] = 0;
+            for (i = 0; i < 2048; i += 4)
+            {
+                /* DON'T optimize this into DWORD !! (breaks overflow) */
+                sum[0] += superblock[i+0];
+                sum[1] += superblock[i+1];
+                sum[2] += superblock[i+2];
+                sum[3] += superblock[i+3];
+            }
+            /*
+             * OK, another braindead one... argh. Just believe it.
+             * Me$$ysoft chose to reverse the serial number in NT4/W2K.
+             * It's true and nobody will ever be able to change it.
+             */
+            if (GetVersion() & 0x80000000)
+                return (sum[3] << 24) | (sum[2] << 16) | (sum[1] << 8) | sum[0];
+            else
+                return (sum[0] << 24) | (sum[1] << 16) | (sum[2] << 8) | sum[3];
+        }
+    }
+    return 0;
+}
+
+
+/**************************************************************************
+ *                              VOLUME_GetAudioCDSerial
+ */
+static DWORD VOLUME_GetAudioCDSerial( const CDROM_TOC *toc )
+{
+    DWORD serial = 0;
+    int i;
+
+    for (i = 0; i <= toc->LastTrack - toc->FirstTrack; i++)
+        serial += ((toc->TrackData[i].Address[1] << 16) |
+                   (toc->TrackData[i].Address[2] << 8) |
+                   toc->TrackData[i].Address[3]);
+
+    /*
+     * dwStart, dwEnd collect the beginning and end of the disc respectively, in
+     * frames.
+     * There it is collected for correcting the serial when there are less than
+     * 3 tracks.
+     */
+    if (toc->LastTrack - toc->FirstTrack + 1 < 3)
+    {
+        DWORD dwStart = FRAME_OF_TOC(toc, toc->FirstTrack);
+        DWORD dwEnd = FRAME_OF_TOC(toc, toc->LastTrack + 1);
+        serial += dwEnd - dwStart;
+    }
+    return serial;
+}
+
+
+/***********************************************************************
+ *           GetVolumeInformationW   (KERNEL32.@)
+ */
+BOOL WINAPI GetVolumeInformationW( LPCWSTR root, LPWSTR label, DWORD label_len,
+                                   DWORD *serial, DWORD *filename_len, DWORD *flags,
+                                   LPWSTR fsname, DWORD fsname_len )
+{
+    static const WCHAR audiocdW[] = {'A','u','d','i','o',' ','C','D',0};
+    static const WCHAR fatW[] = {'F','A','T',0};
+    static const WCHAR cdfsW[] = {'C','D','F','S',0};
+
+    WCHAR device[] = {'\\','\\','.','\\','A',':',0};
+    HANDLE handle;
+    enum fs_type type = FS_UNKNOWN;
+
+    if (!root)
+    {
+        WCHAR path[MAX_PATH];
+        GetCurrentDirectoryW( MAX_PATH, path );
+        device[4] = path[0];
+    }
+    else
+    {
+        if (!root[0] || root[1] != ':')
+        {
+            SetLastError( ERROR_INVALID_NAME );
+            return FALSE;
+        }
+        device[4] = root[0];
+    }
+
+    /* try to open the device */
+
+    handle = CreateFileW( device, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
+                          NULL, OPEN_EXISTING, 0, 0 );
+    if (handle != INVALID_HANDLE_VALUE)
+    {
+        BYTE superblock[SUPERBLOCK_SIZE];
+        CDROM_TOC toc;
+        DWORD br;
+
+        /* check for audio CD */
+        /* FIXME: we only check the first track for now */
+        if (DeviceIoControl( handle, IOCTL_CDROM_READ_TOC, NULL, 0, &toc, sizeof(toc), &br, 0 ))
+        {
+            if (!(toc.TrackData[0].Control & 0x04))  /* audio track */
+            {
+                TRACE( "%s: found audio CD\n", debugstr_w(device) );
+                if (label) lstrcpynW( label, audiocdW, label_len );
+                if (serial) *serial = VOLUME_GetAudioCDSerial( &toc );
+                CloseHandle( handle );
+                type = FS_ISO9660;
+                goto fill_fs_info;
+            }
+            type = VOLUME_ReadCDSuperblock( handle, superblock );
+        }
+        else
+        {
+            type = VOLUME_ReadFATSuperblock( handle, superblock );
+            if (type == FS_UNKNOWN) type = VOLUME_ReadCDSuperblock( handle, superblock );
+        }
+        CloseHandle( handle );
+        TRACE( "%s: found fs type %d\n", debugstr_w(device), type );
+        if (type == FS_ERROR) return FALSE;
+
+        if (label && label_len) VOLUME_GetSuperblockLabel( type, superblock, label, label_len );
+        if (serial) *serial = VOLUME_GetSuperblockSerial( type, superblock );
+        goto fill_fs_info;
+    }
+    else
+    {
+        TRACE( "cannot open device %s: err %ld\n", debugstr_w(device), GetLastError() );
+        if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
+    }
+
+    /* we couldn't open the device, fallback to default strategy */
+
+    switch(GetDriveTypeW( root ))
+    {
+    case DRIVE_UNKNOWN:
+    case DRIVE_NO_ROOT_DIR:
+        SetLastError( ERROR_NOT_READY );
+        return FALSE;
+    case DRIVE_REMOVABLE:
+    case DRIVE_FIXED:
+    case DRIVE_REMOTE:
+    case DRIVE_RAMDISK:
+        type = FS_UNKNOWN;
+        break;
+    case DRIVE_CDROM:
+        type = FS_ISO9660;
+        break;
+    }
+
+    if (label && label_len)
+    {
+        WCHAR labelW[] = {'A',':','\\','.','w','i','n','d','o','w','s','-','l','a','b','e','l',0};
+
+        labelW[0] = device[4];
+        handle = CreateFileW( labelW, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
+                              OPEN_EXISTING, 0, 0 );
+        if (handle != INVALID_HANDLE_VALUE)
+        {
+            char buffer[256], *p;
+            DWORD size;
+
+            if (!ReadFile( handle, buffer, sizeof(buffer)-1, &size, NULL )) size = 0;
+            CloseHandle( handle );
+            p = buffer + size;
+            while (p > buffer && (p[-1] == ' ' || p[-1] == '\r' || p[-1] == '\n')) p--;
+            *p = 0;
+            if (!MultiByteToWideChar( CP_UNIXCP, 0, buffer, -1, label, label_len ))
+                label[label_len-1] = 0;
+        }
+        else label[0] = 0;
+    }
+    if (serial)
+    {
+        WCHAR serialW[] = {'A',':','\\','.','w','i','n','d','o','w','s','-','s','e','r','i','a','l',0};
+
+        serialW[0] = device[4];
+        handle = CreateFileW( serialW, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
+                              OPEN_EXISTING, 0, 0 );
+        if (handle != INVALID_HANDLE_VALUE)
+        {
+            char buffer[32];
+            DWORD size;
+
+            if (!ReadFile( handle, buffer, sizeof(buffer)-1, &size, NULL )) size = 0;
+            CloseHandle( handle );
+            buffer[size] = 0;
+            *serial = strtoul( buffer, NULL, 16 );
+        }
+        else *serial = 0;
+    }
+
+fill_fs_info:  /* now fill in the information that depends on the file system type */
+
+    switch(type)
+    {
+    case FS_ISO9660:
+        if (fsname) lstrcpynW( fsname, cdfsW, fsname_len );
+        if (filename_len) *filename_len = 221;
+        if (flags) *flags = FILE_READ_ONLY_VOLUME;
+        break;
+    case FS_FAT1216:
+    case FS_FAT32:
+    default:  /* default to FAT file system (FIXME) */
+        if (fsname) lstrcpynW( fsname, fatW, fsname_len );
+        if (filename_len) *filename_len = 255;
+        if (flags) *flags = FILE_CASE_PRESERVED_NAMES;  /* FIXME */
+        break;
+    }
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           GetVolumeInformationA   (KERNEL32.@)
+ */
+BOOL WINAPI GetVolumeInformationA( LPCSTR root, LPSTR label,
+                                       DWORD label_len, DWORD *serial,
+                                       DWORD *filename_len, DWORD *flags,
+                                       LPSTR fsname, DWORD fsname_len )
+{
+    UNICODE_STRING rootW;
+    LPWSTR labelW, fsnameW;
+    BOOL ret;
+
+    if (root) RtlCreateUnicodeStringFromAsciiz(&rootW, root);
+    else rootW.Buffer = NULL;
+    labelW = label ? HeapAlloc(GetProcessHeap(), 0, label_len * sizeof(WCHAR)) : NULL;
+    fsnameW = fsname ? HeapAlloc(GetProcessHeap(), 0, fsname_len * sizeof(WCHAR)) : NULL;
+
+    if ((ret = GetVolumeInformationW(rootW.Buffer, labelW, label_len, serial,
+                                    filename_len, flags, fsnameW, fsname_len)))
+    {
+        if (label) WideCharToMultiByte(CP_ACP, 0, labelW, -1, label, label_len, NULL, NULL);
+        if (fsname) WideCharToMultiByte(CP_ACP, 0, fsnameW, -1, fsname, fsname_len, NULL, NULL);
+    }
+
+    RtlFreeUnicodeString(&rootW);
+    if (labelW) HeapFree( GetProcessHeap(), 0, labelW );
+    if (fsnameW) HeapFree( GetProcessHeap(), 0, fsnameW );
+    return ret;
+}
+
+
+
+/***********************************************************************
+ *           SetVolumeLabelW   (KERNEL32.@)
+ */
+BOOL WINAPI SetVolumeLabelW( LPCWSTR root, LPCWSTR label )
+{
+    WCHAR device[] = {'\\','\\','.','\\','A',':',0};
+    HANDLE handle;
+    enum fs_type type = FS_UNKNOWN;
+
+    if (!root)
+    {
+        WCHAR path[MAX_PATH];
+        GetCurrentDirectoryW( MAX_PATH, path );
+        device[4] = path[0];
+    }
+    else
+    {
+        if (!root[0] || root[1] != ':')
+        {
+            SetLastError( ERROR_INVALID_NAME );
+            return FALSE;
+        }
+        device[4] = root[0];
+    }
+
+    /* try to open the device */
+
+    handle = CreateFileW( device, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
+                          NULL, OPEN_EXISTING, 0, 0 );
+    if (handle == INVALID_HANDLE_VALUE)
+    {
+        /* try read-only */
+        handle = CreateFileW( device, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
+                              NULL, OPEN_EXISTING, 0, 0 );
+        if (handle != INVALID_HANDLE_VALUE)
+        {
+            /* device can be read but not written, return error */
+            CloseHandle( handle );
+            SetLastError( ERROR_ACCESS_DENIED );
+            return FALSE;
+        }
+    }
+
+    if (handle != INVALID_HANDLE_VALUE)
+    {
+        BYTE superblock[SUPERBLOCK_SIZE];
+        BOOL ret;
+
+        type = VOLUME_ReadFATSuperblock( handle, superblock );
+        ret = VOLUME_SetSuperblockLabel( type, handle, label );
+        CloseHandle( handle );
+        return ret;
+    }
+    else
+    {
+        TRACE( "cannot open device %s: err %ld\n", debugstr_w(device), GetLastError() );
+        if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
+    }
+
+    /* we couldn't open the device, fallback to default strategy */
+
+    switch(GetDriveTypeW( root ))
+    {
+    case DRIVE_UNKNOWN:
+    case DRIVE_NO_ROOT_DIR:
+        SetLastError( ERROR_NOT_READY );
+        break;
+    case DRIVE_REMOVABLE:
+    case DRIVE_FIXED:
+        {
+            WCHAR labelW[] = {'A',':','\\','.','w','i','n','d','o','w','s','-','l','a','b','e','l',0};
+
+            labelW[0] = device[4];
+            handle = CreateFileW( labelW, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
+                                  CREATE_ALWAYS, 0, 0 );
+            if (handle != INVALID_HANDLE_VALUE)
+            {
+                char buffer[64];
+                DWORD size;
+
+                if (!WideCharToMultiByte( CP_UNIXCP, 0, label, -1, buffer, sizeof(buffer), NULL, NULL ))
+                    buffer[sizeof(buffer)-1] = 0;
+                WriteFile( handle, buffer, strlen(buffer), &size, NULL );
+                CloseHandle( handle );
+                return TRUE;
+            }
+            break;
+        }
+    case DRIVE_REMOTE:
+    case DRIVE_RAMDISK:
+    case DRIVE_CDROM:
+        SetLastError( ERROR_ACCESS_DENIED );
+        break;
+    }
+    return FALSE;
+}
+
+/***********************************************************************
+ *           SetVolumeLabelA   (KERNEL32.@)
+ */
+BOOL WINAPI SetVolumeLabelA(LPCSTR root, LPCSTR volname)
+{
+    UNICODE_STRING rootW, volnameW;
+    BOOL ret;
+
+    if (root) RtlCreateUnicodeStringFromAsciiz(&rootW, root);
+    else rootW.Buffer = NULL;
+    if (volname) RtlCreateUnicodeStringFromAsciiz(&volnameW, volname);
+    else volnameW.Buffer = NULL;
+
+    ret = SetVolumeLabelW( rootW.Buffer, volnameW.Buffer );
+
+    RtlFreeUnicodeString(&rootW);
+    RtlFreeUnicodeString(&volnameW);
+    return ret;
+}
+
+
+/***********************************************************************
+ *           GetVolumeNameForVolumeMountPointW   (KERNEL32.@)
+ */
+BOOL WINAPI GetVolumeNameForVolumeMountPointW(LPCWSTR str, LPWSTR dst, DWORD size)
+{
+    FIXME("(%s, %p, %lx): stub\n", debugstr_w(str), dst, size);
+    return 0;
+}
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index efefd42..0828891 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -227,7 +227,7 @@
     case EINVAL:
     case ENOTEMPTY:    nt = STATUS_DIRECTORY_NOT_EMPTY;     break;
     case EPIPE:        nt = STATUS_PIPE_BROKEN;             break;
-    case EIO:          nt = STATUS_DISK_CORRUPT_ERROR;      break;
+    case EIO:          nt = STATUS_DEVICE_NOT_READY;        break;
     case ENOEXEC:      /* ?? */
     case ESPIPE:       /* ?? */
     case EEXIST:       /* ?? */
diff --git a/documentation/samples/config b/documentation/samples/config
index 7ce3480..39de768 100644
--- a/documentation/samples/config
+++ b/documentation/samples/config
@@ -11,8 +11,6 @@
 ;; [Drive X]
 ;; "Path"="xxx"       (Unix path for drive root)
 ;; "Type"="xxx"       (supported types are 'floppy', 'hd', 'cdrom' and 'network')
-;; "Label"="xxx"      (drive label, at most 11 characters)
-;; "Serial"="xxx"     (serial number, 8 characters hexadecimal number)
 ;; "Filesystem"="xxx" (supported types are 'msdos'/'dos'/'fat', 'win95'/'vfat', 'unix')
 ;;   This is the FS Wine is supposed to emulate on a certain
 ;;   directory structure.
@@ -25,21 +23,17 @@
 [Drive A]
 "Path" = "/mnt/fd0"
 "Type" = "floppy"
-"Label" = "Floppy"
 "Filesystem" = "win95"
-"Serial" = "87654321"
 "Device" = "/dev/fd0"
 
 [Drive C]
 "Path" = "/c"
 "Type" = "hd"
-"Label" = "MS-DOS"
 "Filesystem" = "win95"
 
 [Drive D]
 "Path" = "/cdrom"
 "Type" = "cdrom"
-"Label" = "CD-Rom"
 "Filesystem" = "win95"
 ; make sure that device is correct and has proper permissions !
 "Device" = "/dev/cdrom"
@@ -47,19 +41,16 @@
 [Drive E]
 "Path" = "/tmp"
 "Type" = "hd"
-"Label" = "Tmp Drive"
 "Filesystem" = "win95"
 
 [Drive F]
 "Path" = "%HOME%"
 "Type" = "network"
-"Label" = "Home"
 "Filesystem" = "win95"
 
 [Drive Z]
 "Path" = "/"
 "Type" = "hd"
-"Label" = "Root"
 "Filesystem" = "win95"
 
 [wine]
diff --git a/documentation/wine.conf.man b/documentation/wine.conf.man
index 3e35e81..7590783 100644
--- a/documentation/wine.conf.man
+++ b/documentation/wine.conf.man
@@ -60,19 +60,6 @@
 or DOS programs; supported types are "floppy", "hd", "cdrom"
 and "network".
 .PP
-.I format: """Label""=""<label>"""
-.br
-default: "Drive X"
-.br
-Used to specify the drive label; limited to 11 characters.
-.PP
-.I format: """Serial""=""<serial>"""
-.br
-default: "12345678"
-.br
-Used to specify the drive serial number, as an 8-character hexadecimal
-number.
-.PP
 .I format: """Filesystem""=""<fstype>"""
 .br
 default: "win95"
diff --git a/files/drive.c b/files/drive.c
index af8f70c..8a87545 100644
--- a/files/drive.c
+++ b/files/drive.c
@@ -39,24 +39,9 @@
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif
-
-#ifdef HAVE_SYS_PARAM_H
-# include <sys/param.h>
-#endif
 #ifdef HAVE_SYS_STATVFS_H
 # include <sys/statvfs.h>
 #endif
-#ifdef STATFS_DEFINED_BY_SYS_VFS
-# include <sys/vfs.h>
-#else
-# ifdef STATFS_DEFINED_BY_SYS_MOUNT
-#  include <sys/mount.h>
-# else
-#  ifdef STATFS_DEFINED_BY_SYS_STATFS
-#   include <sys/statfs.h>
-#  endif
-# endif
-#endif
 
 #define NONAMELESSUNION
 #define NONAMELESSSTRUCT
@@ -86,9 +71,6 @@
     LPWSTR    dos_cwd;   /* cwd in DOS format without leading or trailing \ */
     char     *unix_cwd;  /* cwd in Unix format without leading or trailing / */
     char     *device;    /* raw device path */
-    WCHAR     label_conf[12]; /* drive label as cfg'd in wine config */
-    WCHAR     label_read[12]; /* drive label as read from device */
-    DWORD     serial_conf;    /* drive serial number as cfg'd in wine config */
     UINT      type;      /* drive type */
     UINT      flags;     /* drive flags */
     dev_t     dev;       /* unix device number */
@@ -199,15 +181,10 @@
     UNICODE_STRING nameW;
 
     static const WCHAR PathW[] = {'P','a','t','h',0};
-    static const WCHAR LabelW[] = {'L','a','b','e','l',0};
-    static const WCHAR SerialW[] = {'S','e','r','i','a','l',0};
     static const WCHAR TypeW[] = {'T','y','p','e',0};
     static const WCHAR FilesystemW[] = {'F','i','l','e','s','y','s','t','e','m',0};
     static const WCHAR DeviceW[] = {'D','e','v','i','c','e',0};
-    static const WCHAR ReadVolInfoW[] = {'R','e','a','d','V','o','l','I','n','f','o',0};
     static const WCHAR FailReadOnlyW[] = {'F','a','i','l','R','e','a','d','O','n','l','y',0};
-    static const WCHAR driveC_labelW[] = {'D','r','i','v','e',' ','C',' ',' ',' ',' ',0};
-
 
     attr.Length = sizeof(attr);
     attr.RootDirectory = 0;
@@ -283,29 +260,6 @@
             }
             else drive->type = DRIVE_FIXED;
 
-            /* Get the drive label */
-            RtlInitUnicodeString( &nameW, LabelW );
-            if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
-            {
-                WCHAR *data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
-                lstrcpynW( drive->label_conf, data, 12 );
-            }
-            if ((len = strlenW(drive->label_conf)) < 11)
-            {
-                /* Pad label with spaces */
-                while(len < 11) drive->label_conf[len++] = ' ';
-                drive->label_conf[11] = '\0';
-            }
-
-            /* Get the serial number */
-            RtlInitUnicodeString( &nameW, SerialW );
-            if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
-            {
-                WCHAR *data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
-                drive->serial_conf = strtoulW( data, NULL, 16 );
-            }
-            else drive->serial_conf = 12345678;
-
             /* Get the filesystem type */
             RtlInitUnicodeString( &nameW, FilesystemW );
             if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
@@ -324,14 +278,6 @@
                 drive->device = HeapAlloc(GetProcessHeap(), 0, len);
                 WideCharToMultiByte(CP_UNIXCP, 0, data, -1, drive->device, len, NULL, NULL);
 
-                RtlInitUnicodeString( &nameW, ReadVolInfoW );
-                if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
-                {
-                    WCHAR *data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
-                    if (IS_OPTION_TRUE(data[0])) drive->flags |= DRIVE_READ_VOL_INFO;
-                }
-                else drive->flags |= DRIVE_READ_VOL_INFO;
-
                 if (drive->type == DRIVE_CDROM)
                 {
                     int cd_fd;
@@ -356,11 +302,9 @@
                 DRIVE_CurDrive = i;
 
             count++;
-            TRACE("Drive %c: path=%s type=%s label=%s serial=%08lx "
-                  "flags=%08x dev=%x ino=%x\n",
+            TRACE("Drive %c: path=%s type=%s flags=%08x dev=%x ino=%x\n",
                   'A' + i, drive->root, debugstr_w(DRIVE_Types[drive->type]),
-                  debugstr_w(drive->label_conf), drive->serial_conf, drive->flags,
-                  (int)drive->dev, (int)drive->ino );
+                  drive->flags, (int)drive->dev, (int)drive->ino );
         }
 
     next:
@@ -374,8 +318,6 @@
         DOSDrives[2].root     = heap_strdup( "/" );
         DOSDrives[2].dos_cwd  = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DOSDrives[2].dos_cwd[0]));
         DOSDrives[2].unix_cwd = heap_strdup( "" );
-        strcpyW( DOSDrives[2].label_conf, driveC_labelW );
-        DOSDrives[2].serial_conf   = 12345678;
         DOSDrives[2].type     = DRIVE_FIXED;
         DOSDrives[2].device   = NULL;
         DOSDrives[2].flags    = 0;
@@ -653,531 +595,6 @@
     return (DRIVE_IsValid( drive )) ? DOSDrives[drive].device : NULL;
 }
 
-/******************************************************************
- *		static WORD CDROM_Data_FindBestVoldesc
- *
- *
- */
-static WORD CDROM_Data_FindBestVoldesc(int fd)
-{
-    BYTE cur_vd_type, max_vd_type = 0;
-    unsigned int offs, best_offs = 0, extra_offs = 0;
-    char sig[3];
-
-    for (offs = 0x8000; offs <= 0x9800; offs += 0x800)
-    {
-        /* if 'CDROM' occurs at position 8, this is a pre-iso9660 cd, and
-         * the volume label is displaced forward by 8
-         */
-        lseek(fd, offs + 11, SEEK_SET); /* check for non-ISO9660 signature */
-        read(fd, &sig, 3);
-        if ((sig[0] == 'R') && (sig[1] == 'O') && (sig[2]=='M'))
-        {
-            extra_offs = 8;
-        }
-        lseek(fd, offs + extra_offs, SEEK_SET);
-        read(fd, &cur_vd_type, 1);
-        if (cur_vd_type == 0xff) /* voldesc set terminator */
-            break;
-        if (cur_vd_type > max_vd_type)
-        {
-            max_vd_type = cur_vd_type;
-            best_offs = offs + extra_offs;
-        }
-    }
-    return best_offs;
-}
-
-/***********************************************************************
- *           DRIVE_ReadSuperblock
- *
- * NOTE
- *      DRIVE_SetLabel and DRIVE_SetSerialNumber use this in order
- * to check, that they are writing on a FAT filesystem !
- */
-int DRIVE_ReadSuperblock (int drive, char * buff)
-{
-#define DRIVE_SUPER 96
-    int fd;
-    off_t offs;
-    int ret = 0;
-    struct stat stat_buf;
-
-    memset(buff, 0, DRIVE_SUPER);
-       /* O_NONBLOCK in case we're opening FIFO; will be reset later */
-    if ((fd = open(DOSDrives[drive].device, O_RDONLY|O_NOCTTY|O_NONBLOCK)) != -1) {
-	if (fstat(fd, &stat_buf) < 0) {	/* shouldn't happen since we just opened that file */
-	    ERR("fstat() failed for opened device '%s' (drive %c:) ! IT SHOULDN'T HAPPEN !!!\n",
-		DOSDrives[drive].device, 'A'+drive);
-	    ret = -1;
-	} else if (!S_ISBLK(stat_buf.st_mode)) {
-	    ERR("Device '%s' (drive %c:) is not a block device - check your config\n",
-		DOSDrives[drive].device, 'A'+drive);
-	    ret = -1;
-			/* reset O_NONBLOCK */
-        } else if (fcntl(fd, F_SETFL, 0) < 0 || fcntl(fd, F_GETFL) & O_NONBLOCK) {
-	    ERR("fcntl() failed to reset O_NONBLOCK for device '%s' (drive %c:)\n",
-		DOSDrives[drive].device, 'A'+drive);
-	    ret = -1;
-	}
-	if (ret) {
-	    close(fd);
-	    fd = -1;
-	}
-    } else {
-	if (!DOSDrives[drive].device)
-	    ERR("No device configured for drive %c: !\n", 'A'+drive);
-	else
-	    ERR("Couldn't open device '%s' for drive %c: ! (%s)\n", DOSDrives[drive].device, 'A'+drive,
-		(stat(DOSDrives[drive].device, &stat_buf)) ?
-			"not available or symlink not valid ?" : "no permission");
-    }
-    if (fd == -1) {
-	ERR("Can't read drive volume info ! Either pre-set it or make sure the device to read it from is accessible !\n");
-	return -1;
-    }
-
-    switch(DOSDrives[drive].type)
-    {
-	case DRIVE_REMOVABLE:
-	case DRIVE_FIXED:
-	    offs = 0;
-	    break;
-	case DRIVE_CDROM:
-	    offs = CDROM_Data_FindBestVoldesc(fd);
-	    break;
-        default:
-            offs = 0;
-            break;
-    }
-
-    if ((offs) && (lseek(fd,offs,SEEK_SET)!=offs))
-    {
-        ret = -4;
-        goto the_end;
-    }
-    if (read(fd,buff,DRIVE_SUPER)!=DRIVE_SUPER)
-    {
-        ret = -2;
-        goto the_end;
-    }
-
-    switch(DOSDrives[drive].type)
-    {
-	case DRIVE_REMOVABLE:
-	case DRIVE_FIXED:
-	    if ((buff[0x26]!=0x29) ||  /* Check for FAT present */
-                /* FIXME: do really all FAT have their name beginning with
-                   "FAT" ? (At least FAT12, FAT16 and FAT32 have :) */
-	    	memcmp( buff+0x36,"FAT",3))
-            {
-                ERR("The filesystem is not FAT !! (device=%s)\n",
-                    DOSDrives[drive].device);
-                ret = -3;
-                goto the_end;
-            }
-            break;
-	case DRIVE_CDROM:
-	    if (strncmp(&buff[1],"CD001",5)) /* Check for iso9660 present */
-            {
-		ret = -3;
-                goto the_end;
-            }
-	    /* FIXME: do we need to check for "CDROM", too ? (high sierra) */
-            break;
-	default:
-            ret = -3;
-            goto the_end;
-    }
-
-    return close(fd);
- the_end:
-    close(fd);
-    return ret;
-}
-
-
-/***********************************************************************
- *           DRIVE_WriteSuperblockEntry
- *
- * NOTE
- *	We are writing as little as possible (ie. not the whole SuperBlock)
- * not to interfere with kernel. The drive can be mounted !
- */
-int DRIVE_WriteSuperblockEntry (int drive, off_t ofs, size_t len, char * buff)
-{
-    int fd;
-
-    if ((fd=open(DOSDrives[drive].device,O_WRONLY))==-1)
-    {
-        ERR("Cannot open the device %s (for writing)\n",
-            DOSDrives[drive].device);
-        return -1;
-    }
-    if (lseek(fd,ofs,SEEK_SET)!=ofs)
-    {
-        ERR("lseek failed on device %s !\n",
-            DOSDrives[drive].device);
-        close(fd);
-        return -2;
-    }
-    if (write(fd,buff,len)!=len)
-    {
-        close(fd);
-        ERR("Cannot write on %s !\n",
-            DOSDrives[drive].device);
-        return -3;
-    }
-    return close (fd);
-}
-
-/******************************************************************
- *		static HANDLE   CDROM_Open
- *
- *
- */
-static HANDLE   CDROM_Open(int drive)
-{
-    WCHAR root[] = {'\\','\\','.','\\','A',':',0};
-    root[4] += drive;
-    return CreateFileW(root, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
-}
-
-/**************************************************************************
- *                              CDROM_Data_GetLabel             [internal]
- */
-DWORD CDROM_Data_GetLabel(int drive, WCHAR *label)
-{
-#define LABEL_LEN       32+1
-    int dev = open(DOSDrives[drive].device, O_RDONLY|O_NONBLOCK);
-    WORD offs = CDROM_Data_FindBestVoldesc(dev);
-    WCHAR label_read[LABEL_LEN]; /* Unicode possible, too */
-    DWORD unicode_id = 0;
-
-    if (offs)
-    {
-        if ((lseek(dev, offs+0x58, SEEK_SET) == offs+0x58)
-        &&  (read(dev, &unicode_id, 3) == 3))
-        {
-            int ver = (unicode_id & 0xff0000) >> 16;
-
-            if ((lseek(dev, offs+0x28, SEEK_SET) != offs+0x28)
-            ||  (read(dev, &label_read, LABEL_LEN) != LABEL_LEN))
-                goto failure;
-
-            close(dev);
-            if ((LOWORD(unicode_id) == 0x2f25) /* Unicode ID */
-            &&  ((ver == 0x40) || (ver == 0x43) || (ver == 0x45)))
-            { /* yippee, unicode */
-                int i;
-                WORD ch;
-                for (i=0; i<LABEL_LEN;i++)
-                { /* Motorola -> Intel Unicode conversion :-\ */
-                     ch = label_read[i];
-                     label_read[i] = (ch << 8) | (ch >> 8);
-                }
-                strncpyW(label, label_read, 11);
-                label[11] = 0;
-            }
-            else
-            {
-                MultiByteToWideChar(CP_UNIXCP, 0, (LPSTR)label_read, -1, label, 11);
-                label[11] = '\0';
-            }
-            return 1;
-        }
-    }
-failure:
-    close(dev);
-    ERR("error reading label !\n");
-    return 0;
-}
-
-/**************************************************************************
- *				CDROM_GetLabel			[internal]
- */
-static DWORD CDROM_GetLabel(int drive, WCHAR *label)
-{
-    HANDLE              h;
-    CDROM_DISK_DATA     cdd;
-    DWORD               br, ret = 1;
-    BOOL                r;
-
-    h = CDROM_Open(drive);
-    if( !h ) 
-        return 0;
-    r = DeviceIoControl(h, IOCTL_CDROM_DISK_TYPE, NULL, 
-                        0, &cdd, sizeof(cdd), &br, 0);
-    CloseHandle( h );
-    if( !r )
-        return 0;
-
-    switch (cdd.DiskData & 0x03)
-    {
-    case CDROM_DISK_DATA_TRACK:
-        if (!CDROM_Data_GetLabel(drive, label))
-            ret = 0;
-        break;
-    case CDROM_DISK_AUDIO_TRACK:
-    {
-        static const WCHAR audioCD[] = {'A','u','d','i','o',' ','C','D',' ',' ',' ',0};
-        strcpyW(label, audioCD);
-        break;
-    }
-    case CDROM_DISK_DATA_TRACK|CDROM_DISK_AUDIO_TRACK:
-        FIXME("Need to get the label of a mixed mode CD!\n");
-	/* This assumes that the first track is a data track! */
-	/* I guess the correct way would be to enumerate all data tracks
-	   and check each for the title */
-        if (!CDROM_Data_GetLabel(drive, label))
-            ret = 0;
-        break;
-    case 0:
-        ret = 0;
-        break;
-    }
-    TRACE("CD: label is %s\n", debugstr_w(label));
-
-    return ret;
-}
-/***********************************************************************
- *           DRIVE_GetLabel
- */
-LPCWSTR DRIVE_GetLabel( int drive )
-{
-    int read = 0;
-    char buff[DRIVE_SUPER];
-    int offs = -1;
-
-    if (!DRIVE_IsValid( drive )) return NULL;
-    if (DOSDrives[drive].type == DRIVE_CDROM)
-    {
-	read = CDROM_GetLabel(drive, DOSDrives[drive].label_read);
-    }
-    else
-    if (DOSDrives[drive].flags & DRIVE_READ_VOL_INFO)
-    {
-	if (DRIVE_ReadSuperblock(drive,(char *) buff))
-	    ERR("Invalid or unreadable superblock on %s (%c:).\n",
-		DOSDrives[drive].device, (char)(drive+'A'));
-	else {
-	    if (DOSDrives[drive].type == DRIVE_REMOVABLE ||
-		DOSDrives[drive].type == DRIVE_FIXED)
-		offs = 0x2b;
-
-	    /* FIXME: ISO9660 uses a 32 bytes long label. Should we do also? */
-	    if (offs != -1)
-                MultiByteToWideChar(CP_UNIXCP, 0, buff+offs, 11,
-                                    DOSDrives[drive].label_read, 11);
-	    DOSDrives[drive].label_read[11]='\0';
-	    read = 1;
-	}
-    }
-
-    return (read) ?
-	DOSDrives[drive].label_read : DOSDrives[drive].label_conf;
-}
-
-#define CDFRAMES_PERSEC                 75
-#define CDFRAMES_PERMIN                 (CDFRAMES_PERSEC * 60)
-#define FRAME_OF_ADDR(a) ((a)[0] * CDFRAMES_PERMIN + (a)[1] * CDFRAMES_PERSEC + (a)[2])
-#define FRAME_OF_TOC(toc, idx)  FRAME_OF_ADDR((toc).TrackData[idx - (toc).FirstTrack].Address)
-
-/**************************************************************************
- *                              CDROM_Audio_GetSerial           [internal]
- */
-static DWORD CDROM_Audio_GetSerial(HANDLE h)
-{
-    unsigned long serial = 0;
-    int i;
-    WORD wMagic;
-    DWORD dwStart, dwEnd, br;
-    CDROM_TOC toc;
-
-    if (!DeviceIoControl(h, IOCTL_CDROM_READ_TOC, NULL, 0, &toc, sizeof(toc), &br, 0))
-        return 0;
-
-    /*
-     * wMagic collects the wFrames from track 1
-     * dwStart, dwEnd collect the beginning and end of the disc respectively, in
-     * frames.
-     * There it is collected for correcting the serial when there are less than
-     * 3 tracks.
-     */
-    wMagic = toc.TrackData[0].Address[2];
-    dwStart = FRAME_OF_TOC(toc, toc.FirstTrack);
-
-    for (i = 0; i <= toc.LastTrack - toc.FirstTrack; i++) {
-        serial += (toc.TrackData[i].Address[0] << 16) |
-            (toc.TrackData[i].Address[1] << 8) | toc.TrackData[i].Address[2];
-    }
-    dwEnd = FRAME_OF_TOC(toc, toc.LastTrack + 1);
-
-    if (toc.LastTrack - toc.FirstTrack + 1 < 3)
-        serial += wMagic + (dwEnd - dwStart);
-
-    return serial;
-}
-
-/**************************************************************************
- *                              CDROM_Data_GetSerial            [internal]
- */
-static DWORD CDROM_Data_GetSerial(int drive)
-{
-    int dev = open(DOSDrives[drive].device, O_RDONLY|O_NONBLOCK);
-    WORD offs;
-    union {
-        unsigned long val;
-        unsigned char p[4];
-    } serial;
-    BYTE b0 = 0, b1 = 1, b2 = 2, b3 = 3;
-
-
-    if (dev == -1) return 0;
-    offs = CDROM_Data_FindBestVoldesc(dev);
-
-    serial.val = 0;
-    if (offs)
-    {
-        BYTE buf[2048];
-        RTL_OSVERSIONINFOEXW ovi;
-        int i;
-
-        lseek(dev, offs, SEEK_SET);
-        read(dev, buf, 2048);
-        /*
-         * OK, another braindead one... argh. Just believe it.
-         * Me$$ysoft chose to reverse the serial number in NT4/W2K.
-         * It's true and nobody will ever be able to change it.
-         */
-        ovi.dwOSVersionInfoSize = sizeof(ovi);
-        RtlGetVersion(&ovi);
-        if ((ovi.dwPlatformId == VER_PLATFORM_WIN32_NT) &&  (ovi.dwMajorVersion >= 4))
-        {
-            b0 = 3; b1 = 2; b2 = 1; b3 = 0;
-        }
-        for (i = 0; i < 2048; i += 4)
-        {
-            /* DON'T optimize this into DWORD !! (breaks overflow) */
-            serial.p[b0] += buf[i+b0];
-            serial.p[b1] += buf[i+b1];
-            serial.p[b2] += buf[i+b2];
-            serial.p[b3] += buf[i+b3];
-        }
-    }
-    close(dev);
-    return serial.val;
-}
-
-/**************************************************************************
- *				CDROM_GetSerial			[internal]
- */
-static DWORD CDROM_GetSerial(int drive)
-{
-    DWORD               serial = 0;
-    HANDLE              h;
-    CDROM_DISK_DATA     cdd;
-    DWORD               br;
-    BOOL                r;
-
-    TRACE("%d\n", drive);
-
-    h = CDROM_Open(drive);
-    if( !h ) 
-        return 0;
-    r = DeviceIoControl(h, IOCTL_CDROM_DISK_TYPE, NULL, 
-                        0, &cdd, sizeof(cdd), &br, 0);
-    if (!r)
-    {
-        CloseHandle(h);
-        return 0;
-    }
-
-    switch (cdd.DiskData & 0x03)
-    {
-    case CDROM_DISK_DATA_TRACK:
-        /* hopefully a data CD */
-        serial = CDROM_Data_GetSerial(drive);
-        break;
-    case CDROM_DISK_AUDIO_TRACK:
-        /* fall thru */
-    case CDROM_DISK_DATA_TRACK|CDROM_DISK_AUDIO_TRACK:
-        serial = CDROM_Audio_GetSerial(h);
-        break;
-    case 0:
-        break;
-    }
-
-    if (serial)
-        TRACE("CD serial number is %04x-%04x.\n", HIWORD(serial), LOWORD(serial));
-
-    CloseHandle(h);
-
-    return serial;
-}
-
-/***********************************************************************
- *           DRIVE_GetSerialNumber
- */
-DWORD DRIVE_GetSerialNumber( int drive )
-{
-    DWORD serial = 0;
-    char buff[DRIVE_SUPER];
-
-    TRACE("drive %d, type = %d\n", drive, DOSDrives[drive].type);
-
-    if (!DRIVE_IsValid( drive )) return 0;
-
-    if (DOSDrives[drive].flags & DRIVE_READ_VOL_INFO)
-    {
-	switch(DOSDrives[drive].type)
-	{
-        case DRIVE_REMOVABLE:
-        case DRIVE_FIXED:
-            if (DRIVE_ReadSuperblock(drive,(char *) buff))
-                MESSAGE("Invalid or unreadable superblock on %s (%c:)."
-                        " Maybe not FAT?\n" ,
-                        DOSDrives[drive].device, 'A'+drive);
-            else
-                serial = *((DWORD*)(buff+0x27));
-            break;
-        case DRIVE_CDROM:
-            serial = CDROM_GetSerial(drive);
-            break;
-        default:
-            FIXME("Serial number reading from file system on drive %c: not supported yet.\n", drive+'A');
-	}
-    }
-
-    return (serial) ? serial : DOSDrives[drive].serial_conf;
-}
-
-
-/***********************************************************************
- *           DRIVE_SetSerialNumber
- */
-int DRIVE_SetSerialNumber( int drive, DWORD serial )
-{
-    char buff[DRIVE_SUPER];
-
-    if (!DRIVE_IsValid( drive )) return 0;
-
-    if (DOSDrives[drive].flags & DRIVE_READ_VOL_INFO)
-    {
-        if ((DOSDrives[drive].type != DRIVE_REMOVABLE) &&
-            (DOSDrives[drive].type != DRIVE_FIXED)) return 0;
-        /* check, if the drive has a FAT filesystem */
-        if (DRIVE_ReadSuperblock(drive, buff)) return 0;
-        if (DRIVE_WriteSuperblockEntry(drive, 0x27, 4, (char *) &serial)) return 0;
-        return 1;
-    }
-
-    if (DOSDrives[drive].type == DRIVE_CDROM) return 0;
-    DOSDrives[drive].serial_conf = serial;
-    return 1;
-}
-
-
 /***********************************************************************
  *           DRIVE_GetType
  */
@@ -1254,36 +671,6 @@
 
 
 /***********************************************************************
- *           DRIVE_Disable
- */
-int DRIVE_Disable( int drive  )
-{
-    if ((drive < 0) || (drive >= MAX_DOS_DRIVES) || !DOSDrives[drive].root)
-    {
-        SetLastError( ERROR_INVALID_DRIVE );
-        return 0;
-    }
-    DOSDrives[drive].flags |= DRIVE_DISABLED;
-    return 1;
-}
-
-
-/***********************************************************************
- *           DRIVE_Enable
- */
-int DRIVE_Enable( int drive  )
-{
-    if ((drive < 0) || (drive >= MAX_DOS_DRIVES) || !DOSDrives[drive].root)
-    {
-        SetLastError( ERROR_INVALID_DRIVE );
-        return 0;
-    }
-    DOSDrives[drive].flags &= ~DRIVE_DISABLED;
-    return 1;
-}
-
-
-/***********************************************************************
  *           DefineDosDeviceA       (KERNEL32.@)
  */
 BOOL WINAPI DefineDosDeviceA(DWORD flags,LPCSTR devname,LPCSTR targetpath)
@@ -1352,9 +739,6 @@
     strcpyW(new->dos_cwd, old->dos_cwd);
     new->unix_cwd = heap_strdup( old->unix_cwd );
     new->device   = heap_strdup( old->device );
-    memcpy ( new->label_conf, old->label_conf, 12 );
-    memcpy ( new->label_read, old->label_read, 12 );
-    new->serial_conf = old->serial_conf;
     new->type = old->type;
     new->flags = old->flags;
     new->dev = old->dev;
@@ -1980,162 +1364,3 @@
     }
     return ret;
 }
-
-
-/***********************************************************************
- *           GetVolumeInformationW   (KERNEL32.@)
- */
-BOOL WINAPI GetVolumeInformationW( LPCWSTR root, LPWSTR label,
-                                       DWORD label_len, DWORD *serial,
-                                       DWORD *filename_len, DWORD *flags,
-                                       LPWSTR fsname, DWORD fsname_len )
-{
-    int drive;
-    LPWSTR cp;
-
-    /* FIXME, SetLastError()s missing */
-
-    if (!root) drive = DRIVE_GetCurrentDrive();
-    else
-    {
-        if (root[0] && root[1] != ':')
-        {
-            WARN("invalid root %s\n", debugstr_w(root));
-            return FALSE;
-        }
-        drive = toupperW(root[0]) - 'A';
-    }
-    if (!DRIVE_IsValid( drive )) return FALSE;
-    if (label && label_len)
-    {
-       strncpyW( label, DRIVE_GetLabel(drive), label_len );
-       label[label_len - 1] = 0; /* ensure 0 termination */
-       cp = label + strlenW(label);
-       while (cp != label && *(cp-1) == ' ') cp--;
-       *cp = '\0';
-    }
-    if (serial) *serial = DRIVE_GetSerialNumber(drive);
-
-    /* Set the filesystem information */
-    /* Note: we only emulate a FAT fs at present */
-
-    if (filename_len) {
-    	if (DOSDrives[drive].flags & DRIVE_SHORT_NAMES)
-	    *filename_len = 12;
-	else
-	    *filename_len = 255;
-    }
-    if (flags)
-      {
-       *flags=0;
-       if (DOSDrives[drive].flags & DRIVE_CASE_SENSITIVE)
-         *flags|=FS_CASE_SENSITIVE;
-       if (DOSDrives[drive].flags & DRIVE_CASE_PRESERVING)
-         *flags|=FS_CASE_IS_PRESERVED;
-      }
-    if (fsname && fsname_len)
-    {
-    	/* Diablo checks that return code ... */
-        if (DOSDrives[drive].type == DRIVE_CDROM)
-        {
-            static const WCHAR cdfsW[] = {'C','D','F','S',0};
-            strncpyW( fsname, cdfsW, fsname_len );
-        }
-	else
-        {
-            static const WCHAR fatW[] = {'F','A','T',0};
-            strncpyW( fsname, fatW, fsname_len );
-        }
-        fsname[fsname_len - 1] = 0; /* ensure 0 termination */
-    }
-    return TRUE;
-}
-
-
-/***********************************************************************
- *           GetVolumeInformationA   (KERNEL32.@)
- */
-BOOL WINAPI GetVolumeInformationA( LPCSTR root, LPSTR label,
-                                       DWORD label_len, DWORD *serial,
-                                       DWORD *filename_len, DWORD *flags,
-                                       LPSTR fsname, DWORD fsname_len )
-{
-    UNICODE_STRING rootW;
-    LPWSTR labelW, fsnameW;
-    BOOL ret;
-
-    if (root) RtlCreateUnicodeStringFromAsciiz(&rootW, root);
-    else rootW.Buffer = NULL;
-    labelW = label ? HeapAlloc(GetProcessHeap(), 0, label_len * sizeof(WCHAR)) : NULL;
-    fsnameW = fsname ? HeapAlloc(GetProcessHeap(), 0, fsname_len * sizeof(WCHAR)) : NULL;
-
-    if ((ret = GetVolumeInformationW(rootW.Buffer, labelW, label_len, serial,
-                                    filename_len, flags, fsnameW, fsname_len)))
-    {
-        if (label) WideCharToMultiByte(CP_ACP, 0, labelW, -1, label, label_len, NULL, NULL);
-        if (fsname) WideCharToMultiByte(CP_ACP, 0, fsnameW, -1, fsname, fsname_len, NULL, NULL);
-    }
-
-    RtlFreeUnicodeString(&rootW);
-    if (labelW) HeapFree( GetProcessHeap(), 0, labelW );
-    if (fsnameW) HeapFree( GetProcessHeap(), 0, fsnameW );
-    return ret;
-}
-
-/***********************************************************************
- *           SetVolumeLabelW   (KERNEL32.@)
- */
-BOOL WINAPI SetVolumeLabelW( LPCWSTR root, LPCWSTR volname )
-{
-    int drive;
-
-    /* FIXME, SetLastErrors missing */
-
-    if (!root) drive = DRIVE_GetCurrentDrive();
-    else
-    {
-        if ((root[1]) && (root[1] != ':'))
-        {
-            WARN("invalid root %s\n", debugstr_w(root));
-            return FALSE;
-        }
-        drive = toupperW(root[0]) - 'A';
-    }
-    if (!DRIVE_IsValid( drive )) return FALSE;
-
-    /* some copy protection stuff check this */
-    if (DOSDrives[drive].type == DRIVE_CDROM) return FALSE;
-
-    strncpyW(DOSDrives[drive].label_conf, volname, 12);
-    DOSDrives[drive].label_conf[12 - 1] = 0; /* ensure 0 termination */
-    return TRUE;
-}
-
-/***********************************************************************
- *           SetVolumeLabelA   (KERNEL32.@)
- */
-BOOL WINAPI SetVolumeLabelA(LPCSTR root, LPCSTR volname)
-{
-    UNICODE_STRING rootW, volnameW;
-    BOOL ret;
-
-    if (root) RtlCreateUnicodeStringFromAsciiz(&rootW, root);
-    else rootW.Buffer = NULL;
-    if (volname) RtlCreateUnicodeStringFromAsciiz(&volnameW, volname);
-    else volnameW.Buffer = NULL;
-
-    ret = SetVolumeLabelW( rootW.Buffer, volnameW.Buffer );
-
-    RtlFreeUnicodeString(&rootW);
-    RtlFreeUnicodeString(&volnameW);
-    return ret;
-}
-
-/***********************************************************************
- *           GetVolumeNameForVolumeMountPointW   (KERNEL32.@)
- */
-BOOL WINAPI GetVolumeNameForVolumeMountPointW(LPCWSTR str, LPWSTR dst, DWORD size)
-{
-    FIXME("(%s, %p, %lx): stub\n", debugstr_w(str), dst, size);
-    return 0;
-}
diff --git a/include/drive.h b/include/drive.h
index 2f0bec5..b3d1cc1 100644
--- a/include/drive.h
+++ b/include/drive.h
@@ -32,7 +32,6 @@
 #define DRIVE_CASE_SENSITIVE  0x0004  /* Drive fs is case sensitive */
 #define DRIVE_CASE_PRESERVING 0x0008  /* Drive fs is case preserving */
 #define DRIVE_FAIL_READ_ONLY  0x0010  /* Fail opening read-only files for writing */
-#define DRIVE_READ_VOL_INFO   0x0020  /* Try to read volume info from the device? */
 
 extern int DRIVE_Init(void);
 extern int DRIVE_IsValid( int drive );
@@ -44,13 +43,8 @@
 extern LPCWSTR DRIVE_GetDosCwd( int drive );
 extern const char * DRIVE_GetUnixCwd( int drive );
 extern const char * DRIVE_GetDevice( int drive );
-extern LPCWSTR DRIVE_GetLabel( int drive );
-extern DWORD DRIVE_GetSerialNumber( int drive );
-extern int DRIVE_SetSerialNumber( int drive, DWORD serial );
 extern UINT DRIVE_GetFlags( int drive );
 extern int DRIVE_Chdir( int drive, LPCWSTR path );
-extern int DRIVE_Disable( int drive  );
-extern int DRIVE_Enable( int drive  );
 extern WCHAR *DRIVE_BuildEnv(void);
 
 #endif  /* __WINE_DRIVE_H */
diff --git a/include/winnt.h b/include/winnt.h
index a4ec815..41abe85 100644
--- a/include/winnt.h
+++ b/include/winnt.h
@@ -3305,6 +3305,10 @@
 #define FILE_PERSISTENT_ACLS            0x00000008
 #define FILE_FILE_COMPRESSION           0x00000010
 #define FILE_VOLUME_IS_COMPRESSED       0x00008000
+#define FILE_SUPPORTS_OBJECT_IDS        0x00010000
+#define FILE_SUPPORTS_ENCRYPTION        0x00020000
+#define FILE_NAMED_STREAMS              0x00040000
+#define FILE_READ_ONLY_VOLUME           0x00080000
 
 /* File alignments (NT) */
 #define	FILE_BYTE_ALIGNMENT		0x00000000