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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
|
// **************************************************************************
// * 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) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
// **************************************************************************
//
#include "shadow.h"
#include <wx/msw/wrapwin.h> //includes "windows.h"
#include "i18n.h"
#include "dll_loader.h"
#include <stdexcept>
#include "assert_static.h"
#include "build_info.h"
#include "ShadowCopy\shadow.h"
#include "Loki/ScopeGuard.h"
using shadow::ShadowCopy;
using namespace zen;
namespace
{
bool newerThanXP()
{
OSVERSIONINFO osvi = {};
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (::GetVersionEx(&osvi))
return osvi.dwMajorVersion > 5 ||
(osvi.dwMajorVersion == 5 && osvi.dwMinorVersion > 1) ;
//XP has majorVersion == 5, minorVersion == 1
//Server 2003 has majorVersion == 5, minorVersion == 2
//version overview: http://msdn.microsoft.com/en-us/library/ms724834(VS.85).aspx
return false;
}
bool runningWOW64() //test if process is running under WOW64 (reference http://msdn.microsoft.com/en-us/library/ms684139(VS.85).aspx)
{
//dynamically load windows API function
typedef BOOL (WINAPI *IsWow64ProcessFun)(
HANDLE hProcess,
PBOOL Wow64Process);
static const IsWow64ProcessFun isWow64Process =
util::getDllFun<IsWow64ProcessFun>(L"kernel32.dll", "IsWow64Process");
if (isWow64Process)
{
BOOL isWow64 = FALSE;
if (isWow64Process(::GetCurrentProcess(), &isWow64))
return isWow64 == TRUE;
}
return false;
}
inline
std::wstring getShadowDllName()
{
/*
distinguish a bunch of VSS builds: we use XP and Server 2003 implementations...
VSS version and compatibility overview: http://msdn.microsoft.com/en-us/library/aa384627(VS.85).aspx
*/
assert_static(util::is32BitBuild || util::is64BitBuild);
return newerThanXP() ?
(util::is64BitBuild ?
L"Shadow_Server2003_x64.dll" :
L"Shadow_Server2003_Win32.dll") :
(util::is64BitBuild ?
L"Shadow_XP_x64.dll" :
L"Shadow_XP_Win32.dll");
}
}
//#############################################################################################################
class ShadowCopy::ShadowVolume
{
public:
ShadowVolume(const Zstring& volumeNameFormatted) : //throw(FileError)
backupHandle(0)
{
using namespace shadow;
if (!createShadowCopy)
createShadowCopy = util::getDllFun<CreateShadowCopyFct>(getShadowDllName(), createShadowCopyFctName);
if (!releaseShadowCopy)
releaseShadowCopy = util::getDllFun<ReleaseShadowCopyFct>(getShadowDllName(), releaseShadowCopyFctName);
//check if shadow copy dll was loaded correctly
if (createShadowCopy == NULL ||
releaseShadowCopy == NULL)
throw FileError(_("Error starting Volume Shadow Copy Service!") + "\n" +
_("Could not load a required DLL:") + " \"" + getShadowDllName() + "\"");
//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)
static const bool wow64Active = runningWOW64();
if (wow64Active)
throw FileError(_("Error starting Volume Shadow Copy Service!") + "\n" +
_("Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version."));
//---------------------------------------------------------------------------------------------------------
//start shadow volume copy service:
wchar_t shadowVolName[1000];
wchar_t errorMessage[1000];
if (!createShadowCopy(
volumeNameFormatted.c_str(),
shadowVolName,
1000,
&backupHandle,
errorMessage,
1000))
throw FileError(_("Error starting Volume Shadow Copy Service!") + "\n" +
"(" + errorMessage + " Volume: \"" + volumeNameFormatted + "\")");
shadowVol = Zstring(shadowVolName) + FILE_NAME_SEPARATOR; //shadowVolName NEVER has a trailing backslash
}
~ShadowVolume()
{
releaseShadowCopy(backupHandle); //fast! no performance optimization necessary
}
Zstring getShadowVolume() const //trailing path separator
{
return shadowVol;
}
private:
ShadowVolume(const ShadowVolume&);
ShadowVolume& operator=(const ShadowVolume&);
static shadow::CreateShadowCopyFct createShadowCopy;
static shadow::ReleaseShadowCopyFct releaseShadowCopy;
Zstring shadowVol;
ShadowHandle backupHandle;
};
shadow::CreateShadowCopyFct ShadowCopy::ShadowVolume::createShadowCopy;
shadow::ReleaseShadowCopyFct ShadowCopy::ShadowVolume::releaseShadowCopy;
//#############################################################################################################
Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile)
{
using namespace zen;
wchar_t volumeNameRaw[1000];
if (!::GetVolumePathName(inputFile.c_str(), //__in LPCTSTR lpszFileName,
volumeNameRaw, //__out LPTSTR lpszVolumePathName,
1000)) //__in DWORD cchBufferLength
throw FileError(_("Could not determine volume name for file:") + "\n\"" + inputFile + "\"");
Zstring volumeNameFormatted = volumeNameRaw;
if (!volumeNameFormatted.EndsWith(FILE_NAME_SEPARATOR))
volumeNameFormatted += FILE_NAME_SEPARATOR;
//input file is always absolute! directory formatting takes care of this! Therefore volume name can always be found.
const size_t pos = inputFile.find(volumeNameFormatted); //inputFile needs NOT to begin with volumeNameFormatted: consider for example \\?\ prefix!
if (pos == Zstring::npos)
{
std::wstring msg = _("Volume name %x not part of filename %y!");
replace(msg, L"%x", std::wstring(L"\"") + volumeNameFormatted + "\"", false);
replace(msg, L"%y", std::wstring(L"\"") + inputFile + "\"", false);
throw FileError(msg);
}
//get or create instance of shadow volume
VolNameShadowMap::const_iterator iter = shadowVol.find(volumeNameFormatted);
if (iter == shadowVol.end())
{
std::shared_ptr<ShadowVolume> newEntry(new ShadowVolume(volumeNameFormatted));
iter = shadowVol.insert(std::make_pair(volumeNameFormatted, newEntry)).first;
}
//return filename alias on shadow copy volume
return iter->second->getShadowVolume() + Zstring(inputFile.c_str() + pos + volumeNameFormatted.length());
}
|