]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/filed/vss_generic.cpp
Fix problem building the Windows version in the same tree as the Unix version.
[bacula/bacula] / bacula / src / win32 / filed / vss_generic.cpp
1 //                              -*- Mode: C++ -*-
2 // vss.cpp -- Interface to Volume Shadow Copies (VSS)
3 //
4 // Copyright transferred from MATRIX-Computer GmbH to
5 //   Kern Sibbald by express permission.
6 //
7 //  Copyright (C) 2005-2006 Kern Sibbald
8 //
9 //  This program is free software; you can redistribute it and/or
10 //  modify it under the terms of the GNU General Public License
11 //  version 2 as amended with additional clauses defined in the
12 //  file LICENSE in the main source directory.
13 //
14 //  This program is distributed in the hope that it will be useful,
15 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
17 //  the file LICENSE for additional details.
18 //
19 //
20 // Author          : Thorsten Engel
21 // Created On      : Fri May 06 21:44:00 2005
22
23
24 #ifdef WIN32_VSS
25
26 #include "bacula.h"
27
28 #undef setlocale
29
30 // STL includes
31 #include <vector>
32 #include <algorithm>
33 #include <string>
34 #include <sstream>
35 #include <fstream>
36 using namespace std;
37
38 #include "ms_atl.h"
39 #include <objbase.h>
40
41 #if !defined(ENABLE_NLS)
42 #define setlocale(p, d)
43 #endif
44
45 #ifdef HAVE_STRSAFE_H
46 // Used for safe string manipulation
47 #include <strsafe.h>
48 #endif
49
50 BOOL VSSPathConvert(const char *szFilePath, char *szShadowPath, int nBuflen);
51 BOOL VSSPathConvertW(const wchar_t *szFilePath, wchar_t *szShadowPath, int nBuflen);
52
53 #ifdef HAVE_MINGW
54 class IXMLDOMDocument;
55 #endif
56
57 #ifdef B_VSS_XP
58    #pragma message("compile VSS for Windows XP")   
59    #define VSSClientGeneric VSSClientXP
60    
61    #include "inc/WinXP/vss.h"
62    #include "inc/WinXP/vswriter.h"
63    #include "inc/WinXP/vsbackup.h"
64    
65    /* In VSSAPI.DLL */
66    typedef HRESULT (STDAPICALLTYPE* t_CreateVssBackupComponents)(OUT IVssBackupComponents **);
67    typedef void (APIENTRY* t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
68    
69    static t_CreateVssBackupComponents p_CreateVssBackupComponents = NULL;
70    static t_VssFreeSnapshotProperties p_VssFreeSnapshotProperties = NULL;
71
72    #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
73 #endif
74
75 #ifdef B_VSS_W2K3
76    #pragma message("compile VSS for Windows 2003")
77    #define VSSClientGeneric VSSClient2003
78    
79    #include "inc/Win2003/vss.h"
80    #include "inc/Win2003/vswriter.h"
81    #include "inc/Win2003/vsbackup.h"
82    
83    /* In VSSAPI.DLL */
84    typedef HRESULT (STDAPICALLTYPE* t_CreateVssBackupComponents)(OUT IVssBackupComponents **);
85    typedef void (APIENTRY* t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
86    
87    static t_CreateVssBackupComponents p_CreateVssBackupComponents = NULL;
88    static t_VssFreeSnapshotProperties p_VssFreeSnapshotProperties = NULL;
89
90    #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
91 #endif
92
93 #include "vss.h"
94
95 /*  
96  *
97  * some helper functions 
98  *
99  *
100  */
101
102 // Append a backslash to the current string 
103 inline wstring AppendBackslash(wstring str)
104 {
105     if (str.length() == 0)
106         return wstring(L"\\");
107     if (str[str.length() - 1] == L'\\')
108         return str;
109     return str.append(L"\\");
110 }
111
112 // Get the unique volume name for the given path
113 inline wstring GetUniqueVolumeNameForPath(wstring path)
114 {
115     if (path.length() <= 0) {
116        return L"";
117     }
118
119     // Add the backslash termination, if needed
120     path = AppendBackslash(path);
121
122     // Get the root path of the volume
123     wchar_t volumeRootPath[MAX_PATH];
124     wchar_t volumeName[MAX_PATH];
125     wchar_t volumeUniqueName[MAX_PATH];
126
127     if (!p_GetVolumePathNameW || !p_GetVolumePathNameW((LPCWSTR)path.c_str(), volumeRootPath, MAX_PATH))
128       return L"";
129     
130     // Get the volume name alias (might be different from the unique volume name in rare cases)
131     if (!p_GetVolumeNameForVolumeMountPointW || !p_GetVolumeNameForVolumeMountPointW(volumeRootPath, volumeName, MAX_PATH))
132        return L"";
133     
134     // Get the unique volume name    
135     if (!p_GetVolumeNameForVolumeMountPointW(volumeName, volumeUniqueName, MAX_PATH))
136        return L"";
137     
138     return volumeUniqueName;
139 }
140
141
142 // Helper macro for quick treatment of case statements for error codes
143 #define GEN_MERGE(A, B) A##B
144 #define GEN_MAKE_W(A) GEN_MERGE(L, A)
145
146 #define CHECK_CASE_FOR_CONSTANT(value)                      \
147     case value: return (GEN_MAKE_W(#value));
148
149
150 // Convert a writer status into a string
151 inline const wchar_t* GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus)
152 {
153     switch (eWriterStatus) {
154     CHECK_CASE_FOR_CONSTANT(VSS_WS_STABLE);
155     CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_FREEZE);
156     CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_THAW);
157     CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_POST_SNAPSHOT);
158     CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_BACKUP_COMPLETE);
159     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_IDENTIFY);
160     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_BACKUP);
161     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_SNAPSHOT);
162     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_FREEZE);
163     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_THAW);
164     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_SNAPSHOT);
165     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_BACKUP_COMPLETE);
166     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PRE_RESTORE);
167     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_RESTORE);
168     
169     default:
170         return L"Error or Undefined";
171     }
172 }
173
174 // Constructor
175
176 VSSClientGeneric::VSSClientGeneric()
177 {
178    m_hLib = LoadLibraryA("VSSAPI.DLL");
179    if (m_hLib) {      
180       p_CreateVssBackupComponents = (t_CreateVssBackupComponents)
181          GetProcAddress(m_hLib, VSSVBACK_ENTRY);
182                                  
183       p_VssFreeSnapshotProperties = (t_VssFreeSnapshotProperties)
184           GetProcAddress(m_hLib, "VssFreeSnapshotProperties");      
185    } 
186 }
187
188
189
190 // Destructor
191 VSSClientGeneric::~VSSClientGeneric()
192 {
193    if (m_hLib)
194       FreeLibrary(m_hLib);
195 }
196
197 // Initialize the COM infrastructure and the internal pointers
198 BOOL VSSClientGeneric::Initialize(DWORD dwContext, BOOL bDuringRestore)
199 {
200    if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
201       errno = ENOSYS;
202       return FALSE;
203    }
204
205    HRESULT hr;
206    // Initialize COM 
207    if (!m_bCoInitializeCalled)  {
208       if (FAILED(CoInitialize(NULL))) {
209          errno = b_errno_win32;
210          return FALSE;
211       }
212       m_bCoInitializeCalled = true;
213    }
214
215    // Initialize COM security
216    if (!m_bCoInitializeSecurityCalled) {
217       hr =
218          CoInitializeSecurity(
219          NULL,                           //  Allow *all* VSS writers to communicate back!
220          -1,                             //  Default COM authentication service
221          NULL,                           //  Default COM authorization service
222          NULL,                           //  reserved parameter
223          RPC_C_AUTHN_LEVEL_PKT_PRIVACY,  //  Strongest COM authentication level
224          RPC_C_IMP_LEVEL_IDENTIFY,       //  Minimal impersonation abilities 
225          NULL,                           //  Default COM authentication settings
226          EOAC_NONE,                      //  No special options
227          NULL                            //  Reserved parameter
228          );
229
230       if (FAILED(hr)) {         
231          errno = b_errno_win32;
232          return FALSE;
233       }
234       m_bCoInitializeSecurityCalled = true;      
235    }
236    
237    // Release the IVssBackupComponents interface 
238    if (m_pVssObject) {
239       m_pVssObject->Release();
240       m_pVssObject = NULL;
241    }
242
243    // Create the internal backup components object
244    hr = p_CreateVssBackupComponents((IVssBackupComponents**) &m_pVssObject);
245    if (FAILED(hr)) {      
246       errno = b_errno_win32;
247       return FALSE;
248    }
249
250 #ifdef B_VSS_W2K3
251    if (dwContext != VSS_CTX_BACKUP) {
252       hr = ((IVssBackupComponents*) m_pVssObject)->SetContext(dwContext);
253       if (FAILED(hr)) {
254          errno = b_errno_win32;
255          return FALSE;
256       }
257    }
258 #endif
259
260    if (!bDuringRestore) {
261        // 1. InitializeForBackup
262        hr = ((IVssBackupComponents*) m_pVssObject)->InitializeForBackup();
263        if (FAILED(hr)) {
264            errno = b_errno_win32; 
265            return FALSE;
266        }
267  
268        // 2. SetBackupState
269        hr = ((IVssBackupComponents*) m_pVssObject)->SetBackupState(true, true, VSS_BT_FULL, false);
270        if (FAILED(hr)) {
271            errno = b_errno_win32;
272            return FALSE;
273        }
274        
275        CComPtr<IVssAsync>  pAsync1;       
276        // 3. GatherWriterMetaData
277        hr = ((IVssBackupComponents*) m_pVssObject)->GatherWriterMetadata(&pAsync1.p);
278        if (FAILED(hr)) {
279            errno = b_errno_win32;
280            return FALSE;
281        }
282         // Waits for the async operation to finish and checks the result
283        WaitAndCheckForAsyncOperation(pAsync1.p);
284    }
285
286
287    // We are during restore now?
288    m_bDuringRestore = bDuringRestore;
289
290    // Keep the context
291    m_dwContext = dwContext;
292
293    return TRUE;
294 }
295
296
297 BOOL VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
298 {
299    // Wait until the async operation finishes
300    // unfortunately we can't use a timeout here yet.
301    // the interface would allow it on W2k3,
302    // but it is not implemented yet....
303
304    HRESULT hr;
305
306    // Check the result of the asynchronous operation
307    HRESULT hrReturned = S_OK;
308
309    int timeout = 600; // 10 minutes....
310
311    int queryErrors = 0;
312    do {
313       if (hrReturned != S_OK) 
314          Sleep(1000);
315    
316       hrReturned = S_OK;
317       hr = pAsync->QueryStatus(&hrReturned, NULL);
318    
319       if (FAILED(hr)) 
320          queryErrors++;
321    } while ((timeout-- > 0) && (hrReturned == VSS_S_ASYNC_PENDING));
322
323    if (hrReturned == VSS_S_ASYNC_FINISHED)
324       return TRUE;
325
326    
327 #ifdef DEBUG
328    // Check if the async operation succeeded...
329    if(hrReturned != VSS_S_ASYNC_FINISHED) {   
330       wchar_t *pwszBuffer = NULL;
331       DWORD dwRet = ::FormatMessageW(
332                         FORMAT_MESSAGE_ALLOCATE_BUFFER 
333                         | FORMAT_MESSAGE_FROM_SYSTEM 
334                         | FORMAT_MESSAGE_IGNORE_INSERTS,
335                         NULL, hrReturned, 
336                         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
337                         (LPWSTR)&pwszBuffer, 0, NULL);
338
339       if (dwRet != 0) {         
340          LocalFree(pwszBuffer);         
341       }      
342       errno = b_errno_win32;
343    }
344 #endif
345
346    return FALSE;
347 }
348
349 BOOL VSSClientGeneric::CreateSnapshots(char* szDriveLetters)
350 {
351    /* szDriveLetters contains all drive letters in uppercase */
352    /* if a drive can not being added, it's converted to lowercase in szDriveLetters */
353    /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp */
354    
355    if (!m_pVssObject || m_bBackupIsInitialized) {
356       errno = ENOSYS;
357       return FALSE;  
358    }
359
360    m_uidCurrentSnapshotSet = GUID_NULL;
361
362    IVssBackupComponents *pVss = (IVssBackupComponents*)m_pVssObject;
363
364    /* startSnapshotSet */
365
366    pVss->StartSnapshotSet(&m_uidCurrentSnapshotSet);
367
368    /* AddToSnapshotSet */
369
370    wchar_t szDrive[3];
371    szDrive[1] = ':';
372    szDrive[2] = 0;
373
374    wstring volume;
375
376    CComPtr<IVssAsync>  pAsync1;
377    CComPtr<IVssAsync>  pAsync2;   
378    VSS_ID pid;
379
380    for (size_t i=0; i < strlen (szDriveLetters); i++) {
381       szDrive[0] = szDriveLetters[i];
382       volume = GetUniqueVolumeNameForPath(szDrive);
383       // store uniquevolumname
384       if (SUCCEEDED(pVss->AddToSnapshotSet((LPWSTR)volume.c_str(), GUID_NULL, &pid)))
385          wcsncpy (m_wszUniqueVolumeName[szDriveLetters[i]-'A'], (LPWSTR) volume.c_str(), MAX_PATH);
386       else
387       {            
388          szDriveLetters[i] = tolower (szDriveLetters[i]);               
389       }
390    }
391
392    /* PrepareForBackup */
393    if (FAILED(pVss->PrepareForBackup(&pAsync1.p))) {      
394       return FALSE;   
395    }
396    
397    // Waits for the async operation to finish and checks the result
398    WaitAndCheckForAsyncOperation(pAsync1.p);
399
400    /* get latest info about writer status */
401    if (!CheckWriterStatus()) {
402       return FALSE;
403    }
404
405    /* DoSnapShotSet */   
406    if (FAILED(pVss->DoSnapshotSet(&pAsync2.p))) {      
407       return FALSE;   
408    }
409
410    // Waits for the async operation to finish and checks the result
411    WaitAndCheckForAsyncOperation(pAsync2.p); 
412    
413    /* query snapshot info */   
414    QuerySnapshotSet(m_uidCurrentSnapshotSet);
415
416    SetVSSPathConvert(VSSPathConvert, VSSPathConvertW);
417
418    m_bBackupIsInitialized = true;
419
420    return TRUE;
421 }
422
423 BOOL VSSClientGeneric::CloseBackup()
424 {
425    BOOL bRet = FALSE;
426    if (!m_pVssObject)
427       errno = ENOSYS;
428    else {
429       IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
430       CComPtr<IVssAsync>  pAsync;
431
432       SetVSSPathConvert(NULL, NULL);
433
434       m_bBackupIsInitialized = false;
435
436       if (SUCCEEDED(pVss->BackupComplete(&pAsync.p))) {
437          // Waits for the async operation to finish and checks the result
438          WaitAndCheckForAsyncOperation(pAsync.p);
439          bRet = TRUE;     
440       } else {
441          errno = b_errno_win32;
442          pVss->AbortBackup();
443       }
444
445       /* get latest info about writer status */
446       CheckWriterStatus();
447
448       if (m_uidCurrentSnapshotSet != GUID_NULL) {
449          VSS_ID idNonDeletedSnapshotID = GUID_NULL;
450          LONG lSnapshots;
451
452          pVss->DeleteSnapshots(
453             m_uidCurrentSnapshotSet, 
454             VSS_OBJECT_SNAPSHOT_SET,
455             FALSE,
456             &lSnapshots,
457             &idNonDeletedSnapshotID);
458
459          m_uidCurrentSnapshotSet = GUID_NULL;
460       }
461
462       pVss->Release();
463       m_pVssObject = NULL;
464    }
465
466    // Call CoUninitialize if the CoInitialize was performed sucesfully
467    if (m_bCoInitializeCalled) {
468       CoUninitialize();
469       m_bCoInitializeCalled = false;
470    }
471
472    return bRet;
473 }
474
475 // Query all the shadow copies in the given set
476 void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
477 {   
478    if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
479       errno = ENOSYS;
480       return;
481    }
482
483    memset (m_szShadowCopyName,0,sizeof (m_szShadowCopyName));
484    
485    if (snapshotSetID == GUID_NULL || m_pVssObject == NULL) {
486       errno = ENOSYS;
487       return;
488    }
489
490    IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
491                
492    // Get list all shadow copies. 
493    CComPtr<IVssEnumObject> pIEnumSnapshots;
494    HRESULT hr = pVss->Query( GUID_NULL, 
495          VSS_OBJECT_NONE, 
496          VSS_OBJECT_SNAPSHOT, 
497          (IVssEnumObject**)(&pIEnumSnapshots) );    
498
499    // If there are no shadow copies, just return
500    if (FAILED(hr)) {
501       errno = b_errno_win32;
502       return;   
503    }
504
505    // Enumerate all shadow copies. 
506    VSS_OBJECT_PROP Prop;
507    VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap;
508    
509    while (true) {
510       // Get the next element
511       ULONG ulFetched;
512       hr = (pIEnumSnapshots.p)->Next( 1, &Prop, &ulFetched );
513
514       // We reached the end of list
515       if (ulFetched == 0)
516          break;
517
518       // Print the shadow copy (if not filtered out)
519       if (Snap.m_SnapshotSetId == snapshotSetID)  {
520          for (char ch='A'-'A';ch<='Z'-'A';ch++) {
521             if (wcscmp(Snap.m_pwszOriginalVolumeName, m_wszUniqueVolumeName[ch]) == 0) {       
522                wcsncpy (m_szShadowCopyName[ch],Snap.m_pwszSnapshotDeviceObject, MAX_PATH-1);               
523                break;
524             }
525          }
526       }
527       p_VssFreeSnapshotProperties(&Snap);
528    }
529    errno = 0;
530 }
531
532 // Check the status for all selected writers
533 BOOL VSSClientGeneric::CheckWriterStatus()
534 {
535     /* 
536     http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp
537     */
538     IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
539     DestroyWriterInfo();
540
541     // Gather writer status to detect potential errors
542     CComPtr<IVssAsync>  pAsync;
543     
544     HRESULT hr = pVss->GatherWriterStatus(&pAsync.p);
545     if (FAILED(hr)) {
546        errno = b_errno_win32;
547        return FALSE;
548     } 
549
550     // Waits for the async operation to finish and checks the result
551     WaitAndCheckForAsyncOperation(pAsync.p);
552       
553     unsigned cWriters = 0;
554
555     hr = pVss->GetWriterStatusCount(&cWriters);
556     if (FAILED(hr)) {
557        errno = b_errno_win32;
558        return FALSE;
559     }
560
561     int nState;
562     
563     // Enumerate each writer
564     for (unsigned iWriter = 0; iWriter < cWriters; iWriter++) {
565         VSS_ID idInstance = GUID_NULL;
566         VSS_ID idWriter= GUID_NULL;
567         VSS_WRITER_STATE eWriterStatus = VSS_WS_UNKNOWN;
568         CComBSTR bstrWriterName;
569         HRESULT hrWriterFailure = S_OK;
570
571         // Get writer status
572         hr = pVss->GetWriterStatus(iWriter,
573                              &idInstance,
574                              &idWriter,
575                              &bstrWriterName,
576                              &eWriterStatus,
577                              &hrWriterFailure);
578         if (FAILED(hr)) {
579             /* unknown */            
580             nState = 0;
581         }
582         else {            
583             switch(eWriterStatus) {
584             case VSS_WS_FAILED_AT_IDENTIFY:
585             case VSS_WS_FAILED_AT_PREPARE_BACKUP:
586             case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
587             case VSS_WS_FAILED_AT_FREEZE:
588             case VSS_WS_FAILED_AT_THAW:
589             case VSS_WS_FAILED_AT_POST_SNAPSHOT:
590             case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
591             case VSS_WS_FAILED_AT_PRE_RESTORE:
592             case VSS_WS_FAILED_AT_POST_RESTORE:
593     #ifdef B_VSS_W2K3
594             case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
595     #endif
596                 /* failed */                
597                 nState = -1;
598                 break;
599
600             default:
601                 /* ok */
602                 nState = 1;
603             }
604         }
605         /* store text info */
606         char str[1000];
607         char szBuf[200];        
608         strcpy(str, "\"");
609         wchar_2_UTF8(szBuf, bstrWriterName.p, sizeof(szBuf));
610         strcat(str, szBuf);
611         strcat(str, "\", State: 0x");
612         itoa(eWriterStatus, szBuf, sizeof(szBuf));
613         strcat(str, szBuf);
614         strcat(str, " (");
615         wchar_2_UTF8(szBuf, GetStringFromWriterStatus(eWriterStatus), sizeof(szBuf));
616         strcat(str, szBuf);
617         strcat(str, ")");
618
619         AppendWriterInfo(nState, (const char *)str);     
620     }
621
622     hr = pVss->FreeWriterStatus();
623
624     if (FAILED(hr)) {
625         errno = b_errno_win32;
626         return FALSE;
627     } 
628
629     errno = 0;
630     return TRUE;
631 }
632
633 #endif /* WIN32_VSS */