ntdll / kernel32: #44

Eric Pouech pouech-eric at wanadoo.fr
Wed Feb 4 14:55:22 CST 2004


New scheme for type, label & serial number reading on drives
- rewrote GetDriveType[AW], GetDiskFreeSpace[AW],
   GetDiskFreeSpaceEx[AW], GetVolumeInformation[AW], SetVolumeLabel[AW],
   GetLogicalDriveStrings[AW], GetLogicalDrives according to new drive
   scheme (either from device or from files on hd)
- removed no longer needed part from files/drive.c and include/drive.h
-------------- next part --------------
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel43/file16.c dlls/kernel/file16.c
--- dlls/kernel43/file16.c	2004-01-14 22:29:56.000000000 +0100
+++ dlls/kernel/file16.c	2004-02-01 15:50:41.000000000 +0100
@@ -292,3 +292,33 @@
     GlobalFree16( handle );
     return TRUE;
 }
+
+/***********************************************************************
+ *           GetDiskFreeSpace   (KERNEL.422)
+ */
+BOOL16 WINAPI GetDiskFreeSpace16( LPCSTR root, LPDWORD cluster_sectors,
+                                  LPDWORD sector_bytes, LPDWORD free_clusters,
+                                  LPDWORD total_clusters )
+{
+    return GetDiskFreeSpaceA( root, cluster_sectors, sector_bytes,
+                                free_clusters, total_clusters );
+}
+
+/***********************************************************************
+ *           GetDriveType   (KERNEL.136)
+ * This function returns the type of a drive in Win16.
+ * Note that it returns DRIVE_REMOTE for CD-ROMs, since MSCDEX uses the
+ * remote drive API. The return value DRIVE_REMOTE for CD-ROMs has been
+ * verified on Win 3.11 and Windows 95. Some programs rely on it, so don't
+ * do any pseudo-clever changes.
+ *
+ * RETURNS
+ *	drivetype DRIVE_xxx
+ */
+UINT16 WINAPI GetDriveType16( UINT16 drive ) /* [in] number (NOT letter) of drive */
+{
+    WCHAR root[] = {'A'+drive,':',0};
+    UINT type = GetDriveTypeW(root);
+    if (type == DRIVE_CDROM) type = DRIVE_REMOTE;
+    return type;
+}
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel43/volume.c dlls/kernel/volume.c
--- dlls/kernel43/volume.c	2004-01-24 13:44:14.000000000 +0100
+++ dlls/kernel/volume.c	2004-02-01 15:51:22.000000000 +0100
@@ -32,6 +32,21 @@
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <errno.h>
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.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
@@ -40,15 +55,61 @@
 #include "winnls.h"
 #include "winreg.h"
 #include "winternl.h"
+#include "ntstatus.h"
+#include "winioctl.h"
+#include "ntddcdrm.h"
 
 #include "wine/windef16.h"
 #include "kernel_private.h"
 
 #include "wine/unicode.h"
 #include "wine/library.h"
+#include "wine/server.h"
 #include "wine/debug.h"
 
-WINE_DEFAULT_DEBUG_CHANNEL(file);
+WINE_DEFAULT_DEBUG_CHANNEL(volume);
+
+/***********************************************************************
+ *           VOLUME_GetNtStatus(void)
+ *
+ * Retrieve the Nt Status code from errno.
+ * This is a duplicate of ntdll/file.c FILE_GetNtStatus. Should disapear when
+ * volume/drive behavior gets properly handled in ntdll.
+ */
+static DWORD VOLUME_GetNtStatus(void)
+{
+    int err = errno;
+    DWORD nt;
+
+    TRACE( "errno = %d\n", err );
+    switch (err)
+    {
+    case EAGAIN:        nt = STATUS_SHARING_VIOLATION;          break;
+    case EBADF:         nt = STATUS_INVALID_HANDLE;             break;
+    case ENOSPC:        nt = STATUS_DISK_FULL;                  break;
+    case EPERM:
+    case EROFS:
+    case EACCES:        nt = STATUS_ACCESS_DENIED;              break;
+    case ENOENT:        nt = STATUS_OBJECT_NAME_NOT_FOUND;      break;
+    case EISDIR:        nt = STATUS_FILE_IS_A_DIRECTORY;        break;
+    case EMFILE:
+    case ENFILE:        nt = STATUS_NO_MORE_FILES;              break;
+    case EINVAL:
+    case ENOTEMPTY:     nt = STATUS_DIRECTORY_NOT_EMPTY;        break;
+    case EPIPE:         nt = STATUS_PIPE_BROKEN;                break;
+    case ENOTDIR:       nt = STATUS_NOT_A_DIRECTORY;            break;
+    case ENOMEDIUM:     nt = STATUS_NO_MEDIA_IN_DEVICE;         break;
+/*    case EIO:           nt = STATUS_IO_DEVICE_ERROR;            break; */
+    case EIO:           nt = STATUS_DISK_CORRUPT_ERROR;		break;
+    case ENOEXEC:       /* ?? */
+    case ESPIPE:        /* ?? */
+    case EEXIST:        /* ?? */
+    default:
+        FIXME( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
+        nt = STATUS_UNSUCCESSFUL;
+    }
+    return nt;
+}
 
 /******************************************************************
  *              get_volume
@@ -591,3 +652,1060 @@
     SetLastError(ERROR_FILE_NOT_FOUND);
     return 0;
 }
+
+#define DRIVE_SUPER 96
+
+enum FS_Type {FS_UNKNOWN, FS_FAT1216, FS_FAT32, FS_ISO9660};
+
+/******************************************************************
+ *		VOLUME_FindCdRomDataBestVoldesc
+ */
+static WORD VOLUME_FindCdRomDataBestVoldesc(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
+         */
+        if (lseek(fd, offs + 11, SEEK_SET) != offs + 11) continue;; /* check for non-ISO9660 signature */
+        if (read(fd, &sig, 3) != 3) continue;
+        if (sig[0] == 'R' && sig[1] == 'O' && sig[2]== 'M')
+            extra_offs = 8;
+        if (lseek(fd, offs + extra_offs, SEEK_SET) != offs + extra_offs) continue;
+        if (read(fd, &cur_vd_type, 1) != 1) continue;
+        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_ReadSuperblock
+ *
+ */
+static NTSTATUS VOLUME_ReadSuperblock(int fd, BYTE* buff, enum FS_Type *type)
+{
+    off_t       offs;
+    struct stat stat_buf;
+
+    memset(buff, 0, DRIVE_SUPER);
+
+    if (fstat(fd, &stat_buf) != 0) goto failure;
+    if (!S_ISBLK(stat_buf.st_mode))
+    {
+        ERR("Device is not a block device - check your config\n");
+        /* reset O_NONBLOCK */
+        return STATUS_BAD_DEVICE_TYPE;
+    }
+    if (fcntl(fd, F_SETFL, 0) < 0 || fcntl(fd, F_GETFL) & O_NONBLOCK)
+    {
+        ERR("fcntl() failed to reset O_NONBLOCK\n");
+        goto failure;
+    }
+    /* try a fixed disk, with a FAT partition */
+    if (lseek(fd, 0, SEEK_SET) == 0 && read(fd, buff, DRIVE_SUPER) == DRIVE_SUPER)
+    {    
+        if (buff[0] == 0xE9 || (buff[0] == 0xEB && buff[2] == 0x90))
+        {
+            /* guess which type of FAT we have */
+            unsigned sz, nsect, nclust;
+            sz = *(USHORT*)(buff + 0x16);
+            if (!sz) sz = *(ULONG*)(buff + 0x24);
+            nsect = *(USHORT*)(buff + 0x13);
+            if (!nsect) nsect = *(ULONG*)(buff + 0x20);
+            nsect -= *(USHORT*)(buff + 0x0E) + buff[0x10] * sz + 
+                (*(USHORT*)(buff + 0x11) * 32 + (*(USHORT*)(buff + 0x0B) - 1)) / *(USHORT*)(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 :)
+                     */
+                    *type = FS_FAT1216;
+                    return STATUS_SUCCESS;
+                }
+            }
+            else
+            {
+                if (!memcmp(buff+0x52, "FAT", 3))
+                {
+                    *type = FS_FAT32;
+                    return STATUS_SUCCESS;
+                }
+            }
+        }
+    }
+    /* then try a CDROM */
+    offs = VOLUME_FindCdRomDataBestVoldesc(fd);
+    if (!offs) return STATUS_UNSUCCESSFUL;
+    if (lseek(fd, offs, SEEK_SET) == offs && read(fd, buff, DRIVE_SUPER) == DRIVE_SUPER)
+    {
+        if (!strncmp(&buff[1], "CD001", 5)) /* Check for iso9660 present */
+        {
+            *type = FS_ISO9660;
+            return STATUS_SUCCESS;
+        }
+    } else goto failure;
+    return STATUS_UNSUCCESSFUL;
+ failure:
+    return VOLUME_GetNtStatus();
+}
+
+/**************************************************************************
+ *                              VOLUME_GetCdRomDataLabel             [internal]
+ */
+static NTSTATUS VOLUME_GetCdRomDataLabel(int fd, WCHAR *label, unsigned len)
+{
+#define LABEL_LEN       32+1
+    WCHAR       label_read[LABEL_LEN]; /* Unicode possible, too */
+    DWORD       unicode_id = 0;
+    WORD        offs;
+    NTSTATUS    status;
+
+    offs = VOLUME_FindCdRomDataBestVoldesc(fd);
+    if (offs)
+    {
+        if ((lseek(fd, offs+0x58, SEEK_SET) == offs+0x58) &&
+            (read(fd, &unicode_id, 3) == 3))
+        {
+            int ver = (unicode_id & 0xff0000) >> 16;
+
+            if ((lseek(fd, offs + 0x28, SEEK_SET) != offs + 0x28) ||
+                (read(fd, &label_read, LABEL_LEN) != LABEL_LEN))
+            {
+                status = VOLUME_GetNtStatus();
+                goto failure;
+            }
+
+            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
+            {
+                RtlMultiByteToUnicodeN(label, 11 * sizeof(WCHAR), NULL, 
+                                       (LPSTR)label_read, -1);
+                                       
+                label[11] = '\0';
+            }
+            return STATUS_SUCCESS;
+        } else status = VOLUME_GetNtStatus();
+    } else status = STATUS_NOT_SUPPORTED;
+failure:
+    ERR("error reading label !\n");
+    return status;
+}
+
+/**************************************************************************
+ *				VOLUME_GetCdRomLabel		[internal]
+ */
+static NTSTATUS VOLUME_GetCdRomLabel(int devfd, WCHAR* label, unsigned len)
+{
+    CDROM_DISK_DATA     cdd;
+    IO_STATUS_BLOCK     iosb;
+    HANDLE              hDevice;
+    
+    iosb.u.Status = wine_server_fd_to_handle(devfd, GENERIC_READ, FALSE, &hDevice);
+    if (iosb.u.Status) return iosb.u.Status;
+
+    NtDeviceIoControlFile(hDevice, NULL, NULL, NULL, &iosb, IOCTL_CDROM_DISK_TYPE,
+                          NULL, 0, &cdd, sizeof(cdd));
+    if (!iosb.u.Status)
+    {
+        switch (cdd.DiskData & 0x03)
+        {
+        case CDROM_DISK_DATA_TRACK:
+            iosb.u.Status = VOLUME_GetCdRomDataLabel(devfd, label, len);
+            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 */
+            iosb.u.Status = VOLUME_GetCdRomDataLabel(devfd, label, len);
+            break;
+        case 0:
+            iosb.u.Status = STATUS_NOT_IMPLEMENTED;
+            break;
+        }
+        TRACE("CD: label is %s (%lx)\n", debugstr_w(label), iosb.u.Status);
+    }
+    NtClose(hDevice);
+    return iosb.u.Status;
+}
+
+/******************************************************************
+ *		VOLUME_ReadTextFile
+ *
+ */
+static NTSTATUS VOLUME_ReadTextFile(const char* path, LPWSTR buffer, unsigned len)
+{
+    int         fl, rlen;
+    char        tmp[128];
+    NTSTATUS    status;
+
+    TRACE("%s\n", path);
+    fl = open(path, O_RDONLY);
+    if (fl == -1)
+    {
+        TRACE("File %s doesn't exist\n", path);
+        return VOLUME_GetNtStatus();
+    }
+
+    rlen = read(fl, tmp, sizeof(tmp) - 1);
+    if (rlen != -1)
+    {
+        while (rlen && (tmp[rlen - 1] == '\r' || tmp[rlen - 1] == '\n' || isspace(tmp[rlen - 1]))) rlen--;
+        tmp[rlen] = 0;
+        status = STATUS_SUCCESS;
+    }
+    else
+        status = VOLUME_GetNtStatus();
+    close(fl);
+    RtlMultiByteToUnicodeN(buffer, len * sizeof(WCHAR), NULL, tmp, rlen + 1);
+    return status;
+}
+
+/******************************************************************
+ *		VOLUME_GetLabel
+ */
+static NTSTATUS VOLUME_GetLabel(int fd, char drive, unsigned len, LPWSTR buffer)
+{
+    BYTE        buff[DRIVE_SUPER];
+    NTSTATUS    status = STATUS_UNSUCCESSFUL;
+    enum FS_Type type;
+
+    *buffer = 0;
+
+    if (fd != -1)
+    {
+        status = VOLUME_ReadSuperblock(fd, buff, &type);
+        if (status == STATUS_SUCCESS && (type == FS_FAT1216 || type == FS_FAT32))
+        {
+            char*       p = NULL;
+
+            switch (type)
+            {
+            case FS_FAT1216: p = buff + 0x2b; break;
+            case FS_FAT32:   p = buff + 0x47; break;
+            case FS_UNKNOWN: case FS_ISO9660:;
+            }
+	    if (len >= 12)
+            {
+                RtlMultiByteToUnicodeN(buffer, len * sizeof(WCHAR), NULL, p, 11);
+                buffer[11] = '\0';
+            }
+            return status;
+	}
+        status = VOLUME_GetCdRomLabel(fd, buffer, len);
+    }
+    if (status != STATUS_SUCCESS)
+    {
+        char    path[MAX_PATH];
+
+        sprintf(path, "%s/dosdevices/%c:/.windows-label", wine_get_config_dir(), drive);
+        status = VOLUME_ReadTextFile(path, buffer, len);
+        if (status != STATUS_SUCCESS)
+        {
+            sprintf(path, "%s/device/%c:/label", wine_get_config_dir(), drive);
+            status = VOLUME_ReadTextFile(path, buffer, len);
+        }
+    }
+    return status;
+}
+
+#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)
+
+/**************************************************************************
+ *                              VOLUME_GetCdRomAudioSerial           [internal]
+ */
+static NTSTATUS VOLUME_GetCdRomAudioSerial(HANDLE hDevice, DWORD* serial)
+{
+    int                 i;
+    WORD                wMagic;
+    DWORD               dwStart, dwEnd;
+    CDROM_TOC           toc;
+    IO_STATUS_BLOCK     iosb;
+
+    NtDeviceIoControlFile(hDevice, NULL, NULL, NULL, &iosb, IOCTL_CDROM_READ_TOC, 
+                          NULL, 0, &toc, sizeof(toc));
+    if (iosb.u.Status == STATUS_SUCCESS)
+    {
+        /*
+         * 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);
+        *serial = 0;
+        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 iosb.u.Status;
+}
+
+/**************************************************************************
+ *                              VOLUME_GetCdRomDataSerial            [internal]
+ */
+static NTSTATUS VOLUME_GetCdRomDataSerial(int fd, DWORD* serial)
+{
+    WORD        offs;
+    union {
+        unsigned long val;
+        unsigned char p[4];
+    } userial;
+    BYTE        b0 = 0, b1 = 1, b2 = 2, b3 = 3;
+    BYTE        buf[2048];
+    RTL_OSVERSIONINFOEXW ovi;
+    int         i;
+
+    offs = VOLUME_FindCdRomDataBestVoldesc(fd);
+    userial.val = 0;
+    if (!offs) return STATUS_NOT_SUPPORTED;
+
+    lseek(fd, offs, SEEK_SET);
+    read(fd, 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) */
+        userial.p[b0] += buf[i+b0];
+        userial.p[b1] += buf[i+b1];
+        userial.p[b2] += buf[i+b2];
+        userial.p[b3] += buf[i+b3];
+    }
+    *serial = userial.val;
+    return STATUS_SUCCESS;
+}
+
+/**************************************************************************
+ *			VOLUME_GetCdRomSerial			[internal]
+ */
+static NTSTATUS VOLUME_GetCdRomSerial(int devfd, DWORD* serial)
+{
+    CDROM_DISK_DATA     cdd;
+    IO_STATUS_BLOCK     iosb;
+    HANDLE              hDevice;
+
+    iosb.u.Status = wine_server_fd_to_handle(devfd, GENERIC_READ, FALSE, &hDevice);
+    if (iosb.u.Status) return iosb.u.Status;
+
+    NtDeviceIoControlFile(hDevice, NULL, NULL, NULL, &iosb, IOCTL_CDROM_DISK_TYPE, 
+                          NULL, 0, &cdd, sizeof(cdd));
+    if (iosb.u.Status == STATUS_SUCCESS)
+    {
+        switch (cdd.DiskData & 0x03)
+        {
+        case CDROM_DISK_DATA_TRACK:
+            /* hopefully a data CD */
+            iosb.u.Status = VOLUME_GetCdRomDataSerial(devfd, serial);
+            break;
+        case CDROM_DISK_AUDIO_TRACK:
+            /* fall thru */
+        case CDROM_DISK_DATA_TRACK|CDROM_DISK_AUDIO_TRACK:
+            iosb.u.Status = VOLUME_GetCdRomAudioSerial(hDevice, serial);
+            break;
+        case 0:
+            iosb.u.Status = STATUS_NOT_SUPPORTED;
+            break;
+        }
+    } 
+
+    if (iosb.u.Status == STATUS_SUCCESS)
+        TRACE("CD serial number is %04x-%04x.\n", HIWORD(*serial), LOWORD(*serial));
+    NtClose(hDevice);
+
+    return iosb.u.Status;
+}
+
+/******************************************************************
+ *		VOLUME_ReadSerialFile
+ *
+ */
+static NTSTATUS VOLUME_ReadSerialFile(const char* path, DWORD* serial)
+{
+    int         fl, rlen;
+    char        tmp[128];
+    NTSTATUS    status;
+
+    TRACE("%s\n", path);
+    if ((fl = open(path, O_RDONLY)) == -1)
+    {
+        status = VOLUME_GetNtStatus();
+        TRACE("File %s doesn't exist (%lx)\n", path, status);
+    }
+    else
+    {
+        rlen = read(fl, tmp, sizeof(tmp) - 1);
+        status = (rlen == -1) ? VOLUME_GetNtStatus() : STATUS_SUCCESS;
+        close(fl);
+        if (status == STATUS_SUCCESS)
+        {
+            char* end;
+            tmp[rlen] = 0;
+            *serial = strtoul(tmp, &end, 10);
+            if (!*tmp || end == tmp) status = STATUS_INVALID_PARAMETER;
+        }
+    }
+    return status;
+}
+
+/******************************************************************
+ *		VOLUME_GetSerial
+ */
+static NTSTATUS VOLUME_GetSerial(int fd, char drive, DWORD* serial)
+{
+    BYTE        buff[DRIVE_SUPER];
+    NTSTATUS    status = STATUS_NOT_SUPPORTED;
+
+    TRACE("%d %c %p\n", fd, drive, serial);
+
+    /* if we have something already set up (how to get back to registry ??) 
+     * return this
+     */
+    if (fd != -1)
+    {
+        enum FS_Type    type;;
+        
+        status = VOLUME_ReadSuperblock(fd, buff, &type);
+        if (status == STATUS_SUCCESS)
+        {
+            switch (type)
+            {
+            case FS_FAT1216:
+                *serial = *(DWORD*)(buff + 0x27);
+                break;
+            case FS_FAT32:
+                *serial = *(DWORD*)(buff + 0x33);
+                break;
+            default:
+                status = VOLUME_GetCdRomSerial(fd, serial);
+                break;
+            }
+        }
+        else status = VOLUME_GetCdRomSerial(fd, serial);
+    }
+    if (status != STATUS_SUCCESS)
+    {
+        char    path[MAX_PATH];
+
+        sprintf(path, "%s/dosdevices/%c:/.windows-serial", wine_get_config_dir(), drive);
+        status = VOLUME_ReadSerialFile(path, serial);
+
+        if (status != STATUS_SUCCESS)
+        {
+            sprintf(path, "%s/device/%c:/serial", wine_get_config_dir(), drive);
+            status = VOLUME_ReadSerialFile(path, serial);
+        }
+        if (status != STATUS_SUCCESS) *serial = 0;
+    }
+    return status;
+}
+
+
+/******************************************************************
+ *		VOLUME_GetFsInfo
+ */
+static NTSTATUS VOLUME_GetFsInfo(int fd, FILE_FS_SIZE_INFORMATION* ffsi)
+{
+    struct statfs       info;
+
+/* FIXME: add autoconf check for this */
+#if defined(__svr4__) || defined(_SCO_DS) || defined(__sun)
+    /* FIXME: is this still correct ???? */
+    if (fstatfs(fd, &info, 0, 0) < 0)
+#else
+    if (fstatfs(fd, &info) < 0)
+#endif
+    {
+        WARN("cannot do statfs\n");
+        return VOLUME_GetNtStatus();
+    }
+
+    ffsi->BytesPerSector = info.f_bsize;
+    /* FIXME: we don't get the real geometry (yet) */
+    ffsi->SectorsPerAllocationUnit = 1; 
+    ffsi->TotalAllocationUnits.QuadPart = info.f_blocks;
+#ifdef HAVE_STRUCT_STATFS_F_BAVAIL
+    ffsi->AvailableAllocationUnits.QuadPart = info.f_bavail;
+#else
+# ifdef HAVE_STRUCT_STATFS_F_BFREE
+    ffsi->AvailableAllocationUnits.QuadPart = info.f_bfree;
+# else
+#  error "statfs has no bfree/bavail member!"
+# endif
+#endif
+    if (info.f_type == 0x9660) /* ISO 9660 FS */
+        ffsi->AvailableAllocationUnits.QuadPart = 0;
+    return STATUS_SUCCESS;
+}
+
+
+/******************************************************************
+ *		get_root
+ *
+ * Helper for several disk manipulation functions
+ * Check that root is a valid disk definition, and if so open the device
+ */
+static BOOL get_root(LPCWSTR root, BOOL checkslash, char* drive)
+{
+    WCHAR       path[MAX_PATH];
+
+    if (root)
+    {
+        /* FIXME: check length */
+        RtlGetFullPathName_U(root, sizeof(path), path, NULL);
+        if (checkslash)
+            checkslash = (path[2] != '/' && path[2] != '\\') || path[3] != '\0';
+        if (!path[0] || !path[1] || checkslash)
+        {
+            SetLastError(ERROR_PATH_NOT_FOUND);
+            return FALSE;
+        }
+    }
+    else GetCurrentDirectoryW(sizeof(path) / sizeof(WCHAR), path);
+    if (toupperW(path[0]) < 'A' || toupperW(path[0]) > 'Z' || path[1] != ':')
+    {
+        SetLastError(ERROR_PATH_NOT_FOUND);
+        return FALSE;
+    }
+    *drive = tolowerW(path[0]);
+    return TRUE;
+}
+
+/***********************************************************************
+ *           GetDiskFreeSpaceW   (KERNEL32.@)
+ *
+ * Fails if expression resulting from current drive's dir and "root"
+ * is not a root dir of the target drive.
+ *
+ * UNDOC: setting some LPDWORDs to NULL is perfectly possible
+ * if the corresponding info is unneeded.
+ *
+ * FIXME: needs to support UNC names from Win95 OSR2 on.
+ *
+ * Behaviour under Win95a:
+ * CurrDir     root   result
+ * "E:\\TEST"  "E:"   FALSE
+ * "E:\\"      "E:"   TRUE
+ * "E:\\"      "E"    FALSE
+ * "E:\\"      "\\"   TRUE
+ * "E:\\TEST"  "\\"   TRUE
+ * "E:\\TEST"  ":\\"  FALSE
+ * "E:\\TEST"  "E:\\" TRUE
+ * "E:\\TEST"  ""     FALSE
+ * "E:\\"      ""     FALSE (!)
+ * "E:\\"      0x0    TRUE
+ * "E:\\TEST"  0x0    TRUE  (!)
+ * "E:\\TEST"  "C:"   TRUE  (when CurrDir of "C:" set to "\\")
+ * "E:\\TEST"  "C:"   FALSE (when CurrDir of "C:" set to "\\TEST")
+ */
+BOOL WINAPI GetDiskFreeSpaceW( LPCWSTR root, LPDWORD cluster_sectors,
+                               LPDWORD sector_bytes, LPDWORD free_clusters,
+                               LPDWORD total_clusters )
+{
+    char                        drive;
+    FILE_FS_SIZE_INFORMATION    ffsi;
+    char                        path[MAX_PATH];
+    int                         mntfd;
+    NTSTATUS                    status;
+
+    TRACE("%s,%p,%p,%p,%p\n", debugstr_w(root), cluster_sectors, sector_bytes,
+          free_clusters, total_clusters);
+
+    if (!get_root(root, TRUE, &drive)) return FALSE;
+    sprintf(path, "%s/dosdevices/%c:", wine_get_config_dir(), drive);
+
+    if ((mntfd = open(path, O_RDONLY)) != -1)
+    {
+        status = VOLUME_GetFsInfo(mntfd, &ffsi);
+        close(mntfd);
+    }
+    else status = VOLUME_GetNtStatus();
+    if (status)
+    {
+        SetLastError(RtlNtStatusToDosError(status));
+        /* hack hack hack (could be cleaned up a bit) */
+        if (GetLastError() == ERROR_FILE_NOT_FOUND) 
+            SetLastError(ERROR_PATH_NOT_FOUND);
+        return FALSE;
+    }
+
+    if (cluster_sectors) *cluster_sectors = ffsi.SectorsPerAllocationUnit;
+    if (sector_bytes)    *sector_bytes    = ffsi.BytesPerSector;
+    if (free_clusters)   *free_clusters   = ffsi.AvailableAllocationUnits.u.LowPart;
+    if (total_clusters)  *total_clusters  = ffsi.TotalAllocationUnits.u.LowPart;
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           GetDiskFreeSpaceA   (KERNEL32.@)
+ */
+BOOL WINAPI GetDiskFreeSpaceA( LPCSTR root, LPDWORD cluster_sectors,
+                               LPDWORD sector_bytes, LPDWORD free_clusters,
+                               LPDWORD total_clusters )
+{
+    UNICODE_STRING rootW;
+    BOOL ret = FALSE;
+
+    if (root)
+    {
+        if(!RtlCreateUnicodeStringFromAsciiz(&rootW, root))
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            return FALSE;
+        }
+    }
+    else
+        rootW.Buffer = NULL;
+
+    ret = GetDiskFreeSpaceW(rootW.Buffer, cluster_sectors, sector_bytes,
+                            free_clusters, total_clusters );
+    RtlFreeUnicodeString(&rootW);
+
+    return ret;
+}
+
+
+/***********************************************************************
+ *           GetDiskFreeSpaceExW   (KERNEL32.@)
+ *
+ *  This function is used to acquire the size of the available and
+ *  total space on a logical volume.
+ *
+ * RETURNS
+ *
+ *  Zero on failure, nonzero upon success. Use GetLastError to obtain
+ *  detailed error information.
+ *
+ */
+BOOL WINAPI GetDiskFreeSpaceExW( LPCWSTR root,
+                                 PULARGE_INTEGER avail,
+                                 PULARGE_INTEGER total,
+                                 PULARGE_INTEGER totalfree)
+{
+    char                        drive, path[MAX_PATH];
+    FILE_FS_SIZE_INFORMATION    ffsi;
+    NTSTATUS                    status;
+    int                         mntfd;
+
+    /* FIXME: this will give wrong results if root points to a cdrom mount point
+     * which is not mounted (will return info on drive holding the mount point)
+     */
+    if (!get_root(root, TRUE, &drive)) return FALSE;
+
+    sprintf(path, "%s/dosdevices/%c:", wine_get_config_dir(), drive);
+    if ((mntfd = open(path, O_RDONLY)) != -1)
+    {
+        status = VOLUME_GetFsInfo(mntfd, &ffsi);
+        close(mntfd);
+    }
+    else status = VOLUME_GetNtStatus();
+
+    if (status)
+    {
+        SetLastError(RtlNtStatusToDosError(status));
+        return FALSE;
+    }
+    if (total) 
+        total->QuadPart = ffsi.TotalAllocationUnits.QuadPart *
+            ffsi.SectorsPerAllocationUnit *
+            ffsi.BytesPerSector;
+    if (totalfree)
+        totalfree->QuadPart = ffsi.AvailableAllocationUnits.QuadPart *
+            ffsi.SectorsPerAllocationUnit *
+            ffsi.BytesPerSector;
+
+    if (avail)
+    {
+        if (FIXME_ON(volume))
+	{
+            /* On Windows2000, we need to check the disk quota
+	       allocated for the user owning the calling process. We
+	       don't want to be more obtrusive than necessary with the
+	       FIXME messages, so don't print the FIXME unless Wine is
+	       actually masquerading as Windows2000. */
+
+            RTL_OSVERSIONINFOEXW ovi;
+	    ovi.dwOSVersionInfoSize = sizeof(ovi);
+	    if (RtlGetVersion(&ovi))
+	    {
+	      if (ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4)
+                  FIXME("no per-user quota support yet\n");
+	    }
+	}
+
+        /* Quick hack, should eventually be fixed to work 100% with
+           Windows2000 (see comment above). */
+        avail->QuadPart = ffsi.AvailableAllocationUnits.QuadPart *
+            ffsi.SectorsPerAllocationUnit *
+            ffsi.BytesPerSector;
+    }
+
+    return TRUE;
+}
+
+/***********************************************************************
+ *           GetDiskFreeSpaceExA   (KERNEL32.@)
+ */
+BOOL WINAPI GetDiskFreeSpaceExA( LPCSTR root, PULARGE_INTEGER avail,
+				     PULARGE_INTEGER total,
+				     PULARGE_INTEGER  totalfree)
+{
+    UNICODE_STRING rootW;
+    BOOL ret;
+
+    if (root) RtlCreateUnicodeStringFromAsciiz(&rootW, root);
+    else rootW.Buffer = NULL;
+
+    ret = GetDiskFreeSpaceExW( rootW.Buffer, avail, total, totalfree);
+
+    RtlFreeUnicodeString(&rootW);
+    return ret;
+}
+
+/***********************************************************************
+ *           GetDriveTypeW   (KERNEL32.@)
+ *
+ * Returns the type of the disk drive specified. If root is NULL the
+ * root of the current directory is used.
+ *
+ * RETURNS
+ *
+ *  Type of drive (from Win32 SDK):
+ *
+ *   DRIVE_UNKNOWN     unable to find out anything about the drive
+ *   DRIVE_NO_ROOT_DIR nonexistent root dir
+ *   DRIVE_REMOVABLE   the disk can be removed from the machine
+ *   DRIVE_FIXED       the disk can not be removed from the machine
+ *   DRIVE_REMOTE      network disk
+ *   DRIVE_CDROM       CDROM drive
+ *   DRIVE_RAMDISK     virtual disk in RAM
+ */
+UINT WINAPI GetDriveTypeW(LPCWSTR root) /* [in] String describing drive */
+{
+    UINT        res = DRIVE_NO_ROOT_DIR;
+    char        drive;
+
+    TRACE("(%s)\n", debugstr_w(root));
+
+    if (get_root(root, FALSE, &drive)) 
+    {
+        char    path[MAX_PATH];
+        int     fd, rlen;
+        char    tmp[128];
+
+        sprintf(path, "%s/device/%c:/type", wine_get_config_dir(), drive);
+
+        if ((fd = open(path, O_RDONLY)) != -1)
+        {
+            rlen = read(fd, tmp, sizeof(tmp) - 1);
+            if (rlen != -1)
+            {
+                while (rlen && (tmp[rlen - 1] == '\r' || tmp[rlen - 1] == '\n' || isspace(tmp[rlen - 1]))) rlen--;
+                tmp[rlen] = 0;
+                if (!strcmp(tmp, "hard-disk"))                  res = DRIVE_FIXED;
+                else if (!strcmp(tmp, "floppy-disk"))           res = DRIVE_REMOVABLE;
+                else if (!strcmp(tmp, "removable-disk"))        res = DRIVE_REMOVABLE;
+                else if (!strcmp(tmp, "remote-disk"))           res = DRIVE_REMOTE;
+                else if (!strcmp(tmp, "cdrom"))                 res = DRIVE_CDROM;
+                else if (!strcmp(tmp, "ram-disk"))              res = DRIVE_RAMDISK;
+                else
+                {
+                    WARN("Unknown drive type %s for %c:\n", tmp, toupper(drive));
+                    res = DRIVE_UNKNOWN;
+                }
+            }
+            else TRACE("Cannot read file (%s) for type of drive %c:\n", path, toupper(drive));
+            close(fd);
+        }
+        else
+        {
+            struct stat ds;
+            sprintf(path, "%s/device/%c:/", wine_get_config_dir(), drive);
+            if (stat(path, &ds) != -1 && S_ISDIR(ds.st_mode))
+            {
+                TRACE("File %s for type of drive %c: doesn't exist\n", path, toupper(drive));
+                res = DRIVE_FIXED;
+            }
+            else
+                res = DRIVE_NO_ROOT_DIR;
+        }
+    }
+    return res;
+}
+
+
+/***********************************************************************
+ *           GetDriveTypeA   (KERNEL32.@)
+ */
+UINT WINAPI GetDriveTypeA( LPCSTR root )
+{
+    UNICODE_STRING rootW;
+    UINT ret = 0;
+
+    if (root)
+    {
+        if( !RtlCreateUnicodeStringFromAsciiz(&rootW, root))
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            return 0;
+        }
+    }
+    else
+        rootW.Buffer = NULL;
+
+    ret = GetDriveTypeW(rootW.Buffer);
+
+    RtlFreeUnicodeString(&rootW);
+    return ret;
+
+}
+
+/***********************************************************************
+ *           GetLogicalDriveStringsA   (KERNEL32.@)
+ */
+UINT WINAPI GetLogicalDriveStringsA( UINT len, LPSTR buffer )
+{
+    unsigned    size = GetLogicalDriveStringsW(0, NULL);
+    LPWSTR      ptr = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
+
+    if (!ptr) return 0;
+    size = GetLogicalDriveStringsW( size, ptr );
+    if (!size) return 0;
+    WideCharToMultiByte(CP_ACP, 0, ptr, size + 1, buffer, len, NULL, NULL);
+    HeapFree(GetProcessHeap(), 0, ptr);
+    return size; /* FIXME */
+}
+
+
+/***********************************************************************
+ *           GetLogicalDriveStringsW   (KERNEL32.@)
+ */
+UINT WINAPI GetLogicalDriveStringsW( UINT len, LPWSTR buffer )
+{
+    unsigned            count = 0;
+    char                path[MAX_PATH];
+    DIR*                dir;
+    struct dirent*      de;
+
+    sprintf(path, "%s/dosdevices/", wine_get_config_dir());
+    
+    dir = opendir(path);
+    if (!dir)
+    {
+        FILE_SetDosError();
+        return 0;
+    }
+    while ((de = readdir(dir)))
+    {
+        if (de->d_name[1] != ':' || de->d_name[2]) continue;
+        if (count + 4 < len)
+        {
+            buffer[count + 0] = (WCHAR)de->d_name[0];
+            buffer[count + 1] = (WCHAR)':';
+            buffer[count + 2] = (WCHAR)'\\';
+            buffer[count + 3] = (WCHAR)'\0';
+        }
+        count += 4;
+    }
+    closedir(dir);
+    if (count >= len) return count + 1;
+    buffer[count] = (WCHAR)'\0';
+    return count;
+}
+
+
+/***********************************************************************
+ *           GetLogicalDrives   (KERNEL32.@)
+ */
+DWORD WINAPI GetLogicalDrives(void)
+{
+    DWORD               ret = 0;
+    char                path[MAX_PATH];
+    DIR*                dir;
+    struct dirent*      de;
+
+    sprintf(path, "%s/dosdevices/", wine_get_config_dir());
+
+    dir = opendir(path);
+    if (!dir)
+    {
+        FILE_SetDosError();
+        return 0;
+    }
+    while ((de = readdir(dir)))
+    {
+        if (de->d_name[1] != ':' || de->d_name[2]) continue;
+        ret |= 1 << (tolower(de->d_name[0]) - 'a');
+    }
+    closedir(dir);
+    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 )
+{
+    char                drive, dev[MAX_PATH], buff[DRIVE_SUPER];
+    NTSTATUS            status = STATUS_SUCCESS;
+    unsigned            len;
+    int                 devfd;
+    enum FS_Type        type = FS_UNKNOWN;
+    LPCWSTR             ptr = NULL;
+
+    static const WCHAR cdfsW[] = {'C','D','F','S',0};
+    static const WCHAR fatW[] = {'F','A','T',0};
+    static const WCHAR unkW[] = {'U','N','K','N','O','W','N',0};
+
+    if (!get_root(root, TRUE, &drive)) return FALSE;
+
+    sprintf(dev, "%s/device/%c:/device", wine_get_config_dir(), drive);
+    devfd = open(dev, O_RDONLY|O_NONBLOCK);
+    if ((serial && (status = VOLUME_GetSerial(devfd, drive, serial))) ||
+        (label && label_len && (status = VOLUME_GetLabel(devfd, drive, label_len, label))))
+        goto failure;
+
+    if (flags) *flags = 0; /* FIXME */
+    if (filename_len) *filename_len = 255; /* FIXME could be 12 */
+
+    if (fsname && fsname_len)
+    {
+        if (devfd != -1 && VOLUME_ReadSuperblock(devfd, buff, &type))
+            goto failure;
+        /* Note: we only emulate a FAT fs at present */
+        switch (type)
+        {
+        case FS_FAT1216:
+        case FS_FAT32:  ptr = fatW;  break;
+        case FS_ISO9660:ptr = cdfsW; break;
+        case FS_UNKNOWN:ptr = unkW;  break;
+        }
+        len = min(fsname_len, strlenW(ptr) + 1);
+        strncpyW(fsname, ptr, len);
+        fsname[len] = '\0';
+    }
+    if (devfd != -1) close(devfd);
+    return TRUE;
+ failure:
+    if (devfd != -1) close(devfd);
+    SetLastError(RtlNtStatusToDosError(status));
+    return FALSE;
+}
+
+
+/***********************************************************************
+ *           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 )
+{
+    FIXME("%s %p\n", debugstr_w(root), volname);
+
+    SetLastError(ERROR_NOT_SUPPORTED);
+    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;
+}
diff -u -N -r -x '*~' -x '.#*' -x CVS files43/drive.c files/drive.c
--- files43/drive.c	2004-01-23 22:24:19.000000000 +0100
+++ files/drive.c	2004-01-23 22:27:33.000000000 +0100
@@ -82,10 +82,6 @@
     char     *root;      /* root dir in Unix format without trailing / */
     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 */
@@ -196,14 +192,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);
@@ -266,7 +258,6 @@
 
             drive->dos_cwd  = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(drive->dos_cwd[0]));
             drive->unix_cwd = heap_strdup( "" );
-            drive->device   = NULL;
             drive->flags    = 0;
             drive->dev      = drive_stat_buffer.st_dev;
             drive->ino      = drive_stat_buffer.st_ino;
@@ -280,29 +271,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 ))
@@ -317,27 +285,22 @@
             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);
+                char *device;
 
-                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;
+                len = WideCharToMultiByte(CP_UNIXCP, 0, data, -1, NULL, 0, NULL, NULL);
+                device = HeapAlloc(GetProcessHeap(), 0, len);
+                WideCharToMultiByte(CP_UNIXCP, 0, data, -1, device, len, NULL, NULL);
 
                 if (drive->type == DRIVE_CDROM)
                 {
                     int cd_fd;
-                    if ((cd_fd = open(drive->device, O_RDONLY|O_NONBLOCK)) != -1)
+                    if ((cd_fd = open(device, O_RDONLY|O_NONBLOCK)) != -1)
                     {
                         CDROM_InitRegistry(cd_fd);
                         close(cd_fd);
                     }
                 }
+                HeapFree(GetProcessHeap(), 0, device);
             }
 
             /* Get the FailReadOnly flag */
@@ -353,11 +316,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:
@@ -371,10 +332,7 @@
         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;
         DRIVE_CurDrive = 2;
     }
@@ -679,548 +637,6 @@
 
 
 /***********************************************************************
- *           DRIVE_GetDevice
- */
-const char * DRIVE_GetDevice( int drive )
-{
-    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
- */
-static UINT DRIVE_GetType( int drive )
-{
-    if (!DRIVE_IsValid( drive )) return DRIVE_NO_ROOT_DIR;
-    return DOSDrives[drive].type;
-}
-
-
-/***********************************************************************
  *           DRIVE_GetFlags
  */
 UINT DRIVE_GetFlags( int drive )
@@ -1316,49 +732,6 @@
 
 
 /***********************************************************************
- *           DRIVE_GetFreeSpace
- */
-static int DRIVE_GetFreeSpace( int drive, PULARGE_INTEGER size,
-			       PULARGE_INTEGER available )
-{
-    struct statfs info;
-
-    if (!DRIVE_IsValid(drive))
-    {
-        SetLastError( ERROR_PATH_NOT_FOUND );
-        return 0;
-    }
-
-/* FIXME: add autoconf check for this */
-#if defined(__svr4__) || defined(_SCO_DS) || defined(__sun)
-    if (statfs( DOSDrives[drive].root, &info, 0, 0) < 0)
-#else
-    if (statfs( DOSDrives[drive].root, &info) < 0)
-#endif
-    {
-        FILE_SetDosError();
-        WARN("cannot do statfs(%s)\n", DOSDrives[drive].root);
-        return 0;
-    }
-
-    size->QuadPart = RtlEnlargedUnsignedMultiply( info.f_bsize, info.f_blocks );
-#ifdef HAVE_STRUCT_STATFS_F_BAVAIL
-    available->QuadPart = RtlEnlargedUnsignedMultiply( info.f_bavail, info.f_bsize );
-#else
-# ifdef HAVE_STRUCT_STATFS_F_BFREE
-    available->QuadPart = RtlEnlargedUnsignedMultiply( info.f_bfree, info.f_bsize );
-# else
-#  error "statfs has no bfree/bavail member!"
-# endif
-#endif
-    if (DOSDrives[drive].type == DRIVE_CDROM)
-    { /* ALWAYS 0, even if no real CD-ROM mounted there !! */
-        available->QuadPart = 0;
-    }
-    return 1;
-}
-
-/***********************************************************************
  *       DRIVE_GetCurrentDirectory
  * Returns "X:\\path\\etc\\".
  *
@@ -1415,332 +788,6 @@
 
 
 /***********************************************************************
- *           GetDiskFreeSpace   (KERNEL.422)
- */
-BOOL16 WINAPI GetDiskFreeSpace16( LPCSTR root, LPDWORD cluster_sectors,
-                                  LPDWORD sector_bytes, LPDWORD free_clusters,
-                                  LPDWORD total_clusters )
-{
-    return GetDiskFreeSpaceA( root, cluster_sectors, sector_bytes,
-                                free_clusters, total_clusters );
-}
-
-
-/***********************************************************************
- *           GetDiskFreeSpaceW   (KERNEL32.@)
- *
- * Fails if expression resulting from current drive's dir and "root"
- * is not a root dir of the target drive.
- *
- * UNDOC: setting some LPDWORDs to NULL is perfectly possible
- * if the corresponding info is unneeded.
- *
- * FIXME: needs to support UNC names from Win95 OSR2 on.
- *
- * Behaviour under Win95a:
- * CurrDir     root   result
- * "E:\\TEST"  "E:"   FALSE
- * "E:\\"      "E:"   TRUE
- * "E:\\"      "E"    FALSE
- * "E:\\"      "\\"   TRUE
- * "E:\\TEST"  "\\"   TRUE
- * "E:\\TEST"  ":\\"  FALSE
- * "E:\\TEST"  "E:\\" TRUE
- * "E:\\TEST"  ""     FALSE
- * "E:\\"      ""     FALSE (!)
- * "E:\\"      0x0    TRUE
- * "E:\\TEST"  0x0    TRUE  (!)
- * "E:\\TEST"  "C:"   TRUE  (when CurrDir of "C:" set to "\\")
- * "E:\\TEST"  "C:"   FALSE (when CurrDir of "C:" set to "\\TEST")
- */
-BOOL WINAPI GetDiskFreeSpaceW( LPCWSTR root, LPDWORD cluster_sectors,
-                                   LPDWORD sector_bytes, LPDWORD free_clusters,
-                                   LPDWORD total_clusters )
-{
-    int	drive, sec_size;
-    ULARGE_INTEGER size,available;
-    LPCWSTR path;
-    DWORD cluster_sec;
-
-    TRACE("%s,%p,%p,%p,%p\n", debugstr_w(root), cluster_sectors, sector_bytes,
-          free_clusters, total_clusters);
-
-    if (!root || root[0] == '\\' || root[0] == '/')
-	drive = DRIVE_GetCurrentDrive();
-    else
-    if (root[0] && root[1] == ':') /* root contains drive tag */
-    {
-        drive = toupperW(root[0]) - 'A';
-	path = &root[2];
-	if (path[0] == '\0')
-        {
-	    path = DRIVE_GetDosCwd(drive);
-            if (!path)
-            {
-                SetLastError(ERROR_PATH_NOT_FOUND);
-                return FALSE;
-            }
-        }
-	else
-	if (path[0] == '\\')
-	    path++;
-
-        if (path[0]) /* oops, we are in a subdir */
-        {
-            SetLastError(ERROR_INVALID_NAME);
-            return FALSE;
-        }
-    }
-    else
-    {
-        if (!root[0])
-            SetLastError(ERROR_PATH_NOT_FOUND);
-        else
-            SetLastError(ERROR_INVALID_NAME);
-        return FALSE;
-    }
-
-    if (!DRIVE_GetFreeSpace(drive, &size, &available)) return FALSE;
-
-    /* Cap the size and available at 2GB as per specs.  */
-    if ((size.u.HighPart) ||(size.u.LowPart > 0x7fffffff))
-    {
-	size.u.HighPart = 0;
-	size.u.LowPart = 0x7fffffff;
-    }
-    if ((available.u.HighPart) ||(available.u.LowPart > 0x7fffffff))
-    {
-	available.u.HighPart =0;
-	available.u.LowPart = 0x7fffffff;
-    }
-    sec_size = (DRIVE_GetType(drive)==DRIVE_CDROM) ? 2048 : 512;
-    size.u.LowPart            /= sec_size;
-    available.u.LowPart       /= sec_size;
-    /* FIXME: probably have to adjust those variables too for CDFS */
-    cluster_sec = 1;
-    while (cluster_sec * 65536 < size.u.LowPart) cluster_sec *= 2;
-
-    if (cluster_sectors)
-	*cluster_sectors = cluster_sec;
-    if (sector_bytes)
-	*sector_bytes    = sec_size;
-    if (free_clusters)
-	*free_clusters   = available.u.LowPart / cluster_sec;
-    if (total_clusters)
-	*total_clusters  = size.u.LowPart / cluster_sec;
-    return TRUE;
-}
-
-
-/***********************************************************************
- *           GetDiskFreeSpaceA   (KERNEL32.@)
- */
-BOOL WINAPI GetDiskFreeSpaceA( LPCSTR root, LPDWORD cluster_sectors,
-                                   LPDWORD sector_bytes, LPDWORD free_clusters,
-                                   LPDWORD total_clusters )
-{
-    UNICODE_STRING rootW;
-    BOOL ret = FALSE;
-
-    if (root)
-    {
-        if(!RtlCreateUnicodeStringFromAsciiz(&rootW, root))
-        {
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            return FALSE;
-        }
-    }
-    else
-        rootW.Buffer = NULL;
-
-    ret = GetDiskFreeSpaceW(rootW.Buffer, cluster_sectors, sector_bytes,
-                            free_clusters, total_clusters );
-    RtlFreeUnicodeString(&rootW);
-
-    return ret;
-}
-
-
-/***********************************************************************
- *           GetDiskFreeSpaceExW   (KERNEL32.@)
- *
- *  This function is used to acquire the size of the available and
- *  total space on a logical volume.
- *
- * RETURNS
- *
- *  Zero on failure, nonzero upon success. Use GetLastError to obtain
- *  detailed error information.
- *
- */
-BOOL WINAPI GetDiskFreeSpaceExW( LPCWSTR root,
-				     PULARGE_INTEGER avail,
-				     PULARGE_INTEGER total,
-				     PULARGE_INTEGER totalfree)
-{
-    int	drive;
-    ULARGE_INTEGER size,available;
-
-    if (!root) drive = DRIVE_GetCurrentDrive();
-    else
-    { /* C: always works for GetDiskFreeSpaceEx */
-        if ((root[1]) && ((root[1] != ':') || (root[2] && root[2] != '\\')))
-        {
-            FIXME("there are valid root names which are not supported yet\n");
-	    /* ..like UNC names, for instance. */
-
-            WARN("invalid root '%s'\n", debugstr_w(root));
-            return FALSE;
-        }
-        drive = toupperW(root[0]) - 'A';
-    }
-
-    if (!DRIVE_GetFreeSpace(drive, &size, &available)) return FALSE;
-
-    if (total)
-    {
-        total->u.HighPart = size.u.HighPart;
-        total->u.LowPart = size.u.LowPart;
-    }
-
-    if (totalfree)
-    {
-        totalfree->u.HighPart = available.u.HighPart;
-        totalfree->u.LowPart = available.u.LowPart;
-    }
-
-    if (avail)
-    {
-        if (FIXME_ON(dosfs))
-	{
-            /* On Windows2000, we need to check the disk quota
-	       allocated for the user owning the calling process. We
-	       don't want to be more obtrusive than necessary with the
-	       FIXME messages, so don't print the FIXME unless Wine is
-	       actually masquerading as Windows2000. */
-
-            RTL_OSVERSIONINFOEXW ovi;
-	    ovi.dwOSVersionInfoSize = sizeof(ovi);
-	    if (RtlGetVersion(&ovi))
-	    {
-	      if (ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4)
-                  FIXME("no per-user quota support yet\n");
-	    }
-	}
-
-        /* Quick hack, should eventually be fixed to work 100% with
-           Windows2000 (see comment above). */
-        avail->u.HighPart = available.u.HighPart;
-        avail->u.LowPart = available.u.LowPart;
-    }
-
-    return TRUE;
-}
-
-/***********************************************************************
- *           GetDiskFreeSpaceExA   (KERNEL32.@)
- */
-BOOL WINAPI GetDiskFreeSpaceExA( LPCSTR root, PULARGE_INTEGER avail,
-				     PULARGE_INTEGER total,
-				     PULARGE_INTEGER  totalfree)
-{
-    UNICODE_STRING rootW;
-    BOOL ret;
-
-    if (root) RtlCreateUnicodeStringFromAsciiz(&rootW, root);
-    else rootW.Buffer = NULL;
-
-    ret = GetDiskFreeSpaceExW( rootW.Buffer, avail, total, totalfree);
-
-    RtlFreeUnicodeString(&rootW);
-    return ret;
-}
-
-/***********************************************************************
- *           GetDriveType   (KERNEL.136)
- * This function returns the type of a drive in Win16.
- * Note that it returns DRIVE_REMOTE for CD-ROMs, since MSCDEX uses the
- * remote drive API. The return value DRIVE_REMOTE for CD-ROMs has been
- * verified on Win 3.11 and Windows 95. Some programs rely on it, so don't
- * do any pseudo-clever changes.
- *
- * RETURNS
- *	drivetype DRIVE_xxx
- */
-UINT16 WINAPI GetDriveType16( UINT16 drive ) /* [in] number (NOT letter) of drive */
-{
-    UINT type = DRIVE_GetType(drive);
-    TRACE("(%c:)\n", 'A' + drive );
-    if (type == DRIVE_CDROM) type = DRIVE_REMOTE;
-    return type;
-}
-
-
-/***********************************************************************
- *           GetDriveTypeW   (KERNEL32.@)
- *
- * Returns the type of the disk drive specified. If root is NULL the
- * root of the current directory is used.
- *
- * RETURNS
- *
- *  Type of drive (from Win32 SDK):
- *
- *   DRIVE_UNKNOWN     unable to find out anything about the drive
- *   DRIVE_NO_ROOT_DIR nonexistent root dir
- *   DRIVE_REMOVABLE   the disk can be removed from the machine
- *   DRIVE_FIXED       the disk can not be removed from the machine
- *   DRIVE_REMOTE      network disk
- *   DRIVE_CDROM       CDROM drive
- *   DRIVE_RAMDISK     virtual disk in RAM
- */
-UINT WINAPI GetDriveTypeW(LPCWSTR root) /* [in] String describing drive */
-{
-    int drive;
-    TRACE("(%s)\n", debugstr_w(root));
-
-    if (NULL == root) drive = DRIVE_GetCurrentDrive();
-    else
-    {
-        if ((root[1]) && (root[1] != ':'))
-	{
-	    WARN("invalid root %s\n", debugstr_w(root));
-	    return DRIVE_NO_ROOT_DIR;
-	}
-	drive = toupperW(root[0]) - 'A';
-    }
-    return DRIVE_GetType(drive);
-}
-
-
-/***********************************************************************
- *           GetDriveTypeA   (KERNEL32.@)
- */
-UINT WINAPI GetDriveTypeA( LPCSTR root )
-{
-    UNICODE_STRING rootW;
-    UINT ret = 0;
-
-    if (root)
-    {
-        if( !RtlCreateUnicodeStringFromAsciiz(&rootW, root))
-        {
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            return 0;
-        }
-    }
-    else
-        rootW.Buffer = NULL;
-
-    ret = GetDriveTypeW(rootW.Buffer);
-
-    RtlFreeUnicodeString(&rootW);
-    return ret;
-
-}
-
-
-/***********************************************************************
  *           GetCurrentDirectory   (KERNEL.411)
  */
 UINT16 WINAPI GetCurrentDirectory16( UINT16 buflen, LPSTR buf )
@@ -1871,225 +918,4 @@
 }
 
 
-/***********************************************************************
- *           GetLogicalDriveStringsA   (KERNEL32.@)
- */
-UINT WINAPI GetLogicalDriveStringsA( UINT len, LPSTR buffer )
-{
-    int drive, count;
-
-    for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
-        if (DRIVE_IsValid(drive)) count++;
-    if ((count * 4) + 1 <= len)
-    {
-        LPSTR p = buffer;
-        for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
-            if (DRIVE_IsValid(drive))
-            {
-                *p++ = 'a' + drive;
-                *p++ = ':';
-                *p++ = '\\';
-                *p++ = '\0';
-            }
-        *p = '\0';
-        return count * 4;
-    }
-    else
-        return (count * 4) + 1; /* account for terminating null */
-    /* The API tells about these different return values */
-}
-
-
-/***********************************************************************
- *           GetLogicalDriveStringsW   (KERNEL32.@)
- */
-UINT WINAPI GetLogicalDriveStringsW( UINT len, LPWSTR buffer )
-{
-    int drive, count;
-
-    for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
-        if (DRIVE_IsValid(drive)) count++;
-    if (count * 4 * sizeof(WCHAR) <= len)
-    {
-        LPWSTR p = buffer;
-        for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
-            if (DRIVE_IsValid(drive))
-            {
-                *p++ = (WCHAR)('a' + drive);
-                *p++ = (WCHAR)':';
-                *p++ = (WCHAR)'\\';
-                *p++ = (WCHAR)'\0';
-            }
-        *p = (WCHAR)'\0';
-    }
-    return count * 4 * sizeof(WCHAR);
-}
-
-
-/***********************************************************************
- *           GetLogicalDrives   (KERNEL32.@)
- */
-DWORD WINAPI GetLogicalDrives(void)
-{
-    DWORD ret = 0;
-    int drive;
-
-    for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
-    {
-        if ( (DRIVE_IsValid(drive)) ||
-            (DOSDrives[drive].type == DRIVE_CDROM)) /* audio CD is also valid */
-            ret |= (1 << drive);
-    }
-    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;
-}
 
diff -u -N -r -x '*~' -x '.#*' -x CVS include43/drive.h include/drive.h
--- include43/drive.h	2004-01-01 09:54:11.000000000 +0100
+++ include/drive.h	2004-01-19 21:40:20.000000000 +0100
@@ -43,10 +43,6 @@
 extern const char * DRIVE_GetRoot( int drive );
 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  );
diff -u -N -r -x '*~' -x '.#*' -x CVS include43/winternl.h include/winternl.h
--- include43/winternl.h	2004-01-18 19:07:41.000000000 +0100
+++ include/winternl.h	2004-01-19 21:15:28.000000000 +0100
@@ -917,6 +917,15 @@
 #define FILE_EXISTS      0x00000004
 #define FILE_DOES_NOT_EXIST 0x00000005
 
+/* Characteristics of a File System */
+#define FILE_REMOVABLE_MEDIA            0x00000001
+#define FILE_READ_ONLY_DEVICE           0x00000002
+#define FILE_FLOPPY_DISKETTE            0x00000004
+#define FILE_WRITE_ONE_MEDIA            0x00000008
+#define FILE_REMOTE_DEVICE              0x00000010
+#define FILE_DEVICE_IS_MOUNTED          0x00000020
+#define FILE_VIRTUAL_VOLUME             0x00000040
+
 #if (_WIN32_WINNT >= 0x0501)
 #define INTERNAL_TS_ACTIVE_CONSOLE_ID ( *((volatile ULONG*)(0x7ffe02d8)) )
 #endif /* (_WIN32_WINNT >= 0x0501) */


More information about the wine-patches mailing list