1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2005-2010 Free Software Foundation Europe e.V.
5
6 This program is Free Software; you can redistribute it and/or
7 modify it under the terms of version three of the GNU Affero General Public
8 License as published by the Free Software Foundation and included
9 in the file LICENSE.
10
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Affero General Public License for more details.
15
16 You should have received a copy of the GNU Affero General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301, USA.
20 */
21
22 /*
23 * vss.c -- Interface to Volume Shadow Copies (VSS)
24 *
25 * Copyright transferred from MATRIX-Computer GmbH to
26 * Kern Sibbald by express permission.
27 *
28 * Author : Thorsten Engel
29 * Created On : Fri May 06 21:44:00 2005
30 */
31
32 #ifdef WIN32_VSS
33
34 #include "include/bareos.h"
35 #include "include/jcr.h"
36 #include "lib/berrno.h"
37 #include "findlib/find.h"
38 #define FILE_DAEMON 1
39 #include "filed/fd_plugins.h"
40
41 #undef setlocale
42
43 // STL includes
44 #include <vector>
45 #include <algorithm>
46 #include <string>
47 #include <sstream>
48 #include <fstream>
49 using namespace std;
50
51 #include "ms_atl.h"
52 #include <objbase.h>
53
54 /*
55 * Kludges to get Vista code to compile.
56 */
57 #define __in IN
58 #define __out OUT
59 #define __RPC_unique_pointer
60 #define __RPC_string
61 #ifndef __RPC__out_ecount_part
62 #define __RPC__out_ecount_part(x, y)
63 #endif
64 #define __RPC__deref_inout_opt
65 #define __RPC__out
66
67 #if !defined(ENABLE_NLS)
68 #define setlocale(p, d)
69 #endif
70
71 #ifdef HAVE_STRSAFE_H
72 /*
73 * Used for safe string manipulation
74 */
75 #include <strsafe.h>
76 #endif
77
78 #ifdef HAVE_MINGW
79 class IXMLDOMDocument;
80 #endif
81
82 /*
83 * Reduce compiler warnings from Windows vss code
84 */
85 #undef uuid
86 #define uuid(x)
87
88 #ifdef B_VSS_XP
89 #define VSSClientGeneric VSSClientXP
90 #include "WinXP/vss.h"
91 #include "WinXP/vswriter.h"
92 #include "WinXP/vsbackup.h"
93 #endif
94
95 #ifdef B_VSS_W2K3
96 #define VSSClientGeneric VSSClient2003
97 #include "Win2003/vss.h"
98 #include "Win2003/vswriter.h"
99 #include "Win2003/vsbackup.h"
100 #endif
101
102 #ifdef B_VSS_VISTA
103 #define VSSClientGeneric VSSClientVista
104 #include "Win2003/vss.h"
105 #include "Win2003/vswriter.h"
106 #include "Win2003/vsbackup.h"
107 #endif
108
109 #define VSS_ERROR_OBJECT_ALREADY_EXISTS 0x8004230D
110
111 #pragma GCC diagnostic push
112 #pragma GCC diagnostic ignored "-Wunknown-pragmas"
113 #include "vss.h"
114 #pragma GCC diagnostic pop
115
116 using namespace filedaemon;
117
JmsgVssApiStatus(JobControlRecord * jcr,int msg_status,HRESULT hr,const char * apiName)118 static void JmsgVssApiStatus(JobControlRecord* jcr,
119 int msg_status,
120 HRESULT hr,
121 const char* apiName)
122 {
123 const char* errmsg;
124
125 if (hr == S_OK || hr == VSS_S_ASYNC_FINISHED) { return; }
126
127 switch (hr) {
128 case E_INVALIDARG:
129 errmsg = "One of the parameter values is not valid.";
130 break;
131 case E_OUTOFMEMORY:
132 errmsg = "The caller is out of memory or other system resources.";
133 break;
134 case E_ACCESSDENIED:
135 errmsg =
136 "The caller does not have sufficient backup privileges or is not an "
137 "administrator.";
138 break;
139 case VSS_E_INVALID_XML_DOCUMENT:
140 errmsg = "The XML document is not valid.";
141 break;
142 case VSS_E_OBJECT_NOT_FOUND:
143 errmsg = "The specified file does not exist.";
144 break;
145 case VSS_E_BAD_STATE:
146 errmsg =
147 "Object is not initialized; called during restore or not called in "
148 "correct sequence.";
149 break;
150 case VSS_E_WRITER_INFRASTRUCTURE:
151 errmsg =
152 "The writer infrastructure is not operating properly. Check that the "
153 "Event Service and VSS have been started, and check for errors "
154 "associated with those services in the error log.";
155 break;
156 case VSS_S_ASYNC_CANCELLED:
157 errmsg =
158 "The asynchronous operation was canceled by a previous call to "
159 "IVssAsync::Cancel.";
160 break;
161 case VSS_S_ASYNC_PENDING:
162 errmsg = "The asynchronous operation is still running.";
163 break;
164 case RPC_E_CHANGED_MODE:
165 errmsg =
166 "Previous call to CoInitializeEx specified the multithread apartment "
167 "(MTA). This call indicates single-threaded apartment has occurred.";
168 break;
169 case S_FALSE:
170 errmsg = "No writer found for the current component.";
171 break;
172 default:
173 errmsg =
174 "Unexpected error. The error code is logged in the error log file.";
175 break;
176 }
177 Jmsg(jcr, msg_status, 0, "VSS API failure calling \"%s\". ERR=%s\n", apiName,
178 errmsg);
179 }
180
181 #ifndef VSS_WS_FAILED_AT_BACKUPSHUTDOWN
182 #define VSS_WS_FAILED_AT_BACKUPSHUTDOWN (VSS_WRITER_STATE)15
183 #endif
184
JmsgVssWriterStatus(JobControlRecord * jcr,int msg_status,VSS_WRITER_STATE eWriterStatus,char * writer_name)185 static void JmsgVssWriterStatus(JobControlRecord* jcr,
186 int msg_status,
187 VSS_WRITER_STATE eWriterStatus,
188 char* writer_name)
189 {
190 const char* errmsg;
191
192 /*
193 * The following are normal states
194 */
195 if (eWriterStatus == VSS_WS_STABLE ||
196 eWriterStatus == VSS_WS_WAITING_FOR_BACKUP_COMPLETE) {
197 return;
198 }
199
200 /*
201 * Potential errors
202 */
203 switch (eWriterStatus) {
204 default:
205 case VSS_WS_UNKNOWN:
206 errmsg = "The writer's state is not known. This is a writer error.";
207 break;
208 case VSS_WS_WAITING_FOR_FREEZE:
209 errmsg = "The writer is waiting for the freeze state.";
210 break;
211 case VSS_WS_WAITING_FOR_THAW:
212 errmsg = "The writer is waiting for the thaw state.";
213 break;
214 case VSS_WS_WAITING_FOR_POST_SNAPSHOT:
215 errmsg = "The writer is waiting for the PostSnapshot state.";
216 break;
217 case VSS_WS_WAITING_FOR_BACKUP_COMPLETE:
218 errmsg =
219 "The writer is waiting for the requester to finish its backup "
220 "operation.";
221 break;
222 case VSS_WS_FAILED_AT_IDENTIFY:
223 errmsg =
224 "The writer vetoed the shadow copy creation process at the writer "
225 "identification state.";
226 break;
227 case VSS_WS_FAILED_AT_PREPARE_BACKUP:
228 errmsg =
229 "The writer vetoed the shadow copy creation process during the "
230 "backup preparation state.";
231 break;
232 case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
233 errmsg =
234 "The writer vetoed the shadow copy creation process during the "
235 "PrepareForSnapshot state.";
236 break;
237 case VSS_WS_FAILED_AT_FREEZE:
238 errmsg =
239 "The writer vetoed the shadow copy creation process during the "
240 "freeze state.";
241 break;
242 case VSS_WS_FAILED_AT_THAW:
243 errmsg =
244 "The writer vetoed the shadow copy creation process during the thaw "
245 "state.";
246 break;
247 case VSS_WS_FAILED_AT_POST_SNAPSHOT:
248 errmsg =
249 "The writer vetoed the shadow copy creation process during the "
250 "PostSnapshot state.";
251 break;
252 case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
253 errmsg =
254 "The shadow copy has been created and the writer failed during the "
255 "BackupComplete state.";
256 break;
257 case VSS_WS_FAILED_AT_PRE_RESTORE:
258 errmsg = "The writer failed during the PreRestore state.";
259 break;
260 case VSS_WS_FAILED_AT_POST_RESTORE:
261 errmsg = "The writer failed during the PostRestore state.";
262 break;
263 case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
264 errmsg =
265 "The writer failed during the shutdown of the backup application.";
266 }
267 Jmsg(jcr, msg_status, 0, "VSS Writer \"%s\" has invalid state. ERR=%s\n",
268 writer_name, errmsg);
269 }
270
271 /*
272 * Some helper functions
273 */
274
275 /*
276 * strdup a wchar_t string.
277 */
wbstrdup(const wchar_t * str)278 static inline wchar_t* wbstrdup(const wchar_t* str)
279 {
280 int len;
281 wchar_t* dup;
282
283 len = wcslen(str) + 1;
284 dup = (wchar_t*)malloc(len * sizeof(wchar_t));
285 memcpy(dup, str, len * sizeof(wchar_t));
286
287 return dup;
288 }
289
290 /*
291 * Append a backslash to the current string.
292 */
AppendBackslash(wstring str)293 static inline wstring AppendBackslash(wstring str)
294 {
295 if (str.length() == 0) { return wstring(L"\\"); }
296 if (str[str.length() - 1] == L'\\') { return str; }
297 return str.append(L"\\");
298 }
299
300 /*
301 * Get the unique volume name for the given path.
302 */
GetUniqueVolumeNameForPath(wstring path)303 static inline wstring GetUniqueVolumeNameForPath(wstring path)
304 {
305 wchar_t volumeRootPath[MAX_PATH];
306 wchar_t volumeName[MAX_PATH];
307 wchar_t volumeUniqueName[MAX_PATH];
308
309 if (path.length() <= 0) { return L""; }
310
311 /*
312 * Add the backslash termination, if needed.
313 */
314 path = AppendBackslash(path);
315
316 /*
317 * Get the root path of the volume.
318 */
319 if (!p_GetVolumePathNameW ||
320 !p_GetVolumePathNameW((LPCWSTR)path.c_str(), volumeRootPath, MAX_PATH)) {
321 return L"";
322 }
323
324 /*
325 * Get the volume name alias (might be different from the unique volume name
326 * in rare cases).
327 */
328 if (!p_GetVolumeNameForVolumeMountPointW ||
329 !p_GetVolumeNameForVolumeMountPointW(volumeRootPath, volumeName,
330 MAX_PATH)) {
331 return L"";
332 }
333
334 /*
335 * Get the unique volume name.
336 */
337 if (!p_GetVolumeNameForVolumeMountPointW(volumeName, volumeUniqueName,
338 MAX_PATH)) {
339 return L"";
340 }
341
342 return volumeUniqueName;
343 }
344
GetMountedVolumeForMountPointPath(POOLMEM * volumepath,POOLMEM * mountpoint)345 static inline POOLMEM* GetMountedVolumeForMountPointPath(POOLMEM* volumepath,
346 POOLMEM* mountpoint)
347 {
348 POOLMEM *fullPath, *buf, *vol;
349 int len;
350
351 /*
352 * GetUniqueVolumeNameForPath() should be used here
353 */
354 len = strlen(volumepath) + 1;
355 fullPath = GetPoolMemory(PM_FNAME);
356 PmStrcpy(fullPath, volumepath);
357 PmStrcat(fullPath, mountpoint);
358
359 buf = GetPoolMemory(PM_FNAME);
360 GetVolumeNameForVolumeMountPoint(fullPath, buf, len);
361
362 Dmsg3(200, "%s%s mounts volume %s\n", volumepath, mountpoint, buf);
363
364 vol = GetPoolMemory(PM_FNAME);
365 UTF8_2_wchar(vol, buf);
366
367 FreePoolMemory(fullPath);
368 FreePoolMemory(buf);
369
370 return vol;
371 }
372
HandleVolumeMountPoint(VSSClientGeneric * pVssClient,IVssBackupComponents * pVssObj,POOLMEM * & volumepath,POOLMEM * & mountpoint)373 static inline bool HandleVolumeMountPoint(VSSClientGeneric* pVssClient,
374 IVssBackupComponents* pVssObj,
375 POOLMEM*& volumepath,
376 POOLMEM*& mountpoint)
377 {
378 bool retval = false;
379 HRESULT hr;
380 POOLMEM* vol = NULL;
381 POOLMEM* pvol;
382 VSS_ID pid;
383
384 vol = GetMountedVolumeForMountPointPath(volumepath, mountpoint);
385 hr = pVssObj->AddToSnapshotSet((LPWSTR)vol, GUID_NULL, &pid);
386
387 pvol = GetPoolMemory(PM_FNAME);
388 wchar_2_UTF8(pvol, (wchar_t*)vol);
389
390 if (SUCCEEDED(hr)) {
391 pVssClient->AddVolumeMountPointSnapshots(pVssObj, (wchar_t*)vol);
392 Dmsg1(200, "%s added to snapshotset \n", pvol);
393 retval = true;
394 } else if ((unsigned)hr == VSS_ERROR_OBJECT_ALREADY_EXISTS) {
395 Dmsg1(200, "%s already in snapshotset, skipping.\n", pvol);
396 } else {
397 Dmsg3(200,
398 "%s with vmp %s could not be added to snapshotset, COM ERROR: 0x%X\n",
399 vol, mountpoint, hr);
400 }
401
402 FreePoolMemory(pvol);
403 if (vol) { FreePoolMemory(vol); }
404
405 return retval;
406 }
407
408 /*
409 * Helper macro for quick treatment of case statements for error codes
410 */
411 #define GEN_MERGE(A, B) A##B
412 #define GEN_MAKE_W(A) GEN_MERGE(L, A)
413
414 #define CHECK_CASE_FOR_CONSTANT(value) \
415 case value: \
416 return (GEN_MAKE_W(#value));
417
418 /*
419 * Convert a writer status into a string
420 */
GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus)421 static inline const wchar_t* GetStringFromWriterStatus(
422 VSS_WRITER_STATE eWriterStatus)
423 {
424 switch (eWriterStatus) {
425 CHECK_CASE_FOR_CONSTANT(VSS_WS_STABLE);
426 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_FREEZE);
427 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_THAW);
428 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_POST_SNAPSHOT);
429 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_BACKUP_COMPLETE);
430 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_IDENTIFY);
431 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_BACKUP);
432 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_SNAPSHOT);
433 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_FREEZE);
434 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_THAW);
435 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_SNAPSHOT);
436 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_BACKUP_COMPLETE);
437 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PRE_RESTORE);
438 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_RESTORE);
439 default:
440 return L"Error or Undefined";
441 }
442 }
443
444 #ifdef HAVE_VSS64
445 /* 64 bit entrypoint name */
446 #define VSSVBACK_ENTRY \
447 "?CreateVssBackupComponents@@YAJPEAPEAVIVssBackupComponents@@@Z"
448 #else
449 /* 32 bit entrypoint name */
450 #define VSSVBACK_ENTRY \
451 "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
452 #endif
453
454 /*
455 * Constructor
456 */
VSSClientGeneric()457 VSSClientGeneric::VSSClientGeneric()
458 {
459 hLib_ = LoadLibraryA("VSSAPI.DLL");
460 if (hLib_) {
461 CreateVssBackupComponents_ =
462 (t_CreateVssBackupComponents)GetProcAddress(hLib_, VSSVBACK_ENTRY);
463 VssFreeSnapshotProperties_ = (t_VssFreeSnapshotProperties)GetProcAddress(
464 hLib_, "VssFreeSnapshotProperties");
465 }
466 }
467
468 /*
469 * Destructor
470 */
~VSSClientGeneric()471 VSSClientGeneric::~VSSClientGeneric()
472 {
473 if (hLib_) { FreeLibrary(hLib_); }
474 }
475
476 /*
477 * Initialize the COM infrastructure and the internal pointers
478 */
Initialize(DWORD dwContext,bool bDuringRestore)479 bool VSSClientGeneric::Initialize(DWORD dwContext, bool bDuringRestore)
480 {
481 VMPs = 0;
482 VMP_snapshots = 0;
483 HRESULT hr = S_OK;
484 CComPtr<IVssAsync> pAsync1;
485 IVssBackupComponents* pVssObj = (IVssBackupComponents*)pVssObject_;
486
487 if (!(CreateVssBackupComponents_ && VssFreeSnapshotProperties_)) {
488 Dmsg2(0,
489 "VSSClientGeneric::Initialize: CreateVssBackupComponents_=0x%08X, "
490 "VssFreeSnapshotProperties_=0x%08X\n",
491 CreateVssBackupComponents_, VssFreeSnapshotProperties_);
492 Jmsg(jcr_, M_FATAL, 0,
493 "Entry point CreateVssBackupComponents or VssFreeSnapshotProperties "
494 "missing.\n");
495 return false;
496 }
497
498 /*
499 * Initialize COM
500 */
501 if (!bCoInitializeCalled_) {
502 hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
503 if (FAILED(hr)) {
504 Dmsg1(0, "VSSClientGeneric::Initialize: CoInitializeEx returned 0x%08X\n",
505 hr);
506 JmsgVssApiStatus(jcr_, M_FATAL, hr, "CoInitializeEx");
507 errno = b_errno_win32;
508 return false;
509 }
510 bCoInitializeCalled_ = true;
511 }
512
513 /*
514 * Initialize COM security
515 */
516 if (!InitializeComSecurity()) {
517 JmsgVssApiStatus(jcr_, M_FATAL, hr, "CoInitializeSecurity");
518 return false;
519 }
520
521 /*
522 * Release the any old IVssBackupComponents interface
523 */
524 if (pVssObj) {
525 pVssObj->Release();
526 pVssObject_ = NULL;
527 }
528
529 /*
530 * Create new internal backup components object
531 */
532 hr = CreateVssBackupComponents_((IVssBackupComponents**)&pVssObject_);
533 if (FAILED(hr)) {
534 BErrNo be;
535 Dmsg2(0,
536 "VSSClientGeneric::Initialize: CreateVssBackupComponents returned "
537 "0x%08X. ERR=%s\n",
538 hr, be.bstrerror(b_errno_win32));
539 JmsgVssApiStatus(jcr_, M_FATAL, hr, "CreateVssBackupComponents");
540 errno = b_errno_win32;
541 return false;
542 }
543
544 /*
545 * Define shorthand VssObject with time
546 */
547 pVssObj = (IVssBackupComponents*)pVssObject_;
548
549 if (!bDuringRestore) {
550 #if defined(B_VSS_W2K3) || defined(B_VSS_VISTA)
551 if (dwContext != VSS_CTX_BACKUP) {
552 hr = pVssObj->SetContext(dwContext);
553 if (FAILED(hr)) {
554 Dmsg1(0,
555 "VSSClientGeneric::Initialize: IVssBackupComponents->SetContext "
556 "returned 0x%08X\n",
557 hr);
558 JmsgVssApiStatus(jcr_, M_FATAL, hr, "SetContext");
559 errno = b_errno_win32;
560 return false;
561 }
562 }
563 #endif
564
565 /*
566 * 1. InitializeForBackup
567 */
568 hr = pVssObj->InitializeForBackup();
569 if (FAILED(hr)) {
570 Dmsg1(0,
571 "VSSClientGeneric::Initialize: "
572 "IVssBackupComponents->InitializeForBackup returned 0x%08X\n",
573 hr);
574 JmsgVssApiStatus(jcr_, M_FATAL, hr, "InitializeForBackup");
575 errno = b_errno_win32;
576 return false;
577 }
578
579 /*
580 * 2. SetBackupState
581 *
582 * Generate a bEventVssSetBackupState event and if none of the plugins
583 * give back a bRC_Skip it means this will not be performed by any plugin
584 * and we should do the generic handling ourself in the core.
585 */
586 if (GeneratePluginEvent(jcr_, bEventVssSetBackupState) != bRC_Skip) {
587 VSS_BACKUP_TYPE backup_type;
588
589 switch (jcr_->getJobLevel()) {
590 case L_FULL:
591 backup_type = VSS_BT_FULL;
592 break;
593 case L_DIFFERENTIAL:
594 backup_type = VSS_BT_DIFFERENTIAL;
595 break;
596 case L_INCREMENTAL:
597 backup_type = VSS_BT_INCREMENTAL;
598 break;
599 default:
600 Dmsg1(0, "VSSClientGeneric::Initialize: unknown backup level %d\n",
601 jcr_->getJobLevel());
602 backup_type = VSS_BT_FULL;
603 break;
604 }
605
606 hr = pVssObj->SetBackupState(true, /* bSelectComponents */
607 true, /* bBackupBootableSystemState */
608 backup_type, /* backupType */
609 false /* bPartialFileSupport */
610 );
611 if (FAILED(hr)) {
612 Dmsg1(0,
613 "VSSClientGeneric::Initialize: "
614 "IVssBackupComponents->SetBackupState returned 0x%08X\n",
615 hr);
616 JmsgVssApiStatus(jcr_, M_FATAL, hr, "SetBackupState");
617 errno = b_errno_win32;
618 return false;
619 }
620 }
621
622 /*
623 * 3. GatherWriterMetaData
624 */
625 hr = pVssObj->GatherWriterMetadata(&pAsync1.p);
626 if (FAILED(hr)) {
627 Dmsg1(0,
628 "VSSClientGeneric::Initialize: "
629 "IVssBackupComponents->GatherWriterMetadata returned 0x%08X\n",
630 hr);
631 JmsgVssApiStatus(jcr_, M_FATAL, hr, "GatherWriterMetadata");
632 errno = b_errno_win32;
633 return false;
634 }
635
636 /*
637 * Wait for the async operation to finish and checks the result
638 */
639 if (!WaitAndCheckForAsyncOperation(pAsync1.p)) {
640 /*
641 * Error message already printed
642 */
643 errno = b_errno_win32;
644 return false;
645 }
646 }
647
648 /*
649 * We are during restore now?
650 */
651 bDuringRestore_ = bDuringRestore;
652
653 /*
654 * Keep the context
655 */
656 dwContext_ = dwContext;
657
658 return true;
659 }
660
WaitAndCheckForAsyncOperation(IVssAsync * pAsync)661 bool VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
662 {
663 HRESULT hr;
664 HRESULT hrReturned = S_OK;
665 int timeout = 600; /* 10 minutes.... */
666 int queryErrors = 0;
667
668 /*
669 * Wait until the async operation finishes
670 * unfortunately we can't use a timeout here yet.
671 * the interface would allow it on W2k3,
672 * but it is not implemented yet....
673 */
674 do {
675 if (hrReturned != S_OK) { Sleep(1000); }
676 hrReturned = S_OK;
677 hr = pAsync->QueryStatus(&hrReturned, NULL);
678
679 if (FAILED(hr)) { queryErrors++; }
680 } while ((timeout-- > 0) && (hrReturned == VSS_S_ASYNC_PENDING));
681
682 /*
683 * Check the result of the asynchronous operation
684 */
685 if (hrReturned == VSS_S_ASYNC_FINISHED) { return true; }
686
687 JmsgVssApiStatus(jcr_, M_FATAL, hr,
688 "Query Async Status after 10 minute wait");
689
690 return false;
691 }
692
693 /*
694 * Add all drive letters that need to be snapshotted.
695 */
AddDriveSnapshots(IVssBackupComponents * pVssObj,char * szDriveLetters,bool onefs_disabled)696 void VSSClientGeneric::AddDriveSnapshots(IVssBackupComponents* pVssObj,
697 char* szDriveLetters,
698 bool onefs_disabled)
699 {
700 wstring volume;
701 wchar_t szDrive[3];
702 VSS_ID pid;
703
704 szDrive[1] = ':';
705 szDrive[2] = 0;
706
707 /*
708 * szDriveLetters contains all drive letters in uppercase
709 * If a drive can not being added, it's converted to lowercase in
710 * szDriveLetters
711 */
712 for (size_t i = 0; i < strlen(szDriveLetters); i++) {
713 szDrive[0] = szDriveLetters[i];
714 volume = GetUniqueVolumeNameForPath(szDrive);
715
716 /*
717 * Store uniquevolumname.
718 */
719
720 if (SUCCEEDED(pVssObj->AddToSnapshotSet((LPWSTR)volume.c_str(), GUID_NULL,
721 &pid))) {
722 if (debug_level >= 200) {
723 POOLMEM* szBuf = GetPoolMemory(PM_FNAME);
724
725 wchar_2_UTF8(szBuf, volume.c_str());
726 Dmsg2(200, "%s added to snapshotset (Drive %s:\\)\n", szBuf, szDrive);
727 FreePoolMemory(szBuf);
728 }
729 wcsncpy(wszUniqueVolumeName_[szDriveLetters[i] - 'A'],
730 (LPWSTR)volume.c_str(), MAX_PATH);
731 } else {
732 szDriveLetters[i] = tolower(szDriveLetters[i]);
733 }
734 if (onefs_disabled) {
735 AddVolumeMountPointSnapshots(pVssObj, (LPWSTR)volume.c_str());
736 } else {
737 Jmsg(jcr_, M_INFO, 0,
738 "VolumeMountpoints are not processed as onefs = yes.\n");
739 }
740 }
741 }
742
743 /*
744 * Add all volume mountpoints that need to be snapshotted.
745 * Volumes can be mounted multiple times, but can only be added to the
746 * snapshotset once. So we skip adding a volume if it is already in snapshotset.
747 * We count the total number of vmps and the number of volumes we added to the
748 * snapshotset.
749 */
AddVolumeMountPointSnapshots(IVssBackupComponents * pVssObj,LPWSTR volume)750 void VSSClientGeneric::AddVolumeMountPointSnapshots(
751 IVssBackupComponents* pVssObj,
752 LPWSTR volume)
753 {
754 BOOL b;
755 int len;
756 HANDLE hMount;
757 POOLMEM *mp, *path;
758
759 mp = GetPoolMemory(PM_FNAME);
760 path = GetPoolMemory(PM_FNAME);
761
762 wchar_2_UTF8(path, volume);
763
764 len = wcslen(volume) + 1;
765
766 hMount = FindFirstVolumeMountPoint(path, mp, len);
767 if (hMount != INVALID_HANDLE_VALUE) {
768 /*
769 * Count number of vmps.
770 */
771 VMPs += 1;
772 if (HandleVolumeMountPoint(this, pVssObj, path, mp)) {
773 /*
774 * Count vmps that were snapshotted
775 */
776 VMP_snapshots += 1;
777 }
778
779 while ((b = FindNextVolumeMountPoint(hMount, mp, len))) {
780 /*
781 * Count number of vmps.
782 */
783 VMPs += 1;
784 if (HandleVolumeMountPoint(this, pVssObj, path, mp)) {
785 /*
786 * Count vmps that were snapshotted
787 */
788 VMP_snapshots += 1;
789 }
790 }
791 }
792
793 FindVolumeMountPointClose(hMount);
794
795 FreePoolMemory(path);
796 FreePoolMemory(mp);
797 }
798
ShowVolumeMountPointStats(JobControlRecord * jcr)799 void VSSClientGeneric::ShowVolumeMountPointStats(JobControlRecord* jcr)
800 {
801 if (VMPs) {
802 Jmsg(jcr, M_INFO, 0,
803 _("Volume Mount Points found: %d, added to snapshotset: %d\n"), VMPs,
804 VMP_snapshots);
805 }
806 }
807
CreateSnapshots(char * szDriveLetters,bool onefs_disabled)808 bool VSSClientGeneric::CreateSnapshots(char* szDriveLetters,
809 bool onefs_disabled)
810 {
811 IVssBackupComponents* pVssObj;
812 CComPtr<IVssAsync> pAsync1;
813 CComPtr<IVssAsync> pAsync2;
814 HRESULT hr;
815
816 /*
817 * See
818 * http://msdn.microsoft.com/en-us/library/windows/desktop/aa382870%28v=vs.85%29.aspx.
819 */
820 if (!pVssObject_ || bBackupIsInitialized_) {
821 Jmsg(jcr_, M_FATAL, 0,
822 "No pointer to VssObject or Backup is not Initialized\n");
823 errno = ENOSYS;
824 return false;
825 }
826
827 uidCurrentSnapshotSet_ = GUID_NULL;
828
829 pVssObj = (IVssBackupComponents*)pVssObject_;
830
831 /*
832 * startSnapshotSet
833 */
834 hr = pVssObj->StartSnapshotSet(&uidCurrentSnapshotSet_);
835 while ((unsigned)hr == VSS_E_SNAPSHOT_SET_IN_PROGRESS) {
836 Bmicrosleep(5, 0);
837 Jmsg(jcr_, M_INFO, 0, "VSS_E_SNAPSHOT_SET_IN_PROGRESS, retrying ...\n");
838 hr = pVssObj->StartSnapshotSet(&uidCurrentSnapshotSet_);
839 }
840
841 if (FAILED(hr)) {
842 JmsgVssApiStatus(jcr_, M_FATAL, hr, "StartSnapshotSet");
843 errno = ENOSYS;
844 return false;
845 }
846
847 /*
848 * AddToSnapshotSet
849 */
850 if (szDriveLetters) {
851 AddDriveSnapshots(pVssObj, szDriveLetters, onefs_disabled);
852 }
853
854 /*
855 * PrepareForBackup
856 */
857 GeneratePluginEvent(jcr_, bEventVssPrepareSnapshot);
858 hr = pVssObj->PrepareForBackup(&pAsync1.p);
859 if (FAILED(hr)) {
860 JmsgVssApiStatus(jcr_, M_FATAL, hr, "PrepareForBackup");
861 errno = b_errno_win32;
862 return false;
863 }
864
865 /*
866 * Wait for the async operation to finish and checks the result.
867 */
868 if (!WaitAndCheckForAsyncOperation(pAsync1.p)) {
869 errno = b_errno_win32;
870 return false;
871 }
872
873 /*
874 * Get latest info about writer status.
875 */
876 if (!CheckWriterStatus()) {
877 errno = b_errno_win32; /* Error already printed */
878 return false;
879 }
880
881 /*
882 * DoSnapShotSet
883 */
884 hr = pVssObj->DoSnapshotSet(&pAsync2.p);
885 if (FAILED(hr)) {
886 JmsgVssApiStatus(jcr_, M_FATAL, hr, "DoSnapshotSet");
887 errno = b_errno_win32;
888 return false;
889 }
890
891 /*
892 * Waits for the async operation to finish and checks the result.
893 */
894 if (!WaitAndCheckForAsyncOperation(pAsync2.p)) {
895 errno = b_errno_win32;
896 return false;
897 }
898
899 /*
900 * Get latest info about writer status.
901 */
902 if (!CheckWriterStatus()) {
903 errno = b_errno_win32; /* Error already printed */
904 return false;
905 }
906
907 /*
908 * Query snapshot info.
909 */
910 QuerySnapshotSet(uidCurrentSnapshotSet_);
911
912 bBackupIsInitialized_ = true;
913
914 return true;
915 }
916
CloseBackup()917 bool VSSClientGeneric::CloseBackup()
918 {
919 bool bRet = false;
920 HRESULT hr;
921 BSTR xml;
922 IVssBackupComponents* pVssObj = (IVssBackupComponents*)pVssObject_;
923
924 if (!pVssObject_) {
925 Jmsg(jcr_, M_FATAL, 0, "VssObject is NULL.\n");
926 errno = ENOSYS;
927 return bRet;
928 }
929 CComPtr<IVssAsync> pAsync;
930
931 bBackupIsInitialized_ = false;
932
933 hr = pVssObj->BackupComplete(&pAsync.p);
934 if (SUCCEEDED(hr)) {
935 /*
936 * Wait for the async operation to finish and checks the result.
937 */
938 WaitAndCheckForAsyncOperation(pAsync.p);
939 bRet = true;
940 } else {
941 JmsgVssApiStatus(jcr_, M_ERROR, hr, "BackupComplete");
942 errno = b_errno_win32;
943 pVssObj->AbortBackup();
944 }
945
946 /*
947 * Get latest info about writer status.
948 */
949 CheckWriterStatus();
950
951 hr = pVssObj->SaveAsXML(&xml);
952 if (SUCCEEDED(hr)) {
953 metadata_ = xml;
954 } else {
955 metadata_ = NULL;
956 }
957
958 /*
959 * FIXME?: The docs
960 * http://msdn.microsoft.com/en-us/library/aa384582%28v=VS.85%29.aspx say this
961 * isn't required...
962 */
963 if (uidCurrentSnapshotSet_ != GUID_NULL) {
964 VSS_ID idNonDeletedSnapshotID = GUID_NULL;
965 LONG lSnapshots;
966
967 pVssObj->DeleteSnapshots(uidCurrentSnapshotSet_, VSS_OBJECT_SNAPSHOT_SET,
968 false, &lSnapshots, &idNonDeletedSnapshotID);
969
970 uidCurrentSnapshotSet_ = GUID_NULL;
971 }
972
973 if (bWriterStatusCurrent_) {
974 bWriterStatusCurrent_ = false;
975 pVssObj->FreeWriterStatus();
976 }
977
978 pVssObj->Release();
979 pVssObject_ = NULL;
980
981 /*
982 * Call CoUninitialize if the CoInitializeEx was performed sucesfully
983 */
984 if (bCoInitializeCalled_) {
985 CoUninitialize();
986 bCoInitializeCalled_ = false;
987 }
988
989 return bRet;
990 }
991
GetMetadata()992 wchar_t* VSSClientGeneric::GetMetadata() { return metadata_; }
993
CloseRestore()994 bool VSSClientGeneric::CloseRestore()
995 {
996 IVssBackupComponents* pVssObj = (IVssBackupComponents*)pVssObject_;
997 CComPtr<IVssAsync> pAsync;
998
999 if (!pVssObj) {
1000 errno = ENOSYS;
1001 return false;
1002 }
1003 return true;
1004 }
1005
1006 /*
1007 * Query all the shadow copies in the given set
1008 */
QuerySnapshotSet(GUID snapshotSetID)1009 void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
1010 {
1011 if (!(CreateVssBackupComponents_ && VssFreeSnapshotProperties_)) {
1012 Jmsg(jcr_, M_FATAL, 0,
1013 "CreateVssBackupComponents or VssFreeSnapshotProperties API is "
1014 "NULL.\n");
1015 errno = ENOSYS;
1016 return;
1017 }
1018
1019 memset(szShadowCopyName_, 0, sizeof(szShadowCopyName_));
1020
1021 if (snapshotSetID == GUID_NULL || pVssObject_ == NULL) {
1022 Jmsg(jcr_, M_FATAL, 0, "snapshotSetID == NULL or VssObject is NULL.\n");
1023 errno = ENOSYS;
1024 return;
1025 }
1026
1027 IVssBackupComponents* pVssObj = (IVssBackupComponents*)pVssObject_;
1028
1029 /*
1030 * Get list all shadow copies.
1031 */
1032 CComPtr<IVssEnumObject> pIEnumSnapshots;
1033 HRESULT hr = pVssObj->Query(GUID_NULL, VSS_OBJECT_NONE, VSS_OBJECT_SNAPSHOT,
1034 (IVssEnumObject**)(&pIEnumSnapshots));
1035
1036 /*
1037 * If there are no shadow copies, just return
1038 */
1039 if (FAILED(hr)) {
1040 Jmsg(jcr_, M_FATAL, 0, "No Volume Shadow copies made.\n");
1041 errno = b_errno_win32;
1042 return;
1043 }
1044
1045 /*
1046 * Enumerate all shadow copies.
1047 */
1048 VSS_OBJECT_PROP Prop;
1049 VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap;
1050
1051 while (true) {
1052 /*
1053 * Get the next element
1054 */
1055 ULONG ulFetched;
1056 hr = (pIEnumSnapshots.p)->Next(1, &Prop, &ulFetched);
1057
1058 /*
1059 * We reached the end of list
1060 */
1061 if (ulFetched == 0) break;
1062
1063 /*
1064 * Print the shadow copy (if not filtered out)
1065 */
1066 if (Snap.m_SnapshotSetId == snapshotSetID) {
1067 for (int ch = 'A' - 'A'; ch <= 'Z' - 'A'; ch++) {
1068 if (wcscmp(Snap.m_pwszOriginalVolumeName, wszUniqueVolumeName_[ch]) ==
1069 0) {
1070 wcsncpy(szShadowCopyName_[ch], Snap.m_pwszSnapshotDeviceObject,
1071 MAX_PATH - 1);
1072 break;
1073 }
1074 }
1075 }
1076 VssFreeSnapshotProperties_(&Snap);
1077 }
1078 errno = 0;
1079 }
1080
1081 /*
1082 * Check the status for all selected writers
1083 */
CheckWriterStatus()1084 bool VSSClientGeneric::CheckWriterStatus()
1085 {
1086 /*
1087 * See
1088 * http://msdn.microsoft.com/en-us/library/windows/desktop/aa382870%28v=vs.85%29.aspx
1089 */
1090 IVssBackupComponents* pVssObj = (IVssBackupComponents*)pVssObject_;
1091 if (!pVssObj) {
1092 Jmsg(jcr_, M_FATAL, 0, "Cannot get IVssBackupComponents pointer.\n");
1093 errno = ENOSYS;
1094 return false;
1095 }
1096 DestroyWriterInfo();
1097
1098 if (bWriterStatusCurrent_) {
1099 bWriterStatusCurrent_ = false;
1100 pVssObj->FreeWriterStatus();
1101 }
1102
1103 /*
1104 * Gather writer status to detect potential errors
1105 */
1106 CComPtr<IVssAsync> pAsync;
1107
1108 HRESULT hr = pVssObj->GatherWriterStatus(&pAsync.p);
1109 if (FAILED(hr)) {
1110 JmsgVssApiStatus(jcr_, M_FATAL, hr, "GatherWriterStatus");
1111 errno = b_errno_win32;
1112 return false;
1113 }
1114
1115 /*
1116 * Waits for the async operation to finish and checks the result
1117 */
1118 if (!WaitAndCheckForAsyncOperation(pAsync.p)) {
1119 errno = b_errno_win32;
1120 return false;
1121 }
1122
1123 bWriterStatusCurrent_ = true;
1124
1125 unsigned cWriters = 0;
1126
1127 hr = pVssObj->GetWriterStatusCount(&cWriters);
1128 if (FAILED(hr)) {
1129 JmsgVssApiStatus(jcr_, M_FATAL, hr, "GatherWriterStatusCount");
1130 errno = b_errno_win32;
1131 return false;
1132 }
1133
1134 int nState;
1135 POOLMEM* szBuf = GetPoolMemory(PM_FNAME);
1136
1137 /*
1138 * Enumerate each writer
1139 */
1140 for (unsigned iWriter = 0; iWriter < cWriters; iWriter++) {
1141 VSS_ID idInstance = GUID_NULL;
1142 VSS_ID idWriter = GUID_NULL;
1143 VSS_WRITER_STATE eWriterStatus = VSS_WS_UNKNOWN;
1144 CComBSTR bstrWriterName;
1145 HRESULT hrWriterFailure = S_OK;
1146
1147 /*
1148 * Get writer status
1149 */
1150 hr = pVssObj->GetWriterStatus(iWriter, &idInstance, &idWriter,
1151 &bstrWriterName, &eWriterStatus,
1152 &hrWriterFailure);
1153 if (FAILED(hr)) {
1154 /*
1155 * Api failed
1156 */
1157 JmsgVssApiStatus(jcr_, M_WARNING, hr, "GetWriterStatus");
1158 nState = 0; /* Unknown writer state -- API failed */
1159 } else {
1160 switch (eWriterStatus) {
1161 case VSS_WS_FAILED_AT_IDENTIFY:
1162 case VSS_WS_FAILED_AT_PREPARE_BACKUP:
1163 case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
1164 case VSS_WS_FAILED_AT_FREEZE:
1165 case VSS_WS_FAILED_AT_THAW:
1166 case VSS_WS_FAILED_AT_POST_SNAPSHOT:
1167 case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
1168 case VSS_WS_FAILED_AT_PRE_RESTORE:
1169 case VSS_WS_FAILED_AT_POST_RESTORE:
1170 #if defined(B_VSS_W2K3) || defined(B_VSS_VISTA)
1171 case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
1172 #endif
1173 /*
1174 * Writer status problem
1175 */
1176 wchar_2_UTF8(szBuf, bstrWriterName.p);
1177 JmsgVssWriterStatus(jcr_, M_WARNING, eWriterStatus, szBuf);
1178 nState = -1; /* bad writer state */
1179 break;
1180 default:
1181 nState = 1; /* Writer state OK */
1182 }
1183 }
1184
1185 /*
1186 * store text info
1187 */
1188 char str[1000];
1189 bstrncpy(str, "\"", sizeof(str));
1190 wchar_2_UTF8(szBuf, bstrWriterName.p);
1191 bstrncat(str, szBuf, sizeof(str));
1192 bstrncat(str, "\", State: 0x", sizeof(str));
1193 itoa(eWriterStatus, szBuf, SizeofPoolMemory(szBuf));
1194 bstrncat(str, szBuf, sizeof(str));
1195 bstrncat(str, " (", sizeof(str));
1196 wchar_2_UTF8(szBuf, GetStringFromWriterStatus(eWriterStatus));
1197 bstrncat(str, szBuf, sizeof(str));
1198 bstrncat(str, ")", sizeof(str));
1199 AppendWriterInfo(nState, (const char*)str);
1200 }
1201
1202 FreePoolMemory(szBuf);
1203 errno = 0;
1204
1205 return true;
1206 }
1207
1208 #endif /* WIN32_VSS */
1209