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" 152f84cf69SKonstantin 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 2924eecad3SKonstantin Kostiuk #define err_set(e, err, fmt, ...) { \ 3024eecad3SKonstantin Kostiuk (e)->error_setg_win32_wrapper((e)->errp, __FILE__, __LINE__, __func__, \ 3124eecad3SKonstantin Kostiuk err, fmt, ## __VA_ARGS__); \ 3224eecad3SKonstantin Kostiuk qga_debug(fmt, ## __VA_ARGS__); \ 3324eecad3SKonstantin Kostiuk } 3408e64640SMarkus Armbruster /* Bad idea, works only when (e)->errp != NULL: */ 35b39297aeSTomoki Sekiyama #define err_is_set(e) ((e)->errp && *(e)->errp) 3608e64640SMarkus Armbruster /* To lift this restriction, error_propagate(), like we do in QEMU code */ 37b39297aeSTomoki Sekiyama 38b39297aeSTomoki Sekiyama /* Handle to VSSAPI.DLL */ 39b39297aeSTomoki Sekiyama static HMODULE hLib; 40b39297aeSTomoki Sekiyama 41b39297aeSTomoki Sekiyama /* Functions in VSSAPI.DLL */ 42b39297aeSTomoki Sekiyama typedef HRESULT(STDAPICALLTYPE * t_CreateVssBackupComponents)( 43b39297aeSTomoki Sekiyama OUT IVssBackupComponents**); 44b39297aeSTomoki Sekiyama typedef void(APIENTRY * t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*); 45b39297aeSTomoki Sekiyama static t_CreateVssBackupComponents pCreateVssBackupComponents; 46b39297aeSTomoki Sekiyama static t_VssFreeSnapshotProperties pVssFreeSnapshotProperties; 47b39297aeSTomoki Sekiyama 48b39297aeSTomoki Sekiyama /* Variables used while applications and filesystes are frozen by VSS */ 49b39297aeSTomoki Sekiyama static struct QGAVSSContext { 50b39297aeSTomoki Sekiyama IVssBackupComponents *pVssbc; /* VSS requester interface */ 51b39297aeSTomoki Sekiyama IVssAsync *pAsyncSnapshot; /* async info of VSS snapshot operation */ 52b39297aeSTomoki Sekiyama HANDLE hEventFrozen; /* notify fs/writer freeze from provider */ 53b39297aeSTomoki Sekiyama HANDLE hEventThaw; /* request provider to thaw */ 54b39297aeSTomoki Sekiyama HANDLE hEventTimeout; /* notify timeout in provider */ 55b39297aeSTomoki Sekiyama int cFrozenVols; /* number of frozen volumes */ 56b39297aeSTomoki Sekiyama } vss_ctx; 57b39297aeSTomoki Sekiyama 58b39297aeSTomoki Sekiyama STDAPI requester_init(void) 59b39297aeSTomoki Sekiyama { 6061df91b3SKonstantin Kostiuk qga_debug_begin; 6161df91b3SKonstantin Kostiuk 62b39297aeSTomoki Sekiyama COMInitializer initializer; /* to call CoInitializeSecurity */ 63b39297aeSTomoki Sekiyama HRESULT hr = CoInitializeSecurity( 64b39297aeSTomoki Sekiyama NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, 65b39297aeSTomoki Sekiyama RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE, NULL); 66b39297aeSTomoki Sekiyama if (FAILED(hr)) { 672f84cf69SKonstantin Kostiuk qga_debug("failed to CoInitializeSecurity (error %lx)", hr); 68b39297aeSTomoki Sekiyama return hr; 69b39297aeSTomoki Sekiyama } 70b39297aeSTomoki Sekiyama 71b39297aeSTomoki Sekiyama hLib = LoadLibraryA("VSSAPI.DLL"); 72b39297aeSTomoki Sekiyama if (!hLib) { 732f84cf69SKonstantin Kostiuk qga_debug("failed to load VSSAPI.DLL"); 74b39297aeSTomoki Sekiyama return HRESULT_FROM_WIN32(GetLastError()); 75b39297aeSTomoki Sekiyama } 76b39297aeSTomoki Sekiyama 77b39297aeSTomoki Sekiyama pCreateVssBackupComponents = (t_CreateVssBackupComponents) 78b39297aeSTomoki Sekiyama GetProcAddress(hLib, 79b39297aeSTomoki Sekiyama #ifdef _WIN64 /* 64bit environment */ 80b39297aeSTomoki Sekiyama "?CreateVssBackupComponents@@YAJPEAPEAVIVssBackupComponents@@@Z" 81b39297aeSTomoki Sekiyama #else /* 32bit environment */ 82b39297aeSTomoki Sekiyama "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z" 83b39297aeSTomoki Sekiyama #endif 84b39297aeSTomoki Sekiyama ); 85b39297aeSTomoki Sekiyama if (!pCreateVssBackupComponents) { 862f84cf69SKonstantin Kostiuk qga_debug("failed to get proc address from VSSAPI.DLL"); 87b39297aeSTomoki Sekiyama return HRESULT_FROM_WIN32(GetLastError()); 88b39297aeSTomoki Sekiyama } 89b39297aeSTomoki Sekiyama 90b39297aeSTomoki Sekiyama pVssFreeSnapshotProperties = (t_VssFreeSnapshotProperties) 91b39297aeSTomoki Sekiyama GetProcAddress(hLib, "VssFreeSnapshotProperties"); 92b39297aeSTomoki Sekiyama if (!pVssFreeSnapshotProperties) { 932f84cf69SKonstantin Kostiuk qga_debug("failed to get proc address from VSSAPI.DLL"); 94b39297aeSTomoki Sekiyama return HRESULT_FROM_WIN32(GetLastError()); 95b39297aeSTomoki Sekiyama } 96b39297aeSTomoki Sekiyama 9761df91b3SKonstantin Kostiuk qga_debug_end; 98b39297aeSTomoki Sekiyama return S_OK; 99b39297aeSTomoki Sekiyama } 100b39297aeSTomoki Sekiyama 101b39297aeSTomoki Sekiyama static void requester_cleanup(void) 102b39297aeSTomoki Sekiyama { 10361df91b3SKonstantin Kostiuk qga_debug_begin; 10461df91b3SKonstantin Kostiuk 1054c1b8f1eSTomoki Sekiyama if (vss_ctx.hEventFrozen) { 106b39297aeSTomoki Sekiyama CloseHandle(vss_ctx.hEventFrozen); 1074c1b8f1eSTomoki Sekiyama vss_ctx.hEventFrozen = NULL; 108b39297aeSTomoki Sekiyama } 1094c1b8f1eSTomoki Sekiyama if (vss_ctx.hEventThaw) { 110b39297aeSTomoki Sekiyama CloseHandle(vss_ctx.hEventThaw); 1114c1b8f1eSTomoki Sekiyama vss_ctx.hEventThaw = NULL; 112b39297aeSTomoki Sekiyama } 1134c1b8f1eSTomoki Sekiyama if (vss_ctx.hEventTimeout) { 114b39297aeSTomoki Sekiyama CloseHandle(vss_ctx.hEventTimeout); 1154c1b8f1eSTomoki Sekiyama vss_ctx.hEventTimeout = NULL; 116b39297aeSTomoki Sekiyama } 117b39297aeSTomoki Sekiyama if (vss_ctx.pAsyncSnapshot) { 118b39297aeSTomoki Sekiyama vss_ctx.pAsyncSnapshot->Release(); 119b39297aeSTomoki Sekiyama vss_ctx.pAsyncSnapshot = NULL; 120b39297aeSTomoki Sekiyama } 121b39297aeSTomoki Sekiyama if (vss_ctx.pVssbc) { 122b39297aeSTomoki Sekiyama vss_ctx.pVssbc->Release(); 123b39297aeSTomoki Sekiyama vss_ctx.pVssbc = NULL; 124b39297aeSTomoki Sekiyama } 125b39297aeSTomoki Sekiyama vss_ctx.cFrozenVols = 0; 12661df91b3SKonstantin Kostiuk qga_debug_end; 127b39297aeSTomoki Sekiyama } 128b39297aeSTomoki Sekiyama 129b39297aeSTomoki Sekiyama STDAPI requester_deinit(void) 130b39297aeSTomoki Sekiyama { 13161df91b3SKonstantin Kostiuk qga_debug_begin; 13261df91b3SKonstantin Kostiuk 133b39297aeSTomoki Sekiyama requester_cleanup(); 134b39297aeSTomoki Sekiyama 135b39297aeSTomoki Sekiyama pCreateVssBackupComponents = NULL; 136b39297aeSTomoki Sekiyama pVssFreeSnapshotProperties = NULL; 137b39297aeSTomoki Sekiyama if (hLib) { 138b39297aeSTomoki Sekiyama FreeLibrary(hLib); 139b39297aeSTomoki Sekiyama hLib = NULL; 140b39297aeSTomoki Sekiyama } 141b39297aeSTomoki Sekiyama 14261df91b3SKonstantin Kostiuk qga_debug_end; 143b39297aeSTomoki Sekiyama return S_OK; 144b39297aeSTomoki Sekiyama } 145b39297aeSTomoki Sekiyama 146b39297aeSTomoki Sekiyama static HRESULT WaitForAsync(IVssAsync *pAsync) 147b39297aeSTomoki Sekiyama { 14861df91b3SKonstantin Kostiuk qga_debug_begin; 14961df91b3SKonstantin Kostiuk 150b39297aeSTomoki Sekiyama HRESULT ret, hr; 151b39297aeSTomoki Sekiyama 152b39297aeSTomoki Sekiyama do { 153b39297aeSTomoki Sekiyama hr = pAsync->Wait(); 154b39297aeSTomoki Sekiyama if (FAILED(hr)) { 155b39297aeSTomoki Sekiyama ret = hr; 156b39297aeSTomoki Sekiyama break; 157b39297aeSTomoki Sekiyama } 158b39297aeSTomoki Sekiyama hr = pAsync->QueryStatus(&ret, NULL); 159b39297aeSTomoki Sekiyama if (FAILED(hr)) { 160b39297aeSTomoki Sekiyama ret = hr; 161b39297aeSTomoki Sekiyama break; 162b39297aeSTomoki Sekiyama } 163b39297aeSTomoki Sekiyama } while (ret == VSS_S_ASYNC_PENDING); 164b39297aeSTomoki Sekiyama 16561df91b3SKonstantin Kostiuk qga_debug_end; 166b39297aeSTomoki Sekiyama return ret; 167b39297aeSTomoki Sekiyama } 168b39297aeSTomoki Sekiyama 169b39297aeSTomoki Sekiyama static void AddComponents(ErrorSet *errset) 170b39297aeSTomoki Sekiyama { 17161df91b3SKonstantin Kostiuk qga_debug_begin; 17261df91b3SKonstantin Kostiuk 173b39297aeSTomoki Sekiyama unsigned int cWriters, i; 174b39297aeSTomoki Sekiyama VSS_ID id, idInstance, idWriter; 175b39297aeSTomoki Sekiyama BSTR bstrWriterName = NULL; 176b39297aeSTomoki Sekiyama VSS_USAGE_TYPE usage; 177b39297aeSTomoki Sekiyama VSS_SOURCE_TYPE source; 178b39297aeSTomoki Sekiyama unsigned int cComponents, c1, c2, j; 179b39297aeSTomoki Sekiyama COMPointer<IVssExamineWriterMetadata> pMetadata; 180b39297aeSTomoki Sekiyama COMPointer<IVssWMComponent> pComponent; 181b39297aeSTomoki Sekiyama PVSSCOMPONENTINFO info; 182b39297aeSTomoki Sekiyama HRESULT hr; 183b39297aeSTomoki Sekiyama 184b39297aeSTomoki Sekiyama hr = vss_ctx.pVssbc->GetWriterMetadataCount(&cWriters); 185b39297aeSTomoki Sekiyama if (FAILED(hr)) { 186b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to get writer metadata count"); 187b39297aeSTomoki Sekiyama goto out; 188b39297aeSTomoki Sekiyama } 189b39297aeSTomoki Sekiyama 190b39297aeSTomoki Sekiyama for (i = 0; i < cWriters; i++) { 191b39297aeSTomoki Sekiyama hr = vss_ctx.pVssbc->GetWriterMetadata(i, &id, pMetadata.replace()); 192b39297aeSTomoki Sekiyama if (FAILED(hr)) { 193b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to get writer metadata of %d/%d", 194b39297aeSTomoki Sekiyama i, cWriters); 195b39297aeSTomoki Sekiyama goto out; 196b39297aeSTomoki Sekiyama } 197b39297aeSTomoki Sekiyama 198b39297aeSTomoki Sekiyama hr = pMetadata->GetIdentity(&idInstance, &idWriter, 199b39297aeSTomoki Sekiyama &bstrWriterName, &usage, &source); 200b39297aeSTomoki Sekiyama if (FAILED(hr)) { 201b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to get identity of writer %d/%d", 202b39297aeSTomoki Sekiyama i, cWriters); 203b39297aeSTomoki Sekiyama goto out; 204b39297aeSTomoki Sekiyama } 205b39297aeSTomoki Sekiyama 206b39297aeSTomoki Sekiyama hr = pMetadata->GetFileCounts(&c1, &c2, &cComponents); 207b39297aeSTomoki Sekiyama if (FAILED(hr)) { 208b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to get file counts of %S", 209b39297aeSTomoki Sekiyama bstrWriterName); 210b39297aeSTomoki Sekiyama goto out; 211b39297aeSTomoki Sekiyama } 212b39297aeSTomoki Sekiyama 213b39297aeSTomoki Sekiyama for (j = 0; j < cComponents; j++) { 214b39297aeSTomoki Sekiyama hr = pMetadata->GetComponent(j, pComponent.replace()); 215b39297aeSTomoki Sekiyama if (FAILED(hr)) { 216b39297aeSTomoki Sekiyama err_set(errset, hr, 217b39297aeSTomoki Sekiyama "failed to get component %d/%d of %S", 218b39297aeSTomoki Sekiyama j, cComponents, bstrWriterName); 219b39297aeSTomoki Sekiyama goto out; 220b39297aeSTomoki Sekiyama } 221b39297aeSTomoki Sekiyama 222b39297aeSTomoki Sekiyama hr = pComponent->GetComponentInfo(&info); 223b39297aeSTomoki Sekiyama if (FAILED(hr)) { 224b39297aeSTomoki Sekiyama err_set(errset, hr, 225b39297aeSTomoki Sekiyama "failed to get component info %d/%d of %S", 226b39297aeSTomoki Sekiyama j, cComponents, bstrWriterName); 227b39297aeSTomoki Sekiyama goto out; 228b39297aeSTomoki Sekiyama } 229b39297aeSTomoki Sekiyama 230b39297aeSTomoki Sekiyama if (info->bSelectable) { 231b39297aeSTomoki Sekiyama hr = vss_ctx.pVssbc->AddComponent(idInstance, idWriter, 232b39297aeSTomoki Sekiyama info->type, 233b39297aeSTomoki Sekiyama info->bstrLogicalPath, 234b39297aeSTomoki Sekiyama info->bstrComponentName); 235b39297aeSTomoki Sekiyama if (FAILED(hr)) { 236b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to add component %S(%S)", 237b39297aeSTomoki Sekiyama info->bstrComponentName, bstrWriterName); 238b39297aeSTomoki Sekiyama goto out; 239b39297aeSTomoki Sekiyama } 240b39297aeSTomoki Sekiyama } 241b39297aeSTomoki Sekiyama SysFreeString(bstrWriterName); 242b39297aeSTomoki Sekiyama bstrWriterName = NULL; 243b39297aeSTomoki Sekiyama pComponent->FreeComponentInfo(info); 244b39297aeSTomoki Sekiyama info = NULL; 245b39297aeSTomoki Sekiyama } 246b39297aeSTomoki Sekiyama } 247b39297aeSTomoki Sekiyama out: 248b39297aeSTomoki Sekiyama if (bstrWriterName) { 249b39297aeSTomoki Sekiyama SysFreeString(bstrWriterName); 250b39297aeSTomoki Sekiyama } 251b39297aeSTomoki Sekiyama if (pComponent && info) { 252b39297aeSTomoki Sekiyama pComponent->FreeComponentInfo(info); 253b39297aeSTomoki Sekiyama } 25461df91b3SKonstantin Kostiuk qga_debug_end; 255b39297aeSTomoki Sekiyama } 256b39297aeSTomoki Sekiyama 257*73aaabcfSPierrick Bouvier static DWORD get_reg_dword_value(HKEY baseKey, LPCSTR subKey, LPCSTR valueName, 258410542d4SKfir Manor DWORD defaultData) 259410542d4SKfir Manor { 26061df91b3SKonstantin Kostiuk qga_debug_begin; 26161df91b3SKonstantin Kostiuk 262410542d4SKfir Manor DWORD regGetValueError; 263410542d4SKfir Manor DWORD dwordData; 264410542d4SKfir Manor DWORD dataSize = sizeof(DWORD); 265410542d4SKfir Manor 266410542d4SKfir Manor regGetValueError = RegGetValue(baseKey, subKey, valueName, RRF_RT_DWORD, 267410542d4SKfir Manor NULL, &dwordData, &dataSize); 26861df91b3SKonstantin Kostiuk qga_debug_end; 269410542d4SKfir Manor if (regGetValueError != ERROR_SUCCESS) { 270410542d4SKfir Manor return defaultData; 271410542d4SKfir Manor } 272410542d4SKfir Manor return dwordData; 273410542d4SKfir Manor } 274410542d4SKfir Manor 275*73aaabcfSPierrick Bouvier static bool is_valid_vss_backup_type(VSS_BACKUP_TYPE vssBT) 276410542d4SKfir Manor { 277410542d4SKfir Manor return (vssBT > VSS_BT_UNDEFINED && vssBT < VSS_BT_OTHER); 278410542d4SKfir Manor } 279410542d4SKfir Manor 280*73aaabcfSPierrick Bouvier static VSS_BACKUP_TYPE get_vss_backup_type( 281410542d4SKfir Manor VSS_BACKUP_TYPE defaultVssBT = DEFAULT_VSS_BACKUP_TYPE) 282410542d4SKfir Manor { 28361df91b3SKonstantin Kostiuk qga_debug_begin; 28461df91b3SKonstantin Kostiuk 285410542d4SKfir Manor VSS_BACKUP_TYPE vssBackupType; 286410542d4SKfir Manor 287410542d4SKfir Manor vssBackupType = static_cast<VSS_BACKUP_TYPE>( 288410542d4SKfir Manor get_reg_dword_value(HKEY_LOCAL_MACHINE, 289410542d4SKfir Manor QGA_PROVIDER_REGISTRY_ADDRESS, 290410542d4SKfir Manor "VssOption", 291410542d4SKfir Manor defaultVssBT)); 29261df91b3SKonstantin Kostiuk qga_debug_end; 293410542d4SKfir Manor if (!is_valid_vss_backup_type(vssBackupType)) { 294410542d4SKfir Manor return defaultVssBT; 295410542d4SKfir Manor } 296410542d4SKfir Manor return vssBackupType; 297410542d4SKfir Manor } 298410542d4SKfir Manor 2990692b03eSChen Hanxiao void requester_freeze(int *num_vols, void *mountpoints, ErrorSet *errset) 300b39297aeSTomoki Sekiyama { 30161df91b3SKonstantin Kostiuk qga_debug_begin; 30261df91b3SKonstantin Kostiuk 303b39297aeSTomoki Sekiyama COMPointer<IVssAsync> pAsync; 304b39297aeSTomoki Sekiyama HANDLE volume; 305b39297aeSTomoki Sekiyama HRESULT hr; 306b39297aeSTomoki Sekiyama LONG ctx; 307b39297aeSTomoki Sekiyama GUID guidSnapshotSet = GUID_NULL; 308b39297aeSTomoki Sekiyama SECURITY_DESCRIPTOR sd; 309b39297aeSTomoki Sekiyama SECURITY_ATTRIBUTES sa; 310b39297aeSTomoki Sekiyama WCHAR short_volume_name[64], *display_name = short_volume_name; 311b39297aeSTomoki Sekiyama DWORD wait_status; 312b39297aeSTomoki Sekiyama int num_fixed_drives = 0, i; 3130692b03eSChen Hanxiao int num_mount_points = 0; 3140961f929SKfir Manor VSS_BACKUP_TYPE vss_bt = get_vss_backup_type(); 315b39297aeSTomoki Sekiyama 316b39297aeSTomoki Sekiyama if (vss_ctx.pVssbc) { /* already frozen */ 317b39297aeSTomoki Sekiyama *num_vols = 0; 31861df91b3SKonstantin Kostiuk qga_debug("finished, already frozen"); 319b39297aeSTomoki Sekiyama return; 320b39297aeSTomoki Sekiyama } 321b39297aeSTomoki Sekiyama 322b39297aeSTomoki Sekiyama CoInitialize(NULL); 323b39297aeSTomoki Sekiyama 324ff8adbcfSTomoki Sekiyama /* Allow unrestricted access to events */ 325ff8adbcfSTomoki Sekiyama InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); 326ff8adbcfSTomoki Sekiyama SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); 327ff8adbcfSTomoki Sekiyama sa.nLength = sizeof(sa); 328ff8adbcfSTomoki Sekiyama sa.lpSecurityDescriptor = &sd; 329ff8adbcfSTomoki Sekiyama sa.bInheritHandle = FALSE; 330ff8adbcfSTomoki Sekiyama 331ff8adbcfSTomoki Sekiyama vss_ctx.hEventFrozen = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_FROZEN); 332ff8adbcfSTomoki Sekiyama if (!vss_ctx.hEventFrozen) { 333ff8adbcfSTomoki Sekiyama err_set(errset, GetLastError(), "failed to create event %s", 334ff8adbcfSTomoki Sekiyama EVENT_NAME_FROZEN); 335ff8adbcfSTomoki Sekiyama goto out; 336ff8adbcfSTomoki Sekiyama } 337ff8adbcfSTomoki Sekiyama vss_ctx.hEventThaw = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_THAW); 338ff8adbcfSTomoki Sekiyama if (!vss_ctx.hEventThaw) { 339ff8adbcfSTomoki Sekiyama err_set(errset, GetLastError(), "failed to create event %s", 340ff8adbcfSTomoki Sekiyama EVENT_NAME_THAW); 341ff8adbcfSTomoki Sekiyama goto out; 342ff8adbcfSTomoki Sekiyama } 343ff8adbcfSTomoki Sekiyama vss_ctx.hEventTimeout = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_TIMEOUT); 344ff8adbcfSTomoki Sekiyama if (!vss_ctx.hEventTimeout) { 345ff8adbcfSTomoki Sekiyama err_set(errset, GetLastError(), "failed to create event %s", 346ff8adbcfSTomoki Sekiyama EVENT_NAME_TIMEOUT); 347ff8adbcfSTomoki Sekiyama goto out; 348ff8adbcfSTomoki Sekiyama } 349ff8adbcfSTomoki Sekiyama 350b39297aeSTomoki Sekiyama assert(pCreateVssBackupComponents != NULL); 351b39297aeSTomoki Sekiyama hr = pCreateVssBackupComponents(&vss_ctx.pVssbc); 352b39297aeSTomoki Sekiyama if (FAILED(hr)) { 353b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to create VSS backup components"); 354b39297aeSTomoki Sekiyama goto out; 355b39297aeSTomoki Sekiyama } 356b39297aeSTomoki Sekiyama 357b39297aeSTomoki Sekiyama hr = vss_ctx.pVssbc->InitializeForBackup(); 358b39297aeSTomoki Sekiyama if (FAILED(hr)) { 359b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to initialize for backup"); 360b39297aeSTomoki Sekiyama goto out; 361b39297aeSTomoki Sekiyama } 362b39297aeSTomoki Sekiyama 3630961f929SKfir Manor hr = vss_ctx.pVssbc->SetBackupState(true, true, vss_bt, false); 364b39297aeSTomoki Sekiyama if (FAILED(hr)) { 365b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to set backup state"); 366b39297aeSTomoki Sekiyama goto out; 367b39297aeSTomoki Sekiyama } 368b39297aeSTomoki Sekiyama 369b39297aeSTomoki Sekiyama /* 370b39297aeSTomoki Sekiyama * Currently writable snapshots are not supported. 371b39297aeSTomoki Sekiyama * To prevent the final commit (which requires to write to snapshots), 372b39297aeSTomoki Sekiyama * ATTR_NO_AUTORECOVERY and ATTR_TRANSPORTABLE are specified here. 373b39297aeSTomoki Sekiyama */ 374b39297aeSTomoki Sekiyama ctx = VSS_CTX_APP_ROLLBACK | VSS_VOLSNAP_ATTR_TRANSPORTABLE | 375b39297aeSTomoki Sekiyama VSS_VOLSNAP_ATTR_NO_AUTORECOVERY | VSS_VOLSNAP_ATTR_TXF_RECOVERY; 376b39297aeSTomoki Sekiyama hr = vss_ctx.pVssbc->SetContext(ctx); 377b39297aeSTomoki Sekiyama if (hr == (HRESULT)VSS_E_UNSUPPORTED_CONTEXT) { 378b39297aeSTomoki Sekiyama /* Non-server version of Windows doesn't support ATTR_TRANSPORTABLE */ 379b39297aeSTomoki Sekiyama ctx &= ~VSS_VOLSNAP_ATTR_TRANSPORTABLE; 380b39297aeSTomoki Sekiyama hr = vss_ctx.pVssbc->SetContext(ctx); 381b39297aeSTomoki Sekiyama } 382b39297aeSTomoki Sekiyama if (FAILED(hr)) { 383b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to set backup context"); 384b39297aeSTomoki Sekiyama goto out; 385b39297aeSTomoki Sekiyama } 386b39297aeSTomoki Sekiyama 387b39297aeSTomoki Sekiyama hr = vss_ctx.pVssbc->GatherWriterMetadata(pAsync.replace()); 388b39297aeSTomoki Sekiyama if (SUCCEEDED(hr)) { 389b39297aeSTomoki Sekiyama hr = WaitForAsync(pAsync); 390b39297aeSTomoki Sekiyama } 391b39297aeSTomoki Sekiyama if (FAILED(hr)) { 392b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to gather writer metadata"); 393b39297aeSTomoki Sekiyama goto out; 394b39297aeSTomoki Sekiyama } 395b39297aeSTomoki Sekiyama 396b39297aeSTomoki Sekiyama AddComponents(errset); 397b39297aeSTomoki Sekiyama if (err_is_set(errset)) { 398b39297aeSTomoki Sekiyama goto out; 399b39297aeSTomoki Sekiyama } 400b39297aeSTomoki Sekiyama 401b39297aeSTomoki Sekiyama hr = vss_ctx.pVssbc->StartSnapshotSet(&guidSnapshotSet); 402b39297aeSTomoki Sekiyama if (FAILED(hr)) { 403b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to start snapshot set"); 404b39297aeSTomoki Sekiyama goto out; 405b39297aeSTomoki Sekiyama } 406b39297aeSTomoki Sekiyama 4070692b03eSChen Hanxiao if (mountpoints) { 4080692b03eSChen Hanxiao PWCHAR volume_name_wchar; 4090692b03eSChen Hanxiao for (volList *list = (volList *)mountpoints; list; list = list->next) { 4100692b03eSChen Hanxiao size_t len = strlen(list->value) + 1; 4110692b03eSChen Hanxiao size_t converted = 0; 4120692b03eSChen Hanxiao VSS_ID pid; 4130692b03eSChen Hanxiao 4140692b03eSChen Hanxiao volume_name_wchar = new wchar_t[len]; 4150692b03eSChen Hanxiao mbstowcs_s(&converted, volume_name_wchar, len, 4160692b03eSChen Hanxiao list->value, _TRUNCATE); 4170692b03eSChen Hanxiao 4180692b03eSChen Hanxiao hr = vss_ctx.pVssbc->AddToSnapshotSet(volume_name_wchar, 4190692b03eSChen Hanxiao g_gProviderId, &pid); 4200692b03eSChen Hanxiao if (FAILED(hr)) { 4210692b03eSChen Hanxiao err_set(errset, hr, "failed to add %S to snapshot set", 4220692b03eSChen Hanxiao volume_name_wchar); 4236c1d88c7SKonstantin Kostiuk delete[] volume_name_wchar; 4240692b03eSChen Hanxiao goto out; 4250692b03eSChen Hanxiao } 4260692b03eSChen Hanxiao num_mount_points++; 4270692b03eSChen Hanxiao 4286c1d88c7SKonstantin Kostiuk delete[] volume_name_wchar; 4290692b03eSChen Hanxiao } 4300692b03eSChen Hanxiao 4310692b03eSChen Hanxiao if (num_mount_points == 0) { 4320692b03eSChen Hanxiao /* If there is no valid mount points, just exit. */ 4330692b03eSChen Hanxiao goto out; 4340692b03eSChen Hanxiao } 4350692b03eSChen Hanxiao } 4360692b03eSChen Hanxiao 4370692b03eSChen Hanxiao if (!mountpoints) { 438b39297aeSTomoki Sekiyama volume = FindFirstVolumeW(short_volume_name, sizeof(short_volume_name)); 439b39297aeSTomoki Sekiyama if (volume == INVALID_HANDLE_VALUE) { 440b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to find first volume"); 441b39297aeSTomoki Sekiyama goto out; 442b39297aeSTomoki Sekiyama } 4430692b03eSChen Hanxiao 444b39297aeSTomoki Sekiyama for (;;) { 445b39297aeSTomoki Sekiyama if (GetDriveTypeW(short_volume_name) == DRIVE_FIXED) { 446b39297aeSTomoki Sekiyama VSS_ID pid; 447b39297aeSTomoki Sekiyama hr = vss_ctx.pVssbc->AddToSnapshotSet(short_volume_name, 448b39297aeSTomoki Sekiyama g_gProviderId, &pid); 449b39297aeSTomoki Sekiyama if (FAILED(hr)) { 450b39297aeSTomoki Sekiyama WCHAR volume_path_name[PATH_MAX]; 451b39297aeSTomoki Sekiyama if (GetVolumePathNamesForVolumeNameW( 452b39297aeSTomoki Sekiyama short_volume_name, volume_path_name, 4530692b03eSChen Hanxiao sizeof(volume_path_name), NULL) && 4540692b03eSChen Hanxiao *volume_path_name) { 455b39297aeSTomoki Sekiyama display_name = volume_path_name; 456b39297aeSTomoki Sekiyama } 457b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to add %S to snapshot set", 458b39297aeSTomoki Sekiyama display_name); 459b39297aeSTomoki Sekiyama FindVolumeClose(volume); 460b39297aeSTomoki Sekiyama goto out; 461b39297aeSTomoki Sekiyama } 462b39297aeSTomoki Sekiyama num_fixed_drives++; 463b39297aeSTomoki Sekiyama } 464b39297aeSTomoki Sekiyama if (!FindNextVolumeW(volume, short_volume_name, 465b39297aeSTomoki Sekiyama sizeof(short_volume_name))) { 466b39297aeSTomoki Sekiyama FindVolumeClose(volume); 467b39297aeSTomoki Sekiyama break; 468b39297aeSTomoki Sekiyama } 469b39297aeSTomoki Sekiyama } 470b39297aeSTomoki Sekiyama 471b39297aeSTomoki Sekiyama if (num_fixed_drives == 0) { 472b39297aeSTomoki Sekiyama goto out; /* If there is no fixed drive, just exit. */ 473b39297aeSTomoki Sekiyama } 4740692b03eSChen Hanxiao } 475b39297aeSTomoki Sekiyama 47661df91b3SKonstantin Kostiuk qga_debug("preparing for backup"); 477b39297aeSTomoki Sekiyama hr = vss_ctx.pVssbc->PrepareForBackup(pAsync.replace()); 478b39297aeSTomoki Sekiyama if (SUCCEEDED(hr)) { 479b39297aeSTomoki Sekiyama hr = WaitForAsync(pAsync); 480b39297aeSTomoki Sekiyama } 481b39297aeSTomoki Sekiyama if (FAILED(hr)) { 482b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to prepare for backup"); 483b39297aeSTomoki Sekiyama goto out; 484b39297aeSTomoki Sekiyama } 485b39297aeSTomoki Sekiyama 486b39297aeSTomoki Sekiyama hr = vss_ctx.pVssbc->GatherWriterStatus(pAsync.replace()); 487b39297aeSTomoki Sekiyama if (SUCCEEDED(hr)) { 488b39297aeSTomoki Sekiyama hr = WaitForAsync(pAsync); 489b39297aeSTomoki Sekiyama } 490b39297aeSTomoki Sekiyama if (FAILED(hr)) { 491b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to gather writer status"); 492b39297aeSTomoki Sekiyama goto out; 493b39297aeSTomoki Sekiyama } 494b39297aeSTomoki Sekiyama 495b39297aeSTomoki Sekiyama /* 496b39297aeSTomoki Sekiyama * Start VSS quiescing operations. 497b39297aeSTomoki Sekiyama * CQGAVssProvider::CommitSnapshots will kick vss_ctx.hEventFrozen 498b39297aeSTomoki Sekiyama * after the applications and filesystems are frozen. 499b39297aeSTomoki Sekiyama */ 50061df91b3SKonstantin Kostiuk qga_debug("do snapshot set"); 501b39297aeSTomoki Sekiyama hr = vss_ctx.pVssbc->DoSnapshotSet(&vss_ctx.pAsyncSnapshot); 502b39297aeSTomoki Sekiyama if (FAILED(hr)) { 503b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to do snapshot set"); 504b39297aeSTomoki Sekiyama goto out; 505b39297aeSTomoki Sekiyama } 506b39297aeSTomoki Sekiyama 507b39297aeSTomoki Sekiyama /* Need to call QueryStatus several times to make VSS provider progress */ 508b39297aeSTomoki Sekiyama for (i = 0; i < VSS_TIMEOUT_FREEZE_MSEC/VSS_TIMEOUT_EVENT_MSEC; i++) { 509b39297aeSTomoki Sekiyama HRESULT hr2 = vss_ctx.pAsyncSnapshot->QueryStatus(&hr, NULL); 510b39297aeSTomoki Sekiyama if (FAILED(hr2)) { 511b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to do snapshot set"); 512b39297aeSTomoki Sekiyama goto out; 513b39297aeSTomoki Sekiyama } 514b39297aeSTomoki Sekiyama if (hr != VSS_S_ASYNC_PENDING) { 515b39297aeSTomoki Sekiyama err_set(errset, E_FAIL, 516b39297aeSTomoki Sekiyama "DoSnapshotSet exited without Frozen event"); 517b39297aeSTomoki Sekiyama goto out; 518b39297aeSTomoki Sekiyama } 519b39297aeSTomoki Sekiyama wait_status = WaitForSingleObject(vss_ctx.hEventFrozen, 520b39297aeSTomoki Sekiyama VSS_TIMEOUT_EVENT_MSEC); 521b39297aeSTomoki Sekiyama if (wait_status != WAIT_TIMEOUT) { 522b39297aeSTomoki Sekiyama break; 523b39297aeSTomoki Sekiyama } 524b39297aeSTomoki Sekiyama } 5254d80d20fSChen Hanxiao 5264d80d20fSChen Hanxiao if (wait_status == WAIT_TIMEOUT) { 5274d80d20fSChen Hanxiao err_set(errset, E_FAIL, 5284d80d20fSChen Hanxiao "timeout when try to receive Frozen event from VSS provider"); 5294d80d20fSChen Hanxiao /* If we are here, VSS had timeout. 5304d80d20fSChen Hanxiao * Don't call AbortBackup, just return directly. 5314d80d20fSChen Hanxiao */ 5324d80d20fSChen Hanxiao goto out1; 5334d80d20fSChen Hanxiao } 5344d80d20fSChen Hanxiao 535b39297aeSTomoki Sekiyama if (wait_status != WAIT_OBJECT_0) { 536b39297aeSTomoki Sekiyama err_set(errset, E_FAIL, 537b39297aeSTomoki Sekiyama "couldn't receive Frozen event from VSS provider"); 538b39297aeSTomoki Sekiyama goto out; 539b39297aeSTomoki Sekiyama } 540b39297aeSTomoki Sekiyama 5410692b03eSChen Hanxiao if (mountpoints) { 5420692b03eSChen Hanxiao *num_vols = vss_ctx.cFrozenVols = num_mount_points; 5430692b03eSChen Hanxiao } else { 544b39297aeSTomoki Sekiyama *num_vols = vss_ctx.cFrozenVols = num_fixed_drives; 5450692b03eSChen Hanxiao } 5460692b03eSChen Hanxiao 54761df91b3SKonstantin Kostiuk qga_debug("end successful"); 548b39297aeSTomoki Sekiyama return; 549b39297aeSTomoki Sekiyama 550b39297aeSTomoki Sekiyama out: 551b39297aeSTomoki Sekiyama if (vss_ctx.pVssbc) { 552b39297aeSTomoki Sekiyama vss_ctx.pVssbc->AbortBackup(); 553b39297aeSTomoki Sekiyama } 5544d80d20fSChen Hanxiao 5554d80d20fSChen Hanxiao out1: 556b39297aeSTomoki Sekiyama requester_cleanup(); 557b39297aeSTomoki Sekiyama CoUninitialize(); 55861df91b3SKonstantin Kostiuk 55961df91b3SKonstantin Kostiuk qga_debug_end; 560b39297aeSTomoki Sekiyama } 561b39297aeSTomoki Sekiyama 562b39297aeSTomoki Sekiyama 5630692b03eSChen Hanxiao void requester_thaw(int *num_vols, void *mountpints, ErrorSet *errset) 564b39297aeSTomoki Sekiyama { 56561df91b3SKonstantin Kostiuk qga_debug_begin; 566b39297aeSTomoki Sekiyama COMPointer<IVssAsync> pAsync; 567b39297aeSTomoki Sekiyama 5684c1b8f1eSTomoki Sekiyama if (!vss_ctx.hEventThaw) { 569b39297aeSTomoki Sekiyama /* 570b39297aeSTomoki Sekiyama * In this case, DoSnapshotSet is aborted or not started, 571b39297aeSTomoki Sekiyama * and no volumes must be frozen. We return without an error. 572b39297aeSTomoki Sekiyama */ 573b39297aeSTomoki Sekiyama *num_vols = 0; 57461df91b3SKonstantin Kostiuk qga_debug("finished, no volumes were frozen"); 57561df91b3SKonstantin Kostiuk 576b39297aeSTomoki Sekiyama return; 577b39297aeSTomoki Sekiyama } 578b39297aeSTomoki Sekiyama 579b39297aeSTomoki Sekiyama /* Tell the provider that the snapshot is finished. */ 580b39297aeSTomoki Sekiyama SetEvent(vss_ctx.hEventThaw); 581b39297aeSTomoki Sekiyama 582b39297aeSTomoki Sekiyama assert(vss_ctx.pVssbc); 583b39297aeSTomoki Sekiyama assert(vss_ctx.pAsyncSnapshot); 584b39297aeSTomoki Sekiyama 585b39297aeSTomoki Sekiyama HRESULT hr = WaitForAsync(vss_ctx.pAsyncSnapshot); 586b39297aeSTomoki Sekiyama switch (hr) { 587b39297aeSTomoki Sekiyama case VSS_S_ASYNC_FINISHED: 588b39297aeSTomoki Sekiyama hr = vss_ctx.pVssbc->BackupComplete(pAsync.replace()); 589b39297aeSTomoki Sekiyama if (SUCCEEDED(hr)) { 590b39297aeSTomoki Sekiyama hr = WaitForAsync(pAsync); 591b39297aeSTomoki Sekiyama } 592b39297aeSTomoki Sekiyama if (FAILED(hr)) { 593b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to complete backup"); 594b39297aeSTomoki Sekiyama } 595b39297aeSTomoki Sekiyama break; 596b39297aeSTomoki Sekiyama 597b39297aeSTomoki Sekiyama case (HRESULT)VSS_E_OBJECT_NOT_FOUND: 598b39297aeSTomoki Sekiyama /* 599b39297aeSTomoki Sekiyama * On Windows earlier than 2008 SP2 which does not support 600b39297aeSTomoki Sekiyama * VSS_VOLSNAP_ATTR_NO_AUTORECOVERY context, the final commit is not 601b39297aeSTomoki Sekiyama * skipped and VSS is aborted by VSS_E_OBJECT_NOT_FOUND. However, as 602b39297aeSTomoki Sekiyama * the system had been frozen until fsfreeze-thaw command was issued, 603b39297aeSTomoki Sekiyama * we ignore this error. 604b39297aeSTomoki Sekiyama */ 605b39297aeSTomoki Sekiyama vss_ctx.pVssbc->AbortBackup(); 606b39297aeSTomoki Sekiyama break; 607b39297aeSTomoki Sekiyama 608b39297aeSTomoki Sekiyama case VSS_E_UNEXPECTED_PROVIDER_ERROR: 609b39297aeSTomoki Sekiyama if (WaitForSingleObject(vss_ctx.hEventTimeout, 0) != WAIT_OBJECT_0) { 610b39297aeSTomoki Sekiyama err_set(errset, hr, "unexpected error in VSS provider"); 611b39297aeSTomoki Sekiyama break; 612b39297aeSTomoki Sekiyama } 613b39297aeSTomoki Sekiyama /* fall through if hEventTimeout is signaled */ 614b39297aeSTomoki Sekiyama 615b39297aeSTomoki Sekiyama case (HRESULT)VSS_E_HOLD_WRITES_TIMEOUT: 616b39297aeSTomoki Sekiyama err_set(errset, hr, "couldn't hold writes: " 617b39297aeSTomoki Sekiyama "fsfreeze is limited up to 10 seconds"); 618b39297aeSTomoki Sekiyama break; 619b39297aeSTomoki Sekiyama 620b39297aeSTomoki Sekiyama default: 621b39297aeSTomoki Sekiyama err_set(errset, hr, "failed to do snapshot set"); 622b39297aeSTomoki Sekiyama } 623b39297aeSTomoki Sekiyama 624b39297aeSTomoki Sekiyama if (err_is_set(errset)) { 625b39297aeSTomoki Sekiyama vss_ctx.pVssbc->AbortBackup(); 626b39297aeSTomoki Sekiyama } 627b39297aeSTomoki Sekiyama *num_vols = vss_ctx.cFrozenVols; 628b39297aeSTomoki Sekiyama requester_cleanup(); 629b39297aeSTomoki Sekiyama 630b39297aeSTomoki Sekiyama CoUninitialize(); 631f342cc93SSameeh Jubran StopService(); 63261df91b3SKonstantin Kostiuk 63361df91b3SKonstantin Kostiuk qga_debug_end; 634b39297aeSTomoki Sekiyama } 635