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