]> wimlib.net Git - wimlib/blob - src/win32_vss.c
6e5d3ebc5f2e21fa9f2882208c203b64be58fa91
[wimlib] / src / win32_vss.c
1 /*
2  * win32_vss.c - Experimental Windows-specific code for creating VSS (Volume
3  * Shadow Copy Service) snapshots.
4  */
5
6 /*
7  * Copyright (C) 2015 Eric Biggers
8  *
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
12  * later version.
13  *
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
17  * details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this file; if not, see http://www.gnu.org/licenses/.
21  */
22
23 #ifdef __WIN32__
24
25 #ifdef HAVE_CONFIG_H
26 #  include "config.h"
27 #endif
28
29 #include "wimlib/win32_common.h"
30
31 #include <cguid.h>
32 #include <pthread.h>
33
34 #include "wimlib/error.h"
35 #include "wimlib/util.h"
36 #include "wimlib/win32_vss.h"
37
38 /*----------------------------------------------------------------------------*
39  *                             VSS API declarations                           *
40  *----------------------------------------------------------------------------*/
41
42 typedef GUID VSS_ID;
43 typedef LONGLONG VSS_TIMESTAMP;
44 typedef WCHAR *VSS_PWSZ;
45
46 typedef enum {
47         VSS_BT_UNDEFINED      = 0,
48         VSS_BT_FULL           = 1,
49         VSS_BT_INCREMENTAL    = 2,
50         VSS_BT_DIFFERENTIAL   = 3,
51         VSS_BT_LOG            = 4,
52         VSS_BT_COPY           = 5,
53         VSS_BT_OTHER          = 6,
54 } VSS_BACKUP_TYPE;
55
56 typedef enum {
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,
73         VSS_SS_COUNT                        = 0x10,
74 } VSS_SNAPSHOT_STATE;
75
76 typedef enum {
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;
96
97 typedef enum {
98         VSS_CTX_BACKUP                      = 0,
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;
106
107 typedef struct {
108         VSS_ID             m_SnapshotId;
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;
117         VSS_ID             m_ProviderId;
118         LONG               m_lSnapshotAttributes;
119         VSS_TIMESTAMP      m_tsCreationTimestamp;
120         VSS_SNAPSHOT_STATE m_eStatus;
121 } VSS_SNAPSHOT_PROP;
122
123 typedef struct IVssAsyncVTable IVssAsyncVTable;
124
125 typedef struct {
126         IVssAsyncVTable *vtable;
127 } IVssAsync;
128
129 struct IVssAsyncVTable {
130         void *QueryInterface;
131         void *AddRef;
132         ULONG (WINAPI *Release)(IVssAsync *this);
133         void *Cancel;
134         HRESULT (WINAPI *Wait)(IVssAsync *this, DWORD dwMilliseconds);
135         void *QueryStatus;
136 };
137
138 typedef struct IVssBackupComponentsVTable IVssBackupComponentsVTable;
139
140 typedef struct {
141         IVssBackupComponentsVTable *vtable;
142 } IVssBackupComponents;
143
144 struct IVssBackupComponentsVTable {
145         void *QueryInterface;
146         void *AddRef;
147         ULONG (WINAPI *Release)(IVssBackupComponents *this);
148         void *GetWriterComponentsCount;
149         void *GetWriterComponents;
150         HRESULT (WINAPI *InitializeForBackup)(IVssBackupComponents *this,
151                                               BSTR bstrXML);
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;
164         void *AddComponent;
165         HRESULT (WINAPI *PrepareForBackup)(IVssBackupComponents *this,
166                                            IVssAsync **ppAsync);
167         void *AbortBackup;
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;
178         void *SaveAsXML;
179         void *BackupComplete;
180         void *AddAlternativeLocationMapping;
181         void *AddRestoreSubcomponent;
182         void *SetFileRestoreStatus;
183         void *AddNewTarget;
184         void *SetRangesFilePath;
185         void *PreRestore;
186         void *PostRestore;
187         HRESULT (WINAPI *SetContext)(IVssBackupComponents *this,
188                                      LONG lContext);
189         HRESULT (WINAPI *StartSnapshotSet)(IVssBackupComponents *this,
190                                            VSS_ID *pSnapshotSetId);
191         HRESULT (WINAPI *AddToSnapshotSet)(IVssBackupComponents *this,
192                                            VSS_PWSZ pwszVolumeName,
193                                            VSS_ID ProviderId,
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,
201                                                 VSS_ID SnapshotId,
202                                                 VSS_SNAPSHOT_PROP *pprop);
203         void *Query;
204         void *IsVolumeSupported;
205         void *DisableWriterClasses;
206         void *EnableWriterClasses;
207         void *DisableWriterInstances;
208         void *ExposeSnapshot;
209         void *RevertToSnapshot;
210         void *QueryRevertStatus;
211 };
212
213 /*----------------------------------------------------------------------------*
214  *                             VSS API initialization                         *
215  *----------------------------------------------------------------------------*/
216
217 static bool vss_initialized;
218 static pthread_mutex_t vss_initialization_mutex = PTHREAD_MUTEX_INITIALIZER;
219
220 /* vssapi.dll  */
221 static HANDLE hVssapi;
222 static HRESULT (WINAPI *func_CreateVssBackupComponentsInternal)(IVssBackupComponents **ppBackup);
223 static void (WINAPI *func_VssFreeSnapshotPropertiesInternal)(VSS_SNAPSHOT_PROP *pProp);
224
225 /* ole32.dll  */
226 static HANDLE hOle32;
227 static void (WINAPI *func_CoInitialize)(LPVOID *pvReserved);
228 static void (WINAPI *func_CoUninitialize)(void);
229
230 static bool
231 vss_global_init_impl(void)
232 {
233         hVssapi = LoadLibrary(L"vssapi.dll");
234         if (!hVssapi) {
235                 ERROR("vssapi.dll not found");
236                 goto err;
237         }
238
239         func_CreateVssBackupComponentsInternal =
240                 (void *)GetProcAddress(hVssapi, "CreateVssBackupComponentsInternal");
241         if (!func_CreateVssBackupComponentsInternal) {
242                 ERROR("CreateVssBackupComponentsInternal() not found in vssapi.dll");
243                 goto err_vssapi;
244         }
245
246         func_VssFreeSnapshotPropertiesInternal =
247                 (void *)GetProcAddress(hVssapi, "VssFreeSnapshotPropertiesInternal");
248         if (!func_VssFreeSnapshotPropertiesInternal) {
249                 ERROR("VssFreeSnapshotPropertiesInternal() not found in vssapi.dll");
250                 goto err_vssapi;
251         }
252
253         hOle32 = LoadLibrary(L"ole32.dll");
254         if (!hOle32) {
255                 ERROR("ole32.dll not found");
256                 goto err_vssapi;
257         }
258
259         func_CoInitialize = (void *)GetProcAddress(hOle32, "CoInitialize");
260         if (!func_CoInitialize) {
261                 ERROR("CoInitialize() not found in ole32.dll");
262                 goto err_ole32;
263         }
264
265         func_CoUninitialize = (void *)GetProcAddress(hOle32, "CoUninitialize");
266         if (!func_CoUninitialize) {
267                 ERROR("CoUninitialize() not found in ole32.dll");
268                 goto err_ole32;
269         }
270
271         (*func_CoInitialize)(NULL);
272         return true;
273
274 err_ole32:
275         FreeLibrary(hOle32);
276 err_vssapi:
277         FreeLibrary(hVssapi);
278 err:
279         return false;
280 }
281
282 static bool
283 vss_global_init(void)
284 {
285         if (vss_initialized)
286                 return true;
287
288         pthread_mutex_lock(&vss_initialization_mutex);
289         if (!vss_initialized)
290                 vss_initialized = vss_global_init_impl();
291         pthread_mutex_unlock(&vss_initialization_mutex);
292
293         if (vss_initialized)
294                 return true;
295         ERROR("The Volume Shadow Copy Service (VSS) API could not be "
296               "initialized. Probably it isn't supported on this computer.");
297         return false;
298 }
299
300 void
301 vss_global_cleanup(void)
302 {
303         if (!vss_initialized)
304                 return;
305
306         pthread_mutex_lock(&vss_initialization_mutex);
307         if (vss_initialized) {
308                 (*func_CoUninitialize)();
309                 FreeLibrary(hOle32);
310                 FreeLibrary(hVssapi);
311                 vss_initialized = false;
312         }
313         pthread_mutex_unlock(&vss_initialization_mutex);
314 }
315
316 /*----------------------------------------------------------------------------*
317  *                             VSS implementation                             *
318  *----------------------------------------------------------------------------*/
319
320 struct vss_snapshot_internal {
321         struct vss_snapshot base;
322         IVssBackupComponents *vss;
323         VSS_SNAPSHOT_PROP props;
324 };
325
326 /* Delete the specified VSS snapshot.  */
327 void
328 vss_delete_snapshot(struct vss_snapshot *snapshot)
329 {
330         struct vss_snapshot_internal *internal;
331
332         internal = container_of(snapshot, struct vss_snapshot_internal, base);
333
334         if (internal->props.m_pwszSnapshotDeviceObject)
335                 (*func_VssFreeSnapshotPropertiesInternal)(&internal->props);
336         if (internal->vss)
337                 internal->vss->vtable->Release(internal->vss);
338         FREE(internal);
339 }
340
341 static HRESULT
342 wait_and_release(IVssAsync *async)
343 {
344         HRESULT res = async->vtable->Wait(async, INFINITE);
345         async->vtable->Release(async);
346         return res;
347 }
348
349 static bool
350 request_vss_snapshot(IVssBackupComponents *vss, wchar_t *volume,
351                      VSS_ID *snapshot_id)
352 {
353         HRESULT res;
354         IVssAsync *async;
355
356         res = vss->vtable->InitializeForBackup(vss, NULL);
357         if (FAILED(res)) {
358                 ERROR("IVssBackupComponents.InitializeForBackup() error: %x", res);
359                 return false;
360         }
361
362         res = vss->vtable->SetContext(vss, VSS_CTX_BACKUP);
363         if (FAILED(res)) {
364                 ERROR("IVssBackupComponents.SetContext() error: %x", res);
365                 return false;
366         }
367
368         res = vss->vtable->SetBackupState(vss, FALSE, TRUE, VSS_BT_COPY, FALSE);
369         if (FAILED(res)) {
370                 ERROR("IVssBackupComponents.SetBackupState() error: %x", res);
371                 return false;
372         }
373
374         res = vss->vtable->StartSnapshotSet(vss, snapshot_id);
375         if (FAILED(res)) {
376                 ERROR("IVssBackupComponents.StartSnapshotSet() error: %x", res);
377                 return false;
378         }
379
380         res = vss->vtable->AddToSnapshotSet(vss, volume, (GUID){}, snapshot_id);
381         if (FAILED(res)) {
382                 ERROR("IVssBackupComponents.AddToSnapshotSet() error: %x", res);
383                 return false;
384         }
385
386         res = vss->vtable->PrepareForBackup(vss, &async);
387         if (FAILED(res)) {
388                 ERROR("IVssBackupComponents.PrepareForBackup() error: %x", res);
389                 return false;
390         }
391         res = wait_and_release(async);
392         if (FAILED(res)) {
393                 ERROR("IVssAsync.Wait() error while preparing for backup: %x", res);
394                 return false;
395         }
396
397         res = vss->vtable->DoSnapshotSet(vss, &async);
398         if (FAILED(res)) {
399                 ERROR("IVssBackupComponents.DoSnapshotSet() error: %x", res);
400                 return false;
401         }
402         res = wait_and_release(async);
403         if (FAILED(res)) {
404                 ERROR("IVssAsync.Wait() error while doing snapshot set: %x", res);
405                 return false;
406         }
407
408         return true;
409 }
410
411 /*
412  * Create a VSS snapshot of the specified @volume.  Return the NT namespace path
413  * to the snapshot root directory in @vss_path_ret and a handle to the snapshot
414  * in @snapshot_ret.
415  */
416 int
417 vss_create_snapshot(const wchar_t *source, UNICODE_STRING *vss_path_ret,
418                     struct vss_snapshot **snapshot_ret)
419 {
420         wchar_t *source_abspath;
421         wchar_t volume[4];
422         VSS_ID snapshot_id;
423         struct vss_snapshot_internal *snapshot = NULL;
424         IVssBackupComponents *vss;
425         HRESULT res;
426         int ret;
427
428         source_abspath = realpath(source, NULL);
429         if (!source_abspath) {
430                 ret = WIMLIB_ERR_NOMEM;
431                 goto err;
432         }
433
434         if (source_abspath[0] == L'\0' || source_abspath[1] != L':' ||
435             source_abspath[2] != L'\\') {
436                 ERROR("\"%ls\" (full path \"%ls\"): Path format not recognized",
437                       source, source_abspath);
438                 ret = WIMLIB_ERR_UNSUPPORTED;
439                 goto err;
440         }
441
442         wsprintf(volume, L"%lc:\\", source_abspath[0]);
443
444         snapshot = CALLOC(1, sizeof(*snapshot));
445         if (!snapshot) {
446                 ret = WIMLIB_ERR_NOMEM;
447                 goto err;
448         }
449
450         if (!vss_global_init())
451                 goto vss_err;
452
453         res = (*func_CreateVssBackupComponentsInternal)(&vss);
454         if (FAILED(res)) {
455                 ERROR("CreateVssBackupComponents error: %x", res);
456                 goto vss_err;
457         }
458
459         snapshot->vss = vss;
460
461         if (!request_vss_snapshot(vss, volume, &snapshot_id))
462                 goto vss_err;
463
464         res = vss->vtable->GetSnapshotProperties(vss, snapshot_id, &snapshot->props);
465         if (FAILED(res)) {
466                 ERROR("IVssBackupComponents.GetSnapshotProperties() error: %x", res);
467                 goto vss_err;
468         }
469
470         if (wcsncmp(snapshot->props.m_pwszSnapshotDeviceObject, L"\\\\?\\", 4)) {
471                 ERROR("Unexpected volume shadow device path: %ls",
472                       snapshot->props.m_pwszSnapshotDeviceObject);
473                 goto vss_err;
474         }
475
476         vss_path_ret->MaximumLength = sizeof(wchar_t) *
477                 (wcslen(snapshot->props.m_pwszSnapshotDeviceObject) +
478                  1 + wcslen(&source_abspath[3]) + 1);
479         vss_path_ret->Length = vss_path_ret->MaximumLength - sizeof(wchar_t);
480         vss_path_ret->Buffer = HeapAlloc(GetProcessHeap(), 0,
481                                          vss_path_ret->MaximumLength);
482         if (!vss_path_ret->Buffer) {
483                 ret = WIMLIB_ERR_NOMEM;
484                 goto err;
485         }
486
487         wsprintf(vss_path_ret->Buffer, L"\\??\\%ls\\%ls",
488                  &snapshot->props.m_pwszSnapshotDeviceObject[4],
489                  &source_abspath[3]);
490         *snapshot_ret = &snapshot->base;
491         snapshot->base.refcnt = 1;
492         ret = 0;
493         goto out;
494
495 vss_err:
496         ret = WIMLIB_ERR_SNAPSHOT_FAILURE;
497         ERROR("A problem occurred while creating a VSS snapshot of \"%ls\".\n"
498               "        Aborting the operation.", volume);
499 err:
500         if (snapshot)
501                 vss_delete_snapshot(&snapshot->base);
502 out:
503         FREE(source_abspath);
504         return ret;
505 }
506
507 #endif /* __WIN32__ */