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