1b39297aeSTomoki Sekiyama /*
2b39297aeSTomoki Sekiyama * QEMU Guest Agent win32 VSS Requester implementations
3b39297aeSTomoki Sekiyama *
4b39297aeSTomoki Sekiyama * Copyright Hitachi Data Systems Corp. 2013
5b39297aeSTomoki Sekiyama *
6b39297aeSTomoki Sekiyama * Authors:
7b39297aeSTomoki Sekiyama * Tomoki Sekiyama <tomoki.sekiyama@hds.com>
8b39297aeSTomoki Sekiyama *
9b39297aeSTomoki Sekiyama * This work is licensed under the terms of the GNU GPL, version 2 or later.
10b39297aeSTomoki Sekiyama * See the COPYING file in the top-level directory.
11b39297aeSTomoki Sekiyama */
12b39297aeSTomoki Sekiyama
13e55eb806SMichael Roth #include "qemu/osdep.h"
14b39297aeSTomoki Sekiyama #include "vss-common.h"
152f84cf69SKonstantin Kostiuk #include "vss-debug.h"
16b39297aeSTomoki Sekiyama #include "requester.h"
17f342cc93SSameeh Jubran #include "install.h"
1861fb0bd1SMarc-André Lureau #include <vswriter.h>
1961fb0bd1SMarc-André Lureau #include <vsbackup.h>
20b39297aeSTomoki Sekiyama
21b39297aeSTomoki Sekiyama /* Max wait time for frozen event (VSS can only hold writes for 10 seconds) */
223d98f9b6SBasil Salman #define VSS_TIMEOUT_FREEZE_MSEC 60000
23b39297aeSTomoki Sekiyama
24b39297aeSTomoki Sekiyama /* Call QueryStatus every 10 ms while waiting for frozen event */
25b39297aeSTomoki Sekiyama #define VSS_TIMEOUT_EVENT_MSEC 10
26b39297aeSTomoki Sekiyama
27410542d4SKfir Manor #define DEFAULT_VSS_BACKUP_TYPE VSS_BT_FULL
28410542d4SKfir Manor
2924eecad3SKonstantin Kostiuk #define err_set(e, err, fmt, ...) { \
3024eecad3SKonstantin Kostiuk (e)->error_setg_win32_wrapper((e)->errp, __FILE__, __LINE__, __func__, \
3124eecad3SKonstantin Kostiuk err, fmt, ## __VA_ARGS__); \
3224eecad3SKonstantin Kostiuk qga_debug(fmt, ## __VA_ARGS__); \
3324eecad3SKonstantin Kostiuk }
3408e64640SMarkus Armbruster /* Bad idea, works only when (e)->errp != NULL: */
35b39297aeSTomoki Sekiyama #define err_is_set(e) ((e)->errp && *(e)->errp)
3608e64640SMarkus Armbruster /* To lift this restriction, error_propagate(), like we do in QEMU code */
37b39297aeSTomoki Sekiyama
38b39297aeSTomoki Sekiyama /* Handle to VSSAPI.DLL */
39b39297aeSTomoki Sekiyama static HMODULE hLib;
40b39297aeSTomoki Sekiyama
41b39297aeSTomoki Sekiyama /* Functions in VSSAPI.DLL */
42b39297aeSTomoki Sekiyama typedef HRESULT(STDAPICALLTYPE * t_CreateVssBackupComponents)(
43b39297aeSTomoki Sekiyama OUT IVssBackupComponents**);
44b39297aeSTomoki Sekiyama typedef void(APIENTRY * t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
45b39297aeSTomoki Sekiyama static t_CreateVssBackupComponents pCreateVssBackupComponents;
46b39297aeSTomoki Sekiyama static t_VssFreeSnapshotProperties pVssFreeSnapshotProperties;
47b39297aeSTomoki Sekiyama
48b39297aeSTomoki Sekiyama /* Variables used while applications and filesystes are frozen by VSS */
49b39297aeSTomoki Sekiyama static struct QGAVSSContext {
50b39297aeSTomoki Sekiyama IVssBackupComponents *pVssbc; /* VSS requester interface */
51b39297aeSTomoki Sekiyama IVssAsync *pAsyncSnapshot; /* async info of VSS snapshot operation */
52b39297aeSTomoki Sekiyama HANDLE hEventFrozen; /* notify fs/writer freeze from provider */
53b39297aeSTomoki Sekiyama HANDLE hEventThaw; /* request provider to thaw */
54b39297aeSTomoki Sekiyama HANDLE hEventTimeout; /* notify timeout in provider */
55b39297aeSTomoki Sekiyama int cFrozenVols; /* number of frozen volumes */
56b39297aeSTomoki Sekiyama } vss_ctx;
57b39297aeSTomoki Sekiyama
requester_init(void)58b39297aeSTomoki Sekiyama STDAPI requester_init(void)
59b39297aeSTomoki Sekiyama {
6061df91b3SKonstantin Kostiuk qga_debug_begin;
6161df91b3SKonstantin Kostiuk
62b39297aeSTomoki Sekiyama COMInitializer initializer; /* to call CoInitializeSecurity */
63b39297aeSTomoki Sekiyama HRESULT hr = CoInitializeSecurity(
64b39297aeSTomoki Sekiyama NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
65b39297aeSTomoki Sekiyama RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE, NULL);
66b39297aeSTomoki Sekiyama if (FAILED(hr)) {
672f84cf69SKonstantin Kostiuk qga_debug("failed to CoInitializeSecurity (error %lx)", hr);
68b39297aeSTomoki Sekiyama return hr;
69b39297aeSTomoki Sekiyama }
70b39297aeSTomoki Sekiyama
71b39297aeSTomoki Sekiyama hLib = LoadLibraryA("VSSAPI.DLL");
72b39297aeSTomoki Sekiyama if (!hLib) {
732f84cf69SKonstantin Kostiuk qga_debug("failed to load VSSAPI.DLL");
74b39297aeSTomoki Sekiyama return HRESULT_FROM_WIN32(GetLastError());
75b39297aeSTomoki Sekiyama }
76b39297aeSTomoki Sekiyama
77b39297aeSTomoki Sekiyama pCreateVssBackupComponents = (t_CreateVssBackupComponents)
78b39297aeSTomoki Sekiyama GetProcAddress(hLib,
79b39297aeSTomoki Sekiyama #ifdef _WIN64 /* 64bit environment */
80b39297aeSTomoki Sekiyama "?CreateVssBackupComponents@@YAJPEAPEAVIVssBackupComponents@@@Z"
81b39297aeSTomoki Sekiyama #else /* 32bit environment */
82b39297aeSTomoki Sekiyama "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
83b39297aeSTomoki Sekiyama #endif
84b39297aeSTomoki Sekiyama );
85b39297aeSTomoki Sekiyama if (!pCreateVssBackupComponents) {
862f84cf69SKonstantin Kostiuk qga_debug("failed to get proc address from VSSAPI.DLL");
87b39297aeSTomoki Sekiyama return HRESULT_FROM_WIN32(GetLastError());
88b39297aeSTomoki Sekiyama }
89b39297aeSTomoki Sekiyama
90b39297aeSTomoki Sekiyama pVssFreeSnapshotProperties = (t_VssFreeSnapshotProperties)
91b39297aeSTomoki Sekiyama GetProcAddress(hLib, "VssFreeSnapshotProperties");
92b39297aeSTomoki Sekiyama if (!pVssFreeSnapshotProperties) {
932f84cf69SKonstantin Kostiuk qga_debug("failed to get proc address from VSSAPI.DLL");
94b39297aeSTomoki Sekiyama return HRESULT_FROM_WIN32(GetLastError());
95b39297aeSTomoki Sekiyama }
96b39297aeSTomoki Sekiyama
9761df91b3SKonstantin Kostiuk qga_debug_end;
98b39297aeSTomoki Sekiyama return S_OK;
99b39297aeSTomoki Sekiyama }
100b39297aeSTomoki Sekiyama
requester_cleanup(void)101b39297aeSTomoki Sekiyama static void requester_cleanup(void)
102b39297aeSTomoki Sekiyama {
10361df91b3SKonstantin Kostiuk qga_debug_begin;
10461df91b3SKonstantin Kostiuk
1054c1b8f1eSTomoki Sekiyama if (vss_ctx.hEventFrozen) {
106b39297aeSTomoki Sekiyama CloseHandle(vss_ctx.hEventFrozen);
1074c1b8f1eSTomoki Sekiyama vss_ctx.hEventFrozen = NULL;
108b39297aeSTomoki Sekiyama }
1094c1b8f1eSTomoki Sekiyama if (vss_ctx.hEventThaw) {
110b39297aeSTomoki Sekiyama CloseHandle(vss_ctx.hEventThaw);
1114c1b8f1eSTomoki Sekiyama vss_ctx.hEventThaw = NULL;
112b39297aeSTomoki Sekiyama }
1134c1b8f1eSTomoki Sekiyama if (vss_ctx.hEventTimeout) {
114b39297aeSTomoki Sekiyama CloseHandle(vss_ctx.hEventTimeout);
1154c1b8f1eSTomoki Sekiyama vss_ctx.hEventTimeout = NULL;
116b39297aeSTomoki Sekiyama }
117b39297aeSTomoki Sekiyama if (vss_ctx.pAsyncSnapshot) {
118b39297aeSTomoki Sekiyama vss_ctx.pAsyncSnapshot->Release();
119b39297aeSTomoki Sekiyama vss_ctx.pAsyncSnapshot = NULL;
120b39297aeSTomoki Sekiyama }
121b39297aeSTomoki Sekiyama if (vss_ctx.pVssbc) {
122b39297aeSTomoki Sekiyama vss_ctx.pVssbc->Release();
123b39297aeSTomoki Sekiyama vss_ctx.pVssbc = NULL;
124b39297aeSTomoki Sekiyama }
125b39297aeSTomoki Sekiyama vss_ctx.cFrozenVols = 0;
12661df91b3SKonstantin Kostiuk qga_debug_end;
127b39297aeSTomoki Sekiyama }
128b39297aeSTomoki Sekiyama
requester_deinit(void)129b39297aeSTomoki Sekiyama STDAPI requester_deinit(void)
130b39297aeSTomoki Sekiyama {
13161df91b3SKonstantin Kostiuk qga_debug_begin;
13261df91b3SKonstantin Kostiuk
133b39297aeSTomoki Sekiyama requester_cleanup();
134b39297aeSTomoki Sekiyama
135b39297aeSTomoki Sekiyama pCreateVssBackupComponents = NULL;
136b39297aeSTomoki Sekiyama pVssFreeSnapshotProperties = NULL;
137b39297aeSTomoki Sekiyama if (hLib) {
138b39297aeSTomoki Sekiyama FreeLibrary(hLib);
139b39297aeSTomoki Sekiyama hLib = NULL;
140b39297aeSTomoki Sekiyama }
141b39297aeSTomoki Sekiyama
14261df91b3SKonstantin Kostiuk qga_debug_end;
143b39297aeSTomoki Sekiyama return S_OK;
144b39297aeSTomoki Sekiyama }
145b39297aeSTomoki Sekiyama
WaitForAsync(IVssAsync * pAsync)146b39297aeSTomoki Sekiyama static HRESULT WaitForAsync(IVssAsync *pAsync)
147b39297aeSTomoki Sekiyama {
14861df91b3SKonstantin Kostiuk qga_debug_begin;
14961df91b3SKonstantin Kostiuk
150b39297aeSTomoki Sekiyama HRESULT ret, hr;
151b39297aeSTomoki Sekiyama
152b39297aeSTomoki Sekiyama do {
153b39297aeSTomoki Sekiyama hr = pAsync->Wait();
154b39297aeSTomoki Sekiyama if (FAILED(hr)) {
155b39297aeSTomoki Sekiyama ret = hr;
156b39297aeSTomoki Sekiyama break;
157b39297aeSTomoki Sekiyama }
158b39297aeSTomoki Sekiyama hr = pAsync->QueryStatus(&ret, NULL);
159b39297aeSTomoki Sekiyama if (FAILED(hr)) {
160b39297aeSTomoki Sekiyama ret = hr;
161b39297aeSTomoki Sekiyama break;
162b39297aeSTomoki Sekiyama }
163b39297aeSTomoki Sekiyama } while (ret == VSS_S_ASYNC_PENDING);
164b39297aeSTomoki Sekiyama
16561df91b3SKonstantin Kostiuk qga_debug_end;
166b39297aeSTomoki Sekiyama return ret;
167b39297aeSTomoki Sekiyama }
168b39297aeSTomoki Sekiyama
AddComponents(ErrorSet * errset)169b39297aeSTomoki Sekiyama static void AddComponents(ErrorSet *errset)
170b39297aeSTomoki Sekiyama {
17161df91b3SKonstantin Kostiuk qga_debug_begin;
17261df91b3SKonstantin Kostiuk
173b39297aeSTomoki Sekiyama unsigned int cWriters, i;
174b39297aeSTomoki Sekiyama VSS_ID id, idInstance, idWriter;
175b39297aeSTomoki Sekiyama BSTR bstrWriterName = NULL;
176b39297aeSTomoki Sekiyama VSS_USAGE_TYPE usage;
177b39297aeSTomoki Sekiyama VSS_SOURCE_TYPE source;
178b39297aeSTomoki Sekiyama unsigned int cComponents, c1, c2, j;
179b39297aeSTomoki Sekiyama COMPointer<IVssExamineWriterMetadata> pMetadata;
180b39297aeSTomoki Sekiyama COMPointer<IVssWMComponent> pComponent;
181b39297aeSTomoki Sekiyama PVSSCOMPONENTINFO info;
182b39297aeSTomoki Sekiyama HRESULT hr;
183b39297aeSTomoki Sekiyama
184b39297aeSTomoki Sekiyama hr = vss_ctx.pVssbc->GetWriterMetadataCount(&cWriters);
185b39297aeSTomoki Sekiyama if (FAILED(hr)) {
186b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to get writer metadata count");
187b39297aeSTomoki Sekiyama goto out;
188b39297aeSTomoki Sekiyama }
189b39297aeSTomoki Sekiyama
190b39297aeSTomoki Sekiyama for (i = 0; i < cWriters; i++) {
191b39297aeSTomoki Sekiyama hr = vss_ctx.pVssbc->GetWriterMetadata(i, &id, pMetadata.replace());
192b39297aeSTomoki Sekiyama if (FAILED(hr)) {
193b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to get writer metadata of %d/%d",
194b39297aeSTomoki Sekiyama i, cWriters);
195b39297aeSTomoki Sekiyama goto out;
196b39297aeSTomoki Sekiyama }
197b39297aeSTomoki Sekiyama
198b39297aeSTomoki Sekiyama hr = pMetadata->GetIdentity(&idInstance, &idWriter,
199b39297aeSTomoki Sekiyama &bstrWriterName, &usage, &source);
200b39297aeSTomoki Sekiyama if (FAILED(hr)) {
201b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to get identity of writer %d/%d",
202b39297aeSTomoki Sekiyama i, cWriters);
203b39297aeSTomoki Sekiyama goto out;
204b39297aeSTomoki Sekiyama }
205b39297aeSTomoki Sekiyama
206b39297aeSTomoki Sekiyama hr = pMetadata->GetFileCounts(&c1, &c2, &cComponents);
207b39297aeSTomoki Sekiyama if (FAILED(hr)) {
208b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to get file counts of %S",
209b39297aeSTomoki Sekiyama bstrWriterName);
210b39297aeSTomoki Sekiyama goto out;
211b39297aeSTomoki Sekiyama }
212b39297aeSTomoki Sekiyama
213b39297aeSTomoki Sekiyama for (j = 0; j < cComponents; j++) {
214b39297aeSTomoki Sekiyama hr = pMetadata->GetComponent(j, pComponent.replace());
215b39297aeSTomoki Sekiyama if (FAILED(hr)) {
216b39297aeSTomoki Sekiyama err_set(errset, hr,
217b39297aeSTomoki Sekiyama "failed to get component %d/%d of %S",
218b39297aeSTomoki Sekiyama j, cComponents, bstrWriterName);
219b39297aeSTomoki Sekiyama goto out;
220b39297aeSTomoki Sekiyama }
221b39297aeSTomoki Sekiyama
222b39297aeSTomoki Sekiyama hr = pComponent->GetComponentInfo(&info);
223b39297aeSTomoki Sekiyama if (FAILED(hr)) {
224b39297aeSTomoki Sekiyama err_set(errset, hr,
225b39297aeSTomoki Sekiyama "failed to get component info %d/%d of %S",
226b39297aeSTomoki Sekiyama j, cComponents, bstrWriterName);
227b39297aeSTomoki Sekiyama goto out;
228b39297aeSTomoki Sekiyama }
229b39297aeSTomoki Sekiyama
230b39297aeSTomoki Sekiyama if (info->bSelectable) {
231b39297aeSTomoki Sekiyama hr = vss_ctx.pVssbc->AddComponent(idInstance, idWriter,
232b39297aeSTomoki Sekiyama info->type,
233b39297aeSTomoki Sekiyama info->bstrLogicalPath,
234b39297aeSTomoki Sekiyama info->bstrComponentName);
235b39297aeSTomoki Sekiyama if (FAILED(hr)) {
236b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to add component %S(%S)",
237b39297aeSTomoki Sekiyama info->bstrComponentName, bstrWriterName);
238b39297aeSTomoki Sekiyama goto out;
239b39297aeSTomoki Sekiyama }
240b39297aeSTomoki Sekiyama }
241b39297aeSTomoki Sekiyama SysFreeString(bstrWriterName);
242b39297aeSTomoki Sekiyama bstrWriterName = NULL;
243b39297aeSTomoki Sekiyama pComponent->FreeComponentInfo(info);
244b39297aeSTomoki Sekiyama info = NULL;
245b39297aeSTomoki Sekiyama }
246b39297aeSTomoki Sekiyama }
247b39297aeSTomoki Sekiyama out:
248b39297aeSTomoki Sekiyama if (bstrWriterName) {
249b39297aeSTomoki Sekiyama SysFreeString(bstrWriterName);
250b39297aeSTomoki Sekiyama }
251b39297aeSTomoki Sekiyama if (pComponent && info) {
252b39297aeSTomoki Sekiyama pComponent->FreeComponentInfo(info);
253b39297aeSTomoki Sekiyama }
25461df91b3SKonstantin Kostiuk qga_debug_end;
255b39297aeSTomoki Sekiyama }
256b39297aeSTomoki Sekiyama
get_reg_dword_value(HKEY baseKey,LPCSTR subKey,LPCSTR valueName,DWORD defaultData)257*73aaabcfSPierrick Bouvier static DWORD get_reg_dword_value(HKEY baseKey, LPCSTR subKey, LPCSTR valueName,
258410542d4SKfir Manor DWORD defaultData)
259410542d4SKfir Manor {
26061df91b3SKonstantin Kostiuk qga_debug_begin;
26161df91b3SKonstantin Kostiuk
262410542d4SKfir Manor DWORD regGetValueError;
263410542d4SKfir Manor DWORD dwordData;
264410542d4SKfir Manor DWORD dataSize = sizeof(DWORD);
265410542d4SKfir Manor
266410542d4SKfir Manor regGetValueError = RegGetValue(baseKey, subKey, valueName, RRF_RT_DWORD,
267410542d4SKfir Manor NULL, &dwordData, &dataSize);
26861df91b3SKonstantin Kostiuk qga_debug_end;
269410542d4SKfir Manor if (regGetValueError != ERROR_SUCCESS) {
270410542d4SKfir Manor return defaultData;
271410542d4SKfir Manor }
272410542d4SKfir Manor return dwordData;
273410542d4SKfir Manor }
274410542d4SKfir Manor
is_valid_vss_backup_type(VSS_BACKUP_TYPE vssBT)275*73aaabcfSPierrick Bouvier static bool is_valid_vss_backup_type(VSS_BACKUP_TYPE vssBT)
276410542d4SKfir Manor {
277410542d4SKfir Manor return (vssBT > VSS_BT_UNDEFINED && vssBT < VSS_BT_OTHER);
278410542d4SKfir Manor }
279410542d4SKfir Manor
get_vss_backup_type(VSS_BACKUP_TYPE defaultVssBT=DEFAULT_VSS_BACKUP_TYPE)280*73aaabcfSPierrick Bouvier static VSS_BACKUP_TYPE get_vss_backup_type(
281410542d4SKfir Manor VSS_BACKUP_TYPE defaultVssBT = DEFAULT_VSS_BACKUP_TYPE)
282410542d4SKfir Manor {
28361df91b3SKonstantin Kostiuk qga_debug_begin;
28461df91b3SKonstantin Kostiuk
285410542d4SKfir Manor VSS_BACKUP_TYPE vssBackupType;
286410542d4SKfir Manor
287410542d4SKfir Manor vssBackupType = static_cast<VSS_BACKUP_TYPE>(
288410542d4SKfir Manor get_reg_dword_value(HKEY_LOCAL_MACHINE,
289410542d4SKfir Manor QGA_PROVIDER_REGISTRY_ADDRESS,
290410542d4SKfir Manor "VssOption",
291410542d4SKfir Manor defaultVssBT));
29261df91b3SKonstantin Kostiuk qga_debug_end;
293410542d4SKfir Manor if (!is_valid_vss_backup_type(vssBackupType)) {
294410542d4SKfir Manor return defaultVssBT;
295410542d4SKfir Manor }
296410542d4SKfir Manor return vssBackupType;
297410542d4SKfir Manor }
298410542d4SKfir Manor
requester_freeze(int * num_vols,void * mountpoints,ErrorSet * errset)2990692b03eSChen Hanxiao void requester_freeze(int *num_vols, void *mountpoints, ErrorSet *errset)
300b39297aeSTomoki Sekiyama {
30161df91b3SKonstantin Kostiuk qga_debug_begin;
30261df91b3SKonstantin Kostiuk
303b39297aeSTomoki Sekiyama COMPointer<IVssAsync> pAsync;
304b39297aeSTomoki Sekiyama HANDLE volume;
305b39297aeSTomoki Sekiyama HRESULT hr;
306b39297aeSTomoki Sekiyama LONG ctx;
307b39297aeSTomoki Sekiyama GUID guidSnapshotSet = GUID_NULL;
308b39297aeSTomoki Sekiyama SECURITY_DESCRIPTOR sd;
309b39297aeSTomoki Sekiyama SECURITY_ATTRIBUTES sa;
310b39297aeSTomoki Sekiyama WCHAR short_volume_name[64], *display_name = short_volume_name;
311b39297aeSTomoki Sekiyama DWORD wait_status;
312b39297aeSTomoki Sekiyama int num_fixed_drives = 0, i;
3130692b03eSChen Hanxiao int num_mount_points = 0;
3140961f929SKfir Manor VSS_BACKUP_TYPE vss_bt = get_vss_backup_type();
315b39297aeSTomoki Sekiyama
316b39297aeSTomoki Sekiyama if (vss_ctx.pVssbc) { /* already frozen */
317b39297aeSTomoki Sekiyama *num_vols = 0;
31861df91b3SKonstantin Kostiuk qga_debug("finished, already frozen");
319b39297aeSTomoki Sekiyama return;
320b39297aeSTomoki Sekiyama }
321b39297aeSTomoki Sekiyama
322b39297aeSTomoki Sekiyama CoInitialize(NULL);
323b39297aeSTomoki Sekiyama
324ff8adbcfSTomoki Sekiyama /* Allow unrestricted access to events */
325ff8adbcfSTomoki Sekiyama InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
326ff8adbcfSTomoki Sekiyama SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
327ff8adbcfSTomoki Sekiyama sa.nLength = sizeof(sa);
328ff8adbcfSTomoki Sekiyama sa.lpSecurityDescriptor = &sd;
329ff8adbcfSTomoki Sekiyama sa.bInheritHandle = FALSE;
330ff8adbcfSTomoki Sekiyama
331ff8adbcfSTomoki Sekiyama vss_ctx.hEventFrozen = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_FROZEN);
332ff8adbcfSTomoki Sekiyama if (!vss_ctx.hEventFrozen) {
333ff8adbcfSTomoki Sekiyama err_set(errset, GetLastError(), "failed to create event %s",
334ff8adbcfSTomoki Sekiyama EVENT_NAME_FROZEN);
335ff8adbcfSTomoki Sekiyama goto out;
336ff8adbcfSTomoki Sekiyama }
337ff8adbcfSTomoki Sekiyama vss_ctx.hEventThaw = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_THAW);
338ff8adbcfSTomoki Sekiyama if (!vss_ctx.hEventThaw) {
339ff8adbcfSTomoki Sekiyama err_set(errset, GetLastError(), "failed to create event %s",
340ff8adbcfSTomoki Sekiyama EVENT_NAME_THAW);
341ff8adbcfSTomoki Sekiyama goto out;
342ff8adbcfSTomoki Sekiyama }
343ff8adbcfSTomoki Sekiyama vss_ctx.hEventTimeout = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_TIMEOUT);
344ff8adbcfSTomoki Sekiyama if (!vss_ctx.hEventTimeout) {
345ff8adbcfSTomoki Sekiyama err_set(errset, GetLastError(), "failed to create event %s",
346ff8adbcfSTomoki Sekiyama EVENT_NAME_TIMEOUT);
347ff8adbcfSTomoki Sekiyama goto out;
348ff8adbcfSTomoki Sekiyama }
349ff8adbcfSTomoki Sekiyama
350b39297aeSTomoki Sekiyama assert(pCreateVssBackupComponents != NULL);
351b39297aeSTomoki Sekiyama hr = pCreateVssBackupComponents(&vss_ctx.pVssbc);
352b39297aeSTomoki Sekiyama if (FAILED(hr)) {
353b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to create VSS backup components");
354b39297aeSTomoki Sekiyama goto out;
355b39297aeSTomoki Sekiyama }
356b39297aeSTomoki Sekiyama
357b39297aeSTomoki Sekiyama hr = vss_ctx.pVssbc->InitializeForBackup();
358b39297aeSTomoki Sekiyama if (FAILED(hr)) {
359b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to initialize for backup");
360b39297aeSTomoki Sekiyama goto out;
361b39297aeSTomoki Sekiyama }
362b39297aeSTomoki Sekiyama
3630961f929SKfir Manor hr = vss_ctx.pVssbc->SetBackupState(true, true, vss_bt, false);
364b39297aeSTomoki Sekiyama if (FAILED(hr)) {
365b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to set backup state");
366b39297aeSTomoki Sekiyama goto out;
367b39297aeSTomoki Sekiyama }
368b39297aeSTomoki Sekiyama
369b39297aeSTomoki Sekiyama /*
370b39297aeSTomoki Sekiyama * Currently writable snapshots are not supported.
371b39297aeSTomoki Sekiyama * To prevent the final commit (which requires to write to snapshots),
372b39297aeSTomoki Sekiyama * ATTR_NO_AUTORECOVERY and ATTR_TRANSPORTABLE are specified here.
373b39297aeSTomoki Sekiyama */
374b39297aeSTomoki Sekiyama ctx = VSS_CTX_APP_ROLLBACK | VSS_VOLSNAP_ATTR_TRANSPORTABLE |
375b39297aeSTomoki Sekiyama VSS_VOLSNAP_ATTR_NO_AUTORECOVERY | VSS_VOLSNAP_ATTR_TXF_RECOVERY;
376b39297aeSTomoki Sekiyama hr = vss_ctx.pVssbc->SetContext(ctx);
377b39297aeSTomoki Sekiyama if (hr == (HRESULT)VSS_E_UNSUPPORTED_CONTEXT) {
378b39297aeSTomoki Sekiyama /* Non-server version of Windows doesn't support ATTR_TRANSPORTABLE */
379b39297aeSTomoki Sekiyama ctx &= ~VSS_VOLSNAP_ATTR_TRANSPORTABLE;
380b39297aeSTomoki Sekiyama hr = vss_ctx.pVssbc->SetContext(ctx);
381b39297aeSTomoki Sekiyama }
382b39297aeSTomoki Sekiyama if (FAILED(hr)) {
383b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to set backup context");
384b39297aeSTomoki Sekiyama goto out;
385b39297aeSTomoki Sekiyama }
386b39297aeSTomoki Sekiyama
387b39297aeSTomoki Sekiyama hr = vss_ctx.pVssbc->GatherWriterMetadata(pAsync.replace());
388b39297aeSTomoki Sekiyama if (SUCCEEDED(hr)) {
389b39297aeSTomoki Sekiyama hr = WaitForAsync(pAsync);
390b39297aeSTomoki Sekiyama }
391b39297aeSTomoki Sekiyama if (FAILED(hr)) {
392b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to gather writer metadata");
393b39297aeSTomoki Sekiyama goto out;
394b39297aeSTomoki Sekiyama }
395b39297aeSTomoki Sekiyama
396b39297aeSTomoki Sekiyama AddComponents(errset);
397b39297aeSTomoki Sekiyama if (err_is_set(errset)) {
398b39297aeSTomoki Sekiyama goto out;
399b39297aeSTomoki Sekiyama }
400b39297aeSTomoki Sekiyama
401b39297aeSTomoki Sekiyama hr = vss_ctx.pVssbc->StartSnapshotSet(&guidSnapshotSet);
402b39297aeSTomoki Sekiyama if (FAILED(hr)) {
403b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to start snapshot set");
404b39297aeSTomoki Sekiyama goto out;
405b39297aeSTomoki Sekiyama }
406b39297aeSTomoki Sekiyama
4070692b03eSChen Hanxiao if (mountpoints) {
4080692b03eSChen Hanxiao PWCHAR volume_name_wchar;
4090692b03eSChen Hanxiao for (volList *list = (volList *)mountpoints; list; list = list->next) {
4100692b03eSChen Hanxiao size_t len = strlen(list->value) + 1;
4110692b03eSChen Hanxiao size_t converted = 0;
4120692b03eSChen Hanxiao VSS_ID pid;
4130692b03eSChen Hanxiao
4140692b03eSChen Hanxiao volume_name_wchar = new wchar_t[len];
4150692b03eSChen Hanxiao mbstowcs_s(&converted, volume_name_wchar, len,
4160692b03eSChen Hanxiao list->value, _TRUNCATE);
4170692b03eSChen Hanxiao
4180692b03eSChen Hanxiao hr = vss_ctx.pVssbc->AddToSnapshotSet(volume_name_wchar,
4190692b03eSChen Hanxiao g_gProviderId, &pid);
4200692b03eSChen Hanxiao if (FAILED(hr)) {
4210692b03eSChen Hanxiao err_set(errset, hr, "failed to add %S to snapshot set",
4220692b03eSChen Hanxiao volume_name_wchar);
4236c1d88c7SKonstantin Kostiuk delete[] volume_name_wchar;
4240692b03eSChen Hanxiao goto out;
4250692b03eSChen Hanxiao }
4260692b03eSChen Hanxiao num_mount_points++;
4270692b03eSChen Hanxiao
4286c1d88c7SKonstantin Kostiuk delete[] volume_name_wchar;
4290692b03eSChen Hanxiao }
4300692b03eSChen Hanxiao
4310692b03eSChen Hanxiao if (num_mount_points == 0) {
4320692b03eSChen Hanxiao /* If there is no valid mount points, just exit. */
4330692b03eSChen Hanxiao goto out;
4340692b03eSChen Hanxiao }
4350692b03eSChen Hanxiao }
4360692b03eSChen Hanxiao
4370692b03eSChen Hanxiao if (!mountpoints) {
438b39297aeSTomoki Sekiyama volume = FindFirstVolumeW(short_volume_name, sizeof(short_volume_name));
439b39297aeSTomoki Sekiyama if (volume == INVALID_HANDLE_VALUE) {
440b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to find first volume");
441b39297aeSTomoki Sekiyama goto out;
442b39297aeSTomoki Sekiyama }
4430692b03eSChen Hanxiao
444b39297aeSTomoki Sekiyama for (;;) {
445b39297aeSTomoki Sekiyama if (GetDriveTypeW(short_volume_name) == DRIVE_FIXED) {
446b39297aeSTomoki Sekiyama VSS_ID pid;
447b39297aeSTomoki Sekiyama hr = vss_ctx.pVssbc->AddToSnapshotSet(short_volume_name,
448b39297aeSTomoki Sekiyama g_gProviderId, &pid);
449b39297aeSTomoki Sekiyama if (FAILED(hr)) {
450b39297aeSTomoki Sekiyama WCHAR volume_path_name[PATH_MAX];
451b39297aeSTomoki Sekiyama if (GetVolumePathNamesForVolumeNameW(
452b39297aeSTomoki Sekiyama short_volume_name, volume_path_name,
4530692b03eSChen Hanxiao sizeof(volume_path_name), NULL) &&
4540692b03eSChen Hanxiao *volume_path_name) {
455b39297aeSTomoki Sekiyama display_name = volume_path_name;
456b39297aeSTomoki Sekiyama }
457b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to add %S to snapshot set",
458b39297aeSTomoki Sekiyama display_name);
459b39297aeSTomoki Sekiyama FindVolumeClose(volume);
460b39297aeSTomoki Sekiyama goto out;
461b39297aeSTomoki Sekiyama }
462b39297aeSTomoki Sekiyama num_fixed_drives++;
463b39297aeSTomoki Sekiyama }
464b39297aeSTomoki Sekiyama if (!FindNextVolumeW(volume, short_volume_name,
465b39297aeSTomoki Sekiyama sizeof(short_volume_name))) {
466b39297aeSTomoki Sekiyama FindVolumeClose(volume);
467b39297aeSTomoki Sekiyama break;
468b39297aeSTomoki Sekiyama }
469b39297aeSTomoki Sekiyama }
470b39297aeSTomoki Sekiyama
471b39297aeSTomoki Sekiyama if (num_fixed_drives == 0) {
472b39297aeSTomoki Sekiyama goto out; /* If there is no fixed drive, just exit. */
473b39297aeSTomoki Sekiyama }
4740692b03eSChen Hanxiao }
475b39297aeSTomoki Sekiyama
47661df91b3SKonstantin Kostiuk qga_debug("preparing for backup");
477b39297aeSTomoki Sekiyama hr = vss_ctx.pVssbc->PrepareForBackup(pAsync.replace());
478b39297aeSTomoki Sekiyama if (SUCCEEDED(hr)) {
479b39297aeSTomoki Sekiyama hr = WaitForAsync(pAsync);
480b39297aeSTomoki Sekiyama }
481b39297aeSTomoki Sekiyama if (FAILED(hr)) {
482b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to prepare for backup");
483b39297aeSTomoki Sekiyama goto out;
484b39297aeSTomoki Sekiyama }
485b39297aeSTomoki Sekiyama
486b39297aeSTomoki Sekiyama hr = vss_ctx.pVssbc->GatherWriterStatus(pAsync.replace());
487b39297aeSTomoki Sekiyama if (SUCCEEDED(hr)) {
488b39297aeSTomoki Sekiyama hr = WaitForAsync(pAsync);
489b39297aeSTomoki Sekiyama }
490b39297aeSTomoki Sekiyama if (FAILED(hr)) {
491b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to gather writer status");
492b39297aeSTomoki Sekiyama goto out;
493b39297aeSTomoki Sekiyama }
494b39297aeSTomoki Sekiyama
495b39297aeSTomoki Sekiyama /*
496b39297aeSTomoki Sekiyama * Start VSS quiescing operations.
497b39297aeSTomoki Sekiyama * CQGAVssProvider::CommitSnapshots will kick vss_ctx.hEventFrozen
498b39297aeSTomoki Sekiyama * after the applications and filesystems are frozen.
499b39297aeSTomoki Sekiyama */
50061df91b3SKonstantin Kostiuk qga_debug("do snapshot set");
501b39297aeSTomoki Sekiyama hr = vss_ctx.pVssbc->DoSnapshotSet(&vss_ctx.pAsyncSnapshot);
502b39297aeSTomoki Sekiyama if (FAILED(hr)) {
503b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to do snapshot set");
504b39297aeSTomoki Sekiyama goto out;
505b39297aeSTomoki Sekiyama }
506b39297aeSTomoki Sekiyama
507b39297aeSTomoki Sekiyama /* Need to call QueryStatus several times to make VSS provider progress */
508b39297aeSTomoki Sekiyama for (i = 0; i < VSS_TIMEOUT_FREEZE_MSEC/VSS_TIMEOUT_EVENT_MSEC; i++) {
509b39297aeSTomoki Sekiyama HRESULT hr2 = vss_ctx.pAsyncSnapshot->QueryStatus(&hr, NULL);
510b39297aeSTomoki Sekiyama if (FAILED(hr2)) {
511b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to do snapshot set");
512b39297aeSTomoki Sekiyama goto out;
513b39297aeSTomoki Sekiyama }
514b39297aeSTomoki Sekiyama if (hr != VSS_S_ASYNC_PENDING) {
515b39297aeSTomoki Sekiyama err_set(errset, E_FAIL,
516b39297aeSTomoki Sekiyama "DoSnapshotSet exited without Frozen event");
517b39297aeSTomoki Sekiyama goto out;
518b39297aeSTomoki Sekiyama }
519b39297aeSTomoki Sekiyama wait_status = WaitForSingleObject(vss_ctx.hEventFrozen,
520b39297aeSTomoki Sekiyama VSS_TIMEOUT_EVENT_MSEC);
521b39297aeSTomoki Sekiyama if (wait_status != WAIT_TIMEOUT) {
522b39297aeSTomoki Sekiyama break;
523b39297aeSTomoki Sekiyama }
524b39297aeSTomoki Sekiyama }
5254d80d20fSChen Hanxiao
5264d80d20fSChen Hanxiao if (wait_status == WAIT_TIMEOUT) {
5274d80d20fSChen Hanxiao err_set(errset, E_FAIL,
5284d80d20fSChen Hanxiao "timeout when try to receive Frozen event from VSS provider");
5294d80d20fSChen Hanxiao /* If we are here, VSS had timeout.
5304d80d20fSChen Hanxiao * Don't call AbortBackup, just return directly.
5314d80d20fSChen Hanxiao */
5324d80d20fSChen Hanxiao goto out1;
5334d80d20fSChen Hanxiao }
5344d80d20fSChen Hanxiao
535b39297aeSTomoki Sekiyama if (wait_status != WAIT_OBJECT_0) {
536b39297aeSTomoki Sekiyama err_set(errset, E_FAIL,
537b39297aeSTomoki Sekiyama "couldn't receive Frozen event from VSS provider");
538b39297aeSTomoki Sekiyama goto out;
539b39297aeSTomoki Sekiyama }
540b39297aeSTomoki Sekiyama
5410692b03eSChen Hanxiao if (mountpoints) {
5420692b03eSChen Hanxiao *num_vols = vss_ctx.cFrozenVols = num_mount_points;
5430692b03eSChen Hanxiao } else {
544b39297aeSTomoki Sekiyama *num_vols = vss_ctx.cFrozenVols = num_fixed_drives;
5450692b03eSChen Hanxiao }
5460692b03eSChen Hanxiao
54761df91b3SKonstantin Kostiuk qga_debug("end successful");
548b39297aeSTomoki Sekiyama return;
549b39297aeSTomoki Sekiyama
550b39297aeSTomoki Sekiyama out:
551b39297aeSTomoki Sekiyama if (vss_ctx.pVssbc) {
552b39297aeSTomoki Sekiyama vss_ctx.pVssbc->AbortBackup();
553b39297aeSTomoki Sekiyama }
5544d80d20fSChen Hanxiao
5554d80d20fSChen Hanxiao out1:
556b39297aeSTomoki Sekiyama requester_cleanup();
557b39297aeSTomoki Sekiyama CoUninitialize();
55861df91b3SKonstantin Kostiuk
55961df91b3SKonstantin Kostiuk qga_debug_end;
560b39297aeSTomoki Sekiyama }
561b39297aeSTomoki Sekiyama
562b39297aeSTomoki Sekiyama
requester_thaw(int * num_vols,void * mountpints,ErrorSet * errset)5630692b03eSChen Hanxiao void requester_thaw(int *num_vols, void *mountpints, ErrorSet *errset)
564b39297aeSTomoki Sekiyama {
56561df91b3SKonstantin Kostiuk qga_debug_begin;
566b39297aeSTomoki Sekiyama COMPointer<IVssAsync> pAsync;
567b39297aeSTomoki Sekiyama
5684c1b8f1eSTomoki Sekiyama if (!vss_ctx.hEventThaw) {
569b39297aeSTomoki Sekiyama /*
570b39297aeSTomoki Sekiyama * In this case, DoSnapshotSet is aborted or not started,
571b39297aeSTomoki Sekiyama * and no volumes must be frozen. We return without an error.
572b39297aeSTomoki Sekiyama */
573b39297aeSTomoki Sekiyama *num_vols = 0;
57461df91b3SKonstantin Kostiuk qga_debug("finished, no volumes were frozen");
57561df91b3SKonstantin Kostiuk
576b39297aeSTomoki Sekiyama return;
577b39297aeSTomoki Sekiyama }
578b39297aeSTomoki Sekiyama
579b39297aeSTomoki Sekiyama /* Tell the provider that the snapshot is finished. */
580b39297aeSTomoki Sekiyama SetEvent(vss_ctx.hEventThaw);
581b39297aeSTomoki Sekiyama
582b39297aeSTomoki Sekiyama assert(vss_ctx.pVssbc);
583b39297aeSTomoki Sekiyama assert(vss_ctx.pAsyncSnapshot);
584b39297aeSTomoki Sekiyama
585b39297aeSTomoki Sekiyama HRESULT hr = WaitForAsync(vss_ctx.pAsyncSnapshot);
586b39297aeSTomoki Sekiyama switch (hr) {
587b39297aeSTomoki Sekiyama case VSS_S_ASYNC_FINISHED:
588b39297aeSTomoki Sekiyama hr = vss_ctx.pVssbc->BackupComplete(pAsync.replace());
589b39297aeSTomoki Sekiyama if (SUCCEEDED(hr)) {
590b39297aeSTomoki Sekiyama hr = WaitForAsync(pAsync);
591b39297aeSTomoki Sekiyama }
592b39297aeSTomoki Sekiyama if (FAILED(hr)) {
593b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to complete backup");
594b39297aeSTomoki Sekiyama }
595b39297aeSTomoki Sekiyama break;
596b39297aeSTomoki Sekiyama
597b39297aeSTomoki Sekiyama case (HRESULT)VSS_E_OBJECT_NOT_FOUND:
598b39297aeSTomoki Sekiyama /*
599b39297aeSTomoki Sekiyama * On Windows earlier than 2008 SP2 which does not support
600b39297aeSTomoki Sekiyama * VSS_VOLSNAP_ATTR_NO_AUTORECOVERY context, the final commit is not
601b39297aeSTomoki Sekiyama * skipped and VSS is aborted by VSS_E_OBJECT_NOT_FOUND. However, as
602b39297aeSTomoki Sekiyama * the system had been frozen until fsfreeze-thaw command was issued,
603b39297aeSTomoki Sekiyama * we ignore this error.
604b39297aeSTomoki Sekiyama */
605b39297aeSTomoki Sekiyama vss_ctx.pVssbc->AbortBackup();
606b39297aeSTomoki Sekiyama break;
607b39297aeSTomoki Sekiyama
608b39297aeSTomoki Sekiyama case VSS_E_UNEXPECTED_PROVIDER_ERROR:
609b39297aeSTomoki Sekiyama if (WaitForSingleObject(vss_ctx.hEventTimeout, 0) != WAIT_OBJECT_0) {
610b39297aeSTomoki Sekiyama err_set(errset, hr, "unexpected error in VSS provider");
611b39297aeSTomoki Sekiyama break;
612b39297aeSTomoki Sekiyama }
613b39297aeSTomoki Sekiyama /* fall through if hEventTimeout is signaled */
614b39297aeSTomoki Sekiyama
615b39297aeSTomoki Sekiyama case (HRESULT)VSS_E_HOLD_WRITES_TIMEOUT:
616b39297aeSTomoki Sekiyama err_set(errset, hr, "couldn't hold writes: "
617b39297aeSTomoki Sekiyama "fsfreeze is limited up to 10 seconds");
618b39297aeSTomoki Sekiyama break;
619b39297aeSTomoki Sekiyama
620b39297aeSTomoki Sekiyama default:
621b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to do snapshot set");
622b39297aeSTomoki Sekiyama }
623b39297aeSTomoki Sekiyama
624b39297aeSTomoki Sekiyama if (err_is_set(errset)) {
625b39297aeSTomoki Sekiyama vss_ctx.pVssbc->AbortBackup();
626b39297aeSTomoki Sekiyama }
627b39297aeSTomoki Sekiyama *num_vols = vss_ctx.cFrozenVols;
628b39297aeSTomoki Sekiyama requester_cleanup();
629b39297aeSTomoki Sekiyama
630b39297aeSTomoki Sekiyama CoUninitialize();
631f342cc93SSameeh Jubran StopService();
63261df91b3SKonstantin Kostiuk
63361df91b3SKonstantin Kostiuk qga_debug_end;
634b39297aeSTomoki Sekiyama }
635