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