2 * win32_vss.c - Windows-specific code for creating VSS (Volume Shadow Copy
7 * Copyright (C) 2015-2023 Eric Biggers
9 * This file is free software; you can redistribute it and/or modify it under
10 * the terms of the GNU Lesser General Public License as published by the Free
11 * Software Foundation; either version 3 of the License, or (at your option) any
14 * This file is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this file; if not, see https://www.gnu.org/licenses/.
29 #include "wimlib/win32_common.h"
33 #include "wimlib/error.h"
34 #include "wimlib/threads.h"
35 #include "wimlib/util.h"
36 #include "wimlib/win32_vss.h"
38 /*----------------------------------------------------------------------------*
39 * VSS API declarations *
40 *----------------------------------------------------------------------------*/
43 typedef LONGLONG VSS_TIMESTAMP;
44 typedef WCHAR *VSS_PWSZ;
49 VSS_BT_INCREMENTAL = 2,
50 VSS_BT_DIFFERENTIAL = 3,
57 VSS_SS_UNKNOWN = 0x00,
58 VSS_SS_PREPARING = 0x01,
59 VSS_SS_PROCESSING_PREPARE = 0x02,
60 VSS_SS_PREPARED = 0x03,
61 VSS_SS_PROCESSING_PRECOMMIT = 0x04,
62 VSS_SS_PRECOMMITTED = 0x05,
63 VSS_SS_PROCESSING_COMMIT = 0x06,
64 VSS_SS_COMMITTED = 0x07,
65 VSS_SS_PROCESSING_POSTCOMMIT = 0x08,
66 VSS_SS_PROCESSING_PREFINALCOMMIT = 0x09,
67 VSS_SS_PREFINALCOMMITTED = 0x0a,
68 VSS_SS_PROCESSING_POSTFINALCOMMIT = 0x0b,
69 VSS_SS_CREATED = 0x0c,
70 VSS_SS_ABORTED = 0x0d,
71 VSS_SS_DELETED = 0x0e,
72 VSS_SS_POSTCOMMITTED = 0x0f,
77 VSS_VOLSNAP_ATTR_PERSISTENT = 0x00000001,
78 VSS_VOLSNAP_ATTR_NO_AUTORECOVERY = 0x00000002,
79 VSS_VOLSNAP_ATTR_CLIENT_ACCESSIBLE = 0x00000004,
80 VSS_VOLSNAP_ATTR_NO_AUTO_RELEASE = 0x00000008,
81 VSS_VOLSNAP_ATTR_NO_WRITERS = 0x00000010,
82 VSS_VOLSNAP_ATTR_TRANSPORTABLE = 0x00000020,
83 VSS_VOLSNAP_ATTR_NOT_SURFACED = 0x00000040,
84 VSS_VOLSNAP_ATTR_NOT_TRANSACTED = 0x00000080,
85 VSS_VOLSNAP_ATTR_HARDWARE_ASSISTED = 0x00010000,
86 VSS_VOLSNAP_ATTR_DIFFERENTIAL = 0x00020000,
87 VSS_VOLSNAP_ATTR_PLEX = 0x00040000,
88 VSS_VOLSNAP_ATTR_IMPORTED = 0x00080000,
89 VSS_VOLSNAP_ATTR_EXPOSED_LOCALLY = 0x00100000,
90 VSS_VOLSNAP_ATTR_EXPOSED_REMOTELY = 0x00200000,
91 VSS_VOLSNAP_ATTR_AUTORECOVER = 0x00400000,
92 VSS_VOLSNAP_ATTR_ROLLBACK_RECOVERY = 0x00800000,
93 VSS_VOLSNAP_ATTR_DELAYED_POSTSNAPSHOT = 0x01000000,
94 VSS_VOLSNAP_ATTR_TXF_RECOVERY = 0x02000000,
95 } VSS_VOLUME_SNAPSHOT_ATTRIBUTES;
99 VSS_CTX_FILE_SHARE_BACKUP = VSS_VOLSNAP_ATTR_NO_WRITERS,
100 VSS_CTX_NAS_ROLLBACK = ( ( VSS_VOLSNAP_ATTR_PERSISTENT | VSS_VOLSNAP_ATTR_NO_AUTO_RELEASE ) | VSS_VOLSNAP_ATTR_NO_WRITERS ),
101 VSS_CTX_APP_ROLLBACK = ( VSS_VOLSNAP_ATTR_PERSISTENT | VSS_VOLSNAP_ATTR_NO_AUTO_RELEASE ),
102 VSS_CTX_CLIENT_ACCESSIBLE = ( ( ( VSS_VOLSNAP_ATTR_PERSISTENT | VSS_VOLSNAP_ATTR_CLIENT_ACCESSIBLE ) | VSS_VOLSNAP_ATTR_NO_AUTO_RELEASE ) | VSS_VOLSNAP_ATTR_NO_WRITERS ),
103 VSS_CTX_CLIENT_ACCESSIBLE_WRITERS = ( ( VSS_VOLSNAP_ATTR_PERSISTENT | VSS_VOLSNAP_ATTR_CLIENT_ACCESSIBLE ) | VSS_VOLSNAP_ATTR_NO_AUTO_RELEASE ),
104 VSS_CTX_ALL = 0xffffffff,
105 } VSS_SNAPSHOT_CONTEXT;
109 VSS_ID m_SnapshotSetId;
110 LONG m_lSnapshotsCount;
111 VSS_PWSZ m_pwszSnapshotDeviceObject;
112 VSS_PWSZ m_pwszOriginalVolumeName;
113 VSS_PWSZ m_pwszOriginatingMachine;
114 VSS_PWSZ m_pwszServiceMachine;
115 VSS_PWSZ m_pwszExposedName;
116 VSS_PWSZ m_pwszExposedPath;
118 LONG m_lSnapshotAttributes;
119 VSS_TIMESTAMP m_tsCreationTimestamp;
120 VSS_SNAPSHOT_STATE m_eStatus;
123 typedef struct IVssAsyncVTable IVssAsyncVTable;
126 IVssAsyncVTable *vtable;
129 struct IVssAsyncVTable {
130 void *QueryInterface;
132 ULONG (WINAPI *Release)(IVssAsync *this);
134 HRESULT (WINAPI *Wait)(IVssAsync *this, DWORD dwMilliseconds);
138 typedef struct IVssBackupComponentsVTable IVssBackupComponentsVTable;
141 IVssBackupComponentsVTable *vtable;
142 } IVssBackupComponents;
144 struct IVssBackupComponentsVTable {
145 void *QueryInterface;
147 ULONG (WINAPI *Release)(IVssBackupComponents *this);
148 void *GetWriterComponentsCount;
149 void *GetWriterComponents;
150 HRESULT (WINAPI *InitializeForBackup)(IVssBackupComponents *this,
152 HRESULT (WINAPI *SetBackupState)(IVssBackupComponents *this,
153 BOOLEAN bSelectComponents,
154 BOOLEAN bBackupBootableSystemState,
155 VSS_BACKUP_TYPE backupType,
156 BOOLEAN bPartialFileSupport);
157 void *InitializeForRestore;
158 void *SetRestoreState;
159 HRESULT (WINAPI *GatherWriterMetadata)(IVssBackupComponents *this,
160 IVssAsync **ppAsync);
161 void *GetWriterMetadataCount;
162 void *GetWriterMetadata;
163 void *FreeWriterMetadata;
165 HRESULT (WINAPI *PrepareForBackup)(IVssBackupComponents *this,
166 IVssAsync **ppAsync);
168 void *GatherWriterStatus;
169 void *GetWriterStatusCount;
170 void *FreeWriterStatus;
171 void *GetWriterStatus;
172 void *SetBackupSucceeded;
173 void *SetBackupOptions;
174 void *SetSelectedForRestore;
175 void *SetRestoreOptions;
176 void *SetAdditionalRestores;
177 void *SetPreviousBackupStamp;
179 void *BackupComplete;
180 void *AddAlternativeLocationMapping;
181 void *AddRestoreSubcomponent;
182 void *SetFileRestoreStatus;
184 void *SetRangesFilePath;
187 HRESULT (WINAPI *SetContext)(IVssBackupComponents *this,
189 HRESULT (WINAPI *StartSnapshotSet)(IVssBackupComponents *this,
190 VSS_ID *pSnapshotSetId);
191 HRESULT (WINAPI *AddToSnapshotSet)(IVssBackupComponents *this,
192 VSS_PWSZ pwszVolumeName,
194 VSS_ID *pidSnapshot);
195 HRESULT (WINAPI *DoSnapshotSet)(IVssBackupComponents *this,
196 IVssAsync **ppAsync);
197 void *DeleteSnapshots;
198 void *ImportSnapshots;
199 void *BreakSnapshotSet;
200 HRESULT (WINAPI *GetSnapshotProperties)(IVssBackupComponents *this,
202 VSS_SNAPSHOT_PROP *pprop);
204 void *IsVolumeSupported;
205 void *DisableWriterClasses;
206 void *EnableWriterClasses;
207 void *DisableWriterInstances;
208 void *ExposeSnapshot;
209 void *RevertToSnapshot;
210 void *QueryRevertStatus;
213 /*----------------------------------------------------------------------------*
214 * VSS API initialization *
215 *----------------------------------------------------------------------------*/
217 static bool vss_initialized;
218 static struct mutex vss_initialization_mutex = MUTEX_INITIALIZER;
221 static HANDLE hVssapi;
222 static HRESULT (WINAPI *func_CreateVssBackupComponentsInternal)(IVssBackupComponents **ppBackup);
223 static void (WINAPI *func_VssFreeSnapshotPropertiesInternal)(VSS_SNAPSHOT_PROP *pProp);
226 static HANDLE hOle32;
227 static void (WINAPI *func_CoInitialize)(LPVOID *pvReserved);
228 static void (WINAPI *func_CoUninitialize)(void);
231 vss_global_init_impl(void)
233 hVssapi = LoadLibrary(L"vssapi.dll");
235 ERROR("vssapi.dll not found");
239 func_CreateVssBackupComponentsInternal =
240 (void *)GetProcAddress(hVssapi, "CreateVssBackupComponentsInternal");
241 if (!func_CreateVssBackupComponentsInternal) {
242 ERROR("CreateVssBackupComponentsInternal() not found in vssapi.dll");
246 func_VssFreeSnapshotPropertiesInternal =
247 (void *)GetProcAddress(hVssapi, "VssFreeSnapshotPropertiesInternal");
248 if (!func_VssFreeSnapshotPropertiesInternal) {
249 ERROR("VssFreeSnapshotPropertiesInternal() not found in vssapi.dll");
253 hOle32 = LoadLibrary(L"ole32.dll");
255 ERROR("ole32.dll not found");
259 func_CoInitialize = (void *)GetProcAddress(hOle32, "CoInitialize");
260 if (!func_CoInitialize) {
261 ERROR("CoInitialize() not found in ole32.dll");
265 func_CoUninitialize = (void *)GetProcAddress(hOle32, "CoUninitialize");
266 if (!func_CoUninitialize) {
267 ERROR("CoUninitialize() not found in ole32.dll");
271 (*func_CoInitialize)(NULL);
277 FreeLibrary(hVssapi);
283 vss_global_init(void)
288 mutex_lock(&vss_initialization_mutex);
289 if (!vss_initialized)
290 vss_initialized = vss_global_init_impl();
291 mutex_unlock(&vss_initialization_mutex);
295 ERROR("The Volume Shadow Copy Service (VSS) API could not be "
301 vss_global_cleanup(void)
303 if (!vss_initialized)
306 mutex_lock(&vss_initialization_mutex);
307 if (vss_initialized) {
308 (*func_CoUninitialize)();
310 FreeLibrary(hVssapi);
311 vss_initialized = false;
313 mutex_unlock(&vss_initialization_mutex);
316 /*----------------------------------------------------------------------------*
317 * VSS implementation *
318 *----------------------------------------------------------------------------*/
320 struct vss_snapshot_internal {
321 struct vss_snapshot base;
322 IVssBackupComponents *vss;
323 VSS_SNAPSHOT_PROP props;
326 /* Delete the specified VSS snapshot. */
328 vss_delete_snapshot(struct vss_snapshot *snapshot)
330 struct vss_snapshot_internal *internal;
332 internal = container_of(snapshot, struct vss_snapshot_internal, base);
334 if (internal->props.m_pwszSnapshotDeviceObject)
335 (*func_VssFreeSnapshotPropertiesInternal)(&internal->props);
337 internal->vss->vtable->Release(internal->vss);
342 wait_and_release(IVssAsync *async)
344 HRESULT res = async->vtable->Wait(async, INFINITE);
346 async->vtable->Release(async);
351 request_vss_snapshot(IVssBackupComponents *vss, wchar_t *volume,
357 res = vss->vtable->InitializeForBackup(vss, NULL);
359 ERROR("IVssBackupComponents.InitializeForBackup() error: %x",
364 res = vss->vtable->SetBackupState(vss, FALSE, TRUE, VSS_BT_COPY, FALSE);
366 ERROR("IVssBackupComponents.SetBackupState() error: %x",
371 res = vss->vtable->StartSnapshotSet(vss, snapshot_id);
373 ERROR("IVssBackupComponents.StartSnapshotSet() error: %x",
378 res = vss->vtable->AddToSnapshotSet(vss, volume, (GUID){}, snapshot_id);
380 ERROR("IVssBackupComponents.AddToSnapshotSet() error: %x",
385 res = vss->vtable->PrepareForBackup(vss, &async);
387 ERROR("IVssBackupComponents.PrepareForBackup() error: %x",
391 res = wait_and_release(async);
393 ERROR("IVssAsync.Wait() error while preparing for backup: %x",
398 res = vss->vtable->DoSnapshotSet(vss, &async);
400 ERROR("IVssBackupComponents.DoSnapshotSet() error: %x",
404 res = wait_and_release(async);
406 ERROR("IVssAsync.Wait() error while doing snapshot set: %x",
418 if (sizeof(size_t) == 4)
419 IsWow64Process(GetCurrentProcess(), &wow64);
424 * Create a VSS snapshot of the specified @volume. Return the NT namespace path
425 * to the snapshot root directory in @vss_path_ret and a handle to the snapshot
429 vss_create_snapshot(const wchar_t *source, UNICODE_STRING *vss_path_ret,
430 struct vss_snapshot **snapshot_ret)
432 wchar_t *source_abspath;
435 struct vss_snapshot_internal *snapshot = NULL;
436 IVssBackupComponents *vss;
440 source_abspath = realpath(source, NULL);
441 if (!source_abspath) {
442 ret = WIMLIB_ERR_NOMEM;
446 if (source_abspath[0] == L'\0' || source_abspath[1] != L':' ||
447 source_abspath[2] != L'\\') {
448 ERROR("\"%ls\" (full path \"%ls\"): Path format not recognized",
449 source, source_abspath);
450 ret = WIMLIB_ERR_UNSUPPORTED;
454 wsprintf(volume, L"%lc:\\", source_abspath[0]);
456 snapshot = CALLOC(1, sizeof(*snapshot));
458 ret = WIMLIB_ERR_NOMEM;
462 if (!vss_global_init())
465 res = (*func_CreateVssBackupComponentsInternal)(&vss);
467 ERROR("CreateVssBackupComponents error: %x", (u32)res);
473 if (!request_vss_snapshot(vss, volume, &snapshot_id))
476 res = vss->vtable->GetSnapshotProperties(vss, snapshot_id, &snapshot->props);
478 ERROR("IVssBackupComponents.GetSnapshotProperties() error: %x",
483 if (wcsncmp(snapshot->props.m_pwszSnapshotDeviceObject, L"\\\\?\\", 4)) {
484 ERROR("Unexpected volume shadow device path: %ls",
485 snapshot->props.m_pwszSnapshotDeviceObject);
489 vss_path_ret->MaximumLength = sizeof(wchar_t) *
490 (wcslen(snapshot->props.m_pwszSnapshotDeviceObject) +
491 1 + wcslen(&source_abspath[3]) + 1);
492 vss_path_ret->Length = vss_path_ret->MaximumLength - sizeof(wchar_t);
493 vss_path_ret->Buffer = HeapAlloc(GetProcessHeap(), 0,
494 vss_path_ret->MaximumLength);
495 if (!vss_path_ret->Buffer) {
496 ret = WIMLIB_ERR_NOMEM;
500 wsprintf(vss_path_ret->Buffer, L"\\??\\%ls\\%ls",
501 &snapshot->props.m_pwszSnapshotDeviceObject[4],
503 *snapshot_ret = &snapshot->base;
504 snapshot->base.refcnt = 1;
509 ret = WIMLIB_ERR_SNAPSHOT_FAILURE;
511 ERROR("64-bit Windows doesn't allow 32-bit applications to "
512 "create VSS snapshots.\n"
513 " Run the 64-bit version of this application "
516 ERROR("A problem occurred while creating a VSS snapshot of "
518 " Aborting the operation.", volume);
522 vss_delete_snapshot(&snapshot->base);
524 FREE(source_abspath);