summaryrefslogtreecommitdiff
path: root/shared/resolve_path.cpp
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:14:37 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:14:37 +0200
commit8bf668665b107469086f16cb8ad23e47d479d2b4 (patch)
tree66a91ef06a8caa7cd6819dcbe1860693d3eda8d5 /shared/resolve_path.cpp
parent3.21 (diff)
downloadFreeFileSync-8bf668665b107469086f16cb8ad23e47d479d2b4.tar.gz
FreeFileSync-8bf668665b107469086f16cb8ad23e47d479d2b4.tar.bz2
FreeFileSync-8bf668665b107469086f16cb8ad23e47d479d2b4.zip
4.0
Diffstat (limited to 'shared/resolve_path.cpp')
-rw-r--r--shared/resolve_path.cpp262
1 files changed, 234 insertions, 28 deletions
diff --git a/shared/resolve_path.cpp b/shared/resolve_path.cpp
index 2a9cb7e6..f22b4505 100644
--- a/shared/resolve_path.cpp
+++ b/shared/resolve_path.cpp
@@ -3,9 +3,11 @@
#include <wx/datetime.h>
#include "string_conv.h"
#include "loki/ScopeGuard.h"
+#include <map>
#ifdef FFS_WIN
#include "dll_loader.h"
+#include <Shlobj.h>
#include <wx/msw/wrapwin.h> //includes "windows.h"
#include "long_path_prefix.h"
#ifdef _MSC_VER
@@ -26,6 +28,17 @@ namespace
#ifdef FFS_WIN
Zstring resolveBrokenNetworkMap(const Zstring& dirname) //circumvent issue with disconnected network maps that could be activated by a simple explorer double click
{
+ /*
+ ATTENTION: it is not safe to call ::WNetGetConnection() for every network share:
+
+ network type |::WNetGetConnection rv | lpRemoteName | existing UNC path
+ -----------------------------|-------------------------|---------------------------------|----------------
+ inactive local network share | ERROR_CONNECTION_UNAVAIL| \\192.168.1.27\new2 | YES
+ WebDrive | NO_ERROR | \\Webdrive-ZenJu\GNU | NO
+ Box.net (WebDav) | NO_ERROR | \\www.box.net\DavWWWRoot\dav | YES
+ NetDrive | ERROR_NOT_CONNECTED | <empty> | NO
+ */
+
if (dirname.size() >= 2 && iswalpha(dirname[0]) && dirname[1] == L':')
{
Zstring driveLetter(dirname.c_str(), 2); //e.g.: "Q:"
@@ -37,13 +50,12 @@ Zstring resolveBrokenNetworkMap(const Zstring& dirname) //circumvent issue with
DWORD rv = ::WNetGetConnection(driveLetter.c_str(), //__in LPCTSTR lpLocalName in the form "<driveletter>:"
&remoteNameBuffer[0], //__out LPTSTR lpRemoteName,
&bufferSize); //__inout LPDWORD lpnLength
- if (rv == NO_ERROR ||
- rv == ERROR_CONNECTION_UNAVAIL) //remoteNameBuffer will be filled nevertheless!
- {
- Zstring networkShare = &remoteNameBuffer[0];
- if (!networkShare.empty())
- return networkShare + (dirname.c_str() + 2); //replace "Q:\subdir" by "\\server\share\subdir"
- }
+ if (rv == ERROR_CONNECTION_UNAVAIL) //remoteNameBuffer will be filled nevertheless!
+ {
+ Zstring networkShare = &remoteNameBuffer[0];
+ if (!networkShare.empty())
+ return networkShare + (dirname.c_str() + 2); //replace "Q:\subdir" by "\\server\share\subdir"
+ }
}
}
return dirname;
@@ -80,6 +92,96 @@ Zstring resolveRelativePath(const Zstring& relativeName) //additional: resolves
#endif
+#ifdef FFS_WIN
+class CsidlConstants
+{
+public:
+ typedef std::map<Zstring, Zstring, LessFilename> CsidlToDirMap; //case-insensitive comparison
+
+ static const CsidlToDirMap& get()
+ {
+ static CsidlConstants inst;
+ return inst.csidlToDir;
+ }
+
+private:
+ CsidlConstants()
+ {
+ auto addCsidl = [&](int csidl, const Zstring& paramName)
+ {
+ wchar_t buffer[MAX_PATH];
+ if (SUCCEEDED(::SHGetFolderPath(NULL, //__in HWND hwndOwner,
+ csidl | CSIDL_FLAG_DONT_VERIFY, //__in int nFolder,
+ NULL, //__in HANDLE hToken,
+ 0 /* == SHGFP_TYPE_CURRENT*/, //__in DWORD dwFlags,
+ buffer))) //__out LPTSTR pszPath
+ {
+ Zstring dirname = buffer;
+ if (!dirname.empty())
+ csidlToDir.insert(std::make_pair(paramName, dirname));
+ }
+ };
+
+ addCsidl(CSIDL_DESKTOPDIRECTORY, L"csidl_Desktop"); // C:\Users\username\Desktop
+ addCsidl(CSIDL_COMMON_DESKTOPDIRECTORY, L"csidl_PublicDesktop"); // C:\Users\All Users\Desktop
+
+ addCsidl(CSIDL_MYMUSIC, L"csidl_MyMusic"); // C:\Users\username\My Documents\My Music
+ addCsidl(CSIDL_COMMON_MUSIC, L"csidl_PublicMusic"); // C:\Users\All Users\Documents\My Music
+
+ addCsidl(CSIDL_MYPICTURES, L"csidl_MyPictures"); // C:\Users\username\My Documents\My Pictures
+ addCsidl(CSIDL_COMMON_PICTURES, L"csidl_PublicPictures"); // C:\Users\All Users\Documents\My Pictures
+
+ addCsidl(CSIDL_MYVIDEO, L"csidl_MyVideo"); // C:\Users\username\My Documents\My Videos
+ addCsidl(CSIDL_COMMON_VIDEO, L"csidl_PublicVideo"); // C:\Users\All Users\Documents\My Videos
+
+ addCsidl(CSIDL_PERSONAL, L"csidl_MyDocuments"); // C:\Users\username\My Documents
+ addCsidl(CSIDL_COMMON_DOCUMENTS, L"csidl_PublicDocuments"); // C:\Users\All Users\Documents
+
+ addCsidl(CSIDL_STARTMENU, L"csidl_StartMenu"); // C:\Users\username\Start Menu
+ addCsidl(CSIDL_COMMON_STARTMENU, L"csidl_PublicStartMenu"); // C:\Users\All Users\Start Menu
+
+ addCsidl(CSIDL_FAVORITES, L"csidl_Favorites"); // C:\Users\username\Favorites
+ addCsidl(CSIDL_COMMON_FAVORITES, L"csidl_PublicFavorites"); // C:\Users\All Users\Favoriten
+
+ addCsidl(CSIDL_TEMPLATES, L"csidl_Templates"); // C:\Users\username\Templates
+ addCsidl(CSIDL_COMMON_TEMPLATES, L"csidl_PublicTemplates"); // C:\Users\All Users\Templates
+
+ addCsidl(CSIDL_RESOURCES, L"csidl_Resources"); // C:\Windows\Resources
+
+ //CSIDL_APPDATA covered by %AppData%
+ //CSIDL_LOCAL_APPDATA covered by %LocalAppData%
+ //CSIDL_COMMON_APPDATA covered by %ProgramData%
+
+ //CSIDL_PROFILE covered by %UserProfile%
+ }
+
+ CsidlConstants(const CsidlConstants&);
+ CsidlConstants& operator=(const CsidlConstants&);
+
+ CsidlToDirMap csidlToDir;
+};
+#endif
+
+
+wxString getEnvValue(const wxString& envName) //return empty on error
+{
+ //try to apply environment variables
+ wxString envValue;
+ if (wxGetEnv(envName, &envValue))
+ {
+ //some postprocessing:
+ trim(envValue); //remove leading, trailing blanks
+
+ //remove leading, trailing double-quotes
+ if (startsWith(envValue, L"\"") &&
+ endsWith(envValue, L"\"") &&
+ envValue.length() >= 2)
+ envValue = wxString(envValue.c_str() + 1, envValue.length() - 2);
+ }
+ return envValue;
+}
+
+
bool replaceMacro(wxString& macro) //macro without %-characters, return true if replaced successfully
{
if (macro.IsEmpty())
@@ -117,22 +219,27 @@ bool replaceMacro(wxString& macro) //macro without %-characters, return true if
if (processPhrase(L"sec" , L"%S")) return true;
//try to apply environment variables
- wxString envValue;
- if (wxGetEnv(macro, &envValue))
{
- macro = envValue;
-
- //some postprocessing:
- macro.Trim(true); //remove leading, trailing blanks
- macro.Trim(false); //
+ wxString envValue = getEnvValue(macro);
+ if (!envValue.empty())
+ {
+ macro = envValue;
+ return true;
+ }
+ }
- //remove leading, trailing double-quotes
- if (macro.StartsWith(wxT("\"")) &&
- macro.EndsWith(wxT("\"")) &&
- macro.length() >= 2)
- macro = wxString(macro.c_str() + 1, macro.length() - 2);
- return true;
+#ifdef FFS_WIN
+ //try to resolve CSIDL values
+ {
+ auto csidlMap = CsidlConstants::get();
+ auto iter = csidlMap.find(toZ(macro));
+ if (iter != csidlMap.end())
+ {
+ macro = toWx(iter->second);
+ return true;
+ }
}
+#endif
return false;
}
@@ -190,7 +297,7 @@ private:
#endif
-Zstring getVolumePath(const Zstring& volumeName) //empty string on error
+Zstring volumenNameToPath(const Zstring& volumeName) //return empty string on error
{
#ifdef FFS_WIN
std::vector<wchar_t> volGuid(10000);
@@ -198,8 +305,7 @@ Zstring getVolumePath(const Zstring& volumeName) //empty string on error
HANDLE hVol = ::FindFirstVolume(&volGuid[0], static_cast<DWORD>(volGuid.size()));
if (hVol != INVALID_HANDLE_VALUE)
{
- Loki::ScopeGuard dummy = Loki::MakeGuard(::FindVolumeClose, hVol);
- (void)dummy;
+ LOKI_ON_BLOCK_EXIT2(::FindVolumeClose(hVol));
do
{
@@ -222,10 +328,8 @@ Zstring getVolumePath(const Zstring& volumeName) //empty string on error
DWORD cchBufferLength,
PDWORD lpcchReturnLength);
- static const GetVolumePathNamesForVolumeNameWFunc getVolumePathNamesForVolumeName =
- util::getDllFun<GetVolumePathNamesForVolumeNameWFunc>(L"kernel32.dll", "GetVolumePathNamesForVolumeNameW");
-
- if (getVolumePathNamesForVolumeName != NULL)
+ const util::DllFun<GetVolumePathNamesForVolumeNameWFunc> getVolumePathNamesForVolumeName(L"kernel32.dll", "GetVolumePathNamesForVolumeNameW");
+ if (getVolumePathNamesForVolumeName)
{
std::vector<wchar_t> volPath(10000);
@@ -261,6 +365,28 @@ Zstring getVolumePath(const Zstring& volumeName) //empty string on error
}
+#ifdef FFS_WIN
+Zstring volumePathToName(const Zstring& volumePath) //return empty string on error
+{
+ const DWORD bufferSize = MAX_PATH + 1;
+ std::vector<wchar_t> volName(bufferSize);
+
+ if (::GetVolumeInformation(volumePath.c_str(), //__in_opt LPCTSTR lpRootPathName,
+ &volName[0], //__out LPTSTR lpVolumeNameBuffer,
+ bufferSize, //__in DWORD nVolumeNameSize,
+ NULL, //__out_opt LPDWORD lpVolumeSerialNumber,
+ NULL, //__out_opt LPDWORD lpMaximumComponentLength,
+ NULL, //__out_opt LPDWORD lpFileSystemFlags,
+ NULL, //__out LPTSTR lpFileSystemNameBuffer,
+ 0)) //__in DWORD nFileSystemNameSize
+ {
+ return &volName[0];
+ }
+ return Zstring();
+}
+#endif
+
+
void expandVolumeName(Zstring& text) // [volname]:\folder [volname]\folder [volname]folder -> C:\folder
{
Zstring before;
@@ -287,7 +413,7 @@ void expandVolumeName(Zstring& text) // [volname]:\folder [volname]\folde
if (volname.empty())
return;
- Zstring volPath = getVolumePath(volname); //return empty string on error
+ Zstring volPath = volumenNameToPath(volname); //return empty string on error
if (volPath.empty())
return;
@@ -299,6 +425,86 @@ void expandVolumeName(Zstring& text) // [volname]:\folder [volname]\folde
}
+#ifdef FFS_WIN
+std::vector<Zstring> zen::getDirectoryAliases(Zstring dirname)
+{
+ trim(dirname, true, false);
+
+ std::vector<Zstring> output;
+
+ if (dirname.empty())
+ return output;
+
+ //1. replace volume path by volume name: c:\dirname -> [SYSTEM]\dirname
+ if (dirname.size() >= 3 &&
+ std::iswalpha(dirname[0]) &&
+ dirname[1] == L':' &&
+ dirname[2] == L'\\')
+ {
+ Zstring volname = volumePathToName(Zstring(dirname.c_str(), 3));
+ if (!volname.empty())
+ output.push_back(L"[" + volname + L"]" + Zstring(dirname.c_str() + 2));
+ }
+
+ //2. replace volume name by volume path: [SYSTEM]\dirname -> c:\dirname
+ {
+ Zstring testVolname = dirname;
+ expandVolumeName(testVolname);
+ if (testVolname != dirname)
+ output.push_back(testVolname);
+ }
+
+ //3. environment variables: C:\Users\username -> %USERPROFILE%
+ {
+ std::map<Zstring, Zstring> envToDir;
+
+ //get list of useful variables
+ auto addEnvVar = [&](const wxString& envName)
+ {
+ wxString envVal = getEnvValue(envName); //return empty on error
+ if (!envVal.empty())
+ envToDir.insert(std::make_pair(toZ(envName), toZ(envVal)));
+ };
+ addEnvVar(L"AllUsersProfile"); // C:\ProgramData
+ addEnvVar(L"AppData"); // C:\Users\username\AppData\Roaming
+ addEnvVar(L"LocalAppData"); // C:\Users\username\AppData\Local
+ addEnvVar(L"ProgramData"); // C:\ProgramData
+ addEnvVar(L"ProgramFiles"); // C:\Program Files
+ addEnvVar(L"ProgramFiles(x86)");// C:\Program Files (x86)
+ addEnvVar(L"Public"); // C:\Users\Public
+ addEnvVar(L"UserProfile"); // C:\Users\username
+ addEnvVar(L"WinDir"); // C:\Windows
+ addEnvVar(L"Temp"); // C:\Windows\Temp
+
+ //add CSIDL values: http://msdn.microsoft.com/en-us/library/bb762494(v=vs.85).aspx
+ auto csidlMap = CsidlConstants::get();
+ envToDir.insert(csidlMap.begin(), csidlMap.end());
+
+ Zstring tmp = dirname;
+ ::makeUpper(tmp);
+ std::for_each(envToDir.begin(), envToDir.end(),
+ [&](const std::pair<Zstring, Zstring>& entry)
+ {
+ Zstring tmp2 = entry.second; //case-insensitive "startsWith()"
+ ::makeUpper(tmp2); //
+ if (startsWith(tmp, tmp2))
+ output.push_back(L"%" + entry.first + L"%" + (dirname.c_str() + tmp2.size()));
+ });
+ }
+
+ //5. replace (all) macros: //%USERPROFILE% -> C:\Users\username
+ {
+ wxString testMacros = toWx(dirname);
+ expandMacros(testMacros);
+ if (toZ(testMacros) != dirname)
+ output.push_back(toZ(testMacros));
+ }
+
+ return output;
+}
+#endif
+
+
Zstring zen::getFormattedDirectoryName(const Zstring& dirname)
{
//Formatting is needed since functions expect the directory to end with '\' to be able to split the relative names.
bgstack15