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