]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/compat/vss_generic.cpp
small vss improvement (more complete shutdown and startup after each backup instead...
[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"";
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"";
139     
140     // Get the unique volume name    
141     if (!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 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     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 wstring(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    // We are during restore now?
267    m_bDuringRestore = bDuringRestore;
268
269    // Keep the context
270    m_dwContext = dwContext;
271
272    return TRUE;
273 }
274
275
276 void VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
277 {
278      // Wait until the async operation finishes
279     HRESULT hr = pAsync->Wait();
280
281     // Check the result of the asynchronous operation
282     HRESULT hrReturned = S_OK;
283     hr = pAsync->QueryStatus(&hrReturned, NULL);
284
285     // Check if the async operation succeeded...
286     if(FAILED(hrReturned)) {
287       PWCHAR pwszBuffer = NULL;
288       DWORD dwRet = ::FormatMessageW(
289          FORMAT_MESSAGE_ALLOCATE_BUFFER 
290          | FORMAT_MESSAGE_FROM_SYSTEM 
291          | FORMAT_MESSAGE_IGNORE_INSERTS,
292          NULL, hrReturned, 
293          MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
294          (LPWSTR)&pwszBuffer, 0, NULL);
295
296       // No message found for this error. Just return <Unknown>
297       if (dwRet != 0) {
298          LocalFree(pwszBuffer);         
299       }
300     }
301 }
302
303 BOOL VSSClientGeneric::CreateSnapshots(char* szDriveLetters)
304 {
305    /* szDriveLetters contains all drive letters in uppercase */
306    /* if a drive can not being added, it's converted to lowercase in szDriveLetters */
307    /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp */
308    
309    if (!m_pVssObject || m_bBackupIsInitialized) {
310       errno = ENOSYS;
311       return FALSE;  
312    }
313
314    m_uidCurrentSnapshotSet = GUID_NULL;
315
316    IVssBackupComponents *pVss = (IVssBackupComponents*)m_pVssObject;
317
318    // 1. InitializeForBackup
319    HRESULT hr = pVss->InitializeForBackup();
320    if (FAILED(hr)) {
321       errno = b_errno_win32;
322       return FALSE;
323    }
324    
325    // 2. SetBackupState
326    hr = pVss->SetBackupState(true, true, VSS_BT_FULL, false);
327    if (FAILED(hr)) {
328       errno = b_errno_win32;
329       return FALSE;
330    }
331
332    CComPtr<IVssAsync>  pAsync1;
333    CComPtr<IVssAsync>  pAsync2;   
334    CComPtr<IVssAsync>  pAsync3;   
335    VSS_ID pid;
336
337    // 3. GatherWriterMetaData
338    hr = pVss->GatherWriterMetadata(&pAsync3);
339    if (FAILED(hr)) {
340       errno = b_errno_win32;
341       return FALSE;
342    }
343
344    // Waits for the async operation to finish and checks the result
345    WaitAndCheckForAsyncOperation(pAsync3);
346
347    CheckWriterStatus();
348
349    // 4. startSnapshotSet
350
351    pVss->StartSnapshotSet(&m_uidCurrentSnapshotSet);
352
353    // 4. AddToSnapshotSet
354
355    WCHAR szDrive[3];
356    szDrive[1] = ':';
357    szDrive[2] = 0;
358
359    wstring volume;
360
361    for (size_t i=0; i < strlen (szDriveLetters); i++) {
362       szDrive[0] = szDriveLetters[i];
363       volume = GetUniqueVolumeNameForPath(szDrive);
364       // store uniquevolumname
365       if (SUCCEEDED(pVss->AddToSnapshotSet((LPWSTR)volume.c_str(), GUID_NULL, &pid)))
366          wcsncpy (m_wszUniqueVolumeName[szDriveLetters[i]-'A'], (LPWSTR) volume.c_str(), MAX_PATH);
367       else
368          szDriveLetters[i] = tolower (szDriveLetters[i]);               
369    }
370
371    // 5. PrepareForBackup
372    pVss->PrepareForBackup(&pAsync1);
373    
374    // Waits for the async operation to finish and checks the result
375    WaitAndCheckForAsyncOperation(pAsync1);
376
377    // 6. DoSnapShotSet
378    pVss->DoSnapshotSet(&pAsync2);
379
380    // Waits for the async operation to finish and checks the result
381    WaitAndCheckForAsyncOperation(pAsync2); 
382    
383    /* query snapshot info */
384    QuerySnapshotSet(m_uidCurrentSnapshotSet);
385
386    m_bBackupIsInitialized = true;
387
388    return TRUE;
389 }
390
391 BOOL VSSClientGeneric::CloseBackup()
392 {
393    BOOL bRet = FALSE;
394    if (!m_pVssObject)
395       errno = ENOSYS;
396    else {
397       IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
398       CComPtr<IVssAsync>  pAsync;
399       
400       m_bBackupIsInitialized = false;
401
402       if (SUCCEEDED(pVss->BackupComplete(&pAsync))) {
403          // Waits for the async operation to finish and checks the result
404          WaitAndCheckForAsyncOperation(pAsync);
405          bRet = TRUE;     
406       } else {
407          errno = b_errno_win32;
408          pVss->AbortBackup();
409       }
410
411       if (m_uidCurrentSnapshotSet != GUID_NULL) {
412          VSS_ID idNonDeletedSnapshotID = GUID_NULL;
413          LONG lSnapshots;
414
415          pVss->DeleteSnapshots(
416             m_uidCurrentSnapshotSet, 
417             VSS_OBJECT_SNAPSHOT_SET,
418             FALSE,
419             &lSnapshots,
420             &idNonDeletedSnapshotID);
421
422          m_uidCurrentSnapshotSet = GUID_NULL;
423       }
424
425       pVss->Release();
426       m_pVssObject = NULL;
427    }
428
429    // Call CoUninitialize if the CoInitialize was performed sucesfully
430    if (m_bCoInitializeCalled) {
431       CoUninitialize();
432       m_bCoInitializeCalled = false;
433    }
434
435    return bRet;
436 }
437
438 // Query all the shadow copies in the given set
439 void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
440 {   
441    if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
442       errno = ENOSYS;
443       return;
444    }
445
446    memset (m_szShadowCopyName,0,sizeof (m_szShadowCopyName));
447    
448    if (snapshotSetID == GUID_NULL || m_pVssObject == NULL) {
449       errno = ENOSYS;
450       return;
451    }
452
453    IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
454                
455    // Get list all shadow copies. 
456    CComPtr<IVssEnumObject> pIEnumSnapshots;
457    HRESULT hr = pVss->Query( GUID_NULL, 
458          VSS_OBJECT_NONE, 
459          VSS_OBJECT_SNAPSHOT, 
460          &pIEnumSnapshots );    
461
462    // If there are no shadow copies, just return
463    if (FAILED(hr)) {
464       errno = b_errno_win32;
465       return;   
466    }
467
468    // Enumerate all shadow copies. 
469    VSS_OBJECT_PROP Prop;
470    VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap;
471    
472    while (true) {
473       // Get the next element
474       ULONG ulFetched;
475       hr = pIEnumSnapshots->Next( 1, &Prop, &ulFetched );
476
477       // We reached the end of list
478       if (ulFetched == 0)
479          break;
480
481       // Print the shadow copy (if not filtered out)
482       if (Snap.m_SnapshotSetId == snapshotSetID)  {
483          for (char ch='A'-'A';ch<='Z'-'A';ch++) {
484             if (wcscmp(Snap.m_pwszOriginalVolumeName, m_wszUniqueVolumeName[ch]) == 0) {               
485                WideCharToMultiByte(CP_UTF8,0,Snap.m_pwszSnapshotDeviceObject,-1,m_szShadowCopyName[ch],MAX_PATH*2,NULL,NULL);               
486                break;
487             }
488          }
489       }
490       p_VssFreeSnapshotProperties(&Snap);
491    }
492    errno = 0;
493 }
494
495 // Check the status for all selected writers
496 BOOL VSSClientGeneric::CheckWriterStatus()
497 {
498     IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
499     vector<int>* pVWriterStates = (vector<int>*) m_pVectorWriterStates;
500     vector<string>* pVWriterInfo = (vector<string>*) m_pVectorWriterInfo;   
501
502     pVWriterStates->clear();
503     pVWriterInfo->clear();
504
505     // Gather writer status to detect potential errors
506     CComPtr<IVssAsync>  pAsync;
507     
508     HRESULT hr = pVss->GatherWriterStatus(&pAsync);
509     if (FAILED(hr)) {
510        errno = b_errno_win32;
511        return FALSE;
512     } 
513
514     // Waits for the async operation to finish and checks the result
515     WaitAndCheckForAsyncOperation(pAsync);
516       
517     unsigned cWriters = 0;
518
519     hr = pVss->GetWriterStatusCount(&cWriters);
520     if (FAILED(hr)) {
521        errno = b_errno_win32;
522        return FALSE;
523     }
524     
525     // Enumerate each writer
526     for (unsigned iWriter = 0; iWriter < cWriters; iWriter++) {
527         VSS_ID idInstance = GUID_NULL;
528         VSS_ID idWriter= GUID_NULL;
529         VSS_WRITER_STATE eWriterStatus = VSS_WS_UNKNOWN;
530         CComBSTR bstrWriterName;
531         HRESULT hrWriterFailure = S_OK;
532
533         // Get writer status
534         hr = pVss->GetWriterStatus(iWriter,
535                              &idInstance,
536                              &idWriter,
537                              &bstrWriterName,
538                              &eWriterStatus,
539                              &hrWriterFailure);
540         if (FAILED(hr)) {
541            continue;
542         }
543         
544         // If the writer is in non-stable state, break
545         switch(eWriterStatus) {
546         case VSS_WS_FAILED_AT_IDENTIFY:
547         case VSS_WS_FAILED_AT_PREPARE_BACKUP:
548         case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
549         case VSS_WS_FAILED_AT_FREEZE:
550         case VSS_WS_FAILED_AT_THAW:
551         case VSS_WS_FAILED_AT_POST_SNAPSHOT:
552         case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
553         case VSS_WS_FAILED_AT_PRE_RESTORE:
554         case VSS_WS_FAILED_AT_POST_RESTORE:
555 #ifdef B_VSS_W2K3
556         case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
557 #endif
558            /* failed */
559            pVWriterStates->push_back(-1);
560            break;
561
562         default:
563            /* okay */
564            pVWriterStates->push_back(1);                
565         }
566
567                
568         stringstream osf;      
569         osf << "\"" << CW2A(bstrWriterName) << "\", State: " << eWriterStatus << " (" << CW2A(GetStringFromWriterStatus(eWriterStatus).c_str()) << ")";
570     
571         pVWriterInfo->push_back(osf.str());
572     }
573     errno = 0;
574     return TRUE;
575 }