1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
// **************************************************************************
// * This file is part of the FreeFileSync project. It is distributed under *
// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
#include "shadow.h"
#include <stdexcept>
#include <zen/win.h> //includes "windows.h"
#include <zen/dll.h>
#include <zen/assert_static.h>
#include "ShadowCopy/shadow.h"
#include <zen/scope_guard.h>
using namespace zen;
using namespace shadow;
namespace
{
bool runningWOW64() //test if process is running under WOW64 (reference http://msdn.microsoft.com/en-us/library/ms684139(VS.85).aspx)
{
typedef BOOL (WINAPI* IsWow64ProcessFun)(HANDLE hProcess, PBOOL Wow64Process);
const SysDllFun<IsWow64ProcessFun> isWow64Process(L"kernel32.dll", "IsWow64Process");
if (isWow64Process)
{
BOOL isWow64 = FALSE;
if (isWow64Process(::GetCurrentProcess(), &isWow64))
return isWow64 != FALSE;
}
return false;
}
}
//#############################################################################################################
class ShadowCopy::ShadowVolume
{
public:
ShadowVolume(const Zstring& volumeNamePf) : //throw(FileError)
createShadowCopy (getDllName(), funName_createShadowCopy),
releaseShadowCopy(getDllName(), funName_releaseShadowCopy),
getShadowVolume (getDllName(), funName_getShadowVolume),
getLastError (getDllName(), funName_getLastError),
backupHandle(nullptr)
{
//VSS does not support running under WOW64 except for Windows XP and Windows Server 2003
//reference: http://msdn.microsoft.com/en-us/library/aa384627(VS.85).aspx
if (runningWOW64())
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:
backupHandle = createShadowCopy(volumeNamePf.c_str());
if (!backupHandle)
throw FileError(_("Cannot access Volume Shadow Copy Service.") + L"\n" +
getLastError() + L" Volume: " + fmtFileName(volumeNamePf));
shadowVolPf = appendSeparator(getShadowVolume(backupHandle)); //shadowVolName NEVER has a trailing backslash
}
~ShadowVolume() { releaseShadowCopy(backupHandle); } //fast! no performance optimization necessary
Zstring geNamePf() const { return shadowVolPf; } //with trailing path separator
private:
ShadowVolume(const ShadowVolume&);
ShadowVolume& operator=(const ShadowVolume&);
const DllFun<FunType_createShadowCopy> createShadowCopy;
const DllFun<FunType_releaseShadowCopy> releaseShadowCopy;
const DllFun<FunType_getShadowVolume> getShadowVolume;
const DllFun<FunType_getLastError> getLastError;
Zstring shadowVolPf;
ShadowHandle backupHandle;
};
//#############################################################################################################
Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile)
{
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)));
const Zstring volumeNamePf = appendSeparator(&volBuffer[0]);
//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!
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);
throw FileError(msg);
}
//get or create instance of shadow volume
VolNameShadowMap::const_iterator iter = shadowVol.find(volumeNamePf);
if (iter == shadowVol.end())
{
auto newEntry = std::make_shared<ShadowVolume>(volumeNamePf);
iter = shadowVol.insert(std::make_pair(volumeNamePf, newEntry)).first;
}
//return filename alias on shadow copy volume
return iter->second->geNamePf() + Zstring(inputFile.c_str() + pos + volumeNamePf.length());
}
|