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
|
#include "shadow.h"
#include <wx/msw/wrapwin.h> //includes "windows.h"
#include <wx/intl.h>
#include "../structures.h"
using FreeFileSync::ShadowCopy;
class ShadowlDllHandler //dynamically load windows API functions
{
typedef bool (*CreateShadowCopyFct)( //volumeName must end with "\", while shadowVolName does not end with "\"
const wchar_t* volumeName,
wchar_t* shadowVolName,
unsigned int shadowBufferLen,
void** backupHandle,
wchar_t* errorMessage,
unsigned int errorBufferLen);
typedef void (*ReleaseShadowCopyFct)(void* backupHandle);
public:
static const ShadowlDllHandler& getInstance()
{
static ShadowlDllHandler instance;
return instance;
}
CreateShadowCopyFct createShadowCopy;
ReleaseShadowCopyFct releaseShadowCopy;
private:
ShadowlDllHandler() :
createShadowCopy(NULL),
releaseShadowCopy(NULL),
hShadow(NULL)
{
//get a handle to the DLL module containing the required functionality
hShadow = ::LoadLibrary(L"Shadow.dll");
if (hShadow)
{
createShadowCopy = reinterpret_cast<CreateShadowCopyFct>(::GetProcAddress(hShadow, "createShadowCopy"));
releaseShadowCopy = reinterpret_cast<ReleaseShadowCopyFct>(::GetProcAddress(hShadow, "releaseShadowCopy"));
}
}
~ShadowlDllHandler()
{
if (hShadow) ::FreeLibrary(hShadow);
}
HINSTANCE hShadow;
};
ShadowCopy::ShadowCopy() :
backupHandle(NULL) {}
ShadowCopy::~ShadowCopy()
{
if (backupHandle != NULL)
ShadowlDllHandler::getInstance().releaseShadowCopy(backupHandle);
}
bool ShadowCopy::isOkay()
{
//check that all functions could be loaded
return ShadowlDllHandler::getInstance().createShadowCopy != NULL &&
ShadowlDllHandler::getInstance().releaseShadowCopy != NULL;
}
Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile) throw(FreeFileSync::FileError)
{
//check if shadow copy dll was loaded correctly
if (!isOkay())
throw FileError(Zstring(_("Error copying locked file %x!")).Replace(wxT("%x"), Zstring(wxT("\"")) + inputFile + wxT("\"")) + wxT("\n\n") +
_("Error starting Volume Shadow Copy Service!") + wxT("\n") +
_("Please copy the appropriate \"Shadow.dll\" (located in \"Shadow.zip\" archive) into the FreeFileSync installation directory to enable this feature."));
wchar_t volumeNameRaw[1000];
if (!GetVolumePathName(inputFile.c_str(), //__in LPCTSTR lpszFileName,
volumeNameRaw, //__out LPTSTR lpszVolumePathName,
1000)) //__in DWORD cchBufferLength
throw FileError(Zstring(_("Error copying locked file %x!")).Replace(wxT("%x"), Zstring(wxT("\"")) + inputFile + wxT("\"")) + wxT("\n\n") +
_("Could not determine volume name for file:") + wxT("\n\"") + inputFile + wxT("\""));
Zstring volumeNameFormatted = volumeNameRaw;
if (!volumeNameFormatted.EndsWith(FreeFileSync::FILE_NAME_SEPARATOR))
volumeNameFormatted += FreeFileSync::FILE_NAME_SEPARATOR;
if (volumeNameFormatted != realVolumeLast)
{
//release old shadow copy
if (backupHandle != NULL)
{
ShadowlDllHandler::getInstance().releaseShadowCopy(backupHandle);
backupHandle = NULL;
}
realVolumeLast.clear(); //...if next call fails...
shadowVolumeLast.clear(); //...if next call fails...
//start shadow volume copy service:
wchar_t shadowVolName[1000];
void* backupHandleTmp = NULL;
wchar_t errorMessage[1000];
if (!ShadowlDllHandler::getInstance().createShadowCopy(
volumeNameFormatted.c_str(),
shadowVolName,
1000,
&backupHandleTmp,
errorMessage,
1000))
throw FileError(Zstring(_("Error copying locked file %x!")).Replace(wxT("%x"), Zstring(wxT("\"")) + inputFile + wxT("\"")) + wxT("\n\n") +
_("Error starting Volume Shadow Copy Service!") + wxT("\n") +
wxT("(") + errorMessage + wxT(")"));
realVolumeLast = volumeNameFormatted;
shadowVolumeLast = Zstring(shadowVolName) + FreeFileSync::FILE_NAME_SEPARATOR; //shadowVolName NEVER has a trailing backslash
backupHandle = backupHandleTmp;
}
const size_t pos = inputFile.find(volumeNameFormatted);
if (pos == Zstring::npos)
{
Zstring msg = _("Volume name %x not part of filename %y!");
msg.Replace(wxT("%x"), Zstring(wxT("\"")) + volumeNameFormatted + wxT("\""), false);
msg.Replace(wxT("%y"), Zstring(wxT("\"")) + inputFile + wxT("\""), false);
throw FileError(Zstring(_("Error copying locked file %x!")).Replace(wxT("%x"), Zstring(wxT("\"")) + inputFile + wxT("\"")) + wxT("\n\n") +
msg);
}
//return filename alias on shadow copy volume
return shadowVolumeLast + Zstring(inputFile.c_str() + pos + volumeNameFormatted.length());
}
|