ntdll / kernel32: #48

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


Reviewed directory initialisation & management
- now storing system dirs as full & long path names
- rewrote a bit DIR_SearchPath to use better ntdll functions
- nuked DOS_FULL_NAME structure
- in Win NT mode, no longer remember the per drive current directory
- in Win 9x mode, store per drive current directory in =?: environment
   variable (? being the drive)
-------------- next part --------------
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel47/kernel_private.h dlls/kernel/kernel_private.h
--- dlls/kernel47/kernel_private.h	2004-01-19 22:42:21.000000000 +0100
+++ dlls/kernel/kernel_private.h	2004-01-20 21:48:28.000000000 +0100
@@ -50,6 +50,9 @@
 #define MAX_PATHNAME_LEN   1024
 void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing );
 void FILE_SetDosError(void);
+extern DWORD    DIR_SearchPath( LPCWSTR path, LPCWSTR name, LPCWSTR ext,
+                                LPWSTR full_name, unsigned fnlen, LPWSTR* last, BOOL win32 );
+int  DRIVE_GetCurrentDrive(void);
 
 extern void PTHREAD_Init(void);
 extern BOOL WOWTHUNK_Init(void);
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel47/process.c dlls/kernel/process.c
--- dlls/kernel47/process.c	2004-01-23 22:37:39.000000000 +0100
+++ dlls/kernel/process.c	2004-01-23 22:40:02.000000000 +0100
@@ -862,13 +862,13 @@
         ExitProcess(1);
     case BINARY_UNIX_LIB:
         {
-            DOS_FULL_NAME full_name;
+            char        full_name[MAX_PATHNAME_LEN];
 
             TRACE( "starting Winelib app %s\n", debugstr_w(main_exe_name) );
             CloseHandle( main_exe_file );
             main_exe_file = 0;
-            if (DOSFS_GetFullName( main_exe_name, TRUE, &full_name ) &&
-                wine_dlopen( full_name.long_name, RTLD_NOW, error, sizeof(error) ))
+            if (wine_get_unix_file_name( main_exe_name, full_name, sizeof(full_name) / sizeof(WCHAR) ) &&
+                wine_dlopen( full_name, RTLD_NOW, error, sizeof(error) ))
             {
                 static const WCHAR soW[] = {'.','s','o',0};
                 if ((p = strrchrW( main_exe_name, '.' )) && !strcmpW( p, soW ))
@@ -1574,7 +1574,7 @@
     BOOL retv = FALSE;
     HANDLE hFile = 0;
     const char *unixdir = NULL;
-    DOS_FULL_NAME full_dir;
+    char full_dir[MAX_PATHNAME_LEN];
     WCHAR name[MAX_PATH];
     WCHAR *tidy_cmdline, *p, *envW = env;
 
@@ -1596,15 +1596,15 @@
 
     if (cur_dir)
     {
-        if (DOSFS_GetFullName( cur_dir, TRUE, &full_dir )) unixdir = full_dir.long_name;
+        if (wine_get_unix_file_name( cur_dir, full_dir, sizeof(full_dir) ))
+            unixdir = full_dir;
     }
     else
     {
         WCHAR buf[MAX_PATH];
-        if (GetCurrentDirectoryW(MAX_PATH, buf))
-        {
-            if (DOSFS_GetFullName( buf, TRUE, &full_dir )) unixdir = full_dir.long_name;
-        }
+        if (GetCurrentDirectoryW(MAX_PATH, buf) &&
+            wine_get_unix_file_name( buf, full_dir, sizeof(full_dir) ))
+            unixdir = full_dir;
     }
 
     if (env && !(flags & CREATE_UNICODE_ENVIRONMENT))  /* convert environment to unicode */
@@ -1682,13 +1682,13 @@
     case BINARY_UNIX_EXE:
         {
             /* unknown file, try as unix executable */
-            DOS_FULL_NAME full_name;
+            char        uname[MAX_PATH];
 
             TRACE( "starting %s as Unix binary\n", debugstr_w(name) );
 
-            if (DOSFS_GetFullName( name, TRUE, &full_name ))
-                retv = (fork_and_exec( full_name.long_name, tidy_cmdline, envW, unixdir ) != -1);
-        }
+            if (wine_get_unix_file_name( name, uname, sizeof(uname) ))
+                retv = (fork_and_exec( uname, tidy_cmdline, envW, unixdir ) != -1);
+         }
         break;
     }
     CloseHandle( hFile );
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel47/profile.c dlls/kernel/profile.c
--- dlls/kernel47/profile.c	2004-01-01 09:53:32.000000000 +0100
+++ dlls/kernel/profile.c	2004-01-20 22:30:04.000000000 +0100
@@ -521,7 +521,8 @@
  */
 static BOOL PROFILE_Open( LPCWSTR filename )
 {
-    DOS_FULL_NAME full_name;
+    char full_name[MAX_PATHNAME_LEN];
+    WCHAR short_name[MAX_PATHNAME_LEN];
     char buffer[MAX_PATHNAME_LEN];
     WCHAR *newdos_name;
     WCHAR *name, *name_lwr;
@@ -551,7 +552,8 @@
     if (strchrW( filename, '/' ) || strchrW( filename, '\\' ) ||
         strchrW( filename, ':' ))
     {
-        if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
+        if (!wine_get_unix_file_name( filename, full_name, sizeof(full_name) )) return FALSE;
+        GetShortPathNameW(filename, short_name, sizeof(short_name) / sizeof(WCHAR));
     }
     else
     {
@@ -561,13 +563,14 @@
         GetWindowsDirectoryW( windirW, MAX_PATH );
         strcatW( windirW, bkslashW );
         strcatW( windirW, filename );
-        if (!DOSFS_GetFullName( windirW, FALSE, &full_name )) return FALSE;
+        if (!wine_get_unix_file_name( windirW, full_name, sizeof(full_name) )) return FALSE;
+        GetShortPathNameW(windirW, short_name, sizeof(short_name) / sizeof(WCHAR));
     }
 
     for(i=0;i<N_CACHED_PROFILES;i++)
       {
        if ((MRUProfile[i]->filename && !strcmpW( filename, MRUProfile[i]->filename )) ||
-           (MRUProfile[i]->dos_name && !strcmpW( full_name.short_name, MRUProfile[i]->dos_name )))
+           (MRUProfile[i]->dos_name && !strcmpW( short_name, MRUProfile[i]->dos_name )))
          {
           if(i)
             {
@@ -601,8 +604,8 @@
     if(CurProfile->filename) PROFILE_ReleaseFile();
 
     /* OK, now that CurProfile is definitely free we assign it our new file */
-    newdos_name = HeapAlloc( GetProcessHeap(), 0, (strlenW(full_name.short_name)+1) * sizeof(WCHAR) );
-    strcpyW( newdos_name, full_name.short_name );
+    newdos_name = HeapAlloc( GetProcessHeap(), 0, (strlenW(short_name)+1) * sizeof(WCHAR) );
+    strcpyW( newdos_name, short_name );
     CurProfile->dos_name  = newdos_name;
     CurProfile->filename  = HeapAlloc( GetProcessHeap(), 0, (strlenW(filename)+1) * sizeof(WCHAR) );
     strcpyW( CurProfile->filename, filename );
@@ -632,11 +635,11 @@
     }
     else
     {
-        CurProfile->unix_name = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 );
-        strcpy( CurProfile->unix_name, full_name.long_name );
-        if ((file = fopen( full_name.long_name, "r" )))
+        CurProfile->unix_name = HeapAlloc( GetProcessHeap(), 0, strlen(full_name)+1 );
+        strcpy( CurProfile->unix_name, full_name );
+        if ((file = fopen( full_name, "r" )))
             TRACE("(%s): found it in %s\n",
-                             debugstr_w(filename), full_name.long_name );
+                             debugstr_w(filename), full_name );
     }
 
     if (file)
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel47/task.c dlls/kernel/task.c
--- dlls/kernel47/task.c	2004-01-01 09:53:31.000000000 +0100
+++ dlls/kernel/task.c	2004-01-20 21:45:26.000000000 +0100
@@ -37,8 +37,6 @@
 #include "winuser.h"
 
 #include "wine/winbase16.h"
-#include "drive.h"
-#include "file.h"
 #include "module.h"
 #include "winternl.h"
 #include "wine/server.h"
@@ -263,6 +261,7 @@
     TDB *pTask;
     FARPROC16 proc;
     HMODULE16 hModule = pModule ? pModule->self : 0;
+    WCHAR curdirW[MAX_PATH];
 
       /* Allocate the task structure */
 
@@ -292,7 +291,8 @@
     pTask->teb           = teb;
     pTask->curdrive      = DRIVE_GetCurrentDrive() | 0x80;
     strcpy( pTask->curdir, "\\" );
-    WideCharToMultiByte(CP_ACP, 0, DRIVE_GetDosCwd(DRIVE_GetCurrentDrive()), -1,
+    GetCurrentDirectoryW(sizeof(curdirW), curdirW);
+    WideCharToMultiByte(CP_ACP, 0, curdirW, -1,
                         pTask->curdir + 1, sizeof(pTask->curdir) - 1, NULL, NULL);
     pTask->curdir[sizeof(pTask->curdir) - 1] = 0; /* ensure 0 termination */
 
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel47/tests/path.c dlls/kernel/tests/path.c
--- dlls/kernel47/tests/path.c	2004-01-17 18:43:51.000000000 +0100
+++ dlls/kernel/tests/path.c	2004-01-20 22:05:58.000000000 +0100
@@ -414,9 +414,9 @@
 */
   len=GetCurrentDirectoryA(MAX_PATH,origdir);
   ok(len!=0 && len < MAX_PATH,"GetCurrentDirectoryA failed");
-  ok(lstrcmpiA(origdir+(len-1),"\\")!=0,
-     "GetCurrentDirectoryA should not have a trailing \\");
-/* Make sure that CetCurrentDirectoryA doesn't overwrite the buffer when the
+  ok(len == 3 || lstrcmpiA(origdir+(len-1),"\\")!=0,
+     "GetCurrentDirectoryA should not have a trailing \\ (%s)", origdir);
+/* Make sure that GetCurrentDirectoryA doesn't overwrite the buffer when the
    buffer size is too small to hold the current directory
 */
   lstrcpyA(tmpstr,"aaaaaaa");
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel47/wowthunk.c dlls/kernel/wowthunk.c
--- dlls/kernel47/wowthunk.c	2004-01-01 09:53:32.000000000 +0100
+++ dlls/kernel/wowthunk.c	2004-01-20 21:47:19.000000000 +0100
@@ -32,7 +32,6 @@
 #include "excpt.h"
 #include "winreg.h"
 #include "winternl.h"
-#include "file.h"
 #include "miscemu.h"
 #include "module.h"
 #include "stackframe.h"
@@ -644,7 +643,7 @@
 DWORD WINAPI LoadLibraryEx32W16( LPCSTR lpszLibFile, DWORD hFile, DWORD dwFlags )
 {
     HMODULE hModule;
-    DOS_FULL_NAME full_name;
+    WCHAR tmp[MAX_PATHNAME_LEN];
     DWORD mutex_count;
     UNICODE_STRING libfileW;
     LPCWSTR filenameW;
@@ -666,8 +665,8 @@
        a buildin module. This case is handled in MODULE_LoadLibraryExA */
 
     filenameW = libfileW.Buffer;
-    if ( DIR_SearchPath( NULL, filenameW, dllW, &full_name, FALSE ) )
-        filenameW = full_name.short_name;
+    if ( DIR_SearchPath( NULL, filenameW, dllW, tmp, sizeof(tmp)/sizeof(tmp[0]), NULL, FALSE ) )
+        filenameW = tmp;
 
     ReleaseThunkLock( &mutex_count );
     hModule = LoadLibraryExW( filenameW, (HANDLE)hFile, dwFlags );
diff -u -N -r -x '*~' -x '.#*' -x CVS files47/directory.c files/directory.c
--- files47/directory.c	2004-01-18 21:20:00.000000000 +0100
+++ files/directory.c	2004-01-20 22:07:33.000000000 +0100
@@ -45,15 +45,14 @@
 #include "winreg.h"
 #include "winternl.h"
 #include "wine/unicode.h"
-#include "drive.h"
-#include "file.h"
+#include "kernel_private.h"
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(dosfs);
 WINE_DECLARE_DEBUG_CHANNEL(file);
 
-static DOS_FULL_NAME DIR_Windows;
-static DOS_FULL_NAME DIR_System;
+static WCHAR    DIR_Windows[MAX_PATHNAME_LEN];
+static WCHAR    DIR_System[MAX_PATHNAME_LEN];
 
 /***********************************************************************
  *           FILE_contains_pathW
@@ -69,24 +68,26 @@
  *
  * Get a path name from the wine.ini file and make sure it is valid.
  */
-static int DIR_GetPath( HKEY hkey, LPCWSTR keyname, LPCWSTR defval, DOS_FULL_NAME *full_name,
-                        LPWSTR longname, INT longname_len, BOOL warn )
+static int DIR_GetPath( HKEY hkey, LPCWSTR keyname, LPCWSTR defval, 
+                        LPWSTR shortname, INT shortname_len, BOOL warn )
 {
     UNICODE_STRING nameW;
-    DWORD dummy;
-    WCHAR tmp[MAX_PATHNAME_LEN];
-    BY_HANDLE_FILE_INFORMATION info;
-    const WCHAR *path = defval;
-    const char *mess = "does not exist";
+    DWORD       dummy, ret, attr;
+    WCHAR       tmp[MAX_PATHNAME_LEN];
+    LPCWSTR     path = defval;
+    LPCSTR      mess = NULL;
 
     RtlInitUnicodeString( &nameW, keyname );
     if (hkey && !NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
         path = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
 
-    if (!DOSFS_GetFullName( path, TRUE, full_name ) ||
-        (!FILE_Stat( full_name->long_name, &info, NULL ) && (mess=strerror(errno)))||
-        (!(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (mess="not a directory")) ||
-        (!(GetLongPathNameW(full_name->short_name, longname, longname_len))) )
+    ret = GetShortPathNameW(path, shortname, shortname_len);
+    if (!ret) mess = "does not exist";
+    else if (ret > shortname_len) mess = "buffer too small";
+    else if ((attr = GetFileAttributesW(shortname)) == INVALID_FILE_ATTRIBUTES)
+        mess = "does not exist";
+    else if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) mess = "not a directory";
+    if (mess != NULL)
     {
         if (warn)
         {
@@ -102,18 +103,91 @@
 
 
 /***********************************************************************
+ *           DIR_FindDriveRoot
+ *
+ * Find a drive for which the root matches the beginning of the given path.
+ * This can be used to translate a Unix path into a drive + DOS path.
+ * Return value is the drive, or -1 on error. On success, path is modified
+ * to point to the beginning of the DOS path.
+ *
+ * Note: path must be in the encoding of the underlying Unix file system.
+ */
+static int DIR_FindDriveRoot( const char **path )
+{
+    /* Starting with the full path, check if the device and inode match any of
+     * the wine 'drives'. If not then remove the last path component and try
+     * again. If the last component was a '..' then skip a normal component
+     * since it's a directory that's ascended back out of.
+     */
+    int drive, level, len;
+    char buffer[MAX_PATHNAME_LEN], t[MAX_PATHNAME_LEN];
+    char *p;
+    struct stat st, dst;
+
+    strcpy( buffer, *path );
+    for (p = buffer; *p; p++) if (*p == '\\') *p = '/';
+    len = p - buffer;
+
+    /* strip off trailing slashes */
+    while (len > 1 && buffer[len - 1] == '/') buffer[--len] = 0;
+
+    for (;;)
+    {
+        /* Find the drive */
+        if (stat( buffer, &st ) == 0 && S_ISDIR( st.st_mode ))
+        {
+            for (drive = 0; drive < 26; drive++)
+            {
+                sprintf(t, "%s/dosdevices/%c:", wine_get_config_dir(), 'a' + drive);
+                if (stat(t, &dst) == -1 || !S_ISDIR(dst.st_mode)) continue;
+
+                if (dst.st_dev == st.st_dev && dst.st_ino == st.st_ino)
+                {
+                    if (len == 1) len = 0;  /* preserve root slash in returned path */
+                    TRACE( "%s -> drive %c:, root='%s', name='%s'\n",
+                           *path, 'A' + drive, buffer, *path + len);
+                    *path += len;
+                    if (!**path) *path = "\\";
+                    return drive;
+                }
+            }
+        }
+        if (len <= 1) return -1;  /* reached root */
+
+        level = 0;
+        while (level < 1)
+        {
+            /* find start of the last path component */
+            while (len > 1 && buffer[len - 1] != '/') len--;
+            if (!buffer[len]) break;  /* empty component -> reached root */
+            /* does removing it take us up a level? */
+            if (strcmp( buffer + len, "." ) != 0)
+                level += strcmp( buffer + len, ".." ) ? 1 : -1;
+            buffer[len] = 0;
+            /* strip off trailing slashes */
+            while (len > 1 && buffer[len - 1] == '/') buffer[--len] = 0;
+        }
+    }
+}
+
+
+/***********************************************************************
  *           DIR_Init
  */
 int DIR_Init(void)
 {
-    OBJECT_ATTRIBUTES attr;
-    UNICODE_STRING nameW;
-    HKEY hkey;
-    char path[MAX_PATHNAME_LEN];
-    WCHAR longpath[MAX_PATHNAME_LEN];
-    DOS_FULL_NAME tmp_dir, profile_dir;
-    int drive;
-    const char *cwd;
+    OBJECT_ATTRIBUTES   attr;
+    UNICODE_STRING      nameW;
+    HKEY                hkey;
+    char                path[MAX_PATHNAME_LEN];
+    WCHAR               longpath[MAX_PATHNAME_LEN];
+    WCHAR               tmp_dir[MAX_PATHNAME_LEN];
+    WCHAR               profile_dir[MAX_PATHNAME_LEN];
+    int                 drive;
+    const char*         cwd;
+    int                 count = 0;
+    WCHAR               drive_env[] = {'A',':','\\',0};
+
     static const WCHAR wineW[] = {'M','a','c','h','i','n','e','\\',
                                   'S','o','f','t','w','a','r','e','\\',
                                   'W','i','n','e','\\','W','i','n','e','\\',
@@ -138,25 +212,40 @@
     static const WCHAR comspecW[] = {'C','O','M','S','P','E','C',0};
     static const WCHAR empty_strW[] = { 0 };
 
+    for (drive_env[0] = 'A'; drive_env[0] <= 'Z'; drive_env[0]++)
+    {
+        if (GetDriveTypeW(drive_env) != DRIVE_NO_ROOT_DIR) count++;
+    }
+
+    if (!count)
+    {
+        MESSAGE("Warning: no valid DOS drive found, check your configuration file.\n" );
+        /* FIXME: should we create a default setting ? */
+        /* Create a C drive pointing to Unix root dir */
+        return 0;
+    }
+
     if (!getcwd( path, MAX_PATHNAME_LEN ))
     {
         perror( "Could not get current directory" );
         return 0;
     }
     cwd = path;
-    if ((drive = DRIVE_FindDriveRoot( &cwd )) == -1)
+    if ((drive = DIR_FindDriveRoot( &cwd )) == -1)
     {
         MESSAGE("Warning: could not find wine config [Drive x] entry "
-            "for current working directory %s; "
-	    "starting in windows directory.\n", cwd );
+                "for current working directory %s; "
+                "starting in windows directory.\n", cwd );
     }
     else
     {
-        WCHAR szdrive[3]={drive+'A',':',0};
-        MultiByteToWideChar(CP_UNIXCP, 0, cwd, -1, longpath, MAX_PATHNAME_LEN);
-        DRIVE_SetCurrentDrive( drive );
-        DRIVE_Chdir( drive, longpath );
-	if(GetDriveTypeW(szdrive)==DRIVE_CDROM)
+        longpath[0] = drive + 'A';
+        longpath[1] = ':';
+        longpath[2] = '\\';
+        MultiByteToWideChar(CP_UNIXCP, 0, cwd + 1, -1, longpath + 3, MAX_PATHNAME_LEN - 3);
+        SetCurrentDirectoryW(longpath);
+        longpath[2] = '\0';
+	if (GetDriveTypeW(longpath) == DRIVE_CDROM)
             chdir("/"); /* change to root directory so as not to lock cdroms */
     }
 
@@ -170,39 +259,40 @@
     RtlInitUnicodeString( &nameW, wineW );
     if (NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) hkey = 0;
 
-    if (!(DIR_GetPath( hkey, windowsW, windows_dirW, &DIR_Windows, longpath, MAX_PATHNAME_LEN, TRUE )) ||
-        !(DIR_GetPath( hkey, systemW, system_dirW, &DIR_System, longpath, MAX_PATHNAME_LEN, TRUE )) ||
-        !(DIR_GetPath( hkey, tempW, windows_dirW, &tmp_dir, longpath, MAX_PATHNAME_LEN, TRUE )))
+    if (!(DIR_GetPath( hkey, windowsW, windows_dirW, DIR_Windows, MAX_PATHNAME_LEN, TRUE )) ||
+        !(DIR_GetPath( hkey, systemW, system_dirW, DIR_System, MAX_PATHNAME_LEN, TRUE )) ||
+        !(DIR_GetPath( hkey, tempW, windows_dirW, tmp_dir, MAX_PATHNAME_LEN, TRUE )))
     {
         if (hkey) NtClose( hkey );
         return 0;
     }
-    if (-1 == access( tmp_dir.long_name, W_OK ))
+    if (!wine_get_unix_file_name(tmp_dir, path, MAX_PATHNAME_LEN))
     {
-    	if (errno==EACCES)
-	{
-		MESSAGE("Warning: the temporary directory '%s' specified in your\n"
+        if (access( path, W_OK ) == -1)
+        {
+            if (errno == EACCES)
+            {
+                MESSAGE("Warning: the temporary directory '%s' specified in your\n"
                         "configuration file (%s) is not writeable.\n",
-                        tmp_dir.long_name, wine_get_config_dir() );
-	}
-	else
-		MESSAGE("Warning: access to temporary directory '%s' failed (%s).\n",
-		    tmp_dir.long_name, strerror(errno));
+                        path, wine_get_config_dir() );
+            }
+            else
+                MESSAGE("Warning: access to temporary directory '%s' failed (%s).\n",
+                        path, strerror(errno));
+        }
+        else
+            MESSAGE("Warning: access to temporary directory '%s' failed (%s).\n",
+                    debugstr_w(tmp_dir), strerror(errno));
     }
 
-    if (drive == -1)
-    {
-        drive = DIR_Windows.drive;
-        DRIVE_SetCurrentDrive( drive );
-        DRIVE_Chdir( drive, DIR_Windows.short_name + 2 );
-    }
+    if (drive == -1) SetCurrentDirectoryW( DIR_Windows );
 
     /* Set the environment variables */
 
     /* set COMSPEC only if it doesn't exist already */
     if (!GetEnvironmentVariableW( comspecW, NULL, 0 ))
     {
-        strcpyW( longpath, DIR_System.short_name );
+        strcpyW( longpath, DIR_System );
         strcatW( longpath, wcmdW );
         SetEnvironmentVariableW( comspecW, longpath );
     }
@@ -212,46 +302,48 @@
     {
         WCHAR tmp[MAX_PATHNAME_LEN];
         DWORD dummy;
-        const WCHAR *path = path_dirW;
+        const WCHAR *lpathW = path_dirW;
 
         RtlInitUnicodeString( &nameW, pathW );
         if (hkey && !NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
                                       tmp, sizeof(tmp), &dummy ))
         {
-            path = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
+            lpathW = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
         }
 
-        if (strchrW(path, '/'))
+        if (strchrW(lpathW, '/'))
         {
             MESSAGE("Fix your wine config (%s/config) to use DOS drive syntax in [wine] 'Path=' statement! (no '/' allowed)\n", wine_get_config_dir() );
             ExitProcess(1);
         }
-        SetEnvironmentVariableW( path_capsW, path );
-        TRACE("Path       = %s\n", debugstr_w(path) );
+        SetEnvironmentVariableW( path_capsW, lpathW );
+        TRACE("Path       = %s\n", debugstr_w(lpathW) );
     }
 
-    SetEnvironmentVariableW( temp_capsW, tmp_dir.short_name );
-    SetEnvironmentVariableW( tmp_capsW, tmp_dir.short_name );
-    SetEnvironmentVariableW( windirW, DIR_Windows.short_name );
-    SetEnvironmentVariableW( winsysdirW, DIR_System.short_name );
-
-    TRACE("WindowsDir = %s (%s)\n",
-          debugstr_w(DIR_Windows.short_name), DIR_Windows.long_name );
-    TRACE("SystemDir  = %s (%s)\n",
-          debugstr_w(DIR_System.short_name), DIR_System.long_name );
-    TRACE("TempDir    = %s (%s)\n",
-          debugstr_w(tmp_dir.short_name), tmp_dir.long_name );
-    TRACE("Cwd        = %c:\\%s\n",
-          'A' + drive, debugstr_w(DRIVE_GetDosCwd(drive)) );
+    SetEnvironmentVariableW( temp_capsW, tmp_dir );
+    SetEnvironmentVariableW( tmp_capsW, tmp_dir );
+    SetEnvironmentVariableW( windirW, DIR_Windows );
+    SetEnvironmentVariableW( winsysdirW, DIR_System );
+
+    if (TRACE_ON(dosfs))
+    {
+        char    tmp[MAX_PATHNAME_LEN];
+        wine_get_unix_file_name(DIR_Windows, tmp, sizeof(tmp));
+        TRACE("WindowsDir = %s (%s)\n", debugstr_w(DIR_Windows), tmp );
+        wine_get_unix_file_name(DIR_System, tmp, sizeof(tmp));
+        TRACE("SystemDir  = %s (%s)\n", debugstr_w(DIR_System), tmp );
+        wine_get_unix_file_name(tmp_dir, tmp, sizeof(tmp));
+        TRACE("TempDir    = %s (%s)\n", debugstr_w(tmp_dir), tmp );
+    }
 
-    if (DIR_GetPath( hkey, profileW, empty_strW, &profile_dir, longpath, MAX_PATHNAME_LEN, FALSE ))
+    if (DIR_GetPath( hkey, profileW, empty_strW, profile_dir, MAX_PATHNAME_LEN, FALSE ))
     {
         TRACE("USERPROFILE= %s\n", debugstr_w(longpath) );
         SetEnvironmentVariableW( userprofileW, longpath );
     }
 
-    TRACE("SYSTEMROOT = %s\n", debugstr_w(DIR_Windows.short_name) );
-    SetEnvironmentVariableW( systemrootW, DIR_Windows.short_name );
+    TRACE("SYSTEMROOT = %s\n", debugstr_w(DIR_Windows) );
+    SetEnvironmentVariableW( systemrootW, DIR_Windows );
     if (hkey) NtClose( hkey );
 
     return 1;
@@ -340,27 +432,6 @@
     return ret;
 }
 
-
-/***********************************************************************
- *           DIR_GetWindowsUnixDir
- */
-UINT DIR_GetWindowsUnixDir( LPSTR path, UINT count )
-{
-    if (path) lstrcpynA( path, DIR_Windows.long_name, count );
-    return strlen( DIR_Windows.long_name );
-}
-
-
-/***********************************************************************
- *           DIR_GetSystemUnixDir
- */
-UINT DIR_GetSystemUnixDir( LPSTR path, UINT count )
-{
-    if (path) lstrcpynA( path, DIR_System.long_name, count );
-    return strlen( DIR_System.long_name );
-}
-
-
 /***********************************************************************
  *           GetTempDrive   (KERNEL.92)
  * A closer look at krnl386.exe shows what the SDK doesn't mention:
@@ -406,10 +477,10 @@
  */
 UINT WINAPI GetWindowsDirectoryW( LPWSTR path, UINT count )
 {
-    UINT len = strlenW( DIR_Windows.short_name ) + 1;
+    UINT len = strlenW( DIR_Windows ) + 1;
     if (path && count >= len)
     {
-        strcpyW( path, DIR_Windows.short_name );
+        strcpyW( path, DIR_Windows );
         len--;
     }
     return len;
@@ -427,10 +498,10 @@
  */
 UINT WINAPI GetWindowsDirectoryA( LPSTR path, UINT count )
 {
-    UINT len = WideCharToMultiByte( CP_ACP, 0, DIR_Windows.short_name, -1, NULL, 0, NULL, NULL );
+    UINT len = WideCharToMultiByte( CP_ACP, 0, DIR_Windows, -1, NULL, 0, NULL, NULL );
     if (path && count >= len)
     {
-        WideCharToMultiByte( CP_ACP, 0, DIR_Windows.short_name, -1, path, count, NULL, NULL );
+        WideCharToMultiByte( CP_ACP, 0, DIR_Windows, -1, path, count, NULL, NULL );
         len--;
     }
     return len;
@@ -471,10 +542,10 @@
  */
 UINT WINAPI GetSystemDirectoryW( LPWSTR path, UINT count )
 {
-    UINT len = strlenW( DIR_System.short_name ) + 1;
+    UINT len = strlenW( DIR_System ) + 1;
     if (path && count >= len)
     {
-        strcpyW( path, DIR_System.short_name );
+        strcpyW( path, DIR_System );
         len--;
     }
     return len;
@@ -488,10 +559,10 @@
  */
 UINT WINAPI GetSystemDirectoryA( LPSTR path, UINT count )
 {
-    UINT len = WideCharToMultiByte( CP_ACP, 0, DIR_System.short_name, -1, NULL, 0, NULL, NULL );
+    UINT len = WideCharToMultiByte( CP_ACP, 0, DIR_System, -1, NULL, 0, NULL, NULL );
     if (path && count >= len)
     {
-        WideCharToMultiByte( CP_ACP, 0, DIR_System.short_name, -1, path, count, NULL, NULL );
+        WideCharToMultiByte( CP_ACP, 0, DIR_System, -1, path, count, NULL, NULL );
         len--;
     }
     return len;
@@ -519,9 +590,9 @@
  *		ERROR_FILENAME_EXCED_RANGE: too long filename(s)
  */
 BOOL WINAPI CreateDirectoryW( LPCWSTR path,
-                                  LPSECURITY_ATTRIBUTES lpsecattribs )
+                              LPSECURITY_ATTRIBUTES lpsecattribs )
 {
-    DOS_FULL_NAME full_name;
+    char        uname[MAX_PATH];
 
     if (!path || !*path)
     {
@@ -534,25 +605,38 @@
     if (RtlIsDosDeviceName_U( path ))
     {
         TRACE_(file)("cannot use device %s!\n", debugstr_w(path));
-        SetLastError( ERROR_ACCESS_DENIED );
+        SetLastError(ERROR_ACCESS_DENIED);
         return FALSE;
     }
-    if (!DOSFS_GetFullName( path, FALSE, &full_name )) return 0;
-    if (mkdir( full_name.long_name, 0777 ) == -1) {
-        WARN_(file)("Error '%s' trying to create directory '%s'\n", strerror(errno), full_name.long_name);
+    if (!wine_get_unix_file_name(path, uname, sizeof(uname)))
+    {
+        SetLastError(ERROR_PATH_NOT_FOUND);
+        return FALSE;
+    }
+    if (mkdir(uname, 0777) == -1)
+    {
+        WARN_(file)("Error '%s' trying to create directory '%s'\n", strerror(errno), uname);
 	/* the FILE_SetDosError() generated error codes don't match the
 	 * CreateDirectory ones for some errnos */
-	switch (errno) {
-	case EEXIST:
+	switch (errno) 
         {
-            if (!strcmp(DRIVE_GetRoot(full_name.drive), full_name.long_name))
-                SetLastError(ERROR_ACCESS_DENIED);
-            else
-                SetLastError(ERROR_ALREADY_EXISTS);
+	case EEXIST:
+            {
+                WCHAR       x[MAX_PATH];
+                if (!RtlGetFullPathName_U(path, sizeof(x), x, NULL))
+                    SetLastError(ERROR_PATH_NOT_FOUND);
+                else if (strlenW(x) <= 3)
+                    SetLastError(ERROR_ACCESS_DENIED);
+                else
+                    SetLastError(ERROR_ALREADY_EXISTS);
+            }
+            break;
+	case ENOSPC:
+            SetLastError(ERROR_DISK_FULL);
+            break;
+	default:
+            FILE_SetDosError();
             break;
-        }
-	case ENOSPC: SetLastError(ERROR_DISK_FULL); break;
-	default: FILE_SetDosError();break;
 	}
 	return FALSE;
     }
@@ -590,7 +674,7 @@
  *           CreateDirectoryExA   (KERNEL32.@)
  */
 BOOL WINAPI CreateDirectoryExA( LPCSTR template, LPCSTR path,
-                                    LPSECURITY_ATTRIBUTES lpsecattribs)
+                                LPSECURITY_ATTRIBUTES lpsecattribs)
 {
     return CreateDirectoryA(path,lpsecattribs);
 }
@@ -600,7 +684,7 @@
  *           CreateDirectoryExW   (KERNEL32.@)
  */
 BOOL WINAPI CreateDirectoryExW( LPCWSTR template, LPCWSTR path,
-                                    LPSECURITY_ATTRIBUTES lpsecattribs)
+                                LPSECURITY_ATTRIBUTES lpsecattribs)
 {
     return CreateDirectoryW(path,lpsecattribs);
 }
@@ -620,7 +704,7 @@
  */
 BOOL WINAPI RemoveDirectoryW( LPCWSTR path )
 {
-    DOS_FULL_NAME full_name;
+    char        buffer[MAX_PATH];
 
     if (!path)
     {
@@ -636,8 +720,12 @@
         SetLastError( ERROR_FILE_NOT_FOUND );
         return FALSE;
     }
-    if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
-    if (rmdir( full_name.long_name ) == -1)
+    if (!wine_get_unix_file_name( path, buffer, sizeof(buffer) ))
+    {
+        SetLastError(ERROR_PATH_NOT_FOUND);
+        return FALSE;
+    }
+    if (rmdir( buffer ) == -1)
     {
         FILE_SetDosError();
         return FALSE;
@@ -672,131 +760,6 @@
 
 
 /***********************************************************************
- *           DIR_TryPath
- *
- * Helper function for DIR_SearchPath.
- */
-static BOOL DIR_TryPath( const DOS_FULL_NAME *dir, LPCWSTR name,
-                           DOS_FULL_NAME *full_name )
-{
-    LPSTR p_l = full_name->long_name + strlen(dir->long_name) + 1;
-    LPWSTR p_s = full_name->short_name + strlenW(dir->short_name) + 1;
-
-    if ((p_s >= full_name->short_name + sizeof(full_name->short_name)/sizeof(full_name->short_name[0]) - 14) ||
-        (p_l >= full_name->long_name + sizeof(full_name->long_name) - 1))
-    {
-        SetLastError( ERROR_PATH_NOT_FOUND );
-        return FALSE;
-    }
-    if (!DOSFS_FindUnixName( dir, name, p_l,
-                   sizeof(full_name->long_name) - (p_l - full_name->long_name),
-                   p_s, !(DRIVE_GetFlags(dir->drive) & DRIVE_CASE_SENSITIVE) ))
-        return FALSE;
-
-    full_name->drive = dir->drive;
-    strcpy( full_name->long_name, dir->long_name );
-    p_l[-1] = '/';
-    strcpyW( full_name->short_name, dir->short_name );
-    p_s[-1] = '\\';
-    return TRUE;
-}
-
-static BOOL DIR_SearchSemicolonedPaths(LPCWSTR name, DOS_FULL_NAME *full_name, LPWSTR pathlist)
-{
-    LPWSTR next, buffer = NULL;
-    INT len = strlenW(name), newlen, currlen = 0;
-    BOOL ret = FALSE;
-
-    next = pathlist;
-    while (!ret && next)
-    {
-        static const WCHAR bkslashW[] = {'\\',0};
-        LPWSTR cur = next;
-        while (*cur == ';') cur++;
-        if (!*cur) break;
-        next = strchrW( cur, ';' );
-        if (next) *next++ = '\0';
-        newlen = strlenW(cur) + len + 2;
-
-	if (newlen > currlen)
-	{
-	    if (buffer) 
-                buffer = HeapReAlloc( GetProcessHeap(), 0, buffer, newlen * sizeof(WCHAR));
-	    else
-                buffer = HeapAlloc( GetProcessHeap(), 0, newlen * sizeof(WCHAR));
-
-	    if(!buffer)
-                goto done;
-	    currlen = newlen;
-	}
-
-        strcpyW( buffer, cur );
-        strcatW( buffer, bkslashW );
-        strcatW( buffer, name );
-        ret = DOSFS_GetFullName( buffer, TRUE, full_name );
-    }
-done:
-    HeapFree( GetProcessHeap(), 0, buffer );
-    return ret;
-}
-
-
-/***********************************************************************
- *           DIR_TryEnvironmentPath
- *
- * Helper function for DIR_SearchPath.
- * Search in the specified path, or in $PATH if NULL.
- */
-static BOOL DIR_TryEnvironmentPath( LPCWSTR name, DOS_FULL_NAME *full_name, LPCWSTR envpath )
-{
-    LPWSTR path;
-    BOOL ret = FALSE;
-    DWORD size;
-    static const WCHAR pathW[] = {'P','A','T','H',0};
-
-    size = envpath ? strlenW(envpath)+1 : GetEnvironmentVariableW( pathW, NULL, 0 );
-    if (!size) return FALSE;
-    if (!(path = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE;
-    if (envpath) strcpyW( path, envpath );
-    else if (!GetEnvironmentVariableW( pathW, path, size )) goto done;
-
-    ret = DIR_SearchSemicolonedPaths(name, full_name, path);
-
-done:
-    HeapFree( GetProcessHeap(), 0, path );
-    return ret;
-}
-
-
-/***********************************************************************
- *           DIR_TryModulePath
- *
- * Helper function for DIR_SearchPath.
- */
-static BOOL DIR_TryModulePath( LPCWSTR name, DOS_FULL_NAME *full_name, BOOL win32 )
-{
-    WCHAR bufferW[MAX_PATH];
-    LPWSTR p;
-
-    if (!win32)
-    {
-        char buffer[OFS_MAXPATHNAME];
-	if (!GetCurrentTask()) return FALSE;
-	if (!GetModuleFileName16( GetCurrentTask(), buffer, sizeof(buffer) ))
-            return FALSE;
-        MultiByteToWideChar(CP_ACP, 0, buffer, -1, bufferW, MAX_PATH);
-    } else {
-	if (!GetModuleFileNameW( 0, bufferW, MAX_PATH )) return FALSE;
-        bufferW[MAX_PATH - 1] = '\0';
-    }
-    if (!(p = strrchrW( bufferW, '\\' ))) return FALSE;
-    if (MAX_PATH - (++p - bufferW) <= strlenW(name)) return FALSE;
-    strcpyW( p, name );
-    return DOSFS_GetFullName( bufferW, TRUE, full_name );
-}
-
-
-/***********************************************************************
  *           DIR_SearchPath
  *
  * Implementation of SearchPathA. 'win32' specifies whether the search
@@ -805,11 +768,12 @@
  * FIXME: should return long path names.
  */
 DWORD DIR_SearchPath( LPCWSTR path, LPCWSTR name, LPCWSTR ext,
-                      DOS_FULL_NAME *full_name, BOOL win32 )
+                      LPWSTR fullname, unsigned fnlen, LPWSTR* last, BOOL win32 )
 {
-    LPCWSTR p;
-    LPWSTR tmp = NULL;
-    BOOL ret = TRUE;
+    LPCWSTR     p;
+    LPWSTR      tmp = NULL, ev;
+    DWORD       ret = 0, size;
+    static const WCHAR pathW[] = {'P','A','T','H',0};
 
     /* First check the supplied parameters */
 
@@ -839,7 +803,19 @@
 
     if (FILE_contains_pathW(name))
     {
-        ret = DOSFS_GetFullName( name, TRUE, full_name );
+        if (*name == '/')
+        {
+            ret = strlenW(name);
+            if (ret >= fnlen)
+            {
+                SetLastError(ERROR_BUFFER_OVERFLOW);
+                goto done;
+            }
+            strcpyW(fullname, name);
+        }
+        else ret = GetFullPathNameW(name, fnlen, fullname, last);
+        
+        if (!RtlDoesFileExists_U(fullname)) ret = 0;
         goto done;
     }
 
@@ -847,38 +823,58 @@
 
     if (path)
     {
-        ret = DIR_TryEnvironmentPath( name, full_name, path );
+        ret = RtlDosSearchPath_U(path, name, NULL, fnlen, fullname, last);
         goto done;
     }
 
     /* Try the path of the current executable (for Win32 search order) */
-
-    if (win32 && DIR_TryModulePath( name, full_name, win32 )) goto done;
+    if (win32)
+    {
+        WCHAR   bufferW[MAX_PATH];
+	if (GetModuleFileNameW(0, bufferW, MAX_PATH ) &&
+            (ret = RtlDosSearchPath_U(bufferW, name, NULL, fnlen, fullname, last)))
+            goto done;
+    }
 
     /* Try the current directory */
-
-    if (DOSFS_GetFullName( name, TRUE, full_name )) goto done;
+    if ((ret = GetFullPathNameW(name, fnlen, fullname, last)) &&
+        RtlDoesFileExists_U(fullname)) goto done;
 
     /* Try the Windows system directory */
-
-    if (DIR_TryPath( &DIR_System, name, full_name ))
+    if ((ret = RtlDosSearchPath_U(DIR_System, name, NULL, fnlen, fullname, last)))
         goto done;
 
     /* Try the Windows directory */
-
-    if (DIR_TryPath( &DIR_Windows, name, full_name ))
+    if ((ret = RtlDosSearchPath_U(DIR_Windows, name, NULL, fnlen, fullname, last)))
         goto done;
 
     /* Try the path of the current executable (for Win16 search order) */
+    if (!win32)
+    {
+        char    buffer[OFS_MAXPATHNAME];
+        WCHAR   bufferW[MAX_PATH];
 
-    if (!win32 && DIR_TryModulePath( name, full_name, win32 )) goto done;
+	if (GetCurrentTask() && 
+            GetModuleFileName16(GetCurrentTask(), buffer, sizeof(buffer)))
+        {
+            MultiByteToWideChar(CP_ACP, 0, buffer, -1, bufferW, MAX_PATH);
+            if ((ret = RtlDosSearchPath_U(bufferW, name, NULL, fnlen, fullname, last)))
+                goto done;
+        }
+    }
 
     /* Try all directories in path */
-
-    ret = DIR_TryEnvironmentPath( name, full_name, NULL );
+    if ((size = GetEnvironmentVariableW(pathW, NULL, 0)) &&
+        (ev = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR))))
+    {
+        GetEnvironmentVariableW(pathW, ev, size);
+        ret = RtlDosSearchPath_U(ev, name, NULL, fnlen, fullname, last);
+        HeapFree(GetProcessHeap(), 0, ev);
+    }
 
 done:
     if (tmp) HeapFree( GetProcessHeap(), 0, tmp );
+    if (!ret) SetLastError(ERROR_FILE_NOT_FOUND);
     return ret;
 }
 
@@ -914,35 +910,15 @@
 DWORD WINAPI SearchPathW( LPCWSTR path, LPCWSTR name, LPCWSTR ext, DWORD buflen,
                           LPWSTR buffer, LPWSTR *lastpart )
 {
-    LPSTR res;
-    DOS_FULL_NAME full_name;
+    DWORD ret;
 
-    if (!DIR_SearchPath( path, name, ext, &full_name, TRUE ))
-    {
-	SetLastError(ERROR_FILE_NOT_FOUND);
-	return 0;
-    }
+    TRACE("%s %s %s %lu %p %p\n", 
+          debugstr_w(path), debugstr_w(name), debugstr_w(ext), 
+          buflen, buffer, lastpart);
+    ret = DIR_SearchPath( path, name, ext, buffer, buflen, lastpart, TRUE );
 
-TRACE("found %s %s\n", full_name.long_name, debugstr_w(full_name.short_name));
-TRACE("drive %c: root %s\n", 'A' + full_name.drive, DRIVE_GetRoot(full_name.drive));
-
-    lstrcpynW( buffer, full_name.short_name, buflen );
-    res = full_name.long_name +
-              strlen(DRIVE_GetRoot( full_name.drive ));
-    while (*res == '/') res++;
-    if (buflen)
-    {
-        LPWSTR p;
-        if (buflen > 3)
-        {
-            MultiByteToWideChar(CP_UNIXCP, 0, res, -1, buffer + 3, buflen - 3);
-            buffer[buflen - 1] = 0;
-        }
-        for (p = buffer; *p; p++) if (*p == '/') *p = '\\';
-        if (lastpart) *lastpart = strrchrW( buffer, '\\' ) + 1;
-    }
     TRACE("Returning %s\n", debugstr_w(buffer) );
-    return strlenW(buffer);
+    return ret;
 }
 
 
diff -u -N -r -x '*~' -x '.#*' -x CVS files47/dos_fs.c files/dos_fs.c
--- files47/dos_fs.c	2004-01-23 22:38:38.000000000 +0100
+++ files/dos_fs.c	2004-01-23 22:42:48.000000000 +0100
@@ -106,50 +106,6 @@
 } DOS_DIR;
 
 /***********************************************************************
- *           DOSFS_ValidDOSName
- *
- * Return 1 if Unix file 'name' is also a valid MS-DOS name
- * (i.e. contains only valid DOS chars, lower-case only, fits in 8.3 format).
- * File name can be terminated by '\0', '\\' or '/'.
- */
-static int DOSFS_ValidDOSName( LPCWSTR name, int ignore_case )
-{
-    static const char invalid_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" INVALID_DOS_CHARS;
-    const WCHAR *p = name;
-    const char *invalid = ignore_case ? (invalid_chars + 26) : invalid_chars;
-    int len = 0;
-
-    if (*p == '.')
-    {
-        /* Check for "." and ".." */
-        p++;
-        if (*p == '.') p++;
-        /* All other names beginning with '.' are invalid */
-        return (IS_END_OF_NAME(*p));
-    }
-    while (!IS_END_OF_NAME(*p))
-    {
-        if (*p < 256 && strchr( invalid, (char)*p )) return 0;  /* Invalid char */
-        if (*p == '.') break;  /* Start of the extension */
-        if (++len > 8) return 0;  /* Name too long */
-        p++;
-    }
-    if (*p != '.') return 1;  /* End of name */
-    p++;
-    if (IS_END_OF_NAME(*p)) return 0;  /* Empty extension not allowed */
-    len = 0;
-    while (!IS_END_OF_NAME(*p))
-    {
-        if (*p < 256 && strchr( invalid, (char)*p )) return 0;  /* Invalid char */
-        if (*p == '.') return 0;  /* Second extension not allowed */
-        if (++len > 3) return 0;  /* Extension too long */
-        p++;
-    }
-    return 1;
-}
-
-
-/***********************************************************************
  *           DOSFS_ToDosFCBFormat
  *
  * Convert a file name to DOS FCB format (8+3 chars, padded with blanks),
@@ -250,598 +206,6 @@
 
 
 /***********************************************************************
- *           DOSFS_ToDosDTAFormat
- *
- * Convert a file name from FCB to DTA format (name.ext, null-terminated)
- * converting to upper-case in the process.
- * File name can be terminated by '\0', '\\' or '/'.
- * 'buffer' must be at least 13 characters long.
- */
-static void DOSFS_ToDosDTAFormat( LPCWSTR name, LPWSTR buffer )
-{
-    LPWSTR p;
-
-    memcpy( buffer, name, 8 * sizeof(WCHAR) );
-    p = buffer + 8;
-    while ((p > buffer) && (p[-1] == ' ')) p--;
-    *p++ = '.';
-    memcpy( p, name + 8, 3 * sizeof(WCHAR) );
-    p += 3;
-    while (p[-1] == ' ') p--;
-    if (p[-1] == '.') p--;
-    *p = '\0';
-}
-
-
-/***********************************************************************
- *           DOSFS_AddDirEntry
- *
- *  Used to construct an array of filenames in DOSFS_OpenDir
- */
-static BOOL DOSFS_AddDirEntry(DOS_DIR **dir, LPCWSTR name, LPCWSTR dosname)
-{
-    int extra1 = strlenW(name) + 1;
-    int extra2 = strlenW(dosname) + 1;
-
-    /* if we need more, at minimum double the size */
-    if( (extra1 + extra2 + (*dir)->used) > (*dir)->size)
-    {
-        int more = (*dir)->size;
-        DOS_DIR *t;
-
-        if(more<(extra1+extra2))
-            more = extra1+extra2;
-
-        t = HeapReAlloc(GetProcessHeap(), 0, *dir, sizeof(**dir) + 
-                        ((*dir)->size + more)*sizeof(WCHAR) );
-        if(!t)
-        {
-            SetLastError( ERROR_NOT_ENOUGH_MEMORY );
-            ERR("Out of memory caching directory structure %d %d %d\n",
-                 (*dir)->size, more, (*dir)->used);
-            return FALSE;
-        }
-        (*dir) = t;
-        (*dir)->size += more;
-    }
-
-    /* at this point, the dir structure is big enough to hold these names */
-    strcpyW(&(*dir)->names[(*dir)->used], name);
-    (*dir)->used += extra1;
-    strcpyW(&(*dir)->names[(*dir)->used], dosname);
-    (*dir)->used += extra2;
-
-    return TRUE;
-}
-
-
-/***********************************************************************
- *           DOSFS_OpenDir_VFAT
- */
-static BOOL DOSFS_OpenDir_VFAT(DOS_DIR **dir, const char *unix_path)
-{
-#ifdef VFAT_IOCTL_READDIR_BOTH
-    KERNEL_DIRENT de[2];
-    int fd = open( unix_path, O_RDONLY|O_DIRECTORY );
-    BOOL r = TRUE;
-
-    /* Check if the VFAT ioctl is supported on this directory */
-
-    if ( fd<0 )
-        return FALSE;
-
-    while (1)
-    {
-        WCHAR long_name[MAX_PATH];
-        WCHAR short_name[12];
-
-        r = (ioctl( fd, VFAT_IOCTL_READDIR_BOTH, (long)de ) != -1);
-        if(!r)
-            break;
-        if (!de[0].d_reclen)
-            break;
-        MultiByteToWideChar(CP_UNIXCP, 0, de[0].d_name, -1, long_name, MAX_PATH);
-        if (!DOSFS_ToDosFCBFormat( long_name, short_name ))
-            short_name[0] = '\0';
-        if (de[1].d_name[0])
-            MultiByteToWideChar(CP_UNIXCP, 0, de[1].d_name, -1, long_name, MAX_PATH);
-        else
-            MultiByteToWideChar(CP_UNIXCP, 0, de[0].d_name, -1, long_name, MAX_PATH);
-        r = DOSFS_AddDirEntry(dir, long_name, short_name );
-        if(!r)
-            break;
-    }
-    if(r)
-    {
-        static const WCHAR empty_strW[] = { 0 };
-        DOSFS_AddDirEntry(dir, empty_strW, empty_strW);
-    }
-    close(fd);
-    return r;
-#else
-    return FALSE;
-#endif  /* VFAT_IOCTL_READDIR_BOTH */
-}
-
-
-/***********************************************************************
- *           DOSFS_OpenDir_Normal
- *
- * Now use the standard opendir/readdir interface
- */
-static BOOL DOSFS_OpenDir_Normal( DOS_DIR **dir, const char *unix_path )
-{
-    DIR *unixdir = opendir( unix_path );
-    BOOL r = TRUE;
-    static const WCHAR empty_strW[] = { 0 };
-
-    if(!unixdir)
-        return FALSE;
-    while(1)
-    {
-        WCHAR long_name[MAX_PATH];
-        struct dirent *de = readdir(unixdir);
-
-        if(!de)
-            break;
-        MultiByteToWideChar(CP_UNIXCP, 0, de->d_name, -1, long_name, MAX_PATH);
-        r = DOSFS_AddDirEntry(dir, long_name, empty_strW);
-        if(!r)
-            break;
-    }
-    if(r)
-        DOSFS_AddDirEntry(dir, empty_strW, empty_strW);
-    closedir(unixdir);
-    return r;
-}
-
-/***********************************************************************
- *           DOSFS_OpenDir
- */
-static DOS_DIR *DOSFS_OpenDir( const char *unix_path )
-{
-    const int init_size = 0x100;
-    DOS_DIR *dir = HeapAlloc( GetProcessHeap(), 0, sizeof(*dir) + init_size*sizeof (WCHAR));
-    BOOL r;
-
-    TRACE("%s\n",debugstr_a(unix_path));
-
-    if (!dir)
-    {
-        SetLastError( ERROR_NOT_ENOUGH_MEMORY );
-        return NULL;
-    }
-    dir->used = 0;
-    dir->size = init_size;
-
-    /* Treat empty path as root directory. This simplifies path split into
-       directory and mask in several other places */
-    if (!*unix_path) unix_path = "/";
-
-    r = DOSFS_OpenDir_VFAT( &dir, unix_path);
-
-    if(!r)
-        r = DOSFS_OpenDir_Normal( &dir, unix_path);
-
-    if(!r)
-    {
-        HeapFree(GetProcessHeap(), 0, dir);
-        return NULL;
-    }
-    dir->used = 0;
-
-    return dir;
-}
-
-
-/***********************************************************************
- *           DOSFS_CloseDir
- */
-static void DOSFS_CloseDir( DOS_DIR *dir )
-{
-    HeapFree( GetProcessHeap(), 0, dir );
-}
-
-
-/***********************************************************************
- *           DOSFS_ReadDir
- */
-static BOOL DOSFS_ReadDir( DOS_DIR *dir, LPCWSTR *long_name,
-                             LPCWSTR *short_name )
-{
-    LPCWSTR sn, ln;
-
-    if (!dir)
-       return FALSE;
-
-    /* the long pathname is first */
-    ln = &dir->names[dir->used];
-    if(ln[0])
-        *long_name  = ln;
-    else
-        return FALSE;
-    dir->used += (strlenW(ln) + 1);
-
-    /* followed by the short path name */
-    sn = &dir->names[dir->used];
-    if(sn[0])
-        *short_name = sn;
-    else
-        *short_name = NULL;
-    dir->used += (strlenW(sn) + 1);
-
-    return TRUE;
-}
-
-
-/***********************************************************************
- *           DOSFS_Hash
- *
- * Transform a Unix file name into a hashed DOS name. If the name is a valid
- * DOS name, it is converted to upper-case; otherwise it is replaced by a
- * hashed version that fits in 8.3 format.
- * File name can be terminated by '\0', '\\' or '/'.
- * 'buffer' must be at least 13 characters long.
- */
-static void DOSFS_Hash( LPCWSTR name, LPWSTR buffer, BOOL dir_format,
-                        BOOL ignore_case )
-{
-    static const char invalid_chars[] = INVALID_DOS_CHARS "~.";
-    static const char hash_chars[32] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345";
-
-    LPCWSTR p, ext;
-    LPWSTR dst;
-    unsigned short hash;
-    int i;
-
-    if (dir_format)
-    {
-        for(i = 0; i < 11; i++) buffer[i] = ' ';
-        buffer[11] = 0;
-    }
-
-    if (DOSFS_ValidDOSName( name, ignore_case ))
-    {
-        /* Check for '.' and '..' */
-        if (*name == '.')
-        {
-            buffer[0] = '.';
-            if (!dir_format) buffer[1] = buffer[2] = '\0';
-            if (name[1] == '.') buffer[1] = '.';
-            return;
-        }
-
-        /* Simply copy the name, converting to uppercase */
-
-        for (dst = buffer; !IS_END_OF_NAME(*name) && (*name != '.'); name++)
-            *dst++ = toupperW(*name);
-        if (*name == '.')
-        {
-            if (dir_format) dst = buffer + 8;
-            else *dst++ = '.';
-            for (name++; !IS_END_OF_NAME(*name); name++)
-                *dst++ = toupperW(*name);
-        }
-        if (!dir_format) *dst = '\0';
-        return;
-    }
-
-    /* Compute the hash code of the file name */
-    /* If you know something about hash functions, feel free to */
-    /* insert a better algorithm here... */
-    if (ignore_case)
-    {
-        for (p = name, hash = 0xbeef; !IS_END_OF_NAME(p[1]); p++)
-            hash = (hash<<3) ^ (hash>>5) ^ tolowerW(*p) ^ (tolowerW(p[1]) << 8);
-        hash = (hash<<3) ^ (hash>>5) ^ tolowerW(*p); /* Last character */
-    }
-    else
-    {
-        for (p = name, hash = 0xbeef; !IS_END_OF_NAME(p[1]); p++)
-            hash = (hash << 3) ^ (hash >> 5) ^ *p ^ (p[1] << 8);
-        hash = (hash << 3) ^ (hash >> 5) ^ *p;  /* Last character */
-    }
-
-    /* Find last dot for start of the extension */
-    for (p = name+1, ext = NULL; !IS_END_OF_NAME(*p); p++)
-        if (*p == '.') ext = p;
-    if (ext && IS_END_OF_NAME(ext[1]))
-        ext = NULL;  /* Empty extension ignored */
-
-    /* Copy first 4 chars, replacing invalid chars with '_' */
-    for (i = 4, p = name, dst = buffer; i > 0; i--, p++)
-    {
-        if (IS_END_OF_NAME(*p) || (p == ext)) break;
-        *dst++ = (*p < 256 && strchr( invalid_chars, (char)*p )) ? '_' : toupperW(*p);
-    }
-    /* Pad to 5 chars with '~' */
-    while (i-- >= 0) *dst++ = '~';
-
-    /* Insert hash code converted to 3 ASCII chars */
-    *dst++ = hash_chars[(hash >> 10) & 0x1f];
-    *dst++ = hash_chars[(hash >> 5) & 0x1f];
-    *dst++ = hash_chars[hash & 0x1f];
-
-    /* Copy the first 3 chars of the extension (if any) */
-    if (ext)
-    {
-        if (!dir_format) *dst++ = '.';
-        for (i = 3, ext++; (i > 0) && !IS_END_OF_NAME(*ext); i--, ext++)
-            *dst++ = (*ext < 256 && strchr( invalid_chars, (char)*ext )) ? '_' : toupperW(*ext);
-    }
-    if (!dir_format) *dst = '\0';
-}
-
-
-/***********************************************************************
- *           DOSFS_FindUnixName
- *
- * Find the Unix file name in a given directory that corresponds to
- * a file name (either in Unix or DOS format).
- * File name can be terminated by '\0', '\\' or '/'.
- * Return TRUE if OK, FALSE if no file name matches.
- *
- * 'long_buf' must be at least 'long_len' characters long. If the long name
- * turns out to be larger than that, the function returns FALSE.
- * 'short_buf' must be at least 13 characters long.
- */
-BOOL DOSFS_FindUnixName( const DOS_FULL_NAME *path, LPCWSTR name, char *long_buf,
-                         INT long_len, LPWSTR short_buf, BOOL ignore_case)
-{
-    DOS_DIR *dir;
-    LPCWSTR long_name, short_name;
-    WCHAR dos_name[12], tmp_buf[13];
-    BOOL ret;
-
-    LPCWSTR p = strchrW( name, '/' );
-    int len = p ? (int)(p - name) : strlenW(name);
-    if ((p = strchrW( name, '\\' ))) len = min( (int)(p - name), len );
-    /* Ignore trailing dots and spaces */
-    while (len > 1 && (name[len-1] == '.' || name[len-1] == ' ')) len--;
-    if (long_len < len + 1) return FALSE;
-
-    TRACE("%s,%s\n", path->long_name, debugstr_w(name) );
-
-    if (!DOSFS_ToDosFCBFormat( name, dos_name )) dos_name[0] = '\0';
-
-    if (!(dir = DOSFS_OpenDir( path->long_name )))
-    {
-        WARN("(%s,%s): can't open dir: %s\n",
-             path->long_name, debugstr_w(name), strerror(errno) );
-        return FALSE;
-    }
-
-    while ((ret = DOSFS_ReadDir( dir, &long_name, &short_name )))
-    {
-        /* Check against Unix name */
-        if (len == strlenW(long_name))
-        {
-            if (!ignore_case)
-            {
-                if (!strncmpW( long_name, name, len )) break;
-            }
-            else
-            {
-                if (!strncmpiW( long_name, name, len )) break;
-            }
-        }
-        if (dos_name[0])
-        {
-            /* Check against hashed DOS name */
-            if (!short_name)
-            {
-                DOSFS_Hash( long_name, tmp_buf, TRUE, ignore_case );
-                short_name = tmp_buf;
-            }
-            if (!strcmpW( dos_name, short_name )) break;
-        }
-    }
-    if (ret)
-    {
-        if (long_buf) WideCharToMultiByte(CP_UNIXCP, 0, long_name, -1, long_buf, long_len, NULL, NULL);
-        if (short_buf)
-        {
-            if (short_name)
-                DOSFS_ToDosDTAFormat( short_name, short_buf );
-            else
-                DOSFS_Hash( long_name, short_buf, FALSE, ignore_case );
-        }
-        TRACE("(%s,%s) -> %s (%s)\n", path->long_name, debugstr_w(name),
-              debugstr_w(long_name), short_buf ? debugstr_w(short_buf) : "***");
-    }
-    else
-        WARN("%s not found in '%s'\n", debugstr_w(name), path->long_name);
-    DOSFS_CloseDir( dir );
-    return ret;
-}
-
-
-/***********************************************************************
- *           DOSFS_GetPathDrive
- *
- * Get the drive specified by a given path name (DOS or Unix format).
- */
-static int DOSFS_GetPathDrive( LPCWSTR *name )
-{
-    int drive;
-    LPCWSTR p = *name;
-
-    if (*p && (p[1] == ':'))
-    {
-        drive = toupperW(*p) - 'A';
-        *name += 2;
-    }
-    else if (*p == '/') /* Absolute Unix path? */
-    {
-        if ((drive = DRIVE_FindDriveRootW( name )) == -1)
-        {
-            MESSAGE("Warning: %s not accessible from a configured DOS drive\n", debugstr_w(*name) );
-            /* Assume it really was a DOS name */
-            drive = DRIVE_GetCurrentDrive();
-        }
-    }
-    else drive = DRIVE_GetCurrentDrive();
-
-    if (!DRIVE_IsValid(drive))
-    {
-        SetLastError( ERROR_INVALID_DRIVE );
-        return -1;
-    }
-    return drive;
-}
-
-
-/***********************************************************************
- *           DOSFS_GetFullName
- *
- * Convert a file name (DOS or mixed DOS/Unix format) to a valid
- * Unix name / short DOS name pair.
- * Return FALSE if one of the path components does not exist. The last path
- * component is only checked if 'check_last' is non-zero.
- * The buffers pointed to by 'long_buf' and 'short_buf' must be
- * at least MAX_PATHNAME_LEN long.
- */
-BOOL DOSFS_GetFullName( LPCWSTR name, BOOL check_last, DOS_FULL_NAME *full )
-{
-    BOOL found;
-    UINT flags;
-    char *p_l, *root;
-    LPWSTR p_s;
-    static const WCHAR driveA_rootW[] = {'A',':','\\',0};
-    static const WCHAR dos_rootW[] = {'\\',0};
-
-    TRACE("%s (last=%d)\n", debugstr_w(name), check_last );
-
-    if ((!*name) || (*name=='\n'))
-    { /* error code for Win98 */
-        SetLastError(ERROR_BAD_PATHNAME);
-        return FALSE;
-    }
-
-    if ((full->drive = DOSFS_GetPathDrive( &name )) == -1) return FALSE;
-    flags = DRIVE_GetFlags( full->drive );
-
-    lstrcpynA( full->long_name, DRIVE_GetRoot( full->drive ),
-                 sizeof(full->long_name) );
-    if (full->long_name[1]) root = full->long_name + strlen(full->long_name);
-    else root = full->long_name;  /* root directory */
-
-    strcpyW( full->short_name, driveA_rootW );
-    full->short_name[0] += full->drive;
-
-    if ((*name == '\\') || (*name == '/'))  /* Absolute path */
-    {
-        while ((*name == '\\') || (*name == '/')) name++;
-    }
-    else  /* Relative path */
-    {
-        lstrcpynA( root + 1, DRIVE_GetUnixCwd( full->drive ),
-                     sizeof(full->long_name) - (root - full->long_name) - 1 );
-        if (root[1]) *root = '/';
-        lstrcpynW( full->short_name + 3, DRIVE_GetDosCwd( full->drive ),
-                   sizeof(full->short_name)/sizeof(full->short_name[0]) - 3 );
-    }
-
-    p_l = full->long_name[1] ? full->long_name + strlen(full->long_name)
-                             : full->long_name;
-    p_s = full->short_name[3] ? full->short_name + strlenW(full->short_name)
-                              : full->short_name + 2;
-    found = TRUE;
-
-    while (*name && found)
-    {
-        /* Check for '.' and '..' */
-
-        if (*name == '.')
-        {
-            if (IS_END_OF_NAME(name[1]))
-            {
-                name++;
-                while ((*name == '\\') || (*name == '/')) name++;
-                continue;
-            }
-            else if ((name[1] == '.') && IS_END_OF_NAME(name[2]))
-            {
-                name += 2;
-                while ((*name == '\\') || (*name == '/')) name++;
-                while ((p_l > root) && (*p_l != '/')) p_l--;
-                while ((p_s > full->short_name + 2) && (*p_s != '\\')) p_s--;
-                *p_l = *p_s = '\0';  /* Remove trailing separator */
-                continue;
-            }
-        }
-
-        /* Make sure buffers are large enough */
-
-        if ((p_s >= full->short_name + sizeof(full->short_name)/sizeof(full->short_name[0]) - 14) ||
-            (p_l >= full->long_name + sizeof(full->long_name) - 1))
-        {
-            SetLastError( ERROR_PATH_NOT_FOUND );
-            return FALSE;
-        }
-
-        /* Get the long and short name matching the file name */
-
-        if ((found = DOSFS_FindUnixName( full, name, p_l + 1,
-                         sizeof(full->long_name) - (p_l - full->long_name) - 1,
-                         p_s + 1, !(flags & DRIVE_CASE_SENSITIVE) )))
-        {
-            *p_l++ = '/';
-            p_l   += strlen(p_l);
-            *p_s++ = '\\';
-            p_s   += strlenW(p_s);
-            while (!IS_END_OF_NAME(*name)) name++;
-        }
-        else if (!check_last)
-        {
-            *p_l++ = '/';
-            *p_s++ = '\\';
-            while (!IS_END_OF_NAME(*name) &&
-                   (p_s < full->short_name + sizeof(full->short_name)/sizeof(full->short_name[0]) - 1) &&
-                   (p_l < full->long_name + sizeof(full->long_name) - 1))
-            {
-                WCHAR wch;
-                *p_s++ = tolowerW(*name);
-                /* If the drive is case-sensitive we want to create new */
-                /* files in lower-case otherwise we can't reopen them   */
-                /* under the same short name. */
-                if (flags & DRIVE_CASE_SENSITIVE) wch = tolowerW(*name);
-                else wch = *name;
-                p_l += WideCharToMultiByte(CP_UNIXCP, 0, &wch, 1, p_l, 2, NULL, NULL);
-                name++;
-            }
-	    /* Ignore trailing dots and spaces */
-	    while(p_l[-1] == '.' || p_l[-1] == ' ') {
-		--p_l;
-		--p_s;
-	    }
-            *p_l = '\0';
-            *p_s = '\0';
-        }
-        while ((*name == '\\') || (*name == '/')) name++;
-    }
-
-    if (!found)
-    {
-        if (check_last)
-        {
-            SetLastError( ERROR_FILE_NOT_FOUND );
-            return FALSE;
-        }
-        if (*name)  /* Not last */
-        {
-            SetLastError( ERROR_PATH_NOT_FOUND );
-            return FALSE;
-        }
-    }
-    if (!full->long_name[0]) strcpy( full->long_name, "/" );
-    if (!full->short_name[2]) strcpyW( full->short_name + 2, dos_rootW );
-    TRACE("returning %s = %s\n", full->long_name, debugstr_w(full->short_name) );
-    return TRUE;
-}
-
-
-/***********************************************************************
  *           MulDiv   (KERNEL32.@)
  * RETURNS
  *	Result of multiplication and division
diff -u -N -r -x '*~' -x '.#*' -x CVS files47/drive.c files/drive.c
--- files47/drive.c	2004-01-23 22:39:05.000000000 +0100
+++ files/drive.c	2004-01-23 22:43:07.000000000 +0100
@@ -171,6 +171,9 @@
 }
 
 
+/* whether we set the =[A-Z]: environment variables when changing directories */
+static BOOL DRIVE_SetPerDriveEnv;
+
 /***********************************************************************
  *           DRIVE_Init
  */
@@ -646,54 +649,83 @@
 }
 
 /***********************************************************************
+ *           DRIVE_CheckDosCwd
+ */
+void DRIVE_CheckDosCwd(void)
+{
+    TDB *pTask = GlobalLock16(GetCurrentTask());
+    int drive = DRIVE_CurDrive;
+
+    if (!DRIVE_IsValid( 'A' + drive )) return;
+
+    /* Check if we need to change the directory to the new task. */
+    if (pTask && (pTask->curdrive & 0x80) &&    /* The task drive is valid */
+        ((pTask->curdrive & ~0x80) == drive) && /* and it's the one we want */
+        (DRIVE_LastTask != GetCurrentTask()))   /* and the task changed */
+    {
+        static const WCHAR rootW[] = {'\\',0};
+        WCHAR curdirW[MAX_PATH];
+        MultiByteToWideChar(CP_ACP, 0, pTask->curdir, -1, curdirW, MAX_PATH);
+        /* Perform the task-switch */
+        if (!DRIVE_Chdir( drive, curdirW )) DRIVE_Chdir( drive, rootW );
+        DRIVE_LastTask = GetCurrentTask();
+    }
+}
+
+/***********************************************************************
  *           DRIVE_Chdir
  */
 int DRIVE_Chdir( int drive, LPCWSTR path )
 {
-    DOS_FULL_NAME full_name;
-    WCHAR buffer[MAX_PATHNAME_LEN];
-    LPSTR unix_cwd;
-    BY_HANDLE_FILE_INFORMATION info;
-    TDB *pTask = GlobalLock16(GetCurrentTask());
+    WCHAR       buffer[MAX_PATHNAME_LEN], tmp1[MAX_PATHNAME_LEN], tmp2[MAX_PATHNAME_LEN];
+    char        dst[MAX_PATHNAME_LEN];
+    DWORD       attr;
+    TDB*        pTask = GlobalLock16(GetCurrentTask());
 
     buffer[0] = 'A' + drive;
     buffer[1] = ':';
     buffer[2] = 0;
+
     TRACE("(%s,%s)\n", debugstr_w(buffer), debugstr_w(path) );
+
     strncpyW( buffer + 2, path, MAX_PATHNAME_LEN - 2 );
     buffer[MAX_PATHNAME_LEN - 1] = 0; /* ensure 0 termination */
 
-    if (!DOSFS_GetFullName( buffer, TRUE, &full_name )) return 0;
-    if (!FILE_Stat( full_name.long_name, &info, NULL )) return 0;
-    if (!(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+    attr = GetFileAttributesW(buffer);
+    if (attr == INVALID_FILE_ATTRIBUTES) return 0;
+    if (!(attr & FILE_ATTRIBUTE_DIRECTORY))
     {
         SetLastError( ERROR_FILE_NOT_FOUND );
         return 0;
     }
-    unix_cwd = full_name.long_name + strlen( DOSDrives[drive].root );
-    while (*unix_cwd == '/') unix_cwd++;
+    GetFullPathNameW(buffer, sizeof(tmp1) / sizeof(tmp1[0]), tmp1, NULL);
+    GetShortPathNameW(tmp1, tmp2, sizeof(tmp2) / sizeof(tmp2[0]));
+    wine_get_unix_file_name(tmp2, dst, sizeof(dst));
+    if (dst[strlen(dst) - 1] == '\\')
+        dst[strlen(dst) - 1] = '\0';
+    if (tmp2[strlenW(tmp2) - 1] == '\\')
+        tmp2[strlenW(tmp2) - 1] = '\0';
 
     TRACE("(%c:): unix_cwd=%s dos_cwd=%s\n",
-            'A' + drive, unix_cwd, debugstr_w(full_name.short_name + 3) );
+            'A' + drive, dst, debugstr_w(tmp2 + 3) );
 
-    HeapFree( GetProcessHeap(), 0, DOSDrives[drive].dos_cwd );
-    HeapFree( GetProcessHeap(), 0, DOSDrives[drive].unix_cwd );
-    DOSDrives[drive].dos_cwd  = HeapAlloc(GetProcessHeap(), 0, (strlenW(full_name.short_name) - 2) * sizeof(WCHAR));
-    strcpyW(DOSDrives[drive].dos_cwd, full_name.short_name + 3);
-    DOSDrives[drive].unix_cwd = heap_strdup( unix_cwd );
+    if (DRIVE_SetPerDriveEnv)
+    {
+        const WCHAR envW[] = {'=', 'A' + drive, ':', 0};
+        SetEnvironmentVariableW(envW, tmp2);
+    }
 
     if (drive == DRIVE_CurDrive)
     {
         UNICODE_STRING dirW;
-
-        RtlInitUnicodeString( &dirW, full_name.short_name );
+        RtlInitUnicodeString( &dirW, tmp2 );
         RtlSetCurrentDirectory_U( &dirW );
     }
 
     if (pTask && (pTask->curdrive & 0x80) &&
         ((pTask->curdrive & ~0x80) == drive))
     {
-        WideCharToMultiByte(CP_ACP, 0, full_name.short_name + 2, -1,
+        WideCharToMultiByte(CP_ACP, 0, tmp2 + 2, -1,
                             pTask->curdir, sizeof(pTask->curdir), NULL, NULL);
         DRIVE_LastTask = GetCurrentTask();
     }
@@ -740,17 +772,8 @@
 */
 static UINT DRIVE_GetCurrentDirectory( UINT buflen, LPWSTR buf )
 {
-    UINT ret;
-    LPCWSTR dos_cwd = DRIVE_GetDosCwd( DRIVE_GetCurrentDrive() );
-    static const WCHAR driveA_rootW[] = {'A',':','\\',0};
-
-    ret = strlenW(dos_cwd) + 3; /* length of WHOLE current directory */
-    if (ret >= buflen) return ret + 1;
-
-    strcpyW( buf, driveA_rootW );
-    buf[0] += DRIVE_GetCurrentDrive();
-    strcatW( buf, dos_cwd );
-    return ret;
+    DRIVE_CheckDosCwd();
+    return RtlGetCurrentDirectory_U( buflen * sizeof(WCHAR), buf );
 }
 
 
diff -u -N -r -x '*~' -x '.#*' -x CVS files47/file.c files/file.c
--- files47/file.c	2004-01-23 22:37:40.000000000 +0100
+++ files/file.c	2004-01-23 22:40:04.000000000 +0100
@@ -613,17 +613,16 @@
  */
 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
 {
-    DOS_FULL_NAME full_name;
-    BY_HANDLE_FILE_INFORMATION info;
+   char                        buffer[MAX_PATH];
+    BY_HANDLE_FILE_INFORMATION  info;
 
     if (name == NULL)
     {
         SetLastError( ERROR_INVALID_PARAMETER );
         return INVALID_FILE_ATTRIBUTES;
     }
-    if (!DOSFS_GetFullName( name, TRUE, &full_name) )
-        return INVALID_FILE_ATTRIBUTES;
-    if (!FILE_Stat( full_name.long_name, &info, NULL ))
+    if (!wine_get_unix_file_name( name, buffer, sizeof(buffer) ) ||
+        !FILE_Stat( buffer, &info, NULL ))
         return INVALID_FILE_ATTRIBUTES;
     return info.dwFileAttributes;
 }
@@ -660,7 +659,7 @@
 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
 {
     struct stat buf;
-    DOS_FULL_NAME full_name;
+    char        buffer[MAX_PATH];
 
     if (!lpFileName)
     {
@@ -670,17 +669,19 @@
 
     TRACE("(%s,%lx)\n", debugstr_w(lpFileName), attributes);
 
-    if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
+    if (!wine_get_unix_file_name( lpFileName, buffer, sizeof(buffer) ))
+    {
+        SetLastError(ERROR_PATH_NOT_FOUND);
         return FALSE;
-
-    if(stat(full_name.long_name,&buf)==-1)
+    }
+    if (stat(buffer, &buf) == -1)
     {
         FILE_SetDosError();
         return FALSE;
     }
     if (attributes & FILE_ATTRIBUTE_READONLY)
     {
-        if(S_ISDIR(buf.st_mode))
+        if (S_ISDIR(buf.st_mode))
             /* FIXME */
             WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
         else
@@ -702,7 +703,7 @@
     attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
     if (attributes)
         FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName), attributes);
-    if (-1==chmod(full_name.long_name,buf.st_mode))
+    if (-1==chmod(buffer, buf.st_mode))
     {
         if (GetDriveTypeW(lpFileName) == DRIVE_CDROM)
         {
@@ -721,7 +722,7 @@
         *        to change attributes of already installed DLLs.
         */
         FIXME("Couldn't set file attributes for existing file \"%s\".\n"
-              "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
+              "Check permissions or set VFAT \"quiet\" mount flag\n", buffer);
     }
     return TRUE;
 }
@@ -787,14 +788,15 @@
     LPCWSTR lpFileName,     /* [in]  Pointer to name of file */
     LPDWORD lpFileSizeHigh) /* [out] Receives high-order doubleword of size */
 {
-    DOS_FULL_NAME full_name;
+    char        buffer[MAX_PATH];
     struct stat st;
-    DWORD low;
+    DWORD       low;
 
     TRACE("(%s,%p)\n",debugstr_w(lpFileName),lpFileSizeHigh);
 
-    if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return INVALID_FILE_SIZE;
-    if (stat(full_name.long_name, &st) != 0)
+    if (!wine_get_unix_file_name(lpFileName, buffer, sizeof(buffer))) 
+        return INVALID_FILE_SIZE;
+    if (stat(buffer, &st) != 0)
     {
         FILE_SetDosError();
         return INVALID_FILE_SIZE;
@@ -863,9 +865,9 @@
 {
     static const WCHAR formatW[] = {'%','x','.','t','m','p',0};
 
-    DOS_FULL_NAME full_name;
-    int i;
-    LPWSTR p;
+    char        tmp[MAX_PATH];
+    int         i;
+    WCHAR       wch, *p;
 
     if ( !path || !prefix || !buffer )
     {
@@ -911,15 +913,21 @@
     }
 
     /* Get the full path name */
-
-    if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
+    p = buffer + strlenW(buffer);
+    while (--p >= buffer)
     {
-        char *slash;
-        /* Check if we have write access in the directory */
-        if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
-        if (access( full_name.long_name, W_OK ) == -1)
-            WARN("returns %s, which doesn't seem to be writeable.\n",
-                  debugstr_w(buffer) );
+        if (*p == '/' || *p == '\\')
+        {
+            wch = *p; *p = '\0';
+            if (wine_get_unix_file_name(buffer, tmp, sizeof(tmp)))
+            {
+                if (access(tmp, W_OK) == -1 && errno == EACCES)
+                    WARN("returns %s, which doesn't seem to be writeable.\n",
+                         debugstr_w(buffer) );
+            }
+            *p = wch;
+            break;
+        }
     }
     TRACE("returning %s\n", debugstr_w(buffer) );
     return unique;
@@ -933,15 +941,18 @@
  */
 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode, BOOL win32 )
 {
-    HFILE hFileRet;
-    HANDLE handle;
-    FILETIME filetime;
-    WORD filedatetime[2];
-    DOS_FULL_NAME full_name;
-    DWORD access, sharing;
-    WCHAR *p;
-    WCHAR buffer[MAX_PATH];
-    LPWSTR nameW;
+    HFILE       hFileRet;
+    HANDLE      handle;
+    FILETIME    filetime;
+    WORD        filedatetime[2];
+    DWORD       access, sharing;
+    LPWSTR      p;
+    WCHAR       buffer[MAX_PATH];
+    WCHAR       dst[MAX_PATH]; 
+    char        uname[MAX_PATH];
+    LPWSTR      nameW;
+    struct stat st;
+
 
     if (!ofs) return HFILE_ERROR;
 
@@ -1015,8 +1026,9 @@
     if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
     {
         /* First try the file name as is */
-        if (DOSFS_GetFullName( nameW, TRUE, &full_name )) goto found;
-        /* Now remove the path */
+        if (wine_get_unix_file_name(nameW, uname, sizeof(uname)) && 
+            stat(uname, &st) != -1) goto found;
+         /* Now remove the path */
         if (nameW[0] && (nameW[1] == ':')) nameW += 2;
         if ((p = strrchrW( nameW, '\\' ))) nameW = p + 1;
         if ((p = strrchrW( nameW, '/' ))) nameW = p + 1;
@@ -1025,12 +1037,11 @@
 
     /* Now look for the file */
 
-    if (!DIR_SearchPath( NULL, nameW, NULL, &full_name, win32 )) goto not_found;
+    if (!DIR_SearchPath( NULL, nameW, NULL, dst, sizeof(dst)/sizeof(dst[0]), NULL, win32 )) goto not_found;
 
 found:
-    TRACE("found %s = %s\n",
-          full_name.long_name, debugstr_w(full_name.short_name) );
-    WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1,
+    TRACE("found %s\n", debugstr_w(dst) );
+    WideCharToMultiByte(CP_ACP, 0, dst, -1,
                         ofs->szPathName, sizeof(ofs->szPathName), NULL, NULL);
 
     if (mode & OF_DELETE)
@@ -1039,7 +1050,8 @@
                                   NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, 0 );
         if (!handle) goto error;
         CloseHandle( handle );
-        if (unlink( full_name.long_name ) == -1) goto not_found;
+        if (!wine_get_unix_file_name(nameW, uname, sizeof(uname)) ||
+            unlink( uname ) == -1) goto not_found;
         TRACE("(%s): OF_DELETE return = OK\n", name);
         return 1;
     }
@@ -1351,8 +1363,8 @@
  */
 BOOL WINAPI DeleteFileW( LPCWSTR path )
 {
-    DOS_FULL_NAME full_name;
-    HANDLE hFile;
+    char        buffer[MAX_PATH];
+    HANDLE      hFile;
 
     TRACE("%s\n", debugstr_w(path) );
     if (!path || !*path)
@@ -1367,14 +1379,14 @@
         return FALSE;
     }
 
-    if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
+    if (!wine_get_unix_file_name( path, buffer, sizeof(buffer) )) return FALSE;
 
     /* check if we are allowed to delete the source */
     hFile = FILE_CreateFile( path, GENERIC_READ|GENERIC_WRITE, 0,
                              NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, 0 );
     if (!hFile) return FALSE;
 
-    if (unlink( full_name.long_name ) == -1)
+    if (unlink( buffer ) == -1)
     {
         FILE_SetDosError();
         CloseHandle(hFile);
@@ -1584,9 +1596,9 @@
  */
 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
 {
-    DOS_FULL_NAME full_name1, full_name2;
-    HANDLE hFile;
-    DWORD attr = INVALID_FILE_ATTRIBUTES;
+    char                        buffer1[MAX_PATH], buffer2[MAX_PATH];
+    BY_HANDLE_FILE_INFORMATION  info1, info2;
+    HANDLE                      hFile;
 
     TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
 
@@ -1601,7 +1613,8 @@
     /* Filename1 has to be always set to a valid path. Filename2 may be NULL
        if the source file has to be deleted.
     */
-    if (!fn1) {
+    if (!fn1)
+    {
         SetLastError(ERROR_INVALID_PARAMETER);
         return FALSE;
     }
@@ -1612,34 +1625,28 @@
        they are given but it can't reply with a reasonable returncode. Success
        means in that case success for entering the values into the registry.
     */
-    if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
+    if (!wine_get_unix_file_name(fn1, buffer1, sizeof(buffer1)) ||
+        !FILE_Stat(buffer1, &info1, NULL))
     {
-        if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
+        if (!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
             return FALSE;
     }
 
     if (fn2)  /* !fn2 means delete fn1 */
     {
-        if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
+        if (wine_get_unix_file_name(fn2, buffer2, sizeof(buffer2)))
         {
-            if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
-            {
+            if (FILE_Stat(buffer2, &info2, NULL) && /* file exists ? */
+                !(flag & MOVEFILE_DELAY_UNTIL_REBOOT) &&
                 /* target exists, check if we may overwrite */
-                if (!(flag & MOVEFILE_REPLACE_EXISTING))
-                {
-                    SetLastError( ERROR_ALREADY_EXISTS );
-                    return FALSE;
-                }
-            }
-        }
-        else
-        {
-            if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
+                !(flag & MOVEFILE_REPLACE_EXISTING))
             {
-                if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
-                    return FALSE;
+                SetLastError(ERROR_ALREADY_EXISTS);
+                return FALSE;
             }
         }
+        else if (!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
+            return FALSE;
 
         /* Source name and target path are valid */
 
@@ -1648,8 +1655,7 @@
             return FILE_AddBootRenameEntry( fn1, fn2, flag );
         }
 
-        attr = GetFileAttributesW( fn1 );
-        if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
+        if (!FILE_Stat(buffer1, &info1, NULL)) return FALSE;
 
         /* check if we are allowed to rename the source */
         hFile = FILE_CreateFile( fn1, 0, 0,
@@ -1657,9 +1663,11 @@
                                  FILE_ATTRIBUTE_READONLY|FILE_FLAG_BACKUP_SEMANTICS, 0 );
         if (!hFile)
         {
-            if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
-            if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
+            if (GetLastError() != ERROR_ACCESS_DENIED ||
+                !(info1.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) 
+                return FALSE;
             /* if it's a directory we can continue */
+            /* FIXME: check that code, I wonder if it still applies... */
         }
         else CloseHandle(hFile);
 
@@ -1671,49 +1679,43 @@
         if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
         CloseHandle(hFile);
 
-        if (full_name1.drive != full_name2.drive)
+        if (rename(buffer1, buffer2) == -1)
+            /* Try copy/delete unless it's a directory. */
+            /* FIXME: This does not handle the (unlikely) case that the two locations
+               are on the same Wine drive, but on different Unix file systems. */
         {
-            if (!(flag & MOVEFILE_COPY_ALLOWED))
+            if (errno != EXDEV)
             {
-                SetLastError( ERROR_NOT_SAME_DEVICE );
+                FILE_SetDosError();
                 return FALSE;
             }
-            else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
+            if (info1.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
             {
                 /* Strange, but that's what Windows returns */
-                SetLastError ( ERROR_ACCESS_DENIED );
+                SetLastError (ERROR_ACCESS_DENIED);
                 return FALSE;
             }
-        }
-        if (rename( full_name1.long_name, full_name2.long_name ) == -1)
-            /* Try copy/delete unless it's a directory. */
-            /* FIXME: This does not handle the (unlikely) case that the two locations
-               are on the same Wine drive, but on different Unix file systems. */
-        {
-            if ( attr & FILE_ATTRIBUTE_DIRECTORY )
+            if (!(flag & MOVEFILE_COPY_ALLOWED))
             {
-                FILE_SetDosError();
+                SetLastError(ERROR_NOT_SAME_DEVICE);
                 return FALSE;
             }
-            else
-            {
-                if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
-                    return FALSE;
-                if ( ! DeleteFileW ( fn1 ) )
-                    return FALSE;
-            }
+            if (!CopyFileW(fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING)))
+                return FALSE;
+            if (!DeleteFileW(fn1))
+                return FALSE;
         }
-        if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
+        if (is_executable(buffer1) != is_executable(buffer2))
         {
             struct stat fstat;
-            if (stat( full_name2.long_name, &fstat ) != -1)
+            if (stat(buffer2, &fstat) != -1)
             {
-                if (is_executable( full_name2.long_name ))
+                if (is_executable(buffer2))
                     /* set executable bit where read bit is set */
                     fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
                 else
                     fstat.st_mode &= ~0111;
-                chmod( full_name2.long_name, fstat.st_mode );
+                chmod(buffer2, fstat.st_mode);
             }
         }
         return TRUE;
@@ -1722,16 +1724,15 @@
     {
         if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
         {
-            if (flag & MOVEFILE_COPY_ALLOWED) {
+            if (flag & MOVEFILE_COPY_ALLOWED)
+            {
                 WARN("Illegal flag\n");
-                SetLastError( ERROR_GEN_FAILURE );
+                SetLastError(ERROR_GEN_FAILURE);
                 return FALSE;
             }
-
-            return FILE_AddBootRenameEntry( fn1, NULL, flag );
+            return FILE_AddBootRenameEntry(fn1, NULL, flag);
         }
-
-        if (unlink( full_name1.long_name ) == -1)
+        if (unlink(buffer1) == -1)
         {
             FILE_SetDosError();
             return FALSE;
@@ -1952,7 +1953,7 @@
 	LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
 	LPVOID lpFileInformation)
 {
-    DOS_FULL_NAME full_name;
+    char        buffer[MAX_PATH];
     BY_HANDLE_FILE_INFORMATION info;
 
     if (!lpFileName || !lpFileInformation)
@@ -1961,11 +1962,16 @@
         return FALSE;
     }
 
-    if (fInfoLevelId == GetFileExInfoStandard) {
+    if (fInfoLevelId == GetFileExInfoStandard)
+    {
 	LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
 	    (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
-	if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
-	if (!FILE_Stat( full_name.long_name, &info, NULL )) return FALSE;
+	if (!wine_get_unix_file_name( lpFileName, buffer, sizeof(buffer) ))
+        {
+            SetLastError(ERROR_PATH_NOT_FOUND);
+            return FALSE;
+        }
+	if (!FILE_Stat( buffer, &info, NULL )) return FALSE;
 
 	lpFad->dwFileAttributes = info.dwFileAttributes;
 	lpFad->ftCreationTime   = info.ftCreationTime;
@@ -1974,7 +1980,8 @@
 	lpFad->nFileSizeHigh    = info.nFileSizeHigh;
 	lpFad->nFileSizeLow     = info.nFileSizeLow;
     }
-    else {
+    else
+    {
 	FIXME("invalid info level %d!\n", fInfoLevelId);
 	return FALSE;
     }
diff -u -N -r -x '*~' -x '.#*' -x CVS include47/file.h include/file.h
--- include47/file.h	2004-01-19 22:40:11.000000000 +0100
+++ include/file.h	2004-01-20 22:14:05.000000000 +0100
@@ -35,14 +35,6 @@
 
 #define MAX_PATHNAME_LEN   1024
 
-/* Definition of a full DOS file name */
-typedef struct
-{
-    char  long_name[MAX_PATHNAME_LEN];  /* Long pathname in Unix format */
-    WCHAR short_name[MAX_PATHNAME_LEN]; /* Short pathname in DOS 8.3 format */
-    int   drive;
-} DOS_FULL_NAME;
-
 #define IS_END_OF_NAME(ch)  (!(ch) || ((ch) == '/') || ((ch) == '\\'))
 
 /* locale-independent case conversion */
@@ -70,14 +62,8 @@
 extern int DIR_Init(void);
 extern UINT DIR_GetWindowsUnixDir( LPSTR path, UINT count );
 extern UINT DIR_GetSystemUnixDir( LPSTR path, UINT count );
-extern DWORD DIR_SearchPath( LPCWSTR path, LPCWSTR name, LPCWSTR ext,
-                             DOS_FULL_NAME *full_name, BOOL win32 );
 
 /* files/dos_fs.c */
 extern BOOL DOSFS_ToDosFCBFormat( LPCWSTR name, LPWSTR buffer );
-extern BOOL DOSFS_FindUnixName( const DOS_FULL_NAME *path, LPCWSTR name, char *long_buf,
-                                INT long_len, LPWSTR short_buf, BOOL ignore_case );
-extern BOOL DOSFS_GetFullName( LPCWSTR name, BOOL check_last,
-                                 DOS_FULL_NAME *full );
 
 #endif  /* __WINE_FILE_H */
diff -u -N -r -x '*~' -x '.#*' -x CVS include47/winternl.h include/winternl.h
--- include47/winternl.h	2004-01-21 21:48:53.000000000 +0100
+++ include/winternl.h	2004-01-27 20:54:32.000000000 +0100
@@ -999,15 +999,6 @@
 #define FILE_DEVICE_IS_MOUNTED          0x00000020
 #define FILE_VIRTUAL_VOLUME             0x00000040
 
-/* 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