Add support for MSW unique volume names to wxFileName.

Recognize the paths starting with "\\?\Volume{GUID}" under MSW and provide a
way to test for them.

Closes #8874.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@62782 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2009-12-05 17:31:00 +00:00
parent 2450225e87
commit e01a788ee0
5 changed files with 117 additions and 6 deletions

View File

@@ -22,7 +22,16 @@
drive:\dir1\dir2\...\dirN\filename.ext where drive is a single
letter. "." and ".." as for Unix but no "~".
There are also UNC names of the form \\share\fullpath
There are also UNC names of the form \\share\fullpath and
MSW unique volume names of the form \\?\Volume{GUID}\fullpath.
The latter provide a uniform way to access a volume regardless of
its current mount point, i.e. you can change a volume's mount
point from D: to E:, or even remove it, and still be able to
access it through its unique volume name. More on the subject can
be found in MSDN's article "Naming a Volume" that is currently at
http://msdn.microsoft.com/en-us/library/aa365248(VS.85).aspx.
wxPATH_MAC: Mac OS 8/9 and Mac OS X under CodeWarrior 7 format, absolute file
names have the form
@@ -296,7 +305,18 @@ static wxString wxGetVolumeString(const wxString& volume, wxPathFormat format)
// although I didn't find any authoritative docs on this)
if ( format == wxPATH_DOS && volume.length() > 1 )
{
path << wxFILE_SEP_PATH_DOS << wxFILE_SEP_PATH_DOS << volume;
// We also have to check for Windows unique volume names here and
// return it with '\\?\' prepended to it
if ( wxFileName::IsMSWUniqueVolumeNamePath("\\\\?\\" + volume + "\\",
format) )
{
path << "\\\\?\\" << volume;
}
else
{
// it must be a UNC path
path << wxFILE_SEP_PATH_DOS << wxFILE_SEP_PATH_DOS << volume;
}
}
else if ( format == wxPATH_DOS || format == wxPATH_VMS )
{
@@ -326,6 +346,13 @@ static bool IsUNCPath(const wxString& path, wxPathFormat format)
!IsDOSPathSep(path[2u]);
}
// ----------------------------------------------------------------------------
// private constants
// ----------------------------------------------------------------------------
// length of \\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\ string
static const size_t wxMSWUniqueVolumePrefixLength = 49;
} // anonymous namespace
// ============================================================================
@@ -620,12 +647,17 @@ bool wxFileName::DirExists( const wxString &dirPath )
#if defined(__WINDOWS__) || defined(__OS2__)
// Windows fails to find directory named "c:\dir\" even if "c:\dir" exists,
// so remove all trailing backslashes from the path - but don't do this for
// the paths "d:\" (which are different from "d:") nor for just "\"
// the paths "d:\" (which are different from "d:"), for just "\" or for
// windows unique volume names ("\\?\Volume{GUID}\")
while ( wxEndsWithPathSeparator(strPath) )
{
size_t len = strPath.length();
if ( len == 1 || (len == 3 && strPath[len - 2] == wxT(':')) )
if ( len == 1 || (len == 3 && strPath[len - 2] == wxT(':')) ||
(len == wxMSWUniqueVolumePrefixLength &&
wxFileName::IsMSWUniqueVolumeNamePath(strPath)))
{
break;
}
strPath.Truncate(len - 1);
}
@@ -1810,6 +1842,18 @@ bool wxFileName::IsPathSeparator(wxChar ch, wxPathFormat format)
return ch != wxT('\0') && GetPathSeparators(format).Find(ch) != wxNOT_FOUND;
}
/* static */
bool
wxFileName::IsMSWUniqueVolumeNamePath(const wxString& path, wxPathFormat format)
{
// return true if the format used is the DOS/Windows one and the string begins
// with a Windows unique volume name ("\\?\Volume{guid}\")
return format == wxPATH_DOS &&
path.length() >= wxMSWUniqueVolumePrefixLength &&
path.StartsWith(wxS("\\\\?\\Volume{")) &&
path[wxMSWUniqueVolumePrefixLength - 1] == wxFILE_SEP_PATH_DOS;
}
// ----------------------------------------------------------------------------
// path components manipulation
// ----------------------------------------------------------------------------
@@ -2194,9 +2238,26 @@ wxFileName::SplitVolume(const wxString& fullpathWithVolume,
wxString fullpath = fullpathWithVolume;
// special Windows UNC paths hack: transform \\share\path into share:path
if ( IsUNCPath(fullpath, format) )
if ( IsMSWUniqueVolumeNamePath(fullpath, format) )
{
// special Windows unique volume names hack: transform
// \\?\Volume{guid}\path into Volume{guid}:path
// note: this check must be done before the check for UNC path
// we know the last backslash from the unique volume name is located
// there from IsMSWUniqueVolumeNamePath
fullpath[wxMSWUniqueVolumePrefixLength - 1] = wxFILE_SEP_DSK;
// paths starting with a unique volume name should always be absolute
fullpath.insert(wxMSWUniqueVolumePrefixLength, 1, wxFILE_SEP_PATH_DOS);
// remove the leading "\\?\" part
fullpath.erase(0, 4);
}
else if ( IsUNCPath(fullpath, format) )
{
// special Windows UNC paths hack: transform \\share\path into share:path
fullpath.erase(0, 2);
size_t posFirstSlash =