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