2 * QEMU Guest Agent win32 VSS Requester implementations
4 * Copyright Hitachi Data Systems Corp. 2013
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.
14 #include "vss-common.h"
15 #include "requester.h"
17 #include "inc/win2003/vswriter.h"
18 #include "inc/win2003/vsbackup.h"
20 /* Max wait time for frozen event (VSS can only hold writes for 10 seconds) */
21 #define VSS_TIMEOUT_FREEZE_MSEC 10000
23 /* Call QueryStatus every 10 ms while waiting for frozen event */
24 #define VSS_TIMEOUT_EVENT_MSEC 10
26 #define err_set(e, err, fmt, ...) \
27 ((e)->error_set((e)->errp, err, (e)->err_class, fmt, ## __VA_ARGS__))
28 #define err_is_set(e) ((e)->errp && *(e)->errp)
31 /* Handle to VSSAPI.DLL */
34 /* Functions in VSSAPI.DLL */
35 typedef HRESULT(STDAPICALLTYPE
* t_CreateVssBackupComponents
)(
36 OUT IVssBackupComponents
**);
37 typedef void(APIENTRY
* t_VssFreeSnapshotProperties
)(IN VSS_SNAPSHOT_PROP
*);
38 static t_CreateVssBackupComponents pCreateVssBackupComponents
;
39 static t_VssFreeSnapshotProperties pVssFreeSnapshotProperties
;
41 /* Variables used while applications and filesystes are frozen by VSS */
42 static struct QGAVSSContext
{
43 IVssBackupComponents
*pVssbc
; /* VSS requester interface */
44 IVssAsync
*pAsyncSnapshot
; /* async info of VSS snapshot operation */
45 HANDLE hEventFrozen
; /* notify fs/writer freeze from provider */
46 HANDLE hEventThaw
; /* request provider to thaw */
47 HANDLE hEventTimeout
; /* notify timeout in provider */
48 int cFrozenVols
; /* number of frozen volumes */
51 STDAPI
requester_init(void)
53 vss_ctx
.hEventFrozen
= INVALID_HANDLE_VALUE
;
54 vss_ctx
.hEventThaw
= INVALID_HANDLE_VALUE
;
55 vss_ctx
.hEventTimeout
= INVALID_HANDLE_VALUE
;
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
);
62 fprintf(stderr
, "failed to CoInitializeSecurity (error %lx)\n", hr
);
66 hLib
= LoadLibraryA("VSSAPI.DLL");
68 fprintf(stderr
, "failed to load VSSAPI.DLL\n");
69 return HRESULT_FROM_WIN32(GetLastError());
72 pCreateVssBackupComponents
= (t_CreateVssBackupComponents
)
74 #ifdef _WIN64 /* 64bit environment */
75 "?CreateVssBackupComponents@@YAJPEAPEAVIVssBackupComponents@@@Z"
76 #else /* 32bit environment */
77 "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
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());
95 static void requester_cleanup(void)
97 if (vss_ctx
.hEventFrozen
!= INVALID_HANDLE_VALUE
) {
98 CloseHandle(vss_ctx
.hEventFrozen
);
99 vss_ctx
.hEventFrozen
= INVALID_HANDLE_VALUE
;
101 if (vss_ctx
.hEventThaw
!= INVALID_HANDLE_VALUE
) {
102 CloseHandle(vss_ctx
.hEventThaw
);
103 vss_ctx
.hEventThaw
= INVALID_HANDLE_VALUE
;
105 if (vss_ctx
.hEventTimeout
!= INVALID_HANDLE_VALUE
) {
106 CloseHandle(vss_ctx
.hEventTimeout
);
107 vss_ctx
.hEventTimeout
= INVALID_HANDLE_VALUE
;
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)
124 pCreateVssBackupComponents
= NULL
;
125 pVssFreeSnapshotProperties
= NULL
;
134 static HRESULT
WaitForAsync(IVssAsync
*pAsync
)
144 hr
= pAsync
->QueryStatus(&ret
, NULL
);
149 } while (ret
== VSS_S_ASYNC_PENDING
);
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
;
167 hr
= vss_ctx
.pVssbc
->GetWriterMetadataCount(&cWriters
);
169 err_set(errset
, hr
, "failed to get writer metadata count");
173 for (i
= 0; i
< cWriters
; i
++) {
174 hr
= vss_ctx
.pVssbc
->GetWriterMetadata(i
, &id
, pMetadata
.replace());
176 err_set(errset
, hr
, "failed to get writer metadata of %d/%d",
181 hr
= pMetadata
->GetIdentity(&idInstance
, &idWriter
,
182 &bstrWriterName
, &usage
, &source
);
184 err_set(errset
, hr
, "failed to get identity of writer %d/%d",
189 hr
= pMetadata
->GetFileCounts(&c1
, &c2
, &cComponents
);
191 err_set(errset
, hr
, "failed to get file counts of %S",
196 for (j
= 0; j
< cComponents
; j
++) {
197 hr
= pMetadata
->GetComponent(j
, pComponent
.replace());
200 "failed to get component %d/%d of %S",
201 j
, cComponents
, bstrWriterName
);
205 hr
= pComponent
->GetComponentInfo(&info
);
208 "failed to get component info %d/%d of %S",
209 j
, cComponents
, bstrWriterName
);
213 if (info
->bSelectable
) {
214 hr
= vss_ctx
.pVssbc
->AddComponent(idInstance
, idWriter
,
216 info
->bstrLogicalPath
,
217 info
->bstrComponentName
);
219 err_set(errset
, hr
, "failed to add component %S(%S)",
220 info
->bstrComponentName
, bstrWriterName
);
224 SysFreeString(bstrWriterName
);
225 bstrWriterName
= NULL
;
226 pComponent
->FreeComponentInfo(info
);
231 if (bstrWriterName
) {
232 SysFreeString(bstrWriterName
);
234 if (pComponent
&& info
) {
235 pComponent
->FreeComponentInfo(info
);
239 void requester_freeze(int *num_vols
, ErrorSet
*errset
)
241 COMPointer
<IVssAsync
> pAsync
;
245 GUID guidSnapshotSet
= GUID_NULL
;
246 SECURITY_DESCRIPTOR sd
;
247 SECURITY_ATTRIBUTES sa
;
248 WCHAR short_volume_name
[64], *display_name
= short_volume_name
;
250 int num_fixed_drives
= 0, i
;
252 if (vss_ctx
.pVssbc
) { /* already frozen */
259 assert(pCreateVssBackupComponents
!= NULL
);
260 hr
= pCreateVssBackupComponents(&vss_ctx
.pVssbc
);
262 err_set(errset
, hr
, "failed to create VSS backup components");
266 hr
= vss_ctx
.pVssbc
->InitializeForBackup();
268 err_set(errset
, hr
, "failed to initialize for backup");
272 hr
= vss_ctx
.pVssbc
->SetBackupState(true, true, VSS_BT_FULL
, false);
274 err_set(errset
, hr
, "failed to set backup state");
279 * Currently writable snapshots are not supported.
280 * To prevent the final commit (which requires to write to snapshots),
281 * ATTR_NO_AUTORECOVERY and ATTR_TRANSPORTABLE are specified here.
283 ctx
= VSS_CTX_APP_ROLLBACK
| VSS_VOLSNAP_ATTR_TRANSPORTABLE
|
284 VSS_VOLSNAP_ATTR_NO_AUTORECOVERY
| VSS_VOLSNAP_ATTR_TXF_RECOVERY
;
285 hr
= vss_ctx
.pVssbc
->SetContext(ctx
);
286 if (hr
== (HRESULT
)VSS_E_UNSUPPORTED_CONTEXT
) {
287 /* Non-server version of Windows doesn't support ATTR_TRANSPORTABLE */
288 ctx
&= ~VSS_VOLSNAP_ATTR_TRANSPORTABLE
;
289 hr
= vss_ctx
.pVssbc
->SetContext(ctx
);
292 err_set(errset
, hr
, "failed to set backup context");
296 hr
= vss_ctx
.pVssbc
->GatherWriterMetadata(pAsync
.replace());
298 hr
= WaitForAsync(pAsync
);
301 err_set(errset
, hr
, "failed to gather writer metadata");
305 AddComponents(errset
);
306 if (err_is_set(errset
)) {
310 hr
= vss_ctx
.pVssbc
->StartSnapshotSet(&guidSnapshotSet
);
312 err_set(errset
, hr
, "failed to start snapshot set");
316 volume
= FindFirstVolumeW(short_volume_name
, sizeof(short_volume_name
));
317 if (volume
== INVALID_HANDLE_VALUE
) {
318 err_set(errset
, hr
, "failed to find first volume");
322 if (GetDriveTypeW(short_volume_name
) == DRIVE_FIXED
) {
324 hr
= vss_ctx
.pVssbc
->AddToSnapshotSet(short_volume_name
,
325 g_gProviderId
, &pid
);
327 WCHAR volume_path_name
[PATH_MAX
];
328 if (GetVolumePathNamesForVolumeNameW(
329 short_volume_name
, volume_path_name
,
330 sizeof(volume_path_name
), NULL
) && *volume_path_name
) {
331 display_name
= volume_path_name
;
333 err_set(errset
, hr
, "failed to add %S to snapshot set",
335 FindVolumeClose(volume
);
340 if (!FindNextVolumeW(volume
, short_volume_name
,
341 sizeof(short_volume_name
))) {
342 FindVolumeClose(volume
);
347 if (num_fixed_drives
== 0) {
348 goto out
; /* If there is no fixed drive, just exit. */
351 hr
= vss_ctx
.pVssbc
->PrepareForBackup(pAsync
.replace());
353 hr
= WaitForAsync(pAsync
);
356 err_set(errset
, hr
, "failed to prepare for backup");
360 hr
= vss_ctx
.pVssbc
->GatherWriterStatus(pAsync
.replace());
362 hr
= WaitForAsync(pAsync
);
365 err_set(errset
, hr
, "failed to gather writer status");
369 /* Allow unrestricted access to events */
370 InitializeSecurityDescriptor(&sd
, SECURITY_DESCRIPTOR_REVISION
);
371 SetSecurityDescriptorDacl(&sd
, TRUE
, NULL
, FALSE
);
372 sa
.nLength
= sizeof(sa
);
373 sa
.lpSecurityDescriptor
= &sd
;
374 sa
.bInheritHandle
= FALSE
;
376 vss_ctx
.hEventFrozen
= CreateEvent(&sa
, TRUE
, FALSE
, EVENT_NAME_FROZEN
);
377 if (vss_ctx
.hEventFrozen
== INVALID_HANDLE_VALUE
) {
378 err_set(errset
, GetLastError(), "failed to create event %s",
382 vss_ctx
.hEventThaw
= CreateEvent(&sa
, TRUE
, FALSE
, EVENT_NAME_THAW
);
383 if (vss_ctx
.hEventThaw
== INVALID_HANDLE_VALUE
) {
384 err_set(errset
, GetLastError(), "failed to create event %s",
388 vss_ctx
.hEventTimeout
= CreateEvent(&sa
, TRUE
, FALSE
, EVENT_NAME_TIMEOUT
);
389 if (vss_ctx
.hEventTimeout
== INVALID_HANDLE_VALUE
) {
390 err_set(errset
, GetLastError(), "failed to create event %s",
396 * Start VSS quiescing operations.
397 * CQGAVssProvider::CommitSnapshots will kick vss_ctx.hEventFrozen
398 * after the applications and filesystems are frozen.
400 hr
= vss_ctx
.pVssbc
->DoSnapshotSet(&vss_ctx
.pAsyncSnapshot
);
402 err_set(errset
, hr
, "failed to do snapshot set");
406 /* Need to call QueryStatus several times to make VSS provider progress */
407 for (i
= 0; i
< VSS_TIMEOUT_FREEZE_MSEC
/VSS_TIMEOUT_EVENT_MSEC
; i
++) {
408 HRESULT hr2
= vss_ctx
.pAsyncSnapshot
->QueryStatus(&hr
, NULL
);
410 err_set(errset
, hr
, "failed to do snapshot set");
413 if (hr
!= VSS_S_ASYNC_PENDING
) {
414 err_set(errset
, E_FAIL
,
415 "DoSnapshotSet exited without Frozen event");
418 wait_status
= WaitForSingleObject(vss_ctx
.hEventFrozen
,
419 VSS_TIMEOUT_EVENT_MSEC
);
420 if (wait_status
!= WAIT_TIMEOUT
) {
424 if (wait_status
!= WAIT_OBJECT_0
) {
425 err_set(errset
, E_FAIL
,
426 "couldn't receive Frozen event from VSS provider");
430 *num_vols
= vss_ctx
.cFrozenVols
= num_fixed_drives
;
434 if (vss_ctx
.pVssbc
) {
435 vss_ctx
.pVssbc
->AbortBackup();
442 void requester_thaw(int *num_vols
, ErrorSet
*errset
)
444 COMPointer
<IVssAsync
> pAsync
;
446 if (vss_ctx
.hEventThaw
== INVALID_HANDLE_VALUE
) {
448 * In this case, DoSnapshotSet is aborted or not started,
449 * and no volumes must be frozen. We return without an error.
455 /* Tell the provider that the snapshot is finished. */
456 SetEvent(vss_ctx
.hEventThaw
);
458 assert(vss_ctx
.pVssbc
);
459 assert(vss_ctx
.pAsyncSnapshot
);
461 HRESULT hr
= WaitForAsync(vss_ctx
.pAsyncSnapshot
);
463 case VSS_S_ASYNC_FINISHED
:
464 hr
= vss_ctx
.pVssbc
->BackupComplete(pAsync
.replace());
466 hr
= WaitForAsync(pAsync
);
469 err_set(errset
, hr
, "failed to complete backup");
473 case (HRESULT
)VSS_E_OBJECT_NOT_FOUND
:
475 * On Windows earlier than 2008 SP2 which does not support
476 * VSS_VOLSNAP_ATTR_NO_AUTORECOVERY context, the final commit is not
477 * skipped and VSS is aborted by VSS_E_OBJECT_NOT_FOUND. However, as
478 * the system had been frozen until fsfreeze-thaw command was issued,
479 * we ignore this error.
481 vss_ctx
.pVssbc
->AbortBackup();
484 case VSS_E_UNEXPECTED_PROVIDER_ERROR
:
485 if (WaitForSingleObject(vss_ctx
.hEventTimeout
, 0) != WAIT_OBJECT_0
) {
486 err_set(errset
, hr
, "unexpected error in VSS provider");
489 /* fall through if hEventTimeout is signaled */
491 case (HRESULT
)VSS_E_HOLD_WRITES_TIMEOUT
:
492 err_set(errset
, hr
, "couldn't hold writes: "
493 "fsfreeze is limited up to 10 seconds");
497 err_set(errset
, hr
, "failed to do snapshot set");
500 if (err_is_set(errset
)) {
501 vss_ctx
.pVssbc
->AbortBackup();
503 *num_vols
= vss_ctx
.cFrozenVols
;