]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/filed/vss_generic.cpp
Make out of freespace non-fatal for removable devices -- i.e. behaves like tape
[bacula/bacula] / bacula / src / win32 / filed / vss_generic.cpp
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2018 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
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
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
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
263 VSSClientGeneric::VSSClientGeneric()
264 {
265 }
266
267 // Destructor
268 VSSClientGeneric::~VSSClientGeneric()
269 {
270 }
271
272 // Initialize the COM infrastructure and the internal pointers
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
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
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
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
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
630 WCHAR *VSSClientGeneric::GetMetadata()
631 {
632    return m_metadata;
633 }
634
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
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
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 */