xref: /openbmc/qemu/qga/vss-win32/requester.cpp (revision 08e64640357cd9517aa30fd49840f05f0f2ee3a4)
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 
13b39297aeSTomoki Sekiyama #include <stdio.h>
14b39297aeSTomoki Sekiyama #include "vss-common.h"
15b39297aeSTomoki Sekiyama #include "requester.h"
16b39297aeSTomoki Sekiyama #include "assert.h"
17b39297aeSTomoki Sekiyama #include "inc/win2003/vswriter.h"
18b39297aeSTomoki Sekiyama #include "inc/win2003/vsbackup.h"
19b39297aeSTomoki Sekiyama 
20b39297aeSTomoki Sekiyama /* Max wait time for frozen event (VSS can only hold writes for 10 seconds) */
21b39297aeSTomoki Sekiyama #define VSS_TIMEOUT_FREEZE_MSEC 10000
22b39297aeSTomoki Sekiyama 
23b39297aeSTomoki Sekiyama /* Call QueryStatus every 10 ms while waiting for frozen event */
24b39297aeSTomoki Sekiyama #define VSS_TIMEOUT_EVENT_MSEC 10
25b39297aeSTomoki Sekiyama 
26b39297aeSTomoki Sekiyama #define err_set(e, err, fmt, ...) \
27e7cf59e8SMarkus Armbruster     ((e)->error_setg_win32((e)->errp, err, fmt, ## __VA_ARGS__))
28*08e64640SMarkus Armbruster /* Bad idea, works only when (e)->errp != NULL: */
29b39297aeSTomoki Sekiyama #define err_is_set(e) ((e)->errp && *(e)->errp)
30*08e64640SMarkus Armbruster /* To lift this restriction, error_propagate(), like we do in QEMU code */
31b39297aeSTomoki Sekiyama 
32b39297aeSTomoki Sekiyama /* Handle to VSSAPI.DLL */
33b39297aeSTomoki Sekiyama static HMODULE hLib;
34b39297aeSTomoki Sekiyama 
35b39297aeSTomoki Sekiyama /* Functions in VSSAPI.DLL */
36b39297aeSTomoki Sekiyama typedef HRESULT(STDAPICALLTYPE * t_CreateVssBackupComponents)(
37b39297aeSTomoki Sekiyama     OUT IVssBackupComponents**);
38b39297aeSTomoki Sekiyama typedef void(APIENTRY * t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
39b39297aeSTomoki Sekiyama static t_CreateVssBackupComponents pCreateVssBackupComponents;
40b39297aeSTomoki Sekiyama static t_VssFreeSnapshotProperties pVssFreeSnapshotProperties;
41b39297aeSTomoki Sekiyama 
42b39297aeSTomoki Sekiyama /* Variables used while applications and filesystes are frozen by VSS */
43b39297aeSTomoki Sekiyama static struct QGAVSSContext {
44b39297aeSTomoki Sekiyama     IVssBackupComponents *pVssbc;  /* VSS requester interface */
45b39297aeSTomoki Sekiyama     IVssAsync *pAsyncSnapshot;     /* async info of VSS snapshot operation */
46b39297aeSTomoki Sekiyama     HANDLE hEventFrozen;           /* notify fs/writer freeze from provider */
47b39297aeSTomoki Sekiyama     HANDLE hEventThaw;             /* request provider to thaw */
48b39297aeSTomoki Sekiyama     HANDLE hEventTimeout;          /* notify timeout in provider */
49b39297aeSTomoki Sekiyama     int cFrozenVols;               /* number of frozen volumes */
50b39297aeSTomoki Sekiyama } vss_ctx;
51b39297aeSTomoki Sekiyama 
52b39297aeSTomoki Sekiyama STDAPI requester_init(void)
53b39297aeSTomoki Sekiyama {
54b39297aeSTomoki Sekiyama     COMInitializer initializer; /* to call CoInitializeSecurity */
55b39297aeSTomoki Sekiyama     HRESULT hr = CoInitializeSecurity(
56b39297aeSTomoki Sekiyama         NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
57b39297aeSTomoki Sekiyama         RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE, NULL);
58b39297aeSTomoki Sekiyama     if (FAILED(hr)) {
59b39297aeSTomoki Sekiyama         fprintf(stderr, "failed to CoInitializeSecurity (error %lx)\n", hr);
60b39297aeSTomoki Sekiyama         return hr;
61b39297aeSTomoki Sekiyama     }
62b39297aeSTomoki Sekiyama 
63b39297aeSTomoki Sekiyama     hLib = LoadLibraryA("VSSAPI.DLL");
64b39297aeSTomoki Sekiyama     if (!hLib) {
65b39297aeSTomoki Sekiyama         fprintf(stderr, "failed to load VSSAPI.DLL\n");
66b39297aeSTomoki Sekiyama         return HRESULT_FROM_WIN32(GetLastError());
67b39297aeSTomoki Sekiyama     }
68b39297aeSTomoki Sekiyama 
69b39297aeSTomoki Sekiyama     pCreateVssBackupComponents = (t_CreateVssBackupComponents)
70b39297aeSTomoki Sekiyama         GetProcAddress(hLib,
71b39297aeSTomoki Sekiyama #ifdef _WIN64 /* 64bit environment */
72b39297aeSTomoki Sekiyama         "?CreateVssBackupComponents@@YAJPEAPEAVIVssBackupComponents@@@Z"
73b39297aeSTomoki Sekiyama #else /* 32bit environment */
74b39297aeSTomoki Sekiyama         "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
75b39297aeSTomoki Sekiyama #endif
76b39297aeSTomoki Sekiyama         );
77b39297aeSTomoki Sekiyama     if (!pCreateVssBackupComponents) {
78b39297aeSTomoki Sekiyama         fprintf(stderr, "failed to get proc address from VSSAPI.DLL\n");
79b39297aeSTomoki Sekiyama         return HRESULT_FROM_WIN32(GetLastError());
80b39297aeSTomoki Sekiyama     }
81b39297aeSTomoki Sekiyama 
82b39297aeSTomoki Sekiyama     pVssFreeSnapshotProperties = (t_VssFreeSnapshotProperties)
83b39297aeSTomoki Sekiyama         GetProcAddress(hLib, "VssFreeSnapshotProperties");
84b39297aeSTomoki Sekiyama     if (!pVssFreeSnapshotProperties) {
85b39297aeSTomoki Sekiyama         fprintf(stderr, "failed to get proc address from VSSAPI.DLL\n");
86b39297aeSTomoki Sekiyama         return HRESULT_FROM_WIN32(GetLastError());
87b39297aeSTomoki Sekiyama     }
88b39297aeSTomoki Sekiyama 
89b39297aeSTomoki Sekiyama     return S_OK;
90b39297aeSTomoki Sekiyama }
91b39297aeSTomoki Sekiyama 
92b39297aeSTomoki Sekiyama static void requester_cleanup(void)
93b39297aeSTomoki Sekiyama {
944c1b8f1eSTomoki Sekiyama     if (vss_ctx.hEventFrozen) {
95b39297aeSTomoki Sekiyama         CloseHandle(vss_ctx.hEventFrozen);
964c1b8f1eSTomoki Sekiyama         vss_ctx.hEventFrozen = NULL;
97b39297aeSTomoki Sekiyama     }
984c1b8f1eSTomoki Sekiyama     if (vss_ctx.hEventThaw) {
99b39297aeSTomoki Sekiyama         CloseHandle(vss_ctx.hEventThaw);
1004c1b8f1eSTomoki Sekiyama         vss_ctx.hEventThaw = NULL;
101b39297aeSTomoki Sekiyama     }
1024c1b8f1eSTomoki Sekiyama     if (vss_ctx.hEventTimeout) {
103b39297aeSTomoki Sekiyama         CloseHandle(vss_ctx.hEventTimeout);
1044c1b8f1eSTomoki Sekiyama         vss_ctx.hEventTimeout = NULL;
105b39297aeSTomoki Sekiyama     }
106b39297aeSTomoki Sekiyama     if (vss_ctx.pAsyncSnapshot) {
107b39297aeSTomoki Sekiyama         vss_ctx.pAsyncSnapshot->Release();
108b39297aeSTomoki Sekiyama         vss_ctx.pAsyncSnapshot = NULL;
109b39297aeSTomoki Sekiyama     }
110b39297aeSTomoki Sekiyama     if (vss_ctx.pVssbc) {
111b39297aeSTomoki Sekiyama         vss_ctx.pVssbc->Release();
112b39297aeSTomoki Sekiyama         vss_ctx.pVssbc = NULL;
113b39297aeSTomoki Sekiyama     }
114b39297aeSTomoki Sekiyama     vss_ctx.cFrozenVols = 0;
115b39297aeSTomoki Sekiyama }
116b39297aeSTomoki Sekiyama 
117b39297aeSTomoki Sekiyama STDAPI requester_deinit(void)
118b39297aeSTomoki Sekiyama {
119b39297aeSTomoki Sekiyama     requester_cleanup();
120b39297aeSTomoki Sekiyama 
121b39297aeSTomoki Sekiyama     pCreateVssBackupComponents = NULL;
122b39297aeSTomoki Sekiyama     pVssFreeSnapshotProperties = NULL;
123b39297aeSTomoki Sekiyama     if (hLib) {
124b39297aeSTomoki Sekiyama         FreeLibrary(hLib);
125b39297aeSTomoki Sekiyama         hLib = NULL;
126b39297aeSTomoki Sekiyama     }
127b39297aeSTomoki Sekiyama 
128b39297aeSTomoki Sekiyama     return S_OK;
129b39297aeSTomoki Sekiyama }
130b39297aeSTomoki Sekiyama 
131b39297aeSTomoki Sekiyama static HRESULT WaitForAsync(IVssAsync *pAsync)
132b39297aeSTomoki Sekiyama {
133b39297aeSTomoki Sekiyama     HRESULT ret, hr;
134b39297aeSTomoki Sekiyama 
135b39297aeSTomoki Sekiyama     do {
136b39297aeSTomoki Sekiyama         hr = pAsync->Wait();
137b39297aeSTomoki Sekiyama         if (FAILED(hr)) {
138b39297aeSTomoki Sekiyama             ret = hr;
139b39297aeSTomoki Sekiyama             break;
140b39297aeSTomoki Sekiyama         }
141b39297aeSTomoki Sekiyama         hr = pAsync->QueryStatus(&ret, NULL);
142b39297aeSTomoki Sekiyama         if (FAILED(hr)) {
143b39297aeSTomoki Sekiyama             ret = hr;
144b39297aeSTomoki Sekiyama             break;
145b39297aeSTomoki Sekiyama         }
146b39297aeSTomoki Sekiyama     } while (ret == VSS_S_ASYNC_PENDING);
147b39297aeSTomoki Sekiyama 
148b39297aeSTomoki Sekiyama     return ret;
149b39297aeSTomoki Sekiyama }
150b39297aeSTomoki Sekiyama 
151b39297aeSTomoki Sekiyama static void AddComponents(ErrorSet *errset)
152b39297aeSTomoki Sekiyama {
153b39297aeSTomoki Sekiyama     unsigned int cWriters, i;
154b39297aeSTomoki Sekiyama     VSS_ID id, idInstance, idWriter;
155b39297aeSTomoki Sekiyama     BSTR bstrWriterName = NULL;
156b39297aeSTomoki Sekiyama     VSS_USAGE_TYPE usage;
157b39297aeSTomoki Sekiyama     VSS_SOURCE_TYPE source;
158b39297aeSTomoki Sekiyama     unsigned int cComponents, c1, c2, j;
159b39297aeSTomoki Sekiyama     COMPointer<IVssExamineWriterMetadata> pMetadata;
160b39297aeSTomoki Sekiyama     COMPointer<IVssWMComponent> pComponent;
161b39297aeSTomoki Sekiyama     PVSSCOMPONENTINFO info;
162b39297aeSTomoki Sekiyama     HRESULT hr;
163b39297aeSTomoki Sekiyama 
164b39297aeSTomoki Sekiyama     hr = vss_ctx.pVssbc->GetWriterMetadataCount(&cWriters);
165b39297aeSTomoki Sekiyama     if (FAILED(hr)) {
166b39297aeSTomoki Sekiyama         err_set(errset, hr, "failed to get writer metadata count");
167b39297aeSTomoki Sekiyama         goto out;
168b39297aeSTomoki Sekiyama     }
169b39297aeSTomoki Sekiyama 
170b39297aeSTomoki Sekiyama     for (i = 0; i < cWriters; i++) {
171b39297aeSTomoki Sekiyama         hr = vss_ctx.pVssbc->GetWriterMetadata(i, &id, pMetadata.replace());
172b39297aeSTomoki Sekiyama         if (FAILED(hr)) {
173b39297aeSTomoki Sekiyama             err_set(errset, hr, "failed to get writer metadata of %d/%d",
174b39297aeSTomoki Sekiyama                              i, cWriters);
175b39297aeSTomoki Sekiyama             goto out;
176b39297aeSTomoki Sekiyama         }
177b39297aeSTomoki Sekiyama 
178b39297aeSTomoki Sekiyama         hr = pMetadata->GetIdentity(&idInstance, &idWriter,
179b39297aeSTomoki Sekiyama                                     &bstrWriterName, &usage, &source);
180b39297aeSTomoki Sekiyama         if (FAILED(hr)) {
181b39297aeSTomoki Sekiyama             err_set(errset, hr, "failed to get identity of writer %d/%d",
182b39297aeSTomoki Sekiyama                              i, cWriters);
183b39297aeSTomoki Sekiyama             goto out;
184b39297aeSTomoki Sekiyama         }
185b39297aeSTomoki Sekiyama 
186b39297aeSTomoki Sekiyama         hr = pMetadata->GetFileCounts(&c1, &c2, &cComponents);
187b39297aeSTomoki Sekiyama         if (FAILED(hr)) {
188b39297aeSTomoki Sekiyama             err_set(errset, hr, "failed to get file counts of %S",
189b39297aeSTomoki Sekiyama                              bstrWriterName);
190b39297aeSTomoki Sekiyama             goto out;
191b39297aeSTomoki Sekiyama         }
192b39297aeSTomoki Sekiyama 
193b39297aeSTomoki Sekiyama         for (j = 0; j < cComponents; j++) {
194b39297aeSTomoki Sekiyama             hr = pMetadata->GetComponent(j, pComponent.replace());
195b39297aeSTomoki Sekiyama             if (FAILED(hr)) {
196b39297aeSTomoki Sekiyama                 err_set(errset, hr,
197b39297aeSTomoki Sekiyama                                  "failed to get component %d/%d of %S",
198b39297aeSTomoki Sekiyama                                  j, cComponents, bstrWriterName);
199b39297aeSTomoki Sekiyama                 goto out;
200b39297aeSTomoki Sekiyama             }
201b39297aeSTomoki Sekiyama 
202b39297aeSTomoki Sekiyama             hr = pComponent->GetComponentInfo(&info);
203b39297aeSTomoki Sekiyama             if (FAILED(hr)) {
204b39297aeSTomoki Sekiyama                 err_set(errset, hr,
205b39297aeSTomoki Sekiyama                                  "failed to get component info %d/%d of %S",
206b39297aeSTomoki Sekiyama                                  j, cComponents, bstrWriterName);
207b39297aeSTomoki Sekiyama                 goto out;
208b39297aeSTomoki Sekiyama             }
209b39297aeSTomoki Sekiyama 
210b39297aeSTomoki Sekiyama             if (info->bSelectable) {
211b39297aeSTomoki Sekiyama                 hr = vss_ctx.pVssbc->AddComponent(idInstance, idWriter,
212b39297aeSTomoki Sekiyama                                                   info->type,
213b39297aeSTomoki Sekiyama                                                   info->bstrLogicalPath,
214b39297aeSTomoki Sekiyama                                                   info->bstrComponentName);
215b39297aeSTomoki Sekiyama                 if (FAILED(hr)) {
216b39297aeSTomoki Sekiyama                     err_set(errset, hr, "failed to add component %S(%S)",
217b39297aeSTomoki Sekiyama                                      info->bstrComponentName, bstrWriterName);
218b39297aeSTomoki Sekiyama                     goto out;
219b39297aeSTomoki Sekiyama                 }
220b39297aeSTomoki Sekiyama             }
221b39297aeSTomoki Sekiyama             SysFreeString(bstrWriterName);
222b39297aeSTomoki Sekiyama             bstrWriterName = NULL;
223b39297aeSTomoki Sekiyama             pComponent->FreeComponentInfo(info);
224b39297aeSTomoki Sekiyama             info = NULL;
225b39297aeSTomoki Sekiyama         }
226b39297aeSTomoki Sekiyama     }
227b39297aeSTomoki Sekiyama out:
228b39297aeSTomoki Sekiyama     if (bstrWriterName) {
229b39297aeSTomoki Sekiyama         SysFreeString(bstrWriterName);
230b39297aeSTomoki Sekiyama     }
231b39297aeSTomoki Sekiyama     if (pComponent && info) {
232b39297aeSTomoki Sekiyama         pComponent->FreeComponentInfo(info);
233b39297aeSTomoki Sekiyama     }
234b39297aeSTomoki Sekiyama }
235b39297aeSTomoki Sekiyama 
236b39297aeSTomoki Sekiyama void requester_freeze(int *num_vols, ErrorSet *errset)
237b39297aeSTomoki Sekiyama {
238b39297aeSTomoki Sekiyama     COMPointer<IVssAsync> pAsync;
239b39297aeSTomoki Sekiyama     HANDLE volume;
240b39297aeSTomoki Sekiyama     HRESULT hr;
241b39297aeSTomoki Sekiyama     LONG ctx;
242b39297aeSTomoki Sekiyama     GUID guidSnapshotSet = GUID_NULL;
243b39297aeSTomoki Sekiyama     SECURITY_DESCRIPTOR sd;
244b39297aeSTomoki Sekiyama     SECURITY_ATTRIBUTES sa;
245b39297aeSTomoki Sekiyama     WCHAR short_volume_name[64], *display_name = short_volume_name;
246b39297aeSTomoki Sekiyama     DWORD wait_status;
247b39297aeSTomoki Sekiyama     int num_fixed_drives = 0, i;
248b39297aeSTomoki Sekiyama 
249b39297aeSTomoki Sekiyama     if (vss_ctx.pVssbc) { /* already frozen */
250b39297aeSTomoki Sekiyama         *num_vols = 0;
251b39297aeSTomoki Sekiyama         return;
252b39297aeSTomoki Sekiyama     }
253b39297aeSTomoki Sekiyama 
254b39297aeSTomoki Sekiyama     CoInitialize(NULL);
255b39297aeSTomoki Sekiyama 
256ff8adbcfSTomoki Sekiyama     /* Allow unrestricted access to events */
257ff8adbcfSTomoki Sekiyama     InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
258ff8adbcfSTomoki Sekiyama     SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
259ff8adbcfSTomoki Sekiyama     sa.nLength = sizeof(sa);
260ff8adbcfSTomoki Sekiyama     sa.lpSecurityDescriptor = &sd;
261ff8adbcfSTomoki Sekiyama     sa.bInheritHandle = FALSE;
262ff8adbcfSTomoki Sekiyama 
263ff8adbcfSTomoki Sekiyama     vss_ctx.hEventFrozen = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_FROZEN);
264ff8adbcfSTomoki Sekiyama     if (!vss_ctx.hEventFrozen) {
265ff8adbcfSTomoki Sekiyama         err_set(errset, GetLastError(), "failed to create event %s",
266ff8adbcfSTomoki Sekiyama                 EVENT_NAME_FROZEN);
267ff8adbcfSTomoki Sekiyama         goto out;
268ff8adbcfSTomoki Sekiyama     }
269ff8adbcfSTomoki Sekiyama     vss_ctx.hEventThaw = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_THAW);
270ff8adbcfSTomoki Sekiyama     if (!vss_ctx.hEventThaw) {
271ff8adbcfSTomoki Sekiyama         err_set(errset, GetLastError(), "failed to create event %s",
272ff8adbcfSTomoki Sekiyama                 EVENT_NAME_THAW);
273ff8adbcfSTomoki Sekiyama         goto out;
274ff8adbcfSTomoki Sekiyama     }
275ff8adbcfSTomoki Sekiyama     vss_ctx.hEventTimeout = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_TIMEOUT);
276ff8adbcfSTomoki Sekiyama     if (!vss_ctx.hEventTimeout) {
277ff8adbcfSTomoki Sekiyama         err_set(errset, GetLastError(), "failed to create event %s",
278ff8adbcfSTomoki Sekiyama                 EVENT_NAME_TIMEOUT);
279ff8adbcfSTomoki Sekiyama         goto out;
280ff8adbcfSTomoki Sekiyama     }
281ff8adbcfSTomoki Sekiyama 
282b39297aeSTomoki Sekiyama     assert(pCreateVssBackupComponents != NULL);
283b39297aeSTomoki Sekiyama     hr = pCreateVssBackupComponents(&vss_ctx.pVssbc);
284b39297aeSTomoki Sekiyama     if (FAILED(hr)) {
285b39297aeSTomoki Sekiyama         err_set(errset, hr, "failed to create VSS backup components");
286b39297aeSTomoki Sekiyama         goto out;
287b39297aeSTomoki Sekiyama     }
288b39297aeSTomoki Sekiyama 
289b39297aeSTomoki Sekiyama     hr = vss_ctx.pVssbc->InitializeForBackup();
290b39297aeSTomoki Sekiyama     if (FAILED(hr)) {
291b39297aeSTomoki Sekiyama         err_set(errset, hr, "failed to initialize for backup");
292b39297aeSTomoki Sekiyama         goto out;
293b39297aeSTomoki Sekiyama     }
294b39297aeSTomoki Sekiyama 
295b39297aeSTomoki Sekiyama     hr = vss_ctx.pVssbc->SetBackupState(true, true, VSS_BT_FULL, false);
296b39297aeSTomoki Sekiyama     if (FAILED(hr)) {
297b39297aeSTomoki Sekiyama         err_set(errset, hr, "failed to set backup state");
298b39297aeSTomoki Sekiyama         goto out;
299b39297aeSTomoki Sekiyama     }
300b39297aeSTomoki Sekiyama 
301b39297aeSTomoki Sekiyama     /*
302b39297aeSTomoki Sekiyama      * Currently writable snapshots are not supported.
303b39297aeSTomoki Sekiyama      * To prevent the final commit (which requires to write to snapshots),
304b39297aeSTomoki Sekiyama      * ATTR_NO_AUTORECOVERY and ATTR_TRANSPORTABLE are specified here.
305b39297aeSTomoki Sekiyama      */
306b39297aeSTomoki Sekiyama     ctx = VSS_CTX_APP_ROLLBACK | VSS_VOLSNAP_ATTR_TRANSPORTABLE |
307b39297aeSTomoki Sekiyama         VSS_VOLSNAP_ATTR_NO_AUTORECOVERY | VSS_VOLSNAP_ATTR_TXF_RECOVERY;
308b39297aeSTomoki Sekiyama     hr = vss_ctx.pVssbc->SetContext(ctx);
309b39297aeSTomoki Sekiyama     if (hr == (HRESULT)VSS_E_UNSUPPORTED_CONTEXT) {
310b39297aeSTomoki Sekiyama         /* Non-server version of Windows doesn't support ATTR_TRANSPORTABLE */
311b39297aeSTomoki Sekiyama         ctx &= ~VSS_VOLSNAP_ATTR_TRANSPORTABLE;
312b39297aeSTomoki Sekiyama         hr = vss_ctx.pVssbc->SetContext(ctx);
313b39297aeSTomoki Sekiyama     }
314b39297aeSTomoki Sekiyama     if (FAILED(hr)) {
315b39297aeSTomoki Sekiyama         err_set(errset, hr, "failed to set backup context");
316b39297aeSTomoki Sekiyama         goto out;
317b39297aeSTomoki Sekiyama     }
318b39297aeSTomoki Sekiyama 
319b39297aeSTomoki Sekiyama     hr = vss_ctx.pVssbc->GatherWriterMetadata(pAsync.replace());
320b39297aeSTomoki Sekiyama     if (SUCCEEDED(hr)) {
321b39297aeSTomoki Sekiyama         hr = WaitForAsync(pAsync);
322b39297aeSTomoki Sekiyama     }
323b39297aeSTomoki Sekiyama     if (FAILED(hr)) {
324b39297aeSTomoki Sekiyama         err_set(errset, hr, "failed to gather writer metadata");
325b39297aeSTomoki Sekiyama         goto out;
326b39297aeSTomoki Sekiyama     }
327b39297aeSTomoki Sekiyama 
328b39297aeSTomoki Sekiyama     AddComponents(errset);
329b39297aeSTomoki Sekiyama     if (err_is_set(errset)) {
330b39297aeSTomoki Sekiyama         goto out;
331b39297aeSTomoki Sekiyama     }
332b39297aeSTomoki Sekiyama 
333b39297aeSTomoki Sekiyama     hr = vss_ctx.pVssbc->StartSnapshotSet(&guidSnapshotSet);
334b39297aeSTomoki Sekiyama     if (FAILED(hr)) {
335b39297aeSTomoki Sekiyama         err_set(errset, hr, "failed to start snapshot set");
336b39297aeSTomoki Sekiyama         goto out;
337b39297aeSTomoki Sekiyama     }
338b39297aeSTomoki Sekiyama 
339b39297aeSTomoki Sekiyama     volume = FindFirstVolumeW(short_volume_name, sizeof(short_volume_name));
340b39297aeSTomoki Sekiyama     if (volume == INVALID_HANDLE_VALUE) {
341b39297aeSTomoki Sekiyama         err_set(errset, hr, "failed to find first volume");
342b39297aeSTomoki Sekiyama         goto out;
343b39297aeSTomoki Sekiyama     }
344b39297aeSTomoki Sekiyama     for (;;) {
345b39297aeSTomoki Sekiyama         if (GetDriveTypeW(short_volume_name) == DRIVE_FIXED) {
346b39297aeSTomoki Sekiyama             VSS_ID pid;
347b39297aeSTomoki Sekiyama             hr = vss_ctx.pVssbc->AddToSnapshotSet(short_volume_name,
348b39297aeSTomoki Sekiyama                                                   g_gProviderId, &pid);
349b39297aeSTomoki Sekiyama             if (FAILED(hr)) {
350b39297aeSTomoki Sekiyama                 WCHAR volume_path_name[PATH_MAX];
351b39297aeSTomoki Sekiyama                 if (GetVolumePathNamesForVolumeNameW(
352b39297aeSTomoki Sekiyama                         short_volume_name, volume_path_name,
353b39297aeSTomoki Sekiyama                         sizeof(volume_path_name), NULL) && *volume_path_name) {
354b39297aeSTomoki Sekiyama                     display_name = volume_path_name;
355b39297aeSTomoki Sekiyama                 }
356b39297aeSTomoki Sekiyama                 err_set(errset, hr, "failed to add %S to snapshot set",
357b39297aeSTomoki Sekiyama                                  display_name);
358b39297aeSTomoki Sekiyama                 FindVolumeClose(volume);
359b39297aeSTomoki Sekiyama                 goto out;
360b39297aeSTomoki Sekiyama             }
361b39297aeSTomoki Sekiyama             num_fixed_drives++;
362b39297aeSTomoki Sekiyama         }
363b39297aeSTomoki Sekiyama         if (!FindNextVolumeW(volume, short_volume_name,
364b39297aeSTomoki Sekiyama                              sizeof(short_volume_name))) {
365b39297aeSTomoki Sekiyama             FindVolumeClose(volume);
366b39297aeSTomoki Sekiyama             break;
367b39297aeSTomoki Sekiyama         }
368b39297aeSTomoki Sekiyama     }
369b39297aeSTomoki Sekiyama 
370b39297aeSTomoki Sekiyama     if (num_fixed_drives == 0) {
371b39297aeSTomoki Sekiyama         goto out; /* If there is no fixed drive, just exit. */
372b39297aeSTomoki Sekiyama     }
373b39297aeSTomoki Sekiyama 
374b39297aeSTomoki Sekiyama     hr = vss_ctx.pVssbc->PrepareForBackup(pAsync.replace());
375b39297aeSTomoki Sekiyama     if (SUCCEEDED(hr)) {
376b39297aeSTomoki Sekiyama         hr = WaitForAsync(pAsync);
377b39297aeSTomoki Sekiyama     }
378b39297aeSTomoki Sekiyama     if (FAILED(hr)) {
379b39297aeSTomoki Sekiyama         err_set(errset, hr, "failed to prepare for backup");
380b39297aeSTomoki Sekiyama         goto out;
381b39297aeSTomoki Sekiyama     }
382b39297aeSTomoki Sekiyama 
383b39297aeSTomoki Sekiyama     hr = vss_ctx.pVssbc->GatherWriterStatus(pAsync.replace());
384b39297aeSTomoki Sekiyama     if (SUCCEEDED(hr)) {
385b39297aeSTomoki Sekiyama         hr = WaitForAsync(pAsync);
386b39297aeSTomoki Sekiyama     }
387b39297aeSTomoki Sekiyama     if (FAILED(hr)) {
388b39297aeSTomoki Sekiyama         err_set(errset, hr, "failed to gather writer status");
389b39297aeSTomoki Sekiyama         goto out;
390b39297aeSTomoki Sekiyama     }
391b39297aeSTomoki Sekiyama 
392b39297aeSTomoki Sekiyama     /*
393b39297aeSTomoki Sekiyama      * Start VSS quiescing operations.
394b39297aeSTomoki Sekiyama      * CQGAVssProvider::CommitSnapshots will kick vss_ctx.hEventFrozen
395b39297aeSTomoki Sekiyama      * after the applications and filesystems are frozen.
396b39297aeSTomoki Sekiyama      */
397b39297aeSTomoki Sekiyama     hr = vss_ctx.pVssbc->DoSnapshotSet(&vss_ctx.pAsyncSnapshot);
398b39297aeSTomoki Sekiyama     if (FAILED(hr)) {
399b39297aeSTomoki Sekiyama         err_set(errset, hr, "failed to do snapshot set");
400b39297aeSTomoki Sekiyama         goto out;
401b39297aeSTomoki Sekiyama     }
402b39297aeSTomoki Sekiyama 
403b39297aeSTomoki Sekiyama     /* Need to call QueryStatus several times to make VSS provider progress */
404b39297aeSTomoki Sekiyama     for (i = 0; i < VSS_TIMEOUT_FREEZE_MSEC/VSS_TIMEOUT_EVENT_MSEC; i++) {
405b39297aeSTomoki Sekiyama         HRESULT hr2 = vss_ctx.pAsyncSnapshot->QueryStatus(&hr, NULL);
406b39297aeSTomoki Sekiyama         if (FAILED(hr2)) {
407b39297aeSTomoki Sekiyama             err_set(errset, hr, "failed to do snapshot set");
408b39297aeSTomoki Sekiyama             goto out;
409b39297aeSTomoki Sekiyama         }
410b39297aeSTomoki Sekiyama         if (hr != VSS_S_ASYNC_PENDING) {
411b39297aeSTomoki Sekiyama             err_set(errset, E_FAIL,
412b39297aeSTomoki Sekiyama                     "DoSnapshotSet exited without Frozen event");
413b39297aeSTomoki Sekiyama             goto out;
414b39297aeSTomoki Sekiyama         }
415b39297aeSTomoki Sekiyama         wait_status = WaitForSingleObject(vss_ctx.hEventFrozen,
416b39297aeSTomoki Sekiyama                                           VSS_TIMEOUT_EVENT_MSEC);
417b39297aeSTomoki Sekiyama         if (wait_status != WAIT_TIMEOUT) {
418b39297aeSTomoki Sekiyama             break;
419b39297aeSTomoki Sekiyama         }
420b39297aeSTomoki Sekiyama     }
421b39297aeSTomoki Sekiyama     if (wait_status != WAIT_OBJECT_0) {
422b39297aeSTomoki Sekiyama         err_set(errset, E_FAIL,
423b39297aeSTomoki Sekiyama                 "couldn't receive Frozen event from VSS provider");
424b39297aeSTomoki Sekiyama         goto out;
425b39297aeSTomoki Sekiyama     }
426b39297aeSTomoki Sekiyama 
427b39297aeSTomoki Sekiyama     *num_vols = vss_ctx.cFrozenVols = num_fixed_drives;
428b39297aeSTomoki Sekiyama     return;
429b39297aeSTomoki Sekiyama 
430b39297aeSTomoki Sekiyama out:
431b39297aeSTomoki Sekiyama     if (vss_ctx.pVssbc) {
432b39297aeSTomoki Sekiyama         vss_ctx.pVssbc->AbortBackup();
433b39297aeSTomoki Sekiyama     }
434b39297aeSTomoki Sekiyama     requester_cleanup();
435b39297aeSTomoki Sekiyama     CoUninitialize();
436b39297aeSTomoki Sekiyama }
437b39297aeSTomoki Sekiyama 
438b39297aeSTomoki Sekiyama 
439b39297aeSTomoki Sekiyama void requester_thaw(int *num_vols, ErrorSet *errset)
440b39297aeSTomoki Sekiyama {
441b39297aeSTomoki Sekiyama     COMPointer<IVssAsync> pAsync;
442b39297aeSTomoki Sekiyama 
4434c1b8f1eSTomoki Sekiyama     if (!vss_ctx.hEventThaw) {
444b39297aeSTomoki Sekiyama         /*
445b39297aeSTomoki Sekiyama          * In this case, DoSnapshotSet is aborted or not started,
446b39297aeSTomoki Sekiyama          * and no volumes must be frozen. We return without an error.
447b39297aeSTomoki Sekiyama          */
448b39297aeSTomoki Sekiyama         *num_vols = 0;
449b39297aeSTomoki Sekiyama         return;
450b39297aeSTomoki Sekiyama     }
451b39297aeSTomoki Sekiyama 
452b39297aeSTomoki Sekiyama     /* Tell the provider that the snapshot is finished. */
453b39297aeSTomoki Sekiyama     SetEvent(vss_ctx.hEventThaw);
454b39297aeSTomoki Sekiyama 
455b39297aeSTomoki Sekiyama     assert(vss_ctx.pVssbc);
456b39297aeSTomoki Sekiyama     assert(vss_ctx.pAsyncSnapshot);
457b39297aeSTomoki Sekiyama 
458b39297aeSTomoki Sekiyama     HRESULT hr = WaitForAsync(vss_ctx.pAsyncSnapshot);
459b39297aeSTomoki Sekiyama     switch (hr) {
460b39297aeSTomoki Sekiyama     case VSS_S_ASYNC_FINISHED:
461b39297aeSTomoki Sekiyama         hr = vss_ctx.pVssbc->BackupComplete(pAsync.replace());
462b39297aeSTomoki Sekiyama         if (SUCCEEDED(hr)) {
463b39297aeSTomoki Sekiyama             hr = WaitForAsync(pAsync);
464b39297aeSTomoki Sekiyama         }
465b39297aeSTomoki Sekiyama         if (FAILED(hr)) {
466b39297aeSTomoki Sekiyama             err_set(errset, hr, "failed to complete backup");
467b39297aeSTomoki Sekiyama         }
468b39297aeSTomoki Sekiyama         break;
469b39297aeSTomoki Sekiyama 
470b39297aeSTomoki Sekiyama     case (HRESULT)VSS_E_OBJECT_NOT_FOUND:
471b39297aeSTomoki Sekiyama         /*
472b39297aeSTomoki Sekiyama          * On Windows earlier than 2008 SP2 which does not support
473b39297aeSTomoki Sekiyama          * VSS_VOLSNAP_ATTR_NO_AUTORECOVERY context, the final commit is not
474b39297aeSTomoki Sekiyama          * skipped and VSS is aborted by VSS_E_OBJECT_NOT_FOUND. However, as
475b39297aeSTomoki Sekiyama          * the system had been frozen until fsfreeze-thaw command was issued,
476b39297aeSTomoki Sekiyama          * we ignore this error.
477b39297aeSTomoki Sekiyama          */
478b39297aeSTomoki Sekiyama         vss_ctx.pVssbc->AbortBackup();
479b39297aeSTomoki Sekiyama         break;
480b39297aeSTomoki Sekiyama 
481b39297aeSTomoki Sekiyama     case VSS_E_UNEXPECTED_PROVIDER_ERROR:
482b39297aeSTomoki Sekiyama         if (WaitForSingleObject(vss_ctx.hEventTimeout, 0) != WAIT_OBJECT_0) {
483b39297aeSTomoki Sekiyama             err_set(errset, hr, "unexpected error in VSS provider");
484b39297aeSTomoki Sekiyama             break;
485b39297aeSTomoki Sekiyama         }
486b39297aeSTomoki Sekiyama         /* fall through if hEventTimeout is signaled */
487b39297aeSTomoki Sekiyama 
488b39297aeSTomoki Sekiyama     case (HRESULT)VSS_E_HOLD_WRITES_TIMEOUT:
489b39297aeSTomoki Sekiyama         err_set(errset, hr, "couldn't hold writes: "
490b39297aeSTomoki Sekiyama                 "fsfreeze is limited up to 10 seconds");
491b39297aeSTomoki Sekiyama         break;
492b39297aeSTomoki Sekiyama 
493b39297aeSTomoki Sekiyama     default:
494b39297aeSTomoki Sekiyama         err_set(errset, hr, "failed to do snapshot set");
495b39297aeSTomoki Sekiyama     }
496b39297aeSTomoki Sekiyama 
497b39297aeSTomoki Sekiyama     if (err_is_set(errset)) {
498b39297aeSTomoki Sekiyama         vss_ctx.pVssbc->AbortBackup();
499b39297aeSTomoki Sekiyama     }
500b39297aeSTomoki Sekiyama     *num_vols = vss_ctx.cFrozenVols;
501b39297aeSTomoki Sekiyama     requester_cleanup();
502b39297aeSTomoki Sekiyama 
503b39297aeSTomoki Sekiyama     CoUninitialize();
504b39297aeSTomoki Sekiyama }
505