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