aspeed: Introduce a boot_rom region at the machine level
[qemu/armbru.git] / qga / vss-win32 / requester.cpp
blob3e998af4a8898ae3c81d8af31843ee2ddaf83200
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 "install.h"
17 #include <vswriter.h>
18 #include <vsbackup.h>
20 /* Max wait time for frozen event (VSS can only hold writes for 10 seconds) */
21 #define VSS_TIMEOUT_FREEZE_MSEC 60000
23 /* Call QueryStatus every 10 ms while waiting for frozen event */
24 #define VSS_TIMEOUT_EVENT_MSEC 10
26 #define DEFAULT_VSS_BACKUP_TYPE VSS_BT_FULL
28 #define err_set(e, err, fmt, ...) \
29 ((e)->error_setg_win32_wrapper((e)->errp, __FILE__, __LINE__, __func__, \
30 err, fmt, ## __VA_ARGS__))
31 /* Bad idea, works only when (e)->errp != NULL: */
32 #define err_is_set(e) ((e)->errp && *(e)->errp)
33 /* To lift this restriction, error_propagate(), like we do in QEMU code */
35 /* Handle to VSSAPI.DLL */
36 static HMODULE hLib;
38 /* Functions in VSSAPI.DLL */
39 typedef HRESULT(STDAPICALLTYPE * t_CreateVssBackupComponents)(
40 OUT IVssBackupComponents**);
41 typedef void(APIENTRY * t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
42 static t_CreateVssBackupComponents pCreateVssBackupComponents;
43 static t_VssFreeSnapshotProperties pVssFreeSnapshotProperties;
45 /* Variables used while applications and filesystes are frozen by VSS */
46 static struct QGAVSSContext {
47 IVssBackupComponents *pVssbc; /* VSS requester interface */
48 IVssAsync *pAsyncSnapshot; /* async info of VSS snapshot operation */
49 HANDLE hEventFrozen; /* notify fs/writer freeze from provider */
50 HANDLE hEventThaw; /* request provider to thaw */
51 HANDLE hEventTimeout; /* notify timeout in provider */
52 int cFrozenVols; /* number of frozen volumes */
53 } vss_ctx;
55 STDAPI requester_init(void)
57 COMInitializer initializer; /* to call CoInitializeSecurity */
58 HRESULT hr = CoInitializeSecurity(
59 NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
60 RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE, NULL);
61 if (FAILED(hr)) {
62 fprintf(stderr, "failed to CoInitializeSecurity (error %lx)\n", hr);
63 return hr;
66 hLib = LoadLibraryA("VSSAPI.DLL");
67 if (!hLib) {
68 fprintf(stderr, "failed to load VSSAPI.DLL\n");
69 return HRESULT_FROM_WIN32(GetLastError());
72 pCreateVssBackupComponents = (t_CreateVssBackupComponents)
73 GetProcAddress(hLib,
74 #ifdef _WIN64 /* 64bit environment */
75 "?CreateVssBackupComponents@@YAJPEAPEAVIVssBackupComponents@@@Z"
76 #else /* 32bit environment */
77 "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
78 #endif
80 if (!pCreateVssBackupComponents) {
81 fprintf(stderr, "failed to get proc address from VSSAPI.DLL\n");
82 return HRESULT_FROM_WIN32(GetLastError());
85 pVssFreeSnapshotProperties = (t_VssFreeSnapshotProperties)
86 GetProcAddress(hLib, "VssFreeSnapshotProperties");
87 if (!pVssFreeSnapshotProperties) {
88 fprintf(stderr, "failed to get proc address from VSSAPI.DLL\n");
89 return HRESULT_FROM_WIN32(GetLastError());
92 return S_OK;
95 static void requester_cleanup(void)
97 if (vss_ctx.hEventFrozen) {
98 CloseHandle(vss_ctx.hEventFrozen);
99 vss_ctx.hEventFrozen = NULL;
101 if (vss_ctx.hEventThaw) {
102 CloseHandle(vss_ctx.hEventThaw);
103 vss_ctx.hEventThaw = NULL;
105 if (vss_ctx.hEventTimeout) {
106 CloseHandle(vss_ctx.hEventTimeout);
107 vss_ctx.hEventTimeout = NULL;
109 if (vss_ctx.pAsyncSnapshot) {
110 vss_ctx.pAsyncSnapshot->Release();
111 vss_ctx.pAsyncSnapshot = NULL;
113 if (vss_ctx.pVssbc) {
114 vss_ctx.pVssbc->Release();
115 vss_ctx.pVssbc = NULL;
117 vss_ctx.cFrozenVols = 0;
120 STDAPI requester_deinit(void)
122 requester_cleanup();
124 pCreateVssBackupComponents = NULL;
125 pVssFreeSnapshotProperties = NULL;
126 if (hLib) {
127 FreeLibrary(hLib);
128 hLib = NULL;
131 return S_OK;
134 static HRESULT WaitForAsync(IVssAsync *pAsync)
136 HRESULT ret, hr;
138 do {
139 hr = pAsync->Wait();
140 if (FAILED(hr)) {
141 ret = hr;
142 break;
144 hr = pAsync->QueryStatus(&ret, NULL);
145 if (FAILED(hr)) {
146 ret = hr;
147 break;
149 } while (ret == VSS_S_ASYNC_PENDING);
151 return ret;
154 static void AddComponents(ErrorSet *errset)
156 unsigned int cWriters, i;
157 VSS_ID id, idInstance, idWriter;
158 BSTR bstrWriterName = NULL;
159 VSS_USAGE_TYPE usage;
160 VSS_SOURCE_TYPE source;
161 unsigned int cComponents, c1, c2, j;
162 COMPointer<IVssExamineWriterMetadata> pMetadata;
163 COMPointer<IVssWMComponent> pComponent;
164 PVSSCOMPONENTINFO info;
165 HRESULT hr;
167 hr = vss_ctx.pVssbc->GetWriterMetadataCount(&cWriters);
168 if (FAILED(hr)) {
169 err_set(errset, hr, "failed to get writer metadata count");
170 goto out;
173 for (i = 0; i < cWriters; i++) {
174 hr = vss_ctx.pVssbc->GetWriterMetadata(i, &id, pMetadata.replace());
175 if (FAILED(hr)) {
176 err_set(errset, hr, "failed to get writer metadata of %d/%d",
177 i, cWriters);
178 goto out;
181 hr = pMetadata->GetIdentity(&idInstance, &idWriter,
182 &bstrWriterName, &usage, &source);
183 if (FAILED(hr)) {
184 err_set(errset, hr, "failed to get identity of writer %d/%d",
185 i, cWriters);
186 goto out;
189 hr = pMetadata->GetFileCounts(&c1, &c2, &cComponents);
190 if (FAILED(hr)) {
191 err_set(errset, hr, "failed to get file counts of %S",
192 bstrWriterName);
193 goto out;
196 for (j = 0; j < cComponents; j++) {
197 hr = pMetadata->GetComponent(j, pComponent.replace());
198 if (FAILED(hr)) {
199 err_set(errset, hr,
200 "failed to get component %d/%d of %S",
201 j, cComponents, bstrWriterName);
202 goto out;
205 hr = pComponent->GetComponentInfo(&info);
206 if (FAILED(hr)) {
207 err_set(errset, hr,
208 "failed to get component info %d/%d of %S",
209 j, cComponents, bstrWriterName);
210 goto out;
213 if (info->bSelectable) {
214 hr = vss_ctx.pVssbc->AddComponent(idInstance, idWriter,
215 info->type,
216 info->bstrLogicalPath,
217 info->bstrComponentName);
218 if (FAILED(hr)) {
219 err_set(errset, hr, "failed to add component %S(%S)",
220 info->bstrComponentName, bstrWriterName);
221 goto out;
224 SysFreeString(bstrWriterName);
225 bstrWriterName = NULL;
226 pComponent->FreeComponentInfo(info);
227 info = NULL;
230 out:
231 if (bstrWriterName) {
232 SysFreeString(bstrWriterName);
234 if (pComponent && info) {
235 pComponent->FreeComponentInfo(info);
239 DWORD get_reg_dword_value(HKEY baseKey, LPCSTR subKey, LPCSTR valueName,
240 DWORD defaultData)
242 DWORD regGetValueError;
243 DWORD dwordData;
244 DWORD dataSize = sizeof(DWORD);
246 regGetValueError = RegGetValue(baseKey, subKey, valueName, RRF_RT_DWORD,
247 NULL, &dwordData, &dataSize);
248 if (regGetValueError != ERROR_SUCCESS) {
249 return defaultData;
251 return dwordData;
254 bool is_valid_vss_backup_type(VSS_BACKUP_TYPE vssBT)
256 return (vssBT > VSS_BT_UNDEFINED && vssBT < VSS_BT_OTHER);
259 VSS_BACKUP_TYPE get_vss_backup_type(
260 VSS_BACKUP_TYPE defaultVssBT = DEFAULT_VSS_BACKUP_TYPE)
262 VSS_BACKUP_TYPE vssBackupType;
264 vssBackupType = static_cast<VSS_BACKUP_TYPE>(
265 get_reg_dword_value(HKEY_LOCAL_MACHINE,
266 QGA_PROVIDER_REGISTRY_ADDRESS,
267 "VssOption",
268 defaultVssBT));
269 if (!is_valid_vss_backup_type(vssBackupType)) {
270 return defaultVssBT;
272 return vssBackupType;
275 void requester_freeze(int *num_vols, void *mountpoints, ErrorSet *errset)
277 COMPointer<IVssAsync> pAsync;
278 HANDLE volume;
279 HRESULT hr;
280 LONG ctx;
281 GUID guidSnapshotSet = GUID_NULL;
282 SECURITY_DESCRIPTOR sd;
283 SECURITY_ATTRIBUTES sa;
284 WCHAR short_volume_name[64], *display_name = short_volume_name;
285 DWORD wait_status;
286 int num_fixed_drives = 0, i;
287 int num_mount_points = 0;
288 VSS_BACKUP_TYPE vss_bt = get_vss_backup_type();
290 if (vss_ctx.pVssbc) { /* already frozen */
291 *num_vols = 0;
292 return;
295 CoInitialize(NULL);
297 /* Allow unrestricted access to events */
298 InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
299 SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
300 sa.nLength = sizeof(sa);
301 sa.lpSecurityDescriptor = &sd;
302 sa.bInheritHandle = FALSE;
304 vss_ctx.hEventFrozen = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_FROZEN);
305 if (!vss_ctx.hEventFrozen) {
306 err_set(errset, GetLastError(), "failed to create event %s",
307 EVENT_NAME_FROZEN);
308 goto out;
310 vss_ctx.hEventThaw = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_THAW);
311 if (!vss_ctx.hEventThaw) {
312 err_set(errset, GetLastError(), "failed to create event %s",
313 EVENT_NAME_THAW);
314 goto out;
316 vss_ctx.hEventTimeout = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_TIMEOUT);
317 if (!vss_ctx.hEventTimeout) {
318 err_set(errset, GetLastError(), "failed to create event %s",
319 EVENT_NAME_TIMEOUT);
320 goto out;
323 assert(pCreateVssBackupComponents != NULL);
324 hr = pCreateVssBackupComponents(&vss_ctx.pVssbc);
325 if (FAILED(hr)) {
326 err_set(errset, hr, "failed to create VSS backup components");
327 goto out;
330 hr = vss_ctx.pVssbc->InitializeForBackup();
331 if (FAILED(hr)) {
332 err_set(errset, hr, "failed to initialize for backup");
333 goto out;
336 hr = vss_ctx.pVssbc->SetBackupState(true, true, vss_bt, false);
337 if (FAILED(hr)) {
338 err_set(errset, hr, "failed to set backup state");
339 goto out;
343 * Currently writable snapshots are not supported.
344 * To prevent the final commit (which requires to write to snapshots),
345 * ATTR_NO_AUTORECOVERY and ATTR_TRANSPORTABLE are specified here.
347 ctx = VSS_CTX_APP_ROLLBACK | VSS_VOLSNAP_ATTR_TRANSPORTABLE |
348 VSS_VOLSNAP_ATTR_NO_AUTORECOVERY | VSS_VOLSNAP_ATTR_TXF_RECOVERY;
349 hr = vss_ctx.pVssbc->SetContext(ctx);
350 if (hr == (HRESULT)VSS_E_UNSUPPORTED_CONTEXT) {
351 /* Non-server version of Windows doesn't support ATTR_TRANSPORTABLE */
352 ctx &= ~VSS_VOLSNAP_ATTR_TRANSPORTABLE;
353 hr = vss_ctx.pVssbc->SetContext(ctx);
355 if (FAILED(hr)) {
356 err_set(errset, hr, "failed to set backup context");
357 goto out;
360 hr = vss_ctx.pVssbc->GatherWriterMetadata(pAsync.replace());
361 if (SUCCEEDED(hr)) {
362 hr = WaitForAsync(pAsync);
364 if (FAILED(hr)) {
365 err_set(errset, hr, "failed to gather writer metadata");
366 goto out;
369 AddComponents(errset);
370 if (err_is_set(errset)) {
371 goto out;
374 hr = vss_ctx.pVssbc->StartSnapshotSet(&guidSnapshotSet);
375 if (FAILED(hr)) {
376 err_set(errset, hr, "failed to start snapshot set");
377 goto out;
380 if (mountpoints) {
381 PWCHAR volume_name_wchar;
382 for (volList *list = (volList *)mountpoints; list; list = list->next) {
383 size_t len = strlen(list->value) + 1;
384 size_t converted = 0;
385 VSS_ID pid;
387 volume_name_wchar = new wchar_t[len];
388 mbstowcs_s(&converted, volume_name_wchar, len,
389 list->value, _TRUNCATE);
391 hr = vss_ctx.pVssbc->AddToSnapshotSet(volume_name_wchar,
392 g_gProviderId, &pid);
393 if (FAILED(hr)) {
394 err_set(errset, hr, "failed to add %S to snapshot set",
395 volume_name_wchar);
396 delete[] volume_name_wchar;
397 goto out;
399 num_mount_points++;
401 delete[] volume_name_wchar;
404 if (num_mount_points == 0) {
405 /* If there is no valid mount points, just exit. */
406 goto out;
410 if (!mountpoints) {
411 volume = FindFirstVolumeW(short_volume_name, sizeof(short_volume_name));
412 if (volume == INVALID_HANDLE_VALUE) {
413 err_set(errset, hr, "failed to find first volume");
414 goto out;
417 for (;;) {
418 if (GetDriveTypeW(short_volume_name) == DRIVE_FIXED) {
419 VSS_ID pid;
420 hr = vss_ctx.pVssbc->AddToSnapshotSet(short_volume_name,
421 g_gProviderId, &pid);
422 if (FAILED(hr)) {
423 WCHAR volume_path_name[PATH_MAX];
424 if (GetVolumePathNamesForVolumeNameW(
425 short_volume_name, volume_path_name,
426 sizeof(volume_path_name), NULL) &&
427 *volume_path_name) {
428 display_name = volume_path_name;
430 err_set(errset, hr, "failed to add %S to snapshot set",
431 display_name);
432 FindVolumeClose(volume);
433 goto out;
435 num_fixed_drives++;
437 if (!FindNextVolumeW(volume, short_volume_name,
438 sizeof(short_volume_name))) {
439 FindVolumeClose(volume);
440 break;
444 if (num_fixed_drives == 0) {
445 goto out; /* If there is no fixed drive, just exit. */
449 hr = vss_ctx.pVssbc->PrepareForBackup(pAsync.replace());
450 if (SUCCEEDED(hr)) {
451 hr = WaitForAsync(pAsync);
453 if (FAILED(hr)) {
454 err_set(errset, hr, "failed to prepare for backup");
455 goto out;
458 hr = vss_ctx.pVssbc->GatherWriterStatus(pAsync.replace());
459 if (SUCCEEDED(hr)) {
460 hr = WaitForAsync(pAsync);
462 if (FAILED(hr)) {
463 err_set(errset, hr, "failed to gather writer status");
464 goto out;
468 * Start VSS quiescing operations.
469 * CQGAVssProvider::CommitSnapshots will kick vss_ctx.hEventFrozen
470 * after the applications and filesystems are frozen.
472 hr = vss_ctx.pVssbc->DoSnapshotSet(&vss_ctx.pAsyncSnapshot);
473 if (FAILED(hr)) {
474 err_set(errset, hr, "failed to do snapshot set");
475 goto out;
478 /* Need to call QueryStatus several times to make VSS provider progress */
479 for (i = 0; i < VSS_TIMEOUT_FREEZE_MSEC/VSS_TIMEOUT_EVENT_MSEC; i++) {
480 HRESULT hr2 = vss_ctx.pAsyncSnapshot->QueryStatus(&hr, NULL);
481 if (FAILED(hr2)) {
482 err_set(errset, hr, "failed to do snapshot set");
483 goto out;
485 if (hr != VSS_S_ASYNC_PENDING) {
486 err_set(errset, E_FAIL,
487 "DoSnapshotSet exited without Frozen event");
488 goto out;
490 wait_status = WaitForSingleObject(vss_ctx.hEventFrozen,
491 VSS_TIMEOUT_EVENT_MSEC);
492 if (wait_status != WAIT_TIMEOUT) {
493 break;
497 if (wait_status == WAIT_TIMEOUT) {
498 err_set(errset, E_FAIL,
499 "timeout when try to receive Frozen event from VSS provider");
500 /* If we are here, VSS had timeout.
501 * Don't call AbortBackup, just return directly.
503 goto out1;
506 if (wait_status != WAIT_OBJECT_0) {
507 err_set(errset, E_FAIL,
508 "couldn't receive Frozen event from VSS provider");
509 goto out;
512 if (mountpoints) {
513 *num_vols = vss_ctx.cFrozenVols = num_mount_points;
514 } else {
515 *num_vols = vss_ctx.cFrozenVols = num_fixed_drives;
518 return;
520 out:
521 if (vss_ctx.pVssbc) {
522 vss_ctx.pVssbc->AbortBackup();
525 out1:
526 requester_cleanup();
527 CoUninitialize();
531 void requester_thaw(int *num_vols, void *mountpints, ErrorSet *errset)
533 COMPointer<IVssAsync> pAsync;
535 if (!vss_ctx.hEventThaw) {
537 * In this case, DoSnapshotSet is aborted or not started,
538 * and no volumes must be frozen. We return without an error.
540 *num_vols = 0;
541 return;
544 /* Tell the provider that the snapshot is finished. */
545 SetEvent(vss_ctx.hEventThaw);
547 assert(vss_ctx.pVssbc);
548 assert(vss_ctx.pAsyncSnapshot);
550 HRESULT hr = WaitForAsync(vss_ctx.pAsyncSnapshot);
551 switch (hr) {
552 case VSS_S_ASYNC_FINISHED:
553 hr = vss_ctx.pVssbc->BackupComplete(pAsync.replace());
554 if (SUCCEEDED(hr)) {
555 hr = WaitForAsync(pAsync);
557 if (FAILED(hr)) {
558 err_set(errset, hr, "failed to complete backup");
560 break;
562 case (HRESULT)VSS_E_OBJECT_NOT_FOUND:
564 * On Windows earlier than 2008 SP2 which does not support
565 * VSS_VOLSNAP_ATTR_NO_AUTORECOVERY context, the final commit is not
566 * skipped and VSS is aborted by VSS_E_OBJECT_NOT_FOUND. However, as
567 * the system had been frozen until fsfreeze-thaw command was issued,
568 * we ignore this error.
570 vss_ctx.pVssbc->AbortBackup();
571 break;
573 case VSS_E_UNEXPECTED_PROVIDER_ERROR:
574 if (WaitForSingleObject(vss_ctx.hEventTimeout, 0) != WAIT_OBJECT_0) {
575 err_set(errset, hr, "unexpected error in VSS provider");
576 break;
578 /* fall through if hEventTimeout is signaled */
580 case (HRESULT)VSS_E_HOLD_WRITES_TIMEOUT:
581 err_set(errset, hr, "couldn't hold writes: "
582 "fsfreeze is limited up to 10 seconds");
583 break;
585 default:
586 err_set(errset, hr, "failed to do snapshot set");
589 if (err_is_set(errset)) {
590 vss_ctx.pVssbc->AbortBackup();
592 *num_vols = vss_ctx.cFrozenVols;
593 requester_cleanup();
595 CoUninitialize();
596 StopService();