target-hppa: Implement shifts and deposits
[qemu/ar7.git] / qga / vss-win32 / requester.cpp
blob0cd2f0ee7f049684622e524eef4479a02231e59f
1 /*
2 * QEMU Guest Agent win32 VSS Requester implementations
4 * Copyright Hitachi Data Systems Corp. 2013
6 * Authors:
7 * Tomoki Sekiyama <tomoki.sekiyama@hds.com>
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
13 #include "qemu/osdep.h"
14 #include "vss-common.h"
15 #include "requester.h"
16 #include <inc/win2003/vswriter.h>
17 #include <inc/win2003/vsbackup.h>
19 /* Max wait time for frozen event (VSS can only hold writes for 10 seconds) */
20 #define VSS_TIMEOUT_FREEZE_MSEC 10000
22 /* Call QueryStatus every 10 ms while waiting for frozen event */
23 #define VSS_TIMEOUT_EVENT_MSEC 10
25 #define err_set(e, err, fmt, ...) \
26 ((e)->error_setg_win32_wrapper((e)->errp, __FILE__, __LINE__, __func__, \
27 err, fmt, ## __VA_ARGS__))
28 /* Bad idea, works only when (e)->errp != NULL: */
29 #define err_is_set(e) ((e)->errp && *(e)->errp)
30 /* To lift this restriction, error_propagate(), like we do in QEMU code */
32 /* Handle to VSSAPI.DLL */
33 static HMODULE hLib;
35 /* Functions in VSSAPI.DLL */
36 typedef HRESULT(STDAPICALLTYPE * t_CreateVssBackupComponents)(
37 OUT IVssBackupComponents**);
38 typedef void(APIENTRY * t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
39 static t_CreateVssBackupComponents pCreateVssBackupComponents;
40 static t_VssFreeSnapshotProperties pVssFreeSnapshotProperties;
42 /* Variables used while applications and filesystes are frozen by VSS */
43 static struct QGAVSSContext {
44 IVssBackupComponents *pVssbc; /* VSS requester interface */
45 IVssAsync *pAsyncSnapshot; /* async info of VSS snapshot operation */
46 HANDLE hEventFrozen; /* notify fs/writer freeze from provider */
47 HANDLE hEventThaw; /* request provider to thaw */
48 HANDLE hEventTimeout; /* notify timeout in provider */
49 int cFrozenVols; /* number of frozen volumes */
50 } vss_ctx;
52 STDAPI requester_init(void)
54 COMInitializer initializer; /* to call CoInitializeSecurity */
55 HRESULT hr = CoInitializeSecurity(
56 NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
57 RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE, NULL);
58 if (FAILED(hr)) {
59 fprintf(stderr, "failed to CoInitializeSecurity (error %lx)\n", hr);
60 return hr;
63 hLib = LoadLibraryA("VSSAPI.DLL");
64 if (!hLib) {
65 fprintf(stderr, "failed to load VSSAPI.DLL\n");
66 return HRESULT_FROM_WIN32(GetLastError());
69 pCreateVssBackupComponents = (t_CreateVssBackupComponents)
70 GetProcAddress(hLib,
71 #ifdef _WIN64 /* 64bit environment */
72 "?CreateVssBackupComponents@@YAJPEAPEAVIVssBackupComponents@@@Z"
73 #else /* 32bit environment */
74 "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
75 #endif
77 if (!pCreateVssBackupComponents) {
78 fprintf(stderr, "failed to get proc address from VSSAPI.DLL\n");
79 return HRESULT_FROM_WIN32(GetLastError());
82 pVssFreeSnapshotProperties = (t_VssFreeSnapshotProperties)
83 GetProcAddress(hLib, "VssFreeSnapshotProperties");
84 if (!pVssFreeSnapshotProperties) {
85 fprintf(stderr, "failed to get proc address from VSSAPI.DLL\n");
86 return HRESULT_FROM_WIN32(GetLastError());
89 return S_OK;
92 static void requester_cleanup(void)
94 if (vss_ctx.hEventFrozen) {
95 CloseHandle(vss_ctx.hEventFrozen);
96 vss_ctx.hEventFrozen = NULL;
98 if (vss_ctx.hEventThaw) {
99 CloseHandle(vss_ctx.hEventThaw);
100 vss_ctx.hEventThaw = NULL;
102 if (vss_ctx.hEventTimeout) {
103 CloseHandle(vss_ctx.hEventTimeout);
104 vss_ctx.hEventTimeout = NULL;
106 if (vss_ctx.pAsyncSnapshot) {
107 vss_ctx.pAsyncSnapshot->Release();
108 vss_ctx.pAsyncSnapshot = NULL;
110 if (vss_ctx.pVssbc) {
111 vss_ctx.pVssbc->Release();
112 vss_ctx.pVssbc = NULL;
114 vss_ctx.cFrozenVols = 0;
117 STDAPI requester_deinit(void)
119 requester_cleanup();
121 pCreateVssBackupComponents = NULL;
122 pVssFreeSnapshotProperties = NULL;
123 if (hLib) {
124 FreeLibrary(hLib);
125 hLib = NULL;
128 return S_OK;
131 static HRESULT WaitForAsync(IVssAsync *pAsync)
133 HRESULT ret, hr;
135 do {
136 hr = pAsync->Wait();
137 if (FAILED(hr)) {
138 ret = hr;
139 break;
141 hr = pAsync->QueryStatus(&ret, NULL);
142 if (FAILED(hr)) {
143 ret = hr;
144 break;
146 } while (ret == VSS_S_ASYNC_PENDING);
148 return ret;
151 static void AddComponents(ErrorSet *errset)
153 unsigned int cWriters, i;
154 VSS_ID id, idInstance, idWriter;
155 BSTR bstrWriterName = NULL;
156 VSS_USAGE_TYPE usage;
157 VSS_SOURCE_TYPE source;
158 unsigned int cComponents, c1, c2, j;
159 COMPointer<IVssExamineWriterMetadata> pMetadata;
160 COMPointer<IVssWMComponent> pComponent;
161 PVSSCOMPONENTINFO info;
162 HRESULT hr;
164 hr = vss_ctx.pVssbc->GetWriterMetadataCount(&cWriters);
165 if (FAILED(hr)) {
166 err_set(errset, hr, "failed to get writer metadata count");
167 goto out;
170 for (i = 0; i < cWriters; i++) {
171 hr = vss_ctx.pVssbc->GetWriterMetadata(i, &id, pMetadata.replace());
172 if (FAILED(hr)) {
173 err_set(errset, hr, "failed to get writer metadata of %d/%d",
174 i, cWriters);
175 goto out;
178 hr = pMetadata->GetIdentity(&idInstance, &idWriter,
179 &bstrWriterName, &usage, &source);
180 if (FAILED(hr)) {
181 err_set(errset, hr, "failed to get identity of writer %d/%d",
182 i, cWriters);
183 goto out;
186 hr = pMetadata->GetFileCounts(&c1, &c2, &cComponents);
187 if (FAILED(hr)) {
188 err_set(errset, hr, "failed to get file counts of %S",
189 bstrWriterName);
190 goto out;
193 for (j = 0; j < cComponents; j++) {
194 hr = pMetadata->GetComponent(j, pComponent.replace());
195 if (FAILED(hr)) {
196 err_set(errset, hr,
197 "failed to get component %d/%d of %S",
198 j, cComponents, bstrWriterName);
199 goto out;
202 hr = pComponent->GetComponentInfo(&info);
203 if (FAILED(hr)) {
204 err_set(errset, hr,
205 "failed to get component info %d/%d of %S",
206 j, cComponents, bstrWriterName);
207 goto out;
210 if (info->bSelectable) {
211 hr = vss_ctx.pVssbc->AddComponent(idInstance, idWriter,
212 info->type,
213 info->bstrLogicalPath,
214 info->bstrComponentName);
215 if (FAILED(hr)) {
216 err_set(errset, hr, "failed to add component %S(%S)",
217 info->bstrComponentName, bstrWriterName);
218 goto out;
221 SysFreeString(bstrWriterName);
222 bstrWriterName = NULL;
223 pComponent->FreeComponentInfo(info);
224 info = NULL;
227 out:
228 if (bstrWriterName) {
229 SysFreeString(bstrWriterName);
231 if (pComponent && info) {
232 pComponent->FreeComponentInfo(info);
236 void requester_freeze(int *num_vols, ErrorSet *errset)
238 COMPointer<IVssAsync> pAsync;
239 HANDLE volume;
240 HRESULT hr;
241 LONG ctx;
242 GUID guidSnapshotSet = GUID_NULL;
243 SECURITY_DESCRIPTOR sd;
244 SECURITY_ATTRIBUTES sa;
245 WCHAR short_volume_name[64], *display_name = short_volume_name;
246 DWORD wait_status;
247 int num_fixed_drives = 0, i;
249 if (vss_ctx.pVssbc) { /* already frozen */
250 *num_vols = 0;
251 return;
254 CoInitialize(NULL);
256 /* Allow unrestricted access to events */
257 InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
258 SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
259 sa.nLength = sizeof(sa);
260 sa.lpSecurityDescriptor = &sd;
261 sa.bInheritHandle = FALSE;
263 vss_ctx.hEventFrozen = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_FROZEN);
264 if (!vss_ctx.hEventFrozen) {
265 err_set(errset, GetLastError(), "failed to create event %s",
266 EVENT_NAME_FROZEN);
267 goto out;
269 vss_ctx.hEventThaw = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_THAW);
270 if (!vss_ctx.hEventThaw) {
271 err_set(errset, GetLastError(), "failed to create event %s",
272 EVENT_NAME_THAW);
273 goto out;
275 vss_ctx.hEventTimeout = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_TIMEOUT);
276 if (!vss_ctx.hEventTimeout) {
277 err_set(errset, GetLastError(), "failed to create event %s",
278 EVENT_NAME_TIMEOUT);
279 goto out;
282 assert(pCreateVssBackupComponents != NULL);
283 hr = pCreateVssBackupComponents(&vss_ctx.pVssbc);
284 if (FAILED(hr)) {
285 err_set(errset, hr, "failed to create VSS backup components");
286 goto out;
289 hr = vss_ctx.pVssbc->InitializeForBackup();
290 if (FAILED(hr)) {
291 err_set(errset, hr, "failed to initialize for backup");
292 goto out;
295 hr = vss_ctx.pVssbc->SetBackupState(true, true, VSS_BT_FULL, false);
296 if (FAILED(hr)) {
297 err_set(errset, hr, "failed to set backup state");
298 goto out;
302 * Currently writable snapshots are not supported.
303 * To prevent the final commit (which requires to write to snapshots),
304 * ATTR_NO_AUTORECOVERY and ATTR_TRANSPORTABLE are specified here.
306 ctx = VSS_CTX_APP_ROLLBACK | VSS_VOLSNAP_ATTR_TRANSPORTABLE |
307 VSS_VOLSNAP_ATTR_NO_AUTORECOVERY | VSS_VOLSNAP_ATTR_TXF_RECOVERY;
308 hr = vss_ctx.pVssbc->SetContext(ctx);
309 if (hr == (HRESULT)VSS_E_UNSUPPORTED_CONTEXT) {
310 /* Non-server version of Windows doesn't support ATTR_TRANSPORTABLE */
311 ctx &= ~VSS_VOLSNAP_ATTR_TRANSPORTABLE;
312 hr = vss_ctx.pVssbc->SetContext(ctx);
314 if (FAILED(hr)) {
315 err_set(errset, hr, "failed to set backup context");
316 goto out;
319 hr = vss_ctx.pVssbc->GatherWriterMetadata(pAsync.replace());
320 if (SUCCEEDED(hr)) {
321 hr = WaitForAsync(pAsync);
323 if (FAILED(hr)) {
324 err_set(errset, hr, "failed to gather writer metadata");
325 goto out;
328 AddComponents(errset);
329 if (err_is_set(errset)) {
330 goto out;
333 hr = vss_ctx.pVssbc->StartSnapshotSet(&guidSnapshotSet);
334 if (FAILED(hr)) {
335 err_set(errset, hr, "failed to start snapshot set");
336 goto out;
339 volume = FindFirstVolumeW(short_volume_name, sizeof(short_volume_name));
340 if (volume == INVALID_HANDLE_VALUE) {
341 err_set(errset, hr, "failed to find first volume");
342 goto out;
344 for (;;) {
345 if (GetDriveTypeW(short_volume_name) == DRIVE_FIXED) {
346 VSS_ID pid;
347 hr = vss_ctx.pVssbc->AddToSnapshotSet(short_volume_name,
348 g_gProviderId, &pid);
349 if (FAILED(hr)) {
350 WCHAR volume_path_name[PATH_MAX];
351 if (GetVolumePathNamesForVolumeNameW(
352 short_volume_name, volume_path_name,
353 sizeof(volume_path_name), NULL) && *volume_path_name) {
354 display_name = volume_path_name;
356 err_set(errset, hr, "failed to add %S to snapshot set",
357 display_name);
358 FindVolumeClose(volume);
359 goto out;
361 num_fixed_drives++;
363 if (!FindNextVolumeW(volume, short_volume_name,
364 sizeof(short_volume_name))) {
365 FindVolumeClose(volume);
366 break;
370 if (num_fixed_drives == 0) {
371 goto out; /* If there is no fixed drive, just exit. */
374 hr = vss_ctx.pVssbc->PrepareForBackup(pAsync.replace());
375 if (SUCCEEDED(hr)) {
376 hr = WaitForAsync(pAsync);
378 if (FAILED(hr)) {
379 err_set(errset, hr, "failed to prepare for backup");
380 goto out;
383 hr = vss_ctx.pVssbc->GatherWriterStatus(pAsync.replace());
384 if (SUCCEEDED(hr)) {
385 hr = WaitForAsync(pAsync);
387 if (FAILED(hr)) {
388 err_set(errset, hr, "failed to gather writer status");
389 goto out;
393 * Start VSS quiescing operations.
394 * CQGAVssProvider::CommitSnapshots will kick vss_ctx.hEventFrozen
395 * after the applications and filesystems are frozen.
397 hr = vss_ctx.pVssbc->DoSnapshotSet(&vss_ctx.pAsyncSnapshot);
398 if (FAILED(hr)) {
399 err_set(errset, hr, "failed to do snapshot set");
400 goto out;
403 /* Need to call QueryStatus several times to make VSS provider progress */
404 for (i = 0; i < VSS_TIMEOUT_FREEZE_MSEC/VSS_TIMEOUT_EVENT_MSEC; i++) {
405 HRESULT hr2 = vss_ctx.pAsyncSnapshot->QueryStatus(&hr, NULL);
406 if (FAILED(hr2)) {
407 err_set(errset, hr, "failed to do snapshot set");
408 goto out;
410 if (hr != VSS_S_ASYNC_PENDING) {
411 err_set(errset, E_FAIL,
412 "DoSnapshotSet exited without Frozen event");
413 goto out;
415 wait_status = WaitForSingleObject(vss_ctx.hEventFrozen,
416 VSS_TIMEOUT_EVENT_MSEC);
417 if (wait_status != WAIT_TIMEOUT) {
418 break;
421 if (wait_status != WAIT_OBJECT_0) {
422 err_set(errset, E_FAIL,
423 "couldn't receive Frozen event from VSS provider");
424 goto out;
427 *num_vols = vss_ctx.cFrozenVols = num_fixed_drives;
428 return;
430 out:
431 if (vss_ctx.pVssbc) {
432 vss_ctx.pVssbc->AbortBackup();
434 requester_cleanup();
435 CoUninitialize();
439 void requester_thaw(int *num_vols, ErrorSet *errset)
441 COMPointer<IVssAsync> pAsync;
443 if (!vss_ctx.hEventThaw) {
445 * In this case, DoSnapshotSet is aborted or not started,
446 * and no volumes must be frozen. We return without an error.
448 *num_vols = 0;
449 return;
452 /* Tell the provider that the snapshot is finished. */
453 SetEvent(vss_ctx.hEventThaw);
455 assert(vss_ctx.pVssbc);
456 assert(vss_ctx.pAsyncSnapshot);
458 HRESULT hr = WaitForAsync(vss_ctx.pAsyncSnapshot);
459 switch (hr) {
460 case VSS_S_ASYNC_FINISHED:
461 hr = vss_ctx.pVssbc->BackupComplete(pAsync.replace());
462 if (SUCCEEDED(hr)) {
463 hr = WaitForAsync(pAsync);
465 if (FAILED(hr)) {
466 err_set(errset, hr, "failed to complete backup");
468 break;
470 case (HRESULT)VSS_E_OBJECT_NOT_FOUND:
472 * On Windows earlier than 2008 SP2 which does not support
473 * VSS_VOLSNAP_ATTR_NO_AUTORECOVERY context, the final commit is not
474 * skipped and VSS is aborted by VSS_E_OBJECT_NOT_FOUND. However, as
475 * the system had been frozen until fsfreeze-thaw command was issued,
476 * we ignore this error.
478 vss_ctx.pVssbc->AbortBackup();
479 break;
481 case VSS_E_UNEXPECTED_PROVIDER_ERROR:
482 if (WaitForSingleObject(vss_ctx.hEventTimeout, 0) != WAIT_OBJECT_0) {
483 err_set(errset, hr, "unexpected error in VSS provider");
484 break;
486 /* fall through if hEventTimeout is signaled */
488 case (HRESULT)VSS_E_HOLD_WRITES_TIMEOUT:
489 err_set(errset, hr, "couldn't hold writes: "
490 "fsfreeze is limited up to 10 seconds");
491 break;
493 default:
494 err_set(errset, hr, "failed to do snapshot set");
497 if (err_is_set(errset)) {
498 vss_ctx.pVssbc->AbortBackup();
500 *num_vols = vss_ctx.cFrozenVols;
501 requester_cleanup();
503 CoUninitialize();