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