summaryrefslogtreecommitdiff
path: root/lib/shadow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/shadow.cpp')
-rw-r--r--lib/shadow.cpp33
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());
}
bgstack15