]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/compat/vss_generic.cpp
5a3bb481c7e0be0da9c830f512bec23ce1c733f8
[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 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 #include <io.h>
49
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 #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 (!GetVolumePathNameW((LPCWSTR)path.c_str(), volumeRootPath, MAX_PATH))
134       return L'\0';
135     
136     // Get the volume name alias (might be different from the unique volume name in rare cases)
137     if (!GetVolumeNameForVolumeMountPointW(volumeRootPath, volumeName, MAX_PATH))
138        return L'\0';
139     
140     // Get the unique volume name    
141     if (!GetVolumeNameForVolumeMountPointW(volumeName, volumeUniqueName, MAX_PATH))
142        return L'\0';
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 wstring(GEN_MAKE_W(#value));
154
155
156 // Convert a writer status into a string
157 inline wstring GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus)
158 {
159     switch (eWriterStatus)
160     {
161     CHECK_CASE_FOR_CONSTANT(VSS_WS_STABLE);
162     CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_FREEZE);
163     CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_THAW);
164     CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_POST_SNAPSHOT);
165     CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_BACKUP_COMPLETE);
166     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_IDENTIFY);
167     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_BACKUP);
168     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_SNAPSHOT);
169     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_FREEZE);
170     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_THAW);
171     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_SNAPSHOT);
172     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_BACKUP_COMPLETE);
173     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PRE_RESTORE);
174     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_RESTORE);
175
176     default:
177         return wstring(L"Undefined");
178     }
179 }
180
181 // Constructor
182
183 VSSClientGeneric::VSSClientGeneric()
184 {
185    m_hLib = LoadLibraryA("VSSAPI.DLL");
186    if (m_hLib) {      
187       p_CreateVssBackupComponents = (t_CreateVssBackupComponents)
188          GetProcAddress(m_hLib, VSSVBACK_ENTRY);
189                                  
190       p_VssFreeSnapshotProperties = (t_VssFreeSnapshotProperties)
191           GetProcAddress(m_hLib, "VssFreeSnapshotProperties");      
192    } 
193 }
194
195
196
197 // Destructor
198 VSSClientGeneric::~VSSClientGeneric()
199 {
200    if (m_hLib)
201       FreeLibrary(m_hLib);
202 }
203
204 // Initialize the COM infrastructure and the internal pointers
205 BOOL VSSClientGeneric::Initialize(DWORD dwContext, BOOL bDuringRestore)
206 {
207    if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties))
208       return FALSE;
209
210    HRESULT hr;
211    // Initialize COM 
212    if (!m_bCoInitializeCalled)  {
213       if (FAILED(CoInitialize(NULL)))
214          return FALSE;
215
216       m_bCoInitializeCalled = true;
217
218       // Initialize COM security
219       hr =
220          CoInitializeSecurity(
221          NULL,                           //  Allow *all* VSS writers to communicate back!
222          -1,                             //  Default COM authentication service
223          NULL,                           //  Default COM authorization service
224          NULL,                           //  reserved parameter
225          RPC_C_AUTHN_LEVEL_PKT_PRIVACY,  //  Strongest COM authentication level
226          RPC_C_IMP_LEVEL_IDENTIFY,       //  Minimal impersonation abilities 
227          NULL,                           //  Default COM authentication settings
228          EOAC_NONE,                      //  No special options
229          NULL                            //  Reserved parameter
230          );
231
232       if (FAILED(hr))
233          return FALSE;
234    }
235    
236    // Release the IVssBackupComponents interface 
237    if (m_pVssObject) {
238       m_pVssObject->Release();
239       m_pVssObject = NULL;
240    }
241
242    // Create the internal backup components object
243    hr = p_CreateVssBackupComponents((IVssBackupComponents**) &m_pVssObject);
244    if (FAILED(hr))
245       return FALSE;
246
247 #ifdef B_VSS_W2K3
248    if (dwContext != VSS_CTX_BACKUP) {
249       hr = ((IVssBackupComponents*) m_pVssObject)->SetContext(dwContext);
250       if (FAILED(hr))
251          return FALSE;
252    }
253 #endif
254
255    // We are during restore now?
256    m_bDuringRestore = bDuringRestore;
257
258    // Keep the context
259    m_dwContext = dwContext;
260
261    return TRUE;
262 }
263
264
265 void VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
266 {
267      // Wait until the async operation finishes
268     HRESULT hr = pAsync->Wait();
269
270     // Check the result of the asynchronous operation
271     HRESULT hrReturned = S_OK;
272     hr = pAsync->QueryStatus(&hrReturned, NULL);
273
274     // Check if the async operation succeeded...
275     if(FAILED(hrReturned))
276     {
277       PWCHAR pwszBuffer = NULL;
278       DWORD dwRet = ::FormatMessageW(
279          FORMAT_MESSAGE_ALLOCATE_BUFFER 
280          | FORMAT_MESSAGE_FROM_SYSTEM 
281          | FORMAT_MESSAGE_IGNORE_INSERTS,
282          NULL, hrReturned, 
283          MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
284          (LPWSTR)&pwszBuffer, 0, NULL);
285
286       // No message found for this error. Just return <Unknown>
287       if (dwRet != 0)
288       {
289          // Convert the message into wstring         
290     
291          LocalFree(pwszBuffer);         
292       }
293     }
294 }
295
296 BOOL VSSClientGeneric::CreateSnapshots(char* szDriveLetters)
297 {
298    /* szDriveLetters contains all drive letters in uppercase */
299    /* if a drive can not being added, it's converted to lowercase in szDriveLetters */
300    /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp */
301    
302    if (!m_pVssObject || m_bBackupIsInitialized)
303       return FALSE;  
304
305    m_uidCurrentSnapshotSet = GUID_NULL;
306
307    IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
308
309    // 1. InitializeForBackup
310    HRESULT hr = pVss->InitializeForBackup();
311    if (FAILED(hr))
312       return FALSE;
313    
314    // 2. SetBackupState
315    hr = pVss->SetBackupState(true, true, VSS_BT_FULL, false);
316    if (FAILED(hr))
317       return FALSE;
318
319    CComPtr<IVssAsync>  pAsync1;
320    CComPtr<IVssAsync>  pAsync2;   
321    CComPtr<IVssAsync>  pAsync3;   
322    VSS_ID pid;
323
324    // 3. GatherWriterMetaData
325    hr = pVss->GatherWriterMetadata(&pAsync3);
326    if (FAILED(hr))
327       return FALSE;
328
329    // Waits for the async operation to finish and checks the result
330    WaitAndCheckForAsyncOperation(pAsync3);
331
332    CheckWriterStatus();
333
334    // 4. startSnapshotSet
335
336    pVss->StartSnapshotSet(&m_uidCurrentSnapshotSet);
337
338    // 4. AddToSnapshotSet
339
340    WCHAR szDrive[3];
341    szDrive[1] = ':';
342    szDrive[2] = 0;
343
344    wstring volume;
345
346    for (size_t i=0; i < strlen (szDriveLetters); i++) {
347       szDrive[0] = szDriveLetters[i];
348       volume = GetUniqueVolumeNameForPath(szDrive);
349       // store uniquevolumname
350       if (SUCCEEDED(pVss->AddToSnapshotSet((LPWSTR)volume.c_str(), GUID_NULL, &pid)))
351          wcsncpy (m_wszUniqueVolumeName[szDriveLetters[i]-'A'], (LPWSTR) volume.c_str(), MAX_PATH);
352       else
353          szDriveLetters[i] = tolower (szDriveLetters[i]);               
354    }
355
356    // 5. PrepareForBackup
357    pVss->PrepareForBackup(&pAsync1);
358    
359    // Waits for the async operation to finish and checks the result
360    WaitAndCheckForAsyncOperation(pAsync1);
361
362    // 6. DoSnapShotSet
363    pVss->DoSnapshotSet(&pAsync2);
364
365    // Waits for the async operation to finish and checks the result
366    WaitAndCheckForAsyncOperation(pAsync2); 
367    
368    /* query snapshot info */
369    QuerySnapshotSet(m_uidCurrentSnapshotSet);
370
371    m_bBackupIsInitialized = true;
372
373    return TRUE;
374 }
375
376 BOOL VSSClientGeneric::CloseBackup()
377 {
378    if (!m_pVssObject)
379       return FALSE;
380
381    BOOL bRet = FALSE;
382    IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
383    CComPtr<IVssAsync>  pAsync;
384    
385    m_bBackupIsInitialized = false;
386
387    if (SUCCEEDED(pVss->BackupComplete(&pAsync))) {
388      // Waits for the async operation to finish and checks the result
389      WaitAndCheckForAsyncOperation(pAsync);
390      bRet = TRUE;     
391    }
392    else {
393       pVss->AbortBackup();
394    }
395
396    if (m_uidCurrentSnapshotSet != GUID_NULL) {
397       VSS_ID idNonDeletedSnapshotID = GUID_NULL;
398       LONG lSnapshots;
399
400       pVss->DeleteSnapshots(
401          m_uidCurrentSnapshotSet, 
402          VSS_OBJECT_SNAPSHOT_SET,
403          FALSE,
404          &lSnapshots,
405          &idNonDeletedSnapshotID);
406
407       m_uidCurrentSnapshotSet = GUID_NULL;
408    }
409
410
411    pVss->Release();
412    m_pVssObject = NULL;
413
414    return bRet;
415 }
416
417 // Query all the shadow copies in the given set
418 void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
419 {   
420    if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties))
421       return;
422
423    memset (m_szShadowCopyName,0,sizeof (m_szShadowCopyName));
424    
425    if (snapshotSetID == GUID_NULL || m_pVssObject == NULL)
426       return;
427
428    IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
429                
430    // Get list all shadow copies. 
431    CComPtr<IVssEnumObject> pIEnumSnapshots;
432    HRESULT hr = pVss->Query( GUID_NULL, 
433          VSS_OBJECT_NONE, 
434          VSS_OBJECT_SNAPSHOT, 
435          &pIEnumSnapshots );    
436
437    // If there are no shadow copies, just return
438    if (FAILED(hr))
439       return;   
440
441    // Enumerate all shadow copies. 
442    VSS_OBJECT_PROP Prop;
443    VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap;
444    
445    while(true)
446    {
447       // Get the next element
448       ULONG ulFetched;
449       hr = pIEnumSnapshots->Next( 1, &Prop, &ulFetched );
450
451       // We reached the end of list
452       if (ulFetched == 0)
453          break;
454
455       // Print the shadow copy (if not filtered out)
456       if (Snap.m_SnapshotSetId == snapshotSetID)  {
457          for (char ch='A'-'A';ch<='Z'-'A';ch++) {
458             if (wcscmp(Snap.m_pwszOriginalVolumeName, m_wszUniqueVolumeName[ch]) == 0) {               
459                WideCharToMultiByte(CP_UTF8,0,Snap.m_pwszSnapshotDeviceObject,-1,m_szShadowCopyName[ch],MAX_PATH*2,NULL,NULL);               
460                break;
461             }
462          }
463       }
464       p_VssFreeSnapshotProperties(&Snap);
465    }
466 }
467
468 // Check the status for all selected writers
469 BOOL VSSClientGeneric::CheckWriterStatus()
470 {
471     IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
472     vector<int>* pVWriterStates = (vector<int>*) m_pVectorWriterStates;
473     vector<string>* pVWriterInfo = (vector<string>*) m_pVectorWriterInfo;   
474
475     pVWriterStates->clear();
476     pVWriterInfo->clear();
477
478     // Gather writer status to detect potential errors
479     CComPtr<IVssAsync>  pAsync;
480     
481     HRESULT hr = pVss->GatherWriterStatus(&pAsync);
482     if (FAILED(hr))
483       return FALSE;
484
485     // Waits for the async operation to finish and checks the result
486     WaitAndCheckForAsyncOperation(pAsync);
487       
488     unsigned cWriters = 0;
489
490     hr = pVss->GetWriterStatusCount(&cWriters);
491     if (FAILED(hr))
492       return FALSE;
493     
494     // Enumerate each writer
495     for(unsigned iWriter = 0; iWriter < cWriters; iWriter++)
496     {
497         VSS_ID idInstance = GUID_NULL;
498         VSS_ID idWriter= GUID_NULL;
499         VSS_WRITER_STATE eWriterStatus = VSS_WS_UNKNOWN;
500         CComBSTR bstrWriterName;
501         HRESULT hrWriterFailure = S_OK;
502
503         // Get writer status
504         hr = pVss->GetWriterStatus(iWriter,
505                              &idInstance,
506                              &idWriter,
507                              &bstrWriterName,
508                              &eWriterStatus,
509                              &hrWriterFailure);
510         if (FAILED(hr))
511            continue;
512         
513         // If the writer is in non-stable state, break
514         switch(eWriterStatus)
515         {
516             case VSS_WS_FAILED_AT_IDENTIFY:
517             case VSS_WS_FAILED_AT_PREPARE_BACKUP:
518             case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
519             case VSS_WS_FAILED_AT_FREEZE:
520             case VSS_WS_FAILED_AT_THAW:
521             case VSS_WS_FAILED_AT_POST_SNAPSHOT:
522             case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
523             case VSS_WS_FAILED_AT_PRE_RESTORE:
524             case VSS_WS_FAILED_AT_POST_RESTORE:
525 #ifdef B_VSS_W2K3
526             case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
527 #endif
528                /* failed */
529                pVWriterStates->push_back(-1);
530                break;
531
532             default:
533                 /* okay */
534                 pVWriterStates->push_back(1);                
535         }
536
537                
538         stringstream osf;      
539         osf << "\"" << CW2A(bstrWriterName) << "\", State: " << eWriterStatus << " (" << CW2A(GetStringFromWriterStatus(eWriterStatus).c_str()) << ")";
540     
541         pVWriterInfo->push_back(osf.str());
542     }
543     return TRUE;
544 }