xref: /openbmc/qemu/qga/vss-win32/requester.cpp (revision 2f84cf699460f1182402b250064d12d4ab32ef4d)
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 
13e55eb806SMichael Roth #include "qemu/osdep.h"
14b39297aeSTomoki Sekiyama #include "vss-common.h"
15*2f84cf69SKonstantin Kostiuk #include "vss-debug.h"
16b39297aeSTomoki Sekiyama #include "requester.h"
17f342cc93SSameeh Jubran #include "install.h"
1861fb0bd1SMarc-André Lureau #include <vswriter.h>
1961fb0bd1SMarc-André Lureau #include <vsbackup.h>
20b39297aeSTomoki Sekiyama 
21b39297aeSTomoki Sekiyama /* Max wait time for frozen event (VSS can only hold writes for 10 seconds) */
223d98f9b6SBasil Salman #define VSS_TIMEOUT_FREEZE_MSEC 60000
23b39297aeSTomoki Sekiyama 
24b39297aeSTomoki Sekiyama /* Call QueryStatus every 10 ms while waiting for frozen event */
25b39297aeSTomoki Sekiyama #define VSS_TIMEOUT_EVENT_MSEC 10
26b39297aeSTomoki Sekiyama 
27410542d4SKfir Manor #define DEFAULT_VSS_BACKUP_TYPE VSS_BT_FULL
28410542d4SKfir Manor 
29b39297aeSTomoki Sekiyama #define err_set(e, err, fmt, ...)                                           \
30e55eb806SMichael Roth     ((e)->error_setg_win32_wrapper((e)->errp, __FILE__, __LINE__, __func__, \
311e9b65bbSMarkus Armbruster                                    err, fmt, ## __VA_ARGS__))
3208e64640SMarkus Armbruster /* Bad idea, works only when (e)->errp != NULL: */
33b39297aeSTomoki Sekiyama #define err_is_set(e) ((e)->errp && *(e)->errp)
3408e64640SMarkus Armbruster /* To lift this restriction, error_propagate(), like we do in QEMU code */
35b39297aeSTomoki Sekiyama 
36b39297aeSTomoki Sekiyama /* Handle to VSSAPI.DLL */
37b39297aeSTomoki Sekiyama static HMODULE hLib;
38b39297aeSTomoki Sekiyama 
39b39297aeSTomoki Sekiyama /* Functions in VSSAPI.DLL */
40b39297aeSTomoki Sekiyama typedef HRESULT(STDAPICALLTYPE * t_CreateVssBackupComponents)(
41b39297aeSTomoki Sekiyama     OUT IVssBackupComponents**);
42b39297aeSTomoki Sekiyama typedef void(APIENTRY * t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
43b39297aeSTomoki Sekiyama static t_CreateVssBackupComponents pCreateVssBackupComponents;
44b39297aeSTomoki Sekiyama static t_VssFreeSnapshotProperties pVssFreeSnapshotProperties;
45b39297aeSTomoki Sekiyama 
46b39297aeSTomoki Sekiyama /* Variables used while applications and filesystes are frozen by VSS */
47b39297aeSTomoki Sekiyama static struct QGAVSSContext {
48b39297aeSTomoki Sekiyama     IVssBackupComponents *pVssbc;  /* VSS requester interface */
49b39297aeSTomoki Sekiyama     IVssAsync *pAsyncSnapshot;     /* async info of VSS snapshot operation */
50b39297aeSTomoki Sekiyama     HANDLE hEventFrozen;           /* notify fs/writer freeze from provider */
51b39297aeSTomoki Sekiyama     HANDLE hEventThaw;             /* request provider to thaw */
52b39297aeSTomoki Sekiyama     HANDLE hEventTimeout;          /* notify timeout in provider */
53b39297aeSTomoki Sekiyama     int cFrozenVols;               /* number of frozen volumes */
54b39297aeSTomoki Sekiyama } vss_ctx;
55b39297aeSTomoki Sekiyama 
56b39297aeSTomoki Sekiyama STDAPI requester_init(void)
57b39297aeSTomoki Sekiyama {
58b39297aeSTomoki Sekiyama     COMInitializer initializer; /* to call CoInitializeSecurity */
59b39297aeSTomoki Sekiyama     HRESULT hr = CoInitializeSecurity(
60b39297aeSTomoki Sekiyama         NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
61b39297aeSTomoki Sekiyama         RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE, NULL);
62b39297aeSTomoki Sekiyama     if (FAILED(hr)) {
63*2f84cf69SKonstantin Kostiuk         qga_debug("failed to CoInitializeSecurity (error %lx)", hr);
64b39297aeSTomoki Sekiyama         return hr;
65b39297aeSTomoki Sekiyama     }
66b39297aeSTomoki Sekiyama 
67b39297aeSTomoki Sekiyama     hLib = LoadLibraryA("VSSAPI.DLL");
68b39297aeSTomoki Sekiyama     if (!hLib) {
69*2f84cf69SKonstantin Kostiuk         qga_debug("failed to load VSSAPI.DLL");
70b39297aeSTomoki Sekiyama         return HRESULT_FROM_WIN32(GetLastError());
71b39297aeSTomoki Sekiyama     }
72b39297aeSTomoki Sekiyama 
73b39297aeSTomoki Sekiyama     pCreateVssBackupComponents = (t_CreateVssBackupComponents)
74b39297aeSTomoki Sekiyama         GetProcAddress(hLib,
75b39297aeSTomoki Sekiyama #ifdef _WIN64 /* 64bit environment */
76b39297aeSTomoki Sekiyama         "?CreateVssBackupComponents@@YAJPEAPEAVIVssBackupComponents@@@Z"
77b39297aeSTomoki Sekiyama #else /* 32bit environment */
78b39297aeSTomoki Sekiyama         "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
79b39297aeSTomoki Sekiyama #endif
80b39297aeSTomoki Sekiyama         );
81b39297aeSTomoki Sekiyama     if (!pCreateVssBackupComponents) {
82*2f84cf69SKonstantin Kostiuk         qga_debug("failed to get proc address from VSSAPI.DLL");
83b39297aeSTomoki Sekiyama         return HRESULT_FROM_WIN32(GetLastError());
84b39297aeSTomoki Sekiyama     }
85b39297aeSTomoki Sekiyama 
86b39297aeSTomoki Sekiyama     pVssFreeSnapshotProperties = (t_VssFreeSnapshotProperties)
87b39297aeSTomoki Sekiyama         GetProcAddress(hLib, "VssFreeSnapshotProperties");
88b39297aeSTomoki Sekiyama     if (!pVssFreeSnapshotProperties) {
89*2f84cf69SKonstantin Kostiuk         qga_debug("failed to get proc address from VSSAPI.DLL");
90b39297aeSTomoki Sekiyama         return HRESULT_FROM_WIN32(GetLastError());
91b39297aeSTomoki Sekiyama     }
92b39297aeSTomoki Sekiyama 
93b39297aeSTomoki Sekiyama     return S_OK;
94b39297aeSTomoki Sekiyama }
95b39297aeSTomoki Sekiyama 
96b39297aeSTomoki Sekiyama static void requester_cleanup(void)
97b39297aeSTomoki Sekiyama {
984c1b8f1eSTomoki Sekiyama     if (vss_ctx.hEventFrozen) {
99b39297aeSTomoki Sekiyama         CloseHandle(vss_ctx.hEventFrozen);
1004c1b8f1eSTomoki Sekiyama         vss_ctx.hEventFrozen = NULL;
101b39297aeSTomoki Sekiyama     }
1024c1b8f1eSTomoki Sekiyama     if (vss_ctx.hEventThaw) {
103b39297aeSTomoki Sekiyama         CloseHandle(vss_ctx.hEventThaw);
1044c1b8f1eSTomoki Sekiyama         vss_ctx.hEventThaw = NULL;
105b39297aeSTomoki Sekiyama     }
1064c1b8f1eSTomoki Sekiyama     if (vss_ctx.hEventTimeout) {
107b39297aeSTomoki Sekiyama         CloseHandle(vss_ctx.hEventTimeout);
1084c1b8f1eSTomoki Sekiyama         vss_ctx.hEventTimeout = NULL;
109b39297aeSTomoki Sekiyama     }
110b39297aeSTomoki Sekiyama     if (vss_ctx.pAsyncSnapshot) {
111b39297aeSTomoki Sekiyama         vss_ctx.pAsyncSnapshot->Release();
112b39297aeSTomoki Sekiyama         vss_ctx.pAsyncSnapshot = NULL;
113b39297aeSTomoki Sekiyama     }
114b39297aeSTomoki Sekiyama     if (vss_ctx.pVssbc) {
115b39297aeSTomoki Sekiyama         vss_ctx.pVssbc->Release();
116b39297aeSTomoki Sekiyama         vss_ctx.pVssbc = NULL;
117b39297aeSTomoki Sekiyama     }
118b39297aeSTomoki Sekiyama     vss_ctx.cFrozenVols = 0;
119b39297aeSTomoki Sekiyama }
120b39297aeSTomoki Sekiyama 
121b39297aeSTomoki Sekiyama STDAPI requester_deinit(void)
122b39297aeSTomoki Sekiyama {
123b39297aeSTomoki Sekiyama     requester_cleanup();
124b39297aeSTomoki Sekiyama 
125b39297aeSTomoki Sekiyama     pCreateVssBackupComponents = NULL;
126b39297aeSTomoki Sekiyama     pVssFreeSnapshotProperties = NULL;
127b39297aeSTomoki Sekiyama     if (hLib) {
128b39297aeSTomoki Sekiyama         FreeLibrary(hLib);
129b39297aeSTomoki Sekiyama         hLib = NULL;
130b39297aeSTomoki Sekiyama     }
131b39297aeSTomoki Sekiyama 
132b39297aeSTomoki Sekiyama     return S_OK;
133b39297aeSTomoki Sekiyama }
134b39297aeSTomoki Sekiyama 
135b39297aeSTomoki Sekiyama static HRESULT WaitForAsync(IVssAsync *pAsync)
136b39297aeSTomoki Sekiyama {
137b39297aeSTomoki Sekiyama     HRESULT ret, hr;
138b39297aeSTomoki Sekiyama 
139b39297aeSTomoki Sekiyama     do {
140b39297aeSTomoki Sekiyama         hr = pAsync->Wait();
141b39297aeSTomoki Sekiyama         if (FAILED(hr)) {
142b39297aeSTomoki Sekiyama             ret = hr;
143b39297aeSTomoki Sekiyama             break;
144b39297aeSTomoki Sekiyama         }
145b39297aeSTomoki Sekiyama         hr = pAsync->QueryStatus(&ret, NULL);
146b39297aeSTomoki Sekiyama         if (FAILED(hr)) {
147b39297aeSTomoki Sekiyama             ret = hr;
148b39297aeSTomoki Sekiyama             break;
149b39297aeSTomoki Sekiyama         }
150b39297aeSTomoki Sekiyama     } while (ret == VSS_S_ASYNC_PENDING);
151b39297aeSTomoki Sekiyama 
152b39297aeSTomoki Sekiyama     return ret;
153b39297aeSTomoki Sekiyama }
154b39297aeSTomoki Sekiyama 
155b39297aeSTomoki Sekiyama static void AddComponents(ErrorSet *errset)
156b39297aeSTomoki Sekiyama {
157b39297aeSTomoki Sekiyama     unsigned int cWriters, i;
158b39297aeSTomoki Sekiyama     VSS_ID id, idInstance, idWriter;
159b39297aeSTomoki Sekiyama     BSTR bstrWriterName = NULL;
160b39297aeSTomoki Sekiyama     VSS_USAGE_TYPE usage;
161b39297aeSTomoki Sekiyama     VSS_SOURCE_TYPE source;
162b39297aeSTomoki Sekiyama     unsigned int cComponents, c1, c2, j;
163b39297aeSTomoki Sekiyama     COMPointer<IVssExamineWriterMetadata> pMetadata;
164b39297aeSTomoki Sekiyama     COMPointer<IVssWMComponent> pComponent;
165b39297aeSTomoki Sekiyama     PVSSCOMPONENTINFO info;
166b39297aeSTomoki Sekiyama     HRESULT hr;
167b39297aeSTomoki Sekiyama 
168b39297aeSTomoki Sekiyama     hr = vss_ctx.pVssbc->GetWriterMetadataCount(&cWriters);
169b39297aeSTomoki Sekiyama     if (FAILED(hr)) {
170b39297aeSTomoki Sekiyama         err_set(errset, hr, "failed to get writer metadata count");
171b39297aeSTomoki Sekiyama         goto out;
172b39297aeSTomoki Sekiyama     }
173b39297aeSTomoki Sekiyama 
174b39297aeSTomoki Sekiyama     for (i = 0; i < cWriters; i++) {
175b39297aeSTomoki Sekiyama         hr = vss_ctx.pVssbc->GetWriterMetadata(i, &id, pMetadata.replace());
176b39297aeSTomoki Sekiyama         if (FAILED(hr)) {
177b39297aeSTomoki Sekiyama             err_set(errset, hr, "failed to get writer metadata of %d/%d",
178b39297aeSTomoki Sekiyama                              i, cWriters);
179b39297aeSTomoki Sekiyama             goto out;
180b39297aeSTomoki Sekiyama         }
181b39297aeSTomoki Sekiyama 
182b39297aeSTomoki Sekiyama         hr = pMetadata->GetIdentity(&idInstance, &idWriter,
183b39297aeSTomoki Sekiyama                                     &bstrWriterName, &usage, &source);
184b39297aeSTomoki Sekiyama         if (FAILED(hr)) {
185b39297aeSTomoki Sekiyama             err_set(errset, hr, "failed to get identity of writer %d/%d",
186b39297aeSTomoki Sekiyama                              i, cWriters);
187b39297aeSTomoki Sekiyama             goto out;
188b39297aeSTomoki Sekiyama         }
189b39297aeSTomoki Sekiyama 
190b39297aeSTomoki Sekiyama         hr = pMetadata->GetFileCounts(&c1, &c2, &cComponents);
191b39297aeSTomoki Sekiyama         if (FAILED(hr)) {
192b39297aeSTomoki Sekiyama             err_set(errset, hr, "failed to get file counts of %S",
193b39297aeSTomoki Sekiyama                              bstrWriterName);
194b39297aeSTomoki Sekiyama             goto out;
195b39297aeSTomoki Sekiyama         }
196b39297aeSTomoki Sekiyama 
197b39297aeSTomoki Sekiyama         for (j = 0; j < cComponents; j++) {
198b39297aeSTomoki Sekiyama             hr = pMetadata->GetComponent(j, pComponent.replace());
199b39297aeSTomoki Sekiyama             if (FAILED(hr)) {
200b39297aeSTomoki Sekiyama                 err_set(errset, hr,
201b39297aeSTomoki Sekiyama                                  "failed to get component %d/%d of %S",
202b39297aeSTomoki Sekiyama                                  j, cComponents, bstrWriterName);
203b39297aeSTomoki Sekiyama                 goto out;
204b39297aeSTomoki Sekiyama             }
205b39297aeSTomoki Sekiyama 
206b39297aeSTomoki Sekiyama             hr = pComponent->GetComponentInfo(&info);
207b39297aeSTomoki Sekiyama             if (FAILED(hr)) {
208b39297aeSTomoki Sekiyama                 err_set(errset, hr,
209b39297aeSTomoki Sekiyama                                  "failed to get component info %d/%d of %S",
210b39297aeSTomoki Sekiyama                                  j, cComponents, bstrWriterName);
211b39297aeSTomoki Sekiyama                 goto out;
212b39297aeSTomoki Sekiyama             }
213b39297aeSTomoki Sekiyama 
214b39297aeSTomoki Sekiyama             if (info->bSelectable) {
215b39297aeSTomoki Sekiyama                 hr = vss_ctx.pVssbc->AddComponent(idInstance, idWriter,
216b39297aeSTomoki Sekiyama                                                   info->type,
217b39297aeSTomoki Sekiyama                                                   info->bstrLogicalPath,
218b39297aeSTomoki Sekiyama                                                   info->bstrComponentName);
219b39297aeSTomoki Sekiyama                 if (FAILED(hr)) {
220b39297aeSTomoki Sekiyama                     err_set(errset, hr, "failed to add component %S(%S)",
221b39297aeSTomoki Sekiyama                                      info->bstrComponentName, bstrWriterName);
222b39297aeSTomoki Sekiyama                     goto out;
223b39297aeSTomoki Sekiyama                 }
224b39297aeSTomoki Sekiyama             }
225b39297aeSTomoki Sekiyama             SysFreeString(bstrWriterName);
226b39297aeSTomoki Sekiyama             bstrWriterName = NULL;
227b39297aeSTomoki Sekiyama             pComponent->FreeComponentInfo(info);
228b39297aeSTomoki Sekiyama             info = NULL;
229b39297aeSTomoki Sekiyama         }
230b39297aeSTomoki Sekiyama     }
231b39297aeSTomoki Sekiyama out:
232b39297aeSTomoki Sekiyama     if (bstrWriterName) {
233b39297aeSTomoki Sekiyama         SysFreeString(bstrWriterName);
234b39297aeSTomoki Sekiyama     }
235b39297aeSTomoki Sekiyama     if (pComponent && info) {
236b39297aeSTomoki Sekiyama         pComponent->FreeComponentInfo(info);
237b39297aeSTomoki Sekiyama     }
238b39297aeSTomoki Sekiyama }
239b39297aeSTomoki Sekiyama 
240410542d4SKfir Manor DWORD get_reg_dword_value(HKEY baseKey, LPCSTR subKey, LPCSTR valueName,
241410542d4SKfir Manor                           DWORD defaultData)
242410542d4SKfir Manor {
243410542d4SKfir Manor     DWORD regGetValueError;
244410542d4SKfir Manor     DWORD dwordData;
245410542d4SKfir Manor     DWORD dataSize = sizeof(DWORD);
246410542d4SKfir Manor 
247410542d4SKfir Manor     regGetValueError = RegGetValue(baseKey, subKey, valueName, RRF_RT_DWORD,
248410542d4SKfir Manor                                    NULL, &dwordData, &dataSize);
249410542d4SKfir Manor     if (regGetValueError  != ERROR_SUCCESS) {
250410542d4SKfir Manor         return defaultData;
251410542d4SKfir Manor     }
252410542d4SKfir Manor     return dwordData;
253410542d4SKfir Manor }
254410542d4SKfir Manor 
255410542d4SKfir Manor bool is_valid_vss_backup_type(VSS_BACKUP_TYPE vssBT)
256410542d4SKfir Manor {
257410542d4SKfir Manor     return (vssBT > VSS_BT_UNDEFINED && vssBT < VSS_BT_OTHER);
258410542d4SKfir Manor }
259410542d4SKfir Manor 
260410542d4SKfir Manor VSS_BACKUP_TYPE get_vss_backup_type(
261410542d4SKfir Manor     VSS_BACKUP_TYPE defaultVssBT = DEFAULT_VSS_BACKUP_TYPE)
262410542d4SKfir Manor {
263410542d4SKfir Manor     VSS_BACKUP_TYPE vssBackupType;
264410542d4SKfir Manor 
265410542d4SKfir Manor     vssBackupType = static_cast<VSS_BACKUP_TYPE>(
266410542d4SKfir Manor                             get_reg_dword_value(HKEY_LOCAL_MACHINE,
267410542d4SKfir Manor                                                 QGA_PROVIDER_REGISTRY_ADDRESS,
268410542d4SKfir Manor                                                 "VssOption",
269410542d4SKfir Manor                                                 defaultVssBT));
270410542d4SKfir Manor     if (!is_valid_vss_backup_type(vssBackupType)) {
271410542d4SKfir Manor         return defaultVssBT;
272410542d4SKfir Manor     }
273410542d4SKfir Manor     return vssBackupType;
274410542d4SKfir Manor }
275410542d4SKfir Manor 
2760692b03eSChen Hanxiao void requester_freeze(int *num_vols, void *mountpoints, ErrorSet *errset)
277b39297aeSTomoki Sekiyama {
278b39297aeSTomoki Sekiyama     COMPointer<IVssAsync> pAsync;
279b39297aeSTomoki Sekiyama     HANDLE volume;
280b39297aeSTomoki Sekiyama     HRESULT hr;
281b39297aeSTomoki Sekiyama     LONG ctx;
282b39297aeSTomoki Sekiyama     GUID guidSnapshotSet = GUID_NULL;
283b39297aeSTomoki Sekiyama     SECURITY_DESCRIPTOR sd;
284b39297aeSTomoki Sekiyama     SECURITY_ATTRIBUTES sa;
285b39297aeSTomoki Sekiyama     WCHAR short_volume_name[64], *display_name = short_volume_name;
286b39297aeSTomoki Sekiyama     DWORD wait_status;
287b39297aeSTomoki Sekiyama     int num_fixed_drives = 0, i;
2880692b03eSChen Hanxiao     int num_mount_points = 0;
2890961f929SKfir Manor     VSS_BACKUP_TYPE vss_bt = get_vss_backup_type();
290b39297aeSTomoki Sekiyama 
291b39297aeSTomoki Sekiyama     if (vss_ctx.pVssbc) { /* already frozen */
292b39297aeSTomoki Sekiyama         *num_vols = 0;
293b39297aeSTomoki Sekiyama         return;
294b39297aeSTomoki Sekiyama     }
295b39297aeSTomoki Sekiyama 
296b39297aeSTomoki Sekiyama     CoInitialize(NULL);
297b39297aeSTomoki Sekiyama 
298ff8adbcfSTomoki Sekiyama     /* Allow unrestricted access to events */
299ff8adbcfSTomoki Sekiyama     InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
300ff8adbcfSTomoki Sekiyama     SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
301ff8adbcfSTomoki Sekiyama     sa.nLength = sizeof(sa);
302ff8adbcfSTomoki Sekiyama     sa.lpSecurityDescriptor = &sd;
303ff8adbcfSTomoki Sekiyama     sa.bInheritHandle = FALSE;
304ff8adbcfSTomoki Sekiyama 
305ff8adbcfSTomoki Sekiyama     vss_ctx.hEventFrozen = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_FROZEN);
306ff8adbcfSTomoki Sekiyama     if (!vss_ctx.hEventFrozen) {
307ff8adbcfSTomoki Sekiyama         err_set(errset, GetLastError(), "failed to create event %s",
308ff8adbcfSTomoki Sekiyama                 EVENT_NAME_FROZEN);
309ff8adbcfSTomoki Sekiyama         goto out;
310ff8adbcfSTomoki Sekiyama     }
311ff8adbcfSTomoki Sekiyama     vss_ctx.hEventThaw = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_THAW);
312ff8adbcfSTomoki Sekiyama     if (!vss_ctx.hEventThaw) {
313ff8adbcfSTomoki Sekiyama         err_set(errset, GetLastError(), "failed to create event %s",
314ff8adbcfSTomoki Sekiyama                 EVENT_NAME_THAW);
315ff8adbcfSTomoki Sekiyama         goto out;
316ff8adbcfSTomoki Sekiyama     }
317ff8adbcfSTomoki Sekiyama     vss_ctx.hEventTimeout = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_TIMEOUT);
318ff8adbcfSTomoki Sekiyama     if (!vss_ctx.hEventTimeout) {
319ff8adbcfSTomoki Sekiyama         err_set(errset, GetLastError(), "failed to create event %s",
320ff8adbcfSTomoki Sekiyama                 EVENT_NAME_TIMEOUT);
321ff8adbcfSTomoki Sekiyama         goto out;
322ff8adbcfSTomoki Sekiyama     }
323ff8adbcfSTomoki Sekiyama 
324b39297aeSTomoki Sekiyama     assert(pCreateVssBackupComponents != NULL);
325b39297aeSTomoki Sekiyama     hr = pCreateVssBackupComponents(&vss_ctx.pVssbc);
326b39297aeSTomoki Sekiyama     if (FAILED(hr)) {
327b39297aeSTomoki Sekiyama         err_set(errset, hr, "failed to create VSS backup components");
328b39297aeSTomoki Sekiyama         goto out;
329b39297aeSTomoki Sekiyama     }
330b39297aeSTomoki Sekiyama 
331b39297aeSTomoki Sekiyama     hr = vss_ctx.pVssbc->InitializeForBackup();
332b39297aeSTomoki Sekiyama     if (FAILED(hr)) {
333b39297aeSTomoki Sekiyama         err_set(errset, hr, "failed to initialize for backup");
334b39297aeSTomoki Sekiyama         goto out;
335b39297aeSTomoki Sekiyama     }
336b39297aeSTomoki Sekiyama 
3370961f929SKfir Manor     hr = vss_ctx.pVssbc->SetBackupState(true, true, vss_bt, false);
338b39297aeSTomoki Sekiyama     if (FAILED(hr)) {
339b39297aeSTomoki Sekiyama         err_set(errset, hr, "failed to set backup state");
340b39297aeSTomoki Sekiyama         goto out;
341b39297aeSTomoki Sekiyama     }
342b39297aeSTomoki Sekiyama 
343b39297aeSTomoki Sekiyama     /*
344b39297aeSTomoki Sekiyama      * Currently writable snapshots are not supported.
345b39297aeSTomoki Sekiyama      * To prevent the final commit (which requires to write to snapshots),
346b39297aeSTomoki Sekiyama      * ATTR_NO_AUTORECOVERY and ATTR_TRANSPORTABLE are specified here.
347b39297aeSTomoki Sekiyama      */
348b39297aeSTomoki Sekiyama     ctx = VSS_CTX_APP_ROLLBACK | VSS_VOLSNAP_ATTR_TRANSPORTABLE |
349b39297aeSTomoki Sekiyama         VSS_VOLSNAP_ATTR_NO_AUTORECOVERY | VSS_VOLSNAP_ATTR_TXF_RECOVERY;
350b39297aeSTomoki Sekiyama     hr = vss_ctx.pVssbc->SetContext(ctx);
351b39297aeSTomoki Sekiyama     if (hr == (HRESULT)VSS_E_UNSUPPORTED_CONTEXT) {
352b39297aeSTomoki Sekiyama         /* Non-server version of Windows doesn't support ATTR_TRANSPORTABLE */
353b39297aeSTomoki Sekiyama         ctx &= ~VSS_VOLSNAP_ATTR_TRANSPORTABLE;
354b39297aeSTomoki Sekiyama         hr = vss_ctx.pVssbc->SetContext(ctx);
355b39297aeSTomoki Sekiyama     }
356b39297aeSTomoki Sekiyama     if (FAILED(hr)) {
357b39297aeSTomoki Sekiyama         err_set(errset, hr, "failed to set backup context");
358b39297aeSTomoki Sekiyama         goto out;
359b39297aeSTomoki Sekiyama     }
360b39297aeSTomoki Sekiyama 
361b39297aeSTomoki Sekiyama     hr = vss_ctx.pVssbc->GatherWriterMetadata(pAsync.replace());
362b39297aeSTomoki Sekiyama     if (SUCCEEDED(hr)) {
363b39297aeSTomoki Sekiyama         hr = WaitForAsync(pAsync);
364b39297aeSTomoki Sekiyama     }
365b39297aeSTomoki Sekiyama     if (FAILED(hr)) {
366b39297aeSTomoki Sekiyama         err_set(errset, hr, "failed to gather writer metadata");
367b39297aeSTomoki Sekiyama         goto out;
368b39297aeSTomoki Sekiyama     }
369b39297aeSTomoki Sekiyama 
370b39297aeSTomoki Sekiyama     AddComponents(errset);
371b39297aeSTomoki Sekiyama     if (err_is_set(errset)) {
372b39297aeSTomoki Sekiyama         goto out;
373b39297aeSTomoki Sekiyama     }
374b39297aeSTomoki Sekiyama 
375b39297aeSTomoki Sekiyama     hr = vss_ctx.pVssbc->StartSnapshotSet(&guidSnapshotSet);
376b39297aeSTomoki Sekiyama     if (FAILED(hr)) {
377b39297aeSTomoki Sekiyama         err_set(errset, hr, "failed to start snapshot set");
378b39297aeSTomoki Sekiyama         goto out;
379b39297aeSTomoki Sekiyama     }
380b39297aeSTomoki Sekiyama 
3810692b03eSChen Hanxiao     if (mountpoints) {
3820692b03eSChen Hanxiao         PWCHAR volume_name_wchar;
3830692b03eSChen Hanxiao         for (volList *list = (volList *)mountpoints; list; list = list->next) {
3840692b03eSChen Hanxiao             size_t len = strlen(list->value) + 1;
3850692b03eSChen Hanxiao             size_t converted = 0;
3860692b03eSChen Hanxiao             VSS_ID pid;
3870692b03eSChen Hanxiao 
3880692b03eSChen Hanxiao             volume_name_wchar = new wchar_t[len];
3890692b03eSChen Hanxiao             mbstowcs_s(&converted, volume_name_wchar, len,
3900692b03eSChen Hanxiao                        list->value, _TRUNCATE);
3910692b03eSChen Hanxiao 
3920692b03eSChen Hanxiao             hr = vss_ctx.pVssbc->AddToSnapshotSet(volume_name_wchar,
3930692b03eSChen Hanxiao                                                   g_gProviderId, &pid);
3940692b03eSChen Hanxiao             if (FAILED(hr)) {
3950692b03eSChen Hanxiao                 err_set(errset, hr, "failed to add %S to snapshot set",
3960692b03eSChen Hanxiao                         volume_name_wchar);
3976c1d88c7SKonstantin Kostiuk                 delete[] volume_name_wchar;
3980692b03eSChen Hanxiao                 goto out;
3990692b03eSChen Hanxiao             }
4000692b03eSChen Hanxiao             num_mount_points++;
4010692b03eSChen Hanxiao 
4026c1d88c7SKonstantin Kostiuk             delete[] volume_name_wchar;
4030692b03eSChen Hanxiao         }
4040692b03eSChen Hanxiao 
4050692b03eSChen Hanxiao         if (num_mount_points == 0) {
4060692b03eSChen Hanxiao             /* If there is no valid mount points, just exit. */
4070692b03eSChen Hanxiao             goto out;
4080692b03eSChen Hanxiao         }
4090692b03eSChen Hanxiao     }
4100692b03eSChen Hanxiao 
4110692b03eSChen Hanxiao     if (!mountpoints) {
412b39297aeSTomoki Sekiyama         volume = FindFirstVolumeW(short_volume_name, sizeof(short_volume_name));
413b39297aeSTomoki Sekiyama         if (volume == INVALID_HANDLE_VALUE) {
414b39297aeSTomoki Sekiyama             err_set(errset, hr, "failed to find first volume");
415b39297aeSTomoki Sekiyama             goto out;
416b39297aeSTomoki Sekiyama         }
4170692b03eSChen Hanxiao 
418b39297aeSTomoki Sekiyama         for (;;) {
419b39297aeSTomoki Sekiyama             if (GetDriveTypeW(short_volume_name) == DRIVE_FIXED) {
420b39297aeSTomoki Sekiyama                 VSS_ID pid;
421b39297aeSTomoki Sekiyama                 hr = vss_ctx.pVssbc->AddToSnapshotSet(short_volume_name,
422b39297aeSTomoki Sekiyama                                                       g_gProviderId, &pid);
423b39297aeSTomoki Sekiyama                 if (FAILED(hr)) {
424b39297aeSTomoki Sekiyama                     WCHAR volume_path_name[PATH_MAX];
425b39297aeSTomoki Sekiyama                     if (GetVolumePathNamesForVolumeNameW(
426b39297aeSTomoki Sekiyama                             short_volume_name, volume_path_name,
4270692b03eSChen Hanxiao                             sizeof(volume_path_name), NULL) &&
4280692b03eSChen Hanxiao                             *volume_path_name) {
429b39297aeSTomoki Sekiyama                         display_name = volume_path_name;
430b39297aeSTomoki Sekiyama                     }
431b39297aeSTomoki Sekiyama                     err_set(errset, hr, "failed to add %S to snapshot set",
432b39297aeSTomoki Sekiyama                             display_name);
433b39297aeSTomoki Sekiyama                     FindVolumeClose(volume);
434b39297aeSTomoki Sekiyama                     goto out;
435b39297aeSTomoki Sekiyama                 }
436b39297aeSTomoki Sekiyama                 num_fixed_drives++;
437b39297aeSTomoki Sekiyama             }
438b39297aeSTomoki Sekiyama             if (!FindNextVolumeW(volume, short_volume_name,
439b39297aeSTomoki Sekiyama                                  sizeof(short_volume_name))) {
440b39297aeSTomoki Sekiyama                 FindVolumeClose(volume);
441b39297aeSTomoki Sekiyama                 break;
442b39297aeSTomoki Sekiyama             }
443b39297aeSTomoki Sekiyama         }
444b39297aeSTomoki Sekiyama 
445b39297aeSTomoki Sekiyama         if (num_fixed_drives == 0) {
446b39297aeSTomoki Sekiyama             goto out; /* If there is no fixed drive, just exit. */
447b39297aeSTomoki Sekiyama         }
4480692b03eSChen Hanxiao     }
449b39297aeSTomoki Sekiyama 
450b39297aeSTomoki Sekiyama     hr = vss_ctx.pVssbc->PrepareForBackup(pAsync.replace());
451b39297aeSTomoki Sekiyama     if (SUCCEEDED(hr)) {
452b39297aeSTomoki Sekiyama         hr = WaitForAsync(pAsync);
453b39297aeSTomoki Sekiyama     }
454b39297aeSTomoki Sekiyama     if (FAILED(hr)) {
455b39297aeSTomoki Sekiyama         err_set(errset, hr, "failed to prepare for backup");
456b39297aeSTomoki Sekiyama         goto out;
457b39297aeSTomoki Sekiyama     }
458b39297aeSTomoki Sekiyama 
459b39297aeSTomoki Sekiyama     hr = vss_ctx.pVssbc->GatherWriterStatus(pAsync.replace());
460b39297aeSTomoki Sekiyama     if (SUCCEEDED(hr)) {
461b39297aeSTomoki Sekiyama         hr = WaitForAsync(pAsync);
462b39297aeSTomoki Sekiyama     }
463b39297aeSTomoki Sekiyama     if (FAILED(hr)) {
464b39297aeSTomoki Sekiyama         err_set(errset, hr, "failed to gather writer status");
465b39297aeSTomoki Sekiyama         goto out;
466b39297aeSTomoki Sekiyama     }
467b39297aeSTomoki Sekiyama 
468b39297aeSTomoki Sekiyama     /*
469b39297aeSTomoki Sekiyama      * Start VSS quiescing operations.
470b39297aeSTomoki Sekiyama      * CQGAVssProvider::CommitSnapshots will kick vss_ctx.hEventFrozen
471b39297aeSTomoki Sekiyama      * after the applications and filesystems are frozen.
472b39297aeSTomoki Sekiyama      */
473b39297aeSTomoki Sekiyama     hr = vss_ctx.pVssbc->DoSnapshotSet(&vss_ctx.pAsyncSnapshot);
474b39297aeSTomoki Sekiyama     if (FAILED(hr)) {
475b39297aeSTomoki Sekiyama         err_set(errset, hr, "failed to do snapshot set");
476b39297aeSTomoki Sekiyama         goto out;
477b39297aeSTomoki Sekiyama     }
478b39297aeSTomoki Sekiyama 
479b39297aeSTomoki Sekiyama     /* Need to call QueryStatus several times to make VSS provider progress */
480b39297aeSTomoki Sekiyama     for (i = 0; i < VSS_TIMEOUT_FREEZE_MSEC/VSS_TIMEOUT_EVENT_MSEC; i++) {
481b39297aeSTomoki Sekiyama         HRESULT hr2 = vss_ctx.pAsyncSnapshot->QueryStatus(&hr, NULL);
482b39297aeSTomoki Sekiyama         if (FAILED(hr2)) {
483b39297aeSTomoki Sekiyama             err_set(errset, hr, "failed to do snapshot set");
484b39297aeSTomoki Sekiyama             goto out;
485b39297aeSTomoki Sekiyama         }
486b39297aeSTomoki Sekiyama         if (hr != VSS_S_ASYNC_PENDING) {
487b39297aeSTomoki Sekiyama             err_set(errset, E_FAIL,
488b39297aeSTomoki Sekiyama                     "DoSnapshotSet exited without Frozen event");
489b39297aeSTomoki Sekiyama             goto out;
490b39297aeSTomoki Sekiyama         }
491b39297aeSTomoki Sekiyama         wait_status = WaitForSingleObject(vss_ctx.hEventFrozen,
492b39297aeSTomoki Sekiyama                                           VSS_TIMEOUT_EVENT_MSEC);
493b39297aeSTomoki Sekiyama         if (wait_status != WAIT_TIMEOUT) {
494b39297aeSTomoki Sekiyama             break;
495b39297aeSTomoki Sekiyama         }
496b39297aeSTomoki Sekiyama     }
4974d80d20fSChen Hanxiao 
4984d80d20fSChen Hanxiao     if (wait_status == WAIT_TIMEOUT) {
4994d80d20fSChen Hanxiao         err_set(errset, E_FAIL,
5004d80d20fSChen Hanxiao                 "timeout when try to receive Frozen event from VSS provider");
5014d80d20fSChen Hanxiao         /* If we are here, VSS had timeout.
5024d80d20fSChen Hanxiao          * Don't call AbortBackup, just return directly.
5034d80d20fSChen Hanxiao          */
5044d80d20fSChen Hanxiao         goto out1;
5054d80d20fSChen Hanxiao     }
5064d80d20fSChen Hanxiao 
507b39297aeSTomoki Sekiyama     if (wait_status != WAIT_OBJECT_0) {
508b39297aeSTomoki Sekiyama         err_set(errset, E_FAIL,
509b39297aeSTomoki Sekiyama                 "couldn't receive Frozen event from VSS provider");
510b39297aeSTomoki Sekiyama         goto out;
511b39297aeSTomoki Sekiyama     }
512b39297aeSTomoki Sekiyama 
5130692b03eSChen Hanxiao     if (mountpoints) {
5140692b03eSChen Hanxiao         *num_vols = vss_ctx.cFrozenVols = num_mount_points;
5150692b03eSChen Hanxiao     } else {
516b39297aeSTomoki Sekiyama         *num_vols = vss_ctx.cFrozenVols = num_fixed_drives;
5170692b03eSChen Hanxiao     }
5180692b03eSChen Hanxiao 
519b39297aeSTomoki Sekiyama     return;
520b39297aeSTomoki Sekiyama 
521b39297aeSTomoki Sekiyama out:
522b39297aeSTomoki Sekiyama     if (vss_ctx.pVssbc) {
523b39297aeSTomoki Sekiyama         vss_ctx.pVssbc->AbortBackup();
524b39297aeSTomoki Sekiyama     }
5254d80d20fSChen Hanxiao 
5264d80d20fSChen Hanxiao out1:
527b39297aeSTomoki Sekiyama     requester_cleanup();
528b39297aeSTomoki Sekiyama     CoUninitialize();
529b39297aeSTomoki Sekiyama }
530b39297aeSTomoki Sekiyama 
531b39297aeSTomoki Sekiyama 
5320692b03eSChen Hanxiao void requester_thaw(int *num_vols, void *mountpints, ErrorSet *errset)
533b39297aeSTomoki Sekiyama {
534b39297aeSTomoki Sekiyama     COMPointer<IVssAsync> pAsync;
535b39297aeSTomoki Sekiyama 
5364c1b8f1eSTomoki Sekiyama     if (!vss_ctx.hEventThaw) {
537b39297aeSTomoki Sekiyama         /*
538b39297aeSTomoki Sekiyama          * In this case, DoSnapshotSet is aborted or not started,
539b39297aeSTomoki Sekiyama          * and no volumes must be frozen. We return without an error.
540b39297aeSTomoki Sekiyama          */
541b39297aeSTomoki Sekiyama         *num_vols = 0;
542b39297aeSTomoki Sekiyama         return;
543b39297aeSTomoki Sekiyama     }
544b39297aeSTomoki Sekiyama 
545b39297aeSTomoki Sekiyama     /* Tell the provider that the snapshot is finished. */
546b39297aeSTomoki Sekiyama     SetEvent(vss_ctx.hEventThaw);
547b39297aeSTomoki Sekiyama 
548b39297aeSTomoki Sekiyama     assert(vss_ctx.pVssbc);
549b39297aeSTomoki Sekiyama     assert(vss_ctx.pAsyncSnapshot);
550b39297aeSTomoki Sekiyama 
551b39297aeSTomoki Sekiyama     HRESULT hr = WaitForAsync(vss_ctx.pAsyncSnapshot);
552b39297aeSTomoki Sekiyama     switch (hr) {
553b39297aeSTomoki Sekiyama     case VSS_S_ASYNC_FINISHED:
554b39297aeSTomoki Sekiyama         hr = vss_ctx.pVssbc->BackupComplete(pAsync.replace());
555b39297aeSTomoki Sekiyama         if (SUCCEEDED(hr)) {
556b39297aeSTomoki Sekiyama             hr = WaitForAsync(pAsync);
557b39297aeSTomoki Sekiyama         }
558b39297aeSTomoki Sekiyama         if (FAILED(hr)) {
559b39297aeSTomoki Sekiyama             err_set(errset, hr, "failed to complete backup");
560b39297aeSTomoki Sekiyama         }
561b39297aeSTomoki Sekiyama         break;
562b39297aeSTomoki Sekiyama 
563b39297aeSTomoki Sekiyama     case (HRESULT)VSS_E_OBJECT_NOT_FOUND:
564b39297aeSTomoki Sekiyama         /*
565b39297aeSTomoki Sekiyama          * On Windows earlier than 2008 SP2 which does not support
566b39297aeSTomoki Sekiyama          * VSS_VOLSNAP_ATTR_NO_AUTORECOVERY context, the final commit is not
567b39297aeSTomoki Sekiyama          * skipped and VSS is aborted by VSS_E_OBJECT_NOT_FOUND. However, as
568b39297aeSTomoki Sekiyama          * the system had been frozen until fsfreeze-thaw command was issued,
569b39297aeSTomoki Sekiyama          * we ignore this error.
570b39297aeSTomoki Sekiyama          */
571b39297aeSTomoki Sekiyama         vss_ctx.pVssbc->AbortBackup();
572b39297aeSTomoki Sekiyama         break;
573b39297aeSTomoki Sekiyama 
574b39297aeSTomoki Sekiyama     case VSS_E_UNEXPECTED_PROVIDER_ERROR:
575b39297aeSTomoki Sekiyama         if (WaitForSingleObject(vss_ctx.hEventTimeout, 0) != WAIT_OBJECT_0) {
576b39297aeSTomoki Sekiyama             err_set(errset, hr, "unexpected error in VSS provider");
577b39297aeSTomoki Sekiyama             break;
578b39297aeSTomoki Sekiyama         }
579b39297aeSTomoki Sekiyama         /* fall through if hEventTimeout is signaled */
580b39297aeSTomoki Sekiyama 
581b39297aeSTomoki Sekiyama     case (HRESULT)VSS_E_HOLD_WRITES_TIMEOUT:
582b39297aeSTomoki Sekiyama         err_set(errset, hr, "couldn't hold writes: "
583b39297aeSTomoki Sekiyama                 "fsfreeze is limited up to 10 seconds");
584b39297aeSTomoki Sekiyama         break;
585b39297aeSTomoki Sekiyama 
586b39297aeSTomoki Sekiyama     default:
587b39297aeSTomoki Sekiyama         err_set(errset, hr, "failed to do snapshot set");
588b39297aeSTomoki Sekiyama     }
589b39297aeSTomoki Sekiyama 
590b39297aeSTomoki Sekiyama     if (err_is_set(errset)) {
591b39297aeSTomoki Sekiyama         vss_ctx.pVssbc->AbortBackup();
592b39297aeSTomoki Sekiyama     }
593b39297aeSTomoki Sekiyama     *num_vols = vss_ctx.cFrozenVols;
594b39297aeSTomoki Sekiyama     requester_cleanup();
595b39297aeSTomoki Sekiyama 
596b39297aeSTomoki Sekiyama     CoUninitialize();
597f342cc93SSameeh Jubran     StopService();
598b39297aeSTomoki Sekiyama }
599