diff options
Diffstat (limited to 'lib/shadow.cpp')
-rw-r--r-- | lib/shadow.cpp | 33 |
1 files changed, 23 insertions, 10 deletions
diff --git a/lib/shadow.cpp b/lib/shadow.cpp index d3106168..4bb299ac 100644 --- a/lib/shadow.cpp +++ b/lib/shadow.cpp @@ -8,7 +8,10 @@ #include <stdexcept> #include <zen/win.h> //includes "windows.h" #include <zen/dll.h> +#include <zen/win_ver.h> #include <zen/assert_static.h> +#include <zen/long_path_prefix.h> +#include <zen/symlink_target.h> #include "ShadowCopy/shadow.h" #include <zen/scope_guard.h> @@ -31,6 +34,8 @@ bool runningWOW64() //test if process is running under WOW64 (reference http://m } return false; } + +const bool wereVistaOrLater = vistaOrLater(); //thread-safety: init at startup } //############################################################################################################# @@ -51,14 +56,13 @@ public: throw FileError(_("Cannot access Volume Shadow Copy Service.") + L"\n" + _("Please use FreeFileSync 64-bit version to create shadow copies on this system.")); - //check if shadow copy dll was loaded correctly if (!createShadowCopy || !releaseShadowCopy || !getShadowVolume || !getLastError) throw FileError(_("Cannot access Volume Shadow Copy Service.") + L"\n" + replaceCpy(_("Cannot load file %x."), L"%x", fmtFileName(getDllName()))); //--------------------------------------------------------------------------------------------------------- - //start shadow volume copy service: + //start volume shadow copy service: backupHandle = createShadowCopy(volumeNamePf.c_str()); if (!backupHandle) throw FileError(_("Cannot access Volume Shadow Copy Service.") + L"\n" + @@ -88,22 +92,31 @@ private: Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile, const std::function<void(const Zstring&)>& onBeforeMakeVolumeCopy) { + Zstring filenameFinal = inputFile; + + //try to resolve symlinks and junctions: + //1. symlinks: we need to retrieve the target path, else we would just return a symlink on a VSS volume while the target outside were still locked! + //2. junctions: C:\Users\<username> is a junction that may link to e.g. D:\Users\<username>, so GetVolumePathName() returns "D:\" => "Volume name %x not part of file name %y!" + if (wereVistaOrLater) + filenameFinal = getResolvedFilePath(inputFile); //throw FileError; requires Vista or later! + //-> returns paths with \\?\ prefix! => make sure to avoid duplicate shadow copies for volume paths with/without prefix + DWORD bufferSize = 10000; std::vector<wchar_t> volBuffer(bufferSize); - if (!::GetVolumePathName(inputFile.c_str(), //__in LPCTSTR lpszFileName, - &volBuffer[0], //__out LPTSTR lpszVolumePathName, - bufferSize)) //__in DWORD cchBufferLength - throw FileError(replaceCpy(_("Path %x does not contain a volume name."), L"%x", fmtFileName(inputFile))); + if (!::GetVolumePathName(filenameFinal.c_str(), //__in LPCTSTR lpszFileName, + &volBuffer[0], //__out LPTSTR lpszVolumePathName, + bufferSize)) //__in DWORD cchBufferLength + throw FileError(replaceCpy(_("Path %x does not contain a volume name."), L"%x", fmtFileName(filenameFinal))); - const Zstring volumeNamePf = appendSeparator(&volBuffer[0]); + const Zstring volumeNamePf = appendSeparator(&volBuffer[0]); //msdn: if buffer is 1 char too short, GetVolumePathName() may skip last separator without error! //input file is always absolute! directory formatting takes care of this! Therefore volume name can always be found. - const size_t pos = inputFile.find(volumeNamePf); //inputFile needs NOT to begin with volumeNamePf: consider for example \\?\ prefix! + const size_t pos = filenameFinal.find(volumeNamePf); //filenameFinal needs NOT to begin with volumeNamePf: consider for example \\?\ prefix! if (pos == Zstring::npos) { std::wstring msg = _("Volume name %x not part of file name %y!"); replace(msg, L"%x", fmtFileName(volumeNamePf), false); - replace(msg, L"%y", fmtFileName(inputFile), false); + replace(msg, L"%y", fmtFileName(filenameFinal), false); throw FileError(msg); } @@ -117,5 +130,5 @@ Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile, const std::function } //return filename alias on shadow copy volume - return it->second->geNamePf() + Zstring(inputFile.c_str() + pos + volumeNamePf.length()); + return it->second->geNamePf() + Zstring(filenameFinal.c_str() + pos + volumeNamePf.length()); } |