wine_get_unix_file_name, GetShortPathNameA and GetLongPathNameA

Michael Wetherell mike.wetherell at ntlworld.com
Tue Apr 23 18:54:03 CDT 2002


I tried to post this patch a couple of days ago, so I appologise in
advance if that previous email turns up and we end up with a dupliate.

Here's an example of the problem that I've tried to address. Suppose
you have 'Z:\' mapped to '/', 'Y:\' mapped to your home dir, say
'/home/mike' and suppose your current working directory is below that,
say '/home/mike/wine'.

Then currently wine_get_unix_file_name("/home/mike") would return
'/home/mike/wine', the reason being that '/home/mike' translates to
'Y:' which is the cwd. And wine_get_unix_file_name("/home/mike/..")
returns '/home/mike', since it translates to 'Y:\..' which is just
'Y:\'.

For the first problem I've added a check for unix absolute paths
to DOSFS_GetFullName, to make sure they're not treated as relative
paths, so '/home/mike' is 'Y:\' not 'Y:'. For the 2nd I changed
DRIVE_FindDriveRoot to ignore any directories that are ascended back
out of with '..' when selecting the root 'drive' for a given unix
path, so it would choose 'Z:\home' instead of 'Y:\'. The problems
were the same for GetShortPathNameA and GetLongPathNameA since they
too depend on DOSFS_GetFullName (which depends on DRIVE_FindDriveRoot).

I also changed GetShortPathNameA to prepend a DOS drive letter when
given an absolute unix path, so it now returns 'Z:\' for '/' and
'Z:\bin' for '/bin' instead of just "" and "bin".


Index: files/dos_fs.c
===================================================================
RCS file: /home/wine/wine/files/dos_fs.c,v
retrieving revision 1.103
diff -u -r1.103 dos_fs.c
--- files/dos_fs.c	2 Apr 2002 02:46:27 -0000	1.103
+++ files/dos_fs.c	21 Apr 2002 23:52:05 -0000
@@ -866,6 +866,7 @@
  */
 BOOL DOSFS_GetFullName( LPCSTR name, BOOL check_last, DOS_FULL_NAME *full )
 {
+    BOOL unixabsolute = *name == '/';
     BOOL found;
     UINT flags;
     char *p_l, *p_s, *root;
@@ -893,7 +894,7 @@
     {
         while ((*name == '\\') || (*name == '/')) name++;
     }
-    else  /* Relative path */
+    else if (!unixabsolute)  /* Relative path */
     {
         lstrcpynA( root + 1, DRIVE_GetUnixCwd( full->drive ),
                      sizeof(full->long_name) - (root - full->long_name) - 1 );
@@ -1026,6 +1027,7 @@
     DWORD sp = 0, lp = 0;
     int tmplen, drive;
     UINT flags;
+    BOOL unixabsolute = *longpath == '/';
 
     TRACE("%s\n", debugstr_a(longpath));
 
@@ -1052,6 +1054,13 @@
 
     if ( ( drive = DOSFS_GetPathDrive ( &longpath )) == -1 ) return 0;
     flags = DRIVE_GetFlags ( drive );
+
+    if ( unixabsolute ) {
+      tmpshortpath[0] = drive + 'A';
+      tmpshortpath[1] = ':';
+      tmpshortpath[2] = '\\';
+      sp = 3;
+    }
 
     while ( longpath[lp] ) {
 
Index: files/drive.c
===================================================================
RCS file: /home/wine/wine/files/drive.c,v
retrieving revision 1.67
diff -u -r1.67 drive.c
--- files/drive.c	9 Mar 2002 23:50:37 -0000	1.67
+++ files/drive.c	21 Apr 2002 23:52:15 -0000
@@ -364,53 +364,60 @@
  */
 int DRIVE_FindDriveRoot( const char **path )
 {
-    /* idea: check at all '/' positions.
-     * If the device and inode of that path is identical with the
-     * device and inode of the current drive then we found a solution.
-     * If there is another drive pointing to a deeper position in
-     * the file tree, we want to find that one, not the earlier solution.
+    /* 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, rootdrive = -1;
+    int drive, level, len;
     char buffer[MAX_PATHNAME_LEN];
-    char *next = buffer;
-    const char *p = *path;
+    char *p;
     struct stat st;
 
-    strcpy( buffer, "/" );
-    for (;;)
-    {
-        if (stat( buffer, &st ) || !S_ISDIR( st.st_mode )) break;
+    strcpy( buffer, *path );
+    while ((p = strchr( buffer, '\\' )) != NULL)
+        *p = '/';
+    len = strlen(buffer);
 
+    while (len > 0)
+    {
         /* Find the drive */
-
-        for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
+        if (stat( buffer, &st ) == 0 && S_ISDIR( st.st_mode ))
         {
-           if (!DOSDrives[drive].root ||
-               (DOSDrives[drive].flags & DRIVE_DISABLED)) continue;
-
-           if ((DOSDrives[drive].dev == st.st_dev) &&
-               (DOSDrives[drive].ino == st.st_ino))
-           {
-               rootdrive = drive;
-               *path = p;
-	       break;
-           }
+            for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
+            {
+               if (!DOSDrives[drive].root ||
+                   (DOSDrives[drive].flags & DRIVE_DISABLED))
+                   continue;
+
+               if ((DOSDrives[drive].dev == st.st_dev) &&
+                   (DOSDrives[drive].ino == st.st_ino))
+               {
+                   TRACE( "%s -> drive %c:, root='%s', name='%s'\n",
+                       *path, 'A' + drive, buffer, *path + len);
+                   *path += len;
+                   return drive;
+               }
+            }
         }
 
-        /* Get the next path component */
-
-        *next++ = '/';
-        while ((*p == '/') || (*p == '\\')) p++;
-        if (!*p) break;
-        while (!IS_END_OF_NAME(*p)) *next++ = *p++;
-        *next = 0;
+        level = 0;
+        while (len > 0 && level < 1)
+        {
+            /* strip off a trailing slash */
+            while (len > 0 && buffer[len - 1] == '/')
+                buffer[--len] = 0;
+            /* find start of the last path component */
+            while (len > 0 && buffer[len - 1] != '/')
+                --len;
+            /* does removing it take us up a level? */
+            if (strcmp( buffer + len, "." ) != 0)
+                level += strcmp( buffer + len, ".." ) ? 1 : -1;
+            buffer[len] = 0;
+        }
     }
-    *next = 0;
 
-    if (rootdrive != -1)
-        TRACE("%s -> drive %c:, root='%s', name='%s'\n",
-              buffer, 'A' + rootdrive, DOSDrives[rootdrive].root, *path );
-    return rootdrive;
+    return -1;
 }





More information about the wine-patches mailing list