Remove inexistent dir, add a doc reference from shell32.
[wine] / files / drive.c
index ab8b8b0..13544f9 100644 (file)
@@ -29,6 +29,7 @@
 #include <assert.h>
 #include <ctype.h>
 #include <string.h>
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/types.h>
 # endif
 #endif
 
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+#include "ntstatus.h"
+#include "windef.h"
 #include "winbase.h"
+#include "winreg.h"
 #include "winternl.h"
 #include "wine/winbase16.h"   /* for GetCurrentTask */
 #include "winerror.h"
@@ -63,7 +69,6 @@
 #include "ntddcdrm.h"
 #include "drive.h"
 #include "file.h"
-#include "heap.h"
 #include "msdos.h"
 #include "task.h"
 #include "wine/unicode.h"
@@ -137,27 +142,23 @@ inline static char *heap_strdup( const char *str )
     return p;
 }
 
-extern void CDROM_InitRegistry(int dev);
+#define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
+
+extern void CDROM_InitRegistry(int dev, int id, const char *device);
 
 /***********************************************************************
  *           DRIVE_GetDriveType
  */
-static UINT DRIVE_GetDriveType( LPCWSTR name )
+static inline UINT DRIVE_GetDriveType( INT drive, LPCWSTR value )
 {
-    WCHAR buffer[20];
     int i;
-    static const WCHAR TypeW[] = {'T','y','p','e',0};
-    static const WCHAR hdW[] = {'h','d',0};
 
-    PROFILE_GetWineIniString( name, TypeW, hdW, buffer, 20 );
-    if(!buffer[0])
-        strcpyW(buffer,hdW);
     for (i = 0; i < sizeof(DRIVE_Types)/sizeof(DRIVE_Types[0]); i++)
     {
-        if (!strcmpiW( buffer, DRIVE_Types[i] )) return i;
+        if (!strcmpiW( value, DRIVE_Types[i] )) return i;
     }
-    MESSAGE("%s: unknown drive type %s, defaulting to 'hd'.\n",
-            debugstr_w(name), debugstr_w(buffer) );
+    MESSAGE("Drive %c: unknown drive type %s, defaulting to 'hd'.\n",
+            'A' + drive, debugstr_w(value) );
     return DRIVE_FIXED;
 }
 
@@ -165,14 +166,14 @@ static UINT DRIVE_GetDriveType( LPCWSTR name )
 /***********************************************************************
  *           DRIVE_GetFSFlags
  */
-static UINT DRIVE_GetFSFlags( LPCWSTR name, LPCWSTR value )
+static UINT DRIVE_GetFSFlags( INT drive, LPCWSTR value )
 {
     const FS_DESCR *descr;
 
     for (descr = DRIVE_Filesystems; *descr->name; descr++)
         if (!strcmpiW( value, descr->name )) return descr->flags;
-    MESSAGE("%s: unknown filesystem type %s, defaulting to 'win95'.\n",
-            debugstr_w(name), debugstr_w(value) );
+    MESSAGE("Drive %c: unknown filesystem type %s, defaulting to 'win95'.\n",
+            'A' + drive, debugstr_w(value) );
     return DRIVE_CASE_PRESERVING;
 }
 
@@ -183,36 +184,59 @@ static UINT DRIVE_GetFSFlags( LPCWSTR name, LPCWSTR value )
 int DRIVE_Init(void)
 {
     int i, len, count = 0;
-    WCHAR name[] = {'D','r','i','v','e',' ','A',0};
+    WCHAR driveW[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\',
+                      'W','i','n','e','\\','W','i','n','e','\\',
+                      'C','o','n','f','i','g','\\','D','r','i','v','e',' ','A',0};
     WCHAR drive_env[] = {'=','A',':',0};
     WCHAR path[MAX_PATHNAME_LEN];
-    WCHAR buffer[80];
+    char tmp[MAX_PATHNAME_LEN*sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
     struct stat drive_stat_buffer;
     WCHAR *p;
     DOSDRIVE *drive;
+    HKEY hkey;
+    DWORD dummy;
+    OBJECT_ATTRIBUTES attr;
+    UNICODE_STRING nameW;
+
     static const WCHAR PathW[] = {'P','a','t','h',0};
-    static const WCHAR empty_strW[] = { 0 };
     static const WCHAR CodepageW[] = {'C','o','d','e','p','a','g','e',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 zeroW[] = {'0',0};
-    static const WCHAR def_serialW[] = {'1','2','3','4','5','6','7','8',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 win95W[] = {'w','i','n','9','5',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};
 
-    for (i = 0, drive = DOSDrives; i < MAX_DOS_DRIVES; i++, name[6]++, drive++)
+
+    attr.Length = sizeof(attr);
+    attr.RootDirectory = 0;
+    attr.ObjectName = &nameW;
+    attr.Attributes = 0;
+    attr.SecurityDescriptor = NULL;
+    attr.SecurityQualityOfService = NULL;
+
+    for (i = 0, drive = DOSDrives; i < MAX_DOS_DRIVES; i++, drive++)
     {
-        PROFILE_GetWineIniString( name, PathW, empty_strW, path, MAX_PATHNAME_LEN );
-        if (path[0])
+        RtlInitUnicodeString( &nameW, driveW );
+        nameW.Buffer[(nameW.Length / sizeof(WCHAR)) - 1] = 'A' + i;
+        if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ) != STATUS_SUCCESS) continue;
+
+        /* Get the code page number */
+        RtlInitUnicodeString( &nameW, CodepageW );
+        if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
+        {
+            WCHAR *data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
+            drive->codepage = strtolW( data, NULL, 10 );
+        }
+
+        /* Get the root path */
+        RtlInitUnicodeString( &nameW, PathW );
+        if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
         {
-            /* Get the code page number */
-            PROFILE_GetWineIniString( name, CodepageW, zeroW, /* 0 == CP_ACP */
-                                      buffer, 80 );
-            drive->codepage = strtolW( buffer, NULL, 10 );
+            WCHAR *data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
+            ExpandEnvironmentStringsW( data, path, sizeof(path)/sizeof(WCHAR) );
 
             p = path + strlenW(path) - 1;
             while ((p > path) && (*p == '/')) *p-- = '\0';
@@ -231,7 +255,8 @@ int DRIVE_Init(void)
                 len += WideCharToMultiByte(drive->codepage, 0, path, -1, NULL, 0, NULL, NULL) + 2;
                 drive->root = HeapAlloc( GetProcessHeap(), 0, len );
                 len -= sprintf( drive->root, "%s/", config );
-                WideCharToMultiByte(drive->codepage, 0, path, -1, drive->root + strlen(drive->root), len, NULL, NULL);
+                WideCharToMultiByte(drive->codepage, 0, path, -1,
+                                    drive->root + strlen(drive->root), len, NULL, NULL);
             }
 
             if (stat( drive->root, &drive_stat_buffer ))
@@ -240,7 +265,7 @@ int DRIVE_Init(void)
                         drive->root, strerror(errno), 'A' + i);
                 HeapFree( GetProcessHeap(), 0, drive->root );
                 drive->root = NULL;
-                continue;
+                goto next;
             }
             if (!S_ISDIR(drive_stat_buffer.st_mode))
             {
@@ -248,19 +273,32 @@ int DRIVE_Init(void)
                         drive->root, 'A' + i );
                 HeapFree( GetProcessHeap(), 0, drive->root );
                 drive->root = NULL;
-                continue;
+                goto next;
             }
 
             drive->dos_cwd  = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(drive->dos_cwd[0]));
             drive->unix_cwd = heap_strdup( "" );
-            drive->type     = DRIVE_GetDriveType( name );
             drive->device   = NULL;
             drive->flags    = 0;
             drive->dev      = drive_stat_buffer.st_dev;
             drive->ino      = drive_stat_buffer.st_ino;
 
+            /* Get the drive type */
+            RtlInitUnicodeString( &nameW, TypeW );
+            if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
+            {
+                WCHAR *data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
+                drive->type = DRIVE_GetDriveType( i, data );
+            }
+            else drive->type = DRIVE_FIXED;
+
             /* Get the drive label */
-            PROFILE_GetWineIniString( name, LabelW, empty_strW, drive->label_conf, 12 );
+            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 */
@@ -269,51 +307,73 @@ int DRIVE_Init(void)
             }
 
             /* Get the serial number */
-            PROFILE_GetWineIniString( name, SerialW, def_serialW, buffer, 80 );
-            drive->serial_conf = strtoulW( buffer, NULL, 16 );
+            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 */
-            PROFILE_GetWineIniString( name, FilesystemW, win95W, buffer, 80 );
-            drive->flags = DRIVE_GetFSFlags( name, buffer );
+            RtlInitUnicodeString( &nameW, FilesystemW );
+            if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
+            {
+                WCHAR *data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
+                drive->flags = DRIVE_GetFSFlags( i, data );
+            }
+            else drive->flags = DRIVE_CASE_PRESERVING;
 
             /* Get the device */
-            PROFILE_GetWineIniString( name, DeviceW, empty_strW, buffer, 80 );
-            if (buffer[0])
-           {
-               int cd_fd;
-                len = WideCharToMultiByte(CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL);
+            RtlInitUnicodeString( &nameW, DeviceW );
+            if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
+            {
+                WCHAR *data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
+                len = WideCharToMultiByte(drive->codepage, 0, data, -1, NULL, 0, NULL, NULL);
                 drive->device = HeapAlloc(GetProcessHeap(), 0, len);
-                WideCharToMultiByte(drive->codepage, 0, buffer, -1, drive->device, len, NULL, NULL);
+                WideCharToMultiByte(drive->codepage, 0, data, -1, drive->device, len, NULL, NULL);
 
-               if (PROFILE_GetWineIniBool( name, ReadVolInfoW, 1))
-                    drive->flags |= DRIVE_READ_VOL_INFO;
+                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;
                     if ((cd_fd = open(drive->device, O_RDONLY|O_NONBLOCK)) != -1)
                     {
-                        CDROM_InitRegistry(cd_fd);
+                        CDROM_InitRegistry(cd_fd, i, drive->device);
                         close(cd_fd);
                     }
                 }
-           }
+            }
 
             /* Get the FailReadOnly flag */
-            if (PROFILE_GetWineIniBool( name, FailReadOnlyW, 0 ))
-                drive->flags |= DRIVE_FAIL_READ_ONLY;
+            RtlInitUnicodeString( &nameW, FailReadOnlyW );
+            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_FAIL_READ_ONLY;
+            }
 
             /* Make the first hard disk the current drive */
             if ((DRIVE_CurDrive == -1) && (drive->type == DRIVE_FIXED))
                 DRIVE_CurDrive = i;
 
             count++;
-            TRACE("%s: path=%s type=%s label=%s serial=%08lx "
+            TRACE("Drive %c: path=%s type=%s label=%s serial=%08lx "
                   "flags=%08x codepage=%u dev=%x ino=%x\n",
-                  debugstr_w(name), drive->root, debugstr_w(DRIVE_Types[drive->type]),
+                  'A' + i, drive->root, debugstr_w(DRIVE_Types[drive->type]),
                   debugstr_w(drive->label_conf), drive->serial_conf, drive->flags,
                   drive->codepage, (int)drive->dev, (int)drive->ino );
         }
-        else WARN("%s: not defined\n", debugstr_w(name) );
+
+    next:
+        NtClose( hkey );
     }
 
     if (!count)
@@ -372,7 +432,7 @@ int DRIVE_IsValid( int drive )
  */
 int DRIVE_GetCurrentDrive(void)
 {
-    TDB *pTask = TASK_GetCurrent();
+    TDB *pTask = GlobalLock16(GetCurrentTask());
     if (pTask && (pTask->curdrive & 0x80)) return pTask->curdrive & ~0x80;
     return DRIVE_CurDrive;
 }
@@ -383,7 +443,7 @@ int DRIVE_GetCurrentDrive(void)
  */
 int DRIVE_SetCurrentDrive( int drive )
 {
-    TDB *pTask = TASK_GetCurrent();
+    TDB *pTask = GlobalLock16(GetCurrentTask());
     if (!DRIVE_IsValid( drive ))
     {
         SetLastError( ERROR_INVALID_DRIVE );
@@ -475,35 +535,76 @@ int DRIVE_FindDriveRoot( const char **path )
  */
 int DRIVE_FindDriveRootW( LPCWSTR *path )
 {
-    int drive, rootdrive = -1;
-    char buffer[MAX_PATHNAME_LEN];
-    LPCWSTR p = *path;
-    int len, match_len = -1;
+    int drive, level, len;
+    WCHAR buffer[MAX_PATHNAME_LEN];
+    WCHAR *p;
+    struct stat st;
 
-    for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
+    strcpyW( buffer, *path );
+    while ((p = strchrW( buffer, '\\' )) != NULL)
+        *p = '/';
+    len = strlenW(buffer);
+
+    /* strip off trailing slashes */
+    while (len > 1 && buffer[len - 1] == '/') buffer[--len] = 0;
+
+    for (;;)
     {
-        if (!DOSDrives[drive].root ||
-            (DOSDrives[drive].flags & DRIVE_DISABLED)) continue;
+        int codepage = -1;
 
-        WideCharToMultiByte(DOSDrives[drive].codepage, 0, *path, -1,
-                            buffer, MAX_PATHNAME_LEN, NULL, NULL);
+        /* Find the drive */
+        for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
+        {
+            char buffA[MAX_PATHNAME_LEN];
 
-        len = strlen(DOSDrives[drive].root);
-        if(strncmp(DOSDrives[drive].root, buffer, len))
-            continue;
-        if(len <= match_len) continue;
-        match_len = len;
-        rootdrive = drive;
-        p = *path + len;
-    }
+            if (!DOSDrives[drive].root ||
+                (DOSDrives[drive].flags & DRIVE_DISABLED))
+                continue;
 
-    if (rootdrive != -1)
-    {
-        *path = p;
-        TRACE("%s -> drive %c:, root='%s', name=%s\n",
-              buffer, 'A' + rootdrive, DOSDrives[rootdrive].root, debugstr_w(*path) );
+            if (codepage != DOSDrives[drive].codepage)
+            {
+                WideCharToMultiByte( DOSDrives[drive].codepage, 0, buffer, -1,
+                                     buffA, sizeof(buffA), NULL, NULL );
+                if (stat( buffA, &st ) == -1 || !S_ISDIR( st.st_mode ))
+                {
+                    codepage = -1;
+                    continue;
+                }
+                codepage = DOSDrives[drive].codepage;
+            }
+
+            if ((DOSDrives[drive].dev == st.st_dev) &&
+                (DOSDrives[drive].ino == st.st_ino))
+            {
+                static const WCHAR rootW[] = {'\\',0};
+
+                if (len == 1) len = 0;  /* preserve root slash in returned path */
+                TRACE( "%s -> drive %c:, root=%s, name=%s\n",
+                       debugstr_w(*path), 'A' + drive, debugstr_w(buffer), debugstr_w(*path + len));
+                *path += len;
+                if (!**path) *path = rootW;
+                return drive;
+            }
+        }
+        if (len <= 1) return -1;  /* reached root */
+
+        level = 0;
+        while (level < 1)
+        {
+            static const WCHAR dotW[] = {'.',0};
+            static const WCHAR dotdotW[] = {'.','.',0};
+
+            /* find start of the last path component */
+            while (len > 1 && buffer[len - 1] != '/') len--;
+            if (!buffer[len]) break;  /* empty component -> reached root */
+            /* does removing it take us up a level? */
+            if (strcmpW( buffer + len, dotW ) != 0)
+                level += strcmpW( buffer + len, dotdotW ) ? 1 : -1;
+            buffer[len] = 0;
+            /* strip off trailing slashes */
+            while (len > 1 && buffer[len - 1] == '/') buffer[--len] = 0;
+        }
     }
-    return rootdrive;
 }
 
 
@@ -522,7 +623,7 @@ const char * DRIVE_GetRoot( int drive )
  */
 LPCWSTR DRIVE_GetDosCwd( int drive )
 {
-    TDB *pTask = TASK_GetCurrent();
+    TDB *pTask = GlobalLock16(GetCurrentTask());
     if (!DRIVE_IsValid( drive )) return NULL;
 
     /* Check if we need to change the directory to the new task. */
@@ -546,7 +647,7 @@ LPCWSTR DRIVE_GetDosCwd( int drive )
  */
 const char * DRIVE_GetUnixCwd( int drive )
 {
-    TDB *pTask = TASK_GetCurrent();
+    TDB *pTask = GlobalLock16(GetCurrentTask());
     if (!DRIVE_IsValid( drive )) return NULL;
 
     /* Check if we need to change the directory to the new task. */
@@ -621,19 +722,39 @@ int DRIVE_ReadSuperblock (int drive, char * buff)
     int fd;
     off_t offs;
     int ret = 0;
-
-    if (memset(buff,0,DRIVE_SUPER)!=buff) return -1;
-    if ((fd=open(DOSDrives[drive].device,O_RDONLY)) == -1)
-    {
-       struct stat st;
+    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, &st)) ?
+               (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");
-       PROFILE_UsageWineIni();
        return -1;
     }
 
@@ -798,12 +919,18 @@ failure:
  */
 static DWORD CDROM_GetLabel(int drive, WCHAR *label)
 {
-    HANDLE              h = CDROM_Open(drive);
+    HANDLE              h;
     CDROM_DISK_DATA     cdd;
-    DWORD               br;
-    DWORD               ret = 1;
+    DWORD               br, ret = 1;
+    BOOL                r;
 
-    if (!h || !DeviceIoControl(h, IOCTL_CDROM_DISK_TYPE, NULL, 0, &cdd, sizeof(cdd), &br, 0))
+    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)
@@ -819,8 +946,13 @@ static DWORD CDROM_GetLabel(int drive, WCHAR *label)
         break;
     }
     case CDROM_DISK_DATA_TRACK|CDROM_DISK_AUDIO_TRACK:
-        FIXME("Need to get the label of a mixed mode CD: not implemented yet !\n");
-        /* fall through */
+        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;
@@ -929,7 +1061,7 @@ static DWORD CDROM_Data_GetSerial(int drive)
     if (offs)
     {
         BYTE buf[2048];
-        OSVERSIONINFOA ovi;
+        RTL_OSVERSIONINFOEXW ovi;
         int i;
 
         lseek(dev, offs, SEEK_SET);
@@ -939,8 +1071,8 @@ static DWORD CDROM_Data_GetSerial(int drive)
          * 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(OSVERSIONINFOA);
-        GetVersionExA(&ovi);
+        ovi.dwOSVersionInfoSize = sizeof(ovi);
+        RtlGetVersion(&ovi);
         if ((ovi.dwPlatformId == VER_PLATFORM_WIN32_NT) &&  (ovi.dwMajorVersion >= 4))
         {
             b0 = 3; b1 = 2; b2 = 1; b3 = 0;
@@ -964,12 +1096,23 @@ static DWORD CDROM_Data_GetSerial(int drive)
 static DWORD CDROM_GetSerial(int drive)
 {
     DWORD               serial = 0;
-    HANDLE              h = CDROM_Open(drive);
+    HANDLE              h;
     CDROM_DISK_DATA     cdd;
     DWORD               br;
+    BOOL                r;
 
-    if (!h || ! !DeviceIoControl(h, IOCTL_CDROM_DISK_TYPE, NULL, 0, &cdd, sizeof(cdd), &br, 0))
+    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)
     {
@@ -1094,7 +1237,7 @@ int DRIVE_Chdir( int drive, LPCWSTR path )
     WCHAR buffer[MAX_PATHNAME_LEN];
     LPSTR unix_cwd;
     BY_HANDLE_FILE_INFORMATION info;
-    TDB *pTask = TASK_GetCurrent();
+    TDB *pTask = GlobalLock16(GetCurrentTask());
 
     buffer[0] = 'A' + drive;
     buffer[1] = ':';
@@ -1122,6 +1265,14 @@ int DRIVE_Chdir( int drive, LPCWSTR path )
     strcpyW(DOSDrives[drive].dos_cwd, full_name.short_name + 3);
     DOSDrives[drive].unix_cwd = heap_strdup( unix_cwd );
 
+    if (drive == DRIVE_CurDrive)
+    {
+        UNICODE_STRING dirW;
+
+        RtlInitUnicodeString( &dirW, full_name.short_name );
+        RtlSetCurrentDirectory_U( &dirW );
+    }
+
     if (pTask && (pTask->curdrive & 0x80) &&
         ((pTask->curdrive & ~0x80) == drive))
     {
@@ -1226,61 +1377,6 @@ int DRIVE_OpenDevice( int drive, int flags )
 }
 
 
-/***********************************************************************
- *           DRIVE_RawRead
- *
- * Read raw sectors from a device
- */
-int DRIVE_RawRead(BYTE drive, DWORD begin, DWORD nr_sect, BYTE *dataptr, BOOL fake_success)
-{
-    int fd;
-
-    if ((fd = DRIVE_OpenDevice( drive, O_RDONLY )) != -1)
-    {
-        lseek( fd, begin * 512, SEEK_SET );
-        /* FIXME: check errors */
-        read( fd, dataptr, nr_sect * 512 );
-        close( fd );
-    }
-    else
-    {
-        memset(dataptr, 0, nr_sect * 512);
-       if (fake_success)
-        {
-           if (begin == 0 && nr_sect > 1) *(dataptr + 512) = 0xf8;
-           if (begin == 1) *dataptr = 0xf8;
-       }
-       else
-           return 0;
-    }
-    return 1;
-}
-
-
-/***********************************************************************
- *           DRIVE_RawWrite
- *
- * Write raw sectors to a device
- */
-int DRIVE_RawWrite(BYTE drive, DWORD begin, DWORD nr_sect, BYTE *dataptr, BOOL fake_success)
-{
-    int fd;
-
-    if ((fd = DRIVE_OpenDevice( drive, O_RDONLY )) != -1)
-    {
-        lseek( fd, begin * 512, SEEK_SET );
-        /* FIXME: check errors */
-        write( fd, dataptr, nr_sect * 512 );
-        close( fd );
-    }
-    else
-    if (!(fake_success))
-       return 0;
-
-    return 1;
-}
-
-
 /***********************************************************************
  *           DRIVE_GetFreeSpace
  */
@@ -1308,10 +1404,10 @@ static int DRIVE_GetFreeSpace( int drive, PULARGE_INTEGER size,
     }
 
     size->QuadPart = RtlEnlargedUnsignedMultiply( info.f_bsize, info.f_blocks );
-#ifdef STATFS_HAS_BAVAIL
+#ifdef HAVE_STRUCT_STATFS_F_BAVAIL
     available->QuadPart = RtlEnlargedUnsignedMultiply( info.f_bavail, info.f_bsize );
 #else
-# ifdef STATFS_HAS_BFREE
+# ifdef HAVE_STRUCT_STATFS_F_BFREE
     available->QuadPart = RtlEnlargedUnsignedMultiply( info.f_bfree, info.f_bsize );
 # else
 #  error "statfs has no bfree/bavail member!"
@@ -1353,27 +1449,26 @@ static UINT DRIVE_GetCurrentDirectory( UINT buflen, LPWSTR buf )
  * Build the environment array containing the drives' current directories.
  * Resulting pointer must be freed with HeapFree.
  */
-char *DRIVE_BuildEnv(void)
+WCHAR *DRIVE_BuildEnv(void)
 {
     int i, length = 0;
     LPCWSTR cwd[MAX_DOS_DRIVES];
-    char *env, *p;
+    WCHAR *env, *p;
 
     for (i = 0; i < MAX_DOS_DRIVES; i++)
     {
         if ((cwd[i] = DRIVE_GetDosCwd(i)) && cwd[i][0])
-            length += WideCharToMultiByte(DRIVE_GetCodepage(i), 0,
-                                          cwd[i], -1, NULL, 0, NULL, NULL) + 7;
+            length += strlenW(cwd[i]) + 8;
     }
-    if (!(env = HeapAlloc( GetProcessHeap(), 0, length+1 ))) return NULL;
+    if (!(env = HeapAlloc( GetProcessHeap(), 0, (length+1) * sizeof(WCHAR) ))) return NULL;
     for (i = 0, p = env; i < MAX_DOS_DRIVES; i++)
     {
         if (cwd[i] && cwd[i][0])
         {
             *p++ = '='; *p++ = 'A' + i; *p++ = ':';
             *p++ = '='; *p++ = 'A' + i; *p++ = ':'; *p++ = '\\';
-            WideCharToMultiByte(DRIVE_GetCodepage(i), 0, cwd[i], -1, p, 0x7fffffff, NULL, NULL);
-            p += strlen(p) + 1;
+            strcpyW( p, cwd[i] );
+            p += strlenW(p) + 1;
         }
     }
     *p = 0;
@@ -1586,9 +1681,9 @@ BOOL WINAPI GetDiskFreeSpaceExW( LPCWSTR root,
               FIXME messages, so don't print the FIXME unless Wine is
               actually masquerading as Windows2000. */
 
-            OSVERSIONINFOA ovi;
-           ovi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
-           if (GetVersionExA(&ovi))
+            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");
@@ -2059,3 +2154,12 @@ BOOL WINAPI SetVolumeLabelA(LPCSTR root, LPCSTR volname)
     RtlFreeUnicodeString(&volnameW);
     return ret;
 }
+
+/***********************************************************************
+ *           GetVolumeNameForVolumeMountPointW   (KERNEL32.@)
+ */
+DWORD WINAPI GetVolumeNameForVolumeMountPointW(LPWSTR str, DWORD a, DWORD b)
+{
+    FIXME("(%s, %lx, %lx): stub\n", debugstr_w(str), a, b);
+    return 0;
+}