]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/filed/vss_generic.cpp
Tweak fix MySQL quoting again :-(
[bacula/bacula] / bacula / src / win32 / filed / vss_generic.cpp
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2005-2010 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 //                              -*- Mode: C++ -*-
29 // vss.cpp -- Interface to Volume Shadow Copies (VSS)
30 //
31 // Copyright transferred from MATRIX-Computer GmbH to
32 //   Kern Sibbald by express permission.
33 //
34 // Author          : Thorsten Engel
35 // Created On      : Fri May 06 21:44:00 2005
36
37
38 #ifdef WIN32_VSS
39
40 #include "bacula.h"
41 #include "jcr.h"
42
43 #undef setlocale
44
45 // STL includes
46 #include <vector>
47 #include <algorithm>
48 #include <string>
49 #include <sstream>
50 #include <fstream>
51 using namespace std;
52
53 #include "ms_atl.h"
54 #include <objbase.h>
55
56 /* 
57  * Kludges to get Vista code to compile.             
58  *  KES - June 2007
59  */
60 #define __in  IN
61 #define __out OUT
62 #define __RPC_unique_pointer
63 #define __RPC_string
64 #define __RPC__out_ecount_part(x, y)
65 #define __RPC__deref_inout_opt
66 #define __RPC__out
67
68 #if !defined(ENABLE_NLS)
69 #define setlocale(p, d)
70 #endif
71
72 #ifdef HAVE_STRSAFE_H
73 // Used for safe string manipulation
74 #include <strsafe.h>
75 #endif
76
77 BOOL VSSPathConvert(const char *szFilePath, char *szShadowPath, int nBuflen);
78 BOOL VSSPathConvertW(const wchar_t *szFilePath, wchar_t *szShadowPath, int nBuflen);
79
80 #ifdef HAVE_MINGW
81 class IXMLDOMDocument;
82 #endif
83
84 /* Reduce compiler warnings from Windows vss code */
85 #undef uuid
86 #define uuid(x)
87
88 #ifdef B_VSS_XP
89    #define VSSClientGeneric VSSClientXP
90    
91    #include "inc/WinXP/vss.h"
92    #include "inc/WinXP/vswriter.h"
93    #include "inc/WinXP/vsbackup.h"
94
95 #endif
96
97 #ifdef B_VSS_W2K3
98    #define VSSClientGeneric VSSClient2003
99    
100    #include "inc/Win2003/vss.h"
101    #include "inc/Win2003/vswriter.h"
102    #include "inc/Win2003/vsbackup.h"
103 #endif
104
105 #ifdef B_VSS_VISTA
106    #define VSSClientGeneric VSSClientVista
107
108    #include "inc/Win2003/vss.h"
109    #include "inc/Win2003/vswriter.h"
110    #include "inc/Win2003/vsbackup.h"
111 #endif
112    
113 /* In VSSAPI.DLL */
114 typedef HRESULT (STDAPICALLTYPE* t_CreateVssBackupComponents)(OUT IVssBackupComponents **);
115 typedef void (APIENTRY* t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
116    
117 static t_CreateVssBackupComponents p_CreateVssBackupComponents = NULL;
118 static t_VssFreeSnapshotProperties p_VssFreeSnapshotProperties = NULL;
119
120
121
122 #include "vss.h"
123
124 /*  
125  *
126  * some helper functions 
127  *
128  *
129  */
130
131 // Append a backslash to the current string 
132 inline wstring AppendBackslash(wstring str)
133 {
134     if (str.length() == 0)
135         return wstring(L"\\");
136     if (str[str.length() - 1] == L'\\')
137         return str;
138     return str.append(L"\\");
139 }
140
141 // Get the unique volume name for the given path
142 inline wstring GetUniqueVolumeNameForPath(wstring path)
143 {
144     if (path.length() <= 0) {
145        return L"";
146     }
147
148     // Add the backslash termination, if needed
149     path = AppendBackslash(path);
150
151     // Get the root path of the volume
152     wchar_t volumeRootPath[MAX_PATH];
153     wchar_t volumeName[MAX_PATH];
154     wchar_t volumeUniqueName[MAX_PATH];
155
156     if (!p_GetVolumePathNameW || !p_GetVolumePathNameW((LPCWSTR)path.c_str(), volumeRootPath, MAX_PATH))
157       return L"";
158     
159     // Get the volume name alias (might be different from the unique volume name in rare cases)
160     if (!p_GetVolumeNameForVolumeMountPointW || !p_GetVolumeNameForVolumeMountPointW(volumeRootPath, volumeName, MAX_PATH))
161        return L"";
162     
163     // Get the unique volume name    
164     if (!p_GetVolumeNameForVolumeMountPointW(volumeName, volumeUniqueName, MAX_PATH))
165        return L"";
166     
167     return volumeUniqueName;
168 }
169
170
171 // Helper macro for quick treatment of case statements for error codes
172 #define GEN_MERGE(A, B) A##B
173 #define GEN_MAKE_W(A) GEN_MERGE(L, A)
174
175 #define CHECK_CASE_FOR_CONSTANT(value)                      \
176     case value: return (GEN_MAKE_W(#value));
177
178
179 // Convert a writer status into a string
180 inline const wchar_t* GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus)
181 {
182     switch (eWriterStatus) {
183     CHECK_CASE_FOR_CONSTANT(VSS_WS_STABLE);
184     CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_FREEZE);
185     CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_THAW);
186     CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_POST_SNAPSHOT);
187     CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_BACKUP_COMPLETE);
188     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_IDENTIFY);
189     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_BACKUP);
190     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_SNAPSHOT);
191     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_FREEZE);
192     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_THAW);
193     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_SNAPSHOT);
194     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_BACKUP_COMPLETE);
195     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PRE_RESTORE);
196     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_RESTORE);
197     
198     default:
199         return L"Error or Undefined";
200     }
201 }
202
203 // Constructor
204
205 #ifdef HAVE_VSS64
206 /* 64 bit entrypoint name */
207 #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YAJPEAPEAVIVssBackupComponents@@@Z"
208 #else
209 /* 32 bit entrypoint name */
210 #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
211 #endif
212
213 VSSClientGeneric::VSSClientGeneric()
214 {
215    m_hLib = LoadLibraryA("VSSAPI.DLL");
216    if (m_hLib) {      
217       p_CreateVssBackupComponents = (t_CreateVssBackupComponents)
218          GetProcAddress(m_hLib, VSSVBACK_ENTRY);
219       p_VssFreeSnapshotProperties = (t_VssFreeSnapshotProperties)
220           GetProcAddress(m_hLib, "VssFreeSnapshotProperties");      
221    } 
222 }
223
224
225
226 // Destructor
227 VSSClientGeneric::~VSSClientGeneric()
228 {
229    if (m_hLib)
230       FreeLibrary(m_hLib);
231 }
232
233 // Initialize the COM infrastructure and the internal pointers
234 bool VSSClientGeneric::Initialize(DWORD dwContext, bool bDuringRestore, bool (*VssInitCallback)(JCR *, int))
235 {
236    CComPtr<IVssAsync>  pAsync1;
237    VSS_BACKUP_TYPE backup_type;
238
239    if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
240       Dmsg2(0, "VSSClientGeneric::Initialize: p_CreateVssBackupComponents = 0x%08X, p_VssFreeSnapshotProperties = 0x%08X\n", p_CreateVssBackupComponents, p_VssFreeSnapshotProperties);
241       errno = ENOSYS;
242       return false;
243    }
244
245    HRESULT hr;
246    // Initialize COM
247    if (!m_bCoInitializeCalled) {
248       hr = CoInitialize(NULL);
249       if (FAILED(hr)) {
250          Dmsg1(0, "VSSClientGeneric::Initialize: CoInitialize returned 0x%08X\n", hr);
251          errno = b_errno_win32;
252          return false;
253       }
254       m_bCoInitializeCalled = true;
255    }
256
257    // Initialize COM security
258    if (!m_bCoInitializeSecurityCalled) {
259       hr =
260          CoInitializeSecurity(
261          NULL,                           //  Allow *all* VSS writers to communicate back!
262          -1,                             //  Default COM authentication service
263          NULL,                           //  Default COM authorization service
264          NULL,                           //  reserved parameter
265          RPC_C_AUTHN_LEVEL_PKT_PRIVACY,  //  Strongest COM authentication level
266          RPC_C_IMP_LEVEL_IDENTIFY,       //  Minimal impersonation abilities 
267          NULL,                           //  Default COM authentication settings
268          EOAC_NONE,                      //  No special options
269          NULL                            //  Reserved parameter
270          );
271
272       if (FAILED(hr)) {
273          Dmsg1(0, "VSSClientGeneric::Initialize: CoInitializeSecurity returned 0x%08X\n", hr);
274          errno = b_errno_win32;
275          return false;
276       }
277       m_bCoInitializeSecurityCalled = true;
278    }
279
280    // Release the IVssBackupComponents interface 
281    if (m_pVssObject) {
282       m_pVssObject->Release();
283       m_pVssObject = NULL;
284    }
285
286    // Create the internal backup components object
287    hr = p_CreateVssBackupComponents((IVssBackupComponents**) &m_pVssObject);
288    if (FAILED(hr)) {
289       berrno be;
290       Dmsg2(0, "VSSClientGeneric::Initialize: CreateVssBackupComponents returned 0x%08X. ERR=%s\n",
291             hr, be.bstrerror(b_errno_win32));
292       errno = b_errno_win32;
293       return false;
294    }
295
296 #if   defined(B_VSS_W2K3) || defined(B_VSS_VISTA)
297    if (dwContext != VSS_CTX_BACKUP) {
298       hr = ((IVssBackupComponents*) m_pVssObject)->SetContext(dwContext);
299       if (FAILED(hr)) {
300          Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->SetContext returned 0x%08X\n", hr);
301          errno = b_errno_win32;
302          return false;
303       }
304    }
305 #endif
306
307    if (!bDuringRestore) {
308       // 1. InitializeForBackup
309       hr = ((IVssBackupComponents*) m_pVssObject)->InitializeForBackup();
310       if (FAILED(hr)) {
311          Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->InitializeForBackup returned 0x%08X\n", hr);
312          errno = b_errno_win32; 
313          return false;
314       }
315  
316       // 2. SetBackupState
317       switch (m_jcr->getJobLevel())
318       {
319       case L_FULL:
320          backup_type = VSS_BT_FULL;
321          break;
322       case L_DIFFERENTIAL:
323          backup_type = VSS_BT_DIFFERENTIAL;
324          break;
325       case L_INCREMENTAL:
326          backup_type = VSS_BT_INCREMENTAL;
327          break;
328       default:
329          Dmsg1(0, "VSSClientGeneric::Initialize: unknown backup level %d\n", m_jcr->getJobLevel());
330          backup_type = VSS_BT_FULL;
331          break;
332       }
333       hr = ((IVssBackupComponents*) m_pVssObject)->SetBackupState(true, true, backup_type, false);
334       if (FAILED(hr)) {
335          Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->SetBackupState returned 0x%08X\n", hr);
336          errno = b_errno_win32;
337          return false;
338       }
339
340       // 3. GatherWriterMetaData
341       hr = ((IVssBackupComponents*) m_pVssObject)->GatherWriterMetadata(&pAsync1.p);
342       if (FAILED(hr)) {
343          Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->GatherWriterMetadata returned 0x%08X\n", hr);
344          errno = b_errno_win32;
345          return false;
346       }
347       // Waits for the async operation to finish and checks the result
348       WaitAndCheckForAsyncOperation(pAsync1.p);
349    } else {
350  
351    /*
352     * Initialize for restore
353     */
354
355       HRESULT hr;
356
357 #if 0
358       WCHAR *xml;
359       int fd;
360       struct stat stat;
361       /* obviously this is just temporary - the xml should come from somewhere like the catalog */
362       fd = open("C:\\james.xml", O_RDONLY);
363       Dmsg1(0, "fd = %d\n", fd);
364       fstat(fd, &stat);
365       Dmsg1(0, "size = %d\n", stat.st_size);
366       xml = new WCHAR[stat.st_size / sizeof(WCHAR) + 1];
367       read(fd, xml, stat.st_size);
368       close(fd);
369       xml[stat.st_size / sizeof(WCHAR)] = 0;
370 #endif
371
372       // 1. InitializeForRestore
373       hr = ((IVssBackupComponents*) m_pVssObject)->InitializeForRestore(m_metadata);
374       if (FAILED(hr)) {
375          Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->InitializeForRestore returned 0x%08X\n", hr);
376          errno = b_errno_win32;
377          return false;
378       }
379       VssInitCallback(m_jcr, VSS_INIT_RESTORE_AFTER_INIT);
380
381       // 2. GatherWriterMetaData
382       hr = ((IVssBackupComponents*) m_pVssObject)->GatherWriterMetadata(&pAsync1.p);
383       if (FAILED(hr)) {
384          Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->GatherWriterMetadata returned 0x%08X\n", hr);
385          errno = b_errno_win32;
386          return false;
387       }
388       WaitAndCheckForAsyncOperation(pAsync1.p);
389       VssInitCallback(m_jcr, VSS_INIT_RESTORE_AFTER_GATHER);
390
391       // 3. PreRestore
392       hr = ((IVssBackupComponents*) m_pVssObject)->PreRestore(&pAsync1.p);
393       if (FAILED(hr)) {
394          Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->PreRestore returned 0x%08X\n", hr);
395          errno = b_errno_win32;
396          return false;
397       }
398       WaitAndCheckForAsyncOperation(pAsync1.p);
399       /* get latest info about writer status */
400       if (!CheckWriterStatus()) {
401          Dmsg0(0, "VSSClientGeneric::InitializePostPlugin: Failed to CheckWriterstatus\n");
402          errno = b_errno_win32;
403          return false;
404       }
405    }
406
407    // We are during restore now?
408    m_bDuringRestore = bDuringRestore;
409
410    // Keep the context
411    m_dwContext = dwContext;
412
413    return true;
414 }
415
416 bool VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
417 {
418    // Wait until the async operation finishes
419    // unfortunately we can't use a timeout here yet.
420    // the interface would allow it on W2k3,
421    // but it is not implemented yet....
422
423    HRESULT hr;
424
425    // Check the result of the asynchronous operation
426    HRESULT hrReturned = S_OK;
427
428    int timeout = 600; // 10 minutes....
429
430    int queryErrors = 0;
431    do {
432       if (hrReturned != S_OK) 
433          Sleep(1000);
434    
435       hrReturned = S_OK;
436       hr = pAsync->QueryStatus(&hrReturned, NULL);
437    
438       if (FAILED(hr)) 
439          queryErrors++;
440    } while ((timeout-- > 0) && (hrReturned == VSS_S_ASYNC_PENDING));
441
442    if (hrReturned == VSS_S_ASYNC_FINISHED)
443       return true;
444
445    
446 #ifdef xDEBUG 
447    // Check if the async operation succeeded...
448    if(hrReturned != VSS_S_ASYNC_FINISHED) {   
449       wchar_t *pwszBuffer = NULL;
450       /* I don't see the usefulness of the following -- KES */
451       FormatMessageW(
452          FORMAT_MESSAGE_ALLOCATE_BUFFER 
453          | FORMAT_MESSAGE_FROM_SYSTEM 
454          | FORMAT_MESSAGE_IGNORE_INSERTS,
455          NULL, hrReturned, 
456          MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
457          (LPWSTR)&pwszBuffer, 0, NULL);
458
459       LocalFree(pwszBuffer);         
460       errno = b_errno_win32;
461    }
462 #endif
463
464    return false;
465 }
466
467 bool VSSClientGeneric::CreateSnapshots(char* szDriveLetters)
468 {
469    /* szDriveLetters contains all drive letters in uppercase */
470    /* if a drive can not being added, it's converted to lowercase in szDriveLetters */
471    /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp */
472    
473    if (!m_pVssObject || m_bBackupIsInitialized) {
474       errno = ENOSYS;
475       return false;  
476    }
477
478    m_uidCurrentSnapshotSet = GUID_NULL;
479
480    IVssBackupComponents *pVss = (IVssBackupComponents*)m_pVssObject;
481
482    /* startSnapshotSet */
483
484    pVss->StartSnapshotSet(&m_uidCurrentSnapshotSet);
485
486    /* AddToSnapshotSet */
487
488    wchar_t szDrive[3];
489    szDrive[1] = ':';
490    szDrive[2] = 0;
491
492    wstring volume;
493
494    CComPtr<IVssAsync>  pAsync1;
495    CComPtr<IVssAsync>  pAsync2;   
496    VSS_ID pid;
497
498    for (size_t i=0; i < strlen (szDriveLetters); i++) {
499       szDrive[0] = szDriveLetters[i];
500       volume = GetUniqueVolumeNameForPath(szDrive);
501       // store uniquevolumname
502       if (SUCCEEDED(pVss->AddToSnapshotSet((LPWSTR)volume.c_str(), GUID_NULL, &pid))) {
503          wcsncpy (m_wszUniqueVolumeName[szDriveLetters[i]-'A'], (LPWSTR) volume.c_str(), MAX_PATH);
504       } else {            
505          szDriveLetters[i] = tolower (szDriveLetters[i]);               
506       }
507    }
508
509    /* PrepareForBackup */
510    if (FAILED(pVss->PrepareForBackup(&pAsync1.p))) {      
511       errno = b_errno_win32;
512       return false;   
513    }
514    
515    // Waits for the async operation to finish and checks the result
516    WaitAndCheckForAsyncOperation(pAsync1.p);
517
518    /* get latest info about writer status */
519    if (!CheckWriterStatus()) {
520       errno = b_errno_win32;
521       return false;
522    }
523
524    /* DoSnapShotSet */   
525    if (FAILED(pVss->DoSnapshotSet(&pAsync2.p))) {      
526       errno = b_errno_win32;
527       return false;   
528    }
529
530    // Waits for the async operation to finish and checks the result
531    WaitAndCheckForAsyncOperation(pAsync2.p); 
532    
533    /* query snapshot info */   
534    QuerySnapshotSet(m_uidCurrentSnapshotSet);
535
536    SetVSSPathConvert(VSSPathConvert, VSSPathConvertW);
537
538    m_bBackupIsInitialized = true;
539
540    return true;
541 }
542
543 bool VSSClientGeneric::CloseBackup()
544 {
545    bool bRet = false;
546    HRESULT hr;
547    BSTR xml;
548
549    if (!m_pVssObject)
550       errno = ENOSYS;
551    else {
552       IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
553       CComPtr<IVssAsync>  pAsync;
554
555       SetVSSPathConvert(NULL, NULL);
556
557       m_bBackupIsInitialized = false;
558
559       hr = pVss->SaveAsXML(&xml);
560       if (hr == ERROR_SUCCESS)
561          m_metadata = xml;
562       else
563          m_metadata = NULL;
564 #if 0
565 {
566    HRESULT hr;
567    BSTR xml;
568    int fd;
569
570    hr = pVss->SaveAsXML(&xml);
571    fd = open("C:\\james.xml", O_CREAT | O_WRONLY | O_TRUNC, 0777);
572    write(fd, xml, wcslen(xml) * sizeof(WCHAR));
573    close(fd);
574 }
575 #endif
576       if (SUCCEEDED(pVss->BackupComplete(&pAsync.p))) {
577          // Waits for the async operation to finish and checks the result
578          WaitAndCheckForAsyncOperation(pAsync.p);
579          bRet = true;     
580       } else {
581          errno = b_errno_win32;
582          pVss->AbortBackup();
583       }
584
585       /* get latest info about writer status */
586       CheckWriterStatus();
587
588       if (m_uidCurrentSnapshotSet != GUID_NULL) {
589          VSS_ID idNonDeletedSnapshotID = GUID_NULL;
590          LONG lSnapshots;
591
592          pVss->DeleteSnapshots(
593             m_uidCurrentSnapshotSet, 
594             VSS_OBJECT_SNAPSHOT_SET,
595             false,
596             &lSnapshots,
597             &idNonDeletedSnapshotID);
598
599          m_uidCurrentSnapshotSet = GUID_NULL;
600       }
601
602       pVss->Release();
603       m_pVssObject = NULL;
604    }
605
606    // Call CoUninitialize if the CoInitialize was performed sucesfully
607    if (m_bCoInitializeCalled) {
608       CoUninitialize();
609       m_bCoInitializeCalled = false;
610    }
611
612    return bRet;
613 }
614
615 WCHAR *VSSClientGeneric::GetMetadata()
616 {
617    return m_metadata;
618 }
619
620 bool VSSClientGeneric::CloseRestore()
621 {
622    HRESULT hr;
623    IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
624    CComPtr<IVssAsync> pAsync;
625
626    if (!pVss)
627    {
628       errno = ENOSYS;
629       return false;
630    }
631    if (SUCCEEDED(hr = pVss->PostRestore(&pAsync.p))) {
632       // Waits for the async operation to finish and checks the result
633       WaitAndCheckForAsyncOperation(pAsync.p);
634       /* get latest info about writer status */
635       if (!CheckWriterStatus()) {
636          errno = b_errno_win32;
637          return false;
638       }
639    } else {
640       errno = b_errno_win32;
641       return false;
642    }
643    return true;
644 }
645
646 // Query all the shadow copies in the given set
647 void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
648 {   
649    if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
650       errno = ENOSYS;
651       return;
652    }
653
654    memset (m_szShadowCopyName,0,sizeof (m_szShadowCopyName));
655    
656    if (snapshotSetID == GUID_NULL || m_pVssObject == NULL) {
657       errno = ENOSYS;
658       return;
659    }
660
661    IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
662                
663    // Get list all shadow copies. 
664    CComPtr<IVssEnumObject> pIEnumSnapshots;
665    HRESULT hr = pVss->Query( GUID_NULL, 
666          VSS_OBJECT_NONE, 
667          VSS_OBJECT_SNAPSHOT, 
668          (IVssEnumObject**)(&pIEnumSnapshots) );    
669
670    // If there are no shadow copies, just return
671    if (FAILED(hr)) {
672       errno = b_errno_win32;
673       return;   
674    }
675
676    // Enumerate all shadow copies. 
677    VSS_OBJECT_PROP Prop;
678    VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap;
679    
680    while (true) {
681       // Get the next element
682       ULONG ulFetched;
683       hr = (pIEnumSnapshots.p)->Next( 1, &Prop, &ulFetched );
684
685       // We reached the end of list
686       if (ulFetched == 0)
687          break;
688
689       // Print the shadow copy (if not filtered out)
690       if (Snap.m_SnapshotSetId == snapshotSetID)  {
691          for (int ch='A'-'A';ch<='Z'-'A';ch++) {
692             if (wcscmp(Snap.m_pwszOriginalVolumeName, m_wszUniqueVolumeName[ch]) == 0) {       
693                wcsncpy(m_szShadowCopyName[ch],Snap.m_pwszSnapshotDeviceObject, MAX_PATH-1);               
694                break;
695             }
696          }
697       }
698       p_VssFreeSnapshotProperties(&Snap);
699    }
700    errno = 0;
701 }
702
703 // Check the status for all selected writers
704 bool VSSClientGeneric::CheckWriterStatus()
705 {
706     /* 
707     http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp
708     */
709     IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
710     DestroyWriterInfo();
711
712     // Gather writer status to detect potential errors
713     CComPtr<IVssAsync>  pAsync;
714     
715     HRESULT hr = pVss->GatherWriterStatus(&pAsync.p);
716     if (FAILED(hr)) {
717        errno = b_errno_win32;
718        return false;
719     } 
720
721     // Waits for the async operation to finish and checks the result
722     WaitAndCheckForAsyncOperation(pAsync.p);
723       
724     unsigned cWriters = 0;
725
726     hr = pVss->GetWriterStatusCount(&cWriters);
727     if (FAILED(hr)) {
728        errno = b_errno_win32;
729        return false;
730     }
731
732     int nState;
733     
734     // Enumerate each writer
735     for (unsigned iWriter = 0; iWriter < cWriters; iWriter++) {
736         VSS_ID idInstance = GUID_NULL;
737         VSS_ID idWriter= GUID_NULL;
738         VSS_WRITER_STATE eWriterStatus = VSS_WS_UNKNOWN;
739         CComBSTR bstrWriterName;
740         HRESULT hrWriterFailure = S_OK;
741
742         // Get writer status
743         hr = pVss->GetWriterStatus(iWriter,
744                              &idInstance,
745                              &idWriter,
746                              &bstrWriterName,
747                              &eWriterStatus,
748                              &hrWriterFailure);
749         if (FAILED(hr)) {
750             /* unknown */            
751             nState = 0;
752         }
753         else {            
754             switch(eWriterStatus) {
755             case VSS_WS_FAILED_AT_IDENTIFY:
756             case VSS_WS_FAILED_AT_PREPARE_BACKUP:
757             case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
758             case VSS_WS_FAILED_AT_FREEZE:
759             case VSS_WS_FAILED_AT_THAW:
760             case VSS_WS_FAILED_AT_POST_SNAPSHOT:
761             case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
762             case VSS_WS_FAILED_AT_PRE_RESTORE:
763             case VSS_WS_FAILED_AT_POST_RESTORE:
764     #if  defined(B_VSS_W2K3) || defined(B_VSS_VISTA)
765             case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
766     #endif
767                 /* failed */                
768                 nState = -1;
769                 break;
770
771             default:
772                 /* ok */
773                 nState = 1;
774             }
775         }
776         /* store text info */
777         char str[1000];
778         char szBuf[200];        
779         bstrncpy(str, "\"", sizeof(str));
780         wchar_2_UTF8(szBuf, bstrWriterName.p, sizeof(szBuf));
781         bstrncat(str, szBuf, sizeof(str));
782         bstrncat(str, "\", State: 0x", sizeof(str));
783         itoa(eWriterStatus, szBuf, sizeof(szBuf));
784         bstrncat(str, szBuf, sizeof(str));
785         bstrncat(str, " (", sizeof(str));
786         wchar_2_UTF8(szBuf, GetStringFromWriterStatus(eWriterStatus), sizeof(szBuf));
787         bstrncat(str, szBuf, sizeof(str));
788         bstrncat(str, ")", sizeof(str));
789
790         AppendWriterInfo(nState, (const char *)str);     
791     }
792
793     hr = pVss->FreeWriterStatus();
794
795     if (FAILED(hr)) {
796         errno = b_errno_win32;
797         return false;
798     } 
799
800     errno = 0;
801     return true;
802 }
803
804 #endif /* WIN32_VSS */