wine_get_unix_file_name, GetShortPathNameA and GetLongPathNameA

Michael Wetherell mike.wetherell at ntlworld.com
Wed Apr 24 19:29:55 CDT 2002


I forgot the changelog on the last post, and I also forgot to switch off
line breaks, so I thought I'd better post it again.

ChangeLog:
        * files/dos_fs.c, files/drives.c
        Mike Wetherell <mike.wetherell at ntlworld.com>
        Fix handling of unix absolute paths in DOSFS_GetFullName and
        GetShortPathNameA. Handle '..' in paths in DRIVE_FindDriveRoot.

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