1 /*
2 Bacula(R) - The Network Backup Solution
3
4 Copyright (C) 2000-2020 Kern Sibbald
5
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
8
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
13
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
16
17 Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 // -*- Mode: C++ -*-
20 // vss.cpp -- Interface to Volume Shadow Copies (VSS)
21 //
22 // Copyright transferred from MATRIX-Computer GmbH to
23 // Kern Sibbald by express permission.
24 //
25 // Author : Thorsten Engel
26 // Created On : Fri May 06 21:44:00 2005
27
28
29 #ifdef WIN32_VSS
30
31 #include "bacula.h"
32 #include "filed/filed.h"
33
34 #undef setlocale
35
36 // STL includes
37 #include <vector>
38 #include <algorithm>
39 #include <string>
40 #include <sstream>
41 #include <fstream>
42 using namespace std;
43
44 #include "ms_atl.h"
45 #include <objbase.h>
46
47 /*
48 * Kludges to get Vista code to compile.
49 * by Kern Sibbald - June 2007
50 */
51 #define __in IN
52 #define __out OUT
53 #define __RPC_unique_pointer
54 #define __RPC_string
55 #ifndef __RPC__out_ecount_part
56 #define __RPC__out_ecount_part(x, y)
57 #endif
58 #define __RPC__deref_inout_opt
59 #define __RPC__out
60
61 #if !defined(ENABLE_NLS)
62 #define setlocale(p, d)
63 #endif
64
65 #ifdef HAVE_STRSAFE_H
66 // Used for safe string manipulation
67 #include <strsafe.h>
68 #endif
69
70 #ifdef HAVE_MINGW
71 class IXMLDOMDocument;
72 #endif
73
74 /* Reduce compiler warnings from Windows vss code */
75 #undef uuid
76 #define uuid(x)
77
78 #ifdef B_VSS_XP
79 #define VSSClientGeneric VSSClientXP
80 #include "inc/WinXP/vss.h"
81 #include "inc/WinXP/vswriter.h"
82 #include "inc/WinXP/vsbackup.h"
83
84 #endif
85
86 #ifdef B_VSS_W2K3
87 #define VSSClientGeneric VSSClient2003
88 #include "inc/Win2003/vss.h"
89 #include "inc/Win2003/vswriter.h"
90 #include "inc/Win2003/vsbackup.h"
91 #endif
92
93 #ifdef B_VSS_VISTA
94 #define VSSClientGeneric VSSClientVista
95 #include "inc/Win2003/vss.h"
96 #include "inc/Win2003/vswriter.h"
97 #include "inc/Win2003/vsbackup.h"
98 #endif
99
100 #include "vss.h"
101
JmsgVssApiStatus(JCR * jcr,int msg_status,HRESULT hr,const char * apiName)102 static void JmsgVssApiStatus(JCR *jcr, int msg_status, HRESULT hr, const char *apiName)
103 {
104 const char *errmsg;
105 if (hr == S_OK || hr == VSS_S_ASYNC_FINISHED) {
106 return;
107 }
108 switch (hr) {
109 case E_INVALIDARG:
110 errmsg = "One of the parameter values is not valid.";
111 break;
112 case E_OUTOFMEMORY:
113 errmsg = "The caller is out of memory or other system resources.";
114 break;
115 case E_ACCESSDENIED:
116 errmsg = "The caller does not have sufficient backup privileges or is not an administrator.";
117 break;
118 case VSS_E_INVALID_XML_DOCUMENT:
119 errmsg = "The XML document is not valid.";
120 break;
121 case VSS_E_OBJECT_NOT_FOUND:
122 errmsg = "The specified file does not exist.";
123 break;
124 case VSS_E_BAD_STATE:
125 errmsg = "Object is not initialized; called during restore or not called in correct sequence.";
126 break;
127 case VSS_E_WRITER_INFRASTRUCTURE:
128 errmsg = "The writer infrastructure is not operating properly. Check that the Event Service and VSS have been started, and check for errors associated with those services in the error log.";
129 break;
130 case VSS_S_ASYNC_CANCELLED:
131 errmsg = "The asynchronous operation was canceled by a previous call to IVssAsync::Cancel.";
132 break;
133 case VSS_S_ASYNC_PENDING:
134 errmsg = "The asynchronous operation is still running.";
135 break;
136 case RPC_E_CHANGED_MODE:
137 errmsg = "Previous call to CoInitializeEx specified the multithread apartment (MTA). This call indicates single-threaded apartment has occurred.";
138 break;
139 case S_FALSE:
140 errmsg = "No writer found for the current component.";
141 break;
142 default:
143 errmsg = "Unexpected error. The error code is logged in the error log file.";
144 break;
145 }
146 Jmsg(jcr, msg_status, 0, "VSS API failure calling \"%s\". ERR=%s\n", apiName, errmsg);
147 }
148
149 #ifndef VSS_WS_FAILED_AT_BACKUPSHUTDOWN
150 #define VSS_WS_FAILED_AT_BACKUPSHUTDOWN (VSS_WRITER_STATE)15
151 #endif
152
153
JmsgVssWriterStatus(JCR * jcr,int msg_status,VSS_WRITER_STATE eWriterStatus,char * writer_name)154 static void JmsgVssWriterStatus(JCR *jcr, int msg_status, VSS_WRITER_STATE eWriterStatus, char *writer_name)
155 {
156 const char *errmsg;
157
158 /* The following are normal states */
159 if (eWriterStatus == VSS_WS_STABLE ||
160 eWriterStatus == VSS_WS_WAITING_FOR_BACKUP_COMPLETE) {
161 return;
162 }
163
164 /* Potential errors */
165 switch (eWriterStatus) {
166 default:
167 case VSS_WS_UNKNOWN:
168 errmsg = "The writer's state is not known. This is a writer error.";
169 break;
170 case VSS_WS_WAITING_FOR_FREEZE:
171 errmsg = "The writer is waiting for the freeze state.";
172 break;
173 case VSS_WS_WAITING_FOR_THAW:
174 errmsg = "The writer is waiting for the thaw state.";
175 break;
176 case VSS_WS_WAITING_FOR_POST_SNAPSHOT:
177 errmsg = "The writer is waiting for the PostSnapshot state.";
178 break;
179 case VSS_WS_WAITING_FOR_BACKUP_COMPLETE:
180 errmsg = "The writer is waiting for the requester to finish its backup operation.";
181 break;
182 case VSS_WS_FAILED_AT_IDENTIFY:
183 errmsg = "The writer vetoed the shadow copy creation process at the writer identification state.";
184 break;
185 case VSS_WS_FAILED_AT_PREPARE_BACKUP:
186 errmsg = "The writer vetoed the shadow copy creation process during the backup preparation state.";
187 break;
188 case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
189 errmsg = "The writer vetoed the shadow copy creation process during the PrepareForSnapshot state.";
190 break;
191 case VSS_WS_FAILED_AT_FREEZE:
192 errmsg = "The writer vetoed the shadow copy creation process during the freeze state.";
193 break;
194 case VSS_WS_FAILED_AT_THAW:
195 errmsg = "The writer vetoed the shadow copy creation process during the thaw state.";
196 break;
197 case VSS_WS_FAILED_AT_POST_SNAPSHOT:
198 errmsg = "The writer vetoed the shadow copy creation process during the PostSnapshot state.";
199 break;
200 case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
201 errmsg = "The shadow copy has been created and the writer failed during the BackupComplete state.";
202 break;
203 case VSS_WS_FAILED_AT_PRE_RESTORE:
204 errmsg = "The writer failed during the PreRestore state.";
205 break;
206 case VSS_WS_FAILED_AT_POST_RESTORE:
207 errmsg = "The writer failed during the PostRestore state.";
208 break;
209 case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
210 errmsg = "The writer failed during the shutdown of the backup application.";
211
212 }
213 Jmsg(jcr, msg_status, 0, "VSS Writer \"%s\" has invalid state. ERR=%s\n", writer_name, errmsg);
214 }
215
216 /*
217 *
218 * some helper functions
219 *
220 *
221 */
222
223
224 // Defined in vss.cpp
225 // Append a backslash to the current string
226 wstring AppendBackslash(wstring str);
227 // Get the unique volume name for the given path
228 wstring GetUniqueVolumeNameForPath(wstring path, wstring &rootPath);
229
230 // Helper macro for quick treatment of case statements for error codes
231 #define GEN_MERGE(A, B) A##B
232 #define GEN_MAKE_W(A) GEN_MERGE(L, A)
233
234 #define CHECK_CASE_FOR_CONSTANT(value) \
235 case value: return (GEN_MAKE_W(#value));
236
237
238 // Convert a writer status into a string
GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus)239 inline const wchar_t* GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus)
240 {
241 switch (eWriterStatus) {
242 CHECK_CASE_FOR_CONSTANT(VSS_WS_STABLE);
243 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_FREEZE);
244 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_THAW);
245 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_POST_SNAPSHOT);
246 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_BACKUP_COMPLETE);
247 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_IDENTIFY);
248 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_BACKUP);
249 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_SNAPSHOT);
250 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_FREEZE);
251 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_THAW);
252 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_SNAPSHOT);
253 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_BACKUP_COMPLETE);
254 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PRE_RESTORE);
255 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_RESTORE);
256 default:
257 return L"Error or Undefined";
258 }
259 }
260
261 // Constructor
262
VSSClientGeneric()263 VSSClientGeneric::VSSClientGeneric()
264 {
265 }
266
267 // Destructor
~VSSClientGeneric()268 VSSClientGeneric::~VSSClientGeneric()
269 {
270 }
271
272 // Initialize the COM infrastructure and the internal pointers
Initialize(DWORD dwContext,bool bDuringRestore)273 bool VSSClientGeneric::Initialize(DWORD dwContext, bool bDuringRestore)
274 {
275 CComPtr<IVssAsync> pAsync1;
276 VSS_BACKUP_TYPE backup_type;
277 IVssBackupComponents* pVssObj = (IVssBackupComponents*)m_pVssObject;
278
279 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
280 Dmsg2(0, "VSSClientGeneric::Initialize: p_CreateVssBackupComponents=0x%08X, p_VssFreeSnapshotProperties=0x%08X\n", p_CreateVssBackupComponents, p_VssFreeSnapshotProperties);
281 Jmsg(m_jcr, M_FATAL, 0, "Entry point CreateVssBackupComponents or VssFreeSnapshotProperties missing.\n");
282 return false;
283 }
284
285 if (m_VolumeList) {
286 delete m_VolumeList;
287 }
288
289 m_VolumeList = New(MTab()); // TODO: See if we do this part only in backup
290 if (!m_VolumeList->get()) {
291 Jmsg(m_jcr, M_ERROR, 0, "Unable to list devices and volumes.\n");
292 return false;
293 }
294
295 HRESULT hr;
296 // Initialize COM
297 if (!m_bCoInitializeCalled) {
298 hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
299 if (FAILED(hr)) {
300 Dmsg1(0, "VSSClientGeneric::Initialize: CoInitializeEx returned 0x%08X\n", hr);
301 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "CoInitializeEx");
302 errno = b_errno_win32;
303 return false;
304 }
305 m_bCoInitializeCalled = true;
306 }
307
308 // Release the any old IVssBackupComponents interface
309 if (pVssObj) {
310 pVssObj->Release();
311 m_pVssObject = NULL;
312 }
313
314 // Create new internal backup components object
315 hr = p_CreateVssBackupComponents((IVssBackupComponents**)&m_pVssObject);
316 if (FAILED(hr)) {
317 berrno be;
318 Dmsg2(0, "VSSClientGeneric::Initialize: CreateVssBackupComponents returned 0x%08X. ERR=%s\n",
319 hr, be.bstrerror(b_errno_win32));
320 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "CreateVssBackupComponents");
321 errno = b_errno_win32;
322 return false;
323 }
324
325 /* Define shorthand VssObject with time */
326 pVssObj = (IVssBackupComponents*)m_pVssObject;
327
328
329 if (!bDuringRestore) {
330 #if defined(B_VSS_W2K3) || defined(B_VSS_VISTA)
331 if (dwContext != VSS_CTX_BACKUP) {
332 hr = pVssObj->SetContext(dwContext);
333 if (FAILED(hr)) {
334 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->SetContext returned 0x%08X\n", hr);
335 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "SetContext");
336 errno = b_errno_win32;
337 return false;
338 }
339 }
340 #endif
341
342 // 1. InitializeForBackup
343 hr = pVssObj->InitializeForBackup();
344 if (FAILED(hr)) {
345 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->InitializeForBackup returned 0x%08X\n", hr);
346 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "InitializeForBackup");
347 errno = b_errno_win32;
348 return false;
349 }
350
351 // 2. SetBackupState
352 switch (m_jcr->getJobLevel()) {
353 case L_FULL:
354 backup_type = VSS_BT_FULL;
355 break;
356 case L_DIFFERENTIAL:
357 backup_type = VSS_BT_DIFFERENTIAL;
358 break;
359 case L_INCREMENTAL:
360 backup_type = VSS_BT_INCREMENTAL;
361 break;
362 default:
363 Dmsg1(0, "VSSClientGeneric::Initialize: unknown backup level %d\n", m_jcr->getJobLevel());
364 backup_type = VSS_BT_FULL;
365 break;
366 }
367 hr = pVssObj->SetBackupState(true, true, backup_type, false); /* FIXME: need to support partial files - make last parameter true when done */
368 if (FAILED(hr)) {
369 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->SetBackupState returned 0x%08X\n", hr);
370 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "SetBackupState");
371 errno = b_errno_win32;
372 return false;
373 }
374
375 // 3. GatherWriterMetaData
376 hr = pVssObj->GatherWriterMetadata(&pAsync1.p);
377 if (FAILED(hr)) {
378 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->GatherWriterMetadata returned 0x%08X\n", hr);
379 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "GatherWriterMetadata");
380 errno = b_errno_win32;
381 return false;
382 }
383 // Waits for the async operation to finish and checks the result
384 if (!WaitAndCheckForAsyncOperation(pAsync1.p)) {
385 /* Error message already printed */
386 errno = b_errno_win32;
387 return false;
388 }
389 }
390
391 // We are during restore now?
392 m_bDuringRestore = bDuringRestore;
393
394 // Keep the context
395 m_dwContext = dwContext;
396
397 return true;
398 }
399
WaitAndCheckForAsyncOperation(IVssAsync * pAsync)400 bool VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
401 {
402 // Wait until the async operation finishes
403 // unfortunately we can't use a timeout here yet.
404 // the interface would allow it on W2k3,
405 // but it is not implemented yet....
406
407 HRESULT hr;
408
409 // Check the result of the asynchronous operation
410 HRESULT hrReturned = S_OK;
411
412 int timeout = 1800; // 30 minutes ...
413
414 int queryErrors = 0;
415 do {
416 if (hrReturned != S_OK) {
417 Sleep(1000);
418 }
419 hrReturned = S_OK;
420 hr = pAsync->QueryStatus(&hrReturned, NULL);
421 if (FAILED(hr)) {
422 queryErrors++;
423 }
424 } while ((timeout-- > 0) && (hrReturned == VSS_S_ASYNC_PENDING));
425
426 if (hrReturned == VSS_S_ASYNC_FINISHED) {
427 return true;
428 }
429
430 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "Query Async Status after 30 minute wait");
431 return false;
432 }
433
volume_cmp(void * e1,void * e2)434 static int volume_cmp(void *e1, void *e2)
435 {
436 WCHAR *v1 = (WCHAR *) e1;
437 MTabEntry *v2 = (MTabEntry *) e2;
438 return wcscmp(v1, v2->volumeName);
439 }
440
441 static pthread_mutex_t create_mutex = PTHREAD_MUTEX_INITIALIZER;
442
CreateSnapshots(alist * mount_points)443 bool VSSClientGeneric::CreateSnapshots(alist *mount_points)
444 {
445 IVssBackupComponents *pVssObj;
446 bool ret = false;
447 HRESULT hr;
448
449 /* AddToSnapshotSet */
450 CComPtr<IVssAsync> pAsync1;
451 CComPtr<IVssAsync> pAsync2;
452 VSS_ID pid;
453
454 /* While testing the concurrent snapshot creation, I found out that the entire snapshot
455 * creation process should be protected by a mutex. (InitializeForBackups and CreateSnapshots).
456 */
457
458 /* Create only one snapshot set at a time */
459 P(create_mutex);
460
461 /* szDriveLetters contains all drive letters in uppercase */
462 /* if a drive can not being added, it's converted to lowercase in szDriveLetters */
463 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp */
464 if (!m_pVssObject || m_bBackupIsInitialized) {
465 Jmsg(m_jcr, M_FATAL, 0, "No pointer to VssObject or Backup is not Initialized\n");
466 errno = ENOSYS;
467 goto bail_out;
468 }
469
470 m_uidCurrentSnapshotSet = GUID_NULL;
471
472 pVssObj = (IVssBackupComponents*)m_pVssObject;
473
474 /* startSnapshotSet */
475 hr = pVssObj->StartSnapshotSet(&m_uidCurrentSnapshotSet);
476 if (FAILED(hr)) {
477 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "StartSnapshotSet");
478 errno = ENOSYS;
479 goto bail_out;
480 }
481
482 /*
483 * Now try all paths in case they are mount points
484 */
485 for (int i=0; i < mount_points->size(); i++) {
486 wchar_t *p = (wchar_t *)mount_points->get(i);
487 // store uniquevolumname
488 int hresult = pVssObj->AddToSnapshotSet(p, GUID_NULL, &pid);
489 if (SUCCEEDED(hresult)) {
490 MTabEntry *elt = (MTabEntry*)m_VolumeList->entries->search(p, volume_cmp);
491 ASSERT2(elt, "Should find the volume in the list");
492 Jmsg(m_jcr, M_INFO, 0, " Snapshot mount point: %ls\n", elt->first());
493 Dmsg1(50, "AddToSnapshot OK for Vol: %ls\n", p);
494 } else {
495 //Dmsg1(50, "AddToSnapshot() failed for Vol: %ls\n", (LPWSTR)volume.c_str());
496 Dmsg2(50, "AddToSnapshot() failed for path: %ls hresult=0x%x\n", p, hresult);
497 }
498 }
499
500 /* PrepareForBackup */
501 hr = pVssObj->PrepareForBackup(&pAsync1.p);
502 if (FAILED(hr)) {
503 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "PrepareForBackup");
504 errno = b_errno_win32;
505 goto bail_out;
506 }
507
508 // Waits for the async operation to finish and checks the result
509 if (!WaitAndCheckForAsyncOperation(pAsync1.p)) {
510 /* Error message already printed */
511 errno = b_errno_win32;
512 goto bail_out;
513 }
514
515 /* get latest info about writer status */
516 if (!CheckWriterStatus()) {
517 /* Error message already printed */
518 errno = b_errno_win32; /* Error already printed */
519 goto bail_out;
520 }
521
522 /* DoSnapShotSet */
523 hr = pVssObj->DoSnapshotSet(&pAsync2.p);
524 if (FAILED(hr)) {
525 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "DoSnapshotSet");
526 errno = b_errno_win32;
527 goto bail_out;
528 }
529
530 // Waits for the async operation to finish and checks the result
531 if (!WaitAndCheckForAsyncOperation(pAsync2.p)) {
532 /* Error message already printed */
533 errno = b_errno_win32;
534 goto bail_out;
535 }
536
537 /* get latest info about writer status */
538 if (!CheckWriterStatus()) {
539 /* Error message already printed */
540 errno = b_errno_win32; /* Error already printed */
541 goto bail_out;
542 }
543
544 /* query snapshot info */
545 QuerySnapshotSet(m_uidCurrentSnapshotSet);
546
547 m_bBackupIsInitialized = true;
548
549 ret = true;
550 bail_out:
551 V(create_mutex);
552 return ret;
553 }
554
CloseBackup()555 bool VSSClientGeneric::CloseBackup()
556 {
557 bool bRet = false;
558 HRESULT hr;
559 BSTR xml;
560 IVssBackupComponents* pVssObj = (IVssBackupComponents*)m_pVssObject;
561
562 if (!m_pVssObject) {
563 Jmsg(m_jcr, M_FATAL, 0, "VssOject is NULL.\n");
564 errno = ENOSYS;
565 return bRet;
566 }
567 /* Create or Delete Snapshot one at a time */
568 P(create_mutex);
569
570 CComPtr<IVssAsync> pAsync;
571 m_bBackupIsInitialized = false;
572
573 hr = pVssObj->BackupComplete(&pAsync.p);
574 if (SUCCEEDED(hr)) {
575 // Waits for the async operation to finish and checks the result
576 if (!WaitAndCheckForAsyncOperation(pAsync.p)) {
577 /* Error message already printed */
578 errno = b_errno_win32;
579 } else {
580 bRet = true;
581 }
582 } else {
583 JmsgVssApiStatus(m_jcr, M_ERROR, hr, "BackupComplete");
584 errno = b_errno_win32;
585 pVssObj->AbortBackup();
586 }
587
588 /* get latest info about writer status */
589 CheckWriterStatus();
590
591 hr = pVssObj->SaveAsXML(&xml);
592 if (SUCCEEDED(hr)) {
593 m_metadata = xml;
594 } else {
595 m_metadata = NULL;
596 }
597
598 /* FIXME?: The docs http://msdn.microsoft.com/en-us/library/aa384582%28v=VS.85%29.aspx say this isn't required... */
599 if (m_uidCurrentSnapshotSet != GUID_NULL) {
600 VSS_ID idNonDeletedSnapshotID = GUID_NULL;
601 LONG lSnapshots;
602
603 pVssObj->DeleteSnapshots(
604 m_uidCurrentSnapshotSet,
605 VSS_OBJECT_SNAPSHOT_SET,
606 false,
607 &lSnapshots,
608 &idNonDeletedSnapshotID);
609
610 m_uidCurrentSnapshotSet = GUID_NULL;
611 }
612
613 if (m_bWriterStatusCurrent) {
614 m_bWriterStatusCurrent = false;
615 pVssObj->FreeWriterStatus();
616 }
617
618 pVssObj->Release();
619 m_pVssObject = NULL;
620
621 // Call CoUninitialize if the CoInitialize was performed sucesfully
622 if (m_bCoInitializeCalled) {
623 CoUninitialize();
624 m_bCoInitializeCalled = false;
625 }
626
627 V(create_mutex);
628 return bRet;
629 }
630
GetMetadata()631 WCHAR *VSSClientGeneric::GetMetadata()
632 {
633 return m_metadata;
634 }
635
CloseRestore()636 bool VSSClientGeneric::CloseRestore()
637 {
638 //HRESULT hr;
639 IVssBackupComponents* pVssObj = (IVssBackupComponents*)m_pVssObject;
640 CComPtr<IVssAsync> pAsync;
641
642 if (!pVssObj) {
643 Jmsg(m_jcr, M_FATAL, 0, "No pointer to VssObject or Backup is not Initialized\n");
644 errno = ENOSYS;
645 return false;
646 }
647 #if 0
648 /* done by plugin now */
649 if (SUCCEEDED(hr = pVssObj->PostRestore(&pAsync.p))) {
650 // Waits for the async operation to finish and checks the result
651 if (!WaitAndCheckForAsyncOperation(pAsync1.p)) {
652 /* Error message already printed */
653 errno = b_errno_win32;
654 return false;
655 }
656 /* get latest info about writer status */
657 if (!CheckWriterStatus()) {
658 /* Error message already printed */
659 errno = b_errno_win32;
660 return false;
661 }
662 } else {
663 errno = b_errno_win32;
664 return false;
665 }
666 #endif
667 return true;
668 }
669
670 // Query all the shadow copies in the given set
QuerySnapshotSet(GUID snapshotSetID)671 void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
672 {
673 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
674 Jmsg(m_jcr, M_FATAL, 0, "CreateVssBackupComponents or VssFreeSnapshotProperties API is NULL.\n");
675 errno = ENOSYS;
676 return;
677 }
678
679 if (snapshotSetID == GUID_NULL || m_pVssObject == NULL) {
680 Jmsg(m_jcr, M_FATAL, 0, "snapshotSetID == NULL or VssObject is NULL.\n");
681 errno = ENOSYS;
682 return;
683 }
684
685 IVssBackupComponents* pVssObj = (IVssBackupComponents*) m_pVssObject;
686
687 // Get list all shadow copies.
688 CComPtr<IVssEnumObject> pIEnumSnapshots;
689 HRESULT hr = pVssObj->Query( GUID_NULL,
690 VSS_OBJECT_NONE,
691 VSS_OBJECT_SNAPSHOT,
692 (IVssEnumObject**)(&pIEnumSnapshots) );
693
694 // If there are no shadow copies, just return
695 if (FAILED(hr)) {
696 Jmsg(m_jcr, M_FATAL, 0, "No Volume Shadow copies made.\n");
697 errno = b_errno_win32;
698 return;
699 }
700
701 // Enumerate all shadow copies.
702 VSS_OBJECT_PROP Prop;
703 VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap;
704
705 while (true) {
706 // Get the next element
707 ULONG ulFetched;
708 hr = (pIEnumSnapshots.p)->Next(1, &Prop, &ulFetched);
709
710 // We reached the end of list
711 if (ulFetched == 0) {
712 break;
713 }
714
715 Dmsg2(DT_VOLUME|50, "Adding %ls => %ls to m_VolumeList\n",
716 Snap.m_pwszOriginalVolumeName, Snap.m_pwszSnapshotDeviceObject);
717
718 // Print the shadow copy (if not filtered out)
719 if (Snap.m_SnapshotSetId == snapshotSetID) {
720 MTabEntry *elt = (MTabEntry*)m_VolumeList->entries->search(Snap.m_pwszOriginalVolumeName, volume_cmp);
721 if (!elt) {
722 Dmsg1(DT_VOLUME|50, "Unable to find [%ls] in the device list\n", Snap.m_pwszOriginalVolumeName);
723 foreach_rblist(elt, m_VolumeList->entries) {
724 elt->debug_paths();
725 }
726 Jmsg(m_jcr, M_WARNING, 0, _("Unable to find volume %ls in the device list\n"), Snap.m_pwszOriginalVolumeName);
727 } else {
728 elt->shadowCopyName = bwcsdup(Snap.m_pwszSnapshotDeviceObject);
729 elt->setInSnapshotSet();
730 }
731 }
732 p_VssFreeSnapshotProperties(&Snap);
733 }
734 errno = 0;
735 }
736
737 // Check the status for all selected writers
CheckWriterStatus()738 bool VSSClientGeneric::CheckWriterStatus()
739 {
740 /*
741 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp
742 */
743 IVssBackupComponents* pVssObj = (IVssBackupComponents*)m_pVssObject;
744 if (!pVssObj) {
745 Jmsg(m_jcr, M_FATAL, 0, "Cannot get IVssBackupComponents pointer.\n");
746 errno = ENOSYS;
747 return false;
748 }
749 DestroyWriterInfo();
750
751 if (m_bWriterStatusCurrent) {
752 m_bWriterStatusCurrent = false;
753 pVssObj->FreeWriterStatus();
754 }
755 // Gather writer status to detect potential errors
756 CComPtr<IVssAsync> pAsync;
757
758 HRESULT hr = pVssObj->GatherWriterStatus(&pAsync.p);
759 if (FAILED(hr)) {
760 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "GatherWriterStatus");
761 errno = b_errno_win32;
762 return false;
763 }
764
765 // Waits for the async operation to finish and checks the result
766 if (!WaitAndCheckForAsyncOperation(pAsync.p)) {
767 /* Error message already printed */
768 errno = b_errno_win32;
769 return false;
770 }
771
772 m_bWriterStatusCurrent = true;
773
774 unsigned cWriters = 0;
775
776 hr = pVssObj->GetWriterStatusCount(&cWriters);
777 if (FAILED(hr)) {
778 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "GetWriterStatusCount");
779 errno = b_errno_win32;
780 return false;
781 }
782
783 int nState;
784 POOLMEM *szBuf = get_pool_memory(PM_FNAME);
785 // Enumerate each writer
786 for (unsigned iWriter = 0; iWriter < cWriters; iWriter++) {
787 VSS_ID idInstance = GUID_NULL;
788 VSS_ID idWriter= GUID_NULL;
789 VSS_WRITER_STATE eWriterStatus = VSS_WS_UNKNOWN;
790 CComBSTR bstrWriterName;
791 HRESULT hrWriterFailure = S_OK;
792
793 // Get writer status
794 hr = pVssObj->GetWriterStatus(iWriter,
795 &idInstance,
796 &idWriter,
797 &bstrWriterName,
798 &eWriterStatus,
799 &hrWriterFailure);
800 if (FAILED(hr)) {
801 /* Api failed */
802 JmsgVssApiStatus(m_jcr, M_WARNING, hr, "GetWriterStatus");
803 nState = 0; /* Unknown writer state -- API failed */
804 } else {
805 switch(eWriterStatus) {
806 case VSS_WS_FAILED_AT_IDENTIFY:
807 case VSS_WS_FAILED_AT_PREPARE_BACKUP:
808 case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
809 case VSS_WS_FAILED_AT_FREEZE:
810 case VSS_WS_FAILED_AT_THAW:
811 case VSS_WS_FAILED_AT_POST_SNAPSHOT:
812 case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
813 case VSS_WS_FAILED_AT_PRE_RESTORE:
814 case VSS_WS_FAILED_AT_POST_RESTORE:
815 #if defined(B_VSS_W2K3) || defined(B_VSS_VISTA)
816 case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
817 #endif
818 /* Writer status problem */
819 wchar_2_UTF8(&szBuf, bstrWriterName.p);
820 JmsgVssWriterStatus(m_jcr, M_WARNING, eWriterStatus, szBuf);
821 nState = -1; /* bad writer state */
822 break;
823
824 default:
825 /* ok */
826 nState = 1; /* Writer state OK */
827 }
828 }
829 /* store text info */
830 char str[1000];
831 bstrncpy(str, "\"", sizeof(str));
832 wchar_2_UTF8(&szBuf, bstrWriterName.p);
833 bstrncat(str, szBuf, sizeof(str));
834 bstrncat(str, "\", State: 0x", sizeof(str));
835 itoa(eWriterStatus, szBuf, sizeof_pool_memory(szBuf));
836 bstrncat(str, szBuf, sizeof(str));
837 bstrncat(str, " (", sizeof(str));
838 wchar_2_UTF8(&szBuf, GetStringFromWriterStatus(eWriterStatus));
839 bstrncat(str, szBuf, sizeof(str));
840 bstrncat(str, ")", sizeof(str));
841 AppendWriterInfo(nState, (const char *)str);
842 }
843 free_pool_memory(szBuf);
844 errno = 0;
845 return true;
846 }
847
848 #endif /* WIN32_VSS */
849