1 /*
2 Bacula® - The Network Backup Solution
3
4 Copyright (C) 2005-2008 Free Software Foundation Europe e.V.
5
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
11 in the file LICENSE.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.
22
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
27 */
28 // -*- Mode: C++ -*-
29 // vss.cpp -- Interface to Volume Shadow Copies (VSS)
30 //
31 // Copyright transferred from MATRIX-Computer GmbH to
32 // Kern Sibbald by express permission.
33 //
34 // Author : Thorsten Engel
35 // Created On : Fri May 06 21:44:00 2005
36
37
38 #ifdef WIN32_VSS
39
40 #include "burp.h"
41 #include "berrno.h"
42 #include "../../log.h"
43
44 #undef setlocale
45
46 // STL includes.
47 #include <vector>
48 #include <algorithm>
49 #include <string>
50 #include <sstream>
51 #include <fstream>
52 using namespace std;
53
54 #include "ms_atl.h"
55 #include <objbase.h>
56
57 /* Kludges to get Vista code to compile.
58 KES - June 2007 */
59 #define __in IN
60 #define __out OUT
61 #define __RPC_unique_pointer
62 #define __RPC_string
63 #define __RPC__deref_inout_opt
64 #define __RPC__out
65
66 #ifndef ENABLE_NLS
67 #define setlocale(p, d)
68 #endif
69
70 #ifdef HAVE_STRSAFE_H
71 // Used for safe string manipulation
72 #include <strsafe.h>
73 #endif
74
75 BOOL VSSPathConvert(const char *szFilePath,
76 char *szShadowPath, int nBuflen);
77 BOOL VSSPathConvertW(const wchar_t *szFilePath,
78 wchar_t *szShadowPath, int nBuflen);
79
80 class IXMLDOMDocument;
81
82 // Reduce compiler warnings from Windows vss code.
83 #define uuid(x)
84
85 #ifdef B_VSS_XP
86 #define VSSClientGeneric VSSClientXP
87 #include "inc/winxp/vss.h"
88 #include "inc/winxp/vswriter.h"
89 #include "inc/winxp/vsbackup.h"
90 #endif
91
92 #ifdef B_VSS_W2K3
93 #define VSSClientGeneric VSSClient2003
94 #include "inc/win2003/vss.h"
95 #include "inc/win2003/vswriter.h"
96 #include "inc/win2003/vsbackup.h"
97 #endif
98
99 #ifdef B_VSS_VISTA
100 #define VSSClientGeneric VSSClientVista
101 #include "inc/win2003/vss.h"
102 #include "inc/win2003/vswriter.h"
103 #include "inc/win2003/vsbackup.h"
104 #endif
105
106 // In VSSAPI.DLL.
107 typedef HRESULT (STDAPICALLTYPE* t_CreateVssBackupComponents)
108 (OUT IVssBackupComponents **);
109 typedef void (APIENTRY* t_VssFreeSnapshotProperties)
110 (IN VSS_SNAPSHOT_PROP*);
111
112 static t_CreateVssBackupComponents p_CreateVssBackupComponents=NULL;
113 static t_VssFreeSnapshotProperties p_VssFreeSnapshotProperties=NULL;
114
115 #include "vss.h"
116
117 // Some helper functions.
118
AppendBackslash(wstring str)119 inline wstring AppendBackslash(wstring str)
120 {
121 if(!str.length())
122 return wstring(L"\\");
123 if(str[str.length() - 1]==L'\\')
124 return str;
125 return str.append(L"\\");
126 }
127
128 // Get the unique volume name for the given path.
GetUniqueVolumeNameForPath(wstring path)129 inline wstring GetUniqueVolumeNameForPath(wstring path)
130 {
131 if(path.length()<=0) return L"";
132
133 // Add the backslash termination, if needed
134 path=AppendBackslash(path);
135
136 // Get the root path of the volume
137 wchar_t volumeRootPath[MAX_PATH];
138 wchar_t volumeName[MAX_PATH];
139 wchar_t volumeUniqueName[MAX_PATH];
140
141 if(!p_GetVolumePathNameW
142 || !p_GetVolumePathNameW((LPCWSTR)path.c_str(),
143 volumeRootPath, MAX_PATH))
144 return L"";
145
146 // Get the volume name alias (might be different from the unique volume
147 // name in rare cases).
148 if(!p_GetVolumeNameForVolumeMountPointW
149 || !p_GetVolumeNameForVolumeMountPointW(volumeRootPath,
150 volumeName, MAX_PATH))
151 return L"";
152
153 // Get the unique volume name.
154 if(!p_GetVolumeNameForVolumeMountPointW(volumeName,
155 volumeUniqueName, MAX_PATH))
156 return L"";
157
158 return volumeUniqueName;
159 }
160
161
162 // Helper macro for quick treatment of case statements for error codes.
163 #define GEN_MERGE(A, B) A##B
164 #define GEN_MAKE_W(A) GEN_MERGE(L, A)
165
166 #define CHECK_CASE_FOR_CONSTANT(value) case value: return (GEN_MAKE_W(#value));
167
168
169 // Convert a writer status into a string.
GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus)170 inline const wchar_t* GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus)
171 {
172 switch(eWriterStatus)
173 {
174 CHECK_CASE_FOR_CONSTANT(VSS_WS_STABLE);
175 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_FREEZE);
176 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_THAW);
177 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_POST_SNAPSHOT);
178 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_BACKUP_COMPLETE);
179 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_IDENTIFY);
180 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_BACKUP);
181 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_SNAPSHOT);
182 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_FREEZE);
183 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_THAW);
184 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_SNAPSHOT);
185 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_BACKUP_COMPLETE);
186 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PRE_RESTORE);
187 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_RESTORE);
188
189 default:
190 return L"Error or Undefined";
191 }
192 }
193
194 #ifdef HAVE_VSS64
195 // 64 bit entrypoint name.
196 #define VSSVBACK_ENTRY \
197 "?CreateVssBackupComponents@@YAJPEAPEAVIVssBackupComponents@@@Z"
198 #else
199 // 32 bit entrypoint name.
200 #define VSSVBACK_ENTRY \
201 "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
202 #endif
203
VSSClientGeneric()204 VSSClientGeneric::VSSClientGeneric()
205 {
206 m_hLib=LoadLibraryA("VSSAPI.DLL");
207 if(!m_hLib) return;
208 p_CreateVssBackupComponents=(t_CreateVssBackupComponents)
209 GetProcAddress(m_hLib, VSSVBACK_ENTRY);
210 p_VssFreeSnapshotProperties=(t_VssFreeSnapshotProperties)
211 GetProcAddress(m_hLib, "VssFreeSnapshotProperties");
212 }
213
~VSSClientGeneric()214 VSSClientGeneric::~VSSClientGeneric()
215 {
216 if(m_hLib) FreeLibrary(m_hLib);
217 }
218
bsystem_error(void)219 static BOOL bsystem_error(void)
220 {
221 errno=ENOSYS;
222 return FALSE;
223 }
224
set_errno(void)225 static BOOL set_errno(void)
226 {
227 errno=b_errno_win32;
228 return FALSE;
229 }
230
231 // Initialize the COM infrastructure and the internal pointers.
Initialize(struct asfd * asfd,struct cntr * cntr)232 BOOL VSSClientGeneric::Initialize(struct asfd *asfd, struct cntr *cntr)
233 {
234 if(!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties))
235 {
236 logw(asfd, cntr, "%s error\n", __func__);
237 return bsystem_error();
238 }
239
240 HRESULT hr;
241 // Initialize COM.
242 if(!m_bCoInitializeCalled)
243 {
244 hr=CoInitialize(NULL);
245 if(FAILED(hr))
246 {
247 logw(asfd, cntr, "%s: CoInitialize returned 0x%08X\n",
248 __func__, (unsigned int)hr);
249 return set_errno();
250 }
251 m_bCoInitializeCalled=true;
252 }
253
254 // Initialize COM security.
255 if(!m_bCoInitializeSecurityCalled)
256 {
257 hr=CoInitializeSecurity(
258 NULL, // Allow *all* VSS writers to communicate back!
259 -1, // Default COM authentication service.
260 NULL, // Default COM authorization service.
261 NULL, // Reserved parameter.
262 // Strongest COM authentication level.
263 RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
264 // Minimal impersonation abilities.
265 RPC_C_IMP_LEVEL_IDENTIFY,
266 NULL, // Default COM authentication settings.
267 EOAC_NONE, // No special options.
268 NULL // Reserved parameter.
269 );
270
271 if(FAILED(hr))
272 {
273 logw(asfd, cntr,
274 "%s: CoInitializeSecurity returned 0x%08X\n",
275 __func__, (unsigned int)hr);
276 return set_errno();
277 }
278 m_bCoInitializeSecurityCalled=true;
279 }
280
281 // Release the IVssBackupComponents interface.
282 if(m_pVssObject)
283 {
284 m_pVssObject->Release();
285 m_pVssObject=NULL;
286 }
287
288 // Create the internal backup components object.
289 hr=p_CreateVssBackupComponents((IVssBackupComponents**)&m_pVssObject);
290 if(FAILED(hr))
291 {
292 berrno be;
293 berrno_init(&be);
294 logw(asfd, cntr,
295 "%s: CreateVssBackupComponents returned 0x%08X. ERR=%s\n",
296 __func__, (unsigned int)hr,
297 berrno_bstrerror(&be, b_errno_win32));
298 return set_errno();
299 }
300
301 // 1. InitializeForBackup.
302 hr=((IVssBackupComponents*)m_pVssObject)->InitializeForBackup();
303 if(FAILED(hr))
304 {
305 logw(asfd, cntr, "%s: IVssBackupComponents->InitializeForBackup returned 0x%08X\n", __func__, (unsigned int)hr);
306 return set_errno();
307 }
308
309 // 2. SetBackupState.
310 hr=((IVssBackupComponents*)m_pVssObject)->SetBackupState(true,
311 true, VSS_BT_FULL, false);
312 if(FAILED(hr))
313 {
314 logw(asfd, cntr, "%s: IVssBackupComponents->SetBackupState returned 0x%08X\n", __func__, (unsigned int)hr);
315 return set_errno();
316 }
317
318 CComPtr<IVssAsync> pAsync1;
319 // 3. GatherWriterMetaData.
320 hr=((IVssBackupComponents*)
321 m_pVssObject)->GatherWriterMetadata(&pAsync1.p);
322 if(FAILED(hr))
323 {
324 logw(asfd, cntr, "%s: IVssBackupComponents->GatherWriterMetadata returned 0x%08X\n", __func__, (unsigned int)hr);
325 return set_errno();
326 }
327 WaitAndCheckForAsyncOperation(pAsync1.p);
328
329 return TRUE;
330 }
331
WaitAndCheckForAsyncOperation(IVssAsync * pAsync)332 BOOL VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
333 {
334 // Wait until the async operation finishes
335 // unfortunately we can't use a timeout here yet.
336 // the interface would allow it on W2k3,
337 // but it is not implemented yet.
338
339 HRESULT hr;
340
341 // Check the result of the asynchronous operation.
342 HRESULT hrReturned=S_OK;
343
344 int timeout=600; // 10 minutes.
345
346 int queryErrors=0;
347 do
348 {
349 if(hrReturned!=S_OK) Sleep(1000);
350
351 hrReturned=S_OK;
352 hr=pAsync->QueryStatus(&hrReturned, NULL);
353
354 if(FAILED(hr)) queryErrors++;
355 }
356 while ((timeout-->0) && (hrReturned==VSS_S_ASYNC_PENDING));
357
358 if(hrReturned==VSS_S_ASYNC_FINISHED) return TRUE;
359
360 #ifdef xDEBUG
361 // Check if the async operation succeeded.
362 if(hrReturned!=VSS_S_ASYNC_FINISHED)
363 {
364 wchar_t *pwszBuffer=NULL;
365 // I don't see the usefulness of the following -- KES.
366 FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
367 | FORMAT_MESSAGE_FROM_SYSTEM
368 | FORMAT_MESSAGE_IGNORE_INSERTS,
369 NULL, hrReturned,
370 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
371 (LPWSTR)&pwszBuffer, 0, NULL);
372
373 LocalFree(pwszBuffer);
374 errno=b_errno_win32;
375 }
376 #endif
377 return FALSE;
378 }
379
CreateSnapshots(char * szDriveLetters)380 BOOL VSSClientGeneric::CreateSnapshots(char* szDriveLetters)
381 {
382 // szDriveLetters contains all drive letters in uppercase.
383 // If a drive can not being added, it's converted to lowercase in
384 // szDriveLetters.
385 // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp
386
387 if(!m_pVssObject || m_bBackupIsInitialized) return bsystem_error();
388
389 m_uidCurrentSnapshotSet=GUID_NULL;
390
391 IVssBackupComponents *pVss=(IVssBackupComponents*)m_pVssObject;
392
393 pVss->StartSnapshotSet(&m_uidCurrentSnapshotSet);
394
395 wchar_t szDrive[3];
396 szDrive[1]=':';
397 szDrive[2]=0;
398
399 wstring volume;
400
401 CComPtr<IVssAsync> pAsync1;
402 CComPtr<IVssAsync> pAsync2;
403 VSS_ID pid;
404
405 for(size_t i=0; i<strlen (szDriveLetters); i++)
406 {
407 szDrive[0]=szDriveLetters[i];
408 volume=GetUniqueVolumeNameForPath(szDrive);
409 // Store uniquevolumname.
410 if(SUCCEEDED(pVss->AddToSnapshotSet((LPWSTR)volume.c_str(),
411 GUID_NULL, &pid)))
412 wcsncpy(m_wszUniqueVolumeName[szDriveLetters[i]-'A'],
413 (LPWSTR) volume.c_str(), MAX_PATH);
414 else
415 szDriveLetters[i]=tolower(szDriveLetters[i]);
416 }
417
418 if(FAILED(pVss->PrepareForBackup(&pAsync1.p))) return set_errno();
419
420 WaitAndCheckForAsyncOperation(pAsync1.p);
421
422 if(!CheckWriterStatus()) return set_errno();
423
424 if(FAILED(pVss->DoSnapshotSet(&pAsync2.p))) return set_errno();
425
426 WaitAndCheckForAsyncOperation(pAsync2.p);
427
428 QuerySnapshotSet(m_uidCurrentSnapshotSet);
429
430 SetVSSPathConvert(VSSPathConvert, VSSPathConvertW);
431
432 m_bBackupIsInitialized=true;
433
434 return TRUE;
435 }
436
CloseBackup()437 BOOL VSSClientGeneric::CloseBackup()
438 {
439 BOOL bRet=FALSE;
440 if(!m_pVssObject) errno=ENOSYS;
441 else
442 {
443 IVssBackupComponents *pVss=(IVssBackupComponents*)m_pVssObject;
444 CComPtr<IVssAsync> pAsync;
445
446 SetVSSPathConvert(NULL, NULL);
447
448 m_bBackupIsInitialized=false;
449
450 if(SUCCEEDED(pVss->BackupComplete(&pAsync.p)))
451 {
452 WaitAndCheckForAsyncOperation(pAsync.p);
453 bRet=TRUE;
454 }
455 else
456 {
457 errno=b_errno_win32;
458 pVss->AbortBackup();
459 }
460
461 // Get latest info about writer status.
462 CheckWriterStatus();
463
464 if(m_uidCurrentSnapshotSet!=GUID_NULL)
465 {
466 VSS_ID idNonDeletedSnapshotID=GUID_NULL;
467 LONG lSnapshots;
468
469 pVss->DeleteSnapshots(m_uidCurrentSnapshotSet,
470 VSS_OBJECT_SNAPSHOT_SET,
471 FALSE,
472 &lSnapshots,
473 &idNonDeletedSnapshotID);
474
475 m_uidCurrentSnapshotSet=GUID_NULL;
476 }
477
478 pVss->Release();
479 m_pVssObject=NULL;
480 }
481
482 // Call CoUninitialize if the CoInitialize was performed sucesfully.
483 if(m_bCoInitializeCalled)
484 {
485 CoUninitialize();
486 m_bCoInitializeCalled=false;
487 }
488
489 return bRet;
490 }
491
492 // Query all the shadow copies in the given set.
QuerySnapshotSet(GUID snapshotSetID)493 BOOL VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
494 {
495 if(!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties))
496 return bsystem_error();
497
498 memset(m_szShadowCopyName,0,sizeof(m_szShadowCopyName));
499
500 if(snapshotSetID==GUID_NULL || m_pVssObject==NULL)
501 return bsystem_error();
502
503 IVssBackupComponents *pVss=(IVssBackupComponents*)m_pVssObject;
504
505 // Get list all shadow copies.
506 CComPtr<IVssEnumObject> pIEnumSnapshots;
507 HRESULT hr=pVss->Query( GUID_NULL,
508 VSS_OBJECT_NONE,
509 VSS_OBJECT_SNAPSHOT,
510 (IVssEnumObject**)(&pIEnumSnapshots));
511
512 // If there are no shadow copies, just return.
513 if(FAILED(hr)) return set_errno();
514
515 // Enumerate all shadow copies.
516 VSS_OBJECT_PROP Prop;
517 VSS_SNAPSHOT_PROP& Snap=Prop.Obj.Snap;
518
519 while(1)
520 {
521 // Get the next element.
522 ULONG ulFetched;
523 hr=(pIEnumSnapshots.p)->Next(1, &Prop, &ulFetched);
524
525 // We reached the end of list.
526 if(!ulFetched) break;
527
528 // Print the shadow copy (if not filtered out).
529 if(Snap.m_SnapshotSetId == snapshotSetID)
530 {
531 for(int ch='A'-'A';ch<='Z'-'A';ch++)
532 {
533 if(!wcscmp(Snap.m_pwszOriginalVolumeName,
534 m_wszUniqueVolumeName[ch]))
535 {
536 wcsncpy(m_szShadowCopyName[ch],
537 Snap.m_pwszSnapshotDeviceObject,
538 MAX_PATH-1);
539 break;
540 }
541 }
542 }
543 p_VssFreeSnapshotProperties(&Snap);
544 }
545 errno=0;
546 return TRUE;
547 }
548
549 // Check the status for all selected writers.
CheckWriterStatus()550 BOOL VSSClientGeneric::CheckWriterStatus()
551 {
552 // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp
553 IVssBackupComponents *pVss=(IVssBackupComponents*)m_pVssObject;
554 DestroyWriterInfo();
555
556 // Gather writer status to detect potential errors
557 CComPtr<IVssAsync> pAsync;
558
559 HRESULT hr=pVss->GatherWriterStatus(&pAsync.p);
560 if(FAILED(hr)) return set_errno();
561
562 WaitAndCheckForAsyncOperation(pAsync.p);
563
564 unsigned cWriters=0;
565
566 hr=pVss->GetWriterStatusCount(&cWriters);
567 if(FAILED(hr)) return set_errno();
568
569 int nState;
570
571 // Enumerate each writer.
572 for(unsigned iWriter=0; iWriter<cWriters; iWriter++)
573 {
574 VSS_ID idInstance=GUID_NULL;
575 VSS_ID idWriter= GUID_NULL;
576 VSS_WRITER_STATE eWriterStatus=VSS_WS_UNKNOWN;
577 CComBSTR bstrWriterName;
578 HRESULT hrWriterFailure=S_OK;
579
580 // Get writer status
581 hr=pVss->GetWriterStatus(iWriter,
582 &idInstance,
583 &idWriter,
584 &bstrWriterName,
585 &eWriterStatus,
586 &hrWriterFailure);
587 if(FAILED(hr)) nState=0; // Unknown.
588 else
589 {
590 switch(eWriterStatus)
591 {
592 case VSS_WS_FAILED_AT_IDENTIFY:
593 case VSS_WS_FAILED_AT_PREPARE_BACKUP:
594 case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
595 case VSS_WS_FAILED_AT_FREEZE:
596 case VSS_WS_FAILED_AT_THAW:
597 case VSS_WS_FAILED_AT_POST_SNAPSHOT:
598 case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
599 case VSS_WS_FAILED_AT_PRE_RESTORE:
600 case VSS_WS_FAILED_AT_POST_RESTORE:
601 #if defined(B_VSS_W2K3) || defined(B_VSS_VISTA)
602 case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
603 #endif
604 // Failed.
605 nState=-1;
606 break;
607
608 default:
609 // OK.
610 nState=1;
611 }
612 }
613 // Store text info.
614 char str[1000];
615 char szBuf1[200];
616 char szBuf2[200];
617 char szBuf3[200];
618 wchar_2_UTF8(szBuf1, bstrWriterName.p, sizeof(szBuf1));
619 itoa(eWriterStatus, szBuf2, sizeof(szBuf2));
620 wchar_2_UTF8(szBuf3, GetStringFromWriterStatus(eWriterStatus),
621 sizeof(szBuf3));
622 snprintf(str, sizeof(str), "\"%s\", State: 0x%s (%s)",
623 szBuf1, szBuf2, szBuf3);
624
625 AppendWriterInfo(nState, (const char *)str);
626 }
627
628 hr=pVss->FreeWriterStatus();
629
630 if(FAILED(hr)) return set_errno();
631
632 errno=0;
633 return TRUE;
634 }
635
636 #endif
637