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