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 if (SUCCEEDED(pVssObj->AddToSnapshotSet(p, GUID_NULL, &pid))) {
489 MTabEntry *elt = (MTabEntry*)m_VolumeList->entries->search(p, volume_cmp);
490 ASSERT2(elt, "Should find the volume in the list");
491 Jmsg(m_jcr, M_INFO, 0, " Snapshot mount point: %ls\n", elt->first());
492 Dmsg1(50, "AddToSnapshot OK for Vol: %ls\n", p);
493 } else {
494 //Dmsg1(50, "AddToSnapshot() failed for Vol: %ls\n", (LPWSTR)volume.c_str());
495 //Dmsg1(50, "AddToSnapshot() failed for path: %s\n", p);
496 }
497 }
498
499 /* PrepareForBackup */
500 hr = pVssObj->PrepareForBackup(&pAsync1.p);
501 if (FAILED(hr)) {
502 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "PrepareForBackup");
503 errno = b_errno_win32;
504 goto bail_out;
505 }
506
507 // Waits for the async operation to finish and checks the result
508 if (!WaitAndCheckForAsyncOperation(pAsync1.p)) {
509 /* Error message already printed */
510 errno = b_errno_win32;
511 goto bail_out;
512 }
513
514 /* get latest info about writer status */
515 if (!CheckWriterStatus()) {
516 /* Error message already printed */
517 errno = b_errno_win32; /* Error already printed */
518 goto bail_out;
519 }
520
521 /* DoSnapShotSet */
522 hr = pVssObj->DoSnapshotSet(&pAsync2.p);
523 if (FAILED(hr)) {
524 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "DoSnapshotSet");
525 errno = b_errno_win32;
526 goto bail_out;
527 }
528
529 // Waits for the async operation to finish and checks the result
530 if (!WaitAndCheckForAsyncOperation(pAsync2.p)) {
531 /* Error message already printed */
532 errno = b_errno_win32;
533 goto bail_out;
534 }
535
536 /* get latest info about writer status */
537 if (!CheckWriterStatus()) {
538 /* Error message already printed */
539 errno = b_errno_win32; /* Error already printed */
540 goto bail_out;
541 }
542
543 /* query snapshot info */
544 QuerySnapshotSet(m_uidCurrentSnapshotSet);
545
546 m_bBackupIsInitialized = true;
547
548 ret = true;
549 bail_out:
550 V(create_mutex);
551 return ret;
552 }
553
CloseBackup()554 bool VSSClientGeneric::CloseBackup()
555 {
556 bool bRet = false;
557 HRESULT hr;
558 BSTR xml;
559 IVssBackupComponents* pVssObj = (IVssBackupComponents*)m_pVssObject;
560
561 if (!m_pVssObject) {
562 Jmsg(m_jcr, M_FATAL, 0, "VssOject is NULL.\n");
563 errno = ENOSYS;
564 return bRet;
565 }
566 /* Create or Delete Snapshot one at a time */
567 P(create_mutex);
568
569 CComPtr<IVssAsync> pAsync;
570 m_bBackupIsInitialized = false;
571
572 hr = pVssObj->BackupComplete(&pAsync.p);
573 if (SUCCEEDED(hr)) {
574 // Waits for the async operation to finish and checks the result
575 if (!WaitAndCheckForAsyncOperation(pAsync.p)) {
576 /* Error message already printed */
577 errno = b_errno_win32;
578 } else {
579 bRet = true;
580 }
581 } else {
582 JmsgVssApiStatus(m_jcr, M_ERROR, hr, "BackupComplete");
583 errno = b_errno_win32;
584 pVssObj->AbortBackup();
585 }
586
587 /* get latest info about writer status */
588 CheckWriterStatus();
589
590 hr = pVssObj->SaveAsXML(&xml);
591 if (SUCCEEDED(hr)) {
592 m_metadata = xml;
593 } else {
594 m_metadata = NULL;
595 }
596
597 /* FIXME?: The docs http://msdn.microsoft.com/en-us/library/aa384582%28v=VS.85%29.aspx say this isn't required... */
598 if (m_uidCurrentSnapshotSet != GUID_NULL) {
599 VSS_ID idNonDeletedSnapshotID = GUID_NULL;
600 LONG lSnapshots;
601
602 pVssObj->DeleteSnapshots(
603 m_uidCurrentSnapshotSet,
604 VSS_OBJECT_SNAPSHOT_SET,
605 false,
606 &lSnapshots,
607 &idNonDeletedSnapshotID);
608
609 m_uidCurrentSnapshotSet = GUID_NULL;
610 }
611
612 if (m_bWriterStatusCurrent) {
613 m_bWriterStatusCurrent = false;
614 pVssObj->FreeWriterStatus();
615 }
616
617 pVssObj->Release();
618 m_pVssObject = NULL;
619
620 // Call CoUninitialize if the CoInitialize was performed sucesfully
621 if (m_bCoInitializeCalled) {
622 CoUninitialize();
623 m_bCoInitializeCalled = false;
624 }
625
626 V(create_mutex);
627 return bRet;
628 }
629
GetMetadata()630 WCHAR *VSSClientGeneric::GetMetadata()
631 {
632 return m_metadata;
633 }
634
CloseRestore()635 bool VSSClientGeneric::CloseRestore()
636 {
637 //HRESULT hr;
638 IVssBackupComponents* pVssObj = (IVssBackupComponents*)m_pVssObject;
639 CComPtr<IVssAsync> pAsync;
640
641 if (!pVssObj) {
642 Jmsg(m_jcr, M_FATAL, 0, "No pointer to VssObject or Backup is not Initialized\n");
643 errno = ENOSYS;
644 return false;
645 }
646 #if 0
647 /* done by plugin now */
648 if (SUCCEEDED(hr = pVssObj->PostRestore(&pAsync.p))) {
649 // Waits for the async operation to finish and checks the result
650 if (!WaitAndCheckForAsyncOperation(pAsync1.p)) {
651 /* Error message already printed */
652 errno = b_errno_win32;
653 return false;
654 }
655 /* get latest info about writer status */
656 if (!CheckWriterStatus()) {
657 /* Error message already printed */
658 errno = b_errno_win32;
659 return false;
660 }
661 } else {
662 errno = b_errno_win32;
663 return false;
664 }
665 #endif
666 return true;
667 }
668
669 // Query all the shadow copies in the given set
QuerySnapshotSet(GUID snapshotSetID)670 void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
671 {
672 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
673 Jmsg(m_jcr, M_FATAL, 0, "CreateVssBackupComponents or VssFreeSnapshotProperties API is NULL.\n");
674 errno = ENOSYS;
675 return;
676 }
677
678 if (snapshotSetID == GUID_NULL || m_pVssObject == NULL) {
679 Jmsg(m_jcr, M_FATAL, 0, "snapshotSetID == NULL or VssObject is NULL.\n");
680 errno = ENOSYS;
681 return;
682 }
683
684 IVssBackupComponents* pVssObj = (IVssBackupComponents*) m_pVssObject;
685
686 // Get list all shadow copies.
687 CComPtr<IVssEnumObject> pIEnumSnapshots;
688 HRESULT hr = pVssObj->Query( GUID_NULL,
689 VSS_OBJECT_NONE,
690 VSS_OBJECT_SNAPSHOT,
691 (IVssEnumObject**)(&pIEnumSnapshots) );
692
693 // If there are no shadow copies, just return
694 if (FAILED(hr)) {
695 Jmsg(m_jcr, M_FATAL, 0, "No Volume Shadow copies made.\n");
696 errno = b_errno_win32;
697 return;
698 }
699
700 // Enumerate all shadow copies.
701 VSS_OBJECT_PROP Prop;
702 VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap;
703
704 while (true) {
705 // Get the next element
706 ULONG ulFetched;
707 hr = (pIEnumSnapshots.p)->Next(1, &Prop, &ulFetched);
708
709 // We reached the end of list
710 if (ulFetched == 0) {
711 break;
712 }
713
714 Dmsg2(DT_VOLUME|50, "Adding %ls => %ls to m_VolumeList\n",
715 Snap.m_pwszOriginalVolumeName, Snap.m_pwszSnapshotDeviceObject);
716
717 // Print the shadow copy (if not filtered out)
718 if (Snap.m_SnapshotSetId == snapshotSetID) {
719 MTabEntry *elt = (MTabEntry*)m_VolumeList->entries->search(Snap.m_pwszOriginalVolumeName, volume_cmp);
720 if (!elt) {
721 Dmsg1(DT_VOLUME|50, "Unable to find [%ls] in the device list\n", Snap.m_pwszOriginalVolumeName);
722 foreach_rblist(elt, m_VolumeList->entries) {
723 elt->debug_paths();
724 }
725 Jmsg(m_jcr, M_WARNING, 0, _("Unable to find volume %ls in the device list\n"), Snap.m_pwszOriginalVolumeName);
726 } else {
727 elt->shadowCopyName = bwcsdup(Snap.m_pwszSnapshotDeviceObject);
728 elt->setInSnapshotSet();
729 }
730 }
731 p_VssFreeSnapshotProperties(&Snap);
732 }
733 errno = 0;
734 }
735
736 // Check the status for all selected writers
CheckWriterStatus()737 bool VSSClientGeneric::CheckWriterStatus()
738 {
739 /*
740 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp
741 */
742 IVssBackupComponents* pVssObj = (IVssBackupComponents*)m_pVssObject;
743 if (!pVssObj) {
744 Jmsg(m_jcr, M_FATAL, 0, "Cannot get IVssBackupComponents pointer.\n");
745 errno = ENOSYS;
746 return false;
747 }
748 DestroyWriterInfo();
749
750 if (m_bWriterStatusCurrent) {
751 m_bWriterStatusCurrent = false;
752 pVssObj->FreeWriterStatus();
753 }
754 // Gather writer status to detect potential errors
755 CComPtr<IVssAsync> pAsync;
756
757 HRESULT hr = pVssObj->GatherWriterStatus(&pAsync.p);
758 if (FAILED(hr)) {
759 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "GatherWriterStatus");
760 errno = b_errno_win32;
761 return false;
762 }
763
764 // Waits for the async operation to finish and checks the result
765 if (!WaitAndCheckForAsyncOperation(pAsync.p)) {
766 /* Error message already printed */
767 errno = b_errno_win32;
768 return false;
769 }
770
771 m_bWriterStatusCurrent = true;
772
773 unsigned cWriters = 0;
774
775 hr = pVssObj->GetWriterStatusCount(&cWriters);
776 if (FAILED(hr)) {
777 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "GetWriterStatusCount");
778 errno = b_errno_win32;
779 return false;
780 }
781
782 int nState;
783 POOLMEM *szBuf = get_pool_memory(PM_FNAME);
784 // Enumerate each writer
785 for (unsigned iWriter = 0; iWriter < cWriters; iWriter++) {
786 VSS_ID idInstance = GUID_NULL;
787 VSS_ID idWriter= GUID_NULL;
788 VSS_WRITER_STATE eWriterStatus = VSS_WS_UNKNOWN;
789 CComBSTR bstrWriterName;
790 HRESULT hrWriterFailure = S_OK;
791
792 // Get writer status
793 hr = pVssObj->GetWriterStatus(iWriter,
794 &idInstance,
795 &idWriter,
796 &bstrWriterName,
797 &eWriterStatus,
798 &hrWriterFailure);
799 if (FAILED(hr)) {
800 /* Api failed */
801 JmsgVssApiStatus(m_jcr, M_WARNING, hr, "GetWriterStatus");
802 nState = 0; /* Unknown writer state -- API failed */
803 } else {
804 switch(eWriterStatus) {
805 case VSS_WS_FAILED_AT_IDENTIFY:
806 case VSS_WS_FAILED_AT_PREPARE_BACKUP:
807 case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
808 case VSS_WS_FAILED_AT_FREEZE:
809 case VSS_WS_FAILED_AT_THAW:
810 case VSS_WS_FAILED_AT_POST_SNAPSHOT:
811 case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
812 case VSS_WS_FAILED_AT_PRE_RESTORE:
813 case VSS_WS_FAILED_AT_POST_RESTORE:
814 #if defined(B_VSS_W2K3) || defined(B_VSS_VISTA)
815 case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
816 #endif
817 /* Writer status problem */
818 wchar_2_UTF8(&szBuf, bstrWriterName.p);
819 JmsgVssWriterStatus(m_jcr, M_WARNING, eWriterStatus, szBuf);
820 nState = -1; /* bad writer state */
821 break;
822
823 default:
824 /* ok */
825 nState = 1; /* Writer state OK */
826 }
827 }
828 /* store text info */
829 char str[1000];
830 bstrncpy(str, "\"", sizeof(str));
831 wchar_2_UTF8(&szBuf, bstrWriterName.p);
832 bstrncat(str, szBuf, sizeof(str));
833 bstrncat(str, "\", State: 0x", sizeof(str));
834 itoa(eWriterStatus, szBuf, sizeof_pool_memory(szBuf));
835 bstrncat(str, szBuf, sizeof(str));
836 bstrncat(str, " (", sizeof(str));
837 wchar_2_UTF8(&szBuf, GetStringFromWriterStatus(eWriterStatus));
838 bstrncat(str, szBuf, sizeof(str));
839 bstrncat(str, ")", sizeof(str));
840 AppendWriterInfo(nState, (const char *)str);
841 }
842 free_pool_memory(szBuf);
843 errno = 0;
844 return true;
845 }
846
847 #endif /* WIN32_VSS */
848