Hi,
It seems that windows removes .. and it's parent directory from pathnames before verifying that a parent directory exists.
Mike
ChangeLog: * fix pathnames with non-existing directories and ..
Index: files/dos_fs.c =================================================================== RCS file: /home/wine/wine/files/dos_fs.c,v retrieving revision 1.146 diff -u -r1.146 dos_fs.c --- files/dos_fs.c 15 Jan 2004 01:48:44 -0000 1.146 +++ files/dos_fs.c 16 Jan 2004 10:19:08 -0000 @@ -1032,7 +1032,8 @@ * 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 ) +static BOOL DOSFS_GetFullNameNoDots( LPCWSTR name, BOOL check_last, + DOS_FULL_NAME *full ) { BOOL found; UINT flags; @@ -1171,6 +1172,112 @@ return TRUE; } +#define DOSFS_ISSEPERATOR( ch ) ( ((ch)=='\\') || ((ch)=='/') ) + +BOOL DOSFS_GetFullName( LPCWSTR name, BOOL check_last, DOS_FULL_NAME *full ) +{ + LPWSTR szFullPath, p; + LPCWSTR str; + BOOL r; + const WCHAR dots[] = { '.','.','\\',0 }; + int count, drive, len; + + TRACE("%s\n", debugstr_w(name)); + + /* don't mess with unix path names */ + if( strchrW(name,'/') ) + return DOSFS_GetFullNameNoDots( name, check_last, full ); + + str = name; + drive = DOSFS_GetPathDrive( &str ); + if( drive == -1 ) + return FALSE; + + /* make a full path */ + if( !DOSFS_ISSEPERATOR( str[0] ) ) + { + LPCWSTR cwd = DRIVE_GetDosCwd( drive ); + len = strlenW(cwd) + strlenW(str) + 5; + szFullPath = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); + szFullPath[0] = drive + 'A'; + szFullPath[1] = ':'; + szFullPath[2] = '\\'; + szFullPath[3] = 0; + strcatW( szFullPath, cwd ); + strcatW( szFullPath, &dots[2] ); + strcatW( szFullPath, str ); + } + else + { + len = strlenW(name) + 1; + szFullPath = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); + strcpyW( szFullPath, name ); + } + + /* now remove the DOS style dots, starting after the drive letter */ + p = szFullPath; + if( ( p[0] == 0 ) || ( p[1] != ':' ) ) + ERR("Oops\n"); + p += 2; + str = p; + count = 0; + do + { + /* copy one backslash to the destination string for each segment */ + if( DOSFS_ISSEPERATOR( str[0] ) ) + *p++ = *str++; + while( DOSFS_ISSEPERATOR( str[0] ) ) + *str++; + + if( str[0] == '.' ) + { + /* single dot segments can just be skipped */ + if( (str[1] == 0) || DOSFS_ISSEPERATOR(str[1]) ) + { + str++; + continue; + } + + /* + * Double dot segments cancel the previous segment + * NB: We only remove DOS type ..\ not unix ../ + * because each segment in a unix path must exist. + */ + if( ( str[1] == '.' ) && + ( (str[2] == 0) || DOSFS_ISSEPERATOR(str[2]) ) ) + { + if( !count-- ) + { + SetLastError( ERROR_FILE_NOT_FOUND ); + return FALSE; + } + str += 2; + p--; + if( DOSFS_ISSEPERATOR(*p) ) + p--; + while( (p>szFullPath) && !DOSFS_ISSEPERATOR(*p) ) + p--; + continue; + } + } + + /* other segments can be copied as they are */ + while( str[0] && !DOSFS_ISSEPERATOR(str[0]) ) + *p++ = *str++; + count++; + } + while( *str ); + *p = 0; + + TRACE("Path -> %s\n", debugstr_w(szFullPath)); + + r = DOSFS_GetFullNameNoDots( szFullPath, check_last, full ); + HeapFree( GetProcessHeap(), 0, szFullPath ); + + return r; +} + +#undef DOSFS_ISSEPERATOR /*********************************************************************** * DOSFS_DoGetFullPathName