]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/compat/vss_generic.cpp
- bugfix (failure in VSS was not handled correctly)
[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) 2004-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 as
11 //   published by the Free Software Foundation; either version 2 of
12 //   the License, or (at your option) any later version.
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 GNU
17 //   General Public License for more details.
18 //
19 //   You should have received a copy of the GNU General Public
20 //   License along with this program; if not, write to the Free
21 //   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
22 //   MA 02111-1307, USA.
23 //
24 // Author          : Thorsten Engel
25 // Created On      : Fri May 06 21:44:00 2006
26
27
28 #include <stdio.h>
29 #include <basetsd.h>
30 #include <stdarg.h>
31 #include <sys/types.h>
32 #include <process.h>
33 #include <direct.h>
34 #include <winsock2.h>
35 #include <windows.h>
36 #include <wincon.h>
37 #include <winbase.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <stdarg.h>
41 #include <conio.h>
42 #include <process.h>
43 #include <errno.h>
44 #include <string.h>
45 #include <time.h>
46 #include <signal.h>
47 #include <malloc.h>
48 #include <setjmp.h>
49 #include <direct.h>
50 #include <ctype.h>
51 #include <fcntl.h>
52 #include <io.h>
53
54
55 // STL includes
56 #include <vector>
57 #include <algorithm>
58 #include <string>
59 #include <sstream>
60 #include <fstream>
61 using namespace std;   
62
63 #include <atlcomcli.h>
64 #include <objbase.h>
65
66 // Used for safe string manipulation
67 #include <strsafe.h>
68
69 #ifdef B_VSS_XP
70    #pragma message("compile VSS for Windows XP")   
71    #define VSSClientGeneric VSSClientXP
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
91    #include "vss/inc/Win2003/vss.h"
92    #include "vss/inc/Win2003/vswriter.h"
93    #include "vss/inc/Win2003/vsbackup.h"
94    
95    /* In VSSAPI.DLL */
96    typedef HRESULT (STDAPICALLTYPE* t_CreateVssBackupComponents)(OUT IVssBackupComponents **);
97    typedef void (APIENTRY* t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
98    
99    static t_CreateVssBackupComponents p_CreateVssBackupComponents = NULL;
100    static t_VssFreeSnapshotProperties p_VssFreeSnapshotProperties = NULL;
101
102    #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
103 #endif
104
105 #include "vss.h"
106
107 /*  
108  *
109  * some helper functions 
110  *
111  *
112  */
113
114 // Append a backslash to the current string 
115 inline wstring AppendBackslash(wstring str)
116 {
117     if (str.length() == 0)
118         return wstring(L"\\");
119     if (str[str.length() - 1] == L'\\')
120         return str;
121     return str.append(L"\\");
122 }
123
124 // Get the unique volume name for the given path
125 inline wstring GetUniqueVolumeNameForPath(wstring path)
126 {
127     _ASSERTE(path.length() > 0);
128
129     // Add the backslash termination, if needed
130     path = AppendBackslash(path);
131
132     // Get the root path of the volume
133     WCHAR volumeRootPath[MAX_PATH];
134     WCHAR volumeName[MAX_PATH];
135     WCHAR volumeUniqueName[MAX_PATH];
136
137     if (!GetVolumePathNameW((LPCWSTR)path.c_str(), volumeRootPath, MAX_PATH))
138       return L'\0';
139     
140     // Get the volume name alias (might be different from the unique volume name in rare cases)
141     if (!GetVolumeNameForVolumeMountPointW(volumeRootPath, volumeName, MAX_PATH))
142        return L'\0';
143     
144     // Get the unique volume name    
145     if (!GetVolumeNameForVolumeMountPointW(volumeName, volumeUniqueName, MAX_PATH))
146        return L'\0';
147     
148     return volumeUniqueName;
149 }
150
151
152 // Helper macro for quick treatment of case statements for error codes
153 #define GEN_MERGE(A, B) A##B
154 #define GEN_MAKE_W(A) GEN_MERGE(L, A)
155
156 #define CHECK_CASE_FOR_CONSTANT(value)                      \
157     case value: return wstring(GEN_MAKE_W(#value));
158
159
160 // Convert a writer status into a string
161 inline wstring GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus)
162 {
163     switch (eWriterStatus)
164     {
165     CHECK_CASE_FOR_CONSTANT(VSS_WS_STABLE);
166     CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_FREEZE);
167     CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_THAW);
168     CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_POST_SNAPSHOT);
169     CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_BACKUP_COMPLETE);
170     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_IDENTIFY);
171     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_BACKUP);
172     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_SNAPSHOT);
173     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_FREEZE);
174     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_THAW);
175     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_SNAPSHOT);
176     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_BACKUP_COMPLETE);
177     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PRE_RESTORE);
178     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_RESTORE);
179
180     default:
181         return wstring(L"Undefined");
182     }
183 }
184
185 // Constructor
186
187 VSSClientGeneric::VSSClientGeneric()
188 {
189    m_hLib = LoadLibraryA("VSSAPI.DLL");
190    if (m_hLib) {      
191       p_CreateVssBackupComponents = (t_CreateVssBackupComponents)
192          GetProcAddress(m_hLib, VSSVBACK_ENTRY);
193                                  
194       p_VssFreeSnapshotProperties = (t_VssFreeSnapshotProperties)
195           GetProcAddress(m_hLib, "VssFreeSnapshotProperties");      
196    } 
197 }
198
199
200
201 // Destructor
202 VSSClientGeneric::~VSSClientGeneric()
203 {
204    if (m_hLib)
205       FreeLibrary(m_hLib);
206 }
207
208 // Initialize the COM infrastructure and the internal pointers
209 BOOL VSSClientGeneric::Initialize(DWORD dwContext, BOOL bDuringRestore)
210 {
211    if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties))
212       return FALSE;
213
214    HRESULT hr;
215    // Initialize COM 
216    if (!m_bCoInitializeCalled)  {
217       if (FAILED(CoInitialize(NULL)))
218          return FALSE;
219
220       m_bCoInitializeCalled = true;
221
222       // Initialize COM security
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          return FALSE;
238    }
239    
240    // Release the IVssBackupComponents interface 
241    if (m_pVssObject) {
242       m_pVssObject->Release();
243       m_pVssObject = NULL;
244    }
245
246    // Create the internal backup components object
247    hr = p_CreateVssBackupComponents((IVssBackupComponents**) &m_pVssObject);
248    if (FAILED(hr))
249       return FALSE;
250
251 #ifdef B_VSS_W2K3
252    if (dwContext != VSS_CTX_BACKUP) {
253       hr = ((IVssBackupComponents*) m_pVssObject)->SetContext(dwContext);
254       if (FAILED(hr))
255          return FALSE;
256    }
257 #endif
258
259    // We are during restore now?
260    m_bDuringRestore = bDuringRestore;
261
262    // Keep the context
263    m_dwContext = dwContext;
264
265    return TRUE;
266 }
267
268
269 void VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
270 {
271      // Wait until the async operation finishes
272     HRESULT hr = pAsync->Wait();
273
274     // Check the result of the asynchronous operation
275     HRESULT hrReturned = S_OK;
276     hr = pAsync->QueryStatus(&hrReturned, NULL);
277
278     // Check if the async operation succeeded...
279     if(FAILED(hrReturned))
280     {
281       PWCHAR pwszBuffer = NULL;
282       DWORD dwRet = ::FormatMessageW(
283          FORMAT_MESSAGE_ALLOCATE_BUFFER 
284          | FORMAT_MESSAGE_FROM_SYSTEM 
285          | FORMAT_MESSAGE_IGNORE_INSERTS,
286          NULL, hrReturned, 
287          MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
288          (LPWSTR)&pwszBuffer, 0, NULL);
289
290       // No message found for this error. Just return <Unknown>
291       if (dwRet != 0)
292       {
293          // Convert the message into wstring         
294     
295          LocalFree(pwszBuffer);         
296       }
297     }
298 }
299
300 BOOL VSSClientGeneric::CreateSnapshots(char* szDriveLetters)
301 {
302    /* szDriveLetters contains all drive letters in uppercase */
303    /* if a drive can not being added, it's converted to lowercase in szDriveLetters */
304    /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp */
305    
306    if (!m_pVssObject || m_bBackupIsInitialized)
307       return FALSE;  
308
309    m_uidCurrentSnapshotSet = GUID_NULL;
310
311    IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
312
313    // 1. InitializeForBackup
314    HRESULT hr = pVss->InitializeForBackup();
315    if (FAILED(hr))
316       return FALSE;
317    
318    // 2. SetBackupState
319    hr = pVss->SetBackupState(true, true, VSS_BT_FULL, false);
320    if (FAILED(hr))
321       return FALSE;
322
323    CComPtr<IVssAsync>  pAsync1;
324    CComPtr<IVssAsync>  pAsync2;   
325    CComPtr<IVssAsync>  pAsync3;   
326    VSS_ID pid;
327
328    // 3. GatherWriterMetaData
329    hr = pVss->GatherWriterMetadata(&pAsync3);
330    if (FAILED(hr))
331       return FALSE;
332
333    // Waits for the async operation to finish and checks the result
334    WaitAndCheckForAsyncOperation(pAsync3);
335
336    CheckWriterStatus();
337
338    // 4. startSnapshotSet
339
340    pVss->StartSnapshotSet(&m_uidCurrentSnapshotSet);
341
342    // 4. AddToSnapshotSet
343
344    WCHAR szDrive[3];
345    szDrive[1] = ':';
346    szDrive[2] = 0;
347
348    wstring volume;
349
350    for (size_t i=0; i < strlen (szDriveLetters); i++) {
351       szDrive[0] = szDriveLetters[i];
352       volume = GetUniqueVolumeNameForPath(szDrive);
353       // store uniquevolumname
354       if (SUCCEEDED(pVss->AddToSnapshotSet((LPWSTR)volume.c_str(), GUID_NULL, &pid)))
355          wcsncpy (m_wszUniqueVolumeName[szDriveLetters[i]-'A'], (LPWSTR) volume.c_str(), MAX_PATH);
356       else
357          szDriveLetters[i] = tolower (szDriveLetters[i]);               
358    }
359
360    // 5. PrepareForBackup
361    pVss->PrepareForBackup(&pAsync1);
362    
363    // Waits for the async operation to finish and checks the result
364    WaitAndCheckForAsyncOperation(pAsync1);
365
366    // 6. DoSnapShotSet
367    pVss->DoSnapshotSet(&pAsync2);
368
369    // Waits for the async operation to finish and checks the result
370    WaitAndCheckForAsyncOperation(pAsync2); 
371    
372    /* query snapshot info */
373    QuerySnapshotSet(m_uidCurrentSnapshotSet);
374
375    m_bBackupIsInitialized = true;
376
377    return TRUE;
378 }
379
380 BOOL VSSClientGeneric::CloseBackup()
381 {
382    if (!m_pVssObject)
383       return FALSE;
384
385    BOOL bRet = FALSE;
386    IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
387    CComPtr<IVssAsync>  pAsync;
388    
389    m_bBackupIsInitialized = false;
390
391    if (SUCCEEDED(pVss->BackupComplete(&pAsync))) {
392      // Waits for the async operation to finish and checks the result
393      WaitAndCheckForAsyncOperation(pAsync);
394      bRet = TRUE;     
395    }
396    else {
397       pVss->AbortBackup();
398    }
399
400    if (m_uidCurrentSnapshotSet != GUID_NULL) {
401       VSS_ID idNonDeletedSnapshotID = GUID_NULL;
402       LONG lSnapshots;
403
404       pVss->DeleteSnapshots(
405          m_uidCurrentSnapshotSet, 
406          VSS_OBJECT_SNAPSHOT_SET,
407          FALSE,
408          &lSnapshots,
409          &idNonDeletedSnapshotID);
410
411       m_uidCurrentSnapshotSet = GUID_NULL;
412    }
413
414
415    pVss->Release();
416    m_pVssObject = NULL;
417
418    return bRet;
419 }
420
421 // Query all the shadow copies in the given set
422 void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
423 {   
424    if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties))
425       return;
426
427    memset (m_szShadowCopyName,0,sizeof (m_szShadowCopyName));
428    
429    if (snapshotSetID == GUID_NULL || m_pVssObject == NULL)
430       return;
431
432    IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
433                
434    // Get list all shadow copies. 
435    CComPtr<IVssEnumObject> pIEnumSnapshots;
436    HRESULT hr = pVss->Query( GUID_NULL, 
437          VSS_OBJECT_NONE, 
438          VSS_OBJECT_SNAPSHOT, 
439          &pIEnumSnapshots );    
440
441    // If there are no shadow copies, just return
442    if (FAILED(hr))
443       return;   
444
445    // Enumerate all shadow copies. 
446    VSS_OBJECT_PROP Prop;
447    VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap;
448    
449    while(true)
450    {
451       // Get the next element
452       ULONG ulFetched;
453       hr = pIEnumSnapshots->Next( 1, &Prop, &ulFetched );
454
455       // We reached the end of list
456       if (ulFetched == 0)
457          break;
458
459       // Print the shadow copy (if not filtered out)
460       if (Snap.m_SnapshotSetId == snapshotSetID)  {
461          for (char ch='A'-'A';ch<='Z'-'A';ch++) {
462             if (wcscmp(Snap.m_pwszOriginalVolumeName, m_wszUniqueVolumeName[ch]) == 0) {               
463                WideCharToMultiByte(CP_UTF8,0,Snap.m_pwszSnapshotDeviceObject,-1,m_szShadowCopyName[ch],MAX_PATH*2,NULL,NULL);               
464                break;
465             }
466          }
467       }
468       p_VssFreeSnapshotProperties(&Snap);
469    }
470 }
471
472 // Check the status for all selected writers
473 BOOL VSSClientGeneric::CheckWriterStatus()
474 {
475     IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
476     vector<int>* pVWriterStates = (vector<int>*) m_pVectorWriterStates;
477     vector<string>* pVWriterInfo = (vector<string>*) m_pVectorWriterInfo;   
478
479     pVWriterStates->clear();
480     pVWriterInfo->clear();
481
482     // Gather writer status to detect potential errors
483     CComPtr<IVssAsync>  pAsync;
484     
485     HRESULT hr = pVss->GatherWriterStatus(&pAsync);
486     if (FAILED(hr))
487       return FALSE;
488
489     // Waits for the async operation to finish and checks the result
490     WaitAndCheckForAsyncOperation(pAsync);
491       
492     unsigned cWriters = 0;
493
494     hr = pVss->GetWriterStatusCount(&cWriters);
495     if (FAILED(hr))
496       return FALSE;
497     
498     // Enumerate each writer
499     for(unsigned iWriter = 0; iWriter < cWriters; iWriter++)
500     {
501         VSS_ID idInstance = GUID_NULL;
502         VSS_ID idWriter= GUID_NULL;
503         VSS_WRITER_STATE eWriterStatus = VSS_WS_UNKNOWN;
504         CComBSTR bstrWriterName;
505         HRESULT hrWriterFailure = S_OK;
506
507         // Get writer status
508         hr = pVss->GetWriterStatus(iWriter,
509                              &idInstance,
510                              &idWriter,
511                              &bstrWriterName,
512                              &eWriterStatus,
513                              &hrWriterFailure);
514         if (FAILED(hr))
515            continue;
516         
517         // If the writer is in non-stable state, break
518         switch(eWriterStatus)
519         {
520             case VSS_WS_FAILED_AT_IDENTIFY:
521             case VSS_WS_FAILED_AT_PREPARE_BACKUP:
522             case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
523             case VSS_WS_FAILED_AT_FREEZE:
524             case VSS_WS_FAILED_AT_THAW:
525             case VSS_WS_FAILED_AT_POST_SNAPSHOT:
526             case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
527             case VSS_WS_FAILED_AT_PRE_RESTORE:
528             case VSS_WS_FAILED_AT_POST_RESTORE:
529 #ifdef B_VSS_W2K3
530             case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
531 #endif
532                /* failed */
533                pVWriterStates->push_back(-1);
534                break;
535
536             default:
537                 /* okay */
538                 pVWriterStates->push_back(1);                
539         }
540
541                
542         stringstream osf;      
543         osf << "\"" << CW2A(bstrWriterName) << "\", State: " << eWriterStatus << " (" << CW2A(GetStringFromWriterStatus(eWriterStatus).c_str()) << ")";
544     
545         pVWriterInfo->push_back(osf.str());
546     }
547     return TRUE;
548 }